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

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

Issue 10388108: Implement media::VideoDecodeAccelerator on Mac (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: a 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/video_decode_accelerator_mac.mm
diff --git a/content/common/gpu/media/video_decode_accelerator_mac.mm b/content/common/gpu/media/video_decode_accelerator_mac.mm
new file mode 100644
index 0000000000000000000000000000000000000000..c9a00e6d3344c9afccef37abc2f3006770eeb588
--- /dev/null
+++ b/content/common/gpu/media/video_decode_accelerator_mac.mm
@@ -0,0 +1,273 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
Ami GONE FROM CHROMIUM 2012/05/15 17:55:22 I don't know anything about Objective-C so I'm goi
sail 2012/05/15 23:53:31 It would be great if you could look at the way I'm
+// found in the LICENSE file.
+
+#include "content/common/gpu/media/video_decode_accelerator_mac.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 {
+ 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_;
+};
+
+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();
+ if (!io_surface_support)
+ return false;
+
+ CFTypeRef io_surface =
+ io_surface_support->CVPixelBufferGetIOSurface(image);
+ if (!io_surface)
+ 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);
+ glDisable(GL_TEXTURE_RECTANGLE_ARB);
+ if (glGetError() != GL_NO_ERROR)
+ return false;
+
+ return true;
+}
+
+} // namespace
+
+VideoDecodeAcceleratorMac::VideoDecodeAcceleratorMac(
+ 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 VideoDecodeAcceleratorMac::SetGLContext(void* gl_context) {
+ cgl_context_ = static_cast<CGLContextObj>(gl_context);
+}
+
+bool VideoDecodeAcceleratorMac::SetConfigInfo(
+ 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)
+ return false;
+ return true;
+}
+
+bool VideoDecodeAcceleratorMac::Initialize(media::VideoCodecProfile profile) {
+ if (client_)
+ client_->NotifyInitializeDone();
+ return true;
+}
+
+void VideoDecodeAcceleratorMac::Decode(
+ const media::BitstreamBuffer& bitstream_buffer) {
+ base::SharedMemory memory(bitstream_buffer.handle(), true);
+ if (!memory.Map(bitstream_buffer.size())) {
+ CHECK(false);
+ return;
+ }
+
+ size_t buffer_size = bitstream_buffer.size();
+ if (buffer_size < nalu_len_field_size_ + 1) {
+ if (client_)
+ client_->NotifyEndOfBitstreamBuffer(bitstream_buffer.id());
+ return;
+ }
+
+ // The decoder can only handle slice types (1-5).
+ 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) {
+ 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);
+ 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;
+ }
+
+ vda_->Decode(bytes->front(), bytes->size(),
+ base::Bind(&VideoDecodeAcceleratorMac::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 VideoDecodeAcceleratorMac::AssignPictureBuffers(
+ const std::vector<media::PictureBuffer>& buffers) {
+ available_pictures_.insert(
+ available_pictures_.end(), buffers.begin(), buffers.end());
+ SendImages();
+}
+
+void VideoDecodeAcceleratorMac::ReusePictureBuffer(int32 picture_buffer_id) {
+ std::map<int32, PendingPictureInfo>::iterator it =
+ pending_pictures_.find(picture_buffer_id);
+ DCHECK(it != pending_pictures_.end());
+ PendingPictureInfo info = it->second;
+ pending_pictures_.erase(it);
+ available_pictures_.push_back(info.picture_buffer);
+ SendImages();
+}
+
+void VideoDecodeAcceleratorMac::Flush() {
+ vda_->Flush(true);
+ MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+ &VideoDecodeAcceleratorMac::NotifyFlushDone, this));
+}
+
+void VideoDecodeAcceleratorMac::Reset() {
+ vda_->Flush(false);
+ MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+ &VideoDecodeAcceleratorMac::NotifyResetDone, this));
+}
+
+void VideoDecodeAcceleratorMac::Destroy() {
+ vda_->Destroy();
+ vda_ = NULL;
+ client_ = NULL;
+}
+
+VideoDecodeAcceleratorMac::~VideoDecodeAcceleratorMac() {
+}
+
+void VideoDecodeAcceleratorMac::OnFrameReady(
+ int32 bitstream_buffer_id,
+ scoped_refptr<base::RefCountedBytes> bytes,
+ CVImageBufferRef image,
+ int status) {
+ if (image) {
+ DecodedImageInfo info;
+ info.image = image;
+ info.bitstream_buffer_id = bitstream_buffer_id;
+ decoded_images_.push_back(info);
+ SendImages();
+ }
+ if (client_)
+ client_->NotifyEndOfBitstreamBuffer(bitstream_buffer_id);
+}
+
+void VideoDecodeAcceleratorMac::SendImages() {
+ 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();
+ PendingPictureInfo pending_info(picture_buffer, info.image);
+ pending_pictures_.insert(std::pair<int, PendingPictureInfo>(
+ picture_buffer.id(), pending_info));
+ media::Picture picture(picture_buffer.id(), info.bitstream_buffer_id);
+ if (client_)
+ client_->PictureReady(picture);
+}
+
+void VideoDecodeAcceleratorMac::NotifyFlushDone() {
+ if (client_)
+ client_->NotifyFlushDone();
+}
+
+void VideoDecodeAcceleratorMac::NotifyResetDone() {
+ decoded_images_.clear();
+ if (client_)
+ client_->NotifyResetDone();
+}
+
+VideoDecodeAcceleratorMac::PendingPictureInfo::PendingPictureInfo(
+ media::PictureBuffer pic,
+ CVImageBufferRef image)
+ : picture_buffer(pic.id(), pic.size(), pic.texture_id()),
+ image(image) {
+}
+
+VideoDecodeAcceleratorMac::PendingPictureInfo::~PendingPictureInfo() {
+}
+
+VideoDecodeAcceleratorMac::DecodedImageInfo::DecodedImageInfo() {
+}
+
+VideoDecodeAcceleratorMac::DecodedImageInfo::~DecodedImageInfo() {
+}

Powered by Google App Engine
This is Rietveld 408576698