Chromium Code Reviews| Index: media/cdm/ppapi/cdm_helpers.h |
| diff --git a/media/cdm/ppapi/cdm_helpers.h b/media/cdm/ppapi/cdm_helpers.h |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..4e08510936254e22cfa8c316a9966365a13b3ffe |
| --- /dev/null |
| +++ b/media/cdm/ppapi/cdm_helpers.h |
| @@ -0,0 +1,314 @@ |
| +// Copyright 2013 The Chromium Authors. All rights reserved. |
|
xhwang
2013/10/15 20:42:33
This file is copied from cdm_wrapper.cc, with smal
|
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#ifndef MEDIA_CDM_PPAPI_CDM_HELPERS_H_ |
| +#define MEDIA_CDM_PPAPI_CDM_HELPERS_H_ |
| + |
| +#include <map> |
| +#include <utility> |
| + |
| +#include "base/basictypes.h" |
| +#include "base/compiler_specific.h" |
| +#include "build/build_config.h" |
| +#include "media/cdm/ppapi/api/content_decryption_module.h" |
| +#include "ppapi/c/pp_errors.h" |
| +#include "ppapi/c/pp_stdint.h" |
| +#include "ppapi/cpp/core.h" |
| +#include "ppapi/cpp/dev/buffer_dev.h" |
| +#include "ppapi/cpp/instance.h" |
| +#include "ppapi/cpp/logging.h" |
| +#include "ppapi/cpp/module.h" |
|
xhwang
2013/10/15 20:42:33
Includes are trimmed to reflect what we use.
|
| + |
| +namespace media { |
| + |
| +// cdm::Buffer implementation that provides access to memory owned by a |
| +// pp::Buffer_Dev. |
| +// This class holds a reference to the Buffer_Dev throughout its lifetime. |
| +// TODO(xhwang): Find a better name. It's confusing to have PpbBuffer, |
| +// pp::Buffer_Dev and PPB_Buffer_Dev. |
| +class PpbBuffer : public cdm::Buffer { |
| + public: |
| + static PpbBuffer* Create(const pp::Buffer_Dev& buffer, uint32_t buffer_id) { |
| + PP_DCHECK(buffer.data()); |
| + PP_DCHECK(buffer.size()); |
| + PP_DCHECK(buffer_id); |
| + return new PpbBuffer(buffer, buffer_id); |
| + } |
| + |
| + // cdm::Buffer implementation. |
| + virtual void Destroy() OVERRIDE { delete this; } |
| + |
| + virtual int32_t Capacity() const OVERRIDE { return buffer_.size(); } |
| + |
| + virtual uint8_t* Data() OVERRIDE { |
| + return static_cast<uint8_t*>(buffer_.data()); |
| + } |
| + |
| + virtual void SetSize(int32_t size) OVERRIDE { |
| + PP_DCHECK(size >= 0); |
| + PP_DCHECK(size < Capacity()); |
| + if (size < 0 || size > Capacity()) { |
| + size_ = 0; |
| + return; |
| + } |
| + |
| + size_ = size; |
| + } |
| + |
| + virtual int32_t Size() const OVERRIDE { return size_; } |
| + |
| + pp::Buffer_Dev buffer_dev() const { return buffer_; } |
| + |
| + uint32_t buffer_id() const { return buffer_id_; } |
| + |
| + private: |
| + PpbBuffer(pp::Buffer_Dev buffer, uint32_t buffer_id) |
| + : buffer_(buffer), |
| + buffer_id_(buffer_id), |
| + size_(0) {} |
| + virtual ~PpbBuffer() {} |
| + |
| + pp::Buffer_Dev buffer_; |
| + uint32_t buffer_id_; |
| + int32_t size_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(PpbBuffer); |
| +}; |
| + |
| +class PpbBufferAllocator { |
| + public: |
| + explicit PpbBufferAllocator(pp::Instance* instance) |
| + : instance_(instance), |
| + next_buffer_id_(1) {} |
| + ~PpbBufferAllocator() {} |
| + |
| + cdm::Buffer* Allocate(int32_t capacity); |
| + |
| + // Releases the buffer with |buffer_id|. A buffer can be recycled after |
| + // it is released. |
| + void Release(uint32_t buffer_id); |
| + |
| + private: |
| + typedef std::map<uint32_t, pp::Buffer_Dev> AllocatedBufferMap; |
| + typedef std::multimap<int, std::pair<uint32_t, pp::Buffer_Dev> > |
| + FreeBufferMap; |
| + |
| + // Always pad new allocated buffer so that we don't need to reallocate |
| + // buffers frequently if requested sizes fluctuate slightly. |
| + static const int kBufferPadding = 512; |
| + |
| + // Maximum number of free buffers we can keep when allocating new buffers. |
| + static const int kFreeLimit = 3; |
| + |
| + pp::Buffer_Dev AllocateNewBuffer(int capacity); |
| + |
| + pp::Instance* const instance_; |
| + uint32_t next_buffer_id_; |
| + AllocatedBufferMap allocated_buffers_; |
| + FreeBufferMap free_buffers_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(PpbBufferAllocator); |
| +}; |
| + |
| +cdm::Buffer* PpbBufferAllocator::Allocate(int32_t capacity) { |
| + PP_DCHECK(pp::Module::Get()->core()->IsMainThread()); |
|
xhwang
2013/10/15 20:42:33
This was IsMainThread() in cdm_wrapper.cc. I am no
|
| + |
| + if (capacity <= 0) |
| + return NULL; |
| + |
| + pp::Buffer_Dev buffer; |
| + uint32_t buffer_id = 0; |
| + |
| + // Reuse a buffer in the free list if there is one that fits |capacity|. |
| + // Otherwise, create a new one. |
| + FreeBufferMap::iterator found = free_buffers_.lower_bound(capacity); |
| + if (found == free_buffers_.end()) { |
| + // TODO(xhwang): Report statistics about how many new buffers are allocated. |
| + buffer = AllocateNewBuffer(capacity); |
| + if (buffer.is_null()) |
| + return NULL; |
| + buffer_id = next_buffer_id_++; |
| + } else { |
| + buffer = found->second.second; |
| + buffer_id = found->second.first; |
| + free_buffers_.erase(found); |
| + } |
| + |
| + allocated_buffers_.insert(std::make_pair(buffer_id, buffer)); |
| + |
| + return PpbBuffer::Create(buffer, buffer_id); |
| +} |
| + |
| +void PpbBufferAllocator::Release(uint32_t buffer_id) { |
| + if (!buffer_id) |
| + return; |
| + |
| + AllocatedBufferMap::iterator found = allocated_buffers_.find(buffer_id); |
| + if (found == allocated_buffers_.end()) |
| + return; |
| + |
| + pp::Buffer_Dev& buffer = found->second; |
| + free_buffers_.insert( |
| + std::make_pair(buffer.size(), std::make_pair(buffer_id, buffer))); |
| + |
| + allocated_buffers_.erase(found); |
| +} |
| + |
| +pp::Buffer_Dev PpbBufferAllocator::AllocateNewBuffer(int32_t capacity) { |
| + // Destroy the smallest buffer before allocating a new bigger buffer if the |
| + // number of free buffers exceeds a limit. This mechanism helps avoid ending |
| + // up with too many small buffers, which could happen if the size to be |
| + // allocated keeps increasing. |
| + if (free_buffers_.size() >= static_cast<uint32_t>(kFreeLimit)) |
| + free_buffers_.erase(free_buffers_.begin()); |
| + |
| + // Creation of pp::Buffer_Dev is expensive! It involves synchronous IPC calls. |
| + // That's why we try to avoid AllocateNewBuffer() as much as we can. |
| + return pp::Buffer_Dev(instance_, capacity + kBufferPadding); |
| +} |
| + |
| +class DecryptedBlockImpl : public cdm::DecryptedBlock { |
| + public: |
| + DecryptedBlockImpl() : buffer_(NULL), timestamp_(0) {} |
| + virtual ~DecryptedBlockImpl() { if (buffer_) buffer_->Destroy(); } |
| + |
| + virtual void SetDecryptedBuffer(cdm::Buffer* buffer) OVERRIDE { |
| + buffer_ = static_cast<PpbBuffer*>(buffer); |
| + } |
| + virtual cdm::Buffer* DecryptedBuffer() OVERRIDE { return buffer_; } |
| + |
| + virtual void SetTimestamp(int64_t timestamp) OVERRIDE { |
| + timestamp_ = timestamp; |
| + } |
| + virtual int64_t Timestamp() const OVERRIDE { return timestamp_; } |
| + |
| + private: |
| + PpbBuffer* buffer_; |
| + int64_t timestamp_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(DecryptedBlockImpl); |
| +}; |
| + |
| +class VideoFrameImpl : public cdm::VideoFrame { |
| + public: |
| + VideoFrameImpl(); |
| + virtual ~VideoFrameImpl(); |
| + |
| + virtual void SetFormat(cdm::VideoFormat format) OVERRIDE { |
| + format_ = format; |
| + } |
| + virtual cdm::VideoFormat Format() const OVERRIDE { return format_; } |
| + |
| + virtual void SetSize(cdm::Size size) OVERRIDE { size_ = size; } |
| + virtual cdm::Size Size() const OVERRIDE { return size_; } |
| + |
| + virtual void SetFrameBuffer(cdm::Buffer* frame_buffer) OVERRIDE { |
| + frame_buffer_ = static_cast<PpbBuffer*>(frame_buffer); |
| + } |
| + virtual cdm::Buffer* FrameBuffer() OVERRIDE { return frame_buffer_; } |
| + |
| + virtual void SetPlaneOffset(cdm::VideoFrame::VideoPlane plane, |
| + int32_t offset) OVERRIDE { |
| + PP_DCHECK(0 <= plane && plane < kMaxPlanes); |
| + PP_DCHECK(offset >= 0); |
| + plane_offsets_[plane] = offset; |
| + } |
| + virtual int32_t PlaneOffset(VideoPlane plane) OVERRIDE { |
| + PP_DCHECK(0 <= plane && plane < kMaxPlanes); |
| + return plane_offsets_[plane]; |
| + } |
| + |
| + virtual void SetStride(VideoPlane plane, int32_t stride) OVERRIDE { |
| + PP_DCHECK(0 <= plane && plane < kMaxPlanes); |
| + strides_[plane] = stride; |
| + } |
| + virtual int32_t Stride(VideoPlane plane) OVERRIDE { |
| + PP_DCHECK(0 <= plane && plane < kMaxPlanes); |
| + return strides_[plane]; |
| + } |
| + |
| + virtual void SetTimestamp(int64_t timestamp) OVERRIDE { |
| + timestamp_ = timestamp; |
| + } |
| + virtual int64_t Timestamp() const OVERRIDE { return timestamp_; } |
| + |
| + private: |
| + // The video buffer format. |
| + cdm::VideoFormat format_; |
| + |
| + // Width and height of the video frame. |
| + cdm::Size size_; |
| + |
| + // The video frame buffer. |
| + PpbBuffer* frame_buffer_; |
| + |
| + // Array of data pointers to each plane in the video frame buffer. |
| + int32_t plane_offsets_[kMaxPlanes]; |
| + |
| + // Array of strides for each plane, typically greater or equal to the width |
| + // of the surface divided by the horizontal sampling period. Note that |
| + // strides can be negative. |
| + int32_t strides_[kMaxPlanes]; |
| + |
| + // Presentation timestamp in microseconds. |
| + int64_t timestamp_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(VideoFrameImpl); |
| +}; |
| + |
| +VideoFrameImpl::VideoFrameImpl() |
| + : format_(cdm::kUnknownVideoFormat), |
| + frame_buffer_(NULL), |
| + timestamp_(0) { |
| + for (int32_t i = 0; i < kMaxPlanes; ++i) { |
| + plane_offsets_[i] = 0; |
| + strides_[i] = 0; |
| + } |
| +} |
| + |
| +VideoFrameImpl::~VideoFrameImpl() { |
| + if (frame_buffer_) |
| + frame_buffer_->Destroy(); |
| +} |
| + |
| +class AudioFramesImpl : public cdm::AudioFrames_1, |
| + public cdm::AudioFrames_2 { |
| + public: |
| + AudioFramesImpl() : buffer_(NULL), format_(cdm::kAudioFormatS16) {} |
| + virtual ~AudioFramesImpl() { |
| + if (buffer_) |
| + buffer_->Destroy(); |
| + } |
| + |
| + // AudioFrames implementation. |
| + virtual void SetFrameBuffer(cdm::Buffer* buffer) OVERRIDE { |
| + buffer_ = static_cast<PpbBuffer*>(buffer); |
| + } |
| + virtual cdm::Buffer* FrameBuffer() OVERRIDE { |
| + return buffer_; |
| + } |
| + virtual void SetFormat(cdm::AudioFormat format) OVERRIDE { |
| + format_ = format; |
| + } |
| + virtual cdm::AudioFormat Format() const OVERRIDE { |
| + return format_; |
| + } |
| + |
| + cdm::Buffer* PassFrameBuffer() { |
|
xhwang
2013/10/15 20:42:33
Added this function so that we can transfer owners
|
| + PpbBuffer* temp_buffer = buffer_; |
| + if (buffer_) |
| + buffer_ = NULL; |
| + return temp_buffer; |
| + } |
| + |
| + private: |
| + PpbBuffer* buffer_; |
| + cdm::AudioFormat format_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(AudioFramesImpl); |
| +}; |
| + |
| +} // namespace media |
| + |
| +#endif // MEDIA_CDM_PPAPI_CDM_HELPERS_H_ |