e0ea9925215ab4234b5ec6ed373669f951bb7975
[vuplus_xbmc] / xbmc / cores / omxplayer / OMXVideo.cpp
1 /*
2  *      Copyright (C) 2010-2013 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #if (defined HAVE_CONFIG_H) && (!defined TARGET_WINDOWS)
22   #include "config.h"
23 #elif defined(TARGET_WINDOWS)
24 #include "system.h"
25 #endif
26
27 #include "OMXVideo.h"
28
29 #include "utils/log.h"
30 #include "linux/XMemUtils.h"
31 #include "DVDDemuxers/DVDDemuxUtils.h"
32 #include "settings/AdvancedSettings.h"
33 #include "xbmc/guilib/GraphicContext.h"
34 #include "settings/Settings.h"
35 #include "utils/BitstreamConverter.h"
36
37 #include "linux/RBP.h"
38
39 #include <sys/time.h>
40 #include <inttypes.h>
41
42 #ifdef CLASSNAME
43 #undef CLASSNAME
44 #endif
45 #define CLASSNAME "COMXVideo"
46
47 #define OMX_VIDEO_DECODER       "OMX.broadcom.video_decode"
48 #define OMX_H264BASE_DECODER    OMX_VIDEO_DECODER
49 #define OMX_H264MAIN_DECODER    OMX_VIDEO_DECODER
50 #define OMX_H264HIGH_DECODER    OMX_VIDEO_DECODER
51 #define OMX_MPEG4_DECODER       OMX_VIDEO_DECODER
52 #define OMX_MSMPEG4V1_DECODER   OMX_VIDEO_DECODER
53 #define OMX_MSMPEG4V2_DECODER   OMX_VIDEO_DECODER
54 #define OMX_MSMPEG4V3_DECODER   OMX_VIDEO_DECODER
55 #define OMX_MPEG4EXT_DECODER    OMX_VIDEO_DECODER
56 #define OMX_MPEG2V_DECODER      OMX_VIDEO_DECODER
57 #define OMX_VC1_DECODER         OMX_VIDEO_DECODER
58 #define OMX_WMV3_DECODER        OMX_VIDEO_DECODER
59 #define OMX_VP6_DECODER         OMX_VIDEO_DECODER
60 #define OMX_VP8_DECODER         OMX_VIDEO_DECODER
61 #define OMX_THEORA_DECODER      OMX_VIDEO_DECODER
62 #define OMX_MJPEG_DECODER       OMX_VIDEO_DECODER
63
64 #define MAX_TEXT_LENGTH 1024
65
66 COMXVideo::COMXVideo() : m_video_codec_name("")
67 {
68   m_is_open           = false;
69   m_extradata         = NULL;
70   m_extrasize         = 0;
71   m_deinterlace       = false;
72   m_deinterlace_request = VS_DEINTERLACEMODE_OFF;
73   m_hdmi_clock_sync   = false;
74   m_drop_state        = false;
75   m_decoded_width     = 0;
76   m_decoded_height    = 0;
77   m_omx_clock         = NULL;
78   m_av_clock          = NULL;
79   m_res_callback      = NULL;
80   m_res_ctx           = NULL;
81   m_submitted_eos     = false;
82   m_failed_eos        = false;
83   m_settings_changed  = false;
84   m_setStartTime      = false;
85   m_transform         = OMX_DISPLAY_ROT0;
86 }
87
88 COMXVideo::~COMXVideo()
89 {
90   Close();
91 }
92
93 bool COMXVideo::SendDecoderConfig()
94 {
95   CSingleLock lock (m_critSection);
96   OMX_ERRORTYPE omx_err   = OMX_ErrorNone;
97
98   /* send decoder config */
99   if(m_extrasize > 0 && m_extradata != NULL)
100   {
101     OMX_BUFFERHEADERTYPE *omx_buffer = m_omx_decoder.GetInputBuffer();
102
103     if(omx_buffer == NULL)
104     {
105       CLog::Log(LOGERROR, "%s::%s - buffer error 0x%08x", CLASSNAME, __func__, omx_err);
106       return false;
107     }
108
109     omx_buffer->nOffset = 0;
110     omx_buffer->nFilledLen = m_extrasize;
111     if(omx_buffer->nFilledLen > omx_buffer->nAllocLen)
112     {
113       CLog::Log(LOGERROR, "%s::%s - omx_buffer->nFilledLen > omx_buffer->nAllocLen", CLASSNAME, __func__);
114       return false;
115     }
116
117     memset((unsigned char *)omx_buffer->pBuffer, 0x0, omx_buffer->nAllocLen);
118     memcpy((unsigned char *)omx_buffer->pBuffer, m_extradata, omx_buffer->nFilledLen);
119     omx_buffer->nFlags = OMX_BUFFERFLAG_CODECCONFIG | OMX_BUFFERFLAG_ENDOFFRAME;
120   
121     omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer);
122     if (omx_err != OMX_ErrorNone)
123     {
124       CLog::Log(LOGERROR, "%s::%s - OMX_EmptyThisBuffer() failed with result(0x%x)\n", CLASSNAME, __func__, omx_err);
125       return false;
126     }
127   }
128   return true;
129 }
130
131 bool COMXVideo::NaluFormatStartCodes(enum AVCodecID codec, uint8_t *in_extradata, int in_extrasize)
132 {
133   switch(codec)
134   {
135     case AV_CODEC_ID_H264:
136       if (in_extrasize < 7 || in_extradata == NULL)
137         return true;
138       // valid avcC atom data always starts with the value 1 (version), otherwise annexb
139       else if ( *in_extradata != 1 )
140         return true;
141     default: break;
142   }
143   return false;    
144 }
145
146 bool COMXVideo::PortSettingsChanged()
147 {
148   CSingleLock lock (m_critSection);
149   OMX_ERRORTYPE omx_err   = OMX_ErrorNone;
150
151   if (m_settings_changed)
152   {
153     m_omx_decoder.DisablePort(m_omx_decoder.GetOutputPort(), true);
154   }
155
156   OMX_PARAM_PORTDEFINITIONTYPE port_image;
157   OMX_INIT_STRUCTURE(port_image);
158   port_image.nPortIndex = m_omx_decoder.GetOutputPort();
159   omx_err = m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition, &port_image);
160   if(omx_err != OMX_ErrorNone)
161   {
162     CLog::Log(LOGERROR, "%s::%s - error m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition) omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
163   }
164
165   OMX_CONFIG_POINTTYPE pixel_aspect;
166   OMX_INIT_STRUCTURE(pixel_aspect);
167   pixel_aspect.nPortIndex = m_omx_decoder.GetOutputPort();
168   omx_err = m_omx_decoder.GetParameter(OMX_IndexParamBrcmPixelAspectRatio, &pixel_aspect);
169   if(omx_err != OMX_ErrorNone)
170   {
171     CLog::Log(LOGERROR, "%s::%s - error m_omx_decoder.GetParameter(OMX_IndexParamBrcmPixelAspectRatio) omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
172   }
173
174   // let OMXPlayerVideo know about resolution so it can inform RenderManager
175   if (m_res_callback)
176   {
177     float display_aspect = 0.0f;
178     if (pixel_aspect.nX && pixel_aspect.nY)
179       display_aspect = (float)pixel_aspect.nX * port_image.format.video.nFrameWidth /
180         ((float)pixel_aspect.nY * port_image.format.video.nFrameHeight);
181     m_res_callback(m_res_ctx, port_image.format.video.nFrameWidth, port_image.format.video.nFrameHeight, display_aspect);
182   }
183
184   if (m_settings_changed)
185   {
186     m_omx_decoder.EnablePort(m_omx_decoder.GetOutputPort(), true);
187     return true;
188   }
189
190   OMX_CONFIG_INTERLACETYPE interlace;
191   OMX_INIT_STRUCTURE(interlace);
192   interlace.nPortIndex = m_omx_decoder.GetOutputPort();
193   omx_err = m_omx_decoder.GetConfig(OMX_IndexConfigCommonInterlace, &interlace);
194
195   if(m_deinterlace_request == VS_DEINTERLACEMODE_FORCE)
196     m_deinterlace = true;
197   else if(m_deinterlace_request == VS_DEINTERLACEMODE_OFF)
198     m_deinterlace = false;
199   else
200     m_deinterlace = interlace.eMode != OMX_InterlaceProgressive;
201
202   if(!m_omx_render.Initialize("OMX.broadcom.video_render", OMX_IndexParamVideoInit))
203     return false;
204
205   m_omx_render.ResetEos();
206
207   CLog::Log(LOGDEBUG, "%s::%s - %dx%d@%.2f interlace:%d deinterlace:%d", CLASSNAME, __func__,
208       port_image.format.video.nFrameWidth, port_image.format.video.nFrameHeight,
209       port_image.format.video.xFramerate / (float)(1<<16), interlace.eMode, m_deinterlace);
210
211   if(!m_omx_sched.Initialize("OMX.broadcom.video_scheduler", OMX_IndexParamVideoInit))
212     return false;
213
214   if(m_deinterlace)
215   {
216     if(!m_omx_image_fx.Initialize("OMX.broadcom.image_fx", OMX_IndexParamImageInit))
217       return false;
218   }
219
220   OMX_CONFIG_DISPLAYREGIONTYPE configDisplay;
221   OMX_INIT_STRUCTURE(configDisplay);
222   configDisplay.nPortIndex = m_omx_render.GetInputPort();
223
224   configDisplay.set = OMX_DISPLAY_SET_TRANSFORM;
225   configDisplay.transform = m_transform;
226   omx_err = m_omx_render.SetConfig(OMX_IndexConfigDisplayRegion, &configDisplay);
227   if(omx_err != OMX_ErrorNone)
228   {
229     CLog::Log(LOGWARNING, "%s::%s - could not set transform : %d", CLASSNAME, __func__, m_transform);
230     return false;
231   }
232
233   if(m_hdmi_clock_sync)
234   {
235     OMX_CONFIG_LATENCYTARGETTYPE latencyTarget;
236     OMX_INIT_STRUCTURE(latencyTarget);
237     latencyTarget.nPortIndex = m_omx_render.GetInputPort();
238     latencyTarget.bEnabled = OMX_TRUE;
239     latencyTarget.nFilter = 2;
240     latencyTarget.nTarget = 4000;
241     latencyTarget.nShift = 3;
242     latencyTarget.nSpeedFactor = -135;
243     latencyTarget.nInterFactor = 500;
244     latencyTarget.nAdjCap = 20;
245
246     omx_err = m_omx_render.SetConfig(OMX_IndexConfigLatencyTarget, &latencyTarget);
247     if (omx_err != OMX_ErrorNone)
248     {
249       CLog::Log(LOGERROR, "%s::%s - OMX_IndexConfigLatencyTarget omx_err(0%08x)", CLASSNAME, __func__, omx_err);
250       return false;
251     }
252   }
253
254   if(m_deinterlace)
255   {
256     OMX_CONFIG_IMAGEFILTERPARAMSTYPE image_filter;
257     OMX_INIT_STRUCTURE(image_filter);
258
259     image_filter.nPortIndex = m_omx_image_fx.GetOutputPort();
260     image_filter.nNumParams = 1;
261     image_filter.nParams[0] = 3;
262     image_filter.eImageFilter = OMX_ImageFilterDeInterlaceAdvanced;
263
264     omx_err = m_omx_image_fx.SetConfig(OMX_IndexConfigCommonImageFilterParameters, &image_filter);
265     if(omx_err != OMX_ErrorNone)
266     {
267       CLog::Log(LOGERROR, "%s::%s - OMX_IndexConfigCommonImageFilterParameters omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
268       return false;
269     }
270   }
271
272   if(m_deinterlace)
273   {
274     m_omx_tunnel_decoder.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_image_fx, m_omx_image_fx.GetInputPort());
275     m_omx_tunnel_image_fx.Initialize(&m_omx_image_fx, m_omx_image_fx.GetOutputPort(), &m_omx_sched, m_omx_sched.GetInputPort());
276   }
277   else
278   {
279     m_omx_tunnel_decoder.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_sched, m_omx_sched.GetInputPort());
280   }
281   m_omx_tunnel_sched.Initialize(&m_omx_sched, m_omx_sched.GetOutputPort(), &m_omx_render, m_omx_render.GetInputPort());
282
283   m_omx_tunnel_clock.Initialize(m_omx_clock, m_omx_clock->GetInputPort()  + 1, &m_omx_sched, m_omx_sched.GetOutputPort()  + 1);
284
285   omx_err = m_omx_tunnel_clock.Establish();
286   if(omx_err != OMX_ErrorNone)
287   {
288     CLog::Log(LOGERROR, "%s::%s - m_omx_tunnel_clock.Establish omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
289     return false;
290   }
291
292   omx_err = m_omx_tunnel_decoder.Establish();
293   if(omx_err != OMX_ErrorNone)
294   {
295     CLog::Log(LOGERROR, "%s::%s - m_omx_tunnel_decoder.Establish omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
296     return false;
297   }
298
299   if(m_deinterlace)
300   {
301     omx_err = m_omx_tunnel_image_fx.Establish();
302     if(omx_err != OMX_ErrorNone)
303     {
304       CLog::Log(LOGERROR, "%s::%s - m_omx_tunnel_image_fx.Establish omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
305       return false;
306     }
307
308     omx_err = m_omx_image_fx.SetStateForComponent(OMX_StateExecuting);
309     if (omx_err != OMX_ErrorNone)
310     {
311       CLog::Log(LOGERROR, "%s::%s - m_omx_image_fx.SetStateForComponent omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
312       return false;
313     }
314   }
315
316   omx_err = m_omx_tunnel_sched.Establish();
317   if(omx_err != OMX_ErrorNone)
318   {
319     CLog::Log(LOGERROR, "%s::%s - m_omx_tunnel_sched.Establish omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
320     return false;
321   }
322
323   omx_err = m_omx_sched.SetStateForComponent(OMX_StateExecuting);
324   if (omx_err != OMX_ErrorNone)
325   {
326     CLog::Log(LOGERROR, "%s::%s - m_omx_sched.SetStateForComponent omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
327     return false;
328   }
329
330   omx_err = m_omx_render.SetStateForComponent(OMX_StateExecuting);
331   if (omx_err != OMX_ErrorNone)
332   {
333     CLog::Log(LOGERROR, "%s::%s - m_omx_render.SetStateForComponent omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
334     return false;
335   }
336
337   m_settings_changed = true;
338   return true;
339 }
340
341 bool COMXVideo::Open(CDVDStreamInfo &hints, OMXClock *clock, EDEINTERLACEMODE deinterlace, bool hdmi_clock_sync)
342 {
343   CSingleLock lock (m_critSection);
344   bool vflip = false;
345   Close();
346   OMX_ERRORTYPE omx_err   = OMX_ErrorNone;
347   std::string decoder_name;
348   m_settings_changed = false;
349   m_setStartTime = true;
350
351   m_res_ctx           = NULL;
352   m_res_callback      = NULL;
353
354   m_video_codec_name      = "";
355   m_codingType            = OMX_VIDEO_CodingUnused;
356
357   m_decoded_width  = hints.width;
358   m_decoded_height = hints.height;
359
360   m_hdmi_clock_sync = hdmi_clock_sync;
361   m_submitted_eos = false;
362   m_failed_eos    = false;
363
364   if(hints.extrasize > 0 && hints.extradata != NULL)
365   {
366     m_extrasize = hints.extrasize;
367     m_extradata = (uint8_t *)malloc(m_extrasize);
368     memcpy(m_extradata, hints.extradata, hints.extrasize);
369   }
370
371   switch (hints.codec)
372   {
373     case AV_CODEC_ID_H264:
374     {
375       switch(hints.profile)
376       {
377         case FF_PROFILE_H264_BASELINE:
378           // (role name) video_decoder.avc
379           // H.264 Baseline profile
380           decoder_name = OMX_H264BASE_DECODER;
381           m_codingType = OMX_VIDEO_CodingAVC;
382           m_video_codec_name = "omx-h264";
383           break;
384         case FF_PROFILE_H264_MAIN:
385           // (role name) video_decoder.avc
386           // H.264 Main profile
387           decoder_name = OMX_H264MAIN_DECODER;
388           m_codingType = OMX_VIDEO_CodingAVC;
389           m_video_codec_name = "omx-h264";
390           break;
391         case FF_PROFILE_H264_HIGH:
392           // (role name) video_decoder.avc
393           // H.264 Main profile
394           decoder_name = OMX_H264HIGH_DECODER;
395           m_codingType = OMX_VIDEO_CodingAVC;
396           m_video_codec_name = "omx-h264";
397           break;
398         case FF_PROFILE_UNKNOWN:
399           decoder_name = OMX_H264HIGH_DECODER;
400           m_codingType = OMX_VIDEO_CodingAVC;
401           m_video_codec_name = "omx-h264";
402           break;
403         default:
404           decoder_name = OMX_H264HIGH_DECODER;
405           m_codingType = OMX_VIDEO_CodingAVC;
406           m_video_codec_name = "omx-h264";
407           break;
408       }
409     }
410     break;
411     case AV_CODEC_ID_MPEG4:
412       // (role name) video_decoder.mpeg4
413       // MPEG-4, DivX 4/5 and Xvid compatible
414       decoder_name = OMX_MPEG4_DECODER;
415       m_codingType = OMX_VIDEO_CodingMPEG4;
416       m_video_codec_name = "omx-mpeg4";
417       break;
418     case AV_CODEC_ID_MPEG1VIDEO:
419     case AV_CODEC_ID_MPEG2VIDEO:
420       // (role name) video_decoder.mpeg2
421       // MPEG-2
422       decoder_name = OMX_MPEG2V_DECODER;
423       m_codingType = OMX_VIDEO_CodingMPEG2;
424       m_video_codec_name = "omx-mpeg2";
425       break;
426     case AV_CODEC_ID_H263:
427       // (role name) video_decoder.mpeg4
428       // MPEG-4, DivX 4/5 and Xvid compatible
429       decoder_name = OMX_MPEG4_DECODER;
430       m_codingType = OMX_VIDEO_CodingMPEG4;
431       m_video_codec_name = "omx-h263";
432       break;
433     case AV_CODEC_ID_VP6:
434       // this form is encoded upside down
435       vflip = true;
436       // fall through
437     case AV_CODEC_ID_VP6F:
438     case AV_CODEC_ID_VP6A:
439       // (role name) video_decoder.vp6
440       // VP6
441       decoder_name = OMX_VP6_DECODER;
442       m_codingType = OMX_VIDEO_CodingVP6;
443       m_video_codec_name = "omx-vp6";
444     break;
445     case AV_CODEC_ID_VP8:
446       // (role name) video_decoder.vp8
447       // VP8
448       decoder_name = OMX_VP8_DECODER;
449       m_codingType = OMX_VIDEO_CodingVP8;
450       m_video_codec_name = "omx-vp8";
451     break;
452     case AV_CODEC_ID_THEORA:
453       // (role name) video_decoder.theora
454       // theora
455       decoder_name = OMX_THEORA_DECODER;
456       m_codingType = OMX_VIDEO_CodingTheora;
457       m_video_codec_name = "omx-theora";
458     break;
459     case AV_CODEC_ID_MJPEG:
460     case AV_CODEC_ID_MJPEGB:
461       // (role name) video_decoder.mjpg
462       // mjpg
463       decoder_name = OMX_MJPEG_DECODER;
464       m_codingType = OMX_VIDEO_CodingMJPEG;
465       m_video_codec_name = "omx-mjpeg";
466     break;
467     case AV_CODEC_ID_VC1:
468     case AV_CODEC_ID_WMV3:
469       // (role name) video_decoder.vc1
470       // VC-1, WMV9
471       decoder_name = OMX_VC1_DECODER;
472       m_codingType = OMX_VIDEO_CodingWMV;
473       m_video_codec_name = "omx-vc1";
474       break;
475     default:
476       CLog::Log(LOGERROR, "COMXVideo::Open : Video codec unknown: %x", hints.codec);
477       return false;
478     break;
479   }
480   m_deinterlace_request = deinterlace;
481
482   if(!m_omx_decoder.Initialize(decoder_name, OMX_IndexParamVideoInit))
483     return false;
484
485   if(clock == NULL)
486     return false;
487
488   m_av_clock = clock;
489   m_omx_clock = m_av_clock->GetOMXClock();
490
491   if(m_omx_clock->GetComponent() == NULL)
492   {
493     m_av_clock = NULL;
494     m_omx_clock = NULL;
495     return false;
496   }
497
498   omx_err = m_omx_decoder.SetStateForComponent(OMX_StateIdle);
499   if (omx_err != OMX_ErrorNone)
500   {
501     CLog::Log(LOGERROR, "COMXVideo::Open m_omx_decoder.SetStateForComponent\n");
502     return false;
503   }
504
505   OMX_VIDEO_PARAM_PORTFORMATTYPE formatType;
506   OMX_INIT_STRUCTURE(formatType);
507   formatType.nPortIndex = m_omx_decoder.GetInputPort();
508   formatType.eCompressionFormat = m_codingType;
509
510   if (hints.fpsscale > 0 && hints.fpsrate > 0)
511   {
512     formatType.xFramerate = (long long)(1<<16)*hints.fpsrate / hints.fpsscale;
513   }
514   else
515   {
516     formatType.xFramerate = 25 * (1<<16);
517   }
518
519   omx_err = m_omx_decoder.SetParameter(OMX_IndexParamVideoPortFormat, &formatType);
520   if(omx_err != OMX_ErrorNone)
521     return false;
522   
523   OMX_PARAM_PORTDEFINITIONTYPE portParam;
524   OMX_INIT_STRUCTURE(portParam);
525   portParam.nPortIndex = m_omx_decoder.GetInputPort();
526
527   omx_err = m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition, &portParam);
528   if(omx_err != OMX_ErrorNone)
529   {
530     CLog::Log(LOGERROR, "COMXVideo::Open error OMX_IndexParamPortDefinition omx_err(0x%08x)\n", omx_err);
531     return false;
532   }
533
534   portParam.nPortIndex = m_omx_decoder.GetInputPort();
535   bool small_mem = g_RBP.GetArmMem() < 256;
536   portParam.nBufferCountActual = small_mem ? VIDEO_BUFFERS:2*VIDEO_BUFFERS;
537   portParam.format.video.nFrameWidth  = m_decoded_width;
538   portParam.format.video.nFrameHeight = m_decoded_height;
539
540   omx_err = m_omx_decoder.SetParameter(OMX_IndexParamPortDefinition, &portParam);
541   if(omx_err != OMX_ErrorNone)
542   {
543     CLog::Log(LOGERROR, "COMXVideo::Open error OMX_IndexParamPortDefinition omx_err(0x%08x)\n", omx_err);
544     return false;
545   }
546
547   // request portsettingschanged on aspect ratio change
548   OMX_CONFIG_REQUESTCALLBACKTYPE notifications;
549   OMX_INIT_STRUCTURE(notifications);
550   notifications.nPortIndex = m_omx_decoder.GetOutputPort();
551   notifications.nIndex = OMX_IndexParamBrcmPixelAspectRatio;
552   notifications.bEnable = OMX_TRUE;
553
554   omx_err = m_omx_decoder.SetParameter((OMX_INDEXTYPE)OMX_IndexConfigRequestCallback, &notifications);
555   if (omx_err != OMX_ErrorNone)
556   {
557     CLog::Log(LOGERROR, "COMXVideo::Open OMX_IndexConfigRequestCallback error (0%08x)\n", omx_err);
558     return false;
559   }
560
561   OMX_PARAM_BRCMVIDEODECODEERRORCONCEALMENTTYPE concanParam;
562   OMX_INIT_STRUCTURE(concanParam);
563   if(g_advancedSettings.m_omxDecodeStartWithValidFrame)
564     concanParam.bStartWithValidFrame = OMX_TRUE;
565   else
566     concanParam.bStartWithValidFrame = OMX_FALSE;
567
568   omx_err = m_omx_decoder.SetParameter(OMX_IndexParamBrcmVideoDecodeErrorConcealment, &concanParam);
569   if(omx_err != OMX_ErrorNone)
570   {
571     CLog::Log(LOGERROR, "COMXVideo::Open error OMX_IndexParamBrcmVideoDecodeErrorConcealment omx_err(0x%08x)\n", omx_err);
572     return false;
573   }
574
575   if (m_deinterlace_request != VS_DEINTERLACEMODE_OFF)
576   {
577     // the deinterlace component requires 3 additional video buffers in addition to the DPB (this is normally 2).
578     OMX_PARAM_U32TYPE extra_buffers;
579     OMX_INIT_STRUCTURE(extra_buffers);
580     extra_buffers.nU32 = 3;
581
582     omx_err = m_omx_decoder.SetParameter(OMX_IndexParamBrcmExtraBuffers, &extra_buffers);
583     if(omx_err != OMX_ErrorNone)
584     {
585       CLog::Log(LOGERROR, "COMXVideo::Open error OMX_IndexParamBrcmExtraBuffers omx_err(0x%08x)\n", omx_err);
586       return false;
587     }
588   }
589
590
591   // broadcom omx entension:
592   // When enabled, the timestamp fifo mode will change the way incoming timestamps are associated with output images.
593   // In this mode the incoming timestamps get used without re-ordering on output images.
594   if(hints.ptsinvalid)
595   {
596     OMX_CONFIG_BOOLEANTYPE timeStampMode;
597     OMX_INIT_STRUCTURE(timeStampMode);
598     timeStampMode.bEnabled = OMX_TRUE;
599
600     omx_err = m_omx_decoder.SetParameter((OMX_INDEXTYPE)OMX_IndexParamBrcmVideoTimestampFifo, &timeStampMode);
601     if (omx_err != OMX_ErrorNone)
602     {
603       CLog::Log(LOGERROR, "COMXVideo::Open OMX_IndexParamBrcmVideoTimestampFifo error (0%08x)\n", omx_err);
604       return false;
605     }
606   }
607
608   if(NaluFormatStartCodes(hints.codec, m_extradata, m_extrasize))
609   {
610     OMX_NALSTREAMFORMATTYPE nalStreamFormat;
611     OMX_INIT_STRUCTURE(nalStreamFormat);
612     nalStreamFormat.nPortIndex = m_omx_decoder.GetInputPort();
613     nalStreamFormat.eNaluFormat = OMX_NaluFormatStartCodes;
614
615     omx_err = m_omx_decoder.SetParameter((OMX_INDEXTYPE)OMX_IndexParamNalStreamFormatSelect, &nalStreamFormat);
616     if (omx_err != OMX_ErrorNone)
617     {
618       CLog::Log(LOGERROR, "COMXVideo::Open OMX_IndexParamNalStreamFormatSelect error (0%08x)\n", omx_err);
619       return false;
620     }
621   }
622
623
624   // Alloc buffers for the omx intput port.
625   omx_err = m_omx_decoder.AllocInputBuffers();
626   if (omx_err != OMX_ErrorNone)
627   {
628     CLog::Log(LOGERROR, "COMXVideo::Open AllocOMXInputBuffers error (0%08x)\n", omx_err);
629     return false;
630   }
631
632   omx_err = m_omx_decoder.SetStateForComponent(OMX_StateExecuting);
633   if (omx_err != OMX_ErrorNone)
634   {
635     CLog::Log(LOGERROR, "COMXVideo::Open error m_omx_decoder.SetStateForComponent\n");
636     return false;
637   }
638
639   if(!SendDecoderConfig())
640     return false;
641
642   m_is_open           = true;
643   m_drop_state        = false;
644
645   switch(hints.orientation)
646   {
647     case 90:
648       m_transform = OMX_DISPLAY_ROT90;
649       break;
650     case 180:
651       m_transform = OMX_DISPLAY_ROT180;
652       break;
653     case 270:
654       m_transform = OMX_DISPLAY_ROT270;
655       break;
656     default:
657       m_transform = OMX_DISPLAY_ROT0;
658       break;
659   }
660   if (vflip)
661       m_transform = OMX_DISPLAY_MIRROR_ROT180;
662
663   if(m_omx_decoder.BadState())
664     return false;
665
666   CLog::Log(LOGDEBUG,
667     "%s::%s - decoder_component(0x%p), input_port(0x%x), output_port(0x%x) deinterlace %d hdmiclocksync %d\n",
668     CLASSNAME, __func__, m_omx_decoder.GetComponent(), m_omx_decoder.GetInputPort(), m_omx_decoder.GetOutputPort(),
669     m_deinterlace_request, m_hdmi_clock_sync);
670
671   return true;
672 }
673
674
675 void COMXVideo::Close()
676 {
677   CSingleLock lock (m_critSection);
678   m_omx_tunnel_clock.Deestablish();
679   m_omx_tunnel_decoder.Deestablish();
680   if(m_deinterlace)
681     m_omx_tunnel_image_fx.Deestablish();
682   m_omx_tunnel_sched.Deestablish();
683
684   m_omx_decoder.FlushInput();
685
686   m_omx_sched.Deinitialize();
687   m_omx_decoder.Deinitialize();
688   if(m_deinterlace)
689     m_omx_image_fx.Deinitialize();
690   m_omx_render.Deinitialize();
691
692   m_is_open       = false;
693
694   if(m_extradata)
695     free(m_extradata);
696   m_extradata = NULL;
697   m_extrasize = 0;
698
699   m_video_codec_name  = "";
700   m_deinterlace       = false;
701   m_av_clock          = NULL;
702
703   m_res_ctx           = NULL;
704   m_res_callback      = NULL;
705 }
706
707 void COMXVideo::SetDropState(bool bDrop)
708 {
709   m_drop_state = bDrop;
710 }
711
712 unsigned int COMXVideo::GetFreeSpace()
713 {
714   CSingleLock lock (m_critSection);
715   return m_omx_decoder.GetInputBufferSpace();
716 }
717
718 unsigned int COMXVideo::GetSize()
719 {
720   CSingleLock lock (m_critSection);
721   return m_omx_decoder.GetInputBufferSize();
722 }
723
724 int COMXVideo::Decode(uint8_t *pData, int iSize, double pts)
725 {
726   CSingleLock lock (m_critSection);
727   OMX_ERRORTYPE omx_err;
728
729   if( m_drop_state || !m_is_open )
730     return true;
731
732   unsigned int demuxer_bytes = (unsigned int)iSize;
733   uint8_t *demuxer_content = pData;
734
735   if (demuxer_content && demuxer_bytes > 0)
736   {
737     while(demuxer_bytes)
738     {
739       // 500ms timeout
740       OMX_BUFFERHEADERTYPE *omx_buffer = m_omx_decoder.GetInputBuffer(500);
741       if(omx_buffer == NULL)
742       {
743         CLog::Log(LOGERROR, "OMXVideo::Decode timeout\n");
744         return false;
745       }
746
747       omx_buffer->nFlags = 0;
748       omx_buffer->nOffset = 0;
749
750       if(m_setStartTime)
751       {
752         omx_buffer->nFlags |= OMX_BUFFERFLAG_STARTTIME;
753         CLog::Log(LOGDEBUG, "OMXVideo::Decode VDec : setStartTime %f\n", (pts == DVD_NOPTS_VALUE ? 0.0 : pts) / DVD_TIME_BASE);
754         m_setStartTime = false;
755       }
756       if(pts == DVD_NOPTS_VALUE)
757         omx_buffer->nFlags |= OMX_BUFFERFLAG_TIME_UNKNOWN;
758
759       omx_buffer->nTimeStamp = ToOMXTime((uint64_t)(pts == DVD_NOPTS_VALUE) ? 0 : pts);
760       omx_buffer->nFilledLen = (demuxer_bytes > omx_buffer->nAllocLen) ? omx_buffer->nAllocLen : demuxer_bytes;
761       memcpy(omx_buffer->pBuffer, demuxer_content, omx_buffer->nFilledLen);
762
763       demuxer_bytes -= omx_buffer->nFilledLen;
764       demuxer_content += omx_buffer->nFilledLen;
765
766       if(demuxer_bytes == 0)
767         omx_buffer->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME;
768
769       int nRetry = 0;
770       while(true)
771       {
772         omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer);
773         if (omx_err == OMX_ErrorNone)
774         {
775           //CLog::Log(LOGINFO, "VideD: dts:%.0f pts:%.0f size:%d)\n", dts, pts, iSize);
776           break;
777         }
778         else
779         {
780           CLog::Log(LOGERROR, "%s::%s - OMX_EmptyThisBuffer() failed with result(0x%x)\n", CLASSNAME, __func__, omx_err);
781           nRetry++;
782         }
783         if(nRetry == 5)
784         {
785           CLog::Log(LOGERROR, "%s::%s - OMX_EmptyThisBuffer() finally failed\n", CLASSNAME, __func__);
786           return false;
787         }
788       }
789
790       omx_err = m_omx_decoder.WaitForEvent(OMX_EventPortSettingsChanged, 0);
791       if (omx_err == OMX_ErrorNone)
792       {
793         if(!PortSettingsChanged())
794         {
795           CLog::Log(LOGERROR, "%s::%s - error PortSettingsChanged omx_err(0x%08x)\n", CLASSNAME, __func__, omx_err);
796           return false;
797         }
798       }
799       omx_err = m_omx_decoder.WaitForEvent(OMX_EventParamOrConfigChanged, 0);
800       if (omx_err == OMX_ErrorNone)
801       {
802         if(!PortSettingsChanged())
803         {
804           CLog::Log(LOGERROR, "%s::%s - error PortSettingsChanged (EventParamOrConfigChanged) omx_err(0x%08x)\n", CLASSNAME, __func__, omx_err);
805         }
806       }
807     }
808     return true;
809
810   }
811   
812   return false;
813 }
814
815 void COMXVideo::Reset(void)
816 {
817   CSingleLock lock (m_critSection);
818   if(!m_is_open)
819     return;
820
821   m_setStartTime = true;
822   m_omx_decoder.FlushInput();
823   if(m_deinterlace)
824     m_omx_image_fx.FlushInput();
825 }
826
827 ///////////////////////////////////////////////////////////////////////////////////////////
828 void COMXVideo::SetVideoRect(const CRect& SrcRect, const CRect& DestRect)
829 {
830   CSingleLock lock (m_critSection);
831   if(!m_is_open)
832     return;
833
834   OMX_CONFIG_DISPLAYREGIONTYPE configDisplay;
835
836   OMX_INIT_STRUCTURE(configDisplay);
837   configDisplay.nPortIndex = m_omx_render.GetInputPort();
838   configDisplay.fullscreen = OMX_FALSE;
839   configDisplay.noaspect   = OMX_TRUE;
840
841   configDisplay.set                 = (OMX_DISPLAYSETTYPE)(OMX_DISPLAY_SET_DEST_RECT|OMX_DISPLAY_SET_SRC_RECT|OMX_DISPLAY_SET_FULLSCREEN|OMX_DISPLAY_SET_NOASPECT);
842   configDisplay.dest_rect.x_offset  = (int)(DestRect.x1+0.5f);
843   configDisplay.dest_rect.y_offset  = (int)(DestRect.y1+0.5f);
844   configDisplay.dest_rect.width     = (int)(DestRect.Width()+0.5f);
845   configDisplay.dest_rect.height    = (int)(DestRect.Height()+0.5f);
846
847   configDisplay.src_rect.x_offset   = (int)(SrcRect.x1+0.5f);
848   configDisplay.src_rect.y_offset   = (int)(SrcRect.y1+0.5f);
849   configDisplay.src_rect.width      = (int)(SrcRect.Width()+0.5f);
850   configDisplay.src_rect.height     = (int)(SrcRect.Height()+0.5f);
851
852   configDisplay.fullscreen          = configDisplay.dest_rect.width == 0 || configDisplay.dest_rect.width == 0 ? OMX_TRUE : OMX_FALSE;
853
854   m_omx_render.SetConfig(OMX_IndexConfigDisplayRegion, &configDisplay);
855
856   CLog::Log(LOGDEBUG, "dest_rect.x_offset %d dest_rect.y_offset %d dest_rect.width %d dest_rect.height %d\n",
857       configDisplay.dest_rect.x_offset, configDisplay.dest_rect.y_offset, 
858       configDisplay.dest_rect.width, configDisplay.dest_rect.height);
859 }
860
861 int COMXVideo::GetInputBufferSize()
862 {
863   CSingleLock lock (m_critSection);
864   return m_omx_decoder.GetInputBufferSize();
865 }
866
867 void COMXVideo::SubmitEOS()
868 {
869   CSingleLock lock (m_critSection);
870   if(!m_is_open)
871     return;
872
873   m_submitted_eos = true;
874   m_failed_eos = false;
875
876   OMX_ERRORTYPE omx_err = OMX_ErrorNone;
877   OMX_BUFFERHEADERTYPE *omx_buffer = m_omx_decoder.GetInputBuffer(1000);
878   
879   if(omx_buffer == NULL)
880   {
881     CLog::Log(LOGERROR, "%s::%s - buffer error 0x%08x", CLASSNAME, __func__, omx_err);
882     m_failed_eos = true;
883     return;
884   }
885   
886   omx_buffer->nOffset     = 0;
887   omx_buffer->nFilledLen  = 0;
888   omx_buffer->nTimeStamp  = ToOMXTime(0LL);
889
890   omx_buffer->nFlags = OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_EOS | OMX_BUFFERFLAG_TIME_UNKNOWN;
891   
892   omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer);
893   if (omx_err != OMX_ErrorNone)
894   {
895     CLog::Log(LOGERROR, "%s::%s - OMX_EmptyThisBuffer() failed with result(0x%x)\n", CLASSNAME, __func__, omx_err);
896     return;
897   }
898   CLog::Log(LOGINFO, "%s::%s", CLASSNAME, __func__);
899 }
900
901 bool COMXVideo::IsEOS()
902 {
903   CSingleLock lock (m_critSection);
904   if(!m_is_open)
905     return true;
906   if (!m_failed_eos && !m_omx_render.IsEOS())
907     return false;
908   if (m_submitted_eos)
909   {
910     CLog::Log(LOGINFO, "%s::%s", CLASSNAME, __func__);
911     m_submitted_eos = false;
912   }
913   return true;
914 }