Audio/video sync improvements.

Configurable audio delay.
Use monotonic pts.
Support old libav or ffmpeg libraries.
This commit is contained in:
Johns 2011-12-19 17:03:40 +01:00
parent 33460f1370
commit 36b285b5f7
7 changed files with 92 additions and 16 deletions

View File

@ -1,6 +1,9 @@
User johns User johns
Date: 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. Support xcb_icccm_set_wm_protocols with xcb-util <0.3.8.
New video/audio sync code. New video/audio sync code.
Support xcb-util <0.3.8. Support xcb-util <0.3.8.

View File

@ -70,6 +70,9 @@ Setup: /etc/vdr/setup.conf
softhddevice.Scaling = 0 softhddevice.Scaling = 0
0 = normal, 1 = fast, 2 = HQ, 3 = anamorphic 0 = normal, 1 = fast, 2 = HQ, 3 = anamorphic
softhddevice.AudioDelay = 0
+n or -n ms
Requires: Requires:
--------- ---------
media-video/ffmpeg media-video/ffmpeg

37
codec.c
View File

@ -259,6 +259,7 @@ void CodecVideoOpen(VideoDecoder * decoder, const char *name, int codec_id)
Debug(3, "codec: vdpau decoder found\n"); Debug(3, "codec: vdpau decoder found\n");
} else if (!(video_codec = avcodec_find_decoder(codec_id))) { } else if (!(video_codec = avcodec_find_decoder(codec_id))) {
Fatal(_("codec: codec ID %#04x not found\n"), codec_id); Fatal(_("codec: codec ID %#04x not found\n"), codec_id);
// FIXME: none fatal
} }
decoder->VideoCodec = video_codec; 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")); Fatal(_("codec: can't allocate video codec context\n"));
} }
// open codec // 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) { if (avcodec_open2(decoder->VideoCtx, video_codec, NULL) < 0) {
Fatal(_("codec: can't open video codec!\n")); Fatal(_("codec: can't open video codec!\n"));
} }
#endif
decoder->VideoCtx->opaque = decoder; // our structure decoder->VideoCtx->opaque = decoder; // our structure
@ -354,26 +361,36 @@ void CodecVideoClose(VideoDecoder * video_decoder)
#if 0 #if 0
#ifdef DEBUG
/** /**
** Display pts... ** 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) void DisplayPts(AVCodecContext * video_ctx, AVFrame * frame)
{ {
int ms_delay; 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("*"); printf("*");
} }
ms_delay = (1000 * video_ctx->time_base.num) / video_ctx->time_base.den; ms_delay = (1000 * video_ctx->time_base.num) / video_ctx->time_base.den;
ms_delay += frame->repeat_pict * ms_delay / 2; 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->repeat_pict ? "r" : " ", frame->interlaced_frame ? "I" : " ",
frame->pts, video_ctx->time_base.num, video_ctx->time_base.den, pts, (int)(pts - last_pts) / 90, video_ctx->time_base.num,
ms_delay); video_ctx->time_base.den, ms_delay);
last_pts = pts;
} }
#endif
#endif #endif
@ -506,9 +523,15 @@ void CodecAudioOpen(AudioDecoder * audio_decoder, const char *name,
Fatal(_("codec: can't allocate audio codec context\n")); Fatal(_("codec: can't allocate audio codec context\n"));
} }
// open codec // 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) { if (avcodec_open2(audio_decoder->AudioCtx, audio_codec, NULL) < 0) {
Fatal(_("codec: can't open audio codec\n")); Fatal(_("codec: can't open audio codec\n"));
} }
#endif
Debug(3, "codec: audio '%s'\n", audio_decoder->AudioCtx->codec_name); Debug(3, "codec: audio '%s'\n", audio_decoder->AudioCtx->codec_name);
if (audio_codec->capabilities & CODEC_CAP_TRUNCATED) { if (audio_codec->capabilities & CODEC_CAP_TRUNCATED) {

View File

@ -655,6 +655,7 @@ int Poll(int timeout)
{ {
// buffers are too full // buffers are too full
if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX / 2) { if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX / 2) {
Debug(3, "replay: poll %d\n", timeout);
if (timeout) { if (timeout) {
// let display thread work // let display thread work
usleep(timeout * 1000); usleep(timeout * 1000);

View File

@ -51,6 +51,7 @@ static class cSoftHdDevice *MyDevice;
static char ConfigMakePrimary; ///< config primary wanted static char ConfigMakePrimary; ///< config primary wanted
static char ConfigVideoDeinterlace; ///< config deinterlace static char ConfigVideoDeinterlace; ///< config deinterlace
static char ConfigVideoScaling; ///< config scaling static char ConfigVideoScaling; ///< config scaling
static int ConfigVideoAudioDelay; ///< config audio delay
static char DoMakePrimary; ///< flag switch primary static char DoMakePrimary; ///< flag switch primary
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@ -261,6 +262,7 @@ class cMenuSetupSoft:public cMenuSetupPage
int MakePrimary; int MakePrimary;
int Deinterlace; int Deinterlace;
int Scaling; int Scaling;
int AudioDelay;
protected: protected:
virtual void Store(void); virtual void Store(void);
public: public:
@ -286,6 +288,8 @@ cMenuSetupSoft::cMenuSetupSoft(void)
Add(new cMenuEditStraItem(tr("Deinterlace"), &Deinterlace, 5, deinterlace)); Add(new cMenuEditStraItem(tr("Deinterlace"), &Deinterlace, 5, deinterlace));
Scaling = ConfigVideoScaling; Scaling = ConfigVideoScaling;
Add(new cMenuEditStraItem(tr("Scaling"), &Scaling, 4, scaling)); 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); VideoSetDeinterlace(ConfigVideoDeinterlace);
SetupStore("Scaling", ConfigVideoScaling = Scaling); SetupStore("Scaling", ConfigVideoScaling = Scaling);
VideoSetScaling(ConfigVideoScaling); 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)); VideoSetScaling(ConfigVideoScaling = atoi(value));
return true; return true;
} }
if (!strcmp(name, "AudioDelay")) {
VideoSetAudioDelay(ConfigVideoAudioDelay = atoi(value));
return true;
}
return false; return false;
} }

48
video.c
View File

@ -181,6 +181,9 @@ static VideoDeinterlaceModes VideoDeinterlace;
/// Default scaling mode /// Default scaling mode
static VideoScalingModes VideoScaling; static VideoScalingModes VideoScaling;
/// Default audio/video delay
static int VideoAudioDelay;
//static char VideoSoftStartSync; ///< soft start sync audio/video //static char VideoSoftStartSync; ///< soft start sync audio/video
static char Video60HzMode; ///< handle 60hz displays static char Video60HzMode; ///< handle 60hz displays
@ -2520,7 +2523,7 @@ static void VaapiDisplayFrame(void)
// deinterlace and full frame rate // deinterlace and full frame rate
// VDPAU driver only display a frame, if a full frame is put // VDPAU driver only display a frame, if a full frame is put
// INTEL driver does the same, but only with 1080i // 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 // FIXME: buggy libva-driver-vdpau, buggy libva-driver-intel
&& (VaapiBuggyVdpau || (0 && VaapiBuggyIntel && (VaapiBuggyVdpau || (0 && VaapiBuggyIntel
&& decoder->InputHeight == 1080)) && decoder->InputHeight == 1080))
@ -3136,10 +3139,11 @@ static void VaapiSyncDisplayFrame(VaapiDecoder * decoder)
if (abs(video_clock - audio_clock) > 5000 * 90) { if (abs(video_clock - audio_clock) > 5000 * 90) {
Debug(3, "video: pts difference too big\n"); 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"); Debug(3, "video: slow down video\n");
decoder->DupNextFrame = 1; 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"); Debug(3, "video: speed up video\n");
decoder->DropNextFrame = 1; decoder->DropNextFrame = 1;
} }
@ -3502,19 +3506,30 @@ void VideoRenderFrame(VideoHwDecoder * decoder, AVCodecContext * video_ctx,
// FIXME: move into vaapi module // FIXME: move into vaapi module
// update video clock // 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->best_effort_timestamp;
pts = frame->pkt_pts; pts = frame->pkt_pts;
if ((uint64_t) pts == AV_NOPTS_VALUE || !pts) { if ((uint64_t) pts == AV_NOPTS_VALUE || !pts) {
// libav: 0.8pre didn't set pts
pts = frame->pkt_dts; 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 ((uint64_t) pts != AV_NOPTS_VALUE) {
if (decoder->Vaapi.PTS != pts) { if (decoder->Vaapi.PTS != pts) {
Debug(4, Debug(3,
"video: %#012" PRIx64 "->%#012" PRIx64 " %4" PRId64 " pts\n", "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; decoder->Vaapi.PTS = pts;
} }
} }
@ -3557,6 +3572,10 @@ void VideoRenderFrame(VideoHwDecoder * decoder, AVCodecContext * video_ctx,
VaapiSyncDisplayFrame(&decoder->Vaapi); VaapiSyncDisplayFrame(&decoder->Vaapi);
} }
if (frame->repeat_pict) {
Warning("video/vaapi: repeated pict found, but not handle\n");
}
#ifdef USE_VAAPI #ifdef USE_VAAPI
if (VideoVaapiEnabled) { if (VideoVaapiEnabled) {
VaapiRenderFrame(&decoder->Vaapi, video_ctx, frame); VaapiRenderFrame(&decoder->Vaapi, video_ctx, frame);
@ -3634,7 +3653,8 @@ void VideoDisplayHandler(void)
/** /**
** Get video clock. ** 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) int64_t VideoGetClock(void)
{ {
@ -3776,6 +3796,16 @@ void VideoSetScaling(int mode)
VideoScaling = mode; VideoScaling = mode;
} }
/**
** Set audio delay.
**
** @param ms delay in ms
*/
void VideoSetAudioDelay(int ms)
{
VideoAudioDelay = ms * 90;
}
/** /**
** Initialize video output module. ** Initialize video output module.
** **

View File

@ -65,6 +65,9 @@ extern enum PixelFormat Video_get_format(VideoHwDecoder *, AVCodecContext *,
/// Display video TEST /// Display video TEST
extern void VideoDisplayHandler(void); extern void VideoDisplayHandler(void);
/// Poll video events
extern void VideoPollEvent(void);
/// set video mode /// set video mode
//extern void VideoSetVideoMode(int, int, int, int); //extern void VideoSetVideoMode(int, int, int, int);
@ -77,6 +80,9 @@ extern void VideoSetDeinterlace(int);
/// set scaling /// set scaling
extern void VideoSetScaling(int); extern void VideoSetScaling(int);
/// set audio delay
extern void VideoSetAudioDelay(int);
/// Clear OSD /// Clear OSD
extern void VideoOsdClear(void); extern void VideoOsdClear(void);