| // Copyright 2016 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 "media/mojo/common/mojo_shared_buffer_video_frame.h" |
| |
| #include "base/bind.h" |
| #include "base/callback.h" |
| #include "base/compiler_specific.h" |
| #include "base/logging.h" |
| |
| namespace media { |
| |
| // static |
| scoped_refptr<MojoSharedBufferVideoFrame> |
| MojoSharedBufferVideoFrame::CreateDefaultI420(const gfx::Size& dimensions, |
| base::TimeDelta timestamp) { |
| const VideoPixelFormat format = PIXEL_FORMAT_I420; |
| const gfx::Rect visible_rect(dimensions); |
| |
| // Since we're allocating memory for the new frame, pad the requested |
| // size if necessary so that the requested size does line up on sample |
| // boundaries. See related discussion in VideoFrame::CreateFrameInternal(). |
| const gfx::Size coded_size = DetermineAlignedSize(format, dimensions); |
| if (!IsValidConfig(format, STORAGE_MOJO_SHARED_BUFFER, coded_size, |
| visible_rect, dimensions)) { |
| LOG(DFATAL) << __func__ << " Invalid config. " |
| << ConfigToString(format, STORAGE_MOJO_SHARED_BUFFER, |
| dimensions, visible_rect, dimensions); |
| return nullptr; |
| } |
| |
| // Allocate a shared memory buffer big enough to hold the desired frame. |
| const size_t allocation_size = VideoFrame::AllocationSize(format, coded_size); |
| mojo::ScopedSharedBufferHandle handle = |
| mojo::SharedBufferHandle::Create(allocation_size); |
| if (!handle.is_valid()) |
| return nullptr; |
| |
| // Create and initialize the frame. As this is I420 format, the U and V |
| // planes have samples for each 2x2 block. The memory is laid out as follows: |
| // - Yplane, full size (each element represents a 1x1 block) |
| // - Uplane, quarter size (each element represents a 2x2 block) |
| // - Vplane, quarter size (each element represents a 2x2 block) |
| DCHECK((coded_size.width() % 2 == 0) && (coded_size.height() % 2 == 0)); |
| return Create(format, coded_size, visible_rect, dimensions, std::move(handle), |
| allocation_size, 0 /* y_offset */, coded_size.GetArea(), |
| coded_size.GetArea() * 5 / 4, coded_size.width(), |
| coded_size.width() / 2, coded_size.width() / 2, timestamp); |
| } |
| |
| // static |
| scoped_refptr<MojoSharedBufferVideoFrame> MojoSharedBufferVideoFrame::Create( |
| VideoPixelFormat format, |
| const gfx::Size& coded_size, |
| const gfx::Rect& visible_rect, |
| const gfx::Size& natural_size, |
| mojo::ScopedSharedBufferHandle handle, |
| size_t data_size, |
| size_t y_offset, |
| size_t u_offset, |
| size_t v_offset, |
| int32_t y_stride, |
| int32_t u_stride, |
| int32_t v_stride, |
| base::TimeDelta timestamp) { |
| if (!IsValidConfig(format, STORAGE_MOJO_SHARED_BUFFER, coded_size, |
| visible_rect, natural_size)) { |
| LOG(DFATAL) << __func__ << " Invalid config. " |
| << ConfigToString(format, STORAGE_MOJO_SHARED_BUFFER, |
| coded_size, visible_rect, natural_size); |
| return nullptr; |
| } |
| |
| // Now allocate the frame and initialize it. |
| scoped_refptr<MojoSharedBufferVideoFrame> frame( |
| new MojoSharedBufferVideoFrame(format, coded_size, visible_rect, |
| natural_size, std::move(handle), data_size, |
| timestamp)); |
| if (!frame->Init(y_stride, u_stride, v_stride, y_offset, u_offset, v_offset)) |
| return nullptr; |
| |
| return frame; |
| } |
| |
| MojoSharedBufferVideoFrame::MojoSharedBufferVideoFrame( |
| VideoPixelFormat format, |
| const gfx::Size& coded_size, |
| const gfx::Rect& visible_rect, |
| const gfx::Size& natural_size, |
| mojo::ScopedSharedBufferHandle handle, |
| size_t mapped_size, |
| base::TimeDelta timestamp) |
| : VideoFrame(format, |
| STORAGE_MOJO_SHARED_BUFFER, |
| coded_size, |
| visible_rect, |
| natural_size, |
| timestamp), |
| shared_buffer_handle_(std::move(handle)), |
| shared_buffer_size_(mapped_size) { |
| DCHECK(shared_buffer_handle_.is_valid()); |
| } |
| |
| bool MojoSharedBufferVideoFrame::Init(int32_t y_stride, |
| int32_t u_stride, |
| int32_t v_stride, |
| size_t y_offset, |
| size_t u_offset, |
| size_t v_offset) { |
| DCHECK(!shared_buffer_mapping_); |
| shared_buffer_mapping_ = shared_buffer_handle_->Map(shared_buffer_size_); |
| if (!shared_buffer_mapping_) |
| return false; |
| |
| set_stride(kYPlane, y_stride); |
| set_stride(kUPlane, u_stride); |
| set_stride(kVPlane, v_stride); |
| offsets_[kYPlane] = y_offset; |
| offsets_[kUPlane] = u_offset; |
| offsets_[kVPlane] = v_offset; |
| set_data(kYPlane, shared_buffer_data() + y_offset); |
| set_data(kUPlane, shared_buffer_data() + u_offset); |
| set_data(kVPlane, shared_buffer_data() + v_offset); |
| return true; |
| } |
| |
| MojoSharedBufferVideoFrame::~MojoSharedBufferVideoFrame() { |
| // Call |mojo_shared_buffer_done_cb_| to take ownership of |
| // |shared_buffer_handle_|. |
| if (!mojo_shared_buffer_done_cb_.is_null()) |
| mojo_shared_buffer_done_cb_.Run(std::move(shared_buffer_handle_), |
| shared_buffer_size_); |
| } |
| |
| size_t MojoSharedBufferVideoFrame::PlaneOffset(size_t plane) const { |
| DCHECK(IsValidPlane(plane, format())); |
| return offsets_[plane]; |
| } |
| |
| void MojoSharedBufferVideoFrame::SetMojoSharedBufferDoneCB( |
| const MojoSharedBufferDoneCB& mojo_shared_buffer_done_cb) { |
| mojo_shared_buffer_done_cb_ = mojo_shared_buffer_done_cb; |
| } |
| |
| const mojo::SharedBufferHandle& MojoSharedBufferVideoFrame::Handle() const { |
| return shared_buffer_handle_.get(); |
| } |
| |
| size_t MojoSharedBufferVideoFrame::MappedSize() const { |
| return shared_buffer_size_; |
| } |
| |
| } // namespace media |