From 843c61bd834939372788ddd665700697b132dbac Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Sun, 8 Aug 2010 15:36:05 +0300 Subject: [PATCH 2/5] fixed: VDPAU temporal deinterlacer was not provided enough fields According to NVIDIA documentation, the advanced deinterlacers need 2 previous fields and 1 future field for every call to video mixer. Make VDPAU always render the previously decoded frame, so that newly decoded frame can be used as a future field. --- .../DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 22 +++++++++++++++++-- .../DVDCodecs/Video/DVDVideoCodecFFmpeg.h | 5 ++++ xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 16 ++++++++++---- xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h | 3 ++ 4 files changed, 38 insertions(+), 8 deletions(-) diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp index e3a4e96..cf7b11e 100644 --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp @@ -148,6 +148,7 @@ CDVDVideoCodecFFmpeg::CDVDVideoCodecFFmpeg() : CDVDVideoCodec() m_iLastKeyframe = 0; m_dts = DVD_NOPTS_VALUE; m_started = false; + memset(&m_DVDPic, 0, sizeof(m_DVDPic)); } CDVDVideoCodecFFmpeg::~CDVDVideoCodecFFmpeg() @@ -388,6 +389,11 @@ int CDVDVideoCodecFFmpeg::Decode(BYTE* pData, int iSize, double dts, double pts) if(result) return result; + + /* in case of delayed playback we need to store the information from the + * current frame before decoding the next one */ + if (m_pHardware->FrameDelay()) + GetPictureCommon(&m_DVDPic); } m_dts = dts; @@ -506,7 +512,7 @@ void CDVDVideoCodecFFmpeg::Reset() } } -bool CDVDVideoCodecFFmpeg::GetPicture(DVDVideoPicture* pDvdVideoPicture) +bool CDVDVideoCodecFFmpeg::GetPictureCommon(DVDVideoPicture *pDvdVideoPicture) { GetVideoAspect(m_pCodecContext, pDvdVideoPicture->iDisplayWidth, pDvdVideoPicture->iDisplayHeight); @@ -564,6 +570,16 @@ bool CDVDVideoCodecFFmpeg::GetPicture(DVDVideoPicture* pDvdVideoPicture) if(!m_started) pDvdVideoPicture->iFlags |= DVP_FLAG_DROPPED; + return true; +} + +bool CDVDVideoCodecFFmpeg::GetPicture(DVDVideoPicture* pDvdVideoPicture) +{ + if (m_pHardware && m_pHardware->FrameDelay()) + *pDvdVideoPicture = m_DVDPic; + else if (!GetPictureCommon(pDvdVideoPicture)) + return false; + if(m_pHardware) return m_pHardware->GetPicture(m_pCodecContext, m_pFrame, pDvdVideoPicture); @@ -577,9 +593,9 @@ bool CDVDVideoCodecFFmpeg::GetPicture(DVDVideoPicture* pDvdVideoPicture) else { for (int i = 0; i < 4; i++) - pDvdVideoPicture->data[i] = frame->data[i]; + pDvdVideoPicture->data[i] = m_pFrame->data[i]; for (int i = 0; i < 4; i++) - pDvdVideoPicture->iLineSize[i] = frame->linesize[i]; + pDvdVideoPicture->iLineSize[i] = m_pFrame->linesize[i]; } pDvdVideoPicture->iFlags |= pDvdVideoPicture->data[0] ? 0 : DVP_FLAG_DROPPED; diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h index 321e2b7..2afe65f 100644 --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h @@ -45,6 +45,8 @@ public: virtual CCriticalSection* Section() { return NULL; } virtual long Release(); virtual IHardwareDecoder* Acquire(); + /** Queries the decoder if it has a one frame delay */ + virtual bool FrameDelay() const { return false; } protected: long m_references; }; @@ -76,6 +78,9 @@ protected: AVFrame* m_pFrame; AVCodecContext* m_pCodecContext; + bool GetPictureCommon(DVDVideoPicture *pDvdVideoPicture); + DVDVideoPicture m_DVDPic; + AVPicture* m_pConvertFrame; int m_iPictureWidth; diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp index b71b2d6..7ebefc8 100644 --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp @@ -1150,9 +1150,10 @@ int CVDPAU::Decode(AVCodecContext *avctx, AVFrame *pFrame) ClearUsedForRender(&past[0]); past[0] = past[1]; past[1] = current; - current = render; + current = future; + future = render; - if((method == VS_INTERLACEMETHOD_AUTO && pFrame->interlaced_frame) + if((method == VS_INTERLACEMETHOD_AUTO && m_interlaced) || method == VS_INTERLACEMETHOD_VDPAU_BOB || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL || method == VS_INTERLACEMETHOD_VDPAU_TEMPORAL_HALF @@ -1167,7 +1168,7 @@ int CVDPAU::Decode(AVCodecContext *avctx, AVFrame *pFrame) else m_mixerstep = 1; - if(pFrame->top_field_first) + if(m_topFieldFirst) m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD; else m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD; @@ -1178,6 +1179,11 @@ int CVDPAU::Decode(AVCodecContext *avctx, AVFrame *pFrame) m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME; } + m_interlaced = pFrame->interlaced_frame; + m_topFieldFirst = pFrame->top_field_first; + + if (!current) + return VC_BUFFER; } else if(m_mixerstep == 1) { // no new frame given, output second field of old frame @@ -1208,7 +1214,7 @@ int CVDPAU::Decode(AVCodecContext *avctx, AVFrame *pFrame) past_surfaces[1] = past[0]->surface; if (past[1]) past_surfaces[0] = past[1]->surface; - futu_surfaces[0] = VDP_INVALID_HANDLE; + futu_surfaces[0] = future->surface; } else { @@ -1225,7 +1231,7 @@ int CVDPAU::Decode(AVCodecContext *avctx, AVFrame *pFrame) if (past[1]) past_surfaces[1] = past[1]->surface; past_surfaces[0] = current->surface; - futu_surfaces[0] = VDP_INVALID_HANDLE; + futu_surfaces[0] = future->surface; } } diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h index c50229b..e1c9f71 100644 --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h @@ -75,6 +75,7 @@ public: return 0; } virtual const std::string Name() { return "vdpau"; } + virtual bool FrameDelay() const { return true; } bool MakePixmap(int width, int height); bool MakePixmapGL(); @@ -119,6 +120,8 @@ public: float tmpBrightness, tmpContrast; int OutWidth, OutHeight; bool upScale; + bool m_interlaced; + bool m_topFieldFirst; static inline void ClearUsedForRender(vdpau_render_state **st) { -- 1.7.2