AV Foundation ? 使用高幀率捕捉

AVFoundation 中關(guān)于高幀率的支持

????在 高幀率捕捉是開發(fā)者在一些場(chǎng)景中希望使用的技術(shù)。蘋果公司并沒有單獨(dú)推出這一個(gè)功能,而是通過 AV Foundation 框架為這個(gè)功能給出了強(qiáng)大的支撐。

  • 捕捉: 支持每秒 60 幀 (fps) 的完整 720p(1280 x 720 像素)分辨率,包括視頻穩(wěn)定和支持啟動(dòng) droppable P-frames (H.264 編碼的特性 ),即使在較慢和較舊的硬件上也可以流暢地播放電影。
  • 播放: AVPlayer 已經(jīng)支持以多種播放幀率播放資源內(nèi)容,增強(qiáng)了對(duì)慢速和快速播放的音頻支持,AVPlayerItem 有一個(gè) audioTimePitchAlgorithm 可以允許以較慢或較快的速度設(shè)置算法。
  • 編輯:全面支持可變組合成中執(zhí)行縮放編輯。
  • 導(dǎo)出:AV Foundation 提供了保存原始幀率的功能,所以 60 fps 影片可以被導(dǎo)出,或者將電影轉(zhuǎn)換為任意較慢的幀速率,例如每秒 30 幀。

高幀率捕捉概述

????使用高幀率捕捉的首先要獲取到設(shè)備的最高質(zhì)量格式,找到它相關(guān)的幀時(shí)長(zhǎng),之后手動(dòng)設(shè)置捕捉設(shè)備的格式和幀時(shí)長(zhǎng)。AVCaptureDeviceFormat 類確定設(shè)備的捕獲能力。此類具有返回支持的媒體類型、幀速率、視野、最大縮放系數(shù)、是否支持視頻穩(wěn)定等的方法,其具有一個(gè) videoSupportedFrameRateRanges 屬性,包含了一個(gè) AVFrameRateRange 對(duì)象數(shù)組,其中帶有格式所支持的最小幀率、最大幀率和時(shí)長(zhǎng)信息。

支持高幀率捕捉

由于查找設(shè)備最大幀率的過程較為麻煩,通過給 AVCaptureDevice 添加分類的方法來實(shí)現(xiàn),開啟高幀率率捕捉的功能:

  1. 新增分類聲明兩個(gè)方法 - (BOOL)supportsHighFrameRateCapture 判斷當(dāng)前設(shè)備是否支持高幀率捕捉和 - (BOOL)enableMaxFrameRateCapture;開啟高幀率捕捉
  2. 實(shí)現(xiàn) findHighestQualityOfService 遍歷所有的捕捉設(shè)備的支持 formats,并對(duì)每一個(gè)元素獲取相應(yīng)的 codeType,這里篩選出 kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange 格式,接著遍歷 AVFrameRateRange 對(duì)象數(shù)組,獲取最大的 AVFrameRateRange,最終找到提供的最高的format 和幀率并將其存儲(chǔ)起來。
  3. 實(shí)現(xiàn) supportsHighFrameRateCapture,若最大幀率大于 30 fps,則支持高幀率;
  4. 實(shí)現(xiàn) enableMaxFrameRateCapture,修改捕捉設(shè)備的 format 、最小幀時(shí)長(zhǎng) activeVideoMinFrameDuration 和最大幀時(shí)長(zhǎng)activeVideoMaxFrameDuration

@interface AVCaptureDevice (QualityOfService)

- (BOOL)supportsHighFrameRateCapture;
- (BOOL)enableMaxFrameRateCapture;

@end
const void* kMaxFormat = &kMaxFormat;
const void* kMaxFrameRateRange = &kMaxFrameRateRange;
@implementation AVCaptureDevice (QualityOfService)

- (void)setMaxFormat:(AVCaptureDeviceFormat *)maxFormat{
    objc_setAssociatedObject(self, kMaxFormat, maxFormat, OBJC_ASSOCIATION_RETAIN);
}

- (AVCaptureDeviceFormat *)maxFormat{
    return objc_getAssociatedObject(self, &kMaxFormat);
}

- (void)setMaxFrameRateRange:(AVFrameRateRange*)maxFrameRateRange{
    objc_setAssociatedObject(self, kMaxFrameRateRange, maxFrameRateRange, OBJC_ASSOCIATION_RETAIN);
}

- (AVFrameRateRange *)maxFrameRateRange{
    return objc_getAssociatedObject(self, &kMaxFrameRateRange);
}

- (BOOL)supportsHighFrameRateCapture {
    if (![self hasMediaType:AVMediaTypeVideo]) {                            // 1
        return NO;
    }
    return [self isHighFrameRate];              // 2
}

- (BOOL)enableMaxFrameRateCapture{

    if (![self isHighFrameRate]) {                                             // 1
        
        return NO;
    }

    if ([self lockForConfiguration:nil]) {                                // 2

        CMTime minFrameDuration = [self maxFrameRateRange].minFrameDuration;

        self.activeFormat = [self maxFormat];                                     // 3
        self.activeVideoMinFrameDuration = minFrameDuration;                // 4
        self.activeVideoMaxFrameDuration = minFrameDuration;

        [self unlockForConfiguration];
        return YES;
    }
    return NO;
}

- (void)findHighestQualityOfService {

    AVCaptureDeviceFormat *maxFormat = nil;
    AVFrameRateRange *maxFrameRateRange = nil;

    for (AVCaptureDeviceFormat *format in self.formats) {

        FourCharCode codecType =                                           
            CMVideoFormatDescriptionGetCodecType(format.formatDescription);

        if (codecType == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange) { 

            NSArray *frameRateRanges = format.videoSupportedFrameRateRanges;

            for (AVFrameRateRange *range in frameRateRanges) {              
                if (range.maxFrameRate > maxFrameRateRange.maxFrameRate) {
                    maxFormat = format;
                    maxFrameRateRange = range;
                }
            }
        }
    }

    [self setMaxFormat:maxFormat];
    [self setMaxFrameRateRange:maxFrameRateRange];


}

- (BOOL)isHighFrameRate {
    AVFrameRateRange *frameRateRange = [self maxFrameRateRange]
    if(!frameRateRange){
       [self findHighestQualityOfService];
    }
    return [self maxFrameRateRange].maxFrameRate > 30.0f;
}

@end

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容