OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 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 #ifndef MEDIA_BASE_AUDIO_SAMPLE_CONVERSION_H_ | |
6 #define MEDIA_BASE_AUDIO_SAMPLE_CONVERSION_H_ | |
7 | |
8 #include <cstdint> | |
9 | |
10 namespace media { | |
11 | |
12 namespace internal { | |
13 | |
14 // The bias function specifies a bias required for conversion to or from offset | |
15 // types. The only offset data type handled by AudioBus and AudioBuffer is | |
16 // uint8_t so this function is specialized for uint8_t and otherwise returns 0. | |
17 template <typename Integral> | |
18 inline Integral bias() { | |
19 return 0; | |
20 } | |
21 template <> | |
22 inline uint8_t bias() { | |
23 return 128; | |
24 } | |
25 | |
26 // TODO(cleichner): Remove and use std::lrint(f) when C++11 library features | |
DaleCurtis
2016/04/01 00:24:01
This function is now available.
| |
27 // are approved for use in Chromium. | |
28 template <typename Integral, typename Float> | |
29 inline Integral doRound(Float f) { | |
30 const Float point_five = 0.5; | |
31 return f < 0 ? static_cast<Integral>(f - point_five) | |
32 : static_cast<Integral>(f + point_five); | |
33 } | |
34 | |
35 // Special-case conversion from uint8_t to use an intermediate type that | |
36 // won't overflow after removing the offset. | |
37 template <typename Integral> | |
38 struct Expanded { | |
39 typedef Integral type; | |
40 }; | |
41 template <> | |
42 struct Expanded<uint8_t> { | |
43 typedef int16_t type; | |
44 }; | |
45 | |
46 // After removing the offset, the extremal values for uint8_t should come from | |
47 // int8_t. | |
48 template <typename Integral> | |
49 struct Fixed { | |
50 typedef Integral type; | |
51 }; | |
52 template <> | |
53 struct Fixed<uint8_t> { | |
54 typedef int8_t type; | |
55 }; | |
56 | |
57 // int32_t requires double precision for safe handling. | |
58 template <bool NeedsDouble> | |
59 struct SafeFloatHelper; | |
60 | |
61 template <> | |
62 struct SafeFloatHelper<false> { | |
63 typedef float type; | |
64 }; | |
65 | |
66 template <> | |
67 struct SafeFloatHelper<true> { | |
68 typedef double type; | |
DaleCurtis
2016/04/01 00:24:01
Why do we need a double? This will hurt performanc
| |
69 }; | |
70 | |
71 template <typename Integral> | |
72 struct SafeFloat : SafeFloatHelper<sizeof(Integral) >= sizeof(int32_t)> {}; | |
DaleCurtis
2016/04/01 00:24:01
We don't support anything higher than int32_t.
| |
73 | |
74 // The SampleConverter struct exists to partially specialize the ConvertSample() | |
75 // functions. The functions can then capture general strategies for converting | |
76 // between floating-point to integral types with the specifics such as extremal | |
77 // values and offsets being derived from the types rather than passed in as | |
78 // arguments. | |
79 template <typename Source, typename Dest> | |
80 struct SampleConverter { | |
81 static inline Dest Convert(Source sample); | |
82 }; | |
83 | |
84 // Any type can be converted to itself by returning the same values that are | |
85 // supplied. | |
86 template <typename S> | |
87 struct SampleConverter<S, S> { | |
88 static inline S Convert(S sample) { return sample; } | |
89 }; | |
90 | |
91 // Integral to floating type conversion. | |
92 template <typename Integral> | |
93 struct SampleConverter<Integral, float> { | |
94 static inline float Convert(Integral sample) { | |
95 using Fixed = typename Fixed<Integral>::type; | |
96 using Expanded = typename Expanded<Integral>::type; | |
97 const Expanded internal = static_cast<Expanded>(sample) - bias<Integral>(); | |
98 return internal * (internal < 0 ? -1.0f / std::numeric_limits<Fixed>::min() | |
99 : 1.0f / std::numeric_limits<Fixed>::max()); | |
100 } | |
101 }; | |
102 | |
103 // Floating-point to integral type conversion. | |
104 template <typename Integral> | |
105 struct SampleConverter<float, Integral> { | |
106 static inline Integral Convert(float sample) { | |
107 using Fixed = typename Fixed<Integral>::type; | |
108 using SafeFloat = typename SafeFloat<Integral>::type; | |
109 Fixed min = std::numeric_limits<Fixed>::min(); | |
110 Fixed max = std::numeric_limits<Fixed>::max(); | |
111 // Floating point samples are not guaranteed to be in [-1.0, 1.0] so they | |
112 // need to be clamped as a part of conversion to an integral type. | |
113 sample = std::min(std::max(sample, -1.0f), 1.0f); | |
DaleCurtis
2016/04/01 00:24:01
Does the benchmark improve if you write:
if (samp
| |
114 SafeFloat scale = | |
115 sample < 0 ? -static_cast<SafeFloat>(min) : static_cast<SafeFloat>(max); | |
116 SafeFloat safe_sample = static_cast<SafeFloat>(sample) * scale; | |
117 return doRound<Integral>(safe_sample) + bias<Integral>(); | |
118 } | |
119 }; | |
120 | |
121 // Integral -> Integral conversion can be done directly for signed integers | |
122 // through multiplication and division. | |
123 template <> | |
124 struct SampleConverter<int32_t, int16_t> { | |
125 static inline int16_t Convert(int32_t sample) { return sample >> 16; } | |
126 }; | |
127 | |
128 template <> | |
129 struct SampleConverter<int16_t, int32_t> { | |
130 static inline int32_t Convert(int16_t sample) { | |
131 return static_cast<int32_t>(sample) << 16; | |
132 } | |
133 }; | |
134 | |
135 } // namespace internal | |
136 | |
137 // ConvertSample converts a value interpreted as an audio sample from the | |
138 // Source type to the Dest type assuming the normal conventions for audio | |
139 // samples of a given type. | |
140 template <typename Source, typename Dest> | |
141 inline Dest ConvertSample(Source sample) { | |
142 return internal::SampleConverter<Source, Dest>::Convert(sample); | |
143 } | |
144 | |
145 // InterleavedToPlanar takes a pointer to a contiguous block of memory with | |
146 // interleaved samples of type Source, and starting |trim_start| frames into the | |
147 // memory it copies the next |frames_to_copy| frames into each of the channels | |
148 // in |channel_data| such that each channel is copied into the memory pointed to | |
149 // by one entry in the |channel_data| vector. In addition to deinterleaving, | |
150 // this function will convert the samples from the Source type to the Dest type. | |
151 // The memory should already be allocated and there should be enough allocated | |
152 // for each channel entry such that all of the frames in one channel can fit | |
153 // contiguously after conversion to the Dest type. | |
154 // | |
155 // InterleavedToPlanar determines how many channels to deinterleave from the | |
156 // source memory based on the dimension of the |channel_data| vector. | |
157 // | |
158 // The internal type allows this to accept vectors with many different | |
159 // representations such as void* or char* as long as the memory pointed to by | |
160 // the channel pointer can be reinterpreted as containing Source-typed elements. | |
161 // | |
162 // Source and Dest usually need to be explicitly specified, but Internal is | |
163 // normally inferred. | |
164 template <typename Source, typename Dest, typename Internal> | |
165 void InterleavedToPlanar(const Source* source, | |
166 size_t frames_to_copy, | |
167 size_t trim_start, | |
168 const std::vector<Internal*>& channel_data) { | |
169 const size_t channels = channel_data.size(); | |
170 for (size_t ch = 0; ch < channels; ++ch) { | |
171 Dest* single_channel_data = reinterpret_cast<Dest*>(channel_data[ch]); | |
172 for (size_t i = trim_start, offset = ch; i < trim_start + frames_to_copy; | |
173 ++i, offset += channels) { | |
174 single_channel_data[i] = ConvertSample<Source, Dest>(source[offset]); | |
175 } | |
176 } | |
177 } | |
178 | |
179 // PlanarToInterleaved takes a vector of pointers to contiguous memory blocks | |
180 // containing samples of type Source and interleaves them into the contiguous | |
181 // memory pointed to by the dest_data pointer and converts them to type Dest if | |
182 // Source and Dest differ. It trims |trim_start| samples from the beginning of | |
183 // each sample and copies |frames_to_copy| samples from each of the channels | |
184 // specified in |channel_data| into frames in the |dest_data| memory. | |
185 // | |
186 // PlanarToInterleaved determines how many channels to interleave into the | |
187 // dest_data memory based on the dimension of the |channel_data| vector. | |
188 // | |
189 // The internal type allows this to accept vectors with many different | |
190 // representations such as void* or char* as long as the memory pointed to by | |
191 // the channel pointer can be reinterpreted as containing Source-typed elements. | |
192 // | |
193 // Source and Dest usually need to be explicitly specified, but Internal is | |
194 // normally inferred. | |
195 template <typename Source, typename Dest, typename Internal> | |
196 void PlanarToInterleaved(const std::vector<Internal*>& channel_data, | |
197 size_t frames_to_copy, | |
198 size_t trim_start, | |
199 Dest* dest_data) { | |
200 for (size_t ch = 0; ch < channel_data.size(); ++ch) { | |
201 const Source* source_data = | |
202 reinterpret_cast<const Source*>(channel_data[ch]) + trim_start; | |
203 for (size_t i = 0, offset = ch; i < frames_to_copy; | |
204 ++i, offset += channel_data.size()) { | |
205 dest_data[offset] = ConvertSample<Source, Dest>(source_data[i]); | |
206 } | |
207 } | |
208 } | |
209 | |
210 } // namespace media | |
211 | |
212 #endif // MEDIA_BASE_AUDIO_SAMPLE_CONVERSION_H_ | |
OLD | NEW |