| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 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 "ui/gfx/video_decode_acceleration_support_mac.h" | |
| 6 | |
| 7 #include <dlfcn.h> | |
| 8 | |
| 9 #include "base/bind.h" | |
| 10 #include "base/files/file_path.h" | |
| 11 #include "base/location.h" | |
| 12 #import "base/mac/foundation_util.h" | |
| 13 #include "base/mac/scoped_nsautorelease_pool.h" | |
| 14 #include "base/native_library.h" | |
| 15 | |
| 16 using base::mac::CFToNSCast; | |
| 17 using base::mac::NSToCFCast; | |
| 18 | |
| 19 const CFStringRef kVDADecoderConfiguration_Width = CFSTR("width"); | |
| 20 const CFStringRef kVDADecoderConfiguration_Height = CFSTR("height"); | |
| 21 const CFStringRef kVDADecoderConfiguration_SourceFormat = CFSTR("format"); | |
| 22 const CFStringRef kVDADecoderConfiguration_avcCData = CFSTR("avcC"); | |
| 23 const CFStringRef kCVPixelBufferIOSurfacePropertiesKey = | |
| 24 CFSTR("IOSurfaceProperties"); | |
| 25 | |
| 26 namespace { | |
| 27 | |
| 28 // These are 10.6.3 APIs that we look up at run time. | |
| 29 typedef OSStatus (*VDADecoderCreateFunc)( | |
| 30 CFDictionaryRef decoderConfiguration, | |
| 31 CFDictionaryRef destinationImageBufferAttributes, | |
| 32 VDADecoderOutputCallback* outputCallback, | |
| 33 void* decoderOutputCallbackRefcon, | |
| 34 VDADecoder* decoderOut); | |
| 35 | |
| 36 typedef OSStatus (*VDADecoderDecodeFunc)( | |
| 37 VDADecoder decoder, | |
| 38 uint32_t decodeFlags, | |
| 39 CFTypeRef compressedBuffer, | |
| 40 CFDictionaryRef frameInfo); | |
| 41 | |
| 42 typedef OSStatus (*VDADecoderFlushFunc)( | |
| 43 VDADecoder decoder, | |
| 44 uint32_t flushFlags); | |
| 45 | |
| 46 typedef OSStatus (*VDADecoderDestroyFunc)( | |
| 47 VDADecoder decoder); | |
| 48 | |
| 49 VDADecoderCreateFunc g_VDADecoderCreate; | |
| 50 VDADecoderDecodeFunc g_VDADecoderDecode; | |
| 51 VDADecoderFlushFunc g_VDADecoderFlush; | |
| 52 VDADecoderDestroyFunc g_VDADecoderDestroy; | |
| 53 | |
| 54 NSString* const kFrameIdKey = @"frame_id"; | |
| 55 | |
| 56 bool InitializeVdaApis() { | |
| 57 static bool should_initialize = true; | |
| 58 if (should_initialize) { | |
| 59 should_initialize = false; | |
| 60 base::FilePath path; | |
| 61 if (!base::mac::GetSearchPathDirectory( | |
| 62 NSLibraryDirectory, NSSystemDomainMask, &path)) { | |
| 63 return false; | |
| 64 } | |
| 65 | |
| 66 path = path.AppendASCII("Frameworks") | |
| 67 .AppendASCII("VideoDecodeAcceleration.framework") | |
| 68 .AppendASCII("VideoDecodeAcceleration"); | |
| 69 base::NativeLibrary vda_library = base::LoadNativeLibrary(path, NULL); | |
| 70 if (!vda_library) | |
| 71 return false; | |
| 72 | |
| 73 g_VDADecoderCreate = reinterpret_cast<VDADecoderCreateFunc>( | |
| 74 base::GetFunctionPointerFromNativeLibrary( | |
| 75 vda_library, "VDADecoderCreate")); | |
| 76 g_VDADecoderDecode = reinterpret_cast<VDADecoderDecodeFunc>( | |
| 77 base::GetFunctionPointerFromNativeLibrary( | |
| 78 vda_library, "VDADecoderDecode")); | |
| 79 g_VDADecoderFlush = reinterpret_cast<VDADecoderFlushFunc>( | |
| 80 base::GetFunctionPointerFromNativeLibrary( | |
| 81 vda_library, "VDADecoderFlush")); | |
| 82 g_VDADecoderDestroy = reinterpret_cast<VDADecoderDestroyFunc>( | |
| 83 base::GetFunctionPointerFromNativeLibrary( | |
| 84 vda_library, "VDADecoderDestroy")); | |
| 85 } | |
| 86 | |
| 87 return g_VDADecoderCreate && g_VDADecoderDecode && g_VDADecoderFlush && | |
| 88 g_VDADecoderDestroy; | |
| 89 } | |
| 90 | |
| 91 } // namespace | |
| 92 | |
| 93 namespace gfx { | |
| 94 | |
| 95 VideoDecodeAccelerationSupport::VideoDecodeAccelerationSupport() | |
| 96 : decoder_(NULL), | |
| 97 frame_id_count_(0), | |
| 98 loop_(base::MessageLoopProxy::current()) { | |
| 99 } | |
| 100 | |
| 101 VideoDecodeAccelerationSupport::Status VideoDecodeAccelerationSupport::Create( | |
| 102 int width, | |
| 103 int height, | |
| 104 int pixel_format, | |
| 105 const void* avc_bytes, | |
| 106 size_t avc_size) { | |
| 107 if (!InitializeVdaApis()) | |
| 108 return LOAD_FRAMEWORK_ERROR; | |
| 109 | |
| 110 NSData* avc_data = [NSData dataWithBytes:avc_bytes length:avc_size]; | |
| 111 NSDictionary* config = [NSDictionary dictionaryWithObjectsAndKeys: | |
| 112 [NSNumber numberWithInt:width], | |
| 113 CFToNSCast(kVDADecoderConfiguration_Width), | |
| 114 [NSNumber numberWithInt:height], | |
| 115 CFToNSCast(kVDADecoderConfiguration_Height), | |
| 116 [NSNumber numberWithInt:'avc1'], | |
| 117 CFToNSCast(kVDADecoderConfiguration_SourceFormat), | |
| 118 avc_data, | |
| 119 CFToNSCast(kVDADecoderConfiguration_avcCData), | |
| 120 nil]; | |
| 121 | |
| 122 NSDictionary* format_info = [NSDictionary dictionaryWithObjectsAndKeys: | |
| 123 [NSNumber numberWithInt:pixel_format], | |
| 124 CFToNSCast(kCVPixelBufferPixelFormatTypeKey), | |
| 125 // Must set to an empty dictionary as per documentation. | |
| 126 [NSDictionary dictionary], | |
| 127 CFToNSCast(kCVPixelBufferIOSurfacePropertiesKey), | |
| 128 nil]; | |
| 129 | |
| 130 OSStatus status = g_VDADecoderCreate(NSToCFCast(config), | |
| 131 NSToCFCast(format_info), | |
| 132 reinterpret_cast<VDADecoderOutputCallback*>(OnFrameReadyCallback), this, | |
| 133 &decoder_); | |
| 134 switch (status) { | |
| 135 case kVDADecoderNoErr: | |
| 136 return SUCCESS; | |
| 137 case kVDADecoderHardwareNotSupportedErr: | |
| 138 return HARDWARE_NOT_SUPPORTED_ERROR; | |
| 139 default: | |
| 140 return OTHER_ERROR; | |
| 141 } | |
| 142 } | |
| 143 | |
| 144 VideoDecodeAccelerationSupport::Status VideoDecodeAccelerationSupport::Decode( | |
| 145 const void* bytes, | |
| 146 size_t size, | |
| 147 const FrameReadyCallback& cb) { | |
| 148 DCHECK(decoder_); | |
| 149 ++frame_id_count_; | |
| 150 frame_ready_callbacks_[frame_id_count_] = cb; | |
| 151 | |
| 152 NSData* data = [NSData dataWithBytes:bytes length:size]; | |
| 153 NSDictionary* frame_info = [NSDictionary | |
| 154 dictionaryWithObject:[NSNumber numberWithInt:frame_id_count_] | |
| 155 forKey:kFrameIdKey]; | |
| 156 | |
| 157 OSStatus status = g_VDADecoderDecode(decoder_, 0, NSToCFCast(data), | |
| 158 NSToCFCast(frame_info)); | |
| 159 if (status != kVDADecoderNoErr) { | |
| 160 frame_ready_callbacks_.erase(frame_id_count_); | |
| 161 return OTHER_ERROR; | |
| 162 } | |
| 163 return SUCCESS; | |
| 164 } | |
| 165 | |
| 166 VideoDecodeAccelerationSupport::Status VideoDecodeAccelerationSupport::Flush( | |
| 167 bool emit_frames) { | |
| 168 DCHECK(decoder_); | |
| 169 OSStatus status = g_VDADecoderFlush( | |
| 170 decoder_, emit_frames ? kVDADecoderFlush_EmitFrames : 0); | |
| 171 if (!emit_frames) | |
| 172 frame_ready_callbacks_.clear(); | |
| 173 return status == kVDADecoderNoErr ? SUCCESS : OTHER_ERROR; | |
| 174 } | |
| 175 | |
| 176 VideoDecodeAccelerationSupport::Status | |
| 177 VideoDecodeAccelerationSupport::Destroy() { | |
| 178 // Decoder might be NULL if Create() fails. | |
| 179 if (!decoder_) | |
| 180 return SUCCESS; | |
| 181 OSStatus status = g_VDADecoderDestroy(decoder_); | |
| 182 decoder_ = NULL; | |
| 183 return status == kVDADecoderNoErr ? SUCCESS : OTHER_ERROR; | |
| 184 } | |
| 185 | |
| 186 VideoDecodeAccelerationSupport::~VideoDecodeAccelerationSupport() { | |
| 187 DCHECK(!decoder_); | |
| 188 } | |
| 189 | |
| 190 // static | |
| 191 void VideoDecodeAccelerationSupport::OnFrameReadyCallback( | |
| 192 void* callback_data, | |
| 193 CFDictionaryRef frame_info, | |
| 194 OSStatus status, | |
| 195 uint32_t flags, | |
| 196 CVImageBufferRef image_buffer) { | |
| 197 base::mac::ScopedNSAutoreleasePool pool; | |
| 198 NSNumber* frame_id_num = base::mac::ObjCCastStrict<NSNumber>( | |
| 199 [CFToNSCast(frame_info) objectForKey:kFrameIdKey]); | |
| 200 int frame_id = [frame_id_num intValue]; | |
| 201 | |
| 202 // Retain the image while the callback is in flight. | |
| 203 if (image_buffer) | |
| 204 CFRetain(image_buffer); | |
| 205 | |
| 206 VideoDecodeAccelerationSupport* vda = | |
| 207 reinterpret_cast<VideoDecodeAccelerationSupport*>(callback_data); | |
| 208 DCHECK(vda); | |
| 209 vda->loop_->PostTask( | |
| 210 FROM_HERE, base::Bind(&VideoDecodeAccelerationSupport::OnFrameReady, vda, | |
| 211 image_buffer, status, frame_id)); | |
| 212 } | |
| 213 | |
| 214 void VideoDecodeAccelerationSupport::OnFrameReady(CVImageBufferRef image_buffer, | |
| 215 OSStatus status, | |
| 216 int frame_id) { | |
| 217 frame_ready_callbacks_[frame_id].Run(image_buffer, status); | |
| 218 // Match the retain in OnFrameReadyCallback. | |
| 219 if (image_buffer) | |
| 220 CFRelease(image_buffer); | |
| 221 frame_ready_callbacks_.erase(frame_id); | |
| 222 } | |
| 223 | |
| 224 } // namespace | |
| OLD | NEW |