• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
13 namespace media {
14 
15 class VideoDecoderThread : public base::Thread {
16  public:
VideoDecoderThread()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
25 base::LazyInstance<VideoDecoderThread>::Leaky
26     g_video_decoder_thread = LAZY_INSTANCE_INITIALIZER;
27 
VideoDecoderJob(const base::Closure & request_data_cb,const base::Closure & request_resources_cb,const base::Closure & on_demuxer_config_changed_cb)28 VideoDecoderJob::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 
~VideoDecoderJob()44 VideoDecoderJob::~VideoDecoderJob() {}
45 
SetVideoSurface(gfx::ScopedJavaSurface surface)46 bool 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 
HasStream() const60 bool VideoDecoderJob::HasStream() const {
61   return video_codec_ != kUnknownVideoCodec;
62 }
63 
Flush()64 void VideoDecoderJob::Flush() {
65   MediaDecoderJob::Flush();
66   next_video_data_is_iframe_ = true;
67 }
68 
ReleaseDecoderResources()69 void VideoDecoderJob::ReleaseDecoderResources() {
70   MediaDecoderJob::ReleaseDecoderResources();
71   surface_ = gfx::ScopedJavaSurface();
72 }
73 
SetDemuxerConfigs(const DemuxerConfigs & configs)74 void 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 
ReleaseOutputBuffer(int output_buffer_index,size_t size,bool render_output,base::TimeDelta current_presentation_timestamp,const ReleaseOutputCompletionCallback & callback)85 void 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 
ComputeTimeToRender() const95 bool VideoDecoderJob::ComputeTimeToRender() const {
96   return true;
97 }
98 
IsCodecReconfigureNeeded(const DemuxerConfigs & configs) const99 bool 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 
AreDemuxerConfigsChanged(const DemuxerConfigs & configs) const119 bool 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 
CreateMediaCodecBridgeInternal()127 bool 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 
CurrentDataConsumed(bool is_config_change)152 void VideoDecoderJob::CurrentDataConsumed(bool is_config_change) {
153   next_video_data_is_iframe_ = is_config_change;
154 }
155 
UpdateOutputFormat()156 bool 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 
IsProtectedSurfaceRequired()166 bool VideoDecoderJob::IsProtectedSurfaceRequired() {
167   return is_content_encrypted() && drm_bridge() &&
168       drm_bridge()->IsProtectedSurfaceRequired();
169 }
170 
171 }  // namespace media
172