OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "base/logging.h" |
| 6 #include "services/media/framework/parts/lpcm_reformatter.h" |
| 7 |
| 8 namespace mojo { |
| 9 namespace media { |
| 10 |
| 11 // LpcmReformatter implementation that accepts samples of type TIn and |
| 12 // produces samples of type TOut. |
| 13 template<typename TIn, typename TOut> |
| 14 class LpcmReformatterImpl : public LpcmReformatter { |
| 15 public: |
| 16 LpcmReformatterImpl( |
| 17 const LpcmStreamType& in_type, |
| 18 const LpcmStreamTypeSet& out_type); |
| 19 |
| 20 ~LpcmReformatterImpl() override; |
| 21 |
| 22 // LpcmTransform implementation. |
| 23 const LpcmStreamType& input_stream_type() const override; |
| 24 |
| 25 const LpcmStreamType& output_stream_type() const override; |
| 26 |
| 27 void TransformFrames( |
| 28 LpcmFrameBuffer* source, |
| 29 LpcmFrameBuffer* dest, |
| 30 bool mix) override; |
| 31 |
| 32 private: |
| 33 LpcmStreamType in_type_; |
| 34 LpcmStreamType out_type_; |
| 35 }; |
| 36 |
| 37 LpcmReformatterPtr LpcmReformatter::Create( |
| 38 const LpcmStreamType& in_type, |
| 39 const LpcmStreamTypeSet& out_type) { |
| 40 LpcmReformatter* result = nullptr; |
| 41 |
| 42 switch (in_type.sample_format()) { |
| 43 case LpcmStreamType::SampleFormat::kUnsigned8: |
| 44 switch (out_type.sample_format()) { |
| 45 case LpcmStreamType::SampleFormat::kUnsigned8: |
| 46 case LpcmStreamType::SampleFormat::kAny: |
| 47 result = new LpcmReformatterImpl<uint8_t, uint8_t>( |
| 48 in_type, out_type); |
| 49 break; |
| 50 case LpcmStreamType::SampleFormat::kSigned16: |
| 51 result = new LpcmReformatterImpl<uint8_t, int16_t>( |
| 52 in_type, out_type); |
| 53 break; |
| 54 case LpcmStreamType::SampleFormat::kSigned24In32: |
| 55 result = new LpcmReformatterImpl<uint8_t, int32_t>( |
| 56 in_type, out_type); |
| 57 break; |
| 58 case LpcmStreamType::SampleFormat::kFloat: |
| 59 result = new LpcmReformatterImpl<uint8_t, float>( |
| 60 in_type, out_type); |
| 61 break; |
| 62 default: |
| 63 NOTREACHED() << "unsupported sample format"; |
| 64 result = nullptr; |
| 65 break; |
| 66 } |
| 67 break; |
| 68 case LpcmStreamType::SampleFormat::kSigned16: |
| 69 switch (out_type.sample_format()) { |
| 70 case LpcmStreamType::SampleFormat::kUnsigned8: |
| 71 result = new LpcmReformatterImpl<int16_t, uint8_t>( |
| 72 in_type, out_type); |
| 73 break; |
| 74 case LpcmStreamType::SampleFormat::kSigned16: |
| 75 case LpcmStreamType::SampleFormat::kAny: |
| 76 result = new LpcmReformatterImpl<int16_t, int16_t>( |
| 77 in_type, out_type); |
| 78 break; |
| 79 case LpcmStreamType::SampleFormat::kSigned24In32: |
| 80 result = new LpcmReformatterImpl<int16_t, int32_t>( |
| 81 in_type, out_type); |
| 82 break; |
| 83 case LpcmStreamType::SampleFormat::kFloat: |
| 84 result = new LpcmReformatterImpl<int16_t, float>( |
| 85 in_type, out_type); |
| 86 break; |
| 87 default: |
| 88 NOTREACHED() << "unsupported sample format"; |
| 89 result = nullptr; |
| 90 break; |
| 91 } |
| 92 break; |
| 93 case LpcmStreamType::SampleFormat::kSigned24In32: |
| 94 switch (out_type.sample_format()) { |
| 95 case LpcmStreamType::SampleFormat::kUnsigned8: |
| 96 result = new LpcmReformatterImpl<int32_t, uint8_t>( |
| 97 in_type, out_type); |
| 98 break; |
| 99 case LpcmStreamType::SampleFormat::kSigned16: |
| 100 result = new LpcmReformatterImpl<int32_t, int16_t>( |
| 101 in_type, out_type); |
| 102 break; |
| 103 case LpcmStreamType::SampleFormat::kSigned24In32: |
| 104 case LpcmStreamType::SampleFormat::kAny: |
| 105 result = new LpcmReformatterImpl<int32_t, int32_t>( |
| 106 in_type, out_type); |
| 107 break; |
| 108 case LpcmStreamType::SampleFormat::kFloat: |
| 109 result = new LpcmReformatterImpl<int32_t, float>( |
| 110 in_type, out_type); |
| 111 break; |
| 112 default: |
| 113 NOTREACHED() << "unsupported sample format"; |
| 114 result = nullptr; |
| 115 break; |
| 116 } |
| 117 break; |
| 118 case LpcmStreamType::SampleFormat::kFloat: |
| 119 switch (out_type.sample_format()) { |
| 120 case LpcmStreamType::SampleFormat::kUnsigned8: |
| 121 result = new LpcmReformatterImpl<float, uint8_t>( |
| 122 in_type, out_type); |
| 123 break; |
| 124 case LpcmStreamType::SampleFormat::kSigned16: |
| 125 result = new LpcmReformatterImpl<float, int16_t>( |
| 126 in_type, out_type); |
| 127 break; |
| 128 case LpcmStreamType::SampleFormat::kSigned24In32: |
| 129 result = new LpcmReformatterImpl<float, int32_t>( |
| 130 in_type, out_type); |
| 131 break; |
| 132 case LpcmStreamType::SampleFormat::kFloat: |
| 133 case LpcmStreamType::SampleFormat::kAny: |
| 134 result = new LpcmReformatterImpl<float, float>(in_type, out_type); |
| 135 break; |
| 136 default: |
| 137 NOTREACHED() << "unsupported sample format"; |
| 138 result = nullptr; |
| 139 break; |
| 140 } |
| 141 break; |
| 142 default: |
| 143 NOTREACHED() << "unsupported sample format"; |
| 144 result = nullptr; |
| 145 break; |
| 146 } |
| 147 |
| 148 return LpcmReformatterPtr(result); |
| 149 } |
| 150 |
| 151 template<typename TIn, typename TOut> |
| 152 LpcmReformatterImpl<TIn, TOut>::LpcmReformatterImpl( |
| 153 const LpcmStreamType& in_type, |
| 154 const LpcmStreamTypeSet& out_type) : |
| 155 in_type_(in_type), |
| 156 out_type_( |
| 157 out_type.sample_format() == LpcmStreamType::SampleFormat::kAny ? |
| 158 in_type.sample_format() : |
| 159 out_type.sample_format(), |
| 160 in_type.channels(), |
| 161 in_type.frames_per_second()) {} |
| 162 |
| 163 template<typename TIn, typename TOut> |
| 164 LpcmReformatterImpl<TIn, TOut>::~LpcmReformatterImpl() {} |
| 165 |
| 166 namespace { |
| 167 |
| 168 template <typename T> |
| 169 inline constexpr T Clamp(T val, T min, T max) { |
| 170 return (val > max) ? max : ((val < min) ? min : val); |
| 171 } |
| 172 |
| 173 template <typename T> |
| 174 inline constexpr T Clamp(T val); |
| 175 |
| 176 template <> |
| 177 inline constexpr float Clamp(float val) { |
| 178 return Clamp(val, -1.0f, 1.0f); |
| 179 } |
| 180 |
| 181 template <> |
| 182 inline constexpr int32_t Clamp(int32_t val) { |
| 183 return Clamp(val, 1 << 23, -(1 << 23)); |
| 184 } |
| 185 |
| 186 template<typename TIn, typename TOut> |
| 187 inline void CopySample(TOut* dest, TIn* source) { |
| 188 *dest = static_cast<TOut>(*source); |
| 189 } |
| 190 |
| 191 inline void CopySample(uint8_t* dest, int16_t* source) { |
| 192 *dest = static_cast<uint8_t>((*source >> 8) ^ 0x80); |
| 193 } |
| 194 |
| 195 inline void CopySample(uint8_t* dest, int32_t* source) { |
| 196 *dest = static_cast<uint8_t>((Clamp(*source) >> 16) ^ 0x80); |
| 197 } |
| 198 |
| 199 inline void CopySample(uint8_t* dest, float* source) { |
| 200 *dest = static_cast<uint8_t>((Clamp(*source) * 0x7f) + 128); |
| 201 } |
| 202 |
| 203 inline void CopySample(int16_t* dest, uint8_t* source) { |
| 204 *dest = static_cast<int16_t>(*source ^ 0x80) << 8; |
| 205 } |
| 206 |
| 207 inline void CopySample(int16_t* dest, int32_t* source) { |
| 208 *dest = static_cast<int16_t>(Clamp(*source) >> 8); |
| 209 } |
| 210 |
| 211 inline void CopySample(int16_t* dest, float* source) { |
| 212 *dest = static_cast<int16_t>(Clamp(*source) * 0x7fff); |
| 213 } |
| 214 |
| 215 inline void CopySample(int32_t* dest, uint8_t* source) { |
| 216 *dest = static_cast<int32_t>(*source ^ 0x80) << 16; |
| 217 } |
| 218 |
| 219 inline void CopySample(int32_t* dest, int16_t* source) { |
| 220 *dest = static_cast<int32_t>(*source << 8); |
| 221 } |
| 222 |
| 223 inline void CopySample(int32_t* dest, float* source) { |
| 224 *dest = static_cast<int32_t>(Clamp(*source) * 0x7fffff); |
| 225 } |
| 226 |
| 227 inline void CopySample(float* dest, uint8_t* source) { |
| 228 *dest = static_cast<float>(*source ^ 0x80) / 0x80; |
| 229 } |
| 230 |
| 231 inline void CopySample(float* dest, int16_t* source) { |
| 232 *dest = static_cast<float>(*source) / 0x8000; |
| 233 } |
| 234 |
| 235 inline void CopySample(float* dest, int32_t* source) { |
| 236 *dest = static_cast<float>(Clamp(*source)) / 0x800000; |
| 237 } |
| 238 |
| 239 template<typename TIn, typename TOut> |
| 240 inline void MixSample(TOut* dest, TIn* source) { |
| 241 *dest += static_cast<TOut>(*source); |
| 242 } |
| 243 |
| 244 inline void MixSample(uint8_t* dest, int16_t* source) { |
| 245 *dest += static_cast<uint8_t>((*source >> 8) ^ 0x80); |
| 246 } |
| 247 |
| 248 inline void MixSample(uint8_t* dest, int32_t* source) { |
| 249 *dest += static_cast<uint8_t>((Clamp(*source) >> 16) ^ 0x80); |
| 250 } |
| 251 |
| 252 inline void MixSample(uint8_t* dest, float* source) { |
| 253 *dest += static_cast<uint8_t>((Clamp(*source) * 0x7f) + 128); |
| 254 } |
| 255 |
| 256 inline void MixSample(int16_t* dest, uint8_t* source) { |
| 257 *dest += static_cast<int16_t>(*source ^ 0x80) << 8; |
| 258 } |
| 259 |
| 260 inline void MixSample(int16_t* dest, int32_t* source) { |
| 261 *dest += static_cast<int16_t>(Clamp(*source) >> 8); |
| 262 } |
| 263 |
| 264 inline void MixSample(int16_t* dest, float* source) { |
| 265 *dest += static_cast<int16_t>(Clamp(*source) * 0x7fff); |
| 266 } |
| 267 |
| 268 inline void MixSample(int32_t* dest, uint8_t* source) { |
| 269 *dest += static_cast<int32_t>(*source ^ 0x80) << 16; |
| 270 } |
| 271 |
| 272 inline void MixSample(int32_t* dest, int16_t* source) { |
| 273 *dest += static_cast<int32_t>(*source << 8); |
| 274 } |
| 275 |
| 276 inline void MixSample(int32_t* dest, float* source) { |
| 277 *dest += static_cast<int32_t>(Clamp(*source) * 0x7fffff); |
| 278 } |
| 279 |
| 280 inline void MixSample(float* dest, uint8_t* source) { |
| 281 *dest += static_cast<float>(*source ^ 0x80) / 0x80; |
| 282 } |
| 283 |
| 284 inline void MixSample(float* dest, int16_t* source) { |
| 285 *dest += static_cast<float>(*source) / 0x8000; |
| 286 } |
| 287 |
| 288 inline void MixSample(float* dest, int32_t* source) { |
| 289 *dest += static_cast<float>(Clamp(*source)) / 0x800000; |
| 290 } |
| 291 |
| 292 } // namespace |
| 293 |
| 294 template<typename TIn, typename TOut> |
| 295 const LpcmStreamType& LpcmReformatterImpl<TIn, TOut>::input_stream_type() |
| 296 const { |
| 297 return in_type_; |
| 298 } |
| 299 |
| 300 template<typename TIn, typename TOut> |
| 301 const LpcmStreamType& LpcmReformatterImpl<TIn, TOut>::output_stream_type() |
| 302 const { |
| 303 return out_type_; |
| 304 } |
| 305 |
| 306 template<typename TIn, typename TOut> |
| 307 void LpcmReformatterImpl<TIn, TOut>::TransformFrames( |
| 308 LpcmFrameBuffer* source, |
| 309 LpcmFrameBuffer* dest, |
| 310 bool mix) { |
| 311 DCHECK(source); |
| 312 DCHECK(dest); |
| 313 DCHECK(source->buffer()); |
| 314 DCHECK(source->frame_count()); |
| 315 DCHECK(dest->buffer()); |
| 316 DCHECK(dest->frame_count()); |
| 317 |
| 318 uint64_t frame_count = std::min(source->frame_count(), dest->frame_count()); |
| 319 |
| 320 uint8_t* in_channel = static_cast<uint8_t*>(source->buffer()); |
| 321 uint8_t* out_channel = static_cast<uint8_t*>(dest->buffer()); |
| 322 |
| 323 for (uint32_t channel = 0; channel < in_type_.channels(); channel++) { |
| 324 TIn* in_sample = reinterpret_cast<TIn*>(in_channel); |
| 325 TOut* out_sample = reinterpret_cast<TOut*>(out_channel); |
| 326 if (mix) { |
| 327 for (uint64_t sample = 0; sample < frame_count; sample++) { |
| 328 MixSample(out_sample, in_sample); |
| 329 in_sample += in_type_.channels(); |
| 330 out_sample += out_type_.channels(); |
| 331 } |
| 332 } else { |
| 333 for (uint64_t sample = 0; sample < frame_count; sample++) { |
| 334 CopySample(out_sample, in_sample); |
| 335 in_sample += in_type_.channels(); |
| 336 out_sample += out_type_.channels(); |
| 337 } |
| 338 } |
| 339 in_channel += in_type_.sample_size(); |
| 340 out_channel += out_type_.sample_size(); |
| 341 } |
| 342 |
| 343 source->Advance(frame_count); |
| 344 dest->Advance(frame_count); |
| 345 } |
| 346 |
| 347 } // namespace media |
| 348 } // namespace mojo |
OLD | NEW |