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.
5 #include "media/mojo/services/media_type_converters.h"
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"
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)
23 ASSERT_ENUM_EQ(BufferingState, BUFFERING_, BUFFERING_STATE_, HAVE_NOTHING);
24 ASSERT_ENUM_EQ(BufferingState, BUFFERING_, BUFFERING_STATE_, HAVE_ENOUGH);
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);
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,
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,
83 _STEREO_AND_KEYBOARD_MIC);
84 ASSERT_ENUM_EQ(ChannelLayout, CHANNEL_LAYOUT, CHANNEL_LAYOUT_k, _MAX);
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);
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);
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);
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();
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);
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();
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(),
164 MOJO_WRITE_DATA_FLAG_ALL_OR_NONE);
165 return mojo_buffer.Pass();
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
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";
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";
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(),
191 &input->side_data.front(),
192 input->side_data_size);
194 buffer = media::DecoderBuffer::CopyFrom(data.get(), num_bytes);
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));
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);
226 config->seek_preroll_usec = input.seek_preroll().InMicroseconds();
227 config->codec_delay = input.codec_delay();
228 return config.Pass();
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(),
244 base::TimeDelta::FromMicroseconds(input->seek_preroll_usec),