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/services/mojo_audio_decoder.h" | 5 #include "media/mojo/services/mojo_audio_decoder.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/bind_helpers.h" | |
9 #include "base/callback_helpers.h" | |
8 #include "base/location.h" | 10 #include "base/location.h" |
9 #include "base/logging.h" | 11 #include "base/logging.h" |
10 #include "base/single_thread_task_runner.h" | 12 #include "base/single_thread_task_runner.h" |
11 #include "base/thread_task_runner_handle.h" | 13 #include "base/thread_task_runner_handle.h" |
14 #include "media/base/cdm_context.h" | |
15 #include "media/mojo/common/media_type_converters.h" | |
12 | 16 |
13 namespace media { | 17 namespace media { |
14 | 18 |
15 MojoAudioDecoder::MojoAudioDecoder( | 19 MojoAudioDecoder::MojoAudioDecoder( |
16 scoped_refptr<base::SingleThreadTaskRunner> task_runner, | 20 scoped_refptr<base::SingleThreadTaskRunner> task_runner, |
17 interfaces::AudioDecoderPtr remote_decoder) | 21 interfaces::AudioDecoderPtr remote_decoder) |
18 : task_runner_(task_runner), remote_decoder_(std::move(remote_decoder)) { | 22 : task_runner_(task_runner), |
23 remote_decoder_(std::move(remote_decoder)), | |
24 binding_(this), | |
25 has_connection_error_(false), | |
26 needs_bitstream_conversion_(false) { | |
19 DVLOG(1) << __FUNCTION__; | 27 DVLOG(1) << __FUNCTION__; |
20 } | 28 } |
21 | 29 |
22 MojoAudioDecoder::~MojoAudioDecoder() { | 30 MojoAudioDecoder::~MojoAudioDecoder() { |
23 DVLOG(1) << __FUNCTION__; | 31 DVLOG(1) << __FUNCTION__; |
24 } | 32 } |
25 | 33 |
26 std::string MojoAudioDecoder::GetDisplayName() const { | 34 std::string MojoAudioDecoder::GetDisplayName() const { |
27 return "MojoAudioDecoder"; | 35 return "MojoAudioDecoder"; |
28 } | 36 } |
29 | 37 |
30 void MojoAudioDecoder::Initialize(const AudioDecoderConfig& config, | 38 void MojoAudioDecoder::Initialize(const AudioDecoderConfig& config, |
31 CdmContext* cdm_context, | 39 CdmContext* cdm_context, |
32 const InitCB& init_cb, | 40 const InitCB& init_cb, |
33 const OutputCB& output_cb) { | 41 const OutputCB& output_cb) { |
34 DVLOG(1) << __FUNCTION__; | 42 DVLOG(1) << __FUNCTION__; |
35 DCHECK(task_runner_->BelongsToCurrentThread()); | 43 DCHECK(task_runner_->BelongsToCurrentThread()); |
36 | 44 |
37 NOTIMPLEMENTED(); | 45 // Fail immediately if the stream is encrypted but |cdm_context| is invalid. |
46 int cdm_id = (config.is_encrypted() && cdm_context) | |
47 ? cdm_context->GetCdmId() | |
48 : CdmContext::kInvalidCdmId; | |
38 | 49 |
39 // Fail initialization while not implemented. | 50 if (config.is_encrypted() && CdmContext::kInvalidCdmId == cdm_id) { |
40 task_runner_->PostTask(FROM_HERE, base::Bind(init_cb, false)); | 51 task_runner_->PostTask(FROM_HERE, base::Bind(init_cb, false)); |
52 return; | |
53 } | |
54 | |
55 // If connection error has happened, fail immediately. | |
56 if (remote_decoder_.encountered_error()) { | |
57 task_runner_->PostTask(FROM_HERE, base::Bind(init_cb, false)); | |
58 return; | |
59 } | |
60 | |
61 // Otherwise, set an error handler to catch the connection error. | |
62 // Using base::Unretained(this) is safe because |this| owns |remote_decoder_|, | |
63 // and the error handler can't be invoked once |remote_decoder_| is destroyed. | |
64 remote_decoder_.set_connection_error_handler( | |
65 base::Bind(&MojoAudioDecoder::OnConnectionError, base::Unretained(this))); | |
66 | |
67 init_cb_ = init_cb; | |
68 | |
69 // Using base::Unretained(this) is safe because |this| owns |remote_decoder_|, | |
70 // and the callback won't be dispatched if |remote_decoder_| is destroyed. | |
71 remote_decoder_->Initialize( | |
72 binding_.CreateInterfacePtrAndBind(), | |
73 interfaces::AudioDecoderConfig::From(config), cdm_id, | |
74 base::Bind(&MojoAudioDecoder::OnInitialized, base::Unretained(this))); | |
41 } | 75 } |
42 | 76 |
43 void MojoAudioDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, | 77 void MojoAudioDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, |
44 const DecodeCB& decode_cb) { | 78 const DecodeCB& decode_cb) { |
45 DVLOG(3) << __FUNCTION__; | 79 DVLOG(3) << __FUNCTION__; |
46 DCHECK(task_runner_->BelongsToCurrentThread()); | 80 DCHECK(task_runner_->BelongsToCurrentThread()); |
47 | 81 |
48 NOTIMPLEMENTED(); | 82 if (has_connection_error_) { |
83 task_runner_->PostTask(FROM_HERE, base::Bind(decode_cb, kDecodeError)); | |
84 return; | |
85 } | |
49 | 86 |
50 // Actually we can't decode anything. | 87 DCHECK(decode_cb_.is_null()); |
51 task_runner_->PostTask(FROM_HERE, base::Bind(decode_cb, kDecodeError)); | 88 decode_cb_ = decode_cb; |
89 | |
90 remote_decoder_->Decode( | |
xhwang
2016/03/18 02:19:43
Add a comment that this will not work. We need a D
Tima Vaisburd
2016/03/18 19:05:49
In the doc you said we can use MessagePipe instead
xhwang
2016/03/18 19:17:17
There are two places we need to use DataPipe, one
Tima Vaisburd
2016/03/18 19:35:03
Added comment.
| |
91 interfaces::DecoderBuffer::From(buffer), | |
92 base::Bind(&MojoAudioDecoder::OnDecodeStarted, base::Unretained(this))); | |
52 } | 93 } |
53 | 94 |
54 void MojoAudioDecoder::Reset(const base::Closure& closure) { | 95 void MojoAudioDecoder::Reset(const base::Closure& closure) { |
55 DVLOG(2) << __FUNCTION__; | 96 DVLOG(2) << __FUNCTION__; |
56 DCHECK(task_runner_->BelongsToCurrentThread()); | 97 DCHECK(task_runner_->BelongsToCurrentThread()); |
57 | 98 |
58 NOTIMPLEMENTED(); | 99 if (has_connection_error_) { |
100 if (!decode_cb_.is_null()) { | |
101 task_runner_->PostTask( | |
102 FROM_HERE, | |
103 base::Bind(base::ResetAndReturn(&decode_cb_), kDecodeError)); | |
104 } | |
105 | |
106 task_runner_->PostTask(FROM_HERE, closure); | |
107 return; | |
108 } | |
109 | |
110 DCHECK(reset_cb_.is_null()); | |
111 reset_cb_ = closure; | |
xhwang
2016/03/18 02:19:43
Do you want to call remote_decoder_->Reset() here?
Tima Vaisburd
2016/03/18 19:05:49
Yes, I forgot to call remote decoder. Thank you.
| |
59 } | 112 } |
60 | 113 |
61 bool MojoAudioDecoder::NeedsBitstreamConversion() const { | 114 bool MojoAudioDecoder::NeedsBitstreamConversion() const { |
62 DVLOG(1) << __FUNCTION__; | 115 DVLOG(1) << __FUNCTION__; |
63 DCHECK(task_runner_->BelongsToCurrentThread()); | 116 DCHECK(task_runner_->BelongsToCurrentThread()); |
64 | 117 |
118 return needs_bitstream_conversion_; | |
119 } | |
120 | |
121 void MojoAudioDecoder::OnBufferDecoded(interfaces::AudioBufferPtr buffer) { | |
122 DVLOG(1) << __FUNCTION__; | |
123 DCHECK(task_runner_->BelongsToCurrentThread()); | |
124 | |
65 NOTIMPLEMENTED(); | 125 NOTIMPLEMENTED(); |
66 return false; | 126 } |
127 | |
128 void MojoAudioDecoder::OnConnectionError() { | |
129 DVLOG(1) << __FUNCTION__; | |
130 DCHECK(task_runner_->BelongsToCurrentThread()); | |
131 | |
132 has_connection_error_ = true; | |
133 | |
134 if (!init_cb_.is_null()) { | |
135 base::ResetAndReturn(&init_cb_).Run(false); | |
136 return; | |
137 } | |
138 | |
139 if (!decode_cb_.is_null()) | |
140 base::ResetAndReturn(&decode_cb_).Run(kDecodeError); | |
141 if (!reset_cb_.is_null()) | |
142 base::ResetAndReturn(&reset_cb_).Run(); | |
143 } | |
144 | |
145 void MojoAudioDecoder::OnInitialized(bool status, | |
146 bool needs_bitstream_conversion) { | |
147 DVLOG(1) << __FUNCTION__ << ": status:" << status; | |
148 DCHECK(task_runner_->BelongsToCurrentThread()); | |
149 | |
150 needs_bitstream_conversion_ = needs_bitstream_conversion; | |
151 | |
152 task_runner_->PostTask(FROM_HERE, base::Bind(init_cb_, status)); | |
153 } | |
154 | |
155 static media::AudioDecoder::Status ConvertDecodeStatus( | |
xhwang
2016/03/18 02:19:43
FYI, we have a bug to track the work to avoid this
Tima Vaisburd
2016/03/18 19:05:49
I've seen static_cast<>, maybe just cast?
xhwang
2016/03/18 19:17:17
The bug will fix the issue completely. If you do c
Tima Vaisburd
2016/03/18 19:35:03
Acknowledged.
| |
156 interfaces::AudioDecoder::DecodeStatus status) { | |
157 switch (status) { | |
158 case interfaces::AudioDecoder::DecodeStatus::OK: | |
159 return media::AudioDecoder::kOk; | |
160 case interfaces::AudioDecoder::DecodeStatus::ABORTED: | |
161 return media::AudioDecoder::kAborted; | |
162 case interfaces::AudioDecoder::DecodeStatus::DECODE_ERROR: | |
163 return media::AudioDecoder::kDecodeError; | |
164 } | |
165 NOTREACHED(); | |
166 return media::AudioDecoder::kDecodeError; | |
167 } | |
168 | |
169 void MojoAudioDecoder::OnDecodeStarted( | |
170 interfaces::AudioDecoder::DecodeStatus status) { | |
171 DVLOG(1) << __FUNCTION__ << ": status:" << status; | |
172 DCHECK(task_runner_->BelongsToCurrentThread()); | |
173 | |
174 if (!decode_cb_.is_null()) | |
xhwang
2016/03/18 02:19:43
When would this happen? Typically we assume this s
Tima Vaisburd
2016/03/18 19:05:49
Yes, I assumed these can be called after connectio
| |
175 base::ResetAndReturn(&decode_cb_).Run(ConvertDecodeStatus(status)); | |
176 } | |
177 | |
178 void MojoAudioDecoder::OnResetDone() { | |
179 DVLOG(1) << __FUNCTION__; | |
180 DCHECK(task_runner_->BelongsToCurrentThread()); | |
181 | |
182 if (!reset_cb_.is_null()) | |
xhwang
2016/03/18 02:19:43
ditto
Tima Vaisburd
2016/03/18 19:05:49
Changed to DCHECK()
| |
183 base::ResetAndReturn(&reset_cb_).Run(); | |
67 } | 184 } |
68 | 185 |
69 } // namespace media | 186 } // namespace media |
OLD | NEW |