使用VideoToolBox硬解码MJPEG编码格式视频

Motion JPEG(MJPEG,Motion Joint Photographic Experts Group,FourCC:MJPG)是一种视频压缩格式,其中每一帧图像都分别使用JPEG编码。一般我们使用看到的使用VideoToolBox处理的都是H.264压缩格式的视频,这里我介绍一个使用VideoToolBox解码MJPEG视频编码格式的视频的方法,我们同样使用ffmpeg读取一个MJPEG编码格式的网络视频流。

1.同样的我们需要先创建 VTDecompressionSessionRef
<pre>
//根据视频信息创建视频解码的session
if (videoFormatDescr == NULL){

    // 获取视频的宽高
    int videoWidth = pCodecCtx->width;
    int videoHeight = pCodecCtx->height;
    
    //创建视频描叙信息,包括视频的宽,高和编码信息,这里我们使用MJPEG对应的编码类型kCMVideoCodecType_JPEG
    CMVideoFormatDescriptionCreate(kCFAllocatorDefault, kCMVideoCodecType_JPEG, videoWidth, videoHeight, NULL, &videoFormatDescr);
    
    //创建解码回调函数
    VTDecompressionOutputCallbackRecord callback;
    callback.decompressionOutputCallback = didDecompress;
    callback.decompressionOutputRefCon = (__bridge void *)self;
    
    //定义解码得到的图片像素格式
    NSDictionary *destinationImageBufferAttributes =[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO],(id)kCVPixelBufferOpenGLESCompatibilityKey,[NSNumber numberWithInt:kCVPixelFormatType_32BGRA],(id)kCVPixelBufferPixelFormatTypeKey,nil];
    
    //创建session
    status = VTDecompressionSessionCreate(kCFAllocatorDefault, videoFormatDescr, NULL, (__bridge CFDictionaryRef)destinationImageBufferAttributes, &callback, &session);
    if (status != noErr){
        NSLog(@"Init decoder session failed status= %d", (int)status);
    }
}

</pre>

2.开始解码

<pre>
//创建BlockBuffer,这里的数据我们直接使用AVPacket中的数据去填充
CMBlockBufferRef videoBlock = NULL;
status = CMBlockBufferCreateWithMemoryBlock(kCFAllocatorDefault, packet.data, packet.size, kCFAllocatorNull, NULL, 0, packet.size, 0, &videoBlock);
if (status != noErr){
NSLog(@"CMBlockBufferRef failed status=%d", (int)status);
}

//创建sampleBuffer
CMSampleBufferRef sampleBuffer = NULL;

const size_t sampleSizeArray[] = {packet.size};
status = CMSampleBufferCreate(kCFAllocatorDefault, videoBlock, true, NULL, NULL, videoFormatDescr, 1, 0, NULL, 1, sampleSizeArray, &sampleBuffer);
if (status != noErr){
    NSLog(@"CMSampleBufferRef failed status=%d", (int)status);
}

//开始解码
VTDecodeFrameFlags flags = kVTDecodeFrame_EnableAsynchronousDecompression;
VTDecodeInfoFlags flagOut;
status = VTDecompressionSessionDecodeFrame(session, sampleBuffer, flags, &sampleBuffer, &flagOut);

if (status != noErr) {
    NSLog(@"Decode falied status = %d",(int)status);
}

//释放内存
CFRelease(videoBlock);
CFRelease(sampleBuffer);

</pre>

3.解码之后得到的回调结果数据

<pre>
void didDecompress( void *decompressionOutputRefCon, void *sourceFrameRefCon, OSStatus status, VTDecodeInfoFlags infoFlags, CVImageBufferRef imageBuffer, CMTime presentationTimeStamp, CMTime presentationDuration )
{
if (status != noErr || !imageBuffer) {
NSLog(@"Error decompresssing frame at time: %.3f error: %d infoFlags: %u", (float)presentationTimeStamp.value/presentationTimeStamp.timescale, (int)status, (unsigned int)infoFlags);
return;
}
}
</pre>

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容