From 28b21c70cf9612f88ad086ebf9bc9540ef23ab8e Mon Sep 17 00:00:00 2001 From: Marten Richter Date: Sat, 8 Sep 2012 15:57:10 +0200 Subject: [PATCH] Move video feeding to separate thread and enhance video playback --- audioomx.cc | 16 ++--- playerlivetv.cc | 8 ++- stream.cc | 2 +- videoomx.cc | 187 ++++++++++++++++++++++++++++++++++-------------- videoomx.h | 11 ++- videowin.h | 1 + 6 files changed, 160 insertions(+), 65 deletions(-) diff --git a/audioomx.cc b/audioomx.cc index aa8da5b..ebc313f 100644 --- a/audioomx.cc +++ b/audioomx.cc @@ -1391,8 +1391,8 @@ UINT AudioOMX::DeliverMediaPacket(MediaPacket packet, const UCHAR* buffer, 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); + // 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 { @@ -1489,8 +1489,8 @@ UINT AudioOMX::DeliverMediaPacket(MediaPacket packet, const UCHAR* buffer, 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); + // Log::getInstance()->log("Audio", Log::DEBUG, + // "P 2 Time code %lld pts %lld", lastreftimeOMX, packet.pts); OMX_ERRORTYPE error = vw->ProtOMXEmptyThisBuffer(omx_aud_rend/*dec*/, cur_input_buf_omx); if (error != OMX_ErrorNone) { @@ -1506,8 +1506,8 @@ UINT AudioOMX::DeliverMediaPacket(MediaPacket packet, const UCHAR* buffer, 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"); + // Log::getInstance()->log("Audio", Log::DEBUG, + // "Deliver MediaPacket no free sample"); MILLISLEEP(5); if (!omx_running) return *samplepos; continue; @@ -1539,8 +1539,8 @@ UINT AudioOMX::DeliverMediaPacket(MediaPacket packet, const UCHAR* buffer, } if (cur_input_buf_omx->nFilledLen) { - Log::getInstance()->log("Audio", Log::DEBUG, - "P 3 Time code %lld pts %lld", lastreftimeOMX, packet.pts); + //Log::getInstance()->log("Audio", Log::DEBUG, + // "P 3 Time code %lld pts %lld", lastreftimeOMX, packet.pts); error = vw->ProtOMXEmptyThisBuffer(omx_aud_rend/*dec*/, cur_input_buf_omx); if (error != OMX_ErrorNone) { Log::getInstance()->log("Audio", Log::DEBUG, diff --git a/playerlivetv.cc b/playerlivetv.cc index 4e20bcb..64daa78 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,9 +752,9 @@ void PlayerLiveTV::threadMethod() while(streamChunks.size()) { - logger->log("PlayerLiveTV", Log::DEBUG, "chunk mark1"); + //logger->log("PlayerLiveTV", Log::DEBUG, "chunk mark1 %d", streamChunks.size()); chunkToDemuxer(); - logger->log("PlayerLiveTV", Log::DEBUG, "chunk mark2"); + //logger->log("PlayerLiveTV", Log::DEBUG, "chunk mark2 %d", streamChunks.size()); if (state == S_PREBUFFERING) { @@ -778,9 +778,11 @@ void PlayerLiveTV::threadMethod() } } } + // logger->log("PlayerLiveTV", Log::DEBUG, "wait for signal %d", streamChunks.size()); threadLock(); threadWaitForSignal(); // unlocks and waits for signal threadUnlock(); + //logger->log("PlayerLiveTV", Log::DEBUG, "wait for signal2 %d",streamChunks.size()); } logger->log("PlayerLiveTV", Log::DEBUG, "End of thread"); diff --git a/stream.cc b/stream.cc index abea315..c7b5e70 100644 --- a/stream.cc +++ b/stream.cc @@ -154,7 +154,7 @@ int Stream::put(const UCHAR* inbuf, int len, UCHAR type,unsigned int index) mediapackets.push_back(newPacket); unLock(); } else { - // Log::getInstance()->log("Stream", Log::DEBUG, "We are full %d!",bufferSize); + Log::getInstance()->log("Stream", Log::DEBUG, "We are full %d!",bufferSize); } return ret; diff --git a/videoomx.cc b/videoomx.cc index ddd0b55..57e2e6c 100644 --- a/videoomx.cc +++ b/videoomx.cc @@ -141,7 +141,7 @@ OMX_ERRORTYPE VideoOMX::EmptyBufferDone_OMX(OMX_IN OMX_HANDLETYPE hcomp,OMX_IN O void VideoOMX::ReturnEmptyOMXBuffer(OMX_BUFFERHEADERTYPE* buffer){ input_bufs_omx_mutex.Lock(); - //Log::getInstance()->log("Video", Log::NOTICE, "ReturnEmptyOMXBuffer %d",input_bufs_omx_free.size()); +// Log::getInstance()->log("Video", Log::NOTICE, "ReturnEmptyOMXBuffer %d %d %d",input_bufs_omx_free.size(),input_bufs_omx_present.size(),input_bufs_omx_all.size()); input_bufs_omx_free.push_back(buffer); //Log::getInstance()->log("Video", Log::NOTICE, "ReturnEmptyOMXBuffer %d",input_bufs_omx_free.size()); input_bufs_omx_mutex.Unlock(); @@ -934,6 +934,7 @@ int VideoOMX::AllocateCodecsOMX() iframemode=false; omx_running=true; clock_mutex.Unlock(); + threadStart(); setClockExecutingandRunning(); @@ -1110,7 +1111,7 @@ int VideoOMX::PrepareInputBufsOMX() //needs to be called with locked mutex 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=60; + port_def_type.nBufferCountActual=100; port_def_type.nBufferSize=max(port_def_type.nBufferSize,200000); // for transcoder important error=OMX_SetParameter(omx_vid_dec,OMX_IndexParamPortDefinition, &port_def_type); @@ -1181,6 +1182,8 @@ int VideoOMX::DestroyInputBufsOMX() //need s to be called with locked mutex } input_bufs_omx_all.clear(); input_bufs_omx_free.clear(); + input_bufs_omx_present.clear(); + input_time_present.clear(); input_bufs_omx_mutex.Unlock(); } @@ -1193,6 +1196,7 @@ int VideoOMX::DeAllocateCodecsOMX() OMX_ERRORTYPE error; omx_running=false; Log::getInstance()->log("Video", Log::DEBUG, "enter deallocatecodecsomx"); + threadStop(); if (cur_input_buf_omx) { @@ -1647,7 +1651,48 @@ void VideoOMX::WaitUntil(long long time) struct timespec interval; interval.tv_sec=time/10000000LL; interval.tv_nsec=(time %10000000LL)*100LL; - while (clock_nanosleep(CLOCK_MONOTONIC,TIMER_ABSTIME,&interval,NULL)==EINTR) {}; + while (clock_nanosleep(CLOCK_MONOTONIC,TIMER_ABSTIME,&interval,NULL)==EINTR) { + //Log::getInstance()->log("Video", Log::DEBUG, "Wait until multi"); + + }; +} + +bool VideoOMX::FrameSkip(long long pts) +{ + //ok first calculate the absolute time + bool skip=false; + long long target_time=pts-playbacktimeoffset; + // we have to wait untile the next frame + long long offset=Demuxer::getInstance()->getFrameRate(); + if (offset==0) offset=25; + offset=10000000LL/offset; + target_time+=offset; + long long current_time=GetCurrentSystemTime(); + if (!skipping) { + if ((target_time-current_time)<-1000000LL) { + skip=true; // we are too slow + skipping=true; + /* Log::getInstance()->log("Video", Log::DEBUG, + "Skipping frames1 %lld %lld",target_time-current_time,pts); + Log::getInstance()->log("Video", Log::DEBUG, "skip detail pts: %lld target: %lld sys: %lld off: %lld diff %lld",pts,target_time,current_time,offset, + target_time-current_time);*/ + } else { + skipping=false; + } + } else { + if ((target_time - current_time) < 0LL) { + skip = true; // we are too slow + skipping = true; + /* Log::getInstance()->log("Video", Log::DEBUG,"Skipping frames2 %lld %lld",target_time-current_time,pts); + Log::getInstance()->log("Video", Log::DEBUG, "skip detail pts: %lld target: %lld sys: %lld off: %lld diff %lld",pts,target_time,current_time,offset, + target_time-current_time);*/ + } else { + skipping = false; + } + + } + + return skip; } void VideoOMX::FrameWaitforDisplay(long long pts) @@ -1657,15 +1702,15 @@ void VideoOMX::FrameWaitforDisplay(long long pts) // we have to wait untile the next frame long long offset=Demuxer::getInstance()->getFrameRate(); long long current_time=GetCurrentSystemTime(); - if ((target_time-current_time)>5000000LL) target_time=current_time+5000000LL; // something is wrong do not wait too long if (offset==0) offset=25; offset=10000000LL/offset; target_time+=offset; - Log::getInstance()->log("Video", Log::DEBUG, "Wait for display pts: %lld target: %lld sys: %lld off: %lld diff %lld",pts,target_time,current_time,offset, - target_time-current_time); + if ((target_time-current_time)>1000000LL) target_time=current_time+1000000LL; // something is wrong do not wait too long + //Log::getInstance()->log("Video", Log::DEBUG, "Wait for display pts: %lld target: %lld sys: %lld off: %lld diff %lld",pts,target_time,current_time,offset, + // target_time-current_time); WaitUntil(target_time); - Log::getInstance()->log("Video", Log::DEBUG, "Wait for display out %lld",GetCurrentSystemTime()); + //Log::getInstance()->log("Video", Log::DEBUG, "Wait for display out %lld",GetCurrentSystemTime()); } void VideoOMX::AdjustAudioPTS(long long pts) @@ -1680,6 +1725,71 @@ void VideoOMX::AdjustAudioPTS(long long pts) //} } +void VideoOMX::threadPostStopCleanup() +{ + //Doing nothing + //goo; + Log::getInstance()->log("Video", Log::DEBUG, + "end thread"); +} + + +void VideoOMX::threadMethod() +{ + Log::getInstance()->log("Video", Log::DEBUG, + "start thread"); + while (true) { + + OMX_BUFFERHEADERTYPE* pict=NULL; + long long time; + if (!paused) { + input_bufs_omx_mutex.Lock(); + if (input_bufs_omx_present.size()>0) { + + pict=input_bufs_omx_present.front(); + time=input_time_present.front(); + input_bufs_omx_present.pop_front(); + input_time_present.pop_front(); + } + input_bufs_omx_mutex.Unlock(); + } + + if ( pict) { + //Log::getInstance()->log("Video", Log::DEBUG, + // "Got pict"); + if (time!=0 &&FrameSkip(time) && !(pict->nFlags &OMX_BUFFERFLAG_STARTTIME)) { + + input_bufs_omx_mutex.Lock(); + input_bufs_omx_free.push_back(pict); + input_bufs_omx_mutex.Unlock(); + + } else { + OMX_ERRORTYPE error = ProtOMXEmptyThisBuffer(omx_vid_dec, pict); + if (error != OMX_ErrorNone) { + Log::getInstance()->log("Video", Log::DEBUG, + "OMX_EmptyThisBuffer failed %x", error); + } + if (time!=0) FrameWaitforDisplay(time); + } + } else { + MILLISLEEP(5); + } + + threadCheckExit(); + } + Log::getInstance()->log("Video", Log::DEBUG, + "end thread"); +} + +void VideoOMX::PutBufferToPres(OMX_BUFFERHEADERTYPE* buffer, long long time) +{ + input_bufs_omx_mutex.Lock(); + input_bufs_omx_present.push_back(buffer); + input_time_present.push_back(time); + input_bufs_omx_mutex.Unlock(); + +} + OMX_ERRORTYPE VideoOMX::ProtOMXEmptyThisBuffer(OMX_HANDLETYPE handle, OMX_BUFFERHEADERTYPE* buffer) { // protect the call to empty this buffer @@ -1738,13 +1848,13 @@ UINT VideoOMX::DeliverMediaPacket(MediaPacket packet, if (paused) return 0; //Block if we pause long long current_media_time=GetCurrentSystemTime()+playbacktimeoffset; - if (packet.synched && +/* if (packet.synched && (packet.presentation_time<0 /*|| // preroll skip frames - (packet.presentation_time+5000000LL)<(current_media_time)*/)) { // we are late skip + (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; @@ -1759,11 +1869,7 @@ UINT VideoOMX::DeliverMediaPacket(MediaPacket packet, if (packet.disconti) { firstsynched=false; if (cur_input_buf_omx) { - OMX_ERRORTYPE error=ProtOMXEmptyThisBuffer(omx_vid_dec,cur_input_buf_omx); - if (error!=OMX_ErrorNone){ - Log::getInstance()->log("Video", Log::DEBUG, "OMX_EmptyThisBuffer failed %x", error); - } - FrameWaitforDisplay(lastreftimeOMX); + PutBufferToPres(cur_input_buf_omx, lastreftimeOMX); cur_input_buf_omx=NULL; } } @@ -1775,18 +1881,14 @@ UINT VideoOMX::DeliverMediaPacket(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]); + // 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=ProtOMXEmptyThisBuffer(omx_vid_dec,cur_input_buf_omx); - if (error!=OMX_ErrorNone){ - Log::getInstance()->log("Video", Log::DEBUG, "OMX_EmptyThisBuffer failed %x", error); - } + PutBufferToPres(cur_input_buf_omx, lastreftimeOMX); cur_input_buf_omx=NULL;//write out old data - FrameWaitforDisplay(lastreftimeOMX); } @@ -1803,7 +1905,7 @@ UINT VideoOMX::DeliverMediaPacket(MediaPacket packet, 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"); + //Log::getInstance()->log("Video", Log::DEBUG, "Deliver MediaPacket no free sample"); return 0; // we do not have a free media sample } @@ -1820,7 +1922,7 @@ UINT VideoOMX::DeliverMediaPacket(MediaPacket packet, if (cur_input_buf_omx->nFilledLen==0) {//will only be changed on first packet if (packet.synched) { - Log::getInstance()->log("Video", Log::DEBUG, "packet synched marker"); + // Log::getInstance()->log("Video", Log::DEBUG, "packet synched marker"); //lastreftimePTS=packet.pts; if (omx_first_frame) { // TODO time @@ -1832,7 +1934,7 @@ UINT VideoOMX::DeliverMediaPacket(MediaPacket packet, cur_input_buf_omx->nFlags|=OMX_BUFFERFLAG_TIME_UNKNOWN; } lastreftimeOMX=packet.presentation_time; - Log::getInstance()->log("Video", Log::DEBUG, "Time code %lld pts %lld", lastreftimeOMX,packet.pts); + // Log::getInstance()->log("Video", Log::DEBUG, "Time code %lld pts %lld", lastreftimeOMX,packet.pts); lastreftimePTS=packet.pts; cur_input_buf_omx->nTimeStamp=0;//lastreftimeOMX; // the clock component is faulty; } @@ -1859,10 +1961,7 @@ UINT VideoOMX::DeliverMediaPacket(MediaPacket packet, *samplepos+=cancopy; // push old buffer out - OMX_ERRORTYPE error=ProtOMXEmptyThisBuffer(omx_vid_dec,cur_input_buf_omx); - if (error!=OMX_ErrorNone){ - Log::getInstance()->log("Video", Log::DEBUG, "OMX_EmptyThisBuffer failed %x", error); - } + PutBufferToPres(cur_input_buf_omx, 0LL); // get5 new buffer input_bufs_omx_mutex.Lock(); if (input_bufs_omx_free.size()==0) { @@ -1906,8 +2005,8 @@ bool VideoOMX::displayIFrame(const UCHAR* buffer, UINT length) { 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"); + // Log::getInstance()->log("Video", Log::DEBUG, + // "Deliver MediaPacket no free sample"); return false; // we do not have a free media sample } @@ -1952,12 +2051,7 @@ bool VideoOMX::displayIFrame(const UCHAR* buffer, UINT length) { } cur_input_buf_omx->nTimeStamp = 0; - OMX_ERRORTYPE error = ProtOMXEmptyThisBuffer(omx_vid_dec, - cur_input_buf_omx); - if (error != OMX_ErrorNone) { - Log::getInstance()->log("Video", Log::DEBUG, - "OMX_EmptyThisBuffer failed %x", error); - } + PutBufferToPres(cur_input_buf_omx, 0); cur_input_buf_omx = NULL; if (!cur_input_buf_omx) { @@ -1968,8 +2062,8 @@ bool VideoOMX::displayIFrame(const UCHAR* buffer, UINT length) { 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"); + // Log::getInstance()->log("Video", Log::DEBUG, + // "Ifrane no free sample"); MILLISLEEP(5); if (!omx_running) return false; continue; @@ -2012,11 +2106,7 @@ bool VideoOMX::displayIFrame(const UCHAR* buffer, UINT length) { } cur_input_buf_omx->nTimeStamp = 0; - OMX_ERRORTYPE error = ProtOMXEmptyThisBuffer(omx_vid_dec, cur_input_buf_omx); - if (error != OMX_ErrorNone) { - Log::getInstance()->log("Video", Log::DEBUG, - "OMX_EmptyThisBuffer failed %x", error); - } + PutBufferToPres(cur_input_buf_omx, 0); cur_input_buf_omx = NULL; @@ -2028,14 +2118,7 @@ int VideoOMX::EnterIframePlayback() { clock_mutex.Lock(); if (cur_input_buf_omx) { - clock_mutex.Unlock(); - OMX_ERRORTYPE error = ProtOMXEmptyThisBuffer(omx_vid_dec, - cur_input_buf_omx); - clock_mutex.Lock(); - if (error != OMX_ErrorNone) { - Log::getInstance()->log("Video", Log::DEBUG, - "OMX_EmptyThisBuffer failed %x", error); - } + PutBufferToPres(cur_input_buf_omx, lastreftimeOMX); cur_input_buf_omx = NULL; } diff --git a/videoomx.h b/videoomx.h index 72c52b9..8695438 100644 --- a/videoomx.h +++ b/videoomx.h @@ -61,7 +61,7 @@ struct VPE_OMX_EVENT { class AudioVPE; -class VideoOMX : public Video +class VideoOMX : public Video, public Thread_TYPE { friend class AudioOMX; public: @@ -96,6 +96,7 @@ class VideoOMX : public Video bool displayIFrame(const UCHAR* bulibaver, UINT length); virtual bool dtsTimefix(){return true;} //please we need dts time values + virtual int getTeletextBufferFaktor(){return 5;}; // Writing Data to Videodevice virtual void PrepareMediaSample(const MediaPacketList&, UINT samplepos); @@ -151,6 +152,8 @@ class VideoOMX : public Video static long long GetCurrentSystemTime(); static void WaitUntil(long long time); void FrameWaitforDisplay(long long pts); + bool FrameSkip(long long pts); + bool skipping; void AdjustAudioPTS(long long pts); @@ -217,9 +220,15 @@ class VideoOMX : public Video vector input_bufs_omx_all; list input_bufs_omx_free; + list input_bufs_omx_present; + list input_time_present; Mutex input_bufs_omx_mutex; OMX_BUFFERHEADERTYPE* cur_input_buf_omx; + void PutBufferToPres(OMX_BUFFERHEADERTYPE* buffer, long long time); + void threadMethod(); + void threadPostStopCleanup(); + bool omx_running; bool omx_first_frame; diff --git a/videowin.h b/videowin.h index f57f4b7..48682cf 100644 --- a/videowin.h +++ b/videowin.h @@ -104,6 +104,7 @@ public: virtual bool dtsTimefix() {if (h264)return videoH264dtsfix; else return videompeg2dtsfix;} virtual bool supportsh264(); + virtual int getTeletextBufferFaktor(){return 4;}; virtual bool supportsAc3(); -- 2.39.2