XDXHardwareEncoder

所属分类:流媒体/Mpeg4/MP4
开发工具:Objective-C
文件大小:0KB
下载次数:0
上传日期:2019-01-15 10:01:53
上 传 者sh-1993
说明:  使用H264或H265释放编码器,
(Use H264 or H265 release encoder,)

文件列表:
XDXHardwareEncoder/ (0, 2019-01-15)
XDXHardwareEncoder/XDXHardwareEncoder.xcodeproj/ (0, 2019-01-15)
XDXHardwareEncoder/XDXHardwareEncoder.xcodeproj/project.pbxproj (24784, 2019-01-15)
XDXHardwareEncoder/XDXHardwareEncoder.xcodeproj/project.xcworkspace/ (0, 2019-01-15)
XDXHardwareEncoder/XDXHardwareEncoder.xcodeproj/project.xcworkspace/contents.xcworkspacedata (163, 2019-01-15)
XDXHardwareEncoder/XDXHardwareEncoder.xcodeproj/project.xcworkspace/xcshareddata/ (0, 2019-01-15)
XDXHardwareEncoder/XDXHardwareEncoder.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (238, 2019-01-15)
XDXHardwareEncoder/XDXHardwareEncoder.xcodeproj/project.xcworkspace/xcuserdata/ (0, 2019-01-15)
XDXHardwareEncoder/XDXHardwareEncoder.xcodeproj/project.xcworkspace/xcuserdata/demon.xcuserdatad/ (0, 2019-01-15)
XDXHardwareEncoder/XDXHardwareEncoder.xcodeproj/project.xcworkspace/xcuserdata/demon.xcuserdatad/UserInterfaceState.xcuserstate (42141, 2019-01-15)
XDXHardwareEncoder/XDXHardwareEncoder.xcodeproj/project.xcworkspace/xcuserdata/xiao_dx.xcuserdatad/ (0, 2019-01-15)
XDXHardwareEncoder/XDXHardwareEncoder.xcodeproj/project.xcworkspace/xcuserdata/xiao_dx.xcuserdatad/UserInterfaceState.xcuserstate (12181, 2019-01-15)
XDXHardwareEncoder/XDXHardwareEncoder.xcodeproj/xcuserdata/ (0, 2019-01-15)
XDXHardwareEncoder/XDXHardwareEncoder.xcodeproj/xcuserdata/demon.xcuserdatad/ (0, 2019-01-15)
XDXHardwareEncoder/XDXHardwareEncoder.xcodeproj/xcuserdata/demon.xcuserdatad/xcdebugger/ (0, 2019-01-15)
XDXHardwareEncoder/XDXHardwareEncoder.xcodeproj/xcuserdata/demon.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist (523, 2019-01-15)
XDXHardwareEncoder/XDXHardwareEncoder.xcodeproj/xcuserdata/demon.xcuserdatad/xcschemes/ (0, 2019-01-15)
XDXHardwareEncoder/XDXHardwareEncoder.xcodeproj/xcuserdata/demon.xcuserdatad/xcschemes/xcschememanagement.plist (341, 2019-01-15)
XDXHardwareEncoder/XDXHardwareEncoder.xcodeproj/xcuserdata/xiao_dx.xcuserdatad/ (0, 2019-01-15)
XDXHardwareEncoder/XDXHardwareEncoder.xcodeproj/xcuserdata/xiao_dx.xcuserdatad/xcdebugger/ (0, 2019-01-15)
XDXHardwareEncoder/XDXHardwareEncoder.xcodeproj/xcuserdata/xiao_dx.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist (91, 2019-01-15)
XDXHardwareEncoder/XDXHardwareEncoder.xcodeproj/xcuserdata/xiao_dx.xcuserdatad/xcschemes/ (0, 2019-01-15)
XDXHardwareEncoder/XDXHardwareEncoder.xcodeproj/xcuserdata/xiao_dx.xcuserdatad/xcschemes/xcschememanagement.plist (353, 2019-01-15)
XDXHardwareEncoder/XDXHardwareEncoder/ (0, 2019-01-15)
XDXHardwareEncoder/XDXHardwareEncoder/AppDelegate.h (288, 2019-01-15)
XDXHardwareEncoder/XDXHardwareEncoder/AppDelegate.m (2050, 2019-01-15)
XDXHardwareEncoder/XDXHardwareEncoder/Assets.xcassets/ (0, 2019-01-15)
XDXHardwareEncoder/XDXHardwareEncoder/Assets.xcassets/AppIcon.appiconset/ (0, 2019-01-15)
XDXHardwareEncoder/XDXHardwareEncoder/Assets.xcassets/AppIcon.appiconset/Contents.json (1590, 2019-01-15)
XDXHardwareEncoder/XDXHardwareEncoder/Assets.xcassets/Contents.json (62, 2019-01-15)
XDXHardwareEncoder/XDXHardwareEncoder/Assets.xcassets/bg-2.imageset/ (0, 2019-01-15)
XDXHardwareEncoder/XDXHardwareEncoder/Assets.xcassets/bg-2.imageset/Contents.json (301, 2019-01-15)
XDXHardwareEncoder/XDXHardwareEncoder/Assets.xcassets/bg-2.imageset/bg-2.jpg (486635, 2019-01-15)
XDXHardwareEncoder/XDXHardwareEncoder/Base.lproj/ (0, 2019-01-15)
XDXHardwareEncoder/XDXHardwareEncoder/Base.lproj/LaunchScreen.storyboard (1681, 2019-01-15)
XDXHardwareEncoder/XDXHardwareEncoder/Base.lproj/Main.storyboard (3512, 2019-01-15)
XDXHardwareEncoder/XDXHardwareEncoder/Info.plist (1463, 2019-01-15)
XDXHardwareEncoder/XDXHardwareEncoder/ViewController.h (226, 2019-01-15)
XDXHardwareEncoder/XDXHardwareEncoder/ViewController.m (4158, 2019-01-15)
... ...

### -------------------------------------------------------- ### 本例需求:使用H264, H265实现视频数据的编码并录制开始200帧存为文件. ##### 原理:比如做直播功能,需要将客户端的视频数据传给服务器,如果分辨率过大如2K,4K则传输压力太大,所以需要对视频数据进行编码,传给服务器后再解码以实现大数据量的视频数据的传输,而利用硬件编码则可以极大限度减小CPU压力,当前主流使用H264进行编码,iOS 11 之后,iPhone 7以上的设备可以支持新的编码器H265编码器,使得同等质量视频占用的存储空间更小。所以本例中可以使用两种方式实现视频数据的编码 ### -------------------------------------------------------- #### 最终效果如下 : h264 ![h264 编码](http://r.photo.store.qq.com/psb?/V14Id4Zj1TAt9e/Zs.FQtSqK3HEAV0KwhBWsd11gDVDBOGc6C8nEvLWvbI!/r/dLEAAAAAAAAA) #### h265 : ![h265 编码](http://r.photo.store.qq.com/psb?/V14Id4Zj1TAt9e/0laaTVE7fYiJysspAOooBZ3fCdWlUxVfVNz66tO2jv4!/r/dBABAAAAAAAA) ### -------------------------------------------------------- #### GitHub地址(附代码) : [H264,H265Encode](https://github.com/ChengyangLi/XDXHardwareEncoder) #### 简书地址 : [H264,H265Encode](http://www.jianshu.com/p/d783d4a209b6) #### 博客地址 : [H264,H265Encode](https://chengyangli.github.io/2017/11/10/H264H265Encoder/) #### 掘金地址 : [https://juejin.im/post/5a8fe3def265da4e8e78781b](https://juejin.im/post/5a8fe3def265da4e8e78781b) ### -------------------------------------------------------- ## 实现方式: ### 1. H264 : H264是当前主流编码标准,以高压缩高质量和支持多种网络的流媒体传输著称 ### 2. H265 :H264编码器的下一代,它的主要优点提供的压缩比高,相同质量的视频是H264的两倍。 ### -------------------------------------------------------- ## 一.本文需要基本知识点 #### 注意:可以先通过[H264,H265编码器介绍](http://www.jianshu.com/p/668e6abbed8c),[H264 Data Structure](http://www.jianshu.com/p/24f2a069dd7e)了解预备知识。 #### 1. 软编与硬编概念 - 软编码:使用CPU进行编码。 - 硬编码:不使用CPU进行编码,使用显卡GPU,专用的DSP、FPGA、ASIC芯片等硬件进行编码。 - 比较 - 软编码:实现直接、简单,参数调整方便,升级易,但CPU负载重,性能较硬编码低,低码率下质量通常比硬编码要好一点。 - 性能高,低码率下通常质量低于软编码器,但部分产品在GPU硬件平台移植了优秀的软编码算法(如X264)的,质量基本等同于软编码。 - 苹果在iOS 8.0系统之前,没有开放系统的硬件编码解码功能,不过Mac OS系统一直有,被称为Video ToolBox的框架来处理硬件的编码和解码,终于在iOS 8.0后,苹果将该框架引入iOS系统 #### 2.H265优点 - 压缩比高,在相同图片质量情况下,比JPEG高两倍 - 能增加如图片的深度信息,透明通道等辅助图片。 - 支持存放多张图片,类似相册和集合。(实现多重曝光的效果) - 支持多张图片实现GIF和livePhoto的动画效果。 - 无类似JPEG的最大像素限制 - 支持透明像素 - 分块加载机制 - 支持缩略图 ## 二.代码解析 #### 1.实现流程 - 初始化相机参数,设置相机代理,这里就固定只有竖屏模式。 - 初始化编码器参数,并启动编码器 - 在编码成功的回调中从开始录制200帧(文件大小可自行修改)的视频,存到沙盒中,可以通过连接数据线到电脑从itunes中将文件(test0.asf)提取出来 #### 2.编码器实现流程 - 创建编码器需要的session (h264, h265 或同时创建) - 设置session属性,如实时编码,码率,fps, 编码的分辨率的宽高,相邻I帧的最大间隔等等 - ###### 注意H265目前不支持码率的限制 - 当相机回调AVCaptureVideoDataOutputSampleBufferDelegate采集到一帧数据的时候则使用H264/H265编码器对每一帧数据进行编码。 - 若编码成功会触发回调,回调函数首先检测是否有I帧出现,如果有I帧出现则将sps,pps信息写入否则遍历NALU码流并将startCode替换成{0x00, 0x00, 0x00, 0x01} #### 3.主要方法解析 - 初始化编码器 首先选择使用哪种方式实现,在本例中可以设置[XDXHardwareEncoder getInstance].enableH264 = YES 或者 [XDXHardwareEncoder getInstance].enableH265 = YES,也可以同时设置,如果同时设置需要将其中一个回调函数中的writeFile的方法屏蔽掉,并且只有较新的iPhone(> iPhone8 稳定)才支持同时打开两个session。 > 判断当前设备是否支持H265编码,必须满足两个条件,一是iPhone 7 以上设备,二是版本大于iOS 11 ``` if (@available(iOS 11.0, *)) { BOOL hardwareDecodeSupported = VTIsHardwareDecodeSupported(kCMVideoCodecType_HEVC); if (hardwareDecodeSupported) { _deviceSupportH265 = YES; NSLog(@"XDXHardwareEncoder : Support H265 Encode/Decode!"); } }else { _deviceSupportH265 = NO; NSLog(@"XDXHardwareEncoder : Not support H265 Encode/Decode!"); } ``` 系统已经提供VTIsHardwareDecodeSupported判断当前设备是否支持H265编码 > 初始化编码器操作 ``` - (void)prepareForEncode { if(self.width == 0 || self.height == 0) { NSLog(@"XDXHardwareEncoder : VTSession need with and height for init,with = %d,height = %d",self.width, self.height); return; } if(g_isSupportRealTimeEncoder) NSLog(@"XDXHardwareEncoder : Device processor is 64 bit"); else NSLog(@"XDXHardwareEncoder : Device processor is not 64 bit"); NSLog(@"XDXHardwareEncoder : Current h264 open state : %d, h265 open state : %d",self.enableH264, self.enableH265); OSStatus h264Status,h265Status; BOOL isRestart = NO; if (self.enableH264) { if (h264CompressionSession != NULL) { NSLog(@"XDXHardwareEncoder : H264 session not NULL"); return; } [m_h264_lock lock]; NSLog(@"XDXHardwareEncoder : Prepare H264 hardware encoder"); //[self.delegate willEncoderStart]; self.h264ErrCount = 0; h264Status = VTCompressionSessionCreate(NULL, self.width, self.height, kCMVideoCodecType_H264, NULL, NULL, NULL, vtCallBack,(__bridge void *)self, &h264CompressionSession); if (h264Status != noErr) { self.h265ErrCount++; NSLog(@"XDXHardwareEncoder : H264 VTCompressionSessionCreate Failed, status = %d",h264Status); } [self getSupportedPropertyFlags]; [self applyAllSessionProperty:h264CompressionSession propertyArr:self.h264propertyFlags]; h264Status = VTCompressionSessionPrepareToEncodeFrames(h264CompressionSession); if(h264Status != noErr) { NSLog(@"XDXHardwareEncoder : H264 VTCompressionSessionPrepareToEncodeFrames Failed, status = %d",h264Status); }else { initializedH264 = true; NSLog(@"XDXHardwareEncoder : H264 VTSession create success, with = %d, height = %d, framerate = %d",self.width,self.height,self.fps); } if(h264Status != noErr && self.h264ErrCount != 0) isRestart = YES; [m_h264_lock unlock]; } if (self.enableH265) { if (h265CompressionSession != NULL) { NSLog(@"XDXHardwareEncoder : H265 session not NULL"); return; } [m_h265_lock lock]; NSLog(@"XDXHardwareEncoder : Prepare h265 hardware encoder"); // [self.delegate willEncoderStart]; self.h265ErrCount = 0; h265Status = VTCompressionSessionCreate(NULL, self.width, self.height, kCMVideoCodecType_HEVC, NULL, NULL, NULL, vtH265CallBack,(__bridge void *)self, &h265CompressionSession); if (h265Status != noErr) { self.h265ErrCount++; NSLog(@"XDXHardwareEncoder : H265 VTCompressionSessionCreate Failed, status = %d",h265Status); } [self getSupportedPropertyFlags]; [self applyAllSessionProperty:h265CompressionSession propertyArr:self.h265PropertyFlags]; h265Status = VTCompressionSessionPrepareToEncodeFrames(h265CompressionSession); if(h265Status != noErr) { NSLog(@"XDXHardwareEncoder : H265 VTCompressionSessionPrepareToEncodeFrames Failed, status = %d",h265Status); }else { initializedH265 = true; NSLog(@"XDXHardwareEncoder : H265 VTSession create success, with = %d, height = %d, framerate = %d",self.width,self.height,self.fps); } if(h265Status != noErr && self.h265ErrCount != 0) isRestart = YES; [m_h265_lock unlock]; } if (isRestart) { NSLog(@"XDXHardwareEncoder : VTSession create failured!"); static int count = 0; count ++; if (count == 3) { NSLog(@"TVUEncoder : restart 5 times failured! exit!"); return; } sleep(1); NSLog(@"TVUEncoder : try to restart after 1 second!"); NSLog(@"TVUEncoder : vtsession error occured!,resetart encoder width: %d, height %d, times %d",self.width,self.height,count); [self tearDownSession]; [self prepareForEncode]; } } ``` 1> `g_isSupportRealTimeEncoder = (is64Bit == 8) ? true : false;`用来判断当前设备是32位还是64位 2> 创建H264/H265Session 区别仅仅为参数的不同,h264为kCMVideoCodecType_H264。 h265为kCMVideoCodecType_HEVC,在创建Session指定了回调函数后,当编码成功一帧就会调用相应的回调函数。 3> 通过`[self getSupportedPropertyFlags];`获取当前编码器支持设置的属性,经过测试,H265不支持码率的限制。目前暂时得不到解决。等待苹果后续处理。 4> 之后设置编码器相关属性,下面会具体介绍,设置完成后则调用VTCompressionSessionPrepareToEncodeFrames准备编码。 - 设置编码器相关属性 ``` - (OSStatus)setSessionProperty:(VTCompressionSessionRef)session key:(CFStringRef)key value:(CFTypeRef)value { OSStatus status = VTSessionSetProperty(session, key, value); if (status != noErr) { NSString *sessionStr; if (session == h264CompressionSession) { sessionStr = @"h264 Session"; self.h264ErrCount++; }else if (session == h265CompressionSession) { sessionStr = @"h265 Session"; self.h265ErrCount++; } NSLog(@"XDXHardwareEncoder : Set %s of %s Failed, status = %d",CFStringGetCStringPtr(key, kCFStringEncodingUTF8),sessionStr.UTF8String,status); } return status; } - (void)applyAllSessionProperty:(VTCompressionSessionRef)session propertyArr:(NSArray *)propertyArr { OSStatus status; if(!g_isSupportRealTimeEncoder) { /* increase max frame delay from 3 to 6 to reduce encoder pressure*/ int value = 3; CFNumberRef ref = CFNumberCreate(NULL, kCFNumberSInt32Type, &value); [self setSessionProperty:session key:kVTCompressionPropertyKey_MaxFrameDelayCount value:ref]; CFRelease(ref); } if(self.fps) { if([self isSupportPropertyWithKey:Key_ExpectedFrameRate inArray:propertyArr]) { int value = self.fps; CFNumberRef ref = CFNumberCreate(NULL, kCFNumberSInt32Type, &value); [self setSessionProperty:session key:kVTCompressionPropertyKey_ExpectedFrameRate value:ref]; CFRelease(ref); } }else { NSLog(@"XDXHardwareEncoder : Current fps is 0"); } if(self.bitrate) { if([self isSupportPropertyWithKey:Key_AverageBitRate inArray:propertyArr]) { int value = self.bitrate; if (session == h265CompressionSession) value = 2*1000; // if current session is h265, Set birate 2M. CFNumberRef ref = CFNumberCreate(NULL, kCFNumberSInt32Type, &value); [self setSessionProperty:session key:kVTCompressionPropertyKey_AverageBitRate value:ref]; CFRelease(ref); } }else { NSLog(@"XDXHardwareEncoder : Current bitrate is 0"); } /*2016-11-15,@gang, iphone7/7plus do not support realtime encoding, so disable it otherwize ,we can not control encoding bit rate */ if (![[self deviceVersion] isEqualToString:@"iPhone9,1"] && ![[self deviceVersion] isEqualToString:@"iPhone9,2"]) { if(g_isSupportRealTimeEncoder) { if([self isSupportPropertyWithKey:Key_RealTime inArray:propertyArr]) { NSLog(@"use RealTimeEncoder"); NSLog(@"XDXHardwareEncoder : use realTimeEncoder"); [self setSessionProperty:session key:kVTCompressionPropertyKey_RealTime value:kCFBooleanTrue]; } } } if([self isSupportPropertyWithKey:Key_AllowFrameReordering inArray:propertyArr]) { [self setSessionProperty:session key:kVTCompressionPropertyKey_AllowFrameReordering value:kCFBooleanFalse]; } if(g_isSupportRealTimeEncoder) { if([self isSupportPropertyWithKey:Key_ProfileLevel inArray:propertyArr]) { [self setSessionProperty:session key:kVTCompressionPropertyKey_ProfileLevel value:self.enableH264 ? kVTProfileLevel_H264_Main_AutoLevel : kVTProfileLevel_HEVC_Main_AutoLevel]; } }else { if([self isSupportPropertyWithKey:Key_ProfileLevel inArray:propertyArr]) { [self setSessionProperty:session key:kVTCompressionPropertyKey_ProfileLevel value:self.enableH264 ? kVTProfileLevel_H264_Baseline_AutoLevel : kVTProfileLevel_HEVC_Main_AutoLevel]; } if (self.enableH264) { if([self isSupportPropertyWithKey:Key_H264EntropyMode inArray:propertyArr]) { [self setSessionProperty:session key:kVTCompressionPropertyKey_H264EntropyMode value:kVTH264EntropyMode_CAVLC]; } } } if([self isSupportPropertyWithKey:Key_MaxKeyFrameIntervalDuration inArray:propertyArr]) { int value = 1; CFNumberRef ref = CFNumberCreate(NULL, kCFNumberSInt32Type, &value); [self setSessionProperty:session key:kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration value:ref]; CFRelease(ref); } } ``` 上述方法主要设置启动编码器所需的各个参数 1> kVTCompressionPropertyKey_MaxFrameDelayCount : 压缩器被允许保持的最大帧数在输出一个压缩帧之前。例如如果最大帧延迟数是M,那么在编码帧N返回的调用之前,帧N-M必须被排出。 2> kVTCompressionPropertyKey_ExpectedFrameRate : 设置fps 3> kVTCompressionPropertyKey_AverageBitRate : 它不是强制的限制,bit rate可能会超出峰值 4> kVTCompressionPropertyKey_RealTime : 设置编码器是否实时编码,如果设置为False则不是实时编码,视频效果会更好一点。 5> kVTCompressionPropertyKey_AllowFrameReordering : 是否让帧进行重新排序。为了编码B帧,编码器必须对帧重新排序,这将意味着解码的顺序与显示的顺序不同。将其设置为false以防止帧重新排序。 6> kVTCompressionPropertyKey_ProfileLevel : 指定编码比特流的配置文件和级别 7> kVTCompressionPropertyKey_H264EntropyMode :如果支持h264该属性设置编码器是否应该使用基于CAVLC 还是 CABAC 8> kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration : 两个I帧之间最大持续时间,该属性特别有用当frame rate是可变 - 相机回调中对每一帧数据进行编码 ``` - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection { if( !CMSampleBufferDataIsReady(sampleBuffer)) { NSLog( @"sample buffer is not ready. Skipping sample" ); return; } if([XDXHardwareEncoder getInstance] != NULL) { [[XDXHardwareEncoder getInstance] encode:sampleBuffer]; } } ``` 以上方法在每采集到一帧视频数据后会调用一次,我们将拿到的每一帧数据进行编码。 - 编码具体实现 ``` -(void)encode:(CMSampleBufferRef)sampleBuffer { if (self.enableH264) { [m_h264_lock lock]; if(h264CompressionSession == NULL) { [m_h264_lock unlock]; return; } if(initializedH264 == false) { NSLog(@"TVUEncoder : h264 encoder is not ready\n"); return; } } if (self.enableH265) { [m_h265_lock lock]; if(h265CompressionSession == NULL) { [m_h265_lock unlock]; return; } if(initializedH265 == false) { NSLog(@"TVUEncoder : h265 encoder is not ready\n"); return; } } CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); CMTime duration = CMSampleBufferGetOutputDuration(sampleBuffer); frameID++; CMTime presentationTimeStamp = CMTimeMake(frameID, 1000); [self doSetBitrate]; OSStatus status; VTEncodeInfoFlags flags; if (self.enableH264) { status = VTCompressionSessionEncodeFrame(h264CompressionSession, imageBuffer, presentationTimeStamp, duration, NULL, imageBuffer, &flags); if(status != noErr) NSLog(@"TVUEncoder : H264 VTCompressionSessionEncodeFrame failed"); [m_h264_lock unlock]; if (status != noErr) { NSLog(@"TVUEncoder : VTCompressionSessionEncodeFrame failed"); VTCompressionSessionCompleteFrames(h264CompressionSession, kCMTimeInvalid); VTCompressionSessionInvalidate(h264CompressionSession); CFRelease(h264CompressionSession); h264CompressionSession = NULL; }else { // NSLog(@"TVUEncoder : Success VTCompressionSessionCompleteFrames"); } } if (self.enableH265) { status = VTCompressionSessionEncodeFrame(h265CompressionSession, imageBuffer, presentationTimeStamp, duration, NULL, imageBuffer, &flags); if(status != noErr) NSLog(@"TVUEncoder : H265 VTCompressionSessionEncodeFrame failed"); [m_h265_lock unlock]; if (status != noErr) { NSLog(@"TVUEncoder : VTCompressionSessionEncodeFrame failed"); VTCompressionSessionCompleteFrames(h265CompressionSession, kCMTimeInvalid); VTCompressionSessionInvalidate(h265CompressionSession); CFRelease(h265CompressionSession); h265CompressionSession = NULL; }else { NSLog(@"TVUEncoder : Success VTCompressionSessionCompleteFrames"); } } } ``` 1> 通过frameID的递增构造时间戳为了使编码后的每一帧数据连续 2> 设置最大码率的限制,注意:H265目前不支持设置码率的限制,等待官方后续通知。可以对H264进行码率限制 3> kVTCompressionPropertyKey_DataRateLimits : 将数据的bytes和duration封装到CFMutableArrayRef传给API进行调用 4> VTCompressionSessionEncodeFrame : 调用此方法成功后触发回调函数完成编码。 - 回调函数中处理头信息 ``` #pragma mark H264 Callback static void vtCallBack(void *outputCallbackRefCon,void *souceFrameRefCon,OSStatus status,VTEncodeInfoFlags infoFlags, CMSampleBufferRef sampleBuffer) { XDXHardwareEncoder *encoder = (__bridge XDXHardwareEncoder*)outputCallbackRefCon; if(status != noErr) { NSError *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil]; NSLog(@"H264: vtCallBack failed with %@", error); NSLog(@"XDXHardwareEncoder : encode frame failured! %s" ,error.debugDescription.UTF8String); return; } if (!CMSampleBufferDataIsReady(sampleBuffer)) { NSLog(@"didCompressH265 data is not ready "); return; } if (infoFlags == kVTEncodeInfo_FrameDropped) { NSLog(@"%s with frame dropped.", __FUNCTION__); return; } CMBlockBufferRef block = CMSampleBufferGetDataBuffer(sampleBuffer); BOOL isKeyframe = false; CFArrayRef attachments = CMSampleBufferGetSampleAttachmentsArray(sampleBuffer, false); if(attachments != NULL) { CFDictionaryRef attachment =(CFDictionaryRef)CFArrayGetValueAtIndex(attachments, 0); CFBooleanRef dependsOnOthers = (CFBooleanRef)CFDictionaryGetValue(attachment, kCMSampleAttachmentKey_DependsOnOthers); isKeyframe = (dependsOnOthers == kCFBooleanFalse); } if(isKeyframe) { CMFormatDescriptionRef format = CMSampleBufferGetFormatDescription(sampleBuffer); static uint8_t *spsppsNALBuff = NULL; static size_t spsSize, ppsSize; size_t parmCount; const uint8_t*sps, *pps; int NALUnitHeaderLengthOut; CMVideoFormatDescriptionGetH264Paramet ... ...

近期下载者

相关文件


收藏者