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

Side by Side Diff: webrtc/modules/audio_coding/neteq/tools/neteq_rtpplay.cc

Issue 1316903002: Update to the neteq_rtpplay utility to support RtcEventLog input files. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Added automatic filetype detection, lots of refactoring. Created 5 years, 3 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
OLDNEW
1 /* 1 /*
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. 2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license 4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source 5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found 6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may 7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree. 8 * be found in the AUTHORS file in the root of the source tree.
9 */ 9 */
10 10
11 // TODO(hlundin): The functionality in this file should be moved into one or 11 // TODO(hlundin): The functionality in this file should be moved into one or
12 // several classes. 12 // several classes.
13 13
14 #include <assert.h> 14 #include <assert.h>
15 #include <errno.h> 15 #include <errno.h>
16 #include <limits.h> // For ULONG_MAX returned by strtoul. 16 #include <limits.h> // For ULONG_MAX returned by strtoul.
17 #include <stdio.h> 17 #include <stdio.h>
18 #include <stdlib.h> // For strtoul. 18 #include <stdlib.h> // For strtoul.
19 19
20 #include <algorithm> 20 #include <algorithm>
21 #include <iostream> 21 #include <iostream>
22 #include <limits>
22 #include <string> 23 #include <string>
23 24
24 #include "google/gflags.h" 25 #include "google/gflags.h"
25 #include "webrtc/base/checks.h" 26 #include "webrtc/base/checks.h"
26 #include "webrtc/base/scoped_ptr.h" 27 #include "webrtc/base/scoped_ptr.h"
27 #include "webrtc/modules/audio_coding/codecs/pcm16b/include/pcm16b.h" 28 #include "webrtc/modules/audio_coding/codecs/pcm16b/include/pcm16b.h"
28 #include "webrtc/modules/audio_coding/neteq/interface/neteq.h" 29 #include "webrtc/modules/audio_coding/neteq/interface/neteq.h"
29 #include "webrtc/modules/audio_coding/neteq/tools/input_audio_file.h" 30 #include "webrtc/modules/audio_coding/neteq/tools/input_audio_file.h"
30 #include "webrtc/modules/audio_coding/neteq/tools/output_audio_file.h" 31 #include "webrtc/modules/audio_coding/neteq/tools/output_audio_file.h"
31 #include "webrtc/modules/audio_coding/neteq/tools/output_wav_file.h" 32 #include "webrtc/modules/audio_coding/neteq/tools/output_wav_file.h"
32 #include "webrtc/modules/audio_coding/neteq/tools/packet.h" 33 #include "webrtc/modules/audio_coding/neteq/tools/packet.h"
34 #include "webrtc/modules/audio_coding/neteq/tools/rtc_event_log_source.h"
33 #include "webrtc/modules/audio_coding/neteq/tools/rtp_file_source.h" 35 #include "webrtc/modules/audio_coding/neteq/tools/rtp_file_source.h"
34 #include "webrtc/modules/interface/module_common_types.h" 36 #include "webrtc/modules/interface/module_common_types.h"
35 #include "webrtc/system_wrappers/interface/trace.h" 37 #include "webrtc/system_wrappers/interface/trace.h"
36 #include "webrtc/test/testsupport/fileutils.h" 38 #include "webrtc/test/testsupport/fileutils.h"
37 #include "webrtc/typedefs.h" 39 #include "webrtc/typedefs.h"
38 40
39 using webrtc::NetEq; 41 using webrtc::NetEq;
40 using webrtc::WebRtcRTPHeader; 42 using webrtc::WebRtcRTPHeader;
41 43
42 namespace { 44 namespace {
(...skipping 334 matching lines...) Expand 10 before | Expand all | Expand 10 after
377 if (FLAGS_codec_map) { 379 if (FLAGS_codec_map) {
378 // We have already printed the codec map. Just end the program. 380 // We have already printed the codec map. Just end the program.
379 return 0; 381 return 0;
380 } 382 }
381 // Print usage information. 383 // Print usage information.
382 std::cout << google::ProgramUsage(); 384 std::cout << google::ProgramUsage();
383 return 0; 385 return 0;
384 } 386 }
385 387
386 printf("Input file: %s\n", argv[1]); 388 printf("Input file: %s\n", argv[1]);
387 rtc::scoped_ptr<webrtc::test::RtpFileSource> file_source( 389
388 webrtc::test::RtpFileSource::Create(argv[1])); 390 // Check if the magic string "#!rtpplay1.0" appears at the beginning of the
minyue-webrtc 2015/09/01 11:48:35 nice!
hlundin-webrtc 2015/09/02 08:48:51 Yes, but I suggest you also add RTPencode as a mag
ivoc 2015/09/03 08:01:31 Ah, I did not know that. Thanks.
391 // file. If it does, the input file is an RTPdump file, otherwise we will
392 // assume it is an RtcEventLog file.
393 bool is_rtp_dump = false;
hlundin-webrtc 2015/09/02 08:48:51 This is a lot of extra code to check what is essen
ivoc 2015/09/03 08:01:31 You're right, that does seem like a nicer approach
394 {
395 const char magic_string[] = "#!rtpplay1.0";
396 const size_t magic_string_size = sizeof(magic_string) - 1;
397 char first_bytes[magic_string_size];
398 FILE* input_file = fopen(argv[1], "r");
399 if (input_file) {
400 size_t bytes_read = fread(first_bytes, 1, magic_string_size, input_file);
401 if (bytes_read == magic_string_size)
402 if (strncmp(magic_string, first_bytes, magic_string_size) == 0)
403 is_rtp_dump = true;
404 fclose(input_file);
405 } else {
406 std::cerr << "Unable to read input file." << std::endl;
407 return -1;
408 }
409 }
410 rtc::scoped_ptr<webrtc::test::PacketSource> file_source;
411 webrtc::test::RtcEventLogSource* event_log_source = nullptr;
412 if (is_rtp_dump) {
413 file_source.reset(webrtc::test::RtpFileSource::Create(argv[1]));
414 } else {
415 event_log_source = webrtc::test::RtcEventLogSource::Create(argv[1]);
416 file_source.reset(event_log_source);
417 }
418
389 assert(file_source.get()); 419 assert(file_source.get());
390 420
391 // Check if an SSRC value was provided. 421 // Check if an SSRC value was provided.
392 if (!FLAGS_ssrc.empty()) { 422 if (!FLAGS_ssrc.empty()) {
393 uint32_t ssrc; 423 uint32_t ssrc;
394 CHECK(ParseSsrc(FLAGS_ssrc, &ssrc)) << "Flag verification has failed."; 424 CHECK(ParseSsrc(FLAGS_ssrc, &ssrc)) << "Flag verification has failed.";
395 file_source->SelectSsrc(ssrc); 425 file_source->SelectSsrc(ssrc);
396 } 426 }
397 427
398 // Check if a replacement audio file was provided, and if so, open it. 428 // Check if a replacement audio file was provided, and if so, open it.
399 bool replace_payload = false; 429 bool replace_payload = false;
400 rtc::scoped_ptr<webrtc::test::InputAudioFile> replacement_audio_file; 430 rtc::scoped_ptr<webrtc::test::InputAudioFile> replacement_audio_file;
401 if (!FLAGS_replacement_audio_file.empty()) { 431 if (!FLAGS_replacement_audio_file.empty()) {
402 replacement_audio_file.reset( 432 replacement_audio_file.reset(
403 new webrtc::test::InputAudioFile(FLAGS_replacement_audio_file)); 433 new webrtc::test::InputAudioFile(FLAGS_replacement_audio_file));
404 replace_payload = true; 434 replace_payload = true;
405 } 435 }
406 436
407 // Read first packet. 437 // Read first packet.
408 rtc::scoped_ptr<webrtc::test::Packet> packet(file_source->NextPacket()); 438 rtc::scoped_ptr<webrtc::test::Packet> packet(file_source->NextPacket());
409 if (!packet) { 439 if (!packet) {
410 printf( 440 printf(
411 "Warning: input file is empty, or the filters did not match any " 441 "Warning: input file is empty, or the filters did not match any "
412 "packets\n"); 442 "packets\n");
413 webrtc::Trace::ReturnTrace(); 443 webrtc::Trace::ReturnTrace();
414 return 0; 444 return 0;
415 } 445 }
416 bool packet_available = true;
417 446
418 // Check the sample rate. 447 // Check the sample rate.
419 int sample_rate_hz = CodecSampleRate(packet->header().payloadType); 448 int sample_rate_hz = CodecSampleRate(packet->header().payloadType);
420 if (sample_rate_hz <= 0) { 449 if (sample_rate_hz <= 0) {
421 printf("Warning: Invalid sample rate from RTP packet.\n"); 450 printf("Warning: Invalid sample rate from RTP packet.\n");
422 webrtc::Trace::ReturnTrace(); 451 webrtc::Trace::ReturnTrace();
423 return 0; 452 return 0;
424 } 453 }
425 454
426 // Open the output file now that we know the sample rate. (Rate is only needed 455 // Open the output file now that we know the sample rate. (Rate is only needed
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
468 replacement_audio.reset(new int16_t[input_frame_size_timestamps]); 497 replacement_audio.reset(new int16_t[input_frame_size_timestamps]);
469 payload_mem_size_bytes = 2 * input_frame_size_timestamps; 498 payload_mem_size_bytes = 2 * input_frame_size_timestamps;
470 payload.reset(new uint8_t[payload_mem_size_bytes]); 499 payload.reset(new uint8_t[payload_mem_size_bytes]);
471 next_packet.reset(file_source->NextPacket()); 500 next_packet.reset(file_source->NextPacket());
472 assert(next_packet); 501 assert(next_packet);
473 next_packet_available = true; 502 next_packet_available = true;
474 } 503 }
475 504
476 // This is the main simulation loop. 505 // This is the main simulation loop.
477 // Set the simulation clock to start immediately with the first packet. 506 // Set the simulation clock to start immediately with the first packet.
478 int start_time_ms = packet->time_ms(); 507 int64_t start_time_ms = packet->time_ms();
hlundin-webrtc 2015/09/02 08:48:51 packet->time_ms() actually returns a double. Sugge
ivoc 2015/09/03 08:01:31 Done.
479 int time_now_ms = packet->time_ms(); 508 int64_t time_now_ms = packet->time_ms();
480 int next_input_time_ms = time_now_ms; 509 int64_t next_input_time_ms = time_now_ms;
481 int next_output_time_ms = time_now_ms; 510 int64_t next_output_time_ms = time_now_ms;
482 if (time_now_ms % kOutputBlockSizeMs != 0) { 511 if (time_now_ms % kOutputBlockSizeMs != 0) {
483 // Make sure that next_output_time_ms is rounded up to the next multiple 512 // Make sure that next_output_time_ms is rounded up to the next multiple
484 // of kOutputBlockSizeMs. (Legacy bit-exactness.) 513 // of kOutputBlockSizeMs. (Legacy bit-exactness.)
485 next_output_time_ms += 514 next_output_time_ms +=
486 kOutputBlockSizeMs - time_now_ms % kOutputBlockSizeMs; 515 kOutputBlockSizeMs - time_now_ms % kOutputBlockSizeMs;
487 } 516 }
488 while (packet_available) { 517
518 bool packet_available = true;
519 bool output_event_available = true;
520 if (!is_rtp_dump) {
521 next_output_time_ms = event_log_source->NextAudioOutputEventMs();
522 if (next_output_time_ms == std::numeric_limits<int64_t>::max())
523 output_event_available = false;
524 start_time_ms = time_now_ms =
525 std::min(next_input_time_ms, next_output_time_ms);
526 }
527 while (packet_available || output_event_available) {
528 // Advance time to next event.
529 time_now_ms = std::min(next_input_time_ms, next_output_time_ms);
489 // Check if it is time to insert packet. 530 // Check if it is time to insert packet.
490 while (time_now_ms >= next_input_time_ms && packet_available) { 531 while (time_now_ms >= next_input_time_ms && packet_available) {
491 assert(packet->virtual_payload_length_bytes() > 0); 532 assert(packet->virtual_payload_length_bytes() > 0);
492 // Parse RTP header. 533 // Parse RTP header.
493 WebRtcRTPHeader rtp_header; 534 WebRtcRTPHeader rtp_header;
494 packet->ConvertHeader(&rtp_header); 535 packet->ConvertHeader(&rtp_header);
495 const uint8_t* payload_ptr = packet->payload(); 536 const uint8_t* payload_ptr = packet->payload();
minyue-webrtc 2015/09/01 11:48:35 Not very related to this CL, just curious. If pac
hlundin-webrtc 2015/09/02 08:48:51 There will be some errors from NetEq, but it is pr
ivoc 2015/09/03 08:01:31 I added a check for this higher up in the code, on
496 size_t payload_len = packet->payload_length_bytes(); 537 size_t payload_len = packet->payload_length_bytes();
497 if (replace_payload) { 538 if (replace_payload) {
498 payload_len = ReplacePayload(replacement_audio_file.get(), 539 payload_len = ReplacePayload(replacement_audio_file.get(),
499 &replacement_audio, 540 &replacement_audio,
500 &payload, 541 &payload,
501 &payload_mem_size_bytes, 542 &payload_mem_size_bytes,
502 &input_frame_size_timestamps, 543 &input_frame_size_timestamps,
503 &rtp_header, 544 &rtp_header,
504 next_packet.get()); 545 next_packet.get());
505 payload_ptr = payload.get(); 546 payload_ptr = payload.get();
(...skipping 21 matching lines...) Expand all
527 std::cerr << " SN = " << rtp_header.header.sequenceNumber 568 std::cerr << " SN = " << rtp_header.header.sequenceNumber
528 << std::endl; 569 << std::endl;
529 std::cerr << " TS = " << rtp_header.header.timestamp << std::endl; 570 std::cerr << " TS = " << rtp_header.header.timestamp << std::endl;
530 } 571 }
531 } 572 }
532 573
533 // Get next packet from file. 574 // Get next packet from file.
534 webrtc::test::Packet* temp_packet = file_source->NextPacket(); 575 webrtc::test::Packet* temp_packet = file_source->NextPacket();
535 if (temp_packet) { 576 if (temp_packet) {
536 packet.reset(temp_packet); 577 packet.reset(temp_packet);
578 if (replace_payload) {
579 // At this point |packet| contains the packet *after* |next_packet|.
580 // Swap Packet objects between |packet| and |next_packet|.
581 packet.swap(next_packet);
582 // Swap the status indicators unless they're already the same.
583 if (packet_available != next_packet_available) {
584 packet_available = !packet_available;
585 next_packet_available = !next_packet_available;
586 }
587 }
588 next_input_time_ms = packet->time_ms();
hlundin-webrtc 2015/09/02 08:48:51 checked_cast here too
ivoc 2015/09/03 08:01:31 Added. I also added one in the call to neteq->Inse
537 } else { 589 } else {
590 // Set next input time to the maximum value of int64_t to prevent the
591 // time_now_ms from becoming stuck at the final value.
592 next_input_time_ms = std::numeric_limits<int64_t>::max();
538 packet_available = false; 593 packet_available = false;
539 } 594 }
540 if (replace_payload) {
541 // At this point |packet| contains the packet *after* |next_packet|.
542 // Swap Packet objects between |packet| and |next_packet|.
543 packet.swap(next_packet);
544 // Swap the status indicators unless they're already the same.
545 if (packet_available != next_packet_available) {
546 packet_available = !packet_available;
547 next_packet_available = !next_packet_available;
548 }
549 }
550 next_input_time_ms = packet->time_ms();
551 } 595 }
552 596
553 // Check if it is time to get output audio. 597 // Check if it is time to get output audio.
554 if (time_now_ms >= next_output_time_ms) { 598 while (time_now_ms >= next_output_time_ms && output_event_available) {
555 static const int kOutDataLen = 599 static const int kOutDataLen =
556 kOutputBlockSizeMs * kMaxSamplesPerMs * kMaxChannels; 600 kOutputBlockSizeMs * kMaxSamplesPerMs * kMaxChannels;
557 int16_t out_data[kOutDataLen]; 601 int16_t out_data[kOutDataLen];
558 int num_channels; 602 int num_channels;
559 int samples_per_channel; 603 int samples_per_channel;
560 int error = neteq->GetAudio(kOutDataLen, out_data, &samples_per_channel, 604 int error = neteq->GetAudio(kOutDataLen, out_data, &samples_per_channel,
561 &num_channels, NULL); 605 &num_channels, NULL);
562 if (error != NetEq::kOK) { 606 if (error != NetEq::kOK) {
563 std::cerr << "GetAudio returned error code " << 607 std::cerr << "GetAudio returned error code " <<
564 neteq->LastError() << std::endl; 608 neteq->LastError() << std::endl;
565 } else { 609 } else {
566 // Calculate sample rate from output size. 610 // Calculate sample rate from output size.
567 sample_rate_hz = 1000 * samples_per_channel / kOutputBlockSizeMs; 611 sample_rate_hz = 1000 * samples_per_channel / kOutputBlockSizeMs;
568 } 612 }
569 613
570 // Write to file. 614 // Write to file.
571 // TODO(hlundin): Make writing to file optional. 615 // TODO(hlundin): Make writing to file optional.
572 size_t write_len = samples_per_channel * num_channels; 616 size_t write_len = samples_per_channel * num_channels;
573 if (!output->WriteArray(out_data, write_len)) { 617 if (!output->WriteArray(out_data, write_len)) {
574 std::cerr << "Error while writing to file" << std::endl; 618 std::cerr << "Error while writing to file" << std::endl;
575 webrtc::Trace::ReturnTrace(); 619 webrtc::Trace::ReturnTrace();
576 exit(1); 620 exit(1);
577 } 621 }
578 next_output_time_ms += kOutputBlockSizeMs; 622 if (is_rtp_dump) {
623 next_output_time_ms += kOutputBlockSizeMs;
624 if (!packet_available)
625 output_event_available = false;
626 } else {
627 next_output_time_ms = event_log_source->NextAudioOutputEventMs();
628 if (next_output_time_ms == std::numeric_limits<int64_t>::max())
629 output_event_available = false;
630 }
579 } 631 }
580 // Advance time to next event.
581 time_now_ms = std::min(next_input_time_ms, next_output_time_ms);
582 } 632 }
583
584 printf("Simulation done\n"); 633 printf("Simulation done\n");
585 printf("Produced %i ms of audio\n", time_now_ms - start_time_ms); 634 printf("Produced %i ms of audio\n",
635 static_cast<int>(time_now_ms - start_time_ms));
586 636
587 delete neteq; 637 delete neteq;
588 webrtc::Trace::ReturnTrace(); 638 webrtc::Trace::ReturnTrace();
589 return 0; 639 return 0;
590 } 640 }
OLDNEW
« no previous file with comments | « webrtc/modules/audio_coding/neteq/neteq_tests.gypi ('k') | webrtc/modules/audio_coding/neteq/tools/rtc_event_log_source.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698