最简单的基于FFmpeg的直播系统开发移动端例子:IOS 视频解码器
本文记录IOS平台下基于FFmpeg的视频解码器。该示例C语言的源代码来自于《最简单的基于FFMPEG+SDL的视频播放器》。相关的概念就不再重复记录了。
源代码
项目的目录结构如图所示。
C代码位于ViewController.m文件中,内容如下所示。
- /**
- * 最简单的基于FFmpeg的视频解码器-IOS
- * Simplest FFmpeg IOS Decoder
- *
- * 雷霄骅 Lei Xiaohua
- * leixiaohua1020@126.com
- * 中国传媒大学/数字电视技术
- * Communication University of China / Digital TV Technology
- * http://blog.csdn.net/leixiaohua1020
- *
- * 本程序是IOS平台下最简单的基于FFmpeg的视频解码器。
- * 它可以将输入的视频数据解码成YUV像素数据。
- *
- * This software is the simplest decoder based on FFmpeg in IOS.
- * It can decode video stream to raw YUV data.
- *
- */
- #import "ViewController.h"
- #include <libavcodec/avcodec.h>
- #include <libavformat/avformat.h>
- #include <libavutil/imgutils.h>
- #include <libswscale/swscale.h>
- @interface ViewController ()
- @end
- @implementation ViewController
- - (void)viewDidLoad {
- [super viewDidLoad];
- // Do any additional setup after loading the view, typically from a nib.
- }
- - (void)didReceiveMemoryWarning {
- [super didReceiveMemoryWarning];
- // Dispose of any resources that can be recreated.
- }
- - (IBAction)clickDecodeButton:(id)sender {
- AVFormatContext *pFormatCtx;
- int i, videoindex;
- AVCodecContext *pCodecCtx;
- AVCodec *pCodec;
- AVFrame *pFrame,*pFrameYUV;
- uint8_t *out_buffer;
- AVPacket *packet;
- int y_size;
- int ret, got_picture;
- struct SwsContext *img_convert_ctx;
- FILE *fp_yuv;
- int frame_cnt;
- clock_t time_start, time_finish;
- double time_duration = 0.0;
- char input_str_full[500]={0};
- char output_str_full[500]={0};
- char info[1000]={0};
- NSString *input_str= [NSString stringWithFormat:@"resource.bundle/%@",self.inputurl.text];
- NSString *output_str= [NSString stringWithFormat:@"resource.bundle/%@",self.outputurl.text];
- NSString *input_nsstr=[[[NSBundle mainBundle]resourcePath] stringByAppendingPathComponent:input_str];
- NSString *output_nsstr=[[[NSBundle mainBundle]resourcePath] stringByAppendingPathComponent:output_str];
- sprintf(input_str_full,"%s",[input_nsstr UTF8String]);
- sprintf(output_str_full,"%s",[output_nsstr UTF8String]);
- printf("Input Path:%s\n",input_str_full);
- printf("Output Path:%s\n",output_str_full);
- av_register_all();
- avformat_network_init();
- pFormatCtx = avformat_alloc_context();
- if(avformat_open_input(&pFormatCtx,input_str_full,NULL,NULL)!=0){
- printf("Couldn't open input stream.\n");
- return ;
- }
- if(avformat_find_stream_info(pFormatCtx,NULL)<0){
- printf("Couldn't find stream information.\n");
- return;
- }
- videoindex=-1;
- for(i=0; i<pFormatCtx->nb_streams; i++)
- if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO){
- videoindex=i;
- break;
- }
- if(videoindex==-1){
- printf("Couldn't find a video stream.\n");
- return;
- }
- pCodecCtx=pFormatCtx->streams[videoindex]->codec;
- pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
- if(pCodec==NULL){
- printf("Couldn't find Codec.\n");
- return;
- }
- if(avcodec_open2(pCodecCtx, pCodec,NULL)<0){
- printf("Couldn't open codec.\n");
- return;
- }
- pFrame=av_frame_alloc();
- pFrameYUV=av_frame_alloc();
- out_buffer=(unsigned char *)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height,1));
- av_image_fill_arrays(pFrameYUV->data, pFrameYUV->linesize,out_buffer,
- AV_PIX_FMT_YUV420P,pCodecCtx->width, pCodecCtx->height,1);
- packet=(AVPacket *)av_malloc(sizeof(AVPacket));
- img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,
- pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
- sprintf(info, "[Input ]%s\n", [input_str UTF8String]);
- sprintf(info, "%s[Output ]%s\n",info,[output_str UTF8String]);
- sprintf(info, "%s[Format ]%s\n",info, pFormatCtx->iformat->name);
- sprintf(info, "%s[Codec ]%s\n",info, pCodecCtx->codec->name);
- sprintf(info, "%s[Resolution]%dx%d\n",info, pCodecCtx->width,pCodecCtx->height);
- fp_yuv=fopen(output_str_full,"wb+");
- if(fp_yuv==NULL){
- printf("Cannot open output file.\n");
- return;
- }
- frame_cnt=0;
- time_start = clock();
- while(av_read_frame(pFormatCtx, packet)>=0){
- if(packet->stream_index==videoindex){
- ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);
- if(ret < 0){
- printf("Decode Error.\n");
- return;
- }
- if(got_picture){
- sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height,
- pFrameYUV->data, pFrameYUV->linesize);
- y_size=pCodecCtx->width*pCodecCtx->height;
- fwrite(pFrameYUV->data[0],1,y_size,fp_yuv); //Y
- fwrite(pFrameYUV->data[1],1,y_size/4,fp_yuv); //U
- fwrite(pFrameYUV->data[2],1,y_size/4,fp_yuv); //V
- //Output info
- char pictype_str[10]={0};
- switch(pFrame->pict_type){
- case AV_PICTURE_TYPE_I:sprintf(pictype_str,"I");break;
- case AV_PICTURE_TYPE_P:sprintf(pictype_str,"P");break;
- case AV_PICTURE_TYPE_B:sprintf(pictype_str,"B");break;
- default:sprintf(pictype_str,"Other");break;
- }
- printf("Frame Index: %5d. Type:%s\n",frame_cnt,pictype_str);
- frame_cnt++;
- }
- }
- av_free_packet(packet);
- }
- //flush decoder
- //FIX: Flush Frames remained in Codec
- while (1) {
- ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);
- if (ret < 0)
- break;
- if (!got_picture)
- break;
- sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height,
- pFrameYUV->data, pFrameYUV->linesize);
- int y_size=pCodecCtx->width*pCodecCtx->height;
- fwrite(pFrameYUV->data[0],1,y_size,fp_yuv); //Y
- fwrite(pFrameYUV->data[1],1,y_size/4,fp_yuv); //U
- fwrite(pFrameYUV->data[2],1,y_size/4,fp_yuv); //V
- //Output info
- char pictype_str[10]={0};
- switch(pFrame->pict_type){
- case AV_PICTURE_TYPE_I:sprintf(pictype_str,"I");break;
- case AV_PICTURE_TYPE_P:sprintf(pictype_str,"P");break;
- case AV_PICTURE_TYPE_B:sprintf(pictype_str,"B");break;
- default:sprintf(pictype_str,"Other");break;
- }
- printf("Frame Index: %5d. Type:%s\n",frame_cnt,pictype_str);
- frame_cnt++;
- }
- time_finish = clock();
- time_duration=(double)(time_finish - time_start);
- sprintf(info, "%s[Time ]%fus\n",info,time_duration);
- sprintf(info, "%s[Count ]%d\n",info,frame_cnt);
- sws_freeContext(img_convert_ctx);
- fclose(fp_yuv);
- av_frame_free(&pFrameYUV);
- av_frame_free(&pFrame);
- avcodec_close(pCodecCtx);
- avformat_close_input(&pFormatCtx);
- NSString * info_ns = [NSString stringWithFormat:@"%s", info];
- self.infomation.text=info_ns;
- }
- @end
运行结果
App在手机上运行后的结果如下图所示。单击“Decode”,将会把位于resource.bundle中的“sintel.mov”文件解码为“sintel.yuv”文件并存储于相同的目录下。
生成的文件如下图所示。
本文转载自网络,感谢原作者的分享,转载仅为分享干货知识,如有侵权欢迎联系作者进行删除处理。
最简单的基于FFmpeg的直播系统开发移动端例子:IOS 视频解码器的更多相关文章
- 简单red5+obs推流实现直播系统开发,具体设置介绍
前言:随便搞搞,先放一张效果图,
- 最简单的基于FFmpeg的内存读写的例子:内存播放器
===================================================== 最简单的基于FFmpeg的内存读写的例子系列文章列表: 最简单的基于FFmpeg的内存读写的 ...
- (转)最简单的基于FFmpeg的内存读写的例子:内存播放器
ffmpeg内存播放解码 目录(?)[+] ===================================================== 最简单的基于FFmpeg的内存读写的例子系列文章 ...
- 最简单的基于FFmpeg的推流器(以推送RTMP为例)
===================================================== 最简单的基于FFmpeg的推流器系列文章列表: <最简单的基于FFmpeg的推流器(以 ...
- 最简单的基于FFmpeg的AVDevice例子(屏幕录制)
=====================================================最简单的基于FFmpeg的AVDevice例子文章列表: 最简单的基于FFmpeg的AVDev ...
- 最简单的基于FFmpeg的AVDevice例子(读取摄像头)
=====================================================最简单的基于FFmpeg的AVDevice例子文章列表: 最简单的基于FFmpeg的AVDev ...
- [转载] 最简单的基于FFmpeg的AVDevice例子(读取摄像头)
=====================================================最简单的基于FFmpeg的AVDevice例子文章列表: 最简单的基于FFmpeg的AVDev ...
- 100行代码实现最简单的基于FFMPEG+SDL的视频播放器(SDL1.x)【转】
转自:http://blog.csdn.net/leixiaohua1020/article/details/8652605 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[-] ...
- 最简单的基于FFmpeg的AVDevice例子(读取摄像头)【转】
转自:http://blog.csdn.net/leixiaohua1020/article/details/39702113 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[- ...
随机推荐
- CentOS 7安装Nginx 1.10.2
安装epel-release源并进行安装 yum install epel-release yum update(时间会有点长) yum install nginx 相关操作: systemctl s ...
- Matlab 中 imshow 函数
转自: https://blog.csdn.net/xiaochou87/article/details/43488829 matlab中显示图像的语句是: ...
- c中_tmain()和main()区别
来源参考:https://www.cnblogs.com/lucyjiayou/archive/2011/05/07/2039621.html tchar.h>可以找到,如#define _tm ...
- 《C++ primerplus》第13章练习题
1.对CD类的派生练习.基类CD类存储作者和作品号等信息,派生类Classic额外增加一格"主要作品"的信息.主函数使用拷贝构造函数.按引用传递参数的函数和指针来测试基类和派生类的 ...
- IPA的动态库注入+企业重签名过程
[摘录]之前在进行iOS测试过程中由于要获取一定数据信息,因此需要对原本的安装包进行代码注入并且重新打包安装,因此就需要使用重签名策略,在此进行分享,希望大家可以使用其中的方法来运用到自身的项目中. ...
- Android 10不能使用uiautomatorviewer定位元素的终极解决方法
Android app 元素定位除了使用Appium Inspector 外,还可以使用Android SDK 里tools中的uiautomatorviewer 工具.但今天打算使用 uiautom ...
- 跨境 TCP 传输优化实录 — 使用 BBR 解决 LFN 问题
背景 近期开通了一条访问美国机房的 1G 专线,用于提供行情数据备源,并基于 TCP 建立了一套数据传输服务.上线后发现一个严重的问题:应用程序发送队列中的数据大量积压,最终导致程序 OOM Kill ...
- composer使用git作为仓储
composer.json "repositories": [ { "type":"git", "url":" ...
- minianaconda3安装
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh chmod +x Miniconda3-lates ...
- Mac安装stf
1.brew install rethinkdb graphicsmagick zeromq protobuf yasm pkg-config 2.node版本8.x我的是8.15.0 3.npm i ...