【问题标题】:CMFormatDescription to CMVideoFormatDescriptionCMFormatDescription 到 CMVideoFormatDescription
【发布时间】:2020-04-08 15:15:15
【问题描述】:

我正在尝试使用 swift 获取设备相机的分辨率。

我正在使用需要 CMVideoFormatDescription 的 CMVideoFormatDescriptionGetDimensions,但 AVCaptureDevice.formatDescription 返回一个 CMFormatDescription。我尝试了多种将 CMFormatDescription 转换为 CMVideoFormatDescription 的方法,但似乎无法正常工作。

下面是我正在使用的代码示例:

for format in device.formats as [AVCaptureDeviceFormat] {
  let videoDimensions = CMVideoFormatDescriptionGetDimensions(format.formatDescription)
}

【问题讨论】:

    标签: swift avfoundation


    【解决方案1】:

    目前这在 Swift 中似乎是不可能的。一种解决方案是在 Objective-C 中编写一个辅助函数,例如:

    CMVideoDimensions CMFormatDescriptionGetDimensions(CMFormatDescriptionRef formatDescription)
    {
        if (CMFormatDescriptionGetMediaType(formatDescription) == kCMMediaType_Video)
            return CMVideoFormatDescriptionGetDimensions(formatDescription);
        else
            return (CMVideoDimensions) {
                .width = 0,
                .height = 0
            };
    }
    

    在 Swift 桥接头标头中包含带有函数原型的标头,以便它可以作为 Swift 代码中的全局函数访问。

    【讨论】:

    • 这是一个解决方案,但令人失望的是 swift 目前并不能很好地映射到低级可可 API。
    【解决方案2】:

    我能够使用下面的快速方法获得分辨率:

    let captureDevice = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo) as AVCaptureDevice
    
    let formatDesc = captureDevice.activeFormat.formatDescription
    let dimensions = CMVideoFormatDescriptionGetDimensions(formatDesc)
    

    【讨论】:

      【解决方案3】:

      这是一个纯 Swift 的解决方案,实际上仅可用于日志记录等目的。将以下函数粘贴到您的班级或其他地方:

      func widthAndHeightFromTrack(track: AVAssetTrack) -> CGSize {
          let str = track.formatDescriptions.description
      
          let regex = try! NSRegularExpression(pattern: "[0-9]{2,4} x [0-9]{2,4}", options: [])
          if let result = regex.firstMatchInString(str, options: [], range:  NSMakeRange(0, str.characters.count)) {
              let dimensionString = (str as NSString).substringWithRange(result.range)
              let dimensionArray = dimensionString.componentsSeparatedByString(" x ")
              let width = Int(dimensionArray[0])
              let height = Int(dimensionArray[1])
              return CGSize(width: width!, height: height!)
          }
      
          return CGSizeZero
      }
      

      示例用法:

      let allTracks: AVAsset = someAVAsset.tracksWithMediaType(AVMediaTypeVideo)
      let videoTrack = allTracks[0]
      let videoTrackDimensions = widthAndHeightFromTrack(videoTrack)
      // You now have a CGSize, print it
      print("Dimensions: \(videoTrackDimensions)")
      

      当然,只要 Apple 更改 CMFormatDescription 的字符串表示形式中的某些内容,上述解决方案就会完全中断。但它对于记录尺寸很有用。

      【讨论】:

        【解决方案4】:

        也许,问题太老了,但 Swift 问题仍未解决。

        public extension AVURLAsset {
        
            var audioFormatDescription: CMAudioFormatDescription? {
        
                if  let track = self.tracks(withMediaType: .audio).first,
                    let untypedDescription = track.formatDescriptions.first {
        
                    // hacks, warnings, disablings of swiftlint below are wrork-around of
                    //      Swift bug: it fails converting 'Any as CMFormatDescription'
                    let forceTyped: CMFormatDescription?
        //swiftlint:disable force_cast
                                                            = untypedDescription as! CMAudioFormatDescription
        //swiftlint:enable force_cast
                    if  let description = forceTyped {
                        return description
                    } else {
                        return nil
                    }
                } else {
                    return nil
                }
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2019-03-24
          • 2016-01-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-09-15
          相关资源
          最近更新 更多