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