http://blog.csdn.net/u013028303/article/details/41116311
写在前面:iFrameExtractor 的确是个不错的开源工程,可以从里面学到不少东西,建议大家下来看看。但是在捣鼓的过程中发现它不能播放本地后缀.264的视频文件,没办法只好自己捣鼓。
主要思路:打开本地.h264文件,每次从里面取固定buff大小的数据,解码成一张张的图片最后逐张显示。
一、在viewController.h中声明
- @interface ViewController : UIViewController
- {
- AVCodecContext *codec;
- AVPacket packetBuf;
- AVFrame *pFrame;
- AVPicture picture;
- struct SwsContext *img_convert_ctx;
- }
- @property (nonatomic) int outputWidth, outputHeight;
二、viewController.m
这里我用主线程来显示图片而用工作线程来解码。
- NSThread *threadDecode = [[NSThread alloc] initWithTarget:self selector:@selector(decodeVideo) object:nil];
- [threadDecode start];
下面是最重要的解码函数decodeVideo{}
1.首先是初始化以及设置解码器
- avcodec_register_all();
- av_register_all();
- AVCodec *videoCodec = avcodec_find_decoder(CODEC_ID_H264); //得到264的解码器
- AVCodecParserContext *avParserContext = av_parser_init(CODEC_ID_H264);//得到解析帧类,主要用于后面的帧头查找
- codec = avcodec_alloc_context3(videoCodec);//解码会话层
- pFrame = avcodec_alloc_frame();
- av_init_packet(&packetBuf);//初始化
- packetBuf.data = NULL;
- packetBuf.size = 0;
2.初始化一块内存来存储
- #define MAX_LEN 1024 * 50
- int readFileLen = 1;
- char readBuf[MAX_LEN];
- unsigned charchar *parseBuf;
- int parseBufLen = 0;
- int frameFinished = 10;
3.打开.264文件
- FILEFILE *myH264 = fopen("/Users/Gizmosir/desktop/c4.h264", "r");
这里我直接把文件放在桌面用模拟器打开,所以用的是绝对路径。如果要用真机调试或者视频文件放在包内的,则:
- NSString *path2 = [[NSBundle mainBundle] pathForResource:@"c4.h264" ofType:nil];
- FILEFILE *myH264 = fopen([path2 cStringUsingEncoding:NSMacOSRomanStringEncoding], "r");
4.解码
- while(readFileLen >0){
- readFileLen = fread(readBuf, 1, sizeof(readBuf), myH264);//
- if(readFileLen <= 0){
- break;
- }else{
- int handleLen = 0;
- int handleFileLen = readFileLen;
- while(handleFileLen >0){
- av_parser_parse2(avParserContext,codec, &parseBuf, &parseBufLen, readBuf + handleLen, handleFileLen, 0, 0, 0);//查找264帧头
- handleFileLen -= nLength;
- handleLen += nLength;
- if(parseBufLen <= 0){
- continue;//<span style="font-family: Arial, Helvetica, sans-serif;">查找不到帧头
- }
- packetBuf.size = parseBufLen;
- packetBuf.data = parseBuf;
- while (packetBuf.size > 0) {
- int decodeLen = avcodec_decode_video2(codec, pFrame, &frameFinished, &packetBuf);
- if(decodeLen <= 0){
- break;//解码失败
- }
- packetBuf.size -= decodeLen;
- packetBuf.data += decodeLen;
- if (frameFinished >0) {//解码成功
- avpicture_get_size(PIX_FMT_RGB24, codec->width, codec->height);
- [self performSelectorOnMainThread:@selector(displayVideo) withObject:nil waitUntilDone:YES];//用主线程显示图片
- [NSThread sleepForTimeInterval:0.2];//设置图片显示间隔
- }
- }
- }
- }
- }
5.最后不要忘了释放
- av_free(codec);
- av_free_packet(&packetBuf);
- av_frame_free(&pFrame);
接下来是显示函数displayVideo{}
- self.outputWidth = 1980;
- self.outputHeight = 1200;
- imageView.image = self.currentImage;
在这里需要填上你自己播放视频的尺寸。
三、其余的函数:主要参考iFrameExtractor工程
- -(void)setOutputWidth:(int)newValue {
- if (outputWidth == newValue) return;
- outputWidth = newValue;
- }
- -(void)setOutputHeight:(int)newValue {
- if (outputHeight == newValue) return;
- outputHeight = newValue;
- [self setupScaler];
- }
- -(void)setupScaler {
- // Release old picture and scaler
- avpicture_free(&picture);
- sws_freeContext(img_convert_ctx);
- // Allocate RGB picture
- avpicture_alloc(&picture, PIX_FMT_RGB24, outputWidth, outputHeight);
- // Setup scaler
- static int sws_flags = SWS_FAST_BILINEAR;
- img_convert_ctx = sws_getContext(codec->width,
- codec->height,
- codec->pix_fmt,
- outputWidth,
- outputHeight,
- PIX_FMT_RGB24,
- sws_flags, NULL, NULL, NULL);
- }
- -(UIImage *)currentImage {
- if (!pFrame->data[0]) return nil;
- [self convertFrameToRGB];
- return [self imageFromAVPicture:picture width:outputWidth height:outputHeight];
- }
- -(void)convertFrameToRGB {
- sws_scale (img_convert_ctx, pFrame->data, pFrame->linesize,
- 0, codec->height,
- picture.data, picture.linesize);
- }
- -(UIImage *)imageFromAVPicture:(AVPicture)pict width:(int)width height:(int)height {
- CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
- CFDataRef data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, pict.data[0], pict.linesize[0]*height,kCFAllocatorNull);
- CGDataProviderRef provider = CGDataProviderCreateWithCFData(data);
- CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
- CGImageRef cgImage = CGImageCreate(width,
- height,
- 8,
- 24,
- pict.linesize[0],
- colorSpace,
- bitmapInfo,
- provider,
- NULL,
- NO,
- kCGRenderingIntentDefault);
- CGColorSpaceRelease(colorSpace);
- UIImage *image = [UIImage imageWithCGImage:cgImage];
- CGImageRelease(cgImage);
- CGDataProviderRelease(provider);
- CFRelease(data);
- return image;
- }
到这里为止,播放本地.264文件的目标就完成了!
浙公网安备 33010602011771号