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

2017-08-13 Thread Steven Liu
2017-08-12 16:42 GMT+08:00  :
> From: Jiejun Zhang 
>
> 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;
> +}
> +
> +

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

2017-08-12 Thread zhangjiejun1992
From: Jiejun Zhang 

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++) {
+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