首页 > 其他分享 >iOS开发基础138-视频编码

iOS开发基础138-视频编码

时间:2024-07-23 15:50:40浏览次数:15  
标签:编码 NULL void iOS VideoEncoder sampleBuffer compressionSession 138

为完善视频编码的封装和提供一定的拓展性,以下是视频编码的详细示例,其中包括编码参数设置和数据提取处理。以下示例侧重于视频编码部分。

视频编码器示例

下面的代码示例展示了一个视频编码器的实现,包括如何设置关键编码参数和从回调中提取H.264数据。

// VideoEncoder.h
#import <Foundation/Foundation.h>
#import <VideoToolbox/VideoToolbox.h>

@protocol VideoEncoderDelegate <NSObject>
- (void)videoEncoderDidEncodeData:(NSData *)data isKeyFrame:(BOOL)isKeyFrame;
@end

@interface VideoEncoder : NSObject
@property (weak, nonatomic) id<VideoEncoderDelegate> delegate;
- (instancetype)initWithWidth:(int)width height:(int)height;
- (void)encodeSampleBuffer:(CMSampleBufferRef)sampleBuffer;
@end
// VideoEncoder.m
#import "VideoEncoder.h"

@interface VideoEncoder ()
@property (assign, nonatomic) VTCompressionSessionRef compressionSession;
@property (assign, nonatomic) int width;
@property (assign, nonatomic) int height;
@end

@implementation VideoEncoder

- (instancetype)initWithWidth:(int)width height:(int)height {
    if ((self = [super init])) {
        _width = width;
        _height = height;
        [self setupCompressionSession];
    }
    return self;
}

- (void)setupCompressionSession {
    if (VTCompressionSessionCreate(NULL, _width, _height, kCMVideoCodecType_H264, NULL, NULL, NULL, compressionOutputCallback, (__bridge void *)(self), &_compressionSession) != noErr) {
        NSLog(@"Failed to create compression session!");
        return;
    }

    // 更详细的编码器配置
    VTSessionSetProperty(_compressionSession, kVTCompressionPropertyKey_AverageBitRate, (__bridge CFTypeRef)@(1000000)); // 比特率
    VTSessionSetProperty(_compressionSession, kVTCompressionPropertyKey_RealTime, kCFBooleanTrue); // 实时编码
    VTSessionSetProperty(_compressionSession, kVTCompressionPropertyKey_ProfileLevel, kVTProfileLevel_H264_Main_AutoLevel); // 编码等级
    VTSessionSetProperty(_compressionSession, kVTCompressionPropertyKey_MaxKeyFrameInterval, (__bridge CFTypeRef)@(30)); // 关键帧间隔

    VTCompressionSessionPrepareToEncodeFrames(_compressionSession);
}

static void compressionOutputCallback(void *outputCallbackRefCon,
                                       void *sourceFrameRefCon,
                                       OSStatus status,
                                       VTEncodeInfoFlags infoFlags,
                                       CMSampleBufferRef sampleBuffer) {
    if (!sampleBuffer) return;
    if (status != noErr) {
        NSLog(@"Compression failed with status: %d", status);
        return;
    }

    VideoEncoder *encoder = (__bridge VideoEncoder *)outputCallbackRefCon;

    // 判断是否为关键帧
    BOOL isKeyFrame = !CFDictionaryContainsKey(CFArrayGetValueAtIndex(CMSampleBufferGetSampleAttachmentsArray(sampleBuffer, true), 0), kCMSampleAttachmentKey_NotSync);

    // 提取数据
    NSData *data = [encoder dataFromSampleBuffer:sampleBuffer];
    
    [encoder.delegate videoEncoderDidEncodeData:data isKeyFrame:isKeyFrame];
}

- (NSData *)dataFromSampleBuffer:(CMSampleBufferRef)sampleBuffer {
    CMBlockBufferRef blockBuffer = CMSampleBufferGetDataBuffer(sampleBuffer);
    size_t length;
    char *dataPointer;
    CMBlockBufferGetDataPointer(blockBuffer, 0, NULL, &length, &dataPointer);
    
    return [NSData dataWithBytes:dataPointer length:length];
}

- (void)encodeSampleBuffer:(CMSampleBufferRef)sampleBuffer {
    VTCompressionSessionEncodeFrame(_compressionSession, sampleBuffer, kCMTimeInvalid, kCMTimeInvalid, NULL, NULL, NULL);
}

- (void)dealloc {
    if (_compressionSession != NULL) {
        VTCompressionSessionInvalidate(_compressionSession);
        CFRelease(_compressionSession);
        _compressionSession = NULL;
    }
}

@end

使用方式

以下是如何使用VideoEncoder类的示例:

// 定义一个属性以保持对编码器的引用
@property (strong, nonatomic) VideoEncoder *videoEncoder;

// 初始化编码器
self.videoEncoder = [[VideoEncoder alloc] initWithWidth:1920 height:1080];
self.videoEncoder.delegate = self;

// 在获得视频数据的地点调用编码方法(例如,AVCaptureVideoDataOutputSampleBufferDelegate的回调中)
[self.videoEncoder encodeSampleBuffer:sampleBuffer];

// 实现 VideoEncoderDelegate 的回调方法
- (void)videoEncoderDidEncodeData:(NSData *)data isKeyFrame:(BOOL)isKeyFrame {
    // 在这里处理或者存储编码后的数据
}

注意事项

  1. 位率(Bitrate):这个例子中设置的位率是1Mbps,这个值可以根据视频的质量要求和网络条件进行调整。

  2. 实时性能:实时属性告诉编码器尽可能快地进行编码,可能以牺牲一些编码质量为代价。

  3. 关键帧间隔(Key Frame Interval):设置较低的关键帧间隔可以提高视频在网络传输中的恢复能力,但可能增加数据量。

  4. 处理编码后的数据:在实际应用中,编码后的数据经常用于存储或网络传输,这可能需要对数据进行封装(例如,添加SPS/PPS头部信息用于H.264)。

  5. 性能和内存管理:编码过程尤其是在高分辨率下,对性能和内存有较高的要求。必须确保及时释放不再使用的对象和资源,以避免内存泄漏。

标签:编码,NULL,void,iOS,VideoEncoder,sampleBuffer,compressionSession,138
From: https://www.cnblogs.com/chglog/p/18318611

相关文章

  • 系统整容纪:揭秘Java编程之美:掌握这些编码规范,让你的代码一跃成为行业典范
     分享工作中的点点滴滴,贯彻千里之行,始于足下,最终以微不足道的量变引起化蝶的质变精神。以自己为例拒绝在舒适的中央区域安逸的躺着,以便在不知不觉中被社会所淘汰,也不盲目的直接跃迁进困哪区域,在受挫的同时又跌回原有的舒适区域内,造成这样一个浑浑噩噩的让人无法进步的循环怪圈......
  • iOS开发基础136-防暴力点击
    要在Objective-C中创建一个高度可复用的工具类,以防止按钮的暴力点击,并且使用切面编程(AOP)的方式,我们可以考虑使用Aspects这个库来实现方法的拦截。以下是具体的实现步骤:第一步:引入Aspects库首先,需要将Aspects集成到项目中。Aspects是一个轻量级的AOP框架,允许你在运行时拦截类的实......
  • 如何理解JAVA的编码格式是Unicode
    背景今天看以前的JAVA视频,发现课件里面写着JAVA的内部的编码格式是Unicode。这句话,突然勾起了我的好奇心。因为的JAVA代码文件都是UTF8编码,怎么跟Unicode扯上关系的呢?我去问了一下AI,然后整理了一下Unicode是JAVA编译器的读取class文件使用的编码假设,我的如下代码是UTF-8编......
  • R750配置raid_通过bios
    新出厂服务器由于是uefi启动模式,开机引导过程中不会出现传统的raid卡配置界面,可以通过BIOS中进行Raid配置。 1.开机按F2选择SystemSetup进入BIOS。2.进入BIOS后,选择DeviceSettings。3.选择相应Raid卡,我这里是DellPERCH755。4.进入Raid卡界面后,选择MainMenu。5.......
  • 后端API接口定义返回编码规则
    code状态码code返回状态码,一般小伙伴们是在开发的时候需要什么,就添加什么。如接口要返回用户权限异常,我们加一个状态码为101吧,下一次又要加一个数据参数异常,就加一个102的状态码。这样虽然能够照常满足业务,但状态码太凌乱了。我们应该可以参考HTTP请求返回的状态码(下面是常见的......
  • iOS开发-多线程编程
    OC中常用的多线程编程技术:1.NSThreadNSThread是Objective-C中最基本的线程抽象,它允许程序员直接管理线程的生命周期。NSThread*myThread=[[NSThreadalloc]initWithTarget:selfselector:@selector(myThreadMainMethod:)object:nil];[myThreadstart];使用NSThread时,......
  • iOS面试题-load 和 initlize的区别
    +load和+initialize是两个与类的加载和初始化相关的特殊方法。它们在类的生命周期中的作用和调用时机有明显的区别。+load方法调用时机:+load在类初始加载进内存时调用,这通常发生在程序启动的时候,所有类和分类(Category)的+load方法在应用程序的生命周期中只会被调用一次。调用......
  • Android或iOS 与 REST/SOAP测试 工具推荐
    移动测试工具- 有助于自动测试Android或iOS应用程序1)AppiumAppium是用于移动应用程序自动化的开源测试工具之一。它允许用户测试各种原生、移动、web和混合应用程序。它还支持模拟器和模拟器上的自动测试。功能特点:这是一个简单的应用程序,需要很少的内存用于测试过程......
  • iOS开发基础135-Core Data
    Objective-C(OC)中使用CoreData是iOS应用开发中管理模型层对象的一种有效工具。CoreData使用ORM(对象关系映射)技术来抽象化和管理数据。这不仅可以节省时间,还能减少编程错误。以下是使用CoreData的详细介绍,包括示例代码,以及深入底层的一些分析。基本概念持久化......
  • 封禁 NetBIOS Session Service 和 SMB 服务(特别是旧版本的SMB)可能是出于安全性考虑。
    封禁NetBIOSSessionService和SMB服务(特别是旧版本的SMB)可能是出于安全性考虑。这两种服务在过去的实现中存在一些安全漏洞和风险,特别是在现代网络环境中,这些风险可能会被利用来进行攻击或者未经授权的访问。下面是一些常见的安全考虑:中间人攻击:未加密的NetBIOS和旧版本......