zoukankan      html  css  js  c++  java
  • 最简单的基于FFmpeg的移动端例子:IOS 视频解码器

    本文记录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 ",input_str_full);  
    71.     printf("Output Path:%s ",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. ");  
    79.         return ;  
    80.     }  
    81.     if(avformat_find_stream_info(pFormatCtx,NULL)<0){  
    82.         printf("Couldn't find stream information. ");  
    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. ");  
    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. ");  
    99.         return;  
    100.     }  
    101.     if(avcodec_open2(pCodecCtx, pCodec,NULL)<0){  
    102.         printf("Couldn't open codec. ");  
    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 ", [input_str UTF8String]);  
    118.     sprintf(info, "%s[Output    ]%s ",info,[output_str UTF8String]);  
    119.     sprintf(info, "%s[Format    ]%s ",info, pFormatCtx->iformat->name);  
    120.     sprintf(info, "%s[Codec     ]%s ",info, pCodecCtx->codec->name);  
    121.     sprintf(info, "%s[Resolution]%dx%d ",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. ");  
    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. ");  
    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 ",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 ",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 ",info,time_duration);  
    191.     sprintf(info, "%s[Count     ]%d ",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”文件并存储于相同的目录下。

    生成的文件如下图所示。

     

    下载


    simplest ffmpeg mobile

    项目主页

    Github:https://github.com/leixiaohua1020/simplest_ffmpeg_mobile

    开源中国:https://git.oschina.net/leixiaohua1020/simplest_ffmpeg_mobile

    SourceForge:https://sourceforge.net/projects/simplestffmpegmobile/

    CSDN工程下载地址:http://download.csdn.net/detail/leixiaohua1020/8924391

    本解决方案包含了使用FFmpeg在移动端处理多媒体的各种例子:

    [Android]
    simplest_android_player: 基于安卓接口的视频播放器
    simplest_ffmpeg_android_helloworld: 安卓平台下基于FFmpeg的HelloWorld程序
    simplest_ffmpeg_android_decoder: 安卓平台下最简单的基于FFmpeg的视频解码器
    simplest_ffmpeg_android_decoder_onelib: 安卓平台下最简单的基于FFmpeg的视频解码器-单库版
    simplest_ffmpeg_android_streamer: 安卓平台下最简单的基于FFmpeg的推流器
    simplest_ffmpeg_android_transcoder: 安卓平台下移植的FFmpeg命令行工具
    simplest_sdl_android_helloworld: 移植SDL到安卓平台的最简单程序
    [IOS]
    simplest_ios_player: 基于IOS接口的视频播放器
    simplest_ffmpeg_ios_helloworld: IOS平台下基于FFmpeg的HelloWorld程序
    simplest_ffmpeg_ios_decoder: IOS平台下最简单的基于FFmpeg的视频解码器
    simplest_ffmpeg_ios_streamer: IOS平台下最简单的基于FFmpeg的推流器
    simplest_ffmpeg_ios_transcoder: IOS平台下移植的ffmpeg.c命令行工具
    simplest_sdl_ios_helloworld: 移植SDL到IOS平台的最简单程序
  • 相关阅读:
    《深入理解 Java 虚拟机》读书笔记:线程安全与锁优化
    《深入理解 Java 虚拟机》读书笔记:Java 内存模型与线程
    《深入理解 Java 虚拟机》读书笔记:晚期(运行期)优化
    《深入理解 Java 虚拟机》读书笔记:早期(编译期)优化
    《深入理解 Java 虚拟机》读书笔记:虚拟机字节码执行引擎
    《深入理解 Java 虚拟机》读书笔记:虚拟机类加载机制
    Java学习书籍推荐
    IntelliJ IDEA之新建项目后之前的项目不见了
    剑指Offer之左旋转字符串
    剑指Offer之和为S的两个数字
  • 原文地址:https://www.cnblogs.com/Samboo/p/6097432.html
Copyright © 2011-2022 走看看