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
3 // found in the LICENSE file.
5 // Simulate end to end streaming.
9 // WebM used as the source of video and audio frames.
11 // File path to writing out the raw event log of the simulation session.
13 // Unique simulation ID.
15 // Target playout delay to configure (integer number of milliseconds).
16 // Optional; default is 400.
18 // The maximum frame rate allowed at any time during the Cast session.
19 // Optional; default is 30.
20 // --source-frame-rate=
21 // Overrides the playback rate; the source video will play faster/slower.
23 // In seconds, how long the Cast session runs for.
24 // Optional; default is 180.
26 // File path to write PSNR and SSIM metrics between source frames and
27 // decoded frames. Assumes all encoded frames are decoded.
29 // File path to write YUV decoded frames in YUV4MPEG2 format.
31 // Do not run network simulation.
34 // - Raw event log of the simulation session tagged with the unique test ID,
35 // written out to the specified file path.
37 #include "base/at_exit.h"
38 #include "base/base_paths.h"
39 #include "base/command_line.h"
40 #include "base/files/file_path.h"
41 #include "base/files/file_util.h"
42 #include "base/files/memory_mapped_file.h"
43 #include "base/files/scoped_file.h"
44 #include "base/json/json_writer.h"
45 #include "base/logging.h"
46 #include "base/path_service.h"
47 #include "base/strings/string_number_conversions.h"
48 #include "base/strings/stringprintf.h"
49 #include "base/test/simple_test_tick_clock.h"
50 #include "base/thread_task_runner_handle.h"
51 #include "base/time/tick_clock.h"
52 #include "base/values.h"
53 #include "media/base/audio_bus.h"
54 #include "media/base/media.h"
55 #include "media/base/video_frame.h"
56 #include "media/cast/cast_config.h"
57 #include "media/cast/cast_environment.h"
58 #include "media/cast/cast_receiver.h"
59 #include "media/cast/cast_sender.h"
60 #include "media/cast/logging/encoding_event_subscriber.h"
61 #include "media/cast/logging/log_serializer.h"
62 #include "media/cast/logging/logging_defines.h"
63 #include "media/cast/logging/proto/raw_events.pb.h"
64 #include "media/cast/logging/raw_event_subscriber_bundle.h"
65 #include "media/cast/logging/simple_event_subscriber.h"
66 #include "media/cast/net/cast_transport_config.h"
67 #include "media/cast/net/cast_transport_defines.h"
68 #include "media/cast/net/cast_transport_sender.h"
69 #include "media/cast/net/cast_transport_sender_impl.h"
70 #include "media/cast/test/fake_media_source.h"
71 #include "media/cast/test/fake_single_thread_task_runner.h"
72 #include "media/cast/test/loopback_transport.h"
73 #include "media/cast/test/proto/network_simulation_model.pb.h"
74 #include "media/cast/test/skewed_tick_clock.h"
75 #include "media/cast/test/utility/audio_utility.h"
76 #include "media/cast/test/utility/default_config.h"
77 #include "media/cast/test/utility/test_util.h"
78 #include "media/cast/test/utility/udp_proxy.h"
79 #include "media/cast/test/utility/video_utility.h"
81 using media::cast::proto::IPPModel
;
82 using media::cast::proto::NetworkSimulationModel
;
83 using media::cast::proto::NetworkSimulationModelType
;
88 const char kLibDir
[] = "lib-dir";
89 const char kModelPath
[] = "model";
90 const char kMetricsOutputPath
[] = "metrics-output";
91 const char kOutputPath
[] = "output";
92 const char kMaxFrameRate
[] = "max-frame-rate";
93 const char kNoSimulation
[] = "no-simulation";
94 const char kRunTime
[] = "run-time";
95 const char kSimulationId
[] = "sim-id";
96 const char kSourcePath
[] = "source";
97 const char kSourceFrameRate
[] = "source-frame-rate";
98 const char kTargetDelay
[] = "target-delay-ms";
99 const char kYuvOutputPath
[] = "yuv-output";
101 int GetIntegerSwitchValue(const char* switch_name
, int default_value
) {
102 const std::string as_str
=
103 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(switch_name
);
105 return default_value
;
107 CHECK(base::StringToInt(as_str
, &as_int
));
112 void UpdateCastTransportStatus(CastTransportStatus status
) {
113 LOG(INFO
) << "Cast transport status: " << status
;
116 void LogAudioOperationalStatus(OperationalStatus status
) {
117 LOG(INFO
) << "Audio status: " << status
;
120 void LogVideoOperationalStatus(OperationalStatus status
) {
121 LOG(INFO
) << "Video status: " << status
;
124 void LogTransportEvents(const scoped_refptr
<CastEnvironment
>& env
,
125 const std::vector
<PacketEvent
>& packet_events
,
126 const std::vector
<FrameEvent
>& frame_events
) {
127 for (std::vector
<media::cast::PacketEvent
>::const_iterator it
=
128 packet_events
.begin();
129 it
!= packet_events
.end();
131 env
->Logging()->InsertPacketEvent(it
->timestamp
,
140 for (std::vector
<media::cast::FrameEvent
>::const_iterator it
=
141 frame_events
.begin();
142 it
!= frame_events
.end();
144 if (it
->type
== FRAME_PLAYOUT
) {
145 env
->Logging()->InsertFrameEventWithDelay(
153 env
->Logging()->InsertFrameEvent(
163 // Maintains a queue of encoded video frames.
164 // This works by tracking FRAME_CAPTURE_END and FRAME_ENCODED events.
165 // If a video frame is detected to be encoded it transfers a frame
166 // from FakeMediaSource to its internal queue. Otherwise it drops a
167 // frame from FakeMediaSource.
168 class EncodedVideoFrameTracker
: public RawEventSubscriber
{
170 EncodedVideoFrameTracker(FakeMediaSource
* media_source
)
171 : media_source_(media_source
),
172 last_frame_event_type_(UNKNOWN
) {}
173 ~EncodedVideoFrameTracker() final
{}
175 // RawEventSubscriber implementations.
176 void OnReceiveFrameEvent(const FrameEvent
& frame_event
) final
{
177 // This method only cares about video FRAME_CAPTURE_END and
178 // FRAME_ENCODED events.
179 if (frame_event
.media_type
!= VIDEO_EVENT
) {
182 if (frame_event
.type
!= FRAME_CAPTURE_END
&&
183 frame_event
.type
!= FRAME_ENCODED
) {
186 // If there are two consecutive FRAME_CAPTURE_END events that means
187 // a frame is dropped.
188 if (last_frame_event_type_
== FRAME_CAPTURE_END
&&
189 frame_event
.type
== FRAME_CAPTURE_END
) {
190 media_source_
->PopOldestInsertedVideoFrame();
192 if (frame_event
.type
== FRAME_ENCODED
) {
193 video_frames_
.push(media_source_
->PopOldestInsertedVideoFrame());
195 last_frame_event_type_
= frame_event
.type
;
198 void OnReceivePacketEvent(const PacketEvent
& packet_event
) final
{
202 scoped_refptr
<media::VideoFrame
> PopOldestEncodedFrame() {
203 CHECK(!video_frames_
.empty());
204 scoped_refptr
<media::VideoFrame
> video_frame
= video_frames_
.front();
210 FakeMediaSource
* media_source_
;
211 CastLoggingEvent last_frame_event_type_
;
212 std::queue
<scoped_refptr
<media::VideoFrame
> > video_frames_
;
214 DISALLOW_COPY_AND_ASSIGN(EncodedVideoFrameTracker
);
217 // Appends a YUV frame in I420 format to the file located at |path|.
218 void AppendYuvToFile(const base::FilePath
& path
,
219 scoped_refptr
<media::VideoFrame
> frame
) {
220 // Write YUV420 format to file.
223 &header
, "FRAME W%d H%d\n",
224 frame
->coded_size().width(),
225 frame
->coded_size().height());
226 AppendToFile(path
, header
.data(), header
.size());
228 reinterpret_cast<char*>(frame
->data(media::VideoFrame::kYPlane
)),
229 frame
->stride(media::VideoFrame::kYPlane
) *
230 frame
->rows(media::VideoFrame::kYPlane
));
232 reinterpret_cast<char*>(frame
->data(media::VideoFrame::kUPlane
)),
233 frame
->stride(media::VideoFrame::kUPlane
) *
234 frame
->rows(media::VideoFrame::kUPlane
));
236 reinterpret_cast<char*>(frame
->data(media::VideoFrame::kVPlane
)),
237 frame
->stride(media::VideoFrame::kVPlane
) *
238 frame
->rows(media::VideoFrame::kVPlane
));
241 // A container to save output of GotVideoFrame() for computation based
243 struct GotVideoFrameOutput
{
244 GotVideoFrameOutput() : counter(0) {}
246 std::vector
<double> psnr
;
247 std::vector
<double> ssim
;
251 GotVideoFrameOutput
* metrics_output
,
252 const base::FilePath
& yuv_output
,
253 EncodedVideoFrameTracker
* video_frame_tracker
,
254 CastReceiver
* cast_receiver
,
255 const scoped_refptr
<media::VideoFrame
>& video_frame
,
256 const base::TimeTicks
& render_time
,
258 ++metrics_output
->counter
;
259 cast_receiver
->RequestDecodedVideoFrame(
260 base::Bind(&GotVideoFrame
, metrics_output
, yuv_output
,
261 video_frame_tracker
, cast_receiver
));
263 // If |video_frame_tracker| is available that means we're computing
265 if (video_frame_tracker
) {
266 scoped_refptr
<media::VideoFrame
> src_frame
=
267 video_frame_tracker
->PopOldestEncodedFrame();
268 metrics_output
->psnr
.push_back(I420PSNR(src_frame
, video_frame
));
269 metrics_output
->ssim
.push_back(I420SSIM(src_frame
, video_frame
));
272 if (!yuv_output
.empty()) {
273 AppendYuvToFile(yuv_output
, video_frame
);
279 CastReceiver
* cast_receiver
,
280 scoped_ptr
<AudioBus
> audio_bus
,
281 const base::TimeTicks
& playout_time
,
282 bool is_continuous
) {
284 cast_receiver
->RequestDecodedAudioFrame(
285 base::Bind(&GotAudioFrame
, counter
, cast_receiver
));
288 // Serialize |frame_events| and |packet_events| and append to the file
289 // located at |output_path|.
290 void AppendLogToFile(media::cast::proto::LogMetadata
* metadata
,
291 const media::cast::FrameEventList
& frame_events
,
292 const media::cast::PacketEventList
& packet_events
,
293 const base::FilePath
& output_path
) {
294 media::cast::proto::GeneralDescription
* gen_desc
=
295 metadata
->mutable_general_description();
296 gen_desc
->set_product("Cast Simulator");
297 gen_desc
->set_product_version("0.1");
299 scoped_ptr
<char[]> serialized_log(new char[media::cast::kMaxSerializedBytes
]);
301 bool success
= media::cast::SerializeEvents(*metadata
,
305 media::cast::kMaxSerializedBytes
,
306 serialized_log
.get(),
310 LOG(ERROR
) << "Failed to serialize log.";
314 if (!AppendToFile(output_path
, serialized_log
.get(), output_bytes
)) {
315 LOG(ERROR
) << "Failed to append to log.";
319 // Run simulation once.
321 // |log_output_path| is the path to write serialized log.
322 // |extra_data| is extra tagging information to write to log.
323 void RunSimulation(const base::FilePath
& source_path
,
324 const base::FilePath
& log_output_path
,
325 const base::FilePath
& metrics_output_path
,
326 const base::FilePath
& yuv_output_path
,
327 const std::string
& extra_data
,
328 const NetworkSimulationModel
& model
) {
329 // Fake clock. Make sure start time is non zero.
330 base::SimpleTestTickClock testing_clock
;
331 testing_clock
.Advance(base::TimeDelta::FromSeconds(1));
334 scoped_refptr
<test::FakeSingleThreadTaskRunner
> task_runner
=
335 new test::FakeSingleThreadTaskRunner(&testing_clock
);
336 base::ThreadTaskRunnerHandle
task_runner_handle(task_runner
);
339 scoped_refptr
<CastEnvironment
> sender_env
=
341 scoped_ptr
<base::TickClock
>(
342 new test::SkewedTickClock(&testing_clock
)).Pass(),
346 scoped_refptr
<CastEnvironment
> receiver_env
=
348 scoped_ptr
<base::TickClock
>(
349 new test::SkewedTickClock(&testing_clock
)).Pass(),
354 // Event subscriber. Store at most 1 hour of events.
355 EncodingEventSubscriber
audio_event_subscriber(AUDIO_EVENT
,
357 EncodingEventSubscriber
video_event_subscriber(VIDEO_EVENT
,
359 sender_env
->Logging()->AddRawEventSubscriber(&audio_event_subscriber
);
360 sender_env
->Logging()->AddRawEventSubscriber(&video_event_subscriber
);
362 // Audio sender config.
363 AudioSenderConfig audio_sender_config
= GetDefaultAudioSenderConfig();
364 audio_sender_config
.min_playout_delay
=
365 audio_sender_config
.max_playout_delay
= base::TimeDelta::FromMilliseconds(
366 GetIntegerSwitchValue(kTargetDelay
, 400));
368 // Audio receiver config.
369 FrameReceiverConfig audio_receiver_config
=
370 GetDefaultAudioReceiverConfig();
371 audio_receiver_config
.rtp_max_delay_ms
=
372 audio_sender_config
.max_playout_delay
.InMilliseconds();
374 // Video sender config.
375 VideoSenderConfig video_sender_config
= GetDefaultVideoSenderConfig();
376 video_sender_config
.max_bitrate
= 2500000;
377 video_sender_config
.min_bitrate
= 2000000;
378 video_sender_config
.start_bitrate
= 2000000;
379 video_sender_config
.min_playout_delay
=
380 video_sender_config
.max_playout_delay
=
381 audio_sender_config
.max_playout_delay
;
382 video_sender_config
.max_frame_rate
= GetIntegerSwitchValue(kMaxFrameRate
, 30);
384 // Video receiver config.
385 FrameReceiverConfig video_receiver_config
=
386 GetDefaultVideoReceiverConfig();
387 video_receiver_config
.rtp_max_delay_ms
=
388 video_sender_config
.max_playout_delay
.InMilliseconds();
390 // Loopback transport.
391 LoopBackTransport
receiver_to_sender(receiver_env
);
392 LoopBackTransport
sender_to_receiver(sender_env
);
395 PacketProxy() : receiver(NULL
) {}
396 void ReceivePacket(scoped_ptr
<Packet
> packet
) {
398 receiver
->ReceivePacket(packet
.Pass());
400 CastReceiver
* receiver
;
403 PacketProxy packet_proxy
;
406 scoped_ptr
<CastTransportSender
> transport_receiver(
407 new CastTransportSenderImpl(
412 make_scoped_ptr(new base::DictionaryValue
),
413 base::Bind(&UpdateCastTransportStatus
),
414 base::Bind(&LogTransportEvents
, receiver_env
),
415 base::TimeDelta::FromSeconds(1),
417 base::Bind(&PacketProxy::ReceivePacket
,
418 base::Unretained(&packet_proxy
)),
419 &receiver_to_sender
));
420 scoped_ptr
<CastReceiver
> cast_receiver(
421 CastReceiver::Create(receiver_env
,
422 audio_receiver_config
,
423 video_receiver_config
,
424 transport_receiver
.get()));
426 packet_proxy
.receiver
= cast_receiver
.get();
428 // Cast sender and transport sender.
429 scoped_ptr
<CastTransportSender
> transport_sender(
430 new CastTransportSenderImpl(
435 make_scoped_ptr(new base::DictionaryValue
),
436 base::Bind(&UpdateCastTransportStatus
),
437 base::Bind(&LogTransportEvents
, sender_env
),
438 base::TimeDelta::FromSeconds(1),
440 PacketReceiverCallback(),
441 &sender_to_receiver
));
442 scoped_ptr
<CastSender
> cast_sender(
443 CastSender::Create(sender_env
, transport_sender
.get()));
445 // Initialize network simulation model.
446 const bool use_network_simulation
=
447 model
.type() == media::cast::proto::INTERRUPTED_POISSON_PROCESS
;
448 scoped_ptr
<test::InterruptedPoissonProcess
> ipp
;
449 if (use_network_simulation
) {
450 LOG(INFO
) << "Running Poisson based network simulation.";
451 const IPPModel
& ipp_model
= model
.ipp();
452 std::vector
<double> average_rates(ipp_model
.average_rate_size());
453 std::copy(ipp_model
.average_rate().begin(),
454 ipp_model
.average_rate().end(),
455 average_rates
.begin());
456 ipp
.reset(new test::InterruptedPoissonProcess(
458 ipp_model
.coef_burstiness(), ipp_model
.coef_variance(), 0));
459 receiver_to_sender
.Initialize(
460 ipp
->NewBuffer(128 * 1024).Pass(),
461 transport_sender
->PacketReceiverForTesting(),
462 task_runner
, &testing_clock
);
463 sender_to_receiver
.Initialize(
464 ipp
->NewBuffer(128 * 1024).Pass(),
465 transport_receiver
->PacketReceiverForTesting(), task_runner
,
468 LOG(INFO
) << "No network simulation.";
469 receiver_to_sender
.Initialize(
470 scoped_ptr
<test::PacketPipe
>(),
471 transport_sender
->PacketReceiverForTesting(),
472 task_runner
, &testing_clock
);
473 sender_to_receiver
.Initialize(
474 scoped_ptr
<test::PacketPipe
>(),
475 transport_receiver
->PacketReceiverForTesting(), task_runner
,
479 // Initialize a fake media source and a tracker to encoded video frames.
480 const bool quality_test
= !metrics_output_path
.empty();
481 FakeMediaSource
media_source(task_runner
,
486 scoped_ptr
<EncodedVideoFrameTracker
> video_frame_tracker
;
488 video_frame_tracker
.reset(new EncodedVideoFrameTracker(&media_source
));
489 sender_env
->Logging()->AddRawEventSubscriber(video_frame_tracker
.get());
492 // Quality metrics computed for each frame decoded.
493 GotVideoFrameOutput metrics_output
;
496 int audio_frame_count
= 0;
497 cast_receiver
->RequestDecodedVideoFrame(
498 base::Bind(&GotVideoFrame
, &metrics_output
, yuv_output_path
,
499 video_frame_tracker
.get(), cast_receiver
.get()));
500 cast_receiver
->RequestDecodedAudioFrame(
501 base::Bind(&GotAudioFrame
, &audio_frame_count
, cast_receiver
.get()));
503 // Initializing audio and video senders.
504 cast_sender
->InitializeAudio(audio_sender_config
,
505 base::Bind(&LogAudioOperationalStatus
));
506 cast_sender
->InitializeVideo(media_source
.get_video_config(),
507 base::Bind(&LogVideoOperationalStatus
),
508 CreateDefaultVideoEncodeAcceleratorCallback(),
509 CreateDefaultVideoEncodeMemoryCallback());
510 task_runner
->RunTasks();
512 // Truncate YUV files to prepare for writing.
513 if (!yuv_output_path
.empty()) {
514 base::ScopedFILE
file(base::OpenFile(yuv_output_path
, "wb"));
516 LOG(ERROR
) << "Cannot save YUV output to file.";
519 LOG(INFO
) << "Writing YUV output to file: " << yuv_output_path
.value();
521 // Write YUV4MPEG2 header.
522 const std::string
header("YUV4MPEG2 W1280 H720 F30000:1001 Ip A1:1 C420\n");
523 AppendToFile(yuv_output_path
, header
.data(), header
.size());
527 if (!source_path
.empty()) {
528 // 0 means using the FPS from the file.
529 media_source
.SetSourceFile(source_path
,
530 GetIntegerSwitchValue(kSourceFrameRate
, 0));
532 media_source
.Start(cast_sender
->audio_frame_input(),
533 cast_sender
->video_frame_input());
535 // By default runs simulation for 3 minutes or the desired duration
536 // by using --run-time= flag.
537 base::TimeDelta elapsed_time
;
538 const base::TimeDelta desired_run_time
=
539 base::TimeDelta::FromSeconds(GetIntegerSwitchValue(kRunTime
, 180));
540 while (elapsed_time
< desired_run_time
) {
541 // Each step is 100us.
542 base::TimeDelta step
= base::TimeDelta::FromMicroseconds(100);
543 task_runner
->Sleep(step
);
544 elapsed_time
+= step
;
547 // Get event logs for audio and video.
548 media::cast::proto::LogMetadata audio_metadata
, video_metadata
;
549 media::cast::FrameEventList audio_frame_events
, video_frame_events
;
550 media::cast::PacketEventList audio_packet_events
, video_packet_events
;
551 audio_metadata
.set_extra_data(extra_data
);
552 video_metadata
.set_extra_data(extra_data
);
553 audio_event_subscriber
.GetEventsAndReset(
554 &audio_metadata
, &audio_frame_events
, &audio_packet_events
);
555 video_event_subscriber
.GetEventsAndReset(
556 &video_metadata
, &video_frame_events
, &video_packet_events
);
558 // Print simulation results.
560 // Compute and print statistics for video:
562 // * Total video frames captured.
563 // * Total video frames encoded.
564 // * Total video frames dropped.
565 // * Total video frames received late.
566 // * Average target bitrate.
567 // * Average encoded bitrate.
568 int total_video_frames
= 0;
569 int encoded_video_frames
= 0;
570 int dropped_video_frames
= 0;
571 int late_video_frames
= 0;
572 int64 total_delay_of_late_frames_ms
= 0;
573 int64 encoded_size
= 0;
574 int64 target_bitrate
= 0;
575 for (size_t i
= 0; i
< video_frame_events
.size(); ++i
) {
576 const media::cast::proto::AggregatedFrameEvent
& event
=
577 *video_frame_events
[i
];
578 ++total_video_frames
;
579 if (event
.has_encoded_frame_size()) {
580 ++encoded_video_frames
;
581 encoded_size
+= event
.encoded_frame_size();
582 target_bitrate
+= event
.target_bitrate();
584 ++dropped_video_frames
;
586 if (event
.has_delay_millis() && event
.delay_millis() < 0) {
588 total_delay_of_late_frames_ms
+= -event
.delay_millis();
592 // Subtract fraction of dropped frames from |elapsed_time| before estimating
593 // the average encoded bitrate.
594 const base::TimeDelta elapsed_time_undropped
=
595 total_video_frames
<= 0 ? base::TimeDelta() :
596 (elapsed_time
* (total_video_frames
- dropped_video_frames
) /
598 const double avg_encoded_bitrate
=
599 elapsed_time_undropped
<= base::TimeDelta() ? 0 :
600 8.0 * encoded_size
/ elapsed_time_undropped
.InSecondsF() / 1000;
601 double avg_target_bitrate
=
602 !encoded_video_frames
? 0 : target_bitrate
/ encoded_video_frames
/ 1000;
604 LOG(INFO
) << "Configured target playout delay (ms): "
605 << video_receiver_config
.rtp_max_delay_ms
;
606 LOG(INFO
) << "Audio frame count: " << audio_frame_count
;
607 LOG(INFO
) << "Inserted video frames: " << total_video_frames
;
608 LOG(INFO
) << "Decoded video frames: " << metrics_output
.counter
;
609 LOG(INFO
) << "Dropped video frames: " << dropped_video_frames
;
610 LOG(INFO
) << "Late video frames: " << late_video_frames
611 << " (average lateness: "
612 << (late_video_frames
> 0 ?
613 static_cast<double>(total_delay_of_late_frames_ms
) /
617 LOG(INFO
) << "Average encoded bitrate (kbps): " << avg_encoded_bitrate
;
618 LOG(INFO
) << "Average target bitrate (kbps): " << avg_target_bitrate
;
619 LOG(INFO
) << "Writing log: " << log_output_path
.value();
621 // Truncate file and then write serialized log.
623 base::ScopedFILE
file(base::OpenFile(log_output_path
, "wb"));
625 LOG(INFO
) << "Cannot write to log.";
629 AppendLogToFile(&video_metadata
, video_frame_events
, video_packet_events
,
631 AppendLogToFile(&audio_metadata
, audio_frame_events
, audio_packet_events
,
634 // Write quality metrics.
636 LOG(INFO
) << "Writing quality metrics: " << metrics_output_path
.value();
638 for (size_t i
= 0; i
< metrics_output
.psnr
.size() &&
639 i
< metrics_output
.ssim
.size(); ++i
) {
640 base::StringAppendF(&line
, "%f %f\n", metrics_output
.psnr
[i
],
641 metrics_output
.ssim
[i
]);
643 WriteFile(metrics_output_path
, line
.data(), line
.length());
647 NetworkSimulationModel
DefaultModel() {
648 NetworkSimulationModel model
;
649 model
.set_type(cast::proto::INTERRUPTED_POISSON_PROCESS
);
650 IPPModel
* ipp
= model
.mutable_ipp();
651 ipp
->set_coef_burstiness(0.609);
652 ipp
->set_coef_variance(4.1);
654 ipp
->add_average_rate(0.609);
655 ipp
->add_average_rate(0.495);
656 ipp
->add_average_rate(0.561);
657 ipp
->add_average_rate(0.458);
658 ipp
->add_average_rate(0.538);
659 ipp
->add_average_rate(0.513);
660 ipp
->add_average_rate(0.585);
661 ipp
->add_average_rate(0.592);
662 ipp
->add_average_rate(0.658);
663 ipp
->add_average_rate(0.556);
664 ipp
->add_average_rate(0.371);
665 ipp
->add_average_rate(0.595);
666 ipp
->add_average_rate(0.490);
667 ipp
->add_average_rate(0.980);
668 ipp
->add_average_rate(0.781);
669 ipp
->add_average_rate(0.463);
674 bool IsModelValid(const NetworkSimulationModel
& model
) {
675 if (!model
.has_type())
677 NetworkSimulationModelType type
= model
.type();
678 if (type
== media::cast::proto::INTERRUPTED_POISSON_PROCESS
) {
679 if (!model
.has_ipp())
681 const IPPModel
& ipp
= model
.ipp();
682 if (ipp
.coef_burstiness() <= 0.0 || ipp
.coef_variance() <= 0.0)
684 if (ipp
.average_rate_size() == 0)
686 for (int i
= 0; i
< ipp
.average_rate_size(); i
++) {
687 if (ipp
.average_rate(i
) <= 0.0)
695 NetworkSimulationModel
LoadModel(const base::FilePath
& model_path
) {
696 if (base::CommandLine::ForCurrentProcess()->HasSwitch(kNoSimulation
)) {
697 NetworkSimulationModel model
;
698 model
.set_type(media::cast::proto::NO_SIMULATION
);
701 if (model_path
.empty()) {
702 LOG(ERROR
) << "Model path not set; Using default model.";
703 return DefaultModel();
705 std::string model_str
;
706 if (!base::ReadFileToString(model_path
, &model_str
)) {
707 LOG(ERROR
) << "Failed to read model file.";
708 return DefaultModel();
711 NetworkSimulationModel model
;
712 if (!model
.ParseFromString(model_str
)) {
713 LOG(ERROR
) << "Failed to parse model.";
714 return DefaultModel();
716 if (!IsModelValid(model
)) {
717 LOG(ERROR
) << "Invalid model.";
718 return DefaultModel();
728 int main(int argc
, char** argv
) {
729 base::AtExitManager at_exit
;
730 base::CommandLine::Init(argc
, argv
);
731 InitLogging(logging::LoggingSettings());
733 const base::CommandLine
* cmd
= base::CommandLine::ForCurrentProcess();
734 base::FilePath media_path
= cmd
->GetSwitchValuePath(media::cast::kLibDir
);
735 if (media_path
.empty()) {
736 if (!PathService::Get(base::DIR_MODULE
, &media_path
)) {
737 LOG(ERROR
) << "Failed to load FFmpeg.";
742 media::InitializeMediaLibrary();
744 base::FilePath source_path
= cmd
->GetSwitchValuePath(
745 media::cast::kSourcePath
);
746 base::FilePath log_output_path
= cmd
->GetSwitchValuePath(
747 media::cast::kOutputPath
);
748 if (log_output_path
.empty()) {
749 base::GetTempDir(&log_output_path
);
750 log_output_path
= log_output_path
.AppendASCII("sim-events.gz");
752 base::FilePath metrics_output_path
= cmd
->GetSwitchValuePath(
753 media::cast::kMetricsOutputPath
);
754 base::FilePath yuv_output_path
= cmd
->GetSwitchValuePath(
755 media::cast::kYuvOutputPath
);
756 std::string sim_id
= cmd
->GetSwitchValueASCII(media::cast::kSimulationId
);
758 NetworkSimulationModel model
= media::cast::LoadModel(
759 cmd
->GetSwitchValuePath(media::cast::kModelPath
));
761 base::DictionaryValue values
;
762 values
.SetBoolean("sim", true);
763 values
.SetString("sim-id", sim_id
);
765 std::string extra_data
;
766 base::JSONWriter::Write(values
, &extra_data
);
769 media::cast::RunSimulation(source_path
, log_output_path
, metrics_output_path
,
770 yuv_output_path
, extra_data
, model
);