OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 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 "content/renderer/media/android/media_source_delegate.h" | 5 #include "content/renderer/media/android/media_source_delegate.h" |
6 | 6 |
7 #include "base/message_loop/message_loop_proxy.h" | 7 #include "base/message_loop/message_loop_proxy.h" |
8 #include "base/strings/string_number_conversions.h" | 8 #include "base/strings/string_number_conversions.h" |
9 #include "content/renderer/media/android/webmediaplayer_proxy_android.h" | 9 #include "content/renderer/media/android/webmediaplayer_proxy_android.h" |
10 #include "content/renderer/media/webmediaplayer_util.h" | 10 #include "content/renderer/media/webmediaplayer_util.h" |
11 #include "content/renderer/media/webmediasource_impl.h" | 11 #include "content/renderer/media/webmediasource_impl.h" |
12 #include "media/base/android/demuxer_stream_player_params.h" | 12 #include "media/base/android/demuxer_stream_player_params.h" |
13 #include "media/base/bind_to_loop.h" | 13 #include "media/base/bind_to_loop.h" |
14 #include "media/base/demuxer_stream.h" | 14 #include "media/base/demuxer_stream.h" |
15 #include "media/base/media_log.h" | 15 #include "media/base/media_log.h" |
16 #include "media/filters/chunk_demuxer.h" | 16 #include "media/filters/chunk_demuxer.h" |
17 #include "media/filters/decrypting_demuxer_stream.h" | 17 #include "media/filters/decrypting_demuxer_stream.h" |
18 #include "third_party/WebKit/public/platform/WebString.h" | 18 #include "third_party/WebKit/public/platform/WebString.h" |
19 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h" | 19 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h" |
20 | 20 |
21 using media::DemuxerStream; | 21 using media::DemuxerStream; |
22 using media::MediaPlayerHostMsg_DemuxerReady_Params; | 22 using media::MediaConfigs; |
23 using media::MediaPlayerHostMsg_ReadFromDemuxerAck_Params; | 23 using media::MediaData; |
24 using WebKit::WebMediaPlayer; | 24 using WebKit::WebMediaPlayer; |
25 using WebKit::WebString; | 25 using WebKit::WebString; |
26 | 26 |
27 namespace { | 27 namespace { |
28 | 28 |
29 // The size of the access unit to transfer in an IPC in case of MediaSource. | 29 // The size of the access unit to transfer in an IPC in case of MediaSource. |
30 // 16: approximately 250ms of content in 60 fps movies. | 30 // 16: approximately 250ms of content in 60 fps movies. |
31 const size_t kAccessUnitSizeForMediaSource = 16; | 31 const size_t kAccessUnitSizeForMediaSource = 16; |
32 | 32 |
33 const uint8 kVorbisPadding[] = { 0xff, 0xff, 0xff, 0xff }; | 33 const uint8 kVorbisPadding[] = { 0xff, 0xff, 0xff, 0xff }; |
(...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
301 void MediaSourceDelegate::OnReadFromDemuxerInternal( | 301 void MediaSourceDelegate::OnReadFromDemuxerInternal( |
302 media::DemuxerStream::Type type) { | 302 media::DemuxerStream::Type type) { |
303 DCHECK_BELONG_TO_MEDIA_LOOP(); | 303 DCHECK_BELONG_TO_MEDIA_LOOP(); |
304 DVLOG(1) << "OnReadFromDemuxer(" << type << ") : " << player_id_; | 304 DVLOG(1) << "OnReadFromDemuxer(" << type << ") : " << player_id_; |
305 if (IsSeeking()) | 305 if (IsSeeking()) |
306 return; // Drop the request during seeking. | 306 return; // Drop the request during seeking. |
307 | 307 |
308 DCHECK(type == DemuxerStream::AUDIO || type == DemuxerStream::VIDEO); | 308 DCHECK(type == DemuxerStream::AUDIO || type == DemuxerStream::VIDEO); |
309 // The access unit size should have been initialized properly at this stage. | 309 // The access unit size should have been initialized properly at this stage. |
310 DCHECK_GT(access_unit_size_, 0u); | 310 DCHECK_GT(access_unit_size_, 0u); |
311 scoped_ptr<MediaPlayerHostMsg_ReadFromDemuxerAck_Params> params( | 311 scoped_ptr<MediaData> data(new MediaData()); |
312 new MediaPlayerHostMsg_ReadFromDemuxerAck_Params()); | 312 data->type = type; |
313 params->type = type; | 313 data->access_units.resize(access_unit_size_); |
314 params->access_units.resize(access_unit_size_); | 314 ReadFromDemuxerStream(type, data.Pass(), 0); |
315 ReadFromDemuxerStream(type, params.Pass(), 0); | |
316 } | 315 } |
317 | 316 |
318 void MediaSourceDelegate::ReadFromDemuxerStream( | 317 void MediaSourceDelegate::ReadFromDemuxerStream(media::DemuxerStream::Type type, |
319 media::DemuxerStream::Type type, | 318 scoped_ptr<MediaData> data, |
320 scoped_ptr<MediaPlayerHostMsg_ReadFromDemuxerAck_Params> params, | 319 size_t index) { |
321 size_t index) { | |
322 DCHECK_BELONG_TO_MEDIA_LOOP(); | 320 DCHECK_BELONG_TO_MEDIA_LOOP(); |
323 // DemuxerStream::Read() always returns the read callback asynchronously. | 321 // DemuxerStream::Read() always returns the read callback asynchronously. |
324 DemuxerStream* stream = | 322 DemuxerStream* stream = |
325 (type == DemuxerStream::AUDIO) ? audio_stream_ : video_stream_; | 323 (type == DemuxerStream::AUDIO) ? audio_stream_ : video_stream_; |
326 stream->Read(base::Bind( | 324 stream->Read(base::Bind( |
327 &MediaSourceDelegate::OnBufferReady, | 325 &MediaSourceDelegate::OnBufferReady, |
328 media_weak_this_.GetWeakPtr(), type, base::Passed(¶ms), index)); | 326 media_weak_this_.GetWeakPtr(), type, base::Passed(&data), index)); |
329 } | 327 } |
330 | 328 |
331 void MediaSourceDelegate::OnBufferReady( | 329 void MediaSourceDelegate::OnBufferReady( |
332 media::DemuxerStream::Type type, | 330 media::DemuxerStream::Type type, |
333 scoped_ptr<MediaPlayerHostMsg_ReadFromDemuxerAck_Params> params, | 331 scoped_ptr<MediaData> data, |
334 size_t index, | 332 size_t index, |
335 DemuxerStream::Status status, | 333 DemuxerStream::Status status, |
336 const scoped_refptr<media::DecoderBuffer>& buffer) { | 334 const scoped_refptr<media::DecoderBuffer>& buffer) { |
337 DCHECK_BELONG_TO_MEDIA_LOOP(); | 335 DCHECK_BELONG_TO_MEDIA_LOOP(); |
338 DVLOG(1) << "OnBufferReady(" << index << ", " << status << ", " | 336 DVLOG(1) << "OnBufferReady(" << index << ", " << status << ", " |
339 << ((!buffer || buffer->end_of_stream()) ? | 337 << ((!buffer || buffer->end_of_stream()) ? |
340 -1 : buffer->timestamp().InMilliseconds()) | 338 -1 : buffer->timestamp().InMilliseconds()) |
341 << ") : " << player_id_; | 339 << ") : " << player_id_; |
342 DCHECK(demuxer_); | 340 DCHECK(demuxer_); |
343 | 341 |
344 // No new OnReadFromDemuxer() will be called during seeking. So this callback | 342 // No new OnReadFromDemuxer() will be called during seeking. So this callback |
345 // must be from previous OnReadFromDemuxer() call and should be ignored. | 343 // must be from previous OnReadFromDemuxer() call and should be ignored. |
346 if (IsSeeking()) { | 344 if (IsSeeking()) { |
347 DVLOG(1) << "OnBufferReady(): Ignore previous read during seeking."; | 345 DVLOG(1) << "OnBufferReady(): Ignore previous read during seeking."; |
348 return; | 346 return; |
349 } | 347 } |
350 | 348 |
351 bool is_audio = (type == DemuxerStream::AUDIO); | 349 bool is_audio = (type == DemuxerStream::AUDIO); |
352 if (status != DemuxerStream::kAborted && | 350 if (status != DemuxerStream::kAborted && |
353 index >= params->access_units.size()) { | 351 index >= data->access_units.size()) { |
354 LOG(ERROR) << "The internal state inconsistency onBufferReady: " | 352 LOG(ERROR) << "The internal state inconsistency onBufferReady: " |
355 << (is_audio ? "Audio" : "Video") << ", index " << index | 353 << (is_audio ? "Audio" : "Video") << ", index " << index |
356 <<", size " << params->access_units.size() | 354 <<", size " << data->access_units.size() |
357 << ", status " << static_cast<int>(status); | 355 << ", status " << static_cast<int>(status); |
358 NOTREACHED(); | 356 NOTREACHED(); |
359 return; | 357 return; |
360 } | 358 } |
361 | 359 |
362 switch (status) { | 360 switch (status) { |
363 case DemuxerStream::kAborted: | 361 case DemuxerStream::kAborted: |
364 // Because the abort was caused by the seek, don't respond ack. | 362 // Because the abort was caused by the seek, don't respond ack. |
365 DVLOG(1) << "OnBufferReady() : Aborted"; | 363 DVLOG(1) << "OnBufferReady() : Aborted"; |
366 return; | 364 return; |
367 | 365 |
368 case DemuxerStream::kConfigChanged: | 366 case DemuxerStream::kConfigChanged: |
369 // In case of kConfigChanged, need to read decoder_config once | 367 // In case of kConfigChanged, need to read decoder_config once |
370 // for the next reads. | 368 // for the next reads. |
371 // TODO(kjyoun): Investigate if we need to use this new config. See | 369 // TODO(kjyoun): Investigate if we need to use this new config. See |
372 // http://crbug.com/255783 | 370 // http://crbug.com/255783 |
373 if (is_audio) { | 371 if (is_audio) { |
374 audio_stream_->audio_decoder_config(); | 372 audio_stream_->audio_decoder_config(); |
375 } else { | 373 } else { |
376 gfx::Size size = video_stream_->video_decoder_config().coded_size(); | 374 gfx::Size size = video_stream_->video_decoder_config().coded_size(); |
377 DVLOG(1) << "Video config is changed: " << size.width() << "x" | 375 DVLOG(1) << "Video config is changed: " << size.width() << "x" |
378 << size.height(); | 376 << size.height(); |
379 } | 377 } |
380 params->access_units[index].status = status; | 378 data->access_units[index].status = status; |
381 params->access_units.resize(index + 1); | 379 data->access_units.resize(index + 1); |
382 break; | 380 break; |
383 | 381 |
384 case DemuxerStream::kOk: | 382 case DemuxerStream::kOk: |
385 params->access_units[index].status = status; | 383 data->access_units[index].status = status; |
386 if (buffer->end_of_stream()) { | 384 if (buffer->end_of_stream()) { |
387 params->access_units[index].end_of_stream = true; | 385 data->access_units[index].end_of_stream = true; |
388 params->access_units.resize(index + 1); | 386 data->access_units.resize(index + 1); |
389 break; | 387 break; |
390 } | 388 } |
391 // TODO(ycheo): We assume that the inputed stream will be decoded | 389 // TODO(ycheo): We assume that the inputed stream will be decoded |
392 // right away. | 390 // right away. |
393 // Need to implement this properly using MediaPlayer.OnInfoListener. | 391 // Need to implement this properly using MediaPlayer.OnInfoListener. |
394 if (is_audio) { | 392 if (is_audio) { |
395 statistics_.audio_bytes_decoded += buffer->data_size(); | 393 statistics_.audio_bytes_decoded += buffer->data_size(); |
396 } else { | 394 } else { |
397 statistics_.video_bytes_decoded += buffer->data_size(); | 395 statistics_.video_bytes_decoded += buffer->data_size(); |
398 statistics_.video_frames_decoded++; | 396 statistics_.video_frames_decoded++; |
399 } | 397 } |
400 params->access_units[index].timestamp = buffer->timestamp(); | 398 data->access_units[index].timestamp = buffer->timestamp(); |
401 params->access_units[index].data = std::vector<uint8>( | 399 data->access_units[index].data = std::vector<uint8>( |
402 buffer->data(), | 400 buffer->data(), |
403 buffer->data() + buffer->data_size()); | 401 buffer->data() + buffer->data_size()); |
404 #if !defined(GOOGLE_TV) | 402 #if !defined(GOOGLE_TV) |
405 // Vorbis needs 4 extra bytes padding on Android. Check | 403 // Vorbis needs 4 extra bytes padding on Android. Check |
406 // NuMediaExtractor.cpp in Android source code. | 404 // NuMediaExtractor.cpp in Android source code. |
407 if (is_audio && media::kCodecVorbis == | 405 if (is_audio && media::kCodecVorbis == |
408 audio_stream_->audio_decoder_config().codec()) { | 406 audio_stream_->audio_decoder_config().codec()) { |
409 params->access_units[index].data.insert( | 407 data->access_units[index].data.insert( |
410 params->access_units[index].data.end(), kVorbisPadding, | 408 data->access_units[index].data.end(), kVorbisPadding, |
411 kVorbisPadding + 4); | 409 kVorbisPadding + 4); |
412 } | 410 } |
413 #endif | 411 #endif |
414 if (buffer->decrypt_config()) { | 412 if (buffer->decrypt_config()) { |
415 params->access_units[index].key_id = std::vector<char>( | 413 data->access_units[index].key_id = std::vector<char>( |
416 buffer->decrypt_config()->key_id().begin(), | 414 buffer->decrypt_config()->key_id().begin(), |
417 buffer->decrypt_config()->key_id().end()); | 415 buffer->decrypt_config()->key_id().end()); |
418 params->access_units[index].iv = std::vector<char>( | 416 data->access_units[index].iv = std::vector<char>( |
419 buffer->decrypt_config()->iv().begin(), | 417 buffer->decrypt_config()->iv().begin(), |
420 buffer->decrypt_config()->iv().end()); | 418 buffer->decrypt_config()->iv().end()); |
421 params->access_units[index].subsamples = | 419 data->access_units[index].subsamples = |
422 buffer->decrypt_config()->subsamples(); | 420 buffer->decrypt_config()->subsamples(); |
423 } | 421 } |
424 if (++index < params->access_units.size()) { | 422 if (++index < data->access_units.size()) { |
425 ReadFromDemuxerStream(type, params.Pass(), index); | 423 ReadFromDemuxerStream(type, data.Pass(), index); |
426 return; | 424 return; |
427 } | 425 } |
428 break; | 426 break; |
429 | 427 |
430 default: | 428 default: |
431 NOTREACHED(); | 429 NOTREACHED(); |
432 } | 430 } |
433 | 431 |
434 #if defined(GOOGLE_TV) | 432 #if defined(GOOGLE_TV) |
435 send_read_from_demuxer_ack_cb_.Run(params.Pass()); | 433 send_read_from_demuxer_ack_cb_.Run(data.Pass()); |
436 #else | 434 #else |
437 SendReadFromDemuxerAck(params.Pass()); | 435 SendReadFromDemuxerAck(data.Pass()); |
438 #endif | 436 #endif |
439 } | 437 } |
440 | 438 |
441 void MediaSourceDelegate::SendReadFromDemuxerAck( | 439 void MediaSourceDelegate::SendReadFromDemuxerAck(scoped_ptr<MediaData> data) { |
442 scoped_ptr<MediaPlayerHostMsg_ReadFromDemuxerAck_Params> params) { | |
443 DCHECK(main_loop_->BelongsToCurrentThread()); | 440 DCHECK(main_loop_->BelongsToCurrentThread()); |
444 if (!IsSeeking() && proxy_) | 441 if (!IsSeeking() && proxy_) |
445 proxy_->ReadFromDemuxerAck(player_id_, *params); | 442 proxy_->ReadFromDemuxerAck(player_id_, *data); |
446 } | 443 } |
447 | 444 |
448 void MediaSourceDelegate::OnDemuxerError(media::PipelineStatus status) { | 445 void MediaSourceDelegate::OnDemuxerError(media::PipelineStatus status) { |
449 DVLOG(1) << "OnDemuxerError(" << status << ") : " << player_id_; | 446 DVLOG(1) << "OnDemuxerError(" << status << ") : " << player_id_; |
450 // |update_network_state_cb_| is bound to the main thread. | 447 // |update_network_state_cb_| is bound to the main thread. |
451 if (status != media::PIPELINE_OK && !update_network_state_cb_.is_null()) | 448 if (status != media::PIPELINE_OK && !update_network_state_cb_.is_null()) |
452 update_network_state_cb_.Run(PipelineErrorToNetworkState(status)); | 449 update_network_state_cb_.Run(PipelineErrorToNetworkState(status)); |
453 } | 450 } |
454 | 451 |
455 void MediaSourceDelegate::OnDemuxerInitDone(media::PipelineStatus status) { | 452 void MediaSourceDelegate::OnDemuxerInitDone(media::PipelineStatus status) { |
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
669 if (HasEncryptedStream() && !key_added_) | 666 if (HasEncryptedStream() && !key_added_) |
670 return false; | 667 return false; |
671 return true; | 668 return true; |
672 } | 669 } |
673 | 670 |
674 void MediaSourceDelegate::NotifyDemuxerReady() { | 671 void MediaSourceDelegate::NotifyDemuxerReady() { |
675 DCHECK_BELONG_TO_MEDIA_LOOP(); | 672 DCHECK_BELONG_TO_MEDIA_LOOP(); |
676 DVLOG(1) << "NotifyDemuxerReady() : " << player_id_; | 673 DVLOG(1) << "NotifyDemuxerReady() : " << player_id_; |
677 DCHECK(CanNotifyDemuxerReady()); | 674 DCHECK(CanNotifyDemuxerReady()); |
678 | 675 |
679 scoped_ptr<MediaPlayerHostMsg_DemuxerReady_Params> params( | 676 scoped_ptr<MediaConfigs> configs(new MediaConfigs()); |
680 new MediaPlayerHostMsg_DemuxerReady_Params()); | |
681 if (audio_stream_) { | 677 if (audio_stream_) { |
682 media::AudioDecoderConfig config = audio_stream_->audio_decoder_config(); | 678 media::AudioDecoderConfig config = audio_stream_->audio_decoder_config(); |
683 params->audio_codec = config.codec(); | 679 configs->audio_codec = config.codec(); |
684 params->audio_channels = | 680 configs->audio_channels = |
685 media::ChannelLayoutToChannelCount(config.channel_layout()); | 681 media::ChannelLayoutToChannelCount(config.channel_layout()); |
686 params->audio_sampling_rate = config.samples_per_second(); | 682 configs->audio_sampling_rate = config.samples_per_second(); |
687 params->is_audio_encrypted = config.is_encrypted(); | 683 configs->is_audio_encrypted = config.is_encrypted(); |
688 params->audio_extra_data = std::vector<uint8>( | 684 configs->audio_extra_data = std::vector<uint8>( |
689 config.extra_data(), config.extra_data() + config.extra_data_size()); | 685 config.extra_data(), config.extra_data() + config.extra_data_size()); |
690 } | 686 } |
691 if (video_stream_) { | 687 if (video_stream_) { |
692 media::VideoDecoderConfig config = video_stream_->video_decoder_config(); | 688 media::VideoDecoderConfig config = video_stream_->video_decoder_config(); |
693 params->video_codec = config.codec(); | 689 configs->video_codec = config.codec(); |
694 params->video_size = config.natural_size(); | 690 configs->video_size = config.natural_size(); |
695 params->is_video_encrypted = config.is_encrypted(); | 691 configs->is_video_encrypted = config.is_encrypted(); |
696 params->video_extra_data = std::vector<uint8>( | 692 configs->video_extra_data = std::vector<uint8>( |
697 config.extra_data(), config.extra_data() + config.extra_data_size()); | 693 config.extra_data(), config.extra_data() + config.extra_data_size()); |
698 } | 694 } |
699 params->duration_ms = GetDurationMs(); | 695 configs->duration_ms = GetDurationMs(); |
700 params->key_system = HasEncryptedStream() ? key_system_ : ""; | 696 configs->key_system = HasEncryptedStream() ? key_system_ : ""; |
701 | 697 |
702 #if defined(GOOGLE_TV) | 698 #if defined(GOOGLE_TV) |
703 send_demuxer_ready_cb_.Run(params.Pass()); | 699 send_demuxer_ready_cb_.Run(configs.Pass()); |
704 #else | 700 #else |
705 SendDemuxerReady(params.Pass()); | 701 SendDemuxerReady(configs.Pass()); |
706 #endif | 702 #endif |
707 } | 703 } |
708 | 704 |
709 void MediaSourceDelegate::SendDemuxerReady( | 705 void MediaSourceDelegate::SendDemuxerReady(scoped_ptr<MediaConfigs> configs) { |
710 scoped_ptr<MediaPlayerHostMsg_DemuxerReady_Params> params) { | |
711 DCHECK(main_loop_->BelongsToCurrentThread()); | 706 DCHECK(main_loop_->BelongsToCurrentThread()); |
712 if (proxy_) | 707 if (proxy_) |
713 proxy_->DemuxerReady(player_id_, *params); | 708 proxy_->DemuxerReady(player_id_, *configs); |
714 } | 709 } |
715 | 710 |
716 int MediaSourceDelegate::GetDurationMs() { | 711 int MediaSourceDelegate::GetDurationMs() { |
717 DCHECK_BELONG_TO_MEDIA_LOOP(); | 712 DCHECK_BELONG_TO_MEDIA_LOOP(); |
718 if (!chunk_demuxer_) | 713 if (!chunk_demuxer_) |
719 return -1; | 714 return -1; |
720 | 715 |
721 double duration_ms = chunk_demuxer_->GetDuration() * 1000; | 716 double duration_ms = chunk_demuxer_->GetDuration() * 1000; |
722 if (duration_ms > std::numeric_limits<int32>::max()) { | 717 if (duration_ms > std::numeric_limits<int32>::max()) { |
723 LOG(WARNING) << "Duration from ChunkDemuxer is too large; probably " | 718 LOG(WARNING) << "Duration from ChunkDemuxer is too large; probably " |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
765 base::AutoLock auto_lock(seeking_lock_); | 760 base::AutoLock auto_lock(seeking_lock_); |
766 seeking_ = seeking; | 761 seeking_ = seeking; |
767 } | 762 } |
768 | 763 |
769 bool MediaSourceDelegate::IsSeeking() const { | 764 bool MediaSourceDelegate::IsSeeking() const { |
770 base::AutoLock auto_lock(seeking_lock_); | 765 base::AutoLock auto_lock(seeking_lock_); |
771 return seeking_; | 766 return seeking_; |
772 } | 767 } |
773 | 768 |
774 } // namespace content | 769 } // namespace content |
OLD | NEW |