精华内容
下载资源
问答
  • iOS系统中H264硬解码及显示详解

    千次阅读 2018-09-27 16:45:25
    iOS系统中H264硬解码及显示详解 iOS系统中H264硬解码及显示详解 苹果在iOS 8.0系统之前,没有开放系统的硬件编码解码功能,不过Mac OS系统一直有,被称为VideoToolBox的框架来处理硬件的编码和解码,终于在iOS...

    iOS系统中H264硬解码及显示详解


    苹果在iOS 8.0系统之前,没有开放系统的硬件编码解码功能,不过Mac OS系统一直有,被称为VideoToolBox的框架来处理硬件的编码和解码,终于在iOS 8.0后,苹果将该框架引入iOS系统。

    一、VideoToolbox基本数据结构:

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

    2、CMTimeCMClockCMTimebase:时间戳相关。时间以64-bit/32-bit的形式出现;

    3、CMBlockBuffer:编码后,结果图像的数据结构;

    4、CMVideoFormatDescription:图像存储方式,编解码器等格式描述;

    5、CMSampleBuffer:存放编解码前后的视频图像的容器数据结构。

    下图为H264解码前后数据结构示意图:

    这里写图片描述


    二、硬解使用方法:

    H264的码流由NALU单元组成,NALU单元包含视频图像数据和H264的参数信息。其中视频图像数据就是CMBlockBuffer,而H264的参数信息则可以组合成FormatDesc。具体来说参数信息包含SPSSequence Parameter Set)和PPSPicture Parameter Set)。下图显示一个H264码流的结构:

    这里写图片描述


    解码方式一:(通过系统提供的AVSampleBufferDisplayLayer来解码并显示)

    • 1、初始化H264硬解param:
      使用CMVideoFormatDescriptionCreateFromH264ParameterSets函数来构建CMVideoFormatDescriptionRef

      CMVideoFormatDescriptionCreateFromH264ParameterSets(kCFAllocatorDefault,
      				2, //param count
      				parameterSetPointers,
      				parameterSetSizes,
      				4, //nal start code size
      				&_decoderFormatDescription);
      
    • 2、将H264码流转换成解码前的CMSampleBuffer:
      1) 使用CMBlockBufferCreateWithMemoryBlock接口构造CMBlockBufferRef;

      CMBlockBufferRef blockBuffer = NULL;
      CMBlockBufferCreateWithMemoryBlock(kCFAllocatorDefault,
                                        (void*)frame.bytes, 
                                         frame.length,
                                         kCFAllocatorNull,
                                         NULL, 0, frame.length,
                                         0, &blockBuffer);
      

      2)根据上述得到CMVideoFormatDescriptionRef、CMBlockBufferRef和可选的时间信息,使用CMSampleBufferCreate接口得到CMSampleBuffer数据这个待解码的原始的数据。

      CMSampleBufferRef sampleBuffer = NULL;
      CMSampleBufferCreateReady(kCFAllocatorDefault,
                                blockBuffer,
                                _decoderFormatDescription,
                                1, 0, NULL, 1, sampleSizeArray,
                                &sampleBuffer);  
      
    • 3、硬解图像显示:
      通过系统提供的AVSampleBufferDisplayLayer来解码并显示。

      AVSampleBufferDisplayLayer是苹果提供的一个专门显示编码后的H264数据的显示层,它是CALayer的子类,因此使用方式和其它CALayer类似。该层内置了硬件解码功能,将原始的CMSampleBuffer解码后的图像直接显示在屏幕上面,非常的简单方便。

      CFArrayRef attachments = CMSampleBufferGetSampleAttachmentsArray(sampleBuffer, YES);
      CFMutableDictionaryRef dict = (CFMutableDictionaryRef)CFArrayGetValueAtIndex(attachments, 0);
      CFDictionarySetValue(dict, kCMSampleAttachmentKey_DisplayImmediately, kCFBooleanTrue);
      
      if (status == kCMBlockBufferNoErr) {
          if ([_avslayer isReadyForMoreMediaData]) {
              dispatch_sync(dispatch_get_main_queue(),^{
                  [_avslayer enqueueSampleBuffer:sampleBuffer];
              });
          }
          
          CFRelease(sampleBuffer);
      } 
      

      ps:_avslayer为AVSampleBufferDisplayLayer 对象,设置如下:

        AVSampleBufferDisplayLayer *avslayer = [[AVSampleBufferDisplayLayer alloc] init];
        
        avslayer.bounds = self.view.bounds;
        avslayer.position = CGPointMake(CGRectGetMidX(self.view.bounds), CGRectGetMidY(self.view.bounds));
        avslayer.videoGravity = AVLayerVideoGravityResizeAspect;
        
        CMTimebaseRef controlTimebase;
        CMTimebaseCreateWithMasterClock(CFAllocatorGetDefault(), CMClockGetHostTimeClock(), &controlTimebase);
        avslayer.controlTimebase = controlTimebase;
        
        CMTimebaseSetRate(avslayer.controlTimebase, 1.0);
        
        self.avslayer = avslayer;
        
        [self.view.layer addSublayer:self.avslayer];
    

    解码方式二:(通过VTDecompression接口,将CMSampleBuffer解码成图像,将图像通过UIImageView或者OpenGL来显示)

    • 1、初始化H264硬解param:

      在方式一的基础上,使用VTDecompressionSessionCreate接口构造VTDecompressionSessionRef;(初始化VTDecompressionSession,设置解码器的相关信息)

      VTDecompressionSessionRef _deocderSession;
      VTDecompressionSessionCreate(kCFAllocatorDefault,
                                   _decoderFormatDescription,
                                   NULL, attrs,
                                   &callBackRecord,
                                   &_deocderSession);
      
    • 2、将H264码流转换成解码前的CMSampleBuffer:

      同方式一

    • 3、将CMSampleBuffer数据使用VTDecompressionSessionDecodeFrame接口解码成CVPixelBufferRef数据:

      CVPixelBufferRef outputPixelBuffer = NULL;
      VTDecompressionSessionDecodeFrame(_deocderSession,
                                        sampleBuffer,
                                        flags,
                                        &outputPixelBuffer,
                                        &flagOut);
      
    • 4、将CVPixelBufferRef数据转换成UIImage并显示:

    CIImage *ciImage = [CIImage imageWithCVPixelBuffer:pixelBuffer];
    	            
    	CIContext *temporaryContext = [CIContext contextWithOptions:nil];//required
    	CGImageRef videoImage = [temporaryContext
    	                         createCGImage:ciImage
    							 fromRect:CGRectMake(0, 0,
    												 CVPixelBufferGetWidth(pixelBuffer),
    												 CVPixelBufferGetHeight(pixelBuffer))];//required
    	
    	UIImage *uiImage = [UIImage imageWithCGImage:videoImage];
    	CGImageRelease(videoImage);
    

    以上只是部分关键代码,具体代码请查看 完整Demo


    三、程序流程框图:

    这里写图片描述 解码方式一 这里写图片描述 解码方式二


    四、两种解码方式比较:

    解码方式一:

    • 优点: 该方式通过系统提供的AVSampleBufferDisplayLayer显示层来解码并显示。该层内置了硬件解码功能,将原始的CMSampleBuffer解码后的图像直接显示在屏幕上,非常的简单方便,且执行效率高,占用内存相对较少。
    • 缺点: 从解码的数据中不能直接获取图像数据并对其做相应处理,解码后的数据不能直接进行其他方面的应用(一般要做较复杂的转换)。

    解码方式二:

    • 优点: 该方式通过VTDecompressionSessionDecodeFrame接口,得到CVPixelBufferRef数据,我们可以直接从CVPixelBufferRef数据中获取图像数据并对其做相应处理,方便于其他应用。
    • 缺点: 解码中执行效率相对降低,占用的内存也会相对较大。
    展开全文
  • iOS H264硬解码文档

    2015-12-06 17:10:33
    这篇文档详细描述了iOS下视频硬解码的操作流程。可以参考Demo:http://blog.csdn.net/cdut100/article/details/50084853
  • 系列文章:《iOS视频开发(一):视频采集》《iOS视频开发(二):视频H264硬编码》《iOS视频开发(三):视频H264硬解码》《iOS视频开发(四):通俗理解YUV数据》 上一篇《iOS视频开发(二):视频H264硬编码》...

    前言

    系列文章:
    《iOS视频开发(一):视频采集》
    《iOS视频开发(二):视频H264硬编码》
    《iOS视频开发(三):视频H264硬解码》
    《iOS视频开发(四):通俗理解YUV数据》

    上一篇《iOS视频开发(二):视频H264硬编码》我们已经学会了如何对视频数据进行H264编码并且了解了H264码流的基本结构。通常我们将视频进行H264编码是为了进行网络传输,如网络直播、视频会议等应用。网络传输相关的知识点较多且杂,这里我们且先不进行深入研究。我们接着讲对于H264数据,我们如何对其进行解码,本文就来讲一下如何使用VideoToolBox对H264数据进行硬解码。


    解码过程

    硬解码流程很简单:
    1、解析H264数据
    2、初始化解码器(VTDecompressionSessionCreate
    3、将解析后的H264数据送入解码器(VTDecompressionSessionDecodeFrame
    4、解码器回调输出解码后的数据(CVImageBufferRef

    从上一篇文章我们知道H264原始码流是由一个接一个的NALU(Nal Unit)组成的,I帧是一个完整编码的帧,P帧和B帧都需要根据I帧进行生成。这也就是说,若H264码流中没有I帧,即P帧和B帧失去参考,那么将无法对该码流进行解码。VideoToolBox的硬编码器编码出来的H264数据第一帧为I帧,我们也可以手动告诉编码器编一个I帧给我们。按照H264的数据格式,I帧前面必须有sps和pps数据,解码的第一步初始化解码器正是需要sps和pps数据来对编码器进行初始化。

    1、解析并处理H264数据

    既然H264数据是一个接一个的NALU组成,要对数据进行解码我们需要先对NALU数据进行解析。
    NALU数据的前4个字节是开始码,用于标示这是一个NALU 单元的开始,第5字节是NAL类型,我们取出第5个字节转为十进制,看看什么类型,对其进行处理后送入解码器进行解码。

     

    uint8_t *frame = (uint8_t *)naluData.bytes;
    uint32_t frameSize = (uint32_t)naluData.length;
    // frame的前4个字节是NALU数据的开始码,也就是00 00 00 01,
    // 第5个字节是表示数据类型,转为10进制后,7是sps, 8是pps, 5是IDR(I帧)信息
    int nalu_type = (frame[4] & 0x1F);
    
    // 将NALU的开始码转为4字节大端NALU的长度信息
    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);
    switch (nalu_type)
    {
        case 0x05: // I帧
            NSLog(@"NALU type is IDR frame");
            if([self initH264Decoder])
            {
                [self decode:frame withSize:frameSize];
            }
            break;
        case 0x07: // SPS
            NSLog(@"NALU type is SPS frame");
            _spsSize = frameSize - 4;
            _sps = malloc(_spsSize);
            memcpy(_sps, &frame[4], _spsSize);
            break;
        case 0x08: // PPS
            NSLog(@"NALU type is PPS frame");
            _ppsSize = frameSize - 4;
            _pps = malloc(_ppsSize);
            memcpy(_pps, &frame[4], _ppsSize);
            break;
        default: // B帧或P帧
            NSLog(@"NALU type is B/P frame");
            if([self initH264Decoder])
            {
                [self decode:frame withSize:frameSize];
            }
            break;
    }
    

    这里我们需要把前4个字节的开始码转为4字节大端的NALU长度(不包含开始码)

    2、初始化解码器

    ①根据sps pps创建解码视频参数描述器

     

    const uint8_t* const parameterSetPointers[2] = {_sps, _pps};
    const size_t parameterSetSizes[2] = {_spsSize, _ppsSize};
    OSStatus status = CMVideoFormatDescriptionCreateFromH264ParameterSets(kCFAllocatorDefault, 2, parameterSetPointers, parameterSetSizes, 4, &_decoderFormatDescription);
    

    ②创建解码器、设置解码回调

     

    // 从sps pps中获取解码视频的宽高信息
    CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(_decoderFormatDescription);
    
    // kCVPixelBufferPixelFormatTypeKey 解码图像的采样格式
    // kCVPixelBufferWidthKey、kCVPixelBufferHeightKey 解码图像的宽高
    // kCVPixelBufferOpenGLCompatibilityKey制定支持OpenGL渲染,经测试有没有这个参数好像没什么差别
    NSDictionary* destinationPixelBufferAttributes = @{(id)kCVPixelBufferPixelFormatTypeKey : @(kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange), (id)kCVPixelBufferWidthKey : @(dimensions.width), (id)kCVPixelBufferHeightKey : @(dimensions.height),
                                                       (id)kCVPixelBufferOpenGLCompatibilityKey : @(YES)};
    
    // 设置解码输出数据回调
    VTDecompressionOutputCallbackRecord callBackRecord;
    callBackRecord.decompressionOutputCallback = decodeOutputDataCallback;
    callBackRecord.decompressionOutputRefCon = (__bridge void *)self;
    // 创建解码器
    status = VTDecompressionSessionCreate(kCFAllocatorDefault, _decoderFormatDescription, NULL, (__bridge CFDictionaryRef)destinationPixelBufferAttributes, &callBackRecord, &_deocderSession);
    // 解码线程数量
    VTSessionSetProperty(_deocderSession, kVTDecompressionPropertyKey_ThreadCount, (__bridge CFTypeRef)@(1));
    // 是否实时解码
    VTSessionSetProperty(_deocderSession, kVTDecompressionPropertyKey_RealTime, kCFBooleanTrue);
    

    3、将解析后的H264数据送入解码器

    比较简单,直接看代码

     

    CMBlockBufferRef blockBuffer = NULL;
    // 创建 CMBlockBufferRef
    OSStatus status  = CMBlockBufferCreateWithMemoryBlock(NULL, (void *)frame, frameSize, kCFAllocatorNull, NULL, 0, frameSize, FALSE, &blockBuffer);
    if(status != kCMBlockBufferNoErr)
    {
        return;
    }
    CMSampleBufferRef sampleBuffer = NULL;
    const size_t sampleSizeArray[] = {frameSize};
    // 创建 CMSampleBufferRef
    status = CMSampleBufferCreateReady(kCFAllocatorDefault, blockBuffer, _decoderFormatDescription , 1, 0, NULL, 1, sampleSizeArray, &sampleBuffer);
    if (status != kCMBlockBufferNoErr || sampleBuffer == NULL)
    {
        return;
    }
    // VTDecodeFrameFlags 0为允许多线程解码
    VTDecodeFrameFlags flags = 0;
    VTDecodeInfoFlags flagOut = 0;
    // 解码 这里第四个参数会传到解码的callback里的sourceFrameRefCon,可为空
    OSStatus decodeStatus = VTDecompressionSessionDecodeFrame(_deocderSession, sampleBuffer, flags, NULL, &flagOut);
    // Create了就得Release
    CFRelease(sampleBuffer);
    CFRelease(blockBuffer);
    

    踩坑及总结

    解码还没遇到什么问题,这一块还是比较简单的,如果疑惑请留言或私信。

    下一篇我们来捋一下YUV数据是个什么玩意儿吧。
    本文Demo地址:https://github.com/GenoChen/MediaService

    展开全文
  • IOS音视频(二十二)视频H264硬解码原理详解

    IOS音视频(二十二)视频H264硬解码原理详解

    展开全文
  • 最近在使用Gstreamer来实验Android平台的音视频接收,视频编码格式为H264,但是Gstreamer使用软解码效果不是很有,有马赛克的情况出现,不知道哪位大神知道Gstreamer是否提供Android平台的硬解码呢?如果提供,应该...
  • IOS音视频(二十六)视频H264硬解码工具类封装之解码具体实现

    IOS音视频(二十六)视频H264硬解码工具类封装之解码具体实现

    展开全文
  • IOS音视频(二十五)视频H264硬解码工具类封装之解码参数设置
  • android webrtc学习 二(H264硬解码适配)场景 场景 Android webrtc个人觉得不太友好,对H264的支持实在是太低,不过这也正好触发我们不断的去学习和动手去解决遇到的问题;我使用的webrtc版本是m79这个版本,一开始...
  • iOS 视频h264硬解码

    千次阅读 2017-03-07 10:26:46
    [h264HwDecoder decodeH264Nalu:iFrameStartCode3bytesBuffer withSize:(uint32_t)assemblyMutableData.length]; } NSData *iFrameStartCode3bytesData = [NSData dataWithBytes:&videoFrameBuffer[...
  • 视频H264硬解码工具类封装之视频渲染需求分析
  • iOS h264 硬解码

    千次阅读 2015-11-30 17:51:11
    iOS 系统中,H.264 视频流可以硬件解码吗? 具体如何实现? 添加评论 •邀请回答 查看全部 14 个回答 bbcallen,ijkplayer 林坚升、李者璈、Wayne Wang 等人赞
  • android H264硬解码为YUV

    千次阅读 2018-05-22 22:53:49
    音视频方面的视频流大多是h264编码的,现在要把这些视频流通过android编码解码为YUV。解码时注意以及几点:1,视频文件的分辨率2,设置MediaFormat.3,解码输出时,bytebuffer大小够用,不然输出空间不够用会有...
  • iOS videotool h264硬解码

    千次阅读 2016-12-22 08:46:09
    // now we set our H264 parameters   uint8_t * parameterSetPointers[ 2 ] = { spsData , ppsData };   size_t parameterSetSizes[ 2 ] = { spsSize - 4 , ppsSize - 4 };    ...
  • ,"OMX.Nvidia.H264." /*Nexus 7(2012), Nexus 9, Tegra 3, Tegra K1*/ ,"OMX.ittiam.video." /*Xiaomi Mi 1s*/ ,"OMX.SEC.avc." /*Exynos 3110, Nexus S*/ ,"OMX.IMG.MSVDX." /*Huawei Honor 6, Kirin 920*/ ...
  • RTSP H264硬解码显示

    千次阅读 2016-09-29 14:36:30
    记录一个RTSP取流地址:https://github.com/htwahzs/Rtsp-Android-Client
  • MediaCodec : H264硬解码核心代码总结

    千次阅读 2015-10-26 17:52:39
    1.获取h264视屏流,并进视屏流放入到解码器中的buffer中  2.获取解码器的buffer ,并获取buffer中解码后的数据,并将其设置到SurfaceView 上进行显示   显示界面: mSurfaceView = (SurfaceView) findViewById(R.id.sv...
  • webrtc更新日期 2017.11.01 WebRTC默认支持使用了高通,...修改方法:WebRTC通过MediaCodec来支持编码,我们需要修改的核心文件为以下两个 ./src/webrtc/sdk/android/api/org/webrtc/MediaCodecVideoEncode...
  • 问题现象是webrtc,视频连接正常,但是视频是黑屏,不显示。... our service doesn't need this */ ,"OMX.amlogic." /*晶晨芯片*/ Webrtc视频黑屏问题 Android H264 硬解码支持更多的机型(cpu)-兼容源码
  • PREFIX 参数指定输出目录, 如脚本所示:PREFIX=./android/armv7-a-neon-hard为支持neon和硬解码的库 CPU=armv7-a PREFIX=./android/$CPU为不支持neon和硬解码的库。 到这一步,我们的编译就正式完成了。 如图所示...
  • H265解码,H264解码,硬解码,解码库,android H265解码,
  • Android MediaCodec 硬解码H264,包括h264文件,以及另一个硬解码例子。
  • android MediaCodec 实现h264硬解码全过程

    千次下载 热门讨论 2015-05-27 15:51:51
    MediaCodec 实现h264硬解码全过程,视频数据从摄像头读出 yv12格式,转换为I420,投递给encoder,再从encoder取出编码后的h264数据投递给decoder后显示到surfaceView; 实现了udp将h264数据发送到指定主机,可通过...
  • 标签:需求:由于软解码速度跟不上导致解码花屏严重,转用ffmpeg交叉编译android 5.1源码硬解码。假设已经编译好RK3288 android5.1系统(主要是硬编码用到的libstagefright库)修改ffmpeg-2.2/configure文件如果直接...
  • Android利用MediaCodec硬解码H264,AAC文件并播放Demo。相关博客:http://blog.csdn.net/a512337862/article/details/72629755和http://blog.csdn.net/a512337862/article/details/72629755
  • Android平台对H264视频硬解码

    千次阅读 2018-02-15 17:33:20
    可是换了新平台之后,没有拿到底层的接口,所以这两天找在Android上的H264解码方案。前天在友人的提示下找到了MediaCodec这个类,Android developer上面有MediaCodec的描述和用法,还算详细可以慢慢摸索。但是在网上...
  • H264解码

    2018-08-18 02:17:00
    H264编解码(一) —— 基本概览H264编解码(二) —— ios中的H264硬解码的实现H264编解码(三) —— 一个简单的H264编解码示例 ...
  • ios使用videotoolbox硬解码h264数据,在模拟器上运行正常,但是真机调试卡在VTDecompressionSessionDecodeFrame,返回 -12909:kVTVideoDecoderBadDataErr求大神指点迷津啊?

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,458
精华内容 1,783
关键字:

h264硬解码