Created
April 3, 2014 14:30
-
-
Save ericdagenais/9955424 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Index: libavformat/mov.c | |
=================================================================== | |
--- libavformat/mov.c (revision 17434) | |
+++ libavformat/mov.c (working copy) | |
@@ -104,6 +104,11 @@ | |
unsigned flags; | |
} MOVTrackExt; | |
+typedef struct { | |
+ unsigned int track_duration; | |
+ unsigned int media_time; | |
+} MOVElst; | |
+ | |
typedef struct MOVStreamContext { | |
ByteIOContext *pb; | |
int ffindex; /* the ffmpeg stream id */ | |
@@ -118,6 +123,8 @@ | |
MOVStsc *stsc_data; | |
int ctts_index; | |
int ctts_sample; | |
+ unsigned int elst_count; /* number of 'edit' (elst atom) */ | |
+ MOVElst *elst_table; | |
unsigned int sample_size; | |
unsigned int sample_count; | |
int *sample_sizes; | |
@@ -125,7 +132,6 @@ | |
int *keyframes; | |
int time_scale; | |
int time_rate; | |
- int time_offset; ///< time offset of the first edit list entry | |
int current_sample; | |
unsigned int bytes_per_frame; | |
unsigned int samples_per_frame; | |
@@ -1222,6 +1228,85 @@ | |
return 0; | |
} | |
+/* This is a little support function used to process the edit list when | |
+ * building a frame table. */ | |
+#define MAX_DURATION 0x7FFFFFFFFFFFFFFFLL | |
+static void get_next_edit_list_entry(MOVStreamContext *msc, | |
+ unsigned int *edit_list_index, | |
+ unsigned int *edit_list_media_time, | |
+ int64_t *edit_list_duration, | |
+ int64_t global_timescale) { | |
+ /* if there is no edit list, set to max duration and get out */ | |
+ if (!msc->elst_table || (msc->elst_count <= 0)) { | |
+ *edit_list_media_time = 0; | |
+ *edit_list_duration = MAX_DURATION; | |
+ return; | |
+ | |
+ } else while (*edit_list_index < msc->elst_count) { | |
+ | |
+ /* otherwise, find an edit list entries whose media time != -1 */ | |
+ if (msc->elst_table[*edit_list_index].media_time != -1) { | |
+ *edit_list_media_time = | |
+ msc->elst_table[*edit_list_index].media_time; | |
+ *edit_list_duration = | |
+ msc->elst_table[*edit_list_index].track_duration; | |
+ | |
+ /* duration is in global timescale units; convert to msc timescale */ | |
+ *edit_list_duration *= msc->time_scale; | |
+ *edit_list_duration /= global_timescale; | |
+ | |
+ *edit_list_index = *edit_list_index + 1; | |
+ break; | |
+ } | |
+ | |
+ *edit_list_index = *edit_list_index + 1; | |
+ } | |
+ | |
+ /* on the way out, check if this is the last edit list entry; if so, | |
+ * don't let the duration expire (so set it to an absurdly large value) | |
+ */ | |
+ if (*edit_list_index == msc->elst_count) | |
+ *edit_list_duration = MAX_DURATION; | |
+} | |
+ | |
+static void mov_fix_index(MOVContext *mov, AVStream *st) { | |
+ MOVStreamContext *msc = st->priv_data; | |
+ AVIndexEntry *e = st->index_entries; | |
+ | |
+ unsigned int edit_list_media_time = 0; | |
+ int64_t edit_list_duration = 0; | |
+ int64_t frame_duration = 0; | |
+ unsigned int edit_list_pts_counter = 0; | |
+ unsigned int edit_list_index = 0; | |
+ int i; | |
+ | |
+ /* initialize edit list considerations */ | |
+ get_next_edit_list_entry(msc, &edit_list_index, | |
+ &edit_list_media_time, &edit_list_duration, mov->time_scale); | |
+ | |
+ /* fix up pts information w.r.t. the edit list table */ | |
+ for (i = 0; i < st->nb_index_entries; i++, e++) { | |
+ int64_t timestamp = e->timestamp; | |
+ if (timestamp * msc->time_rate < edit_list_media_time) { | |
+ e->timestamp = edit_list_pts_counter/msc->time_rate; | |
+ } else { | |
+ if (i < st->nb_index_entries - 1) | |
+ frame_duration = | |
+ ((e + 1)->timestamp - e->timestamp) * msc->time_rate; | |
+ | |
+ e->timestamp = edit_list_pts_counter/msc->time_rate; | |
+ edit_list_pts_counter += frame_duration; | |
+ edit_list_duration -= frame_duration; | |
+ } | |
+ | |
+ /* reload media time and duration */ | |
+ if (edit_list_duration <= 0) { | |
+ get_next_edit_list_entry(msc, &edit_list_index, | |
+ &edit_list_media_time, &edit_list_duration, mov->time_scale); | |
+ } | |
+ } | |
+} | |
+ | |
static void mov_build_index(MOVContext *mov, AVStream *st) | |
{ | |
MOVStreamContext *sc = st->priv_data; | |
@@ -1232,12 +1317,6 @@ | |
unsigned int stss_index = 0; | |
unsigned int i, j; | |
- /* adjust first dts according to edit list */ | |
- if (sc->time_offset) { | |
- assert(sc->time_offset % sc->time_rate == 0); | |
- current_dts = - (sc->time_offset / sc->time_rate); | |
- } | |
- | |
/* only use old uncompressed audio chunk demuxing when stts specifies it */ | |
if (!(st->codec->codec_type == CODEC_TYPE_AUDIO && | |
sc->stts_count == 1 && sc->stts_data[0].duration == 1)) { | |
@@ -1334,6 +1413,7 @@ | |
out: | |
/* adjust sample count to avindex entries */ | |
sc->sample_count = st->nb_index_entries; | |
+ mov_fix_index(mov, st); | |
} | |
static int mov_read_trak(MOVContext *c, ByteIOContext *pb, MOVAtom atom) | |
@@ -1767,24 +1847,25 @@ | |
static int mov_read_elst(MOVContext *c, ByteIOContext *pb, MOVAtom atom) | |
{ | |
MOVStreamContext *sc = c->fc->streams[c->fc->nb_streams-1]->priv_data; | |
- int i, edit_count; | |
+ MOVElst *elst; | |
+ int i; | |
get_byte(pb); /* version */ | |
get_be24(pb); /* flags */ | |
- edit_count = get_be32(pb); /* entries */ | |
+ sc->elst_count = get_be32(pb); /* entries */ | |
+ if (sc->elst_count <= 0) | |
+ return 0; | |
- for(i=0; i<edit_count; i++){ | |
- int time; | |
- get_be32(pb); /* Track duration */ | |
- time = get_be32(pb); /* Media time */ | |
+ sc->elst_table = elst = | |
+ av_mallocz(sc->elst_count*sizeof(*sc->elst_table)); | |
+ | |
+ for(i=0; i<sc->elst_count; i++, elst++){ | |
+ elst->track_duration = get_be32(pb); /* Track duration */ | |
+ elst->media_time = get_be32(pb); /* Media time */ | |
get_be32(pb); /* Media rate */ | |
- if (i == 0 && time != -1) { | |
- sc->time_offset = time; | |
- sc->time_rate = av_gcd(sc->time_rate, time); | |
- } | |
} | |
- if(edit_count > 1) | |
+ if(sc->elst_count > 1) | |
av_log(c->fc, AV_LOG_WARNING, "multiple edit list entries, " | |
"a/v desync might occur, patch welcome\n"); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment