mirror of
https://projects.vdr-developer.org/git/vdr-plugin-softhddevice.git
synced 2023-10-10 19:16:51 +02:00
Audio/video sync improvements.
Configurable audio delay. Use monotonic pts. Support old libav or ffmpeg libraries.
This commit is contained in:
parent
33460f1370
commit
36b285b5f7
@ -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.
|
||||
|
@ -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
|
||||
|
37
codec.c
37
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) {
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
48
video.c
48
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.
|
||||
**
|
||||
|
6
video.h
6
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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user