做播放器的开发这里面涉及的东西太多,我只能一步步往前走,慢慢深入。播放器播放视频采用的是渲染yuv文件。首先,要知道yuv文件是怎么转换得来的,其次,要知道怎么把视频文件保存为yuv文件。雷神的文章100行代码实现最简单的基于FFMPEG+SDL的视频播放器(SDL1.x) 让我获益匪浅。以读取工程中的本地文件为例,视频文件使用雷神 100行代码实现最简单的基于FFMPEG+SDL的视频播放器(SDL1.x) 中用到的 nwn.mp4 。

  因为ffmpeg是c语言库,所以100行代码实现最简单的基于FFMPEG+SDL的视频播放器(SDL1.x)中的方法步骤可以直接搬过来用,这篇文章使用的开发环境是VS2010,这个不管,放手去干,把其中的关键代码摘取出来就欧了。但是,要注意新旧ffmpeg库,在新的库中一些老的方法被替换了,所以在搬运雷神文章中的代码的时候,要注意使用新的ffmpeg库中的方法。

  开发环境:Mac OS X 10.10.2, Xcode 6.3,iOS SDK 8.3, FFmpeg 2.0

  FFmpeg 2.0:如何编译FFmpeg 2.0库,可以参看我之前写的文章:实战FFmpeg--编译iOS平台使用的FFmpeg库

  废话不多说,上代码。

  

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController
{
AVFormatContext *pFormatCtx;
int i, videoindex;
AVCodecContext *pCodecCtx;
AVCodec *pCodec;
FILE *fp_yuv;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.view.backgroundColor = [UIColor blueColor]; NSString *path = [[NSBundle mainBundle] pathForResource:@"nwn" ofType:@"mp4"];
const char *filepath= [path UTF8String]; av_register_all();
avformat_network_init();
pFormatCtx = avformat_alloc_context();
if(avformat_open_input(&pFormatCtx,filepath,NULL,NULL)!=){
printf("Couldn't open input stream.\n");
exit();
} /*
* av_find_stream_info():ffmpeg版本更新后没有这个函数了,用avformat_find_stream_info这个函数,可以自己看一下版本更新改动
*/
// if(av_find_stream_info(pFormatCtx)<0)
if(avformat_find_stream_info(pFormatCtx, NULL) < )
{
printf("Couldn't find stream information.\n");
exit();
}
videoindex=-;
for(i=; i<pFormatCtx->nb_streams; i++)
if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)
{
videoindex=i;
break;
}
if(videoindex==-)
{
printf("Didn't find a video stream.\n");
exit();
}
pCodecCtx=pFormatCtx->streams[videoindex]->codec;
pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
if(pCodec==NULL)
{
printf("Codec not found.\n");
exit();
}
/*
* avcodec_open():ffmpeg版本更新后没有这个函数了,用avformat_find_stream_info这个函数,可以自己看一下版本更新改动
* avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options)
*/
// if(avcodec_open(pCodecCtx, pCodec)<0)
if(avcodec_open2(pCodecCtx, pCodec, NULL)<)
{
printf("Could not open codec.\n");
exit();
}
AVFrame *pFrame,*pFrameYUV;
pFrame=avcodec_alloc_frame();
pFrameYUV=avcodec_alloc_frame();
uint8_t *out_buffer;
out_buffer=new uint8_t[avpicture_get_size(PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height)];
avpicture_fill((AVPicture *)pFrameYUV, out_buffer, PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height); int ret, got_picture;
static struct SwsContext *img_convert_ctx;
int y_size = pCodecCtx->width * pCodecCtx->height; AVPacket *packet=(AVPacket *)malloc(sizeof(AVPacket));
av_new_packet(packet, y_size); printf("视频文件信息:\n");
av_dump_format(pFormatCtx,,filepath,); //获得应用程序沙盒的Documents目录
NSString* doc_path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[];
//创建文件管理器对象
NSString* filename = [doc_path stringByAppendingPathComponent:@"output.yuv"];
//创建目录
NSFileManager *fileManager = [NSFileManager defaultManager];
if ( ![fileManager fileExistsAtPath:filename]) {
[fileManager createFileAtPath:filename contents:nil attributes:nil];
} const char *fileYUV = [filename UTF8String];
/*
* fopen的参数rb+和wb+都是操作可读可写的二进制文件
区别是
对于rb+如果打开的文件不存在 会报错(返回NULL)
对于wb+ 如果文件不存在则会建立,如果文件存在 会覆盖
*/
fp_yuv=fopen(fileYUV,"rb+"); // while(av_read_frame(pFormatCtx, packet)>=)
{
if(packet->stream_index==videoindex)
{
ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);
if(ret < )
{
printf("Decode Error.\n");
exit();
}
if(got_picture)
{
img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, , pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize); int y_size=pCodecCtx->width*pCodecCtx->height;
fwrite(pFrameYUV->data[],,y_size,fp_yuv); //Y
fwrite(pFrameYUV->data[],,y_size/,fp_yuv); //U
fwrite(pFrameYUV->data[],,y_size/,fp_yuv); //V
printf("将视频数据写入文件");
sleep();
}
}
av_free_packet(packet);
}
delete[] out_buffer;
av_free(pFrameYUV);
avcodec_close(pCodecCtx);
avformat_close_input(&pFormatCtx);
fclose(fp_yuv);
}

  就这么简单,呵呵,知道了视频文件是如何转换为yuv文件的,以及如何将yuv数据按照yuv格式写入到文件并保存。

  得到了yuv文件,就在想yuv文件是如何被OpenGLES渲染,呈现为视频画面的呢,呵呵,这个我将在后续的关于OpenGLES的文章中提到。

  本文完整工程 FFmpegDecodeToYUV 的下载地址:http://pan.baidu.com/s/1dDnOgt7

实战FFmpeg--iOS平台使用FFmpeg将视频文件转换为YUV文件的更多相关文章

  1. 多媒体开发(7):编译Android与iOS平台的FFmpeg

    编译FFmpeg,一个古老的话题,但小程还是介绍一遍,就当记录.之前介绍怎么给视频添加水印时,就已经提到FFmpeg的编译,并且在编译时指定了滤镜的功能. 但是,在手机盛行的时代,读者可能更需要的是能 ...

  2. 在iOS平台使用ffmpeg解码h264视频流(转)

    在iOS平台使用ffmpeg解码h264视频流,有需要的朋友可以参考下. 对于视频文件和rtsp之类的主流视频传输协议,ffmpeg提供avformat_open_input接口,直接将文件路径或UR ...

  3. 在iOS平台使用ffmpeg解码h264视频流

    来源:http://www.aichengxu.com/view/37145 在iOS平台使用ffmpeg解码h264视频流,有需要的朋友可以参考下. 对于视频文件和rtsp之类的主流视频传输协议,f ...

  4. iOS平台基于ffmpeg的视频直播技术揭秘

    现在非常流行直播,相信很多人都跟我一样十分好奇这个技术是如何实现的,正好最近在做一个ffmpeg的项目,发现这个工具很容易就可以做直播,下面来给大家分享下技术要点: 首先你得编译出ffmpeg运行所需 ...

  5. iOS平台在ffmpeg中使用librtmp

    转载请注明出处:http://www.cnblogs.com/fpzeng/p/3202344.html 系统版本:OS X 10.8 一.在iOS平台上交叉编译librtmp librtmp lin ...

  6. FFmpeg编译:mac下编译iOS平台的FFmpeg库(支持armv7, arm64, i386, x86_64)

    环境:FFmpeg 3.4.6Xcode 10.3macOS 10.14.6iOS SDK 12.4 一.准备工作 1. 下载FFmpeg我这里使用的是3.4.6版本的FFmpeg,可以从FFmpeg ...

  7. 实战FFmpeg + OpenGLES--iOS平台上视频解码和播放

    一个星期的努力终于搞定了视频的播放,利用FFmpeg解码视频,将解码的数据通过OpenGLES渲染播放.搞清楚了自己想知道的和完成了自己的学习计划,有点小兴奋.明天就是“五一”,放假三天,更开心啦. ...

  8. 实战OpenGLES--iOS平台使用OpenGLES渲染YUV图片

    上一篇文章 实战FFmpeg--iOS平台使用FFmpeg将视频文件转换为YUV文件 演示了如何将视频文件转换为yuv文件保存,现在要做的是如何将yuv文件利用OpenGLES渲染展示出图像画面.要将 ...

  9. 实战FFmpeg--编译iOS平台使用的FFmpeg库(支持arm64的FFmpeg2.6.2)

    编译环境:Mac OS X 10.10.2 ,Xcode 6.3  iOS SDK 8.3        FFmpeg库的下载地址是 http://www.ffmpeg.org/releases/ . ...

随机推荐

  1. Multi-Agent Reinforcement Learning Based Frame Sampling for Effective Untrimmed Video Recognition

    Multi-Agent Reinforcement Learning Based Frame Sampling for Effective Untrimmed Video Recognition IC ...

  2. Gitlab修改用户密码

    sudo gitlab-rails console production > user=User.where(name: "root").first > user.pa ...

  3. 【转】23 个安卓重难点突破,带你吃透 Service 知识点「长达 1W+ 字」

    前言 学 Android 有一段时间了,想必不少人也和我一样,平时经常东学西凑,感觉知识点有些凌乱难成体系.所以趁着这几天忙里偷闲,把学的东西归纳下,捋捋思路. 这篇文章主要针对 Service 相关 ...

  4. 在asp.net core中使用NLog

    第一步:nuget  引入  NLog.Web.AspNetCore 4.5+ 第二步:放入nlog.config <?xml version="1.0" encoding= ...

  5. 必须要注意的 C++ 动态内存资源管理(二)——指针对象简单实现

    必须要注意的 C++动态内存资源管理(二)——指针对象简单实现 四.拷贝类型的资源         上节我们说过,对于图片类型的资源我们有时候往往采用拷贝(如果对于那种公共图片,可能采用唯一副本,提供 ...

  6. Windows EXE 依赖DLL查看

    dumpbin (这个是visual studio 提供的工具或者可以安装 Dependency Walker)来查看 DLL 依赖关系 dumpbin /dependents filename.ex ...

  7. CefSharp在高DPI的屏幕上出现黑边(winform)

    目录 问题现象 解决办法 1.将cefsharp的gpu设置为无效,(后遗症,h5动画会出现卡顿现象,慎用) 2.将屏幕的DPI置为96(缩放比例为100%)(后遗症,不可能每个电脑都去配置) 3.支 ...

  8. 顶部导航TabBar、TabBarView、DefaultTabController

    原文地址:https://www.cnblogs.com/upwgh/p/11369537.html TabBar:Tab页的选项组件,默认为水平排列. TabBarView:Tab页的内容容器,Ta ...

  9. Python数据库连接池DBUtils详解

    what's the DBUtils DBUtils 是一套用于管理数据库连接池的Python包,为高频度高并发的数据库访问提供更好的性能,可以自动管理连接对象的创建和释放.并允许对非线程安全的数据库 ...

  10. [LeetCode] 107. Binary Tree Level Order Traversal II 二叉树层序遍历 II

    Given a binary tree, return the bottom-up level order traversal of its nodes' values. (ie, from left ...