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 <algorithm> | 5 #include <algorithm> |
6 #include <climits> | 6 #include <climits> |
7 #include <cstdarg> | 7 #include <cstdarg> |
8 #include <cstdio> | 8 #include <cstdio> |
9 #include <deque> | 9 #include <deque> |
| 10 #include <map> |
10 #include <string> | 11 #include <string> |
11 #include <utility> | 12 #include <utility> |
12 | 13 |
13 #include "base/at_exit.h" | 14 #include "base/at_exit.h" |
14 #include "base/command_line.h" | 15 #include "base/command_line.h" |
15 #include "base/logging.h" | 16 #include "base/logging.h" |
16 #include "base/memory/ref_counted.h" | 17 #include "base/memory/ref_counted.h" |
17 #include "base/memory/scoped_ptr.h" | 18 #include "base/memory/scoped_ptr.h" |
18 #include "base/message_loop/message_loop.h" | 19 #include "base/message_loop/message_loop.h" |
19 #include "base/synchronization/lock.h" | 20 #include "base/synchronization/lock.h" |
20 #include "base/synchronization/waitable_event.h" | 21 #include "base/synchronization/waitable_event.h" |
21 #include "base/threading/thread.h" | 22 #include "base/threading/thread.h" |
22 #include "base/time/default_tick_clock.h" | 23 #include "base/time/default_tick_clock.h" |
23 #include "base/timer/timer.h" | 24 #include "base/timer/timer.h" |
24 #include "media/audio/audio_io.h" | 25 #include "media/audio/audio_io.h" |
25 #include "media/audio/audio_manager.h" | 26 #include "media/audio/audio_manager.h" |
26 #include "media/audio/audio_parameters.h" | 27 #include "media/audio/audio_parameters.h" |
27 #include "media/audio/fake_audio_log_factory.h" | 28 #include "media/audio/fake_audio_log_factory.h" |
28 #include "media/base/audio_bus.h" | 29 #include "media/base/audio_bus.h" |
29 #include "media/base/channel_layout.h" | 30 #include "media/base/channel_layout.h" |
30 #include "media/base/video_frame.h" | 31 #include "media/base/video_frame.h" |
31 #include "media/cast/cast_config.h" | 32 #include "media/cast/cast_config.h" |
32 #include "media/cast/cast_environment.h" | 33 #include "media/cast/cast_environment.h" |
33 #include "media/cast/cast_receiver.h" | 34 #include "media/cast/cast_receiver.h" |
34 #include "media/cast/logging/logging_defines.h" | 35 #include "media/cast/logging/logging_defines.h" |
| 36 #include "media/cast/test/utility/audio_utility.h" |
| 37 #include "media/cast/test/utility/barcode.h" |
35 #include "media/cast/test/utility/default_config.h" | 38 #include "media/cast/test/utility/default_config.h" |
36 #include "media/cast/test/utility/in_process_receiver.h" | 39 #include "media/cast/test/utility/in_process_receiver.h" |
37 #include "media/cast/test/utility/input_builder.h" | 40 #include "media/cast/test/utility/input_builder.h" |
38 #include "media/cast/test/utility/standalone_cast_environment.h" | 41 #include "media/cast/test/utility/standalone_cast_environment.h" |
39 #include "media/cast/transport/transport/udp_transport.h" | 42 #include "media/cast/transport/transport/udp_transport.h" |
40 #include "net/base/net_util.h" | 43 #include "net/base/net_util.h" |
41 | 44 |
42 #if defined(OS_LINUX) | 45 #if defined(OS_LINUX) |
43 #include "media/cast/test/linux_output_window.h" | 46 #include "media/cast/test/linux_output_window.h" |
44 #endif // OS_LINUX | 47 #endif // OS_LINUX |
(...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
263 // InProcessReceiver overrides. | 266 // InProcessReceiver overrides. |
264 | 267 |
265 virtual void OnVideoFrame(const scoped_refptr<VideoFrame>& video_frame, | 268 virtual void OnVideoFrame(const scoped_refptr<VideoFrame>& video_frame, |
266 const base::TimeTicks& playout_time, | 269 const base::TimeTicks& playout_time, |
267 bool is_continuous) OVERRIDE { | 270 bool is_continuous) OVERRIDE { |
268 DCHECK(cast_env()->CurrentlyOn(CastEnvironment::MAIN)); | 271 DCHECK(cast_env()->CurrentlyOn(CastEnvironment::MAIN)); |
269 LOG_IF(WARNING, !is_continuous) | 272 LOG_IF(WARNING, !is_continuous) |
270 << "Video: Discontinuity in received frames."; | 273 << "Video: Discontinuity in received frames."; |
271 video_playout_queue_.push_back(std::make_pair(playout_time, video_frame)); | 274 video_playout_queue_.push_back(std::make_pair(playout_time, video_frame)); |
272 ScheduleVideoPlayout(); | 275 ScheduleVideoPlayout(); |
| 276 uint16 frame_no; |
| 277 if (media::cast::test::DecodeBarcode(video_frame, &frame_no)) { |
| 278 video_play_times_.insert( |
| 279 std::pair<uint16, base::TimeTicks>(frame_no, playout_time)); |
| 280 } else { |
| 281 VLOG(2) << "Barcode decode failed!"; |
| 282 } |
273 } | 283 } |
274 | 284 |
275 virtual void OnAudioFrame(scoped_ptr<AudioBus> audio_frame, | 285 virtual void OnAudioFrame(scoped_ptr<AudioBus> audio_frame, |
276 const base::TimeTicks& playout_time, | 286 const base::TimeTicks& playout_time, |
277 bool is_continuous) OVERRIDE { | 287 bool is_continuous) OVERRIDE { |
278 DCHECK(cast_env()->CurrentlyOn(CastEnvironment::MAIN)); | 288 DCHECK(cast_env()->CurrentlyOn(CastEnvironment::MAIN)); |
279 LOG_IF(WARNING, !is_continuous) | 289 LOG_IF(WARNING, !is_continuous) |
280 << "Audio: Discontinuity in received frames."; | 290 << "Audio: Discontinuity in received frames."; |
281 base::AutoLock auto_lock(audio_lock_); | 291 base::AutoLock auto_lock(audio_lock_); |
| 292 uint16 frame_no; |
| 293 if (media::cast::DecodeTimestamp(audio_frame->channel(0), |
| 294 audio_frame->frames(), |
| 295 &frame_no)) { |
| 296 // Since there are lots of audio packets with the same frame_no, |
| 297 // we really want to make sure that we get the playout_time from |
| 298 // the first one. If is_continous is true, then it's possible |
| 299 // that we already missed the first one. |
| 300 if (is_continuous && frame_no == last_audio_frame_no_ + 1) { |
| 301 audio_play_times_.insert( |
| 302 std::pair<uint16, base::TimeTicks>(frame_no, playout_time)); |
| 303 } |
| 304 last_audio_frame_no_ = frame_no; |
| 305 } else { |
| 306 VLOG(2) << "Audio decode failed!"; |
| 307 last_audio_frame_no_ = -2; |
| 308 } |
282 audio_playout_queue_.push_back( | 309 audio_playout_queue_.push_back( |
283 std::make_pair(playout_time, audio_frame.release())); | 310 std::make_pair(playout_time, audio_frame.release())); |
284 } | 311 } |
285 | 312 |
286 // End of InProcessReceiver overrides. | 313 // End of InProcessReceiver overrides. |
287 //////////////////////////////////////////////////////////////////// | 314 //////////////////////////////////////////////////////////////////// |
288 | 315 |
289 //////////////////////////////////////////////////////////////////// | 316 //////////////////////////////////////////////////////////////////// |
290 // AudioSourceCallback implementation. | 317 // AudioSourceCallback implementation. |
291 | 318 |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
389 | 416 |
390 void PlayNextVideoFrame() { | 417 void PlayNextVideoFrame() { |
391 DCHECK(cast_env()->CurrentlyOn(CastEnvironment::MAIN)); | 418 DCHECK(cast_env()->CurrentlyOn(CastEnvironment::MAIN)); |
392 if (!video_playout_queue_.empty()) { | 419 if (!video_playout_queue_.empty()) { |
393 const scoped_refptr<VideoFrame> video_frame = PopOneVideoFrame(false); | 420 const scoped_refptr<VideoFrame> video_frame = PopOneVideoFrame(false); |
394 #ifdef OS_LINUX | 421 #ifdef OS_LINUX |
395 render_.RenderFrame(video_frame); | 422 render_.RenderFrame(video_frame); |
396 #endif // OS_LINUX | 423 #endif // OS_LINUX |
397 } | 424 } |
398 ScheduleVideoPlayout(); | 425 ScheduleVideoPlayout(); |
| 426 CheckAVSync(); |
399 } | 427 } |
400 | 428 |
401 scoped_refptr<VideoFrame> PopOneVideoFrame(bool is_being_skipped) { | 429 scoped_refptr<VideoFrame> PopOneVideoFrame(bool is_being_skipped) { |
402 DCHECK(cast_env()->CurrentlyOn(CastEnvironment::MAIN)); | 430 DCHECK(cast_env()->CurrentlyOn(CastEnvironment::MAIN)); |
403 | 431 |
404 if (is_being_skipped) { | 432 if (is_being_skipped) { |
405 VLOG(1) << "VideoFrame[" << num_video_frames_processed_ << "]: Skipped."; | 433 VLOG(1) << "VideoFrame[" << num_video_frames_processed_ << "]: Skipped."; |
406 } else { | 434 } else { |
407 VLOG(1) << "VideoFrame[" << num_video_frames_processed_ << "]: Playing " | 435 VLOG(1) << "VideoFrame[" << num_video_frames_processed_ << "]: Playing " |
408 << (cast_env()->Clock()->NowTicks() - | 436 << (cast_env()->Clock()->NowTicks() - |
(...skipping 18 matching lines...) Expand all Loading... |
427 audio_playout_queue_.front().first).InMicroseconds() | 455 audio_playout_queue_.front().first).InMicroseconds() |
428 << " usec later than intended."; | 456 << " usec later than intended."; |
429 } | 457 } |
430 | 458 |
431 scoped_ptr<AudioBus> ret(audio_playout_queue_.front().second); | 459 scoped_ptr<AudioBus> ret(audio_playout_queue_.front().second); |
432 audio_playout_queue_.pop_front(); | 460 audio_playout_queue_.pop_front(); |
433 ++num_audio_frames_processed_; | 461 ++num_audio_frames_processed_; |
434 return ret.Pass(); | 462 return ret.Pass(); |
435 } | 463 } |
436 | 464 |
| 465 void CheckAVSync() { |
| 466 if (video_play_times_.size() > 30 && |
| 467 audio_play_times_.size() > 30) { |
| 468 size_t num_events = 0; |
| 469 base::TimeDelta delta; |
| 470 std::map<uint16, base::TimeTicks>::iterator audio_iter, video_iter; |
| 471 for (video_iter = video_play_times_.begin(); |
| 472 video_iter != video_play_times_.end(); |
| 473 ++video_iter) { |
| 474 audio_iter = audio_play_times_.find(video_iter->first); |
| 475 if (audio_iter != audio_play_times_.end()) { |
| 476 num_events++; |
| 477 // Positive values means audio is running behind video. |
| 478 delta += audio_iter->second - video_iter->second; |
| 479 } |
| 480 } |
| 481 |
| 482 if (num_events > 30) { |
| 483 VLOG(0) << "Audio behind by: " |
| 484 << (delta / num_events).InMilliseconds() |
| 485 << "ms"; |
| 486 video_play_times_.clear(); |
| 487 audio_play_times_.clear(); |
| 488 } |
| 489 } else if (video_play_times_.size() + audio_play_times_.size() > 500) { |
| 490 // We are decoding audio or video timestamps, but not both, clear it out. |
| 491 video_play_times_.clear(); |
| 492 audio_play_times_.clear(); |
| 493 } |
| 494 } |
| 495 |
437 // Frames in the queue older than this (relative to NowTicks()) will be | 496 // Frames in the queue older than this (relative to NowTicks()) will be |
438 // dropped (i.e., playback is falling behind). | 497 // dropped (i.e., playback is falling behind). |
439 const base::TimeDelta max_frame_age_; | 498 const base::TimeDelta max_frame_age_; |
440 | 499 |
441 // Outputs created, started, and destroyed by this NaivePlayer. | 500 // Outputs created, started, and destroyed by this NaivePlayer. |
442 #ifdef OS_LINUX | 501 #ifdef OS_LINUX |
443 test::LinuxOutputWindow render_; | 502 test::LinuxOutputWindow render_; |
444 #endif // OS_LINUX | 503 #endif // OS_LINUX |
445 scoped_ptr<AudioOutputStream> audio_output_stream_; | 504 scoped_ptr<AudioOutputStream> audio_output_stream_; |
446 | 505 |
447 // Video playout queue. | 506 // Video playout queue. |
448 typedef std::pair<base::TimeTicks, scoped_refptr<VideoFrame> > | 507 typedef std::pair<base::TimeTicks, scoped_refptr<VideoFrame> > |
449 VideoQueueEntry; | 508 VideoQueueEntry; |
450 std::deque<VideoQueueEntry> video_playout_queue_; | 509 std::deque<VideoQueueEntry> video_playout_queue_; |
451 int64 num_video_frames_processed_; | 510 int64 num_video_frames_processed_; |
452 | 511 |
453 base::OneShotTimer<NaivePlayer> video_playout_timer_; | 512 base::OneShotTimer<NaivePlayer> video_playout_timer_; |
454 | 513 |
455 // Audio playout queue, synchronized by |audio_lock_|. | 514 // Audio playout queue, synchronized by |audio_lock_|. |
456 base::Lock audio_lock_; | 515 base::Lock audio_lock_; |
457 typedef std::pair<base::TimeTicks, AudioBus*> AudioQueueEntry; | 516 typedef std::pair<base::TimeTicks, AudioBus*> AudioQueueEntry; |
458 std::deque<AudioQueueEntry> audio_playout_queue_; | 517 std::deque<AudioQueueEntry> audio_playout_queue_; |
459 int64 num_audio_frames_processed_; | 518 int64 num_audio_frames_processed_; |
460 | 519 |
461 // These must only be used on the audio thread calling OnMoreData(). | 520 // These must only be used on the audio thread calling OnMoreData(). |
462 scoped_ptr<AudioBus> currently_playing_audio_frame_; | 521 scoped_ptr<AudioBus> currently_playing_audio_frame_; |
463 int currently_playing_audio_frame_start_; | 522 int currently_playing_audio_frame_start_; |
| 523 |
| 524 std::map<uint16, base::TimeTicks> audio_play_times_; |
| 525 std::map<uint16, base::TimeTicks> video_play_times_; |
| 526 int32 last_audio_frame_no_; |
464 }; | 527 }; |
465 | 528 |
466 } // namespace cast | 529 } // namespace cast |
467 } // namespace media | 530 } // namespace media |
468 | 531 |
469 int main(int argc, char** argv) { | 532 int main(int argc, char** argv) { |
470 base::AtExitManager at_exit; | 533 base::AtExitManager at_exit; |
471 CommandLine::Init(argc, argv); | 534 CommandLine::Init(argc, argv); |
472 InitLogging(logging::LoggingSettings()); | 535 InitLogging(logging::LoggingSettings()); |
473 | 536 |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
519 audio_config, | 582 audio_config, |
520 video_config, | 583 video_config, |
521 window_width, | 584 window_width, |
522 window_height); | 585 window_height); |
523 player.Start(); | 586 player.Start(); |
524 | 587 |
525 base::MessageLoop().Run(); // Run forever (i.e., until SIGTERM). | 588 base::MessageLoop().Run(); // Run forever (i.e., until SIGTERM). |
526 NOTREACHED(); | 589 NOTREACHED(); |
527 return 0; | 590 return 0; |
528 } | 591 } |
OLD | NEW |