Commit 55faf56c authored by Clément Bœsch's avatar Clément Bœsch

avformat/mov: move edit list heuristics into mov_build_index()

mov_read_elst() is now only responsible from storing the table in a data
structure; this is consistent with other table readers functions.
parent 75cc57f7
...@@ -53,6 +53,12 @@ typedef struct MOVStsc { ...@@ -53,6 +53,12 @@ typedef struct MOVStsc {
int id; int id;
} MOVStsc; } MOVStsc;
typedef struct MOVElst {
int64_t duration;
int64_t time;
float rate;
} MOVElst;
typedef struct MOVDref { typedef struct MOVDref {
uint32_t type; uint32_t type;
char *path; char *path;
...@@ -121,6 +127,8 @@ typedef struct MOVStreamContext { ...@@ -121,6 +127,8 @@ typedef struct MOVStreamContext {
MOVStsc *stsc_data; MOVStsc *stsc_data;
unsigned int stps_count; unsigned int stps_count;
unsigned *stps_data; ///< partial sync sample for mpeg-2 open gop unsigned *stps_data; ///< partial sync sample for mpeg-2 open gop
MOVElst *elst_data;
unsigned int elst_count;
int ctts_index; int ctts_index;
int ctts_sample; int ctts_sample;
unsigned int sample_size; ///< may contain value calculated from stsd or value from stsz atom unsigned int sample_size; ///< may contain value calculated from stsd or value from stsz atom
...@@ -131,8 +139,6 @@ typedef struct MOVStreamContext { ...@@ -131,8 +139,6 @@ typedef struct MOVStreamContext {
unsigned int keyframe_count; unsigned int keyframe_count;
int *keyframes; int *keyframes;
int time_scale; int time_scale;
int64_t empty_duration; ///< empty duration of the first edit list entry
int64_t start_time; ///< start time of the media
int64_t time_offset; ///< time offset of the edit list entries int64_t time_offset; ///< time offset of the edit list entries
int current_sample; int current_sample;
unsigned int bytes_per_frame; unsigned int bytes_per_frame;
......
...@@ -2268,11 +2268,32 @@ static void mov_build_index(MOVContext *mov, AVStream *st) ...@@ -2268,11 +2268,32 @@ static void mov_build_index(MOVContext *mov, AVStream *st)
unsigned int i, j; unsigned int i, j;
uint64_t stream_size = 0; uint64_t stream_size = 0;
if (sc->elst_count) {
int i, edit_start_index = 0, unsupported = 0;
int64_t empty_duration = 0; // empty duration of the first edit list entry
int64_t start_time = 0; // start time of the media
for (i = 0; i < sc->elst_count; i++) {
const MOVElst *e = &sc->elst_data[i];
if (i == 0 && e->time == -1) {
/* if empty, the first entry is the start time of the stream
* relative to the presentation itself */
empty_duration = e->duration;
edit_start_index = 1;
} else if (i == edit_start_index && e->time >= 0) {
start_time = e->time;
} else
unsupported = 1;
}
if (unsupported)
av_log(mov->fc, AV_LOG_WARNING, "multiple edit list entries, "
"a/v desync might occur, patch welcome\n");
/* adjust first dts according to edit list */ /* adjust first dts according to edit list */
if ((sc->empty_duration || sc->start_time) && mov->time_scale > 0) { if ((empty_duration || start_time) && mov->time_scale > 0) {
if (sc->empty_duration) if (empty_duration)
sc->empty_duration = av_rescale(sc->empty_duration, sc->time_scale, mov->time_scale); empty_duration = av_rescale(empty_duration, sc->time_scale, mov->time_scale);
sc->time_offset = sc->start_time - sc->empty_duration; sc->time_offset = start_time - empty_duration;
current_dts = -sc->time_offset; current_dts = -sc->time_offset;
if (sc->ctts_count>0 && sc->stts_count>0 && if (sc->ctts_count>0 && sc->stts_count>0 &&
sc->ctts_data[0].duration / FFMAX(sc->stts_data[0].duration, 1) > 16) { sc->ctts_data[0].duration / FFMAX(sc->stts_data[0].duration, 1) > 16) {
...@@ -2282,6 +2303,7 @@ static void mov_build_index(MOVContext *mov, AVStream *st) ...@@ -2282,6 +2303,7 @@ static void mov_build_index(MOVContext *mov, AVStream *st)
st->codec->has_b_frames = 1; st->codec->has_b_frames = 1;
} }
} }
}
/* only use old uncompressed audio chunk demuxing when stts specifies it */ /* only use old uncompressed audio chunk demuxing when stts specifies it */
if (!(st->codec->codec_type == AVMEDIA_TYPE_AUDIO && if (!(st->codec->codec_type == AVMEDIA_TYPE_AUDIO &&
...@@ -2626,6 +2648,7 @@ static int mov_read_trak(MOVContext *c, AVIOContext *pb, MOVAtom atom) ...@@ -2626,6 +2648,7 @@ static int mov_read_trak(MOVContext *c, AVIOContext *pb, MOVAtom atom)
av_freep(&sc->keyframes); av_freep(&sc->keyframes);
av_freep(&sc->stts_data); av_freep(&sc->stts_data);
av_freep(&sc->stps_data); av_freep(&sc->stps_data);
av_freep(&sc->elst_data);
av_freep(&sc->rap_group); av_freep(&sc->rap_group);
return 0; return 0;
...@@ -3190,8 +3213,7 @@ free_and_return: ...@@ -3190,8 +3213,7 @@ free_and_return:
static int mov_read_elst(MOVContext *c, AVIOContext *pb, MOVAtom atom) static int mov_read_elst(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{ {
MOVStreamContext *sc; MOVStreamContext *sc;
int i, edit_count, version, edit_start_index = 0; int i, edit_count, version;
int unsupported = 0;
if (c->fc->nb_streams < 1 || c->ignore_editlist) if (c->fc->nb_streams < 1 || c->ignore_editlist)
return 0; return 0;
...@@ -3201,37 +3223,32 @@ static int mov_read_elst(MOVContext *c, AVIOContext *pb, MOVAtom atom) ...@@ -3201,37 +3223,32 @@ static int mov_read_elst(MOVContext *c, AVIOContext *pb, MOVAtom atom)
avio_rb24(pb); /* flags */ avio_rb24(pb); /* flags */
edit_count = avio_rb32(pb); /* entries */ edit_count = avio_rb32(pb); /* entries */
if ((uint64_t)edit_count*12+8 > atom.size) if (!edit_count)
return AVERROR_INVALIDDATA; return 0;
if (sc->elst_data)
av_log(c->fc, AV_LOG_WARNING, "Duplicated ELST atom\n");
av_free(sc->elst_data);
sc->elst_count = 0;
sc->elst_data = av_malloc_array(edit_count, sizeof(*sc->elst_data));
if (!sc->elst_data)
return AVERROR(ENOMEM);
av_dlog(c->fc, "track[%i].edit_count = %i\n", c->fc->nb_streams-1, edit_count); av_dlog(c->fc, "track[%i].edit_count = %i\n", c->fc->nb_streams-1, edit_count);
for (i=0; i<edit_count; i++){ for (i = 0; i < edit_count && !pb->eof_reached; i++) {
int64_t time; MOVElst *e = &sc->elst_data[i];
int64_t duration;
int rate;
if (version == 1) { if (version == 1) {
duration = avio_rb64(pb); e->duration = avio_rb64(pb);
time = avio_rb64(pb); e->time = avio_rb64(pb);
} else { } else {
duration = avio_rb32(pb); /* segment duration */ e->duration = avio_rb32(pb); /* segment duration */
time = (int32_t)avio_rb32(pb); /* media time */ e->time = (int32_t)avio_rb32(pb); /* media time */
} }
rate = avio_rb32(pb); e->rate = avio_rb32(pb) / 65536.0;
if (i == 0 && time == -1) {
sc->empty_duration = duration;
edit_start_index = 1;
} else if (i == edit_start_index && time >= 0)
sc->start_time = time;
else
unsupported = 1;
av_dlog(c->fc, "duration=%"PRId64" time=%"PRId64" rate=%f\n", av_dlog(c->fc, "duration=%"PRId64" time=%"PRId64" rate=%f\n",
duration, time, rate / 65536.0); e->duration, e->time, e->rate);
} }
sc->elst_count = i;
if (unsupported)
av_log(c->fc, AV_LOG_WARNING, "multiple edit list entries, "
"a/v desync might occur, patch welcome\n");
return 0; return 0;
} }
...@@ -3746,6 +3763,7 @@ static int mov_read_close(AVFormatContext *s) ...@@ -3746,6 +3763,7 @@ static int mov_read_close(AVFormatContext *s)
av_freep(&sc->keyframes); av_freep(&sc->keyframes);
av_freep(&sc->stts_data); av_freep(&sc->stts_data);
av_freep(&sc->stps_data); av_freep(&sc->stps_data);
av_freep(&sc->elst_data);
av_freep(&sc->rap_group); av_freep(&sc->rap_group);
av_freep(&sc->display_matrix); av_freep(&sc->display_matrix);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment