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,
48 IOCTL_CMD_GET_PROFILE_STATUS,
56 } __attribute__((packed)) IOCTL_Data;
58 #define BRILLCODEC_KEY 'B'
59 #define IOCTL_RW(CMD) (_IOWR(BRILLCODEC_KEY, CMD, IOCTL_Data))
61 #define CODEC_META_DATA_SIZE 256
62 #define GET_OFFSET(buffer) ((uint32_t)buffer - (uint32_t)device_mem)
65 #define OFFSET_PICTURE_BUFFER 0x100
67 static inline bool can_use_new_decode_api(void) {
68 if (CHECK_VERSION(3)) {
75 invoke_device_api(int fd, int32_t ctx_index, int32_t api_index,
76 uint32_t *mem_offset, int32_t buffer_size)
78 IOCTL_Data ioctl_data = { 0, };
81 ioctl_data.api_index = api_index;
82 ioctl_data.ctx_index = ctx_index;
84 ioctl_data.mem_offset = *mem_offset;
86 ioctl_data.buffer_size = buffer_size;
88 ret = ioctl(fd, IOCTL_RW(IOCTL_CMD_INVOKE_API_AND_GET_DATA), &ioctl_data);
91 *mem_offset = ioctl_data.mem_offset;
98 secure_device_mem (int fd, guint ctx_id, guint buf_size, gpointer* buffer)
103 data.ctx_index = ctx_id;
104 data.buffer_size = buf_size;
106 ret = ioctl (fd, IOCTL_RW(IOCTL_CMD_SECURE_BUFFER), &data);
108 *buffer = (gpointer)((uint32_t)device_mem + data.mem_offset);
109 GST_DEBUG ("device_mem %p, offset_size 0x%x", device_mem, data.mem_offset);
115 release_device_mem (int fd, gpointer start)
118 uint32_t offset = start - device_mem;
120 GST_DEBUG ("release device_mem start: %p, offset: 0x%x", start, offset);
121 ret = ioctl (fd, IOCTL_RW(IOCTL_CMD_RELEASE_BUFFER), &offset);
123 GST_ERROR ("failed to release buffer\n");
128 get_context_index (int fd)
132 if (ioctl (fd, IOCTL_RW(IOCTL_CMD_GET_CONTEXT_INDEX), &ctx_index) < 0) {
133 GST_ERROR ("failed to get a context index, %d", fd);
141 buffer_free (gpointer start)
143 release_device_mem (device_fd, start);
147 buffer_free2 (gpointer start)
149 release_device_mem (device_fd, start - OFFSET_PICTURE_BUFFER);
152 static inline void fill_size_header(void *buffer, size_t size)
154 *((uint32_t *)buffer) = (uint32_t)size;
163 init (CodecContext *ctx, CodecElement *codec, CodecDevice *dev)
166 gpointer buffer = NULL;
170 if ((ctx->index = get_context_index(dev->fd)) <= 0) {
171 GST_ERROR ("failed to get a context index");
174 GST_DEBUG ("get context index: %d, %d", ctx->index, dev->fd);
176 /* buffer size is 0. It means that this function is required to
179 if (secure_device_mem(dev->fd, ctx->index, 0, &buffer) < 0) {
180 GST_ERROR ("failed to get a memory block");
184 codec_init_data_to (ctx, codec, buffer);
186 mem_offset = GET_OFFSET(buffer);
187 ret = invoke_device_api (dev->fd, ctx->index, CODEC_INIT, &mem_offset, SMALLDATA);
194 codec_init_data_from (ctx, codec->media_type, device_mem + mem_offset);
197 GST_ERROR ("failed to open Context for %s", codec->name);
202 release_device_mem(dev->fd, device_mem + mem_offset);
208 deinit (CodecContext *ctx, CodecDevice *dev)
210 GST_INFO ("close context %d", ctx->index);
211 invoke_device_api (dev->fd, ctx->index, CODEC_DEINIT, NULL, -1);
216 // VIDEO DECODE / ENCODE
219 struct video_decode_input {
223 uint8_t inbuf; // for pointing inbuf address
224 } __attribute__((packed));
226 struct video_decode_output {
229 uint8_t data; // for pointing data address
230 } __attribute__((packed));
233 decode_video (GstMaruDec *marudec, uint8_t *inbuf, int inbuf_size,
234 gint idx, gint64 in_offset, GstBuffer **out_buf, int *have_data)
236 CodecContext *ctx = marudec->context;
237 CodecDevice *dev = marudec->dev;
238 int len = 0, ret = 0;
239 gpointer buffer = NULL;
241 size_t size = sizeof(inbuf_size) + sizeof(idx) + sizeof(in_offset) + inbuf_size;
243 ret = secure_device_mem(dev->fd, ctx->index, size, &buffer);
245 GST_ERROR ("failed to get available memory to write inbuf");
249 fill_size_header(buffer, size);
250 struct video_decode_input *decode_input = buffer + sizeof(int32_t);
251 decode_input->inbuf_size = inbuf_size;
252 decode_input->idx = idx;
253 decode_input->in_offset = in_offset;
254 memcpy(&decode_input->inbuf, inbuf, inbuf_size);
256 mem_offset = GET_OFFSET(buffer);
258 marudec->is_using_new_decode_api = (can_use_new_decode_api() && (ctx->video.pix_fmt != -1));
259 if (marudec->is_using_new_decode_api) {
260 int picture_size = gst_maru_avpicture_size (ctx->video.pix_fmt,
261 ctx->video.width, ctx->video.height);
262 if (picture_size < 0) {
263 // can not enter here...
264 GST_ERROR ("Can not enter here. Check about it !!!");
265 picture_size = SMALLDATA;
267 ret = invoke_device_api(dev->fd, ctx->index, CODEC_DECODE_VIDEO_AND_PICTURE_COPY, &mem_offset, picture_size);
269 // in case of this, a decoded frame is not given from codec device.
270 ret = invoke_device_api(dev->fd, ctx->index, CODEC_DECODE_VIDEO, &mem_offset, SMALLDATA);
274 GST_ERROR ("invoke API failed");
278 struct video_decode_output *decode_output = device_mem + mem_offset;
279 len = decode_output->len;
280 *have_data = decode_output->got_picture;
281 memcpy(&ctx->video, &decode_output->data, sizeof(VideoData));
283 GST_DEBUG_OBJECT (marudec, "after decode: len %d, have_data %d",
286 if (len >= 0 && *have_data > 0 && marudec->is_using_new_decode_api) {
287 marudec->is_last_buffer = ret;
288 marudec->mem_offset = mem_offset;
290 release_device_mem(dev->fd, device_mem + mem_offset);
297 buffer_alloc_and_copy (GstPad *pad, guint64 offset, guint size,
298 GstCaps *caps, GstBuffer **buf)
300 bool is_last_buffer = 0;
306 *buf = gst_buffer_new ();
308 marudec = (GstMaruDec *)gst_pad_get_element_private(pad);
309 ctx = marudec->context;
312 if (marudec->is_using_new_decode_api) {
313 is_last_buffer = marudec->is_last_buffer;
314 mem_offset = marudec->mem_offset;
316 ctx = marudec->context;
320 GST_DEBUG ("buffer_and_copy. ctx_id: %d", ctx->index);
322 int ret = invoke_device_api(dev->fd, ctx->index, CODEC_PICTURE_COPY, &mem_offset, size);
324 GST_DEBUG ("failed to get available buffer");
325 return GST_FLOW_ERROR;
327 is_last_buffer = ret;
330 gpointer *buffer = NULL;
331 if (is_last_buffer) {
332 // FIXME: we must aligned buffer offset.
333 buffer = g_malloc (size);
335 GST_BUFFER_FREE_FUNC (*buf) = g_free;
337 if (marudec->is_using_new_decode_api) {
338 memcpy (buffer, device_mem + mem_offset + OFFSET_PICTURE_BUFFER, size);
340 memcpy (buffer, device_mem + mem_offset, size);
342 release_device_mem(dev->fd, device_mem + mem_offset);
344 GST_DEBUG ("secured last buffer!! Use heap buffer");
346 // address of "device_mem" and "opaque" is aleady aligned.
347 if (marudec->is_using_new_decode_api) {
348 buffer = (gpointer)(device_mem + mem_offset + OFFSET_PICTURE_BUFFER);
349 GST_BUFFER_FREE_FUNC (*buf) = buffer_free2;
351 buffer = (gpointer)(device_mem + mem_offset);
352 GST_BUFFER_FREE_FUNC (*buf) = buffer_free;
356 GST_DEBUG ("device memory start: 0x%p, offset 0x%x", (intptr_t)buffer, mem_offset);
359 GST_BUFFER_DATA (*buf) = GST_BUFFER_MALLOCDATA (*buf) = (void *)buffer;
360 GST_BUFFER_SIZE (*buf) = size;
361 GST_BUFFER_OFFSET (*buf) = offset;
364 gst_buffer_set_caps (*buf, caps);
370 struct video_encode_input {
372 int64_t in_timestamp;
373 uint8_t inbuf; // for pointing inbuf address
374 } __attribute__((packed));
376 struct video_encode_output {
380 uint8_t data; // for pointing data address
381 } __attribute__((packed));
384 encode_video (CodecContext *ctx, uint8_t *outbuf,
385 int out_size, uint8_t *inbuf,
386 int inbuf_size, int64_t in_timestamp,
387 int *coded_frame, int *is_keyframe,
390 int len = 0, ret = 0;
391 gpointer buffer = NULL;
393 size_t size = sizeof(inbuf_size) + sizeof(in_timestamp) + inbuf_size;
395 ret = secure_device_mem(dev->fd, ctx->index, size, &buffer);
397 GST_ERROR ("failed to small size of buffer");
401 fill_size_header(buffer, size);
402 struct video_encode_input *encode_input = buffer + sizeof(int32_t);
403 encode_input->inbuf_size = inbuf_size;
404 encode_input->in_timestamp = in_timestamp;
405 memcpy(&encode_input->inbuf, inbuf, inbuf_size);
407 mem_offset = GET_OFFSET(buffer);
409 ret = invoke_device_api(dev->fd, ctx->index, CODEC_ENCODE_VIDEO, &mem_offset, SMALLDATA);
412 GST_ERROR ("Invoke API failed");
416 GST_DEBUG ("encode_video. mem_offset = 0x%x", mem_offset);
418 struct video_encode_output *encode_output = device_mem + mem_offset;
419 len = encode_output->len;
420 *coded_frame = encode_output->coded_frame;
421 *is_keyframe = encode_output->key_frame;
422 memcpy(outbuf, &encode_output->data, len);
424 release_device_mem(dev->fd, device_mem + mem_offset);
431 // AUDIO DECODE / ENCODE
434 struct audio_decode_input {
436 uint8_t inbuf; // for pointing inbuf address
437 } __attribute__((packed));
439 struct audio_decode_output {
442 uint8_t data; // for pointing data address
443 } __attribute__((packed));
445 struct audio_encode_input {
447 uint8_t inbuf; // for pointing inbuf address
448 } __attribute__((packed));
450 struct audio_encode_output {
452 uint8_t data; // for pointing data address
453 } __attribute__((packed));
456 decode_audio (CodecContext *ctx, int16_t *samples,
457 int *have_data, uint8_t *inbuf,
458 int inbuf_size, CodecDevice *dev)
460 int len = 0, ret = 0;
461 gpointer buffer = NULL;
463 size_t size = sizeof(inbuf_size) + inbuf_size;
465 ret = secure_device_mem(dev->fd, ctx->index, size, &buffer);
467 GST_ERROR ("failed to get available memory to write inbuf");
471 GST_DEBUG ("decode_audio. in_buffer size %d", inbuf_size);
473 fill_size_header(buffer, size);
474 struct audio_decode_input *decode_input = buffer + sizeof(int32_t);
475 decode_input->inbuf_size = inbuf_size;
476 memcpy(&decode_input->inbuf, inbuf, inbuf_size);
478 mem_offset = GET_OFFSET(buffer);
480 ret = invoke_device_api(dev->fd, ctx->index, CODEC_DECODE_AUDIO, &mem_offset, SMALLDATA);
486 GST_DEBUG ("decode_audio. ctx_id: %d, buffer = 0x%x",
487 ctx->index, device_mem + mem_offset);
489 struct audio_decode_output *decode_output = device_mem + mem_offset;
490 len = decode_output->len;
491 *have_data = decode_output->got_frame;
492 memcpy(&ctx->audio, &decode_output->data, sizeof(AudioData));
494 memcpy (samples, device_mem + mem_offset + OFFSET_PICTURE_BUFFER, len);
496 GST_DEBUG ("decode_audio. sample_fmt %d sample_rate %d, channels %d, ch_layout %lld",
497 ctx->audio.sample_fmt, ctx->audio.sample_rate, ctx->audio.channels, ctx->audio.channel_layout);
499 release_device_mem(dev->fd, device_mem + mem_offset);
505 encode_audio (CodecContext *ctx, uint8_t *outbuf,
506 int max_size, uint8_t *inbuf,
507 int inbuf_size, int64_t timestamp,
510 int len = 0, ret = 0;
511 gpointer buffer = NULL;
513 size_t size = sizeof(inbuf_size) + inbuf_size;
515 ret = secure_device_mem(dev->fd, ctx->index, inbuf_size, &buffer);
517 GST_ERROR ("failed to get available memory to write inbuf");
521 fill_size_header(buffer, size);
522 struct audio_encode_input *encode_input = buffer + sizeof(int32_t);
523 encode_input->inbuf_size = inbuf_size;
524 memcpy(&encode_input->inbuf, inbuf, inbuf_size);
526 mem_offset = GET_OFFSET(buffer);
528 ret = invoke_device_api(dev->fd, ctx->index, CODEC_ENCODE_AUDIO, &mem_offset, SMALLDATA);
534 GST_DEBUG ("encode_audio. mem_offset = 0x%x", mem_offset);
536 struct audio_encode_output *encode_output = device_mem + mem_offset;
537 len = encode_output->len;
539 memcpy (outbuf, &encode_output->data, len);
542 GST_DEBUG ("encode_audio. len: %d", len);
544 release_device_mem(dev->fd, device_mem + mem_offset);
555 flush_buffers (CodecContext *ctx, CodecDevice *dev)
557 GST_DEBUG ("flush buffers of context: %d", ctx->index);
558 invoke_device_api (dev->fd, ctx->index, CODEC_FLUSH_BUFFERS, NULL, -1);
562 get_device_version (int fd)
564 uint32_t device_version;
567 ret = ioctl (fd, IOCTL_RW(IOCTL_CMD_GET_VERSION), &device_version);
572 return device_version;
576 prepare_elements (int fd)
579 int ret, elem_cnt, i;
580 GList *elements = NULL;
583 ret = ioctl (fd, IOCTL_RW(IOCTL_CMD_GET_ELEMENTS_SIZE), &size);
585 GST_ERROR ("get_elements_size failed");
589 elem = g_malloc(size);
591 ret = ioctl (fd, IOCTL_RW(IOCTL_CMD_GET_ELEMENTS), elem);
593 GST_ERROR ("get_elements failed");
598 elem_cnt = size / sizeof(CodecElement);
599 for (i = 0; i < elem_cnt; i++) {
600 elements = g_list_append (elements, &elem[i]);
607 get_profile_status (int fd)
609 uint8_t profile_status;
612 ret = ioctl (fd, IOCTL_RW(IOCTL_CMD_GET_PROFILE_STATUS), &profile_status);
617 return profile_status;
621 Interface *interface_version_3 = &(Interface) {
624 .decode_video = decode_video,
625 .decode_audio = decode_audio,
626 .encode_video = encode_video,
627 .encode_audio = encode_audio,
628 .flush_buffers = flush_buffers,
629 .buffer_alloc_and_copy = buffer_alloc_and_copy,
630 .get_device_version = get_device_version,
631 .prepare_elements = prepare_elements,
632 .get_profile_status = get_profile_status,