我在哪里可以找到 libav、ffmpeg 等的现代教程? [关闭]

Posted

技术标签:

【中文标题】我在哪里可以找到 libav、ffmpeg 等的现代教程? [关闭]【英文标题】:Where can I find modern tutorials for libav, ffmpeg, etc? [closed] 【发布时间】:2013-01-12 00:40:22 【问题描述】:

我想用 C 语言编写一个快速程序,它可以打开视频,将每一帧保存为 ppm,并转储运动矢量。我能找到的所有教程都是近十年前的,并且调用了已弃用或不存在的函数。

是否有任何好的在线资源、网站、视频或教科书涵盖了处理这些类型事情的现代方法?

【问题讨论】:

FFmpeg official examples 包括video decoding 和motion vectors extraction。 【参考方案1】:
        #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <fstream>
    #include <math.h>

    #define __STDC_CONSTANT_MACROS
    //FFMPEG LIBRARIES
    extern "C"
    
    #include "libavcodec/avcodec.h"
    #include "libswscale/swscale.h"
    #include "libavutil/opt.h"
    #include "libavutil/common.h"
    #include "libavutil/channel_layout.h"
    #include "libavutil/imgutils.h"
    #include "libavutil/mathematics.h"
    #include "libavutil/samplefmt.h"
    #include "libavutil/time.h"
    #include "libavformat/avformat.h"
    #include "libavformat/avio.h"
    #include "libavfilter/avfilter.h"
    #include "libavdevice/avdevice.h"
    #include "libavfilter/avfiltergraph.h"
    #include "libavfilter/buffersink.h"
    

    using namespace std;

    void SaveMyFrame(AVFrame *sAVFrame , int swidth, int sheight, int iFrame)
    
    FILE *pfile;
    char szFilename[32];
    int y;

    sprintf(szFilename , "frame%d.ppm" , iFrame);
    pfile = fopen(szFilename , "wb");
    if(pfile == NULL)
    
      cout<<"\n\ncould'nt open file";
      return;
    

    fprintf(pfile , "P6\n%d %d\n255\n" , swidth , sheight );

    for( y=0; y<sheight; y++)
    
      fwrite(sAVFrame->data[0]+y*sAVFrame->linesize[0] , 1 , swidth*3 , pfile );
    

    fclose(pfile);
    

    int CaptureScene(int VideoStreamIndx ,
                       AVFormatContext *bAVFormatContext ,
                       AVCodecContext *bAVCodecContext,
                       AVCodec *bAVCodec )
    
      AVPacket bAVPacket;
      AVFrame *bAVFrame = NULL;
      bAVFrame = av_frame_alloc();
      AVFrame *bAVFrameRGB = NULL;
      bAVFrameRGB = av_frame_alloc();

    if(bAVFrame == NULL)
    
      cout<<"\n\nframe alloc failed";
    

    if(bAVFrameRGB == NULL)
    
      cout<<"\n\nframe alloc RGB failed";
    

      int numBytes;
      uint8_t *buffer = NULL;

    numBytes =  av_image_get_buffer_size(AV_PIX_FMT_RGB24 , bAVCodecContext->width,bAVCodecContext->height, 32);  // avpicture_get_size  deprecated

    buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t));

    avpicture_fill((AVPicture *)bAVFrameRGB , buffer , AV_PIX_FMT_RGB24 , bAVCodecContext->width , bAVCodecContext->height);

    int framefinish;
    struct SwsContext *sws_ctx = NULL;
    sws_ctx = sws_getContext( bAVCodecContext->width,
                              bAVCodecContext->height,
                              bAVCodecContext->pix_fmt,
                              bAVCodecContext->width,
                              bAVCodecContext->height,
                              AV_PIX_FMT_RGB24,
                              SWS_BILINEAR,
                              NULL,NULL,NULL);
    int i =0;

    while(av_read_frame(bAVFormatContext,&bAVPacket) >=0)
    
          if(bAVPacket.stream_index == VideoStreamIndx)
      
          avcodec_decode_video2(bAVCodecContext , bAVFrame , &framefinish , &bAVPacket);
          if(framefinish)
        
          // convert image from native format to RGB
          sws_scale(sws_ctx , (uint8_t const* const *)bAVFrame->data ,
          bAVFrame->linesize , 0, bAVCodecContext->height,
          bAVFrameRGB->data , bAVFrameRGB->linesize);
          // save frame to disk
          if(++i <= 100)SaveMyFrame(bAVFrameRGB , bAVCodecContext->width , bAVCodecContext->height , i );

        

      

    

    av_free(bAVFrame);
    av_free(bAVFrameRGB);
    

    int main()
    

      avdevice_register_all();
      avcodec_register_all();
      av_register_all();

      char *dev_name = "/dev/video0";

     int VideoStreamIndx = -1;
     AVCodecContext *pAVCodecContext = NULL;
     AVCodec *pAVCodec = NULL;
     AVInputFormat *inputFormat =av_find_input_format("v4l2");
     AVDictionary *options = NULL;
     av_dict_set(&options, "framerate", "20", 0);

     AVFormatContext *pAVFormatContext = NULL;

     if(avformat_open_input(&pAVFormatContext, dev_name, inputFormat, NULL) != 0)
     
       cout<<"\nError : could'nt open video source\n\n";
       return -1;
     

     if( avformat_find_stream_info( pAVFormatContext , NULL) < 0)
     
     cout<<"Error : streams not found";
      return -1;
     

      av_dump_format(pAVFormatContext , 0 , "/dev/video1" , 0 );

     for(int i=0; i<pAVFormatContext->nb_streams ;i++ )
     
      if( pAVFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO ) // if video stream found then get the index.
      
        VideoStreamIndx = i;
        break;
      
     

    if((VideoStreamIndx) == -1)
    
      cout<<"Error : video streams not found";
      return -1;
    

    pAVCodecContext = pAVFormatContext->streams[VideoStreamIndx]->codec;

    pAVCodec = avcodec_find_decoder( pAVCodecContext->codec_id );

    if(pAVCodec == NULL)
    
     fprintf(stderr,"Unsupported codec !");
     return -1;
    

    int value = avcodec_open2(pAVCodecContext , pAVCodec , NULL);
    if( value < 0)
    
      cout<<"Error : Could not open codec";
      return -1;
    

    int Vwidth , Vheight , videoFPS , videoBaseTime , duration_2 ;
    int sframe , length , Fheight;

    /*
    To fetch/display some media information programatically
    */

    //int64_t duration_1 = pAVFormatContext->duration;
    videoFPS = av_q2d(pAVFormatContext->streams[VideoStreamIndx]->r_frame_rate);
    videoBaseTime = av_q2d(pAVFormatContext->streams[VideoStreamIndx]->time_base);
    Vwidth = pAVFormatContext->streams[VideoStreamIndx]->codec->width;
    Vheight = pAVFormatContext->streams[VideoStreamIndx]->codec->height;
    //duration_2 = (unsigned long)pAVFormatContext->streams[VideoStreamIndx]->duration*(videoFPS*videoBaseTime);

    cout<<"Video FPS :"<<videoFPS;
    cout<<"\n\n width : "<<Vwidth;
    cout<<"\n\n height : "<<Vheight;
    cout<<"\n\n time base"<<videoBaseTime;
    //cout<<"\n\nduration (1): "<<duration_1;
    //cout<<"\n\nduration (2): "<<duration_2;

    CaptureScene( VideoStreamIndx , pAVFormatContext , pAVCodecContext , pAVCodec );

    avcodec_close(pAVCodecContext);
    avformat_close_input(&pAVFormatContext);

    return 0;
    

此 C++ 代码将帮助您从基于 USB (UVC) 的相机中获取 .ppm 图像。它以 .ppm 格式保存。 linux 使用 v4l2,windows 使用 dshow。 代替相机帧馈送,视频也可以作为输入。 此代码使用最新的 ffmpeg 库编写。

libavutil 55. 24.100 / 55. 24.100

libavcodec 57. 43.100 / 57. 43.100

libavformat 57. 37.100 / 57. 37.100

libavdevice 57.0.101 / 57.0.101

libavfilter 6. 46.100 / 6. 46.100

libswscale 4. 1.100 / 4. 1.100

libswresample 2. 0.101 / 2. 0.101

libpostproc 54. 0.100 / 54. 0.100

【讨论】:

【参考方案2】:

我多年来一直在使用 ffmpeg 和 libav,但最近也没有找到像样的 API 级教程。有时我只需要深入研究源代码就可以弄清楚发生了什么以及如何使用它。此外,阅读 CLI 程序(使用底层库)的源代码也可以提供丰富的信息。

事实上,ffmpeg 建议您只阅读源代码,无论是真正的 OSS 项目还是它们的示例。 Libav 提供 Doxygen 文档,但没有分步教程。 IMO 这是典型的开源项目:源代码可能很好,但通常缺少文档。

退一步,您可能会考虑OpenCV,它有据可查(books 存在!)并且具有更简单的 API。最后,ppm是一种很简单的格式,你可能自己写一个50行的函数来保存像素,我找到了一个运动提取程序here。

【讨论】:

以上是关于我在哪里可以找到 libav、ffmpeg 等的现代教程? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

我在哪里可以找到 C/C++ FFmpeg 扩展教程? [关闭]

记录:libav库的交叉编译

Libav(ffmpeg)将解码的视频时间戳复制到编码器

我使用时间戳/时基使用 libav(ffmpeg)进行帧搜索/读取有啥问题?

在 c++ 中以可变帧速率使用 FFmpeg 库(不是 libav 分支)以编程方式捕获视频

使用 android studio 构建共享库(关于 FFMPEG/Libav 快速傅里叶变换)