apply struct base memory access for audio decoding
[platform/adaptation/emulator/gst-plugins-emulator.git] / src / gstmaruinterface3.c
1 /*
2  * GStreamer codec plugin for Tizen Emulator.
3  *
4  * Copyright (C) 2013 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact:
7  * KiTae Kim <kt920.kim@samsung.com>
8  * SeokYeon Hwang <syeon.hwang@samsung.com>
9  * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
10  *
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.
15  *
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.
20  *
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.
25  *
26  * Contributors:
27  * - S-Core Co., Ltd
28  *
29  */
30
31 #include "gstmaru.h"
32 #include "gstmaruinterface.h"
33 #include "gstmaruutils.h"
34 #include "gstmarumem.h"
35 #include "gstmarudevice.h"
36
37 Interface *interface = NULL;
38
39 enum IOCTL_CMD {
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 };
49
50 typedef struct {
51   uint32_t  api_index;
52   uint32_t  ctx_index;
53   uint32_t  mem_offset;
54   int32_t  buffer_size;
55 } __attribute__((packed)) IOCTL_Data;
56
57 #define BRILLCODEC_KEY         'B'
58 #define IOCTL_RW(CMD)           (_IOWR(BRILLCODEC_KEY, CMD, IOCTL_Data))
59
60 #define CODEC_META_DATA_SIZE    256
61 #define GET_OFFSET(buffer)      ((uint32_t)buffer - (uint32_t)device_mem)
62 #define SMALLDATA               0
63
64 #define OFFSET_PICTURE_BUFFER   0x100
65
66 static inline bool can_use_new_decode_api(void) {
67     if (CHECK_VERSION(3)) {
68         return true;
69     }
70     return false;
71 }
72
73 static int
74 invoke_device_api(int fd, int32_t ctx_index, int32_t api_index,
75                           uint32_t *mem_offset, int32_t buffer_size)
76 {
77   IOCTL_Data ioctl_data = { 0, };
78   int ret = -1;
79
80   CODEC_LOG (DEBUG, "enter: %s\n", __func__);
81
82   ioctl_data.api_index = api_index;
83   ioctl_data.ctx_index = ctx_index;
84   if (mem_offset) {
85     ioctl_data.mem_offset = *mem_offset;
86   }
87   ioctl_data.buffer_size = buffer_size;
88
89   ret = ioctl(fd, IOCTL_RW(IOCTL_CMD_INVOKE_API_AND_GET_DATA), &ioctl_data);
90
91   if (mem_offset) {
92     *mem_offset = ioctl_data.mem_offset;
93   }
94
95   CODEC_LOG (DEBUG, "leave: %s\n", __func__);
96
97   return ret;
98 }
99
100 static int
101 secure_device_mem (int fd, guint ctx_id, guint buf_size, gpointer* buffer)
102 {
103   int ret = 0;
104   IOCTL_Data data;
105
106   CODEC_LOG (DEBUG, "enter: %s\n", __func__);
107   data.ctx_index = ctx_id;
108   data.buffer_size = buf_size;
109
110   ret = ioctl (fd, IOCTL_RW(IOCTL_CMD_SECURE_BUFFER), &data);
111
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);
114
115   CODEC_LOG (DEBUG, "leave: %s\n", __func__);
116
117   return ret;
118 }
119
120 static void
121 release_device_mem (int fd, gpointer start)
122 {
123   int ret;
124   uint32_t offset = start - device_mem;
125
126   CODEC_LOG (DEBUG, "enter: %s\n", __func__);
127
128   GST_DEBUG ("release device_mem start: %p, offset: 0x%x", start, offset);
129   ret = ioctl (fd, IOCTL_RW(IOCTL_CMD_RELEASE_BUFFER), &offset);
130   if (ret < 0) {
131     GST_ERROR ("failed to release buffer\n");
132   }
133
134   CODEC_LOG (DEBUG, "leave: %s\n", __func__);
135 }
136
137 static int
138 get_context_index (int fd)
139 {
140   int ctx_index;
141
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);
144     return -1;
145   }
146
147   return ctx_index;
148 }
149
150 static void
151 buffer_free (gpointer start)
152 {
153   CODEC_LOG (DEBUG, "enter: %s\n", __func__);
154
155   release_device_mem (device_fd, start);
156
157   CODEC_LOG (DEBUG, "leave: %s\n", __func__);
158 }
159
160 static void
161 buffer_free2 (gpointer start)
162 {
163   CODEC_LOG (DEBUG, "enter: %s\n", __func__);
164
165   release_device_mem (device_fd, start - OFFSET_PICTURE_BUFFER);
166
167   CODEC_LOG (DEBUG, "leave: %s\n", __func__);
168 }
169
170 static inline void fill_size_header(void *buffer, size_t size)
171 {
172   *((uint32_t *)buffer) = (uint32_t)size;
173 }
174
175 //
176 // Interface
177 // INIT / DEINIT
178 //
179
180 static int
181 init (CodecContext *ctx, CodecElement *codec, CodecDevice *dev)
182 {
183   int opened = 0;
184   gpointer buffer = NULL;
185   int ret;
186   uint32_t mem_offset;
187
188   CODEC_LOG (DEBUG, "enter: %s\n", __func__);
189
190   if ((ctx->index = get_context_index(dev->fd)) <= 0) {
191     GST_ERROR ("failed to get a context index");
192     return -1;
193   }
194   GST_DEBUG ("get context index: %d, %d", ctx->index, dev->fd);
195
196   /* buffer size is 0. It means that this function is required to
197    * use small size.
198   */
199   if (secure_device_mem(dev->fd, ctx->index, 0, &buffer) < 0) {
200     GST_ERROR ("failed to get a memory block");
201     return -1;
202   }
203
204   codec_init_data_to (ctx, codec, buffer);
205
206   mem_offset = GET_OFFSET(buffer);
207   ret = invoke_device_api (dev->fd, ctx->index, CODEC_INIT, &mem_offset, SMALLDATA);
208
209   if (ret < 0) {
210     return -1;
211   }
212
213   opened =
214     codec_init_data_from (ctx, codec->media_type, device_mem + mem_offset);
215
216   if (opened < 0) {
217     GST_ERROR ("failed to open Context for %s", codec->name);
218   } else {
219     ctx->codec = codec;
220   }
221
222   release_device_mem(dev->fd, device_mem + mem_offset);
223
224   CODEC_LOG (DEBUG, "leave: %s\n", __func__);
225
226   return opened;
227 }
228
229 static void
230 deinit (CodecContext *ctx, CodecDevice *dev)
231 {
232   CODEC_LOG (DEBUG, "enter: %s\n", __func__);
233
234   GST_INFO ("close context %d", ctx->index);
235   invoke_device_api (dev->fd, ctx->index, CODEC_DEINIT, NULL, -1);
236
237   CODEC_LOG (DEBUG, "leave: %s\n", __func__);
238 }
239
240 //
241 // Interface
242 // VIDEO DECODE / ENCODE
243 //
244
245 struct video_decode_input {
246     int32_t inbuf_size;
247     int32_t idx;
248     int64_t in_offset;
249     uint8_t inbuf;          // for pointing inbuf address
250 } __attribute__((packed));
251
252 struct video_decode_output {
253     int32_t len;
254     int32_t got_picture;
255     uint8_t data;           // for pointing data address
256 } __attribute__((packed));
257
258 static int
259 decode_video (GstMaruDec *marudec, uint8_t *inbuf, int inbuf_size,
260                     gint idx, gint64 in_offset, GstBuffer **out_buf, int *have_data)
261 {
262   CodecContext *ctx = marudec->context;
263   CodecDevice *dev = marudec->dev;
264   int len = 0, ret = 0;
265   gpointer buffer = NULL;
266   uint32_t mem_offset;
267   size_t size = sizeof(inbuf_size) + sizeof(idx) + sizeof(in_offset) + inbuf_size;
268
269   CODEC_LOG (DEBUG, "enter: %s\n", __func__);
270
271   ret = secure_device_mem(dev->fd, ctx->index, size, &buffer);
272   if (ret < 0) {
273     GST_ERROR ("failed to get available memory to write inbuf");
274     return -1;
275   }
276
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);
283
284   mem_offset = GET_OFFSET(buffer);
285
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;
294     }
295     ret = invoke_device_api(dev->fd, ctx->index, CODEC_DECODE_VIDEO_AND_PICTURE_COPY, &mem_offset, picture_size);
296   } else {
297     ret = invoke_device_api(dev->fd, ctx->index, CODEC_DECODE_VIDEO, &mem_offset, SMALLDATA);
298   }
299
300   if (ret < 0) {
301     GST_ERROR ("Invoke API failed");
302     return -1;
303   }
304
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));
309
310   GST_DEBUG_OBJECT (marudec, "after decode: len %d, have_data %d",
311         len, *have_data);
312
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;
316   } else {
317     release_device_mem(dev->fd, device_mem + mem_offset);
318   }
319
320   CODEC_LOG (DEBUG, "leave: %s\n", __func__);
321
322   return len;
323 }
324
325 static GstFlowReturn
326 buffer_alloc_and_copy (GstPad *pad, guint64 offset, guint size,
327                   GstCaps *caps, GstBuffer **buf)
328 {
329   bool is_last_buffer = 0;
330   uint32_t mem_offset;
331   GstMaruDec *marudec;
332   CodecContext *ctx;
333   CodecDevice *dev;
334
335   CODEC_LOG (DEBUG, "enter: %s\n", __func__);
336
337   *buf = gst_buffer_new ();
338
339   marudec = (GstMaruDec *)gst_pad_get_element_private(pad);
340   ctx = marudec->context;
341   dev = marudec->dev;
342
343   if (marudec->is_using_new_decode_api) {
344     is_last_buffer = marudec->is_last_buffer;
345     mem_offset = marudec->mem_offset;
346   } else {
347     ctx = marudec->context;
348
349     mem_offset = 0;
350
351     GST_DEBUG ("buffer_and_copy. ctx_id: %d", ctx->index);
352
353     int ret = invoke_device_api(dev->fd, ctx->index, CODEC_PICTURE_COPY, &mem_offset, size);
354     if (ret < 0) {
355       GST_DEBUG ("failed to get available buffer");
356       return GST_FLOW_ERROR;
357     }
358     is_last_buffer = ret;
359   }
360
361   gpointer *buffer = NULL;
362   if (is_last_buffer) {
363     // FIXME: we must aligned buffer offset.
364     buffer = g_malloc (size);
365
366     GST_BUFFER_FREE_FUNC (*buf) = g_free;
367
368     if (marudec->is_using_new_decode_api) {
369       memcpy (buffer, device_mem + mem_offset + OFFSET_PICTURE_BUFFER, size);
370     } else {
371       memcpy (buffer, device_mem + mem_offset, size);
372     }
373     release_device_mem(dev->fd, device_mem + mem_offset);
374
375     GST_DEBUG ("secured last buffer!! Use heap buffer");
376   } else {
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;
381     } else {
382       buffer = (gpointer)(device_mem + mem_offset);
383       GST_BUFFER_FREE_FUNC (*buf) = buffer_free;
384     }
385
386
387     GST_DEBUG ("device memory start: 0x%p, offset 0x%x", (intptr_t)buffer, mem_offset);
388   }
389
390   GST_BUFFER_DATA (*buf) = GST_BUFFER_MALLOCDATA (*buf) = (void *)buffer;
391   GST_BUFFER_SIZE (*buf) = size;
392   GST_BUFFER_OFFSET (*buf) = offset;
393
394   if (caps) {
395     gst_buffer_set_caps (*buf, caps);
396   }
397
398   CODEC_LOG (DEBUG, "leave: %s\n", __func__);
399
400   return GST_FLOW_OK;
401 }
402
403 struct video_encode_input {
404     int32_t inbuf_size;
405     int64_t in_timestamp;
406     uint8_t inbuf;          // for pointing inbuf address
407 } __attribute__((packed));
408
409 struct video_encode_output {
410     int32_t len;
411     int32_t coded_frame;
412     int32_t key_frame;
413     uint8_t data;           // for pointing data address
414 } __attribute__((packed));
415
416 static int
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,
421                     CodecDevice *dev)
422 {
423   int len = 0, ret = 0;
424   gpointer buffer = NULL;
425   uint32_t mem_offset;
426   size_t size = sizeof(inbuf_size) + sizeof(in_timestamp) + inbuf_size;
427
428   CODEC_LOG (DEBUG, "enter: %s\n", __func__);
429
430   ret = secure_device_mem(dev->fd, ctx->index, size, &buffer);
431   if (ret < 0) {
432     GST_ERROR ("failed to small size of buffer");
433     return -1;
434   }
435
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);
441
442   mem_offset = GET_OFFSET(buffer);
443
444   // FIXME: how can we know output data size ?
445   ret = invoke_device_api(dev->fd, ctx->index, CODEC_ENCODE_VIDEO, &mem_offset, SMALLDATA);
446
447   if (ret < 0) {
448     GST_ERROR ("Invoke API failed");
449     return -1;
450   }
451
452   GST_DEBUG ("encode_video. mem_offset = 0x%x", mem_offset);
453
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);
459
460   release_device_mem(dev->fd, device_mem + mem_offset);
461
462   CODEC_LOG (DEBUG, "leave: %s\n", __func__);
463
464   return len;
465 }
466
467 //
468 // Interface
469 // AUDIO DECODE / ENCODE
470 //
471
472 struct audio_decode_input {
473     int32_t inbuf_size;
474     uint8_t inbuf;          // for pointing inbuf address
475 } __attribute__((packed));
476
477 struct audio_decode_output {
478     int32_t len;
479     int32_t got_frame;
480     uint8_t data;           // for pointing data address
481 } __attribute__((packed));
482
483 static int
484 decode_audio (CodecContext *ctx, int16_t *samples,
485                     int *have_data, uint8_t *inbuf,
486                     int inbuf_size, CodecDevice *dev)
487 {
488   int len = 0, ret = 0;
489   gpointer buffer = NULL;
490   uint32_t mem_offset;
491   size_t size = sizeof(inbuf_size) + inbuf_size;
492
493   CODEC_LOG (DEBUG, "enter: %s\n", __func__);
494
495   ret = secure_device_mem(dev->fd, ctx->index, size, &buffer);
496   if (ret < 0) {
497     GST_ERROR ("failed to get available memory to write inbuf");
498     return -1;
499   }
500
501   GST_DEBUG ("decode_audio. in_buffer size %d", inbuf_size);
502
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);
507
508   mem_offset = GET_OFFSET(buffer);
509
510   ret = invoke_device_api(dev->fd, ctx->index, CODEC_DECODE_AUDIO, &mem_offset, SMALLDATA);
511
512   if (ret < 0) {
513     return -1;
514   }
515
516   GST_DEBUG ("decode_audio 2. ctx_id: %d, buffer = 0x%x",
517     ctx->index, device_mem + mem_offset);
518
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));
523
524   memcpy (samples, device_mem + mem_offset + OFFSET_PICTURE_BUFFER, len);
525
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);
529
530   release_device_mem(dev->fd, device_mem + mem_offset);
531
532   CODEC_LOG (DEBUG, "leave: %s\n", __func__);
533
534   return len;
535 }
536
537 static int
538 encode_audio (CodecContext *ctx, uint8_t *out_buf,
539                     int max_size, uint8_t *in_buf,
540                     int in_size, int64_t timestamp,
541                     CodecDevice *dev)
542 {
543   int ret = 0;
544   gpointer buffer = NULL;
545   uint32_t mem_offset;
546
547   CODEC_LOG (DEBUG, "enter: %s\n", __func__);
548
549   ret = secure_device_mem(dev->fd, ctx->index, in_size, &buffer);
550   if (ret < 0) {
551     return -1;
552   }
553
554   codec_encode_audio_data_to (in_size, max_size, in_buf, timestamp, buffer);
555
556   mem_offset = GET_OFFSET(buffer);
557
558   ret = invoke_device_api(dev->fd, ctx->index, CODEC_ENCODE_AUDIO, &mem_offset, SMALLDATA);
559
560   if (ret < 0) {
561     return -1;
562   }
563
564   GST_DEBUG ("encode_audio. mem_offset = 0x%x", mem_offset);
565
566   ret = codec_encode_audio_data_from (out_buf, device_mem + mem_offset);
567
568   release_device_mem(dev->fd, device_mem + mem_offset);
569
570   CODEC_LOG (DEBUG, "leave: %s\n", __func__);
571
572   return ret;
573 }
574
575 //
576 // Interface
577 // MISC
578 //
579
580 static void
581 flush_buffers (CodecContext *ctx, CodecDevice *dev)
582 {
583   CODEC_LOG (DEBUG, "enter: %s\n", __func__);
584
585   GST_DEBUG ("flush buffers of context: %d", ctx->index);
586   invoke_device_api (dev->fd, ctx->index, CODEC_FLUSH_BUFFERS, NULL, -1);
587
588   CODEC_LOG (DEBUG, "leave: %s\n", __func__);
589 }
590
591 static int
592 get_device_version (int fd)
593 {
594   uint32_t device_version;
595   int ret;
596
597   ret = ioctl (fd, IOCTL_RW(IOCTL_CMD_GET_VERSION), &device_version);
598   if (ret < 0) {
599     return ret;
600   }
601
602   return device_version;
603 }
604
605 static GList *
606 prepare_elements (int fd)
607 {
608   uint32_t size = 0;
609   int ret, elem_cnt, i;
610   GList *elements = NULL;
611   CodecElement *elem;
612
613   ret = ioctl (fd, IOCTL_RW(IOCTL_CMD_GET_ELEMENTS_SIZE), &size);
614   if (ret < 0) {
615     GST_ERROR ("get_elements_size failed");
616     return NULL;
617   }
618
619   elem = g_malloc(size);
620
621   ret = ioctl (fd, IOCTL_RW(IOCTL_CMD_GET_ELEMENTS), elem);
622   if (ret < 0) {
623     GST_ERROR ("get_elements failed");
624     g_free (elem);
625     return NULL;
626   }
627
628   elem_cnt = size / sizeof(CodecElement);
629   for (i = 0; i < elem_cnt; i++) {
630     elements = g_list_append (elements, &elem[i]);
631   }
632
633   return elements;
634 }
635
636 // Interfaces
637 Interface *interface_version_3 = &(Interface) {
638   .init = init,
639   .deinit = deinit,
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,
648 };