// 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. #ifndef MEDIA_BASE_DECODER_BUFFER_H_ #define MEDIA_BASE_DECODER_BUFFER_H_ #include #include #include #include #include #include "base/check.h" #include "base/memory/read_only_shared_memory_region.h" #include "base/memory/ref_counted.h" #include "base/memory/shared_memory_mapping.h" #include "base/memory/unsafe_shared_memory_region.h" #include "base/time/time.h" #include "build/build_config.h" #include "media/base/decrypt_config.h" #include "media/base/media_export.h" #include "media/base/timestamp_constants.h" namespace media { // A specialized buffer for interfacing with audio / video decoders. // // Also includes decoder specific functionality for decryption. // // NOTE: It is illegal to call any method when end_of_stream() is true. class MEDIA_EXPORT DecoderBuffer : public base::RefCountedThreadSafe { public: enum { kPaddingSize = 64, #if defined(ARCH_CPU_ARM_FAMILY) kAlignmentSize = 16 #else kAlignmentSize = 32 #endif }; using DiscardPadding = std::pair; struct MEDIA_EXPORT TimeInfo { TimeInfo(); ~TimeInfo(); TimeInfo(const TimeInfo&); TimeInfo& operator=(const TimeInfo&); // Presentation time of the frame. base::TimeDelta timestamp; // Presentation duration of the frame. base::TimeDelta duration; // Duration of (audio) samples from the beginning and end of this frame // which should be discarded after decoding. A value of kInfiniteDuration // for the first value indicates the entire frame should be discarded; the // second value must be base::TimeDelta() in this case. DiscardPadding discard_padding; }; // Allocates buffer with |size| >= 0. |is_key_frame_| will default to false. explicit DecoderBuffer(size_t size); DecoderBuffer(const DecoderBuffer&) = delete; DecoderBuffer& operator=(const DecoderBuffer&) = delete; // Create a DecoderBuffer whose |data_| is copied from |data|. |data| must not // be NULL and |size| >= 0. The buffer's |is_key_frame_| will default to // false. static scoped_refptr CopyFrom(const uint8_t* data, size_t size); // Create a DecoderBuffer whose |data_| is copied from |data| and |side_data_| // is copied from |side_data|. Data pointers must not be NULL and sizes must // be >= 0. The buffer's |is_key_frame_| will default to false. static scoped_refptr CopyFrom(const uint8_t* data, size_t size, const uint8_t* side_data, size_t side_data_size); // Create a DecoderBuffer where data() of |size| bytes resides within the heap // as byte array. The buffer's |is_key_frame_| will default to false. // // Ownership of |data| is transferred to the buffer. static scoped_refptr FromArray(std::unique_ptr data, size_t size); // Create a DecoderBuffer where data() of |size| bytes resides within the // memory referred to by |region| at non-negative offset |offset|. The // buffer's |is_key_frame_| will default to false. // // The shared memory will be mapped read-only. // // If mapping fails, nullptr will be returned. static scoped_refptr FromSharedMemoryRegion( base::UnsafeSharedMemoryRegion region, uint64_t offset, size_t size); // Create a DecoderBuffer where data() of |size| bytes resides within the // ReadOnlySharedMemoryRegion referred to by |mapping| at non-negative offset // |offset|. The buffer's |is_key_frame_| will default to false. // // Ownership of |region| is transferred to the buffer. static scoped_refptr FromSharedMemoryRegion( base::ReadOnlySharedMemoryRegion region, uint64_t offset, size_t size); // Create a DecoderBuffer indicating we've reached end of stream. // // Calling any method other than end_of_stream() on the resulting buffer // is disallowed. static scoped_refptr CreateEOSBuffer(); const TimeInfo& time_info() const { DCHECK(!end_of_stream()); return time_info_; } base::TimeDelta timestamp() const { DCHECK(!end_of_stream()); return time_info_.timestamp; } // TODO(dalecurtis): This should be renamed at some point, but to avoid a yak // shave keep as a virtual with hacker_style() for now. virtual void set_timestamp(base::TimeDelta timestamp); base::TimeDelta duration() const { DCHECK(!end_of_stream()); return time_info_.duration; } void set_duration(base::TimeDelta duration) { DCHECK(!end_of_stream()); DCHECK(duration == kNoTimestamp || (duration >= base::TimeDelta() && duration != kInfiniteDuration)) << duration.InSecondsF(); time_info_.duration = duration; } const uint8_t* data() const { DCHECK(!end_of_stream()); if (read_only_mapping_.IsValid()) return read_only_mapping_.GetMemoryAs(); if (writable_mapping_.IsValid()) return writable_mapping_.GetMemoryAs(); return data_.get(); } // TODO(sandersd): Remove writable_data(). https://crbug.com/834088 uint8_t* writable_data() const { DCHECK(!end_of_stream()); DCHECK(!read_only_mapping_.IsValid()); DCHECK(!writable_mapping_.IsValid()); return data_.get(); } size_t data_size() const { DCHECK(!end_of_stream()); return size_; } const uint8_t* side_data() const { DCHECK(!end_of_stream()); return side_data_.get(); } size_t side_data_size() const { DCHECK(!end_of_stream()); return side_data_size_; } const DiscardPadding& discard_padding() const { DCHECK(!end_of_stream()); return time_info_.discard_padding; } void set_discard_padding(const DiscardPadding& discard_padding) { DCHECK(!end_of_stream()); time_info_.discard_padding = discard_padding; } // Returns DecryptConfig associated with |this|. Returns null iff |this| is // not encrypted. const DecryptConfig* decrypt_config() const { DCHECK(!end_of_stream()); return decrypt_config_.get(); } void set_decrypt_config(std::unique_ptr decrypt_config) { DCHECK(!end_of_stream()); decrypt_config_ = std::move(decrypt_config); } // If there's no data in this buffer, it represents end of stream. bool end_of_stream() const { return !read_only_mapping_.IsValid() && !writable_mapping_.IsValid() && !data_; } bool is_key_frame() const { DCHECK(!end_of_stream()); return is_key_frame_; } void set_is_key_frame(bool is_key_frame) { DCHECK(!end_of_stream()); is_key_frame_ = is_key_frame; } // Returns true if all fields in |buffer| matches this buffer // including |data_| and |side_data_|. bool MatchesForTesting(const DecoderBuffer& buffer) const; // As above, except that |data_| and |side_data_| are not compared. bool MatchesMetadataForTesting(const DecoderBuffer& buffer) const; // Returns a human-readable string describing |*this|. std::string AsHumanReadableString(bool verbose = false) const; // Replaces any existing side data with data copied from |side_data|. void CopySideDataFrom(const uint8_t* side_data, size_t side_data_size); protected: friend class base::RefCountedThreadSafe; // Allocates a buffer of size |size| >= 0 and copies |data| into it. If |data| // is NULL then |data_| is set to NULL and |buffer_size_| to 0. // |is_key_frame_| will default to false. DecoderBuffer(const uint8_t* data, size_t size, const uint8_t* side_data, size_t side_data_size); DecoderBuffer(std::unique_ptr data, size_t size); DecoderBuffer(base::ReadOnlySharedMemoryMapping mapping, size_t size); DecoderBuffer(base::WritableSharedMemoryMapping mapping, size_t size); virtual ~DecoderBuffer(); // Encoded data, if it is stored on the heap. std::unique_ptr data_; private: TimeInfo time_info_; // Size of the encoded data. size_t size_; // Side data. Used for alpha channel in VPx, and for text cues. size_t side_data_size_ = 0; std::unique_ptr side_data_; // Encoded data, if it is stored in a read-only shared memory mapping. base::ReadOnlySharedMemoryMapping read_only_mapping_; // Encoded data, if it is stored in a writable shared memory mapping. base::WritableSharedMemoryMapping writable_mapping_; // Encryption parameters for the encoded data. std::unique_ptr decrypt_config_; // Whether the frame was marked as a keyframe in the container. bool is_key_frame_ = false; // Constructor helper method for memory allocations. void Initialize(); }; } // namespace media #endif // MEDIA_BASE_DECODER_BUFFER_H_