#define AUDIO_AAC_ADTS_LEN 7
#define FILE_PATH_LENGTH 64
int set_acc_adts_header(uint8_t *header, int packet_len)
{
int profile = 2; //AAC LC,MediaCodecInfo.CodecProfileLevel.AACObjectLC;
int freqIdx = 4; //32K, 见后面注释avpriv_mpeg4audio_sample_rates中32000对应的数组下标,来自ffmpeg源码
int chanCfg = 2; //见后面注释channel_configuration,Stero双声道立体声
/*int avpriv_mpeg4audio_sample_rates[] = {
96000, 88200, 64000, 48000, 44100, 32000,
24000, 22050, 16000, 12000, 11025, 8000, 7350
};
channel_configuration: 表示声道数chanCfg
0: Defined in AOT Specifc Config
1: 1 channel: front-center
2: 2 channels: front-left, front-right
3: 3 channels: front-center, front-left, front-right
4: 4 channels: front-center, front-left, front-right, back-center
5: 5 channels: front-center, front-left, front-right, back-left, back-right
6: 6 channels: front-center, front-left, front-right, back-left, back-right, LFE-channel
7: 8 channels: front-center, front-left, front-right, side-left, side-right, back-left, back-right, LFE-channel
8-15: Reserved
*/
//Fill in ADTS data
header[0] = (uint8_t)0xFF;
header[1] = (uint8_t)0xF1;
header[2] = (uint8_t)(((profile - 1) << 6) + (freqIdx << 2) + (chanCfg >> 2));
header[3] = (uint8_t)(((chanCfg & 3) << 6) + (packet_len >> 11));
header[4] = (uint8_t)((packet_len & 0x7FF) >> 3);
header[5] = (uint8_t)(((packet_len & 7) << 5) + 0x1F);
header[6] = (uint8_t)0xFC;
return 0;
}
int main()
{
AVFormatContext* format_context_p = NULL; //ffmpeg文件管理器
AVPacket pkt;
AVCodecContext* codec_context_p = NULL;
AVBitStreamFilterContext* bit_stream_filter_p = NULL;
int read_ret = 0;
int video_index = -1;
int audio_index = -1;
int err_no;
int ff_ret;
char address[FILE_PATH_LENGTH] = "D://TEST.mp4"
char adts_head[AUDIO_AAC_ADTS_LEN]
unsigned char* begin_p = NULL;
av_register_all();
//打开文件
err_no = avformat_open_input(&format_context_p, address, 0, 0);
if (err_no < 0) {
printf("avformat_open_input() error [%d].\n", err_no);
return -1;
}
//找到流信息
err_no = avformat_find_stream_info(format_context_p, 0);
if (err_no < 0) {
printf("avformat_find_stream_info() error [%d].\n", err_no);
return -1;
}
av_dump_format(format_context_p, 0, format_context_p->filename, 0);
//获取视频索引
for (unsigned int i = 0; i < format_context_p->nb_streams; i++) {
if (format_context_p->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
video_index = i;
break;
}
}
//获取音频索引
for (unsigned int i = 0; i < format_context_p->nb_streams; i++) {
if (format_context_p->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
audio_index = i;
break;
}
}
//获取音频编码
if (audio_index == -1 && video_index == -1) {
printf("%s\n", "can not find audio or video codec index error.");
return -1;
}
if (video_index >= 0) {
//mp4中read出来的帧数据并非标准的H264 nal数据,需要filter过滤
bit_stream_filter_p = av_bitstream_filter_init("h264_mp4toannexb");
if (!bit_stream_filter_p) {
printf("%s\n", "av_bitstream_filter_init() error");
return -1;
}
}
//初始化pkt
av_init_packet(&pkt);
//读取帧数据
while(1) {
read_ret = av_read_frame(format_context_p, &pkt);
if (read_ret == AVERROR_EOF) {
/*
说明:格式为mp4、avi等封装格式可以使用seek接口定位到指定位置
但如果是一个H264等源码流的文件无法使用,需要重新初始化format_context
*/
//如果起始时间戳可用
if (format_context_p->streams[video_index]->start_time >= 0) {
read_ret = av_seek_frame(format_context_p, video_index, format_context_p->streams[video_index]->start_time, 0);
if (read_ret >= 0) {
continue;
}
} else {
break;
}
}
if (read_ret < 0) {
printf("av_read_frame() error [%d].", read_ret);
break;
}
if (pkt.stream_index == video_index) {
//视频流
codec_context_p = format_context_p->streams[video_index]->codec;
/*
说明:av_bitstream_filter_filter()函数,根据返回值判断资源的回收
返回值 = 0,没有开辟新的内存空间,pkt.data仍然指向pkt.buf->data
返回值 > 0, 重新开辟了新的内存空间,pkt.data为指针,pkt.size为长度
返回值 < 0, 这种情况可能需要放弃掉该帧数据
*/
ff_ret = av_bitstream_filter_filter(bit_stream_filter_p, codec_context_p, NULL, &pkt.data, &pkt.size, pkt.data, pkt.size, 0);
if (ff_ret >= 0) {
begin_p = pkt.data;
rd_len = pkt.size;
}
//视频帧数据以及长度,保存文件后可以使用H264VISTA查看帧数据的正确性
begin_p;
rd_len;
//分配了新的pkt->data空间,使用后销毁
if (ff_ret > 0 && pkt.size > 0){
av_free(pkt.data);
}
} else if (pkt.stream_index == audio_index) {
//音频流
/*
说明:当音频编码格式为AAC时,是缺少ADTS头信息的,
创建ADTS头
*/
if (format_context_p->streams[audio_index]->codec->codec_id == AV_CODEC_ID_AAC) {
set_acc_adts_header(adts_head, pkt.size + CSS_MEDIA_CHANNEL_MEDIA_AUDIO_AAC_ATDS_LEN);
//拼装音频数据ADTS+pkt.data
} else {
//音频数据,保存文件后使用播放器播放
}
}
av_free_packet(&pkt);
}
if (bit_stream_filter_p) {
av_bitstream_filter_close(bit_stream_filter_p);
}
if(format_context_p) {
avformat_close_input(&format_context_p);
}
return 0;
}