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.
33 #include "gstmaruinterface.h"
34 #include "gstmaruutils.h"
35 #include "gstmarumem.h"
36 #include "gstmarudevice.h"
38 Interface *interface = NULL;
41 IOCTL_CMD_GET_VERSION,
42 IOCTL_CMD_GET_ELEMENTS_SIZE,
43 IOCTL_CMD_GET_ELEMENTS,
44 IOCTL_CMD_GET_CONTEXT_INDEX,
45 IOCTL_CMD_SECURE_BUFFER,
46 IOCTL_CMD_TRY_SECURE_BUFFER,
47 IOCTL_CMD_RELEASE_BUFFER,
48 IOCTL_CMD_INVOKE_API_AND_GET_DATA,
49 IOCTL_CMD_GET_PROFILE_STATUS,
57 } __attribute__((packed)) IOCTL_Data;
59 #define BRILLCODEC_KEY 'B'
60 #define IOCTL_RW(CMD) (_IOWR(BRILLCODEC_KEY, CMD, IOCTL_Data))
62 #define CODEC_META_DATA_SIZE 256
63 #define GET_OFFSET(buffer) ((uintptr_t)buffer - (uintptr_t)device_mem)
66 #define OFFSET_PICTURE_BUFFER 0x100
68 static inline bool can_use_new_decode_api(void) {
69 if (CHECK_VERSION(3)) {
76 invoke_device_api(int fd, int32_t ctx_index, int32_t api_index,
77 uintptr_t *mem_offset, int32_t buffer_size)
79 GST_DEBUG (" >> Enter");
80 IOCTL_Data ioctl_data = { 0, };
83 ioctl_data.api_index = api_index;
84 ioctl_data.ctx_index = ctx_index;
86 ioctl_data.mem_offset = *mem_offset;
88 ioctl_data.buffer_size = buffer_size;
90 ret = ioctl(fd, IOCTL_RW(IOCTL_CMD_INVOKE_API_AND_GET_DATA), &ioctl_data);
93 *mem_offset = ioctl_data.mem_offset;
96 GST_DEBUG (" >> Leave");
101 secure_device_mem (int fd, guint ctx_id, guint buf_size, gpointer* buffer)
103 GST_DEBUG (" >> Enter");
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)(device_mem + data.mem_offset);
113 GST_DEBUG ("device_mem %p, offset_size 0x%"PRIXPTR, device_mem, data.mem_offset);
115 GST_DEBUG (" >> Leave");
120 release_device_mem (int fd, gpointer start)
122 GST_DEBUG (" >> Enter");
124 uint32_t offset = start - device_mem;
126 GST_DEBUG ("release device_mem start: %p, offset: 0x%x", start, offset);
127 ret = ioctl (fd, IOCTL_RW(IOCTL_CMD_RELEASE_BUFFER), &offset);
129 GST_ERROR ("failed to release buffer\n");
131 GST_DEBUG (" >> Leave");
135 get_context_index (int fd)
139 if (ioctl (fd, IOCTL_RW(IOCTL_CMD_GET_CONTEXT_INDEX), &ctx_index) < 0) {
140 GST_ERROR ("failed to get a context index, %d", fd);
146 // TODO: check this code is needed
149 buffer_free (gpointer start)
151 release_device_mem (device_fd, start);
155 buffer_free2 (gpointer start)
157 release_device_mem (device_fd, start - OFFSET_PICTURE_BUFFER);
160 static inline void fill_size_header(void *buffer, size_t size)
162 *((uint32_t *)buffer) = (uint32_t)size;
171 init (CodecContext *ctx, CodecElement *codec, CodecDevice *dev)
174 gpointer buffer = NULL;
176 uintptr_t mem_offset;
178 GST_DEBUG (" >> Enter");
179 if ((ctx->index = get_context_index(dev->fd)) <= 0) {
180 GST_ERROR ("failed to get a context index");
183 GST_DEBUG ("get context index: %d, %d", ctx->index, dev->fd);
185 /* buffer size is 0. It means that this function is required to
188 if (secure_device_mem(dev->fd, ctx->index, 0, &buffer) < 0) {
189 GST_ERROR ("failed to get a memory block");
193 codec_init_data_to (ctx, codec, buffer);
195 mem_offset = GET_OFFSET(buffer);
196 ret = invoke_device_api (dev->fd, ctx->index, CODEC_INIT, &mem_offset, SMALLDATA);
199 GST_ERROR ("invoke_device_api failed");
204 codec_init_data_from (ctx, codec->media_type, device_mem + mem_offset);
207 GST_ERROR ("failed to open Context for %s", codec->name);
212 release_device_mem(dev->fd, device_mem + mem_offset);
214 GST_DEBUG (" >> Leave");
219 deinit (CodecContext *ctx, CodecDevice *dev)
221 GST_INFO ("close context %d", ctx->index);
222 invoke_device_api (dev->fd, ctx->index, CODEC_DEINIT, NULL, -1);
227 // VIDEO DECODE / ENCODE
230 struct video_decode_input {
234 uint8_t inbuf; // for pointing inbuf address
235 } __attribute__((packed));
237 struct video_decode_output {
240 uint8_t data; // for pointing data address
241 } __attribute__((packed));
244 decode_video (GstMaruVidDec *marudec, uint8_t *inbuf, int inbuf_size,
245 gint idx, gint64 in_offset, GstBuffer **out_buf, int *have_data)
247 GST_DEBUG (" >> Enter");
248 CodecContext *ctx = marudec->context;
249 CodecDevice *dev = marudec->dev;
250 int len = 0, ret = 0;
251 gpointer buffer = NULL;
252 uintptr_t mem_offset;
253 size_t size = sizeof(inbuf_size) + sizeof(idx) + sizeof(in_offset) + inbuf_size;
255 ret = secure_device_mem(dev->fd, ctx->index, size, &buffer);
257 GST_ERROR ("failed to get available memory to write inbuf");
261 fill_size_header(buffer, size);
262 struct video_decode_input *decode_input = buffer + sizeof(int32_t);
263 decode_input->inbuf_size = inbuf_size;
264 decode_input->idx = idx;
265 decode_input->in_offset = in_offset;
266 memcpy(&decode_input->inbuf, inbuf, inbuf_size);
268 mem_offset = GET_OFFSET(buffer);
270 marudec->is_using_new_decode_api = (can_use_new_decode_api() && (ctx->video.pix_fmt != -1));
271 if (marudec->is_using_new_decode_api) {
272 int picture_size = gst_maru_avpicture_size (ctx->video.pix_fmt,
273 ctx->video.width, ctx->video.height);
274 if (picture_size < 0) {
275 // can not enter here...
276 GST_ERROR ("Can not enter here. Check about it !!!");
277 picture_size = SMALLDATA;
279 ret = invoke_device_api(dev->fd, ctx->index, CODEC_DECODE_VIDEO_AND_PICTURE_COPY, &mem_offset, picture_size);
281 // in case of this, a decoded frame is not given from codec device.
282 ret = invoke_device_api(dev->fd, ctx->index, CODEC_DECODE_VIDEO, &mem_offset, SMALLDATA);
286 GST_ERROR ("invoke API failed");
290 struct video_decode_output *decode_output = device_mem + mem_offset;
291 len = decode_output->len;
292 *have_data = decode_output->got_picture;
293 memcpy(&ctx->video, &decode_output->data, sizeof(VideoData));
295 GST_DEBUG_OBJECT (marudec, "after decode: len %d, have_data %d",
298 if (len >= 0 && *have_data > 0 && marudec->is_using_new_decode_api) {
299 marudec->is_last_buffer = ret;
300 marudec->mem_offset = mem_offset;
302 release_device_mem(dev->fd, device_mem + mem_offset);
305 GST_DEBUG (" >> Leave");
310 alloc_and_copy (GstMaruVidDec *marudec, guint64 offset, guint size,
311 GstCaps *caps, GstBuffer **buf)
313 GST_DEBUG (" >> enter");
314 bool is_last_buffer = 0;
315 uintptr_t mem_offset;
320 ctx = marudec->context;
323 if (marudec->is_using_new_decode_api) {
324 is_last_buffer = marudec->is_last_buffer;
325 mem_offset = marudec->mem_offset;
327 ctx = marudec->context;
331 int ret = invoke_device_api(dev->fd, ctx->index, CODEC_PICTURE_COPY, &mem_offset, size);
333 GST_DEBUG ("failed to get available buffer");
334 return GST_FLOW_ERROR;
336 is_last_buffer = ret;
339 gpointer *buffer = NULL;
341 if (is_last_buffer) {
342 // FIXME: we must aligned buffer offset.
343 //buffer = g_malloc (size);
344 gst_buffer_map (*buf, &mapinfo, GST_MAP_READWRITE);
346 if (marudec->is_using_new_decode_api) {
347 memcpy (mapinfo.data, device_mem + mem_offset + OFFSET_PICTURE_BUFFER, size);
349 memcpy (mapinfo.data, device_mem + mem_offset, size);
351 release_device_mem(dev->fd, device_mem + mem_offset);
353 GST_DEBUG ("secured last buffer!! Use heap buffer");
355 // address of "device_mem" and "opaque" is aleady aligned.
356 if (marudec->is_using_new_decode_api) {
357 buffer = (gpointer)(device_mem + mem_offset + OFFSET_PICTURE_BUFFER);
358 //GST_BUFFER_FREE_FUNC (*buf) = buffer_free2;
360 buffer = (gpointer)(device_mem + mem_offset);
361 //GST_BUFFER_FREE_FUNC (*buf) = buffer_free;
365 GST_DEBUG ("device memory start: 0x%p, offset 0x%"PRIXPTR, (void *) buffer, mem_offset);
368 gst_buffer_unmap (*buf, &mapinfo);
370 GST_DEBUG (" >> leave");
375 buffer_alloc_and_copy (GstPad *pad, guint64 offset, guint size,
376 GstCaps *caps, GstBuffer **buf)
378 GST_DEBUG (" >> enter");
379 bool is_last_buffer = 0;
380 uintptr_t mem_offset;
386 marudec = (GstMaruDec *)gst_pad_get_element_private(pad);
387 ctx = marudec->context;
390 if (marudec->is_using_new_decode_api) {
391 is_last_buffer = marudec->is_last_buffer;
392 mem_offset = marudec->mem_offset;
394 ctx = marudec->context;
398 GST_DEBUG ("buffer_and_copy. ctx_id: %d", ctx->index);
400 int ret = invoke_device_api(dev->fd, ctx->index, CODEC_PICTURE_COPY, &mem_offset, size);
402 GST_DEBUG ("failed to get available buffer");
403 return GST_FLOW_ERROR;
405 is_last_buffer = ret;
408 gpointer *buffer = NULL;
410 if (is_last_buffer) {
411 // FIXME: we must aligned buffer offset.
412 buffer = g_malloc (size);
414 if (marudec->is_using_new_decode_api) {
415 memcpy (buffer, device_mem + mem_offset + OFFSET_PICTURE_BUFFER, size);
417 memcpy (buffer, device_mem + mem_offset, size);
419 release_device_mem(dev->fd, device_mem + mem_offset);
421 GST_DEBUG ("secured last buffer!! Use heap buffer");
423 // address of "device_mem" and "opaque" is aleady aligned.
424 if (marudec->is_using_new_decode_api) {
425 buffer = (gpointer)(device_mem + mem_offset + OFFSET_PICTURE_BUFFER);
426 //GST_BUFFER_FREE_FUNC (*buf) = buffer_free2;
428 buffer = (gpointer)(device_mem + mem_offset);
429 //GST_BUFFER_FREE_FUNC (*buf) = buffer_free;
433 GST_DEBUG ("device memory start: 0x%p, offset 0x%"PRIXPTR, (void *) buffer, mem_offset);
436 *buf = gst_buffer_new ();
437 //*buf = gst_buffer_new_and_alloc (size);
438 gst_buffer_map (*buf, &mapinfo, GST_MAP_READWRITE);
439 mapinfo.data = (guint8 *)buffer;
441 GST_BUFFER_OFFSET (*buf) = offset;
442 gst_buffer_unmap (*buf, &mapinfo);
444 GST_DEBUG (" >> leave");
448 struct video_encode_input {
450 int64_t in_timestamp;
451 uint8_t inbuf; // for pointing inbuf address
452 } __attribute__((packed));
454 struct video_encode_output {
458 uint8_t data; // for pointing data address
459 } __attribute__((packed));
462 encode_video (CodecContext *ctx, uint8_t *outbuf,
463 int out_size, uint8_t *inbuf,
464 int inbuf_size, int64_t in_timestamp,
465 int *coded_frame, int *is_keyframe,
468 int len = 0, ret = 0;
469 gpointer buffer = NULL;
470 uintptr_t mem_offset;
471 size_t size = sizeof(inbuf_size) + sizeof(in_timestamp) + inbuf_size;
473 ret = secure_device_mem(dev->fd, ctx->index, size, &buffer);
475 GST_ERROR ("failed to small size of buffer");
479 fill_size_header(buffer, size);
480 struct video_encode_input *encode_input = buffer + sizeof(int32_t);
481 encode_input->inbuf_size = inbuf_size;
482 encode_input->in_timestamp = in_timestamp;
483 memcpy(&encode_input->inbuf, inbuf, inbuf_size);
484 GST_DEBUG ("insize: %d, inpts: %lld", encode_input->inbuf_size,(long long) encode_input->in_timestamp);
486 mem_offset = GET_OFFSET(buffer);
488 ret = invoke_device_api(dev->fd, ctx->index, CODEC_ENCODE_VIDEO, &mem_offset, SMALLDATA);
491 GST_ERROR ("Invoke API failed");
495 GST_DEBUG ("encode_video. mem_offset = 0x%"PRIXPTR, mem_offset);
497 struct video_encode_output *encode_output = device_mem + mem_offset;
498 len = encode_output->len;
499 *coded_frame = encode_output->coded_frame;
500 *is_keyframe = encode_output->key_frame;
501 memcpy(outbuf, &encode_output->data, len);
503 release_device_mem(dev->fd, device_mem + mem_offset);
510 // AUDIO DECODE / ENCODE
513 struct audio_decode_input {
515 uint8_t inbuf; // for pointing inbuf address
516 } __attribute__((packed));
518 struct audio_decode_output {
521 uint8_t data; // for pointing data address
522 } __attribute__((packed));
524 struct audio_encode_input {
526 uint8_t inbuf; // for pointing inbuf address
527 } __attribute__((packed));
529 struct audio_encode_output {
531 uint8_t data; // for pointing data address
532 } __attribute__((packed));
535 decode_audio (CodecContext *ctx, int16_t *samples,
536 int *have_data, uint8_t *inbuf,
537 int inbuf_size, CodecDevice *dev)
539 int len = 0, ret = 0;
540 gpointer buffer = NULL;
541 uintptr_t mem_offset;
542 size_t size = sizeof(inbuf_size) + inbuf_size;
544 ret = secure_device_mem(dev->fd, ctx->index, size, &buffer);
546 GST_ERROR ("failed to get available memory to write inbuf");
550 GST_DEBUG ("decode_audio. in_buffer size %d", inbuf_size);
552 fill_size_header(buffer, size);
553 struct audio_decode_input *decode_input = buffer + sizeof(int32_t);
554 decode_input->inbuf_size = inbuf_size;
555 memcpy(&decode_input->inbuf, inbuf, inbuf_size);
557 mem_offset = GET_OFFSET(buffer);
559 ret = invoke_device_api(dev->fd, ctx->index, CODEC_DECODE_AUDIO, &mem_offset, SMALLDATA);
565 GST_DEBUG ("decode_audio. ctx_id: %d, buffer = 0x%p",
566 ctx->index, device_mem + mem_offset);
568 struct audio_decode_output *decode_output = device_mem + mem_offset;
569 len = decode_output->len;
570 *have_data = decode_output->got_frame;
571 memcpy(&ctx->audio, &decode_output->data, sizeof(AudioData));
573 memcpy (samples, device_mem + mem_offset + OFFSET_PICTURE_BUFFER, len);
575 GST_DEBUG ("decode_audio. sample_fmt %d sample_rate %d, channels %d, ch_layout %" PRIu64 ", len %d",
576 ctx->audio.sample_fmt, ctx->audio.sample_rate, ctx->audio.channels,
577 ctx->audio.channel_layout, len);
579 release_device_mem(dev->fd, device_mem + mem_offset);
585 encode_audio (CodecContext *ctx, uint8_t *outbuf,
586 int max_size, uint8_t *inbuf,
587 int inbuf_size, int64_t timestamp,
590 int len = 0, ret = 0;
591 gpointer buffer = NULL;
592 uintptr_t mem_offset;
593 size_t size = sizeof(inbuf_size) + inbuf_size;
595 ret = secure_device_mem(dev->fd, ctx->index, inbuf_size, &buffer);
597 GST_ERROR ("failed to get available memory to write inbuf");
601 fill_size_header(buffer, size);
602 struct audio_encode_input *encode_input = buffer + sizeof(int32_t);
603 encode_input->inbuf_size = inbuf_size;
604 memcpy(&encode_input->inbuf, inbuf, inbuf_size);
606 mem_offset = GET_OFFSET(buffer);
608 ret = invoke_device_api(dev->fd, ctx->index, CODEC_ENCODE_AUDIO, &mem_offset, SMALLDATA);
614 GST_DEBUG ("encode_audio. mem_offset = 0x%"PRIXPTR, mem_offset);
616 struct audio_encode_output *encode_output = device_mem + mem_offset;
617 len = encode_output->len;
619 memcpy (outbuf, &encode_output->data, len);
622 GST_DEBUG ("encode_audio. len: %d", len);
624 release_device_mem(dev->fd, device_mem + mem_offset);
635 flush_buffers (CodecContext *ctx, CodecDevice *dev)
637 GST_DEBUG ("flush buffers of context: %d", ctx->index);
638 invoke_device_api (dev->fd, ctx->index, CODEC_FLUSH_BUFFERS, NULL, -1);
642 get_device_version (int fd)
644 uint32_t device_version;
647 ret = ioctl (fd, IOCTL_RW(IOCTL_CMD_GET_VERSION), &device_version);
652 return device_version;
656 prepare_elements (int fd)
659 int ret, elem_cnt, i;
660 GList *elements = NULL;
663 ret = ioctl (fd, IOCTL_RW(IOCTL_CMD_GET_ELEMENTS_SIZE), &size);
665 GST_ERROR ("get_elements_size failed");
669 elem = g_malloc(size);
671 ret = ioctl (fd, IOCTL_RW(IOCTL_CMD_GET_ELEMENTS), elem);
673 GST_ERROR ("get_elements failed");
678 elem_cnt = size / sizeof(CodecElement);
679 for (i = 0; i < elem_cnt; i++) {
680 elements = g_list_append (elements, &elem[i]);
688 get_profile_status (int fd)
690 uint8_t profile_status;
693 ret = ioctl (fd, IOCTL_RW(IOCTL_CMD_GET_PROFILE_STATUS), &profile_status);
698 return profile_status;
702 Interface *interface_version_3 = &(Interface) {
705 .decode_video = decode_video,
706 .decode_audio = decode_audio,
707 .encode_video = encode_video,
708 .encode_audio = encode_audio,
709 .flush_buffers = flush_buffers,
710 .buffer_alloc_and_copy = buffer_alloc_and_copy,
711 .get_device_version = get_device_version,
712 .prepare_elements = prepare_elements,
713 .get_profile_status = get_profile_status,