Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(473)

Side by Side Diff: media/base/android/media_codec_video_decoder.cc

Issue 1682923003: Rename browser side MediaCodec-based decoders (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Reformatted to make bots happy Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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.
4
5 #include "media/base/android/media_codec_video_decoder.h"
6
7 #include <utility>
8
9 #include "base/bind.h"
10 #include "base/logging.h"
11 #include "media/base/android/media_statistics.h"
12 #include "media/base/android/sdk_media_codec_bridge.h"
13 #include "media/base/demuxer_stream.h"
14 #include "media/base/timestamp_constants.h"
15
16 namespace media {
17
18 namespace {
19 const int kDelayForStandAloneEOS = 2; // milliseconds
20 }
21
22 MediaCodecVideoDecoder::MediaCodecVideoDecoder(
23 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
24 FrameStatistics* frame_statistics,
25 const base::Closure& request_data_cb,
26 const base::Closure& starvation_cb,
27 const base::Closure& decoder_drained_cb,
28 const base::Closure& stop_done_cb,
29 const base::Closure& waiting_for_decryption_key_cb,
30 const base::Closure& error_cb,
31 const SetTimeCallback& update_current_time_cb,
32 const VideoSizeChangedCallback& video_size_changed_cb)
33 : MediaCodecDecoder("VideoDecoder",
34 media_task_runner,
35 frame_statistics,
36 request_data_cb,
37 starvation_cb,
38 decoder_drained_cb,
39 stop_done_cb,
40 waiting_for_decryption_key_cb,
41 error_cb),
42 is_protected_surface_required_(false),
43 update_current_time_cb_(update_current_time_cb),
44 video_size_changed_cb_(video_size_changed_cb) {
45 }
46
47 MediaCodecVideoDecoder::~MediaCodecVideoDecoder() {
48 DCHECK(media_task_runner_->BelongsToCurrentThread());
49 DVLOG(1) << "VideoDecoder::~VideoDecoder()";
50 ReleaseDecoderResources();
51 }
52
53 const char* MediaCodecVideoDecoder::class_name() const {
54 return "VideoDecoder";
55 }
56
57 bool MediaCodecVideoDecoder::HasStream() const {
58 DCHECK(media_task_runner_->BelongsToCurrentThread());
59
60 return configs_.video_codec != kUnknownVideoCodec;
61 }
62
63 void MediaCodecVideoDecoder::SetDemuxerConfigs(const DemuxerConfigs& configs) {
64 DVLOG(1) << class_name() << "::" << __FUNCTION__ << " " << configs;
65
66 configs_ = configs;
67
68 if (video_size_.IsEmpty()) {
69 video_size_ = configs_.video_size;
70 media_task_runner_->PostTask(
71 FROM_HERE, base::Bind(video_size_changed_cb_, video_size_));
72 }
73 }
74
75 bool MediaCodecVideoDecoder::IsContentEncrypted() const {
76 // Make sure SetDemuxerConfigs() as been called.
77 DCHECK(configs_.video_codec != kUnknownVideoCodec);
78 return configs_.is_video_encrypted;
79 }
80
81 void MediaCodecVideoDecoder::ReleaseDecoderResources() {
82 DCHECK(media_task_runner_->BelongsToCurrentThread());
83 DVLOG(1) << class_name() << "::" << __FUNCTION__;
84
85 DoEmergencyStop();
86
87 ReleaseMediaCodec();
88
89 surface_ = gfx::ScopedJavaSurface();
90 }
91
92 void MediaCodecVideoDecoder::ReleaseMediaCodec() {
93 DCHECK(media_task_runner_->BelongsToCurrentThread());
94
95 MediaCodecDecoder::ReleaseMediaCodec();
96 delayed_buffers_.clear();
97 }
98
99 void MediaCodecVideoDecoder::SetVideoSurface(gfx::ScopedJavaSurface surface) {
100 DCHECK(media_task_runner_->BelongsToCurrentThread());
101
102 DVLOG(1) << class_name() << "::" << __FUNCTION__
103 << (surface.IsEmpty() ? " empty" : " non-empty");
104
105 surface_ = std::move(surface);
106
107 needs_reconfigure_ = true;
108 }
109
110 bool MediaCodecVideoDecoder::HasVideoSurface() const {
111 DCHECK(media_task_runner_->BelongsToCurrentThread());
112
113 return !surface_.IsEmpty();
114 }
115
116 void MediaCodecVideoDecoder::SetProtectedSurfaceRequired(bool value) {
117 DCHECK(media_task_runner_->BelongsToCurrentThread());
118
119 is_protected_surface_required_ = value;
120 }
121
122 bool MediaCodecVideoDecoder::IsProtectedSurfaceRequired() const {
123 DCHECK(media_task_runner_->BelongsToCurrentThread());
124
125 return is_protected_surface_required_;
126 }
127
128 bool MediaCodecVideoDecoder::IsCodecReconfigureNeeded(
129 const DemuxerConfigs& next) const {
130 if (always_reconfigure_for_tests_)
131 return true;
132
133 if (configs_.video_codec != next.video_codec ||
134 configs_.is_video_encrypted != next.is_video_encrypted) {
135 return true;
136 }
137
138 // Only size changes below this point
139
140 if (configs_.video_size.width() == next.video_size.width() &&
141 configs_.video_size.height() == next.video_size.height()) {
142 return false; // i.e. configs_ == next
143 }
144
145 return !static_cast<VideoCodecBridge*>(media_codec_bridge_.get())
146 ->IsAdaptivePlaybackSupported(next.video_size.width(),
147 next.video_size.height());
148 }
149
150 MediaCodecDecoder::ConfigStatus MediaCodecVideoDecoder::ConfigureInternal(
151 jobject media_crypto) {
152 DCHECK(media_task_runner_->BelongsToCurrentThread());
153
154 DVLOG(1) << class_name() << "::" << __FUNCTION__;
155
156 // If we cannot find a key frame in cache, the browser seek is needed.
157 if (!au_queue_.RewindToLastKeyFrame()) {
158 DVLOG(1) << class_name() << "::" << __FUNCTION__ << " key frame required";
159 return kConfigKeyFrameRequired;
160 }
161
162 if (configs_.video_codec == kUnknownVideoCodec) {
163 DVLOG(0) << class_name() << "::" << __FUNCTION__
164 << ": configuration parameters are required";
165 return kConfigFailure;
166 }
167
168 if (surface_.IsEmpty()) {
169 DVLOG(0) << class_name() << "::" << __FUNCTION__ << ": surface is required";
170 return kConfigFailure;
171 }
172
173 bool is_secure = IsContentEncrypted() && is_protected_surface_required_;
174
175 media_codec_bridge_.reset(VideoCodecBridge::CreateDecoder(
176 configs_.video_codec,
177 is_secure,
178 configs_.video_size,
179 surface_.j_surface().obj(),
180 media_crypto));
181
182 if (!media_codec_bridge_) {
183 DVLOG(0) << class_name() << "::" << __FUNCTION__
184 << " failed: cannot create video codec";
185 return kConfigFailure;
186 }
187
188 DVLOG(0) << class_name() << "::" << __FUNCTION__ << " succeeded";
189
190 if (!codec_created_for_tests_cb_.is_null())
191 media_task_runner_->PostTask(FROM_HERE, codec_created_for_tests_cb_);
192
193 return kConfigOk;
194 }
195
196 void MediaCodecVideoDecoder::AssociateCurrentTimeWithPTS(base::TimeDelta pts) {
197 DCHECK(media_task_runner_->BelongsToCurrentThread());
198
199 DVLOG(1) << class_name() << "::" << __FUNCTION__ << " pts:" << pts;
200
201 start_time_ticks_ = base::TimeTicks::Now();
202 start_pts_ = pts;
203 last_seen_pts_ = pts;
204 }
205
206 void MediaCodecVideoDecoder::DissociatePTSFromTime() {
207 DCHECK(media_task_runner_->BelongsToCurrentThread());
208
209 start_pts_ = last_seen_pts_ = kNoTimestamp();
210 }
211
212 void MediaCodecVideoDecoder::OnOutputFormatChanged() {
213 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
214
215 gfx::Size prev_size = video_size_;
216
217 // See b/18224769. The values reported from MediaCodecBridge::GetOutputFormat
218 // correspond to the actual video frame size, but this is not necessarily the
219 // size that should be output.
220 video_size_ = configs_.video_size;
221 if (video_size_ != prev_size) {
222 media_task_runner_->PostTask(
223 FROM_HERE, base::Bind(video_size_changed_cb_, video_size_));
224 }
225 }
226
227 void MediaCodecVideoDecoder::Render(int buffer_index,
228 size_t offset,
229 size_t size,
230 RenderMode render_mode,
231 base::TimeDelta pts,
232 bool eos_encountered) {
233 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
234
235 DVLOG(2) << class_name() << "::" << __FUNCTION__ << " pts:" << pts
236 << (eos_encountered ? " EOS " : " ") << AsString(render_mode);
237
238 // Normally EOS comes as a separate access unit that does not have data,
239 // the corresponding |size| will be 0.
240 if (!size && eos_encountered) {
241 // Stand-alone EOS
242 // Discard the PTS that comes with it and ensure it is released last.
243 pts = last_seen_pts_ +
244 base::TimeDelta::FromMilliseconds(kDelayForStandAloneEOS);
245 } else {
246 // Keep track of last seen PTS
247 last_seen_pts_ = pts;
248 }
249
250 // Do not update time for stand-alone EOS.
251 const bool update_time = !(eos_encountered && size == 0u);
252
253 // For video we simplify the preroll operation and render the first frame
254 // after preroll during the preroll phase, i.e. without waiting for audio
255 // stream to finish prerolling.
256 switch (render_mode) {
257 case kRenderSkip:
258 ReleaseOutputBuffer(buffer_index, pts, false, false, eos_encountered);
259 return;
260 case kRenderAfterPreroll:
261 // We get here in the preroll phase. Render now as explained above.
262 // |start_pts_| is not set yet, thus we cannot calculate |time_to_render|.
263 ReleaseOutputBuffer(buffer_index, pts, (size > 0), update_time,
264 eos_encountered);
265 return;
266 case kRenderNow:
267 break;
268 }
269
270 DCHECK_EQ(kRenderNow, render_mode);
271 DCHECK_NE(kNoTimestamp(), start_pts_); // start_pts_ must be set
272
273 base::TimeDelta time_to_render =
274 pts - (base::TimeTicks::Now() - start_time_ticks_ + start_pts_);
275
276 DVLOG(2) << class_name() << "::" << __FUNCTION__ << " pts:" << pts
277 << " ticks delta:" << (base::TimeTicks::Now() - start_time_ticks_)
278 << " time_to_render:" << time_to_render;
279
280 const bool render = (size > 0);
281
282 if (render)
283 frame_statistics_->IncrementFrameCount();
284
285 if (time_to_render < base::TimeDelta()) {
286 if (render) {
287 DVLOG(2) << class_name() << "::" << __FUNCTION__
288 << " LATE FRAME delay:" << (-1) * time_to_render;
289
290 frame_statistics_->IncrementLateFrameCount();
291 }
292
293 // Render late frames immediately.
294 ReleaseOutputBuffer(buffer_index, pts, render, update_time,
295 eos_encountered);
296 return;
297 }
298
299 delayed_buffers_.insert(buffer_index);
300
301 decoder_thread_.task_runner()->PostDelayedTask(
302 FROM_HERE, base::Bind(&MediaCodecVideoDecoder::ReleaseOutputBuffer,
303 base::Unretained(this), buffer_index, pts, render,
304 update_time, eos_encountered),
305 time_to_render);
306 }
307
308 int MediaCodecVideoDecoder::NumDelayedRenderTasks() const {
309 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
310
311 return delayed_buffers_.size();
312 }
313
314 void MediaCodecVideoDecoder::ReleaseDelayedBuffers() {
315 // Media thread
316 // Called when there is no decoder thread
317 for (int index : delayed_buffers_)
318 media_codec_bridge_->ReleaseOutputBuffer(index, false);
319
320 delayed_buffers_.clear();
321 }
322
323 #ifndef NDEBUG
324 void MediaCodecVideoDecoder::VerifyUnitIsKeyFrame(
325 const AccessUnit* unit) const {
326 // The first video frame in a sequence must be a key frame or stand-alone EOS.
327 DCHECK(unit);
328 bool stand_alone_eos = unit->is_end_of_stream && unit->data.empty();
329 DCHECK(stand_alone_eos || unit->is_key_frame);
330 }
331 #endif
332
333 void MediaCodecVideoDecoder::ReleaseOutputBuffer(int buffer_index,
334 base::TimeDelta pts,
335 bool render,
336 bool update_time,
337 bool eos_encountered) {
338 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
339
340 DVLOG(2) << class_name() << "::" << __FUNCTION__ << " pts:" << pts;
341
342 // Do not render if we are in emergency stop, there might be no surface.
343 if (InEmergencyStop())
344 render = false;
345
346 media_codec_bridge_->ReleaseOutputBuffer(buffer_index, render);
347
348 delayed_buffers_.erase(buffer_index);
349
350 CheckLastFrame(eos_encountered, !delayed_buffers_.empty());
351
352 // |update_current_time_cb_| might be null if there is audio stream.
353 // Do not update current time for stand-alone EOS frames.
354 if (!update_current_time_cb_.is_null() && update_time) {
355 media_task_runner_->PostTask(
356 FROM_HERE, base::Bind(update_current_time_cb_, pts, pts, false));
357 }
358 }
359
360 } // namespace media
OLDNEW
« no previous file with comments | « media/base/android/media_codec_video_decoder.h ('k') | media/base/android/video_media_codec_decoder.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698