• ffmpeg 重要函数介绍


    /***********ffmpeg学习笔记*******************/

    AVFormatContext主要存储视音频封装格式中包含的信息;
    AVInputFormat存储输入视音频使用的封装格式。
    每种视音频封装格式都对应一个AVInputFormat 结构。
    每个AVStream存储一个视频/音频流的相关数据;
    每个AVStream对应一个AVCodecContext,存储该视频/音频流使用解码方式的相关数据;
    每个AVCodecContext中对应一个AVCodec,包含该视频/音频对应的解码器。每种解码器都对应一个AVCodec结构。

    视频的话,每个结构一般是存一帧;音频可能有好几帧
    解码前数据:AVPacket
    解码后数据:AVFrame

    /***************************/
    int av_image_get_buffer_size(enum AVPixelFormat pix_fmt, int width, int height, int align);
    函数的作用是通过指定像素格式、图像宽、图像高来计算所需的内存大小
    重点说明一个参数align:此参数是设定内存对齐的对齐数,也就是按多大的字节进行内存对齐。
    比如设置为1,表示按1字节对齐,那么得到的结果就是与实际的内存大小一样。
    再比如设置为4,表示按4字节对齐。也就是内存的起始地址必须是4的整倍数。

    /******************************/
    int av_image_fill_arrays(uint8_t *dst_data[4], int dst_linesize[4], const uint8_t *src,  
                                enum AVPixelFormat pix_fmt, int width, int height, int align);
                                
    av_image_fill_arrays()函数自身不具备内存申请的功能,此函数类似于格式化已经申请的内存,即通过av_malloc()函数申请的内存空间。
    再者,av_image_fill_arrays()中参数具体说明:
    dst_data[4]:        [out]对申请的内存格式化为三个通道后,分别保存其地址
    dst_linesize[4]:        [out]格式化的内存的步长(即内存对齐后的宽度)
    *src:        [in]av_alloc()函数申请的内存地址。
    pix_fmt:    [in] 申请 src内存时的像素格式
           [in]申请src内存时指定的宽度
    height:        [in]申请scr内存时指定的高度
    align:        [in]申请src内存时指定的对齐字节数。
    通过以上实例可以看到,(a)计算所需内存大小av_image_get_bufferz_size() --> (b) 按计算的内存大小申请所需内存 av_malloc()  --> (c) 对申请的内存进行格式化 av_image_fill_arrays();

    /********************************/
    libswscale常用的函数数量很少,一般情况下就3个:
    sws_getContext():初始化一个SwsContext。
    sws_scale():处理图像数据。
    sws_freeContext():释放一个SwsContext。

    /*************************/
    SwsContext *sws_getContext(int srcW, int srcH, enum AVPixelFormat srcFormat,
                               int dstW, int dstH, enum AVPixelFormat dstFormat,
                               int flags, SwsFilter *srcFilter,
                               SwsFilter *dstFilter, const double *param)                
                               
    成功后返回SwsContext 类型的结构体。
    参数1:被转换源的宽
    参数2:被转换源的高
    参数3:被转换源的格式,eg:YUV、RGB……(枚举格式,也可以直接用枚举的代号表示eg:AV_PIX_FMT_YUV420P这些枚举的格式在libavutil/pixfmt.h中列出)
    参数4:转换后指定的宽
    参数5:转换后指定的高
    参数6:转换后指定的格式同参数3的格式
    参数7:转换所使用的算法
    参数8:NULL
    参数9:NULL
    参数10:NULL                           

    /**********************/
    真正用来做转换的函数则是: sws_scale() ,其函数定义如下:
    int sws_scale(struct SwsContext *c, const uint8_t *const srcSlice[],
                  const int srcStride[], int srcSliceY, int srcSliceH,
                  uint8_t *const dst[], const int dstStride[]);
                  
    下面对其函数参数进行详细说明:
    1.参数 SwsContext *c, 转换格式的上下文。也就是 sws_getContext 函数返回的结果。
    2.参数 const uint8_t *const srcSlice[], 输入图像的每个颜色通道的数据指针。其实就是解码后的AVFrame中的data[]数组。因为不同像素的存储格式不同,所以srcSlice[]维数
    也有可能不同。
    以YUV420P为例,它是planar格式,它的内存中的排布如下:
    YYYYYYYY UUUU VVVV
    使用FFmpeg解码后存储在AVFrame的data[]数组中时:
    data[0]——-Y分量, Y1, Y2, Y3, Y4, Y5, Y6, Y7, Y8…… 
    data[1]——-U分量, U1, U2, U3, U4…… 
    data[2]——-V分量, V1, V2, V3, V4…… 
    linesize[]数组中保存的是对应通道的数据宽度 , 
    linesize[0]——-Y分量的宽度 
    linesize[1]——-U分量的宽度 
    linesize[2]——-V分量的宽度

    而RGB24,它是packed格式,它在data[]数组中则只有一维,它在存储方式如下:
    data[0]: R1, G1, B1, R2, G2, B2, R3, G3, B3, R4, G4, B4……
    这里要特别注意,linesize[0]的值并不一定等于图片的宽度,有时候为了对齐各解码器的CPU,实际尺寸会大于图片的宽度,这点在我们编程时(比如OpengGL硬件转换/渲染)要特别注意,否则解码出来的图像会异常。

    3.参数const int srcStride[],输入图像的每个颜色通道的跨度。.也就是每个通道的行字节数,对应的是解码后的AVFrame中的linesize[]数组。根据它可以确立下一行的起始位置,不过stride和width不一定相同,这是因为:
    a.由于数据帧存储的对齐,有可能会向每行后面增加一些填充字节这样 stride = width + N;
    b.packet色彩空间下,每个像素几个通道数据混合在一起,例如RGB24,每个像素3字节连续存放,因此下一行的位置需要跳过3*width字节。

    4.参数int srcSliceY, int srcSliceH,定义在输入图像上处理区域,srcSliceY是起始位置,srcSliceH是处理多少行。如果srcSliceY=0,srcSliceH=height,表示一次性处理完整个图像。
    这种设置是为了多线程并行,例如可以创建两个线程,第一个线程处理 [0, h/2-1]行,第二个线程处理 [h/2, h-1]行。并行处理加快速度。
    5.参数uint8_t *const dst[], const int dstStride[]定义输出图像信息(输出的每个颜色通道数据指针,每个颜色通道行字节数)              


    /********************************************/
    int av_read_frame(AVFormatContext *s, AVPacket *pkt);
    av_read_frame()使用方法在注释中写得很详细,用中文简单描述一下它的两个参数:
    s:输入的AVFormatContext
    pkt:输出的AVPacket
    av_read_frame()的作用是读取码流中的音频若干帧或者视频一帧。
    例如,解码视频的时候,每解码一个视频帧,需要先调用 av_read_frame()获得一帧视频的压缩数据,然后才能对该数据进行解码(例如H.264中一帧压缩数据通常对应一个NAL)。
    再次调用本函数之前,必须使用av_free_packet释放pkt所占用的资源。


    /********************************/
    int avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture,
                             int *got_picture_ptr,
                             const AVPacket *avpkt);
                             
    待解码的数据保存在avpkt->data中,大小为avpkt->size;解码完成后,picture用于保存输出图像数据。
    该方法的各个参数:
    AVCodecContext *avctx:编解码上下文环境,定义了编解码操作的一些细节;
    AVFrame *picture:输出参数;传递到该方法的对象本身必须在外部由av_frame_alloc()分配空间,而实际解码过后的数据储存区将由AVCodecContext.get_buffer2()分配;
            AVCodecContext.refcounted_frames表示该frame的引用计数,当这个值为1时,表示有另外一帧将该帧用作参考帧,而且参考帧返回给调用者;
            当参考完成时,调用者需要调用av_frame_unref()方法解除对该帧的参考;av_frame_is_writable()可以通过返回值是否为1来验证该帧是否可写。
    int *got_picture_ptr:该值为0表明没有图像可以解码,否则表明有图像可以解码;
    const AVPacket *avpkt:输入参数,包含待解码数据。

  • 相关阅读:
    netty+springboot+oracle+protobuf 搭建客户端服务端
    netty框架学习记录
    sql查询替换逗号拼接的字符窜
    Node的webpack打包的核心思想就是单页面富应用(SPA)
    Javascript 中的 CJS, AMD, UMD 和 ESM是什么
    springboot读取jar中resource下的文件
    zmq模块的理解和使用二
    问问题
    Java解析kml文件
    练习本
  • 原文地址:https://www.cnblogs.com/lidabo/p/15897670.html
Copyright © 2020-2023  润新知