Home | History | Annotate | Download | only in android
      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:
     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 
     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 
     44 VideoDecoderJob::~VideoDecoderJob() {}
     45 
     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 
     60 bool VideoDecoderJob::HasStream() const {
     61   return video_codec_ != kUnknownVideoCodec;
     62 }
     63 
     64 void VideoDecoderJob::Flush() {
     65   MediaDecoderJob::Flush();
     66   next_video_data_is_iframe_ = true;
     67 }
     68 
     69 void VideoDecoderJob::ReleaseDecoderResources() {
     70   MediaDecoderJob::ReleaseDecoderResources();
     71   surface_ = gfx::ScopedJavaSurface();
     72 }
     73 
     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 
     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 
     95 bool VideoDecoderJob::ComputeTimeToRender() const {
     96   return true;
     97 }
     98 
     99 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 
    119 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 
    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 
    152 void VideoDecoderJob::CurrentDataConsumed(bool is_config_change) {
    153   next_video_data_is_iframe_ = is_config_change;
    154 }
    155 
    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 
    166 bool VideoDecoderJob::IsProtectedSurfaceRequired() {
    167   return is_content_encrypted() && drm_bridge() &&
    168       drm_bridge()->IsProtectedSurfaceRequired();
    169 }
    170 
    171 }  // namespace media
    172