cf07998bc330c4e75354c658772a67908e21e168
[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 #include <gst/allocators/gsttizenmemory.h>
72
73 // This SUPPORT_NO_MEMORY_COPY function is disabled now.
74 // if the video decoder mmap is supported this function, it will be enabled.
75 #define SUPPORT_NO_MEMORY_COPY  1
76 //#define CODEC_DEC_OUTPUT_DUMP 1
77
78 GST_DEBUG_CATEGORY_STATIC (gst_nxvideodec_debug_category);
79 #define GST_CAT_DEFAULT gst_nxvideodec_debug_category
80
81 /* prototypes */
82 static void gst_nxvideodec_set_property (GObject * object,
83     guint property_id, const GValue * value, GParamSpec * pspec);
84 static void gst_nxvideodec_get_property (GObject * object,
85     guint property_id, GValue * value, GParamSpec * pspec);
86
87 static gboolean gst_nxvideodec_start (GstVideoDecoder * decoder);
88 static gboolean gst_nxvideodec_stop (GstVideoDecoder * decoder);
89 static gboolean gst_nxvideodec_set_format (GstVideoDecoder * decoder,
90     GstVideoCodecState * state);
91 static gboolean gst_nxvideodec_flush (GstVideoDecoder * decoder);
92 static GstFlowReturn gst_nxvideodec_handle_frame (GstVideoDecoder * decoder,
93     GstVideoCodecFrame * frame);
94 static void nxvideodec_base_init (gpointer gclass);
95 static void nxvideodec_buffer_finalize (gpointer pData);
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 inline void
150 decoder_output_dump (GstBuffer *buffer)
151 {
152   int i = 0;
153   char filename[100]={0};
154   FILE *fp = NULL;
155   tbm_surface_h surface;
156   tbm_surface_info_s info;
157   GstMemory *mem = gst_buffer_peek_memory (buffer, 0);
158   unsigned char *temp;
159
160   surface = gst_tizen_memory_get_surface(mem);
161
162   tbm_surface_get_info (surface, &info);
163
164   temp = info.planes[0].ptr;
165
166   sprintf(filename, "/tmp/dec_output_dump_%d_%d.yuv", info.width, info.height);
167   fp = fopen(filename, "ab");
168
169   if(!fp) {
170     return;
171   }
172
173   for (i = 0; i < info.height; i++) {
174     fwrite(temp, info.width, 1, fp);
175     temp += info.planes[0].stride;
176   }
177
178   temp = info.planes[1].ptr;
179
180   for(i = 0; i < info.height/2 ; i++) {
181     fwrite(temp, info.width/2, 1, fp);
182     temp += info.planes[1].stride;
183   }
184
185   temp = info.planes[2].ptr;
186
187   for(i = 0; i < info.height/2 ; i++) {
188     fwrite(temp, info.width/2, 1, fp);
189     temp += info.planes[2].stride;
190   }
191
192   fclose(fp);
193 }
194 #endif
195
196 static void
197 nxvideodec_base_init (gpointer gclass)
198 {
199   GstElementClass *pElement_class = GST_ELEMENT_CLASS (gclass);
200   GstCaps *pCapslist = NULL;
201   GstNxVideoDecClass *pKlass = GST_NXVIDEODEC_CLASS (pElement_class);
202
203   FUNC_IN ();
204
205   gst_element_class_set_details_simple (pElement_class,
206       PLUGIN_LONG_NAME, "Codec/Decoder/Video", PLUGIN_DESC, PLUGIN_AUTHOR);
207
208   pCapslist = gst_caps_new_empty ();
209
210   //      H.263
211   gst_caps_append_structure (pCapslist,
212       gst_structure_new ("video/x-h263",
213           "variant", G_TYPE_STRING, "itu", NULL));
214
215   //      H.264
216   gst_caps_append_structure (pCapslist,
217       gst_structure_new ("video/x-h264",
218           "alignment", G_TYPE_STRING, "au",
219           "width", GST_TYPE_INT_RANGE, 64, NX_MAX_WIDTH,
220           "height", GST_TYPE_INT_RANGE, 64, NX_MAX_HEIGHT, NULL));
221
222   //      XVID
223   gst_caps_append_structure (pCapslist,
224       gst_structure_new ("video/x-xvid",
225           "width", GST_TYPE_INT_RANGE, 64, NX_MAX_WIDTH,
226           "height", GST_TYPE_INT_RANGE, 64, NX_MAX_HEIGHT, NULL));
227
228
229   //      MPEG2
230   gst_caps_append_structure (pCapslist,
231       gst_structure_new ("video/mpeg",
232           "mpegversion", GST_TYPE_INT_RANGE, 1, 2,
233           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL));
234
235   //      MPEG4
236   gst_caps_append_structure (pCapslist,
237       gst_structure_new ("video/mpeg",
238           "mpegversion", G_TYPE_INT, 4,
239           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL));
240
241   //      DIVX
242   gst_caps_append_structure (pCapslist,
243       gst_structure_new ("video/x-divx",
244           "width", GST_TYPE_INT_RANGE, 64, NX_MAX_WIDTH,
245           "height", GST_TYPE_INT_RANGE, 64, NX_MAX_HEIGHT,
246           "divxversion", GST_TYPE_INT_RANGE, 3, 6, NULL));
247
248   //      MSMPEG
249   gst_caps_append_structure (pCapslist,
250       gst_structure_new ("video/x-msmpeg",
251           "width", GST_TYPE_INT_RANGE, 64, NX_MAX_WIDTH,
252           "height", GST_TYPE_INT_RANGE, 64, NX_MAX_HEIGHT,
253           "msmpegversion", G_TYPE_INT, 43, NULL));
254
255   // pad templates
256   pKlass->pSinktempl =
257       gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, pCapslist);
258   gst_element_class_add_pad_template (pElement_class, pKlass->pSinktempl);
259   gst_element_class_add_pad_template (pElement_class,
260       gst_static_pad_template_get (&gst_nxvideodec_src_template));
261
262   FUNC_OUT ();
263 }
264
265 G_DEFINE_TYPE_WITH_CODE (GstNxVideoDec, gst_nxvideodec, GST_TYPE_VIDEO_DECODER,
266     GST_DEBUG_CATEGORY_INIT (gst_nxvideodec_debug_category, "nxvideodec", 0,
267         "debug category for nxvideodec element"));
268
269 // class initialization
270 static void
271 gst_nxvideodec_class_init (GstNxVideoDecClass * pKlass)
272 {
273   FUNC_IN ();
274
275   GObjectClass *pGobjectClass = G_OBJECT_CLASS (pKlass);
276   GstVideoDecoderClass *pVideoDecoderClass = GST_VIDEO_DECODER_CLASS (pKlass);
277
278   nxvideodec_base_init (pKlass);
279
280   pGobjectClass->set_property = gst_nxvideodec_set_property;
281   pGobjectClass->get_property = gst_nxvideodec_get_property;
282
283   pVideoDecoderClass->start = GST_DEBUG_FUNCPTR (gst_nxvideodec_start);
284   pVideoDecoderClass->stop = GST_DEBUG_FUNCPTR (gst_nxvideodec_stop);
285
286   pVideoDecoderClass->set_format =
287       GST_DEBUG_FUNCPTR (gst_nxvideodec_set_format);
288   pVideoDecoderClass->flush = GST_DEBUG_FUNCPTR (gst_nxvideodec_flush);
289   pVideoDecoderClass->handle_frame =
290       GST_DEBUG_FUNCPTR (gst_nxvideodec_handle_frame);
291
292 #if SUPPORT_NO_MEMORY_COPY
293 #else
294   g_object_class_install_property (pGobjectClass,
295       PROP_TYPE,
296       g_param_spec_int ("buffer-type", "buffer-type",
297           "Buffer Type(0:NORMAL 1:MM_VIDEO_BUFFER_TYPE_GEM)", 0, 1,
298           BUFFER_TYPE_GEM, G_PARAM_READWRITE));
299 #endif
300
301   FUNC_OUT ();
302 }
303
304 static void
305 gst_nxvideodec_init (GstNxVideoDec * pNxVideoDec)
306 {
307   FUNC_IN ();
308
309   GST_DEBUG_OBJECT (pNxVideoDec, "dec_init");
310
311   // Initialize variables
312   pNxVideoDec->pNxVideoDecHandle = NULL;
313   pNxVideoDec->pInputState = NULL;
314   pNxVideoDec->isState = STOP;
315 #if SUPPORT_NO_MEMORY_COPY
316 #else
317   pNxVideoDec->bufferType = BUFFER_TYPE_GEM;
318 #endif
319 #ifdef TIZEN_FEATURE_ARTIK530
320   pNxVideoDec->allocator = gst_tizen_allocator_new ();
321 #endif
322   pthread_mutex_init (&pNxVideoDec->mutex, NULL);
323
324   FUNC_OUT ();
325 }
326
327 void
328 gst_nxvideodec_set_property (GObject * pObject, guint propertyId,
329     const GValue * pValue, GParamSpec * pPspec)
330 {
331   GstNxVideoDec *pNxvideodec = GST_NXVIDEODEC (pObject);
332   FUNC_IN ();
333
334   GST_DEBUG_OBJECT (pNxvideodec, "set_property");
335
336   switch (propertyId) {
337 #if SUPPORT_NO_MEMORY_COPY
338 #else
339     case PROP_TYPE:
340       pNxvideodec->bufferType = g_value_get_int (pValue);
341       break;
342 #endif
343     default:
344       G_OBJECT_WARN_INVALID_PROPERTY_ID (pObject, propertyId, pPspec);
345       break;
346   }
347
348   FUNC_OUT ();
349 }
350
351 void
352 gst_nxvideodec_get_property (GObject * pObject, guint propertyId,
353     GValue * pValue, GParamSpec * pPspec)
354 {
355   GstNxVideoDec *pNxvideodec = GST_NXVIDEODEC (pObject);
356   FUNC_IN ();
357
358   GST_DEBUG_OBJECT (pNxvideodec, "get_property");
359
360   switch (propertyId) {
361 #if SUPPORT_NO_MEMORY_COPY
362 #else
363     case PROP_TYPE:
364       g_value_set_int (pValue, pNxvideodec->bufferType);
365       break;
366 #endif
367     default:
368       G_OBJECT_WARN_INVALID_PROPERTY_ID (pObject, propertyId, pPspec);
369       break;
370   }
371
372   FUNC_OUT ();
373 }
374
375 static gboolean
376 gst_nxvideodec_start (GstVideoDecoder * pDecoder)
377 {
378   GstNxVideoDec *pNxVideoDec = GST_NXVIDEODEC (pDecoder);
379   FUNC_IN ();
380
381   GST_DEBUG_OBJECT (pNxVideoDec, "start");
382
383   if (pNxVideoDec->pNxVideoDecHandle) {
384     CloseVideoDec (pNxVideoDec->pNxVideoDecHandle);
385     pNxVideoDec->pNxVideoDecHandle = NULL;
386   }
387
388   pNxVideoDec->pNxVideoDecHandle = OpenVideoDec ();
389
390   if (pNxVideoDec->pNxVideoDecHandle == NULL) {
391     GST_ERROR ("VideoDecHandle is NULL !\n");
392     return FALSE;
393   }
394
395   pthread_mutex_lock (&pNxVideoDec->mutex);
396   pNxVideoDec->isState = PLAY;
397   pthread_mutex_unlock (&pNxVideoDec->mutex);
398
399   FUNC_OUT ();
400
401   return TRUE;
402 }
403
404 static gboolean
405 gst_nxvideodec_stop (GstVideoDecoder * pDecoder)
406 {
407   GstNxVideoDec *pNxVideoDec = GST_NXVIDEODEC (pDecoder);
408   FUNC_IN ();
409   if (pNxVideoDec == NULL) {
410     GST_ERROR ("pDecoder is NULL !\n");
411     return FALSE;
412   }
413
414   GST_DEBUG_OBJECT (pNxVideoDec, "stop");
415
416   pthread_mutex_lock (&pNxVideoDec->mutex);
417   pNxVideoDec->isState = STOP;
418   pthread_mutex_unlock (&pNxVideoDec->mutex);
419
420   if (pNxVideoDec->pNxVideoDecHandle->pSem) {
421     VDecSemSignal (pNxVideoDec->pNxVideoDecHandle->pSem);
422     VDecSemDestroy (pNxVideoDec->pNxVideoDecHandle->pSem);
423     pNxVideoDec->pNxVideoDecHandle->pSem = NULL;
424   }
425
426   CloseVideoDec (pNxVideoDec->pNxVideoDecHandle);
427
428 #ifdef TIZEN_FEATURE_ARTIK530
429   if (pNxVideoDec->allocator) {
430     gst_object_unref (pNxVideoDec->allocator);
431     pNxVideoDec->allocator = NULL;
432   }
433 #endif
434   pthread_mutex_destroy (&pNxVideoDec->mutex);
435
436   FUNC_OUT ();
437   return TRUE;
438 }
439
440 static gboolean
441 gst_nxvideodec_set_format (GstVideoDecoder * pDecoder,
442     GstVideoCodecState * pState)
443 {
444   GstNxVideoDec *pNxVideoDec = GST_NXVIDEODEC (pDecoder);
445   GstStructure *pStructure = NULL;
446   const gchar *pMimeType = NULL;
447   GstBuffer *pCodecData = NULL;
448   GstVideoCodecState *pOutputState = NULL;
449   NX_VIDEO_DEC_STRUCT *pDecHandle = NULL;
450   gint ret = FALSE;
451 #ifdef TIZEN_FEATURE_ARTIK530
452   gboolean bIsFormatChange = FALSE;
453 #endif
454
455   FUNC_IN ();
456
457   GST_DEBUG_OBJECT (pNxVideoDec, "set_format");
458
459   if (pNxVideoDec->pInputState) {
460     gst_video_codec_state_unref (pNxVideoDec->pInputState);
461     pNxVideoDec->pInputState = NULL;
462   }
463
464   pNxVideoDec->pInputState = gst_video_codec_state_ref (pState);
465
466   // Check Support Codec Type
467   pStructure = gst_caps_get_structure (pNxVideoDec->pInputState->caps, 0);
468   pMimeType = gst_structure_get_name (pStructure);
469   if (pNxVideoDec->pNxVideoDecHandle) {
470     pDecHandle = pNxVideoDec->pNxVideoDecHandle;
471   } else {
472     return FALSE;
473   }
474
475 #ifdef TIZEN_FEATURE_ARTIK530
476   GST_DEBUG_OBJECT (pNxVideoDec, "old %dx%d fps=%d/%d %p",
477       pDecHandle->width, pDecHandle->height,
478       pDecHandle->fpsNum, pDecHandle->fpsDen,
479       pDecHandle->codec_data);
480   GST_DEBUG_OBJECT (pNxVideoDec, "new %dx%d fps=%d/%d %p",
481       GST_VIDEO_INFO_WIDTH (&pState->info),
482       GST_VIDEO_INFO_HEIGHT (&pState->info),
483       GST_VIDEO_INFO_FPS_N (&pState->info),
484       GST_VIDEO_INFO_FPS_D (&pState->info),
485       pState->codec_data);
486
487   bIsFormatChange |=
488       pDecHandle->width != GST_VIDEO_INFO_WIDTH (&pState->info);
489   bIsFormatChange |=
490       pDecHandle->height != GST_VIDEO_INFO_HEIGHT (&pState->info);
491   if (GST_VIDEO_INFO_FPS_N (&pState->info) != 0) {
492     bIsFormatChange |=
493         pDecHandle->fpsNum != GST_VIDEO_INFO_FPS_N (&pState->info);
494     bIsFormatChange |=
495         pDecHandle->fpsDen != GST_VIDEO_INFO_FPS_D (&pState->info);
496   } else {
497     bIsFormatChange |= pDecHandle->fpsNum != 30;
498     bIsFormatChange |= pDecHandle->fpsDen != 1;
499   }
500   bIsFormatChange |= (pDecHandle->codec_data != pState->codec_data);
501   gst_buffer_replace (&pDecHandle->codec_data, pState->codec_data);
502   GST_DEBUG_OBJECT (pNxVideoDec, "format changed=%d", bIsFormatChange);
503 #endif
504
505   pDecHandle->codecType = FindCodecInfo (pState, pDecHandle);
506
507   if (pDecHandle->codecType < 0) {
508     GST_ERROR ("Unsupported VideoDecoder Mime Type : %s\n", pMimeType);
509     return FALSE;
510   }
511
512   if (pDecHandle->pExtraData) {
513     g_free (pDecHandle->pExtraData);
514     pDecHandle->pExtraData = NULL;
515     pDecHandle->extraDataSize = 0;
516   }
517
518   pCodecData = pNxVideoDec->pInputState->codec_data;
519
520   if (pCodecData) {
521     GstMapInfo mapInfo;
522
523     if (!gst_buffer_map (pCodecData, &mapInfo, GST_MAP_READ)) {
524       GST_ERROR ("Cannot map input buffer!\n");
525       return FALSE;
526     }
527
528     if (mapInfo.size > 0 && mapInfo.data) {
529       pDecHandle->pExtraData = (guint8 *) g_malloc (mapInfo.size);
530       pDecHandle->extraDataSize = mapInfo.size;
531     }
532
533     if (FALSE == GetExtraInfo (pDecHandle, (guint8 *) mapInfo.data,
534             mapInfo.size)) {
535       gst_buffer_unmap (pCodecData, &mapInfo);
536       return FALSE;
537     }
538     gst_buffer_unmap (pCodecData, &mapInfo);
539   } else {
540     GST_LOG ("No Codec Data\n");
541   }
542
543   if (pDecHandle->codecType == V4L2_PIX_FMT_H264) {
544     const gchar *pStr = NULL;
545
546     if ((pStr = gst_structure_get_string (pStructure, "alignment"))) {
547       if (strcmp (pStr, "au") == 0) {
548         pDecHandle->h264Alignment = H264_PARSE_ALIGN_AU;
549         GST_DEBUG_OBJECT (pNxVideoDec, ">>>>> H264 alignment: au Type.");
550       } else if (strcmp (pStr, "nal") == 0) {
551         pDecHandle->h264Alignment = H264_PARSE_ALIGN_NAL;
552         GST_DEBUG_OBJECT (pNxVideoDec, ">>>>> H264 alignment: nal Type.");
553       } else {
554         GST_DEBUG_OBJECT (pNxVideoDec, "unknown alignment: %s", pStr);
555       }
556     }
557   }
558
559   pOutputState =
560       gst_video_decoder_set_output_state (pDecoder, GST_VIDEO_FORMAT_S420,
561       pDecHandle->width, pDecHandle->height, pNxVideoDec->pInputState);
562
563   pOutputState->caps = gst_caps_new_simple ("video/x-raw",
564       "format", G_TYPE_STRING,
565       gst_video_format_to_string (GST_VIDEO_FORMAT_S420), "width", G_TYPE_INT,
566       pDecHandle->width, "height", G_TYPE_INT, pDecHandle->height, "framerate",
567       GST_TYPE_FRACTION, pDecHandle->fpsNum, pDecHandle->fpsDen, NULL);
568
569   gst_video_codec_state_unref (pOutputState);
570
571   pNxVideoDec->pNxVideoDecHandle->imgPlaneNum = 1;
572 #if SUPPORT_NO_MEMORY_COPY
573   GST_DEBUG_OBJECT (pNxVideoDec, ">>>>> Accelerable.");
574 #else
575   if (BUFFER_TYPE_GEM == pNxVideoDec->bufferType) {
576     GST_DEBUG_OBJECT (pNxVideoDec, ">>>>> Accelerable.");
577   }
578 #endif
579
580   ret = gst_video_decoder_negotiate (pDecoder);
581
582   if (FALSE == ret) {
583     GST_ERROR ("Fail Negotiate !\n");
584     return ret;
585   }
586
587 #ifdef TIZEN_FEATURE_ARTIK530
588   if (!bIsFormatChange) {
589     FUNC_OUT ();
590     return TRUE;
591   }
592
593   if (pDecHandle->hCodec) {
594     NX_V4l2DecClose (pDecHandle->hCodec);
595     pDecHandle->hCodec = NULL;
596
597     if (pDecHandle->pTmpStrmBuf) {
598       g_free (pDecHandle->pTmpStrmBuf);
599       pDecHandle->pTmpStrmBuf = NULL;
600     }
601
602     pDecHandle->bInitialized = FALSE;
603   }
604 #endif
605
606   if (0 != InitVideoDec (pNxVideoDec->pNxVideoDecHandle)) {
607     return FALSE;
608   }
609
610   FUNC_OUT ();
611
612   return ret;
613 }
614
615 static gboolean
616 gst_nxvideodec_flush (GstVideoDecoder * pDecoder)
617 {
618   GstNxVideoDec *pNxvideodec = GST_NXVIDEODEC (pDecoder);
619
620   FUNC_IN ();
621
622   GST_DEBUG_OBJECT (pNxvideodec, "flush");
623
624   if (pNxvideodec->pNxVideoDecHandle) {
625     pNxvideodec->pNxVideoDecHandle->bFlush = TRUE;
626   }
627
628   FUNC_OUT ();
629
630   return TRUE;
631 }
632
633 #if SUPPORT_NO_MEMORY_COPY
634 static void
635 nxvideodec_get_offset_stride (gint width, gint height, guint8 * pSrc,
636     gsize * pOffset, gint * pStride)
637 {
638   guint8 *plu = NULL;
639   guint8 *pcb = NULL;
640   guint8 *pcr = NULL;
641   gint luStride = 0;
642   gint luVStride = 0;
643   gint cStride = 0;
644   gint cVStride = 0;
645
646   luStride = ALIGN (width, 32);
647   luVStride = ALIGN (height, 16);
648   cStride = luStride / 2;
649   cVStride = ALIGN (height / 2, 16);
650   plu = pSrc;
651   pcb = plu + luStride * luVStride;
652   pcr = pcb + cStride * cVStride;
653
654   pOffset[0] = 0;
655   pOffset[1] = pcb - plu;
656   pOffset[2] = pcr - plu;
657
658   pStride[0] = luStride;
659   pStride[1] = cStride;
660   pStride[2] = cStride;
661 }
662
663 static GstFlowReturn
664 gst_nxvideodec_handle_frame (GstVideoDecoder * pDecoder,
665     GstVideoCodecFrame * pFrame)
666 {
667   GstNxVideoDec *pNxVideoDec = GST_NXVIDEODEC (pDecoder);
668   NX_V4L2DEC_OUT decOut;
669   gint64 timeStamp = 0;
670   GstMapInfo mapInfo;
671   gint ret = 0;
672   gboolean bKeyFrame = FALSE;
673
674   GstMemory *pTmem = NULL;
675   GstBuffer *pGstbuf = NULL;
676   struct video_meta_mmap_buffer *pMeta = NULL;
677
678   NX_VID_MEMORY_INFO *pImg = NULL;
679   GstVideoCodecState *pState = NULL;
680
681   GstVideoMeta *pVmeta = NULL;
682
683   guint n_planes = 0;
684   gsize offset[3] = { 0, };
685   gint stride[3] = { 0, };
686
687   FUNC_IN ();
688
689   if (!gst_buffer_map (pFrame->input_buffer, &mapInfo, GST_MAP_READ)) {
690     GST_ERROR ("Cannot map input buffer!");
691     gst_video_codec_frame_unref (pFrame);
692     return GST_FLOW_ERROR;
693   }
694
695   bKeyFrame = GST_VIDEO_CODEC_FRAME_IS_SYNC_POINT (pFrame);
696
697   ret =
698       VideoDecodeFrame (pNxVideoDec->pNxVideoDecHandle, pFrame->input_buffer,
699       &decOut, bKeyFrame);
700
701   gst_buffer_unmap (pFrame->input_buffer, &mapInfo);
702   if (DEC_ERR == ret) {
703     GetTimeStamp (pNxVideoDec->pNxVideoDecHandle, &timeStamp);
704     return gst_video_decoder_drop_frame (pDecoder, pFrame);
705   } else if (DEC_INIT_ERR == ret) {
706     return GST_FLOW_ERROR;
707   }
708
709   if (decOut.dispIdx < 0) {
710     return GST_FLOW_OK;
711   }
712
713   GST_DEBUG_OBJECT (pNxVideoDec, " decOut.dispIdx: %d\n", decOut.dispIdx);
714
715   pMeta =
716       (struct video_meta_mmap_buffer *) g_malloc (sizeof (struct
717           video_meta_mmap_buffer));
718
719   if (!pMeta) {
720     GST_ERROR_OBJECT (pNxVideoDec, "failed to malloc for meta");
721     gst_video_codec_frame_unref (pFrame);
722     return GST_FLOW_ERROR;
723   }
724
725   pImg = &decOut.hImg;
726   pMeta->v4l2BufferIdx = decOut.dispIdx;
727   pMeta->pNxVideoDec = pNxVideoDec;
728
729   pGstbuf = gst_buffer_new ();
730   if (!pGstbuf) {
731     GST_ERROR_OBJECT (pNxVideoDec, "failed to gst_buffer_new");
732     gst_video_codec_frame_unref (pFrame);
733     goto HANDLE_ERROR;
734   }
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   pTmem = gst_tizen_allocator_alloc_surface (pNxVideoDec->allocator, &pState->info, pImg->surface, pMeta, nxvideodec_buffer_finalize);
744
745   pVmeta =
746       gst_buffer_add_video_meta_full (pGstbuf, GST_VIDEO_FRAME_FLAG_NONE,
747       GST_VIDEO_INFO_FORMAT (&pState->info),
748       GST_VIDEO_INFO_WIDTH (&pState->info),
749       GST_VIDEO_INFO_HEIGHT (&pState->info), n_planes, offset, stride);
750
751   if (!pVmeta) {
752     GST_ERROR_OBJECT (pNxVideoDec, "failed to gst_buffer_add_video_meta_full");
753     gst_video_codec_state_unref (pState);
754     gst_video_codec_frame_unref (pFrame);
755     goto HANDLE_ERROR;
756   }
757   gst_buffer_append_memory (pGstbuf, pTmem);
758
759 #ifdef CODEC_DEC_OUTPUT_DUMP /* for decoder output dump */
760   decoder_output_dump (pGstbuf);
761 #endif
762   pFrame->output_buffer = pGstbuf;
763
764   if (-1 == GetTimeStamp (pNxVideoDec->pNxVideoDecHandle, &timeStamp)) {
765     GST_DEBUG_OBJECT (pNxVideoDec, "Cannot Found Time Stamp!!!");
766   }
767   pFrame->pts = timeStamp;
768   GST_BUFFER_PTS (pFrame->output_buffer) = timeStamp;
769
770   gst_video_codec_state_unref (pState);
771
772   ret = gst_video_decoder_finish_frame (pDecoder, pFrame);
773
774   FUNC_OUT ();
775
776   return ret;
777
778 HANDLE_ERROR:
779   if (pGstbuf) {
780     g_free (pGstbuf);
781   }
782
783   if (pMeta) {
784     nxvideodec_buffer_finalize (pMeta);
785   }
786
787   return GST_FLOW_ERROR;
788 }
789 #else
790 static GstFlowReturn
791 gst_nxvideodec_handle_frame (GstVideoDecoder * pDecoder,
792     GstVideoCodecFrame * pFrame)
793 {
794   GstNxVideoDec *pNxVideoDec = GST_NXVIDEODEC (pDecoder);
795   NX_V4L2DEC_OUT decOut;
796   gint64 timeStamp = 0;
797   GstMapInfo mapInfo;
798   gint ret = 0;
799   gboolean bKeyFrame = FALSE;
800   GstMemory *pGstmem = NULL;
801   GstBuffer *pGstbuf = NULL;
802   struct video_meta_mmap_buffer *pMeta = NULL;
803
804   FUNC_IN ();
805
806   if (!gst_buffer_map (pFrame->input_buffer, &mapInfo, GST_MAP_READ)) {
807     GST_ERROR ("Cannot map input buffer!");
808     gst_video_codec_frame_unref (pFrame);
809     return GST_FLOW_ERROR;
810   }
811
812   bKeyFrame = GST_VIDEO_CODEC_FRAME_IS_SYNC_POINT (pFrame);
813
814   ret =
815       VideoDecodeFrame (pNxVideoDec->pNxVideoDecHandle, pFrame->input_buffer,
816       &decOut, bKeyFrame);
817
818   gst_buffer_unmap (pFrame->input_buffer, &mapInfo);
819   if (DEC_ERR == ret) {
820     GetTimeStamp (pNxVideoDec->pNxVideoDecHandle, &timeStamp);
821     return gst_video_decoder_drop_frame (pDecoder, pFrame);
822   } else if (DEC_INIT_ERR == ret) {
823     return GST_FLOW_ERROR;
824   }
825
826   if (decOut.dispIdx < 0) {
827     return GST_FLOW_OK;
828   }
829
830   GST_DEBUG_OBJECT (pNxVideoDec, " decOut.dispIdx: %d\n", decOut.dispIdx);
831
832   if (BUFFER_TYPE_GEM == pNxVideoDec->bufferType) {
833     pGstbuf = gst_buffer_new ();
834     if (!pGstbuf) {
835       GST_ERROR_OBJECT (pNxVideoDec, "failed to gst_buffer_new");
836       gst_video_codec_frame_unref (pFrame);
837       goto HANDLE_ERROR;
838     }
839
840     pMeta =
841         (struct video_meta_mmap_buffer *) g_malloc (sizeof (struct
842             video_meta_mmap_buffer));
843     if (!pMeta) {
844       GST_ERROR_OBJECT (pNxVideoDec, "failed to malloc for meta");
845       gst_video_codec_frame_unref (pFrame);
846       return GST_FLOW_ERROR;
847     }
848     pMeta->v4l2BufferIdx = decOut.dispIdx;
849     pMeta->pNxVideoDec = pNxVideoDec;
850     pGstmem = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
851         pMeta,
852         sizeof (struct video_meta_mmap_buffer),
853         0,
854         sizeof (struct video_meta_mmap_buffer),
855         pMeta, nxvideodec_buffer_finalize);
856     if (!pGstmem) {
857       GST_ERROR_OBJECT (pNxVideoDec,
858           "failed to gst_memory_new_wrapped for mmap buffer");
859       gst_video_codec_frame_unref (pFrame);
860       goto HANDLE_ERROR;
861     }
862     gst_buffer_append_memory (pGstbuf, pGstmem);
863
864     gst_buffer_add_mmvideobuffer_meta (pGstbuf, 0);
865
866     pFrame->output_buffer = pGstbuf;
867
868     if (-1 == GetTimeStamp (pNxVideoDec->pNxVideoDecHandle, &timeStamp)) {
869       GST_DEBUG_OBJECT (pNxVideoDec, "Cannot Found Time Stamp!!!");
870     }
871     pFrame->pts = timeStamp;
872     GST_BUFFER_PTS (pFrame->output_buffer) = timeStamp;
873   } else {
874     GstVideoFrame videoFrame;
875     NX_VID_MEMORY_INFO *pImg = NULL;
876     guint8 *pPtr = NULL;;
877     GstVideoCodecState *pState = NULL;
878     GstFlowReturn flowRet;
879     guint8 *plu = NULL;
880     guint8 *pcb = NULL;
881     guint8 *pcr = NULL;
882     gint luStride = 0;
883     gint luVStride = 0;
884     gint cStride = 0;
885     gint cVStride = 0;
886
887     flowRet = gst_video_decoder_allocate_output_frame (pDecoder, pFrame);
888     pState = gst_video_decoder_get_output_state (pDecoder);
889     if (flowRet != GST_FLOW_OK) {
890       gst_video_codec_state_unref (pState);
891       gst_video_codec_frame_unref (pFrame);
892       return flowRet;
893     }
894
895     if (!gst_video_frame_map (&videoFrame, &pState->info, pFrame->output_buffer,
896             GST_MAP_WRITE)) {
897       GST_ERROR ("Cannot video frame map!\n");
898       gst_video_codec_state_unref (pState);
899       gst_video_codec_frame_unref (pFrame);
900       return GST_FLOW_ERROR;
901     }
902
903     if (-1 == GetTimeStamp (pNxVideoDec->pNxVideoDecHandle, &timeStamp)) {
904       GST_DEBUG_OBJECT (pNxVideoDec, "Cannot Found Time Stamp!!!");
905     }
906     pFrame->pts = timeStamp;
907     GST_BUFFER_PTS (pFrame->output_buffer) = timeStamp;
908
909     pImg = &decOut.hImg;
910     pPtr = GST_VIDEO_FRAME_COMP_DATA (&videoFrame, 0);
911
912     luStride = ALIGN (pNxVideoDec->pNxVideoDecHandle->width, 32);
913     luVStride = ALIGN (pNxVideoDec->pNxVideoDecHandle->height, 16);
914     cStride = luStride / 2;
915     cVStride = ALIGN (pNxVideoDec->pNxVideoDecHandle->height / 2, 16);
916     plu = (guint8 *) pImg->pBuffer[0];
917     pcb = plu + luStride * luVStride;
918     pcr = pcb + cStride * cVStride;
919
920     CopyImageToBufferYV12 ((guint8 *) plu, (guint8 *) pcb, (guint8 *) pcr,
921         pPtr, luStride, cStride, pNxVideoDec->pNxVideoDecHandle->width,
922         pNxVideoDec->pNxVideoDecHandle->height);
923
924     DisplayDone (pNxVideoDec->pNxVideoDecHandle, decOut.dispIdx);
925
926     gst_video_frame_unmap (&videoFrame);
927     gst_video_codec_state_unref (pState);
928   }
929
930   ret = gst_video_decoder_finish_frame (pDecoder, pFrame);
931
932   FUNC_OUT ();
933
934   return ret;
935
936 HANDLE_ERROR:
937   if (pGstbuf) {
938     g_free (pGstbuf);
939   }
940   if (pMeta) {
941     nxvideodec_buffer_finalize (pMeta);
942   }
943
944   return GST_FLOW_ERROR;
945 }
946 #endif
947
948 static void
949 nxvideodec_buffer_finalize (gpointer pData)
950 {
951   gint ret = 0;
952
953   FUNC_IN ();
954
955   struct video_meta_mmap_buffer *pMeta =
956       (struct video_meta_mmap_buffer *) pData;
957
958   if (!pMeta) {
959     GST_ERROR ("Error: pData is null !");
960     return;
961   }
962
963   if ((pMeta->pNxVideoDec) && (pMeta->pNxVideoDec->pNxVideoDecHandle)) {
964     pthread_mutex_lock (&pMeta->pNxVideoDec->mutex);
965     if (PLAY == pMeta->pNxVideoDec->isState) {
966       GST_DEBUG_OBJECT (pMeta->pNxVideoDec, "v4l2BufferIdx: %d\n",
967           pMeta->v4l2BufferIdx);
968       ret =
969           DisplayDone (pMeta->pNxVideoDec->pNxVideoDecHandle,
970           pMeta->v4l2BufferIdx);
971       if (ret) {
972         GST_ERROR ("Fail: DisplayDone !");
973       }
974     }
975     pthread_mutex_unlock (&pMeta->pNxVideoDec->mutex);
976   } else {
977     GST_ERROR ("Error: hCodec is null !");
978   }
979
980   if (pMeta) {
981     g_free (pMeta);
982   }
983 }
984
985 static gboolean
986 plugin_init (GstPlugin * plugin)
987 {
988   gboolean ret;
989
990   FUNC_IN ();
991
992   /* FIXME Remember to set the rank if it's an element that is meant
993      to be autoplugged by decodebin. */
994   ret = gst_element_register (plugin, "nxvideodec", GST_RANK_PRIMARY + 1,
995       GST_TYPE_NXVIDEODEC);
996   FUNC_OUT ();
997
998   return ret;
999 }
1000
1001 #ifndef VERSION
1002 #define VERSION "0.1.0"
1003 #endif
1004 #ifndef PACKAGE
1005 #define PACKAGE "S5P6818 GStreamer PlugIn"
1006 #endif
1007 #ifndef PACKAGE_NAME
1008 #define PACKAGE_NAME "S5P6818 GStreamer PlugIn"
1009 #endif
1010 #ifndef GST_PACKAGE_ORIGIN
1011 #define GST_PACKAGE_ORIGIN "http://www.nexell.co.kr"
1012 #endif
1013
1014 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1015     GST_VERSION_MINOR,
1016     nxvideodec,
1017     "Nexell H/W Video Decoder for S5P6818",
1018     plugin_init, VERSION, "LGPL", PACKAGE_NAME, GST_PACKAGE_ORIGIN)