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

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: Save the first post-preroll audio buffer and replay it when preroll is done 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 DVLOG(1) << class_name() << "::" << __FUNCTION__;
83
84 MediaCodecDecoder::ReleaseMediaCodec();
75 delayed_buffers_.clear(); 85 delayed_buffers_.clear();
76 } 86 }
77 87
78 void MediaCodecVideoDecoder::SetVideoSurface(gfx::ScopedJavaSurface surface) { 88 void MediaCodecVideoDecoder::SetVideoSurface(gfx::ScopedJavaSurface surface) {
79 DCHECK(media_task_runner_->BelongsToCurrentThread()); 89 DCHECK(media_task_runner_->BelongsToCurrentThread());
80 90
81 DVLOG(1) << class_name() << "::" << __FUNCTION__ 91 DVLOG(1) << class_name() << "::" << __FUNCTION__
82 << (surface.IsEmpty() ? " empty" : " non-empty"); 92 << (surface.IsEmpty() ? " empty" : " non-empty");
83 93
84 surface_ = surface.Pass(); 94 surface_ = surface.Pass();
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
152 return kConfigFailure; 162 return kConfigFailure;
153 } 163 }
154 164
155 DVLOG(1) << class_name() << "::" << __FUNCTION__ << " succeeded"; 165 DVLOG(1) << class_name() << "::" << __FUNCTION__ << " succeeded";
156 166
157 media_task_runner_->PostTask(FROM_HERE, codec_created_cb_); 167 media_task_runner_->PostTask(FROM_HERE, codec_created_cb_);
158 168
159 return kConfigOk; 169 return kConfigOk;
160 } 170 }
161 171
162 void MediaCodecVideoDecoder::SynchronizePTSWithTime( 172 void MediaCodecVideoDecoder::AssociateCurrentTimeWithPTS(base::TimeDelta pts) {
163 base::TimeDelta current_time) {
164 DCHECK(media_task_runner_->BelongsToCurrentThread()); 173 DCHECK(media_task_runner_->BelongsToCurrentThread());
165 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" : "");
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 // For video we simplify the preroll operation and render the first frame
225 // after preroll during the preroll phase, i.e. without waiting for audio
226 // stream to finish prerolling.
227 const bool render_output = (render_mode != kRenderSkip);
228
229 if (!render_output || start_pts_ == kNoTimestamp()) {
210 ReleaseOutputBuffer(buffer_index, pts, size, false, eos_encountered); 230 ReleaseOutputBuffer(buffer_index, pts, size, false, eos_encountered);
211 return; 231 return;
212 } 232 }
213 233
214 base::TimeDelta time_to_render = 234 base::TimeDelta time_to_render =
215 pts - (base::TimeTicks::Now() - start_time_ticks_ + start_pts_); 235 pts - (base::TimeTicks::Now() - start_time_ticks_ + start_pts_);
216 236
217 if (time_to_render < base::TimeDelta()) { 237 if (time_to_render < base::TimeDelta()) {
218 // Skip late frames 238 // Skip late frames
219 ReleaseOutputBuffer(buffer_index, pts, size, false, eos_encountered); 239 ReleaseOutputBuffer(buffer_index, pts, size, false, eos_encountered);
220 return; 240 return;
221 } 241 }
222 242
223 delayed_buffers_.insert(buffer_index); 243 delayed_buffers_.insert(buffer_index);
224 244
225 bool do_render = size > 0; 245 bool do_render = size > 0;
226 decoder_thread_.task_runner()->PostDelayedTask( 246 decoder_thread_.task_runner()->PostDelayedTask(
227 FROM_HERE, base::Bind(&MediaCodecVideoDecoder::ReleaseOutputBuffer, 247 FROM_HERE, base::Bind(&MediaCodecVideoDecoder::ReleaseOutputBuffer,
228 base::Unretained(this), buffer_index, pts, 248 base::Unretained(this), buffer_index, pts,
229 size, do_render, eos_encountered), 249 size, do_render, eos_encountered),
230 time_to_render); 250 time_to_render);
231 } 251 }
232 252
233 int MediaCodecVideoDecoder::NumDelayedRenderTasks() const { 253 int MediaCodecVideoDecoder::NumDelayedRenderTasks() const {
234 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); 254 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
235 255
236 return delayed_buffers_.size(); 256 return delayed_buffers_.size();
237 } 257 }
238 258
239 void MediaCodecVideoDecoder::ClearDelayedBuffers(bool release) { 259 void MediaCodecVideoDecoder::ReleaseDelayedBuffers() {
240 // Media thread 260 // Media thread
241 // Called when there is no decoder thread 261 // Called when there is no decoder thread
242 if (release) { 262 for (int index : delayed_buffers_)
243 for (int index : delayed_buffers_) 263 media_codec_bridge_->ReleaseOutputBuffer(index, false);
244 media_codec_bridge_->ReleaseOutputBuffer(index, false);
245 }
246 264
247 delayed_buffers_.clear(); 265 delayed_buffers_.clear();
248 } 266 }
249 267
250 #ifndef NDEBUG 268 #ifndef NDEBUG
251 void MediaCodecVideoDecoder::VerifyUnitIsKeyFrame( 269 void MediaCodecVideoDecoder::VerifyUnitIsKeyFrame(
252 const AccessUnit* unit) const { 270 const AccessUnit* unit) const {
253 // The first video frame in a sequence must be a key frame or stand-alone EOS. 271 // The first video frame in a sequence must be a key frame or stand-alone EOS.
254 DCHECK(unit); 272 DCHECK(unit);
255 bool stand_alone_eos = unit->is_end_of_stream && unit->data.empty(); 273 bool stand_alone_eos = unit->is_end_of_stream && unit->data.empty();
(...skipping 18 matching lines...) Expand all
274 292
275 // |update_current_time_cb_| might be null if there is audio stream. 293 // |update_current_time_cb_| might be null if there is audio stream.
276 // Do not update current time for stand-alone EOS frames. 294 // Do not update current time for stand-alone EOS frames.
277 if (!update_current_time_cb_.is_null() && !(eos_encountered && !size)) { 295 if (!update_current_time_cb_.is_null() && !(eos_encountered && !size)) {
278 media_task_runner_->PostTask(FROM_HERE, 296 media_task_runner_->PostTask(FROM_HERE,
279 base::Bind(update_current_time_cb_, pts, pts)); 297 base::Bind(update_current_time_cb_, pts, pts));
280 } 298 }
281 } 299 }
282 300
283 } // namespace media 301 } // 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