Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / media / base / mac / coremedia_glue.mm
blob61e9199f05b65f03b0f5e0f6f9beb86b116df0d4
1 // Copyright 2013 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.
5 #include "media/base/mac/coremedia_glue.h"
7 #include <dlfcn.h>
8 #import <Foundation/Foundation.h>
10 #include "base/logging.h"
11 #include "base/lazy_instance.h"
13 namespace {
15 // This class is used to retrieve some CoreMedia library functions. It must be
16 // used as a LazyInstance so that it is initialised once and in a thread-safe
17 // way. Normally no work is done in constructors: LazyInstance is an exception.
18 class CoreMediaLibraryInternal {
19  public:
20   typedef CoreMediaGlue::CMTime (*CMTimeMakeMethod)(int64_t, int32_t);
22   typedef OSStatus (*CMBlockBufferCreateContiguousMethod)(
23       CFAllocatorRef,
24       CoreMediaGlue::CMBlockBufferRef,
25       CFAllocatorRef,
26       const CoreMediaGlue::CMBlockBufferCustomBlockSource*,
27       size_t,
28       size_t,
29       CoreMediaGlue::CMBlockBufferFlags,
30       CoreMediaGlue::CMBlockBufferRef*);
31   typedef size_t (*CMBlockBufferGetDataLengthMethod)(
32       CoreMediaGlue::CMBlockBufferRef);
33   typedef OSStatus (*CMBlockBufferGetDataPointerMethod)(
34       CoreMediaGlue::CMBlockBufferRef,
35       size_t,
36       size_t*,
37       size_t*,
38       char**);
39   typedef Boolean (*CMBlockBufferIsRangeContiguousMethod)(
40       CoreMediaGlue::CMBlockBufferRef,
41       size_t,
42       size_t);
44   typedef CoreMediaGlue::CMBlockBufferRef (*CMSampleBufferGetDataBufferMethod)(
45       CoreMediaGlue::CMSampleBufferRef);
46   typedef CoreMediaGlue::CMFormatDescriptionRef (
47       *CMSampleBufferGetFormatDescriptionMethod)(
48       CoreMediaGlue::CMSampleBufferRef);
49   typedef CVImageBufferRef (*CMSampleBufferGetImageBufferMethod)(
50       CoreMediaGlue::CMSampleBufferRef);
51   typedef CFArrayRef (*CMSampleBufferGetSampleAttachmentsArrayMethod)(
52       CoreMediaGlue::CMSampleBufferRef,
53       Boolean);
55   typedef FourCharCode (*CMFormatDescriptionGetMediaSubTypeMethod)(
56       CoreMediaGlue::CMFormatDescriptionRef desc);
57   typedef CoreMediaGlue::CMVideoDimensions
58       (*CMVideoFormatDescriptionGetDimensionsMethod)(
59           CoreMediaGlue::CMVideoFormatDescriptionRef videoDesc);
60   typedef OSStatus (*CMVideoFormatDescriptionGetH264ParameterSetAtIndexMethod)(
61       CoreMediaGlue::CMFormatDescriptionRef,
62       size_t,
63       const uint8_t**,
64       size_t*,
65       size_t*,
66       int*);
68   CoreMediaLibraryInternal() {
69     NSBundle* bundle = [NSBundle
70         bundleWithPath:@"/System/Library/Frameworks/CoreMedia.framework"];
72     const char* path = [[bundle executablePath] fileSystemRepresentation];
73     CHECK(path);
74     void* library_handle = dlopen(path, RTLD_LAZY | RTLD_LOCAL);
75     CHECK(library_handle) << dlerror();
77     // Now extract the methods.
78     cm_time_make_ = reinterpret_cast<CMTimeMakeMethod>(
79         dlsym(library_handle, "CMTimeMake"));
80     CHECK(cm_time_make_) << dlerror();
82     cm_block_buffer_create_contiguous_method_ =
83         reinterpret_cast<CMBlockBufferCreateContiguousMethod>(
84             dlsym(library_handle, "CMBlockBufferCreateContiguous"));
85     CHECK(cm_block_buffer_create_contiguous_method_) << dlerror();
86     cm_block_buffer_get_data_length_method_ =
87         reinterpret_cast<CMBlockBufferGetDataLengthMethod>(
88             dlsym(library_handle, "CMBlockBufferGetDataLength"));
89     CHECK(cm_block_buffer_get_data_length_method_) << dlerror();
90     cm_block_buffer_get_data_pointer_method_ =
91         reinterpret_cast<CMBlockBufferGetDataPointerMethod>(
92             dlsym(library_handle, "CMBlockBufferGetDataPointer"));
93     CHECK(cm_block_buffer_get_data_pointer_method_) << dlerror();
94     cm_block_buffer_is_range_contiguous_method_ =
95         reinterpret_cast<CMBlockBufferIsRangeContiguousMethod>(
96             dlsym(library_handle, "CMBlockBufferIsRangeContiguous"));
97     CHECK(cm_block_buffer_is_range_contiguous_method_) << dlerror();
99     cm_sample_buffer_get_data_buffer_method_ =
100         reinterpret_cast<CMSampleBufferGetDataBufferMethod>(
101             dlsym(library_handle, "CMSampleBufferGetDataBuffer"));
102     CHECK(cm_sample_buffer_get_data_buffer_method_) << dlerror();
103     cm_sample_buffer_get_format_description_method_ =
104         reinterpret_cast<CMSampleBufferGetFormatDescriptionMethod>(
105             dlsym(library_handle, "CMSampleBufferGetFormatDescription"));
106     CHECK(cm_sample_buffer_get_format_description_method_) << dlerror();
107     cm_sample_buffer_get_image_buffer_method_ =
108         reinterpret_cast<CMSampleBufferGetImageBufferMethod>(
109             dlsym(library_handle, "CMSampleBufferGetImageBuffer"));
110     CHECK(cm_sample_buffer_get_image_buffer_method_) << dlerror();
111     cm_sample_buffer_get_sample_attachments_array_method_ =
112         reinterpret_cast<CMSampleBufferGetSampleAttachmentsArrayMethod>(
113             dlsym(library_handle, "CMSampleBufferGetSampleAttachmentsArray"));
114     CHECK(cm_sample_buffer_get_sample_attachments_array_method_) << dlerror();
115     k_cm_sample_attachment_key_not_sync_ = reinterpret_cast<CFStringRef*>(
116         dlsym(library_handle, "kCMSampleAttachmentKey_NotSync"));
117     CHECK(k_cm_sample_attachment_key_not_sync_) << dlerror();
119     cm_format_description_get_media_sub_type_method_ =
120         reinterpret_cast<CMFormatDescriptionGetMediaSubTypeMethod>(
121             dlsym(library_handle, "CMFormatDescriptionGetMediaSubType"));
122     CHECK(cm_format_description_get_media_sub_type_method_) << dlerror();
123     cm_video_format_description_get_dimensions_method_ =
124         reinterpret_cast<CMVideoFormatDescriptionGetDimensionsMethod>(
125             dlsym(library_handle, "CMVideoFormatDescriptionGetDimensions"));
126     CHECK(cm_video_format_description_get_dimensions_method_) << dlerror();
128     // Available starting (OS X 10.9, iOS 7), allow to be null.
129     cm_video_format_description_get_h264_parameter_set_at_index_method_ =
130         reinterpret_cast<
131             CMVideoFormatDescriptionGetH264ParameterSetAtIndexMethod>(
132             dlsym(library_handle,
133                   "CMVideoFormatDescriptionGetH264ParameterSetAtIndex"));
134   }
136   const CMTimeMakeMethod& cm_time_make() const { return cm_time_make_; }
138   const CMBlockBufferCreateContiguousMethod&
139   cm_block_buffer_create_contiguous_method() const {
140     return cm_block_buffer_create_contiguous_method_;
141   }
142   const CMBlockBufferGetDataLengthMethod&
143   cm_block_buffer_get_data_length_method() const {
144     return cm_block_buffer_get_data_length_method_;
145   }
146   const CMBlockBufferGetDataPointerMethod&
147   cm_block_buffer_get_data_pointer_method() const {
148     return cm_block_buffer_get_data_pointer_method_;
149   }
150   const CMBlockBufferIsRangeContiguousMethod&
151   cm_block_buffer_is_range_contiguous_method() const {
152     return cm_block_buffer_is_range_contiguous_method_;
153   }
155   const CMSampleBufferGetDataBufferMethod&
156   cm_sample_buffer_get_data_buffer_method() const {
157     return cm_sample_buffer_get_data_buffer_method_;
158   }
159   const CMSampleBufferGetFormatDescriptionMethod&
160   cm_sample_buffer_get_format_description_method() const {
161     return cm_sample_buffer_get_format_description_method_;
162   }
163   const CMSampleBufferGetImageBufferMethod&
164       cm_sample_buffer_get_image_buffer_method() const {
165     return cm_sample_buffer_get_image_buffer_method_;
166   }
167   const CMSampleBufferGetSampleAttachmentsArrayMethod&
168   cm_sample_buffer_get_sample_attachments_array_method() const {
169     return cm_sample_buffer_get_sample_attachments_array_method_;
170   }
171   CFStringRef* const& k_cm_sample_attachment_key_not_sync() const {
172     return k_cm_sample_attachment_key_not_sync_;
173   }
175   const CMFormatDescriptionGetMediaSubTypeMethod&
176       cm_format_description_get_media_sub_type_method() const {
177     return cm_format_description_get_media_sub_type_method_;
178   }
179   const CMVideoFormatDescriptionGetDimensionsMethod&
180       cm_video_format_description_get_dimensions_method() const {
181     return cm_video_format_description_get_dimensions_method_;
182   }
183   const CMVideoFormatDescriptionGetH264ParameterSetAtIndexMethod&
184   cm_video_format_description_get_h264_parameter_set_at_index_method() const {
185     return cm_video_format_description_get_h264_parameter_set_at_index_method_;
186   }
188  private:
189   CMTimeMakeMethod cm_time_make_;
191   CMBlockBufferCreateContiguousMethod cm_block_buffer_create_contiguous_method_;
192   CMBlockBufferGetDataLengthMethod cm_block_buffer_get_data_length_method_;
193   CMBlockBufferGetDataPointerMethod cm_block_buffer_get_data_pointer_method_;
194   CMBlockBufferIsRangeContiguousMethod
195       cm_block_buffer_is_range_contiguous_method_;
197   CMSampleBufferGetDataBufferMethod cm_sample_buffer_get_data_buffer_method_;
198   CMSampleBufferGetFormatDescriptionMethod
199       cm_sample_buffer_get_format_description_method_;
200   CMSampleBufferGetImageBufferMethod cm_sample_buffer_get_image_buffer_method_;
201   CMSampleBufferGetSampleAttachmentsArrayMethod
202       cm_sample_buffer_get_sample_attachments_array_method_;
203   CFStringRef* k_cm_sample_attachment_key_not_sync_;
205   CMFormatDescriptionGetMediaSubTypeMethod
206       cm_format_description_get_media_sub_type_method_;
207   CMVideoFormatDescriptionGetDimensionsMethod
208       cm_video_format_description_get_dimensions_method_;
209   CMVideoFormatDescriptionGetH264ParameterSetAtIndexMethod
210       cm_video_format_description_get_h264_parameter_set_at_index_method_;
212   DISALLOW_COPY_AND_ASSIGN(CoreMediaLibraryInternal);
215 }  // namespace
217 static base::LazyInstance<CoreMediaLibraryInternal> g_coremedia_handle =
218     LAZY_INSTANCE_INITIALIZER;
220 // static
221 CoreMediaGlue::CMTime CoreMediaGlue::CMTimeMake(int64_t value,
222                                                 int32_t timescale) {
223   return g_coremedia_handle.Get().cm_time_make()(value, timescale);
226 // static
227 OSStatus CoreMediaGlue::CMBlockBufferCreateContiguous(
228     CFAllocatorRef structureAllocator,
229     CMBlockBufferRef sourceBuffer,
230     CFAllocatorRef blockAllocator,
231     const CMBlockBufferCustomBlockSource* customBlockSource,
232     size_t offsetToData,
233     size_t dataLength,
234     CMBlockBufferFlags flags,
235     CMBlockBufferRef* newBBufOut) {
236   return g_coremedia_handle.Get().cm_block_buffer_create_contiguous_method()(
237       structureAllocator,
238       sourceBuffer,
239       blockAllocator,
240       customBlockSource,
241       offsetToData,
242       dataLength,
243       flags,
244       newBBufOut);
247 // static
248 size_t CoreMediaGlue::CMBlockBufferGetDataLength(CMBlockBufferRef theBuffer) {
249   return g_coremedia_handle.Get().cm_block_buffer_get_data_length_method()(
250       theBuffer);
253 // static
254 OSStatus CoreMediaGlue::CMBlockBufferGetDataPointer(CMBlockBufferRef theBuffer,
255                                                     size_t offset,
256                                                     size_t* lengthAtOffset,
257                                                     size_t* totalLength,
258                                                     char** dataPointer) {
259   return g_coremedia_handle.Get().cm_block_buffer_get_data_pointer_method()(
260       theBuffer, offset, lengthAtOffset, totalLength, dataPointer);
263 // static
264 Boolean CoreMediaGlue::CMBlockBufferIsRangeContiguous(
265     CMBlockBufferRef theBuffer,
266     size_t offset,
267     size_t length) {
268   return g_coremedia_handle.Get().cm_block_buffer_is_range_contiguous_method()(
269       theBuffer, offset, length);
272 // static
273 CoreMediaGlue::CMBlockBufferRef CoreMediaGlue::CMSampleBufferGetDataBuffer(
274     CMSampleBufferRef sbuf) {
275   return g_coremedia_handle.Get().cm_sample_buffer_get_data_buffer_method()(
276       sbuf);
279 // static
280 CoreMediaGlue::CMFormatDescriptionRef
281 CoreMediaGlue::CMSampleBufferGetFormatDescription(
282     CoreMediaGlue::CMSampleBufferRef sbuf) {
283   return g_coremedia_handle.Get()
284       .cm_sample_buffer_get_format_description_method()(sbuf);
287 // static
288 CVImageBufferRef CoreMediaGlue::CMSampleBufferGetImageBuffer(
289     CMSampleBufferRef buffer) {
290   return g_coremedia_handle.Get().cm_sample_buffer_get_image_buffer_method()(
291       buffer);
294 // static
295 CFArrayRef CoreMediaGlue::CMSampleBufferGetSampleAttachmentsArray(
296     CMSampleBufferRef sbuf,
297     Boolean createIfNecessary) {
298   return g_coremedia_handle.Get()
299       .cm_sample_buffer_get_sample_attachments_array_method()(
300           sbuf, createIfNecessary);
303 // static
304 CFStringRef CoreMediaGlue::kCMSampleAttachmentKey_NotSync() {
305   return *g_coremedia_handle.Get().k_cm_sample_attachment_key_not_sync();
308 // static
309 FourCharCode CoreMediaGlue::CMFormatDescriptionGetMediaSubType(
310       CMFormatDescriptionRef desc) {
311   return g_coremedia_handle.Get()
312       .cm_format_description_get_media_sub_type_method()(desc);
315 // static
316 CoreMediaGlue::CMVideoDimensions
317     CoreMediaGlue::CMVideoFormatDescriptionGetDimensions(
318         CMVideoFormatDescriptionRef videoDesc) {
319   return g_coremedia_handle.Get()
320       .cm_video_format_description_get_dimensions_method()(videoDesc);
323 // static
324 OSStatus CoreMediaGlue::CMVideoFormatDescriptionGetH264ParameterSetAtIndex(
325     CMFormatDescriptionRef videoDesc,
326     size_t parameterSetIndex,
327     const uint8_t** parameterSetPointerOut,
328     size_t* parameterSetSizeOut,
329     size_t* parameterSetCountOut,
330     int* NALUnitHeaderLengthOut) {
331   return g_coremedia_handle.Get()
332       .cm_video_format_description_get_h264_parameter_set_at_index_method()(
333           videoDesc,
334           parameterSetIndex,
335           parameterSetPointerOut,
336           parameterSetSizeOut,
337           parameterSetCountOut,
338           NALUnitHeaderLengthOut);