| 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/decoder_buffer.h" | 21 #include "media/base/decoder_buffer.h" |
| 22 #include "media/base/media_switches.h" | 22 #include "media/base/media_switches.h" |
| 23 #include "media/base/pipeline.h" | 23 #include "media/base/pipeline.h" |
| 24 #include "media/base/surface_manager.h" |
| 24 #include "media/base/video_decoder_config.h" | 25 #include "media/base/video_decoder_config.h" |
| 25 #include "media/renderers/gpu_video_accelerator_factories.h" | 26 #include "media/renderers/gpu_video_accelerator_factories.h" |
| 26 #include "third_party/skia/include/core/SkBitmap.h" | 27 #include "third_party/skia/include/core/SkBitmap.h" |
| 27 | 28 |
| 28 namespace media { | 29 namespace media { |
| 29 | 30 |
| 30 const char GpuVideoDecoder::kDecoderName[] = "GpuVideoDecoder"; | 31 const char GpuVideoDecoder::kDecoderName[] = "GpuVideoDecoder"; |
| 31 | 32 |
| 32 // Maximum number of concurrent VDA::Decode() operations GVD will maintain. | 33 // Maximum number of concurrent VDA::Decode() operations GVD will maintain. |
| 33 // Higher values allow better pipelining in the GPU, but also require more | 34 // Higher values allow better pipelining in the GPU, but also require more |
| (...skipping 23 matching lines...) Expand all Loading... |
| 57 base::TimeDelta ts, | 58 base::TimeDelta ts, |
| 58 const gfx::Rect& vr, | 59 const gfx::Rect& vr, |
| 59 const gfx::Size& ns) | 60 const gfx::Size& ns) |
| 60 : bitstream_buffer_id(bbid), | 61 : bitstream_buffer_id(bbid), |
| 61 timestamp(ts), | 62 timestamp(ts), |
| 62 visible_rect(vr), | 63 visible_rect(vr), |
| 63 natural_size(ns) {} | 64 natural_size(ns) {} |
| 64 | 65 |
| 65 GpuVideoDecoder::BufferData::~BufferData() {} | 66 GpuVideoDecoder::BufferData::~BufferData() {} |
| 66 | 67 |
| 67 GpuVideoDecoder::GpuVideoDecoder(GpuVideoAcceleratorFactories* factories) | 68 GpuVideoDecoder::GpuVideoDecoder(GpuVideoAcceleratorFactories* factories, |
| 69 const RequestSurfaceCB& request_surface_cb) |
| 68 : needs_bitstream_conversion_(false), | 70 : needs_bitstream_conversion_(false), |
| 69 factories_(factories), | 71 factories_(factories), |
| 70 state_(kNormal), | 72 state_(kNormal), |
| 73 request_surface_cb_(request_surface_cb), |
| 71 decoder_texture_target_(0), | 74 decoder_texture_target_(0), |
| 72 next_picture_buffer_id_(0), | 75 next_picture_buffer_id_(0), |
| 73 next_bitstream_buffer_id_(0), | 76 next_bitstream_buffer_id_(0), |
| 74 available_pictures_(0), | 77 available_pictures_(0), |
| 75 needs_all_picture_buffers_to_decode_(false), | 78 needs_all_picture_buffers_to_decode_(false), |
| 76 weak_factory_(this) { | 79 weak_factory_(this) { |
| 77 DCHECK(factories_); | 80 DCHECK(factories_); |
| 78 } | 81 } |
| 79 | 82 |
| 80 void GpuVideoDecoder::Reset(const base::Closure& closure) { | 83 void GpuVideoDecoder::Reset(const base::Closure& closure) { |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 141 | 144 |
| 142 #if !defined(OS_ANDROID) | 145 #if !defined(OS_ANDROID) |
| 143 if (config.is_encrypted()) { | 146 if (config.is_encrypted()) { |
| 144 DVLOG(1) << "Encrypted stream not supported."; | 147 DVLOG(1) << "Encrypted stream not supported."; |
| 145 bound_init_cb.Run(false); | 148 bound_init_cb.Run(false); |
| 146 return; | 149 return; |
| 147 } | 150 } |
| 148 #endif | 151 #endif |
| 149 | 152 |
| 150 bool previously_initialized = config_.IsValidConfig(); | 153 bool previously_initialized = config_.IsValidConfig(); |
| 151 DVLOG(1) << "(Re)initializing GVD with config: " | 154 DVLOG(1) << (previously_initialized ? "Reinitializing" : "Initializing") |
| 152 << config.AsHumanReadableString(); | 155 << "GVD with config: " << config.AsHumanReadableString(); |
| 153 | 156 |
| 154 // TODO(posciak): destroy and create a new VDA on codec/profile change | 157 // TODO(posciak): destroy and create a new VDA on codec/profile change |
| 155 // (http://crbug.com/260224). | 158 // (http://crbug.com/260224). |
| 156 if (previously_initialized && (config_.profile() != config.profile())) { | 159 if (previously_initialized && (config_.profile() != config.profile())) { |
| 157 DVLOG(1) << "Codec or profile changed, cannot reinitialize."; | 160 DVLOG(1) << "Codec or profile changed, cannot reinitialize."; |
| 158 bound_init_cb.Run(false); | 161 bound_init_cb.Run(false); |
| 159 return; | 162 return; |
| 160 } | 163 } |
| 161 | 164 |
| 162 VideoDecodeAccelerator::Capabilities capabilities = | 165 VideoDecodeAccelerator::Capabilities capabilities = |
| (...skipping 17 matching lines...) Expand all Loading... |
| 180 DVLOG(3) << __FUNCTION__ | 183 DVLOG(3) << __FUNCTION__ |
| 181 << " Expecting initialized VDA to detect in-stream config change."; | 184 << " Expecting initialized VDA to detect in-stream config change."; |
| 182 // Reinitialization with a different config (but same codec and profile). | 185 // Reinitialization with a different config (but same codec and profile). |
| 183 // VDA should handle it by detecting this in-stream by itself, | 186 // VDA should handle it by detecting this in-stream by itself, |
| 184 // no need to notify it. | 187 // no need to notify it. |
| 185 bound_init_cb.Run(true); | 188 bound_init_cb.Run(true); |
| 186 return; | 189 return; |
| 187 } | 190 } |
| 188 | 191 |
| 189 vda_ = factories_->CreateVideoDecodeAccelerator(); | 192 vda_ = factories_->CreateVideoDecodeAccelerator(); |
| 190 | 193 if (!vda_) { |
| 191 VideoDecodeAccelerator::Config vda_config(config); | 194 DVLOG(1) << "Failed to create a VDA."; |
| 192 | |
| 193 if (!vda_ || !vda_->Initialize(vda_config, this)) { | |
| 194 DVLOG(1) << "VDA initialization failed."; | |
| 195 bound_init_cb.Run(false); | 195 bound_init_cb.Run(false); |
| 196 return; | 196 return; |
| 197 } | 197 } |
| 198 | 198 |
| 199 // CompleteInitialization will clear both of these callbacks. |
| 200 init_cb_ = bound_init_cb; |
| 199 if (config.is_encrypted()) { | 201 if (config.is_encrypted()) { |
| 200 init_cb_ = bound_init_cb; | |
| 201 set_cdm_ready_cb_ = set_cdm_ready_cb; | 202 set_cdm_ready_cb_ = set_cdm_ready_cb; |
| 203 } |
| 204 |
| 205 const bool supports_external_output_surface = |
| 206 capabilities.flags & |
| 207 VideoDecodeAccelerator::Capabilities::SUPPORTS_EXTERNAL_OUTPUT_SURFACE; |
| 208 if (supports_external_output_surface && !request_surface_cb_.is_null()) { |
| 209 // If we have surface request callback we should call it and complete |
| 210 // initialization with the returned surface. |
| 211 request_surface_cb_.Run(BindToCurrentLoop(base::Bind( |
| 212 &GpuVideoDecoder::CompleteInitialization, weak_factory_.GetWeakPtr()))); |
| 213 return; |
| 214 } |
| 215 |
| 216 // Complete initialization with a null surface. |
| 217 CompleteInitialization(SurfaceManager::kNoSurfaceID); |
| 218 } |
| 219 |
| 220 void GpuVideoDecoder::CompleteInitialization(int surface_id) { |
| 221 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); |
| 222 DCHECK(!init_cb_.is_null()); |
| 223 |
| 224 VideoDecodeAccelerator::Config vda_config(config_); |
| 225 vda_config.surface_id = surface_id; |
| 226 if (!vda_->Initialize(vda_config, this)) { |
| 227 DVLOG(1) << "VDA::Initialize failed."; |
| 228 set_cdm_ready_cb_.Reset(); |
| 229 base::ResetAndReturn(&init_cb_).Run(false); |
| 230 return; |
| 231 } |
| 232 |
| 233 // The VDA is now initialized, but If the stream is encrypted we need to |
| 234 // request and attach the CDM before completing GVD's initialization. |
| 235 if (config_.is_encrypted()) { |
| 202 set_cdm_ready_cb_.Run(BindToCurrentLoop( | 236 set_cdm_ready_cb_.Run(BindToCurrentLoop( |
| 203 base::Bind(&GpuVideoDecoder::SetCdm, weak_factory_.GetWeakPtr()))); | 237 base::Bind(&GpuVideoDecoder::SetCdm, weak_factory_.GetWeakPtr()))); |
| 204 return; | 238 return; |
| 205 } | 239 } |
| 206 | 240 |
| 207 DVLOG(3) << "GpuVideoDecoder::Initialize() succeeded."; | 241 base::ResetAndReturn(&init_cb_).Run(true); |
| 208 bound_init_cb.Run(true); | |
| 209 } | 242 } |
| 210 | 243 |
| 211 void GpuVideoDecoder::SetCdm(CdmContext* cdm_context, | 244 void GpuVideoDecoder::SetCdm(CdmContext* cdm_context, |
| 212 const CdmAttachedCB& cdm_attached_cb) { | 245 const CdmAttachedCB& cdm_attached_cb) { |
| 213 DVLOG(2) << __FUNCTION__; | 246 DVLOG(2) << __FUNCTION__; |
| 214 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); | 247 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); |
| 215 | 248 |
| 216 DCHECK(!init_cb_.is_null()); | 249 DCHECK(!init_cb_.is_null()); |
| 217 DCHECK(!set_cdm_ready_cb_.is_null()); | 250 DCHECK(!set_cdm_ready_cb_.is_null()); |
| 218 set_cdm_ready_cb_.Reset(); | 251 set_cdm_ready_cb_.Reset(); |
| (...skipping 386 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 605 if (vda_) | 638 if (vda_) |
| 606 DestroyVDA(); | 639 DestroyVDA(); |
| 607 DCHECK(assigned_picture_buffers_.empty()); | 640 DCHECK(assigned_picture_buffers_.empty()); |
| 608 | 641 |
| 609 if (!set_cdm_ready_cb_.is_null()) | 642 if (!set_cdm_ready_cb_.is_null()) |
| 610 base::ResetAndReturn(&set_cdm_ready_cb_).Run(CdmReadyCB()); | 643 base::ResetAndReturn(&set_cdm_ready_cb_).Run(CdmReadyCB()); |
| 611 if (!cdm_attached_cb_.is_null()) | 644 if (!cdm_attached_cb_.is_null()) |
| 612 base::ResetAndReturn(&cdm_attached_cb_).Run(false); | 645 base::ResetAndReturn(&cdm_attached_cb_).Run(false); |
| 613 if (!init_cb_.is_null()) | 646 if (!init_cb_.is_null()) |
| 614 base::ResetAndReturn(&init_cb_).Run(false); | 647 base::ResetAndReturn(&init_cb_).Run(false); |
| 648 if (!request_surface_cb_.is_null()) |
| 649 base::ResetAndReturn(&request_surface_cb_).Run(SurfaceCreatedCB()); |
| 615 | 650 |
| 616 for (size_t i = 0; i < available_shm_segments_.size(); ++i) { | 651 for (size_t i = 0; i < available_shm_segments_.size(); ++i) { |
| 617 delete available_shm_segments_[i]; | 652 delete available_shm_segments_[i]; |
| 618 } | 653 } |
| 619 available_shm_segments_.clear(); | 654 available_shm_segments_.clear(); |
| 620 | 655 |
| 621 for (std::map<int32_t, PendingDecoderBuffer>::iterator it = | 656 for (std::map<int32_t, PendingDecoderBuffer>::iterator it = |
| 622 bitstream_buffers_in_decoder_.begin(); | 657 bitstream_buffers_in_decoder_.begin(); |
| 623 it != bitstream_buffers_in_decoder_.end(); ++it) { | 658 it != bitstream_buffers_in_decoder_.end(); ++it) { |
| 624 delete it->second.shm_buffer; | 659 delete it->second.shm_buffer; |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 686 } | 721 } |
| 687 return false; | 722 return false; |
| 688 } | 723 } |
| 689 | 724 |
| 690 void GpuVideoDecoder::DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent() | 725 void GpuVideoDecoder::DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent() |
| 691 const { | 726 const { |
| 692 DCHECK(factories_->GetTaskRunner()->BelongsToCurrentThread()); | 727 DCHECK(factories_->GetTaskRunner()->BelongsToCurrentThread()); |
| 693 } | 728 } |
| 694 | 729 |
| 695 } // namespace media | 730 } // namespace media |
| OLD | NEW |