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. | |
299 if (is_continuous && frame_no == last_audio_frame_no_ + 1) { | |
miu
2014/04/25 06:47:59
What is supposed to happen if !is_continuous? See
hubbe
2014/04/25 07:21:38
Comment added.
Basically, we're supposed to ignore
| |
300 audio_play_times_.insert( | |
301 std::pair<uint16, base::TimeTicks>(frame_no, playout_time)); | |
302 } | |
303 last_audio_frame_no_ = frame_no; | |
304 } else { | |
305 VLOG(2) << "Audio decode failed!"; | |
306 last_audio_frame_no_ = -2; | |
307 } | |
282 audio_playout_queue_.push_back( | 308 audio_playout_queue_.push_back( |
283 std::make_pair(playout_time, audio_frame.release())); | 309 std::make_pair(playout_time, audio_frame.release())); |
284 } | 310 } |
285 | 311 |
286 // End of InProcessReceiver overrides. | 312 // End of InProcessReceiver overrides. |
287 //////////////////////////////////////////////////////////////////// | 313 //////////////////////////////////////////////////////////////////// |
288 | 314 |
289 //////////////////////////////////////////////////////////////////// | 315 //////////////////////////////////////////////////////////////////// |
290 // AudioSourceCallback implementation. | 316 // AudioSourceCallback implementation. |
291 | 317 |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
389 | 415 |
390 void PlayNextVideoFrame() { | 416 void PlayNextVideoFrame() { |
391 DCHECK(cast_env()->CurrentlyOn(CastEnvironment::MAIN)); | 417 DCHECK(cast_env()->CurrentlyOn(CastEnvironment::MAIN)); |
392 if (!video_playout_queue_.empty()) { | 418 if (!video_playout_queue_.empty()) { |
393 const scoped_refptr<VideoFrame> video_frame = PopOneVideoFrame(false); | 419 const scoped_refptr<VideoFrame> video_frame = PopOneVideoFrame(false); |
394 #ifdef OS_LINUX | 420 #ifdef OS_LINUX |
395 render_.RenderFrame(video_frame); | 421 render_.RenderFrame(video_frame); |
396 #endif // OS_LINUX | 422 #endif // OS_LINUX |
397 } | 423 } |
398 ScheduleVideoPlayout(); | 424 ScheduleVideoPlayout(); |
425 CheckAVSync(); | |
399 } | 426 } |
400 | 427 |
401 scoped_refptr<VideoFrame> PopOneVideoFrame(bool is_being_skipped) { | 428 scoped_refptr<VideoFrame> PopOneVideoFrame(bool is_being_skipped) { |
402 DCHECK(cast_env()->CurrentlyOn(CastEnvironment::MAIN)); | 429 DCHECK(cast_env()->CurrentlyOn(CastEnvironment::MAIN)); |
403 | 430 |
404 if (is_being_skipped) { | 431 if (is_being_skipped) { |
405 VLOG(1) << "VideoFrame[" << num_video_frames_processed_ << "]: Skipped."; | 432 VLOG(1) << "VideoFrame[" << num_video_frames_processed_ << "]: Skipped."; |
406 } else { | 433 } else { |
407 VLOG(1) << "VideoFrame[" << num_video_frames_processed_ << "]: Playing " | 434 VLOG(1) << "VideoFrame[" << num_video_frames_processed_ << "]: Playing " |
408 << (cast_env()->Clock()->NowTicks() - | 435 << (cast_env()->Clock()->NowTicks() - |
(...skipping 18 matching lines...) Expand all Loading... | |
427 audio_playout_queue_.front().first).InMicroseconds() | 454 audio_playout_queue_.front().first).InMicroseconds() |
428 << " usec later than intended."; | 455 << " usec later than intended."; |
429 } | 456 } |
430 | 457 |
431 scoped_ptr<AudioBus> ret(audio_playout_queue_.front().second); | 458 scoped_ptr<AudioBus> ret(audio_playout_queue_.front().second); |
432 audio_playout_queue_.pop_front(); | 459 audio_playout_queue_.pop_front(); |
433 ++num_audio_frames_processed_; | 460 ++num_audio_frames_processed_; |
434 return ret.Pass(); | 461 return ret.Pass(); |
435 } | 462 } |
436 | 463 |
464 void CheckAVSync() { | |
465 if (video_play_times_.size() > 30 && | |
466 audio_play_times_.size() > 30) { | |
467 size_t num_events = 0; | |
468 base::TimeDelta delta; | |
469 std::map<uint16, base::TimeTicks>::iterator audio_iter, video_iter; | |
470 for (video_iter = video_play_times_.begin(); | |
471 video_iter != video_play_times_.end(); | |
472 ++video_iter) { | |
473 audio_iter = audio_play_times_.find(video_iter->first); | |
474 if (audio_iter != audio_play_times_.end()) { | |
475 num_events++; | |
476 // Positive values means audio is running behind video. | |
477 delta += audio_iter->second - video_iter->second; | |
478 } | |
479 } | |
480 | |
481 if (num_events > 30) { | |
482 VLOG(0) << "AV sync: " << (delta / num_events).InMilliseconds() << "ms"; | |
miu
2014/04/25 06:47:59
After "AV sync:" can you add "audio behind by"?
hubbe
2014/04/25 07:21:38
Changed it to just say "Audio behind by:".
| |
483 video_play_times_.clear(); | |
484 audio_play_times_.clear(); | |
485 } | |
486 } else if (video_play_times_.size() + audio_play_times_.size() > 500) { | |
487 // We are decoding audio or video timestamps, but not both, clear it out. | |
488 video_play_times_.clear(); | |
489 audio_play_times_.clear(); | |
490 } | |
491 } | |
492 | |
437 // Frames in the queue older than this (relative to NowTicks()) will be | 493 // Frames in the queue older than this (relative to NowTicks()) will be |
438 // dropped (i.e., playback is falling behind). | 494 // dropped (i.e., playback is falling behind). |
439 const base::TimeDelta max_frame_age_; | 495 const base::TimeDelta max_frame_age_; |
440 | 496 |
441 // Outputs created, started, and destroyed by this NaivePlayer. | 497 // Outputs created, started, and destroyed by this NaivePlayer. |
442 #ifdef OS_LINUX | 498 #ifdef OS_LINUX |
443 test::LinuxOutputWindow render_; | 499 test::LinuxOutputWindow render_; |
444 #endif // OS_LINUX | 500 #endif // OS_LINUX |
445 scoped_ptr<AudioOutputStream> audio_output_stream_; | 501 scoped_ptr<AudioOutputStream> audio_output_stream_; |
446 | 502 |
447 // Video playout queue. | 503 // Video playout queue. |
448 typedef std::pair<base::TimeTicks, scoped_refptr<VideoFrame> > | 504 typedef std::pair<base::TimeTicks, scoped_refptr<VideoFrame> > |
449 VideoQueueEntry; | 505 VideoQueueEntry; |
450 std::deque<VideoQueueEntry> video_playout_queue_; | 506 std::deque<VideoQueueEntry> video_playout_queue_; |
451 int64 num_video_frames_processed_; | 507 int64 num_video_frames_processed_; |
452 | 508 |
453 base::OneShotTimer<NaivePlayer> video_playout_timer_; | 509 base::OneShotTimer<NaivePlayer> video_playout_timer_; |
454 | 510 |
455 // Audio playout queue, synchronized by |audio_lock_|. | 511 // Audio playout queue, synchronized by |audio_lock_|. |
456 base::Lock audio_lock_; | 512 base::Lock audio_lock_; |
457 typedef std::pair<base::TimeTicks, AudioBus*> AudioQueueEntry; | 513 typedef std::pair<base::TimeTicks, AudioBus*> AudioQueueEntry; |
458 std::deque<AudioQueueEntry> audio_playout_queue_; | 514 std::deque<AudioQueueEntry> audio_playout_queue_; |
459 int64 num_audio_frames_processed_; | 515 int64 num_audio_frames_processed_; |
460 | 516 |
461 // These must only be used on the audio thread calling OnMoreData(). | 517 // These must only be used on the audio thread calling OnMoreData(). |
462 scoped_ptr<AudioBus> currently_playing_audio_frame_; | 518 scoped_ptr<AudioBus> currently_playing_audio_frame_; |
463 int currently_playing_audio_frame_start_; | 519 int currently_playing_audio_frame_start_; |
520 | |
521 std::map<uint16, base::TimeTicks> audio_play_times_; | |
522 std::map<uint16, base::TimeTicks> video_play_times_; | |
523 int32 last_audio_frame_no_; | |
464 }; | 524 }; |
465 | 525 |
466 } // namespace cast | 526 } // namespace cast |
467 } // namespace media | 527 } // namespace media |
468 | 528 |
469 int main(int argc, char** argv) { | 529 int main(int argc, char** argv) { |
470 base::AtExitManager at_exit; | 530 base::AtExitManager at_exit; |
471 CommandLine::Init(argc, argv); | 531 CommandLine::Init(argc, argv); |
472 InitLogging(logging::LoggingSettings()); | 532 InitLogging(logging::LoggingSettings()); |
473 | 533 |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
519 audio_config, | 579 audio_config, |
520 video_config, | 580 video_config, |
521 window_width, | 581 window_width, |
522 window_height); | 582 window_height); |
523 player.Start(); | 583 player.Start(); |
524 | 584 |
525 base::MessageLoop().Run(); // Run forever (i.e., until SIGTERM). | 585 base::MessageLoop().Run(); // Run forever (i.e., until SIGTERM). |
526 NOTREACHED(); | 586 NOTREACHED(); |
527 return 0; | 587 return 0; |
528 } | 588 } |
OLD | NEW |