您的位置:

cbr和vbr的区别

一、码率的稳定性

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码率值。