forked from iina/iina
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathHardwareDecodeCapabilities.swift
More file actions
95 lines (86 loc) · 4.24 KB
/
HardwareDecodeCapabilities.swift
File metadata and controls
95 lines (86 loc) · 4.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
//
// HardwareDecodeCapabilities.swift
// iina
//
// Created by low-batt on 5/23/24.
// Copyright © 2024 lhc. All rights reserved.
//
import Foundation
import VideoToolbox
/// Cache containing information about the hardware decoding capabilities of this Mac.
///
/// It is desirable to cache this information because the [Video Toolbox](https://developer.apple.com/documentation/videotoolbox)
/// method [VTIsHardwareDecodeSupported](https://developer.apple.com/documentation/videotoolbox/vtishardwaredecodesupported(_:))
/// is long running and should not be called on the main thread. Instead another thread is used and the information is cached for when
/// code that is running on the main thread needs it.
class HardwareDecodeCapabilities {
/// The `HardwareDecodeCapabilities` singleton object.
static let shared = HardwareDecodeCapabilities()
/// The hardware decoding capabilities of this Mac will be checked for the codecs in this list.
private let codecs = [
kCMVideoCodecType_AppleProRes422,
kCMVideoCodecType_AppleProRes422HQ,
kCMVideoCodecType_AppleProRes422LT,
kCMVideoCodecType_AppleProRes422Proxy,
kCMVideoCodecType_AppleProRes4444,
kCMVideoCodecType_AppleProRes4444XQ,
kCMVideoCodecType_AppleProResRAW,
kCMVideoCodecType_AppleProResRAWHQ,
kCMVideoCodecType_AV1,
kCMVideoCodecType_VP9]
private var initialization: DispatchWorkItem?
private var isInitialized = false
/// Cache containing a map from video codec to whether hardware decoding is supported.
private var supported: [CMVideoCodecType: Bool] = [:]
/// Check the hardware decoding capabilities of this Mac and cache the results.
///
/// As checking the capabilities takes a long time it is performed asynchronously. See `isHardwareDecodeSupported` for details.
/// - Important: This method **must** be called before `isSupported` is called and only be called **once**.
func checkCapabilities() {
guard initialization == nil else {
// Internal error. This method must only be called once.
Logger.fatal("HardwareDecodeCapabilities is already initialized")
}
initialization = DispatchWorkItem() { [self] in
for codec in codecs {
supported[codec] = isHardwareDecodeSupported(codec)
}
}
DispatchQueue.global(qos: .userInitiated).async { self.initialization!.perform() }
}
/// Whether this Mac supports hardware decoding for the given video codec.
/// - Parameter codecType: The video codec as a
/// [CMVideoCodecType](https://developer.apple.com/documentation/coremedia/cmvideocodectype).
/// - Returns: `true` if hardware decoding is supported; `false` otherwise.
func isSupported(_ codecType: CMVideoCodecType) -> Bool {
if !isInitialized {
guard let initialization = initialization else {
// Internal error. The cache must be initialized before calling this method.
Logger.fatal("HardwareDecodeCapabilities.checkCapabilities has not been called")
}
initialization.wait()
isInitialized = true
}
guard let supported = supported[codecType] else {
// Internal error. This codec must not be in the list of codecs above.
Logger.fatal("HardwareDecodeCapabilities is missing support for codec \(codecType)")
}
return supported
}
/// Whether this Mac supports hardware decoding for the given video codec.
/// - Parameter codecType: The video codec as a
/// [CMVideoCodecType](https://developer.apple.com/documentation/coremedia/cmvideocodectype).
/// - Returns: true` if hardware decoding is supported; `false` otherwise.
/// - Important: This method calls
/// [VTIsHardwareDecodeSupported](https://developer.apple.com/documentation/videotoolbox/vtishardwaredecodesupported(_:)),
/// which if called on the main thread will cause Xcode to report: "This method should not be called on the main thread as it may
/// lead to UI unresponsiveness". Use a different thread to call this method. Do not call `isHardwareDecodeSupported`
/// from the main thread.
private func isHardwareDecodeSupported(_ codecType: CMVideoCodecType) -> Bool {
if #available(macOS 11.0, *) {
VTRegisterSupplementalVideoDecoderIfAvailable(codecType)
}
return VTIsHardwareDecodeSupported(codecType)
}
private init() {}
}