av_frame_make_writable 确保帧数据可写,尽可能避免数据复制.如果帧可写,则不执行任何操作,如果不可写,则分配新缓冲区并复制数据.返回: 成功时为 0,错误时为负 AVERROR.
av_samples_fill_arrays 这个函数就是将你输入的一帧数据写入AVFrame格式输出,便于后面编码send,recvice使用
编码注意点:
#ifndef MAINBACK_C
#define MAINBACK_C
#endif // MAINBACK_C
#include
#include
#include
#include
#include
#include
#include
#include
#include
void f32le_convert_to_fltp(float *f32le, float *fltp, int nb_samples) {
float *fltp_l = fltp; // 左通道
float *fltp_r = fltp + nb_samples; // 右通道
for(int i = 0; i < nb_samples; i++) {
fltp_l[i] = f32le[i*2]; // 0 1 - 2 3
fltp_r[i] = f32le[i*2+1]; // 可以尝试注释左声道或者右声道听听声音
}
}
static void get_adts_header(AVCodecContext *ctx, uint8_t *adts_header, int aac_length)
{
uint8_t freq_idx = 0; //0: 96000 Hz 3: 48000 Hz 4: 44100 Hz
switch (ctx->sample_rate) {
case 96000: freq_idx = 0; break;
case 88200: freq_idx = 1; break;
case 64000: freq_idx = 2; break;
case 48000: freq_idx = 3; break;
case 44100: freq_idx = 4; break;
case 32000: freq_idx = 5; break;
case 24000: freq_idx = 6; break;
case 22050: freq_idx = 7; break;
case 16000: freq_idx = 8; break;
case 12000: freq_idx = 9; break;
case 11025: freq_idx = 10; break;
case 8000: freq_idx = 11; break;
case 7350: freq_idx = 12; break;
default: freq_idx = 4; break;
}
uint8_t chanCfg = ctx->channels;
uint32_t frame_length = aac_length + 7;
adts_header[0] = 0xFF;
adts_header[1] = 0xF1;
adts_header[2] = ((ctx->profile) << 6) + (freq_idx << 2) + (chanCfg >> 2);
adts_header[3] = (((chanCfg & 3) << 6) + (frame_length >> 11));
adts_header[4] = ((frame_length & 0x7FF) >> 3);
adts_header[5] = (((frame_length & 7) << 5) + 0x1F);
adts_header[6] = 0xFC;
}
int encode(AVCodecContext* codec_ctx,AVFrame* frame,AVPacket* pkt,FILE* out)
{
int ret=0;
ret = avcodec_send_frame(codec_ctx,frame);
if(ret<0){
printf("avcodec_send_frame failed\n");
return ret;
}
while(1)
{
ret=avcodec_receive_packet(codec_ctx,pkt);
if(ret==AVERROR(EAGAIN)||ret==AVERROR(AVERROR_EOF))
break;
if(ret<0)return ret;
if(codec_ctx->flags&AV_CODEC_FLAG_GLOBAL_HEADER)
{
char header[7]={0};
get_adts_header(codec_ctx,header,pkt->size);
int size=fwrite(header,1,7,out);
if(size!=7)
{
printf("fwrite error\n");
return 0;
}
}
fwrite(pkt->data,1,pkt->size,out);
}
}
//编码流程 先初始化编码器,读取原始文件,send,recvice,写入
int main(int argc,char* argv[])
{
if(argv<3)
{
printf("argv<3\n");
return -1;
}
char* pcm_path=argv[1];
char* out_path=argv[2];
FILE* pcm_file=fopen(pcm_path,"rb");
FILE* out_file=fopen(out_path,"wb");
AVCodec* codec=avcodec_find_encoder(AV_CODEC_ID_AAC);
AVCodecContext* codec_ctx=avcodec_alloc_context3(codec);
codec_ctx->bit_rate=100000;
codec_ctx->channel_layout=AV_CH_LAYOUT_STEREO;
codec_ctx->channels=av_get_channel_layout_nb_channels(codec_ctx->channel_layout);
codec_ctx->sample_fmt=AV_SAMPLE_FMT_FLTP;
// codec_ctx->codec_id=AV_CODEC_ID_AAC;
// codec_ctx->codec_type=AVMEDIA_TYPE_AUDIO;
codec_ctx->sample_rate=48000;
codec_ctx->profile=FF_PROFILE_AAC_LOW;
codec_ctx->flags|=AV_CODEC_FLAG_GLOBAL_HEADER;
avcodec_open2(codec_ctx,codec,NULL);
AVFrame* frame=av_frame_alloc();
AVPacket* pkt=av_packet_alloc();
// frame->channel_layout=codec_ctx->channel_layout;
frame->channels=codec_ctx->channels;
// frame->sample_rate=codec_ctx->sample_rate;
frame->format=codec_ctx->sample_fmt;
frame->nb_samples=codec_ctx->frame_size;
av_frame_get_buffer(frame,0);//分配frame的buff
int frame_bytes=av_get_bytes_per_sample(frame->format)*frame->channels*frame->nb_samples;
uint8_t* pcm_buff=av_malloc(frame_bytes);
memset(pcm_buff,0,frame_bytes);
uint8_t *pcm_temp_buf = (uint8_t *)malloc(frame_bytes);
memset(pcm_temp_buf,0,frame_bytes);
int pts=0;
int ret=0;
while(1)
{
int rsize=fread(pcm_buff,1,frame_bytes,pcm_file);
ret = av_frame_make_writable(frame);
if(ret != 0)
printf("av_frame_make_writable failed, ret = %d\n", ret);
f32le_convert_to_fltp(pcm_buff,pcm_temp_buf,frame->nb_samples);
int need_size=av_samples_fill_arrays(frame->data,frame->linesize,pcm_temp_buf,frame->channels,frame->nb_samples,frame->format,0);
if(rsize!=need_size)break;
frame->pts=pts;
pts+=1;
printf("frame pts:%d\n",pts);
encode(codec_ctx,frame,pkt,out_file);
}
encode(codec_ctx,NULL,pkt,out_file);
return 0;
}