一、码率的稳定性
CBR (Constant Bit Rate)是指编码的码率保持恒定不变;VBR (Variable Bit Rate)则是指编码的码率是根据音视频信号复杂度动态变化的。
CBR相对于VBR而言,应用场景一般是对带宽有限定要求的场景,比如一些实时音视频传输、实时监控等。相对来说,VBR不仅适用于这类场景,它也更为适合于要求较高的音视频质量场景,尤其是在用户对音视频质量有较高要求的时候。
例如,在一些用户上传视频的场景中,要求该视频在上传过程中尽量保证码率(即文件大小)相对稳定,并在非过于复杂的场景下保证视频质量的情况下表现良好,这样的情况下使用CBR编码是最好的选择。
而如果需要在保证高清视频质量的情况下,尽可能减小视频文件大小的场景下,使用VBR动态码率即可实现。
二、码率控制方式
码率控制方式也是cbr和vbr的区别之一。
CBR是在编码开始时指定码率参数,并一直保持到编码结束;VBR则不同,其编码选取的码率常常是根据视频情况和编码的帧来分配的。
对于音频编码来说,CBR和VBR也有各自的区别。在CBR编码下,音频码率和采样率固定,而在VBR编码下,音频码率和采样率是根据音频的音调、响度等因素进行调整。
三、码率类型选择
在实际开发过程中,确定码率类型的选择也是至关重要的。不同的场景、不同的需求都需要选取不同的编码方式。下面给出两个示例,包含代码进行演示。
1、使用CBR编码方式
#include <stdio.h> #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libavutil/avutil.h> int main() { AVFormatContext *pFormatContext = NULL; AVCodecContext *pCodecContext = NULL; AVCodec *pCodec = NULL; av_register_all(); // 注册库中的所有可用的文件格式和编解码器 avformat_network_init(); // 初始化网络流的各个组件 pFormatContext = avformat_alloc_context(); // 初始化 if (0 != avformat_open_input(&pFormatContext, "test.mp4", NULL, NULL)) { printf("打开文件失败!\n"); return -1; } if (0 > avformat_find_stream_info(pFormatContext, NULL)) { printf("获取音频流信息失败!\n"); return -1; } for (int index = 0; index < pFormatContext->nb_streams; index++) { if (pFormatContext->streams[index]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { pCodecContext = avcodec_alloc_context3(NULL); if (0 != avcodec_parameters_to_context(pCodecContext, pFormatContext->streams[index]->codecpar)) { printf("转换codec失败!\n"); return -1; } pCodec = avcodec_find_decoder(pCodecContext->codec_id); if (NULL == pCodec) { printf("找不到音频解码器!\n"); return -1; } if (0 != avcodec_open2(pCodecContext, pCodec, NULL)) { printf("打开音频解码器失败!\n"); return -1; } printf("码率参数为: %d\n", pCodecContext->bit_rate); break; } } return 0; }
在上面的代码中,我们通过使用FFmpeg框架提供的接口,找到MP4格式文件中的音频流,然后通过遍历过程,找到音频流的解码器,通过获取解码器的编码类型,得到该音频文件的码率参数。
2、使用VBR编码方式
#include <stdio.h> #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libavutil/avutil.h> int main() { AVFormatContext *pFormatContext = NULL; AVCodecContext *pCodecContext = NULL; AVCodec *pCodec = NULL; int iRet; av_register_all(); // 注册库中的所有可用的文件格式和编解码器 avformat_network_init(); // 初始化网络流的各个组件 pFormatContext = avformat_alloc_context(); // 初始化 if (0 != avformat_open_input(&pFormatContext, "test.mp4", NULL, NULL)) { printf("打开文件失败!\n"); return -1; } if (0 > avformat_find_stream_info(pFormatContext, NULL)) { printf("获取音频流信息失败!\n"); return -1; } for (int index = 0; index < pFormatContext->nb_streams; index++) { if (pFormatContext->streams[index]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { pCodecContext = avcodec_alloc_context3(NULL); if (0 != avcodec_parameters_to_context(pCodecContext, pFormatContext->streams[index]->codecpar)) { printf("转换codec失败!\n"); return -1; } pCodec = avcodec_find_decoder(pCodecContext->codec_id); if (NULL == pCodec) { printf("找不到音频解码器!\n"); return -1; } if (0 != avcodec_open2(pCodecContext, pCodec, NULL)) { printf("打开音频解码器失败!\n"); return -1; } printf("VBR模式下瞬时码率为: %d\n", pCodecContext->bit_rate); avcodec_flush_buffers(pCodecContext); for (int i = 0; i < 30; i++) { AVPacket packet; av_init_packet(&packet); packet.data = NULL; packet.size = 0; iRet = av_read_frame(pFormatContext, &packet); if (iRet < 0) { printf("解码结束!\n"); break; } if (packet.stream_index == index) { AVFrame *frame = av_frame_alloc(); if (NULL == frame) { printf("申请frame失败!\n"); return -1; } iRet = avcodec_send_packet(pCodecContext, &packet); if (0 == iRet) { while (avcodec_receive_frame(pCodecContext, frame) == 0) {} } av_frame_unref(frame); av_frame_free(&frame); } } break; } } return 0; }
在上面的代码中,我们通过使用FFmpeg框架提供的接口,找到MP4格式文件中的音频流,然后通过遍历过程,找到音频流的解码器,通过获取解码器的编码类型,得到该音频文件瞬间VBR码率值。