[置顶] 基于iOS的网络音视频实时传输系统(五)- 使用VideoToolbox硬解码H264
2017-10-12 15:34
633 查看
下载
GitHub:client 端:https://github.com/AmoAmoAmo/Smart_Device_Client
server端:https://github.com/AmoAmoAmo/Smart_Device_Server
另还写了一份macOS版的server,但是目前还有一些问题,有兴趣的去看看吧:https://github.com/AmoAmoAmo/Server_Mac
使用VideoToolbox硬解码H264。
关于这一部分,由于是第一次使用,便不班门弄斧,
在参考文章中列举了不少说得很详细的博客。
关于最终的效果,可以参考第一篇的文章
部分过程
初始化编码器session
- (void)initVideoToolBox { if (!mDecodeSession) { // 把SPS和PPS包装成CMVideoFormatDescription const uint8_t* parameterSetPointers[2] = {mSPS, mPPS}; const size_t parameterSetSizes[2] = {mSPSSize, mPPSSize}; OSStatus status = CMVideoFormatDescriptionCreateFromH264ParameterSets(kCFAllocatorDefault, 2, //param count parameterSetPointers, parameterSetSizes, 4, //nal start code size &mFormatDescription); if(status == noErr) { CFDictionaryRef attrs = NULL; const void *keys[] = { kCVPixelBufferPixelFormatTypeKey }; // kCVPixelFormatType_420YpCbCr8Planar is YUV420 // kCVPixelFormatType_420YpCbCr8BiPlanarFullRange is NV12 uint32_t v = kCVPixelFormatType_420YpCbCr8BiPlanarFullRange; const void *values[] = { CFNumberCreate(NULL, kCFNumberSInt32Type, &v) }; attrs = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL); VTDecompressionOutputCallbackRecord callBackRecord; callBackRecord.decompressionOutputCallback = didDecompress; callBackRecord.decompressionOutputRefCon = NULL; status = VTDecompressionSessionCreate(kCFAllocatorDefault, mFormatDescription, NULL, attrs, &callBackRecord, &mDecodeSession); CFRelease(attrs); } else { NSLog(@"IOS8VT: reset decoder session failed status = %d", (int)status); } } }
回调函数
void didDecompress(void *decompressionOutputRefCon, void *sourceFrameRefCon, OSStatus status, VTDecodeInfoFlags infoFlags, CVImageBufferRef pixelBuffer, CMTime presentationTimeStamp, CMTime presentationDuration ){ CVPixelBufferRef *outputPixelBuffer = (CVPixelBufferRef *)sourceFrameRefCon; *outputPixelBuffer = CVPixelBufferRetain(pixelBuffer); }
获取H.264开始码,并开始相应的工作
// 一收到数据就调用这个方法,用来刷新屏幕 - (void)updateFrame { // 同步 --》 顺序执行 dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 替换头字节长度 uint32_t nalSize = (uint32_t)(packetSize - 4); uint32_t *pNalSize = (uint32_t *)packetBuffer; *pNalSize = CFSwapInt32HostToBig(nalSize); // 在buffer的前面填入代表长度的int // 以00 00 00 01分割之后的下一个字节就是--NALU类型-- CVPixelBufferRef pixelBuffer = NULL; int nalType = packetBuffer[4] & 0x1F; // NALU类型 & 0001 1111 switch (nalType) { case 0x05: // NSLog(@"*********** IDR frame, I帧"); [self initVideoToolBox]; // 当读入IDR帧的时候初始化VideoToolbox,并开始同步解码 pixelBuffer = [self decode]; // 解码得到的CVPixelBufferRef会传入OpenGL ES类进行解析渲染 break; case 0x07: // NSLog(@"*********** SPS"); mSPSSize = packetSize - 4; mSPS = malloc(mSPSSize); memcpy(mSPS, packetBuffer + 4, mSPSSize); break; case 0x08: // NSLog(@"*********** PPS"); mPPSSize = packetSize - 4; mPPS = malloc(mPPSSize); memcpy(mPPS, packetBuffer + 4, mPPSSize); break; default: // NSLog(@"*********** B/P frame"); // P帧? pixelBuffer = [self decode]; break; } if(pixelBuffer) { // 把解码后的数据block传给viewController self.returnDataBlock(pixelBuffer); CVPixelBufferRelease(pixelBuffer); } }); }
用CMBlockBuffer(未压缩的图像数据) 把NALUnit包装起来
CMBlockBufferRef blockBuffer = NULL; OSStatus status = CMBlockBufferCreateWithMemoryBlock(kCFAllocatorDefault, (void*)packetBuffer, packetSize, kCFAllocatorNull, NULL, 0, packetSize, 0, &blockBuffer);
创建CMSampleBuffer
把原始码流包装成CMSampleBuffer(存放一个或者多个压缩或未压缩的媒体文件)CMSampleBufferRef sampleBuffer = NULL; const size_t sampleSizeArray[] = {packetSize}; status = CMSampleBufferCreateReady(kCFAllocatorDefault, blockBuffer, // 用CMBlockBuffer把NALUnit包装起来 mFormatDescription, // 把SPS和PPS包装成CMVideoFormatDescription 1, 0, NULL, 1, sampleSizeArray, &sampleBuffer);
解码并显示
VTDecodeFrameFlags flags = 0; VTDecodeInfoFlags flagOut = 0; // 默认是同步操作。 // 调用didDecompress,返回后再回调 OSStatus decodeStatus = VTDecompressionSessionDecodeFrame(mDecodeSession, sampleBuffer, flags, &outputPixelBuffer, &flagOut);
上一步即可获得编码后的数据 outputPixelBuffer,再将它传给OpenGL渲染显示解码的结果。
关于OpenGL渲染显示在下一篇文章里。
参考文章:
1. http://www.jianshu.com/p/6dfe49b5dab82. http://www.jianshu.com/p/da18b979aeec
相关文章
基于iOS的网络音视频实时传输系统(一)- 前言基于iOS的网络音视频实时传输系统(二)- 捕获音视频数据
基于iOS的网络音视频实时传输系统(三)- VideoToolbox编码音视频数据为H264、AAC
基于iOS的网络音视频实时传输系统(四)- 自定义socket协议(TCP、UDP)
基于iOS的网络音视频实时传输系统(五)- 使用VideoToolbox硬解码H264
基于iOS的网络音视频实时传输系统(六)- AudioQueue播放音频,OpenGL渲染显示图像
相关文章推荐
- [置顶] 基于iOS的网络音视频实时传输系统(三)- VideoToolbox编码音视频数据为H264、AAC
- [置顶] 基于iOS的网络音视频实时传输系统(六)- AudioQueue播放音频,OpenGL渲染显示图像
- [置顶] 基于iOS的网络音视频实时传输系统(二)- 捕获音视频数据
- [置顶] 基于iOS的网络音视频实时传输系统(四)- 自定义socket协议(TCP、UDP)
- iOS使用VideoToolbox硬编码录制H264视频
- 基于H264-USB摄像头的RTP实时视频的传输
- 基于嵌入式Linux的视频采集系统8----基于RTP协议的实时传输模块
- 基于itop4412在Linux最小系统下的 RTP传输H264视频VLC播放
- 阶段4-独挡一面\项目-基于视频压缩的实时监控系统\Sprint3-采集端传输子系统设计
- iOS使用VideoToolbox硬编码录制H264视频
- iOS使用VideoToolbox硬编码录制H264视频
- 基于AVI的网络视频监控存储系统的实现方法
- (转)利用VC++实现局域网实时视频传输(网络视频)
- 音视频网络传输技术在安防系统中的应用
- Silverlight多人网络实时视频会议系统
- Silverlight多人网络实时视频会议系统
- 基于Linux的视频传输系统(转)
- Silverlight多人网络实时视频会议系统
- 基于ARM9的视频采集传输系统
- 基于DirectShow的MPEG-4视频传输系统的研究与实现