[FFmpeg-devel] [PATCH] libavformat/mov: fix multiple stsd handling of MOV files with edit list
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. Test sample: https://www.dropbox.com/s/qz0ort4znqq9jdy/attachment_video.mov?dl=0 Run `ffmpeg -i attachment_video.mov -f image2 frames%03d.png`. The git-master version cannot decode frame 327 to 330 because a wrong stsd is used. After applying this patch they are decoded correctly. Signed-off-by: Jiejun Zhang --- libavformat/isom.h | 13 +- libavformat/mov.c | 125 + 2 files changed, 109 insertions(+), 29 deletions(-) diff --git a/libavformat/isom.h b/libavformat/isom.h index 02bfedd..141237a 100644 --- a/libavformat/isom.h +++ b/libavformat/isom.h @@ -115,6 +115,14 @@ typedef struct MOVFragmentIndex { MOVFragmentIndexItem *items; } MOVFragmentIndex; +/** + * An entry for: stsd changes to `stsd_id` at sample `sample_index` (inclusive) + */ +typedef struct MOVStsdChangeEntry { +int64_t sample_index; +int stsd_id; +} MOVStsdChangeEntry; + typedef struct MOVStreamContext { AVIOContext *pb; int pb_is_copied; @@ -128,12 +136,13 @@ typedef struct MOVStreamContext { MOVStts *ctts_data; unsigned int stsc_count; MOVStsc *stsc_data; -int stsc_index; -int stsc_sample; unsigned int stps_count; unsigned *stps_data; ///< partial sync sample for mpeg-2 open gop MOVElst *elst_data; unsigned int elst_count; +MOVStsdChangeEntry *stsd_change_data; +int stsd_change_count; +int stsd_change_index; int ctts_index; int ctts_sample; unsigned int sample_size; ///< may contain value calculated from stsd or value from stsz atom diff --git a/libavformat/mov.c b/libavformat/mov.c index 88a79da..e5f7f72 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -2901,6 +2901,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. @@ -2984,6 +3013,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; if (!msc->elst_data || msc->elst_count <= 0 || nb_old <= 0) { return; @@ -3012,6 +3043,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", @@ -3073,6 +3109,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; @@ -3176,12 +3226,36 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) } } -if (add_index_entr
[FFmpeg-devel] [PATCH] libavformat/mov: fix multiple stsd handling of files with edit list, fix #6584
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
[FFmpeg-devel] [PATCH v2] libavformat/mov: fix multiple stsd handling of files with edit list, fix #6584
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 c02caf6719..628cf31cec 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -2926,6 +2926,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. @@ -3058,6 +3087,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; @@ -3094,6 +3125,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", @@ -3156,6 +3192,20 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) } current = e_old + index; +// adjust stsd index +int time_sample = 0; +for (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; @@ -3268,12 +3318,35 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) } } -if (add_index_entry(st, current->pos, edit_list_dts
[FFmpeg-devel] [PATCH v3] libavformat/mov: fix multiple stsd handling of files with edit list, fix #6584
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 | 120 + 2 files changed, 104 insertions(+), 30 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 c02caf6719..e775056c90 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -2926,6 +2926,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. @@ -3058,6 +3087,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; @@ -3094,6 +3125,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", @@ -3156,6 +3192,20 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) } current = e_old + index; +// adjust stsd index +int time_sample = 0; +for (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; @@ -3268,12 +3318,35 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) } } -if (add_index_entry(st, current->pos, edit_list_dt
[FFmpeg-devel] [PATCH] lavc/audiotoolboxenc: fix noise in encoded audio
From: Jiejun Zhang This fixes #6940 --- libavcodec/audiotoolboxenc.c | 20 +++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/libavcodec/audiotoolboxenc.c b/libavcodec/audiotoolboxenc.c index 71885d1530..b70375a692 100644 --- a/libavcodec/audiotoolboxenc.c +++ b/libavcodec/audiotoolboxenc.c @@ -48,6 +48,9 @@ typedef struct ATDecodeContext { AudioFrameQueue afq; int eof; int frame_size; + +uint8_t* audio_data_buf; +uint32_t audio_data_buf_size; } ATDecodeContext; static UInt32 ffat_get_format_id(enum AVCodecID codec, int profile) @@ -442,6 +445,9 @@ static av_cold int ffat_init_encoder(AVCodecContext *avctx) ff_af_queue_init(avctx, &at->afq); +at->audio_data_buf_size = 0; +at->audio_data_buf = NULL; + return 0; } @@ -471,7 +477,15 @@ static OSStatus ffat_encode_callback(AudioConverterRef converter, UInt32 *nb_pac data->mBuffers[0].mDataByteSize = frame->nb_samples * av_get_bytes_per_sample(avctx->sample_fmt) * avctx->channels; -data->mBuffers[0].mData = frame->data[0]; +if (at->audio_data_buf_size < data->mBuffers[0].mDataByteSize) { +av_log(avctx, AV_LOG_INFO, "Increasing audio data buffer size to %u", + data->mBuffers[0].mDataByteSize); +av_free(at->audio_data_buf); +at->audio_data_buf_size = data->mBuffers[0].mDataByteSize; +at->audio_data_buf = av_malloc(at->audio_data_buf_size); +} +memcpy(at->audio_data_buf, frame->data[0], data->mBuffers[0].mDataByteSize); +data->mBuffers[0].mData = at->audio_data_buf; if (*nb_packets > frame->nb_samples) *nb_packets = frame->nb_samples; @@ -565,6 +579,10 @@ static av_cold int ffat_close_encoder(AVCodecContext *avctx) ff_bufqueue_discard_all(&at->frame_queue); ff_bufqueue_discard_all(&at->used_frame_queue); ff_af_queue_close(&at->afq); +if (at->audio_data_buf_size > 0) { +at->audio_data_buf_size = 0; +av_free(at->audio_data_buf); +} return 0; } -- 2.14.3 (Apple Git-98) ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] [PATCH] lavc/audiotoolboxenc: fix noise in encoded audio
From: Jiejun Zhang This fixes #6940 --- libavcodec/audiotoolboxenc.c | 34 +- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/libavcodec/audiotoolboxenc.c b/libavcodec/audiotoolboxenc.c index 71885d1530..0c1e5feadc 100644 --- a/libavcodec/audiotoolboxenc.c +++ b/libavcodec/audiotoolboxenc.c @@ -48,6 +48,9 @@ typedef struct ATDecodeContext { AudioFrameQueue afq; int eof; int frame_size; + +uint8_t* audio_data_buf; +uint32_t audio_data_buf_size; } ATDecodeContext; static UInt32 ffat_get_format_id(enum AVCodecID codec, int profile) @@ -442,6 +445,9 @@ static av_cold int ffat_init_encoder(AVCodecContext *avctx) ff_af_queue_init(avctx, &at->afq); +at->audio_data_buf_size = 0; +at->audio_data_buf = NULL; + return 0; } @@ -465,13 +471,27 @@ static OSStatus ffat_encode_callback(AudioConverterRef converter, UInt32 *nb_pac } frame = ff_bufqueue_get(&at->frame_queue); - +int audio_data_size = frame->nb_samples * + av_get_bytes_per_sample(avctx->sample_fmt) * + avctx->channels; +if (at->audio_data_buf_size < audio_data_size) { +av_log(avctx, AV_LOG_INFO, "Increasing audio data buffer size to %d\n", + audio_data_size); +av_free(at->audio_data_buf); +at->audio_data_buf_size = audio_data_size; +at->audio_data_buf = av_malloc(at->audio_data_buf_size); +if (!at->audio_data_buf) { +at->audio_data_buf_size = 0; +data->mNumberBuffers = 0; +*nb_packets = 0; +return AVERROR(ENOMEM); +} +} data->mNumberBuffers = 1; data->mBuffers[0].mNumberChannels = avctx->channels; -data->mBuffers[0].mDataByteSize = frame->nb_samples * - av_get_bytes_per_sample(avctx->sample_fmt) * -avctx->channels; -data->mBuffers[0].mData = frame->data[0]; +data->mBuffers[0].mDataByteSize = audio_data_size; +data->mBuffers[0].mData = at->audio_data_buf; +memcpy(at->audio_data_buf, frame->data[0], data->mBuffers[0].mDataByteSize); if (*nb_packets > frame->nb_samples) *nb_packets = frame->nb_samples; @@ -565,6 +585,10 @@ static av_cold int ffat_close_encoder(AVCodecContext *avctx) ff_bufqueue_discard_all(&at->frame_queue); ff_bufqueue_discard_all(&at->used_frame_queue); ff_af_queue_close(&at->afq); +if (at->audio_data_buf_size > 0) { +at->audio_data_buf_size = 0; +av_free(at->audio_data_buf); +} return 0; } -- 2.14.3 (Apple Git-98) ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] [PATCH v2] lavc/audiotoolboxenc: fix noise in encoded audio
From: Jiejun Zhang This fixes #6940 Although undocumented, AudioToolbox seems to require the data supplied by the callback (i.e. ffat_encode_callback) being unchanged until the next time the callback is called. In the old implementation, the AVBuffer backing the frame is recycled after the frame is freed, and somebody else (maybe the decoder) will write into the AVBuffer and change the data. AudioToolbox then encodes some wrong data and noise is produced. Copying the data to a separate buffer solves this problem. --- libavcodec/audiotoolboxenc.c | 32 +++- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/libavcodec/audiotoolboxenc.c b/libavcodec/audiotoolboxenc.c index 71885d1530..dcac88cdde 100644 --- a/libavcodec/audiotoolboxenc.c +++ b/libavcodec/audiotoolboxenc.c @@ -48,6 +48,9 @@ typedef struct ATDecodeContext { AudioFrameQueue afq; int eof; int frame_size; + +uint8_t* audio_data_buf; +uint32_t audio_data_buf_size; } ATDecodeContext; static UInt32 ffat_get_format_id(enum AVCodecID codec, int profile) @@ -442,6 +445,9 @@ static av_cold int ffat_init_encoder(AVCodecContext *avctx) ff_af_queue_init(avctx, &at->afq); +at->audio_data_buf_size = 0; +at->audio_data_buf = NULL; + return 0; } @@ -465,13 +471,27 @@ static OSStatus ffat_encode_callback(AudioConverterRef converter, UInt32 *nb_pac } frame = ff_bufqueue_get(&at->frame_queue); - +int audio_data_size = frame->nb_samples * + av_get_bytes_per_sample(avctx->sample_fmt) * + avctx->channels; +if (at->audio_data_buf_size < audio_data_size) { +av_log(avctx, AV_LOG_INFO, "Increasing audio data buffer size to %d\n", + audio_data_size); +av_free(at->audio_data_buf); +at->audio_data_buf_size = audio_data_size; +at->audio_data_buf = av_malloc(at->audio_data_buf_size); +if (!at->audio_data_buf) { +at->audio_data_buf_size = 0; +data->mNumberBuffers = 0; +*nb_packets = 0; +return AVERROR(ENOMEM); +} +} data->mNumberBuffers = 1; data->mBuffers[0].mNumberChannels = avctx->channels; -data->mBuffers[0].mDataByteSize = frame->nb_samples * - av_get_bytes_per_sample(avctx->sample_fmt) * -avctx->channels; -data->mBuffers[0].mData = frame->data[0]; +data->mBuffers[0].mDataByteSize = audio_data_size; +data->mBuffers[0].mData = at->audio_data_buf; +memcpy(at->audio_data_buf, frame->data[0], data->mBuffers[0].mDataByteSize); if (*nb_packets > frame->nb_samples) *nb_packets = frame->nb_samples; @@ -565,6 +585,8 @@ static av_cold int ffat_close_encoder(AVCodecContext *avctx) ff_bufqueue_discard_all(&at->frame_queue); ff_bufqueue_discard_all(&at->used_frame_queue); ff_af_queue_close(&at->afq); +at->audio_data_buf_size = 0; +av_freep(&at->audio_data_buf); return 0; } -- 2.14.3 (Apple Git-98) ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] [PATCH v3] lavc/audiotoolboxenc: fix noise in encoded audio
From: Jiejun Zhang This fixes #6940 Although undocumented, AudioToolbox seems to require the data supplied by the callback (i.e. ffat_encode_callback) being unchanged until the next time the callback is called. In the old implementation, the AVBuffer backing the frame is recycled after the frame is freed, and somebody else (maybe the decoder) will write into the AVBuffer and change the data. AudioToolbox then encodes some wrong data and noise is produced. Retaining a frame reference solves this problem. --- libavcodec/audiotoolboxenc.c | 12 1 file changed, 12 insertions(+) diff --git a/libavcodec/audiotoolboxenc.c b/libavcodec/audiotoolboxenc.c index 71885d1530..5d3a746348 100644 --- a/libavcodec/audiotoolboxenc.c +++ b/libavcodec/audiotoolboxenc.c @@ -48,6 +48,8 @@ typedef struct ATDecodeContext { AudioFrameQueue afq; int eof; int frame_size; + +AVFrame* encoding_frame; } ATDecodeContext; static UInt32 ffat_get_format_id(enum AVCodecID codec, int profile) @@ -442,6 +444,10 @@ static av_cold int ffat_init_encoder(AVCodecContext *avctx) ff_af_queue_init(avctx, &at->afq); +at->encoding_frame = av_frame_alloc(); +if (!at->encoding_frame) +return AVERROR(ENOMEM); + return 0; } @@ -453,6 +459,7 @@ static OSStatus ffat_encode_callback(AudioConverterRef converter, UInt32 *nb_pac AVCodecContext *avctx = inctx; ATDecodeContext *at = avctx->priv_data; AVFrame *frame; +int ret; if (!at->frame_queue.available) { if (at->eof) { @@ -475,6 +482,10 @@ static OSStatus ffat_encode_callback(AudioConverterRef converter, UInt32 *nb_pac if (*nb_packets > frame->nb_samples) *nb_packets = frame->nb_samples; +av_frame_unref(at->encoding_frame); +if ((ret = av_frame_ref(at->encoding_frame, frame)) < 0) +return ret; + ff_bufqueue_add(avctx, &at->used_frame_queue, frame); return 0; @@ -565,6 +576,7 @@ static av_cold int ffat_close_encoder(AVCodecContext *avctx) ff_bufqueue_discard_all(&at->frame_queue); ff_bufqueue_discard_all(&at->used_frame_queue); ff_af_queue_close(&at->afq); +av_frame_free(&at->encoding_frame); return 0; } -- 2.14.3 (Apple Git-98) ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] [PATCH v4] lavc/audiotoolboxenc: fix noise in encoded audio
From: Jiejun Zhang This fixes #6940 Although undocumented, AudioToolbox seems to require the data supplied by the callback (i.e. ffat_encode_callback) being unchanged until the next time the callback is called. In the old implementation, the AVBuffer backing the frame is recycled after the frame is freed, and somebody else (maybe the decoder) will write into the AVBuffer and change the data. AudioToolbox then encodes some wrong data and noise is produced. Retaining a frame reference solves this problem. --- libavcodec/audiotoolboxenc.c | 14 ++ 1 file changed, 14 insertions(+) diff --git a/libavcodec/audiotoolboxenc.c b/libavcodec/audiotoolboxenc.c index 71885d1530..4d8130af96 100644 --- a/libavcodec/audiotoolboxenc.c +++ b/libavcodec/audiotoolboxenc.c @@ -48,6 +48,8 @@ typedef struct ATDecodeContext { AudioFrameQueue afq; int eof; int frame_size; + +AVFrame* encoding_frame; } ATDecodeContext; static UInt32 ffat_get_format_id(enum AVCodecID codec, int profile) @@ -442,6 +444,10 @@ static av_cold int ffat_init_encoder(AVCodecContext *avctx) ff_af_queue_init(avctx, &at->afq); +at->encoding_frame = av_frame_alloc(); +if (!at->encoding_frame) +return AVERROR(ENOMEM); + return 0; } @@ -453,6 +459,7 @@ static OSStatus ffat_encode_callback(AudioConverterRef converter, UInt32 *nb_pac AVCodecContext *avctx = inctx; ATDecodeContext *at = avctx->priv_data; AVFrame *frame; +int ret; if (!at->frame_queue.available) { if (at->eof) { @@ -475,6 +482,12 @@ static OSStatus ffat_encode_callback(AudioConverterRef converter, UInt32 *nb_pac if (*nb_packets > frame->nb_samples) *nb_packets = frame->nb_samples; +av_frame_unref(at->encoding_frame); +if ((ret = av_frame_ref(at->encoding_frame, frame)) < 0) { +*nb_packets = 0; +return ret; +} + ff_bufqueue_add(avctx, &at->used_frame_queue, frame); return 0; @@ -565,6 +578,7 @@ static av_cold int ffat_close_encoder(AVCodecContext *avctx) ff_bufqueue_discard_all(&at->frame_queue); ff_bufqueue_discard_all(&at->used_frame_queue); ff_af_queue_close(&at->afq); +av_frame_free(&at->encoding_frame); return 0; } -- 2.14.3 (Apple Git-98) ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel