bool OMXEGLImage::Open(COMXStreamInfo &hints, OMXClock *clock) { OMX_ERRORTYPE error = OMX_ErrorNone; m_video_codec_name = ""; m_codingType = OMX_VIDEO_CodingUnused; m_decoded_width = hints.width; m_decoded_height = hints.height; if(!m_decoded_width || !m_decoded_height) return false; if(hints.extrasize > 0 && hints.extradata != NULL) { m_extrasize = hints.extrasize; m_extradata = (uint8_t *)malloc(m_extrasize); memcpy(m_extradata, hints.extradata, hints.extrasize); } ProcessCodec(hints); std::string componentName = decoder_name; if(!m_omx_decoder.Initialize(componentName, OMX_IndexParamVideoInit)) { return false; } componentName = "OMX.broadcom.egl_render"; if(!m_omx_render.Initialize(componentName, OMX_IndexParamVideoInit)) { return false; } componentName = "OMX.broadcom.video_scheduler"; if(!m_omx_sched.Initialize(componentName, OMX_IndexParamVideoInit)) { return false; } if(clock == NULL) { return false; } m_av_clock = clock; m_omx_clock = m_av_clock->GetOMXClock(); if(m_omx_clock->GetComponent() == NULL) { m_av_clock = NULL; m_omx_clock = NULL; return false; } m_omx_tunnel_decoder.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_sched, m_omx_sched.GetInputPort()); m_omx_tunnel_sched.Initialize( &m_omx_sched, m_omx_sched.GetOutputPort(), &m_omx_render, m_omx_render.GetInputPort()); m_omx_tunnel_clock.Initialize( m_omx_clock, m_omx_clock->GetInputPort() + 1, &m_omx_sched, m_omx_sched.GetOutputPort() + 1); error = m_omx_decoder.SetStateForComponent(OMX_StateIdle); if (error != OMX_ErrorNone) { ofLogError(__func__) << "m_omx_decoder OMX_StateIdle FAIL"; return false; } OMX_VIDEO_PARAM_PORTFORMATTYPE formatType; OMX_INIT_STRUCTURE(formatType); formatType.nPortIndex = m_omx_decoder.GetInputPort(); formatType.eCompressionFormat = m_codingType; if (hints.fpsscale > 0 && hints.fpsrate > 0) { formatType.xFramerate = (long long)(1<<16)*hints.fpsrate / hints.fpsscale; } else { formatType.xFramerate = 25 * (1<<16); } error = m_omx_decoder.SetParameter(OMX_IndexParamVideoPortFormat, &formatType); if(error == OMX_ErrorNone) { ofLogVerbose() << "m_omx_decoder SET OMX_IndexParamVideoPortFormat PASS"; }else { ofLog(OF_LOG_ERROR, "m_omx_decoder GET OMX_IndexParamVideoPortFormat FAIL error: 0x%08x\n", error); return false; } OMX_PARAM_PORTDEFINITIONTYPE portParam; OMX_INIT_STRUCTURE(portParam); portParam.nPortIndex = m_omx_decoder.GetInputPort(); error = m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition, &portParam); if(error == OMX_ErrorNone) { ofLogVerbose() << "m_omx_decoder GET OMX_IndexParamPortDefinition PASS"; }else { ofLog(OF_LOG_ERROR, "m_omx_decoder GET OMX_IndexParamPortDefinition FAIL error: 0x%08x\n", error); return false; } ofLogVerbose(__func__) << "portParam.nBufferCountActual GET VAR --------------------------:" << portParam.nBufferCountActual; ofLogVerbose(__func__) << "portParam.format.video.nFrameWidth GET VAR --------------------------:" << portParam.format.video.nFrameWidth; int numVideoBuffers = 80; //20 is minimum - can get up to 80 portParam.nBufferCountActual = numVideoBuffers; portParam.format.video.nFrameWidth = m_decoded_width; portParam.format.video.nFrameHeight = m_decoded_height; error = m_omx_decoder.SetParameter(OMX_IndexParamPortDefinition, &portParam); if(error == OMX_ErrorNone) { ofLogVerbose() << "m_omx_decoder SET OMX_IndexParamPortDefinition PASS"; }else { ofLog(OF_LOG_ERROR, "m_omx_decoder SET OMX_IndexParamPortDefinition FAIL error: 0x%08x\n", error); return false; } error = m_omx_tunnel_clock.Establish(false); if(error != OMX_ErrorNone) { ofLogError(__func__) << "m_omx_tunnel_clock.Establish FAIL"; return false; } OMX_PARAM_BRCMVIDEODECODEERRORCONCEALMENTTYPE concanParam; OMX_INIT_STRUCTURE(concanParam); concanParam.bStartWithValidFrame = OMX_FALSE; error = m_omx_decoder.SetParameter(OMX_IndexParamBrcmVideoDecodeErrorConcealment, &concanParam); if(error == OMX_ErrorNone) { ofLogVerbose() << "m_omx_decoder OMX_IndexParamBrcmVideoDecodeErrorConcealment PASS"; }else { ofLog(OF_LOG_ERROR, "m_omx_decoder OMX_IndexParamBrcmVideoDecodeErrorConcealment FAIL error: 0x%08x\n", error); return false; } if(NaluFormatStartCodes(hints.codec, m_extradata, m_extrasize)) { OMX_NALSTREAMFORMATTYPE nalStreamFormat; OMX_INIT_STRUCTURE(nalStreamFormat); nalStreamFormat.nPortIndex = m_omx_decoder.GetInputPort(); nalStreamFormat.eNaluFormat = OMX_NaluFormatOneNaluPerBuffer; error = m_omx_decoder.SetParameter((OMX_INDEXTYPE)OMX_IndexParamNalStreamFormatSelect, &nalStreamFormat); if (error == OMX_ErrorNone) { ofLogVerbose() << "Open OMX_IndexParamNalStreamFormatSelect PASS"; }else { ofLog(OF_LOG_ERROR, "Open OMX_IndexParamNalStreamFormatSelect FAIL (0%08x)\n", error); return false; } } // broadcom omx entension: // When enabled, the timestamp fifo mode will change the way incoming timestamps are associated with output images. // In this mode the incoming timestamps get used without re-ordering on output images. if(hints.ptsinvalid) { OMX_CONFIG_BOOLEANTYPE timeStampMode; OMX_INIT_STRUCTURE(timeStampMode); timeStampMode.bEnabled = OMX_TRUE; error = m_omx_decoder.SetParameter((OMX_INDEXTYPE)OMX_IndexParamBrcmVideoTimestampFifo, &timeStampMode); if (error == OMX_ErrorNone) { ofLogVerbose() << "Open OMX_IndexParamBrcmVideoTimestampFifo PASS"; }else { ofLog(OF_LOG_ERROR, "Open OMX_IndexParamBrcmVideoTimestampFifo error (0%08x)\n", error); return false; } } // Alloc buffers for the omx intput port. error = m_omx_decoder.AllocInputBuffers(); if(error == OMX_ErrorNone) { ofLogVerbose() << "m_omx_decoder AllocInputBuffers PASS"; }else { ofLog(OF_LOG_ERROR, "m_omx_decoder AllocInputBuffers FAIL error: 0x%08x\n", error); return false; } error = m_omx_tunnel_decoder.Establish(false); if(error == OMX_ErrorNone) { ofLogVerbose() << "m_omx_tunnel_decoder Establish PASS"; }else { ofLog(OF_LOG_ERROR, "m_omx_tunnel_decoder Establish FAIL error: 0x%08x\n", error); return false; } error = m_omx_decoder.SetStateForComponent(OMX_StateExecuting); if(error == OMX_ErrorNone) { ofLogVerbose() << "m_omx_decoder OMX_StateExecuting PASS"; }else { ofLog(OF_LOG_ERROR, "m_omx_decoder OMX_StateExecuting FAIL error: 0x%08x", error); return false; } error = m_omx_tunnel_sched.Establish(false); if(error == OMX_ErrorNone) { ofLogVerbose() << "m_omx_tunnel_sched Establish PASS"; }else { ofLog(OF_LOG_ERROR, "m_omx_tunnel_sched Establish FAIL error: 0x%08x", error); return false; } error = m_omx_sched.SetStateForComponent(OMX_StateExecuting); if(error == OMX_ErrorNone) { ofLogVerbose() << "m_omx_sched OMX_StateExecuting PASS"; }else { ofLog(OF_LOG_ERROR, "m_omx_sched OMX_StateExecuting FAIL error: 0x%08x", error); return false; } error = m_omx_render.SetStateForComponent(OMX_StateIdle); if(error == OMX_ErrorNone) { ofLogVerbose() << "m_omx_render OMX_StateIdle PASS"; }else { ofLog(OF_LOG_ERROR, "m_omx_render OMX_StateIdle FAIL error: 0x%08x", error); return false; } ofLogVerbose() << "m_omx_render.GetOutputPort(): " << m_omx_render.GetOutputPort(); m_omx_render.EnablePort(m_omx_render.GetOutputPort(), false); if(error == OMX_ErrorNone) { ofLogVerbose() << "m_omx_render Enable OUTPUT Port PASS"; }else { ofLog(OF_LOG_ERROR, "m_omx_render Enable OUTPUT Port FAIL error: 0x%08x", error); return false; } error = m_omx_render.UseEGLImage(&eglBuffer, m_omx_render.GetOutputPort(), NULL, GlobalEGLContainer::getInstance().eglImage); if(error == OMX_ErrorNone) { ofLogVerbose() << "m_omx_render UseEGLImage PASS"; }else { ofLog(OF_LOG_ERROR, "m_omx_render UseEGLImage FAIL error: 0x%08x", error); return false; } if(SendDecoderConfig()) { ofLogVerbose() << "SendDecoderConfig PASS"; }else { ofLog(OF_LOG_ERROR, "SendDecoderConfig FAIL"); return false; } m_omx_render.SetCustomDecoderFillBufferDoneHandler(onFillBufferDone); error = m_omx_render.SetStateForComponent(OMX_StateExecuting); if(error == OMX_ErrorNone) { ofLogVerbose() << "m_omx_render OMX_StateExecuting PASS"; }else { ofLog(OF_LOG_ERROR, "m_omx_render OMX_StateExecuting FAIL error: 0x%08x", error); return false; } error = m_omx_render.FillThisBuffer(eglBuffer); if(error == OMX_ErrorNone) { ofLogVerbose() << "m_omx_render FillThisBuffer PASS"; }else { ofLog(OF_LOG_ERROR, "m_omx_render FillThisBuffer FAIL error: 0x%08x", error); if (error == OMX_ErrorIncorrectStateOperation) { ofLogError(__func__) << "NEED EGL HACK"; } return false; } m_is_open = true; m_drop_state = false; m_setStartTime = true; ofLog(OF_LOG_VERBOSE, "%s::%s - decoder_component: 0x%p, input_port: 0x%x, output_port: 0x%x \n", "OMXEGLImage", __func__, m_omx_decoder.GetComponent(), m_omx_decoder.GetInputPort(), m_omx_decoder.GetOutputPort()); m_first_frame = true; // start from assuming all recent frames had valid pts m_history_valid_pts = ~0; return true; }
bool COMXVideo::Open(COMXStreamInfo& hints, OMXClock *clock, float display_aspect, bool deinterlace, bool hdmi_clock_sync) { OMX_ERRORTYPE error = OMX_ErrorNone; m_video_codec_name = ""; m_codingType = OMX_VIDEO_CodingUnused; m_decoded_width = hints.width; m_decoded_height = hints.height; m_hdmi_clock_sync = hdmi_clock_sync; if(!m_decoded_width || !m_decoded_height) { return false; } if(hints.extrasize > 0 && hints.extradata != NULL) { m_extrasize = hints.extrasize; m_extradata = (uint8_t *)malloc(m_extrasize); memcpy(m_extradata, hints.extradata, hints.extrasize); } ProcessCodec(hints); if(deinterlace) { ofLog(OF_LOG_VERBOSE, "enable deinterlace\n"); m_deinterlace = true; } else { m_deinterlace = false; } std::string componentName = decoder_name; if(!m_omx_decoder.Initialize(componentName, OMX_IndexParamVideoInit)) { return false; } componentName = "OMX.broadcom.video_render"; if(!m_omx_render.Initialize(componentName, OMX_IndexParamVideoInit)) { return false; } componentName = "OMX.broadcom.video_scheduler"; if(!m_omx_sched.Initialize(componentName, OMX_IndexParamVideoInit)) { return false; } if(m_deinterlace) { componentName = "OMX.broadcom.image_fx"; if(!m_omx_image_fx.Initialize(componentName, OMX_IndexParamImageInit)) { return false; } } if(clock == NULL) { return false; } m_av_clock = clock; m_omx_clock = m_av_clock->GetOMXClock(); if(m_omx_clock->GetComponent() == NULL) { m_av_clock = NULL; m_omx_clock = NULL; return false; } if(m_deinterlace) { m_omx_tunnel_decoder.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_image_fx, m_omx_image_fx.GetInputPort()); m_omx_tunnel_image_fx.Initialize(&m_omx_image_fx, m_omx_image_fx.GetOutputPort(), &m_omx_sched, m_omx_sched.GetInputPort()); } else { m_omx_tunnel_decoder.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_sched, m_omx_sched.GetInputPort()); } m_omx_tunnel_sched.Initialize(&m_omx_sched, m_omx_sched.GetOutputPort(), &m_omx_render, m_omx_render.GetInputPort()); m_omx_tunnel_clock.Initialize(m_omx_clock, m_omx_clock->GetInputPort() + 1, &m_omx_sched, m_omx_sched.GetOutputPort() + 1); error = m_omx_tunnel_clock.Establish(false); if(error != OMX_ErrorNone) { ofLogError(__func__) << "m_omx_tunnel_clock Establish FAIL: " << COMXCore::getOMXError(error); return false; } error = m_omx_decoder.SetStateForComponent(OMX_StateIdle); if (error != OMX_ErrorNone) { ofLogError(__func__) << "m_omx_decoder OMX_StateIdle FAIL: " << COMXCore::getOMXError(error); return false; } OMX_VIDEO_PARAM_PORTFORMATTYPE formatType; OMX_INIT_STRUCTURE(formatType); formatType.nPortIndex = m_omx_decoder.GetInputPort(); formatType.eCompressionFormat = m_codingType; if (hints.fpsscale > 0 && hints.fpsrate > 0) { formatType.xFramerate = (long long)(1<<16)*hints.fpsrate / hints.fpsscale; } else { formatType.xFramerate = 25 * (1<<16); } error = m_omx_decoder.SetParameter(OMX_IndexParamVideoPortFormat, &formatType); if(error != OMX_ErrorNone) { return false; } OMX_PARAM_PORTDEFINITIONTYPE portParam; OMX_INIT_STRUCTURE(portParam); portParam.nPortIndex = m_omx_decoder.GetInputPort(); error = m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition, &portParam); if(error != OMX_ErrorNone) { ofLogError(__func__) << "m_omx_decoder Get OMX_IndexParamPortDefinition FAIL: " << COMXCore::getOMXError(error); return false; } portParam.nPortIndex = m_omx_decoder.GetInputPort(); int videoBuffers = 60; portParam.nBufferCountActual = videoBuffers; portParam.format.video.nFrameWidth = m_decoded_width; portParam.format.video.nFrameHeight = m_decoded_height; error = m_omx_decoder.SetParameter(OMX_IndexParamPortDefinition, &portParam); if(error != OMX_ErrorNone) { ofLogError(__func__) << "m_omx_decoder Set OMX_IndexParamPortDefinition FAIL: " << COMXCore::getOMXError(error); return false; } OMX_PARAM_BRCMVIDEODECODEERRORCONCEALMENTTYPE concanParam; OMX_INIT_STRUCTURE(concanParam); concanParam.bStartWithValidFrame = OMX_FALSE; error = m_omx_decoder.SetParameter(OMX_IndexParamBrcmVideoDecodeErrorConcealment, &concanParam); if(error != OMX_ErrorNone) { ofLogError(__func__) << "m_omx_decoder OMX_IndexParamBrcmVideoDecodeErrorConcealment FAIL: " << COMXCore::getOMXError(error); return false; } if (m_deinterlace) { // the deinterlace component requires 3 additional video buffers in addition to the DPB (this is normally 2). OMX_PARAM_U32TYPE extra_buffers; OMX_INIT_STRUCTURE(extra_buffers); extra_buffers.nU32 = 3; error = m_omx_decoder.SetParameter(OMX_IndexParamBrcmExtraBuffers, &extra_buffers); if(error != OMX_ErrorNone) { ofLogError(__func__) << "m_omx_decoder OMX_IndexParamBrcmExtraBuffers FAIL: " << COMXCore::getOMXError(error); return false; } } // broadcom omx entension: // When enabled, the timestamp fifo mode will change the way incoming timestamps are associated with output images. // In this mode the incoming timestamps get used without re-ordering on output images. // recent firmware will actually automatically choose the timestamp stream with the least variance, so always enable OMX_CONFIG_BOOLEANTYPE timeStampMode; OMX_INIT_STRUCTURE(timeStampMode); timeStampMode.bEnabled = OMX_TRUE; error = m_omx_decoder.SetParameter((OMX_INDEXTYPE)OMX_IndexParamBrcmVideoTimestampFifo, &timeStampMode); if (error != OMX_ErrorNone) { ofLogError(__func__) << "m_omx_decoder OMX_IndexParamBrcmVideoTimestampFifo FAIL: " << COMXCore::getOMXError(error); return false; } if(NaluFormatStartCodes(hints.codec, m_extradata, m_extrasize)) { OMX_NALSTREAMFORMATTYPE nalStreamFormat; OMX_INIT_STRUCTURE(nalStreamFormat); nalStreamFormat.nPortIndex = m_omx_decoder.GetInputPort(); nalStreamFormat.eNaluFormat = OMX_NaluFormatStartCodes; error = m_omx_decoder.SetParameter((OMX_INDEXTYPE)OMX_IndexParamNalStreamFormatSelect, &nalStreamFormat); if (error != OMX_ErrorNone) { ofLogError(__func__) << "m_omx_decoder OMX_IndexParamNalStreamFormatSelect FAIL: " << COMXCore::getOMXError(error); return false; } } if(m_hdmi_clock_sync) { OMX_CONFIG_LATENCYTARGETTYPE latencyTarget; OMX_INIT_STRUCTURE(latencyTarget); latencyTarget.nPortIndex = m_omx_render.GetInputPort(); latencyTarget.bEnabled = OMX_TRUE; latencyTarget.nFilter = 2; latencyTarget.nTarget = 4000; latencyTarget.nShift = 3; latencyTarget.nSpeedFactor = -135; latencyTarget.nInterFactor = 500; latencyTarget.nAdjCap = 20; error = m_omx_render.SetConfig(OMX_IndexConfigLatencyTarget, &latencyTarget); if (error != OMX_ErrorNone) { ofLogError(__func__) << "m_omx_render OMX_IndexConfigLatencyTarget FAIL: " << COMXCore::getOMXError(error); return false; } } // Alloc buffers for the omx input port. error = m_omx_decoder.AllocInputBuffers(); if (error != OMX_ErrorNone) { ofLogError(__func__) << "m_omx_decoder AllocInputBuffers FAIL: " << COMXCore::getOMXError(error); return false; } error = m_omx_tunnel_decoder.Establish(false); if(error != OMX_ErrorNone) { ofLogError(__func__) << "m_omx_tunnel_decoder Establish FAIL: " << COMXCore::getOMXError(error); return false; } error = m_omx_decoder.SetStateForComponent(OMX_StateExecuting); if (error != OMX_ErrorNone) { ofLogError(__func__) << "m_omx_decoder OMX_StateExecuting FAIL: " << COMXCore::getOMXError(error); return false; } if(m_deinterlace) { OMX_CONFIG_IMAGEFILTERPARAMSTYPE image_filter; OMX_INIT_STRUCTURE(image_filter); image_filter.nPortIndex = m_omx_image_fx.GetOutputPort(); image_filter.nNumParams = 1; image_filter.nParams[0] = 3; image_filter.eImageFilter = OMX_ImageFilterDeInterlaceAdvanced; error = m_omx_image_fx.SetConfig(OMX_IndexConfigCommonImageFilterParameters, &image_filter); if(error != OMX_ErrorNone) { ofLogError(__func__) << "m_omx_image_fx SetConfig FAIL: " << COMXCore::getOMXError(error); return false; } error = m_omx_tunnel_image_fx.Establish(false); if(error != OMX_ErrorNone) { ofLogError(__func__) << "m_omx_image_fx Establish FAIL: " << COMXCore::getOMXError(error); return false; } error = m_omx_image_fx.SetStateForComponent(OMX_StateExecuting); if (error != OMX_ErrorNone) { ofLogError(__func__) << "m_omx_image_fx OMX_StateExecuting FAIL: " << COMXCore::getOMXError(error); return false; } m_omx_image_fx.DisablePort(m_omx_image_fx.GetInputPort(), false); m_omx_image_fx.DisablePort(m_omx_image_fx.GetOutputPort(), false); } error = m_omx_tunnel_sched.Establish(false); if(error != OMX_ErrorNone) { ofLogError(__func__) << "m_omx_tunnel_sched Establish FAIL: " << COMXCore::getOMXError(error); return false; } error = m_omx_sched.SetStateForComponent(OMX_StateExecuting); if (error != OMX_ErrorNone) { ofLogError(__func__) << "m_omx_sched OMX_StateExecuting FAIL: " << COMXCore::getOMXError(error); return false; } error = m_omx_render.SetStateForComponent(OMX_StateExecuting); if (error != OMX_ErrorNone) { ofLogError(__func__) << "m_omx_render OMX_StateExecuting FAIL: " << COMXCore::getOMXError(error); return false; } ofAddListener(ofEvents().update, this, &COMXVideo::onUpdate); if(!SendDecoderConfig()) { return false; } m_is_open = true; m_drop_state = false; m_setStartTime = true; OMX_CONFIG_DISPLAYREGIONTYPE configDisplay; OMX_INIT_STRUCTURE(configDisplay); configDisplay.nPortIndex = m_omx_render.GetInputPort(); //we provided a rectangle but returned early as we were not ready if (displayRect.getWidth()>0) { configureDisplay(); }else { float fAspect = (float)hints.aspect / (float)m_decoded_width * (float)m_decoded_height; float par = hints.aspect ? fAspect/display_aspect : 0.0f; // only set aspect when we have a aspect and display doesn't match the aspect bool doDisplayChange = true; if(doDisplayChange) { if(par != 0.0f && fabs(par - 1.0f) > 0.01f) { AVRational aspect; aspect = av_d2q(par, 100); configDisplay.set = OMX_DISPLAY_SET_PIXEL; configDisplay.pixel_x = aspect.num; configDisplay.pixel_y = aspect.den; ofLog(OF_LOG_VERBOSE, "Aspect : num %d den %d aspect %f pixel aspect %f\n", aspect.num, aspect.den, hints.aspect, par); error = m_omx_render.SetConfig(OMX_IndexConfigDisplayRegion, &configDisplay); if(error != OMX_ErrorNone) { return false; } } } } ofLog(OF_LOG_VERBOSE, "%s::%s - decoder_component(0x%p), input_port(0x%x), output_port(0x%x) deinterlace %d hdmiclocksync %d\n", "OMXVideo", __func__, m_omx_decoder.GetComponent(), m_omx_decoder.GetInputPort(), m_omx_decoder.GetOutputPort(), m_deinterlace, m_hdmi_clock_sync); m_first_frame = true; // start from assuming all recent frames had valid pts m_history_valid_pts = ~0; return true; }