From 9f637f986e8f43b2f6f8ba2608528a32310e7ab3 Mon Sep 17 00:00:00 2001 From: Johns Date: Thu, 22 Dec 2011 22:20:52 +0100 Subject: [PATCH] Add video/audio sync to vdpau. --- video.c | 149 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 98 insertions(+), 51 deletions(-) diff --git a/video.c b/video.c index b4078ac..c722d74 100644 --- a/video.c +++ b/video.c @@ -2448,9 +2448,9 @@ static void VaapiRenderFrame(VaapiDecoder * decoder, } } -/** -** Advance displayed frame. -*/ +/// +/// Advance displayed frame. +/// static void VaapiAdvanceFrame(void) { int i; @@ -2703,12 +2703,12 @@ static void VaapiSyncRenderFrame(VaapiDecoder * decoder, #if 0 -/** -** Update video pts. -** -** @param decoder VA-API decoder -** @param frame frame to display -*/ +/// +/// Update video pts. +/// +/// @param decoder VA-API decoder +/// @param frame frame to display +/// static void VaapiSetPts(VaapiDecoder * decoder, const AVFrame * frame) { int64_t pts; @@ -2746,6 +2746,27 @@ static void VaapiSetPts(VaapiDecoder * decoder, const AVFrame * frame) #endif +/// +/// Get VA-API decoder video clock. +/// +/// @param decoder VA-API decoder +/// +static int64_t VaapiGetClock(const VaapiDecoder * decoder) +{ + // pts is the timestamp of the latest decoded frame + if ((uint64_t) decoder->PTS == AV_NOPTS_VALUE) { + return AV_NOPTS_VALUE; + } + // subtract buffered decoded frames + if (decoder->Interlaced) { + return decoder->PTS - + 20 * 90 * (2 * atomic_read(&decoder->SurfacesFilled) + - decoder->SurfaceField); + } + return decoder->PTS - 20 * 90 * (atomic_read(&decoder->SurfacesFilled) - + 1); +} + #ifdef USE_VIDEO_THREAD /** @@ -2998,6 +3019,7 @@ typedef struct _vdpau_decoder_ int InputY; ///< input y int InputWidth; ///< input width int InputHeight; ///< input height + AVRational InputAspect; ///< input aspect ratio #ifdef noyetUSE_GLX GLuint GlTexture[2]; ///< gl texture for VDPAU @@ -4165,7 +4187,7 @@ static void VdpauRenderFrame(VdpauDecoder * decoder, // place in output queue // I place it here, for later thread support - if (0) { // can't wait for output queue empty + if (1) { // can't wait for output queue empty if (atomic_read(&decoder->SurfacesFilled) >= VIDEO_SURFACES_MAX) { Warning(_ ("video/vdpau: output buffer full, dropping frame (%d/%d)\n"), @@ -4373,6 +4395,43 @@ static void VdpauMixVideo(VdpauDecoder * decoder) decoder->SurfaceRead); } +/// +/// Advance displayed frame. +/// +static void VdpauAdvanceFrame(void) +{ + int i; + + for (i = 0; i < VdpauDecoderN; ++i) { + int filled; + VdpauDecoder *decoder; + + decoder = VdpauDecoders[i]; + + // next field + if (decoder->Interlaced) { + decoder->SurfaceField ^= 1; + } + // next surface, if complete frame is displayed + if (!decoder->SurfaceField) { + // check decoder, if new surface is available + // need 2 frames for progressive + // need 4 frames for interlaced + filled = atomic_read(&decoder->SurfacesFilled); + if (filled <= 1 + 2 * decoder->Interlaced) { + // keep use of last surface + ++decoder->FramesDuped; + VdpauPrintFrames(decoder); + decoder->SurfaceField = decoder->Interlaced; + } else { + decoder->SurfaceRead = (decoder->SurfaceRead + 1) + % VIDEO_SURFACES_MAX; + atomic_dec(&decoder->SurfacesFilled); + } + } + } +} + /// /// Display a video frame. /// @@ -4421,36 +4480,17 @@ static void VdpauDisplayFrame(void) VdpauDecoder *decoder; decoder = VdpauDecoders[i]; + decoder->FramesDisplayed++; filled = atomic_read(&decoder->SurfacesFilled); // need 1 frame for progressive, 3 frames for interlaced if (filled < 1 + 2 * decoder->Interlaced) { // FIXME: render black surface + // FIXME: or rewrite MixVideo to support less surfaces continue; } VdpauMixVideo(decoder); - - // next field - if (decoder->Interlaced) { - decoder->SurfaceField ^= 1; - } - // next surface, if complete frame is displayed - if (!decoder->SurfaceField) { - // check decoder, if new surface is available - // need 2 frames for progressive - // need 4 frames for interlaced - if (filled <= 1 + 2 * decoder->Interlaced) { - // keep use of last surface - ++decoder->FramesDuped; - VdpauPrintFrames(decoder); - decoder->SurfaceField = decoder->Interlaced; - } else { - decoder->SurfaceRead = (decoder->SurfaceRead + 1) - % VIDEO_SURFACES_MAX; - atomic_dec(&decoder->SurfacesFilled); - } - } } // @@ -4481,15 +4521,13 @@ static void VdpauDisplayFrame(void) /// static void VdpauSyncDisplayFrame(VdpauDecoder * decoder) { - VdpauDisplayFrame(); -#if 0 int filled; int64_t audio_clock; int64_t video_clock; if (!decoder->DupNextFrame && (!Video60HzMode || decoder->FramesDisplayed % 6)) { - VaapiAdvanceFrame(); + VdpauAdvanceFrame(); } // debug duplicate frames filled = atomic_read(&decoder->SurfacesFilled); @@ -4498,11 +4536,11 @@ static void VdpauSyncDisplayFrame(VdpauDecoder * decoder) Warning(_("video: display buffer empty, duping frame (%d/%d)\n"), decoder->FramesDuped, decoder->FrameCounter); if (!(decoder->FramesDisplayed % 333)) { - VaapiPrintFrames(decoder); + VdpauPrintFrames(decoder); } } - VaapiDisplayFrame(); + VdpauDisplayFrame(); // // audio/video sync @@ -4541,7 +4579,6 @@ static void VdpauSyncDisplayFrame(VdpauDecoder * decoder) last_video_clock = video_clock; } -#endif } /// @@ -4596,6 +4633,27 @@ static void VdpauSyncRenderFrame(VdpauDecoder * decoder, VdpauRenderFrame(decoder, video_ctx, frame); } +/// +/// Get VDPAU decoder video clock. +/// +/// @param decoder VDPAU decoder +/// +static int64_t VdpauGetClock(const VdpauDecoder * decoder) +{ + // pts is the timestamp of the latest decoded frame + if ((uint64_t) decoder->PTS == AV_NOPTS_VALUE) { + return AV_NOPTS_VALUE; + } + // subtract buffered decoded frames + if (decoder->Interlaced) { + return decoder->PTS - + 20 * 90 * (2 * atomic_read(&decoder->SurfacesFilled) + - decoder->SurfaceField); + } + return decoder->PTS - 20 * 90 * (atomic_read(&decoder->SurfacesFilled) - + 1); +} + #ifdef USE_VIDEO_THREAD /** @@ -5557,29 +5615,18 @@ void VideoDisplayHandler(void) ** ** @note this isn't monoton, decoding reorders frames, ** setter keeps it monotonic +** @todo we have multiple clocks, for multiple stream */ int64_t VideoGetClock(void) { #ifdef USE_VAAPI if (VideoVaapiEnabled) { - // FIXME: VaapiGetClock(); - - // pts is the timestamp of the latest decoded frame - if ((uint64_t) VaapiDecoders[0]->PTS == AV_NOPTS_VALUE) { - return AV_NOPTS_VALUE; - } - if (VaapiDecoders[0]->Interlaced) { - return VaapiDecoders[0]->PTS - - 20 * 90 * (2 * atomic_read(&VaapiDecoders[0]->SurfacesFilled) - - VaapiDecoders[0]->SurfaceField); - } - return VaapiDecoders[0]->PTS - - 20 * 90 * (atomic_read(&VaapiDecoders[0]->SurfacesFilled) - 1); + return VaapiGetClock(VaapiDecoders[0]); } #endif #ifdef USE_VDPAU if (VideoVdpauEnabled) { - return 0L; + return VdpauGetClock(VdpauDecoders[0]); } #endif return 0L;