remove unused sources and write some comments.
[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   IOCTL_CMD_GET_PROFILE_STATUS,
49 };
50
51 typedef struct {
52   uint32_t  api_index;
53   uint32_t  ctx_index;
54   uint32_t  mem_offset;
55   int32_t  buffer_size;
56 } __attribute__((packed)) IOCTL_Data;
57
58 #define BRILLCODEC_KEY         'B'
59 #define IOCTL_RW(CMD)           (_IOWR(BRILLCODEC_KEY, CMD, IOCTL_Data))
60
61 #define CODEC_META_DATA_SIZE    256
62 #define GET_OFFSET(buffer)      ((uint32_t)buffer - (uint32_t)device_mem)
63 #define SMALLDATA               0
64
65 #define OFFSET_PICTURE_BUFFER   0x100
66
67 static inline bool can_use_new_decode_api(void) {
68     if (CHECK_VERSION(3)) {
69         return true;
70     }
71     return false;
72 }
73
74 static int
75 invoke_device_api(int fd, int32_t ctx_index, int32_t api_index,
76                           uint32_t *mem_offset, int32_t buffer_size)
77 {
78   IOCTL_Data ioctl_data = { 0, };
79   int ret = -1;
80
81   ioctl_data.api_index = api_index;
82   ioctl_data.ctx_index = ctx_index;
83   if (mem_offset) {
84     ioctl_data.mem_offset = *mem_offset;
85   }
86   ioctl_data.buffer_size = buffer_size;
87
88   ret = ioctl(fd, IOCTL_RW(IOCTL_CMD_INVOKE_API_AND_GET_DATA), &ioctl_data);
89
90   if (mem_offset) {
91     *mem_offset = ioctl_data.mem_offset;
92   }
93
94   return ret;
95 }
96
97 static int
98 secure_device_mem (int fd, guint ctx_id, guint buf_size, gpointer* buffer)
99 {
100   int ret = 0;
101   IOCTL_Data data;
102
103   data.ctx_index = ctx_id;
104   data.buffer_size = buf_size;
105
106   ret = ioctl (fd, IOCTL_RW(IOCTL_CMD_SECURE_BUFFER), &data);
107
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);
110
111   return ret;
112 }
113
114 static void
115 release_device_mem (int fd, gpointer start)
116 {
117   int ret;
118   uint32_t offset = start - device_mem;
119
120   GST_DEBUG ("release device_mem start: %p, offset: 0x%x", start, offset);
121   ret = ioctl (fd, IOCTL_RW(IOCTL_CMD_RELEASE_BUFFER), &offset);
122   if (ret < 0) {
123     GST_ERROR ("failed to release buffer\n");
124   }
125 }
126
127 static int
128 get_context_index (int fd)
129 {
130   int ctx_index;
131
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);
134     return -1;
135   }
136
137   return ctx_index;
138 }
139
140 static void
141 buffer_free (gpointer start)
142 {
143   release_device_mem (device_fd, start);
144 }
145
146 static void
147 buffer_free2 (gpointer start)
148 {
149   release_device_mem (device_fd, start - OFFSET_PICTURE_BUFFER);
150 }
151
152 static inline void fill_size_header(void *buffer, size_t size)
153 {
154   *((uint32_t *)buffer) = (uint32_t)size;
155 }
156
157 //
158 // Interface
159 // INIT / DEINIT
160 //
161
162 static int
163 init (CodecContext *ctx, CodecElement *codec, CodecDevice *dev)
164 {
165   int opened = 0;
166   gpointer buffer = NULL;
167   int ret;
168   uint32_t mem_offset;
169
170   if ((ctx->index = get_context_index(dev->fd)) <= 0) {
171     GST_ERROR ("failed to get a context index");
172     return -1;
173   }
174   GST_DEBUG ("get context index: %d, %d", ctx->index, dev->fd);
175
176   /* buffer size is 0. It means that this function is required to
177    * use small size.
178   */
179   if (secure_device_mem(dev->fd, ctx->index, 0, &buffer) < 0) {
180     GST_ERROR ("failed to get a memory block");
181     return -1;
182   }
183
184   codec_init_data_to (ctx, codec, buffer);
185
186   mem_offset = GET_OFFSET(buffer);
187   ret = invoke_device_api (dev->fd, ctx->index, CODEC_INIT, &mem_offset, SMALLDATA);
188
189   if (ret < 0) {
190     return -1;
191   }
192
193   opened =
194     codec_init_data_from (ctx, codec->media_type, device_mem + mem_offset);
195
196   if (opened < 0) {
197     GST_ERROR ("failed to open Context for %s", codec->name);
198   } else {
199     ctx->codec = codec;
200   }
201
202   release_device_mem(dev->fd, device_mem + mem_offset);
203
204   return opened;
205 }
206
207 static void
208 deinit (CodecContext *ctx, CodecDevice *dev)
209 {
210   GST_INFO ("close context %d", ctx->index);
211   invoke_device_api (dev->fd, ctx->index, CODEC_DEINIT, NULL, -1);
212 }
213
214 //
215 // Interface
216 // VIDEO DECODE / ENCODE
217 //
218
219 struct video_decode_input {
220     int32_t inbuf_size;
221     int32_t idx;
222     int64_t in_offset;
223     uint8_t inbuf;          // for pointing inbuf address
224 } __attribute__((packed));
225
226 struct video_decode_output {
227     int32_t len;
228     int32_t got_picture;
229     uint8_t data;           // for pointing data address
230 } __attribute__((packed));
231
232 static int
233 decode_video (GstMaruDec *marudec, uint8_t *inbuf, int inbuf_size,
234                     gint idx, gint64 in_offset, GstBuffer **out_buf, int *have_data)
235 {
236   CodecContext *ctx = marudec->context;
237   CodecDevice *dev = marudec->dev;
238   int len = 0, ret = 0;
239   gpointer buffer = NULL;
240   uint32_t mem_offset;
241   size_t size = sizeof(inbuf_size) + sizeof(idx) + sizeof(in_offset) + inbuf_size;
242
243   ret = secure_device_mem(dev->fd, ctx->index, size, &buffer);
244   if (ret < 0) {
245     GST_ERROR ("failed to get available memory to write inbuf");
246     return -1;
247   }
248
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);
255
256   mem_offset = GET_OFFSET(buffer);
257
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;
266     }
267     ret = invoke_device_api(dev->fd, ctx->index, CODEC_DECODE_VIDEO_AND_PICTURE_COPY, &mem_offset, picture_size);
268   } else {
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);
271   }
272
273   if (ret < 0) {
274     GST_ERROR ("invoke API failed");
275     return -1;
276   }
277
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));
282
283   GST_DEBUG_OBJECT (marudec, "after decode: len %d, have_data %d",
284         len, *have_data);
285
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;
289   } else {
290     release_device_mem(dev->fd, device_mem + mem_offset);
291   }
292
293   return len;
294 }
295
296 static GstFlowReturn
297 buffer_alloc_and_copy (GstPad *pad, guint64 offset, guint size,
298                   GstCaps *caps, GstBuffer **buf)
299 {
300   bool is_last_buffer = 0;
301   uint32_t mem_offset;
302   GstMaruDec *marudec;
303   CodecContext *ctx;
304   CodecDevice *dev;
305
306   *buf = gst_buffer_new ();
307
308   marudec = (GstMaruDec *)gst_pad_get_element_private(pad);
309   ctx = marudec->context;
310   dev = marudec->dev;
311
312   if (marudec->is_using_new_decode_api) {
313     is_last_buffer = marudec->is_last_buffer;
314     mem_offset = marudec->mem_offset;
315   } else {
316     ctx = marudec->context;
317
318     mem_offset = 0;
319
320     GST_DEBUG ("buffer_and_copy. ctx_id: %d", ctx->index);
321
322     int ret = invoke_device_api(dev->fd, ctx->index, CODEC_PICTURE_COPY, &mem_offset, size);
323     if (ret < 0) {
324       GST_DEBUG ("failed to get available buffer");
325       return GST_FLOW_ERROR;
326     }
327     is_last_buffer = ret;
328   }
329
330   gpointer *buffer = NULL;
331   if (is_last_buffer) {
332     // FIXME: we must aligned buffer offset.
333     buffer = g_malloc (size);
334
335     GST_BUFFER_FREE_FUNC (*buf) = g_free;
336
337     if (marudec->is_using_new_decode_api) {
338       memcpy (buffer, device_mem + mem_offset + OFFSET_PICTURE_BUFFER, size);
339     } else {
340       memcpy (buffer, device_mem + mem_offset, size);
341     }
342     release_device_mem(dev->fd, device_mem + mem_offset);
343
344     GST_DEBUG ("secured last buffer!! Use heap buffer");
345   } else {
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;
350     } else {
351       buffer = (gpointer)(device_mem + mem_offset);
352       GST_BUFFER_FREE_FUNC (*buf) = buffer_free;
353     }
354
355
356     GST_DEBUG ("device memory start: 0x%p, offset 0x%x", (intptr_t)buffer, mem_offset);
357   }
358
359   GST_BUFFER_DATA (*buf) = GST_BUFFER_MALLOCDATA (*buf) = (void *)buffer;
360   GST_BUFFER_SIZE (*buf) = size;
361   GST_BUFFER_OFFSET (*buf) = offset;
362
363   if (caps) {
364     gst_buffer_set_caps (*buf, caps);
365   }
366
367   return GST_FLOW_OK;
368 }
369
370 struct video_encode_input {
371     int32_t inbuf_size;
372     int64_t in_timestamp;
373     uint8_t inbuf;          // for pointing inbuf address
374 } __attribute__((packed));
375
376 struct video_encode_output {
377     int32_t len;
378     int32_t coded_frame;
379     int32_t key_frame;
380     uint8_t data;           // for pointing data address
381 } __attribute__((packed));
382
383 static int
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,
388                     CodecDevice *dev)
389 {
390   int len = 0, ret = 0;
391   gpointer buffer = NULL;
392   uint32_t mem_offset;
393   size_t size = sizeof(inbuf_size) + sizeof(in_timestamp) + inbuf_size;
394
395   ret = secure_device_mem(dev->fd, ctx->index, size, &buffer);
396   if (ret < 0) {
397     GST_ERROR ("failed to small size of buffer");
398     return -1;
399   }
400
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);
406
407   mem_offset = GET_OFFSET(buffer);
408
409   ret = invoke_device_api(dev->fd, ctx->index, CODEC_ENCODE_VIDEO, &mem_offset, SMALLDATA);
410
411   if (ret < 0) {
412     GST_ERROR ("Invoke API failed");
413     return -1;
414   }
415
416   GST_DEBUG ("encode_video. mem_offset = 0x%x", mem_offset);
417
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);
423
424   release_device_mem(dev->fd, device_mem + mem_offset);
425
426   return len;
427 }
428
429 //
430 // Interface
431 // AUDIO DECODE / ENCODE
432 //
433
434 struct audio_decode_input {
435     int32_t inbuf_size;
436     uint8_t inbuf;          // for pointing inbuf address
437 } __attribute__((packed));
438
439 struct audio_decode_output {
440     int32_t len;
441     int32_t got_frame;
442     uint8_t data;           // for pointing data address
443 } __attribute__((packed));
444
445 struct audio_encode_input {
446     int32_t inbuf_size;
447     uint8_t inbuf;          // for pointing inbuf address
448 } __attribute__((packed));
449
450 struct audio_encode_output {
451     int32_t len;
452     uint8_t data;           // for pointing data address
453 } __attribute__((packed));
454
455 static int
456 decode_audio (CodecContext *ctx, int16_t *samples,
457                     int *have_data, uint8_t *inbuf,
458                     int inbuf_size, CodecDevice *dev)
459 {
460   int len = 0, ret = 0;
461   gpointer buffer = NULL;
462   uint32_t mem_offset;
463   size_t size = sizeof(inbuf_size) + inbuf_size;
464
465   ret = secure_device_mem(dev->fd, ctx->index, size, &buffer);
466   if (ret < 0) {
467     GST_ERROR ("failed to get available memory to write inbuf");
468     return -1;
469   }
470
471   GST_DEBUG ("decode_audio. in_buffer size %d", inbuf_size);
472
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);
477
478   mem_offset = GET_OFFSET(buffer);
479
480   ret = invoke_device_api(dev->fd, ctx->index, CODEC_DECODE_AUDIO, &mem_offset, SMALLDATA);
481
482   if (ret < 0) {
483     return -1;
484   }
485
486   GST_DEBUG ("decode_audio. ctx_id: %d, buffer = 0x%x",
487     ctx->index, device_mem + mem_offset);
488
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));
493
494   memcpy (samples, device_mem + mem_offset + OFFSET_PICTURE_BUFFER, len);
495
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);
498
499   release_device_mem(dev->fd, device_mem + mem_offset);
500
501   return len;
502 }
503
504 static int
505 encode_audio (CodecContext *ctx, uint8_t *outbuf,
506                     int max_size, uint8_t *inbuf,
507                     int inbuf_size, int64_t timestamp,
508                     CodecDevice *dev)
509 {
510   int len = 0, ret = 0;
511   gpointer buffer = NULL;
512   uint32_t mem_offset;
513   size_t size = sizeof(inbuf_size) + inbuf_size;
514
515   ret = secure_device_mem(dev->fd, ctx->index, inbuf_size, &buffer);
516   if (ret < 0) {
517     GST_ERROR ("failed to get available memory to write inbuf");
518     return -1;
519   }
520
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);
525
526   mem_offset = GET_OFFSET(buffer);
527
528   ret = invoke_device_api(dev->fd, ctx->index, CODEC_ENCODE_AUDIO, &mem_offset, SMALLDATA);
529
530   if (ret < 0) {
531     return -1;
532   }
533
534   GST_DEBUG ("encode_audio. mem_offset = 0x%x", mem_offset);
535
536   struct audio_encode_output *encode_output = device_mem + mem_offset;
537   len = encode_output->len;
538   if (len > 0) {
539     memcpy (outbuf, &encode_output->data, len);
540   }
541
542   GST_DEBUG ("encode_audio. len: %d", len);
543
544   release_device_mem(dev->fd, device_mem + mem_offset);
545
546   return len;
547 }
548
549 //
550 // Interface
551 // MISC
552 //
553
554 static void
555 flush_buffers (CodecContext *ctx, CodecDevice *dev)
556 {
557   GST_DEBUG ("flush buffers of context: %d", ctx->index);
558   invoke_device_api (dev->fd, ctx->index, CODEC_FLUSH_BUFFERS, NULL, -1);
559 }
560
561 static int
562 get_device_version (int fd)
563 {
564   uint32_t device_version;
565   int ret;
566
567   ret = ioctl (fd, IOCTL_RW(IOCTL_CMD_GET_VERSION), &device_version);
568   if (ret < 0) {
569     return ret;
570   }
571
572   return device_version;
573 }
574
575 static GList *
576 prepare_elements (int fd)
577 {
578   uint32_t size = 0;
579   int ret, elem_cnt, i;
580   GList *elements = NULL;
581   CodecElement *elem;
582
583   ret = ioctl (fd, IOCTL_RW(IOCTL_CMD_GET_ELEMENTS_SIZE), &size);
584   if (ret < 0) {
585     GST_ERROR ("get_elements_size failed");
586     return NULL;
587   }
588
589   elem = g_malloc(size);
590
591   ret = ioctl (fd, IOCTL_RW(IOCTL_CMD_GET_ELEMENTS), elem);
592   if (ret < 0) {
593     GST_ERROR ("get_elements failed");
594     g_free (elem);
595     return NULL;
596   }
597
598   elem_cnt = size / sizeof(CodecElement);
599   for (i = 0; i < elem_cnt; i++) {
600     elements = g_list_append (elements, &elem[i]);
601   }
602
603   return elements;
604 }
605
606 static int
607 get_profile_status (int fd)
608 {
609   uint8_t profile_status;
610   int ret;
611
612   ret = ioctl (fd, IOCTL_RW(IOCTL_CMD_GET_PROFILE_STATUS), &profile_status);
613   if (ret < 0) {
614     return ret;
615   }
616
617   return profile_status;
618 }
619
620 // Interfaces
621 Interface *interface_version_3 = &(Interface) {
622   .init = init,
623   .deinit = deinit,
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,
633 };