6ef5baa99a9fc9430da302e405cf0c7f608226ee
[platform/adaptation/nexell/gst-plugins-video-dec.git] / src / gstnxvideodec.c
1 /*
2  * GStreamer
3  * Copyright (C) 2005 Thomas Vander Stichele <thomas@apestaart.org>
4  * Copyright (C) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
5  * Copyright (C) 2016 ray <<user@hostname.org>>
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation
10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11  * and/or sell copies of the Software, and to permit persons to whom the
12  * Software is furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23  * DEALINGS IN THE SOFTWARE.
24  *
25  * Alternatively, the contents of this file may be used under the
26  * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
27  * which case the following provisions apply instead of the ones
28  * mentioned above:
29  *
30  * This library is free software; you can redistribute it and/or
31  * modify it under the terms of the GNU Library General Public
32  * License as published by the Free Software Foundation; either
33  * version 2 of the License, or (at your option) any later version.
34  *
35  * This library is distributed in the hope that it will be useful,
36  * but WITHOUT ANY WARRANTY; without even the implied warranty of
37  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
38  * Library General Public License for more details.
39  *
40  * You should have received a copy of the GNU Library General Public
41  * License along with this library; if not, write to the
42  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
43  * Boston, MA 02111-1307, USA.
44  */
45
46 /**
47  * SECTION:element-nxvideodec
48  *
49  * FIXME:Describe nxvideodec here.
50  *
51  * <refsect2>
52  * <title>Example launch line</title>
53  * |[
54  * gst-launch -v -m fakesrc ! nxvideodec ! fakesink silent=TRUE
55  * ]|
56  * </refsect2>
57  */
58
59 #ifdef HAVE_CONFIG_H
60 #include "config.h"
61 #endif
62
63 #include <stdio.h>
64 #include <string.h>
65 #include <gst/gst.h>
66 #include <gst/video/video.h>
67 #include <gst/video/gstvideodecoder.h>
68 #include <gstmmvideobuffermeta.h>
69 #include <linux/videodev2.h>
70 #include "gstnxvideodec.h"
71
72 // This SUPPORT_NO_MEMORY_COPY function is disabled now.
73 // if the video decoder mmap is supported this function, it will be enabled.
74 #define SUPPORT_NO_MEMORY_COPY  1
75 //#define CODEC_DEC_OUTPUT_DUMP 1
76
77 GST_DEBUG_CATEGORY_STATIC (gst_nxvideodec_debug_category);
78 #define GST_CAT_DEFAULT gst_nxvideodec_debug_category
79
80 /* prototypes */
81 static void gst_nxvideodec_set_property (GObject * object,
82     guint property_id, const GValue * value, GParamSpec * pspec);
83 static void gst_nxvideodec_get_property (GObject * object,
84     guint property_id, GValue * value, GParamSpec * pspec);
85
86 static gboolean gst_nxvideodec_start (GstVideoDecoder * decoder);
87 static gboolean gst_nxvideodec_stop (GstVideoDecoder * decoder);
88 static gboolean gst_nxvideodec_set_format (GstVideoDecoder * decoder,
89     GstVideoCodecState * state);
90 static gboolean gst_nxvideodec_flush (GstVideoDecoder * decoder);
91 static GstFlowReturn gst_nxvideodec_handle_frame (GstVideoDecoder * decoder,
92     GstVideoCodecFrame * frame);
93 static void nxvideodec_base_init (gpointer gclass);
94 static void nxvideodec_buffer_finalize (gpointer pData);
95 static GstMemory *nxvideodec_mmvideobuf_copy (GstNxVideoDec *pNxVideoDec, NX_V4L2DEC_OUT * pDecOut);
96
97 #if SUPPORT_NO_MEMORY_COPY
98 static void nxvideodec_get_offset_stride (gint width, gint height,
99     guint8 * pSrc, gsize * pOffset, gint * pStride);
100 enum
101 {
102   PROP_0,
103 };
104 #else
105 enum
106 {
107   PROP_0,
108   PROP_TYPE                     //0: 1:MM_VIDEO_BUFFER_TYPE_GEM
109 };
110 enum
111 {
112   BUFFER_TYPE_NORMAL,
113   BUFFER_TYPE_GEM
114 };
115 #endif
116
117 enum
118 {
119   STOP,
120   PLAY
121 };
122
123 #ifndef ALIGN
124 #define  ALIGN(X,N) ( (X+N-1) & (~(N-1)) )
125 #endif
126
127 struct video_meta_mmap_buffer
128 {
129   gint v4l2BufferIdx;
130   GstNxVideoDec *pNxVideoDec;
131 };
132
133 #define PLUGIN_LONG_NAME                "S5P6818 H/W Video Decoder"
134 #define PLUGIN_DESC                             "Nexell H/W Video Decoder for S5P6818, Version: 0.1.0"
135 #define PLUGIN_AUTHOR                   "Hyun Chul Jun <hcjun@nexell.co.kr>"
136
137 // pad templates
138 static GstStaticPadTemplate gst_nxvideodec_src_template =
139 GST_STATIC_PAD_TEMPLATE ("src",
140     GST_PAD_SRC,
141     GST_PAD_ALWAYS,
142     GST_STATIC_CAPS ("video/x-raw, "
143         "format = (string) { S420 }, "
144         "width = (int) [ 64, 1920 ], " "height = (int) [ 64, 1088 ] ")
145
146     );
147
148 #ifdef CODEC_DEC_OUTPUT_DUMP /* for decoder output dump */
149 static void
150 decoder_output_dump(MMVideoBuffer *outbuf)
151 {
152   char *temp = (char *)outbuf->data[0];
153   int i = 0;
154   char filename[100]={0};
155   FILE *fp = NULL;
156   int ret =0;
157
158   GST_ERROR ("codec dec output dump start. w = %d, h = %d", outbuf->width[0], outbuf->height[0]);
159
160   sprintf(filename, "/tmp/dec_output_dump_%d_%d.yuv", outbuf->width[0], outbuf->height[0]);
161   fp = fopen(filename, "ab");
162
163   for (i = 0; i < outbuf->height[0]; i++) {
164     ret = fwrite(temp, outbuf->width[0], 1, fp);
165     temp += outbuf->stride_width[0];
166   }
167
168   temp = outbuf->data[1];
169   for (i = 0; i < outbuf->height[0]/2; i++) {
170    ret = fwrite(temp, outbuf->width[0]/2, 1, fp);
171     temp += outbuf->stride_width[0]/2;
172   }
173
174   temp = outbuf->data[2];
175   for (i = 0; i < outbuf->height[0]/2; i++) {
176    ret = fwrite(temp, outbuf->width[0]/2, 1, fp);
177     temp += outbuf->stride_width[0]/2;
178   }
179
180   GST_ERROR ("codec dec output dumped!! ret = %d", ret);
181   fclose(fp);
182 }
183 #endif
184
185 static void
186 nxvideodec_base_init (gpointer gclass)
187 {
188   GstElementClass *pElement_class = GST_ELEMENT_CLASS (gclass);
189   GstCaps *pCapslist = NULL;
190   GstNxVideoDecClass *pKlass = GST_NXVIDEODEC_CLASS (pElement_class);
191
192   FUNC_IN ();
193
194   gst_element_class_set_details_simple (pElement_class,
195       PLUGIN_LONG_NAME, "Codec/Decoder/Video", PLUGIN_DESC, PLUGIN_AUTHOR);
196
197   pCapslist = gst_caps_new_empty ();
198
199   //      H.263
200   gst_caps_append_structure (pCapslist,
201       gst_structure_new ("video/x-h263",
202           "variant", G_TYPE_STRING, "itu", NULL));
203
204   //      H.264
205   gst_caps_append_structure (pCapslist,
206       gst_structure_new ("video/x-h264",
207           "alignment", G_TYPE_STRING, "au",
208           "width", GST_TYPE_INT_RANGE, 64, NX_MAX_WIDTH,
209           "height", GST_TYPE_INT_RANGE, 64, NX_MAX_HEIGHT, NULL));
210
211   //      XVID
212   gst_caps_append_structure (pCapslist,
213       gst_structure_new ("video/x-xvid",
214           "width", GST_TYPE_INT_RANGE, 64, NX_MAX_WIDTH,
215           "height", GST_TYPE_INT_RANGE, 64, NX_MAX_HEIGHT, NULL));
216
217
218   //      MPEG2
219   gst_caps_append_structure (pCapslist,
220       gst_structure_new ("video/mpeg",
221           "mpegversion", GST_TYPE_INT_RANGE, 1, 2,
222           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL));
223
224   //      MPEG4
225   gst_caps_append_structure (pCapslist,
226       gst_structure_new ("video/mpeg",
227           "mpegversion", G_TYPE_INT, 4,
228           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL));
229
230   //      DIVX
231   gst_caps_append_structure (pCapslist,
232       gst_structure_new ("video/x-divx",
233           "width", GST_TYPE_INT_RANGE, 64, NX_MAX_WIDTH,
234           "height", GST_TYPE_INT_RANGE, 64, NX_MAX_HEIGHT,
235           "divxversion", GST_TYPE_INT_RANGE, 3, 6, NULL));
236
237   //      MSMPEG
238   gst_caps_append_structure (pCapslist,
239       gst_structure_new ("video/x-msmpeg",
240           "width", GST_TYPE_INT_RANGE, 64, NX_MAX_WIDTH,
241           "height", GST_TYPE_INT_RANGE, 64, NX_MAX_HEIGHT,
242           "msmpegversion", G_TYPE_INT, 43, NULL));
243
244   // pad templates
245   pKlass->pSinktempl =
246       gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, pCapslist);
247   gst_element_class_add_pad_template (pElement_class, pKlass->pSinktempl);
248   gst_element_class_add_pad_template (pElement_class,
249       gst_static_pad_template_get (&gst_nxvideodec_src_template));
250
251   FUNC_OUT ();
252 }
253
254 G_DEFINE_TYPE_WITH_CODE (GstNxVideoDec, gst_nxvideodec, GST_TYPE_VIDEO_DECODER,
255     GST_DEBUG_CATEGORY_INIT (gst_nxvideodec_debug_category, "nxvideodec", 0,
256         "debug category for nxvideodec element"));
257
258 // class initialization
259 static void
260 gst_nxvideodec_class_init (GstNxVideoDecClass * pKlass)
261 {
262   FUNC_IN ();
263
264   GObjectClass *pGobjectClass = G_OBJECT_CLASS (pKlass);
265   GstVideoDecoderClass *pVideoDecoderClass = GST_VIDEO_DECODER_CLASS (pKlass);
266
267   nxvideodec_base_init (pKlass);
268
269   pGobjectClass->set_property = gst_nxvideodec_set_property;
270   pGobjectClass->get_property = gst_nxvideodec_get_property;
271
272   pVideoDecoderClass->start = GST_DEBUG_FUNCPTR (gst_nxvideodec_start);
273   pVideoDecoderClass->stop = GST_DEBUG_FUNCPTR (gst_nxvideodec_stop);
274
275   pVideoDecoderClass->set_format =
276       GST_DEBUG_FUNCPTR (gst_nxvideodec_set_format);
277   pVideoDecoderClass->flush = GST_DEBUG_FUNCPTR (gst_nxvideodec_flush);
278   pVideoDecoderClass->handle_frame =
279       GST_DEBUG_FUNCPTR (gst_nxvideodec_handle_frame);
280
281 #if SUPPORT_NO_MEMORY_COPY
282 #else
283   g_object_class_install_property (pGobjectClass,
284       PROP_TYPE,
285       g_param_spec_int ("buffer-type", "buffer-type",
286           "Buffer Type(0:NORMAL 1:MM_VIDEO_BUFFER_TYPE_GEM)", 0, 1,
287           BUFFER_TYPE_GEM, G_PARAM_READWRITE));
288 #endif
289
290   FUNC_OUT ();
291 }
292
293 static void
294 gst_nxvideodec_init (GstNxVideoDec * pNxVideoDec)
295 {
296   FUNC_IN ();
297
298   GST_DEBUG_OBJECT (pNxVideoDec, "dec_init");
299
300   // Initialize variables
301   pNxVideoDec->pNxVideoDecHandle = NULL;
302   pNxVideoDec->pInputState = NULL;
303   pNxVideoDec->isState = STOP;
304 #if SUPPORT_NO_MEMORY_COPY
305 #else
306   pNxVideoDec->bufferType = BUFFER_TYPE_GEM;
307 #endif
308   pthread_mutex_init (&pNxVideoDec->mutex, NULL);
309
310   FUNC_OUT ();
311 }
312
313 void
314 gst_nxvideodec_set_property (GObject * pObject, guint propertyId,
315     const GValue * pValue, GParamSpec * pPspec)
316 {
317   GstNxVideoDec *pNxvideodec = GST_NXVIDEODEC (pObject);
318   FUNC_IN ();
319
320   GST_DEBUG_OBJECT (pNxvideodec, "set_property");
321
322   switch (propertyId) {
323 #if SUPPORT_NO_MEMORY_COPY
324 #else
325     case PROP_TYPE:
326       pNxvideodec->bufferType = g_value_get_int (pValue);
327       break;
328 #endif
329     default:
330       G_OBJECT_WARN_INVALID_PROPERTY_ID (pObject, propertyId, pPspec);
331       break;
332   }
333
334   FUNC_OUT ();
335 }
336
337 void
338 gst_nxvideodec_get_property (GObject * pObject, guint propertyId,
339     GValue * pValue, GParamSpec * pPspec)
340 {
341   GstNxVideoDec *pNxvideodec = GST_NXVIDEODEC (pObject);
342   FUNC_IN ();
343
344   GST_DEBUG_OBJECT (pNxvideodec, "get_property");
345
346   switch (propertyId) {
347 #if SUPPORT_NO_MEMORY_COPY
348 #else
349     case PROP_TYPE:
350       g_value_set_int (pValue, pNxvideodec->bufferType);
351       break;
352 #endif
353     default:
354       G_OBJECT_WARN_INVALID_PROPERTY_ID (pObject, propertyId, pPspec);
355       break;
356   }
357
358   FUNC_OUT ();
359 }
360
361 static gboolean
362 gst_nxvideodec_start (GstVideoDecoder * pDecoder)
363 {
364   GstNxVideoDec *pNxVideoDec = GST_NXVIDEODEC (pDecoder);
365   FUNC_IN ();
366
367   GST_DEBUG_OBJECT (pNxVideoDec, "start");
368
369   if (pNxVideoDec->pNxVideoDecHandle) {
370     CloseVideoDec (pNxVideoDec->pNxVideoDecHandle);
371     pNxVideoDec->pNxVideoDecHandle = NULL;
372   }
373
374   pNxVideoDec->pNxVideoDecHandle = OpenVideoDec ();
375
376   if (pNxVideoDec->pNxVideoDecHandle == NULL) {
377     GST_ERROR ("VideoDecHandle is NULL !\n");
378     return FALSE;
379   }
380
381   pthread_mutex_lock (&pNxVideoDec->mutex);
382   pNxVideoDec->isState = PLAY;
383   pthread_mutex_unlock (&pNxVideoDec->mutex);
384
385   FUNC_OUT ();
386
387   return TRUE;
388 }
389
390 static gboolean
391 gst_nxvideodec_stop (GstVideoDecoder * pDecoder)
392 {
393   GstNxVideoDec *pNxVideoDec = GST_NXVIDEODEC (pDecoder);
394   FUNC_IN ();
395   if (pNxVideoDec == NULL) {
396     GST_ERROR ("pDecoder is NULL !\n");
397     return FALSE;
398   }
399
400   GST_DEBUG_OBJECT (pNxVideoDec, "stop");
401
402   pthread_mutex_lock (&pNxVideoDec->mutex);
403   pNxVideoDec->isState = STOP;
404   pthread_mutex_unlock (&pNxVideoDec->mutex);
405
406   if (pNxVideoDec->pNxVideoDecHandle->pSem) {
407     VDecSemSignal (pNxVideoDec->pNxVideoDecHandle->pSem);
408     VDecSemDestroy (pNxVideoDec->pNxVideoDecHandle->pSem);
409     pNxVideoDec->pNxVideoDecHandle->pSem = NULL;
410   }
411
412   CloseVideoDec (pNxVideoDec->pNxVideoDecHandle);
413
414   pthread_mutex_destroy (&pNxVideoDec->mutex);
415
416   FUNC_OUT ();
417   return TRUE;
418 }
419
420 static gboolean
421 gst_nxvideodec_set_format (GstVideoDecoder * pDecoder,
422     GstVideoCodecState * pState)
423 {
424   GstNxVideoDec *pNxVideoDec = GST_NXVIDEODEC (pDecoder);
425   GstStructure *pStructure = NULL;
426   const gchar *pMimeType = NULL;
427   GstBuffer *pCodecData = NULL;
428   GstVideoCodecState *pOutputState = NULL;
429   NX_VIDEO_DEC_STRUCT *pDecHandle = NULL;
430   gint ret = FALSE;
431 #ifdef TIZEN_FEATURE_ARTIK530
432   gboolean bIsFormatChange = FALSE;
433 #endif
434
435   FUNC_IN ();
436
437   GST_DEBUG_OBJECT (pNxVideoDec, "set_format");
438
439   if (pNxVideoDec->pInputState) {
440     gst_video_codec_state_unref (pNxVideoDec->pInputState);
441     pNxVideoDec->pInputState = NULL;
442   }
443
444   pNxVideoDec->pInputState = gst_video_codec_state_ref (pState);
445
446   // Check Support Codec Type
447   pStructure = gst_caps_get_structure (pNxVideoDec->pInputState->caps, 0);
448   pMimeType = gst_structure_get_name (pStructure);
449   if (pNxVideoDec->pNxVideoDecHandle) {
450     pDecHandle = pNxVideoDec->pNxVideoDecHandle;
451   } else {
452     return FALSE;
453   }
454
455 #ifdef TIZEN_FEATURE_ARTIK530
456   GST_DEBUG_OBJECT (pNxVideoDec, "old %dx%d fps=%d/%d %p",
457       pDecHandle->width, pDecHandle->height,
458       pDecHandle->fpsNum, pDecHandle->fpsDen,
459       pDecHandle->codec_data);
460   GST_DEBUG_OBJECT (pNxVideoDec, "new %dx%d fps=%d/%d %p",
461       GST_VIDEO_INFO_WIDTH (&pState->info),
462       GST_VIDEO_INFO_HEIGHT (&pState->info),
463       GST_VIDEO_INFO_FPS_N (&pState->info),
464       GST_VIDEO_INFO_FPS_D (&pState->info),
465       pState->codec_data);
466
467   bIsFormatChange |=
468       pDecHandle->width != GST_VIDEO_INFO_WIDTH (&pState->info);
469   bIsFormatChange |=
470       pDecHandle->height != GST_VIDEO_INFO_HEIGHT (&pState->info);
471   if (GST_VIDEO_INFO_FPS_N (&pState->info) != 0) {
472     bIsFormatChange |=
473         pDecHandle->fpsNum != GST_VIDEO_INFO_FPS_N (&pState->info);
474     bIsFormatChange |=
475         pDecHandle->fpsDen != GST_VIDEO_INFO_FPS_D (&pState->info);
476   } else {
477     bIsFormatChange |= pDecHandle->fpsNum != 30;
478     bIsFormatChange |= pDecHandle->fpsDen != 1;
479   }
480   bIsFormatChange |= (pDecHandle->codec_data != pState->codec_data);
481   gst_buffer_replace (&pDecHandle->codec_data, pState->codec_data);
482   GST_DEBUG_OBJECT (pNxVideoDec, "format changed=%d", bIsFormatChange);
483 #endif
484
485   pDecHandle->codecType = FindCodecInfo (pState, pDecHandle);
486
487   if (pDecHandle->codecType < 0) {
488     GST_ERROR ("Unsupported VideoDecoder Mime Type : %s\n", pMimeType);
489     return FALSE;
490   }
491
492   if (pDecHandle->pExtraData) {
493     g_free (pDecHandle->pExtraData);
494     pDecHandle->pExtraData = NULL;
495     pDecHandle->extraDataSize = 0;
496   }
497
498   pCodecData = pNxVideoDec->pInputState->codec_data;
499
500   if (pCodecData) {
501     GstMapInfo mapInfo;
502
503     if (!gst_buffer_map (pCodecData, &mapInfo, GST_MAP_READ)) {
504       GST_ERROR ("Cannot map input buffer!\n");
505       return FALSE;
506     }
507
508     if (mapInfo.size > 0 && mapInfo.data) {
509       pDecHandle->pExtraData = (guint8 *) g_malloc (mapInfo.size);
510       pDecHandle->extraDataSize = mapInfo.size;
511     }
512
513     if (FALSE == GetExtraInfo (pDecHandle, (guint8 *) mapInfo.data,
514             mapInfo.size)) {
515       gst_buffer_unmap (pCodecData, &mapInfo);
516       return FALSE;
517     }
518     gst_buffer_unmap (pCodecData, &mapInfo);
519   } else {
520     GST_LOG ("No Codec Data\n");
521   }
522
523   if (pDecHandle->codecType == V4L2_PIX_FMT_H264) {
524     const gchar *pStr = NULL;
525
526     if ((pStr = gst_structure_get_string (pStructure, "alignment"))) {
527       if (strcmp (pStr, "au") == 0) {
528         pDecHandle->h264Alignment = H264_PARSE_ALIGN_AU;
529         GST_DEBUG_OBJECT (pNxVideoDec, ">>>>> H264 alignment: au Type.");
530       } else if (strcmp (pStr, "nal") == 0) {
531         pDecHandle->h264Alignment = H264_PARSE_ALIGN_NAL;
532         GST_DEBUG_OBJECT (pNxVideoDec, ">>>>> H264 alignment: nal Type.");
533       } else {
534         GST_DEBUG_OBJECT (pNxVideoDec, "unknown alignment: %s", pStr);
535       }
536     }
537   }
538
539   pOutputState =
540       gst_video_decoder_set_output_state (pDecoder, GST_VIDEO_FORMAT_S420,
541       pDecHandle->width, pDecHandle->height, pNxVideoDec->pInputState);
542
543   pOutputState->caps = gst_caps_new_simple ("video/x-raw",
544       "format", G_TYPE_STRING,
545       gst_video_format_to_string (GST_VIDEO_FORMAT_S420), "width", G_TYPE_INT,
546       pDecHandle->width, "height", G_TYPE_INT, pDecHandle->height, "framerate",
547       GST_TYPE_FRACTION, pDecHandle->fpsNum, pDecHandle->fpsDen, NULL);
548
549   gst_video_codec_state_unref (pOutputState);
550
551   pNxVideoDec->pNxVideoDecHandle->imgPlaneNum = 1;
552 #if SUPPORT_NO_MEMORY_COPY
553   GST_DEBUG_OBJECT (pNxVideoDec, ">>>>> Accelerable.");
554 #else
555   if (BUFFER_TYPE_GEM == pNxVideoDec->bufferType) {
556     GST_DEBUG_OBJECT (pNxVideoDec, ">>>>> Accelerable.");
557   }
558 #endif
559
560   ret = gst_video_decoder_negotiate (pDecoder);
561
562   if (FALSE == ret) {
563     GST_ERROR ("Fail Negotiate !\n");
564     return ret;
565   }
566
567 #ifdef TIZEN_FEATURE_ARTIK530
568   if (!bIsFormatChange) {
569     FUNC_OUT ();
570     return TRUE;
571   }
572
573   if (pDecHandle->hCodec) {
574     NX_V4l2DecClose (pDecHandle->hCodec);
575     pDecHandle->hCodec = NULL;
576
577     if (pDecHandle->pTmpStrmBuf) {
578       g_free (pDecHandle->pTmpStrmBuf);
579       pDecHandle->pTmpStrmBuf = NULL;
580     }
581
582     pDecHandle->bInitialized = FALSE;
583   }
584 #endif
585
586   if (0 != InitVideoDec (pNxVideoDec->pNxVideoDecHandle)) {
587     return FALSE;
588   }
589
590   FUNC_OUT ();
591
592   return ret;
593 }
594
595 static gboolean
596 gst_nxvideodec_flush (GstVideoDecoder * pDecoder)
597 {
598   GstNxVideoDec *pNxvideodec = GST_NXVIDEODEC (pDecoder);
599
600   FUNC_IN ();
601
602   GST_DEBUG_OBJECT (pNxvideodec, "flush");
603
604   if (pNxvideodec->pNxVideoDecHandle) {
605     pNxvideodec->pNxVideoDecHandle->bFlush = TRUE;
606   }
607
608   FUNC_OUT ();
609
610   return TRUE;
611 }
612
613 #if SUPPORT_NO_MEMORY_COPY
614 static void
615 nxvideodec_get_offset_stride (gint width, gint height, guint8 * pSrc,
616     gsize * pOffset, gint * pStride)
617 {
618   guint8 *plu = NULL;
619   guint8 *pcb = NULL;
620   guint8 *pcr = NULL;
621   gint luStride = 0;
622   gint luVStride = 0;
623   gint cStride = 0;
624   gint cVStride = 0;
625
626   luStride = ALIGN (width, 32);
627   luVStride = ALIGN (height, 16);
628   cStride = luStride / 2;
629   cVStride = ALIGN (height / 2, 16);
630   plu = pSrc;
631   pcb = plu + luStride * luVStride;
632   pcr = pcb + cStride * cVStride;
633
634   pOffset[0] = 0;
635   pOffset[1] = pcb - plu;
636   pOffset[2] = pcr - plu;
637
638   pStride[0] = luStride;
639   pStride[1] = cStride;
640   pStride[2] = cStride;
641 }
642
643 static GstFlowReturn
644 gst_nxvideodec_handle_frame (GstVideoDecoder * pDecoder,
645     GstVideoCodecFrame * pFrame)
646 {
647   GstNxVideoDec *pNxVideoDec = GST_NXVIDEODEC (pDecoder);
648   NX_V4L2DEC_OUT decOut;
649   gint64 timeStamp = 0;
650   GstMapInfo mapInfo;
651   gint ret = 0;
652   gboolean bKeyFrame = FALSE;
653
654   GstMemory *pGstmem = NULL;
655   GstBuffer *pGstbuf = NULL;
656   struct video_meta_mmap_buffer *pMeta = NULL;
657
658   NX_VID_MEMORY_INFO *pImg = NULL;
659   GstVideoCodecState *pState = NULL;
660
661   unsigned char *pVadd = NULL;
662   GstVideoMeta *pVmeta = NULL;
663   gint videoImgSize = 0;
664
665   guint n_planes = 0;
666   gsize offset[3] = { 0, };
667   gint stride[3] = { 0, };
668
669   GstMemory *pMemMMVideoData = NULL;
670
671   FUNC_IN ();
672
673   if (!gst_buffer_map (pFrame->input_buffer, &mapInfo, GST_MAP_READ)) {
674     GST_ERROR ("Cannot map input buffer!");
675     gst_video_codec_frame_unref (pFrame);
676     return GST_FLOW_ERROR;
677   }
678
679   bKeyFrame = GST_VIDEO_CODEC_FRAME_IS_SYNC_POINT (pFrame);
680
681   ret =
682       VideoDecodeFrame (pNxVideoDec->pNxVideoDecHandle, pFrame->input_buffer,
683       &decOut, bKeyFrame);
684
685   gst_buffer_unmap (pFrame->input_buffer, &mapInfo);
686   if (DEC_ERR == ret) {
687     GetTimeStamp (pNxVideoDec->pNxVideoDecHandle, &timeStamp);
688     return gst_video_decoder_drop_frame (pDecoder, pFrame);
689   } else if (DEC_INIT_ERR == ret) {
690     return GST_FLOW_ERROR;
691   }
692
693   if (decOut.dispIdx < 0) {
694     return GST_FLOW_OK;
695   }
696
697   GST_DEBUG_OBJECT (pNxVideoDec, " decOut.dispIdx: %d\n", decOut.dispIdx);
698
699   pMeta =
700       (struct video_meta_mmap_buffer *) g_malloc (sizeof (struct
701           video_meta_mmap_buffer));
702
703   if (!pMeta) {
704     GST_ERROR_OBJECT (pNxVideoDec, "failed to malloc for meta");
705     gst_video_codec_frame_unref (pFrame);
706     return GST_FLOW_ERROR;
707   }
708
709   pImg = &decOut.hImg;
710   pMeta->v4l2BufferIdx = decOut.dispIdx;
711   pVadd = pImg->pBuffer[0];
712   pMeta->pNxVideoDec = pNxVideoDec;
713
714   videoImgSize =
715       pNxVideoDec->pNxVideoDecHandle->width *
716       pNxVideoDec->pNxVideoDecHandle->height * 1.5;
717
718   pGstmem = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
719       pVadd, videoImgSize, 0, videoImgSize, pMeta, nxvideodec_buffer_finalize);
720
721   if (!pGstmem) {
722     GST_ERROR_OBJECT (pNxVideoDec,
723         "failed to gst_memory_new_wrapped for mmap buffer");
724     gst_video_codec_frame_unref (pFrame);
725     goto HANDLE_ERROR;
726   }
727
728   pGstbuf = gst_buffer_new ();
729   if (!pGstbuf) {
730     GST_ERROR_OBJECT (pNxVideoDec, "failed to gst_buffer_new");
731     gst_video_codec_frame_unref (pFrame);
732     goto HANDLE_ERROR;
733   }
734   gst_buffer_append_memory (pGstbuf, pGstmem);
735
736   n_planes = 3;
737   nxvideodec_get_offset_stride (pNxVideoDec->pNxVideoDecHandle->width,
738       pNxVideoDec->pNxVideoDecHandle->height, (guint8 *) pImg->pBuffer[0],
739       offset, stride);
740
741   pState = gst_video_decoder_get_output_state (pDecoder);
742
743   pVmeta =
744       gst_buffer_add_video_meta_full (pGstbuf, GST_VIDEO_FRAME_FLAG_NONE,
745       GST_VIDEO_INFO_FORMAT (&pState->info),
746       GST_VIDEO_INFO_WIDTH (&pState->info),
747       GST_VIDEO_INFO_HEIGHT (&pState->info), n_planes, offset, stride);
748   if (!pVmeta) {
749     GST_ERROR_OBJECT (pNxVideoDec, "failed to gst_buffer_add_video_meta_full");
750     gst_video_codec_state_unref (pState);
751     gst_video_codec_frame_unref (pFrame);
752     goto HANDLE_ERROR;
753   }
754
755   pMemMMVideoData = nxvideodec_mmvideobuf_copy (pNxVideoDec, &decOut);
756   if (!pMemMMVideoData) {
757     GST_ERROR ("failed to get zero copy data");
758     gst_video_codec_state_unref (pState);
759     gst_video_codec_frame_unref (pFrame);
760     goto HANDLE_ERROR;
761   } else {
762     gst_buffer_append_memory (pGstbuf, pMemMMVideoData);
763   }
764   gst_buffer_add_mmvideobuffer_meta (pGstbuf, 1);
765
766   pFrame->output_buffer = pGstbuf;
767
768   if (-1 == GetTimeStamp (pNxVideoDec->pNxVideoDecHandle, &timeStamp)) {
769     GST_DEBUG_OBJECT (pNxVideoDec, "Cannot Found Time Stamp!!!");
770   }
771   pFrame->pts = timeStamp;
772   GST_BUFFER_PTS (pFrame->output_buffer) = timeStamp;
773
774   gst_video_codec_state_unref (pState);
775
776   ret = gst_video_decoder_finish_frame (pDecoder, pFrame);
777
778   FUNC_OUT ();
779
780   return ret;
781
782 HANDLE_ERROR:
783   if (pGstbuf) {
784     g_free (pGstbuf);
785   }
786   if (pGstmem) {
787     g_free (pGstmem);
788   }
789   if (pMeta) {
790     nxvideodec_buffer_finalize (pMeta);
791   }
792
793   return GST_FLOW_ERROR;
794 }
795 #else
796 static GstFlowReturn
797 gst_nxvideodec_handle_frame (GstVideoDecoder * pDecoder,
798     GstVideoCodecFrame * pFrame)
799 {
800   GstNxVideoDec *pNxVideoDec = GST_NXVIDEODEC (pDecoder);
801   NX_V4L2DEC_OUT decOut;
802   gint64 timeStamp = 0;
803   GstMapInfo mapInfo;
804   gint ret = 0;
805   gboolean bKeyFrame = FALSE;
806   GstMemory *pGstmem = NULL;
807   GstBuffer *pGstbuf = NULL;
808   struct video_meta_mmap_buffer *pMeta = NULL;
809   GstMemory *pMemMMVideoData = NULL;
810
811   FUNC_IN ();
812
813   if (!gst_buffer_map (pFrame->input_buffer, &mapInfo, GST_MAP_READ)) {
814     GST_ERROR ("Cannot map input buffer!");
815     gst_video_codec_frame_unref (pFrame);
816     return GST_FLOW_ERROR;
817   }
818
819   bKeyFrame = GST_VIDEO_CODEC_FRAME_IS_SYNC_POINT (pFrame);
820
821   ret =
822       VideoDecodeFrame (pNxVideoDec->pNxVideoDecHandle, pFrame->input_buffer,
823       &decOut, bKeyFrame);
824
825   gst_buffer_unmap (pFrame->input_buffer, &mapInfo);
826   if (DEC_ERR == ret) {
827     GetTimeStamp (pNxVideoDec->pNxVideoDecHandle, &timeStamp);
828     return gst_video_decoder_drop_frame (pDecoder, pFrame);
829   } else if (DEC_INIT_ERR == ret) {
830     return GST_FLOW_ERROR;
831   }
832
833   if (decOut.dispIdx < 0) {
834     return GST_FLOW_OK;
835   }
836
837   GST_DEBUG_OBJECT (pNxVideoDec, " decOut.dispIdx: %d\n", decOut.dispIdx);
838
839   if (BUFFER_TYPE_GEM == pNxVideoDec->bufferType) {
840     pGstbuf = gst_buffer_new ();
841     if (!pGstbuf) {
842       GST_ERROR_OBJECT (pNxVideoDec, "failed to gst_buffer_new");
843       gst_video_codec_frame_unref (pFrame);
844       goto HANDLE_ERROR;
845     }
846
847     pMemMMVideoData = nxvideodec_mmvideobuf_copy (pNxVideoDec, &decOut);
848     if (!pMemMMVideoData) {
849       GST_ERROR ("failed to get zero copy data");
850       gst_video_codec_frame_unref (pFrame);
851       goto HANDLE_ERROR;
852     }
853     gst_buffer_append_memory (pGstbuf, pMemMMVideoData);
854
855     pMeta =
856         (struct video_meta_mmap_buffer *) g_malloc (sizeof (struct
857             video_meta_mmap_buffer));
858     if (!pMeta) {
859       GST_ERROR_OBJECT (pNxVideoDec, "failed to malloc for meta");
860       gst_video_codec_frame_unref (pFrame);
861       return GST_FLOW_ERROR;
862     }
863     pMeta->v4l2BufferIdx = decOut.dispIdx;
864     pMeta->pNxVideoDec = pNxVideoDec;
865     pGstmem = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
866         pMeta,
867         sizeof (struct video_meta_mmap_buffer),
868         0,
869         sizeof (struct video_meta_mmap_buffer),
870         pMeta, nxvideodec_buffer_finalize);
871     if (!pGstmem) {
872       GST_ERROR_OBJECT (pNxVideoDec,
873           "failed to gst_memory_new_wrapped for mmap buffer");
874       gst_video_codec_frame_unref (pFrame);
875       goto HANDLE_ERROR;
876     }
877     gst_buffer_append_memory (pGstbuf, pGstmem);
878
879     gst_buffer_add_mmvideobuffer_meta (pGstbuf, 0);
880
881     pFrame->output_buffer = pGstbuf;
882
883     if (-1 == GetTimeStamp (pNxVideoDec->pNxVideoDecHandle, &timeStamp)) {
884       GST_DEBUG_OBJECT (pNxVideoDec, "Cannot Found Time Stamp!!!");
885     }
886     pFrame->pts = timeStamp;
887     GST_BUFFER_PTS (pFrame->output_buffer) = timeStamp;
888   } else {
889     GstVideoFrame videoFrame;
890     NX_VID_MEMORY_INFO *pImg = NULL;
891     guint8 *pPtr = NULL;;
892     GstVideoCodecState *pState = NULL;
893     GstFlowReturn flowRet;
894     guint8 *plu = NULL;
895     guint8 *pcb = NULL;
896     guint8 *pcr = NULL;
897     gint luStride = 0;
898     gint luVStride = 0;
899     gint cStride = 0;
900     gint cVStride = 0;
901
902     flowRet = gst_video_decoder_allocate_output_frame (pDecoder, pFrame);
903     pState = gst_video_decoder_get_output_state (pDecoder);
904     if (flowRet != GST_FLOW_OK) {
905       gst_video_codec_state_unref (pState);
906       gst_video_codec_frame_unref (pFrame);
907       return flowRet;
908     }
909
910     if (!gst_video_frame_map (&videoFrame, &pState->info, pFrame->output_buffer,
911             GST_MAP_WRITE)) {
912       GST_ERROR ("Cannot video frame map!\n");
913       gst_video_codec_state_unref (pState);
914       gst_video_codec_frame_unref (pFrame);
915       return GST_FLOW_ERROR;
916     }
917
918     if (-1 == GetTimeStamp (pNxVideoDec->pNxVideoDecHandle, &timeStamp)) {
919       GST_DEBUG_OBJECT (pNxVideoDec, "Cannot Found Time Stamp!!!");
920     }
921     pFrame->pts = timeStamp;
922     GST_BUFFER_PTS (pFrame->output_buffer) = timeStamp;
923
924     pImg = &decOut.hImg;
925     pPtr = GST_VIDEO_FRAME_COMP_DATA (&videoFrame, 0);
926
927     luStride = ALIGN (pNxVideoDec->pNxVideoDecHandle->width, 32);
928     luVStride = ALIGN (pNxVideoDec->pNxVideoDecHandle->height, 16);
929     cStride = luStride / 2;
930     cVStride = ALIGN (pNxVideoDec->pNxVideoDecHandle->height / 2, 16);
931     plu = (guint8 *) pImg->pBuffer[0];
932     pcb = plu + luStride * luVStride;
933     pcr = pcb + cStride * cVStride;
934
935     CopyImageToBufferYV12 ((guint8 *) plu, (guint8 *) pcb, (guint8 *) pcr,
936         pPtr, luStride, cStride, pNxVideoDec->pNxVideoDecHandle->width,
937         pNxVideoDec->pNxVideoDecHandle->height);
938
939     DisplayDone (pNxVideoDec->pNxVideoDecHandle, decOut.dispIdx);
940
941     gst_video_frame_unmap (&videoFrame);
942     gst_video_codec_state_unref (pState);
943   }
944
945   ret = gst_video_decoder_finish_frame (pDecoder, pFrame);
946
947   FUNC_OUT ();
948
949   return ret;
950
951 HANDLE_ERROR:
952   if (pGstbuf) {
953     g_free (pGstbuf);
954   }
955   if (pMeta) {
956     nxvideodec_buffer_finalize (pMeta);
957   }
958
959   return GST_FLOW_ERROR;
960 }
961 #endif
962
963 static void
964 nxvideodec_buffer_finalize (gpointer pData)
965 {
966   gint ret = 0;
967
968   FUNC_IN ();
969
970   struct video_meta_mmap_buffer *pMeta =
971       (struct video_meta_mmap_buffer *) pData;
972
973   if (!pMeta) {
974     GST_ERROR ("Error: pData is null !");
975     return;
976   }
977
978   if ((pMeta->pNxVideoDec) && (pMeta->pNxVideoDec->pNxVideoDecHandle)) {
979     pthread_mutex_lock (&pMeta->pNxVideoDec->mutex);
980     if (PLAY == pMeta->pNxVideoDec->isState) {
981       GST_DEBUG_OBJECT (pMeta->pNxVideoDec, "v4l2BufferIdx: %d\n",
982           pMeta->v4l2BufferIdx);
983       ret =
984           DisplayDone (pMeta->pNxVideoDec->pNxVideoDecHandle,
985           pMeta->v4l2BufferIdx);
986       if (ret) {
987         GST_ERROR ("Fail: DisplayDone !");
988       }
989     }
990     pthread_mutex_unlock (&pMeta->pNxVideoDec->mutex);
991   } else {
992     GST_ERROR ("Error: hCodec is null !");
993   }
994
995   if (pMeta) {
996     g_free (pMeta);
997   }
998 }
999
1000 static GstMemory *
1001 nxvideodec_mmvideobuf_copy (GstNxVideoDec *pNxVideoDec, NX_V4L2DEC_OUT * pDecOut)
1002 {
1003   GstMemory *pMeta = NULL;
1004   MMVideoBuffer *pMMVideoBuf = NULL;
1005
1006   pMMVideoBuf = (MMVideoBuffer *) g_malloc (sizeof (MMVideoBuffer));
1007   if (!pMMVideoBuf) {
1008     GST_ERROR ("failed to alloc MMVideoBuffer");
1009     return NULL;
1010   }
1011
1012   memset ((void *) pMMVideoBuf, 0, sizeof (MMVideoBuffer));
1013
1014   if (1 == pDecOut->hImg.planes) {
1015     pMMVideoBuf->type = MM_VIDEO_BUFFER_TYPE_TBM_BO;
1016     pMMVideoBuf->plane_num = 3;
1017     pMMVideoBuf->width[0] = pDecOut->hImg.width;
1018     pMMVideoBuf->height[0] = pDecOut->hImg.height;
1019     pMMVideoBuf->stride_width[0] = GST_ROUND_UP_32 (pDecOut->hImg.width);
1020     pMMVideoBuf->stride_width[1] = pMMVideoBuf->stride_width[0] >> 1;
1021     pMMVideoBuf->stride_width[2] = pMMVideoBuf->stride_width[1];
1022     pMMVideoBuf->stride_height[0] = GST_ROUND_UP_16 (pDecOut->hImg.height);
1023     pMMVideoBuf->stride_height[1] = GST_ROUND_UP_16 (pDecOut->hImg.height >> 1);
1024     pMMVideoBuf->stride_height[2] = pMMVideoBuf->stride_height[1];
1025     pMMVideoBuf->size[0] = pMMVideoBuf->stride_width[0] * pMMVideoBuf->stride_height[0];;
1026     pMMVideoBuf->size[1] = pMMVideoBuf->stride_width[1] * pMMVideoBuf->stride_height[1];
1027     pMMVideoBuf->size[2] = pMMVideoBuf->stride_width[2] * pMMVideoBuf->stride_height[2];
1028     pMMVideoBuf->data[0] = pDecOut->hImg.pBuffer[0];
1029     pMMVideoBuf->data[1] = pDecOut->hImg.pBuffer[0] + pMMVideoBuf->size[0];
1030     pMMVideoBuf->data[2] = pMMVideoBuf->data[1] + pMMVideoBuf->size[1];
1031     pMMVideoBuf->handle_num = 1;
1032     pMMVideoBuf->handle_size[0] = pMMVideoBuf->stride_width[0] * pMMVideoBuf->stride_height[0];
1033     pMMVideoBuf->handle_size[1] = pMMVideoBuf->stride_width[1] * pMMVideoBuf->stride_height[1];
1034     pMMVideoBuf->handle_size[2] = pMMVideoBuf->stride_width[2] * pMMVideoBuf->stride_height[2];
1035 #ifdef TIZEN_FEATURE_ARTIK530
1036     pMMVideoBuf->handle.bo[0] = pDecOut->hImg.bo[0];
1037     if (!pMMVideoBuf->handle.bo[0])
1038       GST_ERROR ("bo = null\n");
1039 #endif
1040   } else if (3 == pDecOut->hImg.planes) {
1041     pMMVideoBuf->type = MM_VIDEO_BUFFER_TYPE_TBM_BO;
1042     pMMVideoBuf->format = MM_PIXEL_FORMAT_I420;
1043     pMMVideoBuf->plane_num = 3;
1044     pMMVideoBuf->width[0] = pDecOut->hImg.width;
1045     pMMVideoBuf->height[0] = pDecOut->hImg.height;
1046     pMMVideoBuf->stride_width[0] = pDecOut->hImg.stride[0];
1047     pMMVideoBuf->stride_width[1] = pDecOut->hImg.stride[1];
1048     pMMVideoBuf->stride_width[2] = pDecOut->hImg.stride[2];
1049     pMMVideoBuf->size[0] = pDecOut->hImg.size[0];
1050     pMMVideoBuf->size[1] = pDecOut->hImg.size[1];
1051     pMMVideoBuf->size[2] = pDecOut->hImg.size[2];
1052     pMMVideoBuf->data[0] = pDecOut->hImg.pBuffer[0];
1053     pMMVideoBuf->data[1] = pDecOut->hImg.pBuffer[1];
1054     pMMVideoBuf->data[2] = pDecOut->hImg.pBuffer[2];
1055     pMMVideoBuf->handle_num = 3;
1056 #ifdef TIZEN_FEATURE_ARTIK530
1057     pMMVideoBuf->handle.bo[0] = pDecOut->hImg.bo[0];
1058     pMMVideoBuf->handle.bo[1] = pDecOut->hImg.bo[1];
1059     pMMVideoBuf->handle.bo[2] = pDecOut->hImg.bo[2];
1060     if (!pMMVideoBuf->handle.bo[0])
1061       GST_ERROR ("bo[0] = null\n");
1062     if (!pMMVideoBuf->handle.bo[1])
1063       GST_ERROR ("bo[1] = null\n");
1064     if (!pMMVideoBuf->handle.bo[2])
1065       GST_ERROR ("bo[2] = null\n");
1066 #endif
1067   }
1068 #ifdef CODEC_DEC_OUTPUT_DUMP /* for decoder output dump */
1069   decoder_output_dump (pMMVideoBuf);
1070 #endif
1071   pMeta = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
1072       pMMVideoBuf,
1073       sizeof (MMVideoBuffer), 0, sizeof (MMVideoBuffer), pMMVideoBuf, g_free);
1074
1075   return pMeta;
1076 }
1077
1078 static gboolean
1079 plugin_init (GstPlugin * plugin)
1080 {
1081   gboolean ret;
1082
1083   FUNC_IN ();
1084
1085   /* FIXME Remember to set the rank if it's an element that is meant
1086      to be autoplugged by decodebin. */
1087   ret = gst_element_register (plugin, "nxvideodec", GST_RANK_PRIMARY + 1,
1088       GST_TYPE_NXVIDEODEC);
1089   FUNC_OUT ();
1090
1091   return ret;
1092 }
1093
1094 #ifndef VERSION
1095 #define VERSION "0.1.0"
1096 #endif
1097 #ifndef PACKAGE
1098 #define PACKAGE "S5P6818 GStreamer PlugIn"
1099 #endif
1100 #ifndef PACKAGE_NAME
1101 #define PACKAGE_NAME "S5P6818 GStreamer PlugIn"
1102 #endif
1103 #ifndef GST_PACKAGE_ORIGIN
1104 #define GST_PACKAGE_ORIGIN "http://www.nexell.co.kr"
1105 #endif
1106
1107 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1108     GST_VERSION_MINOR,
1109     nxvideodec,
1110     "Nexell H/W Video Decoder for S5P6818",
1111     plugin_init, VERSION, "LGPL", PACKAGE_NAME, GST_PACKAGE_ORIGIN)