|
|
|
@@ -93,6 +93,8 @@ typedef struct mkv_cues { |
|
|
|
typedef struct mkv_track { |
|
|
|
int write_dts; |
|
|
|
int has_cue; |
|
|
|
int sample_rate; |
|
|
|
int64_t sample_rate_offset; |
|
|
|
int64_t codecpriv_offset; |
|
|
|
int64_t ts_offset; |
|
|
|
} mkv_track; |
|
|
|
@@ -715,24 +717,40 @@ static int put_flac_codecpriv(AVFormatContext *s, |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static int get_aac_sample_rates(AVFormatContext *s, AVCodecParameters *par, |
|
|
|
static int get_aac_sample_rates(AVFormatContext *s, uint8_t *extradata, int extradata_size, |
|
|
|
int *sample_rate, int *output_sample_rate) |
|
|
|
{ |
|
|
|
MPEG4AudioConfig mp4ac; |
|
|
|
int ret; |
|
|
|
|
|
|
|
if (avpriv_mpeg4audio_get_config(&mp4ac, par->extradata, |
|
|
|
par->extradata_size * 8, 1) < 0) { |
|
|
|
ret = avpriv_mpeg4audio_get_config(&mp4ac, extradata, |
|
|
|
extradata_size * 8, 1); |
|
|
|
/* Don't abort if the failure is because of missing extradata. Assume in that |
|
|
|
* case a bitstream filter will provide the muxer with the extradata in the |
|
|
|
* first packet. |
|
|
|
* Abort however if s->pb is not seekable, as we would not be able to seek back |
|
|
|
* to write the sample rate elements once the extradata shows up, anyway. */ |
|
|
|
if (ret < 0 && (extradata_size || !(s->pb->seekable & AVIO_SEEKABLE_NORMAL))) { |
|
|
|
av_log(s, AV_LOG_ERROR, |
|
|
|
"Error parsing AAC extradata, unable to determine samplerate.\n"); |
|
|
|
return AVERROR(EINVAL); |
|
|
|
} |
|
|
|
|
|
|
|
*sample_rate = mp4ac.sample_rate; |
|
|
|
*output_sample_rate = mp4ac.ext_sample_rate; |
|
|
|
if (ret < 0) { |
|
|
|
/* This will only happen when this function is called while writing the |
|
|
|
* header and no extradata is available. The space for this element has |
|
|
|
* to be reserved for when this function is called again after the |
|
|
|
* extradata shows up in the first packet, as there's no way to know if |
|
|
|
* output_sample_rate will be different than sample_rate or not. */ |
|
|
|
*output_sample_rate = *sample_rate; |
|
|
|
} else { |
|
|
|
*sample_rate = mp4ac.sample_rate; |
|
|
|
*output_sample_rate = mp4ac.ext_sample_rate; |
|
|
|
} |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static int mkv_write_native_codecprivate(AVFormatContext *s, |
|
|
|
static int mkv_write_native_codecprivate(AVFormatContext *s, AVIOContext *pb, |
|
|
|
AVCodecParameters *par, |
|
|
|
AVIOContext *dyn_cp) |
|
|
|
{ |
|
|
|
@@ -761,6 +779,12 @@ static int mkv_write_native_codecprivate(AVFormatContext *s, |
|
|
|
avio_write(dyn_cp, par->extradata + 12, |
|
|
|
par->extradata_size - 12); |
|
|
|
break; |
|
|
|
case AV_CODEC_ID_AAC: |
|
|
|
if (par->extradata_size) |
|
|
|
avio_write(dyn_cp, par->extradata, par->extradata_size); |
|
|
|
else |
|
|
|
put_ebml_void(pb, MAX_PCE_SIZE + 2 + 4); |
|
|
|
break; |
|
|
|
default: |
|
|
|
if (par->codec_id == AV_CODEC_ID_PRORES && |
|
|
|
ff_codec_get_id(ff_codec_movvideo_tags, par->codec_tag) == AV_CODEC_ID_PRORES) { |
|
|
|
@@ -785,7 +809,7 @@ static int mkv_write_codecprivate(AVFormatContext *s, AVIOContext *pb, |
|
|
|
return ret; |
|
|
|
|
|
|
|
if (native_id) { |
|
|
|
ret = mkv_write_native_codecprivate(s, par, dyn_cp); |
|
|
|
ret = mkv_write_native_codecprivate(s, pb, par, dyn_cp); |
|
|
|
} else if (par->codec_type == AVMEDIA_TYPE_VIDEO) { |
|
|
|
if (qt_id) { |
|
|
|
if (!par->codec_tag) |
|
|
|
@@ -1175,7 +1199,8 @@ static int mkv_write_track(AVFormatContext *s, MatroskaMuxContext *mkv, |
|
|
|
} |
|
|
|
|
|
|
|
if (par->codec_id == AV_CODEC_ID_AAC) { |
|
|
|
ret = get_aac_sample_rates(s, par, &sample_rate, &output_sample_rate); |
|
|
|
ret = get_aac_sample_rates(s, par->extradata, par->extradata_size, &sample_rate, |
|
|
|
&output_sample_rate); |
|
|
|
if (ret < 0) |
|
|
|
return ret; |
|
|
|
} |
|
|
|
@@ -1370,6 +1395,8 @@ static int mkv_write_track(AVFormatContext *s, MatroskaMuxContext *mkv, |
|
|
|
|
|
|
|
subinfo = start_ebml_master(pb, MATROSKA_ID_TRACKAUDIO, 0); |
|
|
|
put_ebml_uint (pb, MATROSKA_ID_AUDIOCHANNELS , par->channels); |
|
|
|
|
|
|
|
mkv->tracks[i].sample_rate_offset = avio_tell(pb); |
|
|
|
put_ebml_float (pb, MATROSKA_ID_AUDIOSAMPLINGFREQ, sample_rate); |
|
|
|
if (output_sample_rate) |
|
|
|
put_ebml_float(pb, MATROSKA_ID_AUDIOOUTSAMPLINGFREQ, output_sample_rate); |
|
|
|
@@ -2233,6 +2260,37 @@ static int mkv_check_new_extra_data(AVFormatContext *s, AVPacket *pkt) |
|
|
|
&side_data_size); |
|
|
|
|
|
|
|
switch (par->codec_id) { |
|
|
|
case AV_CODEC_ID_AAC: |
|
|
|
if (side_data_size && (s->pb->seekable & AVIO_SEEKABLE_NORMAL) && !mkv->is_live) { |
|
|
|
int filler, output_sample_rate = 0; |
|
|
|
int64_t curpos; |
|
|
|
ret = get_aac_sample_rates(s, side_data, side_data_size, &track->sample_rate, |
|
|
|
&output_sample_rate); |
|
|
|
if (ret < 0) |
|
|
|
return ret; |
|
|
|
if (!output_sample_rate) |
|
|
|
output_sample_rate = track->sample_rate; // Space is already reserved, so it's this or a void element. |
|
|
|
av_freep(&par->extradata); |
|
|
|
ret = ff_alloc_extradata(par, side_data_size); |
|
|
|
if (ret < 0) |
|
|
|
return ret; |
|
|
|
memcpy(par->extradata, side_data, side_data_size); |
|
|
|
curpos = avio_tell(mkv->tracks_bc); |
|
|
|
avio_seek(mkv->tracks_bc, track->codecpriv_offset, SEEK_SET); |
|
|
|
mkv_write_codecprivate(s, mkv->tracks_bc, par, 1, 0); |
|
|
|
filler = MAX_PCE_SIZE + 2 + 4 - (avio_tell(mkv->tracks_bc) - track->codecpriv_offset); |
|
|
|
if (filler) |
|
|
|
put_ebml_void(mkv->tracks_bc, filler); |
|
|
|
avio_seek(mkv->tracks_bc, track->sample_rate_offset, SEEK_SET); |
|
|
|
put_ebml_float(mkv->tracks_bc, MATROSKA_ID_AUDIOSAMPLINGFREQ, track->sample_rate); |
|
|
|
put_ebml_float(mkv->tracks_bc, MATROSKA_ID_AUDIOOUTSAMPLINGFREQ, output_sample_rate); |
|
|
|
avio_seek(mkv->tracks_bc, curpos, SEEK_SET); |
|
|
|
} else if (!par->extradata_size && !track->sample_rate) { |
|
|
|
// No extradata (codecpar or packet side data). |
|
|
|
av_log(s, AV_LOG_ERROR, "Error parsing AAC extradata, unable to determine samplerate.\n"); |
|
|
|
return AVERROR(EINVAL); |
|
|
|
} |
|
|
|
break; |
|
|
|
case AV_CODEC_ID_FLAC: |
|
|
|
if (side_data_size && (s->pb->seekable & AVIO_SEEKABLE_NORMAL) && !mkv->is_live) { |
|
|
|
AVCodecParameters *codecpriv_par; |
|
|
|
|