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

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: Rebased 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"
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
65 } 65 }
66 } 66 }
67 67
68 void MediaCodecVideoDecoder::ReleaseDecoderResources() { 68 void MediaCodecVideoDecoder::ReleaseDecoderResources() {
69 DCHECK(media_task_runner_->BelongsToCurrentThread()); 69 DCHECK(media_task_runner_->BelongsToCurrentThread());
70 70
71 DVLOG(1) << class_name() << "::" << __FUNCTION__; 71 DVLOG(1) << class_name() << "::" << __FUNCTION__;
72 72
73 MediaCodecDecoder::ReleaseDecoderResources(); 73 MediaCodecDecoder::ReleaseDecoderResources();
74 surface_ = gfx::ScopedJavaSurface(); 74 surface_ = gfx::ScopedJavaSurface();
75 }
76
77 void MediaCodecVideoDecoder::ReleaseMediaCodec() {
78 DCHECK(media_task_runner_->BelongsToCurrentThread());
79
80 MediaCodecDecoder::ReleaseMediaCodec();
75 delayed_buffers_.clear(); 81 delayed_buffers_.clear();
76 } 82 }
77 83
78 void MediaCodecVideoDecoder::SetVideoSurface(gfx::ScopedJavaSurface surface) { 84 void MediaCodecVideoDecoder::SetVideoSurface(gfx::ScopedJavaSurface surface) {
79 DCHECK(media_task_runner_->BelongsToCurrentThread()); 85 DCHECK(media_task_runner_->BelongsToCurrentThread());
80 86
81 DVLOG(1) << class_name() << "::" << __FUNCTION__ 87 DVLOG(1) << class_name() << "::" << __FUNCTION__
82 << (surface.IsEmpty() ? " empty" : " non-empty"); 88 << (surface.IsEmpty() ? " empty" : " non-empty");
83 89
84 surface_ = surface.Pass(); 90 surface_ = surface.Pass();
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
153 return kConfigFailure; 159 return kConfigFailure;
154 } 160 }
155 161
156 DVLOG(0) << class_name() << "::" << __FUNCTION__ << " succeeded"; 162 DVLOG(0) << class_name() << "::" << __FUNCTION__ << " succeeded";
157 163
158 media_task_runner_->PostTask(FROM_HERE, codec_created_cb_); 164 media_task_runner_->PostTask(FROM_HERE, codec_created_cb_);
159 165
160 return kConfigOk; 166 return kConfigOk;
161 } 167 }
162 168
163 void MediaCodecVideoDecoder::SynchronizePTSWithTime( 169 void MediaCodecVideoDecoder::AssociateCurrentTimeWithPTS(base::TimeDelta pts) {
164 base::TimeDelta current_time) {
165 DCHECK(media_task_runner_->BelongsToCurrentThread()); 170 DCHECK(media_task_runner_->BelongsToCurrentThread());
166 171
172 DVLOG(1) << class_name() << "::" << __FUNCTION__ << " pts:" << pts;
173
167 start_time_ticks_ = base::TimeTicks::Now(); 174 start_time_ticks_ = base::TimeTicks::Now();
168 start_pts_ = current_time; 175 start_pts_ = pts;
169 last_seen_pts_ = current_time; 176 last_seen_pts_ = pts;
177 }
178
179 void MediaCodecVideoDecoder::DissociatePTSFromTime() {
180 DCHECK(media_task_runner_->BelongsToCurrentThread());
181
182 start_pts_ = last_seen_pts_ = kNoTimestamp();
170 } 183 }
171 184
172 void MediaCodecVideoDecoder::OnOutputFormatChanged() { 185 void MediaCodecVideoDecoder::OnOutputFormatChanged() {
173 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); 186 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
174 187
175 gfx::Size prev_size = video_size_; 188 gfx::Size prev_size = video_size_;
176 189
177 // See b/18224769. The values reported from MediaCodecBridge::GetOutputFormat 190 // See b/18224769. The values reported from MediaCodecBridge::GetOutputFormat
178 // correspond to the actual video frame size, but this is not necessarily the 191 // correspond to the actual video frame size, but this is not necessarily the
179 // size that should be output. 192 // size that should be output.
180 video_size_ = configs_.video_size; 193 video_size_ = configs_.video_size;
181 if (video_size_ != prev_size) { 194 if (video_size_ != prev_size) {
182 media_task_runner_->PostTask( 195 media_task_runner_->PostTask(
183 FROM_HERE, base::Bind(video_size_changed_cb_, video_size_)); 196 FROM_HERE, base::Bind(video_size_changed_cb_, video_size_));
184 } 197 }
185 } 198 }
186 199
187 void MediaCodecVideoDecoder::Render(int buffer_index, 200 void MediaCodecVideoDecoder::Render(int buffer_index,
188 size_t size, 201 size_t size,
189 bool render_output, 202 RenderMode render_mode,
190 base::TimeDelta pts, 203 base::TimeDelta pts,
191 bool eos_encountered) { 204 bool eos_encountered) {
192 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); 205 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
193 206
194 DVLOG(2) << class_name() << "::" << __FUNCTION__ << " pts:" << pts 207 DVLOG(2) << class_name() << "::" << __FUNCTION__ << " pts:" << pts
195 << " index:" << buffer_index << " size:" << size 208 << " index:" << buffer_index << " size:" << size
196 << (eos_encountered ? " EOS" : ""); 209 << (eos_encountered ? " EOS " : " ") << AsString(render_mode);
197 210
198 // Normally EOS comes as a separate access unit that does not have data, 211 // Normally EOS comes as a separate access unit that does not have data,
199 // the corresponding |size| will be 0. 212 // the corresponding |size| will be 0.
200 if (!size && eos_encountered) { 213 if (!size && eos_encountered) {
201 // Stand-alone EOS 214 // Stand-alone EOS
202 // Discard the PTS that comes with it and ensure it is released last. 215 // Discard the PTS that comes with it and ensure it is released last.
203 pts = last_seen_pts_ + 216 pts = last_seen_pts_ +
204 base::TimeDelta::FromMilliseconds(kDelayForStandAloneEOS); 217 base::TimeDelta::FromMilliseconds(kDelayForStandAloneEOS);
205 } else { 218 } else {
206 // Keep track of last seen PTS 219 // Keep track of last seen PTS
207 last_seen_pts_ = pts; 220 last_seen_pts_ = pts;
208 } 221 }
209 222
210 if (!render_output) { 223 // Do not update time for stand-alone EOS.
211 ReleaseOutputBuffer(buffer_index, pts, size, false, eos_encountered); 224 const bool update_time = !(eos_encountered && size == 0u);
212 return; 225
226 // For video we simplify the preroll operation and render the first frame
227 // after preroll during the preroll phase, i.e. without waiting for audio
228 // stream to finish prerolling.
229 switch (render_mode) {
230 case kRenderSkip:
231 ReleaseOutputBuffer(buffer_index, pts, false, false, eos_encountered);
232 return;
233 case kRenderAfterPreroll:
234 // |start_pts_| is not set yet, always render for size > 0.
235 ReleaseOutputBuffer(buffer_index, pts, (size > 0), update_time,
liberato (no reviews please) 2015/08/20 22:54:09 can this set |start_pts_| and break? if not, then
Tima Vaisburd 2015/08/21 20:18:24 I'm not sure I completely understood your point. W
liberato (no reviews please) 2015/08/21 21:02:17 i misread it. sorry about that.
236 eos_encountered);
237 return;
238 case kRenderNow:
239 break;
213 } 240 }
214 241
242 DCHECK_EQ(kRenderNow, render_mode);
243 DCHECK_NE(kNoTimestamp(), start_pts_); // start_pts_ must be set
244
215 base::TimeDelta time_to_render = 245 base::TimeDelta time_to_render =
216 pts - (base::TimeTicks::Now() - start_time_ticks_ + start_pts_); 246 pts - (base::TimeTicks::Now() - start_time_ticks_ + start_pts_);
217 247
248 DVLOG(2) << class_name() << "::" << __FUNCTION__ << " pts:" << pts
249 << " ticks delta:" << (base::TimeTicks::Now() - start_time_ticks_)
250 << " time_to_render:" << time_to_render;
251
218 if (time_to_render < base::TimeDelta()) { 252 if (time_to_render < base::TimeDelta()) {
219 // Skip late frames 253 // Skip late frames
220 ReleaseOutputBuffer(buffer_index, pts, size, false, eos_encountered); 254 ReleaseOutputBuffer(buffer_index, pts, false, update_time, eos_encountered);
221 return; 255 return;
222 } 256 }
223 257
224 delayed_buffers_.insert(buffer_index); 258 delayed_buffers_.insert(buffer_index);
225 259
226 bool do_render = size > 0; 260 const bool render = (size > 0);
227 decoder_thread_.task_runner()->PostDelayedTask( 261 decoder_thread_.task_runner()->PostDelayedTask(
228 FROM_HERE, base::Bind(&MediaCodecVideoDecoder::ReleaseOutputBuffer, 262 FROM_HERE, base::Bind(&MediaCodecVideoDecoder::ReleaseOutputBuffer,
229 base::Unretained(this), buffer_index, pts, 263 base::Unretained(this), buffer_index, pts, render,
230 size, do_render, eos_encountered), 264 update_time, eos_encountered),
231 time_to_render); 265 time_to_render);
232 } 266 }
233 267
234 int MediaCodecVideoDecoder::NumDelayedRenderTasks() const { 268 int MediaCodecVideoDecoder::NumDelayedRenderTasks() const {
235 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); 269 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
236 270
237 return delayed_buffers_.size(); 271 return delayed_buffers_.size();
238 } 272 }
239 273
240 void MediaCodecVideoDecoder::ClearDelayedBuffers(bool release) { 274 void MediaCodecVideoDecoder::ReleaseDelayedBuffers() {
241 // Media thread 275 // Media thread
242 // Called when there is no decoder thread 276 // Called when there is no decoder thread
243 if (release) { 277 for (int index : delayed_buffers_)
244 for (int index : delayed_buffers_) 278 media_codec_bridge_->ReleaseOutputBuffer(index, false);
245 media_codec_bridge_->ReleaseOutputBuffer(index, false);
246 }
247 279
248 delayed_buffers_.clear(); 280 delayed_buffers_.clear();
249 } 281 }
250 282
251 #ifndef NDEBUG 283 #ifndef NDEBUG
252 void MediaCodecVideoDecoder::VerifyUnitIsKeyFrame( 284 void MediaCodecVideoDecoder::VerifyUnitIsKeyFrame(
253 const AccessUnit* unit) const { 285 const AccessUnit* unit) const {
254 // The first video frame in a sequence must be a key frame or stand-alone EOS. 286 // The first video frame in a sequence must be a key frame or stand-alone EOS.
255 DCHECK(unit); 287 DCHECK(unit);
256 bool stand_alone_eos = unit->is_end_of_stream && unit->data.empty(); 288 bool stand_alone_eos = unit->is_end_of_stream && unit->data.empty();
257 DCHECK(stand_alone_eos || unit->is_key_frame); 289 DCHECK(stand_alone_eos || unit->is_key_frame);
258 } 290 }
259 #endif 291 #endif
260 292
261 void MediaCodecVideoDecoder::ReleaseOutputBuffer(int buffer_index, 293 void MediaCodecVideoDecoder::ReleaseOutputBuffer(int buffer_index,
262 base::TimeDelta pts, 294 base::TimeDelta pts,
263 size_t size,
264 bool render, 295 bool render,
296 bool update_time,
265 bool eos_encountered) { 297 bool eos_encountered) {
266 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); 298 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
267 299
268 DVLOG(2) << class_name() << "::" << __FUNCTION__ << " pts:" << pts; 300 DVLOG(2) << class_name() << "::" << __FUNCTION__ << " pts:" << pts;
269 301
270 media_codec_bridge_->ReleaseOutputBuffer(buffer_index, render); 302 media_codec_bridge_->ReleaseOutputBuffer(buffer_index, render);
271 303
272 delayed_buffers_.erase(buffer_index); 304 delayed_buffers_.erase(buffer_index);
273 305
274 CheckLastFrame(eos_encountered, !delayed_buffers_.empty()); 306 CheckLastFrame(eos_encountered, !delayed_buffers_.empty());
275 307
276 // |update_current_time_cb_| might be null if there is audio stream. 308 // |update_current_time_cb_| might be null if there is audio stream.
277 // Do not update current time for stand-alone EOS frames. 309 // Do not update current time for stand-alone EOS frames.
278 if (!update_current_time_cb_.is_null() && !(eos_encountered && !size)) { 310 if (!update_current_time_cb_.is_null() && update_time) {
279 media_task_runner_->PostTask(FROM_HERE, 311 media_task_runner_->PostTask(FROM_HERE,
280 base::Bind(update_current_time_cb_, pts, pts)); 312 base::Bind(update_current_time_cb_, pts, pts));
281 } 313 }
282 } 314 }
283 315
284 } // namespace media 316 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698