#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <stdio.h>

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;
 
  // Write header
  fprintf(pFile, "P6\n%d %d\n255\n", width, height);
 
  // Write pixel data
  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;
  static int sws_flags = SWS_BICUBIC;
  struct SwsContext *img_convert_ctx;
   AVPicture pict; 
  argc = 2;
  argv[1] = "d:\\temp\\test.264";
  if(argc < 2) {
    printf("Please provide a movie file\n");
    return -1;
  }
  // /*注册所有可用的格式和编解码器*/
  av_register_all();
 
  // Open video file /*以输入方式打开一个媒体文件,也即源文件,
codecs并没有打开,只读取了文件的头信息*/
  if(av_open_input_file(&pFormatCtx, argv[1], NULL, 0, NULL)!=0)
    return -1; // Couldn't open file
 
  // Retrieve stream information
/*通过读取媒体文件的中的包来获取媒体文件中的流信息,对于没有头信息的文件如(mpeg)是非常有用的,

// 该函数通常重算类似mpeg-2帧模式的真实帧率,该函数并未改变逻辑文件的position.
*/
  if(av_find_stream_info(pFormatCtx)<0)
    return -1; // Couldn't find stream information
 
  // Dump information about file onto standard error
//该函数的作用就是检查下初始化过程中设置的参数是否符合规范

dump_format(pFormatCtx, 0, argv[1], 0);
 
  // Find the first video stream
  videoStream=-1;
  for(i=0; i<pFormatCtx->nb_streams; i++)
    if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO&&videoStream < 0)
 {
      videoStream=i;
      break;
    }
  if(videoStream==-1)
    return -1; // Didn't find a video stream
 
  // Get a pointer to the codec context for the video stream
  pCodecCtx=pFormatCtx->streams[videoStream]->codec;
 
  // Find the decoder for the video stream
  pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
/*通过code ID查找一个已经注册的音视频编码器,查找编码器之前,必须先调用av_register_all注册所有支持的编码器
音视频编码器保存在一个链表中,查找过程中,函数从头到尾遍历链表,通过比较编码器的ID来查找

*/
  if(pCodec==NULL) {
    fprintf(stderr, "Unsupported codec!\n");
    return -1; // Codec not found
  }
  // Open codec
//使用给定的AVCodec初始化AVCodecContext

if(avcodec_open(pCodecCtx, pCodec)<0)
    return -1; // Could not open codec
 
  // Allocate video frame
  pFrame=avcodec_alloc_frame();
 
  // Allocate an AVFrame structure
  pFrameRGB=avcodec_alloc_frame();
  if(pFrameRGB==NULL)
    return -1;
 
  // Determine required buffer size and allocate buffer
  numBytes=avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width,
         pCodecCtx->height);
  buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t));
 
  // Assign appropriate parts of buffer to image planes in pFrameRGB
  // Note that pFrameRGB is an AVFrame, but AVFrame is a superset
  // of AVPicture
  avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24,
   pCodecCtx->width, pCodecCtx->height);
 
  // Read frames and save first five frames to disk
  i=0;
  while(av_read_frame(pFormatCtx, &packet)>=0)
  {
    // Is this a packet from the video stream?
    if(packet.stream_index==videoStream)
 {
    // Decode video frame
    avcodec_decode_video(pCodecCtx, pFrame, &frameFinished,
       packet.data, packet.size);
     
    // Did we get a video frame?
    if(frameFinished)
    {
  // Convert the image from its native format to RGB

#if 0
     // Convert the image into YUV format that SDL uses
     img_convert(&pict, PIX_FMT_YUV420P,
         (AVPicture *)pFrame, pCodecCtx->pix_fmt,
       pCodecCtx->width, pCodecCtx->height);
    #else
      /*   img_convert(&pict, dst_pix_fmt,
      (AVPicture *)pFrame, is->video_st->codec->pix_fmt,
      is->video_st->codec->width, is->video_st->codec->height);
      */

img_convert_ctx = sws_getContext( pCodecCtx->width,
               pCodecCtx->height,
               pCodecCtx->pix_fmt,
               pCodecCtx->width,
               pCodecCtx->height,
               PIX_FMT_YUV420P,
               sws_flags, NULL, NULL, NULL);

sws_scale(img_convert_ctx,(const uint8_t* const*)pFrame->data,pFrame->linesize,0,pCodecCtx->height,pFrameRGB->data,pFrameRGB->linesize);  
        sws_freeContext(img_convert_ctx);
    #endif
     
     // Save the frame to disk
     if((++i<=100)&&(i>95))
       SaveFrame(pFrameRGB, pCodecCtx->width, pCodecCtx->height, i);
    }
    }
   
    // Free the packet that was allocated by av_read_frame
    av_free_packet(&packet);
  }
 
  // Free the RGB image
  av_free(buffer);
  av_free(pFrameRGB);
 
  // Free the YUV frame
  av_free(pFrame);
 
  // Close the codec
  avcodec_close(pCodecCtx);
 
  // Close the video file
  av_close_input_file(pFormatCtx);
 
  return 0;
}

ffmpeg入门之 Tutorial01的更多相关文章

  1. FFmpeg 入门(1):截取视频帧

    本文转自:FFmpeg 入门(1):截取视频帧 | www.samirchen.com 背景 在 Mac OS 上如果要运行教程中的相关代码需要先安装 FFmpeg,建议使用 brew 来安装: // ...

  2. FFmpeg入门,简单播放器

    一个偶然的机缘,好像要做直播相关的项目 为了筹备,前期做一些只是储备,于是开始学习ffmpeg 这是学习的第一课 做一个简单的播放器,播放视频画面帧 思路是,将视频文件解码,得到帧,然后使用定时器,1 ...

  3. FFmpeg 入门(7):Seeking

    本文转自:FFmpeg 入门(7):Seeking | www.samirchen.com 处理 seek 命令 我们将为播放器添加 seek 的能力.这个过程中,我们会看到 av_seek_fram ...

  4. FFmpeg 入门(6):音频同步

    本文转自:FFmpeg 入门(6):音频同步 | www.samirchen.com 音频同步 上一节我们做了将视频同步到音频时钟,这一节我们反过来,将音频同步到视频.首先,我们要实现一个视频时钟来跟 ...

  5. FFmpeg 入门(5):视频同步

    本文转自:FFmpeg 入门(5):视频同步 | www.samirchen.com 视频如何同步 在之前的教程中,我们已经可以开始播放视频了,也已经可以开始播放音频了,但是视频和音频的播放还未同步, ...

  6. FFmpeg 入门(4):线程分治

    本文转自:FFmpeg 入门(4):线程分治 | www.samirchen.com 概览 上一节教程中,我们使用 SDL 的音频相关的函数来支持音频播放.SDL 起了一个线程来在需要音频数据的时候去 ...

  7. FFmpeg 入门(2):输出视频到屏幕

    本文转自:FFmpeg 入门(2):输出视频到屏幕 | www.samirchen.com SDL 我们这里使用 SDL 来渲染视频到屏幕.SDL 是 Simple Direct Layer 的缩写, ...

  8. FFmpeg 入门(3):播放音频

    本文转自:FFmpeg 入门(3):播放音频 | www.samirchen.com 音频 SDL 提供了播放音频的方法.SDL_OpenAudio 函数用来让设备播放音频,它需要我们传入一个包含了所 ...

  9. ffmpeg入门

    总入口 http://blog.csdn.net/leixiaohua1020/article/details/15811977 各结构体介绍 http://blog.csdn.net/leixiao ...

随机推荐

  1. IIS与Apache禁止IP地址直接访问网站

    一.IIS 防止恶意域名指向解决方法 首先单击"开始"-"设置"-"控制面板"-"管理工具",找到"Inter ...

  2. 安装puppeteer

    Puppeteer是一个node库,他提供了一组用来操纵Chrome的API,默认headless也就是无UI的chrome,也可以配置为有UI. 其实有点类似于PhantomJS,但Puppetee ...

  3. 小白学Docker之Compose

    承接上篇文章:小白学Docker之基础篇,自学网站来源于https://docs.docker.com/get-started 概念 Compose是一个编排和运行多容器Docker应用的工具,主要是 ...

  4. WPF中,多key值绑定问题,一个key绑定一个界面上的对象

    问题说明: 当用到dictionary<key,value>来储存数据的时候,有时候需要在界面上绑定一个key来显示value,这时候有两种思路: 一种是写一个自定义的扩展类,类似Bind ...

  5. 安装Mercurial进行版本管理

    mercurial是又一个去中心化的版本管理软件,类似git 先介绍如何安装mercurial yum -y install mercurial mercurial需要一个用户名来记录commit动作 ...

  6. ABP官方文档翻译 6.4 导航

    导航 创建菜单 注册导航提供者 显示菜单 每一个网络应用都会有一些菜单用来在pages/screens之间导航.ABP提供了通用的基础设施来创建并显示菜单. 创建菜单 应用可以由不同的模块组成,每一个 ...

  7. CAS基础和原子类

    基于CAS实现的AtomicInteger. AtomicLong. AtomicReference. AtomicBoolean也被称为乐观锁. CAS的语义是“我认为V的值应该为A,如果是,那么将 ...

  8. #1280 : Rikka with Sequence II [meet int the middle]

    tle弃疗了 等着回学校找个标程拍一下吧 #include <iostream> #include <cstdio> #include <cstring> #inc ...

  9. bzoj 4869: [Shoi2017]相逢是问候 [扩展欧拉定理 线段树]

    4869: [Shoi2017]相逢是问候 题意:一个序列,支持区间\(a_i \leftarrow c^{a_i}\),区间求和.在模p意义下. 类似于开根操作,每次取phi在log次后就不变了. ...

  10. Markdown 安装图解(破解汉化教程)

    http://blog.csdn.net/taokai_110/article/details/72934818 终于解决了问题