1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "media/mojo/services/media_type_converters.h" 6 7 #include "base/macros.h" 8 #include "media/base/audio_decoder_config.h" 9 #include "media/base/buffering_state.h" 10 #include "media/base/decoder_buffer.h" 11 #include "media/base/demuxer_stream.h" 12 #include "media/mojo/interfaces/demuxer_stream.mojom.h" 13 #include "mojo/public/cpp/system/data_pipe.h" 14 15 namespace mojo { 16 17 #define ASSERT_ENUM_EQ(media_enum, media_prefix, mojo_prefix, value) \ 18 COMPILE_ASSERT(media::media_prefix##value == \ 19 static_cast<media::media_enum>(mojo_prefix##value), \ 20 value##_enum_value_differs) 21 22 // BufferingState. 23 ASSERT_ENUM_EQ(BufferingState, BUFFERING_, BUFFERING_STATE_, HAVE_NOTHING); 24 ASSERT_ENUM_EQ(BufferingState, BUFFERING_, BUFFERING_STATE_, HAVE_ENOUGH); 25 26 // AudioCodec. 27 COMPILE_ASSERT(media::kUnknownAudioCodec == 28 static_cast<media::AudioCodec>(AUDIO_CODEC_UNKNOWN), 29 kUnknownAudioCodec_enum_value_differs); 30 ASSERT_ENUM_EQ(AudioCodec, kCodec, AUDIO_CODEC_, AAC); 31 ASSERT_ENUM_EQ(AudioCodec, kCodec, AUDIO_CODEC_, MP3); 32 ASSERT_ENUM_EQ(AudioCodec, kCodec, AUDIO_CODEC_, PCM); 33 ASSERT_ENUM_EQ(AudioCodec, kCodec, AUDIO_CODEC_, Vorbis); 34 ASSERT_ENUM_EQ(AudioCodec, kCodec, AUDIO_CODEC_, FLAC); 35 ASSERT_ENUM_EQ(AudioCodec, kCodec, AUDIO_CODEC_, AMR_NB); 36 ASSERT_ENUM_EQ(AudioCodec, kCodec, AUDIO_CODEC_, PCM_MULAW); 37 ASSERT_ENUM_EQ(AudioCodec, kCodec, AUDIO_CODEC_, GSM_MS); 38 ASSERT_ENUM_EQ(AudioCodec, kCodec, AUDIO_CODEC_, PCM_S16BE); 39 ASSERT_ENUM_EQ(AudioCodec, kCodec, AUDIO_CODEC_, PCM_S24BE); 40 ASSERT_ENUM_EQ(AudioCodec, kCodec, AUDIO_CODEC_, Opus); 41 ASSERT_ENUM_EQ(AudioCodec, kCodec, AUDIO_CODEC_, PCM_ALAW); 42 COMPILE_ASSERT(media::kAudioCodecMax == 43 static_cast<media::AudioCodec>(AUDIO_CODEC_MAX), 44 kAudioCodecMax_enum_value_differs); 45 46 // ChannelLayout. 47 ASSERT_ENUM_EQ(ChannelLayout, CHANNEL_LAYOUT, CHANNEL_LAYOUT_k, _NONE); 48 ASSERT_ENUM_EQ(ChannelLayout, CHANNEL_LAYOUT, CHANNEL_LAYOUT_k, _UNSUPPORTED); 49 ASSERT_ENUM_EQ(ChannelLayout, CHANNEL_LAYOUT, CHANNEL_LAYOUT_k, _MONO); 50 ASSERT_ENUM_EQ(ChannelLayout, CHANNEL_LAYOUT, CHANNEL_LAYOUT_k, _STEREO); 51 ASSERT_ENUM_EQ(ChannelLayout, CHANNEL_LAYOUT, CHANNEL_LAYOUT_k, _2_1); 52 ASSERT_ENUM_EQ(ChannelLayout, CHANNEL_LAYOUT, CHANNEL_LAYOUT_k, _SURROUND); 53 ASSERT_ENUM_EQ(ChannelLayout, CHANNEL_LAYOUT, CHANNEL_LAYOUT_k, _4_0); 54 ASSERT_ENUM_EQ(ChannelLayout, CHANNEL_LAYOUT, CHANNEL_LAYOUT_k, _2_2); 55 ASSERT_ENUM_EQ(ChannelLayout, CHANNEL_LAYOUT, CHANNEL_LAYOUT_k, _QUAD); 56 ASSERT_ENUM_EQ(ChannelLayout, CHANNEL_LAYOUT, CHANNEL_LAYOUT_k, _5_0); 57 ASSERT_ENUM_EQ(ChannelLayout, CHANNEL_LAYOUT, CHANNEL_LAYOUT_k, _5_1); 58 ASSERT_ENUM_EQ(ChannelLayout, CHANNEL_LAYOUT, CHANNEL_LAYOUT_k, _5_0_BACK); 59 ASSERT_ENUM_EQ(ChannelLayout, CHANNEL_LAYOUT, CHANNEL_LAYOUT_k, _5_1_BACK); 60 ASSERT_ENUM_EQ(ChannelLayout, CHANNEL_LAYOUT, CHANNEL_LAYOUT_k, _7_0); 61 ASSERT_ENUM_EQ(ChannelLayout, CHANNEL_LAYOUT, CHANNEL_LAYOUT_k, _7_1); 62 ASSERT_ENUM_EQ(ChannelLayout, CHANNEL_LAYOUT, CHANNEL_LAYOUT_k, _7_1_WIDE); 63 ASSERT_ENUM_EQ(ChannelLayout, 64 CHANNEL_LAYOUT, 65 CHANNEL_LAYOUT_k, 66 _STEREO_DOWNMIX); 67 ASSERT_ENUM_EQ(ChannelLayout, CHANNEL_LAYOUT, CHANNEL_LAYOUT_k, _2POINT1); 68 ASSERT_ENUM_EQ(ChannelLayout, CHANNEL_LAYOUT, CHANNEL_LAYOUT_k, _3_1); 69 ASSERT_ENUM_EQ(ChannelLayout, CHANNEL_LAYOUT, CHANNEL_LAYOUT_k, _4_1); 70 ASSERT_ENUM_EQ(ChannelLayout, CHANNEL_LAYOUT, CHANNEL_LAYOUT_k, _6_0); 71 ASSERT_ENUM_EQ(ChannelLayout, CHANNEL_LAYOUT, CHANNEL_LAYOUT_k, _6_0_FRONT); 72 ASSERT_ENUM_EQ(ChannelLayout, CHANNEL_LAYOUT, CHANNEL_LAYOUT_k, _HEXAGONAL); 73 ASSERT_ENUM_EQ(ChannelLayout, CHANNEL_LAYOUT, CHANNEL_LAYOUT_k, _6_1); 74 ASSERT_ENUM_EQ(ChannelLayout, CHANNEL_LAYOUT, CHANNEL_LAYOUT_k, _6_1_BACK); 75 ASSERT_ENUM_EQ(ChannelLayout, CHANNEL_LAYOUT, CHANNEL_LAYOUT_k, _6_1_FRONT); 76 ASSERT_ENUM_EQ(ChannelLayout, CHANNEL_LAYOUT, CHANNEL_LAYOUT_k, _7_0_FRONT); 77 ASSERT_ENUM_EQ(ChannelLayout, CHANNEL_LAYOUT, CHANNEL_LAYOUT_k, _7_1_WIDE_BACK); 78 ASSERT_ENUM_EQ(ChannelLayout, CHANNEL_LAYOUT, CHANNEL_LAYOUT_k, _OCTAGONAL); 79 ASSERT_ENUM_EQ(ChannelLayout, CHANNEL_LAYOUT, CHANNEL_LAYOUT_k, _DISCRETE); 80 ASSERT_ENUM_EQ(ChannelLayout, 81 CHANNEL_LAYOUT, 82 CHANNEL_LAYOUT_k, 83 _STEREO_AND_KEYBOARD_MIC); 84 ASSERT_ENUM_EQ(ChannelLayout, CHANNEL_LAYOUT, CHANNEL_LAYOUT_k, _MAX); 85 86 // SampleFormat. 87 COMPILE_ASSERT(media::kUnknownSampleFormat == 88 static_cast<media::SampleFormat>(SAMPLE_FORMAT_UNKNOWN), 89 kUnknownSampleFormat_enum_value_differs); 90 ASSERT_ENUM_EQ(SampleFormat, kSampleFormat, SAMPLE_FORMAT_, U8); 91 ASSERT_ENUM_EQ(SampleFormat, kSampleFormat, SAMPLE_FORMAT_, S16); 92 ASSERT_ENUM_EQ(SampleFormat, kSampleFormat, SAMPLE_FORMAT_, S32); 93 ASSERT_ENUM_EQ(SampleFormat, kSampleFormat, SAMPLE_FORMAT_, F32); 94 ASSERT_ENUM_EQ(SampleFormat, kSampleFormat, SAMPLE_FORMAT_, PlanarS16); 95 ASSERT_ENUM_EQ(SampleFormat, kSampleFormat, SAMPLE_FORMAT_, PlanarF32); 96 ASSERT_ENUM_EQ(SampleFormat, kSampleFormat, SAMPLE_FORMAT_, Max); 97 98 // DemuxerStream Type. 99 COMPILE_ASSERT(media::DemuxerStream::UNKNOWN == 100 static_cast<media::DemuxerStream::Type>( 101 mojo::DemuxerStream::TYPE_UNKNOWN), 102 DemuxerStream_Type_enum_value_differs); 103 COMPILE_ASSERT(media::DemuxerStream::AUDIO == 104 static_cast<media::DemuxerStream::Type>( 105 mojo::DemuxerStream::TYPE_AUDIO), 106 DemuxerStream_Type_enum_value_differs); 107 // Update this if new media::DemuxerStream::Type values are introduced. 108 COMPILE_ASSERT(media::DemuxerStream::NUM_TYPES == 109 static_cast<media::DemuxerStream::Type>( 110 mojo::DemuxerStream::TYPE_LAST_TYPE + 3), 111 DemuxerStream_Type_enum_value_differs); 112 113 // DemuxerStream Status. 114 COMPILE_ASSERT(media::DemuxerStream::kOk == 115 static_cast<media::DemuxerStream::Status>( 116 mojo::DemuxerStream::STATUS_OK), 117 DemuxerStream_Status_enum_value_differs); 118 COMPILE_ASSERT(media::DemuxerStream::kAborted == 119 static_cast<media::DemuxerStream::Status>( 120 mojo::DemuxerStream::STATUS_ABORTED), 121 DemuxerStream_Status_enum_value_differs); 122 COMPILE_ASSERT(media::DemuxerStream::kConfigChanged == 123 static_cast<media::DemuxerStream::Status>( 124 mojo::DemuxerStream::STATUS_CONFIG_CHANGED), 125 DemuxerStream_Status_enum_value_differs); 126 127 // static 128 MediaDecoderBufferPtr TypeConverter<MediaDecoderBufferPtr, 129 scoped_refptr<media::DecoderBuffer> >::Convert( 130 const scoped_refptr<media::DecoderBuffer>& input) { 131 MediaDecoderBufferPtr mojo_buffer(MediaDecoderBuffer::New()); 132 mojo_buffer->timestamp_usec = input->timestamp().InMicroseconds(); 133 mojo_buffer->duration_usec = input->duration().InMicroseconds(); 134 mojo_buffer->data_size = input->data_size(); 135 mojo_buffer->side_data_size = input->side_data_size(); 136 mojo_buffer->front_discard_usec = 137 input->discard_padding().first.InMicroseconds(); 138 mojo_buffer->back_discard_usec = 139 input->discard_padding().second.InMicroseconds(); 140 mojo_buffer->splice_timestamp_usec = 141 input->splice_timestamp().InMicroseconds(); 142 143 // TODO(tim): Assuming this is small so allowing extra copies. 144 std::vector<uint8> side_data(input->side_data(), 145 input->side_data() + input->side_data_size()); 146 mojo_buffer->side_data.Swap(&side_data); 147 148 MojoCreateDataPipeOptions options; 149 options.struct_size = sizeof(MojoCreateDataPipeOptions); 150 options.flags = MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE; 151 options.element_num_bytes = 1; 152 options.capacity_num_bytes = input->data_size(); 153 DataPipe data_pipe(options); 154 mojo_buffer->data = data_pipe.consumer_handle.Pass(); 155 156 uint32_t num_bytes = input->data_size(); 157 // TODO(tim): ALL_OR_NONE isn't really appropriate. Check success? 158 // If fails, we'd still return the buffer, but we'd need to HandleWatch 159 // to fill the pipe at a later time, which means the de-marshalling code 160 // needs to wait for a readable pipe (which it currently doesn't). 161 WriteDataRaw(data_pipe.producer_handle.get(), 162 input->data(), 163 &num_bytes, 164 MOJO_WRITE_DATA_FLAG_ALL_OR_NONE); 165 return mojo_buffer.Pass(); 166 } 167 168 // static 169 scoped_refptr<media::DecoderBuffer> TypeConverter< 170 scoped_refptr<media::DecoderBuffer>, MediaDecoderBufferPtr>::Convert( 171 const MediaDecoderBufferPtr& input) { 172 uint32_t num_bytes = 0; 173 // TODO(tim): We're assuming that because we always write to the pipe above 174 // before sending the MediaDecoderBuffer that the pipe is readable when 175 // we get here. 176 ReadDataRaw(input->data.get(), NULL, &num_bytes, MOJO_READ_DATA_FLAG_QUERY); 177 CHECK_EQ(num_bytes, input->data_size) << "Pipe error converting buffer"; 178 179 scoped_ptr<uint8[]> data(new uint8[num_bytes]); // Uninitialized. 180 ReadDataRaw(input->data.get(), data.get(), &num_bytes, 181 MOJO_READ_DATA_FLAG_ALL_OR_NONE); 182 CHECK_EQ(num_bytes, input->data_size) << "Pipe error converting buffer"; 183 184 // TODO(tim): We can't create a media::DecoderBuffer that has side_data 185 // without copying data because it wants to ensure alignment. Could we 186 // read directly into a pre-padded DecoderBuffer? 187 scoped_refptr<media::DecoderBuffer> buffer; 188 if (input->side_data_size) { 189 buffer = media::DecoderBuffer::CopyFrom(data.get(), 190 num_bytes, 191 &input->side_data.front(), 192 input->side_data_size); 193 } else { 194 buffer = media::DecoderBuffer::CopyFrom(data.get(), num_bytes); 195 } 196 197 buffer->set_timestamp( 198 base::TimeDelta::FromMicroseconds(input->timestamp_usec)); 199 buffer->set_duration( 200 base::TimeDelta::FromMicroseconds(input->duration_usec)); 201 media::DecoderBuffer::DiscardPadding discard_padding( 202 base::TimeDelta::FromMicroseconds(input->front_discard_usec), 203 base::TimeDelta::FromMicroseconds(input->back_discard_usec)); 204 buffer->set_discard_padding(discard_padding); 205 buffer->set_splice_timestamp( 206 base::TimeDelta::FromMicroseconds(input->splice_timestamp_usec)); 207 return buffer; 208 } 209 210 // static 211 AudioDecoderConfigPtr 212 TypeConverter<AudioDecoderConfigPtr, media::AudioDecoderConfig>::Convert( 213 const media::AudioDecoderConfig& input) { 214 mojo::AudioDecoderConfigPtr config(mojo::AudioDecoderConfig::New()); 215 config->codec = static_cast<mojo::AudioCodec>(input.codec()); 216 config->sample_format = 217 static_cast<mojo::SampleFormat>(input.sample_format()); 218 config->channel_layout = 219 static_cast<mojo::ChannelLayout>(input.channel_layout()); 220 config->samples_per_second = input.samples_per_second(); 221 if (input.extra_data()) { 222 std::vector<uint8> data(input.extra_data(), 223 input.extra_data() + input.extra_data_size()); 224 config->extra_data.Swap(&data); 225 } 226 config->seek_preroll_usec = input.seek_preroll().InMicroseconds(); 227 config->codec_delay = input.codec_delay(); 228 return config.Pass(); 229 } 230 231 // static 232 media::AudioDecoderConfig 233 TypeConverter<media::AudioDecoderConfig, AudioDecoderConfigPtr>::Convert( 234 const AudioDecoderConfigPtr& input) { 235 media::AudioDecoderConfig config; 236 config.Initialize(static_cast<media::AudioCodec>(input->codec), 237 static_cast<media::SampleFormat>(input->sample_format), 238 static_cast<media::ChannelLayout>(input->channel_layout), 239 input->samples_per_second, 240 &input->extra_data.front(), 241 input->extra_data.size(), 242 false, 243 false, 244 base::TimeDelta::FromMicroseconds(input->seek_preroll_usec), 245 input->codec_delay); 246 return config; 247 } 248 249 } // namespace mojo 250