本文记录IOS平台下基于FFmpeg的视频解码器。该示例C语言的源代码来自于《最简单的基于FFMPEG+SDL的视频播放器》。相关的概念就不再重复记录了。

源代码

项目的目录结构如图所示。

C代码位于ViewController.m文件中,内容如下所示。

  1.  
    /**
  2.  
    * 最简单的基于FFmpeg的视频解码器-IOS
  3.  
    * Simplest FFmpeg IOS Decoder
  4.  
    *
  5.  
    * 雷霄骅 Lei Xiaohua
  6.  
    * leixiaohua1020@126.com
  7.  
    * 中国传媒大学/数字电视技术
  8.  
    * Communication University of China / Digital TV Technology
  9.  
    * http://blog.csdn.net/leixiaohua1020
  10.  
    *
  11.  
    * 本程序是IOS平台下最简单的基于FFmpeg的视频解码器。
  12.  
    * 它可以将输入的视频数据解码成YUV像素数据。
  13.  
    *
  14.  
    * This software is the simplest decoder based on FFmpeg in IOS.
  15.  
    * It can decode video stream to raw YUV data.
  16.  
    *
  17.  
    */
  18.  
     
  19.  
    #import "ViewController.h"
  20.  
    #include <libavcodec/avcodec.h>
  21.  
    #include <libavformat/avformat.h>
  22.  
    #include <libavutil/imgutils.h>
  23.  
    #include <libswscale/swscale.h>
  24.  
     
  25.  
    @interface ViewController ()
  26.  
     
  27.  
    @end
  28.  
     
  29.  
    @implementation ViewController
  30.  
     
  31.  
    - (void)viewDidLoad {
  32.  
    [super viewDidLoad];
  33.  
    // Do any additional setup after loading the view, typically from a nib.
  34.  
    }
  35.  
     
  36.  
    - (void)didReceiveMemoryWarning {
  37.  
    [super didReceiveMemoryWarning];
  38.  
    // Dispose of any resources that can be recreated.
  39.  
    }
  40.  
     
  41.  
    - (IBAction)clickDecodeButton:(id)sender {
  42.  
    AVFormatContext *pFormatCtx;
  43.  
    int i, videoindex;
  44.  
    AVCodecContext *pCodecCtx;
  45.  
    AVCodec *pCodec;
  46.  
    AVFrame *pFrame,*pFrameYUV;
  47.  
    uint8_t *out_buffer;
  48.  
    AVPacket *packet;
  49.  
    int y_size;
  50.  
    int ret, got_picture;
  51.  
    struct SwsContext *img_convert_ctx;
  52.  
    FILE *fp_yuv;
  53.  
    int frame_cnt;
  54.  
    clock_t time_start, time_finish;
  55.  
    double time_duration = 0.0;
  56.  
     
  57.  
    char input_str_full[500]={0};
  58.  
    char output_str_full[500]={0};
  59.  
    char info[1000]={0};
  60.  
     
  61.  
    NSString *input_str= [NSString stringWithFormat:@"resource.bundle/%@",self.inputurl.text];
  62.  
    NSString *output_str= [NSString stringWithFormat:@"resource.bundle/%@",self.outputurl.text];
  63.  
     
  64.  
    NSString *input_nsstr=[[[NSBundle mainBundle]resourcePath] stringByAppendingPathComponent:input_str];
  65.  
    NSString *output_nsstr=[[[NSBundle mainBundle]resourcePath] stringByAppendingPathComponent:output_str];
  66.  
     
  67.  
    sprintf(input_str_full,"%s",[input_nsstr UTF8String]);
  68.  
    sprintf(output_str_full,"%s",[output_nsstr UTF8String]);
  69.  
     
  70.  
    printf("Input Path:%s\n",input_str_full);
  71.  
    printf("Output Path:%s\n",output_str_full);
  72.  
     
  73.  
    av_register_all();
  74.  
    avformat_network_init();
  75.  
    pFormatCtx = avformat_alloc_context();
  76.  
     
  77.  
    if(avformat_open_input(&pFormatCtx,input_str_full,NULL,NULL)!=0){
  78.  
    printf("Couldn't open input stream.\n");
  79.  
    return ;
  80.  
    }
  81.  
    if(avformat_find_stream_info(pFormatCtx,NULL)<0){
  82.  
    printf("Couldn't find stream information.\n");
  83.  
    return;
  84.  
    }
  85.  
    videoindex=-1;
  86.  
    for(i=0; i<pFormatCtx->nb_streams; i++)
  87.  
    if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO){
  88.  
    videoindex=i;
  89.  
    break;
  90.  
    }
  91.  
    if(videoindex==-1){
  92.  
    printf("Couldn't find a video stream.\n");
  93.  
    return;
  94.  
    }
  95.  
    pCodecCtx=pFormatCtx->streams[videoindex]->codec;
  96.  
    pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
  97.  
    if(pCodec==NULL){
  98.  
    printf("Couldn't find Codec.\n");
  99.  
    return;
  100.  
    }
  101.  
    if(avcodec_open2(pCodecCtx, pCodec,NULL)<0){
  102.  
    printf("Couldn't open codec.\n");
  103.  
    return;
  104.  
    }
  105.  
     
  106.  
    pFrame=av_frame_alloc();
  107.  
    pFrameYUV=av_frame_alloc();
  108.  
    out_buffer=(unsigned char *)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height,1));
  109.  
    av_image_fill_arrays(pFrameYUV->data, pFrameYUV->linesize,out_buffer,
  110.  
    AV_PIX_FMT_YUV420P,pCodecCtx->width, pCodecCtx->height,1);
  111.  
    packet=(AVPacket *)av_malloc(sizeof(AVPacket));
  112.  
     
  113.  
    img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,
  114.  
    pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
  115.  
     
  116.  
     
  117.  
    sprintf(info, "[Input ]%s\n", [input_str UTF8String]);
  118.  
    sprintf(info, "%s[Output ]%s\n",info,[output_str UTF8String]);
  119.  
    sprintf(info, "%s[Format ]%s\n",info, pFormatCtx->iformat->name);
  120.  
    sprintf(info, "%s[Codec ]%s\n",info, pCodecCtx->codec->name);
  121.  
    sprintf(info, "%s[Resolution]%dx%d\n",info, pCodecCtx->width,pCodecCtx->height);
  122.  
     
  123.  
     
  124.  
    fp_yuv=fopen(output_str_full,"wb+");
  125.  
    if(fp_yuv==NULL){
  126.  
    printf("Cannot open output file.\n");
  127.  
    return;
  128.  
    }
  129.  
     
  130.  
    frame_cnt=0;
  131.  
    time_start = clock();
  132.  
     
  133.  
    while(av_read_frame(pFormatCtx, packet)>=0){
  134.  
    if(packet->stream_index==videoindex){
  135.  
    ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);
  136.  
    if(ret < 0){
  137.  
    printf("Decode Error.\n");
  138.  
    return;
  139.  
    }
  140.  
    if(got_picture){
  141.  
    sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height,
  142.  
    pFrameYUV->data, pFrameYUV->linesize);
  143.  
     
  144.  
    y_size=pCodecCtx->width*pCodecCtx->height;
  145.  
    fwrite(pFrameYUV->data[0],1,y_size,fp_yuv); //Y
  146.  
    fwrite(pFrameYUV->data[1],1,y_size/4,fp_yuv); //U
  147.  
    fwrite(pFrameYUV->data[2],1,y_size/4,fp_yuv); //V
  148.  
    //Output info
  149.  
    char pictype_str[10]={0};
  150.  
    switch(pFrame->pict_type){
  151.  
    case AV_PICTURE_TYPE_I:sprintf(pictype_str,"I");break;
  152.  
    case AV_PICTURE_TYPE_P:sprintf(pictype_str,"P");break;
  153.  
    case AV_PICTURE_TYPE_B:sprintf(pictype_str,"B");break;
  154.  
    default:sprintf(pictype_str,"Other");break;
  155.  
    }
  156.  
    printf("Frame Index: %5d. Type:%s\n",frame_cnt,pictype_str);
  157.  
    frame_cnt++;
  158.  
    }
  159.  
    }
  160.  
    av_free_packet(packet);
  161.  
    }
  162.  
    //flush decoder
  163.  
    //FIX: Flush Frames remained in Codec
  164.  
    while (1) {
  165.  
    ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);
  166.  
    if (ret < 0)
  167.  
    break;
  168.  
    if (!got_picture)
  169.  
    break;
  170.  
    sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height,
  171.  
    pFrameYUV->data, pFrameYUV->linesize);
  172.  
    int y_size=pCodecCtx->width*pCodecCtx->height;
  173.  
    fwrite(pFrameYUV->data[0],1,y_size,fp_yuv); //Y
  174.  
    fwrite(pFrameYUV->data[1],1,y_size/4,fp_yuv); //U
  175.  
    fwrite(pFrameYUV->data[2],1,y_size/4,fp_yuv); //V
  176.  
    //Output info
  177.  
    char pictype_str[10]={0};
  178.  
    switch(pFrame->pict_type){
  179.  
    case AV_PICTURE_TYPE_I:sprintf(pictype_str,"I");break;
  180.  
    case AV_PICTURE_TYPE_P:sprintf(pictype_str,"P");break;
  181.  
    case AV_PICTURE_TYPE_B:sprintf(pictype_str,"B");break;
  182.  
    default:sprintf(pictype_str,"Other");break;
  183.  
    }
  184.  
    printf("Frame Index: %5d. Type:%s\n",frame_cnt,pictype_str);
  185.  
    frame_cnt++;
  186.  
    }
  187.  
    time_finish = clock();
  188.  
    time_duration=(double)(time_finish - time_start);
  189.  
     
  190.  
    sprintf(info, "%s[Time ]%fus\n",info,time_duration);
  191.  
    sprintf(info, "%s[Count ]%d\n",info,frame_cnt);
  192.  
     
  193.  
    sws_freeContext(img_convert_ctx);
  194.  
     
  195.  
    fclose(fp_yuv);
  196.  
     
  197.  
    av_frame_free(&pFrameYUV);
  198.  
    av_frame_free(&pFrame);
  199.  
    avcodec_close(pCodecCtx);
  200.  
    avformat_close_input(&pFormatCtx);
  201.  
     
  202.  
    NSString * info_ns = [NSString stringWithFormat:@"%s", info];
  203.  
    self.infomation.text=info_ns;
  204.  
     
  205.  
    }
  206.  
     
  207.  
     
  208.  
    @end

运行结果

App在手机上运行后的结果如下图所示。单击“Decode”,将会把位于resource.bundle中的“sintel.mov”文件解码为“sintel.yuv”文件并存储于相同的目录下。

生成的文件如下图所示。

 
 

本文转载自网络,感谢原作者的分享,转载仅为分享干货知识,如有侵权欢迎联系作者进行删除处理。

最简单的基于FFmpeg的直播系统开发移动端例子:IOS 视频解码器的更多相关文章

  1. 简单red5+obs推流实现直播系统开发,具体设置介绍

    前言:随便搞搞,先放一张效果图,

  2. 最简单的基于FFmpeg的内存读写的例子:内存播放器

    ===================================================== 最简单的基于FFmpeg的内存读写的例子系列文章列表: 最简单的基于FFmpeg的内存读写的 ...

  3. (转)最简单的基于FFmpeg的内存读写的例子:内存播放器

    ffmpeg内存播放解码 目录(?)[+] ===================================================== 最简单的基于FFmpeg的内存读写的例子系列文章 ...

  4. 最简单的基于FFmpeg的推流器(以推送RTMP为例)

    ===================================================== 最简单的基于FFmpeg的推流器系列文章列表: <最简单的基于FFmpeg的推流器(以 ...

  5. 最简单的基于FFmpeg的AVDevice例子(屏幕录制)

    =====================================================最简单的基于FFmpeg的AVDevice例子文章列表: 最简单的基于FFmpeg的AVDev ...

  6. 最简单的基于FFmpeg的AVDevice例子(读取摄像头)

    =====================================================最简单的基于FFmpeg的AVDevice例子文章列表: 最简单的基于FFmpeg的AVDev ...

  7. [转载] 最简单的基于FFmpeg的AVDevice例子(读取摄像头)

    =====================================================最简单的基于FFmpeg的AVDevice例子文章列表: 最简单的基于FFmpeg的AVDev ...

  8. 100行代码实现最简单的基于FFMPEG+SDL的视频播放器(SDL1.x)【转】

    转自:http://blog.csdn.net/leixiaohua1020/article/details/8652605 版权声明:本文为博主原创文章,未经博主允许不得转载.   目录(?)[-] ...

  9. 最简单的基于FFmpeg的AVDevice例子(读取摄像头)【转】

    转自:http://blog.csdn.net/leixiaohua1020/article/details/39702113 版权声明:本文为博主原创文章,未经博主允许不得转载.   目录(?)[- ...

随机推荐

  1. gitlab-centos的安装

    一:gitlab-CentOS的安装  1. 环境准备 1 [root@1-231 ~]# cat /etc/redhat-release 2 CentOS Linux release 7.4.170 ...

  2. volatile型变量语义讲解一 :对所有线程的可见性

    volatile型变量语义讲解一 :对所有线程的可见性 一.volatile变量语义一的概念 当一个变量被定义成volatile之后,具备两个特性: 特性一:保证此变量对所有线程的可见性.这里的&qu ...

  3. 多测师讲解自动化测试 _RF自定义关键字_高级讲师肖sir

    RF自定义关键字 在rf中叫关键字 在python中就叫做函数 或实例方法 我们自己可以写自定义关键字 自己创建一个库===库里面去创建模块===模块里面创建类和实例方法==>rf导入和引用 库 ...

  4. 修改LiveChart的提示显示位置

    问题:修改LiveChart的提示显示位置 摘要:相信WPF开发者在用LiveCharts的时候会有遇到这个需求.就是产品要求折线图的提示要显示的正常点. 需求:如下图所示.原本显示是在下方并且没有小 ...

  5. linux centos 03

    linux用户权限相关 root用户  相当于qq群的群主 sudo命令  相当于qq群的管理员 普通用户  相当于qq群的 水军 超级用户root的UID是 0  组ID也是 0  普通用户的UID ...

  6. 【图论】HDU 5961 传递

    题目内容 题目链接 我们称一个有向图G是传递的当且仅当对任意三个不同的顶点a,若G中有 一条边从a到b且有一条边从b到c ,则G中同样有一条边从a到c. 我们称图G是一个竞赛图,当且仅当它是一个有向图 ...

  7. git的一些操作命令

    一,如何修改一个commit的注释? root@kubuntu:/data/git/clog# git commit --amend 说明:架构森林是一个专注架构的博客,地址:https://www. ...

  8. 第十一章 LNMP架构基础介绍

    一.LNMP架构 1.简介 oLNMP是一套技术的组合,L=Linux.N=Nginx.M~=MySQL.P~=PHP不仅仅包含这些,还有redis/ELK/zabbix/git/jenkins/ka ...

  9. JAVA中Object类方法详解

    一.引言 Object是java所有类的基类,是整个类继承结构的顶端,也是最抽象的一个类.大家天天都在使用toString().equals().hashCode().waite().notify() ...

  10. UVA 12298 Super Poker II (FFT)

    #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> using ...