1// Copyright 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "media/base/android/video_decoder_job.h" 6 7#include "base/bind.h" 8#include "base/lazy_instance.h" 9#include "base/threading/thread.h" 10#include "media/base/android/media_codec_bridge.h" 11#include "media/base/android/media_drm_bridge.h" 12 13namespace media { 14 15class VideoDecoderThread : public base::Thread { 16 public: 17 VideoDecoderThread() : base::Thread("MediaSource_VideoDecoderThread") { 18 Start(); 19 } 20}; 21 22// TODO(qinmin): Check if it is tolerable to use worker pool to handle all the 23// decoding tasks so that we don't need a global thread here. 24// http://crbug.com/245750 25base::LazyInstance<VideoDecoderThread>::Leaky 26 g_video_decoder_thread = LAZY_INSTANCE_INITIALIZER; 27 28VideoDecoderJob::VideoDecoderJob( 29 const base::Closure& request_data_cb, 30 const base::Closure& request_resources_cb, 31 const base::Closure& on_demuxer_config_changed_cb) 32 : MediaDecoderJob(g_video_decoder_thread.Pointer()->message_loop_proxy(), 33 request_data_cb, 34 on_demuxer_config_changed_cb), 35 video_codec_(kUnknownVideoCodec), 36 config_width_(0), 37 config_height_(0), 38 output_width_(0), 39 output_height_(0), 40 request_resources_cb_(request_resources_cb), 41 next_video_data_is_iframe_(true) { 42} 43 44VideoDecoderJob::~VideoDecoderJob() {} 45 46bool VideoDecoderJob::SetVideoSurface(gfx::ScopedJavaSurface surface) { 47 // For an empty surface, always pass it to the |media_codec_bridge_| job so 48 // that it can detach from the current one. Otherwise, don't pass an 49 // unprotected surface if the video content requires a protected one. 50 if (!surface.IsEmpty() && IsProtectedSurfaceRequired() && 51 !surface.is_protected()) { 52 return false; 53 } 54 55 surface_ = surface.Pass(); 56 need_to_reconfig_decoder_job_ = true; 57 return true; 58} 59 60bool VideoDecoderJob::HasStream() const { 61 return video_codec_ != kUnknownVideoCodec; 62} 63 64void VideoDecoderJob::Flush() { 65 MediaDecoderJob::Flush(); 66 next_video_data_is_iframe_ = true; 67} 68 69void VideoDecoderJob::ReleaseDecoderResources() { 70 MediaDecoderJob::ReleaseDecoderResources(); 71 surface_ = gfx::ScopedJavaSurface(); 72} 73 74void VideoDecoderJob::SetDemuxerConfigs(const DemuxerConfigs& configs) { 75 video_codec_ = configs.video_codec; 76 config_width_ = configs.video_size.width(); 77 config_height_ = configs.video_size.height(); 78 set_is_content_encrypted(configs.is_video_encrypted); 79 if (!media_codec_bridge_) { 80 output_width_ = config_width_; 81 output_height_ = config_height_; 82 } 83} 84 85void VideoDecoderJob::ReleaseOutputBuffer( 86 int output_buffer_index, 87 size_t size, 88 bool render_output, 89 base::TimeDelta current_presentation_timestamp, 90 const ReleaseOutputCompletionCallback& callback) { 91 media_codec_bridge_->ReleaseOutputBuffer(output_buffer_index, render_output); 92 callback.Run(current_presentation_timestamp, current_presentation_timestamp); 93} 94 95bool VideoDecoderJob::ComputeTimeToRender() const { 96 return true; 97} 98 99bool VideoDecoderJob::IsCodecReconfigureNeeded( 100 const DemuxerConfigs& configs) const { 101 if (!media_codec_bridge_) 102 return true; 103 104 if (!AreDemuxerConfigsChanged(configs)) 105 return false; 106 107 bool only_size_changed = false; 108 if (video_codec_ == configs.video_codec && 109 is_content_encrypted() == configs.is_video_encrypted) { 110 only_size_changed = true; 111 } 112 113 return !only_size_changed || 114 !static_cast<VideoCodecBridge*>(media_codec_bridge_.get())-> 115 IsAdaptivePlaybackSupported(configs.video_size.width(), 116 configs.video_size.height()); 117} 118 119bool VideoDecoderJob::AreDemuxerConfigsChanged( 120 const DemuxerConfigs& configs) const { 121 return video_codec_ != configs.video_codec || 122 is_content_encrypted() != configs.is_video_encrypted || 123 config_width_ != configs.video_size.width() || 124 config_height_ != configs.video_size.height(); 125} 126 127bool VideoDecoderJob::CreateMediaCodecBridgeInternal() { 128 if (surface_.IsEmpty()) { 129 ReleaseMediaCodecBridge(); 130 return false; 131 } 132 133 // If the next data is not iframe, return false so that the player need to 134 // perform a browser seek. 135 if (!next_video_data_is_iframe_) 136 return false; 137 138 bool is_secure = is_content_encrypted() && drm_bridge() && 139 drm_bridge()->IsProtectedSurfaceRequired(); 140 141 media_codec_bridge_.reset(VideoCodecBridge::CreateDecoder( 142 video_codec_, is_secure, gfx::Size(config_width_, config_height_), 143 surface_.j_surface().obj(), GetMediaCrypto().obj())); 144 145 if (!media_codec_bridge_) 146 return false; 147 148 request_resources_cb_.Run(); 149 return true; 150} 151 152void VideoDecoderJob::CurrentDataConsumed(bool is_config_change) { 153 next_video_data_is_iframe_ = is_config_change; 154} 155 156bool VideoDecoderJob::UpdateOutputFormat() { 157 if (!media_codec_bridge_) 158 return false; 159 int prev_output_width = output_width_; 160 int prev_output_height = output_height_; 161 media_codec_bridge_->GetOutputFormat(&output_width_, &output_height_); 162 return (output_width_ != prev_output_width) || 163 (output_height_ != prev_output_height); 164} 165 166bool VideoDecoderJob::IsProtectedSurfaceRequired() { 167 return is_content_encrypted() && drm_bridge() && 168 drm_bridge()->IsProtectedSurfaceRequired(); 169} 170 171} // namespace media 172