simulator.cc 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715
  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.
  4. // Simulate end to end streaming.
  5. //
  6. // Input:
  7. // --source=
  8. // WebM used as the source of video and audio frames.
  9. // --output=
  10. // File path to writing out the raw event log of the simulation session.
  11. // --sim-id=
  12. // Unique simulation ID.
  13. // --target-delay-ms=
  14. // Target playout delay to configure (integer number of milliseconds).
  15. // Optional; default is 400.
  16. // --max-frame-rate=
  17. // The maximum frame rate allowed at any time during the Cast session.
  18. // Optional; default is 30.
  19. // --source-frame-rate=
  20. // Overrides the playback rate; the source video will play faster/slower.
  21. // --run-time=
  22. // In seconds, how long the Cast session runs for.
  23. // Optional; default is 180.
  24. // --metrics-output=
  25. // File path to write PSNR and SSIM metrics between source frames and
  26. // decoded frames. Assumes all encoded frames are decoded.
  27. // --yuv-output=
  28. // File path to write YUV decoded frames in YUV4MPEG2 format.
  29. // --no-simulation
  30. // Do not run network simulation.
  31. //
  32. // Output:
  33. // - Raw event log of the simulation session tagged with the unique test ID,
  34. // written out to the specified file path.
  35. #include <stddef.h>
  36. #include <stdint.h>
  37. #include <memory>
  38. #include <utility>
  39. #include "base/at_exit.h"
  40. #include "base/base_paths.h"
  41. #include "base/bind.h"
  42. #include "base/callback_helpers.h"
  43. #include "base/command_line.h"
  44. #include "base/containers/queue.h"
  45. #include "base/containers/span.h"
  46. #include "base/files/file_path.h"
  47. #include "base/files/file_util.h"
  48. #include "base/files/memory_mapped_file.h"
  49. #include "base/files/scoped_file.h"
  50. #include "base/json/json_writer.h"
  51. #include "base/logging.h"
  52. #include "base/memory/ptr_util.h"
  53. #include "base/memory/raw_ptr.h"
  54. #include "base/path_service.h"
  55. #include "base/strings/string_number_conversions.h"
  56. #include "base/strings/stringprintf.h"
  57. #include "base/test/simple_test_tick_clock.h"
  58. #include "base/threading/thread_task_runner_handle.h"
  59. #include "base/time/tick_clock.h"
  60. #include "base/time/time.h"
  61. #include "base/values.h"
  62. #include "media/base/audio_bus.h"
  63. #include "media/base/fake_single_thread_task_runner.h"
  64. #include "media/base/media.h"
  65. #include "media/base/video_frame.h"
  66. #include "media/cast/cast_config.h"
  67. #include "media/cast/cast_environment.h"
  68. #include "media/cast/cast_sender.h"
  69. #include "media/cast/logging/encoding_event_subscriber.h"
  70. #include "media/cast/logging/logging_defines.h"
  71. #include "media/cast/logging/proto/raw_events.pb.h"
  72. #include "media/cast/logging/raw_event_subscriber_bundle.h"
  73. #include "media/cast/logging/simple_event_subscriber.h"
  74. #include "media/cast/net/cast_transport.h"
  75. #include "media/cast/net/cast_transport_config.h"
  76. #include "media/cast/net/cast_transport_defines.h"
  77. #include "media/cast/net/cast_transport_impl.h"
  78. #include "media/cast/test/fake_media_source.h"
  79. #include "media/cast/test/loopback_transport.h"
  80. #include "media/cast/test/proto/network_simulation_model.pb.h"
  81. #include "media/cast/test/receiver/cast_receiver.h"
  82. #include "media/cast/test/skewed_tick_clock.h"
  83. #include "media/cast/test/utility/audio_utility.h"
  84. #include "media/cast/test/utility/default_config.h"
  85. #include "media/cast/test/utility/test_util.h"
  86. #include "media/cast/test/utility/udp_proxy.h"
  87. #include "media/cast/test/utility/video_utility.h"
  88. using media::cast::proto::IPPModel;
  89. using media::cast::proto::NetworkSimulationModel;
  90. using media::cast::proto::NetworkSimulationModelType;
  91. namespace media {
  92. namespace cast {
  93. namespace {
  94. const char kLibDir[] = "lib-dir";
  95. const char kModelPath[] = "model";
  96. const char kMetricsOutputPath[] = "metrics-output";
  97. const char kOutputPath[] = "output";
  98. const char kMaxFrameRate[] = "max-frame-rate";
  99. const char kNoSimulation[] = "no-simulation";
  100. const char kRunTime[] = "run-time";
  101. const char kSimulationId[] = "sim-id";
  102. const char kSourcePath[] = "source";
  103. const char kSourceFrameRate[] = "source-frame-rate";
  104. const char kTargetDelay[] = "target-delay-ms";
  105. const char kYuvOutputPath[] = "yuv-output";
  106. int GetIntegerSwitchValue(const char* switch_name, int default_value) {
  107. const std::string as_str =
  108. base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(switch_name);
  109. if (as_str.empty())
  110. return default_value;
  111. int as_int;
  112. CHECK(base::StringToInt(as_str, &as_int));
  113. CHECK_GT(as_int, 0);
  114. return as_int;
  115. }
  116. void LogAudioOperationalStatus(OperationalStatus status) {
  117. LOG(INFO) << "Audio status: " << status;
  118. }
  119. void LogVideoOperationalStatus(OperationalStatus status) {
  120. LOG(INFO) << "Video status: " << status;
  121. }
  122. struct PacketProxy {
  123. PacketProxy() : receiver(nullptr) {}
  124. void ReceivePacket(std::unique_ptr<Packet> packet) {
  125. if (receiver)
  126. receiver->ReceivePacket(std::move(packet));
  127. }
  128. raw_ptr<CastReceiver> receiver;
  129. };
  130. class TransportClient : public CastTransport::Client {
  131. public:
  132. TransportClient(LogEventDispatcher* log_event_dispatcher,
  133. PacketProxy* packet_proxy)
  134. : log_event_dispatcher_(log_event_dispatcher),
  135. packet_proxy_(packet_proxy) {}
  136. TransportClient(const TransportClient&) = delete;
  137. TransportClient& operator=(const TransportClient&) = delete;
  138. void OnStatusChanged(CastTransportStatus status) final {
  139. LOG(INFO) << "Cast transport status: " << status;
  140. }
  141. void OnLoggingEventsReceived(
  142. std::unique_ptr<std::vector<FrameEvent>> frame_events,
  143. std::unique_ptr<std::vector<PacketEvent>> packet_events) final {
  144. DCHECK(log_event_dispatcher_);
  145. log_event_dispatcher_->DispatchBatchOfEvents(std::move(frame_events),
  146. std::move(packet_events));
  147. }
  148. void ProcessRtpPacket(std::unique_ptr<Packet> packet) final {
  149. if (packet_proxy_)
  150. packet_proxy_->ReceivePacket(std::move(packet));
  151. }
  152. private:
  153. const raw_ptr<LogEventDispatcher>
  154. log_event_dispatcher_; // Not owned by this class.
  155. const raw_ptr<PacketProxy> packet_proxy_; // Not owned by this class.
  156. };
  157. // Maintains a queue of encoded video frames.
  158. // This works by tracking FRAME_CAPTURE_END and FRAME_ENCODED events.
  159. // If a video frame is detected to be encoded it transfers a frame
  160. // from FakeMediaSource to its internal queue. Otherwise it drops a
  161. // frame from FakeMediaSource.
  162. class EncodedVideoFrameTracker final : public RawEventSubscriber {
  163. public:
  164. EncodedVideoFrameTracker(FakeMediaSource* media_source)
  165. : media_source_(media_source),
  166. last_frame_event_type_(UNKNOWN) {}
  167. EncodedVideoFrameTracker(const EncodedVideoFrameTracker&) = delete;
  168. EncodedVideoFrameTracker& operator=(const EncodedVideoFrameTracker&) = delete;
  169. ~EncodedVideoFrameTracker() override = default;
  170. // RawEventSubscriber implementations.
  171. void OnReceiveFrameEvent(const FrameEvent& frame_event) override {
  172. // This method only cares about video FRAME_CAPTURE_END and
  173. // FRAME_ENCODED events.
  174. if (frame_event.media_type != VIDEO_EVENT) {
  175. return;
  176. }
  177. if (frame_event.type != FRAME_CAPTURE_END &&
  178. frame_event.type != FRAME_ENCODED) {
  179. return;
  180. }
  181. // If there are two consecutive FRAME_CAPTURE_END events that means
  182. // a frame is dropped.
  183. if (last_frame_event_type_ == FRAME_CAPTURE_END &&
  184. frame_event.type == FRAME_CAPTURE_END) {
  185. media_source_->PopOldestInsertedVideoFrame();
  186. }
  187. if (frame_event.type == FRAME_ENCODED) {
  188. video_frames_.push(media_source_->PopOldestInsertedVideoFrame());
  189. }
  190. last_frame_event_type_ = frame_event.type;
  191. }
  192. void OnReceivePacketEvent(const PacketEvent& packet_event) override {
  193. // Don't care.
  194. }
  195. scoped_refptr<media::VideoFrame> PopOldestEncodedFrame() {
  196. CHECK(!video_frames_.empty());
  197. scoped_refptr<media::VideoFrame> video_frame = video_frames_.front();
  198. video_frames_.pop();
  199. return video_frame;
  200. }
  201. private:
  202. raw_ptr<FakeMediaSource> media_source_;
  203. CastLoggingEvent last_frame_event_type_;
  204. base::queue<scoped_refptr<media::VideoFrame>> video_frames_;
  205. };
  206. // Appends a YUV frame in I420 format to the file located at |path|.
  207. void AppendYuvToFile(const base::FilePath& path,
  208. scoped_refptr<media::VideoFrame> frame) {
  209. // Write YUV420 format to file.
  210. std::string header;
  211. base::StringAppendF(
  212. &header, "FRAME W%d H%d\n",
  213. frame->coded_size().width(),
  214. frame->coded_size().height());
  215. AppendToFile(path, header);
  216. AppendToFile(path,
  217. base::make_span(frame->data(media::VideoFrame::kYPlane),
  218. frame->stride(media::VideoFrame::kYPlane) *
  219. frame->rows(media::VideoFrame::kYPlane)));
  220. AppendToFile(path,
  221. base::make_span(frame->data(media::VideoFrame::kUPlane),
  222. frame->stride(media::VideoFrame::kUPlane) *
  223. frame->rows(media::VideoFrame::kUPlane)));
  224. AppendToFile(path,
  225. base::make_span(frame->data(media::VideoFrame::kVPlane),
  226. frame->stride(media::VideoFrame::kVPlane) *
  227. frame->rows(media::VideoFrame::kVPlane)));
  228. }
  229. // A container to save output of GotVideoFrame() for computation based
  230. // on output frames.
  231. struct GotVideoFrameOutput {
  232. GotVideoFrameOutput() : counter(0) {}
  233. int counter;
  234. std::vector<double> psnr;
  235. std::vector<double> ssim;
  236. };
  237. void GotVideoFrame(GotVideoFrameOutput* metrics_output,
  238. const base::FilePath& yuv_output,
  239. EncodedVideoFrameTracker* video_frame_tracker,
  240. CastReceiver* cast_receiver,
  241. scoped_refptr<media::VideoFrame> video_frame,
  242. base::TimeTicks render_time,
  243. bool continuous) {
  244. ++metrics_output->counter;
  245. cast_receiver->RequestDecodedVideoFrame(
  246. base::BindRepeating(&GotVideoFrame, metrics_output, yuv_output,
  247. video_frame_tracker, cast_receiver));
  248. // If |video_frame_tracker| is available that means we're computing
  249. // quality metrices.
  250. if (video_frame_tracker) {
  251. scoped_refptr<media::VideoFrame> src_frame =
  252. video_frame_tracker->PopOldestEncodedFrame();
  253. metrics_output->psnr.push_back(I420PSNR(*src_frame, *video_frame));
  254. metrics_output->ssim.push_back(I420SSIM(*src_frame, *video_frame));
  255. }
  256. if (!yuv_output.empty()) {
  257. AppendYuvToFile(yuv_output, std::move(video_frame));
  258. }
  259. }
  260. void GotAudioFrame(int* counter,
  261. CastReceiver* cast_receiver,
  262. std::unique_ptr<AudioBus> audio_bus,
  263. base::TimeTicks playout_time,
  264. bool is_continuous) {
  265. ++*counter;
  266. cast_receiver->RequestDecodedAudioFrame(
  267. base::BindRepeating(&GotAudioFrame, counter, cast_receiver));
  268. }
  269. // Run simulation once.
  270. //
  271. // |log_output_path| is the path to write serialized log.
  272. // |extra_data| is extra tagging information to write to log.
  273. void RunSimulation(const base::FilePath& source_path,
  274. const base::FilePath& log_output_path,
  275. const base::FilePath& metrics_output_path,
  276. const base::FilePath& yuv_output_path,
  277. const std::string& extra_data,
  278. const NetworkSimulationModel& model) {
  279. // Fake clock. Make sure start time is non zero.
  280. base::SimpleTestTickClock testing_clock;
  281. testing_clock.Advance(base::Seconds(1));
  282. // Task runner.
  283. scoped_refptr<FakeSingleThreadTaskRunner> task_runner =
  284. new FakeSingleThreadTaskRunner(&testing_clock);
  285. base::ThreadTaskRunnerHandle task_runner_handle(task_runner);
  286. // CastEnvironments.
  287. test::SkewedTickClock sender_clock(&testing_clock);
  288. scoped_refptr<CastEnvironment> sender_env =
  289. new CastEnvironment(&sender_clock, task_runner, task_runner, task_runner);
  290. test::SkewedTickClock receiver_clock(&testing_clock);
  291. scoped_refptr<CastEnvironment> receiver_env = new CastEnvironment(
  292. &receiver_clock, task_runner, task_runner, task_runner);
  293. // Event subscriber. Store at most 1 hour of events.
  294. EncodingEventSubscriber audio_event_subscriber(AUDIO_EVENT,
  295. 100 * 60 * 60);
  296. EncodingEventSubscriber video_event_subscriber(VIDEO_EVENT,
  297. 30 * 60 * 60);
  298. sender_env->logger()->Subscribe(&audio_event_subscriber);
  299. sender_env->logger()->Subscribe(&video_event_subscriber);
  300. // Audio sender config.
  301. FrameSenderConfig audio_sender_config = GetDefaultAudioSenderConfig();
  302. audio_sender_config.min_playout_delay =
  303. audio_sender_config.max_playout_delay =
  304. base::Milliseconds(GetIntegerSwitchValue(kTargetDelay, 400));
  305. // Audio receiver config.
  306. FrameReceiverConfig audio_receiver_config =
  307. GetDefaultAudioReceiverConfig();
  308. audio_receiver_config.rtp_max_delay_ms =
  309. audio_sender_config.max_playout_delay.InMilliseconds();
  310. // Video sender config.
  311. FrameSenderConfig video_sender_config = GetDefaultVideoSenderConfig();
  312. video_sender_config.max_bitrate = 2500000;
  313. video_sender_config.min_bitrate = 2000000;
  314. video_sender_config.start_bitrate = 2000000;
  315. video_sender_config.min_playout_delay =
  316. video_sender_config.max_playout_delay =
  317. audio_sender_config.max_playout_delay;
  318. video_sender_config.max_frame_rate = GetIntegerSwitchValue(kMaxFrameRate, 30);
  319. // Video receiver config.
  320. FrameReceiverConfig video_receiver_config =
  321. GetDefaultVideoReceiverConfig();
  322. video_receiver_config.rtp_max_delay_ms =
  323. video_sender_config.max_playout_delay.InMilliseconds();
  324. // Loopback transport. Owned by CastTransport.
  325. LoopBackTransport* receiver_to_sender = new LoopBackTransport(receiver_env);
  326. LoopBackTransport* sender_to_receiver = new LoopBackTransport(sender_env);
  327. PacketProxy packet_proxy;
  328. // Cast receiver.
  329. std::unique_ptr<CastTransport> transport_receiver(new CastTransportImpl(
  330. &testing_clock, base::Seconds(1),
  331. std::make_unique<TransportClient>(receiver_env->logger(), &packet_proxy),
  332. base::WrapUnique(receiver_to_sender), task_runner));
  333. std::unique_ptr<CastReceiver> cast_receiver(
  334. CastReceiver::Create(receiver_env, audio_receiver_config,
  335. video_receiver_config, transport_receiver.get()));
  336. packet_proxy.receiver = cast_receiver.get();
  337. // Cast sender and transport sender.
  338. std::unique_ptr<CastTransport> transport_sender(new CastTransportImpl(
  339. &testing_clock, base::Seconds(1),
  340. std::make_unique<TransportClient>(sender_env->logger(), nullptr),
  341. base::WrapUnique(sender_to_receiver), task_runner));
  342. std::unique_ptr<CastSender> cast_sender(
  343. CastSender::Create(sender_env, transport_sender.get()));
  344. // Initialize network simulation model.
  345. const bool use_network_simulation =
  346. model.type() == media::cast::proto::INTERRUPTED_POISSON_PROCESS;
  347. std::unique_ptr<test::InterruptedPoissonProcess> ipp;
  348. if (use_network_simulation) {
  349. LOG(INFO) << "Running Poisson based network simulation.";
  350. const IPPModel& ipp_model = model.ipp();
  351. std::vector<double> average_rates(ipp_model.average_rate_size());
  352. std::copy(ipp_model.average_rate().begin(),
  353. ipp_model.average_rate().end(),
  354. average_rates.begin());
  355. ipp = std::make_unique<test::InterruptedPoissonProcess>(
  356. average_rates, ipp_model.coef_burstiness(), ipp_model.coef_variance(),
  357. 0);
  358. receiver_to_sender->Initialize(ipp->NewBuffer(128 * 1024),
  359. transport_sender->PacketReceiverForTesting(),
  360. task_runner, &testing_clock);
  361. sender_to_receiver->Initialize(
  362. ipp->NewBuffer(128 * 1024),
  363. transport_receiver->PacketReceiverForTesting(), task_runner,
  364. &testing_clock);
  365. } else {
  366. LOG(INFO) << "No network simulation.";
  367. receiver_to_sender->Initialize(std::unique_ptr<test::PacketPipe>(),
  368. transport_sender->PacketReceiverForTesting(),
  369. task_runner, &testing_clock);
  370. sender_to_receiver->Initialize(
  371. std::unique_ptr<test::PacketPipe>(),
  372. transport_receiver->PacketReceiverForTesting(), task_runner,
  373. &testing_clock);
  374. }
  375. // Initialize a fake media source and a tracker to encoded video frames.
  376. const bool quality_test = !metrics_output_path.empty();
  377. FakeMediaSource media_source(task_runner,
  378. &testing_clock,
  379. audio_sender_config,
  380. video_sender_config,
  381. quality_test);
  382. std::unique_ptr<EncodedVideoFrameTracker> video_frame_tracker;
  383. if (quality_test) {
  384. video_frame_tracker =
  385. std::make_unique<EncodedVideoFrameTracker>(&media_source);
  386. sender_env->logger()->Subscribe(video_frame_tracker.get());
  387. }
  388. // Quality metrics computed for each frame decoded.
  389. GotVideoFrameOutput metrics_output;
  390. // Start receiver.
  391. int audio_frame_count = 0;
  392. cast_receiver->RequestDecodedVideoFrame(
  393. base::BindRepeating(&GotVideoFrame, &metrics_output, yuv_output_path,
  394. video_frame_tracker.get(), cast_receiver.get()));
  395. cast_receiver->RequestDecodedAudioFrame(base::BindRepeating(
  396. &GotAudioFrame, &audio_frame_count, cast_receiver.get()));
  397. // Initializing audio and video senders.
  398. cast_sender->InitializeAudio(audio_sender_config,
  399. base::BindOnce(&LogAudioOperationalStatus));
  400. cast_sender->InitializeVideo(media_source.get_video_config(),
  401. base::BindRepeating(&LogVideoOperationalStatus),
  402. base::DoNothing());
  403. task_runner->RunTasks();
  404. // Truncate YUV files to prepare for writing.
  405. if (!yuv_output_path.empty()) {
  406. base::ScopedFILE file(base::OpenFile(yuv_output_path, "wb"));
  407. if (!file.get()) {
  408. LOG(ERROR) << "Cannot save YUV output to file.";
  409. return;
  410. }
  411. LOG(INFO) << "Writing YUV output to file: " << yuv_output_path.value();
  412. // Write YUV4MPEG2 header.
  413. const std::string header("YUV4MPEG2 W1280 H720 F30000:1001 Ip A1:1 C420\n");
  414. AppendToFile(yuv_output_path, header);
  415. }
  416. // Start sending.
  417. if (!source_path.empty()) {
  418. // 0 means using the FPS from the file.
  419. media_source.SetSourceFile(source_path,
  420. GetIntegerSwitchValue(kSourceFrameRate, 0));
  421. }
  422. media_source.Start(cast_sender->audio_frame_input(),
  423. cast_sender->video_frame_input());
  424. // By default runs simulation for 3 minutes or the desired duration
  425. // by using --run-time= flag.
  426. base::TimeDelta elapsed_time;
  427. const base::TimeDelta desired_run_time =
  428. base::Seconds(GetIntegerSwitchValue(kRunTime, 180));
  429. while (elapsed_time < desired_run_time) {
  430. // Each step is 100us.
  431. base::TimeDelta step = base::Microseconds(100);
  432. task_runner->Sleep(step);
  433. elapsed_time += step;
  434. }
  435. // Unsubscribe from logging events.
  436. sender_env->logger()->Unsubscribe(&audio_event_subscriber);
  437. sender_env->logger()->Unsubscribe(&video_event_subscriber);
  438. if (quality_test)
  439. sender_env->logger()->Unsubscribe(video_frame_tracker.get());
  440. // Get event logs for audio and video.
  441. media::cast::proto::LogMetadata audio_metadata, video_metadata;
  442. media::cast::FrameEventList audio_frame_events, video_frame_events;
  443. media::cast::PacketEventList audio_packet_events, video_packet_events;
  444. audio_metadata.set_extra_data(extra_data);
  445. video_metadata.set_extra_data(extra_data);
  446. audio_event_subscriber.GetEventsAndReset(
  447. &audio_metadata, &audio_frame_events, &audio_packet_events);
  448. video_event_subscriber.GetEventsAndReset(
  449. &video_metadata, &video_frame_events, &video_packet_events);
  450. // Print simulation results.
  451. // Compute and print statistics for video:
  452. //
  453. // * Total video frames captured.
  454. // * Total video frames encoded.
  455. // * Total video frames dropped.
  456. // * Total video frames received late.
  457. // * Average target bitrate.
  458. // * Average encoded bitrate.
  459. int total_video_frames = 0;
  460. int encoded_video_frames = 0;
  461. int dropped_video_frames = 0;
  462. int late_video_frames = 0;
  463. int64_t total_delay_of_late_frames_ms = 0;
  464. int64_t encoded_size = 0;
  465. int64_t target_bitrate = 0;
  466. for (size_t i = 0; i < video_frame_events.size(); ++i) {
  467. const media::cast::proto::AggregatedFrameEvent& event =
  468. *video_frame_events[i];
  469. ++total_video_frames;
  470. if (event.has_encoded_frame_size()) {
  471. ++encoded_video_frames;
  472. encoded_size += event.encoded_frame_size();
  473. target_bitrate += event.target_bitrate();
  474. } else {
  475. ++dropped_video_frames;
  476. }
  477. if (event.has_delay_millis() && event.delay_millis() < 0) {
  478. ++late_video_frames;
  479. total_delay_of_late_frames_ms += -event.delay_millis();
  480. }
  481. }
  482. // Subtract fraction of dropped frames from |elapsed_time| before estimating
  483. // the average encoded bitrate.
  484. const base::TimeDelta elapsed_time_undropped =
  485. total_video_frames <= 0
  486. ? base::TimeDelta()
  487. : (elapsed_time * (total_video_frames - dropped_video_frames) /
  488. total_video_frames);
  489. constexpr double kKilobitsPerByte = 8.0 / 1000;
  490. const double avg_encoded_bitrate =
  491. elapsed_time_undropped <= base::TimeDelta()
  492. ? 0
  493. : encoded_size * kKilobitsPerByte * elapsed_time_undropped.ToHz();
  494. double avg_target_bitrate =
  495. encoded_video_frames ? target_bitrate / encoded_video_frames / 1000 : 0;
  496. LOG(INFO) << "Configured target playout delay (ms): "
  497. << video_receiver_config.rtp_max_delay_ms;
  498. LOG(INFO) << "Audio frame count: " << audio_frame_count;
  499. LOG(INFO) << "Inserted video frames: " << total_video_frames;
  500. LOG(INFO) << "Decoded video frames: " << metrics_output.counter;
  501. LOG(INFO) << "Dropped video frames: " << dropped_video_frames;
  502. LOG(INFO) << "Late video frames: " << late_video_frames
  503. << " (average lateness: "
  504. << (late_video_frames > 0 ?
  505. static_cast<double>(total_delay_of_late_frames_ms) /
  506. late_video_frames :
  507. 0)
  508. << " ms)";
  509. LOG(INFO) << "Average encoded bitrate (kbps): " << avg_encoded_bitrate;
  510. LOG(INFO) << "Average target bitrate (kbps): " << avg_target_bitrate;
  511. LOG(INFO) << "Writing log: " << log_output_path.value();
  512. // Truncate file and then write serialized log.
  513. {
  514. base::ScopedFILE file(base::OpenFile(log_output_path, "wb"));
  515. if (!file.get()) {
  516. LOG(INFO) << "Cannot write to log.";
  517. return;
  518. }
  519. }
  520. // Write quality metrics.
  521. if (quality_test) {
  522. LOG(INFO) << "Writing quality metrics: " << metrics_output_path.value();
  523. std::string line;
  524. for (size_t i = 0; i < metrics_output.psnr.size() &&
  525. i < metrics_output.ssim.size(); ++i) {
  526. base::StringAppendF(&line, "%f %f\n", metrics_output.psnr[i],
  527. metrics_output.ssim[i]);
  528. }
  529. WriteFile(metrics_output_path, line.data(), line.length());
  530. }
  531. }
  532. NetworkSimulationModel DefaultModel() {
  533. NetworkSimulationModel model;
  534. model.set_type(cast::proto::INTERRUPTED_POISSON_PROCESS);
  535. IPPModel* ipp = model.mutable_ipp();
  536. ipp->set_coef_burstiness(0.609);
  537. ipp->set_coef_variance(4.1);
  538. ipp->add_average_rate(0.609);
  539. ipp->add_average_rate(0.495);
  540. ipp->add_average_rate(0.561);
  541. ipp->add_average_rate(0.458);
  542. ipp->add_average_rate(0.538);
  543. ipp->add_average_rate(0.513);
  544. ipp->add_average_rate(0.585);
  545. ipp->add_average_rate(0.592);
  546. ipp->add_average_rate(0.658);
  547. ipp->add_average_rate(0.556);
  548. ipp->add_average_rate(0.371);
  549. ipp->add_average_rate(0.595);
  550. ipp->add_average_rate(0.490);
  551. ipp->add_average_rate(0.980);
  552. ipp->add_average_rate(0.781);
  553. ipp->add_average_rate(0.463);
  554. return model;
  555. }
  556. bool IsModelValid(const NetworkSimulationModel& model) {
  557. if (!model.has_type())
  558. return false;
  559. NetworkSimulationModelType type = model.type();
  560. if (type == media::cast::proto::INTERRUPTED_POISSON_PROCESS) {
  561. if (!model.has_ipp())
  562. return false;
  563. const IPPModel& ipp = model.ipp();
  564. if (ipp.coef_burstiness() <= 0.0 || ipp.coef_variance() <= 0.0)
  565. return false;
  566. if (ipp.average_rate_size() == 0)
  567. return false;
  568. for (int i = 0; i < ipp.average_rate_size(); i++) {
  569. if (ipp.average_rate(i) <= 0.0)
  570. return false;
  571. }
  572. }
  573. return true;
  574. }
  575. NetworkSimulationModel LoadModel(const base::FilePath& model_path) {
  576. if (base::CommandLine::ForCurrentProcess()->HasSwitch(kNoSimulation)) {
  577. NetworkSimulationModel model;
  578. model.set_type(media::cast::proto::NO_SIMULATION);
  579. return model;
  580. }
  581. if (model_path.empty()) {
  582. LOG(ERROR) << "Model path not set; Using default model.";
  583. return DefaultModel();
  584. }
  585. std::string model_str;
  586. if (!base::ReadFileToString(model_path, &model_str)) {
  587. LOG(ERROR) << "Failed to read model file.";
  588. return DefaultModel();
  589. }
  590. NetworkSimulationModel model;
  591. if (!model.ParseFromString(model_str)) {
  592. LOG(ERROR) << "Failed to parse model.";
  593. return DefaultModel();
  594. }
  595. if (!IsModelValid(model)) {
  596. LOG(ERROR) << "Invalid model.";
  597. return DefaultModel();
  598. }
  599. return model;
  600. }
  601. } // namespace
  602. } // namespace cast
  603. } // namespace media
  604. int main(int argc, char** argv) {
  605. base::AtExitManager at_exit;
  606. base::CommandLine::Init(argc, argv);
  607. InitLogging(logging::LoggingSettings());
  608. const base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
  609. base::FilePath media_path = cmd->GetSwitchValuePath(media::cast::kLibDir);
  610. if (media_path.empty()) {
  611. if (!base::PathService::Get(base::DIR_GEN_TEST_DATA_ROOT, &media_path)) {
  612. LOG(ERROR) << "Failed to load FFmpeg.";
  613. return 1;
  614. }
  615. }
  616. media::InitializeMediaLibrary();
  617. base::FilePath source_path = cmd->GetSwitchValuePath(
  618. media::cast::kSourcePath);
  619. base::FilePath log_output_path = cmd->GetSwitchValuePath(
  620. media::cast::kOutputPath);
  621. if (log_output_path.empty()) {
  622. base::GetTempDir(&log_output_path);
  623. log_output_path = log_output_path.AppendASCII("sim-events.gz");
  624. }
  625. base::FilePath metrics_output_path = cmd->GetSwitchValuePath(
  626. media::cast::kMetricsOutputPath);
  627. base::FilePath yuv_output_path = cmd->GetSwitchValuePath(
  628. media::cast::kYuvOutputPath);
  629. std::string sim_id = cmd->GetSwitchValueASCII(media::cast::kSimulationId);
  630. NetworkSimulationModel model = media::cast::LoadModel(
  631. cmd->GetSwitchValuePath(media::cast::kModelPath));
  632. base::Value values(base::Value::Type::DICTIONARY);
  633. values.SetBoolKey("sim", true);
  634. values.SetStringKey("sim-id", sim_id);
  635. std::string extra_data;
  636. base::JSONWriter::Write(values, &extra_data);
  637. // Run.
  638. media::cast::RunSimulation(source_path, log_output_path, metrics_output_path,
  639. yuv_output_path, extra_data, model);
  640. return 0;
  641. }