summaryrefslogtreecommitdiffstats
path: root/filters/f_decoder_wrapper.c
diff options
context:
space:
mode:
Diffstat (limited to 'filters/f_decoder_wrapper.c')
-rw-r--r--filters/f_decoder_wrapper.c128
1 files changed, 115 insertions, 13 deletions
diff --git a/filters/f_decoder_wrapper.c b/filters/f_decoder_wrapper.c
index 0edca5c83d..0b2a4f52ec 100644
--- a/filters/f_decoder_wrapper.c
+++ b/filters/f_decoder_wrapper.c
@@ -87,6 +87,13 @@ struct priv {
double start, end;
struct demux_packet *new_segment;
struct mp_frame packet;
+ bool packet_fed;
+ int preroll_discard;
+
+ size_t reverse_queue_byte_size;
+ struct mp_frame *reverse_queue;
+ int num_reverse_queue;
+ bool reverse_queue_complete;
struct mp_frame decoded_coverart;
int coverart_returned; // 0: no, 1: coverart frame itself, 2: EOF returned
@@ -108,11 +115,19 @@ static void reset_decoder(struct priv *p)
p->public.pts_reset = false;
p->packets_without_output = 0;
mp_frame_unref(&p->packet);
+ p->packet_fed = false;
+ p->preroll_discard = 0;
talloc_free(p->new_segment);
p->new_segment = NULL;
p->start = p->end = MP_NOPTS_VALUE;
p->coverart_returned = 0;
+ for (int n = 0; n < p->num_reverse_queue; n++)
+ mp_frame_unref(&p->reverse_queue[n]);
+ p->num_reverse_queue = 0;
+ p->reverse_queue_byte_size = 0;
+ p->reverse_queue_complete = false;
+
if (p->decoder)
mp_filter_reset(p->decoder->f);
}
@@ -307,18 +322,22 @@ static void process_video_frame(struct priv *p, struct mp_image *mpi)
struct MPOpts *opts = p->opt_cache->opts;
m_config_cache_update(p->opt_cache);
+ int dir = p->public.play_dir;
+
// Note: the PTS is reordered, but the DTS is not. Both should be monotonic.
double pts = mpi->pts;
double dts = mpi->dts;
if (pts != MP_NOPTS_VALUE) {
- if (pts < p->codec_pts)
+ pts *= dir;
+ if (pts < p->codec_pts && dir > 0)
p->num_codec_pts_problems++;
p->codec_pts = mpi->pts;
}
if (dts != MP_NOPTS_VALUE) {
- if (dts <= p->codec_dts)
+ dts *= dir;
+ if (dts <= p->codec_dts && dir > 0)
p->num_codec_dts_problems++;
p->codec_dts = mpi->dts;
}
@@ -401,8 +420,12 @@ void mp_decoder_wrapper_get_video_dec_params(struct mp_decoder_wrapper *d,
static void process_audio_frame(struct priv *p, struct mp_aframe *aframe)
{
+ double dir = p->public.play_dir;
+
double frame_pts = mp_aframe_get_pts(aframe);
if (frame_pts != MP_NOPTS_VALUE) {
+ frame_pts *= dir;
+
if (p->pts != MP_NOPTS_VALUE)
MP_STATS(p, "value %f audio-pts-err", p->pts - frame_pts);
@@ -429,7 +452,10 @@ static void process_audio_frame(struct priv *p, struct mp_aframe *aframe)
mp_aframe_set_pts(aframe, p->pts);
if (p->pts != MP_NOPTS_VALUE)
- p->pts += mp_aframe_duration(aframe);
+ p->pts += mp_aframe_duration(aframe) * dir;
+
+ if (dir < 0)
+ mp_aframe_set_pts(aframe, p->pts);
}
@@ -445,8 +471,9 @@ static bool is_new_segment(struct priv *p, struct mp_frame frame)
if (frame.type != MP_FRAME_PACKET)
return false;
struct demux_packet *pkt = frame.data;
- return pkt->segmented && (pkt->start != p->start || pkt->end != p->end ||
- pkt->codec != p->codec);
+ return (pkt->segmented && (pkt->start != p->start || pkt->end != p->end ||
+ pkt->codec != p->codec)) ||
+ (p->public.play_dir < 0 && pkt->back_restart && p->packet_fed);
}
static void feed_packet(struct priv *p)
@@ -466,6 +493,9 @@ static void feed_packet(struct priv *p)
}
}
+ if (!p->packet.type)
+ return;
+
// Flush current data if the packet is a new segment.
if (is_new_segment(p, p->packet)) {
assert(!p->new_segment);
@@ -474,7 +504,8 @@ static void feed_packet(struct priv *p)
}
assert(p->packet.type == MP_FRAME_PACKET || p->packet.type == MP_FRAME_EOF);
- struct demux_packet *packet = p->packet.data;
+ struct demux_packet *packet =
+ p->packet.type == MP_FRAME_PACKET ? p->packet.data : NULL;
// For video framedropping, including parts of the hr-seek logic.
if (p->decoder->control) {
@@ -488,7 +519,7 @@ static void feed_packet(struct priv *p)
if (p->public.attempt_framedrops)
framedrop_type = 1;
- if (start_pts != MP_NOPTS_VALUE && packet &&
+ if (start_pts != MP_NOPTS_VALUE && packet && p->public.play_dir > 0 &&
packet->pts < start_pts - .005 && !p->has_broken_packet_pts)
framedrop_type = 2;
@@ -511,8 +542,12 @@ static void feed_packet(struct priv *p)
if (p->first_packet_pdts == MP_NOPTS_VALUE)
p->first_packet_pdts = pkt_pdts;
+ if (packet && packet->back_preroll)
+ p->preroll_discard += 1;
+
mp_pin_in_write(p->decoder->f->pins[0], p->packet);
p->packet = MP_NO_FRAME;
+ p->packet_fed = true;
p->packets_without_output += 1;
}
@@ -549,6 +584,10 @@ static bool process_decoded_frame(struct priv *p, struct mp_frame *frame)
double pts = mp_aframe_get_pts(aframe);
if (pts != MP_NOPTS_VALUE && p->start != MP_NOPTS_VALUE)
segment_ended = pts >= p->end;
+
+ if (p->public.play_dir < 0 && !mp_aframe_reverse(aframe))
+ MP_ERR(p, "Couldn't reverse audio frame.\n");
+
if (mp_aframe_get_size(aframe) == 0)
mp_frame_unref(frame);
} else {
@@ -558,6 +597,35 @@ static bool process_decoded_frame(struct priv *p, struct mp_frame *frame)
return segment_ended;
}
+static void enqueue_backward_frame(struct priv *p, struct mp_frame frame)
+{
+ bool eof = frame.type == MP_FRAME_EOF;
+
+ if (!eof) {
+ struct MPOpts *opts = p->opt_cache->opts;
+
+ uint64_t queue_size = 0;
+ switch (p->header->type) {
+ case STREAM_VIDEO: queue_size = opts->video_reverse_size; break;
+ case STREAM_AUDIO: queue_size = opts->audio_reverse_size; break;
+ }
+
+ if (p->reverse_queue_byte_size >= queue_size) {
+ MP_ERR(p, "Reversal queue overflow, discarding frame.\n");
+ mp_frame_unref(&frame);
+ return;
+ }
+
+ p->reverse_queue_byte_size += mp_frame_approx_size(frame);
+ }
+
+ // Note: EOF (really BOF) is propagated, but not reversed.
+ MP_TARRAY_INSERT_AT(p, p->reverse_queue, p->num_reverse_queue,
+ eof ? 0 : p->num_reverse_queue, frame);
+
+ p->reverse_queue_complete = eof;
+}
+
static void read_frame(struct priv *p)
{
struct mp_pin *pin = p->f->ppins[0];
@@ -576,6 +644,14 @@ static void read_frame(struct priv *p)
return;
}
+ if (p->reverse_queue_complete && p->num_reverse_queue) {
+ struct mp_frame frame = p->reverse_queue[p->num_reverse_queue - 1];
+ p->num_reverse_queue -= 1;
+ mp_pin_in_write(pin, frame);
+ return;
+ }
+ p->reverse_queue_complete = false;
+
struct mp_frame frame = mp_pin_out_read(p->decoder->f->pins[1]);
if (!frame.type)
return;
@@ -593,23 +669,47 @@ static void read_frame(struct priv *p)
}
p->packets_without_output = 0;
+ if (p->preroll_discard > 0 && frame.type != MP_FRAME_EOF) {
+ p->preroll_discard -= 1;
+ mp_frame_unref(&frame);
+ mp_filter_internal_mark_progress(p->f);
+ return;
+ }
+
bool segment_ended = process_decoded_frame(p, &frame);
+ if (p->public.play_dir < 0 && frame.type) {
+ enqueue_backward_frame(p, frame);
+ frame = MP_NO_FRAME;
+ }
+
// If there's a new segment, start it as soon as we're drained/finished.
if (segment_ended && p->new_segment) {
struct demux_packet *new_segment = p->new_segment;
p->new_segment = NULL;
+ struct mp_frame *reverse_queue = p->reverse_queue;
+ int num_reverse_queue = p->num_reverse_queue;
+ p->reverse_queue = NULL;
+ p->num_reverse_queue = 0;
+
reset_decoder(p);
- if (p->codec != new_segment->codec) {
- p->codec = new_segment->codec;
- if (!mp_decoder_wrapper_reinit(&p->public))
- mp_filter_internal_mark_failed(p->f);
+ if (new_segment->segmented) {
+ if (p->codec != new_segment->codec) {
+ p->codec = new_segment->codec;
+ if (!mp_decoder_wrapper_reinit(&p->public))
+ mp_filter_internal_mark_failed(p->f);
+ }
+
+ p->start = new_segment->start;
+ p->end = new_segment->end;
}
- p->start = new_segment->start;
- p->end = new_segment->end;
+ assert(!p->reverse_queue);
+ p->reverse_queue = reverse_queue;
+ p->num_reverse_queue = num_reverse_queue;
+ p->reverse_queue_complete = p->num_reverse_queue > 0;
p->packet = MAKE_FRAME(MP_FRAME_PACKET, new_segment);
mp_filter_internal_mark_progress(p->f);
@@ -655,6 +755,8 @@ struct mp_decoder_wrapper *mp_decoder_wrapper_create(struct mp_filter *parent,
p->codec = p->header->codec;
w->f = f;
+ w->play_dir = 1;
+
struct MPOpts *opts = p->opt_cache->opts;
mp_filter_add_pin(f, MP_PIN_OUT, "out");