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

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

Issue 16098014: Handle config changes for MSE on android (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: addressing comments Created 7 years, 6 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 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_source_player.h" 5 #include "media/base/android/media_source_player.h"
6 6
7 #include "base/android/jni_android.h" 7 #include "base/android/jni_android.h"
8 #include "base/android/jni_string.h" 8 #include "base/android/jni_string.h"
9 #include "base/basictypes.h" 9 #include "base/basictypes.h"
10 #include "base/bind.h" 10 #include "base/bind.h"
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
48 48
49 } 49 }
50 50
51 namespace media { 51 namespace media {
52 52
53 MediaDecoderJob::MediaDecoderJob(base::Thread* thread, bool is_audio) 53 MediaDecoderJob::MediaDecoderJob(base::Thread* thread, bool is_audio)
54 : message_loop_(base::MessageLoopProxy::current()), 54 : message_loop_(base::MessageLoopProxy::current()),
55 thread_(thread), 55 thread_(thread),
56 needs_flush_(false), 56 needs_flush_(false),
57 is_audio_(is_audio), 57 is_audio_(is_audio),
58 weak_this_(this) { 58 weak_this_(this),
59 decoding_(false) {
59 } 60 }
60 61
61 MediaDecoderJob::~MediaDecoderJob() {} 62 MediaDecoderJob::~MediaDecoderJob() {}
62 63
63 // Class for managing audio decoding jobs. 64 // Class for managing audio decoding jobs.
64 class AudioDecoderJob : public MediaDecoderJob { 65 class AudioDecoderJob : public MediaDecoderJob {
65 public: 66 public:
66 AudioDecoderJob( 67 AudioDecoderJob(
67 const AudioCodec audio_codec, int sample_rate, 68 const AudioCodec audio_codec, int sample_rate,
68 int channel_count, const uint8* extra_data, size_t extra_data_size); 69 int channel_count, const uint8* extra_data, size_t extra_data_size);
69 virtual ~AudioDecoderJob() {} 70 virtual ~AudioDecoderJob() {}
70 }; 71 };
71 72
72 // Class for managing video decoding jobs. 73 // Class for managing video decoding jobs.
73 class VideoDecoderJob : public MediaDecoderJob { 74 class VideoDecoderJob : public MediaDecoderJob {
74 public: 75 public:
75 VideoDecoderJob( 76 VideoDecoderJob(
76 const VideoCodec video_codec, const gfx::Size& size, jobject surface); 77 const VideoCodec video_codec, const gfx::Size& size, jobject surface);
77 virtual ~VideoDecoderJob() {} 78 virtual ~VideoDecoderJob() {}
78 79
79 void Configure( 80 void Configure(
80 const VideoCodec codec, const gfx::Size& size, jobject surface); 81 const VideoCodec codec, const gfx::Size& size, jobject surface);
81 }; 82 };
82 83
83 void MediaDecoderJob::Decode( 84 void MediaDecoderJob::Decode(
84 const MediaPlayerHostMsg_ReadFromDemuxerAck_Params::AccessUnit& unit, 85 const MediaPlayerHostMsg_ReadFromDemuxerAck_Params::AccessUnit& unit,
85 const base::Time& start_wallclock_time, 86 const base::Time& start_wallclock_time,
86 const base::TimeDelta& start_presentation_timestamp, 87 const base::TimeDelta& start_presentation_timestamp,
87 const MediaDecoderJob::DecoderCallback& callback) { 88 const MediaDecoderJob::DecoderCallback& callback) {
89 DCHECK(!decoding_);
90 decoding_ = true;
88 thread_->message_loop()->PostTask(FROM_HERE, base::Bind( 91 thread_->message_loop()->PostTask(FROM_HERE, base::Bind(
89 &MediaDecoderJob::DecodeInternal, base::Unretained(this), unit, 92 &MediaDecoderJob::DecodeInternal, base::Unretained(this), unit,
90 start_wallclock_time, start_presentation_timestamp, needs_flush_, 93 start_wallclock_time, start_presentation_timestamp, needs_flush_,
91 callback)); 94 callback));
92 needs_flush_ = false; 95 needs_flush_ = false;
93 } 96 }
94 97
95 void MediaDecoderJob::DecodeInternal( 98 void MediaDecoderJob::DecodeInternal(
96 const MediaPlayerHostMsg_ReadFromDemuxerAck_Params::AccessUnit& unit, 99 const MediaPlayerHostMsg_ReadFromDemuxerAck_Params::AccessUnit& unit,
97 const base::Time& start_wallclock_time, 100 const base::Time& start_wallclock_time,
98 const base::TimeDelta& start_presentation_timestamp, 101 const base::TimeDelta& start_presentation_timestamp,
99 bool needs_flush, 102 bool needs_flush,
100 const MediaDecoderJob::DecoderCallback& callback) { 103 const MediaDecoderJob::DecoderCallback& callback) {
101 if (needs_flush) 104 if (needs_flush)
102 media_codec_bridge_->Reset(); 105 media_codec_bridge_->Reset();
103 base::TimeDelta timeout = base::TimeDelta::FromMicroseconds( 106 base::TimeDelta timeout = base::TimeDelta::FromMicroseconds(
104 kMediaCodecTimeoutInMicroseconds); 107 kMediaCodecTimeoutInMicroseconds);
105 int input_buf_index = media_codec_bridge_->DequeueInputBuffer(timeout); 108 int input_buf_index = media_codec_bridge_->DequeueInputBuffer(timeout);
109 if (input_buf_index == MediaCodecBridge::INFO_MEDIA_CODEC_ERROR) {
110 message_loop_->PostTask(FROM_HERE, base::Bind(
111 callback, false, start_presentation_timestamp, start_wallclock_time,
112 false));
113 return;
114 }
106 // TODO(qinmin): skip frames if video is falling far behind. 115 // TODO(qinmin): skip frames if video is falling far behind.
107 if (input_buf_index >= 0) { 116 if (input_buf_index >= 0) {
108 if (unit.end_of_stream) { 117 if (unit.end_of_stream) {
109 media_codec_bridge_->QueueEOS(input_buf_index); 118 media_codec_bridge_->QueueEOS(input_buf_index);
110 } else { 119 } else {
111 media_codec_bridge_->QueueInputBuffer( 120 media_codec_bridge_->QueueInputBuffer(
112 input_buf_index, &unit.data[0], unit.data.size(), unit.timestamp); 121 input_buf_index, &unit.data[0], unit.data.size(), unit.timestamp);
113 } 122 }
114 } 123 }
115 size_t offset = 0; 124 size_t offset = 0;
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
172 if (is_audio_) { 181 if (is_audio_) {
173 static_cast<AudioCodecBridge*>(media_codec_bridge_.get())->PlayOutputBuffer( 182 static_cast<AudioCodecBridge*>(media_codec_bridge_.get())->PlayOutputBuffer(
174 outputBufferIndex, size); 183 outputBufferIndex, size);
175 } 184 }
176 media_codec_bridge_->ReleaseOutputBuffer(outputBufferIndex, !is_audio_); 185 media_codec_bridge_->ReleaseOutputBuffer(outputBufferIndex, !is_audio_);
177 message_loop_->PostTask(FROM_HERE, base::Bind( 186 message_loop_->PostTask(FROM_HERE, base::Bind(
178 callback, true, presentation_timestamp, base::Time::Now(), 187 callback, true, presentation_timestamp, base::Time::Now(),
179 end_of_stream)); 188 end_of_stream));
180 } 189 }
181 190
191 void MediaDecoderJob::OnDecodeCompleted() {
192 decoding_ = false;
193 }
194
182 void MediaDecoderJob::Flush() { 195 void MediaDecoderJob::Flush() {
183 // Do nothing, flush when the next Decode() happens. 196 // Do nothing, flush when the next Decode() happens.
184 needs_flush_ = true; 197 needs_flush_ = true;
185 } 198 }
186 199
187 void MediaDecoderJob::Release() { 200 void MediaDecoderJob::Release() {
188 if (thread_->IsRunning() && 201 // If |decoding_| is false, there is nothing running on the decoder thread.
189 thread_->message_loop() != base::MessageLoop::current()) { 202 // So it is safe to delete the MediaDecoderJob on the UI thread. However,
203 // if we post a task to the decoder thread to delete object, then we cannot
204 // immediately pass the surface to a new MediaDecoderJob instance because
205 // the java surface is still owned by the old object. New decoder creation
206 // will be blocked on the UI thread until the previous decoder gets deleted.
207 // This introduces extra latency during config changes, and makes the logic in
208 // MediaSourcePlayer more complicated.
209 //
210 // TODO(qinmin): Figure out the logic to passing the surface to a new
211 // MediaDecoderJob instance after the previous one gets deleted on the decoder
212 // thread.
213 if (decoding_ && thread_->message_loop() != base::MessageLoop::current())
acolwell GONE FROM CHROMIUM 2013/06/05 23:13:38 This logic still doesn't seem safe to me, but I'm
qinmin 2013/06/06 01:17:25 ok, i will follow up with another CL to address th
190 thread_->message_loop()->DeleteSoon(FROM_HERE, this); 214 thread_->message_loop()->DeleteSoon(FROM_HERE, this);
191 } else { 215 else
192 delete this; 216 delete this;
193 }
194 } 217 }
195 218
196 VideoDecoderJob::VideoDecoderJob( 219 VideoDecoderJob::VideoDecoderJob(
197 const VideoCodec video_codec, const gfx::Size& size, jobject surface) 220 const VideoCodec video_codec, const gfx::Size& size, jobject surface)
198 : MediaDecoderJob(g_video_decoder_thread.Pointer(), false) { 221 : MediaDecoderJob(g_video_decoder_thread.Pointer(), false) {
199 scoped_ptr<VideoCodecBridge> codec(VideoCodecBridge::Create(video_codec)); 222 scoped_ptr<VideoCodecBridge> codec(VideoCodecBridge::Create(video_codec));
200 codec->Start(video_codec, size, surface); 223 codec->Start(video_codec, size, surface);
201 media_codec_bridge_.reset(codec.release()); 224 media_codec_bridge_.reset(codec.release());
202 } 225 }
203 226
204 AudioDecoderJob::AudioDecoderJob( 227 AudioDecoderJob::AudioDecoderJob(
205 const AudioCodec audio_codec, 228 const AudioCodec audio_codec,
206 int sample_rate, 229 int sample_rate,
207 int channel_count, 230 int channel_count,
208 const uint8* extra_data, 231 const uint8* extra_data,
209 size_t extra_data_size) 232 size_t extra_data_size)
210 : MediaDecoderJob(g_audio_decoder_thread.Pointer(), true) { 233 : MediaDecoderJob(g_audio_decoder_thread.Pointer(), true) {
211 scoped_ptr<AudioCodecBridge> codec(AudioCodecBridge::Create(audio_codec)); 234 scoped_ptr<AudioCodecBridge> codec(AudioCodecBridge::Create(audio_codec));
212 codec->Start(audio_codec, sample_rate, channel_count, extra_data, 235 codec->Start(audio_codec, sample_rate, channel_count, extra_data,
213 extra_data_size, true); 236 extra_data_size, true);
214 media_codec_bridge_.reset(codec.release()); 237 media_codec_bridge_.reset(codec.release());
215 } 238 }
216 239
217 MediaSourcePlayer::MediaSourcePlayer( 240 MediaSourcePlayer::MediaSourcePlayer(
218 int player_id, 241 int player_id,
219 MediaPlayerManager* manager) 242 MediaPlayerManager* manager)
220 : MediaPlayerAndroid(player_id, manager), 243 : MediaPlayerAndroid(player_id, manager),
221 pending_event_(NO_EVENT_PENDING), 244 pending_event_(NO_EVENT_PENDING),
222 active_decoding_tasks_(0), 245 active_decoding_tasks_(0),
246 seek_request_id_(0),
223 width_(0), 247 width_(0),
224 height_(0), 248 height_(0),
225 audio_codec_(kUnknownAudioCodec), 249 audio_codec_(kUnknownAudioCodec),
226 video_codec_(kUnknownVideoCodec), 250 video_codec_(kUnknownVideoCodec),
227 num_channels_(0), 251 num_channels_(0),
228 sampling_rate_(0), 252 sampling_rate_(0),
229 seekable_(true), 253 seekable_(true),
230 audio_finished_(true), 254 audio_finished_(true),
231 video_finished_(true), 255 video_finished_(true),
232 playing_(false), 256 playing_(false),
257 reconfig_audio_decoder_(true),
acolwell GONE FROM CHROMIUM 2013/06/05 23:13:38 Nit: I think these should default to false so the
qinmin 2013/06/06 01:17:25 Done.
258 reconfig_video_decoder_(true),
233 audio_access_unit_index_(0), 259 audio_access_unit_index_(0),
234 video_access_unit_index_(0), 260 video_access_unit_index_(0),
235 waiting_for_audio_data_(false), 261 waiting_for_audio_data_(false),
236 waiting_for_video_data_(false), 262 waiting_for_video_data_(false),
237 use_empty_surface_(true),
238 weak_this_(this) { 263 weak_this_(this) {
239 } 264 }
240 265
241 MediaSourcePlayer::~MediaSourcePlayer() { 266 MediaSourcePlayer::~MediaSourcePlayer() {
242 Release(); 267 Release();
243 } 268 }
244 269
245 void MediaSourcePlayer::SetVideoSurface(gfx::ScopedJavaSurface surface) { 270 void MediaSourcePlayer::SetVideoSurface(gfx::ScopedJavaSurface surface) {
246 use_empty_surface_ = surface.IsSurfaceEmpty(); 271 surface_ = surface.Pass();
247 272
248 // If we haven't processed a surface change event, do so now. 273 reconfig_video_decoder_ = true;
acolwell GONE FROM CHROMIUM 2013/06/05 23:13:38 nit: Shouldn't this also set CONFIG_CHANGE_EVENT_P
qinmin 2013/06/06 01:17:25 Surface change is a little different from config c
249 if (active_decoding_tasks_ > 0) { 274 pending_event_ |= SURFACE_CHANGE_EVENT_PENDING;
250 pending_event_ |= SURFACE_CHANGE_EVENT_PENDING; 275 // Setting a new surface will require a new MediaCodec to be created.
251 // Request a seek so that the next decoder will decode an I-frame first. 276 // Request a seek so that the new decoder will decode an I-frame first.
252 // Or otherwise, MediaCodec might crash. See b/8950387. 277 // Or otherwise, the new MediaCodec might crash. See b/8950387.
253 pending_event_ |= SEEK_EVENT_PENDING; 278 pending_event_ |= SEEK_EVENT_PENDING;
254 ProcessPendingEvents(); 279 ProcessPendingEvents();
255 return;
256 }
257
258 if (HasVideo()) {
259 video_decoder_job_.reset(new VideoDecoderJob(
260 video_codec_, gfx::Size(width_, height_), surface.j_surface().obj()));
261 }
262
263 // Inform the fullscreen view the player is ready.
264 // TODO(qinmin): refactor MediaPlayerBridge so that we have a better way
265 // to inform ContentVideoView.
266 OnMediaMetadataChanged(duration_, width_, height_, true);
267
268 if (pending_event_ & SURFACE_CHANGE_EVENT_PENDING) {
269 // We should already requested a seek in this case.
270 pending_event_ &= ~SURFACE_CHANGE_EVENT_PENDING;
271 } else {
272 // Perform a seek so the new decoder can get the I-frame first.
273 pending_event_ |= SEEK_EVENT_PENDING;
274 ProcessPendingEvents();
275 return;
276 }
277
278 if (playing_)
279 StartInternal();
280 } 280 }
281 281
282 void MediaSourcePlayer::Start() { 282 void MediaSourcePlayer::Start() {
283 playing_ = true; 283 playing_ = true;
284 if (HasAudio() && !audio_decoder_job_) {
285 audio_decoder_job_.reset(new AudioDecoderJob(
286 audio_codec_, sampling_rate_, num_channels_,
287 &audio_extra_data_[0], audio_extra_data_.size()));
288 }
289 284
290 if (HasVideo() && !video_decoder_job_) { 285 CreateMediaDecoderJobs();
291 // StartInternal() will be delayed until SetVideoSurface() gets called.
292 return;
293 }
294 286
295 StartInternal(); 287 StartInternal();
296 } 288 }
297 289
298 void MediaSourcePlayer::Pause() { 290 void MediaSourcePlayer::Pause() {
299 playing_ = false; 291 playing_ = false;
300 start_wallclock_time_ = base::Time(); 292 start_wallclock_time_ = base::Time();
301 } 293 }
302 294
303 bool MediaSourcePlayer::IsPlaying() { 295 bool MediaSourcePlayer::IsPlaying() {
(...skipping 19 matching lines...) Expand all
323 } 315 }
324 316
325 base::TimeDelta MediaSourcePlayer::GetDuration() { 317 base::TimeDelta MediaSourcePlayer::GetDuration() {
326 return duration_; 318 return duration_;
327 } 319 }
328 320
329 void MediaSourcePlayer::Release() { 321 void MediaSourcePlayer::Release() {
330 ClearDecodingData(); 322 ClearDecodingData();
331 audio_decoder_job_.reset(); 323 audio_decoder_job_.reset();
332 video_decoder_job_.reset(); 324 video_decoder_job_.reset();
325 reconfig_audio_decoder_ = true;
326 reconfig_video_decoder_ = true;
333 active_decoding_tasks_ = 0; 327 active_decoding_tasks_ = 0;
334 playing_ = false; 328 playing_ = false;
335 pending_event_ = NO_EVENT_PENDING; 329 pending_event_ = NO_EVENT_PENDING;
330 surface_ = gfx::ScopedJavaSurface();
336 ReleaseMediaResourcesFromManager(); 331 ReleaseMediaResourcesFromManager();
337 } 332 }
338 333
339 void MediaSourcePlayer::SetVolume(float leftVolume, float rightVolume) { 334 void MediaSourcePlayer::SetVolume(float leftVolume, float rightVolume) {
340 } 335 }
341 336
342 bool MediaSourcePlayer::CanPause() { 337 bool MediaSourcePlayer::CanPause() {
343 return seekable_; 338 return seekable_;
344 } 339 }
345 340
346 bool MediaSourcePlayer::CanSeekForward() { 341 bool MediaSourcePlayer::CanSeekForward() {
347 return seekable_; 342 return seekable_;
348 } 343 }
349 344
350 bool MediaSourcePlayer::CanSeekBackward() { 345 bool MediaSourcePlayer::CanSeekBackward() {
351 return seekable_; 346 return seekable_;
352 } 347 }
353 348
354 bool MediaSourcePlayer::IsPlayerReady() { 349 bool MediaSourcePlayer::IsPlayerReady() {
355 return audio_decoder_job_ || video_decoder_job_; 350 return audio_decoder_job_ || video_decoder_job_;
356 } 351 }
357 352
358 void MediaSourcePlayer::StartInternal() { 353 void MediaSourcePlayer::StartInternal() {
359 // Do nothing if the decoders are already running. 354 // Do nothing if the decoders are already running.
360 if (active_decoding_tasks_ > 0 || pending_event_ != NO_EVENT_PENDING) 355 if (active_decoding_tasks_ > 0 || pending_event_ != NO_EVENT_PENDING)
361 return; 356 return;
362 357
358 // If one of the decoder job is not ready, do nothing.
359 if ((HasAudio() && !audio_decoder_job_) ||
360 (HasVideo() && !video_decoder_job_)) {
361 return;
362 }
363
363 if (HasAudio()) { 364 if (HasAudio()) {
364 audio_finished_ = false; 365 audio_finished_ = false;
365 DecodeMoreAudio(); 366 DecodeMoreAudio();
366 } 367 }
367 if (HasVideo()) { 368 if (HasVideo()) {
368 video_finished_ = false; 369 video_finished_ = false;
369 DecodeMoreVideo(); 370 DecodeMoreVideo();
370 } 371 }
371 } 372 }
372 373
373 void MediaSourcePlayer::DemuxerReady( 374 void MediaSourcePlayer::DemuxerReady(
374 const MediaPlayerHostMsg_DemuxerReady_Params& params) { 375 const MediaPlayerHostMsg_DemuxerReady_Params& params) {
375 if (params.duration_ms == std::numeric_limits<int>::max()) 376 if (params.duration_ms == std::numeric_limits<int>::max())
376 seekable_ = false; 377 seekable_ = false;
377 duration_ = base::TimeDelta::FromMilliseconds(params.duration_ms); 378 duration_ = base::TimeDelta::FromMilliseconds(params.duration_ms);
378 width_ = params.video_size.width(); 379 width_ = params.video_size.width();
379 height_ = params.video_size.height(); 380 height_ = params.video_size.height();
380 num_channels_ = params.audio_channels; 381 num_channels_ = params.audio_channels;
381 sampling_rate_ = params.audio_sampling_rate; 382 sampling_rate_ = params.audio_sampling_rate;
382 audio_codec_ = params.audio_codec; 383 audio_codec_ = params.audio_codec;
383 video_codec_ = params.video_codec; 384 video_codec_ = params.video_codec;
384 audio_extra_data_ = params.audio_extra_data; 385 audio_extra_data_ = params.audio_extra_data;
385 OnMediaMetadataChanged(duration_, width_, height_, true); 386 OnMediaMetadataChanged(duration_, width_, height_, true);
387 if (pending_event_ & CONFIG_CHANGE_EVENT_PENDING) {
388 CreateMediaDecoderJobs();
389 pending_event_ &= ~CONFIG_CHANGE_EVENT_PENDING;
390 // If there is a pending surface change, we can merge it with the config
391 // change.
392 pending_event_ &= ~SURFACE_CHANGE_EVENT_PENDING;
acolwell GONE FROM CHROMIUM 2013/06/05 23:13:38 Shouldn't this only be done if a video config chec
qinmin 2013/06/06 01:17:25 good catch, fixed. On 2013/06/05 23:13:38, acolwe
393 if (playing_ && pending_event_ == NO_EVENT_PENDING)
394 StartInternal();
395 }
386 } 396 }
387 397
388 void MediaSourcePlayer::ReadFromDemuxerAck( 398 void MediaSourcePlayer::ReadFromDemuxerAck(
389 const MediaPlayerHostMsg_ReadFromDemuxerAck_Params& params) { 399 const MediaPlayerHostMsg_ReadFromDemuxerAck_Params& params) {
390 if (params.type == DemuxerStream::AUDIO) 400 if (params.type == DemuxerStream::AUDIO)
391 waiting_for_audio_data_ = false; 401 waiting_for_audio_data_ = false;
392 else 402 else
393 waiting_for_video_data_ = false; 403 waiting_for_video_data_ = false;
394 404
395 // If there is a pending seek request, ignore the data from the chunk demuxer. 405 // If there is a pending seek request, ignore the data from the chunk demuxer.
396 // The data will be requested later when OnSeekRequestAck() is called. 406 // The data will be requested later when OnSeekRequestAck() is called.
397 if (pending_event_ & SEEK_EVENT_PENDING) 407 if (pending_event_ & SEEK_EVENT_PENDING)
398 return; 408 return;
399 409
400 if (params.type == DemuxerStream::AUDIO) { 410 if (params.type == DemuxerStream::AUDIO) {
401 DCHECK_EQ(0u, audio_access_unit_index_); 411 DCHECK_EQ(0u, audio_access_unit_index_);
402 received_audio_ = params; 412 received_audio_ = params;
403 if (!pending_event_) 413 if (!pending_event_)
404 DecodeMoreAudio(); 414 DecodeMoreAudio();
405 } else { 415 } else {
406 DCHECK_EQ(0u, video_access_unit_index_); 416 DCHECK_EQ(0u, video_access_unit_index_);
407 received_video_ = params; 417 received_video_ = params;
408 if (!pending_event_) 418 if (!pending_event_)
409 DecodeMoreVideo(); 419 DecodeMoreVideo();
410 } 420 }
411 } 421 }
412 422
413 void MediaSourcePlayer::OnSeekRequestAck() { 423 void MediaSourcePlayer::OnSeekRequestAck(unsigned seek_request_id) {
424 // Do nothing until the most recent seek request is processed.
425 if (seek_request_id_ != seek_request_id)
426 return;
414 pending_event_ &= ~SEEK_EVENT_PENDING; 427 pending_event_ &= ~SEEK_EVENT_PENDING;
415 OnSeekComplete(); 428 OnSeekComplete();
416 if (playing_) 429 ProcessPendingEvents();
417 StartInternal();
418 } 430 }
419 431
420 void MediaSourcePlayer::UpdateTimestamps( 432 void MediaSourcePlayer::UpdateTimestamps(
421 const base::TimeDelta& presentation_timestamp, 433 const base::TimeDelta& presentation_timestamp,
422 const base::Time& wallclock_time) { 434 const base::Time& wallclock_time) {
423 last_presentation_timestamp_ = presentation_timestamp; 435 last_presentation_timestamp_ = presentation_timestamp;
424 OnTimeUpdated(); 436 OnTimeUpdated();
425 if (start_wallclock_time_.is_null() && playing_) { 437 if (start_wallclock_time_.is_null() && playing_) {
426 start_wallclock_time_ = wallclock_time; 438 start_wallclock_time_ = wallclock_time;
427 start_presentation_timestamp_ = last_presentation_timestamp_; 439 start_presentation_timestamp_ = last_presentation_timestamp_;
428 } 440 }
429 } 441 }
430 442
431 void MediaSourcePlayer::ProcessPendingEvents() { 443 void MediaSourcePlayer::ProcessPendingEvents() {
432 // Wait for all the decoding jobs to finish before sending a seek request. 444 // Wait for all the decoding jobs to finish before processing pending tasks.
433 if (active_decoding_tasks_ > 0) 445 if (active_decoding_tasks_ > 0)
434 return; 446 return;
435 447
436 DCHECK(pending_event_ != NO_EVENT_PENDING); 448 if (pending_event_ & SEEK_EVENT_PENDING) {
437 if (use_empty_surface_ && (pending_event_ & SURFACE_CHANGE_EVENT_PENDING)) { 449 ClearDecodingData();
438 video_decoder_job_.reset(); 450 manager()->OnMediaSeekRequest(
451 player_id(), last_presentation_timestamp_, ++seek_request_id_);
452 return;
453 }
454
455 start_wallclock_time_ = base::Time();
456 if (pending_event_ & CONFIG_CHANGE_EVENT_PENDING) {
457 manager()->OnMediaConfigRequest(player_id());
458 return;
459 }
460
461 if (pending_event_ & SURFACE_CHANGE_EVENT_PENDING) {
462 DCHECK(reconfig_audio_decoder_ || reconfig_video_decoder_);
463 CreateMediaDecoderJobs();
acolwell GONE FROM CHROMIUM 2013/06/05 23:13:38 Shouldn't this only apply for a video reconfig? It
qinmin 2013/06/06 01:17:25 Done, split the function into CreateVideoDecoderJo
439 pending_event_ &= ~SURFACE_CHANGE_EVENT_PENDING; 464 pending_event_ &= ~SURFACE_CHANGE_EVENT_PENDING;
440 } 465 }
441 466
442 ClearDecodingData(); 467 if (playing_ && pending_event_ == NO_EVENT_PENDING)
443 manager()->OnMediaSeekRequest(player_id(), 468 StartInternal();
444 last_presentation_timestamp_,
445 pending_event_ & SURFACE_CHANGE_EVENT_PENDING);
446 } 469 }
447 470
448 void MediaSourcePlayer::MediaDecoderCallback( 471 void MediaSourcePlayer::MediaDecoderCallback(
449 bool is_audio, bool decode_succeeded, 472 bool is_audio, bool decode_succeeded,
450 const base::TimeDelta& presentation_timestamp, 473 const base::TimeDelta& presentation_timestamp,
451 const base::Time& wallclock_time, bool end_of_stream) { 474 const base::Time& wallclock_time, bool end_of_stream) {
452 if (active_decoding_tasks_ > 0) 475 if (active_decoding_tasks_ > 0)
453 active_decoding_tasks_--; 476 active_decoding_tasks_--;
454 477
478 if (is_audio && audio_decoder_job_)
479 audio_decoder_job_->OnDecodeCompleted();
480 if (!is_audio && video_decoder_job_)
481 video_decoder_job_->OnDecodeCompleted();
482
455 if (!decode_succeeded) { 483 if (!decode_succeeded) {
456 Release(); 484 Release();
457 OnMediaError(MEDIA_ERROR_DECODE); 485 OnMediaError(MEDIA_ERROR_DECODE);
458 return; 486 return;
459 } 487 }
460 488
461 if (pending_event_ != NO_EVENT_PENDING) { 489 if (pending_event_ != NO_EVENT_PENDING) {
462 ProcessPendingEvents(); 490 ProcessPendingEvents();
463 return; 491 return;
464 } 492 }
(...skipping 19 matching lines...) Expand all
484 if (audio_access_unit_index_ >= received_audio_.access_units.size()) { 512 if (audio_access_unit_index_ >= received_audio_.access_units.size()) {
485 if (!waiting_for_audio_data_) { 513 if (!waiting_for_audio_data_) {
486 manager()->OnReadFromDemuxer(player_id(), DemuxerStream::AUDIO, true); 514 manager()->OnReadFromDemuxer(player_id(), DemuxerStream::AUDIO, true);
487 received_audio_ = MediaPlayerHostMsg_ReadFromDemuxerAck_Params(); 515 received_audio_ = MediaPlayerHostMsg_ReadFromDemuxerAck_Params();
488 audio_access_unit_index_ = 0; 516 audio_access_unit_index_ = 0;
489 waiting_for_audio_data_ = true; 517 waiting_for_audio_data_ = true;
490 } 518 }
491 return; 519 return;
492 } 520 }
493 521
522 if (DemuxerStream::kConfigChanged ==
523 received_audio_.access_units[audio_access_unit_index_].status) {
524 // Wait for demuxer ready message.
525 reconfig_audio_decoder_ = true;
526 pending_event_ |= CONFIG_CHANGE_EVENT_PENDING;
527 received_audio_ = MediaPlayerHostMsg_ReadFromDemuxerAck_Params();
528 audio_access_unit_index_ = 0;
529 ProcessPendingEvents();
530 return;
531 }
532
494 audio_decoder_job_->Decode( 533 audio_decoder_job_->Decode(
495 received_audio_.access_units[audio_access_unit_index_], 534 received_audio_.access_units[audio_access_unit_index_],
496 start_wallclock_time_, start_presentation_timestamp_, 535 start_wallclock_time_, start_presentation_timestamp_,
497 base::Bind(&MediaSourcePlayer::MediaDecoderCallback, 536 base::Bind(&MediaSourcePlayer::MediaDecoderCallback,
498 weak_this_.GetWeakPtr(), true)); 537 weak_this_.GetWeakPtr(), true));
499 active_decoding_tasks_++; 538 active_decoding_tasks_++;
500 audio_access_unit_index_++; 539 audio_access_unit_index_++;
501 } 540 }
502 541
503 void MediaSourcePlayer::DecodeMoreVideo() { 542 void MediaSourcePlayer::DecodeMoreVideo() {
504 if (video_access_unit_index_ >= received_video_.access_units.size()) { 543 if (video_access_unit_index_ >= received_video_.access_units.size()) {
505 if (!waiting_for_video_data_) { 544 if (!waiting_for_video_data_) {
506 manager()->OnReadFromDemuxer(player_id(), DemuxerStream::VIDEO, true); 545 manager()->OnReadFromDemuxer(player_id(), DemuxerStream::VIDEO, true);
507 received_video_ = MediaPlayerHostMsg_ReadFromDemuxerAck_Params(); 546 received_video_ = MediaPlayerHostMsg_ReadFromDemuxerAck_Params();
508 video_access_unit_index_ = 0; 547 video_access_unit_index_ = 0;
509 waiting_for_video_data_ = true; 548 waiting_for_video_data_ = true;
510 } 549 }
511 return; 550 return;
512 } 551 }
513 552
553 if (DemuxerStream::kConfigChanged ==
554 received_video_.access_units[video_access_unit_index_].status) {
555 // Wait for demuxer ready message.
556 reconfig_video_decoder_ = true;
557 pending_event_ |= CONFIG_CHANGE_EVENT_PENDING;
558 received_video_ = MediaPlayerHostMsg_ReadFromDemuxerAck_Params();
559 video_access_unit_index_ = 0;
560 ProcessPendingEvents();
561 return;
562 }
563
514 video_decoder_job_->Decode( 564 video_decoder_job_->Decode(
515 received_video_.access_units[video_access_unit_index_], 565 received_video_.access_units[video_access_unit_index_],
516 start_wallclock_time_, start_presentation_timestamp_, 566 start_wallclock_time_, start_presentation_timestamp_,
517 base::Bind(&MediaSourcePlayer::MediaDecoderCallback, 567 base::Bind(&MediaSourcePlayer::MediaDecoderCallback,
518 weak_this_.GetWeakPtr(), false)); 568 weak_this_.GetWeakPtr(), false));
519 active_decoding_tasks_++; 569 active_decoding_tasks_++;
520 video_access_unit_index_++; 570 video_access_unit_index_++;
521 } 571 }
522 572
523 573
(...skipping 23 matching lines...) Expand all
547 } 597 }
548 598
549 bool MediaSourcePlayer::HasVideo() { 599 bool MediaSourcePlayer::HasVideo() {
550 return kUnknownVideoCodec != video_codec_; 600 return kUnknownVideoCodec != video_codec_;
551 } 601 }
552 602
553 bool MediaSourcePlayer::HasAudio() { 603 bool MediaSourcePlayer::HasAudio() {
554 return kUnknownAudioCodec != audio_codec_; 604 return kUnknownAudioCodec != audio_codec_;
555 } 605 }
556 606
607 void MediaSourcePlayer::CreateMediaDecoderJobs() {
608 DCHECK_EQ(0, active_decoding_tasks_);
609
610 // Create audio decoder job only if config changes.
611 if (HasAudio() && (reconfig_audio_decoder_ || !audio_decoder_job_)) {
612 audio_decoder_job_.reset(new AudioDecoderJob(
613 audio_codec_, sampling_rate_, num_channels_,
614 &audio_extra_data_[0], audio_extra_data_.size()));
615 reconfig_audio_decoder_ = false;
616 }
617
618 if (!HasVideo() || surface_.IsSurfaceEmpty()) {
619 video_decoder_job_.reset();
620 return;
621 }
622
623 if (reconfig_video_decoder_ || !video_decoder_job_) {
624 video_decoder_job_.reset(new VideoDecoderJob(
625 video_codec_, gfx::Size(width_, height_), surface_.j_surface().obj()));
626 reconfig_video_decoder_ = false;
627 }
628
629 // Inform the fullscreen view the player is ready.
630 // TODO(qinmin): refactor MediaPlayerBridge so that we have a better way
631 // to inform ContentVideoView.
632 OnMediaMetadataChanged(duration_, width_, height_, true);
633 }
634
557 } // namespace media 635 } // namespace media
OLDNEW
« no previous file with comments | « media/base/android/media_source_player.h ('k') | webkit/renderer/media/android/media_source_delegate.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698