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. 4 5#include "media/base/mac/coremedia_glue.h" 6 7#include <dlfcn.h> 8#import <Foundation/Foundation.h> 9 10#include "base/logging.h" 11#include "base/lazy_instance.h" 12 13namespace { 14 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. 18class CoreMediaLibraryInternal { 19 public: 20 typedef CoreMediaGlue::CMTime (*CMTimeMakeMethod)(int64_t, int32_t); 21 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); 43 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); 54 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*); 67 68 CoreMediaLibraryInternal() { 69 NSBundle* bundle = [NSBundle 70 bundleWithPath:@"/System/Library/Frameworks/CoreMedia.framework"]; 71 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(); 76 77 // Now extract the methods. 78 cm_time_make_ = reinterpret_cast<CMTimeMakeMethod>( 79 dlsym(library_handle, "CMTimeMake")); 80 CHECK(cm_time_make_) << dlerror(); 81 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(); 98 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(); 118 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(); 127 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 } 135 136 const CMTimeMakeMethod& cm_time_make() const { return cm_time_make_; } 137 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 } 154 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 } 174 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 } 187 188 private: 189 CMTimeMakeMethod cm_time_make_; 190 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_; 196 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_; 204 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_; 211 212 DISALLOW_COPY_AND_ASSIGN(CoreMediaLibraryInternal); 213}; 214 215} // namespace 216 217static base::LazyInstance<CoreMediaLibraryInternal> g_coremedia_handle = 218 LAZY_INSTANCE_INITIALIZER; 219 220// static 221CoreMediaGlue::CMTime CoreMediaGlue::CMTimeMake(int64_t value, 222 int32_t timescale) { 223 return g_coremedia_handle.Get().cm_time_make()(value, timescale); 224} 225 226// static 227OSStatus 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); 245} 246 247// static 248size_t CoreMediaGlue::CMBlockBufferGetDataLength(CMBlockBufferRef theBuffer) { 249 return g_coremedia_handle.Get().cm_block_buffer_get_data_length_method()( 250 theBuffer); 251} 252 253// static 254OSStatus 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); 261} 262 263// static 264Boolean 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); 270} 271 272// static 273CoreMediaGlue::CMBlockBufferRef CoreMediaGlue::CMSampleBufferGetDataBuffer( 274 CMSampleBufferRef sbuf) { 275 return g_coremedia_handle.Get().cm_sample_buffer_get_data_buffer_method()( 276 sbuf); 277} 278 279// static 280CoreMediaGlue::CMFormatDescriptionRef 281CoreMediaGlue::CMSampleBufferGetFormatDescription( 282 CoreMediaGlue::CMSampleBufferRef sbuf) { 283 return g_coremedia_handle.Get() 284 .cm_sample_buffer_get_format_description_method()(sbuf); 285} 286 287// static 288CVImageBufferRef CoreMediaGlue::CMSampleBufferGetImageBuffer( 289 CMSampleBufferRef buffer) { 290 return g_coremedia_handle.Get().cm_sample_buffer_get_image_buffer_method()( 291 buffer); 292} 293 294// static 295CFArrayRef 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); 301} 302 303// static 304CFStringRef CoreMediaGlue::kCMSampleAttachmentKey_NotSync() { 305 return *g_coremedia_handle.Get().k_cm_sample_attachment_key_not_sync(); 306} 307 308// static 309FourCharCode CoreMediaGlue::CMFormatDescriptionGetMediaSubType( 310 CMFormatDescriptionRef desc) { 311 return g_coremedia_handle.Get() 312 .cm_format_description_get_media_sub_type_method()(desc); 313} 314 315// static 316CoreMediaGlue::CMVideoDimensions 317 CoreMediaGlue::CMVideoFormatDescriptionGetDimensions( 318 CMVideoFormatDescriptionRef videoDesc) { 319 return g_coremedia_handle.Get() 320 .cm_video_format_description_get_dimensions_method()(videoDesc); 321} 322 323// static 324OSStatus 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); 339} 340