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_video_decoder.h" | 5 #include "media/mojo/clients/mojo_video_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" |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 25 : task_runner_(task_runner), | 25 : task_runner_(task_runner), |
| 26 gpu_factories_(gpu_factories), | 26 gpu_factories_(gpu_factories), |
| 27 remote_decoder_info_(remote_decoder.PassInterface()), | 27 remote_decoder_info_(remote_decoder.PassInterface()), |
| 28 client_binding_(this) { | 28 client_binding_(this) { |
| 29 (void)gpu_factories_; | 29 (void)gpu_factories_; |
| 30 DVLOG(1) << __FUNCTION__; | 30 DVLOG(1) << __FUNCTION__; |
| 31 } | 31 } |
| 32 | 32 |
| 33 MojoVideoDecoder::~MojoVideoDecoder() { | 33 MojoVideoDecoder::~MojoVideoDecoder() { |
| 34 DVLOG(1) << __FUNCTION__; | 34 DVLOG(1) << __FUNCTION__; |
| 35 Stop(); | |
| 35 } | 36 } |
| 36 | 37 |
| 37 std::string MojoVideoDecoder::GetDisplayName() const { | 38 std::string MojoVideoDecoder::GetDisplayName() const { |
| 39 // TODO(sandersd): Build the name including information from the remote end. | |
| 38 return "MojoVideoDecoder"; | 40 return "MojoVideoDecoder"; |
| 39 } | 41 } |
| 40 | 42 |
| 41 void MojoVideoDecoder::Initialize(const VideoDecoderConfig& config, | 43 void MojoVideoDecoder::Initialize(const VideoDecoderConfig& config, |
| 42 bool low_delay, | 44 bool low_delay, |
| 43 CdmContext* cdm_context, | 45 CdmContext* cdm_context, |
| 44 const InitCB& init_cb, | 46 const InitCB& init_cb, |
| 45 const OutputCB& output_cb) { | 47 const OutputCB& output_cb) { |
| 46 DVLOG(1) << __FUNCTION__; | 48 DVLOG(1) << __FUNCTION__; |
| 47 DCHECK(task_runner_->BelongsToCurrentThread()); | 49 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 48 DCHECK(!cdm_context); | 50 DCHECK(!cdm_context); |
| 49 | 51 |
| 50 if (!remote_decoder_bound_) | 52 if (!remote_decoder_bound_) |
| 51 BindRemoteDecoder(); | 53 BindRemoteDecoder(); |
| 52 | 54 |
| 53 if (has_connection_error_) { | 55 if (has_connection_error_) { |
| 54 task_runner_->PostTask(FROM_HERE, base::Bind(init_cb, false)); | 56 task_runner_->PostTask(FROM_HERE, base::Bind(init_cb, false)); |
| 55 return; | 57 return; |
| 56 } | 58 } |
| 57 | 59 |
| 60 initialized_ = false; | |
| 58 init_cb_ = init_cb; | 61 init_cb_ = init_cb; |
| 59 output_cb_ = output_cb; | 62 output_cb_ = output_cb; |
| 60 remote_decoder_->Initialize( | 63 remote_decoder_->Initialize( |
| 61 mojom::VideoDecoderConfig::From(config), low_delay, | 64 mojom::VideoDecoderConfig::From(config), low_delay, |
| 62 base::Bind(&MojoVideoDecoder::OnInitializeDone, base::Unretained(this))); | 65 base::Bind(&MojoVideoDecoder::OnInitializeDone, base::Unretained(this))); |
| 63 } | 66 } |
| 64 | 67 |
| 65 // TODO(sandersd): Remove this indirection once a working decoder has been | 68 void MojoVideoDecoder::OnInitializeDone(bool status, |
| 66 // brought up. | 69 bool needs_bitstream_conversion, |
| 67 void MojoVideoDecoder::OnInitializeDone(bool status) { | 70 int32_t max_decode_requests) { |
| 68 DVLOG(1) << __FUNCTION__; | 71 DVLOG(1) << __FUNCTION__; |
| 69 DCHECK(task_runner_->BelongsToCurrentThread()); | 72 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 73 initialized_ = true; | |
| 74 needs_bitstream_conversion_ = needs_bitstream_conversion; | |
| 75 max_decode_requests_ = max_decode_requests; | |
| 76 can_read_without_stalling_ = true; | |
| 70 base::ResetAndReturn(&init_cb_).Run(status); | 77 base::ResetAndReturn(&init_cb_).Run(status); |
| 71 } | 78 } |
| 72 | 79 |
| 73 void MojoVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, | 80 void MojoVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, |
| 74 const DecodeCB& decode_cb) { | 81 const DecodeCB& decode_cb) { |
| 75 DVLOG(1) << __FUNCTION__; | 82 DVLOG(2) << __FUNCTION__; |
| 76 DCHECK(task_runner_->BelongsToCurrentThread()); | 83 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 77 | 84 |
| 78 if (has_connection_error_) { | 85 if (has_connection_error_) { |
| 79 task_runner_->PostTask(FROM_HERE, | 86 task_runner_->PostTask(FROM_HERE, |
| 80 base::Bind(decode_cb, DecodeStatus::DECODE_ERROR)); | 87 base::Bind(decode_cb, DecodeStatus::DECODE_ERROR)); |
| 81 return; | 88 return; |
| 82 } | 89 } |
| 83 | 90 |
| 84 mojom::DecoderBufferPtr mojo_buffer = | 91 mojom::DecoderBufferPtr mojo_buffer = |
| 85 mojo_decoder_buffer_writer_->WriteDecoderBuffer(buffer); | 92 mojo_decoder_buffer_writer_->WriteDecoderBuffer(buffer); |
| 86 if (!mojo_buffer) { | 93 if (!mojo_buffer) { |
| 87 task_runner_->PostTask(FROM_HERE, | 94 task_runner_->PostTask(FROM_HERE, |
| 88 base::Bind(decode_cb, DecodeStatus::DECODE_ERROR)); | 95 base::Bind(decode_cb, DecodeStatus::DECODE_ERROR)); |
| 89 return; | 96 return; |
| 90 } | 97 } |
| 91 | 98 |
| 92 // TODO(sandersd): Support more than one decode at a time. | 99 uint64_t decode_id = decode_counter_++; |
| 93 decode_cb_ = decode_cb; | 100 pending_decodes_[decode_id] = decode_cb; |
|
slan
2016/10/18 20:46:25
What if we bind |decode_cb| directly to OnDecodeDo
slan
2016/10/18 20:49:41
Sorry, this is a typo, you know what I mean :)
sandersd (OOO until July 31)
2016/10/18 21:09:56
The problem this solves is having a list of outsta
slan
2016/10/18 22:06:44
Right, I overlooked that bit. Your method SGTM.
| |
| 94 remote_decoder_->Decode( | 101 remote_decoder_->Decode(std::move(mojo_buffer), |
| 95 std::move(mojo_buffer), | 102 base::Bind(&MojoVideoDecoder::OnDecodeDone, |
| 96 base::Bind(&MojoVideoDecoder::OnDecodeDone, base::Unretained(this))); | 103 base::Unretained(this), decode_id)); |
|
dcheng
2016/10/18 20:39:05
Can we just bind the callback directly instead of
dcheng
2016/10/19 02:42:39
OK, thanks for the explanation. +rockot, do you kn
Ken Rockot(use gerrit already)
2016/10/19 05:50:34
It's not a pattern that has come up often. This ap
| |
| 97 } | 104 } |
| 98 | 105 |
| 99 void MojoVideoDecoder::OnVideoFrameDecoded(mojom::VideoFramePtr frame) { | 106 void MojoVideoDecoder::OnVideoFrameDecoded(mojom::VideoFramePtr frame) { |
| 100 DVLOG(1) << __FUNCTION__; | 107 DVLOG(2) << __FUNCTION__; |
| 101 DCHECK(task_runner_->BelongsToCurrentThread()); | 108 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 102 output_cb_.Run(frame.To<scoped_refptr<VideoFrame>>()); | 109 output_cb_.Run(frame.To<scoped_refptr<VideoFrame>>()); |
| 103 } | 110 } |
| 104 | 111 |
| 105 void MojoVideoDecoder::OnDecodeDone(DecodeStatus status) { | 112 void MojoVideoDecoder::OnDecodeDone(uint64_t decode_id, |
| 106 DVLOG(1) << __FUNCTION__; | 113 DecodeStatus status, |
| 114 bool can_read_without_stalling) { | |
| 115 DVLOG(2) << __FUNCTION__; | |
| 107 DCHECK(task_runner_->BelongsToCurrentThread()); | 116 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 108 base::ResetAndReturn(&decode_cb_).Run(status); | 117 DCHECK(pending_decodes_.count(decode_id)); |
| 118 DCHECK(pending_decodes_.size() > 1 || can_read_without_stalling); | |
|
dcheng
2016/10/18 20:39:05
Should these actually be DCHECKs? Presumably, the
sandersd (OOO until July 31)
2016/10/18 21:09:56
In fact it lives in a more privileged process (the
dcheng
2016/10/19 02:42:39
Hmm, can you link to the GpuVideoDecoder you're re
sandersd (OOO until July 31)
2016/10/19 17:51:24
https://cs.chromium.org/chromium/src/media/filters
| |
| 119 can_read_without_stalling_ = can_read_without_stalling; | |
| 120 DecodeCB decode_cb = pending_decodes_[decode_id]; | |
| 121 pending_decodes_.erase(decode_id); | |
| 122 decode_cb.Run(status); | |
| 109 } | 123 } |
| 110 | 124 |
| 111 void MojoVideoDecoder::Reset(const base::Closure& reset_cb) { | 125 void MojoVideoDecoder::Reset(const base::Closure& reset_cb) { |
| 112 DVLOG(1) << __FUNCTION__; | 126 DVLOG(1) << __FUNCTION__; |
| 113 DCHECK(task_runner_->BelongsToCurrentThread()); | 127 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 114 | 128 |
| 115 if (has_connection_error_) { | 129 if (has_connection_error_) { |
| 116 task_runner_->PostTask(FROM_HERE, reset_cb); | 130 task_runner_->PostTask(FROM_HERE, reset_cb); |
| 117 return; | 131 return; |
| 118 } | 132 } |
| 119 | 133 |
| 120 reset_cb_ = reset_cb; | 134 reset_cb_ = reset_cb; |
| 121 remote_decoder_->Reset( | 135 remote_decoder_->Reset( |
| 122 base::Bind(&MojoVideoDecoder::OnResetDone, base::Unretained(this))); | 136 base::Bind(&MojoVideoDecoder::OnResetDone, base::Unretained(this))); |
| 123 } | 137 } |
| 124 | 138 |
| 125 void MojoVideoDecoder::OnResetDone() { | 139 void MojoVideoDecoder::OnResetDone() { |
| 126 DVLOG(1) << __FUNCTION__; | 140 DVLOG(1) << __FUNCTION__; |
| 127 DCHECK(task_runner_->BelongsToCurrentThread()); | 141 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 142 can_read_without_stalling_ = true; | |
| 128 base::ResetAndReturn(&reset_cb_).Run(); | 143 base::ResetAndReturn(&reset_cb_).Run(); |
| 129 } | 144 } |
| 130 | 145 |
| 131 bool MojoVideoDecoder::NeedsBitstreamConversion() const { | 146 bool MojoVideoDecoder::NeedsBitstreamConversion() const { |
| 132 DVLOG(1) << __FUNCTION__; | 147 DVLOG(3) << __FUNCTION__; |
| 133 return false; | 148 DCHECK(initialized_); |
| 149 return needs_bitstream_conversion_; | |
| 134 } | 150 } |
| 135 | 151 |
| 136 bool MojoVideoDecoder::CanReadWithoutStalling() const { | 152 bool MojoVideoDecoder::CanReadWithoutStalling() const { |
| 137 DVLOG(1) << __FUNCTION__; | 153 DVLOG(3) << __FUNCTION__; |
| 138 return true; | 154 DCHECK(initialized_); |
| 155 return can_read_without_stalling_; | |
| 139 } | 156 } |
| 140 | 157 |
| 141 int MojoVideoDecoder::GetMaxDecodeRequests() const { | 158 int MojoVideoDecoder::GetMaxDecodeRequests() const { |
| 142 DVLOG(1) << __FUNCTION__; | 159 DVLOG(3) << __FUNCTION__; |
| 143 return 1; | 160 DCHECK(initialized_); |
| 161 return max_decode_requests_; | |
| 144 } | 162 } |
| 145 | 163 |
| 146 void MojoVideoDecoder::BindRemoteDecoder() { | 164 void MojoVideoDecoder::BindRemoteDecoder() { |
| 147 DVLOG(1) << __FUNCTION__; | 165 DVLOG(3) << __FUNCTION__; |
| 148 DCHECK(task_runner_->BelongsToCurrentThread()); | 166 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 149 DCHECK(!remote_decoder_bound_); | 167 DCHECK(!remote_decoder_bound_); |
| 150 | 168 |
| 151 remote_decoder_.Bind(std::move(remote_decoder_info_)); | 169 remote_decoder_.Bind(std::move(remote_decoder_info_)); |
| 152 remote_decoder_bound_ = true; | 170 remote_decoder_bound_ = true; |
| 153 | 171 |
| 154 remote_decoder_.set_connection_error_handler( | 172 remote_decoder_.set_connection_error_handler( |
| 155 base::Bind(&MojoVideoDecoder::OnConnectionError, base::Unretained(this))); | 173 base::Bind(&MojoVideoDecoder::Stop, base::Unretained(this))); |
| 156 | 174 |
| 175 // TODO(sandersd): Does this need its own error handler? | |
| 157 mojom::VideoDecoderClientAssociatedPtrInfo client_ptr_info; | 176 mojom::VideoDecoderClientAssociatedPtrInfo client_ptr_info; |
| 158 client_binding_.Bind(&client_ptr_info, remote_decoder_.associated_group()); | 177 client_binding_.Bind(&client_ptr_info, remote_decoder_.associated_group()); |
| 159 | 178 |
| 160 // TODO(sandersd): Better buffer sizing. | 179 // TODO(sandersd): Better buffer sizing. |
| 161 mojo::ScopedDataPipeConsumerHandle remote_consumer_handle; | 180 mojo::ScopedDataPipeConsumerHandle remote_consumer_handle; |
| 162 mojo_decoder_buffer_writer_ = MojoDecoderBufferWriter::Create( | 181 mojo_decoder_buffer_writer_ = MojoDecoderBufferWriter::Create( |
| 163 DemuxerStream::VIDEO, &remote_consumer_handle); | 182 DemuxerStream::VIDEO, &remote_consumer_handle); |
| 164 | 183 |
| 165 remote_decoder_->Construct(std::move(client_ptr_info), | 184 remote_decoder_->Construct(std::move(client_ptr_info), |
| 166 std::move(remote_consumer_handle)); | 185 std::move(remote_consumer_handle)); |
| 167 } | 186 } |
| 168 | 187 |
| 169 void MojoVideoDecoder::OnConnectionError() { | 188 void MojoVideoDecoder::Stop() { |
| 170 DVLOG(1) << __FUNCTION__; | 189 DVLOG(2) << __FUNCTION__; |
| 171 DCHECK(task_runner_->BelongsToCurrentThread()); | 190 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 172 | 191 |
| 173 has_connection_error_ = true; | 192 has_connection_error_ = true; |
| 174 | 193 |
| 175 // TODO(sandersd): Write a wrapper class (like BindToCurrentLoop) that handles | |
| 176 // the lifetime of callbacks like this. | |
| 177 if (!init_cb_.is_null()) | 194 if (!init_cb_.is_null()) |
| 178 base::ResetAndReturn(&init_cb_).Run(false); | 195 base::ResetAndReturn(&init_cb_).Run(false); |
| 179 // TODO(sandersd): If there is a pending reset, should these be aborted? | 196 |
| 180 if (!decode_cb_.is_null()) | 197 for (const auto& pending_decode : pending_decodes_) |
| 181 base::ResetAndReturn(&decode_cb_).Run(DecodeStatus::DECODE_ERROR); | 198 pending_decode.second.Run(DecodeStatus::DECODE_ERROR); |
| 199 pending_decodes_.clear(); | |
| 200 | |
| 182 if (!reset_cb_.is_null()) | 201 if (!reset_cb_.is_null()) |
| 183 base::ResetAndReturn(&reset_cb_).Run(); | 202 base::ResetAndReturn(&reset_cb_).Run(); |
| 184 } | 203 } |
| 185 | 204 |
| 186 } // namespace media | 205 } // namespace media |
| OLD | NEW |