编码器内部有一个缓冲区, 对于音频来说, 输入一帧数据就能够输出一帧数据, 但是对于视频来说, 需要输入多帧数据才能输出一帧数据, 所以无论对于音频还是视频, 都需要输入一部分数据之后才会输出数据.
创建编码器: 说是创建 其实是查找编码器, 因为所有的编解码器都是一开始就注册好的, 需要使用哪个编码器 就从列表中查找到哪个编码器. 可以通过查找ID或者名字来找到相应编码器: avcodec_find_encoder / avcodec_find_encoder_by_name.
创建上下文: avcodec_alloc_context3, “3”表示对老版本的区分, 老版本继续支持, 新版本接口增加编号.
打开编码器: avcodec_open2, “2”的解释同上.
staticAVCodecContext* open_coder(void) { // 创建编解码器 AVCodec *codec = avcodec_find_encoder_by_name("libfdk_aac");// AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_AAC); // 创建codec 上下文 AVCodecContext *codec_ctx = avcodec_alloc_context3(codec); codec_ctx -> sample_fmt = AV_SAMPLE_FMT_S16; // 输入音频采样大小 必须按照fdkaac库设置相应的值:s16 codec_ctx -> channel_layout = AV_CH_LAYOUT_STEREO; // 输入音频声道布局 codec_ctx -> channels = 2; // 输入音频声道数 codec_ctx -> sample_rate = 44100; // 输入音频码率 codec_ctx -> bit_rate = 0; // 设置为0 profile 才会生效 codec_ctx -> profile = FF_PROFILE_AAC_HE; // 选择好编码器后 会生成对应大小的码率 32k /* open it */ if (avcodec_open2(codec_ctx, codec, NULL) < 0) { fprintf(stderr, "Could not open codec\n"); exit(1); } return codec_ctx;}
输入输出数据
主要API:
avcodec_send_frame : 输入frame
avcodec_receive_packet : 输出packet
AVFrame 存放未编码的数据pcm, AVPacket存放编码后的数据aac、opus
创建frame
staticAVFrame* create_frame(AVCodecContext *codec_ctx) { // 音频输入数据 AVFrame *frame : 在堆中分配, AVFrame frame: 在栈中分配 AVFrame *frame = av_frame_alloc(); if (!frame) { printf("error, no memory!"); goto __ERROR; } frame -> nb_samples = 512; // 单通道每帧采样个数 机器读取到每个包的大小4096 位深32位 双声道, 4096/4/2 = 512 frame -> format = codec_ctx -> sample_fmt; // AV_SAMPLE_FMT_S16; // 采样大小 16位 = 2byte frame -> channel_layout = codec_ctx -> channel_layout; // AV_CH_LAYOUT_STEREO; av_frame_get_buffer(frame, 0); // 大小 = 512 * 2 * 2 = 2048 if (!frame->buf[0]) { printf("error, av_frame_get_buffer \n"); goto __ERROR; } return frame;__ERROR: if (frame) { av_frame_free(&frame); } return NULL;}
// 将重采样的数据拷贝到 frame 中
memcpy((void *)frame->data[0], dst_data[0], dst_linesize);
编码
staticvoid encode(AVCodecContext *ctx, AVFrame *frame, AVPacket *pkt, FILE *output) { int ret = 0; // 将数据送编码器 ret = avcodec_send_frame(ctx, frame); if (ret < 0) { fprintf(stderr, "Error sending the frame to the encoder [%d]\n", ret); } // 如果ret>=0 说明设置数据成功 while (ret >= 0) { // 获取编码后的数据,如果成功 则重复获取 直到失败为止 ret = avcodec_receive_packet(ctx, pkt); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { // AVERROR 加负号 EAGAIN数据暂时不够进行编码, AVERROR_EOF 没有可用数据 需读取数据 return; } else if (ret < 0) { printf("error , encoding audio frame \n"); exit(-1); } fwrite(pkt->data, pkt->size, 1, output); fflush(output); // fflush()会强制将缓冲区内的数据写回参数stream 指定的文件中。 }}