aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRainer Hochecker <fernetmenta@online.de>2015-03-24 09:26:52 +0100
committerRainer Hochecker <fernetmenta@online.de>2015-03-24 09:26:52 +0100
commit0fbe7600ae8d1e70a0b455897d695fa6ca995688 (patch)
treea4fccc29c7dc83526c7b3696c1a2b05d9260ddc7
parent7beb7235d2cee4692fe55a919dcef18a1cec0ccc (diff)
parent84958d01451b6d1fd2ecdf048559c75e6d7f0b21 (diff)
Merge pull request #6771 from FernetMenta/ffmpegthread
rework frame threading for ffmpeg
-rw-r--r--xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h7
-rw-r--r--xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp115
-rw-r--r--xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h9
-rw-r--r--xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp3
-rw-r--r--xbmc/cores/dvdplayer/DVDPlayerVideo.cpp18
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)
{