[Libav-user] FMP4 -> ADTS/AAC using libavformat/libavcodec

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

[Libav-user] FMP4 -> ADTS/AAC using libavformat/libavcodec

libav-users mailing list
Hi,

I’m writing a C++ program to validate the integrity of a Fragmented MP4 file containing AAC audio.
This program would parse the FMP4 file, read each audio packet, attachment ADTS headers, and then try to decode the AAC using libfdk_aac.

I am using libavformat, and I am able to parse the MP4 atoms correctly, however I’m having issues figuring out the best way to attach the ADTS headers.

My current idea is to use a libavformat mp4 demuxed and send that to an adts muxer. I’ve written all the code to do it now; but I’m now getting errors like so:

[adts @ 0x7fae51001600] MPEG-4 AOT 0 is not allowed in ADTS

I’m not sure what to do now.

My code is as below:

AudioAssetReader::AudioAssetReader(const AudioAssetReaderInput &input) throw (invalid_argument):
input(input), segmentsIter(input.getBeginSegmentsIter()), audioBufferSize(409600), adtsPacketBufferSize(409600) {
if (input.getSegments()->empty()) {
throw invalid_argument("A reader must read at least 1 segment of audio!");
}

this->audioBuffer = new uint8_t[audioBufferSize];

// create the main context used to parse the audio asset, segment by segment
bool isBufferWritable = false;
this->assetSegmentReaderContext = avio_alloc_context(this->audioBuffer, this->audioBufferSize, isBufferWritable, this, AudioAssetReader::readSegment, NULL, NULL);
this->assetParsingContext = avformat_alloc_context();
this->assetParsingContext->pb = this->assetSegmentReaderContext;
this->assetParsingContext->flags = AVFMT_FLAG_CUSTOM_IO;

// create another context used to append ADTS headers to the parsed segments, if we need them
this->initializeADTSMuxerContext(input);
}

void AudioAssetReader::initializeADTSMuxerContext(const AudioAssetReaderInput &input) {

this->adtsPacketBuffer = new uint8_t[adtsPacketBufferSize];
this->adtsPacket = av_packet_alloc();

// create another context used to append ADTS headers to the parsed segments, if we need them
bool isBufferWritable = true;
avformat_alloc_output_context2(&this->adtsMuxerContext, NULL, "adts", NULL);
this->adtsMuxerWriterContext = avio_alloc_context(this->adtsPacketBuffer, this->adtsPacketBufferSize, isBufferWritable, this, NULL, AudioAssetReader::writeADTSPacket, NULL);
this->adtsMuxerContext->pb = this->adtsMuxerWriterContext;

// initialize an ADTS stream
AVCodecID aacCodec = AVCodecID::AV_CODEC_ID_AAC;
AVCodec *codec = avcodec_find_encoder(aacCodec);
AVStream *stream = avformat_new_stream(this->adtsMuxerContext, codec);
stream->id = this->adtsMuxerContext->nb_streams - 1;
stream->time_base.den = input.getSampleRateHz();
stream->time_base.num = 1;

// configure the stream with the details of the AAC packets
AVCodecParameters *codecParameters = stream->codecpar;
codecParameters->codec_id = aacCodec;
codecParameters->bit_rate = input.getBitrateBps();
codecParameters->profile = this->getAACProfileForCodec(input.getCodec());
codecParameters->sample_rate = input.getSampleRateHz();
codecParameters->channels = input.getChannelCount();
codecParameters->codec_type = AVMEDIA_TYPE_AUDIO;
codecParameters->channel_layout = av_get_default_channel_layout(input.getChannelCount());

uint8_t* header = new uint8_t[7];
memset(header, 1, 7);
//header[3] = 2 << 6;

codecParameters->extradata = header;
codecParameters->extradata_size = 7;

// write out a header to the muxer; this is a no-op for our purposes
const int result = avformat_write_header(this->adtsMuxerContext, NULL);
if (result < 0) {
char *message = new char[AV_ERROR_MAX_STRING_SIZE];
av_make_error_string(message, AV_ERROR_MAX_STRING_SIZE, result);
cerr<<endl<<"Failed to write the ADTS muxer header due to: "<<result<<": "<<message<<endl;
delete[] message;
}
}

Ronak

_______________________________________________
Libav-user mailing list
[hidden email]
https://ffmpeg.org/mailman/listinfo/libav-user

To unsubscribe, visit link above, or email
[hidden email] with subject "unsubscribe".
Reply | Threaded
Open this post in threaded view
|

Re: FMP4 -> ADTS/AAC using libavformat/libavcodec

libav-users mailing list
I am in a time crunch and would appreciate a prompt reply for this…I’m amazed that it is this complicated to append an ADTS header to MPEG4 Audio.


On Oct 3, 2019, at 5:44 PM, Ronak via Libav-user <[hidden email]> wrote:

Hi,

I’m writing a C++ program to validate the integrity of a Fragmented MP4 file containing AAC audio.
This program would parse the FMP4 file, read each audio packet, attachment ADTS headers, and then try to decode the AAC using libfdk_aac.

I am using libavformat, and I am able to parse the MP4 atoms correctly, however I’m having issues figuring out the best way to attach the ADTS headers.

My current idea is to use a libavformat mp4 demuxed and send that to an adts muxer. I’ve written all the code to do it now; but I’m now getting errors like so:

[adts @ 0x7fae51001600] MPEG-4 AOT 0 is not allowed in ADTS

I’m not sure what to do now.

My code is as below:

AudioAssetReader::AudioAssetReader(const AudioAssetReaderInput &input) throw (invalid_argument):
input(input), segmentsIter(input.getBeginSegmentsIter()), audioBufferSize(409600), adtsPacketBufferSize(409600) {
if (input.getSegments()->empty()) {
throw invalid_argument("A reader must read at least 1 segment of audio!");
}

this->audioBuffer = new uint8_t[audioBufferSize];

// create the main context used to parse the audio asset, segment by segment
bool isBufferWritable = false;
this->assetSegmentReaderContext = avio_alloc_context(this->audioBuffer, this->audioBufferSize, isBufferWritable, this, AudioAssetReader::readSegment, NULL, NULL);
this->assetParsingContext = avformat_alloc_context();
this->assetParsingContext->pb = this->assetSegmentReaderContext;
this->assetParsingContext->flags = AVFMT_FLAG_CUSTOM_IO;

// create another context used to append ADTS headers to the parsed segments, if we need them
this->initializeADTSMuxerContext(input);
}

void AudioAssetReader::initializeADTSMuxerContext(const AudioAssetReaderInput &input) {

this->adtsPacketBuffer = new uint8_t[adtsPacketBufferSize];
this->adtsPacket = av_packet_alloc();

// create another context used to append ADTS headers to the parsed segments, if we need them
bool isBufferWritable = true;
avformat_alloc_output_context2(&this->adtsMuxerContext, NULL, "adts", NULL);
this->adtsMuxerWriterContext = avio_alloc_context(this->adtsPacketBuffer, this->adtsPacketBufferSize, isBufferWritable, this, NULL, AudioAssetReader::writeADTSPacket, NULL);
this->adtsMuxerContext->pb = this->adtsMuxerWriterContext;

// initialize an ADTS stream
AVCodecID aacCodec = AVCodecID::AV_CODEC_ID_AAC;
AVCodec *codec = avcodec_find_encoder(aacCodec);
AVStream *stream = avformat_new_stream(this->adtsMuxerContext, codec);
stream->id = this->adtsMuxerContext->nb_streams - 1;
stream->time_base.den = input.getSampleRateHz();
stream->time_base.num = 1;

// configure the stream with the details of the AAC packets
AVCodecParameters *codecParameters = stream->codecpar;
codecParameters->codec_id = aacCodec;
codecParameters->bit_rate = input.getBitrateBps();
codecParameters->profile = this->getAACProfileForCodec(input.getCodec());
codecParameters->sample_rate = input.getSampleRateHz();
codecParameters->channels = input.getChannelCount();
codecParameters->codec_type = AVMEDIA_TYPE_AUDIO;
codecParameters->channel_layout = av_get_default_channel_layout(input.getChannelCount());

uint8_t* header = new uint8_t[7];
memset(header, 1, 7);
//header[3] = 2 << 6;

codecParameters->extradata = header;
codecParameters->extradata_size = 7;

// write out a header to the muxer; this is a no-op for our purposes
const int result = avformat_write_header(this->adtsMuxerContext, NULL);
if (result < 0) {
char *message = new char[AV_ERROR_MAX_STRING_SIZE];
av_make_error_string(message, AV_ERROR_MAX_STRING_SIZE, result);
cerr<<endl<<"Failed to write the ADTS muxer header due to: "<<result<<": "<<message<<endl;
delete[] message;
}
}

Ronak
_______________________________________________
Libav-user mailing list
[hidden email]
https://ffmpeg.org/mailman/listinfo/libav-user

To unsubscribe, visit link above, or email
[hidden email] with subject "unsubscribe".


_______________________________________________
Libav-user mailing list
[hidden email]
https://ffmpeg.org/mailman/listinfo/libav-user

To unsubscribe, visit link above, or email
[hidden email] with subject "unsubscribe".
Reply | Threaded
Open this post in threaded view
|

Re: FMP4 -> ADTS/AAC using libavformat/libavcodec

libav-users mailing list


On Oct 3, 2019, at 6:22 PM, Ronak via Libav-user <[hidden email]> wrote:

I am in a time crunch and would appreciate a prompt reply for this…I’m amazed that it is this complicated to append an ADTS header to MPEG4 Audio.

So it looks like I need to make an MPEG4 AudioSpecificConfig.

However I wonder what’s the point of using this muxer if I have to do that. I already specified all the parameters in the CodecParameters struct.

I’m thinking of abandoning FFmpeg to write the adts header and just do this myself.

This is just too complicated of a public api with too little documentation which provides almost no value.

There isn’t even a public helper function I can call to make that AudioSpecificConfig.

I would suggest these apis be added to Ffmpeg to make this a lot easier. If these apis already exist; I would suggest they be documented MUCH better.



On Oct 3, 2019, at 5:44 PM, Ronak via Libav-user <[hidden email]> wrote:

Hi,

I’m writing a C++ program to validate the integrity of a Fragmented MP4 file containing AAC audio.
This program would parse the FMP4 file, read each audio packet, attachment ADTS headers, and then try to decode the AAC using libfdk_aac.

I am using libavformat, and I am able to parse the MP4 atoms correctly, however I’m having issues figuring out the best way to attach the ADTS headers.

My current idea is to use a libavformat mp4 demuxed and send that to an adts muxer. I’ve written all the code to do it now; but I’m now getting errors like so:

[adts @ 0x7fae51001600] MPEG-4 AOT 0 is not allowed in ADTS

I’m not sure what to do now.

My code is as below:

AudioAssetReader::AudioAssetReader(const AudioAssetReaderInput &input) throw (invalid_argument):
input(input), segmentsIter(input.getBeginSegmentsIter()), audioBufferSize(409600), adtsPacketBufferSize(409600) {
if (input.getSegments()->empty()) {
throw invalid_argument("A reader must read at least 1 segment of audio!");
}

this->audioBuffer = new uint8_t[audioBufferSize];

// create the main context used to parse the audio asset, segment by segment
bool isBufferWritable = false;
this->assetSegmentReaderContext = avio_alloc_context(this->audioBuffer, this->audioBufferSize, isBufferWritable, this, AudioAssetReader::readSegment, NULL, NULL);
this->assetParsingContext = avformat_alloc_context();
this->assetParsingContext->pb = this->assetSegmentReaderContext;
this->assetParsingContext->flags = AVFMT_FLAG_CUSTOM_IO;

// create another context used to append ADTS headers to the parsed segments, if we need them
this->initializeADTSMuxerContext(input);
}

void AudioAssetReader::initializeADTSMuxerContext(const AudioAssetReaderInput &input) {

this->adtsPacketBuffer = new uint8_t[adtsPacketBufferSize];
this->adtsPacket = av_packet_alloc();

// create another context used to append ADTS headers to the parsed segments, if we need them
bool isBufferWritable = true;
avformat_alloc_output_context2(&this->adtsMuxerContext, NULL, "adts", NULL);
this->adtsMuxerWriterContext = avio_alloc_context(this->adtsPacketBuffer, this->adtsPacketBufferSize, isBufferWritable, this, NULL, AudioAssetReader::writeADTSPacket, NULL);
this->adtsMuxerContext->pb = this->adtsMuxerWriterContext;

// initialize an ADTS stream
AVCodecID aacCodec = AVCodecID::AV_CODEC_ID_AAC;
AVCodec *codec = avcodec_find_encoder(aacCodec);
AVStream *stream = avformat_new_stream(this->adtsMuxerContext, codec);
stream->id = this->adtsMuxerContext->nb_streams - 1;
stream->time_base.den = input.getSampleRateHz();
stream->time_base.num = 1;

// configure the stream with the details of the AAC packets
AVCodecParameters *codecParameters = stream->codecpar;
codecParameters->codec_id = aacCodec;
codecParameters->bit_rate = input.getBitrateBps();
codecParameters->profile = this->getAACProfileForCodec(input.getCodec());
codecParameters->sample_rate = input.getSampleRateHz();
codecParameters->channels = input.getChannelCount();
codecParameters->codec_type = AVMEDIA_TYPE_AUDIO;
codecParameters->channel_layout = av_get_default_channel_layout(input.getChannelCount());

uint8_t* header = new uint8_t[7];
memset(header, 1, 7);
//header[3] = 2 << 6;

codecParameters->extradata = header;
codecParameters->extradata_size = 7;

// write out a header to the muxer; this is a no-op for our purposes
const int result = avformat_write_header(this->adtsMuxerContext, NULL);
if (result < 0) {
char *message = new char[AV_ERROR_MAX_STRING_SIZE];
av_make_error_string(message, AV_ERROR_MAX_STRING_SIZE, result);
cerr<<endl<<"Failed to write the ADTS muxer header due to: "<<result<<": "<<message<<endl;
delete[] message;
}
}

Ronak
_______________________________________________
Libav-user mailing list
[hidden email]
https://ffmpeg.org/mailman/listinfo/libav-user

To unsubscribe, visit link above, or email
[hidden email] with subject "unsubscribe".

_______________________________________________
Libav-user mailing list
[hidden email]
https://ffmpeg.org/mailman/listinfo/libav-user

To unsubscribe, visit link above, or email
[hidden email] with subject "unsubscribe".

_______________________________________________
Libav-user mailing list
[hidden email]
https://ffmpeg.org/mailman/listinfo/libav-user

To unsubscribe, visit link above, or email
[hidden email] with subject "unsubscribe".