diff --git a/deps/libff/libff/ff-audio-decoder.c b/deps/libff/libff/ff-audio-decoder.c index b31a6633d..ebf8caed1 100644 --- a/deps/libff/libff/ff-audio-decoder.c +++ b/deps/libff/libff/ff-audio-decoder.c @@ -39,6 +39,22 @@ static inline void shrink_packet(struct ff_packet *packet, int packet_length) } } +static bool handle_reset_packet(struct ff_decoder *decoder, + struct ff_packet *packet) +{ + if (decoder->clock != NULL) + ff_clock_release(&decoder->clock); + decoder->clock = packet->clock; + av_free_packet(&packet->base); + + // not a real packet, so try to get another packet + if (packet_queue_get(&decoder->packet_queue, packet, 1) + == FF_PACKET_FAIL) + return false; + + return true; +} + static int decode_frame(struct ff_decoder *decoder, struct ff_packet *packet, AVFrame *frame, bool *frame_complete) { @@ -86,6 +102,11 @@ static int decode_frame(struct ff_decoder *decoder, return -1; } } + + // Packet has a new clock (reset packet) + if (packet->clock != NULL) + if (!handle_reset_packet(decoder, packet)) + return -1; } } @@ -113,6 +134,7 @@ static bool queue_frame(struct ff_decoder *decoder, AVFrame *frame, av_frame_free(&queue_frame->frame); queue_frame->frame = av_frame_clone(frame); + queue_frame->clock = ff_clock_retain(decoder->clock); if (call_initialize) ff_callbacks_frame_initialize(queue_frame, decoder->callbacks); @@ -154,6 +176,9 @@ void *ff_audio_decoder_thread(void *opaque_audio_decoder) av_free_packet(&packet.base); } + if (decoder->clock != NULL) + ff_clock_release(&decoder->clock); + av_frame_free(&frame); return NULL; } diff --git a/deps/libff/libff/ff-decoder.c b/deps/libff/libff/ff-decoder.c index a9fd5fe62..b51d6a81d 100644 --- a/deps/libff/libff/ff-decoder.c +++ b/deps/libff/libff/ff-decoder.c @@ -117,10 +117,13 @@ void ff_decoder_free(struct ff_decoder *decoder) ff_callbacks_frame_free(frame, decoder->callbacks); - if (frame != NULL && frame->frame != NULL) - av_frame_unref(frame->frame); - if (frame != NULL) + if (frame != NULL) { + if (frame->frame != NULL) + av_frame_unref(frame->frame); + if (frame->clock != NULL) + ff_clock_release(&frame->clock); av_free(frame); + } } packet_queue_free(&decoder->packet_queue); @@ -143,11 +146,11 @@ double ff_decoder_clock(void *opaque) return decoder->current_pts + delta; } -static double get_sync_adjusted_pts_diff(struct ff_decoder *decoder, +static double get_sync_adjusted_pts_diff(struct ff_clock *clock, double pts, double pts_diff) { double new_pts_diff = pts_diff; - double sync_time = ff_get_sync_clock(decoder->clock); + double sync_time = ff_get_sync_clock(clock); double diff = pts - sync_time; double sync_threshold; @@ -191,6 +194,29 @@ void ff_decoder_refresh(void *opaque) frame = ff_circular_queue_peek_read( &decoder->frame_queue); + // Get frame clock and start it if needed + ff_clock_t *clock = ff_clock_move(&frame->clock); + if (!ff_clock_start(clock, decoder->natural_sync_clock, + &decoder->refresh_timer.abort)) { + ff_clock_release(&clock); + + // Our clock was never started and deleted or + // aborted + + // Drop this frame? The only way this can happen + // is if one stream finishes before another and + // the input is looping or canceled. Until we + // get another clock we will unable to continue + + ff_decoder_schedule_refresh(decoder, 100); + + // Drop this frame as we have no way of timing + // it + ff_circular_queue_advance_read( + &decoder->frame_queue); + return; + } + decoder->current_pts = frame->pts; decoder->current_pts_time = av_gettime(); @@ -208,9 +234,9 @@ void ff_decoder_refresh(void *opaque) decoder->previous_pts = frame->pts; // if not synced against natural clock - if (decoder->clock->sync_type + if (clock->sync_type != decoder->natural_sync_clock) { - pts_diff = get_sync_adjusted_pts_diff(decoder, + pts_diff = get_sync_adjusted_pts_diff(clock, frame->pts, pts_diff); } @@ -224,6 +250,10 @@ void ff_decoder_refresh(void *opaque) delay_until_next_wake = 0.010L; } + if (delay_until_next_wake > pts_diff) + delay_until_next_wake = pts_diff; + + ff_clock_release(&clock); ff_callbacks_frame(decoder->callbacks, frame); ff_decoder_schedule_refresh(decoder, diff --git a/deps/libff/libff/ff-demuxer.c b/deps/libff/libff/ff-demuxer.c index 03ed44ca3..8b725d22f 100644 --- a/deps/libff/libff/ff-demuxer.c +++ b/deps/libff/libff/ff-demuxer.c @@ -196,8 +196,6 @@ static bool initialize_decoder(struct ff_demuxer *demuxer, demuxer->audio_decoder->hwaccel_decoder = hwaccel_decoder; demuxer->audio_decoder->natural_sync_clock = AV_SYNC_AUDIO_MASTER; - demuxer->audio_decoder->clock = &demuxer->clock; - demuxer->audio_decoder->callbacks = &demuxer->audio_callbacks; if (!ff_callbacks_format(&demuxer->audio_callbacks, @@ -219,8 +217,6 @@ static bool initialize_decoder(struct ff_demuxer *demuxer, demuxer->video_decoder->hwaccel_decoder = hwaccel_decoder; demuxer->video_decoder->natural_sync_clock = AV_SYNC_VIDEO_MASTER; - demuxer->video_decoder->clock = &demuxer->clock; - demuxer->video_decoder->callbacks = &demuxer->video_callbacks; if (!ff_callbacks_format(&demuxer->video_callbacks, @@ -316,6 +312,27 @@ void ff_demuxer_flush(struct ff_demuxer *demuxer) } } +void ff_demuxer_reset(struct ff_demuxer *demuxer) +{ + struct ff_packet *packet = av_mallocz(sizeof(struct ff_packet)); + struct ff_clock *clock = ff_clock_init(); + clock->sync_type = demuxer->clock.sync_type; + clock->sync_clock = demuxer->clock.sync_clock; + clock->opaque = demuxer->clock.opaque; + + packet->clock = clock; + + if (demuxer->audio_decoder != NULL) { + packet_queue_put(&demuxer->audio_decoder->packet_queue, packet); + ff_clock_retain(clock); + } + + if (demuxer->video_decoder != NULL) { + packet_queue_put(&demuxer->video_decoder->packet_queue, packet); + ff_clock_retain(clock); + } +} + static bool open_input(struct ff_demuxer *demuxer, AVFormatContext **format_context) { @@ -446,6 +463,7 @@ static bool handle_seek(struct ff_demuxer *demuxer) } else { if (demuxer->seek_flush) ff_demuxer_flush(demuxer); + ff_demuxer_reset(demuxer); } demuxer->seek_request = false; @@ -477,6 +495,8 @@ static void *demux_thread(void *opaque) if (!find_and_initialize_stream_decoders(demuxer)) goto fail; + ff_demuxer_reset(demuxer); + while (!demuxer->abort) { // failed to seek (looping?) if (!handle_seek(demuxer)) diff --git a/deps/libff/libff/ff-frame.h b/deps/libff/libff/ff-frame.h index 091967cac..4c7f91d1f 100644 --- a/deps/libff/libff/ff-frame.h +++ b/deps/libff/libff/ff-frame.h @@ -16,11 +16,13 @@ #pragma once +#include "ff-clock.h" + #include struct ff_frame { AVFrame *frame; - void *opaque; + struct ff_clock *clock; double pts; int64_t duration; }; diff --git a/deps/libff/libff/ff-packet-queue.c b/deps/libff/libff/ff-packet-queue.c index 4bf63d379..bec472fa9 100644 --- a/deps/libff/libff/ff-packet-queue.c +++ b/deps/libff/libff/ff-packet-queue.c @@ -147,6 +147,8 @@ void packet_queue_flush(struct ff_packet_queue *q) packet = q->first_packet) { q->first_packet = packet->next; av_free_packet(&packet->packet.base); + if (packet->packet.clock != NULL) + ff_clock_release(&packet->packet.clock); av_freep(&packet); } diff --git a/deps/libff/libff/ff-packet-queue.h b/deps/libff/libff/ff-packet-queue.h index 26e00dcf6..2bbf8e2aa 100644 --- a/deps/libff/libff/ff-packet-queue.h +++ b/deps/libff/libff/ff-packet-queue.h @@ -16,6 +16,8 @@ #pragma once +#include "ff-clock.h" + #include #include #include @@ -26,6 +28,7 @@ struct ff_packet { AVPacket base; + ff_clock_t *clock; }; struct ff_packet_list { diff --git a/deps/libff/libff/ff-video-decoder.c b/deps/libff/libff/ff-video-decoder.c index ce1c0987d..c22381ad0 100644 --- a/deps/libff/libff/ff-video-decoder.c +++ b/deps/libff/libff/ff-video-decoder.c @@ -53,6 +53,7 @@ static bool queue_frame(struct ff_decoder *decoder, AVFrame *frame, av_frame_free(&queue_frame->frame); queue_frame->frame = av_frame_clone(frame); + queue_frame->clock = ff_clock_retain(decoder->clock); if (call_initialize) ff_callbacks_frame_initialize(queue_frame, decoder->callbacks); @@ -85,6 +86,15 @@ void *ff_video_decoder_thread(void *opaque_video_decoder) continue; } + // We received a reset packet with a new clock + if (packet.clock != NULL) { + if (decoder->clock != NULL) + ff_clock_release(&decoder->clock); + decoder->clock = ff_clock_move(&packet.clock); + av_free_packet(&packet.base); + continue; + } + avcodec_decode_video2(decoder->codec, frame, &complete, &packet.base); @@ -107,6 +117,9 @@ void *ff_video_decoder_thread(void *opaque_video_decoder) av_free_packet(&packet.base); } + if (decoder->clock != NULL) + ff_clock_release(&decoder->clock); + av_frame_free(&frame); return NULL; }