1 // Copyright 2015 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/media_codec_video_decoder.h"
8 #include "base/logging.h"
9 #include "media/base/android/media_codec_bridge.h"
10 #include "media/base/buffers.h"
11 #include "media/base/demuxer_stream.h"
16 const int kDelayForStandAloneEOS
= 2; // milliseconds
19 MediaCodecVideoDecoder::MediaCodecVideoDecoder(
20 const scoped_refptr
<base::SingleThreadTaskRunner
>& media_task_runner
,
21 const base::Closure
& request_data_cb
,
22 const base::Closure
& starvation_cb
,
23 const base::Closure
& stop_done_cb
,
24 const base::Closure
& error_cb
,
25 const SetTimeCallback
& update_current_time_cb
,
26 const VideoSizeChangedCallback
& video_size_changed_cb
,
27 const base::Closure
& codec_created_cb
)
28 : MediaCodecDecoder(media_task_runner
,
34 update_current_time_cb_(update_current_time_cb
),
35 video_size_changed_cb_(video_size_changed_cb
),
36 codec_created_cb_(codec_created_cb
) {
39 MediaCodecVideoDecoder::~MediaCodecVideoDecoder() {
40 DVLOG(1) << "VideoDecoder::~VideoDecoder()";
41 ReleaseDecoderResources();
44 const char* MediaCodecVideoDecoder::class_name() const {
45 return "VideoDecoder";
48 bool MediaCodecVideoDecoder::HasStream() const {
49 DCHECK(media_task_runner_
->BelongsToCurrentThread());
51 return configs_
.video_codec
!= kUnknownVideoCodec
;
54 void MediaCodecVideoDecoder::SetDemuxerConfigs(const DemuxerConfigs
& configs
) {
55 DCHECK(media_task_runner_
->BelongsToCurrentThread());
57 DVLOG(1) << class_name() << "::" << __FUNCTION__
<< " " << configs
;
61 if (video_size_
.IsEmpty()) {
62 video_size_
= configs_
.video_size
;
63 media_task_runner_
->PostTask(
64 FROM_HERE
, base::Bind(video_size_changed_cb_
, video_size_
));
68 void MediaCodecVideoDecoder::ReleaseDecoderResources() {
69 DCHECK(media_task_runner_
->BelongsToCurrentThread());
71 DVLOG(1) << class_name() << "::" << __FUNCTION__
;
73 MediaCodecDecoder::ReleaseDecoderResources();
74 surface_
= gfx::ScopedJavaSurface();
75 delayed_buffers_
.clear();
78 void MediaCodecVideoDecoder::SetPendingSurface(gfx::ScopedJavaSurface surface
) {
79 DCHECK(media_task_runner_
->BelongsToCurrentThread());
81 surface_
= surface
.Pass();
83 if (surface_
.IsEmpty()) {
84 // Synchronously stop decoder thread and release MediaCodec
85 ReleaseDecoderResources();
89 bool MediaCodecVideoDecoder::HasPendingSurface() const {
90 DCHECK(media_task_runner_
->BelongsToCurrentThread());
92 return !surface_
.IsEmpty();
95 bool MediaCodecVideoDecoder::IsCodecReconfigureNeeded(
96 const DemuxerConfigs
& curr
,
97 const DemuxerConfigs
& next
) const {
98 if (curr
.video_codec
!= next
.video_codec
||
99 curr
.is_video_encrypted
!= next
.is_video_encrypted
) {
103 // Only size changes below this point
105 if (curr
.video_size
.width() == next
.video_size
.width() &&
106 curr
.video_size
.height() == next
.video_size
.height()) {
107 return false; // i.e. curr == next
110 return !static_cast<VideoCodecBridge
*>(media_codec_bridge_
.get())
111 ->IsAdaptivePlaybackSupported(next
.video_size
.width(),
112 next
.video_size
.height());
115 MediaCodecDecoder::ConfigStatus
MediaCodecVideoDecoder::ConfigureInternal() {
116 DCHECK(media_task_runner_
->BelongsToCurrentThread());
118 DVLOG(1) << class_name() << "::" << __FUNCTION__
;
120 // If we cannot find a key frame in cache, the browser seek is needed.
121 if (!au_queue_
.RewindToLastKeyFrame()) {
122 DVLOG(1) << class_name() << "::" << __FUNCTION__
<< " key frame required";
124 // The processing of CONFIG_KEY_FRAME_REQUIRED is not implemented yet,
125 // return error for now.
126 // TODO(timav): Replace this with the following line together with
127 // implementing the browser seek:
128 // return CONFIG_KEY_FRAME_REQUIRED;
129 return CONFIG_FAILURE
;
132 // TODO(timav): implement DRM.
133 // bool is_secure = is_content_encrypted() && drm_bridge() &&
134 // drm_bridge()->IsProtectedSurfaceRequired();
136 bool is_secure
= false; // DRM is not implemented
138 if (surface_
.IsEmpty()) {
139 DVLOG(0) << class_name() << "::" << __FUNCTION__
<< " surface required";
140 return CONFIG_FAILURE
;
143 media_codec_bridge_
.reset(VideoCodecBridge::CreateDecoder(
144 configs_
.video_codec
,
147 surface_
.j_surface().obj(),
148 GetMediaCrypto().obj()));
150 if (!media_codec_bridge_
) {
151 DVLOG(1) << class_name() << "::" << __FUNCTION__
<< " failed";
152 return CONFIG_FAILURE
;
155 DVLOG(1) << class_name() << "::" << __FUNCTION__
<< " succeeded";
157 media_task_runner_
->PostTask(FROM_HERE
, codec_created_cb_
);
162 void MediaCodecVideoDecoder::SynchronizePTSWithTime(
163 base::TimeDelta current_time
) {
164 DCHECK(media_task_runner_
->BelongsToCurrentThread());
166 start_time_ticks_
= base::TimeTicks::Now();
167 start_pts_
= current_time
;
168 last_seen_pts_
= current_time
;
171 void MediaCodecVideoDecoder::OnOutputFormatChanged() {
172 DCHECK(decoder_thread_
.task_runner()->BelongsToCurrentThread());
174 gfx::Size prev_size
= video_size_
;
176 // See b/18224769. The values reported from MediaCodecBridge::GetOutputFormat
177 // correspond to the actual video frame size, but this is not necessarily the
178 // size that should be output.
179 video_size_
= configs_
.video_size
;
180 if (video_size_
!= prev_size
) {
181 media_task_runner_
->PostTask(
182 FROM_HERE
, base::Bind(video_size_changed_cb_
, video_size_
));
186 void MediaCodecVideoDecoder::Render(int buffer_index
,
190 bool eos_encountered
) {
191 DCHECK(decoder_thread_
.task_runner()->BelongsToCurrentThread());
193 DVLOG(2) << class_name() << "::" << __FUNCTION__
<< " pts:" << pts
194 << " index:" << buffer_index
<< " size:" << size
195 << (eos_encountered
? " EOS" : "");
197 // Normally EOS comes as a separate access unit that does not have data,
198 // the corresponding |size| will be 0.
199 if (!size
&& eos_encountered
) {
201 // Discard the PTS that comes with it and ensure it is released last.
202 pts
= last_seen_pts_
+
203 base::TimeDelta::FromMilliseconds(kDelayForStandAloneEOS
);
205 // Keep track of last seen PTS
206 last_seen_pts_
= pts
;
209 if (!render_output
) {
210 ReleaseOutputBuffer(buffer_index
, pts
, size
, false, eos_encountered
);
214 base::TimeDelta time_to_render
=
215 pts
- (base::TimeTicks::Now() - start_time_ticks_
+ start_pts_
);
217 if (time_to_render
< base::TimeDelta()) {
219 ReleaseOutputBuffer(buffer_index
, pts
, size
, false, eos_encountered
);
223 delayed_buffers_
.insert(buffer_index
);
225 bool do_render
= size
> 0;
226 decoder_thread_
.task_runner()->PostDelayedTask(
227 FROM_HERE
, base::Bind(&MediaCodecVideoDecoder::ReleaseOutputBuffer
,
228 base::Unretained(this), buffer_index
, pts
,
229 size
, do_render
, eos_encountered
),
233 int MediaCodecVideoDecoder::NumDelayedRenderTasks() const {
234 DCHECK(decoder_thread_
.task_runner()->BelongsToCurrentThread());
236 return delayed_buffers_
.size();
239 void MediaCodecVideoDecoder::ReleaseDelayedBuffers() {
241 // Called when there is no decoder thread
242 for (int index
: delayed_buffers_
)
243 media_codec_bridge_
->ReleaseOutputBuffer(index
, false);
244 delayed_buffers_
.clear();
247 void MediaCodecVideoDecoder::ReleaseOutputBuffer(int buffer_index
,
251 bool eos_encountered
) {
252 DCHECK(decoder_thread_
.task_runner()->BelongsToCurrentThread());
254 DVLOG(2) << class_name() << "::" << __FUNCTION__
<< " pts:" << pts
;
256 media_codec_bridge_
->ReleaseOutputBuffer(buffer_index
, render
);
258 delayed_buffers_
.erase(buffer_index
);
260 CheckLastFrame(eos_encountered
, !delayed_buffers_
.empty());
262 // |update_current_time_cb_| might be null if there is audio stream.
263 // Do not update current time for stand-alone EOS frames.
264 if (!update_current_time_cb_
.is_null() && !(eos_encountered
&& !size
)) {
265 media_task_runner_
->PostTask(FROM_HERE
,
266 base::Bind(update_current_time_cb_
, pts
, pts
));