Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 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 "media/mojo/clients/mojo_audio_decoder.h" | 5 #include "media/mojo/clients/mojo_audio_decoder.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/bind_helpers.h" | 8 #include "base/bind_helpers.h" |
| 9 #include "base/callback_helpers.h" | 9 #include "base/callback_helpers.h" |
| 10 #include "base/location.h" | 10 #include "base/location.h" |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/single_thread_task_runner.h" | 12 #include "base/single_thread_task_runner.h" |
| 13 #include "base/threading/thread_task_runner_handle.h" | 13 #include "base/threading/thread_task_runner_handle.h" |
| 14 #include "media/base/audio_buffer.h" | 14 #include "media/base/audio_buffer.h" |
| 15 #include "media/base/cdm_context.h" | 15 #include "media/base/cdm_context.h" |
| 16 #include "media/base/demuxer_stream.h" | |
| 16 #include "media/mojo/common/media_type_converters.h" | 17 #include "media/mojo/common/media_type_converters.h" |
| 18 #include "media/mojo/common/mojo_decoder_buffer_converter.h" | |
| 17 | 19 |
| 18 namespace media { | 20 namespace media { |
| 19 | 21 |
| 20 MojoAudioDecoder::MojoAudioDecoder( | 22 MojoAudioDecoder::MojoAudioDecoder( |
| 21 scoped_refptr<base::SingleThreadTaskRunner> task_runner, | 23 scoped_refptr<base::SingleThreadTaskRunner> task_runner, |
| 22 mojom::AudioDecoderPtr remote_decoder) | 24 mojom::AudioDecoderPtr remote_decoder) |
| 23 : task_runner_(task_runner), | 25 : task_runner_(task_runner), |
| 24 remote_decoder_info_(remote_decoder.PassInterface()), | 26 remote_decoder_info_(remote_decoder.PassInterface()), |
| 25 binding_(this), | 27 binding_(this), |
| 26 has_connection_error_(false), | 28 has_connection_error_(false), |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 49 // Fail immediately if the stream is encrypted but |cdm_context| is invalid. | 51 // Fail immediately if the stream is encrypted but |cdm_context| is invalid. |
| 50 int cdm_id = (config.is_encrypted() && cdm_context) | 52 int cdm_id = (config.is_encrypted() && cdm_context) |
| 51 ? cdm_context->GetCdmId() | 53 ? cdm_context->GetCdmId() |
| 52 : CdmContext::kInvalidCdmId; | 54 : CdmContext::kInvalidCdmId; |
| 53 | 55 |
| 54 if (config.is_encrypted() && CdmContext::kInvalidCdmId == cdm_id) { | 56 if (config.is_encrypted() && CdmContext::kInvalidCdmId == cdm_id) { |
| 55 task_runner_->PostTask(FROM_HERE, base::Bind(init_cb, false)); | 57 task_runner_->PostTask(FROM_HERE, base::Bind(init_cb, false)); |
| 56 return; | 58 return; |
| 57 } | 59 } |
| 58 | 60 |
| 59 // If connection error has happened, fail immediately. | |
| 60 if (remote_decoder_.encountered_error()) { | |
|
sandersd (OOO until July 31)
2016/06/27 20:24:54
We use this pattern everywhere; what is the expect
sandersd (OOO until July 31)
2016/06/27 20:25:20
*now guaranteed
Ken Rockot(use gerrit already)
2016/06/27 21:00:27
The correct thing to do is set an error handler an
sandersd (OOO until July 31)
2016/06/27 21:04:21
Right, but what if an error has already happened?
Ken Rockot(use gerrit already)
2016/06/27 21:17:21
encountered_error() only ever changes value in res
xhwang
2016/06/28 01:11:48
What Ken said. Basically encountered_error() will
| |
| 61 task_runner_->PostTask(FROM_HERE, base::Bind(init_cb, false)); | |
| 62 return; | |
| 63 } | |
| 64 | |
| 65 // Otherwise, set an error handler to catch the connection error. | 61 // Otherwise, set an error handler to catch the connection error. |
| 66 // Using base::Unretained(this) is safe because |this| owns |remote_decoder_|, | 62 // Using base::Unretained(this) is safe because |this| owns |remote_decoder_|, |
| 67 // and the error handler can't be invoked once |remote_decoder_| is destroyed. | 63 // and the error handler can't be invoked once |remote_decoder_| is destroyed. |
| 68 remote_decoder_.set_connection_error_handler( | 64 remote_decoder_.set_connection_error_handler( |
| 69 base::Bind(&MojoAudioDecoder::OnConnectionError, base::Unretained(this))); | 65 base::Bind(&MojoAudioDecoder::OnConnectionError, base::Unretained(this))); |
| 70 | 66 |
| 71 init_cb_ = init_cb; | 67 init_cb_ = init_cb; |
| 72 output_cb_ = output_cb; | 68 output_cb_ = output_cb; |
| 73 | 69 |
| 74 // Using base::Unretained(this) is safe because |this| owns |remote_decoder_|, | 70 // Using base::Unretained(this) is safe because |this| owns |remote_decoder_|, |
| 75 // and the callback won't be dispatched if |remote_decoder_| is destroyed. | 71 // and the callback won't be dispatched if |remote_decoder_| is destroyed. |
| 76 remote_decoder_->Initialize( | 72 remote_decoder_->Initialize( |
| 77 binding_.CreateInterfacePtrAndBind(), | 73 binding_.CreateInterfacePtrAndBind(), |
| 78 mojom::AudioDecoderConfig::From(config), cdm_id, | 74 mojom::AudioDecoderConfig::From(config), cdm_id, |
| 79 base::Bind(&MojoAudioDecoder::OnInitialized, base::Unretained(this))); | 75 base::Bind(&MojoAudioDecoder::OnInitialized, base::Unretained(this))); |
| 80 } | 76 } |
| 81 | 77 |
| 82 void MojoAudioDecoder::Decode(const scoped_refptr<DecoderBuffer>& media_buffer, | 78 void MojoAudioDecoder::Decode(const scoped_refptr<DecoderBuffer>& media_buffer, |
| 83 const DecodeCB& decode_cb) { | 79 const DecodeCB& decode_cb) { |
| 84 DVLOG(3) << __FUNCTION__; | 80 DVLOG(3) << __FUNCTION__; |
| 85 DCHECK(task_runner_->BelongsToCurrentThread()); | 81 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 86 | 82 |
| 87 if (has_connection_error_) { | 83 if (has_connection_error_) { |
| 88 task_runner_->PostTask(FROM_HERE, | 84 task_runner_->PostTask(FROM_HERE, |
| 89 base::Bind(decode_cb, DecodeStatus::DECODE_ERROR)); | 85 base::Bind(decode_cb, DecodeStatus::DECODE_ERROR)); |
| 90 return; | 86 return; |
| 91 } | 87 } |
| 92 | 88 |
| 93 mojom::DecoderBufferPtr buffer = TransferDecoderBuffer(media_buffer); | 89 mojom::DecoderBufferPtr buffer = |
| 90 mojo_decoder_buffer_writer_->WriteDecoderBuffer(media_buffer); | |
| 94 if (!buffer) { | 91 if (!buffer) { |
| 95 task_runner_->PostTask(FROM_HERE, | 92 task_runner_->PostTask(FROM_HERE, |
| 96 base::Bind(decode_cb, DecodeStatus::DECODE_ERROR)); | 93 base::Bind(decode_cb, DecodeStatus::DECODE_ERROR)); |
| 97 return; | 94 return; |
| 98 } | 95 } |
| 99 | 96 |
| 100 DCHECK(decode_cb_.is_null()); | 97 DCHECK(decode_cb_.is_null()); |
| 101 decode_cb_ = decode_cb; | 98 decode_cb_ = decode_cb; |
| 102 | 99 |
| 103 remote_decoder_->Decode( | 100 remote_decoder_->Decode( |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 157 base::ResetAndReturn(&reset_cb_).Run(); | 154 base::ResetAndReturn(&reset_cb_).Run(); |
| 158 } | 155 } |
| 159 | 156 |
| 160 void MojoAudioDecoder::OnInitialized(bool success, | 157 void MojoAudioDecoder::OnInitialized(bool success, |
| 161 bool needs_bitstream_conversion) { | 158 bool needs_bitstream_conversion) { |
| 162 DVLOG(1) << __FUNCTION__ << ": success:" << success; | 159 DVLOG(1) << __FUNCTION__ << ": success:" << success; |
| 163 DCHECK(task_runner_->BelongsToCurrentThread()); | 160 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 164 | 161 |
| 165 needs_bitstream_conversion_ = needs_bitstream_conversion; | 162 needs_bitstream_conversion_ = needs_bitstream_conversion; |
| 166 | 163 |
| 167 if (success) | 164 if (success) { |
| 168 CreateDataPipe(); | 165 mojo::ScopedDataPipeConsumerHandle remote_consumer_handle; |
| 166 mojo_decoder_buffer_writer_ = MojoDecoderBufferWriter::Create( | |
| 167 DemuxerStream::AUDIO, &remote_consumer_handle); | |
| 168 // Pass consumer end to |remote_decoder_|. | |
| 169 remote_decoder_->SetDataSource(std::move(remote_consumer_handle)); | |
| 170 } | |
| 169 | 171 |
| 170 base::ResetAndReturn(&init_cb_).Run(success); | 172 base::ResetAndReturn(&init_cb_).Run(success); |
| 171 } | 173 } |
| 172 | 174 |
| 173 void MojoAudioDecoder::OnDecodeStatus(mojom::DecodeStatus status) { | 175 void MojoAudioDecoder::OnDecodeStatus(mojom::DecodeStatus status) { |
| 174 DVLOG(1) << __FUNCTION__ << ": status:" << status; | 176 DVLOG(1) << __FUNCTION__ << ": status:" << status; |
| 175 DCHECK(task_runner_->BelongsToCurrentThread()); | 177 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 176 | 178 |
| 177 DCHECK(!decode_cb_.is_null()); | 179 DCHECK(!decode_cb_.is_null()); |
| 178 base::ResetAndReturn(&decode_cb_).Run(static_cast<DecodeStatus>(status)); | 180 base::ResetAndReturn(&decode_cb_).Run(static_cast<DecodeStatus>(status)); |
| 179 } | 181 } |
| 180 | 182 |
| 181 void MojoAudioDecoder::OnResetDone() { | 183 void MojoAudioDecoder::OnResetDone() { |
| 182 DVLOG(1) << __FUNCTION__; | 184 DVLOG(1) << __FUNCTION__; |
| 183 DCHECK(task_runner_->BelongsToCurrentThread()); | 185 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 184 | 186 |
| 185 // For pending decodes OnDecodeStatus() should arrive before OnResetDone(). | 187 // For pending decodes OnDecodeStatus() should arrive before OnResetDone(). |
| 186 DCHECK(decode_cb_.is_null()); | 188 DCHECK(decode_cb_.is_null()); |
| 187 | 189 |
| 188 DCHECK(!reset_cb_.is_null()); | 190 DCHECK(!reset_cb_.is_null()); |
| 189 base::ResetAndReturn(&reset_cb_).Run(); | 191 base::ResetAndReturn(&reset_cb_).Run(); |
| 190 } | 192 } |
| 191 | 193 |
| 192 void MojoAudioDecoder::CreateDataPipe() { | |
| 193 MojoCreateDataPipeOptions options; | |
| 194 options.struct_size = sizeof(MojoCreateDataPipeOptions); | |
| 195 options.flags = MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE; | |
| 196 options.element_num_bytes = 1; | |
| 197 // TODO(timav): Consider capacity calculation based on AudioDecoderConfig. | |
| 198 options.capacity_num_bytes = 512 * 1024; | |
| 199 | |
| 200 mojo::DataPipe write_pipe(options); | |
| 201 | |
| 202 // Keep producer end. | |
| 203 producer_handle_ = std::move(write_pipe.producer_handle); | |
| 204 | |
| 205 // Pass consumer end to |remote_decoder_|. | |
| 206 remote_decoder_->SetDataSource(std::move(write_pipe.consumer_handle)); | |
| 207 } | |
| 208 | |
| 209 mojom::DecoderBufferPtr MojoAudioDecoder::TransferDecoderBuffer( | |
| 210 const scoped_refptr<DecoderBuffer>& media_buffer) { | |
| 211 mojom::DecoderBufferPtr buffer = mojom::DecoderBuffer::From(media_buffer); | |
| 212 if (media_buffer->end_of_stream()) | |
| 213 return buffer; | |
| 214 | |
| 215 // Serialize the data section of the DecoderBuffer into our pipe. | |
| 216 uint32_t num_bytes = base::checked_cast<uint32_t>(media_buffer->data_size()); | |
| 217 DCHECK_GT(num_bytes, 0u); | |
| 218 MojoResult result = | |
| 219 WriteDataRaw(producer_handle_.get(), media_buffer->data(), &num_bytes, | |
| 220 MOJO_WRITE_DATA_FLAG_ALL_OR_NONE); | |
| 221 if (result != MOJO_RESULT_OK || num_bytes != media_buffer->data_size()) { | |
| 222 DVLOG(1) << __FUNCTION__ << ": writing to data pipe failed"; | |
| 223 return nullptr; | |
| 224 } | |
| 225 | |
| 226 return buffer; | |
| 227 } | |
| 228 | |
| 229 } // namespace media | 194 } // namespace media |
| OLD | NEW |