iOS平台使用ffmpeg解码h264视频流
2015-12-29 10:09
627 查看
对于视频文件和rtsp之类的主流视频传输协议,ffmpeg提供avformat_open_input接口,直接将文件路径或URL传入即可打开。读取视频数据、解码器初始参数设置等,都可以通过调用API来完成。但是对于h264流,没有任何封装格式,也就无法使用libavformat。所以许多工作需要自己手工完成。这里的h264流指AnnexB,也就是每个nal unit以起始码00 00 00 01 或 00 00 01开始的格式。
在传入参数的时候,我们要指定原始数据的buff,长度,和时间,后面转换有需要用到。
AVFrame —> RGB
data[0] — RGG数据
linesize[0] —- width*pixel_size for RGB
done,把转换出来的UIImage画到UIImgeView上即可显示出来!
初始化ffmpeg
- (BOOL)initFFmpegDecoder { /*注册所有的编码器,解析器,码流过滤器,只需要初始化一次*/ static dispatch_once_t once; dispatch_once(&once, ^{ avcodec_register_all(); }); /*查找指定格式的解析器,这里我们使用H264*/ AVCodec *pCodec = avcodec_find_decoder(CODEC_ID_H264); if (pCodec == NULL) { NSLog(@"codec not found"); return NO; } /*初始化解析器容器*/ if (pCodecCtx == NULL) { pCodecCtx = avcodec_alloc_context3(pCodec); if (pCodecCtx == NULL) { NSLog(@"Allocate codec context failed"); return NO; } av_opt_set(pCodecCtx->priv_data, "tune", "zerolatency", 0); } /*打开指定的解析器*/ int ret = avcodec_open2(pCodecCtx, pCodec, NULL); if (ret != 0) { NSLog(@"open codec error :%d", ret); return NO; } /*AVFrame用来描述原始的解码音频和视频数据*/ if (pFrame == NULL) { pFrame = av_frame_alloc(); if (pFrame == NULL) { NSLog(@"av_frame_alloc failed"); return NO; } } avpicture_free(&avPicture); avpicture_alloc(&avPicture, AV_PIX_FMT_RGB24, _outputSize.width, _outputSize.height); return YES; }
获取原始数据进行解码
这里我们主要是解码视频数据,使用的是avcodec_decode_video2函数,int avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture, int *got_picture_ptr, const AVPacket *avpkt)该函数有4个参数,第一个是我们之前初始化的context,第二个是输出值,解码后的原始数据,第三个是判断是否存在可以解码的数据,第四个是输入参数:
@synchronized(self) { AVPacket packet; av_new_packet(&packet, length); memcpy(packet.data, pFrameData, length); result = avcodec_decode_video2(pCodecCtx, pFrame, &decoderFrameOK, &packet); av_free_packet(&packet); }
在传入参数的时候,我们要指定原始数据的buff,长度,和时间,后面转换有需要用到。
AVFrame转UIImage
使用ffmepg解码视频一般都是生成AVFrame。然后再转换成RGB或YUV.AVFrame 转RGB:AVFrame —> RGB
data[0] — RGG数据
linesize[0] —- width*pixel_size for RGB
- (UIImage*)imageFromAVFrame:(AVFrame *)avFrame { float width = avFrame->width; float height = avFrame->height; avpicture_free(&avPicture); avpicture_alloc(&avPicture, AV_PIX_FMT_RGB24, width, height); struct SwsContext * imgConvertCtx = sws_getContext(avFrame->width, avFrame->height, PIX_FMT_YUV420P, width, height, AV_PIX_FMT_RGB24, SWS_FAST_BILINEAR, NULL, NULL, NULL); if(imgConvertCtx == nil) return nil; sws_scale(imgConvertCtx, avFrame->data, avFrame->linesize, 0, avFrame->height, avPicture.data, avPicture.linesize); sws_freeContext(imgConvertCtx); CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault; CFDataRef data = CFDataCreate(kCFAllocatorDefault, avPicture.data[0], avPicture.linesize[0] * height); CGDataProviderRef provider = CGDataProviderCreateWithCFData(data); CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); CGImageRef cgImage = CGImageCreate(width, height, 8, 24, avPicture.linesize[0], colorSpace, bitmapInfo, provider, NULL, NO, kCGRenderingIntentDefault); UIImage *image = [UIImage imageWithCGImage:cgImage]; CGImageRelease(cgImage); CGColorSpaceRelease(colorSpace); CGDataProviderRelease(provider); CFRelease(data); return image; }
done,把转换出来的UIImage画到UIImgeView上即可显示出来!
相关文章推荐
- iOS 国际化 本地化步骤 Localizations
- 去除iOS 7 grouped tableview与navigationBar之间的间隔
- ios捕捉奔溃日志
- iOS9 3DTouch、ShortcutItem、Peek And Pop技术一览
- 微软的Live SDK各个API简介
- ios之NSDictionary、NSMutableDictionary使用小结
- ios 简易日程(获取XX年XX月第一天是星期X)
- 运维监控工具之 Nagios 客户端安装(二)
- iOS 学习资料整理
- 运维监控工具之 Nagios (一)
- IOS倒计时的制作
- IOS 内存优化和调试技巧
- iOS应用程序基础:Cocoa Touch框架
- iOS开发中音频工具类的封装以及音乐播放器的细节控制
- iOS 集合的深复制与浅复制
- iOS 视图---动画渲染机制探究
- iOS适配流程规范
- 适配iOS9
- IOS开发 @property中assign、copy 、retain等关键字的理解
- iOS Quartz 2D 绘制图形(线段\三角形\矩形\圆\圆弧等)