2 * GStreamer codec plugin for Tizen Emulator.
4 * Copyright (C) 2013 Samsung Electronics Co., Ltd. All rights reserved.
7 * KiTae Kim <kt920.kim@samsung.com>
8 * SeokYeon Hwang <syeon.hwang@samsung.com>
9 * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Library General Public License for more details.
21 * You should have received a copy of the GNU Library General Public
22 * License along with this library; if not, write to the
23 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24 * Boston, MA 02111-1307, USA.
32 #include "gstmaruinterface.h"
33 #include "gstmaruutils.h"
34 #include "gstmarumem.h"
35 #include "gstmarudevice.h"
37 Interface *interface = NULL;
40 IOCTL_CMD_GET_VERSION,
41 IOCTL_CMD_GET_ELEMENTS_SIZE,
42 IOCTL_CMD_GET_ELEMENTS,
43 IOCTL_CMD_GET_CONTEXT_INDEX,
44 IOCTL_CMD_SECURE_BUFFER,
45 IOCTL_CMD_TRY_SECURE_BUFFER,
46 IOCTL_CMD_RELEASE_BUFFER,
47 IOCTL_CMD_INVOKE_API_AND_GET_DATA,
55 } __attribute__((packed)) IOCTL_Data;
57 #define BRILLCODEC_KEY 'B'
58 #define IOCTL_RW(CMD) (_IOWR(BRILLCODEC_KEY, CMD, IOCTL_Data))
60 #define CODEC_META_DATA_SIZE 256
61 #define GET_OFFSET(buffer) ((uint32_t)buffer - (uint32_t)device_mem)
64 #define OFFSET_PICTURE_BUFFER 0x100
66 static inline bool can_use_new_decode_api(void) {
67 if (CHECK_VERSION(3)) {
74 invoke_device_api(int fd, int32_t ctx_index, int32_t api_index,
75 uint32_t *mem_offset, int32_t buffer_size)
77 IOCTL_Data ioctl_data = { 0, };
80 CODEC_LOG (DEBUG, "enter: %s\n", __func__);
82 ioctl_data.api_index = api_index;
83 ioctl_data.ctx_index = ctx_index;
85 ioctl_data.mem_offset = *mem_offset;
87 ioctl_data.buffer_size = buffer_size;
89 ret = ioctl(fd, IOCTL_RW(IOCTL_CMD_INVOKE_API_AND_GET_DATA), &ioctl_data);
92 *mem_offset = ioctl_data.mem_offset;
95 CODEC_LOG (DEBUG, "leave: %s\n", __func__);
101 secure_device_mem (int fd, guint ctx_id, guint buf_size, gpointer* buffer)
106 CODEC_LOG (DEBUG, "enter: %s\n", __func__);
107 data.ctx_index = ctx_id;
108 data.buffer_size = buf_size;
110 ret = ioctl (fd, IOCTL_RW(IOCTL_CMD_SECURE_BUFFER), &data);
112 *buffer = (gpointer)((uint32_t)device_mem + data.mem_offset);
113 GST_DEBUG ("device_mem %p, offset_size 0x%x", device_mem, data.mem_offset);
115 CODEC_LOG (DEBUG, "leave: %s\n", __func__);
121 release_device_mem (int fd, gpointer start)
124 uint32_t offset = start - device_mem;
126 CODEC_LOG (DEBUG, "enter: %s\n", __func__);
128 GST_DEBUG ("release device_mem start: %p, offset: 0x%x", start, offset);
129 ret = ioctl (fd, IOCTL_RW(IOCTL_CMD_RELEASE_BUFFER), &offset);
131 GST_ERROR ("failed to release buffer\n");
134 CODEC_LOG (DEBUG, "leave: %s\n", __func__);
138 get_context_index (int fd)
142 if (ioctl (fd, IOCTL_RW(IOCTL_CMD_GET_CONTEXT_INDEX), &ctx_index) < 0) {
143 GST_ERROR ("failed to get a context index, %d", fd);
151 buffer_free (gpointer start)
153 CODEC_LOG (DEBUG, "enter: %s\n", __func__);
155 release_device_mem (device_fd, start);
157 CODEC_LOG (DEBUG, "leave: %s\n", __func__);
161 buffer_free2 (gpointer start)
163 CODEC_LOG (DEBUG, "enter: %s\n", __func__);
165 release_device_mem (device_fd, start - OFFSET_PICTURE_BUFFER);
167 CODEC_LOG (DEBUG, "leave: %s\n", __func__);
170 static inline void fill_size_header(void *buffer, size_t size)
172 *((uint32_t *)buffer) = (uint32_t)size;
181 init (CodecContext *ctx, CodecElement *codec, CodecDevice *dev)
184 gpointer buffer = NULL;
188 CODEC_LOG (DEBUG, "enter: %s\n", __func__);
190 if ((ctx->index = get_context_index(dev->fd)) <= 0) {
191 GST_ERROR ("failed to get a context index");
194 GST_DEBUG ("get context index: %d, %d", ctx->index, dev->fd);
196 /* buffer size is 0. It means that this function is required to
199 if (secure_device_mem(dev->fd, ctx->index, 0, &buffer) < 0) {
200 GST_ERROR ("failed to get a memory block");
204 codec_init_data_to (ctx, codec, buffer);
206 mem_offset = GET_OFFSET(buffer);
207 ret = invoke_device_api (dev->fd, ctx->index, CODEC_INIT, &mem_offset, SMALLDATA);
214 codec_init_data_from (ctx, codec->media_type, device_mem + mem_offset);
217 GST_ERROR ("failed to open Context for %s", codec->name);
222 release_device_mem(dev->fd, device_mem + mem_offset);
224 CODEC_LOG (DEBUG, "leave: %s\n", __func__);
230 deinit (CodecContext *ctx, CodecDevice *dev)
232 CODEC_LOG (DEBUG, "enter: %s\n", __func__);
234 GST_INFO ("close context %d", ctx->index);
235 invoke_device_api (dev->fd, ctx->index, CODEC_DEINIT, NULL, -1);
237 CODEC_LOG (DEBUG, "leave: %s\n", __func__);
242 // VIDEO DECODE / ENCODE
245 struct video_decode_input {
249 uint8_t inbuf; // for pointing inbuf address
250 } __attribute__((packed));
252 struct video_decode_output {
255 uint8_t data; // for pointing data address
256 } __attribute__((packed));
259 decode_video (GstMaruDec *marudec, uint8_t *inbuf, int inbuf_size,
260 gint idx, gint64 in_offset, GstBuffer **out_buf, int *have_data)
262 CodecContext *ctx = marudec->context;
263 CodecDevice *dev = marudec->dev;
264 int len = 0, ret = 0;
265 gpointer buffer = NULL;
267 size_t size = sizeof(inbuf_size) + sizeof(idx) + sizeof(in_offset) + inbuf_size;
269 CODEC_LOG (DEBUG, "enter: %s\n", __func__);
271 ret = secure_device_mem(dev->fd, ctx->index, size, &buffer);
273 GST_ERROR ("failed to get available memory to write inbuf");
277 fill_size_header(buffer, size);
278 struct video_decode_input *decode_input = buffer + sizeof(int32_t);
279 decode_input->inbuf_size = inbuf_size;
280 decode_input->idx = idx;
281 decode_input->in_offset = in_offset;
282 memcpy(&decode_input->inbuf, inbuf, inbuf_size);
284 mem_offset = GET_OFFSET(buffer);
286 marudec->is_using_new_decode_api = (can_use_new_decode_api() && (ctx->video.pix_fmt != -1));
287 if (marudec->is_using_new_decode_api) {
288 int picture_size = gst_maru_avpicture_size (ctx->video.pix_fmt,
289 ctx->video.width, ctx->video.height);
290 if (picture_size < 0) {
291 // can not enter here...
292 GST_ERROR ("Can not enter here. Check about it !!!");
293 picture_size = SMALLDATA;
295 ret = invoke_device_api(dev->fd, ctx->index, CODEC_DECODE_VIDEO_AND_PICTURE_COPY, &mem_offset, picture_size);
297 ret = invoke_device_api(dev->fd, ctx->index, CODEC_DECODE_VIDEO, &mem_offset, SMALLDATA);
301 GST_ERROR ("Invoke API failed");
305 struct video_decode_output *decode_output = device_mem + mem_offset;
306 len = decode_output->len;
307 *have_data = decode_output->got_picture;
308 memcpy(&ctx->video, &decode_output->data, sizeof(VideoData));
310 GST_DEBUG_OBJECT (marudec, "after decode: len %d, have_data %d",
313 if (len >= 0 && *have_data > 0 && marudec->is_using_new_decode_api) {
314 marudec->is_last_buffer = ret;
315 marudec->mem_offset = mem_offset;
317 release_device_mem(dev->fd, device_mem + mem_offset);
320 CODEC_LOG (DEBUG, "leave: %s\n", __func__);
326 buffer_alloc_and_copy (GstPad *pad, guint64 offset, guint size,
327 GstCaps *caps, GstBuffer **buf)
329 bool is_last_buffer = 0;
335 CODEC_LOG (DEBUG, "enter: %s\n", __func__);
337 *buf = gst_buffer_new ();
339 marudec = (GstMaruDec *)gst_pad_get_element_private(pad);
340 ctx = marudec->context;
343 if (marudec->is_using_new_decode_api) {
344 is_last_buffer = marudec->is_last_buffer;
345 mem_offset = marudec->mem_offset;
347 ctx = marudec->context;
351 GST_DEBUG ("buffer_and_copy. ctx_id: %d", ctx->index);
353 int ret = invoke_device_api(dev->fd, ctx->index, CODEC_PICTURE_COPY, &mem_offset, size);
355 GST_DEBUG ("failed to get available buffer");
356 return GST_FLOW_ERROR;
358 is_last_buffer = ret;
361 gpointer *buffer = NULL;
362 if (is_last_buffer) {
363 // FIXME: we must aligned buffer offset.
364 buffer = g_malloc (size);
366 GST_BUFFER_FREE_FUNC (*buf) = g_free;
368 if (marudec->is_using_new_decode_api) {
369 memcpy (buffer, device_mem + mem_offset + OFFSET_PICTURE_BUFFER, size);
371 memcpy (buffer, device_mem + mem_offset, size);
373 release_device_mem(dev->fd, device_mem + mem_offset);
375 GST_DEBUG ("secured last buffer!! Use heap buffer");
377 // address of "device_mem" and "opaque" is aleady aligned.
378 if (marudec->is_using_new_decode_api) {
379 buffer = (gpointer)(device_mem + mem_offset + OFFSET_PICTURE_BUFFER);
380 GST_BUFFER_FREE_FUNC (*buf) = buffer_free2;
382 buffer = (gpointer)(device_mem + mem_offset);
383 GST_BUFFER_FREE_FUNC (*buf) = buffer_free;
387 GST_DEBUG ("device memory start: 0x%p, offset 0x%x", (intptr_t)buffer, mem_offset);
390 GST_BUFFER_DATA (*buf) = GST_BUFFER_MALLOCDATA (*buf) = (void *)buffer;
391 GST_BUFFER_SIZE (*buf) = size;
392 GST_BUFFER_OFFSET (*buf) = offset;
395 gst_buffer_set_caps (*buf, caps);
398 CODEC_LOG (DEBUG, "leave: %s\n", __func__);
403 struct video_encode_input {
405 int64_t in_timestamp;
406 uint8_t inbuf; // for pointing inbuf address
407 } __attribute__((packed));
409 struct video_encode_output {
413 uint8_t data; // for pointing data address
414 } __attribute__((packed));
417 encode_video (CodecContext *ctx, uint8_t *outbuf,
418 int out_size, uint8_t *inbuf,
419 int inbuf_size, int64_t in_timestamp,
420 int *coded_frame, int *is_keyframe,
423 int len = 0, ret = 0;
424 gpointer buffer = NULL;
426 size_t size = sizeof(inbuf_size) + sizeof(in_timestamp) + inbuf_size;
428 CODEC_LOG (DEBUG, "enter: %s\n", __func__);
430 ret = secure_device_mem(dev->fd, ctx->index, size, &buffer);
432 GST_ERROR ("failed to small size of buffer");
436 fill_size_header(buffer, size);
437 struct video_encode_input *encode_input = buffer + sizeof(int32_t);
438 encode_input->inbuf_size = inbuf_size;
439 encode_input->in_timestamp = in_timestamp;
440 memcpy(&encode_input->inbuf, inbuf, inbuf_size);
442 mem_offset = GET_OFFSET(buffer);
444 // FIXME: how can we know output data size ?
445 ret = invoke_device_api(dev->fd, ctx->index, CODEC_ENCODE_VIDEO, &mem_offset, SMALLDATA);
448 GST_ERROR ("Invoke API failed");
452 GST_DEBUG ("encode_video. mem_offset = 0x%x", mem_offset);
454 struct video_encode_output *encode_output = device_mem + mem_offset;
455 len = encode_output->len;
456 *coded_frame = encode_output->coded_frame;
457 *is_keyframe = encode_output->key_frame;
458 memcpy(outbuf, &encode_output->data, len);
460 release_device_mem(dev->fd, device_mem + mem_offset);
462 CODEC_LOG (DEBUG, "leave: %s\n", __func__);
469 // AUDIO DECODE / ENCODE
472 struct audio_decode_input {
474 uint8_t inbuf; // for pointing inbuf address
475 } __attribute__((packed));
477 struct audio_decode_output {
480 uint8_t data; // for pointing data address
481 } __attribute__((packed));
484 decode_audio (CodecContext *ctx, int16_t *samples,
485 int *have_data, uint8_t *inbuf,
486 int inbuf_size, CodecDevice *dev)
488 int len = 0, ret = 0;
489 gpointer buffer = NULL;
491 size_t size = sizeof(inbuf_size) + inbuf_size;
493 CODEC_LOG (DEBUG, "enter: %s\n", __func__);
495 ret = secure_device_mem(dev->fd, ctx->index, size, &buffer);
497 GST_ERROR ("failed to get available memory to write inbuf");
501 GST_DEBUG ("decode_audio. in_buffer size %d", inbuf_size);
503 fill_size_header(buffer, size);
504 struct audio_decode_input *decode_input = buffer + sizeof(int32_t);
505 decode_input->inbuf_size = inbuf_size;
506 memcpy(&decode_input->inbuf, inbuf, inbuf_size);
508 mem_offset = GET_OFFSET(buffer);
510 ret = invoke_device_api(dev->fd, ctx->index, CODEC_DECODE_AUDIO, &mem_offset, SMALLDATA);
516 GST_DEBUG ("decode_audio 2. ctx_id: %d, buffer = 0x%x",
517 ctx->index, device_mem + mem_offset);
519 struct audio_decode_output *decode_output = device_mem + mem_offset;
520 len = decode_output->len;
521 *have_data = decode_output->got_frame;
522 memcpy(&ctx->audio, &decode_output->data, sizeof(AudioData));
524 memcpy (samples, device_mem + mem_offset + OFFSET_PICTURE_BUFFER, len);
526 GST_DEBUG ("decode_audio. sample_fmt %d sample_rate %d, channels %d, ch_layout %lld",
527 ctx->audio.sample_fmt, ctx->audio.sample_rate, ctx->audio.channels, ctx->audio.channel_layout);
528 // GST_DEBUG ("decode_audio 3. ctx_id: %d len: %d", ctx->index, len);
530 release_device_mem(dev->fd, device_mem + mem_offset);
532 CODEC_LOG (DEBUG, "leave: %s\n", __func__);
538 encode_audio (CodecContext *ctx, uint8_t *out_buf,
539 int max_size, uint8_t *in_buf,
540 int in_size, int64_t timestamp,
544 gpointer buffer = NULL;
547 CODEC_LOG (DEBUG, "enter: %s\n", __func__);
549 ret = secure_device_mem(dev->fd, ctx->index, in_size, &buffer);
554 codec_encode_audio_data_to (in_size, max_size, in_buf, timestamp, buffer);
556 mem_offset = GET_OFFSET(buffer);
558 ret = invoke_device_api(dev->fd, ctx->index, CODEC_ENCODE_AUDIO, &mem_offset, SMALLDATA);
564 GST_DEBUG ("encode_audio. mem_offset = 0x%x", mem_offset);
566 ret = codec_encode_audio_data_from (out_buf, device_mem + mem_offset);
568 release_device_mem(dev->fd, device_mem + mem_offset);
570 CODEC_LOG (DEBUG, "leave: %s\n", __func__);
581 flush_buffers (CodecContext *ctx, CodecDevice *dev)
583 CODEC_LOG (DEBUG, "enter: %s\n", __func__);
585 GST_DEBUG ("flush buffers of context: %d", ctx->index);
586 invoke_device_api (dev->fd, ctx->index, CODEC_FLUSH_BUFFERS, NULL, -1);
588 CODEC_LOG (DEBUG, "leave: %s\n", __func__);
592 get_device_version (int fd)
594 uint32_t device_version;
597 ret = ioctl (fd, IOCTL_RW(IOCTL_CMD_GET_VERSION), &device_version);
602 return device_version;
606 prepare_elements (int fd)
609 int ret, elem_cnt, i;
610 GList *elements = NULL;
613 ret = ioctl (fd, IOCTL_RW(IOCTL_CMD_GET_ELEMENTS_SIZE), &size);
615 GST_ERROR ("get_elements_size failed");
619 elem = g_malloc(size);
621 ret = ioctl (fd, IOCTL_RW(IOCTL_CMD_GET_ELEMENTS), elem);
623 GST_ERROR ("get_elements failed");
628 elem_cnt = size / sizeof(CodecElement);
629 for (i = 0; i < elem_cnt; i++) {
630 elements = g_list_append (elements, &elem[i]);
637 Interface *interface_version_3 = &(Interface) {
640 .decode_video = decode_video,
641 .decode_audio = decode_audio,
642 .encode_video = encode_video,
643 .encode_audio = encode_audio,
644 .flush_buffers = flush_buffers,
645 .buffer_alloc_and_copy = buffer_alloc_and_copy,
646 .get_device_version = get_device_version,
647 .prepare_elements = prepare_elements,