IOS上编译ffmpeg 播放本地 .h264视频(二)---播放本地文件

http://blog.csdn.net/u013028303/article/details/41116311

 

写在前面:iFrameExtractor 的确是个不错的开源工程,可以从里面学到不少东西,建议大家下来看看。但是在捣鼓的过程中发现它不能播放本地后缀.264的视频文件,没办法只好自己捣鼓。

主要思路:打开本地.h264文件,每次从里面取固定buff大小的数据,解码成一张张的图片最后逐张显示。 

一、在viewController.h中声明

 

  1. @interface ViewController : UIViewController  
  2. {  
  3.     AVCodecContext *codec;  
  4.     AVPacket packetBuf;  
  5.     AVFrame *pFrame;  
  6.     AVPicture picture;  
  7.   
  8.     struct SwsContext *img_convert_ctx;  
  9.   
  10. }  
  11.   
  12. @property (nonatomic) int outputWidth, outputHeight;  

 

二、viewController.m

这里我用主线程来显示图片而用工作线程来解码。

[objc] view plaincopy
 
  1. NSThread *threadDecode = [[NSThread alloc] initWithTarget:self selector:@selector(decodeVideo) object:nil];  
  2. [threadDecode start];  

下面是最重要的解码函数decodeVideo{}

1.首先是初始化以及设置解码器

  1. avcodec_register_all();  
  2. av_register_all();  

 

  1. AVCodec *videoCodec = avcodec_find_decoder(CODEC_ID_H264);  //得到264的解码器  
  2. AVCodecParserContext *avParserContext = av_parser_init(CODEC_ID_H264);//得到解析帧类,主要用于后面的帧头查找  
  3. codec = avcodec_alloc_context3(videoCodec);//解码会话层  
  4. pFrame = avcodec_alloc_frame();   
  1. av_init_packet(&packetBuf);//初始化  
  1. packetBuf.data = NULL;  
  2. packetBuf.size = 0; 

2.初始化一块内存来存储

  1. #define MAX_LEN  1024 * 50  
  1. int readFileLen = 1;  
  2. char readBuf[MAX_LEN];  
  3. unsigned charchar *parseBuf;  
  4. int parseBufLen = 0;  
  5. int frameFinished = 10;   

3.打开.264文件

  1. FILEFILE *myH264 = fopen("/Users/Gizmosir/desktop/c4.h264", "r");  

这里我直接把文件放在桌面用模拟器打开,所以用的是绝对路径。如果要用真机调试或者视频文件放在包内的,则:

 

[objc] view plaincopy
 
  1. NSString *path2 = [[NSBundle mainBundle] pathForResource:@"c4.h264" ofType:nil];  
  2. FILEFILE *myH264 = fopen([path2 cStringUsingEncoding:NSMacOSRomanStringEncoding], "r");  

 

 

4.解码

 

[objc] view plaincopy
 
  1. while(readFileLen >0){  
  2.   
  3.     readFileLen = fread(readBuf, 1, sizeof(readBuf), myH264);//  
  4.     if(readFileLen <= 0){  
  5.         break;  
  6.     }else{  
  7.         int handleLen = 0;  
  8.         int handleFileLen = readFileLen;  
  9.           
  10.         while(handleFileLen >0){  
  11.             av_parser_parse2(avParserContext,codec, &parseBuf, &parseBufLen, readBuf + handleLen, handleFileLen, 0, 0, 0);//查找264帧头  
  12.             handleFileLen -= nLength;  
  13.             handleLen += nLength;  
  14.               
  15.             if(parseBufLen <= 0){  
  16.                 continue;//<span style="font-family: Arial, Helvetica, sans-serif;">查找不到帧头  
  17.             }  
  18.               
  19.             packetBuf.size = parseBufLen;  
  20.             packetBuf.data = parseBuf;  
  21.               
  22.             while (packetBuf.size > 0) {  
  23.                 int decodeLen = avcodec_decode_video2(codec, pFrame, &frameFinished, &packetBuf);  
  24.                 if(decodeLen <= 0){  
  25.                     break;//解码失败  
  26.                 }  
  27.                 packetBuf.size -= decodeLen;  
  28.                 packetBuf.data += decodeLen;  
  29.                   
  30.                 if (frameFinished >0) {//解码成功  
  31.                     avpicture_get_size(PIX_FMT_RGB24, codec->width, codec->height);  
  32.                       
  33.                     [self performSelectorOnMainThread:@selector(displayVideo) withObject:nil waitUntilDone:YES];//用主线程显示图片  
  34.   
  35.                     [NSThread sleepForTimeInterval:0.2];//设置图片显示间隔  
  36.                 }  
  37.             }  
  38.         }  
  39.     }  
  40. }  

 

5.最后不要忘了释放

 

  1. av_free(codec);  
  2. av_free_packet(&packetBuf);  
  3. av_frame_free(&pFrame); 

接下来是显示函数displayVideo{}

[objc] view plaincopy
 
  1. self.outputWidth = 1980;   
  2. self.outputHeight = 1200;   
  3. imageView.image = self.currentImage;  

在这里需要填上你自己播放视频的尺寸。

三、其余的函数:主要参考iFrameExtractor工程

[objc] view plaincopy
 
  1. -(void)setOutputWidth:(int)newValue {  
  2.     if (outputWidth == newValue) return;  
  3.     outputWidth = newValue;  
  4. }  
  5.   
  6. -(void)setOutputHeight:(int)newValue {  
  7.     if (outputHeight == newValue) return;  
  8.     outputHeight = newValue;  
  9.     [self setupScaler];  
  10. }  
  11.   
  12. -(void)setupScaler {  
  13.       
  14.     // Release old picture and scaler  
  15.     avpicture_free(&picture);  
  16.     sws_freeContext(img_convert_ctx);  
  17.       
  18.     // Allocate RGB picture  
  19.     avpicture_alloc(&picture, PIX_FMT_RGB24, outputWidth, outputHeight);  
  20.       
  21.     // Setup scaler  
  22.     static int sws_flags =  SWS_FAST_BILINEAR;  
  23.     img_convert_ctx = sws_getContext(codec->width,  
  24.                                      codec->height,  
  25.                                      codec->pix_fmt,  
  26.                                      outputWidth,  
  27.                                      outputHeight,  
  28.                                      PIX_FMT_RGB24,  
  29.                                      sws_flags, NULL, NULL, NULL);      
  30. }  
  31.   
  32. -(UIImage *)currentImage {  
  33.     if (!pFrame->data[0]) return nil;  
  34.     [self convertFrameToRGB];  
  35.     return [self imageFromAVPicture:picture width:outputWidth height:outputHeight];  
  36. }  
  37.   
  38. -(void)convertFrameToRGB {  
  39.     sws_scale (img_convert_ctx, pFrame->data, pFrame->linesize,  
  40.                0, codec->height,  
  41.                picture.data, picture.linesize);  
  42.       
  43. }  
  44.   
  45. -(UIImage *)imageFromAVPicture:(AVPicture)pict width:(int)width height:(int)height {  
  46.     CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;  
  47.     CFDataRef data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, pict.data[0], pict.linesize[0]*height,kCFAllocatorNull);  
  48.     CGDataProviderRef provider = CGDataProviderCreateWithCFData(data);  
  49.     CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();  
  50.     CGImageRef cgImage = CGImageCreate(width,  
  51.                                        height,  
  52.                                        8,  
  53.                                        24,  
  54.                                        pict.linesize[0],  
  55.                                        colorSpace,  
  56.                                        bitmapInfo,  
  57.                                        provider,  
  58.                                        NULL,  
  59.                                        NO,  
  60.                                        kCGRenderingIntentDefault);  
  61.       
  62.     CGColorSpaceRelease(colorSpace);  
  63.     UIImage *image = [UIImage imageWithCGImage:cgImage];  
  64.     CGImageRelease(cgImage);  
  65.     CGDataProviderRelease(provider);  
  66.     CFRelease(data);  
  67.   
  68.     return image;  
  69. }  


到这里为止,播放本地.264文件的目标就完成了!

posted on 2015-09-01 17:59  pTrack  阅读(547)  评论(0)    收藏  举报