简单介绍

本例解说了怎样使用ffmpeg SDK解码媒体文件;

參考源代码是ffmpeg 自带的apiexample.c

一、源代码
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>

#ifdef HAVE_AV_CONFIG_H
#undef HAVE_AV_CONFIG_H
#endif

#include "libavcodec/avcodec.h"
#define INBUF_SIZE 4096

void pgm_save(unsigned char *buf,int wrap, int xsize,int ysize,char *filename)
{
  FILE *f;
  int i;

  f=fopen(filename,"w");
  fprintf(f,"P5\n%d %d\n%d\n",xsize,ysize,255);
  for(i=0;i<ysize;i++)
  fwrite(buf + i * wrap,1,xsize,f);
  fclose(f);
}

/*
 * Video decoding
 */
void video_decode_example(const char *outfilename, const char *filename)
{
  AVCodec *codec;
  AVCodecContext *c= NULL;
  int frame, size, got_picture, len;
  FILE *f;
  AVFrame *picture;
  uint8_t inbuf[INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE], *inbuf_ptr;
  char buf[1024];

  uint8_t *pkt_ptr, pkt_len;

  /* set end of buffer to 0 (this ensures that no overreading happens for damaged mpeg streams) */
  memset(inbuf + INBUF_SIZE, 0, FF_INPUT_BUFFER_PADDING_SIZE);

  printf("Video decoding\n");

  /* find the mpeg1 video decoder */
  //codec = avcodec_find_decoder(CODEC_ID_H264);
  codec = avcodec_find_decoder(CODEC_ID_MPEG2VIDEO);
  if (!codec) {
    fprintf(stderr, "codec not found\n");
    exit(1);
  }

  c= avcodec_alloc_context();
  picture= avcodec_alloc_frame();

  if(codec->capabilities&CODEC_CAP_TRUNCATED)
  c->flags|= CODEC_FLAG_TRUNCATED; /* we dont send complete frames */

  /* for some codecs, such as msmpeg4 and mpeg4, width and height
     MUST be initialized there because these info are not available
     in the bitstream */

  /* open it */
  if (avcodec_open(c, codec) < 0) {
    fprintf(stderr, "could not open codec\n");
    exit(1);
  }

  /* the codec gives us the frame size, in samples */
  f = fopen(filename, "rb");
  if (!f) {
    fprintf(stderr, "could not open %s\n", filename);
    exit(1);
  }
  frame = 0;
  for(;;) {
    AVPacket pkt;

    if (av_read_frame(c, &pkt) < 0) {
      continue;
    }

    //        size = fread(inbuf, 1, INBUF_SIZE, f);
    //        if (size == 0)
    //            break;

    /* NOTE1: some codecs are stream based (mpegvideo, mpegaudio)
       and this is the only method to use them because you cannot
       know the compressed data size before analysing it.

       BUT some other codecs (msmpeg4, mpeg4) are inherently frame
       based, so you must call them with all the data for one
       frame exactly. You must also initialize 'width' and
       'height' before initializing them. */

    /* NOTE2: some codecs allow the raw parameters (frame size,
       sample rate) to be changed at any frame. We handle this, so
       you should also take care of it */

    /* here, we use a stream based decoder (mpeg1video), so we
       feed decoder and see if it could decode a frame */
    pkt_len = pkt.size;
    pkt_ptr = pkt.data;

    //  inbuf_ptr = inbuf;
    while (pkt_len > 0) {
      len = avcodec_decode_video2(c, picture, &got_picture,
            &pkt);
      if (len < 0) {
        fprintf(stderr, "Error while decoding frame %d\n", frame);
        exit(1);
      }
      if (got_picture) {
        printf("saving frame %3d\n", frame);
        fflush(stdout);

        /* the picture is allocated by the decoder. no need to
           free it */
        snprintf(buf, sizeof(buf), outfilename, frame);
        pgm_save(picture->data[0], picture->linesize[0],
              c->width, c->height, buf);
        frame++;
      }
      size -= len;
      inbuf_ptr += len;
    }
    av_free_packet(&pkt);
  }

  /* some codecs, such as MPEG, transmit the I and P frame with a
     latency of one frame. You must do the following to have a
     chance to get the last frame of the video */
  len = avcodec_decode_video2(c, picture, &got_picture,
        NULL);
  if (got_picture) {
    printf("saving last frame %3d\n", frame);
    fflush(stdout);

    /* the picture is allocated by the decoder. no need to
       free it */
    snprintf(buf, sizeof(buf), outfilename, frame);
    pgm_save(picture->data[0], picture->linesize[0],
          c->width, c->height, buf);
    frame++;
  }

  fclose(f);

  avcodec_close(c);
  av_free(c);
  av_free(picture);
  printf("\n");
}

int main(int argc, char **argv)
{
  const char *filename;

  /* must be called before using avcodec lib */
  avcodec_init();

  /* register all the codecs (you can also register only the codec
     you wish to have smaller code */
  avcodec_register_all();

  if (argc <= 1) {
    //        audio_encode_example("/tmp/test.mp2");
    //        audio_decode_example("/tmp/test.sw", "/tmp/test.mp2");

    video_encode_example("/tmp/test.mpg");
    filename = "/tmp/test.mpg";
  } else {
    filename = argv[1];
  }

  //    audio_decode_example("/tmp/test.sw", filename);
  video_decode_example("/tmp/test%d.pgm", filename);

  return 0;
}

二、代码分析
01  avcodec_init(), 初始化libavcodec
02  avcodec_register_all(), 注冊全部编解码器和格式

03  codec = avcodec_find_decoder(CODEC_ID_MPEG2VIDEO), 查找mpeg2 video解码器
04  c     = avcodec_alloc_context(), 分配AVCodecContext空间并初始化
05  picture = avcodec_alloc_frame(), 分配AVFrame的空间
06  avcodec_open(c, codec),  使用codec来初始化c

07  FOR循环 {
      07.1 av_read_frame(c, &pkt), 从输入文件里读取一个包
      07.2 pkt_len = pkt.size;
           pkt_ptr = pkt.data;
      07.3 while(pkt_len > 0) {
             07.3.1 avcodec_decode_video2(c, picture, &got_picture, &pkt), 解码当前包
             07.3.2 if (got_picture) {
                       pgm_save(picture->data[0], ...), 对解码后的YUV数据进行处理;
                       frame++;
                    }
             07.3.3 size -= len;
           }
      07.4 av_free_packet(&pkt), 释放当前包
    }
08  len = avcodec_decode_video2(c, picture, &got_picture, NULL); 解码最后的帧;
09  if (got_picture) { ...}, 处理最后帧的YUV数据

10  avcodec_close(c);
11  av_free(c)
12  av_free(picture);

FFmpeg SDK开发模型之中的一个:解码器的更多相关文章

  1. FFMPEG SDK 开发介绍(原创)

    来源:http://blog.sina.com.cn/s/blog_62a8419a01016exv.html 本文是作者在使用ffmpeg sdk开发过程中的实际经验,现在与大家分享,欢迎学习交流. ...

  2. SDK开发断点失效

    做SDK开发,一般会创建一个静态库工程,然后添加一个app的Target 可是,Xcode7创建的工程,app的Target中断点有效,能断住,为什么静态库的Target中的断点断不住呀. 断点断住发 ...

  3. 开发你的第一个BLE应用程序—Blinky

    本文将和大家一起编写我们的第一个BLE应用程序:Blinky(闪灯程序),哪怕你之前没有任何BLE开发经验,也不用担心,只要跟着文中所述步骤,你就可以一步步搭建自己的第一个BLE应用程序.通过这个Bl ...

  4. Android | 教你如何用华为HMS MLKit 图像分割 SDK开发一个证件照DIY小程序

    Android | 教你如何用华为HMS MLKit 图像分割 SDK开发一个证件照DIY小程序 引子   上期给大家介绍了如何使用如何用华为HMS MLKit SDK 三十分钟在安卓上开发一个微笑抓 ...

  5. iOS开发UI篇—使用嵌套模型完成的一个简单汽车图标展示程序

    iOS开发UI篇—使用嵌套模型完成的一个简单汽车图标展示程序 一.plist文件和项目结构图 说明:这是一个嵌套模型的示例 二.代码示例: YYcarsgroup.h文件代码: // // YYcar ...

  6. 使用Jquery+EasyUI进行框架项目开发案例解说之中的一个---员工管理源代码分享

    使用Jquery+EasyUI 进行框架项目开发案例解说之中的一个 员工管理源代码分享 在開始解说之前,我们先来看一下什么是Jquery EasyUI?jQuery EasyUI是一组基于jQuery ...

  7. 如何使用Add-on SDK开发一个自己的火狐扩展

    黄聪:如何使用Add-on SDK开发一个自己的火狐扩展 火狐开放了扩展的开发权限给程序员们,相信很多人都会希望自己做一些扩展来方便一些使用. 我最近做一些项目也需要开发一个火狐扩展,方便收集自己需要 ...

  8. 黄聪:如何使用Add-on SDK开发一个自己的火狐扩展

    火狐开放了扩展的开发权限给程序员们,相信很多人都会希望自己做一些扩展来方便一些使用. 我最近做一些项目也需要开发一个火狐扩展,方便收集自己需要的数据,因此研究了几天怎么开发,现在已经差不多完成了,就顺 ...

  9. FFMPEG SDK流媒体开发2---分离.mp4等输入流音视频而且进行解码输出

    对于FFMPEG SDK  提供的Demuxing 为我们实现多路复用  提供了非常多方便,以下的案案例 实现的是 分离一个媒体文件的音频 视频流 而且解码输出 到  不同的文件里. 对于音频被还原回 ...

随机推荐

  1. npm 安装与卸载模块

    1. 只卸载模块 由于之前安装过,在 package.json 中的记录仍然存在 npm uninstall lodash 2. --save 参数使用 卸载模块的同时删除在 package.json ...

  2. BZOJ 3545: [ONTAK2010]Peaks 启发式合并 + 离线 + Splay

    Description 在Bytemountains有N座山峰,每座山峰有他的高度h_i.有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询 ...

  3. 箱排序(Bin Sort)

    1.基本思想 排序过程无须比较关键字,而是通过"分配"和"收集"过程来实现排序.它们的时间复杂度可达到线性阶:O(n). 箱排序也称桶排序(Bucket Sor ...

  4. Python文件对象方法

    使用open()函数创建一个文件对象,这里是可以在这个对象上调用的函数的列表 - 编号 方法名称 描述 1 file.close() 关闭文件,无法读取或写入关闭的文件. 2 file.flush() ...

  5. Django学习之缓存

    1.配置 2.应用 由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用:缓存.缓存将一个某个views的返回值保存至内存或者m ...

  6. (转)使用NMAP工具扫描端口

    原文:http://www.linuxde.net/2013/02/12354.html nmap 是一个用于网络探索或安全评测的工具.它支持 ping 扫描(判定哪些主机在运行),多端口扫描技术(判 ...

  7. C# 自定义集合类

    .NET中提供了一种称为集合的类型,类似于数组,将一组类型化对象组合在一起,可通过遍历获取其中的每一个元素 本篇记录一个自定义集合的小实例.自定义集合需要通过实现System.Collections命 ...

  8. NeDB——node嵌入式数据库

    参考资料1:[http://www.alloyteam.com/2016/03/node-embedded-database-nedb/] 参考资料2:[https://github.com/loui ...

  9. c++中byte数组与字符串的转化

    我们不讨论与字符集有关的内容,只讨论在字节流传递过程中的问题. 我们在做一系统操作时会需要使用到数据流,比如接收网络数据,文件数据,图片数据,原始数据大多是以byte数组的形式提供,与其它语言(c#, ...

  10. Java之类的继承

    说起来Java的类,不得不说以下几个方面:继承.转型.重写.多态和接口. 今天来说一说继承,转型和重写几个方面: 继承(extends)即子类继承父类,就好比玻璃杯.保温杯等子类继承了杯子这个父类,子 ...