| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 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 "content/renderer/media/android/audio_decoder_android.h" | 5 #include "content/renderer/media/android/audio_decoder_android.h" |
| 6 | 6 |
| 7 #include <errno.h> | 7 #include <errno.h> |
| 8 #include <fcntl.h> | 8 #include <fcntl.h> |
| 9 #include <limits.h> | 9 #include <limits.h> |
| 10 #include <sys/mman.h> | 10 #include <sys/mman.h> |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 106 // basic guide to the WAVE file format. | 106 // basic guide to the WAVE file format. |
| 107 class WAVEDecoder { | 107 class WAVEDecoder { |
| 108 public: | 108 public: |
| 109 WAVEDecoder(const uint8* data, size_t data_size); | 109 WAVEDecoder(const uint8* data, size_t data_size); |
| 110 ~WAVEDecoder(); | 110 ~WAVEDecoder(); |
| 111 | 111 |
| 112 // Try to decode the data as a WAVE file. If the data is a supported | 112 // Try to decode the data as a WAVE file. If the data is a supported |
| 113 // WAVE file, |destination_bus| is filled with the decoded data and | 113 // WAVE file, |destination_bus| is filled with the decoded data and |
| 114 // DecodeWAVEFile returns true. Otherwise, DecodeWAVEFile returns | 114 // DecodeWAVEFile returns true. Otherwise, DecodeWAVEFile returns |
| 115 // false. | 115 // false. |
| 116 bool DecodeWAVEFile(WebKit::WebAudioBus* destination_bus); | 116 bool DecodeWAVEFile(blink::WebAudioBus* destination_bus); |
| 117 | 117 |
| 118 private: | 118 private: |
| 119 // Minimum number of bytes in a WAVE file to hold all of the data we | 119 // Minimum number of bytes in a WAVE file to hold all of the data we |
| 120 // need to interpret it as a WAVE file. | 120 // need to interpret it as a WAVE file. |
| 121 static const unsigned kMinimumWAVLength = 44; | 121 static const unsigned kMinimumWAVLength = 44; |
| 122 | 122 |
| 123 // Number of bytes in the chunk ID field. | 123 // Number of bytes in the chunk ID field. |
| 124 static const unsigned kChunkIDLength = 4; | 124 static const unsigned kChunkIDLength = 4; |
| 125 | 125 |
| 126 // Number of bytes in the chunk size field. | 126 // Number of bytes in the chunk size field. |
| (...skipping 23 matching lines...) Expand all Loading... |
| 150 // Read a WAVE chunk header including the chunk ID and chunk size. | 150 // Read a WAVE chunk header including the chunk ID and chunk size. |
| 151 // Returns false if the header could not be read. | 151 // Returns false if the header could not be read. |
| 152 bool ReadChunkHeader(); | 152 bool ReadChunkHeader(); |
| 153 | 153 |
| 154 // Read and parse the "fmt" chunk. Returns false if the fmt chunk | 154 // Read and parse the "fmt" chunk. Returns false if the fmt chunk |
| 155 // could not be read or contained unsupported formats. | 155 // could not be read or contained unsupported formats. |
| 156 bool ReadFMTChunk(); | 156 bool ReadFMTChunk(); |
| 157 | 157 |
| 158 // Read data chunk and save it to |destination_bus|. Returns false | 158 // Read data chunk and save it to |destination_bus|. Returns false |
| 159 // if the data chunk could not be read correctly. | 159 // if the data chunk could not be read correctly. |
| 160 bool CopyDataChunkToBus(WebKit::WebAudioBus* destination_bus); | 160 bool CopyDataChunkToBus(blink::WebAudioBus* destination_bus); |
| 161 | 161 |
| 162 // The WAVE chunk ID that identifies the chunk. | 162 // The WAVE chunk ID that identifies the chunk. |
| 163 uint8_t chunk_id_[kChunkIDLength]; | 163 uint8_t chunk_id_[kChunkIDLength]; |
| 164 | 164 |
| 165 // The number of bytes in the data portion of the chunk. | 165 // The number of bytes in the data portion of the chunk. |
| 166 size_t chunk_size_; | 166 size_t chunk_size_; |
| 167 | 167 |
| 168 // The current position within the WAVE file. | 168 // The current position within the WAVE file. |
| 169 const uint8_t* buffer_; | 169 const uint8_t* buffer_; |
| 170 | 170 |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 286 // We only support 8, 16, and 24 bits per sample. | 286 // We only support 8, 16, and 24 bits per sample. |
| 287 if (bits_per_sample == 8 || bits_per_sample == 16 || bits_per_sample == 24) { | 287 if (bits_per_sample == 8 || bits_per_sample == 16 || bits_per_sample == 24) { |
| 288 bytes_per_sample_ = bits_per_sample / 8; | 288 bytes_per_sample_ = bits_per_sample / 8; |
| 289 return true; | 289 return true; |
| 290 } | 290 } |
| 291 | 291 |
| 292 DVLOG(1) << "Unsupported bits per sample: " << bits_per_sample; | 292 DVLOG(1) << "Unsupported bits per sample: " << bits_per_sample; |
| 293 return false; | 293 return false; |
| 294 } | 294 } |
| 295 | 295 |
| 296 bool WAVEDecoder::CopyDataChunkToBus(WebKit::WebAudioBus* destination_bus) { | 296 bool WAVEDecoder::CopyDataChunkToBus(blink::WebAudioBus* destination_bus) { |
| 297 // The data chunk contains the audio data itself. | 297 // The data chunk contains the audio data itself. |
| 298 if (!bytes_per_sample_ || bytes_per_sample_ > kMaximumBytesPerSample) { | 298 if (!bytes_per_sample_ || bytes_per_sample_ > kMaximumBytesPerSample) { |
| 299 DVLOG(1) << "WARNING: data chunk without preceeding fmt chunk," | 299 DVLOG(1) << "WARNING: data chunk without preceeding fmt chunk," |
| 300 << " or invalid bytes per sample."; | 300 << " or invalid bytes per sample."; |
| 301 return false; | 301 return false; |
| 302 } | 302 } |
| 303 | 303 |
| 304 VLOG(0) << "Decoding WAVE file: " << number_of_channels_ << " channels, " | 304 VLOG(0) << "Decoding WAVE file: " << number_of_channels_ << " channels, " |
| 305 << sample_rate_ << " kHz, " | 305 << sample_rate_ << " kHz, " |
| 306 << chunk_size_ / bytes_per_sample_ / number_of_channels_ | 306 << chunk_size_ / bytes_per_sample_ / number_of_channels_ |
| (...skipping 12 matching lines...) Expand all Loading... |
| 319 int16_t sample = ReadPCMSample(buffer_); | 319 int16_t sample = ReadPCMSample(buffer_); |
| 320 | 320 |
| 321 buffer_ += bytes_per_sample_; | 321 buffer_ += bytes_per_sample_; |
| 322 destination_bus->channelData(k)[m] = ConvertSampleToFloat(sample); | 322 destination_bus->channelData(k)[m] = ConvertSampleToFloat(sample); |
| 323 } | 323 } |
| 324 } | 324 } |
| 325 | 325 |
| 326 return true; | 326 return true; |
| 327 } | 327 } |
| 328 | 328 |
| 329 bool WAVEDecoder::DecodeWAVEFile(WebKit::WebAudioBus* destination_bus) { | 329 bool WAVEDecoder::DecodeWAVEFile(blink::WebAudioBus* destination_bus) { |
| 330 // Parse and decode WAVE file. If we can't parse it, return false. | 330 // Parse and decode WAVE file. If we can't parse it, return false. |
| 331 | 331 |
| 332 if (buffer_ + kMinimumWAVLength > buffer_end_) { | 332 if (buffer_ + kMinimumWAVLength > buffer_end_) { |
| 333 DVLOG(1) << "Buffer too small to contain full WAVE header: "; | 333 DVLOG(1) << "Buffer too small to contain full WAVE header: "; |
| 334 return false; | 334 return false; |
| 335 } | 335 } |
| 336 | 336 |
| 337 // Do we have a RIFF file? | 337 // Do we have a RIFF file? |
| 338 ReadChunkHeader(); | 338 ReadChunkHeader(); |
| 339 if (memcmp(chunk_id_, "RIFF", kChunkIDLength) != 0) { | 339 if (memcmp(chunk_id_, "RIFF", kChunkIDLength) != 0) { |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 388 // If we get here, that means we didn't find a data chunk, so we | 388 // If we get here, that means we didn't find a data chunk, so we |
| 389 // couldn't handle this WAVE file. | 389 // couldn't handle this WAVE file. |
| 390 | 390 |
| 391 return false; | 391 return false; |
| 392 } | 392 } |
| 393 | 393 |
| 394 // The number of frames is known so preallocate the destination | 394 // The number of frames is known so preallocate the destination |
| 395 // bus and copy the pcm data to the destination bus as it's being | 395 // bus and copy the pcm data to the destination bus as it's being |
| 396 // received. | 396 // received. |
| 397 static void CopyPcmDataToBus(int input_fd, | 397 static void CopyPcmDataToBus(int input_fd, |
| 398 WebKit::WebAudioBus* destination_bus, | 398 blink::WebAudioBus* destination_bus, |
| 399 size_t number_of_frames, | 399 size_t number_of_frames, |
| 400 unsigned number_of_channels, | 400 unsigned number_of_channels, |
| 401 double file_sample_rate) { | 401 double file_sample_rate) { |
| 402 destination_bus->initialize(number_of_channels, | 402 destination_bus->initialize(number_of_channels, |
| 403 number_of_frames, | 403 number_of_frames, |
| 404 file_sample_rate); | 404 file_sample_rate); |
| 405 | 405 |
| 406 int16_t pipe_data[PIPE_BUF / sizeof(int16_t)]; | 406 int16_t pipe_data[PIPE_BUF / sizeof(int16_t)]; |
| 407 size_t decoded_frames = 0; | 407 size_t decoded_frames = 0; |
| 408 ssize_t nread; | 408 ssize_t nread; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 426 // number_of_frames is only an estimate. Resize the buffer with the | 426 // number_of_frames is only an estimate. Resize the buffer with the |
| 427 // actual number of received frames. | 427 // actual number of received frames. |
| 428 if (decoded_frames < number_of_frames) | 428 if (decoded_frames < number_of_frames) |
| 429 destination_bus->resizeSmaller(decoded_frames); | 429 destination_bus->resizeSmaller(decoded_frames); |
| 430 } | 430 } |
| 431 | 431 |
| 432 // The number of frames is unknown, so keep reading and buffering | 432 // The number of frames is unknown, so keep reading and buffering |
| 433 // until there's no more data and then copy the data to the | 433 // until there's no more data and then copy the data to the |
| 434 // destination bus. | 434 // destination bus. |
| 435 static void BufferAndCopyPcmDataToBus(int input_fd, | 435 static void BufferAndCopyPcmDataToBus(int input_fd, |
| 436 WebKit::WebAudioBus* destination_bus, | 436 blink::WebAudioBus* destination_bus, |
| 437 unsigned number_of_channels, | 437 unsigned number_of_channels, |
| 438 double file_sample_rate) { | 438 double file_sample_rate) { |
| 439 int16_t pipe_data[PIPE_BUF / sizeof(int16_t)]; | 439 int16_t pipe_data[PIPE_BUF / sizeof(int16_t)]; |
| 440 std::vector<int16_t> decoded_samples; | 440 std::vector<int16_t> decoded_samples; |
| 441 ssize_t nread; | 441 ssize_t nread; |
| 442 | 442 |
| 443 while ((nread = HANDLE_EINTR(read(input_fd, pipe_data, sizeof(pipe_data)))) > | 443 while ((nread = HANDLE_EINTR(read(input_fd, pipe_data, sizeof(pipe_data)))) > |
| 444 0) { | 444 0) { |
| 445 size_t samples_in_pipe = nread / sizeof(int16_t); | 445 size_t samples_in_pipe = nread / sizeof(int16_t); |
| 446 if (decoded_samples.size() + samples_in_pipe > decoded_samples.capacity()) { | 446 if (decoded_samples.size() + samples_in_pipe > decoded_samples.capacity()) { |
| (...skipping 24 matching lines...) Expand all Loading... |
| 471 } | 471 } |
| 472 ++decoded_frames; | 472 ++decoded_frames; |
| 473 } | 473 } |
| 474 | 474 |
| 475 // number_of_frames is only an estimate. Resize the buffer with the | 475 // number_of_frames is only an estimate. Resize the buffer with the |
| 476 // actual number of received frames. | 476 // actual number of received frames. |
| 477 if (decoded_frames < number_of_frames) | 477 if (decoded_frames < number_of_frames) |
| 478 destination_bus->resizeSmaller(decoded_frames); | 478 destination_bus->resizeSmaller(decoded_frames); |
| 479 } | 479 } |
| 480 | 480 |
| 481 static bool TryWAVEFileDecoder(WebKit::WebAudioBus* destination_bus, | 481 static bool TryWAVEFileDecoder(blink::WebAudioBus* destination_bus, |
| 482 const uint8_t* encoded_data, | 482 const uint8_t* encoded_data, |
| 483 size_t data_size) { | 483 size_t data_size) { |
| 484 WAVEDecoder decoder(encoded_data, data_size); | 484 WAVEDecoder decoder(encoded_data, data_size); |
| 485 | 485 |
| 486 return decoder.DecodeWAVEFile(destination_bus); | 486 return decoder.DecodeWAVEFile(destination_bus); |
| 487 } | 487 } |
| 488 | 488 |
| 489 // To decode audio data, we want to use the Android MediaCodec class. | 489 // To decode audio data, we want to use the Android MediaCodec class. |
| 490 // But this can't run in a sandboxed process so we need initiate the | 490 // But this can't run in a sandboxed process so we need initiate the |
| 491 // request to MediaCodec in the browser. To do this, we create a | 491 // request to MediaCodec in the browser. To do this, we create a |
| 492 // shared memory buffer that holds the audio data. We send a message | 492 // shared memory buffer that holds the audio data. We send a message |
| 493 // to the browser to start the decoder using this buffer and one end | 493 // to the browser to start the decoder using this buffer and one end |
| 494 // of a pipe. The MediaCodec class will decode the data from the | 494 // of a pipe. The MediaCodec class will decode the data from the |
| 495 // shared memory and write the PCM samples back to us over a pipe. | 495 // shared memory and write the PCM samples back to us over a pipe. |
| 496 bool DecodeAudioFileData(WebKit::WebAudioBus* destination_bus, const char* data, | 496 bool DecodeAudioFileData(blink::WebAudioBus* destination_bus, const char* data, |
| 497 size_t data_size, double sample_rate, | 497 size_t data_size, double sample_rate, |
| 498 scoped_refptr<ThreadSafeSender> sender) { | 498 scoped_refptr<ThreadSafeSender> sender) { |
| 499 // Try to decode the data as a WAVE file first. If it can't be | 499 // Try to decode the data as a WAVE file first. If it can't be |
| 500 // decoded, use MediaCodec. See crbug.com/259048. | 500 // decoded, use MediaCodec. See crbug.com/259048. |
| 501 if (TryWAVEFileDecoder( | 501 if (TryWAVEFileDecoder( |
| 502 destination_bus, reinterpret_cast<const uint8_t*>(data), data_size)) { | 502 destination_bus, reinterpret_cast<const uint8_t*>(data), data_size)) { |
| 503 return true; | 503 return true; |
| 504 } | 504 } |
| 505 | 505 |
| 506 AudioDecoderIO audio_decoder(data, data_size); | 506 AudioDecoderIO audio_decoder(data, data_size); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 565 BufferAndCopyPcmDataToBus(input_fd, | 565 BufferAndCopyPcmDataToBus(input_fd, |
| 566 destination_bus, | 566 destination_bus, |
| 567 number_of_channels, | 567 number_of_channels, |
| 568 file_sample_rate); | 568 file_sample_rate); |
| 569 } | 569 } |
| 570 | 570 |
| 571 return true; | 571 return true; |
| 572 } | 572 } |
| 573 | 573 |
| 574 } // namespace content | 574 } // namespace content |
| OLD | NEW |