[FFmpeg-devel] libavformat/mov: fix multiple stsd handling of files with edit list, fix #6584

Submitted by zhangjiejun1992@gmail.com on Aug. 12, 2017, 8:42 a.m.

Details

Message ID 20170812084223.94158-1-zhangjiejun1992@gmail.com
State Superseded
Headers show

Commit Message

zhangjiejun1992@gmail.com Aug. 12, 2017, 8:42 a.m.
From: Jiejun Zhang <zhangjiejun1992@gmail.com>

When an edit list exists in a MOV file, counting by stscs no longer
works because stscs' order is different from the actual timeline. This
commit adds stsd-change markers to the actual timeline and changes stsd
according to these markers.
---
 libavformat/isom.h |  14 ++++--
 libavformat/mov.c  | 122 +++++++++++++++++++++++++++++++++++++++++------------
 2 files changed, 105 insertions(+), 31 deletions(-)

Comments

Steven Liu Aug. 14, 2017, 5:16 a.m.
2017-08-12 16:42 GMT+08:00  <zhangjiejun1992@gmail.com>:
> From: Jiejun Zhang <zhangjiejun1992@gmail.com>
>
> When an edit list exists in a MOV file, counting by stscs no longer
> works because stscs' order is different from the actual timeline. This
> commit adds stsd-change markers to the actual timeline and changes stsd
> according to these markers.
> ---
>  libavformat/isom.h |  14 ++++--
>  libavformat/mov.c  | 122 +++++++++++++++++++++++++++++++++++++++++------------
>  2 files changed, 105 insertions(+), 31 deletions(-)
>
> diff --git a/libavformat/isom.h b/libavformat/isom.h
> index ff009b0896..51cd333a8c 100644
> --- a/libavformat/isom.h
> +++ b/libavformat/isom.h
> @@ -127,6 +127,11 @@ typedef struct MOVIndexRange {
>      int64_t end;
>  } MOVIndexRange;
>
> +typedef struct MOVStsdChangeEntry {
> +    int64_t sample_index;  ///< stsd changes at this sample index
> +    int stsd_id;  ///< stsd changes to stsd_id
> +} MOVStsdChangeEntry;
> +
>  typedef struct MOVStreamContext {
>      AVIOContext *pb;
>      int pb_is_copied;
> @@ -140,16 +145,17 @@ typedef struct MOVStreamContext {
>      MOVStts *ctts_data;
>      unsigned int stsc_count;
>      MOVStsc *stsc_data;
> -    int stsc_index;
> -    int stsc_sample;
> +    MOVStsdChangeEntry *stsd_change_data;
> +    int stsd_change_count;
> +    int stsd_change_index;
>      unsigned int stps_count;
>      unsigned *stps_data;  ///< partial sync sample for mpeg-2 open gop
>      MOVElst *elst_data;
>      unsigned int elst_count;
>      int ctts_index;
>      int ctts_sample;
> -    unsigned int sample_size; ///< may contain value calculated from stsd or value from stsz atom
> -    unsigned int stsz_sample_size; ///< always contains sample size from stsz atom
> +    unsigned int sample_size; ///< may contain value calculated from stsd or value from stsz atom unsigned
> +    int stsz_sample_size; ///< always contains sample size from stsz atom
>      unsigned int sample_count;
>      int *sample_sizes;
>      int keyframe_absent;
> diff --git a/libavformat/mov.c b/libavformat/mov.c
> index 63f84be782..f3239047c8 100644
> --- a/libavformat/mov.c
> +++ b/libavformat/mov.c
> @@ -2923,6 +2923,35 @@ static int64_t add_index_entry(AVStream *st, int64_t pos, int64_t timestamp,
>      return index;
>  }
>
> +static int add_stsd_change_entry(MOVStreamContext *msc, int64_t sample_index, int stsd_id,
> +        unsigned int* allocated_size)
> +{
> +    MOVStsdChangeEntry *entries;
> +    const size_t min_size_needed = (msc->stsd_change_count + 1) * sizeof(MOVStsdChangeEntry);
> +
> +    const size_t requested_size =
> +        min_size_needed > *allocated_size ?
> +        FFMAX(min_size_needed, 2 * (*allocated_size)) :
> +        min_size_needed;
> +
> +    if ((unsigned)msc->stsd_change_count + 1 >= UINT_MAX / sizeof(MOVStsdChangeEntry))
> +        return -1;
> +
> +    entries = av_fast_realloc(msc->stsd_change_data,
> +                              allocated_size,
> +                              requested_size);
> +
> +    if (!entries)
> +        return -1;
> +
> +    msc->stsd_change_data = entries;
> +    entries[msc->stsd_change_count].sample_index = sample_index;
> +    entries[msc->stsd_change_count].stsd_id = stsd_id;
> +    msc->stsd_change_count++;
> +
> +    return 0;
> +}
> +
>  /**
>   * Rewrite timestamps of index entries in the range [end_index - frame_duration_buffer_size, end_index)
>   * by subtracting end_ts successively by the amounts given in frame_duration_buffer.
> @@ -3055,6 +3084,8 @@ static void mov_fix_index(MOVContext *mov, AVStream *st)
>      int num_discarded_begin = 0;
>      int first_non_zero_audio_edit = -1;
>      int packet_skip_samples = 0;
> +    int stsc_index = 0;
> +    int stsc_sample = 0;
>      MOVIndexRange *current_index_range;
>      int i;
>
> @@ -3091,6 +3122,11 @@ static void mov_fix_index(MOVContext *mov, AVStream *st)
>
>      start_dts = edit_list_dts_entry_end;
>
> +    msc->last_stsd_index = -1;
> +    unsigned int stsd_change_data_allocated_size = 0;
> +    msc->stsd_change_data = NULL;
> +    msc->stsd_change_count = 0;
> +
>      while (get_edit_list_entry(mov, msc, edit_list_index, &edit_list_media_time,
>                                 &edit_list_duration, mov->time_scale)) {
>          av_log(mov->fc, AV_LOG_DEBUG, "Processing st: %d, edit list %"PRId64" - media time: %"PRId64", duration: %"PRId64"\n",
> @@ -3153,6 +3189,20 @@ static void mov_fix_index(MOVContext *mov, AVStream *st)
>          }
>          current = e_old + index;
>
> +        // adjust stsd index
> +        int time_sample = 0;
> +        for (int i = 0; i < msc->stsc_count; i++) {
the i redefined, first define at the top of the function mov_list_index
> +            int next = time_sample + mov_get_stsc_samples(msc, i);
> +            if (next > index) {
> +                stsc_index = i;
> +                stsc_sample = index - time_sample;
> +                break;
> +            }
> +            time_sample = next;
> +        }
> +
> +        av_log(mov->fc, AV_LOG_INFO, "stream %d, adjusted stsc_index: %d, stsc_sample: %d\n", st->index, stsc_index, stsc_sample);
> +
>          ctts_index_old = 0;
>          ctts_sample_old = 0;
>
> @@ -3265,12 +3315,35 @@ static void mov_fix_index(MOVContext *mov, AVStream *st)
>                  }
>              }
>
> -            if (add_index_entry(st, current->pos, edit_list_dts_counter, current->size,
> -                                current->min_distance, flags) == -1) {
> +            int index_entry_index = add_index_entry(st, current->pos, edit_list_dts_counter, current->size,
> +                    current->min_distance, flags);
> +            if (index_entry_index == -1) {
>                  av_log(mov->fc, AV_LOG_ERROR, "Cannot add index entry\n");
>                  break;
>              }
>
> +            if (msc->stsc_data) {
> +                if (msc->stsc_data[stsc_index].id > 0 &&
> +                   msc->stsc_data[stsc_index].id - 1 < msc->stsd_count &&
> +                   msc->stsc_data[stsc_index].id - 1 != msc->last_stsd_index) {
> +                    msc->last_stsd_index = msc->stsc_data[stsc_index].id - 1;
> +                    int ret = add_stsd_change_entry(msc, index_entry_index, msc->last_stsd_index, &stsd_change_data_allocated_size);
> +                    if (ret < 0) {
> +                        av_log(mov->fc, AV_LOG_ERROR, "Cannot add stsd change entry\n");
> +                        break;
> +                    }
> +                    av_log(mov->fc, AV_LOG_INFO, "added a stsd change entry sample_index: %d, stsd_index:%d\n",
> +                            index_entry_index,
> +                            msc->last_stsd_index);
> +                }
> +                stsc_sample++;
> +                if (stsc_index < msc->stsc_count - 1 &&
> +                    mov_get_stsc_samples(msc, stsc_index) == stsc_sample) {
> +                    stsc_index++;
> +                    stsc_sample = 0;
> +                }
> +            }
> +
>              // Update the index ranges array
>              if (current_index_range < msc->index_ranges || index != current_index_range->end) {
>                  current_index_range++;
> @@ -3327,6 +3400,7 @@ static void mov_fix_index(MOVContext *mov, AVStream *st)
>      current_index_range->start = 0;
>      current_index_range->end = 0;
>      msc->current_index = msc->index_ranges[0].start;
> +    msc->last_stsd_index = 0;
>  }
>
>  static void mov_build_index(MOVContext *mov, AVStream *st)
> @@ -6432,9 +6506,6 @@ static int mov_change_extradata(MOVStreamContext *sc, AVPacket *pkt)
>      uint8_t *side, *extradata;
>      int extradata_size;
>
> -    /* Save the current index. */
> -    sc->last_stsd_index = sc->stsc_data[sc->stsc_index].id - 1;
> -
>      /* Notify the decoder that extradata changed. */
>      extradata_size = sc->extradata_size[sc->last_stsd_index];
>      extradata = sc->extradata[sc->last_stsd_index];
> @@ -6554,18 +6625,18 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
>      pkt->pos = sample->pos;
>
>      /* Multiple stsd handling. */
> -    if (sc->stsc_data) {
> -        /* Keep track of the stsc index for the given sample, then check
> -        * if the stsd index is different from the last used one. */
> -        sc->stsc_sample++;
> -        if (mov_stsc_index_valid(sc->stsc_index, sc->stsc_count) &&
> -            mov_get_stsc_samples(sc, sc->stsc_index) == sc->stsc_sample) {
> -            sc->stsc_index++;
> -            sc->stsc_sample = 0;
> -        /* Do not check indexes after a switch. */
> -        } else if (sc->stsc_data[sc->stsc_index].id > 0 &&
> -                   sc->stsc_data[sc->stsc_index].id - 1 < sc->stsd_count &&
> -                   sc->stsc_data[sc->stsc_index].id - 1 != sc->last_stsd_index) {
> +    if (sc->stsd_change_data) {
> +        if (sc->stsd_change_index + 1 < sc->stsd_change_count &&
> +                // sc->current_sample is already the next sample, so subtract 1
> +                sc->stsd_change_data[sc->stsd_change_index + 1].sample_index == sc->current_sample - 1) {
> +            ++sc->stsd_change_index;
> +        }
> +        if (sc->last_stsd_index != sc->stsd_change_data[sc->stsd_change_index].stsd_id) {
> +            av_log(mov->fc, AV_LOG_INFO, "stsd id changed from %d to %d, at sample %d\n",
> +                    sc->last_stsd_index,
> +                    sc->stsd_change_data[sc->stsd_change_index].stsd_id,
> +                    sc->current_sample - 1);
> +            sc->last_stsd_index = sc->stsd_change_data[sc->stsd_change_index].stsd_id;
>              ret = mov_change_extradata(sc, pkt);
>              if (ret < 0)
>                  return ret;
> @@ -6643,18 +6714,15 @@ static int mov_seek_stream(AVFormatContext *s, AVStream *st, int64_t timestamp,
>          }
>      }
>
> -    /* adjust stsd index */
> -    time_sample = 0;
> -    for (i = 0; i < sc->stsc_count; i++) {
> -        int next = time_sample + mov_get_stsc_samples(sc, i);
> -        if (next > sc->current_sample) {
> -            sc->stsc_index = i;
> -            sc->stsc_sample = sc->current_sample - time_sample;
> -            break;
> +    /* adjust stsd change index */
> +    for (i = 0; i < sc->stsd_change_count; i++) {
> +        if (sc->current_sample >= sc->stsd_change_data[i].sample_index &&
> +                (i + 1 == sc->stsd_change_count ||
> +                 sc->current_sample < sc->stsd_change_data[i + 1].sample_index)) {
> +            sc->stsd_change_index = i;
>          }
> -        time_sample = next;
>      }
> -
> +
>      return sample;
>  }
>
> --
> 2.11.0 (Apple Git-81)
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


This patch is LGTM!

Patch hide | download patch | download mbox

diff --git a/libavformat/isom.h b/libavformat/isom.h
index ff009b0896..51cd333a8c 100644
--- a/libavformat/isom.h
+++ b/libavformat/isom.h
@@ -127,6 +127,11 @@  typedef struct MOVIndexRange {
     int64_t end;
 } MOVIndexRange;
 
+typedef struct MOVStsdChangeEntry {
+    int64_t sample_index;  ///< stsd changes at this sample index
+    int stsd_id;  ///< stsd changes to stsd_id
+} MOVStsdChangeEntry;
+
 typedef struct MOVStreamContext {
     AVIOContext *pb;
     int pb_is_copied;
@@ -140,16 +145,17 @@  typedef struct MOVStreamContext {
     MOVStts *ctts_data;
     unsigned int stsc_count;
     MOVStsc *stsc_data;
-    int stsc_index;
-    int stsc_sample;
+    MOVStsdChangeEntry *stsd_change_data;
+    int stsd_change_count;
+    int stsd_change_index;
     unsigned int stps_count;
     unsigned *stps_data;  ///< partial sync sample for mpeg-2 open gop
     MOVElst *elst_data;
     unsigned int elst_count;
     int ctts_index;
     int ctts_sample;
-    unsigned int sample_size; ///< may contain value calculated from stsd or value from stsz atom
-    unsigned int stsz_sample_size; ///< always contains sample size from stsz atom
+    unsigned int sample_size; ///< may contain value calculated from stsd or value from stsz atom unsigned 
+    int stsz_sample_size; ///< always contains sample size from stsz atom
     unsigned int sample_count;
     int *sample_sizes;
     int keyframe_absent;
diff --git a/libavformat/mov.c b/libavformat/mov.c
index 63f84be782..f3239047c8 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -2923,6 +2923,35 @@  static int64_t add_index_entry(AVStream *st, int64_t pos, int64_t timestamp,
     return index;
 }
 
+static int add_stsd_change_entry(MOVStreamContext *msc, int64_t sample_index, int stsd_id,
+        unsigned int* allocated_size)
+{
+    MOVStsdChangeEntry *entries;
+    const size_t min_size_needed = (msc->stsd_change_count + 1) * sizeof(MOVStsdChangeEntry);
+
+    const size_t requested_size =
+        min_size_needed > *allocated_size ?
+        FFMAX(min_size_needed, 2 * (*allocated_size)) :
+        min_size_needed;
+
+    if ((unsigned)msc->stsd_change_count + 1 >= UINT_MAX / sizeof(MOVStsdChangeEntry))
+        return -1;
+
+    entries = av_fast_realloc(msc->stsd_change_data,
+                              allocated_size,
+                              requested_size);
+
+    if (!entries)
+        return -1;
+
+    msc->stsd_change_data = entries;
+    entries[msc->stsd_change_count].sample_index = sample_index;
+    entries[msc->stsd_change_count].stsd_id = stsd_id;
+    msc->stsd_change_count++;
+
+    return 0;
+}
+
 /**
  * Rewrite timestamps of index entries in the range [end_index - frame_duration_buffer_size, end_index)
  * by subtracting end_ts successively by the amounts given in frame_duration_buffer.
@@ -3055,6 +3084,8 @@  static void mov_fix_index(MOVContext *mov, AVStream *st)
     int num_discarded_begin = 0;
     int first_non_zero_audio_edit = -1;
     int packet_skip_samples = 0;
+    int stsc_index = 0;
+    int stsc_sample = 0;
     MOVIndexRange *current_index_range;
     int i;
 
@@ -3091,6 +3122,11 @@  static void mov_fix_index(MOVContext *mov, AVStream *st)
 
     start_dts = edit_list_dts_entry_end;
 
+    msc->last_stsd_index = -1;
+    unsigned int stsd_change_data_allocated_size = 0;
+    msc->stsd_change_data = NULL;
+    msc->stsd_change_count = 0;
+
     while (get_edit_list_entry(mov, msc, edit_list_index, &edit_list_media_time,
                                &edit_list_duration, mov->time_scale)) {
         av_log(mov->fc, AV_LOG_DEBUG, "Processing st: %d, edit list %"PRId64" - media time: %"PRId64", duration: %"PRId64"\n",
@@ -3153,6 +3189,20 @@  static void mov_fix_index(MOVContext *mov, AVStream *st)
         }
         current = e_old + index;
 
+        // adjust stsd index
+        int time_sample = 0;
+        for (int i = 0; i < msc->stsc_count; i++) {
+            int next = time_sample + mov_get_stsc_samples(msc, i);
+            if (next > index) {
+                stsc_index = i;
+                stsc_sample = index - time_sample;
+                break;
+            }
+            time_sample = next;
+        }
+
+        av_log(mov->fc, AV_LOG_INFO, "stream %d, adjusted stsc_index: %d, stsc_sample: %d\n", st->index, stsc_index, stsc_sample);
+
         ctts_index_old = 0;
         ctts_sample_old = 0;
 
@@ -3265,12 +3315,35 @@  static void mov_fix_index(MOVContext *mov, AVStream *st)
                 }
             }
 
-            if (add_index_entry(st, current->pos, edit_list_dts_counter, current->size,
-                                current->min_distance, flags) == -1) {
+            int index_entry_index = add_index_entry(st, current->pos, edit_list_dts_counter, current->size,
+                    current->min_distance, flags);
+            if (index_entry_index == -1) {
                 av_log(mov->fc, AV_LOG_ERROR, "Cannot add index entry\n");
                 break;
             }
 
+            if (msc->stsc_data) {
+                if (msc->stsc_data[stsc_index].id > 0 &&
+                   msc->stsc_data[stsc_index].id - 1 < msc->stsd_count &&
+                   msc->stsc_data[stsc_index].id - 1 != msc->last_stsd_index) {
+                    msc->last_stsd_index = msc->stsc_data[stsc_index].id - 1;
+                    int ret = add_stsd_change_entry(msc, index_entry_index, msc->last_stsd_index, &stsd_change_data_allocated_size);
+                    if (ret < 0) {
+                        av_log(mov->fc, AV_LOG_ERROR, "Cannot add stsd change entry\n");
+                        break;
+                    }
+                    av_log(mov->fc, AV_LOG_INFO, "added a stsd change entry sample_index: %d, stsd_index:%d\n",
+                            index_entry_index,
+                            msc->last_stsd_index);
+                }
+                stsc_sample++;
+                if (stsc_index < msc->stsc_count - 1 &&
+                    mov_get_stsc_samples(msc, stsc_index) == stsc_sample) {
+                    stsc_index++;
+                    stsc_sample = 0;
+                }
+            }
+
             // Update the index ranges array
             if (current_index_range < msc->index_ranges || index != current_index_range->end) {
                 current_index_range++;
@@ -3327,6 +3400,7 @@  static void mov_fix_index(MOVContext *mov, AVStream *st)
     current_index_range->start = 0;
     current_index_range->end = 0;
     msc->current_index = msc->index_ranges[0].start;
+    msc->last_stsd_index = 0;
 }
 
 static void mov_build_index(MOVContext *mov, AVStream *st)
@@ -6432,9 +6506,6 @@  static int mov_change_extradata(MOVStreamContext *sc, AVPacket *pkt)
     uint8_t *side, *extradata;
     int extradata_size;
 
-    /* Save the current index. */
-    sc->last_stsd_index = sc->stsc_data[sc->stsc_index].id - 1;
-
     /* Notify the decoder that extradata changed. */
     extradata_size = sc->extradata_size[sc->last_stsd_index];
     extradata = sc->extradata[sc->last_stsd_index];
@@ -6554,18 +6625,18 @@  static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
     pkt->pos = sample->pos;
 
     /* Multiple stsd handling. */
-    if (sc->stsc_data) {
-        /* Keep track of the stsc index for the given sample, then check
-        * if the stsd index is different from the last used one. */
-        sc->stsc_sample++;
-        if (mov_stsc_index_valid(sc->stsc_index, sc->stsc_count) &&
-            mov_get_stsc_samples(sc, sc->stsc_index) == sc->stsc_sample) {
-            sc->stsc_index++;
-            sc->stsc_sample = 0;
-        /* Do not check indexes after a switch. */
-        } else if (sc->stsc_data[sc->stsc_index].id > 0 &&
-                   sc->stsc_data[sc->stsc_index].id - 1 < sc->stsd_count &&
-                   sc->stsc_data[sc->stsc_index].id - 1 != sc->last_stsd_index) {
+    if (sc->stsd_change_data) {
+        if (sc->stsd_change_index + 1 < sc->stsd_change_count &&
+                // sc->current_sample is already the next sample, so subtract 1
+                sc->stsd_change_data[sc->stsd_change_index + 1].sample_index == sc->current_sample - 1) {
+            ++sc->stsd_change_index;
+        }
+        if (sc->last_stsd_index != sc->stsd_change_data[sc->stsd_change_index].stsd_id) {
+            av_log(mov->fc, AV_LOG_INFO, "stsd id changed from %d to %d, at sample %d\n",
+                    sc->last_stsd_index,
+                    sc->stsd_change_data[sc->stsd_change_index].stsd_id,
+                    sc->current_sample - 1);
+            sc->last_stsd_index = sc->stsd_change_data[sc->stsd_change_index].stsd_id;
             ret = mov_change_extradata(sc, pkt);
             if (ret < 0)
                 return ret;
@@ -6643,18 +6714,15 @@  static int mov_seek_stream(AVFormatContext *s, AVStream *st, int64_t timestamp,
         }
     }
 
-    /* adjust stsd index */
-    time_sample = 0;
-    for (i = 0; i < sc->stsc_count; i++) {
-        int next = time_sample + mov_get_stsc_samples(sc, i);
-        if (next > sc->current_sample) {
-            sc->stsc_index = i;
-            sc->stsc_sample = sc->current_sample - time_sample;
-            break;
+    /* adjust stsd change index */
+    for (i = 0; i < sc->stsd_change_count; i++) {
+        if (sc->current_sample >= sc->stsd_change_data[i].sample_index &&
+                (i + 1 == sc->stsd_change_count ||
+                 sc->current_sample < sc->stsd_change_data[i + 1].sample_index)) {
+            sc->stsd_change_index = i;
         }
-        time_sample = next;
     }
-
+    
     return sample;
 }