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

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

Issue 1254293003: MediaCodecPlayer implementation (stage 4 - preroll) (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@mtplayer-browserseek
Patch Set: Added unit test for video-only preroll Created 5 years, 4 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
1 // Copyright 2015 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/base/android/media_codec_video_decoder.h" 5 #include "media/base/android/media_codec_video_decoder.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "media/base/android/media_codec_bridge.h" 9 #include "media/base/android/media_codec_bridge.h"
10 #include "media/base/buffers.h" 10 #include "media/base/buffers.h"
11 #include "media/base/demuxer_stream.h" 11 #include "media/base/demuxer_stream.h"
12 12
13 namespace media { 13 namespace media {
14 14
15 namespace { 15 namespace {
16 const int kDelayForStandAloneEOS = 2; // milliseconds 16 const int kDelayForStandAloneEOS = 2; // milliseconds
17 } 17 }
18 18
19 MediaCodecVideoDecoder::MediaCodecVideoDecoder( 19 MediaCodecVideoDecoder::MediaCodecVideoDecoder(
20 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, 20 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
21 const base::Closure& request_data_cb, 21 const base::Closure& request_data_cb,
22 const base::Closure& starvation_cb, 22 const base::Closure& starvation_cb,
23 const base::Closure& preroll_done_cb,
23 const base::Closure& stop_done_cb, 24 const base::Closure& stop_done_cb,
24 const base::Closure& error_cb, 25 const base::Closure& error_cb,
25 const SetTimeCallback& update_current_time_cb, 26 const SetTimeCallback& update_current_time_cb,
26 const VideoSizeChangedCallback& video_size_changed_cb, 27 const VideoSizeChangedCallback& video_size_changed_cb,
27 const base::Closure& codec_created_cb) 28 const base::Closure& codec_created_cb)
28 : MediaCodecDecoder(media_task_runner, 29 : MediaCodecDecoder(media_task_runner,
29 request_data_cb, 30 request_data_cb,
30 starvation_cb, 31 starvation_cb,
32 preroll_done_cb,
31 stop_done_cb, 33 stop_done_cb,
32 error_cb, 34 error_cb,
33 "VideoDecoder"), 35 "VideoDecoder"),
34 update_current_time_cb_(update_current_time_cb), 36 update_current_time_cb_(update_current_time_cb),
35 video_size_changed_cb_(video_size_changed_cb), 37 video_size_changed_cb_(video_size_changed_cb),
36 codec_created_cb_(codec_created_cb) { 38 codec_created_cb_(codec_created_cb) {
37 } 39 }
38 40
39 MediaCodecVideoDecoder::~MediaCodecVideoDecoder() { 41 MediaCodecVideoDecoder::~MediaCodecVideoDecoder() {
40 DVLOG(1) << "VideoDecoder::~VideoDecoder()"; 42 DVLOG(1) << "VideoDecoder::~VideoDecoder()";
(...skipping 24 matching lines...) Expand all
65 } 67 }
66 } 68 }
67 69
68 void MediaCodecVideoDecoder::ReleaseDecoderResources() { 70 void MediaCodecVideoDecoder::ReleaseDecoderResources() {
69 DCHECK(media_task_runner_->BelongsToCurrentThread()); 71 DCHECK(media_task_runner_->BelongsToCurrentThread());
70 72
71 DVLOG(1) << class_name() << "::" << __FUNCTION__; 73 DVLOG(1) << class_name() << "::" << __FUNCTION__;
72 74
73 MediaCodecDecoder::ReleaseDecoderResources(); 75 MediaCodecDecoder::ReleaseDecoderResources();
74 surface_ = gfx::ScopedJavaSurface(); 76 surface_ = gfx::ScopedJavaSurface();
77 }
78
79 void MediaCodecVideoDecoder::ReleaseMediaCodec() {
80 DCHECK(media_task_runner_->BelongsToCurrentThread());
81
82 MediaCodecDecoder::ReleaseMediaCodec();
75 delayed_buffers_.clear(); 83 delayed_buffers_.clear();
76 } 84 }
77 85
78 void MediaCodecVideoDecoder::SetVideoSurface(gfx::ScopedJavaSurface surface) { 86 void MediaCodecVideoDecoder::SetVideoSurface(gfx::ScopedJavaSurface surface) {
79 DCHECK(media_task_runner_->BelongsToCurrentThread()); 87 DCHECK(media_task_runner_->BelongsToCurrentThread());
80 88
81 DVLOG(1) << class_name() << "::" << __FUNCTION__ 89 DVLOG(1) << class_name() << "::" << __FUNCTION__
82 << (surface.IsEmpty() ? " empty" : " non-empty"); 90 << (surface.IsEmpty() ? " empty" : " non-empty");
83 91
84 surface_ = surface.Pass(); 92 surface_ = surface.Pass();
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
152 return kConfigFailure; 160 return kConfigFailure;
153 } 161 }
154 162
155 DVLOG(1) << class_name() << "::" << __FUNCTION__ << " succeeded"; 163 DVLOG(1) << class_name() << "::" << __FUNCTION__ << " succeeded";
156 164
157 media_task_runner_->PostTask(FROM_HERE, codec_created_cb_); 165 media_task_runner_->PostTask(FROM_HERE, codec_created_cb_);
158 166
159 return kConfigOk; 167 return kConfigOk;
160 } 168 }
161 169
162 void MediaCodecVideoDecoder::SynchronizePTSWithTime( 170 void MediaCodecVideoDecoder::AssociateCurrentTimeWithPTS(base::TimeDelta pts) {
163 base::TimeDelta current_time) {
164 DCHECK(media_task_runner_->BelongsToCurrentThread()); 171 DCHECK(media_task_runner_->BelongsToCurrentThread());
165 172
173 DVLOG(1) << class_name() << "::" << __FUNCTION__ << " pts:" << pts;
174
166 start_time_ticks_ = base::TimeTicks::Now(); 175 start_time_ticks_ = base::TimeTicks::Now();
167 start_pts_ = current_time; 176 start_pts_ = pts;
168 last_seen_pts_ = current_time; 177 last_seen_pts_ = pts;
178 }
179
180 void MediaCodecVideoDecoder::DissociatePTSFromTime() {
181 DCHECK(media_task_runner_->BelongsToCurrentThread());
182
183 start_pts_ = last_seen_pts_ = kNoTimestamp();
169 } 184 }
170 185
171 void MediaCodecVideoDecoder::OnOutputFormatChanged() { 186 void MediaCodecVideoDecoder::OnOutputFormatChanged() {
172 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); 187 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
173 188
174 gfx::Size prev_size = video_size_; 189 gfx::Size prev_size = video_size_;
175 190
176 // See b/18224769. The values reported from MediaCodecBridge::GetOutputFormat 191 // See b/18224769. The values reported from MediaCodecBridge::GetOutputFormat
177 // correspond to the actual video frame size, but this is not necessarily the 192 // correspond to the actual video frame size, but this is not necessarily the
178 // size that should be output. 193 // size that should be output.
179 video_size_ = configs_.video_size; 194 video_size_ = configs_.video_size;
180 if (video_size_ != prev_size) { 195 if (video_size_ != prev_size) {
181 media_task_runner_->PostTask( 196 media_task_runner_->PostTask(
182 FROM_HERE, base::Bind(video_size_changed_cb_, video_size_)); 197 FROM_HERE, base::Bind(video_size_changed_cb_, video_size_));
183 } 198 }
184 } 199 }
185 200
186 void MediaCodecVideoDecoder::Render(int buffer_index, 201 void MediaCodecVideoDecoder::Render(int buffer_index,
187 size_t size, 202 size_t size,
188 bool render_output, 203 RenderMode render_mode,
189 base::TimeDelta pts, 204 base::TimeDelta pts,
190 bool eos_encountered) { 205 bool eos_encountered) {
191 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); 206 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
192 207
193 DVLOG(2) << class_name() << "::" << __FUNCTION__ << " pts:" << pts 208 DVLOG(2) << class_name() << "::" << __FUNCTION__ << " pts:" << pts
194 << " index:" << buffer_index << " size:" << size 209 << " index:" << buffer_index << " size:" << size
195 << (eos_encountered ? " EOS" : ""); 210 << (eos_encountered ? " EOS " : " ") << AsString(render_mode);
196 211
197 // Normally EOS comes as a separate access unit that does not have data, 212 // Normally EOS comes as a separate access unit that does not have data,
198 // the corresponding |size| will be 0. 213 // the corresponding |size| will be 0.
199 if (!size && eos_encountered) { 214 if (!size && eos_encountered) {
200 // Stand-alone EOS 215 // Stand-alone EOS
201 // Discard the PTS that comes with it and ensure it is released last. 216 // Discard the PTS that comes with it and ensure it is released last.
202 pts = last_seen_pts_ + 217 pts = last_seen_pts_ +
203 base::TimeDelta::FromMilliseconds(kDelayForStandAloneEOS); 218 base::TimeDelta::FromMilliseconds(kDelayForStandAloneEOS);
204 } else { 219 } else {
205 // Keep track of last seen PTS 220 // Keep track of last seen PTS
206 last_seen_pts_ = pts; 221 last_seen_pts_ = pts;
207 } 222 }
208 223
209 if (!render_output) { 224 // Do not update time for stand-alone EOS.
210 ReleaseOutputBuffer(buffer_index, pts, size, false, eos_encountered); 225 const bool update_time = !(eos_encountered && size == 0u);
211 return; 226
227 // For video we simplify the preroll operation and render the first frame
228 // after preroll during the preroll phase, i.e. without waiting for audio
229 // stream to finish prerolling.
230 switch (render_mode) {
231 case kRenderSkip:
232 ReleaseOutputBuffer(buffer_index, pts, false, false, eos_encountered);
233 return;
234 case kRenderAfterPreroll:
235 // |start_pts_| is not set yet, always render for size > 0.
236 ReleaseOutputBuffer(buffer_index, pts, (size > 0), update_time,
237 eos_encountered);
238 return;
239 case kRenderNow:
240 break;
212 } 241 }
213 242
243 DCHECK_EQ(kRenderNow, render_mode);
244 DCHECK_NE(kNoTimestamp(), start_pts_); // start_pts_ must be set
245
214 base::TimeDelta time_to_render = 246 base::TimeDelta time_to_render =
215 pts - (base::TimeTicks::Now() - start_time_ticks_ + start_pts_); 247 pts - (base::TimeTicks::Now() - start_time_ticks_ + start_pts_);
216 248
249 DVLOG(2) << class_name() << "::" << __FUNCTION__ << " pts:" << pts
250 << " ticks delta:" << (base::TimeTicks::Now() - start_time_ticks_)
251 << " time_to_render:" << time_to_render;
252
217 if (time_to_render < base::TimeDelta()) { 253 if (time_to_render < base::TimeDelta()) {
218 // Skip late frames 254 // Skip late frames
219 ReleaseOutputBuffer(buffer_index, pts, size, false, eos_encountered); 255 ReleaseOutputBuffer(buffer_index, pts, false, update_time, eos_encountered);
220 return; 256 return;
221 } 257 }
222 258
223 delayed_buffers_.insert(buffer_index); 259 delayed_buffers_.insert(buffer_index);
224 260
225 bool do_render = size > 0; 261 const bool render = (size > 0);
226 decoder_thread_.task_runner()->PostDelayedTask( 262 decoder_thread_.task_runner()->PostDelayedTask(
227 FROM_HERE, base::Bind(&MediaCodecVideoDecoder::ReleaseOutputBuffer, 263 FROM_HERE, base::Bind(&MediaCodecVideoDecoder::ReleaseOutputBuffer,
228 base::Unretained(this), buffer_index, pts, 264 base::Unretained(this), buffer_index, pts, render,
229 size, do_render, eos_encountered), 265 update_time, eos_encountered),
230 time_to_render); 266 time_to_render);
231 } 267 }
232 268
233 int MediaCodecVideoDecoder::NumDelayedRenderTasks() const { 269 int MediaCodecVideoDecoder::NumDelayedRenderTasks() const {
234 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); 270 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
235 271
236 return delayed_buffers_.size(); 272 return delayed_buffers_.size();
237 } 273 }
238 274
239 void MediaCodecVideoDecoder::ClearDelayedBuffers(bool release) { 275 void MediaCodecVideoDecoder::ReleaseDelayedBuffers() {
240 // Media thread 276 // Media thread
241 // Called when there is no decoder thread 277 // Called when there is no decoder thread
242 if (release) { 278 for (int index : delayed_buffers_)
243 for (int index : delayed_buffers_) 279 media_codec_bridge_->ReleaseOutputBuffer(index, false);
244 media_codec_bridge_->ReleaseOutputBuffer(index, false);
245 }
246 280
247 delayed_buffers_.clear(); 281 delayed_buffers_.clear();
248 } 282 }
249 283
250 #ifndef NDEBUG 284 #ifndef NDEBUG
251 void MediaCodecVideoDecoder::VerifyUnitIsKeyFrame( 285 void MediaCodecVideoDecoder::VerifyUnitIsKeyFrame(
252 const AccessUnit* unit) const { 286 const AccessUnit* unit) const {
253 // The first video frame in a sequence must be a key frame or stand-alone EOS. 287 // The first video frame in a sequence must be a key frame or stand-alone EOS.
254 DCHECK(unit); 288 DCHECK(unit);
255 bool stand_alone_eos = unit->is_end_of_stream && unit->data.empty(); 289 bool stand_alone_eos = unit->is_end_of_stream && unit->data.empty();
256 DCHECK(stand_alone_eos || unit->is_key_frame); 290 DCHECK(stand_alone_eos || unit->is_key_frame);
257 } 291 }
258 #endif 292 #endif
259 293
260 void MediaCodecVideoDecoder::ReleaseOutputBuffer(int buffer_index, 294 void MediaCodecVideoDecoder::ReleaseOutputBuffer(int buffer_index,
261 base::TimeDelta pts, 295 base::TimeDelta pts,
262 size_t size,
263 bool render, 296 bool render,
297 bool update_time,
264 bool eos_encountered) { 298 bool eos_encountered) {
265 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); 299 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
266 300
267 DVLOG(2) << class_name() << "::" << __FUNCTION__ << " pts:" << pts; 301 DVLOG(2) << class_name() << "::" << __FUNCTION__ << " pts:" << pts;
268 302
269 media_codec_bridge_->ReleaseOutputBuffer(buffer_index, render); 303 media_codec_bridge_->ReleaseOutputBuffer(buffer_index, render);
270 304
271 delayed_buffers_.erase(buffer_index); 305 delayed_buffers_.erase(buffer_index);
272 306
273 CheckLastFrame(eos_encountered, !delayed_buffers_.empty()); 307 CheckLastFrame(eos_encountered, !delayed_buffers_.empty());
274 308
275 // |update_current_time_cb_| might be null if there is audio stream. 309 // |update_current_time_cb_| might be null if there is audio stream.
276 // Do not update current time for stand-alone EOS frames. 310 // Do not update current time for stand-alone EOS frames.
277 if (!update_current_time_cb_.is_null() && !(eos_encountered && !size)) { 311 if (!update_current_time_cb_.is_null() && update_time) {
278 media_task_runner_->PostTask(FROM_HERE, 312 media_task_runner_->PostTask(FROM_HERE,
279 base::Bind(update_current_time_cb_, pts, pts)); 313 base::Bind(update_current_time_cb_, pts, pts));
280 } 314 }
281 } 315 }
282 316
283 } // namespace media 317 } // namespace media
OLDNEW
« media/base/android/media_codec_decoder.cc ('K') | « media/base/android/media_codec_video_decoder.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698