ffmpeg 学习: 004-参考文档进行的开发

背景

在学习ffmpeg时,由于文档老旧以及ffmpeg新旧版本对于一些api的改动,导致学习受阻。

本来可以直接下载老的库,使用老的源码进行学习,但本人觉得,一味地守旧并不是一种好的方法。

ffmpeg 文档:

ffmpeg-在线文档 : v4.1
使用 Doxygen 生成文档 (以FFmpeg 4.1.1 为例)

思路

由于对于FFmpeg的了解还比较皮毛,所以我们使用一些旧的例程,将提示过时的方法改为新的方法。

首先,我们查看一份过时的例程

下面的代码基于 ffmpeg v4.0 编译,为了保证编译通过,已经事先做了小部分的更改。

// ffmpeg v4.0 
#include <stdio.h>

#define __STDC_CONSTANT_MACROS

//Linux...
#ifdef __cplusplus
extern "C"
{
#endif
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavfilter/avfilter.h>
#include <libswscale/swscale.h>
//#include <libavutil/imgutils.h>
#ifdef __cplusplus
};
#endif

void SaveFrame (AVFrame * pFrame, int width, int height, int iFrame)
{
    FILE *pFile;
    char szFilename[32];
    int y;
    // open file
    sprintf(szFilename, "frame%d.ppm", iFrame);
    pFile = fopen(szFilename, "wb");
    if(pFile == NULL) return;
    fprintf(pFile, "p6 
 %d %d
", width, height);
    for (y=0; y< height;y++)
    {
        fwrite(pFrame->data[0]+ y*pFrame->linesize[0], 1, width*3, pFile);
    }
    // Close file
    fclose(pFile);
}

int main(int argc, char *argv[])
{
    AVFormatContext *pFormatCtx;
    int i, videoStream;
    AVCodecContext *pCodecCtx;
    AVCodec *pCodec;
    AVFrame *pFrame;
    AVFrame *pFrameRGB;
    AVPacket packet;
    int frameFinished;
    int numBytes;
    uint8_t *buffer;
    if (argc <2 )
    {
        printf("Please provide a movie file
");
        return -1;
    }
    av_register_all();
    avformat_network_init();
    pFormatCtx = avformat_alloc_context();

    // Open the media file and read the header
    if (avformat_open_input(&pFormatCtx, argv[1], NULL,NULL)!=0)
    {
        printf("Couldn't open file
");
        return -1;
    }
    // retrieve stream information
    if(avformat_find_stream_info(pFormatCtx, NULL) < 0)
        return -1;
    // dump information about file into stand error
    av_dump_format(pFormatCtx, -1, argv[1], 0);

    // Find the first video stream
    videoStream = -1;
    for(i =0; i< pFormatCtx->nb_streams; i++)
    {
        if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
        {
            videoStream = i;
            printf("First stream is [%d]
", videoStream);
            break;
        }
    }
    if (videoStream == -1)
        return -1;
    // Get a pointer to the codec context for the video stream
    pCodecCtx = pFormatCtx->streams[videoStream]->codec;
    pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
    if(pCodec == NULL)
    {
        fprintf(stderr, "unsupported codec
");
        return -1;
    }
    // Open codec
    if(avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
        return -1;
    // allocate video frame
    pFrame = av_frame_alloc();
    if (NULL == pFrame) return -1;
    // allocate an avframe structure
    pFrameRGB = av_frame_alloc();
    if(pFrameRGB == NULL) return -1;
    // Determine required buffer size and allocate buffer
    numBytes = avpicture_get_size(AV_PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height);
    printf("avpicture isze is %d
", numBytes);
    buffer = (uint8_t *) av_malloc(numBytes * sizeof(uint8_t));
    avpicture_fill((AVPicture *)pFrameRGB, buffer, AV_PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height);
    i = 0;
    while(av_read_frame(pFormatCtx, &packet) >= 0)
    {
        if(packet.stream_index ==videoStream)
        {
            avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);

            if(frameFinished)
            {
                struct SwsContext * img_convert_ctx = NULL;
                img_convert_ctx = sws_getCachedContext(img_convert_ctx, pCodecCtx->width, pCodecCtx->height,
                    pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_RGB24, SWS_BICUBIC,
                    NULL, NULL, NULL);

                if (!img_convert_ctx)
                {
                    fprintf(stderr, "Cannot initalize sws conversion context
");
                    exit (-1);

                }
                sws_scale(img_convert_ctx, pFrame->data,
                          pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);
                if(i ++ < 50)
                    SaveFrame(pFrameRGB, pCodecCtx->width, pCodecCtx->height, i);
            }
        }
        av_packet_unref(&packet);
    }

    // Free the RGB image
    av_free(buffer);
    av_free(pFrameRGB);
    av_free(pFrame);
    avcodec_close(pCodecCtx);
    //av_close_input_file(pFormatCtx);
    avformat_close_input(&pFormatCtx);

    return 0;
}

编译,除了一堆警告以外,没有什么错误。

开始修改

先将每一个警告消除。

  1. 变量类型的不匹配
    for(i =0; i< pFormatCtx->nb_streams; i++)出现问题
    查阅有关的数据结构发现,是变量类型不匹配,将i改成 uint。

  2. 成员改名
    if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) 提示codec过气
    同样,查阅以后,将codec修改为codecpar

  3. 处理方式不同
    pCodecCtx = pFormatCtx->streams[videoStream]->codec;

之前的版本

    pCodecCtx = pFormatCtx->streams[videoStream]->codec;
    pCodec = avcodec_find_decoder(pCodecCtx->codec_id);

之后的版本

    pCodecCtx = avcodec_alloc_context3(NULL);  
    pCodecCtx = pFormatCtx->streams[videoStream]->codec;

    if (pCodecCtx == NULL)  
    {  
        // printf("Could not allocate AVCodecContext
");  
        return -1;  
    }  

     if (pFormatCtx->streams[i]/*视音频流*/->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
        // 处理音频
    }
    avcodec_parameters_to_context(pCodecCtx, pFormatCtx->streams[videoStream]->codecpar);  
    pCodecCtx = pFormatCtx->streams[videoStream]->codec;
  1. 过气函数 avpicture_get_size
    官方文档已经在 libavcodec/avcodec.h 说明:

/**
 * @deprecated use av_image_get_buffer_size() instead.
 */
attribute_deprecated int avpicture_get_size(enum AVPixelFormat pix_fmt, int width, int height);

由于没有在文档中很快找到 av_image_get_buffer_size,于是我在 头文件目录下搜索grep -nR av_image_get_buffer_size,找到是 libavutil这里的函数

libavcodec/avcodec.h:5650: * @deprecated use av_image_get_buffer_size() instead.
libavutil/imgutils.h:181:int av_image_get_buffer_size(enum AVPixelFormat pix_fmt, int width, int height, int align);
libavutil/imgutils.h:186: * av_image_get_buffer_size() can be used to compute the required size
原文地址:https://www.cnblogs.com/schips/p/12199634.html