Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(270)

Side by Side Diff: content/common/gpu/media/mac_video_decode_accelerator.mm

Issue 14401013: Delete MacVDA from the codebase since it is dead code and not being worked on. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Remove pointless flag from linux & mac Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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 "content/common/gpu/media/mac_video_decode_accelerator.h"
6
7 #include "base/bind.h"
8 #include "base/files/file_path.h"
9 #include "base/location.h"
10 #import "base/mac/foundation_util.h"
11 #import "base/memory/ref_counted_memory.h"
12 #import "base/message_loop.h"
13 #include "base/native_library.h"
14 #include "ui/gfx/video_decode_acceleration_support_mac.h"
15 #include "ui/surface/io_surface_support_mac.h"
16
17 namespace content {
18
19 // Helper macros for dealing with failure. If |result| evaluates false, emit
20 // |log| to ERROR, register |error| with the decoder, and return |ret_val|
21 // (which may be omitted for functions that return void).
22 #define RETURN_ON_FAILURE(result, log, error, ret_val) \
23 do { \
24 if (!(result)) { \
25 DLOG(ERROR) << log; \
26 StopOnError(error); \
27 return ret_val; \
28 } \
29 } while (0)
30
31 namespace {
32
33 enum { kNumPictureBuffers = 4 };
34
35 class ScopedContextSetter {
36 public:
37 ScopedContextSetter(CGLContextObj context)
38 : old_context_(NULL),
39 did_succeed_(false) {
40 old_context_ = CGLGetCurrentContext();
41 did_succeed_ = CGLSetCurrentContext(context) == kCGLNoError;
42 }
43
44 ~ScopedContextSetter() {
45 if (did_succeed_)
46 CGLSetCurrentContext(old_context_);
47 }
48
49 bool did_succeed() const {
50 return did_succeed_;
51 }
52
53 private:
54 CGLContextObj old_context_;
55 bool did_succeed_;
56 };
57
58 } // namespace
59
60 static bool BindImageToTexture(CGLContextObj context,
61 CVImageBufferRef image,
62 uint32 texture_id) {
63 ScopedContextSetter scoped_context_setter(context);
64 if (!scoped_context_setter.did_succeed()) {
65 DVLOG(1) << "Unable to set OpenGL context.";
66 return false;
67 }
68
69 IOSurfaceSupport* io_surface_support = IOSurfaceSupport::Initialize();
70 DCHECK(io_surface_support);
71
72 CFTypeRef io_surface =
73 io_surface_support->CVPixelBufferGetIOSurface(image);
74 if (!io_surface) {
75 DVLOG(1) << "Unable to get IOSurface for CVPixelBuffer.";
76 return false;
77 }
78
79 glEnable(GL_TEXTURE_RECTANGLE_ARB);
80 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture_id);
81 if (io_surface_support->CGLTexImageIOSurface2D(
82 context,
83 GL_TEXTURE_RECTANGLE_ARB,
84 GL_RGB,
85 io_surface_support->IOSurfaceGetWidth(io_surface),
86 io_surface_support->IOSurfaceGetHeight(io_surface),
87 GL_YCBCR_422_APPLE,
88 GL_UNSIGNED_SHORT_8_8_APPLE,
89 io_surface,
90 0) != kCGLNoError) {
91 DVLOG(1) << "Failed to bind image to texture.";
92 return false;
93 }
94 return glGetError() == GL_NO_ERROR;
95 }
96
97 MacVideoDecodeAccelerator::MacVideoDecodeAccelerator(
98 CGLContextObj cgl_context, media::VideoDecodeAccelerator::Client* client)
99 : client_(client),
100 cgl_context_(cgl_context),
101 did_build_config_record_(false) {
102 }
103
104 bool MacVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile) {
105 DCHECK(CalledOnValidThread());
106
107 // MacVDA still fails on too many videos to be useful, even to users who
108 // ignore the GPU blacklist. Fail unconditionally here until enough of
109 // crbug.com/133828's blockers are resolved.
110 if (true)
111 return false;
112
113 if (profile < media::H264PROFILE_MIN || profile > media::H264PROFILE_MAX)
114 return false;
115
116 IOSurfaceSupport* io_surface_support = IOSurfaceSupport::Initialize();
117 if (!io_surface_support)
118 return false;
119
120 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
121 &MacVideoDecodeAccelerator::NotifyInitializeDone, base::AsWeakPtr(this)));
122 return true;
123 }
124
125 void MacVideoDecodeAccelerator::Decode(
126 const media::BitstreamBuffer& bitstream_buffer) {
127 DCHECK(CalledOnValidThread());
128 RETURN_ON_FAILURE(client_,
129 "Call to Decode() during invalid state.", ILLEGAL_STATE,);
130
131 base::SharedMemory memory(bitstream_buffer.handle(), true);
132 RETURN_ON_FAILURE(memory.Map(bitstream_buffer.size()),
133 "Failed to SharedMemory::Map().", UNREADABLE_INPUT,);
134
135 h264_parser_.SetStream(static_cast<const uint8_t*>(memory.memory()),
136 bitstream_buffer.size());
137 while (true) {
138 H264NALU nalu;
139 H264Parser::Result result = h264_parser_.AdvanceToNextNALU(&nalu);
140 if (result == H264Parser::kEOStream) {
141 if (bitstream_nalu_count_.count(bitstream_buffer.id()) == 0) {
142 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
143 &MacVideoDecodeAccelerator::NotifyInputBufferRead,
144 base::AsWeakPtr(this), bitstream_buffer.id()));
145 }
146 return;
147 }
148 RETURN_ON_FAILURE(result == H264Parser::kOk,
149 "Unable to parse bitstream.", UNREADABLE_INPUT,);
150 if (!did_build_config_record_) {
151 std::vector<uint8_t> config_record;
152 RETURN_ON_FAILURE(config_record_builder_.ProcessNALU(&h264_parser_, nalu,
153 &config_record),
154 "Unable to build AVC configuraiton record.",
155 UNREADABLE_INPUT,);
156 if (!config_record.empty()) {
157 did_build_config_record_ = true;
158 if (!CreateDecoder(config_record))
159 return;
160 }
161 }
162 // If the decoder has been created and this is a slice type then pass it
163 // to the decoder.
164 if (vda_support_.get() && nalu.nal_unit_type >= 1 &&
165 nalu.nal_unit_type <= 5) {
166 bitstream_nalu_count_[bitstream_buffer.id()]++;
167 DecodeNALU(nalu, bitstream_buffer.id());
168 }
169 }
170 }
171
172 void MacVideoDecodeAccelerator::AssignPictureBuffers(
173 const std::vector<media::PictureBuffer>& buffers) {
174 DCHECK(CalledOnValidThread());
175 RETURN_ON_FAILURE(client_,
176 "Call to AssignPictureBuffers() during invalid state.",
177 ILLEGAL_STATE,);
178 available_pictures_.insert(
179 available_pictures_.end(), buffers.begin(), buffers.end());
180 SendImages();
181 }
182
183 void MacVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) {
184 DCHECK(CalledOnValidThread());
185 RETURN_ON_FAILURE(client_,
186 "Call to ReusePictureBuffe() during invalid state.",
187 ILLEGAL_STATE,);
188
189 std::map<int32, UsedPictureInfo>::iterator it =
190 used_pictures_.find(picture_buffer_id);
191 RETURN_ON_FAILURE(it != used_pictures_.end(),
192 "Missing picture buffer id: " << picture_buffer_id,
193 INVALID_ARGUMENT,);
194 UsedPictureInfo info = it->second;
195 used_pictures_.erase(it);
196 available_pictures_.push_back(info.picture_buffer);
197 SendImages();
198 }
199
200 void MacVideoDecodeAccelerator::Flush() {
201 DCHECK(CalledOnValidThread());
202 RETURN_ON_FAILURE(vda_support_,
203 "Call to Flush() during invalid state.", ILLEGAL_STATE,);
204 vda_support_->Flush(true);
205 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
206 &MacVideoDecodeAccelerator::NotifyFlushDone, base::AsWeakPtr(this)));
207 }
208
209 void MacVideoDecodeAccelerator::Reset() {
210 DCHECK(CalledOnValidThread());
211 RETURN_ON_FAILURE(vda_support_,
212 "Call to Reset() during invalid state.", ILLEGAL_STATE,);
213 vda_support_->Flush(false);
214 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
215 &MacVideoDecodeAccelerator::NotifyResetDone, base::AsWeakPtr(this)));
216 }
217
218 void MacVideoDecodeAccelerator::Cleanup() {
219 DCHECK(CalledOnValidThread());
220 if (vda_support_) {
221 vda_support_->Destroy();
222 vda_support_ = NULL;
223 }
224 client_ = NULL;
225 decoded_images_.clear();
226 }
227
228 void MacVideoDecodeAccelerator::Destroy() {
229 DCHECK(CalledOnValidThread());
230 Cleanup();
231 delete this;
232 }
233
234 MacVideoDecodeAccelerator::~MacVideoDecodeAccelerator() {
235 DCHECK(CalledOnValidThread());
236 DCHECK(!vda_support_);
237 DCHECK(!client_);
238 DCHECK(decoded_images_.empty());
239 }
240
241 void MacVideoDecodeAccelerator::OnFrameReady(
242 int32 bitstream_buffer_id,
243 scoped_refptr<base::RefCountedBytes> bytes,
244 CVImageBufferRef image,
245 int status) {
246 DCHECK(CalledOnValidThread());
247 RETURN_ON_FAILURE(status == noErr,
248 "Decoding image failed with error code: " << status,
249 PLATFORM_FAILURE,);
250 if (!client_)
251 return;
252 if (image) {
253 DecodedImageInfo info;
254 info.image.reset(image, base::scoped_policy::RETAIN);
255 info.bitstream_buffer_id = bitstream_buffer_id;
256 decoded_images_.push_back(info);
257 SendImages();
258 }
259 std::map<int32, int>::iterator bitstream_count_it =
260 bitstream_nalu_count_.find(bitstream_buffer_id);
261 if (--bitstream_count_it->second == 0) {
262 bitstream_nalu_count_.erase(bitstream_count_it);
263 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
264 &MacVideoDecodeAccelerator::NotifyInputBufferRead,
265 base::AsWeakPtr(this), bitstream_buffer_id));
266 }
267 }
268
269 void MacVideoDecodeAccelerator::SendImages() {
270 if (!client_) {
271 DCHECK(decoded_images_.empty());
272 return;
273 }
274
275 while (available_pictures_.size() && decoded_images_.size()) {
276 DecodedImageInfo info = decoded_images_.front();
277 decoded_images_.pop_front();
278 media::PictureBuffer picture_buffer = available_pictures_.front();
279 available_pictures_.pop_front();
280
281 RETURN_ON_FAILURE(BindImageToTexture(
282 cgl_context_, info.image, picture_buffer.texture_id()),
283 "Error binding image to texture.", PLATFORM_FAILURE,);
284
285 used_pictures_.insert(std::make_pair(
286 picture_buffer.id(), UsedPictureInfo(picture_buffer, info.image)));
287 client_->PictureReady(
288 media::Picture(picture_buffer.id(), info.bitstream_buffer_id));
289 }
290 }
291
292 void MacVideoDecodeAccelerator::StopOnError(
293 media::VideoDecodeAccelerator::Error error) {
294 if (client_)
295 client_->NotifyError(error);
296 Cleanup();
297 }
298
299 bool MacVideoDecodeAccelerator::CreateDecoder(
300 const std::vector<uint8_t>& extra_data) {
301 DCHECK(client_);
302 DCHECK(!vda_support_.get());
303
304 vda_support_ = new gfx::VideoDecodeAccelerationSupport();
305 gfx::VideoDecodeAccelerationSupport::Status status = vda_support_->Create(
306 config_record_builder_.coded_width(),
307 config_record_builder_.coded_height(),
308 kCVPixelFormatType_422YpCbCr8,
309 &extra_data[0], extra_data.size());
310 RETURN_ON_FAILURE(status == gfx::VideoDecodeAccelerationSupport::SUCCESS,
311 "Creating video decoder failed with error: " << status,
312 PLATFORM_FAILURE, false);
313
314 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
315 &MacVideoDecodeAccelerator::RequestPictures, base::AsWeakPtr(this)));
316 return true;
317 }
318
319 void MacVideoDecodeAccelerator::DecodeNALU(const H264NALU& nalu,
320 int32 bitstream_buffer_id) {
321 // Assume the NALU length field size is 4 bytes.
322 const int kNALULengthFieldSize = 4;
323 std::vector<uint8_t> data(kNALULengthFieldSize + nalu.size);
324
325 // Store the buffer size at the beginning of the buffer as the decoder
326 // expects.
327 for (size_t i = 0; i < kNALULengthFieldSize; ++i) {
328 size_t shift = kNALULengthFieldSize * 8 - (i + 1) * 8;
329 data[i] = (nalu.size >> shift) & 0xff;
330 }
331
332 // Copy the NALU data.
333 memcpy(&data[kNALULengthFieldSize], nalu.data, nalu.size);
334
335 // Keep a ref counted copy of the buffer.
336 scoped_refptr<base::RefCountedBytes> bytes(
337 base::RefCountedBytes::TakeVector(&data));
338 vda_support_->Decode(bytes->front(), bytes->size(), base::Bind(
339 &MacVideoDecodeAccelerator::OnFrameReady,
340 base::AsWeakPtr(this), bitstream_buffer_id, bytes));
341 }
342
343 void MacVideoDecodeAccelerator::NotifyInitializeDone() {
344 if (client_)
345 client_->NotifyInitializeDone();
346 }
347
348 void MacVideoDecodeAccelerator::RequestPictures() {
349 if (client_) {
350 client_->ProvidePictureBuffers(
351 kNumPictureBuffers,
352 gfx::Size(config_record_builder_.coded_width(),
353 config_record_builder_.coded_height()),
354 GL_TEXTURE_RECTANGLE_ARB);
355 }
356 }
357
358 void MacVideoDecodeAccelerator::NotifyFlushDone() {
359 if (client_)
360 client_->NotifyFlushDone();
361 }
362
363 void MacVideoDecodeAccelerator::NotifyResetDone() {
364 decoded_images_.clear();
365 if (client_)
366 client_->NotifyResetDone();
367 }
368
369 void MacVideoDecodeAccelerator::NotifyInputBufferRead(int input_buffer_id) {
370 if (client_)
371 client_->NotifyEndOfBitstreamBuffer(input_buffer_id);
372 }
373
374 MacVideoDecodeAccelerator::UsedPictureInfo::UsedPictureInfo(
375 const media::PictureBuffer& pic,
376 const base::mac::ScopedCFTypeRef<CVImageBufferRef>& image)
377 : picture_buffer(pic),
378 image(image, base::scoped_policy::RETAIN) {
379 }
380
381 MacVideoDecodeAccelerator::UsedPictureInfo::~UsedPictureInfo() {
382 }
383
384 MacVideoDecodeAccelerator::DecodedImageInfo::DecodedImageInfo() {
385 }
386
387 MacVideoDecodeAccelerator::DecodedImageInfo::~DecodedImageInfo() {
388 }
389
390 } // namespace content
OLDNEW
« no previous file with comments | « content/common/gpu/media/mac_video_decode_accelerator.h ('k') | content/common/gpu/media/rendering_helper_mac.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698