ios 硬解码h264


#import <UIKit/UIKit.h>

#import <Foundation/Foundation.h>

#import <VideoToolbox/VideoToolbox.h>

#import <AVFoundation/AVSampleBufferDisplayLayer.h>



@protocol H264HwDecoderImplDelegate <NSObject>


- (void)displayDecodedFrame:(CVImageBufferRef )imageBuffer;



@end


@interface H264HwDecoderImpl : NSObject

@property (weak,nonatomic) id<H264HwDecoderImplDelegate> delegate;


@property(nonatomic,assign)int vheight;

@property(nonatomic,assign)int vwidth;


-(BOOL)initH264Decoder;

-(void)decodeNalu:(uint8_t *)frame withSize:(uint32_t)frameSize;


//停止解码销毁session

-(void)stopDecode;



//截图

-(UIImage*)getImageCVPixel:(CVPixelBufferRef)pixelBuffer;


@end





#import "H264HwDecoderImpl.h"

#import "config.h"

@interface H264HwDecoderImpl()

{

    uint8_t *_sps;

    NSInteger _spsSize;

    uint8_t *_pps;

    NSInteger _ppsSize;

    VTDecompressionSessionRef _deocderSession;

    CMVideoFormatDescriptionRef _decoderFormatDescription;

}

@end


@implementation H264HwDecoderImpl

//解码回调函数

static void didDecompress(void *decompressionOutputRefCon,void *sourceFrameRefCon,OSStatus status, VTDecodeInfoFlags infoFlags, CVImageBufferRef pixelBuffer, CMTime presentationTimeStamp, CMTime presentationDuration ){

    CVPixelBufferRef *outputPixelBuffer = (CVPixelBufferRef *)sourceFrameRefCon;

    *outputPixelBuffer = CVPixelBufferRetain(pixelBuffer);

    H264HwDecoderImpl *decoder = (__bridgeH264HwDecoderImpl *)decompressionOutputRefCon;

    if (decoder.delegate!=nil)

    {

        [decoder.delegatedisplayDecodedFrame:pixelBuffer];

    }

}



-(id)init

{

    self = [superinit];

    if (self) {

        

        _vwidth =640;

        _vheight =480;

        

    }

    returnself;

}


-(BOOL)initH264Decoder {

    if(_deocderSession) {

        returnYES;

    }

    constuint8_t* const parameterSetPointers[2] = {_sps, _pps };

    constsize_t parameterSetSizes[2] = {_spsSize, _ppsSize };

    OSStatus status =CMVideoFormatDescriptionCreateFromH264ParameterSets(kCFAllocatorDefault,2,parameterSetPointers,parameterSetSizes,4,&_decoderFormatDescription);

    

    if(status ==noErr) {

        //硬解必须是 kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange

        //或者是kCVPixelFormatType_420YpCbCr8Planar

        //因为iOS  nv12 其他是nv21

        //这里宽高和编码反的

      NSDictionary* destinationPixelBufferAttributes =@{

                                                           (id)kCVPixelBufferPixelFormatTypeKey : [NSNumbernumberWithInt:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange],                                                           (id)kCVPixelBufferWidthKey : [NSNumber numberWithInt:_vwidth],

                                                           (id)kCVPixelBufferHeightKey : [NSNumbernumberWithInt:_vheight],                                                           (id)kCVPixelBufferOpenGLCompatibilityKey : [NSNumber numberWithBool:YES]

                                                           };

        

        

        VTDecompressionOutputCallbackRecord callBackRecord;

        callBackRecord.decompressionOutputCallback =didDecompress;

        callBackRecord.decompressionOutputRefCon = (__bridgevoid *)self;

        status = VTDecompressionSessionCreate(kCFAllocatorDefault,

                                              _decoderFormatDescription,

                                              NULL,

                                              (__bridgeCFDictionaryRef)destinationPixelBufferAttributes,

                                              &callBackRecord,

                                              &_deocderSession);

        VTSessionSetProperty(_deocderSession,kVTDecompressionPropertyKey_ThreadCount, (__bridgeCFTypeRef)[NSNumbernumberWithInt:1]);

        VTSessionSetProperty(_deocderSession,kVTDecompressionPropertyKey_RealTime,kCFBooleanTrue);

    } else {

        NSLog(@"IOS8VT: reset decoder session failed status=%d===会话失败", (int)status);

    }

    

    returnYES;

}


-(CVPixelBufferRef)decode:(uint8_t *)frame withSize:(uint32_t)frameSize

{

    CVPixelBufferRef outputPixelBuffer =NULL;

    

    CMBlockBufferRef blockBuffer =NULL;

    OSStatus status  =CMBlockBufferCreateWithMemoryBlock(NULL,

                                                          (void *)frame,

                                                          frameSize,

                                                          kCFAllocatorNull,

                                                          NULL,

                                                          0,

                                                          frameSize,

                                                          FALSE,

                                                          &blockBuffer);

    if(status ==kCMBlockBufferNoErr) {

        CMSampleBufferRef sampleBuffer =NULL;

        constsize_t sampleSizeArray[] = {frameSize};

        status = CMSampleBufferCreateReady(kCFAllocatorDefault,

                                           blockBuffer,

                                           _decoderFormatDescription ,

                                           1,0, NULL,1, sampleSizeArray,

                                           &sampleBuffer);

        if (status ==kCMBlockBufferNoErr && sampleBuffer) {

            VTDecodeFrameFlags flags =0;

            VTDecodeInfoFlags flagOut =0;

            OSStatus decodeStatus =VTDecompressionSessionDecodeFrame(_deocderSession,

                                                                      sampleBuffer,

                                                                      flags,

                                                                      &outputPixelBuffer,

                                                                      &flagOut);


            if(decodeStatus ==kVTInvalidSessionErr) {

//                VTDecompressionSessionInvalidate(_deocderSession);

                _deocderSession =nil;

                NSLog(@"IOS8VT: Invalid session, reset decoder session");

            } elseif(decodeStatus == kVTVideoDecoderBadDataErr) {

                NSLog(@"IOS8VT: decode failed status=%d(Bad data)", (int)decodeStatus);

            } elseif(decodeStatus != noErr) {

                NSLog(@"IOS8VT: decode failed status=%d", (int)decodeStatus);

            }

            CFRelease(sampleBuffer);

        }

        CFRelease(blockBuffer);

    }

    

    return outputPixelBuffer;

}



-(void) decodeNalu:(uint8_t *)frame withSize:(uint32_t)frameSize

{

//    NSLog(@">>>>>>>>>>开始解码");

    int nalu_type = (frame[4] &0x1F);

    CVPixelBufferRef pixelBuffer =NULL;

    uint32_t nalSize = (uint32_t)(frameSize -4);

    uint8_t *pNalSize = (uint8_t*)(&nalSize);

    frame[0] = *(pNalSize +3);

    frame[1] = *(pNalSize +2);

    frame[2] = *(pNalSize +1);

    frame[3] = *(pNalSize);

    //传输的时候。关键帧不能丢数据否则绿屏   B/P可以丢 这样会卡顿

    switch (nalu_type)

    {

        case0x05:

           NSLog(@"nalu_type:%d Nal type is IDR frame",nalu_type); //关键帧

            if([selfinitH264Decoder])

            {

                pixelBuffer = [selfdecode:frame withSize:frameSize];

            }

            break;

        case0x07:

           NSLog(@"nalu_type:%d Nal type is SPS",nalu_type);  //sps

            _spsSize = frameSize -4;

            _sps =malloc(_spsSize);

            memcpy(_sps, &frame[4], _spsSize);

            

            break;

        case0x08:

        {

            NSLog(@"nalu_type:%d Nal type is PPS",nalu_type);  //pps

            _ppsSize = frameSize -4;

            _pps =malloc(_ppsSize);

            memcpy(_pps, &frame[4], _ppsSize);

            break;

        }

        default:

        {

            NSLog(@"Nal type is B/P frame");//其他帧

           if([selfinitH264Decoder])

            {

                pixelBuffer = [selfdecode:frame withSize:frameSize];

            }

            break;

        }

    }

//    CVPixelBufferRelease(pixelBuffer);

}



-(void)stopDecode

{

    VTDecompressionSessionInvalidate(_deocderSession);

}


-(UIImage*)getImageCVPixel:(CVPixelBufferRef)pixelBuffer

{

    CIImage *ciImage = [CIImageimageWithCVPixelBuffer:pixelBuffer];

    UIImage *uiImage = [UIImageimageWithCIImage:ciImage];

    return uiImage;

}



@end



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
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二进制流可能涉及到更多的配置和处理,具体的实现方式可能因应用需求而有所不同。以上只是一个简单的示例,你可以根据自己的需求进行相应的调整和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值