| // Copyright 2014 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/media_type_converters.h" |
| |
| #include <stddef.h> |
| #include <stdint.h> |
| |
| #include "base/memory/ptr_util.h" |
| #include "base/numerics/safe_conversions.h" |
| #include "media/base/audio_buffer.h" |
| #include "media/base/audio_decoder_config.h" |
| #include "media/base/cdm_config.h" |
| #include "media/base/cdm_key_information.h" |
| #include "media/base/decoder_buffer.h" |
| #include "media/base/decrypt_config.h" |
| #include "media/base/encryption_scheme.h" |
| #include "media/base/subsample_entry.h" |
| #include "media/base/video_decoder_config.h" |
| #include "media/base/video_frame.h" |
| #include "media/mojo/common/mojo_shared_buffer_video_frame.h" |
| #include "mojo/public/cpp/system/buffer.h" |
| |
| namespace mojo { |
| |
| template <> |
| struct TypeConverter<media::mojom::PatternPtr, |
| media::EncryptionScheme::Pattern> { |
| static media::mojom::PatternPtr Convert( |
| const media::EncryptionScheme::Pattern& input); |
| }; |
| template <> |
| struct TypeConverter<media::EncryptionScheme::Pattern, |
| media::mojom::PatternPtr> { |
| static media::EncryptionScheme::Pattern Convert( |
| const media::mojom::PatternPtr& input); |
| }; |
| |
| // static |
| media::mojom::PatternPtr |
| TypeConverter<media::mojom::PatternPtr, media::EncryptionScheme::Pattern>:: |
| Convert(const media::EncryptionScheme::Pattern& input) { |
| media::mojom::PatternPtr mojo_pattern(media::mojom::Pattern::New()); |
| mojo_pattern->encrypt_blocks = input.encrypt_blocks(); |
| mojo_pattern->skip_blocks = input.skip_blocks(); |
| return mojo_pattern; |
| } |
| |
| // static |
| media::EncryptionScheme::Pattern TypeConverter< |
| media::EncryptionScheme::Pattern, |
| media::mojom::PatternPtr>::Convert(const media::mojom::PatternPtr& input) { |
| return media::EncryptionScheme::Pattern(input->encrypt_blocks, |
| input->skip_blocks); |
| } |
| |
| // static |
| media::mojom::EncryptionSchemePtr TypeConverter< |
| media::mojom::EncryptionSchemePtr, |
| media::EncryptionScheme>::Convert(const media::EncryptionScheme& input) { |
| media::mojom::EncryptionSchemePtr mojo_encryption_scheme( |
| media::mojom::EncryptionScheme::New()); |
| mojo_encryption_scheme->mode = input.mode(); |
| mojo_encryption_scheme->pattern = |
| media::mojom::Pattern::From(input.pattern()); |
| return mojo_encryption_scheme; |
| } |
| |
| // static |
| media::EncryptionScheme |
| TypeConverter<media::EncryptionScheme, media::mojom::EncryptionSchemePtr>:: |
| Convert(const media::mojom::EncryptionSchemePtr& input) { |
| return media::EncryptionScheme( |
| input->mode, input->pattern.To<media::EncryptionScheme::Pattern>()); |
| } |
| |
| // static |
| media::mojom::DecryptConfigPtr |
| TypeConverter<media::mojom::DecryptConfigPtr, media::DecryptConfig>::Convert( |
| const media::DecryptConfig& input) { |
| media::mojom::DecryptConfigPtr mojo_decrypt_config( |
| media::mojom::DecryptConfig::New()); |
| mojo_decrypt_config->key_id = input.key_id(); |
| mojo_decrypt_config->iv = input.iv(); |
| mojo_decrypt_config->subsamples = input.subsamples(); |
| |
| return mojo_decrypt_config; |
| } |
| |
| // static |
| std::unique_ptr<media::DecryptConfig> |
| TypeConverter<std::unique_ptr<media::DecryptConfig>, |
| media::mojom::DecryptConfigPtr>:: |
| Convert(const media::mojom::DecryptConfigPtr& input) { |
| return base::MakeUnique<media::DecryptConfig>(input->key_id, input->iv, |
| input->subsamples); |
| } |
| |
| // static |
| media::mojom::DecoderBufferPtr |
| TypeConverter<media::mojom::DecoderBufferPtr, |
| scoped_refptr<media::DecoderBuffer>>:: |
| Convert(const scoped_refptr<media::DecoderBuffer>& input) { |
| DCHECK(input); |
| |
| media::mojom::DecoderBufferPtr mojo_buffer( |
| media::mojom::DecoderBuffer::New()); |
| if (input->end_of_stream()) { |
| mojo_buffer->is_end_of_stream = true; |
| return mojo_buffer; |
| } |
| |
| mojo_buffer->is_end_of_stream = false; |
| mojo_buffer->timestamp = input->timestamp(); |
| mojo_buffer->duration = input->duration(); |
| mojo_buffer->is_key_frame = input->is_key_frame(); |
| mojo_buffer->data_size = base::checked_cast<uint32_t>(input->data_size()); |
| mojo_buffer->front_discard = input->discard_padding().first; |
| mojo_buffer->back_discard = input->discard_padding().second; |
| mojo_buffer->splice_timestamp = input->splice_timestamp(); |
| |
| // Note: The side data is always small, so this copy is okay. |
| if (input->side_data()) { |
| DCHECK_GT(input->side_data_size(), 0u); |
| mojo_buffer->side_data.assign(input->side_data(), |
| input->side_data() + input->side_data_size()); |
| } |
| |
| if (input->decrypt_config()) { |
| mojo_buffer->decrypt_config = |
| media::mojom::DecryptConfig::From(*input->decrypt_config()); |
| } |
| |
| // TODO(dalecurtis): We intentionally do not serialize the data section of |
| // the DecoderBuffer here; this must instead be done by clients via their |
| // own DataPipe. See http://crbug.com/432960 |
| |
| return mojo_buffer; |
| } |
| |
| // static |
| scoped_refptr<media::DecoderBuffer> |
| TypeConverter<scoped_refptr<media::DecoderBuffer>, |
| media::mojom::DecoderBufferPtr>:: |
| Convert(const media::mojom::DecoderBufferPtr& input) { |
| if (input->is_end_of_stream) |
| return media::DecoderBuffer::CreateEOSBuffer(); |
| |
| scoped_refptr<media::DecoderBuffer> buffer( |
| new media::DecoderBuffer(input->data_size)); |
| |
| if (!input->side_data.empty()) |
| buffer->CopySideDataFrom(input->side_data.data(), input->side_data.size()); |
| |
| buffer->set_timestamp(input->timestamp); |
| buffer->set_duration(input->duration); |
| buffer->set_is_key_frame(input->is_key_frame); |
| |
| if (input->decrypt_config) { |
| buffer->set_decrypt_config( |
| input->decrypt_config.To<std::unique_ptr<media::DecryptConfig>>()); |
| } |
| |
| media::DecoderBuffer::DiscardPadding discard_padding(input->front_discard, |
| input->back_discard); |
| buffer->set_discard_padding(discard_padding); |
| buffer->set_splice_timestamp(input->splice_timestamp); |
| |
| // TODO(dalecurtis): We intentionally do not deserialize the data section of |
| // the DecoderBuffer here; this must instead be done by clients via their |
| // own DataPipe. See http://crbug.com/432960 |
| |
| return buffer; |
| } |
| |
| // static |
| media::mojom::AudioDecoderConfigPtr |
| TypeConverter<media::mojom::AudioDecoderConfigPtr, media::AudioDecoderConfig>:: |
| Convert(const media::AudioDecoderConfig& input) { |
| media::mojom::AudioDecoderConfigPtr config( |
| media::mojom::AudioDecoderConfig::New()); |
| config->codec = input.codec(); |
| config->sample_format = input.sample_format(); |
| config->channel_layout = input.channel_layout(); |
| config->samples_per_second = input.samples_per_second(); |
| config->extra_data = input.extra_data(); |
| config->seek_preroll = input.seek_preroll(); |
| config->codec_delay = input.codec_delay(); |
| config->encryption_scheme = |
| media::mojom::EncryptionScheme::From(input.encryption_scheme()); |
| return config; |
| } |
| |
| // static |
| media::AudioDecoderConfig |
| TypeConverter<media::AudioDecoderConfig, media::mojom::AudioDecoderConfigPtr>:: |
| Convert(const media::mojom::AudioDecoderConfigPtr& input) { |
| media::AudioDecoderConfig config; |
| config.Initialize(input->codec, input->sample_format, input->channel_layout, |
| input->samples_per_second, input->extra_data, |
| input->encryption_scheme.To<media::EncryptionScheme>(), |
| input->seek_preroll, input->codec_delay); |
| return config; |
| } |
| |
| // static |
| media::mojom::VideoDecoderConfigPtr |
| TypeConverter<media::mojom::VideoDecoderConfigPtr, media::VideoDecoderConfig>:: |
| Convert(const media::VideoDecoderConfig& input) { |
| media::mojom::VideoDecoderConfigPtr config( |
| media::mojom::VideoDecoderConfig::New()); |
| config->codec = input.codec(); |
| config->profile = input.profile(); |
| config->format = input.format(); |
| config->color_space = input.color_space(); |
| config->coded_size = input.coded_size(); |
| config->visible_rect = input.visible_rect(); |
| config->natural_size = input.natural_size(); |
| config->extra_data = input.extra_data(); |
| config->encryption_scheme = |
| media::mojom::EncryptionScheme::From(input.encryption_scheme()); |
| return config; |
| } |
| |
| // static |
| media::VideoDecoderConfig |
| TypeConverter<media::VideoDecoderConfig, media::mojom::VideoDecoderConfigPtr>:: |
| Convert(const media::mojom::VideoDecoderConfigPtr& input) { |
| media::VideoDecoderConfig config; |
| config.Initialize(input->codec, input->profile, input->format, |
| input->color_space, input->coded_size, input->visible_rect, |
| input->natural_size, input->extra_data, |
| input->encryption_scheme.To<media::EncryptionScheme>()); |
| return config; |
| } |
| |
| // static |
| media::mojom::CdmKeyInformationPtr TypeConverter< |
| media::mojom::CdmKeyInformationPtr, |
| media::CdmKeyInformation>::Convert(const media::CdmKeyInformation& input) { |
| media::mojom::CdmKeyInformationPtr info( |
| media::mojom::CdmKeyInformation::New()); |
| info->key_id = input.key_id; |
| info->status = input.status; |
| info->system_code = input.system_code; |
| return info; |
| } |
| |
| // static |
| std::unique_ptr<media::CdmKeyInformation> |
| TypeConverter<std::unique_ptr<media::CdmKeyInformation>, |
| media::mojom::CdmKeyInformationPtr>:: |
| Convert(const media::mojom::CdmKeyInformationPtr& input) { |
| return base::MakeUnique<media::CdmKeyInformation>( |
| input->key_id, input->status, input->system_code); |
| } |
| |
| // static |
| media::mojom::CdmConfigPtr |
| TypeConverter<media::mojom::CdmConfigPtr, media::CdmConfig>::Convert( |
| const media::CdmConfig& input) { |
| media::mojom::CdmConfigPtr config(media::mojom::CdmConfig::New()); |
| config->allow_distinctive_identifier = input.allow_distinctive_identifier; |
| config->allow_persistent_state = input.allow_persistent_state; |
| config->use_hw_secure_codecs = input.use_hw_secure_codecs; |
| return config; |
| } |
| |
| // static |
| media::CdmConfig |
| TypeConverter<media::CdmConfig, media::mojom::CdmConfigPtr>::Convert( |
| const media::mojom::CdmConfigPtr& input) { |
| media::CdmConfig config; |
| config.allow_distinctive_identifier = input->allow_distinctive_identifier; |
| config.allow_persistent_state = input->allow_persistent_state; |
| config.use_hw_secure_codecs = input->use_hw_secure_codecs; |
| return config; |
| } |
| |
| // static |
| media::mojom::AudioBufferPtr |
| TypeConverter<media::mojom::AudioBufferPtr, scoped_refptr<media::AudioBuffer>>:: |
| Convert(const scoped_refptr<media::AudioBuffer>& input) { |
| media::mojom::AudioBufferPtr buffer(media::mojom::AudioBuffer::New()); |
| buffer->sample_format = input->sample_format_; |
| buffer->channel_layout = input->channel_layout(); |
| buffer->channel_count = input->channel_count(); |
| buffer->sample_rate = input->sample_rate(); |
| buffer->frame_count = input->frame_count(); |
| buffer->end_of_stream = input->end_of_stream(); |
| buffer->timestamp = input->timestamp(); |
| |
| if (input->data_) { |
| DCHECK_GT(input->data_size(), 0u); |
| buffer->data.assign(input->data_.get(), |
| input->data_.get() + input->data_size_); |
| } |
| |
| return buffer; |
| } |
| |
| // static |
| scoped_refptr<media::AudioBuffer> |
| TypeConverter<scoped_refptr<media::AudioBuffer>, media::mojom::AudioBufferPtr>:: |
| Convert(const media::mojom::AudioBufferPtr& input) { |
| if (input->end_of_stream) |
| return media::AudioBuffer::CreateEOSBuffer(); |
| |
| // Setup channel pointers. AudioBuffer::CopyFrom() will only use the first |
| // one in the case of interleaved data. |
| std::vector<const uint8_t*> channel_ptrs(input->channel_count, nullptr); |
| const size_t size_per_channel = input->data.size() / input->channel_count; |
| DCHECK_EQ(0u, input->data.size() % input->channel_count); |
| for (int i = 0; i < input->channel_count; ++i) |
| channel_ptrs[i] = input->data.data() + i * size_per_channel; |
| |
| return media::AudioBuffer::CopyFrom( |
| input->sample_format, input->channel_layout, input->channel_count, |
| input->sample_rate, input->frame_count, &channel_ptrs[0], |
| input->timestamp); |
| } |
| |
| // static |
| media::mojom::VideoFramePtr |
| TypeConverter<media::mojom::VideoFramePtr, scoped_refptr<media::VideoFrame>>:: |
| Convert(const scoped_refptr<media::VideoFrame>& input) { |
| media::mojom::VideoFramePtr frame(media::mojom::VideoFrame::New()); |
| frame->end_of_stream = |
| input->metadata()->IsTrue(media::VideoFrameMetadata::END_OF_STREAM); |
| if (frame->end_of_stream) |
| return frame; |
| |
| // Handle non EOS frame. It must be a MojoSharedBufferVideoFrame. |
| // TODO(jrummell): Support other types of VideoFrame. |
| CHECK_EQ(media::VideoFrame::STORAGE_MOJO_SHARED_BUFFER, |
| input->storage_type()); |
| media::MojoSharedBufferVideoFrame* input_frame = |
| static_cast<media::MojoSharedBufferVideoFrame*>(input.get()); |
| mojo::ScopedSharedBufferHandle duplicated_handle = |
| input_frame->Handle().Clone(); |
| CHECK(duplicated_handle.is_valid()); |
| |
| frame->format = input->format(); |
| frame->coded_size = input->coded_size(); |
| frame->visible_rect = input->visible_rect(); |
| frame->natural_size = input->natural_size(); |
| frame->timestamp = input->timestamp(); |
| |
| media::mojom::SharedBufferVideoFrameDataPtr data = |
| media::mojom::SharedBufferVideoFrameData::New(); |
| data->frame_data = std::move(duplicated_handle); |
| data->frame_data_size = input_frame->MappedSize(); |
| data->y_stride = input_frame->stride(media::VideoFrame::kYPlane); |
| data->u_stride = input_frame->stride(media::VideoFrame::kUPlane); |
| data->v_stride = input_frame->stride(media::VideoFrame::kVPlane); |
| data->y_offset = input_frame->PlaneOffset(media::VideoFrame::kYPlane); |
| data->u_offset = input_frame->PlaneOffset(media::VideoFrame::kUPlane); |
| data->v_offset = input_frame->PlaneOffset(media::VideoFrame::kVPlane); |
| |
| frame->data = media::mojom::VideoFrameData::New(); |
| frame->data->set_shared_buffer_data(std::move(data)); |
| return frame; |
| } |
| |
| // static |
| scoped_refptr<media::VideoFrame> |
| TypeConverter<scoped_refptr<media::VideoFrame>, media::mojom::VideoFramePtr>:: |
| Convert(const media::mojom::VideoFramePtr& input) { |
| if (input->end_of_stream) |
| return media::VideoFrame::CreateEOSFrame(); |
| |
| // Handle non EOS frame. It must be a MojoSharedBufferVideoFrame. |
| // TODO(jrummell): Support other types of VideoFrame. |
| DCHECK(input->data->is_shared_buffer_data()); |
| const media::mojom::SharedBufferVideoFrameDataPtr& data = |
| input->data->get_shared_buffer_data(); |
| |
| return media::MojoSharedBufferVideoFrame::Create( |
| input->format, input->coded_size, input->visible_rect, |
| input->natural_size, std::move(data->frame_data), |
| base::saturated_cast<size_t>(data->frame_data_size), |
| base::saturated_cast<size_t>(data->y_offset), |
| base::saturated_cast<size_t>(data->u_offset), |
| base::saturated_cast<size_t>(data->v_offset), data->y_stride, |
| data->u_stride, data->v_stride, input->timestamp); |
| } |
| |
| } // namespace mojo |