Skip to content

Instantly share code, notes, and snippets.

@ericdagenais
Created April 3, 2014 14:30
Show Gist options
  • Save ericdagenais/9955424 to your computer and use it in GitHub Desktop.
Save ericdagenais/9955424 to your computer and use it in GitHub Desktop.
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