From 36b285b5f7351836f0ad6a364c3d4743549a99c7 Mon Sep 17 00:00:00 2001 From: Johns Date: Mon, 19 Dec 2011 17:03:40 +0100 Subject: [PATCH] Audio/video sync improvements. Configurable audio delay. Use monotonic pts. Support old libav or ffmpeg libraries. --- ChangeLog | 3 +++ README.txt | 3 +++ codec.c | 37 ++++++++++++++++++++++++++++++------- softhddev.c | 1 + softhddevice.cpp | 10 ++++++++++ video.c | 48 +++++++++++++++++++++++++++++++++++++++--------- video.h | 6 ++++++ 7 files changed, 92 insertions(+), 16 deletions(-) diff --git a/ChangeLog b/ChangeLog index 59d21d4..91d3cfe 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,9 @@ User johns Date: + Configurable audio delay. + Make pts monotonic. + Support old libav and ffmpeg libs. Support xcb_icccm_set_wm_protocols with xcb-util <0.3.8. New video/audio sync code. Support xcb-util <0.3.8. diff --git a/README.txt b/README.txt index 6d1436f..f4279f7 100644 --- a/README.txt +++ b/README.txt @@ -70,6 +70,9 @@ Setup: /etc/vdr/setup.conf softhddevice.Scaling = 0 0 = normal, 1 = fast, 2 = HQ, 3 = anamorphic + softhddevice.AudioDelay = 0 + +n or -n ms + Requires: --------- media-video/ffmpeg diff --git a/codec.c b/codec.c index fd5258d..656052a 100644 --- a/codec.c +++ b/codec.c @@ -259,6 +259,7 @@ void CodecVideoOpen(VideoDecoder * decoder, const char *name, int codec_id) Debug(3, "codec: vdpau decoder found\n"); } else if (!(video_codec = avcodec_find_decoder(codec_id))) { Fatal(_("codec: codec ID %#04x not found\n"), codec_id); + // FIXME: none fatal } decoder->VideoCodec = video_codec; @@ -266,9 +267,15 @@ void CodecVideoOpen(VideoDecoder * decoder, const char *name, int codec_id) Fatal(_("codec: can't allocate video codec context\n")); } // open codec +#if LIBAVCODEC_VERSION_INT <= AV_VERSION_INT(52,122,0) + if (avcodec_open(decoder->VideoCtx, video_codec) < 0) { + Fatal(_("codec: can't open video codec!\n")); + } +#else if (avcodec_open2(decoder->VideoCtx, video_codec, NULL) < 0) { Fatal(_("codec: can't open video codec!\n")); } +#endif decoder->VideoCtx->opaque = decoder; // our structure @@ -354,26 +361,36 @@ void CodecVideoClose(VideoDecoder * video_decoder) #if 0 -#ifdef DEBUG - /** ** Display pts... +** +** ffmpeg 0.9 pts always AV_NOPTS_VALUE +** ffmpeg 0.9 pkt_pts nice monotonic (only with HD) +** ffmpeg 0.9 pkt_dts wild jumping -160 - 340 ms +** +** libav 0.8_pre20111116 pts always AV_NOPTS_VALUE +** libav 0.8_pre20111116 pkt_pts always 0 +** libav 0.8_pre20111116 pkt_dts wild jumping -160 - 340 ms */ void DisplayPts(AVCodecContext * video_ctx, AVFrame * frame) { int ms_delay; + int64_t pts; + static int64_t last_pts; - if (frame->pts == (int64_t) AV_NOPTS_VALUE) { + pts = frame->pkt_pts; + if (pts == (int64_t) AV_NOPTS_VALUE) { printf("*"); } ms_delay = (1000 * video_ctx->time_base.num) / video_ctx->time_base.den; ms_delay += frame->repeat_pict * ms_delay / 2; - printf("codec: PTS %s%s %" PRId64 " %d/%d %dms\n", + printf("codec: PTS %s%s %" PRId64 " %d %d/%d %dms\n", frame->repeat_pict ? "r" : " ", frame->interlaced_frame ? "I" : " ", - frame->pts, video_ctx->time_base.num, video_ctx->time_base.den, - ms_delay); + pts, (int)(pts - last_pts) / 90, video_ctx->time_base.num, + video_ctx->time_base.den, ms_delay); + + last_pts = pts; } -#endif #endif @@ -506,9 +523,15 @@ void CodecAudioOpen(AudioDecoder * audio_decoder, const char *name, Fatal(_("codec: can't allocate audio codec context\n")); } // open codec +#if LIBAVCODEC_VERSION_INT <= AV_VERSION_INT(52,122,0) + if (avcodec_open(audio_decoder->AudioCtx, audio_codec) < 0) { + Fatal(_("codec: can't open audio codec\n")); + } +#else if (avcodec_open2(audio_decoder->AudioCtx, audio_codec, NULL) < 0) { Fatal(_("codec: can't open audio codec\n")); } +#endif Debug(3, "codec: audio '%s'\n", audio_decoder->AudioCtx->codec_name); if (audio_codec->capabilities & CODEC_CAP_TRUNCATED) { diff --git a/softhddev.c b/softhddev.c index a57eff9..a6c731b 100644 --- a/softhddev.c +++ b/softhddev.c @@ -655,6 +655,7 @@ int Poll(int timeout) { // buffers are too full if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX / 2) { + Debug(3, "replay: poll %d\n", timeout); if (timeout) { // let display thread work usleep(timeout * 1000); diff --git a/softhddevice.cpp b/softhddevice.cpp index 260cc5f..ff675c9 100644 --- a/softhddevice.cpp +++ b/softhddevice.cpp @@ -51,6 +51,7 @@ static class cSoftHdDevice *MyDevice; static char ConfigMakePrimary; ///< config primary wanted static char ConfigVideoDeinterlace; ///< config deinterlace static char ConfigVideoScaling; ///< config scaling +static int ConfigVideoAudioDelay; ///< config audio delay static char DoMakePrimary; ///< flag switch primary ////////////////////////////////////////////////////////////////////////////// @@ -261,6 +262,7 @@ class cMenuSetupSoft:public cMenuSetupPage int MakePrimary; int Deinterlace; int Scaling; + int AudioDelay; protected: virtual void Store(void); public: @@ -286,6 +288,8 @@ cMenuSetupSoft::cMenuSetupSoft(void) Add(new cMenuEditStraItem(tr("Deinterlace"), &Deinterlace, 5, deinterlace)); Scaling = ConfigVideoScaling; Add(new cMenuEditStraItem(tr("Scaling"), &Scaling, 4, scaling)); + AudioDelay = ConfigVideoAudioDelay; + Add(new cMenuEditIntItem(tr("Audio delay (ms)"), &AudioDelay, -1000, 1000)); } /** @@ -298,6 +302,8 @@ void cMenuSetupSoft::Store(void) VideoSetDeinterlace(ConfigVideoDeinterlace); SetupStore("Scaling", ConfigVideoScaling = Scaling); VideoSetScaling(ConfigVideoScaling); + SetupStore("AudioDelay", ConfigVideoAudioDelay = AudioDelay); + VideoSetAudioDelay(ConfigVideoAudioDelay); } ////////////////////////////////////////////////////////////////////////////// @@ -766,6 +772,10 @@ bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value) VideoSetScaling(ConfigVideoScaling = atoi(value)); return true; } + if (!strcmp(name, "AudioDelay")) { + VideoSetAudioDelay(ConfigVideoAudioDelay = atoi(value)); + return true; + } return false; } diff --git a/video.c b/video.c index 0e437d8..b7930b8 100644 --- a/video.c +++ b/video.c @@ -181,6 +181,9 @@ static VideoDeinterlaceModes VideoDeinterlace; /// Default scaling mode static VideoScalingModes VideoScaling; + /// Default audio/video delay +static int VideoAudioDelay; + //static char VideoSoftStartSync; ///< soft start sync audio/video static char Video60HzMode; ///< handle 60hz displays @@ -2520,7 +2523,7 @@ static void VaapiDisplayFrame(void) // deinterlace and full frame rate // VDPAU driver only display a frame, if a full frame is put // INTEL driver does the same, but only with 1080i - if (decoder->Interlaced + if (0 && decoder->Interlaced // FIXME: buggy libva-driver-vdpau, buggy libva-driver-intel && (VaapiBuggyVdpau || (0 && VaapiBuggyIntel && decoder->InputHeight == 1080)) @@ -3136,10 +3139,11 @@ static void VaapiSyncDisplayFrame(VaapiDecoder * decoder) if (abs(video_clock - audio_clock) > 5000 * 90) { Debug(3, "video: pts difference too big\n"); - } else if (video_clock > audio_clock + 300 * 90) { + } else if (video_clock > audio_clock + VideoAudioDelay + 30 * 90) { Debug(3, "video: slow down video\n"); decoder->DupNextFrame = 1; - } else if (audio_clock > video_clock + 300 * 90) { + } else if (audio_clock + VideoAudioDelay > video_clock + 50 * 90 + && filled > 1) { Debug(3, "video: speed up video\n"); decoder->DropNextFrame = 1; } @@ -3502,19 +3506,30 @@ void VideoRenderFrame(VideoHwDecoder * decoder, AVCodecContext * video_ctx, // FIXME: move into vaapi module // update video clock - decoder->Vaapi.PTS += decoder->Vaapi.Interlaced ? 40 * 90 : 20 * 90; - + if ((uint64_t) decoder->Vaapi.PTS != AV_NOPTS_VALUE) { + decoder->Vaapi.PTS += decoder->Vaapi.Interlaced ? 40 * 90 : 20 * 90; + } //pts = frame->best_effort_timestamp; pts = frame->pkt_pts; if ((uint64_t) pts == AV_NOPTS_VALUE || !pts) { + // libav: 0.8pre didn't set pts pts = frame->pkt_dts; } - // libav: sets only pkt_dts + if (!pts) { + pts = AV_NOPTS_VALUE; + } + // build a monotonic pts + if ((uint64_t) decoder->Vaapi.PTS != AV_NOPTS_VALUE) { + if (pts - decoder->Vaapi.PTS < -10 * 90) { + pts = AV_NOPTS_VALUE; + } + } + // libav: sets only pkt_dts which can be 0 if ((uint64_t) pts != AV_NOPTS_VALUE) { if (decoder->Vaapi.PTS != pts) { - Debug(4, + Debug(3, "video: %#012" PRIx64 "->%#012" PRIx64 " %4" PRId64 " pts\n", - decoder->Vaapi.PTS, pts, decoder->Vaapi.PTS - pts); + decoder->Vaapi.PTS, pts, pts - decoder->Vaapi.PTS); decoder->Vaapi.PTS = pts; } } @@ -3557,6 +3572,10 @@ void VideoRenderFrame(VideoHwDecoder * decoder, AVCodecContext * video_ctx, VaapiSyncDisplayFrame(&decoder->Vaapi); } + + if (frame->repeat_pict) { + Warning("video/vaapi: repeated pict found, but not handle\n"); + } #ifdef USE_VAAPI if (VideoVaapiEnabled) { VaapiRenderFrame(&decoder->Vaapi, video_ctx, frame); @@ -3634,7 +3653,8 @@ void VideoDisplayHandler(void) /** ** Get video clock. ** -** @note this isn't monoton, decoding reorders frames. +** @note this isn't monoton, decoding reorders frames, +** setter keeps it monotonic */ int64_t VideoGetClock(void) { @@ -3776,6 +3796,16 @@ void VideoSetScaling(int mode) VideoScaling = mode; } +/** +** Set audio delay. +** +** @param ms delay in ms +*/ +void VideoSetAudioDelay(int ms) +{ + VideoAudioDelay = ms * 90; +} + /** ** Initialize video output module. ** diff --git a/video.h b/video.h index 47fcf41..eaacc0a 100644 --- a/video.h +++ b/video.h @@ -65,6 +65,9 @@ extern enum PixelFormat Video_get_format(VideoHwDecoder *, AVCodecContext *, /// Display video TEST extern void VideoDisplayHandler(void); + /// Poll video events +extern void VideoPollEvent(void); + /// set video mode //extern void VideoSetVideoMode(int, int, int, int); @@ -77,6 +80,9 @@ extern void VideoSetDeinterlace(int); /// set scaling extern void VideoSetScaling(int); + /// set audio delay +extern void VideoSetAudioDelay(int); + /// Clear OSD extern void VideoOsdClear(void);