Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(192)

Side by Side Diff: media/cast/test/sender.cc

Issue 162103002: Cast: Added a EncodingEventSubscriber to cast sender app. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@encoding-event-subscriber
Patch Set: Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« media/cast/DEPS ('K') | « media/cast/cast.gyp ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 // Test application that simulates a cast sender - Data can be either generated 5 // Test application that simulates a cast sender - Data can be either generated
6 // or read from a file. 6 // or read from a file.
7 7
8 #include "base/at_exit.h" 8 #include "base/at_exit.h"
9 #include "base/file_util.h"
9 #include "base/logging.h" 10 #include "base/logging.h"
10 #include "base/memory/scoped_ptr.h" 11 #include "base/memory/scoped_ptr.h"
11 #include "base/threading/thread.h" 12 #include "base/threading/thread.h"
12 #include "base/time/default_tick_clock.h" 13 #include "base/time/default_tick_clock.h"
13 #include "media/base/video_frame.h" 14 #include "media/base/video_frame.h"
14 #include "media/cast/cast_config.h" 15 #include "media/cast/cast_config.h"
15 #include "media/cast/cast_environment.h" 16 #include "media/cast/cast_environment.h"
16 #include "media/cast/cast_sender.h" 17 #include "media/cast/cast_sender.h"
18 #include "media/cast/logging/encoding_event_subscriber.h"
17 #include "media/cast/logging/logging_defines.h" 19 #include "media/cast/logging/logging_defines.h"
20 #include "media/cast/logging/proto/raw_events.pb.h"
18 #include "media/cast/test/utility/audio_utility.h" 21 #include "media/cast/test/utility/audio_utility.h"
19 #include "media/cast/test/utility/input_builder.h" 22 #include "media/cast/test/utility/input_builder.h"
20 #include "media/cast/test/utility/video_utility.h" 23 #include "media/cast/test/utility/video_utility.h"
21 #include "media/cast/transport/cast_transport_defines.h" 24 #include "media/cast/transport/cast_transport_defines.h"
22 #include "media/cast/transport/cast_transport_sender.h" 25 #include "media/cast/transport/cast_transport_sender.h"
23 #include "media/cast/transport/transport/udp_transport.h" 26 #include "media/cast/transport/transport/udp_transport.h"
24 #include "ui/gfx/size.h" 27 #include "ui/gfx/size.h"
25 28
29 #if defined(USE_SYSTEM_PROTOBUF)
30 #include <google/protobuf/io/coded_stream.h>
31 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
32 #else
33 #include "third_party/protobuf/src/google/protobuf/io/coded_stream.h"
34 #include "third_party/protobuf/src/google/protobuf/io/zero_copy_stream_impl_lite .h"
35 #endif
36
26 namespace media { 37 namespace media {
27 namespace cast { 38 namespace cast {
28 // Settings chosen to match default receiver settings. 39 // Settings chosen to match default receiver settings.
29 #define DEFAULT_SEND_PORT "2344" 40 #define DEFAULT_SEND_PORT "2344"
30 #define DEFAULT_RECEIVE_PORT "2346" 41 #define DEFAULT_RECEIVE_PORT "2346"
31 #define DEFAULT_SEND_IP "127.0.0.1" 42 #define DEFAULT_SEND_IP "127.0.0.1"
32 #define DEFAULT_READ_FROM_FILE "0" 43 #define DEFAULT_READ_FROM_FILE "0"
33 #define DEFAULT_AUDIO_SENDER_SSRC "1" 44 #define DEFAULT_AUDIO_SENDER_SSRC "1"
34 #define DEFAULT_AUDIO_RECEIVER_SSRC "2" 45 #define DEFAULT_AUDIO_RECEIVER_SSRC "2"
35 #define DEFAULT_AUDIO_PAYLOAD_TYPE "127" 46 #define DEFAULT_AUDIO_PAYLOAD_TYPE "127"
36 #define DEFAULT_VIDEO_SENDER_SSRC "11" 47 #define DEFAULT_VIDEO_SENDER_SSRC "11"
37 #define DEFAULT_VIDEO_RECEIVER_SSRC "12" 48 #define DEFAULT_VIDEO_RECEIVER_SSRC "12"
38 #define DEFAULT_VIDEO_PAYLOAD_TYPE "96" 49 #define DEFAULT_VIDEO_PAYLOAD_TYPE "96"
39 #define DEFAULT_VIDEO_CODEC_WIDTH "1280" 50 #define DEFAULT_VIDEO_CODEC_WIDTH "1280"
40 #define DEFAULT_VIDEO_CODEC_HEIGHT "720" 51 #define DEFAULT_VIDEO_CODEC_HEIGHT "720"
41 #define DEFAULT_VIDEO_CODEC_BITRATE "2000" 52 #define DEFAULT_VIDEO_CODEC_BITRATE "2000"
42 #define DEFAULT_VIDEO_CODEC_MAX_BITRATE "4000" 53 #define DEFAULT_VIDEO_CODEC_MAX_BITRATE "4000"
43 #define DEFAULT_VIDEO_CODEC_MIN_BITRATE "1000" 54 #define DEFAULT_VIDEO_CODEC_MIN_BITRATE "1000"
44 55
56 #define DEFAULT_LOGGING_DURATION "300"
57
45 namespace { 58 namespace {
46 static const int kAudioChannels = 2; 59 static const int kAudioChannels = 2;
47 static const int kAudioSamplingFrequency = 48000; 60 static const int kAudioSamplingFrequency = 48000;
48 static const int kSoundFrequency = 1234; // Frequency of sinusoid wave. 61 static const int kSoundFrequency = 1234; // Frequency of sinusoid wave.
49 // The tests are commonly implemented with |kFrameTimerMs| RunTask function; 62 // The tests are commonly implemented with |kFrameTimerMs| RunTask function;
50 // a normal video is 30 fps hence the 33 ms between frames. 63 // a normal video is 30 fps hence the 33 ms between frames.
51 static const float kSoundVolume = 0.5f; 64 static const float kSoundVolume = 0.5f;
52 static const int kFrameTimerMs = 33; 65 static const int kFrameTimerMs = 33;
53 66
54 // Dummy callback function that does nothing except to accept ownership of 67 // Dummy callback function that does nothing except to accept ownership of
(...skipping 15 matching lines...) Expand all
70 std::string GetIpAddress(const std::string display_text) { 83 std::string GetIpAddress(const std::string display_text) {
71 test::InputBuilder input(display_text, DEFAULT_SEND_IP, INT_MIN, INT_MAX); 84 test::InputBuilder input(display_text, DEFAULT_SEND_IP, INT_MIN, INT_MAX);
72 std::string ip_address = input.GetStringInput(); 85 std::string ip_address = input.GetStringInput();
73 // Verify correct form: 86 // Verify correct form:
74 while (std::count(ip_address.begin(), ip_address.end(), '.') != 3) { 87 while (std::count(ip_address.begin(), ip_address.end(), '.') != 3) {
75 ip_address = input.GetStringInput(); 88 ip_address = input.GetStringInput();
76 } 89 }
77 return ip_address; 90 return ip_address;
78 } 91 }
79 92
93 int GetLoggingDuration() {
94 test::InputBuilder input(
95 "Choose logging duration (seconds), 0 for no logging.",
96 DEFAULT_LOGGING_DURATION, 0, INT_MAX);
97 return input.GetIntInput();
98 }
99
100 std::string GetLogFileDestination() {
101 test::InputBuilder input(
102 "Enter log file destination.",
103 "/tmp/raw_events.log", INT_MIN, INT_MAX);
Alpha Left Google 2014/02/13 20:30:58 Save the log to current dir is better.
imcheng 2014/02/13 21:49:26 Done.
104 return input.GetStringInput();
105 }
106
80 bool ReadFromFile() { 107 bool ReadFromFile() {
81 test::InputBuilder input( 108 test::InputBuilder input(
82 "Enter 1 to read from file.", DEFAULT_READ_FROM_FILE, 0, 1); 109 "Enter 1 to read from file.", DEFAULT_READ_FROM_FILE, 0, 1);
83 return (1 == input.GetIntInput()); 110 return (1 == input.GetIntInput());
84 } 111 }
85 112
86 std::string GetVideoFile() { 113 std::string GetVideoFile() {
87 test::InputBuilder input( 114 test::InputBuilder input(
88 "Enter file and path to raw video file.", "", INT_MIN, INT_MAX); 115 "Enter file and path to raw video file.", "", INT_MIN, INT_MAX);
89 return input.GetStringInput(); 116 return input.GetStringInput();
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after
305 CHECK_EQ(result, media::cast::STATUS_INITIALIZED); 332 CHECK_EQ(result, media::cast::STATUS_INITIALIZED);
306 VLOG(1) << "Cast Sender initialized"; 333 VLOG(1) << "Cast Sender initialized";
307 } 334 }
308 335
309 net::IPEndPoint CreateUDPAddress(std::string ip_str, int port) { 336 net::IPEndPoint CreateUDPAddress(std::string ip_str, int port) {
310 net::IPAddressNumber ip_number; 337 net::IPAddressNumber ip_number;
311 CHECK(net::ParseIPLiteralToNumber(ip_str, &ip_number)); 338 CHECK(net::ParseIPLiteralToNumber(ip_str, &ip_number));
312 return net::IPEndPoint(ip_number, port); 339 return net::IPEndPoint(ip_number, port);
313 } 340 }
314 341
342 // TODO(imcheng): Extract this function to a class.
Alpha Left Google 2014/02/13 20:30:58 No need for this TODO.
imcheng 2014/02/13 21:49:26 I want to do extract this to a class though so tha
343 void WriteTo(const media::cast::FrameEventMap& frame_events,
344 const media::cast::PacketEventMap& packet_events,
345 const media::cast::GenericEventMap& generic_events,
346 std::string* output_string) {
347 google::protobuf::io::StringOutputStream string_output_stream(output_string);
348
349 google::protobuf::io::CodedOutputStream output_stream(&string_output_stream);
350
351 int byte_count = 0;
352 int last_byte_count = 0;
353 // Frame events - write size first, then write entries
Alpha Left Google 2014/02/13 20:30:58 nit: period at the end of sentence.
imcheng 2014/02/13 21:49:26 Done.
354 output_stream.WriteLittleEndian32(frame_events.size());
355 for (media::cast::FrameEventMap::const_iterator it = frame_events.begin();
356 it != frame_events.end(); ++it) {
357 int proto_size = it->second->ByteSize();
358
359 // Write size of the proto, then write the proto
Alpha Left Google 2014/02/13 20:30:58 nit: period at the end of sentence.
imcheng 2014/02/13 21:49:26 Done.
360 output_stream.WriteLittleEndian32(proto_size);
361
362 bool success = it->second->SerializeToCodedStream(&output_stream);
363 DCHECK(success);
364 }
365
366 byte_count = output_stream.ByteCount();
367 printf("Encoded frame events byte count: %d\n", byte_count - last_byte_count);
368 last_byte_count = byte_count;
369
370 // Write packet events
Alpha Left Google 2014/02/13 20:30:58 nit: period at the end of sentence.
imcheng 2014/02/13 21:49:26 Done.
371 output_stream.WriteLittleEndian32(packet_events.size());
372 for (media::cast::PacketEventMap::const_iterator it = packet_events.begin();
373 it != packet_events.end(); ++it) {
374 int proto_size = it->second->ByteSize();
375 // Write size of the proto, then write the proto
Alpha Left Google 2014/02/13 20:30:58 nit: period at the end of sentence.
imcheng 2014/02/13 21:49:26 Done.
376 output_stream.WriteLittleEndian32(proto_size);
377
378 bool success = it->second->SerializeToCodedStream(&output_stream);
379 DCHECK(success);
380 }
381
382 byte_count = output_stream.ByteCount();
383 printf("Encoded packet events byte count: %d\n",
384 byte_count - last_byte_count);
385 last_byte_count = byte_count;
386
387 // Write generic events
Alpha Left Google 2014/02/13 20:30:58 nit: period at the end of sentence.
imcheng 2014/02/13 21:49:26 Done.
388 output_stream.WriteLittleEndian32(generic_events.size());
389 for (media::cast::GenericEventMap::const_iterator it = generic_events.begin();
390 it != generic_events.end(); ++it) {
391 // Write size of the proto, then write the proto
Alpha Left Google 2014/02/13 20:30:58 nit: period at the end of sentence.
imcheng 2014/02/13 21:49:26 Done.
392 output_stream.WriteLittleEndian32(it->second->ByteSize());
393
394 bool success = it->second->SerializeToCodedStream(&output_stream);
395 DCHECK(success);
396 }
397
398 byte_count = output_stream.ByteCount();
399 printf("Encoded generic events byte count: %d\n",
400 byte_count - last_byte_count);
401 last_byte_count = byte_count;
402 }
403
404 void WriteLogsToFileAndStopSubscribing(
405 const scoped_refptr<media::cast::CastEnvironment>& cast_environment,
406 scoped_ptr<media::cast::EncodingEventSubscriber> subscriber,
407 file_util::ScopedFILE log_file) {
408 cast_environment->Logging()->RemoveRawEventSubscriber(subscriber.get());
409 media::cast::FrameEventMap frame_events;
410 media::cast::PacketEventMap packet_events;
411 media::cast::GenericEventMap generic_events;
412 subscriber->GetFrameEventsAndReset(&frame_events);
413 subscriber->GetPacketEventsAndReset(&packet_events);
414 subscriber->GetGenericEventsAndReset(&generic_events);
415
416 // TODO(imcheng): Consider sending the maps to another thread for processing
Alpha Left Google 2014/02/13 20:30:58 There's no need for this. This is a test app any w
imcheng 2014/02/13 21:49:26 Done.
417 // so that it won't block the main thread.
418 printf("Frame map size: %lu\n", frame_events.size());
419 printf("Packet map size: %lu\n", packet_events.size());
420 printf("Generic map size: %lu\n", generic_events.size());
421
422 std::string serialized_string;
423 WriteTo(frame_events, packet_events, generic_events, &serialized_string);
424
425 size_t ret = fwrite(&serialized_string[0], 1, serialized_string.size(),
426 log_file.get());
427 if (ret != serialized_string.size())
428 VLOG(1) << "Failed to write logs to file.";
429 }
430
315 } // namespace 431 } // namespace
316 432
317 int main(int argc, char** argv) { 433 int main(int argc, char** argv) {
318 base::AtExitManager at_exit; 434 base::AtExitManager at_exit;
319 VLOG(1) << "Cast Sender"; 435 VLOG(1) << "Cast Sender";
320 base::Thread test_thread("Cast sender test app thread"); 436 base::Thread test_thread("Cast sender test app thread");
321 base::Thread audio_thread("Cast audio encoder thread"); 437 base::Thread audio_thread("Cast audio encoder thread");
322 base::Thread video_thread("Cast video encoder thread"); 438 base::Thread video_thread("Cast video encoder thread");
323 test_thread.Start(); 439 test_thread.Start();
324 audio_thread.Start(); 440 audio_thread.Start();
(...skipping 23 matching lines...) Expand all
348 config.audio_rtp_config = audio_config.rtp_config; 464 config.audio_rtp_config = audio_config.rtp_config;
349 config.video_rtp_config = video_config.rtp_config; 465 config.video_rtp_config = video_config.rtp_config;
350 466
351 scoped_ptr<media::cast::transport::CastTransportSender> transport_sender( 467 scoped_ptr<media::cast::transport::CastTransportSender> transport_sender(
352 media::cast::transport::CastTransportSender::CreateCastTransportSender( 468 media::cast::transport::CastTransportSender::CreateCastTransportSender(
353 clock.get(), 469 clock.get(),
354 config, 470 config,
355 base::Bind(&UpdateCastTransportStatus), 471 base::Bind(&UpdateCastTransportStatus),
356 io_message_loop.message_loop_proxy())); 472 io_message_loop.message_loop_proxy()));
357 473
358 // Enable main and send side threads only. Disable logging. 474 // Enable main and send side threads only. Enable raw event logging.
359 // Running transport on the main thread. 475 // Running transport on the main thread.
476 media::cast::CastLoggingConfig logging_config(true);
477 logging_config.enable_raw_data_collection = true;
478
360 scoped_refptr<media::cast::CastEnvironment> cast_environment( 479 scoped_refptr<media::cast::CastEnvironment> cast_environment(
361 new media::cast::CastEnvironment( 480 new media::cast::CastEnvironment(
362 clock.Pass(), 481 clock.Pass(),
363 io_message_loop.message_loop_proxy(), 482 io_message_loop.message_loop_proxy(),
364 audio_thread.message_loop_proxy(), 483 audio_thread.message_loop_proxy(),
365 NULL, 484 NULL,
366 video_thread.message_loop_proxy(), 485 video_thread.message_loop_proxy(),
367 NULL, 486 NULL,
368 io_message_loop.message_loop_proxy(), 487 io_message_loop.message_loop_proxy(),
369 media::cast::GetDefaultCastSenderLoggingConfig())); 488 logging_config));
370 489
371 scoped_ptr<media::cast::CastSender> cast_sender( 490 scoped_ptr<media::cast::CastSender> cast_sender(
372 media::cast::CastSender::CreateCastSender( 491 media::cast::CastSender::CreateCastSender(
373 cast_environment, 492 cast_environment,
374 audio_config, 493 audio_config,
375 video_config, 494 video_config,
376 NULL, // gpu_factories. 495 NULL, // gpu_factories.
377 base::Bind(&InitializationResult), 496 base::Bind(&InitializationResult),
378 transport_sender.get())); 497 transport_sender.get()));
379 498
380 transport_sender->SetPacketReceiver(cast_sender->packet_receiver()); 499 transport_sender->SetPacketReceiver(cast_sender->packet_receiver());
381 500
382 media::cast::FrameInput* frame_input = cast_sender->frame_input(); 501 media::cast::FrameInput* frame_input = cast_sender->frame_input();
383 scoped_ptr<media::cast::SendProcess> send_process( 502 scoped_ptr<media::cast::SendProcess> send_process(
384 new media::cast::SendProcess(test_thread.message_loop_proxy(), 503 new media::cast::SendProcess(test_thread.message_loop_proxy(),
385 cast_environment->Clock(), 504 cast_environment->Clock(),
386 video_config, 505 video_config,
387 frame_input)); 506 frame_input));
388 507
508 // Set up event subscribers.
509 // TODO(imcheng): Set up separate subscribers for audio / video / other.
510 int logging_duration = media::cast::GetLoggingDuration();
511 scoped_ptr<media::cast::EncodingEventSubscriber> event_subscriber;
512 if (logging_duration > 0) {
513 std::string log_file_name(media::cast::GetLogFileDestination());
514 event_subscriber.reset(new media::cast::EncodingEventSubscriber);
515 cast_environment->Logging()->AddRawEventSubscriber(event_subscriber.get());
516 file_util::ScopedFILE log_file(fopen(log_file_name.c_str(), "w"));
517 if (!log_file) {
518 printf("Failed to open log file for writing.\n");
519 exit(-1);
520 }
521
522 io_message_loop.message_loop_proxy()->PostDelayedTask(FROM_HERE,
523 base::Bind(&WriteLogsToFileAndStopSubscribing,
524 cast_environment,
525 base::Passed(&event_subscriber),
526 base::Passed(&log_file)),
527 base::TimeDelta::FromSeconds(logging_duration));
528 }
529
389 test_thread.message_loop_proxy()->PostTask( 530 test_thread.message_loop_proxy()->PostTask(
390 FROM_HERE, 531 FROM_HERE,
391 base::Bind(&media::cast::SendProcess::SendFrame, 532 base::Bind(&media::cast::SendProcess::SendFrame,
392 base::Unretained(send_process.get()))); 533 base::Unretained(send_process.get())));
393 534
394 io_message_loop.Run(); 535 io_message_loop.Run();
536
395 return 0; 537 return 0;
396 } 538 }
OLDNEW
« media/cast/DEPS ('K') | « media/cast/cast.gyp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698