1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "media/base/mac/videotoolbox_glue.h"
6
7#include <dlfcn.h>
8#import <Foundation/Foundation.h>
9
10#include "base/lazy_instance.h"
11#include "base/memory/scoped_ptr.h"
12
13// This class stores VideoToolbox library symbol pointers.
14struct VideoToolboxGlue::Library {
15  typedef OSStatus (*VTCompressionSessionCreateMethod)(
16      CFAllocatorRef,
17      int32_t,
18      int32_t,
19      CoreMediaGlue::CMVideoCodecType,
20      CFDictionaryRef,
21      CFDictionaryRef,
22      CFAllocatorRef,
23      VTCompressionOutputCallback,
24      void*,
25      VTCompressionSessionRef*);
26  typedef OSStatus (*VTCompressionSessionEncodeFrameMethod)(
27      VTCompressionSessionRef,
28      CVImageBufferRef,
29      CoreMediaGlue::CMTime,
30      CoreMediaGlue::CMTime,
31      CFDictionaryRef,
32      void*,
33      VTEncodeInfoFlags*);
34  typedef CVPixelBufferPoolRef (*VTCompressionSessionGetPixelBufferPoolMethod)(
35      VTCompressionSessionRef);
36  typedef void (*VTCompressionSessionInvalidateMethod)(VTCompressionSessionRef);
37  typedef OSStatus (*VTSessionSetPropertyMethod)(VTSessionRef,
38                                                 CFStringRef,
39                                                 CFTypeRef);
40
41  VTCompressionSessionCreateMethod VTCompressionSessionCreate;
42  VTCompressionSessionEncodeFrameMethod VTCompressionSessionEncodeFrame;
43  VTCompressionSessionGetPixelBufferPoolMethod
44      VTCompressionSessionGetPixelBufferPool;
45  VTCompressionSessionInvalidateMethod VTCompressionSessionInvalidate;
46  VTSessionSetPropertyMethod VTSessionSetProperty;
47
48  CFStringRef* kVTCompressionPropertyKey_AllowFrameReordering;
49  CFStringRef* kVTCompressionPropertyKey_AverageBitRate;
50  CFStringRef* kVTCompressionPropertyKey_ColorPrimaries;
51  CFStringRef* kVTCompressionPropertyKey_ExpectedFrameRate;
52  CFStringRef* kVTCompressionPropertyKey_MaxKeyFrameInterval;
53  CFStringRef* kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration;
54  CFStringRef* kVTCompressionPropertyKey_ProfileLevel;
55  CFStringRef* kVTCompressionPropertyKey_RealTime;
56  CFStringRef* kVTCompressionPropertyKey_TransferFunction;
57  CFStringRef* kVTCompressionPropertyKey_YCbCrMatrix;
58  CFStringRef* kVTEncodeFrameOptionKey_ForceKeyFrame;
59  CFStringRef* kVTProfileLevel_H264_Baseline_AutoLevel;
60  CFStringRef* kVTProfileLevel_H264_Main_AutoLevel;
61  CFStringRef* kVTProfileLevel_H264_Extended_AutoLevel;
62  CFStringRef* kVTProfileLevel_H264_High_AutoLevel;
63  CFStringRef*
64      kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder;
65};
66
67// Lazy-instance responsible for loading VideoToolbox.
68class VideoToolboxGlue::Loader {
69 public:
70  Loader() {
71    NSBundle* bundle = [NSBundle
72        bundleWithPath:@"/System/Library/Frameworks/VideoToolbox.framework"];
73    const char* path = [[bundle executablePath] fileSystemRepresentation];
74    if (!path)
75      return;
76
77    handle_ = dlopen(path, RTLD_LAZY | RTLD_LOCAL);
78    if (!handle_)
79      return;
80
81#define LOAD_SYMBOL(SYMBOL)                                             \
82  if (!LoadSymbol(#SYMBOL, reinterpret_cast<void**>(&library_.SYMBOL))) \
83    return;
84
85    LOAD_SYMBOL(VTCompressionSessionCreate)
86    LOAD_SYMBOL(VTCompressionSessionEncodeFrame)
87    LOAD_SYMBOL(VTCompressionSessionGetPixelBufferPool)
88    LOAD_SYMBOL(VTCompressionSessionInvalidate)
89    LOAD_SYMBOL(VTSessionSetProperty)
90
91    LOAD_SYMBOL(kVTCompressionPropertyKey_AllowFrameReordering)
92    LOAD_SYMBOL(kVTCompressionPropertyKey_AverageBitRate)
93    LOAD_SYMBOL(kVTCompressionPropertyKey_ColorPrimaries)
94    LOAD_SYMBOL(kVTCompressionPropertyKey_ExpectedFrameRate)
95    LOAD_SYMBOL(kVTCompressionPropertyKey_MaxKeyFrameInterval)
96    LOAD_SYMBOL(kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration)
97    LOAD_SYMBOL(kVTCompressionPropertyKey_ProfileLevel)
98    LOAD_SYMBOL(kVTCompressionPropertyKey_RealTime)
99    LOAD_SYMBOL(kVTCompressionPropertyKey_TransferFunction)
100    LOAD_SYMBOL(kVTCompressionPropertyKey_YCbCrMatrix)
101    LOAD_SYMBOL(kVTEncodeFrameOptionKey_ForceKeyFrame);
102    LOAD_SYMBOL(kVTProfileLevel_H264_Baseline_AutoLevel)
103    LOAD_SYMBOL(kVTProfileLevel_H264_Main_AutoLevel)
104    LOAD_SYMBOL(kVTProfileLevel_H264_Extended_AutoLevel)
105    LOAD_SYMBOL(kVTProfileLevel_H264_High_AutoLevel)
106    LOAD_SYMBOL(
107        kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder)
108
109#undef LOAD_SYMBOL
110
111    glue_.library_ = &library_;
112  }
113
114  const VideoToolboxGlue* glue() const {
115    return (glue_.library_) ? &glue_ : NULL;
116  }
117
118 private:
119  bool LoadSymbol(const char* name, void** symbol_out) {
120    *symbol_out = dlsym(handle_, name);
121    return *symbol_out != NULL;
122  }
123
124  Library library_;
125  VideoToolboxGlue glue_;
126  void* handle_;
127
128  DISALLOW_COPY_AND_ASSIGN(Loader);
129};
130
131static base::LazyInstance<VideoToolboxGlue::Loader> g_videotoolbox_loader =
132    LAZY_INSTANCE_INITIALIZER;
133
134// static
135const VideoToolboxGlue* VideoToolboxGlue::Get() {
136  return g_videotoolbox_loader.Get().glue();
137}
138
139VideoToolboxGlue::VideoToolboxGlue() : library_(NULL) {
140}
141
142OSStatus VideoToolboxGlue::VTCompressionSessionCreate(
143    CFAllocatorRef allocator,
144    int32_t width,
145    int32_t height,
146    CoreMediaGlue::CMVideoCodecType codecType,
147    CFDictionaryRef encoderSpecification,
148    CFDictionaryRef sourceImageBufferAttributes,
149    CFAllocatorRef compressedDataAllocator,
150    VTCompressionOutputCallback outputCallback,
151    void* outputCallbackRefCon,
152    VTCompressionSessionRef* compressionSessionOut) const {
153  return library_->VTCompressionSessionCreate(allocator,
154                                              width,
155                                              height,
156                                              codecType,
157                                              encoderSpecification,
158                                              sourceImageBufferAttributes,
159                                              compressedDataAllocator,
160                                              outputCallback,
161                                              outputCallbackRefCon,
162                                              compressionSessionOut);
163}
164
165OSStatus VideoToolboxGlue::VTCompressionSessionEncodeFrame(
166    VTCompressionSessionRef session,
167    CVImageBufferRef imageBuffer,
168    CoreMediaGlue::CMTime presentationTimeStamp,
169    CoreMediaGlue::CMTime duration,
170    CFDictionaryRef frameProperties,
171    void* sourceFrameRefCon,
172    VTEncodeInfoFlags* infoFlagsOut) const {
173  return library_->VTCompressionSessionEncodeFrame(session,
174                                                   imageBuffer,
175                                                   presentationTimeStamp,
176                                                   duration,
177                                                   frameProperties,
178                                                   sourceFrameRefCon,
179                                                   infoFlagsOut);
180}
181
182CVPixelBufferPoolRef VideoToolboxGlue::VTCompressionSessionGetPixelBufferPool(
183    VTCompressionSessionRef session) const {
184  return library_->VTCompressionSessionGetPixelBufferPool(session);
185}
186
187void VideoToolboxGlue::VTCompressionSessionInvalidate(
188    VTCompressionSessionRef session) const {
189  library_->VTCompressionSessionInvalidate(session);
190}
191
192OSStatus VideoToolboxGlue::VTSessionSetProperty(VTSessionRef session,
193                                                CFStringRef propertyKey,
194                                                CFTypeRef propertyValue) const {
195  return library_->VTSessionSetProperty(session, propertyKey, propertyValue);
196}
197
198#define KEY_ACCESSOR(KEY) \
199  CFStringRef VideoToolboxGlue::KEY() const { return *library_->KEY; }
200
201KEY_ACCESSOR(kVTCompressionPropertyKey_AllowFrameReordering)
202KEY_ACCESSOR(kVTCompressionPropertyKey_AverageBitRate)
203KEY_ACCESSOR(kVTCompressionPropertyKey_ColorPrimaries)
204KEY_ACCESSOR(kVTCompressionPropertyKey_ExpectedFrameRate)
205KEY_ACCESSOR(kVTCompressionPropertyKey_MaxKeyFrameInterval)
206KEY_ACCESSOR(kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration)
207KEY_ACCESSOR(kVTCompressionPropertyKey_ProfileLevel)
208KEY_ACCESSOR(kVTCompressionPropertyKey_RealTime)
209KEY_ACCESSOR(kVTCompressionPropertyKey_TransferFunction)
210KEY_ACCESSOR(kVTCompressionPropertyKey_YCbCrMatrix)
211KEY_ACCESSOR(kVTEncodeFrameOptionKey_ForceKeyFrame)
212KEY_ACCESSOR(kVTProfileLevel_H264_Baseline_AutoLevel)
213KEY_ACCESSOR(kVTProfileLevel_H264_Main_AutoLevel)
214KEY_ACCESSOR(kVTProfileLevel_H264_Extended_AutoLevel)
215KEY_ACCESSOR(kVTProfileLevel_H264_High_AutoLevel)
216KEY_ACCESSOR(kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder)
217
218#undef KEY_ACCESSOR
219