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