zoukankan      html  css  js  c++  java
  • 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
    
  • 相关阅读:
    sed command
    【Python3】作用域(局部变量、全局变量)
    【Python3】函数与参数
    【Python3】编程范式
    【Python3】字符解码与编码
    【Python3】文件操作
    【Python3】集合
    【Python3】目录
    【Python3】字典
    【Python3】字符串操作
  • 原文地址:https://www.cnblogs.com/schips/p/12199634.html
Copyright © 2011-2022 走看看