From 2c8f83bcd8144ab39f450e2cd063917ce32a9125 Mon Sep 17 00:00:00 2001 From: Marten Richter Date: Sun, 2 Sep 2012 23:19:54 +0200 Subject: [PATCH] Add basic audio playback (stereo), fast forward, ThreadP bugfix and Stream interface change --- afeed.cc | 7 +- audiovpe.cc | 1146 +++++++++++++++++++++++++++++++++++++++++++---- audiovpe.h | 72 ++- defines.h | 11 +- demuxer.cc | 12 +- demuxer.h | 6 +- player.cc | 8 +- playerlivetv.cc | 5 +- remote.cc | 2 +- remotelinux.cc | 4 + stream.cc | 4 +- stream.h | 2 +- threadp.cc | 22 +- vfeed.cc | 0 videovpeogl.cc | 608 +++++++++++++++++++------ videovpeogl.h | 33 +- vopts.cc | 2 +- 17 files changed, 1674 insertions(+), 270 deletions(-) mode change 100755 => 100644 stream.cc mode change 100755 => 100644 vfeed.cc diff --git a/afeed.cc b/afeed.cc index 4da46c7..3649d39 100644 --- a/afeed.cc +++ b/afeed.cc @@ -73,12 +73,13 @@ void AFeed::threadMethod() if (audioEnabled) { - alen = Demuxer::getInstance()->writeAudio(); + bool newdata=false; + alen = Demuxer::getInstance()->writeAudio(&newdata); + if (newdata) cb.call(this); if (alen) { - cb.call(this); -// Log::getInstance()->log("Afeed", Log::DEBUG, "written"); + //Log::getInstance()->log("Afeed", Log::DEBUG, "written"); } else { diff --git a/audiovpe.cc b/audiovpe.cc index 93f2942..2e544cf 100644 --- a/audiovpe.cc +++ b/audiovpe.cc @@ -27,8 +27,6 @@ AudioVPE::AudioVPE() { initted = 0; - lastpacketnum=-1; - currentpacketnum=-1; streamType = 0; volume = 20; muted = 0; @@ -42,40 +40,59 @@ AudioVPE::AudioVPE() prefered_ac3=0; //0 stereo PCM, 1 passthrough 2 Multichannel PCM prefered_mp2=0; prefered_mp3=0; + hdmi=true; + + omx_running=false; + + omx_aud_rend/*dec*/=0; + cur_input_buf_omx=NULL; + + ac3codec_libav=NULL; + ac3codec_context_libav=NULL; + + mp23codec_libav=NULL; + mp23codec_context_libav=NULL; + } AudioVPE::~AudioVPE() { } -int AudioVPE::init(UCHAR tstreamType) -{ - if (initted) return 0; - initted = 1; +int AudioVPE::init(UCHAR tstreamType) { + if (initted) + return 0; + initted = 1; -// // if ((fdAudio = open("/dev/adec_mpg", O_RDWR | O_NONBLOCK)) < 0) return 0; - // if ((fdAudio = open("/dev/adec_mpg", O_WRONLY)) < 0) return 0; + streamType = tstreamType; - streamType = tstreamType; + if (!initAllParams()) { + shutdown(); + return 0; + } - if (!initAllParams()) - { - shutdown(); - return 0; - } + unMute(); - unMute(); - // Set the volume variable to what the hardware is set at now - int hwvol = -1; -/* int hwvolFail = ioctl(fdAudio, AV_GET_AUD_VOLUME, &hwvol); - if (!hwvolFail) - { - volume = 20 - ((hwvol >> 16) & 0xFF); - if ((volume < 0) || (volume > 20)) volume = 20; - }*/ - return 1; + av_register_all(); + av_log_set_flags(AV_LOG_SKIP_REPEATED); + + ac3codec_libav = avcodec_find_decoder(CODEC_ID_AC3); + if (ac3codec_libav == NULL) { + Log::getInstance()->log("Audio", Log::DEBUG, + "Find libav ac3 decoder failed"); + return 0; + } + + mp23codec_libav = avcodec_find_decoder(CODEC_ID_MP3); + if (mp23codec_libav == NULL) { + Log::getInstance()->log("Audio", Log::DEBUG, + "Find libav mpeg audio decoder failed"); + return 0; + } + + return 1; } int AudioVPE::initAllParams() @@ -87,12 +104,16 @@ int AudioVPE::shutdown() { if (!initted) return 0; initted = 0; - //close(fdAudio); + + Log::getInstance()->log("Audio", Log::DEBUG, "audio shutdown called"); + DeAllocateCodecsOMX(); + return 1; } bool AudioVPE::loadOptionsfromServer(VDR* vdr) { + Log::getInstance()->log("Audio", Log::DEBUG, "AudioOMX config load"); char *name=vdr->configLoad("AudioOMX","AC3DecodingMode"); if (name != NULL) { @@ -245,7 +266,7 @@ bool AudioVPE::saveOptionstoServer() break; }; - if (hdmi) + if (!hdmi) VDR::getInstance()->configSave("AudioOMX", "AudioOutput", "analog"); else VDR::getInstance()->configSave("AudioOMX", "AudioOutput", "HDMI"); @@ -343,6 +364,32 @@ bool AudioVPE::addOptionsToPanes(int panenumber,Options *options,WOptionPane* pa + + +OMX_ERRORTYPE AudioVPE::EmptyBufferDone_OMX(OMX_IN OMX_HANDLETYPE hcomp,OMX_IN OMX_PTR appdata,OMX_IN OMX_BUFFERHEADERTYPE* buffer){ + + //Log::getInstance()->log("Audio", Log::NOTICE, "EmptyBufferDone"); + AudioVPE *audio=(AudioVPE *)getInstance(); + audio->ReturnEmptyOMXBuffer(buffer); + return OMX_ErrorNone; + +} + +void AudioVPE::ReturnEmptyOMXBuffer(OMX_BUFFERHEADERTYPE* buffer){ + input_bufs_omx_mutex.Lock(); + //Log::getInstance()->log("Audio", Log::NOTICE, "ReturnEmptyOMXBuffer %d",input_bufs_omx_free.size()); + input_bufs_omx_free.push_back(buffer); + //Log::getInstance()->log("Audio", Log::NOTICE, "ReturnEmptyOMXBuffer %d",input_bufs_omx_free.size()); + input_bufs_omx_mutex.Unlock(); +} + + OMX_ERRORTYPE AudioVPE::FillBufferDone_OMX(OMX_IN OMX_HANDLETYPE hcomp, OMX_IN OMX_PTR appdata,OMX_IN OMX_BUFFERHEADERTYPE* buffer) { + Log::getInstance()->log("Audio", Log::NOTICE, "FillBufferDone"); + return OMX_ErrorNone; +} + + + int AudioVPE::setStreamType(UCHAR type) { if (!initted) return 0; @@ -375,21 +422,664 @@ int AudioVPE::sync() return 1; } -int AudioVPE::play() +int AudioVPE::play() { + if (!initted) + return 0; + lastAType=MPTYPE_MPEG_AUDIO; + Log::getInstance()->log("Audio", Log::DEBUG, "enter play"); + + if (!AllocateCodecsOMX()) { + return 0; + } + return 1; +} + + +int AudioVPE::ChangeAudioDestination() //clock aka omx mutex needs to be locked { - if (!initted) return 0; - lastpacketnum=-1; - currentpacketnum=-1; + OMX_ERRORTYPE error; + const char * destinations[]={"local","hdmi"}; + int dest=0; + if (hdmi) dest=1; + else dest=0; + + OMX_CONFIG_BRCMAUDIODESTINATIONTYPE auddest; + memset(&auddest,0,sizeof(auddest)); + auddest.nSize=sizeof(auddest); + auddest.nVersion.nVersion=OMX_VERSION; + strcpy((char *)auddest.sName, destinations[dest]); + + Log::getInstance()->log("Audio", Log::DEBUG, "setting destination to: %s",auddest.sName); + error=OMX_SetConfig(omx_aud_rend,OMX_IndexConfigBrcmAudioDestination,&auddest); + if (error!=OMX_ErrorNone){ + Log::getInstance()->log("Audio", Log::DEBUG, "Init OMX_IndexConfigBrcmAudioDestination failed %x %x %s", error,omx_aud_rend,auddest.sName); + DeAllocateCodecsOMX(); + return 0; + } + return 1; - //if (ioctl(fdAudio, AV_SET_AUD_PLAY, 0) != 0) return 0; - return 1; } +int AudioVPE::ChangeAudioPortConfig() //clock aka omx mutex needs to be locked +{ + OMX_ERRORTYPE error; + //Ok first fidle a working configuration + Log::getInstance()->log("Audio", Log::DEBUG, + "ChangeAudioPortConfig"); + + if (hdmi) { + switch (lastAType) { + case MPTYPE_MPEG_AUDIO: { + if (prefered_mp2 == 3 && false) { //not supported yet + + } else { + if (prefered_mp2 == 2 && canpass_mp2) { + passthrough = true; + } else + passthrough = false; + } + } + break; + case MPTYPE_AC3_PRE13: + case MPTYPE_AC3: { + if (prefered_ac3 == 3 && false) { //not supported yet + + } else { + if (prefered_ac3 == 2 && canpass_ac3) { + passthrough = true; + } else + passthrough = false; + } + } + break; + case MPTYPE_MPEG_AUDIO_LAYER3: { + if (prefered_mp3 == 3 && false) { //not supported yet + + } else { + if (prefered_mp3 == 2 && canpass_mp2) { + passthrough = true; + } else + passthrough = false; + } + } + break; + }; + } else { + passthrough=false; + //mch=false; // multichannel also false + } + + + + /*OMX_CONFIG_BOOLEANTYPE booly; + memset(&booly, 0, sizeof(booly)); + booly.nSize = sizeof(booly); + booly.nVersion.nVersion = OMX_VERSION; + if (passthrough) + booly.bEnabled = OMX_TRUE; + else + booly.bEnabled = OMX_FALSE; + + error = OMX_SetParameter(omx_aud_dec, OMX_IndexParamBrcmDecoderPassThrough, + &booly); + if (error != OMX_ErrorNone) { + Log::getInstance()->log("Audio", Log::DEBUG, + "Init OMX_IndexParamBrcmDecoderPassThrough failed %x", error); + DeAllocateCodecsOMX(); + return 0; + }*/ + VideoVPEOGL *video=(VideoVPEOGL*)Video::getInstance(); + + + if (!omx_running) { + if (passthrough) { + // TODO coding + } else { + + OMX_AUDIO_PARAM_PCMMODETYPE audio_pcm; + memset(&audio_pcm, 0, sizeof(audio_pcm)); + audio_pcm.nSize = sizeof(audio_pcm); + audio_pcm.nVersion.nVersion = OMX_VERSION; + audio_pcm.nChannels = 2; + audio_pcm.eChannelMapping[0] = OMX_AUDIO_ChannelLF; + audio_pcm.eChannelMapping[1] = OMX_AUDIO_ChannelRF; + //audio_pcm.eChannelMapping[2]=OMX_AUDIO_ChannelMax; + audio_pcm.eNumData = OMX_NumericalDataSigned; + audio_pcm.eEndian = OMX_EndianLittle; + audio_pcm.bInterleaved = OMX_TRUE; + audio_pcm.nBitPerSample = 16; + audio_pcm.ePCMMode = OMX_AUDIO_PCMModeLinear; + audio_pcm.nChannels = 2; + audio_pcm.nSamplingRate = 48000; + audio_pcm.nPortIndex = omx_rend_input_port; + error = OMX_SetParameter(omx_aud_rend, OMX_IndexParamAudioPcm, + &audio_pcm); + if (error != OMX_ErrorNone) { + Log::getInstance()->log("Audio", Log::DEBUG, + "Init OMX_IndexParamAudioPcm failed %x %d", error, + omx_rend_input_port); + DeAllocateCodecsOMX(); + return 0; + } + + } + } + + + + return 1; + + + +} +int AudioVPE::InitDecoderLibAV() +{ + ac3codec_context_libav = avcodec_alloc_context3(ac3codec_libav); + if (!ac3codec_context_libav) { + Log::getInstance()->log("Audio", Log::DEBUG, "Alloc avcodec for ac3 decoding context failed!"); + return 0; + } + + ac3codec_context_libav->flags |= CODEC_FLAG_TRUNCATED; + ac3codec_context_libav->request_channels=2; + + int avc_ret = avcodec_open2(ac3codec_context_libav, ac3codec_libav, NULL); + if (avc_ret < 0) { + Log::getInstance()->log("Audio", Log::DEBUG, "Opening libav codec failed \n"); + return 0; + } + + mp23codec_context_libav = avcodec_alloc_context3(mp23codec_libav); + if (!ac3codec_context_libav) { + Log::getInstance()->log("Audio", Log::DEBUG, "Alloc avcodec for mp23 decoding context failed!"); + return 0; + } + + mp23codec_context_libav->flags |= CODEC_FLAG_TRUNCATED; + mp23codec_context_libav->request_channels=2; + + avc_ret = avcodec_open2(mp23codec_context_libav, mp23codec_libav, NULL); + if (avc_ret < 0) { + Log::getInstance()->log("Audio", Log::DEBUG, "Opening libav codec failed \n"); + return 0; + } + + av_init_packet(&incoming_paket_libav); + decode_frame_libav=avcodec_alloc_frame(); + + + + return 1; +} + +void AudioVPE::DeinitDecoderLibAV() { + + + if (ac3codec_context_libav) { + avcodec_close(ac3codec_context_libav); + av_free(ac3codec_context_libav); + ac3codec_context_libav = NULL; + av_free(decode_frame_libav); + + } + +} + + +int AudioVPE::AllocateCodecsOMX() +{ + OMX_ERRORTYPE error; + static OMX_CALLBACKTYPE callbacks= {&VideoVPEOGL::EventHandler_OMX,&EmptyBufferDone_OMX,&FillBufferDone_OMX}; + + Log::getInstance()->log("Audio", Log::NOTICE, "Allocate Codecs OMX"); + //Clock, move later to audio + VideoVPEOGL *video=(VideoVPEOGL*)Video::getInstance(); + + if (!InitDecoderLibAV()) return 0;; + + + OMX_PORT_PARAM_TYPE p_param; + memset(&p_param,0,sizeof(p_param)); + p_param.nSize=sizeof(p_param); + p_param.nVersion.nVersion=OMX_VERSION; + + + if (!video->getClockAudioandInit(&omx_clock,&omx_clock_output_port)){ + return 0;// get the clock and init it if necessary + } + + /* TODO end */ + if (!video->idleClock()) { + return 0; + } + video->LockClock(); + + error = OMX_GetHandle(&omx_aud_rend, VPE_OMX_AUDIO_REND, NULL, &callbacks); + if (error != OMX_ErrorNone) { + Log::getInstance()->log("Audio", Log::DEBUG, + "Init OMX audio rend failed %x", error); + video->UnlockClock(); + DeAllocateCodecsOMX(); + return 0; + } + + if (!ChangeAudioDestination()) { + video->UnlockClock(); + DeAllocateCodecsOMX(); + return 0; + } + + error = OMX_GetParameter(omx_aud_rend, OMX_IndexParamAudioInit, &p_param); + if (error != OMX_ErrorNone) { + Log::getInstance()->log("Audio", Log::DEBUG, + "Init OMX audio rend OMX_GetParameter failed %x", error); + video->UnlockClock(); + DeAllocateCodecsOMX(); + return 0; + } + omx_rend_input_port = p_param.nStartPortNumber; + + error = OMX_GetParameter(omx_aud_rend, OMX_IndexParamOtherInit, &p_param); + if (error != OMX_ErrorNone) { + Log::getInstance()->log("Audio", Log::DEBUG, + "Init OMX aud rend OMX_GetParameter failed %x", error); + video->UnlockClock(); + DeAllocateCodecsOMX(); + return 0; + } + // buggy return value + omx_rend_clock_port = p_param.nStartPortNumber; + + +/* error=OMX_GetHandle(&omx_aud_dec,VPE_OMX_AUDIO_DECODER,NULL,&callbacks); + + if (error!=OMX_ErrorNone){ + Log::getInstance()->log("Audio", Log::DEBUG, "Init OMX audio decoder failed %x", error); + video->UnlockClock(); + DeAllocateCodecsOMX(); + return 0; + } + + error=OMX_GetParameter(omx_aud_dec,OMX_IndexParamAudioInit,&p_param); + if (error!=OMX_ErrorNone){ + Log::getInstance()->log("Audio", Log::DEBUG, "Init OMX audio decoder OMX_GetParameter failed %x", error); + video->UnlockClock(); + DeAllocateCodecsOMX(); + return 0; + } + omx_codec_input_port=p_param.nStartPortNumber; + omx_codec_output_port=p_param.nStartPortNumber+1; + + if (!video->DisablePort(omx_aud_dec,omx_codec_input_port) || !video->DisablePort(omx_aud_dec,omx_codec_output_port)) { + Log::getInstance()->log("Audio", Log::DEBUG, "Disable Ports OMX audio decoder failed"); + video->UnlockClock(); + DeAllocateCodecsOMX(); + return 0; + }*/ + + + + + if (!video->DisablePort(omx_aud_rend,omx_rend_input_port,true) ) { + Log::getInstance()->log("Audio", Log::DEBUG, "Disable Ports OMX audio rend failed %d",omx_rend_input_port); + video->UnlockClock(); + DeAllocateCodecsOMX(); + return 0; + } + + if ( !video->DisablePort(omx_aud_rend, omx_rend_clock_port, true)) { + Log::getInstance()->log("Audio", Log::DEBUG, + "Disable Ports OMX rend clock port failed %d",omx_rend_clock_port); + video->UnlockClock(); + DeAllocateCodecsOMX(); + return 0; + } + + + + + //Setuo chain + + + error=OMX_SetupTunnel(omx_clock,omx_clock_output_port,omx_aud_rend,omx_rend_clock_port); + if (error!=OMX_ErrorNone){ + Log::getInstance()->log("Audio", Log::DEBUG, "OMX_Setup tunnel clock to rend failed %x %d %d", error,omx_clock_output_port,omx_rend_clock_port); + video->UnlockClock(); + DeAllocateCodecsOMX(); + return 0; + } + + if (!video->EnablePort(omx_clock,omx_clock_output_port,false) || !video->EnablePort(omx_aud_rend,omx_rend_clock_port,false) + ) { + Log::getInstance()->log("Audio", Log::DEBUG, "Enable Ports OMX clock rend failed"); + video->UnlockClock(); + DeAllocateCodecsOMX(); + return 0; + } + + if (!video->ChangeComponentState(omx_aud_rend,OMX_StateIdle)) { + Log::getInstance()->log("Audio", Log::DEBUG, "aud_rend idle ChangeComponentState"); + video->UnlockClock(); + DeAllocateCodecsOMX(); + return 0; + } + + + + + if ( !video->CommandFinished(omx_aud_rend,OMX_CommandPortEnable,omx_rend_clock_port)) { + video->UnlockClock(); + DeAllocateCodecsOMX(); + return 0; + } + + if ( !video->CommandFinished(omx_clock,OMX_CommandPortEnable,omx_clock_output_port)) { + video->UnlockClock(); + DeAllocateCodecsOMX(); + return 0; + } + + + + if (!ChangeAudioPortConfig()){ + Log::getInstance()->log("Audio", Log::NOTICE, "Change AudioPortConfig failed"); + video->UnlockClock(); + DeAllocateCodecsOMX(); + return 0; + } + +/* if (!video->ChangeComponentState(omx_aud_dec,OMX_StateIdle)) { + Log::getInstance()->log("Audio", Log::DEBUG, "aud_dec ChangeComponentState"); + DeAllocateCodecsOMX(); + return 0; + }*/ + + + + if (!PrepareInputBufsOMX()) { + video->UnlockClock(); + DeAllocateCodecsOMX(); + return 0; + } + + + +/* error=OMX_SetupTunnel(omx_aud_dec,omx_codec_output_port,omx_aud_rend,omx_rend_input_port); + if (error!=OMX_ErrorNone){ + Log::getInstance()->log("Audio", Log::DEBUG, "OMX_Setup tunnel dec to render failed %x", error); + video->UnlockClock(); + DeAllocateCodecsOMX(); + return 0; + }*/ + + + +/* if (!video->EnablePort(omx_aud_dec,omx_codec_output_port,false) || !video->EnablePort(omx_aud_rend,omx_rend_input_port,false) + ) { + Log::getInstance()->log("Audio", Log::DEBUG, "Enable Ports OMX codec rend failed"); + video->UnlockClock(); + DeAllocateCodecsOMX(); + return 0; + }*/ + +/* if ( !video->CommandFinished(omx_aud_dec,OMX_CommandPortEnable,omx_codec_output_port) + || !video->CommandFinished(omx_aud_rend,OMX_CommandPortEnable,omx_rend_input_port)) { + video->UnlockClock(); + DeAllocateCodecsOMX(); + return 0; + }*/ + + if (!video->ChangeComponentState(omx_aud_rend,OMX_StateExecuting)) { + Log::getInstance()->log("Audio", Log::DEBUG, "omx_aud_rend ChangeComponentState Execute"); + video->UnlockClock(); + DeAllocateCodecsOMX(); + return 0; + } + + + video->UnlockClock(); + paused=false; + omx_running=true; + + + if (!video->setClockExecutingandRunning()) return 0; + + Log::getInstance()->log("Audio", Log::NOTICE, "Allocate Codecs OMX finished"); + + return 1; +} + + + + +int AudioVPE::PrepareInputBufsOMX() //needs to be called with locvke omx clock mutex +{ + VideoVPEOGL *video=(VideoVPEOGL*)Video::getInstance(); + OMX_ERRORTYPE error; + OMX_PARAM_PORTDEFINITIONTYPE port_def_type; + memset(&port_def_type,0,sizeof(port_def_type)); + port_def_type.nSize=sizeof(port_def_type); + port_def_type.nVersion.nVersion=OMX_VERSION; + port_def_type.nPortIndex=omx_rend_input_port;//omx_codec_input_port; + + error=OMX_GetParameter(omx_aud_rend/*dec*/,OMX_IndexParamPortDefinition, &port_def_type); + + if (error!=OMX_ErrorNone){ + Log::getInstance()->log("Audio", Log::DEBUG, "Get OMX OMX_IndexParamPortDefinition failed %x", error); + } + + + port_def_type.nBufferCountActual=2; + port_def_type.nBufferSize=max(port_def_type.nBufferSize,50000); // for transcoder important + + error=OMX_SetParameter(omx_aud_rend/*dec*/,OMX_IndexParamPortDefinition, &port_def_type); + + if (error!=OMX_ErrorNone){ + Log::getInstance()->log("Audio", Log::DEBUG, "Set OMX OMX_IndexParamPortDefinition failed %x", error); + } + + + error=OMX_SendCommand(omx_aud_rend/*dec*/,OMX_CommandPortEnable,omx_rend_input_port/*codec*/,0); + if (error!=OMX_ErrorNone){ + Log::getInstance()->log("Audio", Log::DEBUG, "Prepare Input bufs Send Command to enable port %x", error); + return 0; + } + + input_bufs_omx_mutex.Lock(); + for (unsigned int i=0; i< port_def_type.nBufferCountActual;i++) { + OMX_BUFFERHEADERTYPE *buf_head=NULL; + error=OMX_AllocateBuffer(omx_aud_rend/*dec*/,&buf_head,omx_rend_input_port/*codec*/,NULL,port_def_type.nBufferSize); + if (error!=OMX_ErrorNone){ + Log::getInstance()->log("Audio", Log::DEBUG, "Use OMX_AllocateBuffer failed %x", error); + input_bufs_omx_mutex.Unlock(); + return 0; + } + input_bufs_omx_all.push_back(buf_head); + input_bufs_omx_free.push_back(buf_head); + } + omx_first_frame=true; + + firstsynched=false; + cur_input_buf_omx=NULL; + input_bufs_omx_mutex.Unlock(); + + if (!video->CommandFinished(omx_aud_rend/*dec*/,OMX_CommandPortEnable,omx_rend_input_port /*codec*/)) { + return 0; + } + + return 1; +} + +int AudioVPE::DestroyInputBufsOMX() //call with clock mutex locked +{ + OMX_ERRORTYPE error; + + cur_input_buf_omx=NULL; + input_bufs_omx_mutex.Lock(); + for (int i=0; i< input_bufs_omx_all.size();i++) { + error=OMX_FreeBuffer(omx_aud_rend/*dec*/,omx_rend_input_port/*codec*/,input_bufs_omx_all[i]); + if (error!=OMX_ErrorNone){ + Log::getInstance()->log("Audio", Log::DEBUG, "Use OMX_FreeBuffer failed %x", error); + input_bufs_omx_mutex.Unlock(); + return 0; + } + + } + input_bufs_omx_all.clear(); + input_bufs_omx_free.clear(); + input_bufs_omx_mutex.Unlock(); + +} + + +int AudioVPE::DeAllocateCodecsOMX() +{ + OMX_ERRORTYPE error; + omx_running=false; + VideoVPEOGL *video=(VideoVPEOGL*)Video::getInstance(); + Log::getInstance()->log("Audio", Log::DEBUG, "enter deallocatecodecsomx"); + DeinitDecoderLibAV(); + + video->LockClock(); + if (cur_input_buf_omx) { + cur_input_buf_omx->nFlags|=OMX_BUFFERFLAG_EOS; + OMX_ERRORTYPE error=OMX_EmptyThisBuffer(omx_aud_rend/*dec*/,cur_input_buf_omx); + if (error!=OMX_ErrorNone) { + Log::getInstance()->log("Audio", Log::DEBUG, "OMX_EmptyThisBuffer failed %x", error); + } + + cur_input_buf_omx=NULL;//write out old data + } + + if (omx_aud_rend/*dec*/) { + // first stop the omx elements + /* if (!video->ChangeComponentState(omx_aud_dec,OMX_StateIdle)) { + Log::getInstance()->log("Audio", Log::DEBUG, "aud_dec ChangeComponentState"); + }*/ + + video->UnlockClock(); + video->idleClock(); + video->LockClock(); + + if (!video->ChangeComponentState(omx_aud_rend,OMX_StateIdle)) { + Log::getInstance()->log("Audio", Log::DEBUG, "aud_rend ChangeComponentState"); + } + + // TODO proper deinit sequence + // first flush all buffers + + error=OMX_SendCommand(omx_aud_rend,OMX_CommandFlush, omx_rend_input_port, NULL); + if (error!=OMX_ErrorNone) { + Log::getInstance()->log("Audio", Log::DEBUG, "OMX_Flush rend in failed %x", error); + + } + + /* error=OMX_SendCommand(omx_aud_dec,OMX_CommandFlush, omx_codec_input_port, NULL); + if (error!=OMX_ErrorNone){ + Log::getInstance()->log("Audio", Log::DEBUG, "OMX_Flush codec out failed %x", error); + + }*/ + + + /* if (!video->CommandFinished(omx_aud_dec,OMX_CommandFlush,omx_codec_input_port)) { + Log::getInstance()->log("Audio", Log::DEBUG, "flush cmd codec input failed"); + }*/ + + + + error=OMX_SendCommand(omx_clock,OMX_CommandFlush, omx_clock_output_port, NULL); + if (error!=OMX_ErrorNone){ + Log::getInstance()->log("Audio", Log::DEBUG, "OMX_Flush clock out failed %x", error); + + } + + error=OMX_SendCommand(omx_aud_rend,OMX_CommandFlush, omx_rend_clock_port, NULL); + if (error!=OMX_ErrorNone){ + Log::getInstance()->log("Audio", Log::DEBUG, "OMX_Flush rend clock failed %x", error); + + } + + if (!video->CommandFinished(omx_clock,OMX_CommandFlush,omx_clock_output_port) || + !video->CommandFinished(omx_aud_rend,OMX_CommandFlush,omx_rend_clock_port)) { + Log::getInstance()->log("Audio", Log::DEBUG, "flush cmd clock shed failed"); + } + + DestroyInputBufsOMX(); + + //todo flushing + if (!video->DisablePort(omx_aud_rend,omx_rend_input_port,true)) { + Log::getInstance()->log("Audio", Log::DEBUG, "Disable Tunnel Port failed 1"); + } + + /* if (!video->DisablePort(omx_aud_dec,omx_codec_output_port,true)) { + Log::getInstance()->log("Audio", Log::DEBUG, "Disable Tunnel Port failed 6"); + } + + if (!video->DisablePort(omx_aud_dec,omx_codec_input_port,true)) { + Log::getInstance()->log("Audio", Log::DEBUG, "Disable Tunnel Port failed 7"); + }*/ + + + if (!video->DisablePort(omx_aud_rend,omx_rend_clock_port,true)) { + Log::getInstance()->log("Audio", Log::DEBUG, "Disable Tunnel Port failed 4"); + } + + if (!video->DisablePort(omx_clock,omx_clock_output_port,true)) { + Log::getInstance()->log("Audio", Log::DEBUG, "Disable Tunnel Port failed 5"); + } + + + + /* error=OMX_SetupTunnel(omx_aud_dec,omx_codec_output_port,NULL,NULL); + if (error!=OMX_ErrorNone) { + Log::getInstance()->log("Audio", Log::DEBUG, "OMX_Setup tunnel teardown failed %x", error); + + }*/ + + + + error=OMX_SetupTunnel(omx_aud_rend,omx_rend_input_port,NULL,NULL); + if (error!=OMX_ErrorNone) { + Log::getInstance()->log("Audio", Log::DEBUG, "OMX_Setup tunnel teardown failed %x", error); + + } + + error=OMX_SetupTunnel(omx_clock,omx_clock_output_port,NULL,NULL); + if (error!=OMX_ErrorNone) { + Log::getInstance()->log("Audio", Log::DEBUG, "OMX_Setup tunnel teardown failed %x", error); + + } + + error=OMX_SetupTunnel(omx_aud_rend,omx_rend_clock_port,NULL,NULL); + if (error!=OMX_ErrorNone) { + Log::getInstance()->log("Audio", Log::DEBUG, "OMX_Setup tunnel teardown failed %x", error); + + } + + + //error=OMX_FreeHandle(omx_aud_dec); + error=OMX_FreeHandle(omx_aud_rend); + video->UnlockClock(); + video->destroyClock(); + omx_aud_rend/*dec*/=NULL; + if (error!=OMX_ErrorNone) { + Log::getInstance()->log("Audio", Log::DEBUG, "FreeHandle failed %d", error); + } + } else video->UnlockClock(); + Log::getInstance()->log("Audio", Log::DEBUG, "leave deallocate codecs OMX"); + + return 1; +} + + + int AudioVPE::stop() { if (!initted) return 0; + Log::getInstance()->log("Audio", Log::DEBUG, "Audio stop called"); + DeAllocateCodecsOMX(); //if (ioctl(fdAudio, AV_SET_AUD_RESET, 0x11) != 0) return 0; return 1; } @@ -416,19 +1106,35 @@ int AudioVPE::unMute() return 1; } -int AudioVPE::pause() -{ - if (!initted) return 0; +int AudioVPE::pause() { + if (!initted) + return 0; + if (!paused) { + paused = true; + VideoVPEOGL *vw = (VideoVPEOGL*) Video::getInstance(); + vw->LockClock(); + OMX_ERRORTYPE error; + error = OMX_SendCommand(omx_aud_rend, OMX_CommandFlush, + omx_rend_input_port, NULL); + if (error != OMX_ErrorNone) { + Log::getInstance()->log("Audio", Log::DEBUG, + "OMX_Flush rend in failed %x", error); - // if (ioctl(fdAudio, AV_SET_AUD_PAUSE, 1) != 0) return 0; - return 1; + } + vw->UnlockClock(); + vw->clockPause(); + } + return 1; } int AudioVPE::unPause() { if (!initted) return 0; - - // if (ioctl(fdAudio, AV_SET_AUD_UNPAUSE, 1) != 0) return 0; + if (paused) { + paused=false; // may be also change omx clock + VideoVPEOGL *vw = (VideoVPEOGL*) Video::getInstance(); + vw->clockUnpause(); + } return 1; } @@ -437,7 +1143,7 @@ int AudioVPE::reset() if (!initted) return 0; //test(); Log::getInstance()->log("Audio", Log::DEBUG, "reset called"); - + DeAllocateCodecsOMX(); // if (ioctl(fdAudio, AV_SET_AUD_RESET, 0x11) != 0) return 0; // Log::getInstance()->log("Audio", Log::DEBUG, "reset back"); @@ -504,59 +1210,313 @@ void AudioVPE::PrepareMediaSample(const MediaPacketList& mplist,UINT samplepos) packet = mplist.front(); } -UINT AudioVPE::DeliverMediaSample(UCHAR* buffer, UINT* samplepos) -{/* - VideoVPEOGL *video=(VideoVPEOGL*)Video::getInstance(); - //Log::getInstance()->log("Audio", Log::DEBUG, "lastpacket %d lastbuddypacket %d currentpacket %d",lastpacketnum,video->getLastPacketNum(),packet.index); - currentpacketnum=packet.index; - if (lastpacketnum!=-1 && packet.index-1!=lastpacketnum && packet.index-1>video->getLastPacketNum()) return 0; //Not in order - - //format pes - switch (packet.type) { - case MPTYPE_MPEG_AUDIO: - buffer[packet.pos_buffer + 3]=0xc0; break; - case MPTYPE_AC3: - buffer[packet.pos_buffer +buffer[packet.pos_buffer+8]+9]=0x80; - buffer[packet.pos_buffer + 3]=0xbd; break; - break; - default: - case MPTYPE_AC3_PRE13://Not tested no recording availiable - buffer[packet.pos_buffer + 3]=0xbd; break; - break; - }; - - if (packet.type!=lastAType && lastpacketnum!=-1){//Format Change //Push data out ! - video->deinitMuxer(); - lastAType=packet.type; - video->initMuxer(); - } - lastAType=packet.type; - - - /* Mutex *mutex=video->getMuxMutex(); - mutex->Lock(); - FILE *muxout=video->getMuxFile(); - if (!muxout) {mutex->Unlock(); return 0;}* - int written=0; - //written=fwrite(buffer + packet.pos_buffer,1,packet.length,muxout); - written=video->WriteOutTS(buffer + packet.pos_buffer,packet.length,packet.type); - lastpacketnum=packet.index; - - //mutex->Unlock(); - - //Log::getInstance()->log("Audio", Log::DEBUG, "wrote %d bytes to mux",written); - - if (written == (int)packet.length) { *samplepos = 0; return 1;} - if (written <= 0) { - return 0; - } - *samplepos = written;*/ - // Handle a partial write. Is this possible? Should we bother? No! - - *samplepos=packet.length; - return 1; +UINT AudioVPE::DeliverMediaSample(UCHAR* buffer, UINT* samplepos) { + DeliverMediaPacket(packet, buffer, samplepos); + if (*samplepos == packet.length) { + *samplepos = 0; + return 1; + } else + return 0; } -void AudioVPE::ResetTimeOffsets() -{ + +long long AudioVPE::correctAudioLatency(long long pts,int addsamples,int srate) { + + VideoVPEOGL *video = (VideoVPEOGL*) Video::getInstance(); + video->LockClock(); + OMX_PARAM_U32TYPE audio_lat; + OMX_ERRORTYPE error; + memset(&audio_lat, 0, sizeof(audio_lat)); + audio_lat.nSize = sizeof(audio_lat); + audio_lat.nVersion.nVersion = OMX_VERSION; + audio_lat.nPortIndex = omx_rend_input_port; + + error = OMX_GetConfig(omx_aud_rend, OMX_IndexConfigAudioRenderingLatency, + &audio_lat); + video->UnlockClock(); + if (error != OMX_ErrorNone) { + Log::getInstance()->log("Audio", Log::DEBUG, + "Init OMX_IndexConfigAudioRenderingLatencyfailed %x %d", error, + omx_rend_input_port); + return pts; // no correction in case of error + } + /*Log::getInstance()->log("Audio", Log::DEBUG, "Current audio latency %d", + audio_lat.nU32);*/ + + long long workpts=0; + workpts+=addsamples; + workpts-=audio_lat.nU32; + workpts*=10LL*1000LL*1000LL; + workpts=workpts/((long long)srate); //one second /samplerate + workpts+=pts; + + return workpts; +} + + + +UINT AudioVPE::DeliverMediaPacket(MediaPacket packet, const UCHAR* buffer, + UINT *samplepos) { + /*First Check, if we have an audio sample*/ + VideoVPEOGL *vw = (VideoVPEOGL*) Video::getInstance(); + bool achange=false; + OMX_ERRORTYPE error; + Log *logger=Log::getInstance(); + if (vw->InIframemode()) { + samplepos = 0; + MILLISLEEP(10); + return 0; //Not in iframe mode! + } + + if (!omx_running) return 0; // if we are not runnig do not do this + if (paused) return 0; //Block if we pause + + UINT headerstrip = 0; + if (packet.disconti) { + firstsynched = false; + if (cur_input_buf_omx) { + OMX_ERRORTYPE error = OMX_EmptyThisBuffer(omx_aud_rend/*dec*/, + cur_input_buf_omx); + if (error != OMX_ErrorNone) { + Log::getInstance()->log("Audio", Log::DEBUG, + "OMX_EmptyThisBuffer failed %x", error); + } + cur_input_buf_omx = NULL; + } + } + + if (packet.type != lastAType) {//Format Change //Push data out ! + firstsynched = false; + achange=true; + lastAType = packet.type; + + if (cur_input_buf_omx) { + OMX_ERRORTYPE error = OMX_EmptyThisBuffer(omx_aud_rend/*dec*/, + cur_input_buf_omx); + if (error != OMX_ErrorNone) { + Log::getInstance()->log("Audio", Log::DEBUG, + "OMX_EmptyThisBuffer failed %x", error); + } + cur_input_buf_omx = NULL; + } + if (!ChangeAudioPortConfig()) { + Log::getInstance()->log("Audio", Log::DEBUG, + "Changing audio port config failed", error); + } + + } + + /*Inspect PES-Header */ + if (*samplepos == 0 && packet.type != MPTYPE_MPEG_AUDIO_LAYER3) {//stripheader + headerstrip = buffer[packet.pos_buffer + 8] + 9; + if (packet.type == MPTYPE_AC3) + headerstrip += 4; //skip ac3 bytes + *samplepos += headerstrip; + if (packet.synched) { + if (cur_input_buf_omx) { + cur_input_buf_omx->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME; + OMX_ERRORTYPE error = OMX_EmptyThisBuffer(omx_aud_rend/*dec*/, + cur_input_buf_omx); + if (error != OMX_ErrorNone) { + Log::getInstance()->log("Audio", Log::DEBUG, + "OMX_EmptyThisBuffer failed %x", error); + } + //FrameWaitforDisplay(lastreftimeOMX); + vw->AdjustAudioPTS(correctAudioLatency(lastreftimeOMX,cur_input_buf_omx->nFilledLen/(2*2),48000)); + + cur_input_buf_omx = NULL;//write out old data + } + firstsynched = true; + } else { + if (!firstsynched) {// + *samplepos = packet.length;//if we have not processed at least one + return packet.length;//synched packet ignore it! + } + } + } + if (!cur_input_buf_omx) { + input_bufs_omx_mutex.Lock(); + if (input_bufs_omx_free.size()==0) { + input_bufs_omx_mutex.Unlock(); + //Log::getInstance()->log("Audio", Log::DEBUG, "Deliver MediaPacket no free sample"); + return 0; // we do not have a free media sample + + } + cur_input_buf_omx=input_bufs_omx_free.front(); + cur_input_buf_omx->nFilledLen=0; + cur_input_buf_omx->nOffset=0; + cur_input_buf_omx->nTimeStamp=0; + input_bufs_omx_free.pop_front(); + input_bufs_omx_mutex.Unlock(); + } + + + if (cur_input_buf_omx->nFilledLen == 0) {//will only be changed on first packet + if (packet.synched) { + //Log::getInstance()->log("Audio", Log::DEBUG, + // "packet synched marker"); + + //lastreftimePTS=packet.pts; + if (omx_first_frame) { // TODO time + cur_input_buf_omx->nFlags = OMX_BUFFERFLAG_STARTTIME; + Log::getInstance()->log("Audio", Log::DEBUG, "Starttime"); + omx_first_frame = false; + } else { + cur_input_buf_omx->nFlags = 0; + cur_input_buf_omx->nFlags|=OMX_BUFFERFLAG_TIME_UNKNOWN; + } + lastreftimeOMX = packet.presentation_time; + Log::getInstance()->log("Audio", Log::DEBUG, + "Time code %lld pts %lld dts %lld", lastreftimeOMX, packet.pts,packet.dts); + lastreftimePTS = packet.pts; + cur_input_buf_omx->nTimeStamp =0;// lastreftimeOMX; // the clock component is faulty; + } else { + // Log::getInstance()->log("Audio", Log::DEBUG, + // "packet NOT synched marker"); + cur_input_buf_omx->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN; + cur_input_buf_omx->nTimeStamp = 0; + + } + if (packet.disconti || achange) { + cur_input_buf_omx->nFlags |= OMX_BUFFERFLAG_DISCONTINUITY; + //mp23codec_context_libav->frame_size=-1; + //ac3codec_context_libav->frame_size=-1; + } + + } + + unsigned int haveToCopy=packet.length-*samplepos; + if (passthrough) { + //TODO + } else { + int len; + int gotta; + int framesize=0; + int errcount=0; + + AVCodecContext *current_context; + switch (packet.type) { + case MPTYPE_MPEG_AUDIO: + case MPTYPE_MPEG_AUDIO_LAYER3: { + current_context = mp23codec_context_libav; + if (current_context->frame_size<0) framesize=1152; //Maximum framesize + else framesize=current_context->frame_size; + }break; + case MPTYPE_AC3: + case MPTYPE_AC3_PRE13: { + current_context = ac3codec_context_libav; + }break; + }; + + incoming_paket_libav.data =(uint8_t*) buffer+packet.pos_buffer+*samplepos; + incoming_paket_libav.size = haveToCopy; + + while (haveToCopy> 0 && errcount<2) { + + //Log::getInstance()->log("Audio", Log::DEBUG,"libav in %d %d",framesize,current_context->frame_size); + len = avcodec_decode_audio4(current_context, decode_frame_libav, + &gotta, &incoming_paket_libav); + // Log::getInstance()->log("Audio", Log::DEBUG,"libav out"); + if (len>0) { + incoming_paket_libav.data += len; + haveToCopy -= len; + *samplepos += len; + errcount=0; + if (current_context->frame_size>0) framesize=min(current_context->frame_size,haveToCopy); + else framesize=haveToCopy; + } else { + errcount++; + framesize=haveToCopy; + } + + incoming_paket_libav.size =framesize; + if (gotta) { + //Log::getInstance()->log("Audio", Log::DEBUG, + // "Got a frame"); + int dsize = av_samples_get_buffer_size(NULL, + current_context->channels, decode_frame_libav->nb_samples, + current_context->sample_fmt, 1); + if ((cur_input_buf_omx->nFilledLen + dsize) + > cur_input_buf_omx->nAllocLen ) { + // I doubt that this will ever happen + Log::getInstance()->log("Audio", Log::DEBUG, + "P 2 Time code %lld pts %lld", lastreftimeOMX, packet.pts); + OMX_ERRORTYPE error = OMX_EmptyThisBuffer(omx_aud_rend/*dec*/, + cur_input_buf_omx); + if (error != OMX_ErrorNone) { + Log::getInstance()->log("Audio", Log::DEBUG, + "OMX_EmptyThisBuffer failed %x", error); + } + cur_input_buf_omx = NULL; + + if (!cur_input_buf_omx) { + int count = 0; + while (count < 10 && omx_running) { + count++; + input_bufs_omx_mutex.Lock(); + if (input_bufs_omx_free.size() == 0) { + input_bufs_omx_mutex.Unlock(); + Log::getInstance()->log("Audio", Log::DEBUG, + "Deliver MediaPacket no free sample"); + MILLISLEEP(5); + if (!omx_running) return false; + continue; + } + cur_input_buf_omx = input_bufs_omx_free.front(); + cur_input_buf_omx->nFilledLen = 0; + cur_input_buf_omx->nOffset = 0; + cur_input_buf_omx->nTimeStamp = 0; + input_bufs_omx_free.pop_front(); + input_bufs_omx_mutex.Unlock(); + break; + } + if (!cur_input_buf_omx) return *samplepos; + } + + } + + //Log::getInstance()->log("Audio", Log::DEBUG,"memcpy in %d %d %d" ,dsize,current_context->sample_rate,cur_input_buf_omx->nFilledLen); + memcpy(cur_input_buf_omx->pBuffer + cur_input_buf_omx->nFilledLen, + decode_frame_libav->data[0], dsize); + //Log::getInstance()->log("Audio", Log::DEBUG,"memcpy out"); + cur_input_buf_omx->nFilledLen += dsize; + } else { + //Log::getInstance()->log("Audio", Log::DEBUG,"Incomplete mpeg frames in pes packet %d",incoming_paket_libav.size); + } + + } + + } + + if (cur_input_buf_omx->nFilledLen) { + Log::getInstance()->log("Audio", Log::DEBUG, + "P 3 Time code %lld pts %lld", lastreftimeOMX, packet.pts); + error = OMX_EmptyThisBuffer(omx_aud_rend/*dec*/, cur_input_buf_omx); + if (error != OMX_ErrorNone) { + Log::getInstance()->log("Audio", Log::DEBUG, + "OMX_EmptyThisBuffer failed %x", error); + } + if (packet.synched) vw->AdjustAudioPTS(correctAudioLatency(lastreftimeOMX,cur_input_buf_omx->nFilledLen/(2*2),48000)); + cur_input_buf_omx = NULL; + } + + + + *samplepos=packet.length; + return packet.length; + +} + + + +long long AudioVPE::SetStartOffset(long long curreftime, bool *rsync){ + VideoVPEOGL *vw=(VideoVPEOGL*)Video::getInstance(); + return vw->SetStartAudioOffset(curreftime,rsync); } + +void AudioVPE::ResetTimeOffsets() { + VideoVPEOGL *vw=(VideoVPEOGL*)Video::getInstance(); + vw->ResetTimeOffsets(); +} + + diff --git a/audiovpe.h b/audiovpe.h index 1d52f23..7524c2e 100644 --- a/audiovpe.h +++ b/audiovpe.h @@ -28,7 +28,12 @@ #include "defines.h" #include "audio.h" +#include "videovpeogl.h" +extern "C" { +#include +#include +} @@ -55,15 +60,17 @@ class AudioVPE : public Audio int mute(); int unMute(); bool supportsAc3() { return true; } + virtual bool maysupportAc3(){return true;} //Writing Data to Audiodevice virtual void PrepareMediaSample(const MediaPacketList&, UINT samplepos); virtual UINT DeliverMediaSample(UCHAR* buffer, UINT *samplepos); - virtual long long SetStartOffset(long long curreftime, bool *rsync) { return 0; }; + UINT DeliverMediaPacket(MediaPacket packet, const UCHAR* buffer,UINT *samplepos); + + virtual long long SetStartOffset(long long curreftime, bool *rsync); virtual void ResetTimeOffsets(); - int getLastPacketNum() {return lastpacketnum;}; - int getCurrentPacketNum(){return currentpacketnum;}; + UCHAR getLastAType() {return lastAType;} bool loadOptionsfromServer(VDR* vdr); @@ -80,12 +87,13 @@ class AudioVPE : public Audio int initAllParams(); UCHAR streamType; UCHAR lastAType; - int lastpacketnum; - int currentpacketnum; + bool firstsynched; MediaPacket packet; UINT packetpos; + bool paused; + bool hdmi; // use hdmi as audio output bool passthrough; // use audio passthrough for the current audio type @@ -98,6 +106,60 @@ class AudioVPE : public Audio int prefered_ac3; //0 stereo PCM, 1 passthrough 2 Multichannel PCM int prefered_mp2; int prefered_mp3; + + + + static OMX_ERRORTYPE EmptyBufferDone_OMX(OMX_IN OMX_HANDLETYPE hcomp,OMX_IN OMX_PTR appdata,OMX_IN OMX_BUFFERHEADERTYPE* bulibaver); + static OMX_ERRORTYPE FillBufferDone_OMX(OMX_IN OMX_HANDLETYPE hcomp, OMX_IN OMX_PTR appdata,OMX_IN OMX_BUFFERHEADERTYPE* bulibaver); + + + + void ReturnEmptyOMXBuffer(OMX_BUFFERHEADERTYPE* bulibaver); + + // OMX_HANDLETYPE omx_aud_dec; + OMX_HANDLETYPE omx_aud_rend; + OMX_HANDLETYPE omx_clock; + + //OMX_U32 omx_codec_input_port; + //OMX_U32 omx_codec_output_port; + OMX_U32 omx_rend_input_port; + OMX_U32 omx_rend_clock_port; + OMX_U32 omx_clock_output_port; + + OMX_TICKS lastreftimeOMX; + ULLONG lastreftimePTS; + + + + int AllocateCodecsOMX(); + int DeAllocateCodecsOMX(); + + int PrepareInputBufsOMX(); + int DestroyInputBufsOMX(); + + int ChangeAudioPortConfig(); + int ChangeAudioDestination(); + long long correctAudioLatency(long long pts,int addsamples,int srate); + + vector input_bufs_omx_all; + list input_bufs_omx_free; + Mutex input_bufs_omx_mutex; + OMX_BUFFERHEADERTYPE* cur_input_buf_omx; + + bool omx_running; + bool omx_first_frame; + + AVCodec *ac3codec_libav; + AVCodecContext *ac3codec_context_libav; + AVCodec *mp23codec_libav; + AVCodecContext *mp23codec_context_libav; + AVPacket incoming_paket_libav; + AVFrame *decode_frame_libav; + + + int InitDecoderLibAV(); + void DeinitDecoderLibAV(); + }; #endif diff --git a/defines.h b/defines.h index fcb0bf9..1cb045d 100644 --- a/defines.h +++ b/defines.h @@ -50,6 +50,7 @@ long long getTimeMS(); /* #define STRTOULL _strtoui64 */ #define STRTOUL strtoul #define CLOSESOCKET closesocket + #define DEFAULT_TCP_WINDOWSIZENR 1 /*=2048*/ #else @@ -91,8 +92,8 @@ long long getTimeMS(); #define Led_TYPE LedRaspberry //this is device dependent #define Osd_TYPE OsdOpenGL // This OpenGL ES 2.0, in the moment only for raspberry, but might be splitted for other devices #define OsdStartDev "" - #define Audio_TYPE AudioVPE // This is Audio based on VPE (Vomp Presentation Engine) should support OpenMax and Alsa with ffmpeg in the end - #define Video_TYPE VideoVPEOGL // This is Video based on VPE (Vomp Presentation Engine) should support OpenMax and ffmpeg and opengl in the end + #define Audio_TYPE AudioVPE // This is Audio based on VPE (Vomp Presentation Engine) should support OpenMax and libav for decoding + #define Video_TYPE VideoVPEOGL // This is Video based on VPE (Vomp Presentation Engine) should support OpenMax @@ -103,10 +104,14 @@ long long getTimeMS(); #define VPE_OMX_VIDEO_REND "OMX.broadcom.video_render" #define VPE_OMX_VIDEO_DEINTERLACE "OMX.broadcom.image_fx" #define VPE_OMX_CLOCK "OMX.broadcom.clock" + #define VPE_OMX_AUDIO_DECODER "OMX.broadcom.audio_decode" + #define VPE_OMX_AUDIO_REND "OMX.broadcom.audio_render" //#define VPE_LIBAV_SUPPORT // #define VPE_LIBAV_MPEG2_TRANSCODING + #define DEFAULT_TCP_WINDOWSIZENR 6 /*=2048*/ + #endif #ifdef VOMP_PLATTFORM_MVP #define Remote_TYPE RemoteMVP @@ -117,6 +122,7 @@ long long getTimeMS(); #define OsdStartDev "/dev/stbgfx" #define Audio_TYPE AudioMVP #define Video_TYPE VideoMVP + #define DEFAULT_TCP_WINDOWSIZENR 1 /*=2048*/ #endif #ifdef VOMP_PLATTFORM_NMT // This was the attempt to port vomp to nmt, it failed but maybe the code is useful at some time @@ -128,6 +134,7 @@ long long getTimeMS(); #define OsdStartDev "" #define Audio_TYPE AudioNMT #define Video_TYPE VideoNMT + #define DEFAULT_TCP_WINDOWSIZENR 1 /*=2048*/ #endif diff --git a/demuxer.cc b/demuxer.cc index e2e2fe7..9884f36 100644 --- a/demuxer.cc +++ b/demuxer.cc @@ -519,19 +519,19 @@ void Demuxer::setAspectRatio(enum AspectRatio ar) arcnt = 0; } -bool Demuxer::writeAudio() +bool Demuxer::writeAudio(bool * dataavail) { - return audiostream.drain(); + return audiostream.drain(dataavail); } -bool Demuxer::writeVideo() +bool Demuxer::writeVideo(bool * dataavail) { - return videostream.drain(); + return videostream.drain(dataavail); } -bool Demuxer::writeTeletext() +bool Demuxer::writeTeletext(bool * dataavail) { - return teletextstream.drain(); + return teletextstream.drain(dataavail); } bool Demuxer::submitPacket(PESPacket& packet) diff --git a/demuxer.h b/demuxer.h index a05f7bc..1db2749 100644 --- a/demuxer.h +++ b/demuxer.h @@ -97,9 +97,9 @@ class Demuxer void setAudioStream(int id); void setTeletextStream(int id); void setDVBSubtitleStream(int id); - bool writeAudio(); - bool writeVideo(); - bool writeTeletext(); + bool writeAudio(bool * dataavail=NULL); + bool writeVideo(bool * dataavail=NULL); + bool writeTeletext(bool * dataavail=NULL); virtual int scan(UCHAR* buf, int len) = 0; virtual int findPTS(UCHAR* buf, int len, ULLONG* dest) = 0; diff --git a/player.cc b/player.cc index 2c2b5b0..0c032bc 100644 --- a/player.cc +++ b/player.cc @@ -91,9 +91,13 @@ int Player::init(bool p_isPesRecording,double framespersecond) if (!teletext) return 0; teletext->setRecordigMode(true); unsigned int demux_video_size=2097152; - if (video->supportsh264()) demux_video_size*=5; + unsigned int demux_audio_size=524288; + if (video->supportsh264()) { + demux_video_size*=5*2;//5; + demux_audio_size*=2; + } - if (!demuxer->init(this, audio, video,teletext, demux_video_size,524288,65536, framespersecond, subtitles)) + if (!demuxer->init(this, audio, video,teletext, demux_video_size,demux_audio_size,65536, framespersecond, subtitles)) { logger->log("Player", Log::ERR, "Demuxer failed to init"); shutdown(); diff --git a/playerlivetv.cc b/playerlivetv.cc index 7113f8e..4e20bcb 100644 --- a/playerlivetv.cc +++ b/playerlivetv.cc @@ -666,7 +666,7 @@ void PlayerLiveTV::threadMethod() while(1) { -// logger->log("PlayerLiveTV", Log::DEBUG, "VS: %d pA %d",videoStartup,pendingAudioPlay); + logger->log("PlayerLiveTV", Log::DEBUG, "VS: %d pA %d",videoStartup,pendingAudioPlay); if (videoStartup && !pendingAudioPlay) // we are in S_VIDEOSTARTUP, afeed has signalled that it has written some data { logger->log("PlayerLiveTV", Log::DEBUG, "Enter prebuffering"); @@ -752,10 +752,13 @@ void PlayerLiveTV::threadMethod() while(streamChunks.size()) { + logger->log("PlayerLiveTV", Log::DEBUG, "chunk mark1"); chunkToDemuxer(); + logger->log("PlayerLiveTV", Log::DEBUG, "chunk mark2"); if (state == S_PREBUFFERING) { + logger->log("PlayerLiveTV", Log::DEBUG, "chunk mark3"); ++preBufferCount; ULONG percentDone = (ULONG)(preBufferCount / (float)preBufferAmount * 100); logger->log("PlayerLiveTV", Log::DEBUG, "Prebuffering %lu%%", percentDone); diff --git a/remote.cc b/remote.cc index 67fff6d..7c20b6f 100644 --- a/remote.cc +++ b/remote.cc @@ -127,7 +127,7 @@ void Remote::setRemoteType(UCHAR newType) void Remote::EnterLearningMode(UCHAR command) { - learnmode = command; //Armed + learnmode = command; //Armed } void Remote::ResetToDefault() diff --git a/remotelinux.cc b/remotelinux.cc index 93517da..b31cbb7 100644 --- a/remotelinux.cc +++ b/remotelinux.cc @@ -308,9 +308,13 @@ void RemoteLinux::InitHWCListwithDefaults() translist[W_G_HCW(W_HCW_KC,KEY_PLAYPAUSE)] = PLAYPAUSE; translist[W_G_HCW(W_HCW_KC,KEY_P)] = PLAYPAUSE; translist[W_G_HCW(W_HCW_KC,KEY_NEXT)] = SKIPFORWARD; + translist[W_G_HCW(W_HCW_KC,KEY_F2)] = SKIPFORWARD; translist[W_G_HCW(W_HCW_KC,KEY_PREVIOUS)] = SKIPBACK; + translist[W_G_HCW(W_HCW_KC,KEY_F1)] = SKIPBACK; translist[W_G_HCW(W_HCW_KC,KEY_FORWARD)] = FORWARD; + translist[W_G_HCW(W_HCW_KC,KEY_F)] = FORWARD; translist[W_G_HCW(W_HCW_KC,KEY_BACK)] = REVERSE; + translist[W_G_HCW(W_HCW_KC,KEY_R)] = REVERSE; translist[W_G_HCW(W_HCW_KC,KEY_MUTE)] = MUTE; translist[W_G_HCW(W_HCW_KC,KEY_F9)] = VOLUMEUP; translist[W_G_HCW(W_HCW_KC,KEY_F10)] = VOLUMEDOWN; diff --git a/stream.cc b/stream.cc old mode 100755 new mode 100644 index 710b55c..e2b1e55 --- a/stream.cc +++ b/stream.cc @@ -160,15 +160,17 @@ int Stream::put(const UCHAR* inbuf, int len, UCHAR type,unsigned int index) return ret; } -bool Stream::drain() +bool Stream::drain(bool * dataavail) { bool ret = false; + if (dataavail) *dataavail=false; lock(); UINT listlength = mediapackets.size(); if (listlength != 0) { draintarget->PrepareMediaSample(mediapackets, cur_packet_pos); unLock(); + if (dataavail) *dataavail=true; UINT consumed = draintarget->DeliverMediaSample(outbuf, &cur_packet_pos); lock(); if (consumed != 0) ret = true; diff --git a/stream.h b/stream.h index 26916eb..dc97dfc 100644 --- a/stream.h +++ b/stream.h @@ -46,7 +46,7 @@ class Stream void shutdown(); void flush(); int put(const UCHAR* inbuf, int len, UCHAR type,unsigned int index); - bool drain(); + bool drain(bool * dataavail=NULL); private: MediaPacketList mediapackets; diff --git a/threadp.cc b/threadp.cc index fdd7df1..a40a681 100644 --- a/threadp.cc +++ b/threadp.cc @@ -44,20 +44,24 @@ int ThreadP::threadStart() void ThreadP::threadStop() { - threadActive = 0; - // Signal thread here in case it's waiting - threadSignal(); - pthread_join(pthread, NULL); - this->threadPostStopCleanup(); + if (threadActive) { // we need this, on some implementations this will fail, if already stopped + threadActive = 0; + // Signal thread here in case it's waiting + threadSignal(); + pthread_join(pthread, NULL); + this->threadPostStopCleanup(); + } } void ThreadP::threadCancel() { - threadActive = 0; - pthread_cancel(pthread); - pthread_join(pthread, NULL); - this->threadPostStopCleanup(); + if (threadActive) { + threadActive = 0; + pthread_cancel(pthread); + pthread_join(pthread, NULL); + this->threadPostStopCleanup(); + } } diff --git a/vfeed.cc b/vfeed.cc old mode 100755 new mode 100644 diff --git a/videovpeogl.cc b/videovpeogl.cc index 294bc3a..1ce1253 100644 --- a/videovpeogl.cc +++ b/videovpeogl.cc @@ -31,7 +31,6 @@ VideoVPEOGL::VideoVPEOGL() { - lastpacketnum=-1; #ifdef VPE_OMX_SUPPORT omx_running=false; @@ -39,6 +38,7 @@ VideoVPEOGL::VideoVPEOGL() omx_vid_dec=0; cur_input_buf_omx=NULL; omx_h264=omx_mpeg2=true; + clock_references=0; #endif #ifdef VPE_LIBAV_SUPPORT @@ -94,8 +94,6 @@ int VideoVPEOGL::init(UCHAR tformat) if (initted) return 0; initted = 1; -// if ((fdVideo = open("/dev/vdec_dev", O_WRONLY)) < 0) return 0; - if (!setFormat(tformat)) { shutdown(); return 0; } if (!setConnection(COMPOSITERGB)) { shutdown(); return 0; } if (!setAspectRatio(ASPECT4X3)) { shutdown(); return 0; } @@ -105,10 +103,6 @@ int VideoVPEOGL::init(UCHAR tformat) setTVsize(ASPECT4X3); -/* if (format == PAL) setLetterboxBorder("38"); - else setLetterboxBorder("31");*/ - - /* new stulibav */ @@ -1029,6 +1023,7 @@ int VideoVPEOGL::play() { if (!initted) return 0; decoding_backend=0; + iframemode=false; #ifdef VPE_OMX_SUPPORT bool doomx=true; Log::getInstance()->log("Video", Log::DEBUG, "enter play"); @@ -1119,28 +1114,86 @@ int VideoVPEOGL::DeInitTranscoderLibAV() { #endif #ifdef VPE_OMX_SUPPORT -int VideoVPEOGL::AllocateCodecsOMX() + +int VideoVPEOGL::initClock() { OMX_ERRORTYPE error; - static OMX_CALLBACKTYPE callbacks= {&EventHandler_OMX,&EmptyBufferDone_OMX,&FillBufferDone_OMX}; + clock_mutex.Lock(); + if (clock_references==0) + { - Log::getInstance()->log("Video", Log::NOTICE, "Allocate Codecs OMX"); - //Clock, move later to audio + static OMX_CALLBACKTYPE callbacks= {&EventHandler_OMX,&EmptyBufferDone_OMX,&FillBufferDone_OMX}; + omx_events.clear(); - omx_events.clear(); + error=OMX_GetHandle(&omx_clock,VPE_OMX_CLOCK,NULL,&callbacks); - error=OMX_GetHandle(&omx_clock,VPE_OMX_CLOCK,NULL,&callbacks); + if (error!=OMX_ErrorNone) { + Log::getInstance()->log("Video", Log::DEBUG, "Init OMX clock failed %x", error); + clock_mutex.Unlock(); + DeAllocateCodecsOMX(); + return 0; + } + /* TODO Clock config to separate method */ + OMX_PORT_PARAM_TYPE p_param; + memset(&p_param,0,sizeof(p_param)); + p_param.nSize=sizeof(p_param); + p_param.nVersion.nVersion=OMX_VERSION; + error=OMX_GetParameter(omx_clock,OMX_IndexParamOtherInit,&p_param); + if (error!=OMX_ErrorNone) { + Log::getInstance()->log("Video", Log::DEBUG, "Init clock OMX_GetParameter failed %x", error); + clock_mutex.Unlock(); + DeAllocateCodecsOMX(); + return 0; + } + omx_clock_output_port=p_param.nStartPortNumber; - if (error!=OMX_ErrorNone){ - Log::getInstance()->log("Video", Log::DEBUG, "Init OMX clock failed %x", error); - DeAllocateCodecsOMX(); + for (unsigned int i=0;ilog("Video", Log::DEBUG, "Disable Ports OMX clock failed %d",i); + clock_mutex.Unlock(); + DeAllocateCodecsOMX(); + return 0; + } + } + + + + + } + Log::getInstance()->log("Video", Log::DEBUG, "init omx clock %x %x",this,omx_clock); + clock_references++; + clock_mutex.Unlock(); + return 1; +} + +int VideoVPEOGL::getClockAudioandInit(OMX_HANDLETYPE *p_omx_clock,OMX_U32 *p_omx_clock_output_port) +{ + OMX_ERRORTYPE error; + *p_omx_clock=NULL; + *p_omx_clock_output_port=0; + + if (!initClock()) { return 0; } + clock_mutex.Lock(); + OMX_TIME_CONFIG_ACTIVEREFCLOCKTYPE refclock; + memset(&refclock,0,sizeof(refclock)); + refclock.nSize=sizeof(refclock); + refclock.nVersion.nVersion=OMX_VERSION; + refclock.eClock=OMX_TIME_RefClockAudio; + + //refclock.eClock=OMX_TIME_RefClockVideo; + error=OMX_SetConfig(omx_clock,OMX_IndexConfigTimeActiveRefClock,&refclock); + if (error!=OMX_ErrorNone){ + Log::getInstance()->log("Video", Log::DEBUG, "Clock OMX_IndexConfigTimeActiveRefClock failed %x", error); + clock_mutex.Unlock(); + DeAllocateCodecsOMX(); + return 0; + } - /* TODO Clock config to separate method */ OMX_PORT_PARAM_TYPE p_param; memset(&p_param,0,sizeof(p_param)); p_param.nSize=sizeof(p_param); @@ -1148,20 +1201,70 @@ int VideoVPEOGL::AllocateCodecsOMX() error=OMX_GetParameter(omx_clock,OMX_IndexParamOtherInit,&p_param); if (error!=OMX_ErrorNone){ Log::getInstance()->log("Video", Log::DEBUG, "Init clock OMX_GetParameter failed %x", error); + clock_mutex.Unlock(); DeAllocateCodecsOMX(); return 0; } - omx_clock_output_port=p_param.nStartPortNumber; - for (unsigned int i=0;ilog("Video", Log::DEBUG, "Disable Ports OMX clock failed %d",i); + OMX_TIME_CONFIG_CLOCKSTATETYPE clock_conf; + memset(&clock_conf,0,sizeof(clock_conf)); + clock_conf.nSize=sizeof(clock_conf); + clock_conf.nVersion.nVersion=OMX_VERSION; + clock_conf.eState=OMX_TIME_ClockStateWaitingForStartTime; + clock_conf.nStartTime=0; + clock_conf.nOffset=0; + if (clock_references==1) clock_conf.nWaitMask=OMX_CLOCKPORT1; + else clock_conf.nWaitMask=OMX_CLOCKPORT0|OMX_CLOCKPORT1; + error=OMX_SetConfig(omx_clock,OMX_IndexConfigTimeClockState,&clock_conf); + if (error!=OMX_ErrorNone) { + Log::getInstance()->log("Video", Log::DEBUG, "Clock IndexConfigTimeClockState failed %x", error); + } + + + *p_omx_clock_output_port=p_param.nStartPortNumber+1; + *p_omx_clock=omx_clock; + clock_mutex.Unlock(); + return 1; +} + +int VideoVPEOGL::getClockVideoandInit() +{ + OMX_ERRORTYPE error; + + if (!initClock()) { + return 0; + } + clock_mutex.Lock(); + + if (clock_references==1) { // only if no audio is attached to this clock! + OMX_TIME_CONFIG_ACTIVEREFCLOCKTYPE refclock; + memset(&refclock,0,sizeof(refclock)); + refclock.nSize=sizeof(refclock); + refclock.nVersion.nVersion=OMX_VERSION; + + //refclock.eClock=OMX_TIME_RefClockAudio; + + refclock.eClock=OMX_TIME_RefClockVideo; + error=OMX_SetConfig(omx_clock,OMX_IndexConfigTimeActiveRefClock,&refclock); + if (error!=OMX_ErrorNone) { + Log::getInstance()->log("Video", Log::DEBUG, "Clock OMX_IndexConfigTimeActiveRefClock failed %x", error); + clock_mutex.Unlock(); DeAllocateCodecsOMX(); return 0; } } - + OMX_PORT_PARAM_TYPE p_param; + memset(&p_param,0,sizeof(p_param)); + p_param.nSize=sizeof(p_param); + p_param.nVersion.nVersion=OMX_VERSION; + error=OMX_GetParameter(omx_clock,OMX_IndexParamOtherInit,&p_param); + if (error!=OMX_ErrorNone){ + Log::getInstance()->log("Video", Log::DEBUG, "Init clock OMX_GetParameter failed %x", error); + clock_mutex.Unlock(); + DeAllocateCodecsOMX(); + return 0; + } OMX_TIME_CONFIG_CLOCKSTATETYPE clock_conf; @@ -1171,46 +1274,83 @@ int VideoVPEOGL::AllocateCodecsOMX() clock_conf.eState=OMX_TIME_ClockStateWaitingForStartTime; clock_conf.nStartTime=0; clock_conf.nOffset=0; - clock_conf.nWaitMask=OMX_CLOCKPORT0; + if (clock_references==1) clock_conf.nWaitMask=OMX_CLOCKPORT0; + else clock_conf.nWaitMask=OMX_CLOCKPORT0|OMX_CLOCKPORT1; error=OMX_SetConfig(omx_clock,OMX_IndexConfigTimeClockState,&clock_conf); - if (error!=OMX_ErrorNone){ + if (error!=OMX_ErrorNone) { Log::getInstance()->log("Video", Log::DEBUG, "Clock IndexConfigTimeClockState failed %x", error); - DeAllocateCodecsOMX(); - return 0; } + omx_clock_output_port=p_param.nStartPortNumber; + clock_mutex.Unlock(); - OMX_TIME_CONFIG_ACTIVEREFCLOCKTYPE refclock; - memset(&refclock,0,sizeof(refclock)); - refclock.nSize=sizeof(refclock); - refclock.nVersion.nVersion=OMX_VERSION; + return 1; +} - if (/*AUDIO*/ false) { - refclock.eClock=OMX_TIME_RefClockAudio; - } else { - refclock.eClock=OMX_TIME_RefClockVideo; - } - error=OMX_SetConfig(omx_clock,OMX_IndexConfigTimeActiveRefClock,&refclock); - if (error!=OMX_ErrorNone){ - Log::getInstance()->log("Video", Log::DEBUG, "Clock OMX_IndexConfigTimeActiveRefClock failed %x", error); - DeAllocateCodecsOMX(); - return 0; +void VideoVPEOGL::clockUnpause() +{ + OMX_ERRORTYPE error; + clock_mutex.Lock(); + OMX_TIME_CONFIG_CLOCKSTATETYPE clock_conf; + memset(&clock_conf,0,sizeof(clock_conf)); + clock_conf.nSize=sizeof(clock_conf); + clock_conf.nVersion.nVersion=OMX_VERSION; + clock_conf.eState=OMX_TIME_ClockStateRunning; + clock_conf.nStartTime=0; + clock_conf.nOffset=0; + clock_conf.nWaitMask=OMX_CLOCKPORT1; + error=OMX_SetConfig(omx_clock,OMX_IndexConfigTimeClockState,&clock_conf); + if (error!=OMX_ErrorNone) { + Log::getInstance()->log("Video", Log::DEBUG, "ClockUnpause IndexConfigTimeClockState failed %x", error); } - if (!ChangeComponentState(omx_clock,OMX_StateIdle)) { - Log::getInstance()->log("Video", Log::DEBUG, "omx_clock ChangeComponentState Idle"); - DeAllocateCodecsOMX(); - return 0; + clock_mutex.Unlock(); +} + + +void VideoVPEOGL::clockPause() +{ + OMX_ERRORTYPE error; + clock_mutex.Lock(); + OMX_TIME_CONFIG_CLOCKSTATETYPE clock_conf; + memset(&clock_conf,0,sizeof(clock_conf)); + clock_conf.nSize=sizeof(clock_conf); + clock_conf.nVersion.nVersion=OMX_VERSION; + clock_conf.eState=OMX_TIME_ClockStateStopped; + clock_conf.nStartTime=0; + clock_conf.nOffset=0; + clock_conf.nWaitMask=OMX_CLOCKPORT1; + error=OMX_SetConfig(omx_clock,OMX_IndexConfigTimeClockState,&clock_conf); + if (error!=OMX_ErrorNone) { + Log::getInstance()->log("Video", Log::DEBUG, "ClockUnpause IndexConfigTimeClockState failed %x", error); } + clock_mutex.Unlock(); +} +int VideoVPEOGL::AllocateCodecsOMX() +{ + OMX_ERRORTYPE error; + static OMX_CALLBACKTYPE callbacks= {&EventHandler_OMX,&EmptyBufferDone_OMX,&FillBufferDone_OMX}; - /* TODO end */ + Log::getInstance()->log("Video", Log::NOTICE, "Allocate Codecs OMX"); + //Clock, move later to audio including events + Log::getInstance()->log("Video", Log::DEBUG, "Nmark1 "); + if (!getClockVideoandInit()){ + return 0;// get the clock and init it if necessary + } + Log::getInstance()->log("Video", Log::DEBUG, "Nmark2 "); + if (!idleClock()) { + Log::getInstance()->log("Video", Log::DEBUG, "idleClock failed"); + return 0; + } + /* TODO end */ + clock_mutex.Lock(); if (h264) { error=OMX_GetHandle(&omx_vid_dec,VPE_OMX_H264_DECODER,NULL,&callbacks); } else { @@ -1219,18 +1359,21 @@ int VideoVPEOGL::AllocateCodecsOMX() if (error!=OMX_ErrorNone){ Log::getInstance()->log("Video", Log::DEBUG, "Init OMX video decoder failed %x", error); + clock_mutex.Unlock(); DeAllocateCodecsOMX(); return 0; } - + Log::getInstance()->log("Video", Log::DEBUG, "Nmark3 "); + OMX_PORT_PARAM_TYPE p_param; memset(&p_param,0,sizeof(p_param)); p_param.nSize=sizeof(p_param); p_param.nVersion.nVersion=OMX_VERSION; error=OMX_GetParameter(omx_vid_dec,OMX_IndexParamVideoInit,&p_param); if (error!=OMX_ErrorNone){ Log::getInstance()->log("Video", Log::DEBUG, "Init OMX h264 decoder OMX_GetParameter failed %x", error); + clock_mutex.Unlock(); DeAllocateCodecsOMX(); return 0; } @@ -1239,10 +1382,12 @@ int VideoVPEOGL::AllocateCodecsOMX() if (!DisablePort(omx_vid_dec,omx_codec_input_port) || !DisablePort(omx_vid_dec,omx_codec_output_port)) { Log::getInstance()->log("Video", Log::DEBUG, "Disable Ports OMX video decoder failed"); + clock_mutex.Unlock(); DeAllocateCodecsOMX(); return 0; } + Log::getInstance()->log("Video", Log::DEBUG, "Nmark4 "); OMX_PARAM_BRCMVIDEODECODEERRORCONCEALMENTTYPE conceal; memset(&conceal,0,sizeof(conceal)); @@ -1253,6 +1398,7 @@ int VideoVPEOGL::AllocateCodecsOMX() error=OMX_SetParameter(omx_vid_dec,OMX_IndexParamBrcmVideoDecodeErrorConcealment,&conceal); if (error!=OMX_ErrorNone){ Log::getInstance()->log("Video", Log::DEBUG, "OMX_IndexParamBrcmVideoDecodeErrorConcealment failed %x", error); + clock_mutex.Unlock(); DeAllocateCodecsOMX(); return 0; } @@ -1261,6 +1407,7 @@ int VideoVPEOGL::AllocateCodecsOMX() error=OMX_GetHandle(&omx_vid_sched,VPE_OMX_VIDEO_SCHED,NULL,&callbacks); if (error!=OMX_ErrorNone){ Log::getInstance()->log("Video", Log::DEBUG, "Init OMX video scheduler failed %x", error); + clock_mutex.Unlock(); DeAllocateCodecsOMX(); return 0; } @@ -1270,6 +1417,7 @@ int VideoVPEOGL::AllocateCodecsOMX() error=OMX_GetParameter(omx_vid_sched,OMX_IndexParamVideoInit,&p_param); if (error!=OMX_ErrorNone){ Log::getInstance()->log("Video", Log::DEBUG, "Init OMX video scheduler OMX_GetParameter failed %x", error); + clock_mutex.Unlock(); DeAllocateCodecsOMX(); return 0; } @@ -1280,6 +1428,7 @@ int VideoVPEOGL::AllocateCodecsOMX() error=OMX_GetParameter(omx_vid_sched,OMX_IndexParamOtherInit,&p_param); if (error!=OMX_ErrorNone){ Log::getInstance()->log("Video", Log::DEBUG, "Init OMX video scheduler OMX_GetParameter failed %x", error); + clock_mutex.Unlock(); DeAllocateCodecsOMX(); return 0; } @@ -1290,6 +1439,7 @@ int VideoVPEOGL::AllocateCodecsOMX() if (!DisablePort(omx_vid_sched,omx_shed_input_port,true) || !DisablePort(omx_vid_sched,omx_shed_output_port,true) || !DisablePort(omx_vid_sched,omx_shed_clock_port,true)) { Log::getInstance()->log("Video", Log::DEBUG, "Disable Ports OMX video shed failed"); + clock_mutex.Unlock(); DeAllocateCodecsOMX(); return 0; } @@ -1298,6 +1448,7 @@ int VideoVPEOGL::AllocateCodecsOMX() error=OMX_GetHandle(&omx_vid_rend,VPE_OMX_VIDEO_REND,NULL,&callbacks); if (error!=OMX_ErrorNone){ Log::getInstance()->log("Video", Log::DEBUG, "Init OMX video rend failed %x", error); + clock_mutex.Unlock(); DeAllocateCodecsOMX(); return 0; } @@ -1305,6 +1456,7 @@ int VideoVPEOGL::AllocateCodecsOMX() error=OMX_GetParameter(omx_vid_rend,OMX_IndexParamVideoInit,&p_param); if (error!=OMX_ErrorNone){ Log::getInstance()->log("Video", Log::DEBUG, "Init OMX video rend OMX_GetParameter failed %x", error); + clock_mutex.Unlock(); DeAllocateCodecsOMX(); return 0; } @@ -1315,6 +1467,7 @@ int VideoVPEOGL::AllocateCodecsOMX() if (!DisablePort(omx_vid_rend,omx_rend_input_port,true) /*|| !DisablePort(omx_vid_rend,omx_rend_output_port)*/ ) { Log::getInstance()->log("Video", Log::DEBUG, "Disable Ports OMX video rend failed"); + clock_mutex.Unlock(); DeAllocateCodecsOMX(); return 0; } @@ -1323,10 +1476,10 @@ int VideoVPEOGL::AllocateCodecsOMX() - error=OMX_SetupTunnel(omx_clock,omx_clock_output_port,omx_vid_sched,omx_shed_clock_port); if (error!=OMX_ErrorNone){ Log::getInstance()->log("Video", Log::DEBUG, "OMX_Setup tunnel clock to sched failed %x %d %d", error,omx_clock_output_port,omx_shed_clock_port); + clock_mutex.Unlock(); DeAllocateCodecsOMX(); return 0; } @@ -1334,13 +1487,16 @@ int VideoVPEOGL::AllocateCodecsOMX() if (!EnablePort(omx_clock,omx_clock_output_port,false) || !EnablePort(omx_vid_sched,omx_shed_clock_port,false) ) { Log::getInstance()->log("Video", Log::DEBUG, "Enable Ports OMX clock shed failed"); + clock_mutex.Unlock(); DeAllocateCodecsOMX(); return 0; } + Log::getInstance()->log("Video", Log::DEBUG, "mark2 "); if (!ChangeComponentState(omx_vid_sched,OMX_StateIdle)) { Log::getInstance()->log("Video", Log::DEBUG, "vid_sched idle ChangeComponentState"); + clock_mutex.Unlock(); DeAllocateCodecsOMX(); return 0; } @@ -1349,6 +1505,7 @@ int VideoVPEOGL::AllocateCodecsOMX() Log::getInstance()->log("Video", Log::DEBUG, "mark1 "); if ( !CommandFinished(omx_vid_sched,OMX_CommandPortEnable,omx_shed_clock_port)) { + clock_mutex.Unlock(); DeAllocateCodecsOMX(); return 0; } @@ -1358,9 +1515,11 @@ int VideoVPEOGL::AllocateCodecsOMX() Log::getInstance()->log("Video", Log::DEBUG, "mark1 special "); if ( !CommandFinished(omx_clock,OMX_CommandPortEnable,omx_clock_output_port)) { + clock_mutex.Unlock(); DeAllocateCodecsOMX(); return 0; } + clock_mutex.Unlock(); Log::getInstance()->log("Video", Log::DEBUG, "mark1b "); @@ -1397,6 +1556,7 @@ int VideoVPEOGL::AllocateCodecsOMX() error=OMX_SetParameter(omx_vid_dec,OMX_IndexParamVideoPortFormat,&ft_type); if (error!=OMX_ErrorNone){ Log::getInstance()->log("Video", Log::DEBUG, "Init OMX_IndexParamVideoPortFormat failed %x", error); + clock_mutex.Unlock(); DeAllocateCodecsOMX(); return 0; } @@ -1404,12 +1564,14 @@ int VideoVPEOGL::AllocateCodecsOMX() if (!ChangeComponentState(omx_vid_dec,OMX_StateIdle)) { Log::getInstance()->log("Video", Log::DEBUG, "vid_dec ChangeComponentState"); + clock_mutex.Unlock(); DeAllocateCodecsOMX(); return 0; } if (!PrepareInputBufsOMX()) { + clock_mutex.Unlock(); DeAllocateCodecsOMX(); return 0; } @@ -1418,6 +1580,7 @@ int VideoVPEOGL::AllocateCodecsOMX() error=OMX_SetupTunnel(omx_vid_dec,omx_codec_output_port,omx_vid_sched,omx_shed_input_port); if (error!=OMX_ErrorNone){ Log::getInstance()->log("Video", Log::DEBUG, "OMX_Setup tunnel dec to sched failed %x", error); + clock_mutex.Unlock(); DeAllocateCodecsOMX(); return 0; } @@ -1427,17 +1590,20 @@ int VideoVPEOGL::AllocateCodecsOMX() if (!EnablePort(omx_vid_dec,omx_codec_output_port,false) || !EnablePort(omx_vid_sched,omx_shed_input_port,false) ) { Log::getInstance()->log("Video", Log::DEBUG, "Enable Ports OMX codec shed failed"); + clock_mutex.Unlock(); DeAllocateCodecsOMX(); return 0; } if ( !CommandFinished(omx_vid_dec,OMX_CommandPortEnable,omx_codec_output_port) || !CommandFinished(omx_vid_sched,OMX_CommandPortEnable,omx_shed_input_port)) { + clock_mutex.Unlock(); DeAllocateCodecsOMX(); return 0; } if (!ChangeComponentState(omx_vid_dec,OMX_StateExecuting)) { Log::getInstance()->log("Video", Log::DEBUG, "omx_vid_dec ChangeComponentState Execute"); + clock_mutex.Unlock(); DeAllocateCodecsOMX(); return 0; } @@ -1445,6 +1611,7 @@ int VideoVPEOGL::AllocateCodecsOMX() error=OMX_SetupTunnel(omx_vid_sched,omx_shed_output_port,omx_vid_rend,omx_rend_input_port); if (error!=OMX_ErrorNone){ Log::getInstance()->log("Video", Log::DEBUG, "OMX_Setup tunnel sched to rend failed %x", error); + clock_mutex.Unlock(); DeAllocateCodecsOMX(); return 0; } @@ -1452,18 +1619,21 @@ int VideoVPEOGL::AllocateCodecsOMX() if (!EnablePort(omx_vid_sched,omx_shed_output_port,false) || !EnablePort(omx_vid_rend,omx_rend_input_port,false) ) { Log::getInstance()->log("Video", Log::DEBUG, "Enable Ports OMX shed rend failed"); + clock_mutex.Unlock(); DeAllocateCodecsOMX(); return 0; } if (!CommandFinished(omx_vid_sched,OMX_CommandPortEnable,omx_shed_output_port) || !CommandFinished(omx_vid_rend,OMX_CommandPortEnable,omx_rend_input_port)) { + clock_mutex.Unlock(); DeAllocateCodecsOMX(); return 0; } if (!ChangeComponentState(omx_vid_rend,OMX_StateIdle)) { Log::getInstance()->log("Video", Log::DEBUG, "vid_rend ChangeComponentState"); + clock_mutex.Unlock(); DeAllocateCodecsOMX(); return 0; } @@ -1471,12 +1641,14 @@ int VideoVPEOGL::AllocateCodecsOMX() if (!ChangeComponentState(omx_vid_sched,OMX_StateExecuting)) { Log::getInstance()->log("Video", Log::DEBUG, "omx_vid_sched ChangeComponentState Execute"); + clock_mutex.Unlock(); DeAllocateCodecsOMX(); return 0; } if (!ChangeComponentState(omx_vid_rend,OMX_StateExecuting)) { Log::getInstance()->log("Video", Log::DEBUG, "omx_vid_rend ChangeComponentState Execute"); + clock_mutex.Unlock(); DeAllocateCodecsOMX(); return 0; } @@ -1494,6 +1666,7 @@ int VideoVPEOGL::AllocateCodecsOMX() error=OMX_SetConfig(omx_vid_rend,OMX_IndexConfigDisplayRegion,&dispconf); if (error!=OMX_ErrorNone){ Log::getInstance()->log("Video", Log::DEBUG, "Init OMX_IndexConfigDisplayRegion failed %x", error); + clock_mutex.Unlock(); DeAllocateCodecsOMX(); return 0; } @@ -1503,6 +1676,7 @@ int VideoVPEOGL::AllocateCodecsOMX() error=OMX_SetParameter(omx_vid_rend,OMX_IndexConfigDisplayRegion,&dispconf); if (error!=OMX_ErrorNone){ Log::getInstance()->log("Video", Log::DEBUG, "Init OMX_IndexConfigDisplayRegion failed %x", error); + clock_mutex.Unlock(); DeAllocateCodecsOMX(); return 0; } @@ -1515,6 +1689,7 @@ int VideoVPEOGL::AllocateCodecsOMX() error=OMX_SetParameter(omx_vid_rend,OMX_IndexConfigDisplayRegion,&dispconf); if (error!=OMX_ErrorNone){ Log::getInstance()->log("Video", Log::DEBUG, "Init OMX_IndexConfigDisplayRegion failed %x", error); + clock_mutex.Unlock(); DeAllocateCodecsOMX(); return 0; }*/ @@ -1523,36 +1698,72 @@ int VideoVPEOGL::AllocateCodecsOMX() playbacktimeoffset=-GetCurrentSystemTime(); paused=false; + iframemode=false; omx_running=true; + clock_mutex.Unlock(); - if (!ChangeComponentState(omx_clock,OMX_StateExecuting)) { - Log::getInstance()->log("Video", Log::DEBUG, "omx_clock ChangeComponentState Execute failed"); - DeAllocateCodecsOMX(); - return 0; + setClockExecutingandRunning(); + + + + + + return 1; +} + +int VideoVPEOGL::idleClock() +{ + OMX_ERRORTYPE error; + OMX_STATETYPE temp_state; + clock_mutex.Lock(); + OMX_GetState(omx_clock,&temp_state); + + if (temp_state!=OMX_StateIdle) { + if (!ChangeComponentState(omx_clock,OMX_StateIdle)) { + Log::getInstance()->log("Video", Log::DEBUG, "omx_clock ChangeComponentState Idle failed"); + clock_mutex.Unlock(); + return 0; + } } + clock_mutex.Unlock(); + return 1; +} +int VideoVPEOGL::setClockExecutingandRunning() +{ + OMX_ERRORTYPE error; + OMX_STATETYPE temp_state; + clock_mutex.Lock(); + OMX_GetState(omx_clock,&temp_state); + + if (temp_state!=OMX_StateExecuting) { + if (!ChangeComponentState(omx_clock,OMX_StateExecuting)) { + Log::getInstance()->log("Video", Log::DEBUG, "omx_clock ChangeComponentState Execute failed"); + clock_mutex.Unlock(); + DeAllocateCodecsOMX(); + return 0; + } + } - //OMX_TIME_CONFIG_CLOCKSTATETYPE clock_conf; + OMX_TIME_CONFIG_CLOCKSTATETYPE clock_conf; memset(&clock_conf,0,sizeof(clock_conf)); clock_conf.nSize=sizeof(clock_conf); clock_conf.nVersion.nVersion=OMX_VERSION; clock_conf.eState=OMX_TIME_ClockStateRunning; error=OMX_SetConfig(omx_clock,OMX_IndexConfigTimeClockState,&clock_conf); - if (error!=OMX_ErrorNone){ + if (error!=OMX_ErrorNone) { Log::getInstance()->log("Video", Log::DEBUG, "Clock IndexConfigTimeClockState failed %x", error); + clock_mutex.Unlock(); DeAllocateCodecsOMX(); return 0; } - - - - - + clock_mutex.Unlock(); return 1; + } -int VideoVPEOGL::ChangeComponentState(OMX_HANDLETYPE handle,OMX_STATETYPE type) +int VideoVPEOGL::ChangeComponentState(OMX_HANDLETYPE handle,OMX_STATETYPE type) //needs to be called with locked mutex { OMX_ERRORTYPE error; error=OMX_SendCommand(handle,OMX_CommandStateSet,type,0); @@ -1569,7 +1780,7 @@ int VideoVPEOGL::ChangeComponentState(OMX_HANDLETYPE handle,OMX_STATETYPE type) } -int VideoVPEOGL::EnablePort(OMX_HANDLETYPE handle,OMX_U32 port,bool wait) +int VideoVPEOGL::EnablePort(OMX_HANDLETYPE handle,OMX_U32 port,bool wait) //needs to be called with locked mutex { OMX_ERRORTYPE error; error=OMX_SendCommand(handle,OMX_CommandPortEnable,port,0); @@ -1587,7 +1798,7 @@ int VideoVPEOGL::EnablePort(OMX_HANDLETYPE handle,OMX_U32 port,bool wait) } -int VideoVPEOGL::DisablePort(OMX_HANDLETYPE handle,OMX_U32 port,bool wait) +int VideoVPEOGL::DisablePort(OMX_HANDLETYPE handle,OMX_U32 port,bool wait) //needs to be called with locked mutex { OMX_ERRORTYPE error; error=OMX_SendCommand(handle,OMX_CommandPortDisable,port,0); @@ -1608,7 +1819,7 @@ int VideoVPEOGL::DisablePort(OMX_HANDLETYPE handle,OMX_U32 port,bool wait) -int VideoVPEOGL::CommandFinished(OMX_HANDLETYPE handle,OMX_U32 command,OMX_U32 data2) +int VideoVPEOGL::CommandFinished(OMX_HANDLETYPE handle,OMX_U32 command,OMX_U32 data2) //needs to be called with locked mutex { int i=0; while (i<1000) { @@ -1648,7 +1859,7 @@ int VideoVPEOGL::CommandFinished(OMX_HANDLETYPE handle,OMX_U32 command,OMX_U32 d -int VideoVPEOGL::PrepareInputBufsOMX() +int VideoVPEOGL::PrepareInputBufsOMX() //needs to be called with locked mutex { OMX_ERRORTYPE error; OMX_PARAM_PORTDEFINITIONTYPE port_def_type; @@ -1666,7 +1877,7 @@ int VideoVPEOGL::PrepareInputBufsOMX() port_def_type.nBufferCountMin,port_def_type.nBufferSize,port_def_type.bEnabled,port_def_type.bPopulated, port_def_type.bBuffersContiguous,port_def_type.nBufferAlignment);*/ - port_def_type.nBufferCountActual=10; + port_def_type.nBufferCountActual=60; port_def_type.nBufferSize=max(port_def_type.nBufferSize,200000); // for transcoder important error=OMX_SetParameter(omx_vid_dec,OMX_IndexParamPortDefinition, &port_def_type); @@ -1724,7 +1935,7 @@ int VideoVPEOGL::PrepareInputBufsOMX() return 1; } -int VideoVPEOGL::DestroyInputBufsOMX() +int VideoVPEOGL::DestroyInputBufsOMX() //need s to be called with locked mutex { OMX_ERRORTYPE error; @@ -1768,6 +1979,7 @@ int VideoVPEOGL::DeAllocateCodecsOMX() DeInitTranscoderLibAV(); #endif + clock_mutex.Lock(); if (cur_input_buf_omx) { cur_input_buf_omx->nFlags|=OMX_BUFFERFLAG_EOS; OMX_ERRORTYPE error=OMX_EmptyThisBuffer(omx_vid_dec,cur_input_buf_omx); @@ -1782,26 +1994,22 @@ int VideoVPEOGL::DeAllocateCodecsOMX() // first stop the omx elements if (!ChangeComponentState(omx_vid_dec,OMX_StateIdle)) { Log::getInstance()->log("Video", Log::DEBUG, "vid_dec ChangeComponentState"); - DeAllocateCodecsOMX(); - return 0; - } - if (!ChangeComponentState(omx_clock,OMX_StateIdle)) { - Log::getInstance()->log("Video", Log::DEBUG, "vid_clock ChangeComponentState"); - DeAllocateCodecsOMX(); - return 0; } + clock_mutex.Unlock(); + + idleClock(); + clock_mutex.Lock(); + if (!ChangeComponentState(omx_vid_sched,OMX_StateIdle)) { Log::getInstance()->log("Video", Log::DEBUG, "vid_shed ChangeComponentState"); - DeAllocateCodecsOMX(); - return 0; + } if (!ChangeComponentState(omx_vid_rend,OMX_StateIdle)) { Log::getInstance()->log("Video", Log::DEBUG, "vid_rend ChangeComponentState"); - DeAllocateCodecsOMX(); - return 0; + } @@ -1826,18 +2034,6 @@ int VideoVPEOGL::DeAllocateCodecsOMX() } - if (!CommandFinished(omx_vid_dec,OMX_CommandFlush,omx_codec_input_port)) { - Log::getInstance()->log("Video", Log::DEBUG, "flush cmd codec input failed"); - } - - error=OMX_SendCommand(omx_vid_dec,OMX_CommandFlush, omx_codec_output_port, NULL); - if (error!=OMX_ErrorNone){ - Log::getInstance()->log("Video", Log::DEBUG, "OMX_Flush codec out failed %x", error); - - } - - - error=OMX_SendCommand(omx_vid_sched,OMX_CommandFlush, omx_shed_input_port, NULL); if (error!=OMX_ErrorNone){ @@ -1850,6 +2046,7 @@ int VideoVPEOGL::DeAllocateCodecsOMX() Log::getInstance()->log("Video", Log::DEBUG, "flush cmd codec shed failed"); } + error=OMX_SendCommand(omx_clock,OMX_CommandFlush, omx_clock_output_port, NULL); if (error!=OMX_ErrorNone){ Log::getInstance()->log("Video", Log::DEBUG, "OMX_Flush clock out failed %x", error); @@ -1924,6 +2121,7 @@ int VideoVPEOGL::DeAllocateCodecsOMX() + error=OMX_SetupTunnel(omx_vid_dec,omx_codec_output_port,NULL,NULL); if (error!=OMX_ErrorNone) { Log::getInstance()->log("Video", Log::DEBUG, "OMX_Setup tunnel teardown failed %x", error); @@ -1949,6 +2147,7 @@ int VideoVPEOGL::DeAllocateCodecsOMX() } + error=OMX_SetupTunnel(omx_clock,omx_clock_output_port,NULL,NULL); if (error!=OMX_ErrorNone) { Log::getInstance()->log("Video", Log::DEBUG, "OMX_Setup tunnel teardown failed %x", error); @@ -1964,28 +2163,41 @@ int VideoVPEOGL::DeAllocateCodecsOMX() - - - - - - - - error=OMX_FreeHandle(omx_vid_dec); error=OMX_FreeHandle(omx_vid_sched); error=OMX_FreeHandle(omx_vid_rend); - error=OMX_FreeHandle(omx_clock); omx_vid_dec=NULL; + clock_mutex.Unlock(); + destroyClock(); if (error!=OMX_ErrorNone) { Log::getInstance()->log("Video", Log::DEBUG, "FreeHandle failed %d", error); } - } + } else clock_mutex.Unlock(); Log::getInstance()->log("Video", Log::DEBUG, "leave deallocate codecs OMX"); return 1; } + +void VideoVPEOGL::destroyClock() +{ + clock_mutex.Lock(); + if (clock_references>0) { + clock_references--; + if (clock_references==0) { + OMX_ERRORTYPE error; + Log::getInstance()->log("Video", Log::DEBUG, "destroy omx clock"); + error=OMX_FreeHandle(omx_clock); + if (error!=OMX_ErrorNone) { + Log::getInstance()->log("Video", Log::DEBUG, "FreeHandle failed %d", error); + } + + } + } + clock_mutex.Unlock(); + +} + #endif @@ -2471,6 +2683,7 @@ void VideoVPEOGL::add_dec_frame_upload_only(struct AVCodecContext *s,const AVFra int VideoVPEOGL::stop() { if (!initted) return 0; + iframemode=false; #ifdef VPE_OMX_SUPPORT //Check if libav mode @@ -2489,6 +2702,8 @@ int VideoVPEOGL::reset() { if (!initted) return 0; + iframemode=false; + DeAllocateCodecsOMX(); // if (ioctl(fdVideo, AV_SET_VID_RESET, 0x11) != 0) return 0; return 1; } @@ -2554,7 +2769,7 @@ int VideoVPEOGL::blank(void) ULLONG VideoVPEOGL::getCurrentTimestamp() { - + if (iframemode) return 0; return lastreftimePTS; } @@ -2687,7 +2902,19 @@ void VideoVPEOGL::FrameWaitforDisplay(long long pts) target_time-current_time); WaitUntil(target_time); - Log::getInstance()->log("Video", Log::DEBUG, "Wait for display out"); + Log::getInstance()->log("Video", Log::DEBUG, "Wait for display out %lld",GetCurrentSystemTime()); +} + +void VideoVPEOGL::AdjustAudioPTS(long long pts) +{ + long long newplaybacktimeoffset=pts-GetCurrentSystemTime(); +/* if ((newplaybacktimeoffset-1000000LL)>playbacktimeoffset + || (newplaybacktimeoffset+1000000LL)log("Video", Log::DEBUG, "Adjust Playbackoffsettime o: %lld n: %lld", + playbacktimeoffset,newplaybacktimeoffset);*/ + playbacktimeoffset=newplaybacktimeoffset; + + //} } @@ -2751,27 +2978,16 @@ UINT VideoVPEOGL::DeliverMediaPacketOMX(MediaPacket packet, long long current_media_time=GetCurrentSystemTime()+playbacktimeoffset; if (packet.synched && - (packet.presentation_time<0 || // preroll skip frames - (packet.presentation_time-1000000LL)>(current_media_time))) { // we are late skip - Log::getInstance()->log("Video", Log::DEBUG, "DeliverMediaPacketOMX Preroll or too late %lld %lld", packet.presentation_time,current_media_time); + (packet.presentation_time<0 /*|| // preroll skip frames + (packet.presentation_time+5000000LL)<(current_media_time)*/)) { // we are late skip + Log::getInstance()->log("Video", Log::DEBUG, "DeliverMediaPacketOMX Preroll or too late %lld %lld; %lld", packet.presentation_time,current_media_time,playbacktimeoffset); *samplepos=packet.length; return packet.length; } OMX_ERRORTYPE error; -/* OMX_PARAM_PORTDEFINITIONTYPE port_image; - memset(&port_image,0,sizeof(port_image)); - port_image.nSize=sizeof(port_image); - port_image.nVersion.nVersion=OMX_VERSION; - port_image.nPortIndex =omx_codec_output_port; - error=OMX_GetParameter(omx_vid_dec,OMX_IndexParamPortDefinition, &port_image); - if (error!= OMX_ErrorNone){ - Log::getInstance()->log("Video", Log::DEBUG, "OMX_GetParameter failed %x", error); - } - Log::getInstance()->log("Video", Log::DEBUG, "Image port %d %d", port_image.format.video.nFrameWidth , port_image.format.video.nFrameHeight);*/ - - /*First Check, if we have an audio sample*/ + /*First Check, if we have an video sample*/ if (iframemode) { //samplepos=0; MILLISLEEP(10); @@ -2786,6 +3002,7 @@ UINT VideoVPEOGL::DeliverMediaPacketOMX(MediaPacket packet, if (error!=OMX_ErrorNone){ Log::getInstance()->log("Video", Log::DEBUG, "OMX_EmptyThisBuffer failed %x", error); } + FrameWaitforDisplay(lastreftimeOMX); cur_input_buf_omx=NULL; } } @@ -2797,21 +3014,21 @@ UINT VideoVPEOGL::DeliverMediaPacketOMX(MediaPacket packet, if (*samplepos==0) {//stripheader headerstrip=buffer[packet.pos_buffer+8]+9/*is this right*/; + if (h264) Log::getInstance()->log("Video", Log::DEBUG, "PES info %x %x %x %x", + buffer[packet.pos_buffer+0],buffer[packet.pos_buffer+1],buffer[packet.pos_buffer+2],buffer[packet.pos_buffer+3]); *samplepos+=headerstrip; if ( packet.synched ) { - if (cur_input_buf_omx) { cur_input_buf_omx->nFlags|=OMX_BUFFERFLAG_ENDOFFRAME; OMX_ERRORTYPE error=OMX_EmptyThisBuffer(omx_vid_dec,cur_input_buf_omx); if (error!=OMX_ErrorNone){ Log::getInstance()->log("Video", Log::DEBUG, "OMX_EmptyThisBuffer failed %x", error); } + cur_input_buf_omx=NULL;//write out old data FrameWaitforDisplay(lastreftimeOMX); - cur_input_buf_omx=NULL;//write out old data + } - // reftime1=packet.presentation_time; - // reftime2=reftime1+1; firstsynched=true; } else { if (!firstsynched) {// @@ -2841,11 +3058,6 @@ UINT VideoVPEOGL::DeliverMediaPacketOMX(MediaPacket packet, if (cur_input_buf_omx->nFilledLen==0) {//will only be changed on first packet - /*if (packet.disconti) { - ms->SetDiscontinuity(TRUE); - } else { - ms->SetDiscontinuity(FALSE); - }*/ if (packet.synched) { Log::getInstance()->log("Video", Log::DEBUG, "packet synched marker"); @@ -3268,19 +3480,151 @@ UINT VideoVPEOGL::DeliverMediaPacketlibav(MediaPacket packet, #endif -bool VideoVPEOGL::displayIFrame(const UCHAR* buffer, UINT length) -{ - //write(fdVideo, buffer, length); - if (!iframemode) EnterIframePlayback(); -// WriteOutTS(buffer,length, h264?MPTYPE_VIDEO_H264 :MPTYPE_VIDEO_MPEG2 ); +bool VideoVPEOGL::displayIFrame(const UCHAR* buffer, UINT length) { + if (!omx_running) return false; + if (!iframemode) + EnterIframePlayback(); + + int haveToCopy = length; + + if (!cur_input_buf_omx) { + input_bufs_omx_mutex.Lock(); + if (input_bufs_omx_free.size() == 0) { + input_bufs_omx_mutex.Unlock(); + Log::getInstance()->log("Video", Log::DEBUG, + "Deliver MediaPacket no free sample"); + return false; // we do not have a free media sample - lastpacketnum=-1; - return true; + } + cur_input_buf_omx = input_bufs_omx_free.front(); + cur_input_buf_omx->nFilledLen = 0; + cur_input_buf_omx->nOffset = 0; + cur_input_buf_omx->nTimeStamp = 0; + input_bufs_omx_free.pop_front(); + input_bufs_omx_mutex.Unlock(); + } + + int read_pos = 0; + unsigned int pattern, packet_length; + unsigned int headerstrip = 0; + bool first = true; + if (length < 4){ + return false; + } + //Now we strip the pes header + pattern = (buffer[0] << 16) | (buffer[1] << 8) | (buffer[2]); + while (read_pos + 7 <= length) { + pattern = ((pattern << 8) & 0xFFFFFFFF) | buffer[read_pos + 3]; + if (pattern < 0x000001E0 || pattern > 0x000001EF) { + read_pos++; + continue; + } else { + headerstrip = buffer[read_pos + 8] + 9/*is this right*/; + packet_length = ((buffer[read_pos + 4] << 8) + | (buffer[read_pos + 5])) + 6; + if (read_pos + packet_length > length) + read_pos = length; + else { + if ((headerstrip < packet_length) + && (cur_input_buf_omx->nFilledLen + packet_length + - headerstrip) > cur_input_buf_omx->nAllocLen) { + if (first) { + cur_input_buf_omx->nFlags = OMX_BUFFERFLAG_STARTTIME; + + } else { + cur_input_buf_omx->nFlags + |= OMX_BUFFERFLAG_TIME_UNKNOWN; + + } + cur_input_buf_omx->nTimeStamp = 0; + OMX_ERRORTYPE error = OMX_EmptyThisBuffer(omx_vid_dec, + cur_input_buf_omx); + if (error != OMX_ErrorNone) { + Log::getInstance()->log("Video", Log::DEBUG, + "OMX_EmptyThisBuffer failed %x", error); + } + cur_input_buf_omx = NULL; + + if (!cur_input_buf_omx) { + int count = 0; + while (count < 100 && omx_running && iframemode) { + count++; + + input_bufs_omx_mutex.Lock(); + if (input_bufs_omx_free.size() == 0) { + input_bufs_omx_mutex.Unlock(); + Log::getInstance()->log("Video", Log::DEBUG, + "Ifrane no free sample"); + MILLISLEEP(5); + if (!omx_running) return false; + continue; + } + cur_input_buf_omx = input_bufs_omx_free.front(); + cur_input_buf_omx->nFilledLen = 0; + cur_input_buf_omx->nOffset = 0; + cur_input_buf_omx->nTimeStamp = 0; + input_bufs_omx_free.pop_front(); + input_bufs_omx_mutex.Unlock(); + break; + } + if (!cur_input_buf_omx) + return false; + } + + } + if (packet_length > headerstrip) { + memcpy( + cur_input_buf_omx->pBuffer + + cur_input_buf_omx->nFilledLen, + buffer + read_pos + headerstrip, + packet_length - headerstrip); + cur_input_buf_omx->nFilledLen += packet_length + - headerstrip; + } + read_pos += packet_length; + + pattern = (buffer[read_pos] << 16) + | (buffer[read_pos + 1] << 8) | (buffer[read_pos + 2]); + } + } + } + + if (first) { + cur_input_buf_omx->nFlags = OMX_BUFFERFLAG_STARTTIME; + + } else { + cur_input_buf_omx->nFlags |= OMX_BUFFERFLAG_TIME_UNKNOWN; + + } + cur_input_buf_omx->nTimeStamp = 0; + OMX_ERRORTYPE error = OMX_EmptyThisBuffer(omx_vid_dec, cur_input_buf_omx); + if (error != OMX_ErrorNone) { + Log::getInstance()->log("Video", Log::DEBUG, + "OMX_EmptyThisBuffer failed %x", error); + } + cur_input_buf_omx = NULL; + + + MILLISLEEP(40); //Block a bit + return true; } int VideoVPEOGL::EnterIframePlayback() { + clock_mutex.Lock(); + if (cur_input_buf_omx) { + OMX_ERRORTYPE error = OMX_EmptyThisBuffer(omx_vid_dec, + cur_input_buf_omx); + if (error != OMX_ErrorNone) { + Log::getInstance()->log("Video", Log::DEBUG, + "OMX_EmptyThisBuffer failed %x", error); + } - return 0; + cur_input_buf_omx = NULL; + } + clock_mutex.Unlock(); + iframemode=true; + + return 1; } diff --git a/videovpeogl.h b/videovpeogl.h index 97a589c..2acda35 100644 --- a/videovpeogl.h +++ b/videovpeogl.h @@ -123,10 +123,11 @@ struct VPEOGLFrame { - +class AudioVPE; class VideoVPEOGL : public Video, public Thread_TYPE { + friend class AudioVPE; public: VideoVPEOGL(); virtual ~VideoVPEOGL(); @@ -179,14 +180,7 @@ class VideoVPEOGL : public Video, public Thread_TYPE long long SetStartAudioOffset(long long curreftime, bool *rsync); virtual void ResetTimeOffsets(); - static long long GetCurrentSystemTime(); - static void WaitUntil(long long time); - void FrameWaitforDisplay(long long pts); - - - - int getLastPacketNum() {return lastpacketnum;}; #ifdef DEV int test(); int test2(); @@ -204,6 +198,7 @@ class VideoVPEOGL : public Video, public Thread_TYPE private: int EnterIframePlayback(); bool iframemode; + bool InIframemode() {return iframemode;}; UINT DeliverMediaPacket(MediaPacket packet,const UCHAR* bulibaver,UINT *samplepos); @@ -226,6 +221,11 @@ class VideoVPEOGL : public Video, public Thread_TYPE long long pausetimecode; bool paused; + static long long GetCurrentSystemTime(); + static void WaitUntil(long long time); + void FrameWaitforDisplay(long long pts); + void AdjustAudioPTS(long long pts); + @@ -252,17 +252,31 @@ class VideoVPEOGL : public Video, public Thread_TYPE int DisablePort(OMX_HANDLETYPE handle,OMX_U32 port,bool wait=true); + int setClockExecutingandRunning(); + int initClock(); + void destroyClock(); + int idleClock(); + int getClockAudioandInit(OMX_HANDLETYPE *p_omx_clock,OMX_U32 *p_omx_clock_output_port); + int getClockVideoandInit(); + void LockClock() {clock_mutex.Lock();}; + void UnlockClock() {clock_mutex.Unlock();}; + void clockPause(); + void clockUnpause(); + + Mutex clock_mutex; //clock mutex is now responsible for all omx stuff + + OMX_HANDLETYPE omx_vid_dec; OMX_HANDLETYPE omx_vid_sched; OMX_HANDLETYPE omx_vid_rend; OMX_HANDLETYPE omx_clock; + int clock_references; OMX_U32 omx_codec_input_port; OMX_U32 omx_codec_output_port; OMX_U32 omx_rend_input_port; - OMX_U32 omx_rend_output_port; OMX_U32 omx_shed_input_port; OMX_U32 omx_shed_output_port; OMX_U32 omx_shed_clock_port; @@ -412,7 +426,6 @@ class VideoVPEOGL : public Video, public Thread_TYPE bool firstsynched; - int lastpacketnum; EGLDisplay egl_display; EGLSurface egl_surface; diff --git a/vopts.cc b/vopts.cc index bb40d73..393aa79 100644 --- a/vopts.cc +++ b/vopts.cc @@ -160,7 +160,7 @@ VOpts::VOpts() option = new Option(8, "VDR-Pri 0=OK !See forums!", "General", "Live priority", Option::TYPE_INT, 100, 0, 0, NULL); options.push_back(option); wop->addOptionLine(option); - option = new Option(13, "TCP receive window size", "Advanced", "TCP receive window", Option::TYPE_TEXT, 7, 1, 0, options13); + option = new Option(13, "TCP receive window size", "Advanced", "TCP receive window", Option::TYPE_TEXT, 7, /*1*/DEFAULT_TCP_WINDOWSIZENR, 0, options13); options.push_back(option); wop->addOptionLine(option); option = new Option(14, "Use WSS (PAL only)", "General", "WSS", Option::TYPE_TEXT, 2, 0, 0, options14); -- 2.39.2