FFmpeg 4.3 H265十三:编码-将AVFrame转换成AVPacket。视频编码原理.编码相关api,H264特殊参数说明。将一个yuv420p文件编码成h264,代码是重点。VBR CBR

前提:

从前面的学习我们知道 AVFrame中是最原始的 视频数据,这一节开始我们需要将这个最原始的视频数据 压缩成 AVPacket数据,

我们前面,将YUV数据或者 RGBA 数据装进入了 AVFrame里面,并且在SDL中显示。

也就是说:对于安防项目来说,我们将原始从摄像头数据(YUV,RGB)转换成 AVFrame后,可以直接显示出来。但是如果我们将要数据存储,则要将 AVFrame转成  AVPacket.

视频编码 以及原理

从摄像头得到原始数据 ---- > 像素格式转换---->编码 ------>封装

编码的原因很好理解,YUV数据太大了,我们要编码成 h264,h265 等较小的格式

背后的原理是这样,一个YUV视频是由一张一张YUV图片组成的。

帧内压缩:

我们将一张YUV图片,假设是 1280x728大小的,我们将其划分成16x16的大小,总有一些像素点是一样的,或者接近的,例如下图:

帧间压缩:

假设上述图片是YUV 的第一张图片,第二帧图片是师爷 在讲话,那么第二帧图片可能只是嘴巴变化了一下,那么我们参考第一张图片,去存储第二张图片,就只用存储第二章图片 和 第一张图片不同的地方就好。。在还原的时候,参考第一张图片和差异,通过算法还原,这就叫做帧间压缩

我们这一节将 AVFrame转成 AVPacket,实际上就是编码的过程。

在将AVFrame转成AVPacket的过程中,我们会使用ffmpeg的提供的现成的API。

编码过程中的专业词语

为了更好的理解这些API的参数,我们需要大致明白这个转化流程中用到的专业方法,知道了这些专业方法,对于我们在使用API参数的时候,有个比较好的理解,实际上我们基本不会改动ffmpeg的源码,明白这些专业方法的对于开发者的含义是:你在使用API参数的时候,会能更好的明白为什么参数这么定义。

将AVFrame转成 AVPakcet,经过了 DCT离散余弦变换----->量化------>熵编码

在量化 阶段:有一个QP量化参数,也叫做QStep。这个QP取值为0---51,越大,质量越差。

AVPacket 重要函数以及重要结构体成员

FFmpeg存放压缩后的音视频数据的结构体:AVPacket简介,结构体,函数-CSDN博客

pts 和 dts 的区别

https://zhuanlan.zhihu.com/p/707384213

从avframe 变成 avpacket 也就是编码,编码相关API

0.从核心api出发倒推需要哪些API

0.1核心api 是将 avframe 发送给 AVCodecContext。

int avcodec_send_frame(AVCodecContext *avctx, const AVFrame *frame);

0.2 然后从AVCodecContext获得avpacket 

int avcodec_receive_packet(AVCodecContext *avctx, AVPacket *avpkt);

对于视频来说:一帧avframe对应一帧avpacket

对于音频来说:一帧avframe对应多帧avpacket

注意的点:

这个过程实际可以看成是 生产者消费者模式。我们发送 AVFrame到AVCodecContext,然后从AVCodecContext就可以获得AVPacket了。

avcodec_send_frame方法 内部实现是开启线程 的,参见源码从这一行往下看 :return do_encode(avctx, frame, &(int){0});

得到的结论:

那么这个从源码实现看会 开启线程, 这说明啥呢?说明 这个过程一定是耗时的。

对于开发者来说:

立即从 avcodec_receive_packet 得到的 avpacket,这个avpacket有可能没有值,

那么对于这种情况开发者正确使用呢?

avcodec_receive_packet  对于这部分的说明是:

     返回值<0, 说明有问题。但是<0的情况有4种。

        如果 是 EAGAIN,说明output目前不可用,user必须再次发送 input。

 * @return 0 on success, otherwise negative error code:
 *      AVERROR(EAGAIN):   output is not available in the current state - user
 *                         must try to send input
 *      AVERROR_EOF:       the encoder has been fully flushed, and there will be
 *                         no more output packets
 *      AVERROR(EINVAL):   codec not opened, or it is a decoder
 *      other errors: legitimate encoding errors
 */

0.3 从前面的两个API可知,我们需要三个参数,avcodecContext,avframe,avpacket

0.4 获得avframe

前提条件是:

我们要从一个YUV420p文件中读取一帧 avframe,

要知道这个 YUV420P文件的 分辨率(也就是宽高),

要知道 YUV420P文件的 AVPixelFormat,

要知道这个文件的 linesize[0], linesize[1], linesize[2], 或者 对齐方式(知道了对齐方式,是可以计算出来 linesize[0],linesize[1],linesize[2]的)。如果不指定 linesize[0], linesize[1], linesize[2],ffmepg在av_frame_get_buffer 方法内部会自己计算出  linesize[0], linesize[1], linesize[2],计算的依据是 av_frame_get_buffer(avframe, 0)的第二个参数,传0会使用32位对齐的方式。

 AVFrame* avframe = av_frame_alloc();

    avframe->width = 800;
    avframe->height = 600;
    avframe->format = AV_PIX_FMT_YUV420P;

    avframe->linesize[0] = 800;
    avframe->linesize[1] = 400;
    avframe->linesize[2] = 400;
    ret = av_frame_get_buffer(avframe, 0);

如果是从头读取一个avframe,还应该设置 avframe的pts,pts就是显示时间,因为YUV420P文件就是原始的文件,因此按照顺序读取一帧avframe,就应该给pts++,那么在最前面的时候,应该给 avframe->pts 赋值为0 ;

0.5 获得 avpacket

创建 avpacket
    AVPacket* avpacket = av_packet_alloc();
    if (avpacket == nullptr) {
        cout << "av_packet_alloc  error" << endl;
        return;
    }

0.6 获得 avcodec

    AVCodec* encoderAVCodec = avcodec_find_encoder(AV_CODEC_ID_H264);

    if (avpacket == nullptr) {
        cout << "avcodec_find_encoder AV_CODEC_ID_H264 error" << endl;
        return;
    }

0.7 获得 avcodecContext,并给AVCodecContext 设置基本参数,timebase,pix_fmt,width,height

 //4.创建 AVCodecContext
    AVCodecContext* encoderAVCodecContext = avcodec_alloc_context3(encoderAVCodec);
    if (encoderAVCodecContext == nullptr) {
        cout << "avcodec_alloc_context3  error" << endl;
        return;
    }
    //4.1 这里要设置 avcodecContext的基本参数,如果不设置,在 avcodec_open2的时候会有问题,参见如下的测试代码
    encoderAVCodecContext->time_base = {1,25};
    encoderAVCodecContext->pix_fmt = AV_PIX_FMT_YUV420P;
    encoderAVCodecContext->width = avframe->width;
    encoderAVCodecContext->height = avframe->height;

0.8 打开 AVCodecContexxt

    ret = avcodec_open2(encoderAVCodecContext, nullptr, nullptr);
    if (ret < 0) {
        //如果不设置 encoderAVCodecContext的参数,这里会报错 -Invalid argument,
        //[libx264 @ 00BAAE00] The encoder timebase is not set.
        //[libx264 @ 007AAE00] Specified pixel format -1 is invalid or not supported
        //[libx264 @ 00EFCBC0] dimensions not set..测试如果不设置encoderAVCodecContext->width 和 encoderAVCodecContext->height,就会有这个问题
        cout << "avcodec_open2 error" << endl; 
        PrintErr(ret);
    }

0.9 将 avframe 发送给 AVCodecContext。也就是0.1的操作

1.0 从 AVCodecContext 获得 avpacket。也就是0.2的操作

1.1 一般情况下,我们要读取的YUV文件都是很多帧,因此 0.9 和 1.0 要在一个读取YUV文件的循环里面做

1.2 当YUV文件读取完成后,还应该 刷新 AVCodecContext的缓存

具体方法是:通过 avcodec_send_frame(encoderAVCodecContext, nullptr);

然后通过 avcodec_receive_packet(encoderAVCodecContext, avpacket);接受,但是注意的是:一般的缓存有多个avpacket。因此要用循环接收

     ret = avcodec_send_frame(encoderAVCodecContext, nullptr);
     if (ret < 0) {
         cout << "avcodec_send_frame nullptr error" << endl;
         PrintErr(ret);
     }

int count = 0;

     //*@return 0 on success, otherwise negative error code :
     //    *AVERROR(EAGAIN) : output is not available in the current state - user
     //    * must try to send input
     //    * AVERROR_EOF : the encoder has been fully flushed, and there will be
     //    * no more output packets
     //    * AVERROR(EINVAL) : codec not opened, or it is a decoder
     //    * other errors : legitimate encoding errors
     //    * /
     //    int avcodec_receive_packet(AVCodecContext * avctx, AVPacket * avpkt);
     while (true) {
         ret = avcodec_receive_packet(encoderAVCodecContext, avpacket);
         if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
             cout << "last avcodec_receive_packet ret = " << ret << endl;
             PrintErr(ret);
             break;
         }
         if (ret < 0) {
             char buf[1024] = { 0 };
             av_strerror(ret, buf, sizeof(buf) - 1);
             cerr << "avcodec_receive_packet failed!" << buf << endl;
             break;
         }
         if (ret == 0) {
             //这时候 说明 编码器中的 avpacket是真的有数据的
             count++;
             avpacketofs.write((char*)avpacket->data, avpacket->size);
             cerr << "avcodec_receive_packet good! ret = " << ret << endl;

             av_packet_unref(avpacket);
         }
     }
     cout << "count = " << count << endl;
 

1.3 avpacket的清理工作。

每一帧的avpacket的大小都有可能不一样大,这个很好理解,IDR帧就很多,P和B帧就相对小的多。

我们通过 avcodec_receive_packet 读取到avpacket后,

下一次循环的时候,还会使用这个avpacket,这时候需要清理一下avpacket,

以防止可能的问题发生---使用方法为av_packet_unref(avpacket);

代码如下:

ret = avcodec_receive_packet(encoderAVCodecContext, avpacket);

if (ret == 0) {
             //这时候 说明 编码器中的 avpacket是真的有数据的
             count++;
             avpacketofs.write((char*)avpacket->data, avpacket->size);
             cerr << "avcodec_receive_packet good! ret = " << ret << endl;

             av_packet_unref(avpacket); //清理avpacket,以防止问题发生。
}

那么这个问题是啥问题?内存泄漏吗?

我们将 avframe中的数据发送 10000000 次,并通过avcodec_receive_packet 得到 avpacket,每次都清空 avpakcet的情况下,没有内存泄漏问题发生。

    int times = 10000000;
    while (times != 0) {
         ret = avcodec_send_frame(encoderAVCodecContext,  avframe);
         if (ret < 0) {
             cout << "avcodec_send_frame error" << endl;
            PrintErr(ret);
          }

         //我们看到,如果只有一帧的情况下,avcodec_receive_packet的返回值就是
         ret = avcodec_receive_packet(encoderAVCodecContext, avpacket);
         if (ret < 0) {

             cout << "avcodec_receive_packet error ret = " << ret << endl;
             PrintErr(ret);
             // log如下
             //avcodec_receive_packet error ret = -11
             //Resource temporarily unavailable
             av_packet_unref(avpacket);
             times--;
         }
         else if (ret == 0) {
             cerr << "avcodec_receive_packet good good godd  ret = " << ret << endl;
         }
     }

其他条件不变,但是每次不清空,也不会有内存泄漏问题

    int times = 10000000;
    while (times != 0) {
         ret = avcodec_send_frame(encoderAVCodecContext,  avframe);
         if (ret < 0) {
             cout << "avcodec_send_frame error" << endl;
            PrintErr(ret);
          }

         //我们看到,如果只有一帧的情况下,avcodec_receive_packet的返回值就是
         ret = avcodec_receive_packet(encoderAVCodecContext, avpacket);
         if (ret < 0) {

             cout << "avcodec_receive_packet error ret = " << ret << endl;
             PrintErr(ret);
             // log如下
             //avcodec_receive_packet error ret = -11
             //Resource temporarily unavailable
             //av_packet_unref(avpacket);
             times--;
         }
         else if (ret == 0) {
             cerr << "avcodec_receive_packet good good godd  ret = " << ret << endl;
         }
     }

1.4 avframe的清理工作。

我们来看从yuvfile 文件中读取一帧 avframe中,然后将这一帧avframe 编码成一帧 avpacket,然后存储文件成 xxx.h264文件的操作,在这个过程中,观察应该方法

1.查找编码器

/**
 * Find a registered encoder with a matching codec ID.
 *
 * @param id AVCodecID of the requested encoder
 * @return An encoder if one was found, NULL otherwise.
 */


const AVCodec *avcodec_find_encoder(enum AVCodecID id);

如果参数 是 AVCodecID ,那么对应的值如下,重要的为    

AV_CODEC_ID_H264, 

#define AV_CODEC_ID_H265 AV_CODEC_ID_HEVC

enum AVCodecID {
    AV_CODEC_ID_NONE,

    /* video codecs */
    AV_CODEC_ID_MPEG1VIDEO,
    AV_CODEC_ID_MPEG2VIDEO, ///< preferred ID for MPEG-1/2 video decoding
    AV_CODEC_ID_H261,
    AV_CODEC_ID_H263,
    AV_CODEC_ID_RV10,
    AV_CODEC_ID_RV20,
    AV_CODEC_ID_MJPEG,
    AV_CODEC_ID_MJPEGB,
    AV_CODEC_ID_LJPEG,
    AV_CODEC_ID_SP5X,
    AV_CODEC_ID_JPEGLS,
    AV_CODEC_ID_MPEG4,
    AV_CODEC_ID_RAWVIDEO,
    AV_CODEC_ID_MSMPEG4V1,
    AV_CODEC_ID_MSMPEG4V2,
    AV_CODEC_ID_MSMPEG4V3,
    AV_CODEC_ID_WMV1,
    AV_CODEC_ID_WMV2,
    AV_CODEC_ID_H263P,
    AV_CODEC_ID_H263I,
    AV_CODEC_ID_FLV1,
    AV_CODEC_ID_SVQ1,
    AV_CODEC_ID_SVQ3,
    AV_CODEC_ID_DVVIDEO,
    AV_CODEC_ID_HUFFYUV,
    AV_CODEC_ID_CYUV,
    AV_CODEC_ID_H264,
    AV_CODEC_ID_INDEO3,
    AV_CODEC_ID_VP3,
    AV_CODEC_ID_THEORA,
    AV_CODEC_ID_ASV1,
    AV_CODEC_ID_ASV2,
    AV_CODEC_ID_FFV1,
    AV_CODEC_ID_4XM,
    AV_CODEC_ID_VCR1,
    AV_CODEC_ID_CLJR,
    AV_CODEC_ID_MDEC,
    AV_CODEC_ID_ROQ,
    AV_CODEC_ID_INTERPLAY_VIDEO,
    AV_CODEC_ID_XAN_WC3,
    AV_CODEC_ID_XAN_WC4,
    AV_CODEC_ID_RPZA,
    AV_CODEC_ID_CINEPAK,
    AV_CODEC_ID_WS_VQA,
    AV_CODEC_ID_MSRLE,
    AV_CODEC_ID_MSVIDEO1,
    AV_CODEC_ID_IDCIN,
    AV_CODEC_ID_8BPS,
    AV_CODEC_ID_SMC,
    AV_CODEC_ID_FLIC,
    AV_CODEC_ID_TRUEMOTION1,
    AV_CODEC_ID_VMDVIDEO,
    AV_CODEC_ID_MSZH,
    AV_CODEC_ID_ZLIB,
    AV_CODEC_ID_QTRLE,
    AV_CODEC_ID_TSCC,
    AV_CODEC_ID_ULTI,
    AV_CODEC_ID_QDRAW,
    AV_CODEC_ID_VIXL,
    AV_CODEC_ID_QPEG,
    AV_CODEC_ID_PNG,
    AV_CODEC_ID_PPM,
    AV_CODEC_ID_PBM,
    AV_CODEC_ID_PGM,
    AV_CODEC_ID_PGMYUV,
    AV_CODEC_ID_PAM,
    AV_CODEC_ID_FFVHUFF,
    AV_CODEC_ID_RV30,
    AV_CODEC_ID_RV40,
    AV_CODEC_ID_VC1,
    AV_CODEC_ID_WMV3,
    AV_CODEC_ID_LOCO,
    AV_CODEC_ID_WNV1,
    AV_CODEC_ID_AASC,
    AV_CODEC_ID_INDEO2,
    AV_CODEC_ID_FRAPS,
    AV_CODEC_ID_TRUEMOTION2,
    AV_CODEC_ID_BMP,
    AV_CODEC_ID_CSCD,
    AV_CODEC_ID_MMVIDEO,
    AV_CODEC_ID_ZMBV,
    AV_CODEC_ID_AVS,
    AV_CODEC_ID_SMACKVIDEO,
    AV_CODEC_ID_NUV,
    AV_CODEC_ID_KMVC,
    AV_CODEC_ID_FLASHSV,
    AV_CODEC_ID_CAVS,
    AV_CODEC_ID_JPEG2000,
    AV_CODEC_ID_VMNC,
    AV_CODEC_ID_VP5,
    AV_CODEC_ID_VP6,
    AV_CODEC_ID_VP6F,
    AV_CODEC_ID_TARGA,
    AV_CODEC_ID_DSICINVIDEO,
    AV_CODEC_ID_TIERTEXSEQVIDEO,
    AV_CODEC_ID_TIFF,
    AV_CODEC_ID_GIF,
    AV_CODEC_ID_DXA,
    AV_CODEC_ID_DNXHD,
    AV_CODEC_ID_THP,
    AV_CODEC_ID_SGI,
    AV_CODEC_ID_C93,
    AV_CODEC_ID_BETHSOFTVID,
    AV_CODEC_ID_PTX,
    AV_CODEC_ID_TXD,
    AV_CODEC_ID_VP6A,
    AV_CODEC_ID_AMV,
    AV_CODEC_ID_VB,
    AV_CODEC_ID_PCX,
    AV_CODEC_ID_SUNRAST,
    AV_CODEC_ID_INDEO4,
    AV_CODEC_ID_INDEO5,
    AV_CODEC_ID_MIMIC,
    AV_CODEC_ID_RL2,
    AV_CODEC_ID_ESCAPE124,
    AV_CODEC_ID_DIRAC,
    AV_CODEC_ID_BFI,
    AV_CODEC_ID_CMV,
    AV_CODEC_ID_MOTIONPIXELS,
    AV_CODEC_ID_TGV,
    AV_CODEC_ID_TGQ,
    AV_CODEC_ID_TQI,
    AV_CODEC_ID_AURA,
    AV_CODEC_ID_AURA2,
    AV_CODEC_ID_V210X,
    AV_CODEC_ID_TMV,
    AV_CODEC_ID_V210,
    AV_CODEC_ID_DPX,
    AV_CODEC_ID_MAD,
    AV_CODEC_ID_FRWU,
    AV_CODEC_ID_FLASHSV2,
    AV_CODEC_ID_CDGRAPHICS,
    AV_CODEC_ID_R210,
    AV_CODEC_ID_ANM,
    AV_CODEC_ID_BINKVIDEO,
    AV_CODEC_ID_IFF_ILBM,
#define AV_CODEC_ID_IFF_BYTERUN1 AV_CODEC_ID_IFF_ILBM
    AV_CODEC_ID_KGV1,
    AV_CODEC_ID_YOP,
    AV_CODEC_ID_VP8,
    AV_CODEC_ID_PICTOR,
    AV_CODEC_ID_ANSI,
    AV_CODEC_ID_A64_MULTI,
    AV_CODEC_ID_A64_MULTI5,
    AV_CODEC_ID_R10K,
    AV_CODEC_ID_MXPEG,
    AV_CODEC_ID_LAGARITH,
    AV_CODEC_ID_PRORES,
    AV_CODEC_ID_JV,
    AV_CODEC_ID_DFA,
    AV_CODEC_ID_WMV3IMAGE,
    AV_CODEC_ID_VC1IMAGE,
    AV_CODEC_ID_UTVIDEO,
    AV_CODEC_ID_BMV_VIDEO,
    AV_CODEC_ID_VBLE,
    AV_CODEC_ID_DXTORY,
    AV_CODEC_ID_V410,
    AV_CODEC_ID_XWD,
    AV_CODEC_ID_CDXL,
    AV_CODEC_ID_XBM,
    AV_CODEC_ID_ZEROCODEC,
    AV_CODEC_ID_MSS1,
    AV_CODEC_ID_MSA1,
    AV_CODEC_ID_TSCC2,
    AV_CODEC_ID_MTS2,
    AV_CODEC_ID_CLLC,
    AV_CODEC_ID_MSS2,
    AV_CODEC_ID_VP9,
    AV_CODEC_ID_AIC,
    AV_CODEC_ID_ESCAPE130,
    AV_CODEC_ID_G2M,
    AV_CODEC_ID_WEBP,
    AV_CODEC_ID_HNM4_VIDEO,
    AV_CODEC_ID_HEVC,
#define AV_CODEC_ID_H265 AV_CODEC_ID_HEVC
    AV_CODEC_ID_FIC,
    AV_CODEC_ID_ALIAS_PIX,
    AV_CODEC_ID_BRENDER_PIX,
    AV_CODEC_ID_PAF_VIDEO,
    AV_CODEC_ID_EXR,
    AV_CODEC_ID_VP7,
    AV_CODEC_ID_SANM,
    AV_CODEC_ID_SGIRLE,
    AV_CODEC_ID_MVC1,
    AV_CODEC_ID_MVC2,
    AV_CODEC_ID_HQX,
    AV_CODEC_ID_TDSC,
    AV_CODEC_ID_HQ_HQA,
    AV_CODEC_ID_HAP,
    AV_CODEC_ID_DDS,
    AV_CODEC_ID_DXV,
    AV_CODEC_ID_SCREENPRESSO,
    AV_CODEC_ID_RSCC,
    AV_CODEC_ID_AVS2,

    AV_CODEC_ID_Y41P = 0x8000,
    AV_CODEC_ID_AVRP,
    AV_CODEC_ID_012V,
    AV_CODEC_ID_AVUI,
    AV_CODEC_ID_AYUV,
    AV_CODEC_ID_TARGA_Y216,
    AV_CODEC_ID_V308,
    AV_CODEC_ID_V408,
    AV_CODEC_ID_YUV4,
    AV_CODEC_ID_AVRN,
    AV_CODEC_ID_CPIA,
    AV_CODEC_ID_XFACE,
    AV_CODEC_ID_SNOW,
    AV_CODEC_ID_SMVJPEG,
    AV_CODEC_ID_APNG,
    AV_CODEC_ID_DAALA,
    AV_CODEC_ID_CFHD,
    AV_CODEC_ID_TRUEMOTION2RT,
    AV_CODEC_ID_M101,
    AV_CODEC_ID_MAGICYUV,
    AV_CODEC_ID_SHEERVIDEO,
    AV_CODEC_ID_YLC,
    AV_CODEC_ID_PSD,
    AV_CODEC_ID_PIXLET,
    AV_CODEC_ID_SPEEDHQ,
    AV_CODEC_ID_FMVC,
    AV_CODEC_ID_SCPR,
    AV_CODEC_ID_CLEARVIDEO,
    AV_CODEC_ID_XPM,
    AV_CODEC_ID_AV1,
    AV_CODEC_ID_BITPACKED,
    AV_CODEC_ID_MSCC,
    AV_CODEC_ID_SRGC,
    AV_CODEC_ID_SVG,
    AV_CODEC_ID_GDV,
    AV_CODEC_ID_FITS,
    AV_CODEC_ID_IMM4,
    AV_CODEC_ID_PROSUMER,
    AV_CODEC_ID_MWSC,
    AV_CODEC_ID_WCMV,
    AV_CODEC_ID_RASC,
    AV_CODEC_ID_HYMT,
    AV_CODEC_ID_ARBC,
    AV_CODEC_ID_AGM,
    AV_CODEC_ID_LSCR,
    AV_CODEC_ID_VP4,
    AV_CODEC_ID_IMM5,
    AV_CODEC_ID_MVDV,
    AV_CODEC_ID_MVHA,
    AV_CODEC_ID_CDTOONS,
    AV_CODEC_ID_MV30,
    AV_CODEC_ID_NOTCHLC,
    AV_CODEC_ID_PFM,

    /* various PCM "codecs" */
    AV_CODEC_ID_FIRST_AUDIO = 0x10000,     ///< A dummy id pointing at the start of audio codecs
    AV_CODEC_ID_PCM_S16LE = 0x10000,
    AV_CODEC_ID_PCM_S16BE,
    AV_CODEC_ID_PCM_U16LE,
    AV_CODEC_ID_PCM_U16BE,
    AV_CODEC_ID_PCM_S8,
    AV_CODEC_ID_PCM_U8,
    AV_CODEC_ID_PCM_MULAW,
    AV_CODEC_ID_PCM_ALAW,
    AV_CODEC_ID_PCM_S32LE,
    AV_CODEC_ID_PCM_S32BE,
    AV_CODEC_ID_PCM_U32LE,
    AV_CODEC_ID_PCM_U32BE,
    AV_CODEC_ID_PCM_S24LE,
    AV_CODEC_ID_PCM_S24BE,
    AV_CODEC_ID_PCM_U24LE,
    AV_CODEC_ID_PCM_U24BE,
    AV_CODEC_ID_PCM_S24DAUD,
    AV_CODEC_ID_PCM_ZORK,
    AV_CODEC_ID_PCM_S16LE_PLANAR,
    AV_CODEC_ID_PCM_DVD,
    AV_CODEC_ID_PCM_F32BE,
    AV_CODEC_ID_PCM_F32LE,
    AV_CODEC_ID_PCM_F64BE,
    AV_CODEC_ID_PCM_F64LE,
    AV_CODEC_ID_PCM_BLURAY,
    AV_CODEC_ID_PCM_LXF,
    AV_CODEC_ID_S302M,
    AV_CODEC_ID_PCM_S8_PLANAR,
    AV_CODEC_ID_PCM_S24LE_PLANAR,
    AV_CODEC_ID_PCM_S32LE_PLANAR,
    AV_CODEC_ID_PCM_S16BE_PLANAR,

    AV_CODEC_ID_PCM_S64LE = 0x10800,
    AV_CODEC_ID_PCM_S64BE,
    AV_CODEC_ID_PCM_F16LE,
    AV_CODEC_ID_PCM_F24LE,
    AV_CODEC_ID_PCM_VIDC,

    /* various ADPCM codecs */
    AV_CODEC_ID_ADPCM_IMA_QT = 0x11000,
    AV_CODEC_ID_ADPCM_IMA_WAV,
    AV_CODEC_ID_ADPCM_IMA_DK3,
    AV_CODEC_ID_
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值