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_ = status; | |
74 needs_bitstream_conversion_ = needs_bitstream_conversion; | |
75 max_decode_requests_ = max_decode_requests; | |
70 base::ResetAndReturn(&init_cb_).Run(status); | 76 base::ResetAndReturn(&init_cb_).Run(status); |
71 } | 77 } |
72 | 78 |
73 void MojoVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, | 79 void MojoVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, |
74 const DecodeCB& decode_cb) { | 80 const DecodeCB& decode_cb) { |
75 DVLOG(1) << __FUNCTION__; | 81 DVLOG(2) << __FUNCTION__; |
76 DCHECK(task_runner_->BelongsToCurrentThread()); | 82 DCHECK(task_runner_->BelongsToCurrentThread()); |
77 | 83 |
78 if (has_connection_error_) { | 84 if (has_connection_error_) { |
79 task_runner_->PostTask(FROM_HERE, | 85 task_runner_->PostTask(FROM_HERE, |
80 base::Bind(decode_cb, DecodeStatus::DECODE_ERROR)); | 86 base::Bind(decode_cb, DecodeStatus::DECODE_ERROR)); |
81 return; | 87 return; |
82 } | 88 } |
83 | 89 |
84 mojom::DecoderBufferPtr mojo_buffer = | 90 mojom::DecoderBufferPtr mojo_buffer = |
85 mojo_decoder_buffer_writer_->WriteDecoderBuffer(buffer); | 91 mojo_decoder_buffer_writer_->WriteDecoderBuffer(buffer); |
86 if (!mojo_buffer) { | 92 if (!mojo_buffer) { |
87 task_runner_->PostTask(FROM_HERE, | 93 task_runner_->PostTask(FROM_HERE, |
88 base::Bind(decode_cb, DecodeStatus::DECODE_ERROR)); | 94 base::Bind(decode_cb, DecodeStatus::DECODE_ERROR)); |
89 return; | 95 return; |
90 } | 96 } |
91 | 97 |
92 // TODO(sandersd): Support more than one decode at a time. | 98 uint64_t decode_id = decode_counter_++; |
93 decode_cb_ = decode_cb; | 99 pending_decodes_[decode_id] = decode_cb; |
94 remote_decoder_->Decode( | 100 remote_decoder_->Decode(std::move(mojo_buffer), |
95 std::move(mojo_buffer), | 101 base::Bind(&MojoVideoDecoder::OnDecodeDone, |
96 base::Bind(&MojoVideoDecoder::OnDecodeDone, base::Unretained(this))); | 102 base::Unretained(this), decode_id)); |
97 } | 103 } |
98 | 104 |
99 void MojoVideoDecoder::OnVideoFrameDecoded(mojom::VideoFramePtr frame) { | 105 void MojoVideoDecoder::OnVideoFrameDecoded(mojom::VideoFramePtr frame) { |
100 DVLOG(1) << __FUNCTION__; | 106 DVLOG(2) << __FUNCTION__; |
101 DCHECK(task_runner_->BelongsToCurrentThread()); | 107 DCHECK(task_runner_->BelongsToCurrentThread()); |
102 output_cb_.Run(frame.To<scoped_refptr<VideoFrame>>()); | 108 output_cb_.Run(frame.To<scoped_refptr<VideoFrame>>()); |
103 } | 109 } |
104 | 110 |
105 void MojoVideoDecoder::OnDecodeDone(DecodeStatus status) { | 111 void MojoVideoDecoder::OnDecodeDone(uint64_t decode_id, DecodeStatus status) { |
106 DVLOG(1) << __FUNCTION__; | 112 DVLOG(2) << __FUNCTION__; |
107 DCHECK(task_runner_->BelongsToCurrentThread()); | 113 DCHECK(task_runner_->BelongsToCurrentThread()); |
108 base::ResetAndReturn(&decode_cb_).Run(status); | 114 |
115 auto it = pending_decodes_.find(decode_id); | |
116 if (it == pending_decodes_.end()) { | |
117 DLOG(ERROR) << "Decode request " << decode_id << " not found"; | |
118 Stop(); | |
dcheng
2016/10/19 22:18:32
This needs to return as well; otherwise, it->secon
sandersd (OOO until July 31)
2016/10/19 22:27:54
Done. (Oops.)
| |
119 } | |
120 DecodeCB decode_cb = it->second; | |
121 pending_decodes_.erase(it); | |
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()); |
128 base::ResetAndReturn(&reset_cb_).Run(); | 142 base::ResetAndReturn(&reset_cb_).Run(); |
129 } | 143 } |
130 | 144 |
131 bool MojoVideoDecoder::NeedsBitstreamConversion() const { | 145 bool MojoVideoDecoder::NeedsBitstreamConversion() const { |
132 DVLOG(1) << __FUNCTION__; | 146 DVLOG(3) << __FUNCTION__; |
133 return false; | 147 DCHECK(initialized_); |
148 return needs_bitstream_conversion_; | |
134 } | 149 } |
135 | 150 |
136 bool MojoVideoDecoder::CanReadWithoutStalling() const { | 151 bool MojoVideoDecoder::CanReadWithoutStalling() const { |
137 DVLOG(1) << __FUNCTION__; | 152 DVLOG(3) << __FUNCTION__; |
138 return true; | 153 return true; |
139 } | 154 } |
140 | 155 |
141 int MojoVideoDecoder::GetMaxDecodeRequests() const { | 156 int MojoVideoDecoder::GetMaxDecodeRequests() const { |
142 DVLOG(1) << __FUNCTION__; | 157 DVLOG(3) << __FUNCTION__; |
143 return 1; | 158 DCHECK(initialized_); |
159 return max_decode_requests_; | |
144 } | 160 } |
145 | 161 |
146 void MojoVideoDecoder::BindRemoteDecoder() { | 162 void MojoVideoDecoder::BindRemoteDecoder() { |
147 DVLOG(1) << __FUNCTION__; | 163 DVLOG(3) << __FUNCTION__; |
148 DCHECK(task_runner_->BelongsToCurrentThread()); | 164 DCHECK(task_runner_->BelongsToCurrentThread()); |
149 DCHECK(!remote_decoder_bound_); | 165 DCHECK(!remote_decoder_bound_); |
150 | 166 |
151 remote_decoder_.Bind(std::move(remote_decoder_info_)); | 167 remote_decoder_.Bind(std::move(remote_decoder_info_)); |
152 remote_decoder_bound_ = true; | 168 remote_decoder_bound_ = true; |
153 | 169 |
154 remote_decoder_.set_connection_error_handler( | 170 remote_decoder_.set_connection_error_handler( |
155 base::Bind(&MojoVideoDecoder::OnConnectionError, base::Unretained(this))); | 171 base::Bind(&MojoVideoDecoder::Stop, base::Unretained(this))); |
156 | 172 |
173 // TODO(sandersd): Does this need its own error handler? | |
157 mojom::VideoDecoderClientAssociatedPtrInfo client_ptr_info; | 174 mojom::VideoDecoderClientAssociatedPtrInfo client_ptr_info; |
158 client_binding_.Bind(&client_ptr_info, remote_decoder_.associated_group()); | 175 client_binding_.Bind(&client_ptr_info, remote_decoder_.associated_group()); |
159 | 176 |
160 // TODO(sandersd): Better buffer sizing. | 177 // TODO(sandersd): Better buffer sizing. |
161 mojo::ScopedDataPipeConsumerHandle remote_consumer_handle; | 178 mojo::ScopedDataPipeConsumerHandle remote_consumer_handle; |
162 mojo_decoder_buffer_writer_ = MojoDecoderBufferWriter::Create( | 179 mojo_decoder_buffer_writer_ = MojoDecoderBufferWriter::Create( |
163 DemuxerStream::VIDEO, &remote_consumer_handle); | 180 DemuxerStream::VIDEO, &remote_consumer_handle); |
164 | 181 |
165 remote_decoder_->Construct(std::move(client_ptr_info), | 182 remote_decoder_->Construct(std::move(client_ptr_info), |
166 std::move(remote_consumer_handle)); | 183 std::move(remote_consumer_handle)); |
167 } | 184 } |
168 | 185 |
169 void MojoVideoDecoder::OnConnectionError() { | 186 void MojoVideoDecoder::Stop() { |
170 DVLOG(1) << __FUNCTION__; | 187 DVLOG(2) << __FUNCTION__; |
171 DCHECK(task_runner_->BelongsToCurrentThread()); | 188 DCHECK(task_runner_->BelongsToCurrentThread()); |
172 | 189 |
173 has_connection_error_ = true; | 190 has_connection_error_ = true; |
174 | 191 |
175 // TODO(sandersd): Write a wrapper class (like BindToCurrentLoop) that handles | |
176 // the lifetime of callbacks like this. | |
177 if (!init_cb_.is_null()) | 192 if (!init_cb_.is_null()) |
178 base::ResetAndReturn(&init_cb_).Run(false); | 193 base::ResetAndReturn(&init_cb_).Run(false); |
179 // TODO(sandersd): If there is a pending reset, should these be aborted? | 194 |
180 if (!decode_cb_.is_null()) | 195 for (const auto& pending_decode : pending_decodes_) |
181 base::ResetAndReturn(&decode_cb_).Run(DecodeStatus::DECODE_ERROR); | 196 pending_decode.second.Run(DecodeStatus::DECODE_ERROR); |
197 pending_decodes_.clear(); | |
198 | |
182 if (!reset_cb_.is_null()) | 199 if (!reset_cb_.is_null()) |
183 base::ResetAndReturn(&reset_cb_).Run(); | 200 base::ResetAndReturn(&reset_cb_).Run(); |
184 } | 201 } |
185 | 202 |
186 } // namespace media | 203 } // namespace media |
OLD | NEW |