2 * Copyright (C) 2010-2012 Team XBMC
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)
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.
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/>.
21 #if (defined HAVE_CONFIG_H) && (!defined WIN32)
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"
44 #define CLASSNAME "COMXVideo"
47 // TODO: These are Nvidia Tegra2 dependent, need to dynamiclly find the
48 // right codec matched to video format.
49 #define OMX_H264BASE_DECODER "OMX.Nvidia.h264.decode"
50 // OMX.Nvidia.h264ext.decode segfaults, not sure why.
51 //#define OMX_H264MAIN_DECODER "OMX.Nvidia.h264ext.decode"
52 #define OMX_H264MAIN_DECODER "OMX.Nvidia.h264.decode"
53 #define OMX_H264HIGH_DECODER "OMX.Nvidia.h264ext.decode"
54 #define OMX_MPEG4_DECODER "OMX.Nvidia.mp4.decode"
55 #define OMX_MPEG4EXT_DECODER "OMX.Nvidia.mp4ext.decode"
56 #define OMX_MPEG2V_DECODER "OMX.Nvidia.mpeg2v.decode"
57 #define OMX_VC1_DECODER "OMX.Nvidia.vc1.decode"
60 #define OMX_VIDEO_DECODER "OMX.broadcom.video_decode"
61 #define OMX_H264BASE_DECODER OMX_VIDEO_DECODER
62 #define OMX_H264MAIN_DECODER OMX_VIDEO_DECODER
63 #define OMX_H264HIGH_DECODER OMX_VIDEO_DECODER
64 #define OMX_MPEG4_DECODER OMX_VIDEO_DECODER
65 #define OMX_MSMPEG4V1_DECODER OMX_VIDEO_DECODER
66 #define OMX_MSMPEG4V2_DECODER OMX_VIDEO_DECODER
67 #define OMX_MSMPEG4V3_DECODER OMX_VIDEO_DECODER
68 #define OMX_MPEG4EXT_DECODER OMX_VIDEO_DECODER
69 #define OMX_MPEG2V_DECODER OMX_VIDEO_DECODER
70 #define OMX_VC1_DECODER OMX_VIDEO_DECODER
71 #define OMX_WMV3_DECODER OMX_VIDEO_DECODER
72 #define OMX_VP8_DECODER OMX_VIDEO_DECODER
74 #define MAX_TEXT_LENGTH 1024
76 COMXVideo::COMXVideo()
82 m_video_convert = false;
83 m_video_codec_name = "";
84 m_deinterlace = false;
85 m_hdmi_clock_sync = false;
89 COMXVideo::~COMXVideo()
94 bool COMXVideo::SendDecoderConfig()
96 OMX_ERRORTYPE omx_err = OMX_ErrorNone;
98 /* send decoder config */
99 if(m_extrasize > 0 && m_extradata != NULL)
101 OMX_BUFFERHEADERTYPE *omx_buffer = m_omx_decoder.GetInputBuffer();
103 if(omx_buffer == NULL)
105 CLog::Log(LOGERROR, "%s::%s - buffer error 0x%08x", CLASSNAME, __func__, omx_err);
109 omx_buffer->nOffset = 0;
110 omx_buffer->nFilledLen = m_extrasize;
111 if(omx_buffer->nFilledLen > omx_buffer->nAllocLen)
113 CLog::Log(LOGERROR, "%s::%s - omx_buffer->nFilledLen > omx_buffer->nAllocLen", CLASSNAME, __func__);
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;
121 omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer);
122 if (omx_err != OMX_ErrorNone)
124 CLog::Log(LOGERROR, "%s::%s - OMX_EmptyThisBuffer() failed with result(0x%x)\n", CLASSNAME, __func__, omx_err);
131 bool COMXVideo::NaluFormatStartCodes(enum CodecID codec, uint8_t *in_extradata, int in_extrasize)
136 if (in_extrasize < 7 || in_extradata == NULL)
138 // valid avcC atom data always starts with the value 1 (version), otherwise annexb
139 else if ( *in_extradata != 1 )
146 bool COMXVideo::Open(CDVDStreamInfo &hints, OMXClock *clock, bool deinterlace, bool hdmi_clock_sync)
150 OMX_ERRORTYPE omx_err = OMX_ErrorNone;
151 std::string decoder_name;
153 m_video_codec_name = "";
154 m_codingType = OMX_VIDEO_CodingUnused;
156 m_decoded_width = hints.width;
157 m_decoded_height = hints.height;
159 m_hdmi_clock_sync = hdmi_clock_sync;
161 if(!m_decoded_width || !m_decoded_height)
164 if(hints.extrasize > 0 && hints.extradata != NULL)
166 m_extrasize = hints.extrasize;
167 m_extradata = (uint8_t *)malloc(m_extrasize);
168 memcpy(m_extradata, hints.extradata, hints.extrasize);
175 switch(hints.profile)
177 case FF_PROFILE_H264_BASELINE:
178 // (role name) video_decoder.avc
179 // H.264 Baseline profile
180 decoder_name = OMX_H264BASE_DECODER;
181 m_codingType = OMX_VIDEO_CodingAVC;
182 m_video_codec_name = "omx-h264";
184 case FF_PROFILE_H264_MAIN:
185 // (role name) video_decoder.avc
186 // H.264 Main profile
187 decoder_name = OMX_H264MAIN_DECODER;
188 m_codingType = OMX_VIDEO_CodingAVC;
189 m_video_codec_name = "omx-h264";
191 case FF_PROFILE_H264_HIGH:
192 // (role name) video_decoder.avc
193 // H.264 Main profile
194 decoder_name = OMX_H264HIGH_DECODER;
195 m_codingType = OMX_VIDEO_CodingAVC;
196 m_video_codec_name = "omx-h264";
198 case FF_PROFILE_UNKNOWN:
199 decoder_name = OMX_H264HIGH_DECODER;
200 m_codingType = OMX_VIDEO_CodingAVC;
201 m_video_codec_name = "omx-h264";
204 decoder_name = OMX_H264HIGH_DECODER;
205 m_codingType = OMX_VIDEO_CodingAVC;
206 m_video_codec_name = "omx-h264";
210 /* check interlaced */
211 if(m_extrasize > 9 && m_extradata[0] == 1)
213 CBitstreamConverter converter;
214 converter.Open(hints.codec, (uint8_t *)hints.extradata, hints.extrasize, true);
216 int32_t max_ref_frames = 0;
217 uint8_t *spc = m_extradata + 6;
218 uint32_t sps_size = BS_RB16(spc);
219 bool interlaced = true;
221 converter.parseh264_sps(spc+3, sps_size-1, &interlaced, &max_ref_frames);
222 if(!interlaced && deinterlace)
230 // (role name) video_decoder.mpeg4
231 // MPEG-4, DivX 4/5 and Xvid compatible
232 decoder_name = OMX_MPEG4_DECODER;
233 m_codingType = OMX_VIDEO_CodingMPEG4;
234 m_video_codec_name = "omx-mpeg4";
236 case CODEC_ID_MPEG1VIDEO:
237 case CODEC_ID_MPEG2VIDEO:
238 // (role name) video_decoder.mpeg2
240 decoder_name = OMX_MPEG2V_DECODER;
241 m_codingType = OMX_VIDEO_CodingMPEG2;
242 m_video_codec_name = "omx-mpeg2";
245 // (role name) video_decoder.mpeg4
246 // MPEG-4, DivX 4/5 and Xvid compatible
247 decoder_name = OMX_MPEG4_DECODER;
248 m_codingType = OMX_VIDEO_CodingMPEG4;
249 m_video_codec_name = "omx-h263";
252 // (role name) video_decoder.vp8
254 decoder_name = OMX_VP8_DECODER;
255 m_codingType = OMX_VIDEO_CodingVP8;
256 m_video_codec_name = "omx-vp8";
260 // (role name) video_decoder.vc1
262 decoder_name = OMX_VC1_DECODER;
263 m_codingType = OMX_VIDEO_CodingWMV;
264 m_video_codec_name = "omx-vc1";
271 /* enable deintelace on SD and 1080i */
272 if(m_decoded_width <= 720 && m_decoded_height <=576 && deinterlace)
273 m_deinterlace = deinterlace;
274 else if(m_decoded_width >= 1920 && m_decoded_height >= 540 && deinterlace)
275 m_deinterlace = deinterlace;
278 CLog::Log(LOGDEBUG, "COMXVideo::Open : enable deinterlace\n");
280 std::string componentName = "";
282 componentName = decoder_name;
283 if(!m_omx_decoder.Initialize((const std::string)componentName, OMX_IndexParamVideoInit))
286 componentName = "OMX.broadcom.video_render";
287 if(!m_omx_render.Initialize((const std::string)componentName, OMX_IndexParamVideoInit))
290 componentName = "OMX.broadcom.video_scheduler";
291 if(!m_omx_sched.Initialize((const std::string)componentName, OMX_IndexParamVideoInit))
296 componentName = "OMX.broadcom.image_fx";
297 if(!m_omx_image_fx.Initialize((const std::string)componentName, OMX_IndexParamImageInit))
301 OMX_VIDEO_PARAM_PORTFORMATTYPE formatType;
303 OMX_INIT_STRUCTURE(formatType);
304 formatType.nPortIndex = m_omx_decoder.GetInputPort();
308 omx_err = OMX_ErrorNone;
311 formatType.nIndex = nIndex;
312 omx_err = m_omx_decoder.GetParameter(OMX_IndexParamVideoPortFormat, &formatType);
313 if(formatType.eCompressionFormat == m_codingType)
320 while(omx_err == OMX_ErrorNone);
324 CLog::Log(LOGINFO, "COMXVideo::Open coding : %s not supported\n", m_video_codec_name.c_str());
333 m_omx_clock = m_av_clock->GetOMXClock();
335 if(m_omx_clock->GetComponent() == NULL)
344 m_omx_tunnel_decoder.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_image_fx, m_omx_image_fx.GetInputPort());
345 m_omx_tunnel_image_fx.Initialize(&m_omx_image_fx, m_omx_image_fx.GetOutputPort(), &m_omx_sched, m_omx_sched.GetInputPort());
349 m_omx_tunnel_decoder.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_sched, m_omx_sched.GetInputPort());
351 m_omx_tunnel_sched.Initialize(&m_omx_sched, m_omx_sched.GetOutputPort(), &m_omx_render, m_omx_render.GetInputPort());
353 m_omx_tunnel_clock.Initialize(m_omx_clock, m_omx_clock->GetInputPort() + 1, &m_omx_sched, m_omx_sched.GetOutputPort() + 1);
355 omx_err = m_omx_tunnel_clock.Establish(false);
356 if(omx_err != OMX_ErrorNone)
358 CLog::Log(LOGERROR, "COMXVideo::Open m_omx_tunnel_clock.Establish\n");
362 omx_err = m_omx_decoder.SetStateForComponent(OMX_StateIdle);
363 if (omx_err != OMX_ErrorNone)
365 CLog::Log(LOGERROR, "COMXVideo::Open m_omx_decoder.SetStateForComponent\n");
369 OMX_INIT_STRUCTURE(formatType);
370 formatType.nPortIndex = m_omx_decoder.GetInputPort();
371 formatType.eCompressionFormat = m_codingType;
373 if (hints.fpsscale > 0 && hints.fpsrate > 0)
375 formatType.xFramerate = (long long)(1<<16)*hints.fpsrate / hints.fpsscale;
379 formatType.xFramerate = 25 * (1<<16);
382 omx_err = m_omx_decoder.SetParameter(OMX_IndexParamVideoPortFormat, &formatType);
383 if(omx_err != OMX_ErrorNone)
386 OMX_PARAM_PORTDEFINITIONTYPE portParam;
387 OMX_INIT_STRUCTURE(portParam);
388 portParam.nPortIndex = m_omx_decoder.GetInputPort();
390 omx_err = m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition, &portParam);
391 if(omx_err != OMX_ErrorNone)
393 CLog::Log(LOGERROR, "COMXVideo::Open error OMX_IndexParamPortDefinition omx_err(0x%08x)\n", omx_err);
397 portParam.nPortIndex = m_omx_decoder.GetInputPort();
398 portParam.nBufferCountActual = VIDEO_BUFFERS;
400 portParam.format.video.nFrameWidth = m_decoded_width;
401 portParam.format.video.nFrameHeight = m_decoded_height;
403 omx_err = m_omx_decoder.SetParameter(OMX_IndexParamPortDefinition, &portParam);
404 if(omx_err != OMX_ErrorNone)
406 CLog::Log(LOGERROR, "COMXVideo::Open error OMX_IndexParamPortDefinition omx_err(0x%08x)\n", omx_err);
410 OMX_PARAM_BRCMVIDEODECODEERRORCONCEALMENTTYPE concanParam;
411 OMX_INIT_STRUCTURE(concanParam);
412 if(g_advancedSettings.m_omxDecodeStartWithValidFrame)
413 concanParam.bStartWithValidFrame = OMX_TRUE;
415 concanParam.bStartWithValidFrame = OMX_FALSE;
417 omx_err = m_omx_decoder.SetParameter(OMX_IndexParamBrcmVideoDecodeErrorConcealment, &concanParam);
418 if(omx_err != OMX_ErrorNone)
420 CLog::Log(LOGERROR, "COMXVideo::Open error OMX_IndexParamBrcmVideoDecodeErrorConcealment omx_err(0x%08x)\n", omx_err);
426 // the deinterlace component requires 3 additional video buffers in addition to the DPB (this is normally 2).
427 OMX_PARAM_U32TYPE extra_buffers;
428 OMX_INIT_STRUCTURE(extra_buffers);
429 extra_buffers.nU32 = 3;
431 omx_err = m_omx_decoder.SetParameter(OMX_IndexParamBrcmExtraBuffers, &extra_buffers);
432 if(omx_err != OMX_ErrorNone)
434 CLog::Log(LOGERROR, "COMXVideo::Open error OMX_IndexParamBrcmExtraBuffers omx_err(0x%08x)\n", omx_err);
439 // broadcom omx entension:
440 // When enabled, the timestamp fifo mode will change the way incoming timestamps are associated with output images.
441 // In this mode the incoming timestamps get used without re-ordering on output images.
444 OMX_CONFIG_BOOLEANTYPE timeStampMode;
445 OMX_INIT_STRUCTURE(timeStampMode);
446 timeStampMode.bEnabled = OMX_TRUE;
448 omx_err = m_omx_decoder.SetParameter((OMX_INDEXTYPE)OMX_IndexParamBrcmVideoTimestampFifo, &timeStampMode);
449 if (omx_err != OMX_ErrorNone)
451 CLog::Log(LOGERROR, "COMXVideo::Open OMX_IndexParamBrcmVideoTimestampFifo error (0%08x)\n", omx_err);
456 if(NaluFormatStartCodes(hints.codec, m_extradata, m_extrasize))
458 OMX_NALSTREAMFORMATTYPE nalStreamFormat;
459 OMX_INIT_STRUCTURE(nalStreamFormat);
460 nalStreamFormat.nPortIndex = m_omx_decoder.GetInputPort();
461 nalStreamFormat.eNaluFormat = OMX_NaluFormatStartCodes;
463 omx_err = m_omx_decoder.SetParameter((OMX_INDEXTYPE)OMX_IndexParamNalStreamFormatSelect, &nalStreamFormat);
464 if (omx_err != OMX_ErrorNone)
466 CLog::Log(LOGERROR, "COMXVideo::Open OMX_IndexParamNalStreamFormatSelect error (0%08x)\n", omx_err);
471 if(m_hdmi_clock_sync)
473 OMX_CONFIG_LATENCYTARGETTYPE latencyTarget;
474 OMX_INIT_STRUCTURE(latencyTarget);
475 latencyTarget.nPortIndex = m_omx_render.GetInputPort();
476 latencyTarget.bEnabled = OMX_TRUE;
477 latencyTarget.nFilter = 2;
478 latencyTarget.nTarget = 4000;
479 latencyTarget.nShift = 3;
480 latencyTarget.nSpeedFactor = -135;
481 latencyTarget.nInterFactor = 500;
482 latencyTarget.nAdjCap = 20;
484 omx_err = m_omx_render.SetConfig(OMX_IndexConfigLatencyTarget, &latencyTarget);
485 if (omx_err != OMX_ErrorNone)
487 CLog::Log(LOGERROR, "COMXVideo::Open OMX_IndexConfigLatencyTarget error (0%08x)\n", omx_err);
492 // Alloc buffers for the omx intput port.
493 omx_err = m_omx_decoder.AllocInputBuffers();
494 if (omx_err != OMX_ErrorNone)
496 CLog::Log(LOGERROR, "COMXVideo::Open AllocOMXInputBuffers error (0%08x)\n", omx_err);
500 omx_err = m_omx_tunnel_decoder.Establish(false);
501 if(omx_err != OMX_ErrorNone)
503 CLog::Log(LOGERROR, "COMXVideo::Open m_omx_tunnel_decoder.Establish\n");
507 omx_err = m_omx_decoder.SetStateForComponent(OMX_StateExecuting);
508 if (omx_err != OMX_ErrorNone)
510 CLog::Log(LOGERROR, "COMXVideo::Open error m_omx_decoder.SetStateForComponent\n");
516 OMX_CONFIG_IMAGEFILTERPARAMSTYPE image_filter;
517 OMX_INIT_STRUCTURE(image_filter);
519 image_filter.nPortIndex = m_omx_image_fx.GetOutputPort();
520 image_filter.nNumParams = 1;
521 image_filter.nParams[0] = 3;
522 image_filter.eImageFilter = OMX_ImageFilterDeInterlaceAdvanced;
524 omx_err = m_omx_image_fx.SetConfig(OMX_IndexConfigCommonImageFilterParameters, &image_filter);
525 if(omx_err != OMX_ErrorNone)
527 CLog::Log(LOGERROR, "COMXVideo::Open error OMX_IndexConfigCommonImageFilterParameters omx_err(0x%08x)\n", omx_err);
531 omx_err = m_omx_tunnel_image_fx.Establish(false);
532 if(omx_err != OMX_ErrorNone)
534 CLog::Log(LOGERROR, "COMXVideo::Open m_omx_tunnel_image_fx.Establish\n");
538 omx_err = m_omx_image_fx.SetStateForComponent(OMX_StateExecuting);
539 if (omx_err != OMX_ErrorNone)
541 CLog::Log(LOGERROR, "COMXVideo::Open error m_omx_image_fx.SetStateForComponent\n");
545 m_omx_image_fx.DisablePort(m_omx_image_fx.GetInputPort(), false);
546 m_omx_image_fx.DisablePort(m_omx_image_fx.GetOutputPort(), false);
549 omx_err = m_omx_tunnel_sched.Establish(false);
550 if(omx_err != OMX_ErrorNone)
552 CLog::Log(LOGERROR, "COMXVideo::Open m_omx_tunnel_sched.Establish\n");
556 omx_err = m_omx_sched.SetStateForComponent(OMX_StateExecuting);
557 if (omx_err != OMX_ErrorNone)
559 CLog::Log(LOGERROR, "COMXVideo::Open error m_omx_sched.SetStateForComponent\n");
563 omx_err = m_omx_render.SetStateForComponent(OMX_StateExecuting);
564 if (omx_err != OMX_ErrorNone)
566 CLog::Log(LOGERROR, "COMXVideo::Open error m_omx_render.SetStateForComponent\n");
570 if(!SendDecoderConfig())
574 m_drop_state = false;
576 OMX_CONFIG_DISPLAYREGIONTYPE configDisplay;
577 OMX_INIT_STRUCTURE(configDisplay);
578 configDisplay.nPortIndex = m_omx_render.GetInputPort();
580 configDisplay.set = OMX_DISPLAY_SET_TRANSFORM;
582 switch(hints.orientation)
585 configDisplay.transform = OMX_DISPLAY_ROT90;
588 configDisplay.transform = OMX_DISPLAY_ROT180;
591 configDisplay.transform = OMX_DISPLAY_ROT270;
594 configDisplay.transform = OMX_DISPLAY_ROT0;
598 omx_err = m_omx_render.SetConfig(OMX_IndexConfigDisplayRegion, &configDisplay);
599 if(omx_err != OMX_ErrorNone)
601 CLog::Log(LOGWARNING, "COMXVideo::Open could not set orientation : %d\n", hints.orientation);
605 configDisplay.set = OMX_DISPLAY_SET_LAYER;
606 configDisplay.layer = 2;
608 omx_err = m_omx_render.SetConfig(OMX_IndexConfigDisplayRegion, &configDisplay);
609 if(omx_err != OMX_ErrorNone)
612 configDisplay.set = OMX_DISPLAY_SET_DEST_RECT;
613 configDisplay.dest_rect.x_offset = 100;
614 configDisplay.dest_rect.y_offset = 100;
615 configDisplay.dest_rect.width = 640;
616 configDisplay.dest_rect.height = 480;
618 omx_err = m_omx_render.SetConfig(OMX_IndexConfigDisplayRegion, &configDisplay);
619 if(omx_err != OMX_ErrorNone)
622 configDisplay.set = OMX_DISPLAY_SET_TRANSFORM;
623 configDisplay.transform = OMX_DISPLAY_ROT180;
625 omx_err = m_omx_render.SetConfig(OMX_IndexConfigDisplayRegion, &configDisplay);
626 if(omx_err != OMX_ErrorNone)
629 configDisplay.set = OMX_DISPLAY_SET_FULLSCREEN;
630 configDisplay.fullscreen = OMX_FALSE;
632 omx_err = m_omx_render.SetConfig(OMX_IndexConfigDisplayRegion, &configDisplay);
633 if(omx_err != OMX_ErrorNone)
636 configDisplay.set = OMX_DISPLAY_SET_MODE;
637 configDisplay.mode = OMX_DISPLAY_MODE_FILL; //OMX_DISPLAY_MODE_LETTERBOX;
639 omx_err = m_omx_render.SetConfig(OMX_IndexConfigDisplayRegion, &configDisplay);
640 if(omx_err != OMX_ErrorNone)
643 configDisplay.set = OMX_DISPLAY_SET_LAYER;
644 configDisplay.layer = 1;
646 omx_err = m_omx_render.SetConfig(OMX_IndexConfigDisplayRegion, &configDisplay);
647 if(omx_err != OMX_ErrorNone)
650 configDisplay.set = OMX_DISPLAY_SET_ALPHA;
651 configDisplay.alpha = OMX_FALSE;
653 omx_err = m_omx_render.SetConfig(OMX_IndexConfigDisplayRegion, &configDisplay);
654 if(omx_err != OMX_ErrorNone)
659 if(m_omx_decoder.BadState())
663 "%s::%s - decoder_component(0x%p), input_port(0x%x), output_port(0x%x) deinterlace %d hdmiclocksync %d\n",
664 CLASSNAME, __func__, m_omx_decoder.GetComponent(), m_omx_decoder.GetInputPort(), m_omx_decoder.GetOutputPort(),
665 m_deinterlace, m_hdmi_clock_sync);
667 m_first_frame = true;
668 // start from assuming all recent frames had valid pts
669 m_history_valid_pts = ~0;
674 void COMXVideo::Close()
676 m_omx_tunnel_decoder.Flush();
678 m_omx_tunnel_image_fx.Flush();
679 m_omx_tunnel_clock.Flush();
680 m_omx_tunnel_sched.Flush();
682 m_omx_tunnel_clock.Deestablish();
683 m_omx_tunnel_decoder.Deestablish();
685 m_omx_tunnel_image_fx.Deestablish();
686 m_omx_tunnel_sched.Deestablish();
688 m_omx_decoder.FlushInput();
690 m_omx_sched.Deinitialize(true);
691 m_omx_decoder.Deinitialize(true);
693 m_omx_image_fx.Deinitialize(true);
694 m_omx_render.Deinitialize(true);
703 m_video_convert = false;
704 m_video_codec_name = "";
705 m_deinterlace = false;
706 m_first_frame = true;
710 void COMXVideo::SetDropState(bool bDrop)
712 m_drop_state = bDrop;
715 unsigned int COMXVideo::GetFreeSpace()
717 return m_omx_decoder.GetInputBufferSpace();
720 unsigned int COMXVideo::GetSize()
722 return m_omx_decoder.GetInputBufferSize();
725 static unsigned count_bits(int32_t value)
733 int COMXVideo::Decode(uint8_t *pData, int iSize, double dts, double pts)
735 OMX_ERRORTYPE omx_err;
740 unsigned int demuxer_bytes = (unsigned int)iSize;
741 uint8_t *demuxer_content = pData;
743 if (demuxer_content && demuxer_bytes > 0)
748 OMX_BUFFERHEADERTYPE *omx_buffer = m_omx_decoder.GetInputBuffer(500);
749 if(omx_buffer == NULL)
751 CLog::Log(LOGERROR, "OMXVideo::Decode timeout\n");
756 CLog::Log(DEBUG, "COMXVideo::Video VDec : pts %lld omx_buffer 0x%08x buffer 0x%08x number %d\n",
757 pts, omx_buffer, omx_buffer->pBuffer, (int)omx_buffer->pAppPrivate);
758 if(pts == DVD_NOPTS_VALUE)
760 CLog::Log(LOGDEBUG, "VDec : pts %f omx_buffer 0x%08x buffer 0x%08x number %d\n",
761 (float)pts / AV_TIME_BASE, (int)omx_buffer, (int)omx_buffer->pBuffer, (int)omx_buffer->pAppPrivate);
765 omx_buffer->nFlags = 0;
766 omx_buffer->nOffset = 0;
767 // some packed bitstream AVI files set almost all pts values to DVD_NOPTS_VALUE, but have a scattering of real pts values.
768 // the valid pts values match the dts values.
769 // if a stream has had more than 4 valid pts values in the last 16, the use UNKNOWN, otherwise use dts
770 m_history_valid_pts = (m_history_valid_pts << 1) | (pts != DVD_NOPTS_VALUE);
771 if(pts == DVD_NOPTS_VALUE && count_bits(m_history_valid_pts & 0xffff) < 4)
774 if(m_av_clock->VideoStart())
776 // only send dts on first frame to get nearly correct starttime
777 if(pts == DVD_NOPTS_VALUE)
779 if(pts == DVD_NOPTS_VALUE)
780 omx_buffer->nFlags |= OMX_BUFFERFLAG_TIME_UNKNOWN;
781 omx_buffer->nFlags = OMX_BUFFERFLAG_STARTTIME;
782 CLog::Log(LOGDEBUG, "OMXVideo::Decode VDec : setStartTime %f\n", (pts == DVD_NOPTS_VALUE ? 0.0 : pts) / DVD_TIME_BASE);
783 m_av_clock->VideoStart(false);
787 if(pts == DVD_NOPTS_VALUE)
788 omx_buffer->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN;
791 omx_buffer->nTimeStamp = ToOMXTime((uint64_t)(pts == DVD_NOPTS_VALUE) ? 0 : pts);
792 omx_buffer->nFilledLen = (demuxer_bytes > omx_buffer->nAllocLen) ? omx_buffer->nAllocLen : demuxer_bytes;
793 memcpy(omx_buffer->pBuffer, demuxer_content, omx_buffer->nFilledLen);
795 demuxer_bytes -= omx_buffer->nFilledLen;
796 demuxer_content += omx_buffer->nFilledLen;
798 if(demuxer_bytes == 0)
799 omx_buffer->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME;
804 omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer);
805 if (omx_err == OMX_ErrorNone)
811 CLog::Log(LOGERROR, "%s::%s - OMX_EmptyThisBuffer() failed with result(0x%x)\n", CLASSNAME, __func__, omx_err);
816 CLog::Log(LOGERROR, "%s::%s - OMX_EmptyThisBuffer() finaly failed\n", CLASSNAME, __func__);
821 if(m_first_frame && m_deinterlace)
823 OMX_PARAM_PORTDEFINITIONTYPE port_image;
824 OMX_INIT_STRUCTURE(port_image);
825 port_image.nPortIndex = m_omx_decoder.GetOutputPort();
827 omx_err = m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition, &port_image);
828 if(omx_err != OMX_ErrorNone)
829 CLog::Log(LOGERROR, "%s::%s - error OMX_IndexParamPortDefinition 1 omx_err(0x%08x)\n", CLASSNAME, __func__, omx_err);
831 /* we assume when the sizes equal we have the first decoded frame */
832 if(port_image.format.video.nFrameWidth == m_decoded_width && port_image.format.video.nFrameHeight == m_decoded_height)
834 m_first_frame = false;
836 omx_err = m_omx_decoder.WaitForEvent(OMX_EventPortSettingsChanged);
837 if(omx_err == OMX_ErrorStreamCorrupt)
839 CLog::Log(LOGERROR, "%s::%s - image not unsupported\n", CLASSNAME, __func__);
843 m_omx_decoder.DisablePort(m_omx_decoder.GetOutputPort(), false);
844 m_omx_sched.DisablePort(m_omx_sched.GetInputPort(), false);
848 m_omx_image_fx.DisablePort(m_omx_image_fx.GetOutputPort(), false);
849 m_omx_image_fx.DisablePort(m_omx_image_fx.GetInputPort(), false);
851 port_image.nPortIndex = m_omx_image_fx.GetInputPort();
852 omx_err = m_omx_image_fx.SetParameter(OMX_IndexParamPortDefinition, &port_image);
853 if(omx_err != OMX_ErrorNone)
854 CLog::Log(LOGERROR, "%s::%s - error OMX_IndexParamPortDefinition 2 omx_err(0x%08x)\n", CLASSNAME, __func__, omx_err);
856 port_image.nPortIndex = m_omx_image_fx.GetOutputPort();
857 omx_err = m_omx_image_fx.SetParameter(OMX_IndexParamPortDefinition, &port_image);
858 if(omx_err != OMX_ErrorNone)
859 CLog::Log(LOGERROR, "%s::%s - error OMX_IndexParamPortDefinition 3 omx_err(0x%08x)\n", CLASSNAME, __func__, omx_err);
862 m_omx_decoder.EnablePort(m_omx_decoder.GetOutputPort(), false);
866 m_omx_image_fx.EnablePort(m_omx_image_fx.GetOutputPort(), false);
867 m_omx_image_fx.EnablePort(m_omx_image_fx.GetInputPort(), false);
870 m_omx_sched.EnablePort(m_omx_sched.GetInputPort(), false);
882 void COMXVideo::Reset(void)
887 m_omx_decoder.FlushInput();
888 m_omx_tunnel_decoder.Flush();
891 OMX_ERRORTYPE omx_err;
892 OMX_CONFIG_BOOLEANTYPE configBool;
893 OMX_INIT_STRUCTURE(configBool);
894 configBool.bEnabled = OMX_TRUE;
896 omx_err = m_omx_decoder.SetConfig(OMX_IndexConfigRefreshCodec, &configBool);
897 if (omx_err != OMX_ErrorNone)
898 CLog::Log(LOGERROR, "%s::%s - error reopen codec omx_err(0x%08x)\n", CLASSNAME, __func__, omx_err);
902 m_first_frame = true;
906 ///////////////////////////////////////////////////////////////////////////////////////////
907 bool COMXVideo::Pause()
909 if(m_omx_render.GetComponent() == NULL)
912 if(m_Pause) return true;
915 m_omx_sched.SetStateForComponent(OMX_StatePause);
916 m_omx_render.SetStateForComponent(OMX_StatePause);
921 ///////////////////////////////////////////////////////////////////////////////////////////
922 bool COMXVideo::Resume()
924 if(m_omx_render.GetComponent() == NULL)
927 if(!m_Pause) return true;
930 m_omx_sched.SetStateForComponent(OMX_StateExecuting);
931 m_omx_render.SetStateForComponent(OMX_StateExecuting);
936 ///////////////////////////////////////////////////////////////////////////////////////////
937 void COMXVideo::SetVideoRect(const CRect& SrcRect, const CRect& DestRect)
942 OMX_CONFIG_DISPLAYREGIONTYPE configDisplay;
943 float sx1 = SrcRect.x1, sy1 = SrcRect.y1, sx2 = SrcRect.x2, sy2 = SrcRect.y2;
944 float dx1 = DestRect.x1, dy1 = DestRect.y1, dx2 = DestRect.x2, dy2 = DestRect.y2;
945 float sw = SrcRect.Width() / DestRect.Width();
946 float sh = SrcRect.Height() / DestRect.Height();
948 // doesn't like negative coordinates on dest_rect. So adjust by increasing src_rect
958 OMX_INIT_STRUCTURE(configDisplay);
959 configDisplay.nPortIndex = m_omx_render.GetInputPort();
960 configDisplay.fullscreen = OMX_FALSE;
961 configDisplay.noaspect = OMX_TRUE;
963 configDisplay.set = (OMX_DISPLAYSETTYPE)(OMX_DISPLAY_SET_DEST_RECT|OMX_DISPLAY_SET_SRC_RECT|OMX_DISPLAY_SET_FULLSCREEN|OMX_DISPLAY_SET_NOASPECT);
964 configDisplay.dest_rect.x_offset = (int)(dx1+0.5f);
965 configDisplay.dest_rect.y_offset = (int)(dy1+0.5f);
966 configDisplay.dest_rect.width = (int)(dx2-dx1+0.5f);
967 configDisplay.dest_rect.height = (int)(dy2-dy1+0.5f);
969 configDisplay.src_rect.x_offset = (int)(sx1+0.5f);
970 configDisplay.src_rect.y_offset = (int)(sy1+0.5f);
971 configDisplay.src_rect.width = (int)(sx2-sx1+0.5f);
972 configDisplay.src_rect.height = (int)(sy2-sy1+0.5f);
974 m_omx_render.SetConfig(OMX_IndexConfigDisplayRegion, &configDisplay);
976 CLog::Log(LOGDEBUG, "dest_rect.x_offset %d dest_rect.y_offset %d dest_rect.width %d dest_rect.height %d\n",
977 configDisplay.dest_rect.x_offset, configDisplay.dest_rect.y_offset,
978 configDisplay.dest_rect.width, configDisplay.dest_rect.height);
981 int COMXVideo::GetInputBufferSize()
983 return m_omx_decoder.GetInputBufferSize();
986 void COMXVideo::WaitCompletion()
991 OMX_ERRORTYPE omx_err = OMX_ErrorNone;
992 OMX_BUFFERHEADERTYPE *omx_buffer = m_omx_decoder.GetInputBuffer();
994 if(omx_buffer == NULL)
996 CLog::Log(LOGERROR, "%s::%s - buffer error 0x%08x", CLASSNAME, __func__, omx_err);
1000 omx_buffer->nOffset = 0;
1001 omx_buffer->nFilledLen = 0;
1002 omx_buffer->nTimeStamp = ToOMXTime(0LL);
1004 omx_buffer->nFlags = OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_EOS | OMX_BUFFERFLAG_TIME_UNKNOWN;
1006 omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer);
1007 if (omx_err != OMX_ErrorNone)
1009 CLog::Log(LOGERROR, "%s::%s - OMX_EmptyThisBuffer() failed with result(0x%x)\n", CLASSNAME, __func__, omx_err);
1013 unsigned int nTimeOut = 30000;
1017 if(m_omx_render.IsEOS())
1019 CLog::Log(LOGDEBUG, "%s::%s - got eos\n", CLASSNAME, __func__);
1025 CLog::Log(LOGERROR, "%s::%s - wait for eos timed out\n", CLASSNAME, __func__);
1032 m_omx_render.ResetEos();