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.
5 #include "media/base/android/video_decoder_job.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"
15 class VideoDecoderThread : public base::Thread {
17 VideoDecoderThread() : base::Thread("MediaSource_VideoDecoderThread") {
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;
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(),
34 on_demuxer_config_changed_cb),
35 video_codec_(kUnknownVideoCodec),
38 request_resources_cb_(request_resources_cb),
39 next_video_data_is_iframe_(true) {
42 VideoDecoderJob::~VideoDecoderJob() {}
44 bool VideoDecoderJob::SetVideoSurface(gfx::ScopedJavaSurface surface) {
45 // For an empty surface, always pass it to the |media_codec_bridge_| job so
46 // that it can detach from the current one. Otherwise, don't pass an
47 // unprotected surface if the video content requires a protected one.
48 if (!surface.IsEmpty() && IsProtectedSurfaceRequired() &&
49 !surface.is_protected()) {
53 surface_ = surface.Pass();
54 need_to_reconfig_decoder_job_ = true;
58 bool VideoDecoderJob::HasStream() const {
59 return video_codec_ != kUnknownVideoCodec;
62 void VideoDecoderJob::Flush() {
63 MediaDecoderJob::Flush();
64 next_video_data_is_iframe_ = true;
67 void VideoDecoderJob::ReleaseDecoderResources() {
68 MediaDecoderJob::ReleaseDecoderResources();
69 surface_ = gfx::ScopedJavaSurface();
72 void VideoDecoderJob::ReleaseOutputBuffer(
73 int output_buffer_index,
76 base::TimeDelta current_presentation_timestamp,
77 const ReleaseOutputCompletionCallback& callback) {
78 media_codec_bridge_->ReleaseOutputBuffer(output_buffer_index, render_output);
79 callback.Run(current_presentation_timestamp, current_presentation_timestamp);
82 bool VideoDecoderJob::ComputeTimeToRender() const {
86 void VideoDecoderJob::UpdateDemuxerConfigs(const DemuxerConfigs& configs) {
87 video_codec_ = configs.video_codec;
88 width_ = configs.video_size.width();
89 height_ = configs.video_size.height();
90 set_is_content_encrypted(configs.is_video_encrypted);
93 bool VideoDecoderJob::IsCodecReconfigureNeeded(
94 const DemuxerConfigs& configs) const {
95 if (!media_codec_bridge_)
98 if (!AreDemuxerConfigsChanged(configs))
101 bool only_size_changed = false;
102 if (video_codec_ == configs.video_codec &&
103 is_content_encrypted() == configs.is_video_encrypted) {
104 only_size_changed = true;
107 return !only_size_changed ||
108 !static_cast<VideoCodecBridge*>(media_codec_bridge_.get())->
109 IsAdaptivePlaybackSupported(configs.video_size.width(),
110 configs.video_size.height());
113 bool VideoDecoderJob::AreDemuxerConfigsChanged(
114 const DemuxerConfigs& configs) const {
115 return video_codec_ != configs.video_codec ||
116 is_content_encrypted() != configs.is_video_encrypted ||
117 width_ != configs.video_size.width() ||
118 height_ != configs.video_size.height();
121 bool VideoDecoderJob::CreateMediaCodecBridgeInternal() {
122 if (surface_.IsEmpty()) {
123 ReleaseMediaCodecBridge();
127 // If the next data is not iframe, return false so that the player need to
128 // perform a browser seek.
129 if (!next_video_data_is_iframe_)
132 bool is_secure = is_content_encrypted() && drm_bridge() &&
133 drm_bridge()->IsProtectedSurfaceRequired();
135 media_codec_bridge_.reset(VideoCodecBridge::CreateDecoder(
136 video_codec_, is_secure, gfx::Size(width_, height_),
137 surface_.j_surface().obj(), GetMediaCrypto().obj()));
139 if (!media_codec_bridge_)
142 request_resources_cb_.Run();
146 void VideoDecoderJob::CurrentDataConsumed(bool is_config_change) {
147 next_video_data_is_iframe_ = is_config_change;
150 bool VideoDecoderJob::IsProtectedSurfaceRequired() {
151 return is_content_encrypted() && drm_bridge() &&
152 drm_bridge()->IsProtectedSurfaceRequired();