diff --git a/audio.c b/audio.c index e9d72883..6e749eee 100644 --- a/audio.c +++ b/audio.c @@ -769,7 +769,6 @@ static int AlsaPlayRingbuffer(void) Error("audio/alsa: bytes lost -> out of sync"); } #endif - for (;;) { pthread_mutex_lock(&ReadAdvance_mutex); if (AlsaUseMmap) { @@ -779,12 +778,13 @@ static int AlsaPlayRingbuffer(void) } if (err != frames) { if (err < 0) { - pthread_mutex_unlock(&ReadAdvance_mutex); if (err == -EAGAIN) { + pthread_mutex_unlock(&ReadAdvance_mutex); continue; } Error("audio/alsa: writei underrun error? '%s'", snd_strerror(err)); err = snd_pcm_recover(AlsaPCMHandle, err, 0); + pthread_mutex_unlock(&ReadAdvance_mutex); if (err >= 0) { return 0; } @@ -1361,8 +1361,8 @@ static int AudioNextRing(void) if (remain <= AUDIO_MIN_BUFFER_FREE) { Debug5("audio: force start"); } - if (remain <= AUDIO_MIN_BUFFER_FREE || ((AudioVideoIsReady || !SoftIsPlayingVideo) - && AudioStartThreshold < used)) { + if (AudioStartThreshold * 4 < used || remain <= AUDIO_MIN_BUFFER_FREE || ((AudioVideoIsReady + || !SoftIsPlayingVideo) && AudioStartThreshold < used)) { return 0; } return 1; @@ -1613,8 +1613,8 @@ void AudioEnqueue(const void *samples, int count) if (remain <= AUDIO_MIN_BUFFER_FREE) { Debug5("audio: force start"); } - if (remain <= AUDIO_MIN_BUFFER_FREE || ((AudioVideoIsReady || !SoftIsPlayingVideo) - && AudioStartThreshold < n)) { + if (AudioStartThreshold * 4 < n || remain <= AUDIO_MIN_BUFFER_FREE || ((AudioVideoIsReady + || !SoftIsPlayingVideo) && AudioStartThreshold < n)) { // restart play-back // no lock needed, can wakeup next time AudioRunning = 1; diff --git a/codec.c b/codec.c index 063e8854..09c80352 100644 --- a/codec.c +++ b/codec.c @@ -450,7 +450,7 @@ void CodecVideoFlushBuffers(VideoDecoder * decoder) ** ** @param decoder video decoder data */ -const char* CodecVideoGetCodecName(VideoDecoder * decoder) +const char *CodecVideoGetCodecName(VideoDecoder * decoder) { if (decoder && decoder->VideoCodec) return avcodec_get_name(decoder->VideoCodec->id); @@ -458,7 +458,6 @@ const char* CodecVideoGetCodecName(VideoDecoder * decoder) return avcodec_get_name(AV_CODEC_ID_NONE); } - //---------------------------------------------------------------------------- // Audio //---------------------------------------------------------------------------- @@ -567,7 +566,7 @@ void CodecAudioOpen(AudioDecoder * audio_decoder, int codec_id_old) switch (device_get_atype()) { case 0: break; - case 0x3: /* FALLTHRU */ + case 0x3: /* FALLTHRU */ case 0x4: codec_id = AV_CODEC_ID_MP2; break; @@ -600,7 +599,7 @@ void CodecAudioOpen(AudioDecoder * audio_decoder, int codec_id_old) audio_decoder->AudioFmtCtx->audio_codec_id = codec_id; av_dict_set_int(&options, "analyzeduration", 500, 0); - av_dict_set_int(&options, "probesize", alloc_size / 2 , 0); + av_dict_set_int(&options, "probesize", alloc_size / 2, 0); input_format = av_find_input_format("mpeg"); if (!input_format) { @@ -622,18 +621,14 @@ void CodecAudioOpen(AudioDecoder * audio_decoder, int codec_id_old) Error("codec: failed to add audio stream to context"); goto error_avformat_new_stream; } - -#if 1 audio_decoder->AudioFmtCtx->streams[0]->codecpar->codec_id = codec_id; audio_decoder->AudioFmtCtx->streams[0]->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; -#endif -#if 1 + ret = avformat_find_stream_info(audio_decoder->AudioFmtCtx, NULL); if (ret < 0) { Error("codec: can't find audio stream info: %s", av_err2str(ret)); goto error_avformat_find_stream_info; } -#endif av_dump_format(audio_decoder->AudioFmtCtx, 0, "vaapidevice audio", 0); #if 0 @@ -704,7 +699,9 @@ void CodecAudioOpen(AudioDecoder * audio_decoder, int codec_id_old) error_avcodec_alloc_context3: error_avcodec_find_decoder: error_avformat_new_stream: +#if 0 error_avformat_find_best_stream: +#endif error_avformat_find_stream_info: error_avformat_open_input: av_freep(avio_ctx); diff --git a/codec.h b/codec.h index 3e0ada47..b4a9276e 100644 --- a/codec.h +++ b/codec.h @@ -75,7 +75,7 @@ extern void CodecVideoDecode(VideoDecoder *); extern void CodecVideoFlushBuffers(VideoDecoder *); /// Get video decoder name. -extern const char* CodecVideoGetCodecName(VideoDecoder *); +extern const char *CodecVideoGetCodecName(VideoDecoder *); /// Allocate a new audio decoder context. extern AudioDecoder *CodecAudioNewDecoder(void); diff --git a/vaapidev.c b/vaapidev.c index 4dbda95f..5331989c 100644 --- a/vaapidev.c +++ b/vaapidev.c @@ -36,7 +36,6 @@ #include "video.h" #include "codec.h" - ////////////////////////////////////////////////////////////////////////////// // Variables ////////////////////////////////////////////////////////////////////////////// @@ -1613,6 +1612,7 @@ char *GetVideoStats(void) char *GetVideoInfo(void) { const char *codec = CodecVideoGetCodecName(MyVideoStream->Decoder); + return MyVideoStream->HwDecoder ? VideoGetInfo(MyVideoStream->HwDecoder, codec) : NULL; } diff --git a/vaapidevice.cpp b/vaapidevice.cpp index 7c0733cf..97c9e38d 100644 --- a/vaapidevice.cpp +++ b/vaapidevice.cpp @@ -1985,6 +1985,7 @@ void cVaapiDevice::GetOsdSize(int &width, int &height, double &pixel_aspect) int cVaapiDevice::PlayAudio(const uchar * data, int length, uchar id) { const int ringBufferSize = KILOBYTE(512); + if (length > ringBufferSize) { Error("Audio PES packet size (%d) too large for frame ringbuffer", length); return 0; @@ -1999,6 +2000,7 @@ int cVaapiDevice::PlayAudio(const uchar * data, int length, uchar id) if (audioEof || !audioBuffer->Put(packet)) { // If this happens often enough vdr will start asking for a clear of device delete packet; + return 0; } // TODO: remove vaapidev code @@ -2046,6 +2048,7 @@ void cVaapiDevice::SetVolumeDevice(int volume) int cVaapiDevice::PlayVideo(const uchar * data, int length) { const int ringBufferSize = MEGABYTE(1); + if (length > ringBufferSize) { Error("Video PES packet size (%d) too large for frame ringbuffer", length); return 0; @@ -2060,6 +2063,7 @@ int cVaapiDevice::PlayVideo(const uchar * data, int length) if (videoEof || !videoBuffer->Put(packet)) { // If this happens often enough vdr will start asking for a clear of device delete packet; + return 0; } @@ -2124,10 +2128,9 @@ int cVaapiDevice::DeviceGetAtype() eTrackType track = GetCurrentAudioTrack(); if (IS_AUDIO_TRACK(track)) { - return PatPmtParser()->Atype(int(track - ttAudioFirst)); - } - else if (IS_DOLBY_TRACK(track)) { - return PatPmtParser()->Dtype(int(track - ttDolbyFirst)); + return PatPmtParser()->Atype(int (track - ttAudioFirst)); + } else if (IS_DOLBY_TRACK(track)) { + return PatPmtParser()->Dtype(int (track - ttDolbyFirst)); } return -1; @@ -2209,7 +2212,6 @@ int cVaapiDevice::DeviceAudioReadCallback(uchar * data, int size) } while (!packet && ffmpegMode == 0 && retries++ < 3); - if (!packet) { return ffmpegMode ? 0 : AVERROR_EOF; } diff --git a/video.c b/video.c index 3e6cbc69..7f6f4f49 100644 --- a/video.c +++ b/video.c @@ -74,6 +74,9 @@ #define TO_VAAPI_DEVICE_CTX(x) ((AVVAAPIDeviceContext*)TO_AVHW_DEVICE_CTX(x)->hwctx) #define TO_VAAPI_FRAMES_CTX(x) ((AVVAAPIFramesContext*)TO_AVHW_FRAMES_CTX(x)->hwctx) +// PTS Filter-Elements of 1, 2, 4, 8, 16, .. +#define LP_FILTER_CNT 2 + //---------------------------------------------------------------------------- // Declarations //---------------------------------------------------------------------------- @@ -830,7 +833,11 @@ struct _vaapi_decoder_ int SyncOnAudio; ///< flag sync to audio int64_t PTS; ///< video PTS clock - int LastAVDiff; ///< last audio - video difference + int64_t AvPtsDiffFilter; ///< AV-PTS-Diff Delay element – 64 bits + int AvPtsDiffFilterInit; ///< Filter Init Done + int64_t LastVideoPTS; ///< Video-PTS Rollover Test + int64_t LastAudioPTS; ///< Audio-PTS Rollover Test + int SyncCounter; ///< counter to sync frames int StartCounter; ///< counter for video start int FramesDuped; ///< number of frames duplicated @@ -1343,6 +1350,13 @@ static VaapiDecoder *VaapiNewHwDecoder(VideoStream * stream) decoder->GetPutImage = 1; + decoder->AvPtsDiffFilterInit = 1; + decoder->AvPtsDiffFilter = 0; + decoder->LastVideoPTS = 0; + decoder->LastAudioPTS = 0; + decoder->SyncCounter = 0; + decoder->StartCounter = 0; + VaapiDecoders[VaapiDecoderN++] = decoder; return decoder; @@ -3603,7 +3617,8 @@ char *VaapiGetStats(VaapiDecoder * decoder) if (snprintf(&buffer[0], sizeof(buffer), " Frames: missed(%d) duped(%d) dropped(%d) total(%d) PTS(%s) drift(%" PRId64 ") audio(%" PRId64 ") video(%" PRId64 ")", decoder->FramesMissed, decoder->FramesDuped, decoder->FramesDropped, decoder->FrameCounter, - Timestamp2String(video_clock), (video_clock - audio_clock) / 90, AudioGetDelay() / 90, VideoDeltaPTS / 90)) { + Timestamp2String(video_clock), (video_clock - audio_clock) / 90, AudioGetDelay() / 90, + VideoDeltaPTS / 90)) { return strdup(buffer); } @@ -3654,6 +3669,11 @@ static void VaapiSyncDecoder(VaapiDecoder * decoder) int filled; int64_t audio_clock; int64_t video_clock; + int64_t diff; + + if (decoder == NULL) { + return; + } err = 0; mutex_start_time = GetMsTicks(); @@ -3675,7 +3695,7 @@ static void VaapiSyncDecoder(VaapiDecoder * decoder) goto out; } // both clocks are known - if (audio_clock + VideoAudioDelay <= video_clock + 25 * 90) { + if (audio_clock + (int64_t) VideoAudioDelay <= video_clock + (int64_t) 25 * 90) { goto out; } // out of sync: audio before video @@ -3705,35 +3725,48 @@ static void VaapiSyncDecoder(VaapiDecoder * decoder) if (audio_clock != (int64_t) AV_NOPTS_VALUE && video_clock != (int64_t) AV_NOPTS_VALUE) { // both clocks are known - int diff; - int lower_limit; - - diff = video_clock - audio_clock - VideoAudioDelay; - lower_limit = !IsReplay()? -25 : 32; - if (!IsReplay()) { - diff = (decoder->LastAVDiff + diff) / 2; - decoder->LastAVDiff = diff; + // FIXME: "diff" doesn't checks frametype (i - Top/Bottom, p - Full) + diff = video_clock - audio_clock - (int64_t) VideoAudioDelay; + + // AV-Diff greater than 1:00:00.000 should be a PTS-Rollover, + // but observable is: audio_clock jumps to negative values... + if ((audio_clock < 0) || (video_clock < 0) || (abs(diff) > (int64_t) 60 * 60 * 90000)) { + // Set Bit 34 of video_clock if below 1:00:00.000 + if (video_clock < (int64_t) 60 * 60 * 90000) + video_clock = video_clock + (int64_t) 0x200000000; + // Set Bit 34 of audio_clock if below 1:00:00.000 + if (audio_clock < (int64_t) 60 * 60 * 90000) + audio_clock = audio_clock + (int64_t) 0x200000000; + + // Calc correct diff + err = VaapiMessage(1, "AV-PTS Rollover, correcting AV-PTS Difference"); + diff = (video_clock - audio_clock - (int64_t) VideoAudioDelay); + } + // Low-Pass Filter AV-PTS-Diff, if in Sync-Range of +/- 250 ms + if (abs(diff) < (int64_t) 250 * 90) { + // Filter-Init done? + if (decoder->AvPtsDiffFilterInit) { + // No. + decoder->AvPtsDiffFilterInit = 0; + decoder->AvPtsDiffFilter = diff * LP_FILTER_CNT; + } + decoder->AvPtsDiffFilter = decoder->AvPtsDiffFilter - (decoder->AvPtsDiffFilter / LP_FILTER_CNT) + diff; + diff = decoder->AvPtsDiffFilter / LP_FILTER_CNT; } - if (abs(diff) > 5000 * 90) { // more than 5s + if (abs(diff) > (int64_t) 5000 * 90) { // more than 5s err = VaapiMessage(2, "video: audio/video difference too big"); - } else if (diff > 100 * 90) { - // FIXME: this quicker sync step, did not work with new code! - err = VaapiMessage(2, "video: slow down video, duping frame"); - ++decoder->FramesDuped; - if (VideoSoftStartSync) { - decoder->SyncCounter = 1; - goto out; - } - } else if (diff > 55 * 90) { - err = VaapiMessage(2, "video: slow down video, duping frame"); + } else if (diff > (int64_t) 40 * 90) { + Debug("video: slow down video, duping frame (/\\=%.2f ms, vClk %s - aClk %s)", diff * 1000 / (double)90000, + Timestamp2String(video_clock), Timestamp2String(audio_clock)); ++decoder->FramesDuped; if (VideoSoftStartSync) { decoder->SyncCounter = 1; goto out; } - } else if (diff < lower_limit * 90 && filled > 1 + 2 * decoder->Interlaced) { - err = VaapiMessage(2, "video: speed up video, droping frame"); + } else if ((diff < (int64_t) - 20 * 90) && (filled > 1 + 2 * decoder->Interlaced)) { + Debug("video: speed up video, droping frame (/\\=%.2f ms, vClk %s - aClk %s)", diff * 1000 / (double)90000, + Timestamp2String(video_clock), Timestamp2String(audio_clock)); ++decoder->FramesDropped; VaapiAdvanceDecoderFrame(decoder); if (VideoSoftStartSync) { @@ -3780,9 +3813,9 @@ static void VaapiSyncDecoder(VaapiDecoder * decoder) } Info("video: %s%+5" PRId64 " %4" PRId64 " %3d/\\ms %3d%+d v-buf", Timestamp2String(video_clock), (video_clock - audio_clock) / 90, AudioGetDelay() / 90, (int)VideoDeltaPTS / 90, - VideoGetBuffers(decoder->Stream), decoder->Interlaced ? - (2 * atomic_read(&decoder->SurfacesFilled) - decoder->SurfaceField) : - atomic_read(&decoder->SurfacesFilled)); + VideoGetBuffers(decoder->Stream), + decoder->Interlaced ? (2 * atomic_read(&decoder->SurfacesFilled) - + decoder->SurfaceField) : atomic_read(&decoder->SurfacesFilled)); if (!(decoder->FramesDisplayed % (5 * 60 * 60))) { VaapiPrintFrames(decoder); }