diff options
author | Rainer Hochecker <fernetmenta@online.de> | 2015-03-24 09:26:52 +0100 |
---|---|---|
committer | Rainer Hochecker <fernetmenta@online.de> | 2015-03-24 09:26:52 +0100 |
commit | 0fbe7600ae8d1e70a0b455897d695fa6ca995688 (patch) | |
tree | a4fccc29c7dc83526c7b3696c1a2b05d9260ddc7 | |
parent | 7beb7235d2cee4692fe55a919dcef18a1cec0ccc (diff) | |
parent | 84958d01451b6d1fd2ecdf048559c75e6d7f0b21 (diff) |
Merge pull request #6771 from FernetMenta/ffmpegthread
rework frame threading for ffmpeg
5 files changed, 87 insertions, 65 deletions
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h index 909704e543..6fb88e03f5 100644 --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h @@ -172,6 +172,7 @@ class CDVDCodecOptions; #define VC_FLUSHED 0x00000010 // the decoder lost it's state, we need to restart decoding again #define VC_DROPPED 0x00000020 // needed to identify if a picture was dropped #define VC_NOBUFFER 0x00000040 // last FFmpeg GetBuffer failed +#define VC_REOPEN 0x00000080 // decoder request to re-open class CDVDVideoCodec { @@ -339,4 +340,10 @@ public: * */ virtual void SetCodecControl(int flags) {} + + /* + * Re-open the decoder. + * Decoder request to re-open + */ + virtual void Reopen() {}; }; diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp index 22847dd602..4fb3248ca3 100644 --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp @@ -72,15 +72,23 @@ extern "C" { using namespace std; +enum DecoderState +{ + STATE_NONE, + STATE_SW_SINGLE, + STATE_HW_SINGLE, + STATE_HW_FAILED, + STATE_SW_MULTI +}; + enum PixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avctx , const PixelFormat * fmt ) { CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)avctx->opaque; // if frame threading is enabled hw accel is not allowed - if((EDECODEMETHOD) CSettings::Get().GetInt("videoplayer.decodingmethod") != VS_DECODEMETHOD_HARDWARE || !ctx->IsHardwareAllowed()) + if(ctx->m_decoderState != STATE_HW_SINGLE) { - ctx->m_pCodecContext->thread_safe_callbacks = 1; return avcodec_default_get_format(avctx, fmt); } @@ -155,7 +163,7 @@ enum PixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avctx avctx->hwaccel_context = 0; } - ctx->m_pCodecContext->thread_safe_callbacks = 1; + ctx->m_decoderState = STATE_HW_FAILED; return avcodec_default_get_format(avctx, fmt); } @@ -176,13 +184,7 @@ CDVDVideoCodecFFmpeg::CDVDVideoCodecFFmpeg() : CDVDVideoCodec() m_iScreenWidth = 0; m_iScreenHeight = 0; m_iOrientation = 0; - m_bSoftware = false; - #if defined(TARGET_ANDROID) || defined(TARGET_DARWIN_IOS) - // If we get here on Android or iOS, it's always software - m_isFrameThreaded = true; - #else - m_isFrameThreaded = false; - #endif + m_decoderState = STATE_NONE; m_pHardware = NULL; m_iLastKeyframe = 0; m_dts = DVD_NOPTS_VALUE; @@ -200,10 +202,12 @@ CDVDVideoCodecFFmpeg::~CDVDVideoCodecFFmpeg() bool CDVDVideoCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) { + m_hints = hints; + m_options = options; + AVCodec* pCodec; - m_bSoftware = hints.software; - m_iOrientation = hints.orientation; + m_iOrientation = hints.orientation; for(std::vector<ERenderFormat>::iterator it = options.m_formats.begin(); it != options.m_formats.end(); ++it) { @@ -213,33 +217,7 @@ bool CDVDVideoCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options } m_formats.push_back(PIX_FMT_NONE); /* always add none to get a terminated list in ffmpeg world */ - pCodec = NULL; - m_pCodecContext = NULL; - - if (hints.codec == AV_CODEC_ID_H264) - { - switch (hints.profile) - { - case FF_PROFILE_H264_HIGH_10: - case FF_PROFILE_H264_HIGH_10_INTRA: - case FF_PROFILE_H264_HIGH_422: - case FF_PROFILE_H264_HIGH_422_INTRA: - case FF_PROFILE_H264_HIGH_444_PREDICTIVE: - case FF_PROFILE_H264_HIGH_444_INTRA: - case FF_PROFILE_H264_CAVLC_444: - // this is needed to not open the decoders - m_bSoftware = true; - // this we need to enable multithreading for hi10p via advancedsettings - m_isFrameThreaded = true; - break; - } - } - else if (hints.codec == AV_CODEC_ID_HEVC - || hints.codec == AV_CODEC_ID_VP9) - m_isFrameThreaded = true; - - if(pCodec == NULL) - pCodec = avcodec_find_decoder(hints.codec); + pCodec = avcodec_find_decoder(hints.codec); if(pCodec == NULL) { @@ -249,9 +227,7 @@ bool CDVDVideoCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options CLog::Log(LOGNOTICE,"CDVDVideoCodecFFmpeg::Open() Using codec: %s",pCodec->long_name ? pCodec->long_name : pCodec->name); - if(m_pCodecContext == NULL) - m_pCodecContext = avcodec_alloc_context3(pCodec); - + m_pCodecContext = avcodec_alloc_context3(pCodec); m_pCodecContext->opaque = (void*)this; m_pCodecContext->debug_mv = 0; m_pCodecContext->debug = 0; @@ -259,17 +235,31 @@ bool CDVDVideoCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options m_pCodecContext->get_format = GetFormat; m_pCodecContext->codec_tag = hints.codec_tag; - /* Only allow slice threading, since frame threading is more - * sensitive to changes in frame sizes, and it causes crashes - * during HW accell - so we unset it in this case. - * */ - if ((EDECODEMETHOD)CSettings::Get().GetInt("videoplayer.decodingmethod") == VS_DECODEMETHOD_SOFTWARE || m_isFrameThreaded) + // setup threading model + if (!hints.software) { - CLog::Log(LOGDEBUG, "CDVDVideoCodecFFmpeg::Open() Keeping default threading %d", - m_pCodecContext->thread_type); + if ((EDECODEMETHOD)CSettings::Get().GetInt("videoplayer.decodingmethod") == VS_DECODEMETHOD_HARDWARE && + m_decoderState == STATE_NONE) + { +#if defined(TARGET_ANDROID) || defined(TARGET_DARWIN_IOS) + // If we get here on Android or iOS, it's always multi + m_decoderState = STATE_SW_MULTI; +#else + m_decoderState = STATE_HW_SINGLE; +#endif + } + else + { + int num_threads = std::min(8 /*MAX_THREADS*/, g_cpuInfo.getCPUCount()); + if( num_threads > 1) + m_pCodecContext->thread_count = num_threads; + m_pCodecContext->thread_safe_callbacks = 1; + m_decoderState = STATE_SW_MULTI; + CLog::Log(LOGDEBUG, "CDVDVideoCodecFFmpeg - open frame threaded with %d threads", num_threads); + } } else - m_pCodecContext->thread_type = FF_THREAD_SLICE; + m_decoderState = STATE_SW_SINGLE; #if defined(TARGET_DARWIN_IOS) // ffmpeg with enabled neon will crash and burn if this is enabled @@ -309,10 +299,6 @@ bool CDVDVideoCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options av_opt_set(m_pCodecContext, it->m_name.c_str(), it->m_value.c_str(), 0); } - int num_threads = std::min(8 /*MAX_THREADS*/, g_cpuInfo.getCPUCount()); - if( num_threads > 1 && !hints.software) // thumbnail extraction fails when run threaded - m_pCodecContext->thread_count = num_threads; - if (avcodec_open2(m_pCodecContext, pCodec, NULL) < 0) { CLog::Log(LOGDEBUG,"CDVDVideoCodecFFmpeg::Open() Unable to open codec"); @@ -338,7 +324,9 @@ void CDVDVideoCodecFFmpeg::Dispose() if (m_pCodecContext) { - if (m_pCodecContext->codec) avcodec_close(m_pCodecContext); + if (m_pCodecContext->codec) + avcodec_close(m_pCodecContext); + if (m_pCodecContext->extradata) { av_free(m_pCodecContext->extradata); @@ -491,6 +479,9 @@ int CDVDVideoCodecFFmpeg::Decode(uint8_t* pData, int iSize, double dts, double p avpkt.flags = AV_PKT_FLAG_KEY; len = avcodec_decode_video2(m_pCodecContext, m_pFrame, &iGotPicture, &avpkt); + if (m_decoderState == STATE_HW_FAILED && !m_pHardware) + return VC_REOPEN; + if(m_iLastKeyframe < m_pCodecContext->has_b_frames + 2) m_iLastKeyframe = m_pCodecContext->has_b_frames + 2; @@ -585,6 +576,15 @@ void CDVDVideoCodecFFmpeg::Reset() FilterClose(); } +void CDVDVideoCodecFFmpeg::Reopen() +{ + Dispose(); + if (!Open(m_hints, m_options)) + { + Dispose(); + } +} + bool CDVDVideoCodecFFmpeg::GetPictureCommon(DVDVideoPicture* pDvdVideoPicture) { if (!m_pFrame) @@ -871,10 +871,7 @@ int CDVDVideoCodecFFmpeg::FilterProcess(AVFrame* frame) unsigned CDVDVideoCodecFFmpeg::GetConvergeCount() { - if(m_pHardware) - return m_iLastKeyframe; - else - return 0; + return m_iLastKeyframe; } unsigned CDVDVideoCodecFFmpeg::GetAllowedReferences() diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h index ca9ff5d8c8..52705651c8 100644 --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h @@ -20,6 +20,8 @@ * */ +#include "cores/dvdplayer/DVDCodecs/DVDCodecs.h" +#include "cores/dvdplayer/DVDStreamInfo.h" #include "DVDVideoCodec.h" #include "DVDResource.h" #include <string> @@ -60,6 +62,7 @@ public: virtual void Dispose(); virtual int Decode(uint8_t* pData, int iSize, double dts, double pts); virtual void Reset(); + virtual void Reopen(); bool GetPictureCommon(DVDVideoPicture* pDvdVideoPicture); virtual bool GetPicture(DVDVideoPicture* pDvdVideoPicture); virtual void SetDropState(bool bDrop); @@ -70,7 +73,6 @@ public: virtual bool GetCodecStats(double &pts, int &droppedPics); virtual void SetCodecControl(int flags); - bool IsHardwareAllowed() { return !m_bSoftware; } IHardwareDecoder * GetHardware() { return m_pHardware; }; void SetHardware(IHardwareDecoder* hardware); @@ -113,8 +115,7 @@ protected: unsigned int m_uSurfacesCount; std::string m_name; - bool m_bSoftware; - bool m_isFrameThreaded; + int m_decoderState; IHardwareDecoder *m_pHardware; std::vector<IHardwareDecoder*> m_disposeDecoders; int m_iLastKeyframe; @@ -125,4 +126,6 @@ protected: int m_skippedDeint; bool m_requestSkipDeint; int m_codecControlFlags; + CDVDStreamInfo m_hints; + CDVDCodecOptions m_options; }; diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp index 4806509203..33a2f93cde 100644 --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp @@ -599,8 +599,7 @@ bool CDecoder::Open(AVCodecContext* avctx, AVCodecContext* mainctx, const enum P // add an extra surface for safety, some faulty material // make ffmpeg require more buffers - // frame threading requires an additional one - m_vaapiConfig.maxReferences += surfaces + 2; + m_vaapiConfig.maxReferences += surfaces + 1; if (!ConfigVAAPI()) { diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp index 062f8fd839..69dc501c18 100644 --- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp @@ -592,7 +592,6 @@ void CDVDPlayerVideo::Process() // loop while no error while (!m_bStop) { - // if decoder was flushed, we need to seek back again to resume rendering if (iDecoderState & VC_FLUSHED) { @@ -615,6 +614,23 @@ void CDVDPlayerVideo::Process() break; } + if (iDecoderState & VC_REOPEN) + { + while(!m_packets.empty()) + { + CDVDMsgDemuxerPacket* msg = (CDVDMsgDemuxerPacket*)m_packets.front().message->Acquire(); + msg->m_drop = false; + m_packets.pop_front(); + m_messageQueue.Put(msg, iPriority + 10); + } + + m_pVideoCodec->Reopen(); + m_packets.clear(); + picture.iFlags &= ~DVP_FLAG_ALLOCATED; + g_renderManager.DiscardBuffer(); + break; + } + // if decoder had an error, tell it to reset to avoid more problems if (iDecoderState & VC_ERROR) { |