| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 // Simulate end to end streaming. | 5 // Simulate end to end streaming. |
| 6 // | 6 // |
| 7 // Input: | 7 // Input: |
| 8 // --source= | 8 // --source= |
| 9 // WebM used as the source of video and audio frames. | 9 // WebM used as the source of video and audio frames. |
| 10 // --output= | 10 // --output= |
| (...skipping 18 matching lines...) Expand all Loading... |
| 29 // File path to write YUV decoded frames in YUV4MPEG2 format. | 29 // File path to write YUV decoded frames in YUV4MPEG2 format. |
| 30 // --no-simulation | 30 // --no-simulation |
| 31 // Do not run network simulation. | 31 // Do not run network simulation. |
| 32 // | 32 // |
| 33 // Output: | 33 // Output: |
| 34 // - Raw event log of the simulation session tagged with the unique test ID, | 34 // - Raw event log of the simulation session tagged with the unique test ID, |
| 35 // written out to the specified file path. | 35 // written out to the specified file path. |
| 36 | 36 |
| 37 #include <stddef.h> | 37 #include <stddef.h> |
| 38 #include <stdint.h> | 38 #include <stdint.h> |
| 39 |
| 39 #include <utility> | 40 #include <utility> |
| 40 | 41 |
| 41 #include "base/at_exit.h" | 42 #include "base/at_exit.h" |
| 42 #include "base/base_paths.h" | 43 #include "base/base_paths.h" |
| 43 #include "base/command_line.h" | 44 #include "base/command_line.h" |
| 44 #include "base/files/file_path.h" | 45 #include "base/files/file_path.h" |
| 45 #include "base/files/file_util.h" | 46 #include "base/files/file_util.h" |
| 46 #include "base/files/memory_mapped_file.h" | 47 #include "base/files/memory_mapped_file.h" |
| 47 #include "base/files/scoped_file.h" | 48 #include "base/files/scoped_file.h" |
| 48 #include "base/json/json_writer.h" | 49 #include "base/json/json_writer.h" |
| 49 #include "base/logging.h" | 50 #include "base/logging.h" |
| 50 #include "base/macros.h" | 51 #include "base/macros.h" |
| 52 #include "base/memory/ptr_util.h" |
| 51 #include "base/path_service.h" | 53 #include "base/path_service.h" |
| 52 #include "base/strings/string_number_conversions.h" | 54 #include "base/strings/string_number_conversions.h" |
| 53 #include "base/strings/stringprintf.h" | 55 #include "base/strings/stringprintf.h" |
| 54 #include "base/test/simple_test_tick_clock.h" | 56 #include "base/test/simple_test_tick_clock.h" |
| 55 #include "base/thread_task_runner_handle.h" | 57 #include "base/thread_task_runner_handle.h" |
| 56 #include "base/time/tick_clock.h" | 58 #include "base/time/tick_clock.h" |
| 57 #include "base/values.h" | 59 #include "base/values.h" |
| 58 #include "media/base/audio_bus.h" | 60 #include "media/base/audio_bus.h" |
| 59 #include "media/base/fake_single_thread_task_runner.h" | 61 #include "media/base/fake_single_thread_task_runner.h" |
| 60 #include "media/base/media.h" | 62 #include "media/base/media.h" |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 117 void LogAudioOperationalStatus(OperationalStatus status) { | 119 void LogAudioOperationalStatus(OperationalStatus status) { |
| 118 LOG(INFO) << "Audio status: " << status; | 120 LOG(INFO) << "Audio status: " << status; |
| 119 } | 121 } |
| 120 | 122 |
| 121 void LogVideoOperationalStatus(OperationalStatus status) { | 123 void LogVideoOperationalStatus(OperationalStatus status) { |
| 122 LOG(INFO) << "Video status: " << status; | 124 LOG(INFO) << "Video status: " << status; |
| 123 } | 125 } |
| 124 | 126 |
| 125 struct PacketProxy { | 127 struct PacketProxy { |
| 126 PacketProxy() : receiver(NULL) {} | 128 PacketProxy() : receiver(NULL) {} |
| 127 void ReceivePacket(scoped_ptr<Packet> packet) { | 129 void ReceivePacket(std::unique_ptr<Packet> packet) { |
| 128 if (receiver) | 130 if (receiver) |
| 129 receiver->ReceivePacket(std::move(packet)); | 131 receiver->ReceivePacket(std::move(packet)); |
| 130 } | 132 } |
| 131 CastReceiver* receiver; | 133 CastReceiver* receiver; |
| 132 }; | 134 }; |
| 133 | 135 |
| 134 class TransportClient : public CastTransport::Client { | 136 class TransportClient : public CastTransport::Client { |
| 135 public: | 137 public: |
| 136 TransportClient(LogEventDispatcher* log_event_dispatcher, | 138 TransportClient(LogEventDispatcher* log_event_dispatcher, |
| 137 PacketProxy* packet_proxy) | 139 PacketProxy* packet_proxy) |
| 138 : log_event_dispatcher_(log_event_dispatcher), | 140 : log_event_dispatcher_(log_event_dispatcher), |
| 139 packet_proxy_(packet_proxy) {} | 141 packet_proxy_(packet_proxy) {} |
| 140 | 142 |
| 141 void OnStatusChanged(CastTransportStatus status) final { | 143 void OnStatusChanged(CastTransportStatus status) final { |
| 142 LOG(INFO) << "Cast transport status: " << status; | 144 LOG(INFO) << "Cast transport status: " << status; |
| 143 }; | 145 }; |
| 144 void OnLoggingEventsReceived( | 146 void OnLoggingEventsReceived( |
| 145 scoped_ptr<std::vector<FrameEvent>> frame_events, | 147 std::unique_ptr<std::vector<FrameEvent>> frame_events, |
| 146 scoped_ptr<std::vector<PacketEvent>> packet_events) final { | 148 std::unique_ptr<std::vector<PacketEvent>> packet_events) final { |
| 147 DCHECK(log_event_dispatcher_); | 149 DCHECK(log_event_dispatcher_); |
| 148 log_event_dispatcher_->DispatchBatchOfEvents(std::move(frame_events), | 150 log_event_dispatcher_->DispatchBatchOfEvents(std::move(frame_events), |
| 149 std::move(packet_events)); | 151 std::move(packet_events)); |
| 150 }; | 152 }; |
| 151 void ProcessRtpPacket(scoped_ptr<Packet> packet) final { | 153 void ProcessRtpPacket(std::unique_ptr<Packet> packet) final { |
| 152 if (packet_proxy_) | 154 if (packet_proxy_) |
| 153 packet_proxy_->ReceivePacket(std::move(packet)); | 155 packet_proxy_->ReceivePacket(std::move(packet)); |
| 154 }; | 156 }; |
| 155 | 157 |
| 156 private: | 158 private: |
| 157 LogEventDispatcher* const log_event_dispatcher_; // Not owned by this class. | 159 LogEventDispatcher* const log_event_dispatcher_; // Not owned by this class. |
| 158 PacketProxy* const packet_proxy_; // Not owned by this class. | 160 PacketProxy* const packet_proxy_; // Not owned by this class. |
| 159 | 161 |
| 160 DISALLOW_COPY_AND_ASSIGN(TransportClient); | 162 DISALLOW_COPY_AND_ASSIGN(TransportClient); |
| 161 }; | 163 }; |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 267 video_frame_tracker->PopOldestEncodedFrame(); | 269 video_frame_tracker->PopOldestEncodedFrame(); |
| 268 metrics_output->psnr.push_back(I420PSNR(src_frame, video_frame)); | 270 metrics_output->psnr.push_back(I420PSNR(src_frame, video_frame)); |
| 269 metrics_output->ssim.push_back(I420SSIM(src_frame, video_frame)); | 271 metrics_output->ssim.push_back(I420SSIM(src_frame, video_frame)); |
| 270 } | 272 } |
| 271 | 273 |
| 272 if (!yuv_output.empty()) { | 274 if (!yuv_output.empty()) { |
| 273 AppendYuvToFile(yuv_output, video_frame); | 275 AppendYuvToFile(yuv_output, video_frame); |
| 274 } | 276 } |
| 275 } | 277 } |
| 276 | 278 |
| 277 void GotAudioFrame( | 279 void GotAudioFrame(int* counter, |
| 278 int* counter, | 280 CastReceiver* cast_receiver, |
| 279 CastReceiver* cast_receiver, | 281 std::unique_ptr<AudioBus> audio_bus, |
| 280 scoped_ptr<AudioBus> audio_bus, | 282 const base::TimeTicks& playout_time, |
| 281 const base::TimeTicks& playout_time, | 283 bool is_continuous) { |
| 282 bool is_continuous) { | |
| 283 ++*counter; | 284 ++*counter; |
| 284 cast_receiver->RequestDecodedAudioFrame( | 285 cast_receiver->RequestDecodedAudioFrame( |
| 285 base::Bind(&GotAudioFrame, counter, cast_receiver)); | 286 base::Bind(&GotAudioFrame, counter, cast_receiver)); |
| 286 } | 287 } |
| 287 | 288 |
| 288 // Serialize |frame_events| and |packet_events| and append to the file | 289 // Serialize |frame_events| and |packet_events| and append to the file |
| 289 // located at |output_path|. | 290 // located at |output_path|. |
| 290 void AppendLogToFile(media::cast::proto::LogMetadata* metadata, | 291 void AppendLogToFile(media::cast::proto::LogMetadata* metadata, |
| 291 const media::cast::FrameEventList& frame_events, | 292 const media::cast::FrameEventList& frame_events, |
| 292 const media::cast::PacketEventList& packet_events, | 293 const media::cast::PacketEventList& packet_events, |
| 293 const base::FilePath& output_path) { | 294 const base::FilePath& output_path) { |
| 294 media::cast::proto::GeneralDescription* gen_desc = | 295 media::cast::proto::GeneralDescription* gen_desc = |
| 295 metadata->mutable_general_description(); | 296 metadata->mutable_general_description(); |
| 296 gen_desc->set_product("Cast Simulator"); | 297 gen_desc->set_product("Cast Simulator"); |
| 297 gen_desc->set_product_version("0.1"); | 298 gen_desc->set_product_version("0.1"); |
| 298 | 299 |
| 299 scoped_ptr<char[]> serialized_log(new char[media::cast::kMaxSerializedBytes]); | 300 std::unique_ptr<char[]> serialized_log( |
| 301 new char[media::cast::kMaxSerializedBytes]); |
| 300 int output_bytes; | 302 int output_bytes; |
| 301 bool success = media::cast::SerializeEvents(*metadata, | 303 bool success = media::cast::SerializeEvents(*metadata, |
| 302 frame_events, | 304 frame_events, |
| 303 packet_events, | 305 packet_events, |
| 304 true, | 306 true, |
| 305 media::cast::kMaxSerializedBytes, | 307 media::cast::kMaxSerializedBytes, |
| 306 serialized_log.get(), | 308 serialized_log.get(), |
| 307 &output_bytes); | 309 &output_bytes); |
| 308 | 310 |
| 309 if (!success) { | 311 if (!success) { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 329 // Fake clock. Make sure start time is non zero. | 331 // Fake clock. Make sure start time is non zero. |
| 330 base::SimpleTestTickClock testing_clock; | 332 base::SimpleTestTickClock testing_clock; |
| 331 testing_clock.Advance(base::TimeDelta::FromSeconds(1)); | 333 testing_clock.Advance(base::TimeDelta::FromSeconds(1)); |
| 332 | 334 |
| 333 // Task runner. | 335 // Task runner. |
| 334 scoped_refptr<FakeSingleThreadTaskRunner> task_runner = | 336 scoped_refptr<FakeSingleThreadTaskRunner> task_runner = |
| 335 new FakeSingleThreadTaskRunner(&testing_clock); | 337 new FakeSingleThreadTaskRunner(&testing_clock); |
| 336 base::ThreadTaskRunnerHandle task_runner_handle(task_runner); | 338 base::ThreadTaskRunnerHandle task_runner_handle(task_runner); |
| 337 | 339 |
| 338 // CastEnvironments. | 340 // CastEnvironments. |
| 339 scoped_refptr<CastEnvironment> sender_env = new CastEnvironment( | 341 scoped_refptr<CastEnvironment> sender_env = |
| 340 scoped_ptr<base::TickClock>(new test::SkewedTickClock(&testing_clock)), | 342 new CastEnvironment(std::unique_ptr<base::TickClock>( |
| 341 task_runner, task_runner, task_runner); | 343 new test::SkewedTickClock(&testing_clock)), |
| 342 scoped_refptr<CastEnvironment> receiver_env = new CastEnvironment( | 344 task_runner, task_runner, task_runner); |
| 343 scoped_ptr<base::TickClock>(new test::SkewedTickClock(&testing_clock)), | 345 scoped_refptr<CastEnvironment> receiver_env = |
| 344 task_runner, task_runner, task_runner); | 346 new CastEnvironment(std::unique_ptr<base::TickClock>( |
| 347 new test::SkewedTickClock(&testing_clock)), |
| 348 task_runner, task_runner, task_runner); |
| 345 | 349 |
| 346 // Event subscriber. Store at most 1 hour of events. | 350 // Event subscriber. Store at most 1 hour of events. |
| 347 EncodingEventSubscriber audio_event_subscriber(AUDIO_EVENT, | 351 EncodingEventSubscriber audio_event_subscriber(AUDIO_EVENT, |
| 348 100 * 60 * 60); | 352 100 * 60 * 60); |
| 349 EncodingEventSubscriber video_event_subscriber(VIDEO_EVENT, | 353 EncodingEventSubscriber video_event_subscriber(VIDEO_EVENT, |
| 350 30 * 60 * 60); | 354 30 * 60 * 60); |
| 351 sender_env->logger()->Subscribe(&audio_event_subscriber); | 355 sender_env->logger()->Subscribe(&audio_event_subscriber); |
| 352 sender_env->logger()->Subscribe(&video_event_subscriber); | 356 sender_env->logger()->Subscribe(&video_event_subscriber); |
| 353 | 357 |
| 354 // Audio sender config. | 358 // Audio sender config. |
| (...skipping 24 matching lines...) Expand all Loading... |
| 379 video_receiver_config.rtp_max_delay_ms = | 383 video_receiver_config.rtp_max_delay_ms = |
| 380 video_sender_config.max_playout_delay.InMilliseconds(); | 384 video_sender_config.max_playout_delay.InMilliseconds(); |
| 381 | 385 |
| 382 // Loopback transport. Owned by CastTransport. | 386 // Loopback transport. Owned by CastTransport. |
| 383 LoopBackTransport* receiver_to_sender = new LoopBackTransport(receiver_env); | 387 LoopBackTransport* receiver_to_sender = new LoopBackTransport(receiver_env); |
| 384 LoopBackTransport* sender_to_receiver = new LoopBackTransport(sender_env); | 388 LoopBackTransport* sender_to_receiver = new LoopBackTransport(sender_env); |
| 385 | 389 |
| 386 PacketProxy packet_proxy; | 390 PacketProxy packet_proxy; |
| 387 | 391 |
| 388 // Cast receiver. | 392 // Cast receiver. |
| 389 scoped_ptr<CastTransport> transport_receiver( | 393 std::unique_ptr<CastTransport> transport_receiver( |
| 390 new CastTransportImpl(&testing_clock, base::TimeDelta::FromSeconds(1), | 394 new CastTransportImpl(&testing_clock, base::TimeDelta::FromSeconds(1), |
| 391 make_scoped_ptr(new TransportClient( | 395 base::WrapUnique(new TransportClient( |
| 392 receiver_env->logger(), &packet_proxy)), | 396 receiver_env->logger(), &packet_proxy)), |
| 393 make_scoped_ptr(receiver_to_sender), task_runner)); | 397 base::WrapUnique(receiver_to_sender), task_runner)); |
| 394 scoped_ptr<CastReceiver> cast_receiver( | 398 std::unique_ptr<CastReceiver> cast_receiver( |
| 395 CastReceiver::Create(receiver_env, | 399 CastReceiver::Create(receiver_env, audio_receiver_config, |
| 396 audio_receiver_config, | 400 video_receiver_config, transport_receiver.get())); |
| 397 video_receiver_config, | |
| 398 transport_receiver.get())); | |
| 399 | 401 |
| 400 packet_proxy.receiver = cast_receiver.get(); | 402 packet_proxy.receiver = cast_receiver.get(); |
| 401 | 403 |
| 402 // Cast sender and transport sender. | 404 // Cast sender and transport sender. |
| 403 scoped_ptr<CastTransport> transport_sender(new CastTransportImpl( | 405 std::unique_ptr<CastTransport> transport_sender(new CastTransportImpl( |
| 404 &testing_clock, base::TimeDelta::FromSeconds(1), | 406 &testing_clock, base::TimeDelta::FromSeconds(1), |
| 405 make_scoped_ptr(new TransportClient(sender_env->logger(), nullptr)), | 407 base::WrapUnique(new TransportClient(sender_env->logger(), nullptr)), |
| 406 make_scoped_ptr(sender_to_receiver), task_runner)); | 408 base::WrapUnique(sender_to_receiver), task_runner)); |
| 407 scoped_ptr<CastSender> cast_sender( | 409 std::unique_ptr<CastSender> cast_sender( |
| 408 CastSender::Create(sender_env, transport_sender.get())); | 410 CastSender::Create(sender_env, transport_sender.get())); |
| 409 | 411 |
| 410 // Initialize network simulation model. | 412 // Initialize network simulation model. |
| 411 const bool use_network_simulation = | 413 const bool use_network_simulation = |
| 412 model.type() == media::cast::proto::INTERRUPTED_POISSON_PROCESS; | 414 model.type() == media::cast::proto::INTERRUPTED_POISSON_PROCESS; |
| 413 scoped_ptr<test::InterruptedPoissonProcess> ipp; | 415 std::unique_ptr<test::InterruptedPoissonProcess> ipp; |
| 414 if (use_network_simulation) { | 416 if (use_network_simulation) { |
| 415 LOG(INFO) << "Running Poisson based network simulation."; | 417 LOG(INFO) << "Running Poisson based network simulation."; |
| 416 const IPPModel& ipp_model = model.ipp(); | 418 const IPPModel& ipp_model = model.ipp(); |
| 417 std::vector<double> average_rates(ipp_model.average_rate_size()); | 419 std::vector<double> average_rates(ipp_model.average_rate_size()); |
| 418 std::copy(ipp_model.average_rate().begin(), | 420 std::copy(ipp_model.average_rate().begin(), |
| 419 ipp_model.average_rate().end(), | 421 ipp_model.average_rate().end(), |
| 420 average_rates.begin()); | 422 average_rates.begin()); |
| 421 ipp.reset(new test::InterruptedPoissonProcess( | 423 ipp.reset(new test::InterruptedPoissonProcess( |
| 422 average_rates, | 424 average_rates, |
| 423 ipp_model.coef_burstiness(), ipp_model.coef_variance(), 0)); | 425 ipp_model.coef_burstiness(), ipp_model.coef_variance(), 0)); |
| 424 receiver_to_sender->Initialize(ipp->NewBuffer(128 * 1024), | 426 receiver_to_sender->Initialize(ipp->NewBuffer(128 * 1024), |
| 425 transport_sender->PacketReceiverForTesting(), | 427 transport_sender->PacketReceiverForTesting(), |
| 426 task_runner, &testing_clock); | 428 task_runner, &testing_clock); |
| 427 sender_to_receiver->Initialize( | 429 sender_to_receiver->Initialize( |
| 428 ipp->NewBuffer(128 * 1024), | 430 ipp->NewBuffer(128 * 1024), |
| 429 transport_receiver->PacketReceiverForTesting(), task_runner, | 431 transport_receiver->PacketReceiverForTesting(), task_runner, |
| 430 &testing_clock); | 432 &testing_clock); |
| 431 } else { | 433 } else { |
| 432 LOG(INFO) << "No network simulation."; | 434 LOG(INFO) << "No network simulation."; |
| 433 receiver_to_sender->Initialize(scoped_ptr<test::PacketPipe>(), | 435 receiver_to_sender->Initialize(std::unique_ptr<test::PacketPipe>(), |
| 434 transport_sender->PacketReceiverForTesting(), | 436 transport_sender->PacketReceiverForTesting(), |
| 435 task_runner, &testing_clock); | 437 task_runner, &testing_clock); |
| 436 sender_to_receiver->Initialize( | 438 sender_to_receiver->Initialize( |
| 437 scoped_ptr<test::PacketPipe>(), | 439 std::unique_ptr<test::PacketPipe>(), |
| 438 transport_receiver->PacketReceiverForTesting(), task_runner, | 440 transport_receiver->PacketReceiverForTesting(), task_runner, |
| 439 &testing_clock); | 441 &testing_clock); |
| 440 } | 442 } |
| 441 | 443 |
| 442 // Initialize a fake media source and a tracker to encoded video frames. | 444 // Initialize a fake media source and a tracker to encoded video frames. |
| 443 const bool quality_test = !metrics_output_path.empty(); | 445 const bool quality_test = !metrics_output_path.empty(); |
| 444 FakeMediaSource media_source(task_runner, | 446 FakeMediaSource media_source(task_runner, |
| 445 &testing_clock, | 447 &testing_clock, |
| 446 audio_sender_config, | 448 audio_sender_config, |
| 447 video_sender_config, | 449 video_sender_config, |
| 448 quality_test); | 450 quality_test); |
| 449 scoped_ptr<EncodedVideoFrameTracker> video_frame_tracker; | 451 std::unique_ptr<EncodedVideoFrameTracker> video_frame_tracker; |
| 450 if (quality_test) { | 452 if (quality_test) { |
| 451 video_frame_tracker.reset(new EncodedVideoFrameTracker(&media_source)); | 453 video_frame_tracker.reset(new EncodedVideoFrameTracker(&media_source)); |
| 452 sender_env->logger()->Subscribe(video_frame_tracker.get()); | 454 sender_env->logger()->Subscribe(video_frame_tracker.get()); |
| 453 } | 455 } |
| 454 | 456 |
| 455 // Quality metrics computed for each frame decoded. | 457 // Quality metrics computed for each frame decoded. |
| 456 GotVideoFrameOutput metrics_output; | 458 GotVideoFrameOutput metrics_output; |
| 457 | 459 |
| 458 // Start receiver. | 460 // Start receiver. |
| 459 int audio_frame_count = 0; | 461 int audio_frame_count = 0; |
| (...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 732 values.SetString("sim-id", sim_id); | 734 values.SetString("sim-id", sim_id); |
| 733 | 735 |
| 734 std::string extra_data; | 736 std::string extra_data; |
| 735 base::JSONWriter::Write(values, &extra_data); | 737 base::JSONWriter::Write(values, &extra_data); |
| 736 | 738 |
| 737 // Run. | 739 // Run. |
| 738 media::cast::RunSimulation(source_path, log_output_path, metrics_output_path, | 740 media::cast::RunSimulation(source_path, log_output_path, metrics_output_path, |
| 739 yuv_output_path, extra_data, model); | 741 yuv_output_path, extra_data, model); |
| 740 return 0; | 742 return 0; |
| 741 } | 743 } |
| OLD | NEW |