Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(61)

Side by Side Diff: media/base/audio_sample_conversion.h

Issue 1854433002: Clamp AudioBuffer float to int{16,32} conversion (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix handling of 32-bit, fix asymmetric scale Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « media/base/audio_bus_unittest.cc ('k') | media/media.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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_
OLDNEW
« no previous file with comments | « media/base/audio_bus_unittest.cc ('k') | media/media.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698