OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/filters/gpu_video_decoder.h" | 5 #include "media/filters/gpu_video_decoder.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/callback_helpers.h" | 11 #include "base/callback_helpers.h" |
12 #include "base/command_line.h" | 12 #include "base/command_line.h" |
13 #include "base/cpu.h" | 13 #include "base/cpu.h" |
14 #include "base/message_loop/message_loop.h" | 14 #include "base/message_loop/message_loop.h" |
15 #include "base/metrics/histogram.h" | 15 #include "base/metrics/histogram.h" |
16 #include "base/stl_util.h" | 16 #include "base/stl_util.h" |
17 #include "base/task_runner_util.h" | 17 #include "base/task_runner_util.h" |
18 #include "build/build_config.h" | 18 #include "build/build_config.h" |
19 #include "gpu/command_buffer/common/mailbox_holder.h" | 19 #include "gpu/command_buffer/common/mailbox_holder.h" |
20 #include "media/base/bind_to_current_loop.h" | 20 #include "media/base/bind_to_current_loop.h" |
21 #include "media/base/cdm_context.h" | 21 #include "media/base/cdm_context.h" |
22 #include "media/base/decoder_buffer.h" | 22 #include "media/base/decoder_buffer.h" |
23 #include "media/base/media_switches.h" | 23 #include "media/base/media_switches.h" |
24 #include "media/base/pipeline.h" | 24 #include "media/base/pipeline.h" |
| 25 #include "media/base/surface_manager.h" |
25 #include "media/base/video_decoder_config.h" | 26 #include "media/base/video_decoder_config.h" |
26 #include "media/renderers/gpu_video_accelerator_factories.h" | 27 #include "media/renderers/gpu_video_accelerator_factories.h" |
27 #include "third_party/skia/include/core/SkBitmap.h" | 28 #include "third_party/skia/include/core/SkBitmap.h" |
28 | 29 |
29 namespace media { | 30 namespace media { |
30 | 31 |
31 const char GpuVideoDecoder::kDecoderName[] = "GpuVideoDecoder"; | 32 const char GpuVideoDecoder::kDecoderName[] = "GpuVideoDecoder"; |
32 | 33 |
33 // Maximum number of concurrent VDA::Decode() operations GVD will maintain. | 34 // Maximum number of concurrent VDA::Decode() operations GVD will maintain. |
34 // Higher values allow better pipelining in the GPU, but also require more | 35 // Higher values allow better pipelining in the GPU, but also require more |
(...skipping 23 matching lines...) Expand all Loading... |
58 base::TimeDelta ts, | 59 base::TimeDelta ts, |
59 const gfx::Rect& vr, | 60 const gfx::Rect& vr, |
60 const gfx::Size& ns) | 61 const gfx::Size& ns) |
61 : bitstream_buffer_id(bbid), | 62 : bitstream_buffer_id(bbid), |
62 timestamp(ts), | 63 timestamp(ts), |
63 visible_rect(vr), | 64 visible_rect(vr), |
64 natural_size(ns) {} | 65 natural_size(ns) {} |
65 | 66 |
66 GpuVideoDecoder::BufferData::~BufferData() {} | 67 GpuVideoDecoder::BufferData::~BufferData() {} |
67 | 68 |
68 GpuVideoDecoder::GpuVideoDecoder(GpuVideoAcceleratorFactories* factories) | 69 GpuVideoDecoder::GpuVideoDecoder(GpuVideoAcceleratorFactories* factories, |
| 70 const RequestSurfaceCB& request_surface_cb) |
69 : needs_bitstream_conversion_(false), | 71 : needs_bitstream_conversion_(false), |
70 factories_(factories), | 72 factories_(factories), |
71 state_(kNormal), | 73 state_(kNormal), |
| 74 request_surface_cb_(request_surface_cb), |
72 decoder_texture_target_(0), | 75 decoder_texture_target_(0), |
73 next_picture_buffer_id_(0), | 76 next_picture_buffer_id_(0), |
74 next_bitstream_buffer_id_(0), | 77 next_bitstream_buffer_id_(0), |
75 available_pictures_(0), | 78 available_pictures_(0), |
76 needs_all_picture_buffers_to_decode_(false), | 79 needs_all_picture_buffers_to_decode_(false), |
77 weak_factory_(this) { | 80 weak_factory_(this) { |
78 DCHECK(factories_); | 81 DCHECK(factories_); |
79 } | 82 } |
80 | 83 |
81 void GpuVideoDecoder::Reset(const base::Closure& closure) { | 84 void GpuVideoDecoder::Reset(const base::Closure& closure) { |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
142 | 145 |
143 #if !defined(OS_ANDROID) | 146 #if !defined(OS_ANDROID) |
144 if (config.is_encrypted()) { | 147 if (config.is_encrypted()) { |
145 DVLOG(1) << "Encrypted stream not supported."; | 148 DVLOG(1) << "Encrypted stream not supported."; |
146 bound_init_cb.Run(false); | 149 bound_init_cb.Run(false); |
147 return; | 150 return; |
148 } | 151 } |
149 #endif | 152 #endif |
150 | 153 |
151 bool previously_initialized = config_.IsValidConfig(); | 154 bool previously_initialized = config_.IsValidConfig(); |
152 DVLOG(1) << "(Re)initializing GVD with config: " | 155 DVLOG(1) << (previously_initialized ? "Reinitializing" : "Initializing") |
153 << config.AsHumanReadableString(); | 156 << "GVD with config: " << config.AsHumanReadableString(); |
154 | 157 |
155 // TODO(posciak): destroy and create a new VDA on codec/profile change | 158 // TODO(posciak): destroy and create a new VDA on codec/profile change |
156 // (http://crbug.com/260224). | 159 // (http://crbug.com/260224). |
157 if (previously_initialized && (config_.profile() != config.profile())) { | 160 if (previously_initialized && (config_.profile() != config.profile())) { |
158 DVLOG(1) << "Codec or profile changed, cannot reinitialize."; | 161 DVLOG(1) << "Codec or profile changed, cannot reinitialize."; |
159 bound_init_cb.Run(false); | 162 bound_init_cb.Run(false); |
160 return; | 163 return; |
161 } | 164 } |
162 | 165 |
163 VideoDecodeAccelerator::Capabilities capabilities = | 166 VideoDecodeAccelerator::Capabilities capabilities = |
(...skipping 17 matching lines...) Expand all Loading... |
181 DVLOG(3) << __FUNCTION__ | 184 DVLOG(3) << __FUNCTION__ |
182 << " Expecting initialized VDA to detect in-stream config change."; | 185 << " Expecting initialized VDA to detect in-stream config change."; |
183 // Reinitialization with a different config (but same codec and profile). | 186 // Reinitialization with a different config (but same codec and profile). |
184 // VDA should handle it by detecting this in-stream by itself, | 187 // VDA should handle it by detecting this in-stream by itself, |
185 // no need to notify it. | 188 // no need to notify it. |
186 bound_init_cb.Run(true); | 189 bound_init_cb.Run(true); |
187 return; | 190 return; |
188 } | 191 } |
189 | 192 |
190 vda_ = factories_->CreateVideoDecodeAccelerator(); | 193 vda_ = factories_->CreateVideoDecodeAccelerator(); |
191 | 194 if (!vda_) { |
192 VideoDecodeAccelerator::Config vda_config(config); | 195 DVLOG(1) << "Failed to create a VDA."; |
193 | |
194 if (!vda_ || !vda_->Initialize(vda_config, this)) { | |
195 DVLOG(1) << "VDA initialization failed."; | |
196 bound_init_cb.Run(false); | 196 bound_init_cb.Run(false); |
197 return; | 197 return; |
198 } | 198 } |
199 | 199 |
| 200 int cdm_id = CdmContext::kInvalidCdmId; |
200 if (config.is_encrypted()) { | 201 if (config.is_encrypted()) { |
201 DCHECK(cdm_context); | 202 DCHECK(cdm_context); |
| 203 cdm_id = cdm_context->GetCdmId(); |
202 // No need to store |cdm_context| since it's not needed in reinitialization. | 204 // No need to store |cdm_context| since it's not needed in reinitialization. |
203 if (cdm_context->GetCdmId() == CdmContext::kInvalidCdmId) { | 205 if (cdm_id == CdmContext::kInvalidCdmId) { |
204 DVLOG(1) << "CDM ID not available."; | 206 DVLOG(1) << "CDM ID not available."; |
205 bound_init_cb.Run(false); | 207 bound_init_cb.Run(false); |
206 return; | 208 return; |
207 } | 209 } |
| 210 } |
208 | 211 |
209 // |init_cb_| will be fired when CDM is attached. | 212 init_cb_ = bound_init_cb; |
210 init_cb_ = bound_init_cb; | 213 |
211 vda_->SetCdm(cdm_context->GetCdmId()); | 214 const bool supports_external_output_surface = |
| 215 (capabilities.flags & VideoDecodeAccelerator::Capabilities:: |
| 216 SUPPORTS_EXTERNAL_OUTPUT_SURFACE) != 0; |
| 217 if (supports_external_output_surface && !request_surface_cb_.is_null()) { |
| 218 // If we have a surface request callback we should call it and complete |
| 219 // initialization with the returned surface. |
| 220 request_surface_cb_.Run( |
| 221 BindToCurrentLoop(base::Bind(&GpuVideoDecoder::CompleteInitialization, |
| 222 weak_factory_.GetWeakPtr(), cdm_id))); |
212 return; | 223 return; |
213 } | 224 } |
214 | 225 |
215 DVLOG(3) << "GpuVideoDecoder::Initialize() succeeded."; | 226 // If we don't have to wait for a surface complete initialization with a null |
216 bound_init_cb.Run(true); | 227 // surface. |
| 228 CompleteInitialization(cdm_id, SurfaceManager::kNoSurfaceID); |
| 229 } |
| 230 |
| 231 void GpuVideoDecoder::CompleteInitialization(int cdm_id, int surface_id) { |
| 232 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); |
| 233 DCHECK(!init_cb_.is_null()); |
| 234 |
| 235 VideoDecodeAccelerator::Config vda_config(config_); |
| 236 vda_config.surface_id = surface_id; |
| 237 if (!vda_->Initialize(vda_config, this)) { |
| 238 DVLOG(1) << "VDA::Initialize failed."; |
| 239 base::ResetAndReturn(&init_cb_).Run(false); |
| 240 return; |
| 241 } |
| 242 |
| 243 // The VDA is now initialized, but if the stream is encrypted we need to |
| 244 // attach the CDM before completing GVD's initialization. |
| 245 if (config_.is_encrypted()) { |
| 246 // TODO(watk,timav): Pass this in the VDA::Config. |
| 247 vda_->SetCdm(cdm_id); |
| 248 return; |
| 249 } |
| 250 |
| 251 base::ResetAndReturn(&init_cb_).Run(true); |
217 } | 252 } |
218 | 253 |
219 void GpuVideoDecoder::NotifyCdmAttached(bool success) { | 254 void GpuVideoDecoder::NotifyCdmAttached(bool success) { |
220 DVLOG_IF(2, !success) << __FUNCTION__ << ": CDM not attached."; | 255 DVLOG_IF(2, !success) << __FUNCTION__ << ": CDM not attached."; |
221 DCHECK(!init_cb_.is_null()); | 256 DCHECK(!init_cb_.is_null()); |
222 | 257 |
223 base::ResetAndReturn(&init_cb_).Run(success); | 258 base::ResetAndReturn(&init_cb_).Run(success); |
224 } | 259 } |
225 | 260 |
226 void GpuVideoDecoder::DestroyPictureBuffers(PictureBufferMap* buffers) { | 261 void GpuVideoDecoder::DestroyPictureBuffers(PictureBufferMap* buffers) { |
(...skipping 360 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
587 GpuVideoDecoder::~GpuVideoDecoder() { | 622 GpuVideoDecoder::~GpuVideoDecoder() { |
588 DVLOG(3) << __FUNCTION__; | 623 DVLOG(3) << __FUNCTION__; |
589 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); | 624 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); |
590 | 625 |
591 if (vda_) | 626 if (vda_) |
592 DestroyVDA(); | 627 DestroyVDA(); |
593 DCHECK(assigned_picture_buffers_.empty()); | 628 DCHECK(assigned_picture_buffers_.empty()); |
594 | 629 |
595 if (!init_cb_.is_null()) | 630 if (!init_cb_.is_null()) |
596 base::ResetAndReturn(&init_cb_).Run(false); | 631 base::ResetAndReturn(&init_cb_).Run(false); |
| 632 if (!request_surface_cb_.is_null()) |
| 633 base::ResetAndReturn(&request_surface_cb_).Run(SurfaceCreatedCB()); |
597 | 634 |
598 for (size_t i = 0; i < available_shm_segments_.size(); ++i) { | 635 for (size_t i = 0; i < available_shm_segments_.size(); ++i) { |
599 delete available_shm_segments_[i]; | 636 delete available_shm_segments_[i]; |
600 } | 637 } |
601 available_shm_segments_.clear(); | 638 available_shm_segments_.clear(); |
602 | 639 |
603 for (std::map<int32_t, PendingDecoderBuffer>::iterator it = | 640 for (std::map<int32_t, PendingDecoderBuffer>::iterator it = |
604 bitstream_buffers_in_decoder_.begin(); | 641 bitstream_buffers_in_decoder_.begin(); |
605 it != bitstream_buffers_in_decoder_.end(); ++it) { | 642 it != bitstream_buffers_in_decoder_.end(); ++it) { |
606 delete it->second.shm_buffer; | 643 delete it->second.shm_buffer; |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
668 } | 705 } |
669 return false; | 706 return false; |
670 } | 707 } |
671 | 708 |
672 void GpuVideoDecoder::DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent() | 709 void GpuVideoDecoder::DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent() |
673 const { | 710 const { |
674 DCHECK(factories_->GetTaskRunner()->BelongsToCurrentThread()); | 711 DCHECK(factories_->GetTaskRunner()->BelongsToCurrentThread()); |
675 } | 712 } |
676 | 713 |
677 } // namespace media | 714 } // namespace media |
OLD | NEW |