We're encoding video into H264 and raw PCM samples into AAC for HLS streaming. The video works fine, but having trouble configuring the AAC encoder in libavcodec.
This SO question says:
There are two ways to put AAC into transport stream.
1. Using ADTS syntax (MPEG2-style).
In a such case PMT's stream_type should be specified as 0x0F (ISO/IEC 13818-7 Audio with ADTS transport syntax).
So, you are limited to using "old" (MPEG2) AAC versions only, without SBR and PS.
2. Using LATM+LOAS/AudioSyncStream syntax (MPEG4-style).
In a such case PMT's stream_type should be specified as 0x11 (ISO/IEC 14496-3 Audio with the LATM transport syntax).
And you can use all the force of "new" (MPEG4) AAC features, including SBR and PS.
Furthermore, DVB standard ETSI TS 101 154 demands: HEv1/HEv2 AAC shall be transmitted using LATM syntax.
But after a lot of searching I cannot find any documentation on how to do either of these. What is missing from the configuration below to get the encoded audio with either ADTS or LATM before it is passed to the MPEG-TS mux (for output to HLS)?
The current code to set up the AAC codec gives the error [mpegts @ 0x7fc4c00343c0] AAC bitstream not in ADTS format and extradata missing
The AAC encoder setup (error checking removed for brevity)
/// Set up Encoder ///
mpAudioCodec = avcodec_find_encoder(AV_CODEC_ID_AAC);
mpAudioCodecContext = avcodec_alloc_context3(mpAudioCodec);
mpAudioCodecContext->bit_rate = DEFAULT_AUD_BITRATE;
mpAudioCodecContext->sample_rate = DEFAULT_AUD_SAMPLE_RATE;
mpAudioCodecContext->channel_layout = DEFAULT_AUD_CHAN_LAYOUT;
mpAudioCodecContext->channels = 2;
mpAudioCodecContext->sample_fmt = AV_SAMPLE_FMT_FLTP; // S16 not supported. Must convert
mpAudioCodecContext->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
rc = avcodec_open2(mpAudioCodecContext, mpAudioCodec, 0);
HLS MUX SETUP
avformat_alloc_output_context2(&mpOutputMux, 0, "hls", path.c_str());
// VIDEO TRACK
mpVideoTrack = avformat_new_stream(mpOutputMux, 0);
mpVideoTrack->id = 0;
mpVideoTrack->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
mpVideoTrack->codecpar->codec_id = AV_CODEC_ID_H264;
mpVideoTrack->time_base = (AVRational) { 1, mFrameRate };
mpVideoTrack->avg_frame_rate = (AVRational) { mFrameRate, 1 };
// AUDIO TRACK
mpAudioTrack = avformat_new_stream(mpOutputMux, 0);
mpAudioTrack->id = 1;
mpAudioTrack->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
mpAudioTrack->codecpar->codec_id = DEFAULT_AUDIO_CODEC;
mpAudioTrack->codecpar->sample_rate = mpAudioCodecContext->sample_rate;
mpAudioTrack->time_base.den = mpAudioCodecContext->sample_rate;
mpAudioTrack->time_base.num = 1;
AVDictionary *hlsOptions = NULL;
av_dict_set(&hlsOptions, "hls_segment_type", "mpegts", 0);
av_dict_set(&hlsOptions, "segment_list_type", "m3u8", 0);
av_dict_set_int(&hlsOptions, "hls_list_size", mPlaylistSize, 0);
av_dict_set_int(&hlsOptions, "hls_time", mChunkDurSec, 0);
av_dict_set(&hlsOptions, "hls_flags", "delete_segments", 0);
av_dict_set(&hlsOptions, "hls_segment_filename", segPath.c_str(), 0);
av_dict_set_int(&hlsOptions, "reference_stream", mpVideoTrack->index, 0);
av_dict_set(&hlsOptions, "segment_list_flags", "cache+live", 0);
int ret = avformat_write_header(mpOutputMux, &hlsOptions);
Encode Loop
int bytesCopied = mAudEsBuffer.popData(mpPcmS16Buf, mpPcmAudioFrame->nb_samples);
// resample to float
int rc = swr_convert(mpAudioResampleCtx, mpPcmAudioFrame->data, mpPcmAudioFrame->nb_samples, (const uint8_t**) &mpPcmS16Buf, mpPcmAudioFrame->nb_samples);
/* Set a timestamp based on the sample rate for the container. */
mCurAudPts += mpPcmAudioFrame->nb_samples;
mpPcmAudioFrame->pts = mCurAudPts;
// send frame for encoding to AAC
rc = avcodec_send_frame(mpAudioCodecContext, mpPcmAudioFrame);
/* read all the available output packets (in general there may be any number of them */
while (rc >= 0)
{
// need to init packet every time??
/* Set the packet data and size so that it is recognized as being empty. */
av_init_packet(mpEncAudioPacket);
mpEncAudioPacket->data = NULL;
mpEncAudioPacket->size = 0;
rc = avcodec_receive_packet(mpAudioCodecContext, mpEncAudioPacket);
if (rc < 0)
{
printf("TqHlsLib::readAndMuxAudio() - Error encoding audio frame: %s\n", av_make_error_string(mpErr, TQERRLEN, rc));
return HLS_DEC_ERROR;
}
TRACE(("%T %t TqHlsLib::readAndMuxAudio() - Got an encoded audio packet. %u bytes\n",
mpEncAudioPacket->size ));
/* rescale output packet timestamp values from codec to stream timebase */
av_packet_rescale_ts(mpEncAudioPacket, mpAudioTrack->time_base, mpAudioTrack->time_base);
mpEncAudioPacket->stream_index = mpAudioTrack->index;
/* Write the compressed frame to the media file. */
rc = av_interleaved_write_frame(mpOutputMux, mpEncAudioPacket);
if (rc < 0)
{
fprintf(stderr, "TqHlsLib::addVideoH264Packet - Error while writing audio packet: %s\n",
av_make_error_string(mpErr, TQERRLEN, ret));
// return some error here
}
av_packet_unref(mpEncAudioPacket);
}
The Output
[mpegts @ 0x7fb280144e00] AAC bitstream not in ADTS format and extradata missing
20:24:52.327418 24388 TqHlsLib::readAndMuxAudio() - Got an encoded audio packet. 185 bytes
[mpegts @ 0x7fb280144e00] AAC bitstream not in ADTS format and extradata missing
20:24:52.372975 24388 TqHlsLib::readAndMuxAudio() - Got an encoded audio packet. 188 bytes
[mpegts @ 0x7fb280144e00] AAC bitstream not in ADTS format and extradata missing