Hello.

I've problems playing a short clip [1] in a continuous loop using the -loop 
option 
and I'm not sure, how to fix this.

Running
  avconv -loop -1 -i in.mp4 -qscale 2 out.avi
leads to an infinite loop (without any output) after the first iteration.

I narrowed down the problem to a call to av_seek_frame(), looking for a 
non-existant 
timestamp. See below.

The clip is a stream capture of a live stream containing one video and one 
audio track.
Both tracks start with negative stamps:

Video:
    ts[0] = -512 (keyframe)
    ts[1] = -256 (no keyframe)
    ts[2] = 0 (no keyframe)
    ts[3] = 256 (no keyframe)
    ts[4] = 512 (no keyframe)

Audio:
    ts[0] = -1024 (keyframe)
    ts[1] = 0 (keyframe)
    ts[2] = 1024 (keyframe)
    ts[3] = 2048 (keyframe)
    ts[4] = 3072 (keyframe)

In libavformat/utils.c:1664 in update_stream_timings(), the smallest timestamp 
of all streams of the given format context is calculated and set as 
"start_time".

In my case
  streams[0].start_time = 0
  streams[0].time_base = 1/12800

  streams[1].start_time = -1024
  streams[1].time_base = 1/48000

leads to
  ic->start_time = -21333

due to the smaller timestamp of the audio track.

When the clip ends, seek_to_start() (avtools/avconv.c:2515) is called, which
calls av_seek_frame() with stream_index -1 and this start_time.

And there is the issue: stream_index=-1 indicates no specific stream is 
selected, but the given start_time relates to the audio track.

The called seek_frame_internal() then selects the default stream, since no
specific stream was selected, which is in my case stream 0, the video track.
Then the "start_time" timestamp (of the audio track) gets rescaled with the 
time_base of the selected stream (the video track).

  timestamp = -273

The following call to read_seek (in my case mov_read_seek) then fails to 
find a frame with that invalid timestamp and returns AVERROR_INVALIDDATA.
This leads to seek_to_start() to return, as well as process_input() and
the loop starts again with the same result, leading to the described infinite 
loop.

My question is now: which of these issues are bugs and how to fix them properly?

Should the AVFormatContext->start_time be set to smallest timestamp of all 
streams 
or only of the default stream? Maybe also store the stream index the timestamp 
refers to?

Should seek_to_start() use stream_index=-1 and the context start_time together?

How should the errors occurring during seek_to_start() be handled? I guess 
in the context of live streams restarting the encoding after errors 
is nice, but when decoding files any errors should make avconv exit, since 
recovering from decoding problems of the same file is not likely.

How should the mov demuxer handle negative timestamps when seeking?
Currently, all negative timestamps are set to 0 in mov_read_seek() (mov.c:4053),
which leads in my case to mov_seek_stream() bailing out with 
AVERROR_INVALIDDATA, 
since no key frame with that timestamp is found (keyframe is at -512) and the 
condition

  if (sample < 0 && st->nb_index_entries && 
      timestamp < st->index_entries[0].timestamp)

is not met: timestamp=0 is not smaller than the first (negative) timestamp.

Looking through the code, I noticed a time_offset is calculated when parsing 
the header 
of the clip. Using this offset when seeking for timestamp=0 fixed the immediate 
problem, 
see attached patch. But I'm not sure, if this is correct and I think the other 
issues are 
still valid.

I hope the information provided is enough to reproduce the issue.

Regards
Peter

[1] https://trac.ffmpeg.org/raw-attachment/ticket/6139/loop.mp4
>From a643f0fad49672b9b9a5d817212d270359e1307e Mon Sep 17 00:00:00 2001
From: Jonas Licht <jonas.li...@fem.tu-ilmenau.de>
Date: Tue, 27 Jun 2017 20:29:57 +0200
Subject: [PATCH] libavformat/mov.c: use calculated dts offset when seeking in
 streams

Subtract the calculated dts offset from the requested timestamp before
seeking. This fixes an infinite loop observed with a short file which
contains only one key frame and starts with negative timestamps.

Then, av_index_search_timestamp() returns a valid negative timestamp,
but mov_seek_stream bails out with AVERROR_INVALIDDATA.

Signed-off-by: Jonas Licht <jonas.li...@fem.tu-ilmenau.de>
---
 libavformat/mov.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/libavformat/mov.c b/libavformat/mov.c
index bf68fbd46a..3293772226 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -4003,6 +4003,8 @@ static int mov_seek_stream(AVFormatContext *s, AVStream *st, int64_t timestamp,
     int sample, time_sample;
     unsigned int i;
 
+    timestamp -= sc->time_offset;
+
     sample = av_index_search_timestamp(st, timestamp, flags);
     av_log(s, AV_LOG_TRACE, "stream %d, timestamp %"PRId64", sample %d\n", st->index, timestamp, sample);
     if (sample < 0 && st->nb_index_entries && timestamp < st->index_entries[0].timestamp)
-- 
2.13.0

_______________________________________________
libav-devel mailing list
libav-devel@libav.org
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to