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

Unified Diff: content/common/gpu/media/mac_video_decode_accelerator.mm

Issue 10388108: Implement media::VideoDecodeAccelerator on Mac (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: address review comments Created 8 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 side-by-side diff with in-line comments
Download patch
Index: content/common/gpu/media/mac_video_decode_accelerator.mm
diff --git a/content/common/gpu/media/mac_video_decode_accelerator.mm b/content/common/gpu/media/mac_video_decode_accelerator.mm
new file mode 100644
index 0000000000000000000000000000000000000000..a68b4d22c41114c19af4a5be6c20040fd812b2d0
--- /dev/null
+++ b/content/common/gpu/media/mac_video_decode_accelerator.mm
@@ -0,0 +1,272 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/common/gpu/media/mac_video_decode_accelerator.h"
+
+#include "base/bind.h"
+#include "base/file_path.h"
+#import "base/mac/foundation_util.h"
+#import "base/memory/ref_counted_memory.h"
+#import "base/message_loop.h"
+#include "base/location.h"
+#include "base/native_library.h"
+#include "ui/surface/io_surface_support_mac.h"
+#include "ui/gfx/video_decode_acceleration_support_mac.h"
+
+namespace {
+
+enum { kNumPictureBuffers = 4 };
+
+class ScopedContextSetter {
Ami GONE FROM CHROMIUM 2012/05/17 21:44:47 This seems like kind of overkill considering you u
sail 2012/05/23 23:02:29 I agree that this is pretty verbose but I really l
Ami GONE FROM CHROMIUM 2012/05/24 21:30:29 "simplicity" I don't think that word means what yo
+ public:
+ ScopedContextSetter(CGLContextObj context)
+ : old_context_(NULL),
+ did_succeed_(false) {
+ old_context_ = CGLGetCurrentContext();
+ did_succeed_ = CGLSetCurrentContext(context) == kCGLNoError;
+ }
+
+ ~ScopedContextSetter() {
+ if (did_succeed_)
+ CGLSetCurrentContext(old_context_);
+ }
+
+ bool did_succeed() const {
+ return did_succeed_;
+ }
+
+ private:
+ CGLContextObj old_context_;
+ bool did_succeed_;
+};
+
+} // namespace
+
+static bool BindImageToTexture(CGLContextObj context,
+ CVImageBufferRef image,
+ uint32 texture_id) {
+ ScopedContextSetter scoped_context_setter(context);
+ if (!scoped_context_setter.did_succeed())
+ return false;
+
+ IOSurfaceSupport* io_surface_support = IOSurfaceSupport::Initialize();
Ami GONE FROM CHROMIUM 2012/05/17 21:44:47 Get & check this before Initialize returns true?
sail 2012/05/23 23:02:29 Done.
+ if (!io_surface_support)
+ return false;
+
+ CFTypeRef io_surface =
+ io_surface_support->CVPixelBufferGetIOSurface(image);
+ if (!io_surface)
Ami GONE FROM CHROMIUM 2012/05/17 21:44:47 When can this happen? Do you want to log somethin
sail 2012/05/23 23:02:29 Done. Added logging.
+ return false;
+
+ glEnable(GL_TEXTURE_RECTANGLE_ARB);
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture_id);
+ if (io_surface_support->CGLTexImageIOSurface2D(
+ context,
+ GL_TEXTURE_RECTANGLE_ARB,
+ GL_RGB,
+ io_surface_support->IOSurfaceGetWidth(io_surface),
+ io_surface_support->IOSurfaceGetHeight(io_surface),
+ GL_YCBCR_422_APPLE,
+ GL_UNSIGNED_SHORT_8_8_APPLE,
+ io_surface,
+ 0) != kCGLNoError) {
+ return false;
+ }
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
Ami GONE FROM CHROMIUM 2012/05/17 21:44:47 Why this line & the next?
sail 2012/05/23 23:02:29 Hm.. it looks like we don't normally clear this in
+ glDisable(GL_TEXTURE_RECTANGLE_ARB);
+ if (glGetError() != GL_NO_ERROR)
Ami GONE FROM CHROMIUM 2012/05/17 21:44:47 if (foo != bar) return false; return true; is m
sail 2012/05/23 23:02:29 Done.
+ return false;
+
+ return true;
+}
+
+MacVideoDecodeAccelerator::MacVideoDecodeAccelerator(
+ media::VideoDecodeAccelerator::Client* client)
+ : client_(client),
+ cgl_context_(NULL),
+ nalu_len_field_size_(0),
+ frame_width_(0),
+ frame_height_(0),
+ did_request_pictures_(false) {
+}
+
+void MacVideoDecodeAccelerator::SetGLContext(void* gl_context) {
+ cgl_context_ = static_cast<CGLContextObj>(gl_context);
Ami GONE FROM CHROMIUM 2012/05/17 21:44:47 Why not type the param explicitly and avoid the ca
sail 2012/05/23 23:02:29 gfx::GLContext::GetHandle() returns void*. It seem
Ami GONE FROM CHROMIUM 2012/05/24 21:30:29 I disagree b/c the call-site is not cross-platform
sail 2012/05/29 03:45:01 Done.
+}
+
+bool MacVideoDecodeAccelerator::SetConfigInfo(
Ami GONE FROM CHROMIUM 2012/05/17 21:44:47 This at least needs a TODO to support mid-stream f
sail 2012/05/23 23:02:29 I'm not sure if this config info is related to mid
+ uint32_t frame_width,
+ uint32_t frame_height,
+ const std::vector<uint8_t>& avc_data) {
+ frame_width_ = frame_width;
+ frame_height_ = frame_height;
+ nalu_len_field_size_ = (avc_data[4] & 0x03) + 1;
+
+ DCHECK(!vda_.get());
+ vda_ = new gfx::VideoDecodeAccelerationSupport();
+ gfx::VideoDecodeAccelerationSupport::Status status = vda_->Create(
+ frame_width_, frame_height_,
+ kCVPixelFormatType_422YpCbCr8, &avc_data.front(), avc_data.size());
+ if (status != gfx::VideoDecodeAccelerationSupport::VDA_SUCCESS)
Ami GONE FROM CHROMIUM 2012/05/17 21:44:47 That's a funny name for the enum given it's alread
Ami GONE FROM CHROMIUM 2012/05/17 21:44:47 again shorter/clearer as: return status == gfx::Vi
sail 2012/05/23 23:02:29 Done.
sail 2012/05/23 23:02:29 Done.
+ return false;
+ return true;
+}
+
+bool MacVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile) {
+ if (client_)
+ client_->NotifyInitializeDone();
Ami GONE FROM CHROMIUM 2012/05/17 21:44:47 IIRC this can't be done in-line b/c of reentrancy
sail 2012/05/23 23:02:29 Done.
+ return true;
+}
+
+void MacVideoDecodeAccelerator::Decode(
+ const media::BitstreamBuffer& bitstream_buffer) {
+ base::SharedMemory memory(bitstream_buffer.handle(), true);
+ if (!memory.Map(bitstream_buffer.size())) {
+ CHECK(false);
Ami GONE FROM CHROMIUM 2012/05/17 21:44:47 This isn't very cool ;)
sail 2012/05/23 23:02:29 Done.
+ return;
+ }
+
+ size_t buffer_size = bitstream_buffer.size();
+ if (buffer_size < nalu_len_field_size_ + 1) {
Ami GONE FROM CHROMIUM 2012/05/17 21:44:47 Why so forgiving? Shouldn't this be an invalid-st
sail 2012/05/23 23:02:29 Done.
+ if (client_)
+ client_->NotifyEndOfBitstreamBuffer(bitstream_buffer.id());
+ return;
+ }
+
+ // The decoder can only handle slice types (1-5).
Ami GONE FROM CHROMIUM 2012/05/17 21:44:47 Drop the parens?
sail 2012/05/23 23:02:29 Done.
+ const uint8_t* buffer = static_cast<const uint8_t*>(memory.memory());
+ uint8_t nalu_type = buffer[nalu_len_field_size_] & 0x1f;
+ if (nalu_type < 1 || nalu_type > 5) {
Ami GONE FROM CHROMIUM 2012/05/17 21:44:47 are you sure about these bounds? H264Parser claim
sail 2012/05/23 23:02:29 Yea, the bounds are correct. 0 is unspecified whic
+ if (client_)
+ client_->NotifyEndOfBitstreamBuffer(bitstream_buffer.id());
+ return;
+ }
+
+ // Keep a ref counted copy of the buffer.
+ std::vector<uint8_t> vector(buffer, buffer + buffer_size);
Ami GONE FROM CHROMIUM 2012/05/17 21:44:47 That's quite the variable name.... vbuffer?
sail 2012/05/23 23:02:29 Done.
+ scoped_refptr<base::RefCountedBytes> bytes(
+ base::RefCountedBytes::TakeVector(&vector));
+
+ // Store the buffer size at the beginning of the buffer as the decoder
+ // expects.
+ size_t frame_buffer_size = buffer_size - nalu_len_field_size_;
+ for (size_t i = 0; i < nalu_len_field_size_; ++i) {
+ size_t shift = nalu_len_field_size_ * 8 - (i + 1) * 8;
+ bytes->data()[i] = (frame_buffer_size >> shift) & 0xff;
+ }
Ami GONE FROM CHROMIUM 2012/05/17 21:44:47 Do you want to have any kind of error checking?
sail 2012/05/23 23:02:29 Done.
+
+ vda_->Decode(bytes->front(), bytes->size(),
+ base::Bind(&MacVideoDecodeAccelerator::OnFrameReady, this,
+ bitstream_buffer.id(), bytes));
+
+ if (!did_request_pictures_) {
+ did_request_pictures_ = true;
+ if (client_)
+ client_->ProvidePictureBuffers(
+ kNumPictureBuffers, gfx::Size(frame_width_, frame_height_));
+ }
+}
+
+void MacVideoDecodeAccelerator::AssignPictureBuffers(
+ const std::vector<media::PictureBuffer>& buffers) {
+ available_pictures_.insert(
+ available_pictures_.end(), buffers.begin(), buffers.end());
+ SendImages();
+}
+
+void MacVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) {
+ std::map<int32, PendingPictureInfo>::iterator it =
+ pending_pictures_.find(picture_buffer_id);
+ DCHECK(it != pending_pictures_.end());
Ami GONE FROM CHROMIUM 2012/05/17 21:44:47 Do you really want to crash the GPU process if a b
sail 2012/05/23 23:02:29 Done.
+ PendingPictureInfo info = it->second;
+ pending_pictures_.erase(it);
+ available_pictures_.push_back(info.picture_buffer);
+ SendImages();
+}
+
+void MacVideoDecodeAccelerator::Flush() {
+ vda_->Flush(true);
+ MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+ &MacVideoDecodeAccelerator::NotifyFlushDone, this));
+}
+
+void MacVideoDecodeAccelerator::Reset() {
+ vda_->Flush(false);
+ MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+ &MacVideoDecodeAccelerator::NotifyResetDone, this));
+}
+
+void MacVideoDecodeAccelerator::Destroy() {
+ vda_->Destroy();
+ vda_ = NULL;
Ami GONE FROM CHROMIUM 2012/05/17 21:44:47 Don't all the other entry points want to check for
sail 2012/05/23 23:02:29 Done.
+ client_ = NULL;
+}
+
+MacVideoDecodeAccelerator::~MacVideoDecodeAccelerator() {
Ami GONE FROM CHROMIUM 2012/05/17 21:44:47 move to below ctor call Destroy()?
sail 2012/05/23 23:02:29 I'd rather leave it here to match the declaration
+}
+
+void MacVideoDecodeAccelerator::OnFrameReady(
+ int32 bitstream_buffer_id,
+ scoped_refptr<base::RefCountedBytes> bytes,
+ CVImageBufferRef image,
+ int status) {
+ if (image) {
Ami GONE FROM CHROMIUM 2012/05/17 21:44:47 how can this fail?
sail 2012/05/23 23:02:29 The decoder can send a NULL image if it failed to
+ DecodedImageInfo info;
+ info.image.reset(image, base::mac::RETAIN);
+ info.bitstream_buffer_id = bitstream_buffer_id;
+ decoded_images_.push_back(info);
+ SendImages();
+ }
+ if (client_)
+ client_->NotifyEndOfBitstreamBuffer(bitstream_buffer_id);
Ami GONE FROM CHROMIUM 2012/05/17 21:44:47 This is wrong if multiple frames are encoded in a
sail 2012/05/23 23:02:29 The Mac API can only handle a single NALU at a tim
+}
+
+void MacVideoDecodeAccelerator::SendImages() {
Ami GONE FROM CHROMIUM 2012/05/17 21:44:47 This sends at most one image, so the name is misle
sail 2012/05/23 23:02:29 Done.
+ if (available_pictures_.size() == 0 || decoded_images_.size() == 0)
+ return;
+
+ DecodedImageInfo info = decoded_images_.front();
+ decoded_images_.pop_front();
+ media::PictureBuffer picture_buffer = available_pictures_.front();
+
+ if (!BindImageToTexture(cgl_context_, info.image,
+ picture_buffer.texture_id())) {
+ LOG(ERROR) << "Error binding image to texture.";
+ return;
+ }
+
+ available_pictures_.pop_front();
Ami GONE FROM CHROMIUM 2012/05/17 21:44:47 move this up to right below the .front() call?
sail 2012/05/23 23:02:29 Done.
+ PendingPictureInfo pending_info(picture_buffer);
Ami GONE FROM CHROMIUM 2012/05/17 21:44:47 why use the intermediate?
sail 2012/05/23 23:02:29 Done.
+ pending_info.image = info.image;
Ami GONE FROM CHROMIUM 2012/05/17 21:44:47 why not pass both buffer & image to the PPI ctor?
sail 2012/05/23 23:02:29 Done.
+ pending_pictures_.insert(std::pair<int, PendingPictureInfo>(
Ami GONE FROM CHROMIUM 2012/05/17 21:44:47 std::make_pair lets you drop the template params.
sail 2012/05/23 23:02:29 The Mac compiler doesn't seem to allow this.
+ picture_buffer.id(), pending_info));
+ media::Picture picture(picture_buffer.id(), info.bitstream_buffer_id);
+ if (client_)
Ami GONE FROM CHROMIUM 2012/05/17 21:44:47 If !client_ early-return at the top of the functio
sail 2012/05/23 23:02:29 Done.
+ client_->PictureReady(picture);
Ami GONE FROM CHROMIUM 2012/05/17 21:44:47 can construct this inline: client_->PictureReady(m
sail 2012/05/23 23:02:29 Done.
+}
+
+void MacVideoDecodeAccelerator::NotifyFlushDone() {
+ if (client_)
Ami GONE FROM CHROMIUM 2012/05/17 21:44:47 assert decoded_images_ is empty?
sail 2012/05/23 23:02:29 Hm... it's possible that there are no available im
+ client_->NotifyFlushDone();
+}
+
+void MacVideoDecodeAccelerator::NotifyResetDone() {
+ decoded_images_.clear();
+ if (client_)
+ client_->NotifyResetDone();
+}
+
+MacVideoDecodeAccelerator::PendingPictureInfo::PendingPictureInfo(
+ media::PictureBuffer pic)
+ : picture_buffer(pic.id(), pic.size(), pic.texture_id()) {
Ami GONE FROM CHROMIUM 2012/05/17 21:44:47 what's wrong w/ the copy ctor?
sail 2012/05/23 23:02:29 Done.
+}
+
+MacVideoDecodeAccelerator::PendingPictureInfo::~PendingPictureInfo() {
+}
+
+MacVideoDecodeAccelerator::DecodedImageInfo::DecodedImageInfo() {
+}
+
+MacVideoDecodeAccelerator::DecodedImageInfo::~DecodedImageInfo() {
+}

Powered by Google App Engine
This is Rietveld 408576698