用ffmpeg代码打开mp4,读取后分离出其中的aac包,依次写入一个文件audio.aac中,然后播放无音频,出错。把编码后的aac放入.aac容器后,并没有包含这些音频的信息,比如声道数,采样率等,因此播放器就不知道如何播放它。在每个包写入前,都需要写入adts头。之后播放成功。
adts头有7个字节,按位描述音频信息,获取adts头需要自己编个函数,把描述信息写进这7位数据。后附代码和完整用法,需要根据自己的音频信息改下配置参数。
概括用法如下:
char adts_buf[7];
adts_header(adts_buf, pkt.size);
fwrite(adts_buf, 1, 7, fd);//将adts头写入文件
fwrite(pkt.data, 1, pkt.size, fd);//将音频数据写入文件。
更多关于adts每位代表什么怎么设置可以访问官网:官网
#include <stdio.h> #include <libavutil/log.h> #include <libavformat/avio.h> #include <libavformat/avformat.h> #define ADTS_HEADER_LEN 7; void adts_header(char *szAdtsHeader, int dataLen){ int audio_object_type = 2; int sampling_frequency_index = 7; int channel_config = 2; int adtsLen = dataLen + 7; szAdtsHeader[0] = 0xff; //syncword:0xfff 高8bits szAdtsHeader[1] = 0xf0; //syncword:0xfff 低4bits szAdtsHeader[1] |= (0 << 3); //MPEG Version:0 for MPEG-4,1 for MPEG-2 1bit szAdtsHeader[1] |= (0 << 1); //Layer:0 2bits szAdtsHeader[1] |= 1; //protection absent:1 1bit szAdtsHeader[2] = (audio_object_type - 1)<<6; //profile:audio_object_type - 1 2bits szAdtsHeader[2] |= (sampling_frequency_index & 0x0f)<<2; //sampling frequency index:sampling_frequency_index 4bits szAdtsHeader[2] |= (0 << 1); //private bit:0 1bit szAdtsHeader[2] |= (channel_config & 0x04)>>2; //channel configuration:channel_config 高1bit szAdtsHeader[3] = (channel_config & 0x03)<<6; //channel configuration:channel_config 低2bits szAdtsHeader[3] |= (0 << 5); //original:0 1bit szAdtsHeader[3] |= (0 << 4); //home:0 1bit szAdtsHeader[3] |= (0 << 3); //copyright id bit:0 1bit szAdtsHeader[3] |= (0 << 2); //copyright id start:0 1bit szAdtsHeader[3] |= ((adtsLen & 0x1800) >> 11); //frame length:value 高2bits szAdtsHeader[4] = (uint8_t)((adtsLen & 0x7f8) >> 3); //frame length:value 中间8bits szAdtsHeader[5] = (uint8_t)((adtsLen & 0x7) << 5); //frame length:value 低3bits szAdtsHeader[5] |= 0x1f; //buffer fullness:0x7ff 高5bits szAdtsHeader[6] = 0xfc; } int main(int argc, char *argv[]) { int err_code; char errors[1024]; char *src_filename = NULL; char *dst_filename = NULL; FILE *dst_fd = NULL; int audio_stream_index = -1; int len; AVFormatContext *ofmt_ctx = NULL; AVOutputFormat *output_fmt = NULL; AVStream *out_stream = NULL; AVFormatContext *fmt_ctx = NULL; AVFrame *frame = NULL; AVPacket pkt; av_log_set_level(AV_LOG_DEBUG); if(argc < 3){ av_log(NULL, AV_LOG_DEBUG, "the count of parameters should be more than three!\n"); return -1; } src_filename = argv[1]; dst_filename = argv[2]; if(src_filename == NULL || dst_filename == NULL){ av_log(NULL, AV_LOG_DEBUG, "src or dts file is null, plz check them!\n"); return -1; } /*register all formats and codec*/ av_register_all(); /* ofmt_ctx = avformat_alloc_context(); output_fmt = av_guess_format(NULL, dst_filename, NULL); if(!output_fmt){ av_log(NULL, AV_LOG_DEBUG, "Cloud not guess file format \n"); exit(1); } ofmt_ctx->oformat = output_fmt; out_stream = avformat_new_stream(ofmt_ctx, NULL); if(!out_stream){ av_log(NULL, AV_LOG_DEBUG, "Failed to create out stream!\n"); exit(1); } if((err_code = avio_open(&ofmt_ctx->pb, dst_filename, AVIO_FLAG_WRITE)) < 0) { av_strerror(err_code, errors, 1024); av_log(NULL, AV_LOG_DEBUG, "Could not open file %s, %d(%s)\n", dst_filename, err_code, errors); exit(1); } */ dst_fd = fopen(dst_filename, "wb"); if (!dst_fd) { av_log(NULL, AV_LOG_DEBUG, "Could not open destination file %s\n", dst_filename); return -1; } /*open input media file, and allocate format context*/ if((err_code = avformat_open_input(&fmt_ctx, src_filename, NULL, NULL)) < 0){ av_strerror(err_code, errors, 1024); av_log(NULL, AV_LOG_DEBUG, "Could not open source file: %s, %d(%s)\n", src_filename, err_code, errors); return -1; } /*retrieve audio stream*/ if((err_code = avformat_find_stream_info(fmt_ctx, NULL)) < 0) { av_strerror(err_code, errors, 1024); av_log(NULL, AV_LOG_DEBUG, "failed to find stream information: %s, %d(%s)\n", src_filename, err_code, errors); return -1; } /*dump input information*/ av_dump_format(fmt_ctx, 0, src_filename, 0); /*dump output information*/ //av_dump_format(ofmt_ctx, 0, dst_filename, 1); frame = av_frame_alloc(); if(!frame){ av_log(NULL, AV_LOG_DEBUG, "Could not allocate frame\n"); return AVERROR(ENOMEM); } /*initialize packet*/ av_init_packet(&pkt); pkt.data = NULL; pkt.size = 0; /*find best audio stream*/ audio_stream_index = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0); if(audio_stream_index < 0){ av_log(NULL, AV_LOG_DEBUG, "Could not find %s stream in input file %s\n", av_get_media_type_string(AVMEDIA_TYPE_AUDIO), src_filename); return AVERROR(EINVAL); } /* if (avformat_write_header(ofmt_ctx, NULL) < 0) { av_log(NULL, AV_LOG_DEBUG, "Error occurred when opening output file"); exit(1); } */ /*read frames from media file*/ while(av_read_frame(fmt_ctx, &pkt) >=0 ){ if(pkt.stream_index == audio_stream_index){ /* pkt.stream_index = 0; av_write_frame(ofmt_ctx, &pkt); av_free_packet(&pkt); */ char adts_header_buf[7]; adts_header(adts_header_buf, pkt.size); fwrite(adts_header_buf, 1, 7, dst_fd); len = fwrite( pkt.data, 1, pkt.size, dst_fd); if(len != pkt.size){ av_log(NULL, AV_LOG_DEBUG, "warning, length of writed data isn't equal pkt.size(%d, %d)\n", len, pkt.size); } } } //av_write_trailer(ofmt_ctx); /*close input media file*/ avformat_close_input(&fmt_ctx); if(dst_fd) { fclose(dst_fd); } //avio_close(ofmt_ctx->pb); return 0; }
sampling_frequency_index采样率,通过下标,以一一对应。
1: 88200 Hz
2: 64000 Hz
3: 48000 Hz
4: 44100 Hz
5: 32000 Hz
6: 24000 Hz
7: 22050 Hz
8: 16000 Hz
9: 12000 Hz
10: 11025 Hz
11: 8000 Hz
12: 7350 Hz
13: Reserved
14: Reserved
15: frequency is written explictly
声道数下标对应关系:
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