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

Side by Side Diff: webkit/renderer/media/android/audio_decoder_android.cc

Issue 17502007: Move webkit/renderer/media/android/ to content/renderer/media/android/. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 6 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2013 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 "webkit/renderer/media/audio_decoder.h"
6
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <limits.h>
10 #include <sys/mman.h>
11 #include <unistd.h>
12 #include <vector>
13
14 #include "base/callback.h"
15 #include "base/file_descriptor_posix.h"
16 #include "base/logging.h"
17 #include "base/posix/eintr_wrapper.h"
18 #include "base/shared_memory.h"
19 #include "media/base/android/webaudio_media_codec_info.h"
20 #include "media/base/audio_bus.h"
21 #include "media/base/limits.h"
22 #include "third_party/WebKit/public/platform/WebAudioBus.h"
23
24 namespace webkit_media {
25
26 class AudioDecoderIO {
27 public:
28 AudioDecoderIO(const char* data, size_t data_size);
29 ~AudioDecoderIO();
30 bool ShareEncodedToProcess(base::SharedMemoryHandle* handle);
31
32 // Returns true if AudioDecoderIO was successfully created.
33 bool IsValid() const;
34
35 int read_fd() const { return read_fd_; }
36 int write_fd() const { return write_fd_; }
37
38 private:
39 // Shared memory that will hold the encoded audio data. This is
40 // used by MediaCodec for decoding.
41 base::SharedMemory encoded_shared_memory_;
42
43 // A pipe used to communicate with MediaCodec. MediaCodec owns
44 // write_fd_ and writes to it.
45 int read_fd_;
46 int write_fd_;
47
48 DISALLOW_COPY_AND_ASSIGN(AudioDecoderIO);
49 };
50
51 AudioDecoderIO::AudioDecoderIO(const char* data, size_t data_size)
52 : read_fd_(-1),
53 write_fd_(-1) {
54
55 if (!data || !data_size || data_size > 0x80000000)
56 return;
57
58 // Create the shared memory and copy our data to it so that
59 // MediaCodec can access it.
60 encoded_shared_memory_.CreateAndMapAnonymous(data_size);
61
62 if (!encoded_shared_memory_.memory())
63 return;
64
65 memcpy(encoded_shared_memory_.memory(), data, data_size);
66
67 // Create a pipe for reading/writing the decoded PCM data
68 int pipefd[2];
69
70 if (pipe(pipefd))
71 return;
72
73 read_fd_ = pipefd[0];
74 write_fd_ = pipefd[1];
75 }
76
77 AudioDecoderIO::~AudioDecoderIO() {
78 // Close the read end of the pipe. The write end should have been
79 // closed by MediaCodec.
80 if (read_fd_ >= 0 && close(read_fd_)) {
81 DVLOG(1) << "Cannot close read fd " << read_fd_
82 << ": " << strerror(errno);
83 }
84 }
85
86 bool AudioDecoderIO::IsValid() const {
87 return read_fd_ >= 0 && write_fd_ >= 0 &&
88 encoded_shared_memory_.memory();
89 }
90
91 bool AudioDecoderIO::ShareEncodedToProcess(base::SharedMemoryHandle* handle) {
92 return encoded_shared_memory_.ShareToProcess(
93 base::Process::Current().handle(),
94 handle);
95 }
96
97 static float ConvertSampleToFloat(int16_t sample) {
98 const float kMaxScale = 1.0f / std::numeric_limits<int16_t>::max();
99 const float kMinScale = -1.0f / std::numeric_limits<int16_t>::min();
100
101 return sample * (sample < 0 ? kMinScale : kMaxScale);
102 }
103
104 // The number of frames is known so preallocate the destination
105 // bus and copy the pcm data to the destination bus as it's being
106 // received.
107 static void CopyPcmDataToBus(int input_fd,
108 WebKit::WebAudioBus* destination_bus,
109 size_t number_of_frames,
110 unsigned number_of_channels,
111 double file_sample_rate) {
112 destination_bus->initialize(number_of_channels,
113 number_of_frames,
114 file_sample_rate);
115
116 int16_t pipe_data[PIPE_BUF / sizeof(int16_t)];
117 size_t decoded_frames = 0;
118 ssize_t nread;
119
120 while ((nread = HANDLE_EINTR(read(input_fd, pipe_data, sizeof(pipe_data)))) >
121 0) {
122 size_t samples_in_pipe = nread / sizeof(int16_t);
123 for (size_t m = 0; m < samples_in_pipe; m += number_of_channels) {
124 if (decoded_frames >= number_of_frames)
125 break;
126
127 for (size_t k = 0; k < number_of_channels; ++k) {
128 int16_t sample = pipe_data[m + k];
129 destination_bus->channelData(k)[decoded_frames] =
130 ConvertSampleToFloat(sample);
131 }
132 ++decoded_frames;
133 }
134 }
135 }
136
137 // The number of frames is unknown, so keep reading and buffering
138 // until there's no more data and then copy the data to the
139 // destination bus.
140 static void BufferAndCopyPcmDataToBus(int input_fd,
141 WebKit::WebAudioBus* destination_bus,
142 unsigned number_of_channels,
143 double file_sample_rate) {
144 int16_t pipe_data[PIPE_BUF / sizeof(int16_t)];
145 std::vector<int16_t> decoded_samples;
146 ssize_t nread;
147
148 while ((nread = HANDLE_EINTR(read(input_fd, pipe_data, sizeof(pipe_data)))) >
149 0) {
150 size_t samples_in_pipe = nread / sizeof(int16_t);
151 if (decoded_samples.size() + samples_in_pipe > decoded_samples.capacity()) {
152 decoded_samples.reserve(std::max(samples_in_pipe,
153 2 * decoded_samples.capacity()));
154 }
155 std::copy(pipe_data,
156 pipe_data + samples_in_pipe,
157 back_inserter(decoded_samples));
158 }
159
160 DVLOG(1) << "Total samples read = " << decoded_samples.size();
161
162 // Convert the samples and save them in the audio bus.
163 size_t number_of_samples = decoded_samples.size();
164 size_t number_of_frames = decoded_samples.size() / number_of_channels;
165 size_t decoded_frames = 0;
166
167 destination_bus->initialize(number_of_channels,
168 number_of_frames,
169 file_sample_rate);
170
171 for (size_t m = 0; m < number_of_samples; m += number_of_channels) {
172 for (size_t k = 0; k < number_of_channels; ++k) {
173 int16_t sample = decoded_samples[m + k];
174 destination_bus->channelData(k)[decoded_frames] =
175 ConvertSampleToFloat(sample);
176 }
177 ++decoded_frames;
178 }
179 }
180
181 // To decode audio data, we want to use the Android MediaCodec class.
182 // But this can't run in a sandboxed process so we need initiate the
183 // request to MediaCodec in the browser. To do this, we create a
184 // shared memory buffer that holds the audio data. We send a message
185 // to the browser to start the decoder using this buffer and one end
186 // of a pipe. The MediaCodec class will decode the data from the
187 // shared memory and write the PCM samples back to us over a pipe.
188 bool DecodeAudioFileData(WebKit::WebAudioBus* destination_bus, const char* data,
189 size_t data_size, double sample_rate,
190 const WebAudioMediaCodecRunner& runner) {
191 AudioDecoderIO audio_decoder(data, data_size);
192
193 if (!audio_decoder.IsValid())
194 return false;
195
196 base::SharedMemoryHandle encoded_data_handle;
197 audio_decoder.ShareEncodedToProcess(&encoded_data_handle);
198 base::FileDescriptor fd(audio_decoder.write_fd(), true);
199
200 DVLOG(1) << "DecodeAudioFileData: Starting MediaCodec";
201
202 // Start MediaCodec processing in the browser which will read from
203 // encoded_data_handle for our shared memory and write the decoded
204 // PCM samples (16-bit integer) to our pipe.
205
206 runner.Run(encoded_data_handle, fd, data_size);
207
208 // First, read the number of channels, the sample rate, and the
209 // number of frames and a flag indicating if the file is an
210 // ogg/vorbis file. This must be coordinated with
211 // WebAudioMediaCodecBridge!
212 //
213 // TODO(rtoy): If we know the number of samples, we can create the
214 // destination bus directly and do the conversion directly to the
215 // bus instead of buffering up everything before saving the data to
216 // the bus.
217
218 int input_fd = audio_decoder.read_fd();
219 struct media::WebAudioMediaCodecInfo info;
220
221 DVLOG(1) << "Reading audio file info from fd " << input_fd;
222 ssize_t nread = HANDLE_EINTR(read(input_fd, &info, sizeof(info)));
223 DVLOG(1) << "read: " << nread << " bytes:\n"
224 << " 0: number of channels = " << info.channel_count << "\n"
225 << " 1: sample rate = " << info.sample_rate << "\n"
226 << " 2: number of frames = " << info.number_of_frames << "\n";
227
228 if (nread != sizeof(info))
229 return false;
230
231 unsigned number_of_channels = info.channel_count;
232 double file_sample_rate = static_cast<double>(info.sample_rate);
233 size_t number_of_frames = info.number_of_frames;
234
235 // Sanity checks
236 if (!number_of_channels ||
237 number_of_channels > media::limits::kMaxChannels ||
238 file_sample_rate < media::limits::kMinSampleRate ||
239 file_sample_rate > media::limits::kMaxSampleRate) {
240 return false;
241 }
242
243 if (number_of_frames > 0) {
244 CopyPcmDataToBus(input_fd,
245 destination_bus,
246 number_of_frames,
247 number_of_channels,
248 file_sample_rate);
249 } else {
250 BufferAndCopyPcmDataToBus(input_fd,
251 destination_bus,
252 number_of_channels,
253 file_sample_rate);
254 }
255
256 return true;
257 }
258
259 } // namespace webkit_media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698