您的位置:首页 > 移动开发 > IOS开发

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开始的格式。

初始化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上即可显示出来!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: