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
473 decode_audio (CodecContext *ctx, int16_t *samples,
474 int *have_data, uint8_t *in_buf,
475 int in_size, CodecDevice *dev)
477 int len = 0, ret = 0;
478 gpointer buffer = NULL;
481 CODEC_LOG (DEBUG, "enter: %s\n", __func__);
483 ret = secure_device_mem(dev->fd, ctx->index, in_size, &buffer);
485 GST_ERROR ("failed to get available memory to write inbuf");
489 GST_DEBUG ("decode_audio 1. in_buffer size %d", in_size);
490 codec_decode_audio_data_to (in_size, in_buf, buffer);
492 mem_offset = GET_OFFSET(buffer);
494 ret = invoke_device_api(dev->fd, ctx->index, CODEC_DECODE_AUDIO, &mem_offset, SMALLDATA);
500 GST_DEBUG ("decode_audio 2. ctx_id: %d, buffer = 0x%x",
501 ctx->index, device_mem + mem_offset);
503 len = codec_decode_audio_data_from (have_data, samples,
504 &ctx->audio, device_mem + mem_offset);
506 GST_DEBUG ("decode_audio 3. ctx_id: %d len: %d", ctx->index, len);
508 release_device_mem(dev->fd, device_mem + mem_offset);
510 CODEC_LOG (DEBUG, "leave: %s\n", __func__);
516 encode_audio (CodecContext *ctx, uint8_t *out_buf,
517 int max_size, uint8_t *in_buf,
518 int in_size, int64_t timestamp,
522 gpointer buffer = NULL;
525 CODEC_LOG (DEBUG, "enter: %s\n", __func__);
527 ret = secure_device_mem(dev->fd, ctx->index, in_size, &buffer);
532 codec_encode_audio_data_to (in_size, max_size, in_buf, timestamp, buffer);
534 mem_offset = GET_OFFSET(buffer);
536 ret = invoke_device_api(dev->fd, ctx->index, CODEC_ENCODE_AUDIO, &mem_offset, SMALLDATA);
542 GST_DEBUG ("encode_audio. mem_offset = 0x%x", mem_offset);
544 ret = codec_encode_audio_data_from (out_buf, device_mem + mem_offset);
546 release_device_mem(dev->fd, device_mem + mem_offset);
548 CODEC_LOG (DEBUG, "leave: %s\n", __func__);
559 flush_buffers (CodecContext *ctx, CodecDevice *dev)
561 CODEC_LOG (DEBUG, "enter: %s\n", __func__);
563 GST_DEBUG ("flush buffers of context: %d", ctx->index);
564 invoke_device_api (dev->fd, ctx->index, CODEC_FLUSH_BUFFERS, NULL, -1);
566 CODEC_LOG (DEBUG, "leave: %s\n", __func__);
570 get_device_version (int fd)
572 uint32_t device_version;
575 ret = ioctl (fd, IOCTL_RW(IOCTL_CMD_GET_VERSION), &device_version);
580 return device_version;
584 prepare_elements (int fd)
587 int ret, elem_cnt, i;
588 GList *elements = NULL;
591 ret = ioctl (fd, IOCTL_RW(IOCTL_CMD_GET_ELEMENTS_SIZE), &size);
593 GST_ERROR ("get_elements_size failed");
597 elem = g_malloc(size);
599 ret = ioctl (fd, IOCTL_RW(IOCTL_CMD_GET_ELEMENTS), elem);
601 GST_ERROR ("get_elements failed");
606 elem_cnt = size / sizeof(CodecElement);
607 for (i = 0; i < elem_cnt; i++) {
608 elements = g_list_append (elements, &elem[i]);
615 Interface *interface_version_3 = &(Interface) {
618 .decode_video = decode_video,
619 .decode_audio = decode_audio,
620 .encode_video = encode_video,
621 .encode_audio = encode_audio,
622 .flush_buffers = flush_buffers,
623 .buffer_alloc_and_copy = buffer_alloc_and_copy,
624 .get_device_version = get_device_version,
625 .prepare_elements = prepare_elements,