Can I get PHAsset / AVAsset is hdr video/dolby vision on iphone12?

Viewed 703

I want to add HDR icon to indicate some asset is HDR, but I can't get any info to check a video if this is a HDR video record from iphone12

3 Answers
+ (BOOL)isHDRVideo:(AVAsset *)avasset {
    if (!avasset) {
        return NO;
    }
    __block BOOL isHDRVideo = NO;
    [avasset.tracks enumerateObjectsUsingBlock:^(AVAssetTrack * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stopTracks) {
        [obj.formatDescriptions enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stopFormatDescriptions) {
            CMFormatDescriptionRef desc = (__bridge  CMVideoFormatDescriptionRef)obj;
            NSDictionary *dic = (__bridge NSDictionary *)CMFormatDescriptionGetExtensions(desc);
            NSString *imageBufferColorPrimaries = dic[(__bridge  id)kCVImageBufferColorPrimariesKey];
            if ([imageBufferColorPrimaries isEqualToString:(__bridge  id)kCVImageBufferColorPrimaries_ITU_R_2020]) {
                *stopFormatDescriptions = YES;
                *stopTracks = YES;
                isHDRVideo = YES;
            }
        }];
    }];
    
    return isHDRVideo;
}

A better approach could be using avasset.tracks(withMediaCharacteristic: .containsHDRVideo) Or simpleVideo.tracks.forEach{$0.hasMediaCharacteristic(.containsHDRVideo)}

This post really helped my out, so I felt like I had to share back what I've found out to provide a swift based approach for future readers.

One can extend AVAssetTrack to move all the logic where the CMFormatDescription is defined:


public extension AVAssetTrack {
  var isHDRVideo: Bool {
    guard
      self.mediaType == .video, // If is not a video track is not HDR
      let cmFormatDescription = self.formatDescriptions.map { $0 as!  CMFormatDescription }.first, // Safely get the description
      let transferFunction = CMFormatDescriptionGetExtension(
        cmFormatDescription,
        extensionKey: kCVImageBufferTransferFunctionKey), // It can be nil, which will make the as! CFString fail
    else { return false }

    return [
      kCVImageBufferTransferFunction_ITU_R_2020,
      kCVImageBufferTransferFunction_ITU_R_2100_HLG,
      kCVImageBufferTransferFunction_SMPTE_ST_2084_PQ
    ].contains(transferFunction as! CFString)
  }
}

Then say you have an AVAsset called asset, you can do:

asset.tracks(withMediaType: .video).map { $0.isHDRVideo }

and build your logic on that.

Related