Fix close routine at decoder plugin.
[platform/adaptation/emulator/gst-plugins-emulator.git] / src / gstmaruinterface.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 extern int device_fd;
38 extern gpointer device_mem;
39
40 typedef struct {
41   int32_t   api_index;
42   uint32_t  mem_offset;
43 } CodecHeader;
44
45 typedef struct {
46   uint32_t  buffer_index;
47   uint32_t  buffer_size;
48 } CodecBufferId;
49
50 typedef struct {
51   int32_t   api_index;
52   int32_t   ctx_index;
53   uint32_t  mem_offset;
54 } CodecIOParams;
55
56 enum CODEC_IO_CMD {
57   CODEC_CMD_GET_VERSION = 20,
58   CODEC_CMD_GET_ELEMENT,
59   CODEC_CMD_GET_CONTEXT_INDEX,
60   CODEC_CMD_GET_ELEMENT_DATA,
61   CODEC_CMD_PUT_DATA_INTO_BUFFER = 40,
62   CODEC_CMD_SECURE_BUFFER,
63   CODEC_CMD_TRY_SECURE_BUFFER,
64   CODEC_CMD_RELEASE_BUFFER,
65   CODEC_CMD_INVOKE_API_AND_RELEASE_BUFFER,
66 };
67
68
69 #define CODEC_META_DATA_SIZE    256
70 #define GET_OFFSET(buffer)      ((uint32_t)buffer - (uint32_t)device_mem)
71 #define SMALLDATA               0
72
73
74 static int
75 _codec_invoke_qemu(int32_t ctx_index, int32_t api_index,
76                           uint32_t mem_offset, int fd, CodecBufferId *buffer_id)
77 {
78   CodecIOParams ioparam = { 0, };
79   int ret = -1;
80
81   ioparam.api_index = api_index;
82   ioparam.ctx_index = ctx_index;
83   ioparam.mem_offset = mem_offset;
84
85   if (ioctl(fd, CODEC_CMD_INVOKE_API_AND_RELEASE_BUFFER, &ioparam) < 0) {
86       return -1;
87   }
88   if (buffer_id) {
89       ret = ioctl(fd, CODEC_CMD_PUT_DATA_INTO_BUFFER, buffer_id);
90   }
91
92   return ret;
93 }
94
95 static int
96 secure_device_mem (int fd, guint ctx_id, guint buf_size, gpointer* buffer)
97 {
98   int ret = 0;
99   CodecBufferId opaque;
100
101   opaque.buffer_index = ctx_id;
102   opaque.buffer_size = buf_size;
103
104   ret = ioctl (fd, CODEC_CMD_SECURE_BUFFER, &opaque);
105   /* ioctl: CODEC_CMD_SECURE_BUFFER
106    *  - sets device memory offset into opaque.buffer_size
107    */
108   *buffer = (gpointer)((uint32_t)device_mem + opaque.buffer_size);
109   GST_DEBUG ("device_mem %p, offset_size 0x%x", device_mem, opaque.buffer_size);
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, CODEC_CMD_RELEASE_BUFFER, &offset);
122   if (ret < 0) {
123     GST_ERROR ("failed to release buffer");
124   }
125 }
126
127 static void
128 codec_buffer_free (gpointer start)
129 {
130   release_device_mem (device_fd, start);
131 }
132
133 static GstFlowReturn
134 codec_buffer_alloc_and_copy (GstPad *pad, guint64 offset, guint size,
135                   GstCaps *caps, GstBuffer **buf)
136 {
137   bool is_last_buffer = 0;
138   int mem_offset;
139   CodecBufferId opaque;
140   GstMaruDec *marudec;
141   CodecContext *ctx;
142   CodecDevice *dev;
143
144   *buf = gst_buffer_new ();
145
146   marudec = (GstMaruDec *)gst_pad_get_element_private(pad);
147   ctx = marudec->context;
148   dev = marudec->dev;
149
150   ctx = marudec->context;
151
152   opaque.buffer_index = ctx->index;
153   opaque.buffer_size = size;
154
155   GST_DEBUG ("buffer_and_copy. ctx_id: %d", ctx->index);
156
157   int ret = _codec_invoke_qemu(ctx->index, CODEC_PICTURE_COPY, 0, dev->fd, &opaque);
158   if (ret < 0) {
159     GST_DEBUG ("failed to get available buffer");
160     return GST_FLOW_ERROR;
161   }
162   is_last_buffer = ret;
163   mem_offset = opaque.buffer_size;
164
165   gpointer *buffer = NULL;
166   if (is_last_buffer) {
167     // FIXME: we must aligned buffer offset.
168     buffer = g_malloc (size);
169
170     GST_BUFFER_FREE_FUNC (*buf) = g_free;
171
172     memcpy (buffer, device_mem + mem_offset, size);
173     release_device_mem(dev->fd, device_mem + mem_offset);
174
175     GST_DEBUG ("secured last buffer!! Use heap buffer");
176   } else {
177     // address of "device_mem" and "opaque" is aleady aligned.
178     buffer = (gpointer)(device_mem + mem_offset);
179     GST_BUFFER_FREE_FUNC (*buf) = codec_buffer_free;
180
181     GST_DEBUG ("device memory start: 0x%p, offset 0x%x", (intptr_t)buffer, mem_offset);
182   }
183
184   GST_BUFFER_DATA (*buf) = GST_BUFFER_MALLOCDATA (*buf) = (void *)buffer;
185   GST_BUFFER_SIZE (*buf) = size;
186   GST_BUFFER_OFFSET (*buf) = offset;
187
188   if (caps) {
189     gst_buffer_set_caps (*buf, caps);
190   }
191
192   return GST_FLOW_OK;
193 }
194
195 static int
196 codec_init (CodecContext *ctx, CodecElement *codec, CodecDevice *dev)
197 {
198   int opened = 0;
199   gpointer buffer = NULL;
200   CodecBufferId opaque;
201   int ret;
202
203   if (ioctl(dev->fd, CODEC_CMD_GET_CONTEXT_INDEX, &ctx->index) < 0) {
204     GST_ERROR ("failed to get a context index");
205     return -1;
206   }
207   GST_DEBUG ("get context index: %d", ctx->index);
208
209   /* buffer size is 0. It means that this function is required to
210    * use small size.
211   */
212   if (secure_device_mem(dev->fd, ctx->index, 0, &buffer) < 0) {
213     GST_ERROR ("failed to get a memory block");
214     return -1;
215   }
216
217   codec_init_data_to (ctx, codec, buffer);
218
219   opaque.buffer_index = ctx->index;
220   opaque.buffer_size = SMALLDATA;
221
222   ret = _codec_invoke_qemu (ctx->index, CODEC_INIT, GET_OFFSET(buffer), dev->fd, &opaque);
223
224   if (ret < 0) {
225     return -1;
226   }
227
228   opened =
229     codec_init_data_from (ctx, codec->media_type, device_mem + opaque.buffer_size);
230
231   if (opened < 0) {
232     GST_ERROR ("failed to open Context for %s", codec->name);
233   } else {
234     ctx->codec = codec;
235   }
236
237   release_device_mem(dev->fd, device_mem + opaque.buffer_size);
238
239   return opened;
240 }
241
242 static void
243 codec_deinit (CodecContext *ctx, CodecDevice *dev)
244 {
245   GST_INFO ("close context %d", ctx->index);
246   _codec_invoke_qemu (ctx->index, CODEC_DEINIT, 0, dev->fd, NULL);
247 }
248
249 static void
250 codec_flush_buffers (CodecContext *ctx, CodecDevice *dev)
251 {
252   GST_DEBUG ("flush buffers of context: %d", ctx->index);
253   _codec_invoke_qemu (ctx->index, CODEC_FLUSH_BUFFERS, 0, dev->fd, NULL);
254 }
255
256 static int
257 codec_decode_video (GstMaruDec *marudec, uint8_t *in_buf, int in_size,
258                     gint idx, gint64 in_offset, GstBuffer **out_buf, int *have_data)
259 {
260   CodecContext *ctx = marudec->context;
261   CodecDevice *dev = marudec->dev;
262   int len = 0, ret = 0;
263   gpointer buffer = NULL;
264   CodecBufferId opaque = { 0, };
265
266   ret = secure_device_mem(dev->fd, ctx->index, in_size, &buffer);
267   if (ret < 0) {
268     GST_ERROR ("failed to get available memory to write inbuf");
269     return -1;
270   }
271
272   codec_decode_video_data_to (in_size, idx, in_offset, in_buf, buffer);
273
274   opaque.buffer_index = ctx->index;
275
276   opaque.buffer_size = SMALLDATA;
277   ret = _codec_invoke_qemu(ctx->index, CODEC_DECODE_VIDEO, GET_OFFSET(buffer), dev->fd, &opaque);
278
279   if (ret < 0) {
280     // FIXME:
281     return -1;
282   }
283   len = codec_decode_video_data_from (have_data, &ctx->video, device_mem + opaque.buffer_size);
284
285   GST_DEBUG_OBJECT (marudec, "after decode: len %d, have_data %d",
286         len, *have_data);
287
288   release_device_mem(dev->fd, device_mem + opaque.buffer_size);
289
290   if (len < 0 || *have_data <= 0) {
291     GST_DEBUG_OBJECT (marudec, "return flow %d, out %p, len %d",
292         ret, *out_buf, len);
293   }
294
295   return len;
296 }
297
298 static int
299 codec_decode_audio (CodecContext *ctx, int16_t *samples,
300                     int *have_data, uint8_t *in_buf,
301                     int in_size, CodecDevice *dev)
302 {
303   int len = 0, ret = 0;
304   gpointer buffer = NULL;
305   CodecBufferId opaque;
306
307   ret = secure_device_mem(dev->fd, ctx->index, in_size, &buffer);
308   if (ret < 0) {
309     GST_ERROR ("failed to get available memory to write inbuf");
310     return -1;
311   }
312
313   GST_DEBUG ("decode_audio 1. in_buffer size %d", in_size);
314   codec_decode_audio_data_to (in_size, in_buf, buffer);
315
316   opaque.buffer_index = ctx->index;
317   opaque.buffer_size = SMALLDATA;
318
319   ret = _codec_invoke_qemu(ctx->index, CODEC_DECODE_AUDIO, GET_OFFSET(buffer), dev->fd, &opaque);
320
321   if (ret < 0) {
322     return -1;
323   }
324
325   GST_DEBUG ("decode_audio 2. ctx_id: %d, buffer = 0x%x",
326     ctx->index, device_mem + opaque.buffer_size);
327
328   len = codec_decode_audio_data_from (have_data, samples,
329     &ctx->audio, device_mem + opaque.buffer_size);
330
331   GST_DEBUG ("decode_audio 3. ctx_id: %d len: %d", ctx->index, len);
332
333   release_device_mem(dev->fd, device_mem + opaque.buffer_size);
334
335   return len;
336 }
337
338 static int
339 codec_encode_video (CodecContext *ctx, uint8_t *out_buf,
340                     int out_size, uint8_t *in_buf,
341                     int in_size, int64_t in_timestamp,
342                     int *coded_frame, int *is_keyframe,
343                     CodecDevice *dev)
344 {
345   int len = 0, ret = 0;
346   gpointer buffer = NULL;
347   CodecBufferId opaque;
348
349   ret = secure_device_mem(dev->fd, ctx->index, in_size, &buffer);
350   if (ret < 0) {
351     GST_ERROR ("failed to small size of buffer");
352     return -1;
353   }
354
355   codec_encode_video_data_to (in_size, in_timestamp, in_buf, buffer);
356
357   opaque.buffer_index = ctx->index;
358   opaque.buffer_size = SMALLDATA;
359
360   // FIXME: how can we know output data size ?
361   ret = _codec_invoke_qemu(ctx->index, CODEC_ENCODE_VIDEO, GET_OFFSET(buffer), dev->fd, &opaque);
362
363   if (ret < 0) {
364     return -1;
365   }
366
367   GST_DEBUG ("encode_video. mem_offset = 0x%x", opaque.buffer_size);
368
369   len = codec_encode_video_data_from (out_buf, coded_frame, is_keyframe, device_mem + opaque.buffer_size);
370
371   release_device_mem(dev->fd, device_mem + opaque.buffer_size);
372
373   return len;
374 }
375
376 int
377 static codec_encode_audio (CodecContext *ctx, uint8_t *out_buf,
378                     int max_size, uint8_t *in_buf,
379                     int in_size, int64_t timestamp,
380                     CodecDevice *dev)
381 {
382   int ret = 0;
383   gpointer buffer = NULL;
384   CodecBufferId opaque;
385
386   ret = secure_device_mem(dev->fd, ctx->index, in_size, &buffer);
387   if (ret < 0) {
388     return -1;
389   }
390
391   codec_encode_audio_data_to (in_size, max_size, in_buf, timestamp, buffer);
392
393   opaque.buffer_index = ctx->index;
394   opaque.buffer_size = SMALLDATA;
395
396   ret = _codec_invoke_qemu(ctx->index, CODEC_ENCODE_AUDIO, GET_OFFSET(buffer), dev->fd, &opaque);
397
398   if (ret < 0) {
399     return -1;
400   }
401
402   GST_DEBUG ("encode_audio. mem_offset = 0x%x", opaque.buffer_size);
403
404   ret = codec_encode_audio_data_from (out_buf, device_mem + opaque.buffer_size);
405
406   release_device_mem(dev->fd, device_mem + opaque.buffer_size);
407
408   return ret;
409 }
410
411 static int
412 get_device_version (int fd)
413 {
414   uint32_t device_version;
415   int ret;
416
417   ret = ioctl (fd, CODEC_CMD_GET_VERSION, &device_version);
418   if (ret < 0) {
419     return ret;
420   }
421
422   return device_version;
423 }
424
425 static GList *
426 prepare_elements (int fd)
427 {
428   uint32_t size = 0;
429   int ret, elem_cnt, i;
430   GList *elements = NULL;
431   CodecElement *elem;
432
433   ret = ioctl (fd, CODEC_CMD_GET_ELEMENT, &size);
434   if (ret < 0) {
435     return NULL;
436   }
437
438   elem = g_malloc(size);
439
440   ret = ioctl (fd, CODEC_CMD_GET_ELEMENT_DATA, elem);
441   if (ret < 0) {
442     g_free (elem);
443     return NULL;
444   }
445
446   elem_cnt = size / sizeof(CodecElement);
447   for (i = 0; i < elem_cnt; i++) {
448     elements = g_list_append (elements, &elem[i]);
449   }
450
451   return elements;
452 }
453
454 Interface *interface_version_2 = &(Interface) {
455   .init = codec_init,
456   .deinit = codec_deinit,
457   .decode_video = codec_decode_video,
458   .decode_audio = codec_decode_audio,
459   .encode_video = codec_encode_video,
460   .encode_audio = codec_encode_audio,
461   .flush_buffers = codec_flush_buffers,
462   .buffer_alloc_and_copy = codec_buffer_alloc_and_copy,
463   .get_device_version = get_device_version,
464   .prepare_elements = prepare_elements,
465 };