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

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: Rebased. 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/safe_conversions.h" 27 #include "webrtc/base/safe_conversions.h"
27 #include "webrtc/base/scoped_ptr.h" 28 #include "webrtc/base/scoped_ptr.h"
28 #include "webrtc/modules/audio_coding/codecs/pcm16b/include/pcm16b.h" 29 #include "webrtc/modules/audio_coding/codecs/pcm16b/include/pcm16b.h"
29 #include "webrtc/modules/audio_coding/neteq/interface/neteq.h" 30 #include "webrtc/modules/audio_coding/neteq/interface/neteq.h"
30 #include "webrtc/modules/audio_coding/neteq/tools/input_audio_file.h" 31 #include "webrtc/modules/audio_coding/neteq/tools/input_audio_file.h"
31 #include "webrtc/modules/audio_coding/neteq/tools/output_audio_file.h" 32 #include "webrtc/modules/audio_coding/neteq/tools/output_audio_file.h"
32 #include "webrtc/modules/audio_coding/neteq/tools/output_wav_file.h" 33 #include "webrtc/modules/audio_coding/neteq/tools/output_wav_file.h"
33 #include "webrtc/modules/audio_coding/neteq/tools/packet.h" 34 #include "webrtc/modules/audio_coding/neteq/tools/packet.h"
35 #include "webrtc/modules/audio_coding/neteq/tools/rtc_event_log_source.h"
34 #include "webrtc/modules/audio_coding/neteq/tools/rtp_file_source.h" 36 #include "webrtc/modules/audio_coding/neteq/tools/rtp_file_source.h"
35 #include "webrtc/modules/interface/module_common_types.h" 37 #include "webrtc/modules/interface/module_common_types.h"
36 #include "webrtc/system_wrappers/interface/trace.h" 38 #include "webrtc/system_wrappers/interface/trace.h"
39 #include "webrtc/test/rtp_file_reader.h"
37 #include "webrtc/test/testsupport/fileutils.h" 40 #include "webrtc/test/testsupport/fileutils.h"
38 #include "webrtc/typedefs.h" 41 #include "webrtc/typedefs.h"
39 42
40 using webrtc::NetEq; 43 using webrtc::NetEq;
41 using webrtc::WebRtcRTPHeader; 44 using webrtc::WebRtcRTPHeader;
42 45
43 namespace { 46 namespace {
44 47
45 // Parses the input string for a valid SSRC (at the start of the string). If a 48 // Parses the input string for a valid SSRC (at the start of the string). If a
46 // valid SSRC is found, it is written to the output variable |ssrc|, and true is 49 // valid SSRC is found, it is written to the output variable |ssrc|, and true is
(...skipping 331 matching lines...) Expand 10 before | Expand all | Expand 10 after
378 if (FLAGS_codec_map) { 381 if (FLAGS_codec_map) {
379 // We have already printed the codec map. Just end the program. 382 // We have already printed the codec map. Just end the program.
380 return 0; 383 return 0;
381 } 384 }
382 // Print usage information. 385 // Print usage information.
383 std::cout << google::ProgramUsage(); 386 std::cout << google::ProgramUsage();
384 return 0; 387 return 0;
385 } 388 }
386 389
387 printf("Input file: %s\n", argv[1]); 390 printf("Input file: %s\n", argv[1]);
388 rtc::scoped_ptr<webrtc::test::RtpFileSource> file_source( 391
389 webrtc::test::RtpFileSource::Create(argv[1])); 392 // TODO(ivoc): Modify the RtpFileSource::Create and RtcEventLogSource::Create
393 // functions to return a nullptr on failure instead of crashing
394 // the program.
395
396 // This temporary solution uses a RtpFileReader directly to check if the file
397 // is a valid RtpDump file.
398 bool is_rtp_dump = false;
399 {
400 rtc::scoped_ptr<webrtc::test::RtpFileReader> rtp_reader(
401 webrtc::test::RtpFileReader::Create(
402 webrtc::test::RtpFileReader::kRtpDump, argv[1]));
403 if (rtp_reader)
404 is_rtp_dump = true;
405 }
406 rtc::scoped_ptr<webrtc::test::PacketSource> file_source;
407 webrtc::test::RtcEventLogSource* event_log_source = nullptr;
408 if (is_rtp_dump) {
409 file_source.reset(webrtc::test::RtpFileSource::Create(argv[1]));
410 } else {
411 event_log_source = webrtc::test::RtcEventLogSource::Create(argv[1]);
412 file_source.reset(event_log_source);
413 }
414
390 assert(file_source.get()); 415 assert(file_source.get());
391 416
392 // Check if an SSRC value was provided. 417 // Check if an SSRC value was provided.
393 if (!FLAGS_ssrc.empty()) { 418 if (!FLAGS_ssrc.empty()) {
394 uint32_t ssrc; 419 uint32_t ssrc;
395 CHECK(ParseSsrc(FLAGS_ssrc, &ssrc)) << "Flag verification has failed."; 420 CHECK(ParseSsrc(FLAGS_ssrc, &ssrc)) << "Flag verification has failed.";
396 file_source->SelectSsrc(ssrc); 421 file_source->SelectSsrc(ssrc);
397 } 422 }
398 423
399 // Check if a replacement audio file was provided, and if so, open it. 424 // Check if a replacement audio file was provided, and if so, open it.
400 bool replace_payload = false; 425 bool replace_payload = false;
401 rtc::scoped_ptr<webrtc::test::InputAudioFile> replacement_audio_file; 426 rtc::scoped_ptr<webrtc::test::InputAudioFile> replacement_audio_file;
402 if (!FLAGS_replacement_audio_file.empty()) { 427 if (!FLAGS_replacement_audio_file.empty()) {
403 replacement_audio_file.reset( 428 replacement_audio_file.reset(
404 new webrtc::test::InputAudioFile(FLAGS_replacement_audio_file)); 429 new webrtc::test::InputAudioFile(FLAGS_replacement_audio_file));
405 replace_payload = true; 430 replace_payload = true;
406 } 431 }
407 432
408 // Read first packet. 433 // Read first packet.
409 rtc::scoped_ptr<webrtc::test::Packet> packet(file_source->NextPacket()); 434 rtc::scoped_ptr<webrtc::test::Packet> packet(file_source->NextPacket());
410 if (!packet) { 435 if (!packet) {
411 printf( 436 printf(
412 "Warning: input file is empty, or the filters did not match any " 437 "Warning: input file is empty, or the filters did not match any "
413 "packets\n"); 438 "packets\n");
414 webrtc::Trace::ReturnTrace(); 439 webrtc::Trace::ReturnTrace();
415 return 0; 440 return 0;
416 } 441 }
417 bool packet_available = true; 442 if (packet->payload_length_bytes() == 0 && !replace_payload) {
443 std::cerr << "Warning: input file contains header-only packets, but no "
444 << "replacement file is specified." << std::endl;
445 webrtc::Trace::ReturnTrace();
446 return -1;
447 }
418 448
419 // Check the sample rate. 449 // Check the sample rate.
420 int sample_rate_hz = CodecSampleRate(packet->header().payloadType); 450 int sample_rate_hz = CodecSampleRate(packet->header().payloadType);
421 if (sample_rate_hz <= 0) { 451 if (sample_rate_hz <= 0) {
422 printf("Warning: Invalid sample rate from RTP packet.\n"); 452 printf("Warning: Invalid sample rate from RTP packet.\n");
423 webrtc::Trace::ReturnTrace(); 453 webrtc::Trace::ReturnTrace();
424 return 0; 454 return 0;
425 } 455 }
426 456
427 // Open the output file now that we know the sample rate. (Rate is only needed 457 // 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
469 replacement_audio.reset(new int16_t[input_frame_size_timestamps]); 499 replacement_audio.reset(new int16_t[input_frame_size_timestamps]);
470 payload_mem_size_bytes = 2 * input_frame_size_timestamps; 500 payload_mem_size_bytes = 2 * input_frame_size_timestamps;
471 payload.reset(new uint8_t[payload_mem_size_bytes]); 501 payload.reset(new uint8_t[payload_mem_size_bytes]);
472 next_packet.reset(file_source->NextPacket()); 502 next_packet.reset(file_source->NextPacket());
473 assert(next_packet); 503 assert(next_packet);
474 next_packet_available = true; 504 next_packet_available = true;
475 } 505 }
476 506
477 // This is the main simulation loop. 507 // This is the main simulation loop.
478 // Set the simulation clock to start immediately with the first packet. 508 // Set the simulation clock to start immediately with the first packet.
479 int start_time_ms = packet->time_ms(); 509 int64_t start_time_ms = rtc::checked_cast<int64_t>(packet->time_ms());
480 int time_now_ms = packet->time_ms(); 510 int64_t time_now_ms = start_time_ms;
481 int next_input_time_ms = time_now_ms; 511 int64_t next_input_time_ms = time_now_ms;
482 int next_output_time_ms = time_now_ms; 512 int64_t next_output_time_ms = time_now_ms;
483 if (time_now_ms % kOutputBlockSizeMs != 0) { 513 if (time_now_ms % kOutputBlockSizeMs != 0) {
484 // Make sure that next_output_time_ms is rounded up to the next multiple 514 // Make sure that next_output_time_ms is rounded up to the next multiple
485 // of kOutputBlockSizeMs. (Legacy bit-exactness.) 515 // of kOutputBlockSizeMs. (Legacy bit-exactness.)
486 next_output_time_ms += 516 next_output_time_ms +=
487 kOutputBlockSizeMs - time_now_ms % kOutputBlockSizeMs; 517 kOutputBlockSizeMs - time_now_ms % kOutputBlockSizeMs;
488 } 518 }
489 while (packet_available) { 519
520 bool packet_available = true;
521 bool output_event_available = true;
522 if (!is_rtp_dump) {
523 next_output_time_ms = event_log_source->NextAudioOutputEventMs();
524 if (next_output_time_ms == std::numeric_limits<int64_t>::max())
525 output_event_available = false;
526 start_time_ms = time_now_ms =
527 std::min(next_input_time_ms, next_output_time_ms);
528 }
529 while (packet_available || output_event_available) {
530 // Advance time to next event.
531 time_now_ms = std::min(next_input_time_ms, next_output_time_ms);
490 // Check if it is time to insert packet. 532 // Check if it is time to insert packet.
491 while (time_now_ms >= next_input_time_ms && packet_available) { 533 while (time_now_ms >= next_input_time_ms && packet_available) {
492 assert(packet->virtual_payload_length_bytes() > 0); 534 assert(packet->virtual_payload_length_bytes() > 0);
493 // Parse RTP header. 535 // Parse RTP header.
494 WebRtcRTPHeader rtp_header; 536 WebRtcRTPHeader rtp_header;
495 packet->ConvertHeader(&rtp_header); 537 packet->ConvertHeader(&rtp_header);
496 const uint8_t* payload_ptr = packet->payload(); 538 const uint8_t* payload_ptr = packet->payload();
497 size_t payload_len = packet->payload_length_bytes(); 539 size_t payload_len = packet->payload_length_bytes();
498 if (replace_payload) { 540 if (replace_payload) {
499 payload_len = ReplacePayload(replacement_audio_file.get(), 541 payload_len = ReplacePayload(replacement_audio_file.get(),
500 &replacement_audio, 542 &replacement_audio,
501 &payload, 543 &payload,
502 &payload_mem_size_bytes, 544 &payload_mem_size_bytes,
503 &input_frame_size_timestamps, 545 &input_frame_size_timestamps,
504 &rtp_header, 546 &rtp_header,
505 next_packet.get()); 547 next_packet.get());
506 payload_ptr = payload.get(); 548 payload_ptr = payload.get();
507 } 549 }
508 int error = 550 int error = neteq->InsertPacket(
509 neteq->InsertPacket(rtp_header, 551 rtp_header, payload_ptr, payload_len,
510 payload_ptr, 552 static_cast<uint32_t>(packet->time_ms() * sample_rate_hz / 1000));
511 payload_len,
512 packet->time_ms() * sample_rate_hz / 1000);
513 if (error != NetEq::kOK) { 553 if (error != NetEq::kOK) {
514 if (neteq->LastError() == NetEq::kUnknownRtpPayloadType) { 554 if (neteq->LastError() == NetEq::kUnknownRtpPayloadType) {
515 std::cerr << "RTP Payload type " 555 std::cerr << "RTP Payload type "
516 << static_cast<int>(rtp_header.header.payloadType) 556 << static_cast<int>(rtp_header.header.payloadType)
517 << " is unknown." << std::endl; 557 << " is unknown." << std::endl;
518 std::cerr << "Use --codec_map to view default mapping." << std::endl; 558 std::cerr << "Use --codec_map to view default mapping." << std::endl;
519 std::cerr << "Use --helpshort for information on how to make custom " 559 std::cerr << "Use --helpshort for information on how to make custom "
520 "mappings." << std::endl; 560 "mappings." << std::endl;
521 } else { 561 } else {
522 std::cerr << "InsertPacket returned error code " << neteq->LastError() 562 std::cerr << "InsertPacket returned error code " << neteq->LastError()
523 << std::endl; 563 << std::endl;
524 std::cerr << "Header data:" << std::endl; 564 std::cerr << "Header data:" << std::endl;
525 std::cerr << " PT = " 565 std::cerr << " PT = "
526 << static_cast<int>(rtp_header.header.payloadType) 566 << static_cast<int>(rtp_header.header.payloadType)
527 << std::endl; 567 << std::endl;
528 std::cerr << " SN = " << rtp_header.header.sequenceNumber 568 std::cerr << " SN = " << rtp_header.header.sequenceNumber
529 << std::endl; 569 << std::endl;
530 std::cerr << " TS = " << rtp_header.header.timestamp << std::endl; 570 std::cerr << " TS = " << rtp_header.header.timestamp << std::endl;
531 } 571 }
532 } 572 }
533 573
534 // Get next packet from file. 574 // Get next packet from file.
535 webrtc::test::Packet* temp_packet = file_source->NextPacket(); 575 webrtc::test::Packet* temp_packet = file_source->NextPacket();
536 if (temp_packet) { 576 if (temp_packet) {
537 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 = rtc::checked_cast<int64_t>(packet->time_ms());
538 } 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();
539 packet_available = false; 593 packet_available = false;
540 } 594 }
541 if (replace_payload) {
542 // At this point |packet| contains the packet *after* |next_packet|.
543 // Swap Packet objects between |packet| and |next_packet|.
544 packet.swap(next_packet);
545 // Swap the status indicators unless they're already the same.
546 if (packet_available != next_packet_available) {
547 packet_available = !packet_available;
548 next_packet_available = !next_packet_available;
549 }
550 }
551 next_input_time_ms = packet->time_ms();
552 } 595 }
553 596
554 // Check if it is time to get output audio. 597 // Check if it is time to get output audio.
555 if (time_now_ms >= next_output_time_ms) { 598 while (time_now_ms >= next_output_time_ms && output_event_available) {
556 static const size_t kOutDataLen = 599 static const size_t kOutDataLen =
557 kOutputBlockSizeMs * kMaxSamplesPerMs * kMaxChannels; 600 kOutputBlockSizeMs * kMaxSamplesPerMs * kMaxChannels;
558 int16_t out_data[kOutDataLen]; 601 int16_t out_data[kOutDataLen];
559 int num_channels; 602 int num_channels;
560 size_t samples_per_channel; 603 size_t samples_per_channel;
561 int error = neteq->GetAudio(kOutDataLen, out_data, &samples_per_channel, 604 int error = neteq->GetAudio(kOutDataLen, out_data, &samples_per_channel,
562 &num_channels, NULL); 605 &num_channels, NULL);
563 if (error != NetEq::kOK) { 606 if (error != NetEq::kOK) {
564 std::cerr << "GetAudio returned error code " << 607 std::cerr << "GetAudio returned error code " <<
565 neteq->LastError() << std::endl; 608 neteq->LastError() << std::endl;
566 } else { 609 } else {
567 // Calculate sample rate from output size. 610 // Calculate sample rate from output size.
568 sample_rate_hz = rtc::checked_cast<int>( 611 sample_rate_hz = rtc::checked_cast<int>(
569 1000 * samples_per_channel / kOutputBlockSizeMs); 612 1000 * samples_per_channel / kOutputBlockSizeMs);
570 } 613 }
571 614
572 // Write to file. 615 // Write to file.
573 // TODO(hlundin): Make writing to file optional. 616 // TODO(hlundin): Make writing to file optional.
574 size_t write_len = samples_per_channel * num_channels; 617 size_t write_len = samples_per_channel * num_channels;
575 if (!output->WriteArray(out_data, write_len)) { 618 if (!output->WriteArray(out_data, write_len)) {
576 std::cerr << "Error while writing to file" << std::endl; 619 std::cerr << "Error while writing to file" << std::endl;
577 webrtc::Trace::ReturnTrace(); 620 webrtc::Trace::ReturnTrace();
578 exit(1); 621 exit(1);
579 } 622 }
580 next_output_time_ms += kOutputBlockSizeMs; 623 if (is_rtp_dump) {
624 next_output_time_ms += kOutputBlockSizeMs;
625 if (!packet_available)
626 output_event_available = false;
627 } else {
628 next_output_time_ms = event_log_source->NextAudioOutputEventMs();
629 if (next_output_time_ms == std::numeric_limits<int64_t>::max())
630 output_event_available = false;
631 }
581 } 632 }
582 // Advance time to next event.
583 time_now_ms = std::min(next_input_time_ms, next_output_time_ms);
584 } 633 }
585
586 printf("Simulation done\n"); 634 printf("Simulation done\n");
587 printf("Produced %i ms of audio\n", time_now_ms - start_time_ms); 635 printf("Produced %i ms of audio\n",
636 static_cast<int>(time_now_ms - start_time_ms));
588 637
589 delete neteq; 638 delete neteq;
590 webrtc::Trace::ReturnTrace(); 639 webrtc::Trace::ReturnTrace();
591 return 0; 640 return 0;
592 } 641 }
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