diff --git a/Makefile b/Makefile index 519048a3..85b0f2cb 100644 --- a/Makefile +++ b/Makefile @@ -64,9 +64,9 @@ ffmpeg: dist: omxplayer.bin mkdir -p $(DIST)/usr/lib/omxplayer mkdir -p $(DIST)/usr/bin - mkdir -p $(DIST)/usr/share/doc + mkdir -p $(DIST)/usr/share/doc/omxplayer cp omxplayer omxplayer.bin $(DIST)/usr/bin - cp COPYING $(DIST)/usr/share/doc/ - cp README.md $(DIST)/usr/share/doc/README + cp COPYING $(DIST)/usr/share/doc/omxplayer/ + cp README.md $(DIST)/usr/share/doc/omxplayer/README cp -a ffmpeg_compiled/usr/local/lib/*.so* $(DIST)/usr/lib/omxplayer/ tar -czf omxplayer-dist.tar.gz $(DIST) diff --git a/OMXAudio.cpp b/OMXAudio.cpp index f88396c0..e03e30e0 100644 --- a/OMXAudio.cpp +++ b/OMXAudio.cpp @@ -193,8 +193,10 @@ bool COMXAudio::Initialize(IAudioCallback* pCallback, const CStdString& device, deviceuse = "local"; } - if(!m_dllAvUtil.Load()) + if(!m_dllAvUtil.Load()) { + printf("COMXAudio dll error\n"); return false; + } m_Passthrough = false; @@ -338,26 +340,34 @@ bool COMXAudio::Initialize(IAudioCallback* pCallback, const CStdString& device, std::string componentName = ""; componentName = "OMX.broadcom.audio_render"; - if(!m_omx_render.Initialize(componentName, OMX_IndexParamAudioInit)) + if(!m_omx_render.Initialize(componentName, OMX_IndexParamAudioInit)) { + printf("COMXAudio audio_render init error\n"); return false; + } OMX_CONFIG_BRCMAUDIODESTINATIONTYPE audioDest; OMX_INIT_STRUCTURE(audioDest); strncpy((char *)audioDest.sName, device.c_str(), strlen(device.c_str())); omx_err = m_omx_render.SetConfig(OMX_IndexConfigBrcmAudioDestination, &audioDest); - if (omx_err != OMX_ErrorNone) + if (omx_err != OMX_ErrorNone) { + printf("COMXAudio audiodest error %d\n", omx_err); return false; + } componentName = "OMX.broadcom.audio_decode"; - if(!m_omx_decoder.Initialize(componentName, OMX_IndexParamAudioInit)) + if(!m_omx_decoder.Initialize(componentName, OMX_IndexParamAudioInit)) { + printf("COMXAudio audio_decode error\n"); return false; + } if(!m_Passthrough) { componentName = "OMX.broadcom.audio_mixer"; - if(!m_omx_mixer.Initialize(componentName, OMX_IndexParamAudioInit)) + if(!m_omx_mixer.Initialize(componentName, OMX_IndexParamAudioInit)) { + printf("COMXAudio audio_mixer error\n"); return false; + } } if(m_Passthrough) diff --git a/OMXClock.cpp b/OMXClock.cpp index 802ec63a..997b950c 100644 --- a/OMXClock.cpp +++ b/OMXClock.cpp @@ -95,6 +95,7 @@ double OMXClock::SystemToPlaying(int64_t system) m_pauseClock = 0; m_iDisc = 0; m_bReset = false; + //CLog::Log(LOGDEBUG, "**** reset: m_startClock %lld\n", m_startClock); } if (m_pauseClock) @@ -221,6 +222,7 @@ void OMXClock::Discontinuity(double currentPts) m_pauseClock = m_startClock; m_iDisc = currentPts; m_bReset = false; + //CLog::Log(LOGDEBUG, "**** discontinuity: cpts %f m_startClock %lld\n", currentPts, m_startClock); UnLock(); } @@ -680,6 +682,32 @@ bool OMXClock::OMXUpdateClock(double pts, bool lock /* = true */) return true; } +bool OMXClock::OMXSeek(int porti, double pts, bool lock /* = true */) +{ + if(m_omx_clock.GetComponent() == NULL) + return false; + + if(lock) + Lock(); + + OMX_ERRORTYPE omx_err = OMX_ErrorNone; + OMX_TIME_CONFIG_TIMESTAMPTYPE ts; + OMX_INIT_STRUCTURE(ts); + + ts.nPortIndex = m_omx_clock.GetInputPort(); + ts.nTimestamp = ToOMXTime((uint64_t)pts); + + omx_err = OMX_SetConfig(m_omx_clock.GetComponent(), OMX_IndexConfigTimeClientStartTime, &ts); + if(omx_err != OMX_ErrorNone) { + CLog::Log(LOGERROR, "OMXClock::OMXUpdateClock error setting OMX_IndexConfigTimeClientStartTime: %x\n", omx_err); + } + + if(lock) + UnLock(); + + return true; +} + bool OMXClock::OMXWaitStart(double pts, bool lock /* = true */) { if(m_omx_clock.GetComponent() == NULL) diff --git a/OMXClock.h b/OMXClock.h index 5cccc9fe..454af706 100644 --- a/OMXClock.h +++ b/OMXClock.h @@ -129,6 +129,7 @@ class OMXClock double OMXMediaTime(bool lock = true); bool OMXPause(bool lock = true); bool OMXResume(bool lock = true); + bool OMXSeek(int porti, double pts, bool lock = true); bool OMXUpdateClock(double pts, bool lock = true); bool OMXWaitStart(double pts, bool lock = true); bool OMXSpeed(int speed, bool lock = true); diff --git a/OMXPlayerAudio.cpp b/OMXPlayerAudio.cpp index 590fec9e..dabd41ea 100644 --- a/OMXPlayerAudio.cpp +++ b/OMXPlayerAudio.cpp @@ -105,14 +105,17 @@ bool OMXPlayerAudio::Open(COMXStreamInfo &hints, OMXClock *av_clock, OMXReader * if(ThreadHandle()) Close(); - if (!m_dllAvUtil.Load() || !m_dllAvCodec.Load() || !m_dllAvFormat.Load() || !av_clock) + if (!m_dllAvUtil.Load() || !m_dllAvCodec.Load() || !m_dllAvFormat.Load() || !av_clock) { + printf("OMXPlayerAudio DLL error\n"); return false; + } m_dllAvFormat.av_register_all(); + SetReader(omx_reader); + m_hints = hints; m_av_clock = av_clock; - m_omx_reader = omx_reader; m_device = device; m_passthrough = IAudioRenderer::ENCODED_NONE; m_hw_decode = false; @@ -121,7 +124,6 @@ bool OMXPlayerAudio::Open(COMXStreamInfo &hints, OMXClock *av_clock, OMXReader * m_boost_on_downmix = boost_on_downmix; m_iCurrentPts = DVD_NOPTS_VALUE; m_bAbort = false; - m_bMpeg = m_omx_reader->IsMpegVideo(); m_use_thread = use_thread; m_flush = false; m_cached_size = 0; @@ -164,6 +166,12 @@ bool OMXPlayerAudio::Open(COMXStreamInfo &hints, OMXClock *av_clock, OMXReader * return true; } +void OMXPlayerAudio::SetReader(OMXReader *omx_reader) +{ + m_omx_reader = omx_reader; + m_bMpeg = m_omx_reader->IsMpegVideo(); +} + bool OMXPlayerAudio::Close() { m_bAbort = true; @@ -494,6 +502,11 @@ void OMXPlayerAudio::Flush() UnLock(); } +void OMXPlayerAudio::UnFlush() +{ + m_flush = false; +} + bool OMXPlayerAudio::AddPacket(OMXPacket *pkt) { bool ret = false; @@ -523,6 +536,7 @@ bool OMXPlayerAudio::OpenAudioCodec() if(!m_pAudioCodec->Open(m_hints)) { + printf("OMXPlayerAudio audio codec open error\n"); delete m_pAudioCodec; m_pAudioCodec = NULL; return false; } @@ -634,6 +648,7 @@ bool OMXPlayerAudio::OpenDecoder() if(!bAudioRenderOpen) { + printf("OMXPlayerAudio audio decoder open error\n"); delete m_decoder; m_decoder = NULL; return false; diff --git a/OMXPlayerAudio.h b/OMXPlayerAudio.h index 3a262fa2..676715b7 100644 --- a/OMXPlayerAudio.h +++ b/OMXPlayerAudio.h @@ -111,10 +111,12 @@ class OMXPlayerAudio : public CThread bool Open(COMXStreamInfo &hints, OMXClock *av_clock, OMXReader *omx_reader, std::string device, bool passthrough, bool hw_decode, bool boost_on_downmix, bool use_thread); + void SetReader(OMXReader *omx_reader); bool Close(); bool Decode(OMXPacket *pkt); void Process(); void Flush(); + void UnFlush(); bool AddPacket(OMXPacket *pkt); bool OpenAudioCodec(); void CloseAudioCodec(); diff --git a/OMXPlayerVideo.cpp b/OMXPlayerVideo.cpp index bd45f868..5e4f646b 100644 --- a/OMXPlayerVideo.cpp +++ b/OMXPlayerVideo.cpp @@ -131,21 +131,18 @@ bool OMXPlayerVideo::Open(COMXStreamInfo &hints, OMXClock *av_clock, const CRect m_Deinterlace = deinterlace; m_display_aspect = display_aspect; m_bMpeg = mpeg; - m_iCurrentPts = DVD_NOPTS_VALUE; - m_bAbort = false; m_use_thread = use_thread; m_flush = false; m_cached_size = 0; m_iVideoDelay = 0; m_hdmi_clock_sync = hdmi_clock_sync; m_pts = 0; - m_syncclock = true; m_speed = DVD_PLAYSPEED_NORMAL; m_iSubtitleDelay = 0; m_pSubtitleCodec = NULL; m_DestRect = DestRect; - m_FlipTimeStamp = m_av_clock->GetAbsoluteClock(); + Reset(); if(!OpenDecoder()) { @@ -161,6 +158,16 @@ bool OMXPlayerVideo::Open(COMXStreamInfo &hints, OMXClock *av_clock, const CRect return true; } +void OMXPlayerVideo::Reset() +{ + m_iCurrentPts = DVD_NOPTS_VALUE; + m_bAbort = false; + m_syncclock = true; + m_FlipTimeStamp = m_av_clock->GetAbsoluteClock(); + if(m_decoder) + m_decoder->Reset(); +} + bool OMXPlayerVideo::Close() { m_bAbort = true; @@ -246,13 +253,17 @@ void OMXPlayerVideo::Output(double pts) m_av_clock->SetPTS(m_iCurrentPts); + // CLog::Log(LOGDEBUG, "PlayerVideo output pts %f(=%f) icc %f ipc %f ics %f ifs %f ifd %f\n", pts, m_iCurrentPts, iCurrentClock, iPlayingClock, iClockSleep, iFrameSleep, iFrameDuration); + // timestamp when we think next picture should be displayed based on current duration m_FlipTimeStamp = iCurrentClock; m_FlipTimeStamp += max(0.0, iSleepTime); m_FlipTimeStamp += iFrameDuration; - while(m_av_clock->GetAbsoluteClock(false) < (iCurrentClock + iSleepTime + DVD_MSEC_TO_TIME(500)) ) + double absclock; + while((absclock = m_av_clock->GetAbsoluteClock(false)) < (iCurrentClock + iSleepTime + DVD_MSEC_TO_TIME(500)) ) { + // CLog::Log(LOGDEBUG, "PlayerVideo wait (absclock %f < icc %f + ist %f + 500msec)\n", absclock, iCurrentClock, iSleepTime); OMXClock::OMXSleep(10); } @@ -266,11 +277,14 @@ void OMXPlayerVideo::Output(double pts) //g_renderManager.FlipPage(CThread::m_bStop, (iCurrentClock + iSleepTime) / DVD_TIME_BASE, -1, mDisplayField); + // CLog::Log(LOGDEBUG, "PlayerVideo abswait\n"); m_av_clock->WaitAbsoluteClock((iCurrentClock + iSleepTime)); + // CLog::Log(LOGDEBUG, "PlayerVideo abswait over; m_pts %lld\n", (long long) m_pts); // guess next frame pts. iDuration is always valid if (m_speed != 0) m_pts += m_frametime * m_speed / abs(m_speed); + // CLog::Log(LOGDEBUG, "PlayerVideo final m_pts %lld\n", (long long) m_pts); } bool OMXPlayerVideo::Decode(OMXPacket *pkt) @@ -280,8 +294,10 @@ bool OMXPlayerVideo::Decode(OMXPacket *pkt) bool ret = false; - if(!((unsigned long)m_decoder->GetFreeSpace() > pkt->size)) + if(!((unsigned long)m_decoder->GetFreeSpace() > pkt->size)) { + // CLog::Log(LOGDEBUG, "decoder buffer full\n"); OMXClock::OMXSleep(10); + } if (pkt->dts == DVD_NOPTS_VALUE && pkt->pts == DVD_NOPTS_VALUE) pkt->pts = m_pts; @@ -363,16 +379,20 @@ bool OMXPlayerVideo::Decode(OMXPacket *pkt) } else if((unsigned long)m_decoder->GetFreeSpace() > pkt->size) { - if(m_bMpeg) + if(m_bMpeg) { m_decoder->Decode(pkt->data, pkt->size, DVD_NOPTS_VALUE, DVD_NOPTS_VALUE); - else + } else { + // CLog::Log(LOGDEBUG, "--- decode pts %f\n", m_pts); m_decoder->Decode(pkt->data, pkt->size, m_pts, m_pts); + } m_av_clock->SetVideoClock(m_pts); Output(m_pts); ret = true; + } else { + // CLog::Log(LOGDEBUG, "--- decoder buffer full, dropping frame\n"); } return ret; @@ -482,6 +502,11 @@ void OMXPlayerVideo::Flush() UnLock(); } +void OMXPlayerVideo::UnFlush() +{ + m_flush = false; +} + bool OMXPlayerVideo::AddPacket(OMXPacket *pkt) { bool ret = false; diff --git a/OMXPlayerVideo.h b/OMXPlayerVideo.h index d237f1ea..8dc1c7a4 100644 --- a/OMXPlayerVideo.h +++ b/OMXPlayerVideo.h @@ -104,12 +104,14 @@ class OMXPlayerVideo : public CThread OMXPlayerVideo(); ~OMXPlayerVideo(); bool Open(COMXStreamInfo &hints, OMXClock *av_clock, const CRect& DestRect, bool deinterlace, bool mpeg, bool hdmi_clock_sync, bool use_thread, float display_aspect); + void Reset(); bool Close(); void Output(double pts); bool Decode(OMXPacket *pkt); void Process(); void FlushSubtitles(); void Flush(); + void UnFlush(); bool AddPacket(OMXPacket *pkt); bool OpenDecoder(); bool CloseDecoder(); diff --git a/OMXThread.cpp b/OMXThread.cpp index 6e7cff45..e71fa021 100644 --- a/OMXThread.cpp +++ b/OMXThread.cpp @@ -68,7 +68,7 @@ bool OMXThread::StopThread() m_thread = 0; - CLog::Log(LOGDEBUG, "%s::%s - Thread stopped\n", CLASSNAME, __func__); + CLog::Log(LOGDEBUG, "%s::%s - Thread with id %d stopped\n", CLASSNAME, __func__, (int)m_thread); return true; } diff --git a/OMXVideo.cpp b/OMXVideo.cpp index 531fcc5a..23c7214c 100644 --- a/OMXVideo.cpp +++ b/OMXVideo.cpp @@ -921,6 +921,7 @@ int COMXVideo::Decode(uint8_t *pData, int iSize, double dts, double pts) if(m_setStartTime) { + //if (val > 0) m_av_clock->OMXSeek(m_omx_decoder.GetOutputPort(), val); omx_buffer->nFlags = OMX_BUFFERFLAG_STARTTIME; m_setStartTime = false; } @@ -941,6 +942,8 @@ int COMXVideo::Decode(uint8_t *pData, int iSize, double dts, double pts) if(demuxer_bytes == 0) omx_buffer->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME; + // CLog::Log(LOGDEBUG, "decoder ts %llu flags %lx\n", val, omx_buffer->nFlags); + int nRetry = 0; while(true) { @@ -1045,10 +1048,10 @@ void COMXVideo::Reset(void) m_omx_decoder.FlushInput(); m_omx_tunnel_decoder.Flush(); - //m_setStartTime = true; - //m_setStartTimeText = true; + m_setStartTime = true; + m_setStartTimeText = true; - //m_first_frame = true; + // m_first_frame = true; } /////////////////////////////////////////////////////////////////////////////////////////// @@ -1152,7 +1155,7 @@ void COMXVideo::WaitCompletion() omx_buffer->nFilledLen = 0; omx_buffer->nTimeStamp = ToOMXTime(0LL); - omx_buffer->nFlags = OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_EOS | OMX_BUFFERFLAG_TIME_UNKNOWN; + omx_buffer->nFlags = OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_TIME_UNKNOWN; omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer); if (omx_err != OMX_ErrorNone) diff --git a/omxplayer.cpp b/omxplayer.cpp index fba4662d..9934b6ec 100644 --- a/omxplayer.cpp +++ b/omxplayer.cpp @@ -61,6 +61,10 @@ extern "C" { #include typedef enum {CONF_FLAGS_FORMAT_NONE, CONF_FLAGS_FORMAT_SBS, CONF_FLAGS_FORMAT_TB } FORMAT_3D_T; + +CRBP g_RBP; +COMXCore g_OMX; +TV_DISPLAY_STATE_T tv_state; enum PCMChannels *m_pChannelMap = NULL; volatile sig_atomic_t g_abort = false; bool m_bMpeg = false; @@ -77,7 +81,11 @@ float m_font_size = 0.055f; bool m_centered = false; unsigned int m_subtitle_lines = 3; bool m_Pause = false; -OMXReader m_omx_reader; +OMXReader *m_omx_reader = NULL; +OMXReader *m_omx_reader_next = NULL; +bool m_omx_reader_openok; +pthread_t m_omx_reader_thread; +bool m_dump_format = false; int m_audio_index_use = -1; int m_seek_pos = 0; bool m_buffer_empty = true; @@ -100,6 +108,7 @@ bool m_has_audio = false; bool m_has_subtitle = false; float m_display_aspect = 0.0f; bool m_boost_on_downmix = false; +bool m_loop = false; enum{ERROR=-1,SUCCESS,ONEBYTE}; @@ -124,7 +133,7 @@ void sig_handler(int s) void print_usage() { - printf("Usage: omxplayer [OPTIONS] [FILE]\n"); + printf("Usage: omxplayer [OPTIONS] [FILE...]\n"); printf("Options :\n"); printf(" -h / --help print this help\n"); // printf(" -a / --alang language audio language : e.g. ger\n"); @@ -141,6 +150,7 @@ void print_usage() printf(" -t / --sid index show subtitle with index\n"); printf(" -r / --refresh adjust framerate/resolution to video\n"); printf(" -l / --pos start position (in seconds)\n"); + printf(" -L / --loop loop files endlessly\n"); printf(" --boost-on-downmix boost volume when downmixing\n"); printf(" --subtitles path external subtitles in UTF-8 srt format\n"); printf(" --font path subtitle font\n"); @@ -155,7 +165,7 @@ void print_usage() void PrintSubtitleInfo() { - auto count = m_omx_reader.SubtitleStreamCount(); + auto count = m_omx_reader->SubtitleStreamCount(); size_t index = 0; if(m_has_external_subtitles) @@ -176,6 +186,91 @@ void PrintSubtitleInfo() m_has_subtitle ? m_player_subtitles.GetDelay() : 0); } +bool Exists(const std::string& path) +{ + struct stat buf; + auto error = stat(path.c_str(), &buf); + return !error || errno != ENOENT; +} + +bool IsURL(const std::string& str) +{ + auto result = str.find("://"); + if(result == std::string::npos || result == 0) + return false; + + for(size_t i = 0; i < result; ++i) + { + if(!isalpha(str[i])) + return false; + } + return true; +} + +void PrintFileNotFound(const std::string& path) +{ + printf("File \"%s\" not found.\n", path.c_str()); +} + +void * +reader_open_thread(void *data) +{ + char *filename = (char *) data; + + if(!IsURL(filename) && !Exists(filename)) + { + PrintFileNotFound(filename); + m_omx_reader_openok = 0; + return 0; + } + + if(m_has_external_subtitles && !Exists(m_external_subtitles_path)) + { + PrintFileNotFound(m_external_subtitles_path); + m_omx_reader_openok = 0; + return 0; + } + + m_omx_reader_next = new OMXReader; + printf("thread nextreader %p (%d)\n", m_omx_reader_next, m_omx_reader_next->AudioStreamCount()); + m_omx_reader_openok = m_omx_reader_next->Open(filename, m_dump_format); + printf("thread opened %p (%d) openok %d\n", m_omx_reader_next, m_omx_reader_next->AudioStreamCount(), m_omx_reader_openok); + return m_omx_reader_next; +} + +void start_omx() +{ + g_RBP.Initialize(); + g_OMX.Initialize(); + + m_av_clock = new OMXClock(); +} + +void stop_omx() +{ + vc_tv_show_info(0); + + delete m_av_clock; + + g_OMX.Deinitialize(); + g_RBP.Deinitialize(); +} + +void stop_player(bool m_refresh) +{ + if(m_has_video && m_refresh && tv_state.display.hdmi.group && tv_state.display.hdmi.mode) + { + m_BcmHost.vc_tv_hdmi_power_on_explicit_new(HDMI_MODE_HDMI, (HDMI_RES_GROUP_T)tv_state.display.hdmi.group, tv_state.display.hdmi.mode); + } + + m_av_clock->OMXStop(); + m_av_clock->OMXStateIdle(); + + m_player_subtitles.Close(); + m_player_video.Close(); + m_player_audio.Close(); +} + void SetSpeed(int iSpeed) { if(!m_av_clock) @@ -184,7 +279,7 @@ void SetSpeed(int iSpeed) if(iSpeed < OMX_PLAYSPEED_PAUSE) return; - m_omx_reader.SetSpeed(iSpeed); + m_omx_reader->SetSpeed(iSpeed); if(m_av_clock->OMXPlaySpeed() != OMX_PLAYSPEED_PAUSE && iSpeed == OMX_PLAYSPEED_PAUSE) m_Pause = true; @@ -238,7 +333,7 @@ void FlushStreams(double pts) if(m_omx_pkt) { - m_omx_reader.FreePacket(m_omx_pkt); + m_omx_reader->FreePacket(m_omx_pkt); m_omx_pkt = NULL; } @@ -373,27 +468,6 @@ void SetVideoMode(int width, int height, int fpsrate, int fpsscale, FORMAT_3D_T } } -bool Exists(const std::string& path) -{ - struct stat buf; - auto error = stat(path.c_str(), &buf); - return !error || errno != ENOENT; -} - -bool IsURL(const std::string& str) -{ - auto result = str.find("://"); - if(result == std::string::npos || result == 0) - return false; - - for(size_t i = 0; i < result; ++i) - { - if(!isalpha(str[i])) - return false; - } - return true; -} - int main(int argc, char *argv[]) { signal(SIGINT, sig_handler); @@ -422,15 +496,15 @@ int main(int argc, char *argv[]) std::string m_filename; double m_incr = 0; - CRBP g_RBP; - COMXCore g_OMX; bool m_stats = false; bool m_dump_format = false; FORMAT_3D_T m_3d = CONF_FLAGS_FORMAT_NONE; bool m_refresh = false; + bool m_loop = false; + bool m_player_init = false; double startpts = 0; + int optind_filenames; CRect DestRect = {0,0,0,0}; - TV_DISPLAY_STATE_T tv_state; const int font_opt = 0x100; const int font_size_opt = 0x101; @@ -455,6 +529,7 @@ int main(int argc, char *argv[]) { "refresh", no_argument, NULL, 'r' }, { "sid", required_argument, NULL, 't' }, { "pos", required_argument, NULL, 'l' }, + { "loop", no_argument, NULL, 'L' }, { "font", required_argument, NULL, font_opt }, { "font-size", required_argument, NULL, font_size_opt }, { "align", required_argument, NULL, align_opt }, @@ -467,7 +542,7 @@ int main(int argc, char *argv[]) int c; std::string mode; - while ((c = getopt_long(argc, argv, "wihn:l:o:cslpd3:yzt:r", longopts, NULL)) != -1) + while ((c = getopt_long(argc, argv, "wihn:l:o:cslpd3:yzt:rL", longopts, NULL)) != -1) { switch (c) { @@ -558,6 +633,9 @@ int main(int argc, char *argv[]) case boost_on_downmix_opt: m_boost_on_downmix = true; break; + case 'L': + m_loop = true; + break; case 0: break; case 'h': @@ -578,34 +656,42 @@ int main(int argc, char *argv[]) return 0; } - m_filename = argv[optind]; - - auto PrintFileNotFound = [](const std::string& path) - { - printf("File \"%s\" not found.\n", path.c_str()); - }; - - bool filename_is_URL = IsURL(m_filename); - - if(!filename_is_URL && !Exists(m_filename)) - { - PrintFileNotFound(m_filename); - return 0; - } - if(m_has_font && !Exists(m_font_path)) { PrintFileNotFound(m_font_path); return 0; } - if(m_has_external_subtitles && !Exists(m_external_subtitles_path)) - { - PrintFileNotFound(m_external_subtitles_path); - return 0; + CLog::Init("./"); + + optind_filenames = optind; + + pthread_create(&m_omx_reader_thread, NULL, reader_open_thread, argv[optind]); + + start_omx(); +play_file: + + /* This is now not much used variable as we look directly into argv[] + * earlier in the process. */ + m_filename = argv[optind++]; + + m_thread_player = true; + + pthread_join(m_omx_reader_thread, NULL); + if(!m_omx_reader_openok) { + printf("reader not openok. emergency exit!!!\n"); + m_stop = 1; + goto do_exit; } - if(!m_has_external_subtitles && !filename_is_URL) + if (m_omx_reader) { + m_omx_reader->Close(); + delete m_omx_reader; + m_player_audio.SetReader(m_omx_reader_next); + } + m_omx_reader = m_omx_reader_next; + + if(!m_has_external_subtitles && !IsURL(m_filename)) { auto subtitles_path = m_filename.substr(0, m_filename.find_last_of(".")) + ".srt"; @@ -617,124 +703,139 @@ int main(int argc, char *argv[]) } } - CLog::Init("./"); - - g_RBP.Initialize(); - g_OMX.Initialize(); - - m_av_clock = new OMXClock(); - - m_thread_player = true; - - if(!m_omx_reader.Open(m_filename.c_str(), m_dump_format)) - goto do_exit; - - if(m_dump_format) + if(m_dump_format) { + m_stop = 1; goto do_exit; + } - m_bMpeg = m_omx_reader.IsMpegVideo(); - m_has_video = m_omx_reader.VideoStreamCount(); - m_has_audio = m_omx_reader.AudioStreamCount(); - m_has_subtitle = m_has_external_subtitles || - m_omx_reader.SubtitleStreamCount(); + if(!m_player_init) { + m_bMpeg = m_omx_reader->IsMpegVideo(); + m_has_video = m_omx_reader->VideoStreamCount(); + m_has_audio = m_omx_reader->AudioStreamCount(); + m_has_subtitle = m_has_external_subtitles || + m_omx_reader->SubtitleStreamCount(); + + if(m_filename.find("3DSBS") != string::npos || m_filename.find("HSBS") != string::npos) + m_3d = CONF_FLAGS_FORMAT_SBS; + else if(m_filename.find("3DTAB") != string::npos || m_filename.find("HTAB") != string::npos) + m_3d = CONF_FLAGS_FORMAT_TB; + + // 3d modes don't work without switch hdmi mode + if (m_3d != CONF_FLAGS_FORMAT_NONE) + m_refresh = true; + + // you really don't want want to match refresh rate without hdmi clock sync + if (m_refresh && !m_no_hdmi_clock_sync) + m_hdmi_clock_sync = true; + + if(!m_av_clock->OMXInitialize(m_has_video, m_has_audio)) { + printf("avclock error. emergency exit!!!\n"); + m_stop = 1; + goto do_exit; + } - if(m_filename.find("3DSBS") != string::npos || m_filename.find("HSBS") != string::npos) - m_3d = CONF_FLAGS_FORMAT_SBS; - else if(m_filename.find("3DTAB") != string::npos || m_filename.find("HTAB") != string::npos) - m_3d = CONF_FLAGS_FORMAT_TB; + if(m_hdmi_clock_sync && !m_av_clock->HDMIClockSync()) { + printf("hdmi clock sync error. emergency exit!!!\n"); + m_stop = 1; + goto do_exit; + } - // 3d modes don't work without switch hdmi mode - if (m_3d != CONF_FLAGS_FORMAT_NONE) - m_refresh = true; + m_omx_reader->GetHints(OMXSTREAM_AUDIO, m_hints_audio); + m_omx_reader->GetHints(OMXSTREAM_VIDEO, m_hints_video); + + if(m_has_video && m_refresh) + { + memset(&tv_state, 0, sizeof(TV_DISPLAY_STATE_T)); + m_BcmHost.vc_tv_get_display_state(&tv_state); - // you really don't want want to match refresh rate without hdmi clock sync - if (m_refresh && !m_no_hdmi_clock_sync) - m_hdmi_clock_sync = true; + SetVideoMode(m_hints_video.width, m_hints_video.height, m_hints_video.fpsrate, m_hints_video.fpsscale, m_3d); + } - if(!m_av_clock->OMXInitialize(m_has_video, m_has_audio)) - goto do_exit; + // get display aspect + TV_DISPLAY_STATE_T current_tv_state; + memset(¤t_tv_state, 0, sizeof(TV_DISPLAY_STATE_T)); + m_BcmHost.vc_tv_get_display_state(¤t_tv_state); + if(current_tv_state.state & ( VC_HDMI_HDMI | VC_HDMI_DVI )) { + //HDMI or DVI on + m_display_aspect = get_display_aspect_ratio((HDMI_ASPECT_T)current_tv_state.display.hdmi.aspect_ratio); + } else { + //composite on + m_display_aspect = get_display_aspect_ratio((SDTV_ASPECT_T)current_tv_state.display.sdtv.display_options.aspect); + } + m_display_aspect *= (float)current_tv_state.display.hdmi.height/(float)current_tv_state.display.hdmi.width; - if(m_hdmi_clock_sync && !m_av_clock->HDMIClockSync()) + if(m_has_video && !m_player_video.Open(m_hints_video, m_av_clock, DestRect, m_Deinterlace, m_bMpeg, + m_hdmi_clock_sync, m_thread_player, m_display_aspect)) { + printf("video open error. emergency exit!!!\n"); + m_stop = 1; goto do_exit; + } - m_omx_reader.GetHints(OMXSTREAM_AUDIO, m_hints_audio); - m_omx_reader.GetHints(OMXSTREAM_VIDEO, m_hints_video); - - if(m_audio_index_use != -1) - m_omx_reader.SetActiveStream(OMXSTREAM_AUDIO, m_audio_index_use); - - if(m_has_video && m_refresh) - { - memset(&tv_state, 0, sizeof(TV_DISPLAY_STATE_T)); - m_BcmHost.vc_tv_get_display_state(&tv_state); - - SetVideoMode(m_hints_video.width, m_hints_video.height, m_hints_video.fpsrate, m_hints_video.fpsscale, m_3d); - } - // get display aspect - TV_DISPLAY_STATE_T current_tv_state; - memset(¤t_tv_state, 0, sizeof(TV_DISPLAY_STATE_T)); - m_BcmHost.vc_tv_get_display_state(¤t_tv_state); - if(current_tv_state.state & ( VC_HDMI_HDMI | VC_HDMI_DVI )) { - //HDMI or DVI on - m_display_aspect = get_display_aspect_ratio((HDMI_ASPECT_T)current_tv_state.display.hdmi.aspect_ratio); - } else { - //composite on - m_display_aspect = get_display_aspect_ratio((SDTV_ASPECT_T)current_tv_state.display.sdtv.display_options.aspect); - } - m_display_aspect *= (float)current_tv_state.display.hdmi.height/(float)current_tv_state.display.hdmi.width; - - // seek on start - if (m_seek_pos !=0 && m_omx_reader.CanSeek()) { - printf("Seeking start of video to %i seconds\n", m_seek_pos); - m_omx_reader.SeekTime(m_seek_pos * 1000.0f, 0, &startpts); // from seconds to DVD_TIME_BASE - } - - if(m_has_video && !m_player_video.Open(m_hints_video, m_av_clock, DestRect, m_Deinterlace, m_bMpeg, - m_hdmi_clock_sync, m_thread_player, m_display_aspect)) - goto do_exit; + while(m_has_audio && !m_player_audio.Open(m_hints_audio, m_av_clock, m_omx_reader, deviceString, + m_passthrough, m_use_hw_audio, + m_boost_on_downmix, m_thread_player)) { + printf("audio open error. press enter to reset state\n"); + sleep(1); + while (getchar() == EOF) ; + goto do_exit; + } - { - std::vector external_subtitles; - if(m_has_external_subtitles && - !ReadSrt(m_external_subtitles_path, external_subtitles)) { - puts("Unable to read the subtitle file."); - goto do_exit; - } + std::vector external_subtitles; + if(m_has_external_subtitles && + !ReadSrt(m_external_subtitles_path, external_subtitles)) + { + puts("Unable to read the subtitle file."); + goto do_exit; + } - if(m_has_subtitle && - !m_player_subtitles.Open(m_omx_reader.SubtitleStreamCount(), - std::move(external_subtitles), - m_font_path, - m_font_size, - m_centered, - m_subtitle_lines, - m_av_clock)) - goto do_exit; - } + if(m_has_subtitle && + !m_player_subtitles.Open(m_omx_reader->SubtitleStreamCount(), + std::move(external_subtitles), + m_font_path, + m_font_size, + m_centered, + m_subtitle_lines, + m_av_clock)) { + printf("subtitles open error. emergency exit!!!\n"); + m_stop = 1; + goto do_exit; + } + } - if(m_has_subtitle) - { - if(!m_has_external_subtitles) + if(m_has_subtitle) { - if(m_subtitle_index != -1) + if(!m_has_external_subtitles) { - m_player_subtitles.SetActiveStream( - std::min(m_subtitle_index, m_omx_reader.SubtitleStreamCount()-1)); + if(m_subtitle_index != -1) + { + m_player_subtitles.SetActiveStream( + std::min(m_subtitle_index, m_omx_reader->SubtitleStreamCount()-1)); + } + m_player_subtitles.SetUseExternalSubtitles(false); } - m_player_subtitles.SetUseExternalSubtitles(false); + + if(m_subtitle_index == -1 && !m_has_external_subtitles) + m_player_subtitles.SetVisible(false); } - if(m_subtitle_index == -1 && !m_has_external_subtitles) - m_player_subtitles.SetVisible(false); + m_player_init = true; + + } else { + m_av_clock->OMXStop(); + m_av_clock->OMXStateIdle(); + + m_player_video.Reset(); } - m_omx_reader.GetHints(OMXSTREAM_AUDIO, m_hints_audio); + if(m_audio_index_use != -1) + m_omx_reader->SetActiveStream(OMXSTREAM_AUDIO, m_audio_index_use); - if(m_has_audio && !m_player_audio.Open(m_hints_audio, m_av_clock, &m_omx_reader, deviceString, - m_passthrough, m_use_hw_audio, - m_boost_on_downmix, m_thread_player)) - goto do_exit; + // seek on start + if (m_seek_pos !=0 && m_omx_reader->CanSeek()) { + printf("Seeking start of video to %i seconds\n", m_seek_pos); + m_omx_reader->SeekTime(m_seek_pos * 1000.0f, 0, &startpts); // from seconds to DVD_TIME_BASE + } m_av_clock->SetSpeed(DVD_PLAYSPEED_NORMAL); m_av_clock->OMXStateExecute(); @@ -744,6 +845,14 @@ int main(int argc, char *argv[]) PrintSubtitleInfo(); + /* Start opening next file on background. */ + if (optind < argc) + pthread_create(&m_omx_reader_thread, NULL, reader_open_thread, argv[optind]); + else if (m_loop) + pthread_create(&m_omx_reader_thread, NULL, reader_open_thread, argv[optind_filenames]); + + m_av_clock->OMXReset(); + while(!m_stop) { int ch[8]; @@ -770,19 +879,19 @@ int main(int argc, char *argv[]) case 'j': if(m_has_audio) { - int new_index = m_omx_reader.GetAudioIndex() - 1; + int new_index = m_omx_reader->GetAudioIndex() - 1; if (new_index >= 0) - m_omx_reader.SetActiveStream(OMXSTREAM_AUDIO, new_index); + m_omx_reader->SetActiveStream(OMXSTREAM_AUDIO, new_index); } break; case 'k': if(m_has_audio) - m_omx_reader.SetActiveStream(OMXSTREAM_AUDIO, m_omx_reader.GetAudioIndex() + 1); + m_omx_reader->SetActiveStream(OMXSTREAM_AUDIO, m_omx_reader->GetAudioIndex() + 1); break; case 'i': - if(m_omx_reader.GetChapterCount() > 0) + if(m_omx_reader->GetChapterCount() > 0) { - m_omx_reader.SeekChapter(m_omx_reader.GetChapter() - 1, &startpts); + m_omx_reader->SeekChapter(m_omx_reader->GetChapter() - 1, &startpts); FlushStreams(startpts); } else @@ -791,9 +900,9 @@ int main(int argc, char *argv[]) } break; case 'o': - if(m_omx_reader.GetChapterCount() > 0) + if(m_omx_reader->GetChapterCount() > 0) { - m_omx_reader.SeekChapter(m_omx_reader.GetChapter() + 1, &startpts); + m_omx_reader->SeekChapter(m_omx_reader->GetChapter() + 1, &startpts); FlushStreams(startpts); } else @@ -827,7 +936,7 @@ int main(int argc, char *argv[]) { if(m_player_subtitles.GetUseExternalSubtitles()) { - if(m_omx_reader.SubtitleStreamCount()) + if(m_omx_reader->SubtitleStreamCount()) { assert(m_player_subtitles.GetActiveStream() == 0); m_player_subtitles.SetUseExternalSubtitles(false); @@ -836,7 +945,7 @@ int main(int argc, char *argv[]) else { auto new_index = m_player_subtitles.GetActiveStream()+1; - if(new_index < (size_t) m_omx_reader.SubtitleStreamCount()) + if(new_index < (size_t) m_omx_reader->SubtitleStreamCount()) m_player_subtitles.SetActiveStream(new_index); } @@ -870,16 +979,16 @@ int main(int argc, char *argv[]) goto do_exit; break; case 0x5b44: // key left - if(m_omx_reader.CanSeek()) m_incr = -30.0; + if(m_omx_reader->CanSeek()) m_incr = -30.0; break; case 0x5b43: // key right - if(m_omx_reader.CanSeek()) m_incr = 30.0; + if(m_omx_reader->CanSeek()) m_incr = 30.0; break; case 0x5b41: // key up - if(m_omx_reader.CanSeek()) m_incr = 600.0; + if(m_omx_reader->CanSeek()) m_incr = 600.0; break; case 0x5b42: // key down - if(m_omx_reader.CanSeek()) m_incr = -600.0; + if(m_omx_reader->CanSeek()) m_incr = -600.0; break; case ' ': case 'p': @@ -937,13 +1046,16 @@ int main(int argc, char *argv[]) m_incr = 0; - if(m_omx_reader.SeekTime(seek_pos, seek_flags, &startpts)) + if(m_omx_reader->SeekTime(seek_pos, seek_flags, &startpts)) FlushStreams(startpts); m_player_video.Close(); if(m_has_video && !m_player_video.Open(m_hints_video, m_av_clock, DestRect, m_Deinterlace, m_bMpeg, - m_hdmi_clock_sync, m_thread_player, m_display_aspect)) + m_hdmi_clock_sync, m_thread_player, m_display_aspect)) { + printf("video open error. emergency exit!!!\n"); + m_stop = 1; goto do_exit; + } m_av_clock->OMXStart(startpts); @@ -955,28 +1067,36 @@ int main(int argc, char *argv[]) if(m_player_audio.Error()) { printf("audio player error. emergency exit!!!\n"); + m_stop = 1; goto do_exit; } if(m_stats) { - printf("V : %8.02f %8d %8d A : %8.02f %8.02f Cv : %8d Ca : %8d \r", +#if 0 + CLog::Log(LOGDEBUG, "V : %8.02f %8d %8d A : %8.02f %8.02f Cv : %8d Ca : %8d \n", m_av_clock->OMXMediaTime(), m_player_video.GetDecoderBufferSize(), m_player_video.GetDecoderFreeSpace(), m_player_audio.GetCurrentPTS() / DVD_TIME_BASE, m_player_audio.GetDelay(), m_player_video.GetCached(), m_player_audio.GetCached()); +#endif } - if(m_omx_reader.IsEof() && !m_omx_pkt) + if(m_omx_reader->IsEof() && !m_omx_pkt) { if (!m_player_audio.GetCached() && !m_player_video.GetCached()) - break; - - // Abort audio buffering, now we're on our own - if (m_buffer_empty) - m_av_clock->OMXResume(); + { + break; + } + else + { + // CLog::Log(LOGDEBUG, "waiting before eof: %d %d\n", m_player_audio.GetCached(), m_player_video.GetCached()); + // Abort audio buffering, now we're on our own + if (m_buffer_empty) + m_av_clock->OMXResume(); - OMXClock::OMXSleep(10); - continue; + OMXClock::OMXSleep(10); + continue; + } } /* when the audio buffer runs under 0.1 seconds we buffer up */ @@ -1014,14 +1134,17 @@ int main(int argc, char *argv[]) } if(!m_omx_pkt) - m_omx_pkt = m_omx_reader.Read(); + m_omx_pkt = m_omx_reader->Read(); - if(m_has_video && m_omx_pkt && m_omx_reader.IsActive(OMXSTREAM_VIDEO, m_omx_pkt->stream_index)) + if(m_has_video && m_omx_pkt && m_omx_reader->IsActive(OMXSTREAM_VIDEO, m_omx_pkt->stream_index)) { - if(m_player_video.AddPacket(m_omx_pkt)) + if(m_player_video.AddPacket(m_omx_pkt)) { + // CLog::Log(LOGDEBUG, "+packet nok\n"); m_omx_pkt = NULL; - else + } else { + // CLog::Log(LOGDEBUG, "+packet ok\n"); OMXClock::OMXSleep(10); + } if(m_tv_show_info) { @@ -1044,7 +1167,7 @@ int main(int argc, char *argv[]) m_omx_pkt->codec_type == AVMEDIA_TYPE_SUBTITLE) { auto result = m_player_subtitles.AddPacket(m_omx_pkt, - m_omx_reader.GetRelativeIndex(m_omx_pkt->stream_index)); + m_omx_reader->GetRelativeIndex(m_omx_pkt->stream_index)); if (result) m_omx_pkt = NULL; else @@ -1054,7 +1177,7 @@ int main(int argc, char *argv[]) { if(m_omx_pkt) { - m_omx_reader.FreePacket(m_omx_pkt); + m_omx_reader->FreePacket(m_omx_pkt); m_omx_pkt = NULL; } } @@ -1071,30 +1194,42 @@ int main(int argc, char *argv[]) m_player_video.WaitCompletion(); } - if(m_has_video && m_refresh && tv_state.display.hdmi.group && tv_state.display.hdmi.mode) - { - m_BcmHost.vc_tv_hdmi_power_on_explicit_new(HDMI_MODE_HDMI, (HDMI_RES_GROUP_T)tv_state.display.hdmi.group, tv_state.display.hdmi.mode); - } - - m_av_clock->OMXStop(); - m_av_clock->OMXStateIdle(); - - m_player_subtitles.Close(); - m_player_video.Close(); - m_player_audio.Close(); - if(m_omx_pkt) { - m_omx_reader.FreePacket(m_omx_pkt); + m_omx_reader->FreePacket(m_omx_pkt); m_omx_pkt = NULL; } - m_omx_reader.Close(); + if (!m_stop && !g_abort) { + if (optind < argc) + { + FlushStreams(startpts); + if (m_has_video) m_player_video.UnFlush(); + goto play_file; + } - vc_tv_show_info(0); + else if (m_loop) + { +#if 0 + // full reset of OMX state + stop_player(m_refresh); + stop_omx(); + m_player_init = false; + start_omx(); +#else + FlushStreams(startpts); + if (m_has_video) m_player_video.UnFlush(); + //if (m_has_audio) m_player_audio.UnFlush(); +#endif + + optind = optind_filenames; + goto play_file; + } + } - g_OMX.Deinitialize(); - g_RBP.Deinitialize(); + stop_player(m_refresh); + + stop_omx(); printf("have a nice day ;)\n"); return 1; diff --git a/utils/log.cpp b/utils/log.cpp index 43102a1a..91fb08aa 100644 --- a/utils/log.cpp +++ b/utils/log.cpp @@ -24,6 +24,7 @@ #include "stdio_utf8.h" #include "stat_utf8.h" #include "utils/StdString.h" +#include static FILE* m_file = NULL; static int m_repeatCount = 0; @@ -57,7 +58,7 @@ void CLog::Log(int loglevel, const char *format, ... ) { pthread_mutex_lock(&m_log_mutex); - static const char* prefixFormat = "%02.2d:%02.2d:%02.2d T:%" PRIu64 " %7s: "; + static const char* prefixFormat = "%02.2d:%02.2d:%02.2d.%04.4d %7s: "; #if !(defined(_DEBUG) || defined(PROFILE)) if (m_logLevel > LOG_LEVEL_NORMAL || (m_logLevel > LOG_LEVEL_NONE && loglevel >= LOGNOTICE)) @@ -69,8 +70,13 @@ void CLog::Log(int loglevel, const char *format, ... ) return; } + struct timeval tv; + gettimeofday(&tv, NULL); SYSTEMTIME time; - //GetLocalTime(&time); + time.wHour = (tv.tv_sec / 3600) % 24; + time.wMinute = (tv.tv_sec / 60) % 60; + time.wSecond = tv.tv_sec % 60; + time.wMilliseconds = tv.tv_usec / 1000; CStdString strPrefix, strData; @@ -89,10 +95,7 @@ void CLog::Log(int loglevel, const char *format, ... ) else if (m_repeatCount) { CStdString strData2; - time.wHour = 0; - time.wMinute = 0; - time.wSecond = 0; - strPrefix.Format(prefixFormat, time.wHour, time.wMinute, time.wSecond, (uint64_t)0, levelNames[m_repeatLogLevel]); + strPrefix.Format(prefixFormat, time.wHour, time.wMinute, time.wSecond, time.wMilliseconds, levelNames[m_repeatLogLevel]); strData2.Format("Previous line repeats %d times." LINE_ENDING, m_repeatCount); fputs(strPrefix.c_str(), m_file); @@ -125,7 +128,7 @@ void CLog::Log(int loglevel, const char *format, ... ) strData.Replace("\n", LINE_ENDING" "); strData += LINE_ENDING; - strPrefix.Format(prefixFormat, time.wHour, time.wMinute, time.wSecond, (uint64_t)0, levelNames[loglevel]); + strPrefix.Format(prefixFormat, time.wHour, time.wMinute, time.wSecond, time.wMilliseconds, levelNames[loglevel]); fputs(strPrefix.c_str(), m_file); fputs(strData.c_str(), m_file);