OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "services/media/framework/conversion_pipeline_builder.h" | 5 #include "services/media/framework/conversion_pipeline_builder.h" |
6 #include "services/media/framework/formatting.h" | 6 #include "services/media/framework/formatting.h" |
7 #include "services/media/framework/parts/decoder.h" | 7 #include "services/media/framework/parts/decoder.h" |
8 #include "services/media/framework/parts/lpcm_reformatter.h" | 8 #include "services/media/framework/parts/lpcm_reformatter.h" |
9 | 9 |
10 namespace mojo { | 10 namespace mojo { |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
66 // Very much prefer not to resample. | 66 // Very much prefer not to resample. |
67 score += 50; | 67 score += 50; |
68 } else { | 68 } else { |
69 return 0; // TODO(dalesat): Remove when we have resamplers. | 69 return 0; // TODO(dalesat): Remove when we have resamplers. |
70 } | 70 } |
71 | 71 |
72 return score; | 72 return score; |
73 } | 73 } |
74 | 74 |
75 // Finds the media type set that best matches in_type. | 75 // Finds the media type set that best matches in_type. |
76 const StreamTypeSetPtr* FindBestLpcm( | 76 const std::unique_ptr<StreamTypeSet>* FindBestLpcm( |
77 const LpcmStreamType& in_type, | 77 const LpcmStreamType& in_type, |
78 const StreamTypeSetsPtr& out_type_sets) { | 78 const std::unique_ptr<std::vector<std::unique_ptr<StreamTypeSet>>>& |
79 const StreamTypeSetPtr* best = nullptr; | 79 out_type_sets) { |
| 80 const std::unique_ptr<StreamTypeSet>* best = nullptr; |
80 int best_score = 0; | 81 int best_score = 0; |
81 for (const StreamTypeSetPtr& out_type_set : *out_type_sets) { | 82 for (const std::unique_ptr<StreamTypeSet>& out_type_set : *out_type_sets) { |
82 switch (out_type_set->scheme()) { | 83 switch (out_type_set->scheme()) { |
83 case StreamType::Scheme::kAnyElementary: | 84 case StreamType::Scheme::kAnyElementary: |
84 case StreamType::Scheme::kAnyAudio: | 85 case StreamType::Scheme::kAnyAudio: |
85 case StreamType::Scheme::kAny: | 86 case StreamType::Scheme::kAny: |
86 // Wildcard scheme allows any type without conversion. | 87 // Wildcard scheme allows any type without conversion. |
87 return &out_type_set; | 88 return &out_type_set; |
88 case StreamType::Scheme::kLpcm: { | 89 case StreamType::Scheme::kLpcm: { |
89 int score = Score(in_type, *out_type_set->lpcm()); | 90 int score = Score(in_type, *out_type_set->lpcm()); |
90 if (best_score < score) { | 91 if (best_score < score) { |
91 best_score = score; | 92 best_score = score; |
92 best = &out_type_set; | 93 best = &out_type_set; |
93 } | 94 } |
94 break; | 95 break; |
95 } | 96 } |
96 default: | 97 default: |
97 break; | 98 break; |
98 } | 99 } |
99 } | 100 } |
100 return best; | 101 return best; |
101 } | 102 } |
102 | 103 |
103 // Attempts to add transforms to the pipeline given an input compressed audio | 104 // Attempts to add transforms to the pipeline given an input compressed audio |
104 // stream type with (in_type) and the set of output types we need to convert to | 105 // stream type with (in_type) and the set of output types we need to convert to |
105 // (out_type_sets). If the call succeeds, *out_type is set to the new output | 106 // (out_type_sets). If the call succeeds, *out_type is set to the new output |
106 // type. Otherwise, *out_type is set to nullptr. | 107 // type. Otherwise, *out_type is set to nullptr. |
107 AddResult AddTransformsForCompressedAudio( | 108 AddResult AddTransformsForCompressedAudio( |
108 const CompressedAudioStreamType& in_type, | 109 const CompressedAudioStreamType& in_type, |
109 const StreamTypePtr& in_type_ptr, | 110 const std::unique_ptr<StreamType>& in_type_ptr, |
110 const StreamTypeSetsPtr& out_type_sets, | 111 const std::unique_ptr<std::vector<std::unique_ptr<StreamTypeSet>>>& |
111 Engine* engine, | 112 out_type_sets, |
112 Engine::Output* output, | 113 Graph* graph, |
113 StreamTypePtr* out_type) { | 114 OutputRef* output, |
| 115 std::unique_ptr<StreamType>* out_type) { |
114 DCHECK(out_type); | 116 DCHECK(out_type); |
115 DCHECK(engine); | 117 DCHECK(graph); |
116 | 118 |
117 // See if we have a matching COMPRESSED_AUDIO type. | 119 // See if we have a matching COMPRESSED_AUDIO type. |
118 for (const StreamTypeSetPtr& out_type_set : *out_type_sets) { | 120 for (const std::unique_ptr<StreamTypeSet>& out_type_set : *out_type_sets) { |
119 switch (out_type_set->scheme()) { | 121 switch (out_type_set->scheme()) { |
120 case StreamType::Scheme::kAnyElementary: | 122 case StreamType::Scheme::kAnyElementary: |
121 case StreamType::Scheme::kAnyAudio: | 123 case StreamType::Scheme::kAnyAudio: |
122 case StreamType::Scheme::kAny: | 124 case StreamType::Scheme::kAny: |
123 // Wildcard scheme allows any type without conversion. | 125 // Wildcard scheme allows any type without conversion. |
124 *out_type = in_type.Clone(); | 126 *out_type = in_type.Clone(); |
125 return AddResult::kFinished; | 127 return AddResult::kFinished; |
126 case StreamType::Scheme::kCompressedAudio: { | 128 case StreamType::Scheme::kCompressedAudio: { |
127 if (out_type_set->compressed_audio()->contains(in_type)) { | 129 if (out_type_set->compressed_audio()->contains(in_type)) { |
128 // No transform needed. | 130 // No transform needed. |
129 *out_type = in_type.Clone(); | 131 *out_type = in_type.Clone(); |
130 return AddResult::kFinished; | 132 return AddResult::kFinished; |
131 } | 133 } |
132 break; | 134 break; |
133 } | 135 } |
134 default: | 136 default: |
135 break; | 137 break; |
136 } | 138 } |
137 // TODO(dalesat): Support a different compressed output type by transcoding. | 139 // TODO(dalesat): Support a different compressed output type by transcoding. |
138 } | 140 } |
139 | 141 |
140 // Find the best LPCM output type. | 142 // Find the best LPCM output type. |
141 const StreamTypeSetPtr* best = FindBestLpcm(in_type, out_type_sets); | 143 const std::unique_ptr<StreamTypeSet>* best = |
| 144 FindBestLpcm(in_type, out_type_sets); |
142 if (best == nullptr) { | 145 if (best == nullptr) { |
143 // No candidates found. | 146 // No candidates found. |
144 *out_type = nullptr; | 147 *out_type = nullptr; |
145 return AddResult::kFailed; | 148 return AddResult::kFailed; |
146 } | 149 } |
147 | 150 |
148 DCHECK_EQ((*best)->scheme(), StreamType::Scheme::kLpcm); | 151 DCHECK_EQ((*best)->scheme(), StreamType::Scheme::kLpcm); |
149 | 152 |
150 // Need to decode. Create a decoder and go from there. | 153 // Need to decode. Create a decoder and go from there. |
151 DecoderPtr decoder; | 154 std::shared_ptr<Decoder> decoder; |
152 Result result = Decoder::Create(in_type_ptr, &decoder); | 155 Result result = Decoder::Create(in_type_ptr, &decoder); |
153 if (result != Result::kOk) { | 156 if (result != Result::kOk) { |
154 // No decoder found. | 157 // No decoder found. |
155 *out_type = nullptr; | 158 *out_type = nullptr; |
156 return AddResult::kFailed; | 159 return AddResult::kFailed; |
157 } | 160 } |
158 | 161 |
159 *output = engine->ConnectOutputToPart(*output, engine->Add(decoder)).output(); | 162 *output = graph->ConnectOutputToPart(*output, graph->Add(decoder)).output(); |
160 *out_type = decoder->output_stream_type(); | 163 *out_type = decoder->output_stream_type(); |
161 | 164 |
162 return AddResult::kProgressed; | 165 return AddResult::kProgressed; |
163 } | 166 } |
164 | 167 |
165 // Attempts to add transforms to the pipeline given an input LPCM stream type | 168 // Attempts to add transforms to the pipeline given an input LPCM stream type |
166 // (in_type) and the output lpcm stream type set for the type we need to convert | 169 // (in_type) and the output lpcm stream type set for the type we need to convert |
167 // to (out_type_set). If the call succeeds, *out_type is set to the new output | 170 // to (out_type_set). If the call succeeds, *out_type is set to the new output |
168 // type. Otherwise, *out_type is set to nullptr. | 171 // type. Otherwise, *out_type is set to nullptr. |
169 AddResult AddTransformsForLpcm( | 172 AddResult AddTransformsForLpcm( |
170 const LpcmStreamType& in_type, | 173 const LpcmStreamType& in_type, |
171 const LpcmStreamTypeSet& out_type_set, | 174 const LpcmStreamTypeSet& out_type_set, |
172 Engine* engine, | 175 Graph* graph, |
173 Engine::Output* output, | 176 OutputRef* output, |
174 StreamTypePtr* out_type) { | 177 std::unique_ptr<StreamType>* out_type) { |
175 DCHECK(engine); | 178 DCHECK(graph); |
176 DCHECK(out_type); | 179 DCHECK(out_type); |
177 | 180 |
178 // TODO(dalesat): Room for more intelligence here wrt transform ordering and | 181 // TODO(dalesat): Room for more intelligence here wrt transform ordering and |
179 // transforms that handle more than one conversion. | 182 // transforms that handle more than one conversion. |
180 if (in_type.sample_format() != out_type_set.sample_format() && | 183 if (in_type.sample_format() != out_type_set.sample_format() && |
181 out_type_set.sample_format() != LpcmStreamType::SampleFormat::kAny) { | 184 out_type_set.sample_format() != LpcmStreamType::SampleFormat::kAny) { |
182 // The reformatter will fix interleave conversion. | 185 // The reformatter will fix interleave conversion. |
183 *output = engine->ConnectOutputToPart( | 186 *output = graph->ConnectOutputToPart( |
184 *output, | 187 *output, |
185 engine->Add(LpcmReformatter::Create(in_type, out_type_set))).output(); | 188 graph->Add(LpcmReformatter::Create(in_type, out_type_set))).output(); |
186 } | 189 } |
187 | 190 |
188 if (!out_type_set.channels().contains(in_type.channels())) { | 191 if (!out_type_set.channels().contains(in_type.channels())) { |
189 // TODO(dalesat): Insert mixdown/up transform. | 192 // TODO(dalesat): Insert mixdown/up transform. |
190 NOTREACHED() << "conversion requires mixdown/up - not supported"; | 193 NOTREACHED() << "conversion requires mixdown/up - not supported"; |
191 *out_type = nullptr; | 194 *out_type = nullptr; |
192 return AddResult::kFailed; | 195 return AddResult::kFailed; |
193 } | 196 } |
194 | 197 |
195 if (!out_type_set.frames_per_second().contains(in_type.frames_per_second())) { | 198 if (!out_type_set.frames_per_second().contains(in_type.frames_per_second())) { |
(...skipping 13 matching lines...) Expand all Loading... |
209 | 212 |
210 return AddResult::kFinished; | 213 return AddResult::kFinished; |
211 } | 214 } |
212 | 215 |
213 // Attempts to add transforms to the pipeline given an input media type with | 216 // Attempts to add transforms to the pipeline given an input media type with |
214 // scheme LPCM (in_type) and the set of output types we need to convert to | 217 // scheme LPCM (in_type) and the set of output types we need to convert to |
215 // (out_type_sets). If the call succeeds, *out_type is set to the new output | 218 // (out_type_sets). If the call succeeds, *out_type is set to the new output |
216 // type. Otherwise, *out_type is set to nullptr. | 219 // type. Otherwise, *out_type is set to nullptr. |
217 AddResult AddTransformsForLpcm( | 220 AddResult AddTransformsForLpcm( |
218 const LpcmStreamType& in_type, | 221 const LpcmStreamType& in_type, |
219 const StreamTypeSetsPtr& out_type_sets, | 222 const std::unique_ptr<std::vector<std::unique_ptr<StreamTypeSet>>>& |
220 Engine* engine, | 223 out_type_sets, |
221 Engine::Output* output, | 224 Graph* graph, |
222 StreamTypePtr* out_type) { | 225 OutputRef* output, |
223 DCHECK(engine); | 226 std::unique_ptr<StreamType>* out_type) { |
| 227 DCHECK(graph); |
224 DCHECK(out_type); | 228 DCHECK(out_type); |
225 | 229 |
226 const StreamTypeSetPtr* best = FindBestLpcm(in_type, out_type_sets); | 230 const std::unique_ptr<StreamTypeSet>* best = |
| 231 FindBestLpcm(in_type, out_type_sets); |
227 if (best == nullptr) { | 232 if (best == nullptr) { |
228 // TODO(dalesat): Support a compressed output type by encoding. | 233 // TODO(dalesat): Support a compressed output type by encoding. |
229 NOTREACHED() << "conversion using encoder not supported"; | 234 NOTREACHED() << "conversion using encoder not supported"; |
230 *out_type = nullptr; | 235 *out_type = nullptr; |
231 return AddResult::kFailed; | 236 return AddResult::kFailed; |
232 } | 237 } |
233 | 238 |
234 switch ((*best)->scheme()) { | 239 switch ((*best)->scheme()) { |
235 case StreamType::Scheme::kAnyElementary: | 240 case StreamType::Scheme::kAnyElementary: |
236 case StreamType::Scheme::kAnyAudio: | 241 case StreamType::Scheme::kAnyAudio: |
237 case StreamType::Scheme::kAny: | 242 case StreamType::Scheme::kAny: |
238 // Wildcard scheme allows any type without conversion. | 243 // Wildcard scheme allows any type without conversion. |
239 *out_type = in_type.Clone(); | 244 *out_type = in_type.Clone(); |
240 return AddResult::kFinished; | 245 return AddResult::kFinished; |
241 case StreamType::Scheme::kLpcm: | 246 case StreamType::Scheme::kLpcm: |
242 return AddTransformsForLpcm( | 247 return AddTransformsForLpcm( |
243 in_type, | 248 in_type, |
244 *(*best)->lpcm(), | 249 *(*best)->lpcm(), |
245 engine, | 250 graph, |
246 output, | 251 output, |
247 out_type); | 252 out_type); |
248 default: | 253 default: |
249 NOTREACHED() << "FindBestLpcm produced unexpected type set scheme" | 254 NOTREACHED() << "FindBestLpcm produced unexpected type set scheme" |
250 << (*best)->scheme(); | 255 << (*best)->scheme(); |
251 return AddResult::kFailed; | 256 return AddResult::kFailed; |
252 } | 257 } |
253 } | 258 } |
254 | 259 |
255 // Attempts to add transforms to the pipeline given an input media type of any | 260 // Attempts to add transforms to the pipeline given an input media type of any |
256 // scheme (in_type) and the set of output types we need to convert to | 261 // scheme (in_type) and the set of output types we need to convert to |
257 // (out_type_sets). If the call succeeds, *out_type is set to the new output | 262 // (out_type_sets). If the call succeeds, *out_type is set to the new output |
258 // type. Otherwise, *out_type is set to nullptr. | 263 // type. Otherwise, *out_type is set to nullptr. |
259 AddResult AddTransforms( | 264 AddResult AddTransforms( |
260 const StreamTypePtr& in_type, | 265 const std::unique_ptr<StreamType>& in_type, |
261 const StreamTypeSetsPtr& out_type_sets, | 266 const std::unique_ptr<std::vector<std::unique_ptr<StreamTypeSet>>>& |
262 Engine* engine, | 267 out_type_sets, |
263 Engine::Output* output, | 268 Graph* graph, |
264 StreamTypePtr* out_type) { | 269 OutputRef* output, |
| 270 std::unique_ptr<StreamType>* out_type) { |
265 DCHECK(in_type); | 271 DCHECK(in_type); |
266 DCHECK(engine); | 272 DCHECK(graph); |
267 DCHECK(out_type); | 273 DCHECK(out_type); |
268 | 274 |
269 switch (in_type->scheme()) { | 275 switch (in_type->scheme()) { |
270 case StreamType::Scheme::kLpcm: | 276 case StreamType::Scheme::kLpcm: |
271 return AddTransformsForLpcm( | 277 return AddTransformsForLpcm( |
272 *in_type->lpcm(), | 278 *in_type->lpcm(), |
273 out_type_sets, | 279 out_type_sets, |
274 engine, | 280 graph, |
275 output, | 281 output, |
276 out_type); | 282 out_type); |
277 case StreamType::Scheme::kCompressedAudio: | 283 case StreamType::Scheme::kCompressedAudio: |
278 return AddTransformsForCompressedAudio( | 284 return AddTransformsForCompressedAudio( |
279 *in_type->compressed_audio(), | 285 *in_type->compressed_audio(), |
280 in_type, | 286 in_type, |
281 out_type_sets, | 287 out_type_sets, |
282 engine, | 288 graph, |
283 output, | 289 output, |
284 out_type); | 290 out_type); |
285 default: | 291 default: |
286 NOTREACHED() << "conversion not supported for scheme" | 292 NOTREACHED() << "conversion not supported for scheme" |
287 << in_type->scheme(); | 293 << in_type->scheme(); |
288 *out_type = nullptr; | 294 *out_type = nullptr; |
289 return AddResult::kFailed; | 295 return AddResult::kFailed; |
290 } | 296 } |
291 } | 297 } |
292 | 298 |
293 } // namespace | 299 } // namespace |
294 | 300 |
295 bool BuildConversionPipeline( | 301 bool BuildConversionPipeline( |
296 const StreamTypePtr& in_type, | 302 const std::unique_ptr<StreamType>& in_type, |
297 const StreamTypeSetsPtr& out_type_sets, | 303 const std::unique_ptr<std::vector<std::unique_ptr<StreamTypeSet>>>& |
298 Engine* engine, | 304 out_type_sets, |
299 Engine::Output* output, | 305 Graph* graph, |
300 StreamTypePtr* out_type) { | 306 OutputRef* output, |
| 307 std::unique_ptr<StreamType>* out_type) { |
301 DCHECK(in_type); | 308 DCHECK(in_type); |
302 DCHECK(out_type_sets); | 309 DCHECK(out_type_sets); |
303 DCHECK(engine); | 310 DCHECK(graph); |
304 DCHECK(output); | 311 DCHECK(output); |
305 DCHECK(out_type); | 312 DCHECK(out_type); |
306 | 313 |
307 Engine::Output out = *output; | 314 OutputRef out = *output; |
308 | 315 |
309 const StreamTypePtr* type_to_convert = &in_type; | 316 const std::unique_ptr<StreamType>* type_to_convert = &in_type; |
310 StreamTypePtr next_in_type; | 317 std::unique_ptr<StreamType> next_in_type; |
311 while (true) { | 318 while (true) { |
312 StreamTypePtr converted_type; | 319 std::unique_ptr<StreamType> converted_type; |
313 switch (AddTransforms( | 320 switch (AddTransforms( |
314 *type_to_convert, | 321 *type_to_convert, |
315 out_type_sets, | 322 out_type_sets, |
316 engine, | 323 graph, |
317 &out, | 324 &out, |
318 &converted_type)) { | 325 &converted_type)) { |
319 case AddResult::kFailed: | 326 case AddResult::kFailed: |
320 // Failed to find a suitable conversion. Return the pipeline to its | 327 // Failed to find a suitable conversion. Return the pipeline to its |
321 // original state. | 328 // original state. |
322 engine->RemovePartsConnectedToOutput(*output); | 329 graph->RemovePartsConnectedToOutput(*output); |
323 *out_type = nullptr; | 330 *out_type = nullptr; |
324 return false; | 331 return false; |
325 case AddResult::kProgressed: | 332 case AddResult::kProgressed: |
326 // Made progress. Continue. | 333 // Made progress. Continue. |
327 break; | 334 break; |
328 case AddResult::kFinished: | 335 case AddResult::kFinished: |
329 // No further conversion required. | 336 // No further conversion required. |
330 *output = out; | 337 *output = out; |
331 *out_type = std::move(converted_type); | 338 *out_type = std::move(converted_type); |
332 return true; | 339 return true; |
333 } | 340 } |
334 | 341 |
335 next_in_type = std::move(converted_type); | 342 next_in_type = std::move(converted_type); |
336 type_to_convert = &next_in_type; | 343 type_to_convert = &next_in_type; |
337 } | 344 } |
338 } | 345 } |
339 | 346 |
340 } // namespace media | 347 } // namespace media |
341 } // namespace mojo | 348 } // namespace mojo |
OLD | NEW |