iOS硬解码H264视频流

本文介绍了iOS 8.0及以上版本使用VideoToolbox框架进行H264硬解码的过程,包括名词解释、解码流程、IDR帧数据结构以及初始化解码器、硬件解码和解码后数据显示的详细步骤。同时,提供了完整的H264解码代码供参考。
摘要由CSDN通过智能技术生成

        苹果在iOS 8.0系统之前若要做音视频开发需使用第三方软件进行编解码(FFmpeg软解码H264视频流可看到这里),学习成本较大,项目开发进度也可能超出预期。在iOS 8.0之后开放了视频编解码框架VideoToolbox,在此之后对于音视频开发变得相对简单。

 

 

 

一、硬解码名词(结构)解释

1、VTDecompressionSessionRef:解码器对象数据结构;

2、CMVideoFormatDescriptionRef:图形解码相关格式及描述;

3、CVPixelBufferRef:编码前和解码后的图像数据结构;

4、CMBlockBufferRef:存在解码前图像数据内存结构;

5、CMSampleBufferRef:存放解码前的视频图像的容器数据结构;

6、AVSampleBufferDisplayLayer:以CMSampleBufferRef进行解码并显示Layer图层;

7、SPSPPS:h.264解码参数信息;IDR:h.264视频流I帧;

二、H264硬解码流程图

 

三:IDR(I帧)网络裸流数据结构

        一般情况下网络视频裸流I帧中基本会包含SPS、PPS、SEI、IDR帧数据,如下图所示,但是部分只含有IDR帧数据,其他解码参数信息被单独已Slice获取。

 

四、硬解码相关接口

 

1、初始化H264硬解解码器

1)使用CMVideoFormatDescriptionCreateFromH264ParameterSets函数构建解码描述结构CMVideoFormatDescriptionRef

    const uint8_t *const parameterSetPointers[2] = {pSPS,pPPS};
    const size_t parameterSetSizes[2] = {mSpsSize, mPpsSize};
    
    OSStatus status = CMVideoFormatDescriptionCreateFromH264ParameterSets(kCFAllocatorDefault,
                                                                          2,    //参数个数,主要包含SPS、PPS
                                                                          parameterSetPointers,
                                                                          parameterSetSizes,
                                                                          4,    //NALU起始位个数
                                                                          &mDecoderFormatDescription);

2)使用VTDecompressionSessionCreate函数构建解码器结构VTDecompressionSessionRef

 

    uint32_t pixelFormatType = kCVPixelFormatType_420YpCbCr8BiPlanarFullRange;  //NV12
    const void *keys[] = { kCVPixelBufferPixelFormatTypeKey };
    const void *values[] = { CFNumberCreate(NULL, kCFNumberSInt32Type, &pixelFormatType) };    //32位
    CFDictionaryRef attrs = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
    
    VTDecompressionOutputCallbackRecord callBackRecord;
    callBackRecord.decompressionOutputCallback = didDecompress;    
    callBackRecord.decompressionOutputRefCon = NULL;
    
    status = VTDecompressionSessionCreate(kCFAllocatorDefault,
                                          mDecoderFormatDescription,
                                          NULL, attrs,
                                          &callBackRecord,
                                          &mDeocderSession);
    CFRelease(attrs);

2、H264硬件解码

1)将视频裸流数据构建成CMBlockBufferRef,主要目的是进一步转换为CMSampleBufferRef

    CMBlockBufferRef blockBuffer = NULL;
    OSStatus status  = CMBlockBufferCreateWithMemoryBlock(kCFAllocatorDefault, (void *)videoBuffer, videoBufferSize, kCFAllocatorNull, NULL, 0, videoBufferSize, 0, &blockBuffer);
    CMSampleBufferRef sampleBuffer = NULL;
    const size_t sampleSizeArray[] = { videoBufferSize };
    OSStatus status = CMSampleBufferCreateReady(kCFAllocatorDefault, blockBuffer, mDecoderFormatDescription , 1, 0, NULL, 1, sampleSizeArray, &sampleBuffer);

2)将CMSampleBufferRef结构送入VTDecompressionSessionDecodeFrame函数进行解码处理:

    VTDecodeFrameFlags flags = 0;
    VTDecodeInfoFlags flagOut = 0;
    CVPixelBufferRef outputPixelBuffer = NULL;
    OSStatus decodeStatus = VTDecompressionSessionDecodeFrame(mDeocderSession, sampleBuffer, flags, &outputPixelBuffer, &flagOut);

3)若使用AVSampleBufferDisplayLayer图层进行直接显示,可忽略上一步的还行,直接将CMSampleBufferRef送入AVSampleBufferDisplayLayer进行显示:

    CFArrayRef attachments = CMSampleBufferGetSampleAttachmentsArray(sampleBuffer, YES);
    CFMutableDictionaryRef dict = (CFMutableDictionaryRef)CFArrayGetValueAtIndex(attachments, 0);
    CFDictionarySetValue(dict, kCMSampleAttachmentKey_DisplayImmediately, kCFBooleanTrue);
    if ([self.displayLayer isReadyForMoreMediaData]) {
        @weaki
Flutter是一种跨平台的移动应用开发框架可以用于开发iOS和Android应用。要解码H264二进制流,可以使用Flutter的插件来实现。 一个常用的Flutter插件是flutter_ffmpeg,它是FFmpeg在Flutter中的封装。FFmpeg是一个开源的音视频处理库,支持多种音视频编解码格式,包括H264。 使用flutter_ffmpeg插件,你可以将H264二进制流传递给FFmpeg进行解码。以下是一个简单的示例代码: 1. 首先,在pubspec.yaml文件中添加flutter_ffmpeg插件的依赖: ``` dependencies: flutter_ffmpeg: ^0.4.0 ``` 2. 然后,在Flutter代码中导入flutter_ffmpeg插件: ``` import 'package:flutter_ffmpeg/flutter_ffmpeg.dart'; ``` 3. 创建一个FlutterFFmpeg对象,并使用decode方法解码H264二进制流: ``` FlutterFFmpeg flutterFFmpeg = FlutterFFmpeg(); String inputPath = "path_to_h264_stream"; String outputPath = "path_to_output_file"; flutterFFmpeg.execute("-i $inputPath -c:v copy $outputPath").then((rc) { if (rc == 0) { print("解码成功"); // 解码成功后的处理逻辑 } else { print("解码失败"); // 解码失败后的处理逻辑 } }); ``` 在上面的代码中,`inputPath`是H264二进制流的路径或URL,`outputPath`是解码后的输出文件路径。`-c:v copy`参数表示直接复制视频流,不进行重新编码。 请注意,解码H264二进制流可能涉及到更多的配置和处理,具体的实现方式可能因应用需求而有所不同。以上只是一个简单的示例,你可以根据自己的需求进行相应的调整和扩展。
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值