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 |