summaryrefslogtreecommitdiffstats
path: root/libavformat/matroskaenc.c
diff options
context:
space:
mode:
authorJames Almer <jamrial@gmail.com>2016-11-09 18:38:23 -0300
committerAnton Khirnov <anton@khirnov.net>2016-11-10 09:01:18 +0100
commitf4bf236338f6001736a4784b9c23de863057a583 (patch)
tree5818ea93e38c27f5bf9709af1c1f101120aeb895 /libavformat/matroskaenc.c
parent84f225684cd389747907381122c073aa1c8b6bf1 (diff)
downloadffmpeg-streaming-f4bf236338f6001736a4784b9c23de863057a583.zip
ffmpeg-streaming-f4bf236338f6001736a4784b9c23de863057a583.tar.gz
matroskaenc: fix muxing AAC streams when using aac_adtstoasc bsf
aac_adtstoasc makes the aac extradata available only after the first packet is filtered, and as packet side data. Assume extradata will be available as part of the first packet if avpriv_mpeg4audio_get_config() fails the first time due to missing extradata and reserve space for the OutputSampleRate element in the Tracks master. Signed-off-by: James Almer <jamrial@gmail.com> Signed-off-by: Anton Khirnov <anton@khirnov.net>
Diffstat (limited to 'libavformat/matroskaenc.c')
-rw-r--r--libavformat/matroskaenc.c80
1 files changed, 74 insertions, 6 deletions
diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c
index cfced72..5593237 100644
--- a/libavformat/matroskaenc.c
+++ b/libavformat/matroskaenc.c
@@ -81,6 +81,8 @@ typedef struct mkv_cues {
typedef struct mkv_track {
int write_dts;
+ int sample_rate;
+ int64_t sample_rate_offset;
int64_t ts_offset;
} mkv_track;
@@ -521,20 +523,36 @@ 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;
}
@@ -790,7 +808,8 @@ static int mkv_write_track(AVFormatContext *s, MatroskaMuxContext *mkv,
bit_depth = av_get_bytes_per_sample(par->format) << 3;
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;
}
@@ -890,6 +909,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);
@@ -909,6 +930,7 @@ static int mkv_write_track(AVFormatContext *s, MatroskaMuxContext *mkv,
av_log(s, AV_LOG_ERROR, "Only audio, video, and subtitles are supported for Matroska.\n");
break;
}
+
ret = mkv_write_codecprivate(s, pb, par, native_id, qt_id);
if (ret < 0)
return ret;
@@ -1531,6 +1553,48 @@ static void mkv_flush_dynbuf(AVFormatContext *s)
mkv->dyn_bc = NULL;
}
+static int mkv_check_new_extra_data(AVFormatContext *s, AVPacket *pkt)
+{
+ MatroskaMuxContext *mkv = s->priv_data;
+ AVCodecParameters *par = s->streams[pkt->stream_index]->codecpar;
+ mkv_track *track = &mkv->tracks[pkt->stream_index];
+ uint8_t *side_data;
+ int side_data_size = 0, ret;
+
+ side_data = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA,
+ &side_data_size);
+
+ switch (par->codec_id) {
+ case AV_CODEC_ID_AAC:
+ if (side_data_size && (s->pb->seekable & AVIO_SEEKABLE_NORMAL)) {
+ int 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.
+ curpos = avio_tell(s->pb);
+ avio_seek(s->pb, track->sample_rate_offset, SEEK_SET);
+ put_ebml_float(s->pb, MATROSKA_ID_AUDIOSAMPLINGFREQ, track->sample_rate);
+ put_ebml_float(s->pb, MATROSKA_ID_AUDIOOUTSAMPLINGFREQ, output_sample_rate);
+ avio_seek(s->pb, 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;
+ default:
+ if (side_data_size)
+ av_log(s, AV_LOG_DEBUG, "Ignoring new extradata in a packet for stream %d.\n", pkt->stream_index);
+ break;
+ }
+
+ return 0;
+}
+
static int mkv_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
{
MatroskaMuxContext *mkv = s->priv_data;
@@ -1605,6 +1669,10 @@ static int mkv_write_packet(AVFormatContext *s, AVPacket *pkt)
AVIOContext *pb;
int ret;
+ ret = mkv_check_new_extra_data(s, pkt);
+ if (ret < 0)
+ return ret;
+
if (mkv->tracks[pkt->stream_index].write_dts)
cluster_time = pkt->dts - mkv->cluster_pts;
else
OpenPOWER on IntegriCloud