Replacing the legacy tool RTPencode with a new rtp_encode
This new tool provides the same functionality as the legacy tool, but it is implemented using AudioCodingModule and AudioEncoder APIs instead of the naked codecs. Bug: webrtc:2692 Change-Id: I29accd77d4ba5c7b5e1559853cbaf20ee812e6bc Reviewed-on: https://webrtc-review.googlesource.com/24861 Commit-Queue: Henrik Lundin <henrik.lundin@webrtc.org> Reviewed-by: Karl Wiberg <kwiberg@webrtc.org> Cr-Commit-Position: refs/heads/master@{#20857}
This commit is contained in:
committed by
Commit Bot
parent
bb5ca2ef41
commit
1391bd472c
@ -1190,7 +1190,6 @@ if (rtc_include_tests) {
|
||||
testonly = true
|
||||
public_deps = [
|
||||
":RTPchange",
|
||||
":RTPencode",
|
||||
":RTPjitter",
|
||||
":RTPtimeshift",
|
||||
":acm_receive_test",
|
||||
@ -1213,6 +1212,7 @@ if (rtc_include_tests) {
|
||||
":neteq_pcmu_quality_test",
|
||||
":neteq_speed_test",
|
||||
":rtp_analyze",
|
||||
":rtp_encode",
|
||||
":rtpcat",
|
||||
":webrtc_opus_fec_test",
|
||||
]
|
||||
@ -1645,65 +1645,27 @@ if (rtc_include_tests) {
|
||||
}
|
||||
}
|
||||
|
||||
config("RTPencode_config") {
|
||||
defines = [
|
||||
"CODEC_ILBC",
|
||||
"CODEC_PCM16B",
|
||||
"CODEC_G711",
|
||||
"CODEC_G722",
|
||||
"CODEC_ISAC",
|
||||
"CODEC_PCM16B_WB",
|
||||
"CODEC_ISAC_SWB",
|
||||
"CODEC_PCM16B_32KHZ",
|
||||
"CODEC_PCM16B_48KHZ",
|
||||
"CODEC_CNGCODEC8",
|
||||
"CODEC_CNGCODEC16",
|
||||
"CODEC_CNGCODEC32",
|
||||
"CODEC_ATEVENT_DECODE",
|
||||
"CODEC_RED",
|
||||
"CODEC_OPUS",
|
||||
]
|
||||
}
|
||||
|
||||
rtc_executable("RTPencode") {
|
||||
rtc_executable("rtp_encode") {
|
||||
testonly = true
|
||||
|
||||
deps = [
|
||||
# TODO(hlundin): Make RTPencode use ACM to encode files.
|
||||
":cng",
|
||||
":g711",
|
||||
":g722",
|
||||
":ilbc",
|
||||
":isac",
|
||||
":neteq",
|
||||
":neteq_test_tools_deprecated",
|
||||
":pcm16b",
|
||||
":webrtc_opus",
|
||||
"../..:webrtc_common",
|
||||
"../../common_audio",
|
||||
deps = audio_coding_deps + [
|
||||
":audio_coding",
|
||||
":neteq_input_audio_tools",
|
||||
"../../api/audio_codecs/g711:audio_encoder_g711",
|
||||
"../../api/audio_codecs/L16:audio_encoder_L16",
|
||||
"../../api/audio_codecs/g722:audio_encoder_g722",
|
||||
"../../api/audio_codecs/ilbc:audio_encoder_ilbc",
|
||||
"../../api/audio_codecs/isac:audio_encoder_isac",
|
||||
"../../api/audio_codecs/opus:audio_encoder_opus",
|
||||
"../../rtc_base:rtc_base_approved",
|
||||
"../../system_wrappers:metrics_default",
|
||||
"../../test:field_trial",
|
||||
"../../system_wrappers:system_wrappers_default",
|
||||
]
|
||||
|
||||
configs += [ ":RTPencode_config" ]
|
||||
|
||||
sources = [
|
||||
"neteq/test/PayloadTypes.h",
|
||||
"neteq/test/RTPencode.cc",
|
||||
"neteq/tools/rtp_encode.cc",
|
||||
]
|
||||
|
||||
include_dirs = [
|
||||
"neteq/include",
|
||||
"neteq/test",
|
||||
]
|
||||
|
||||
if (is_win) {
|
||||
cflags = [
|
||||
# Disable warnings to enable Win64 build, issue 1323.
|
||||
"/wd4267", # size_t to int truncation
|
||||
]
|
||||
}
|
||||
defines = audio_coding_defines
|
||||
}
|
||||
|
||||
rtc_executable("RTPchange") {
|
||||
|
||||
@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/* PayloadTypes.h */
|
||||
/* Used by RTPencode application */
|
||||
// TODO(henrik.lundin) Remove this once RTPencode is refactored.
|
||||
|
||||
/* RTP defined codepoints */
|
||||
#define NETEQ_CODEC_PCMU_PT 0
|
||||
#define NETEQ_CODEC_PCMA_PT 8
|
||||
#define NETEQ_CODEC_G722_PT 9
|
||||
#define NETEQ_CODEC_CN_PT 13
|
||||
|
||||
/* Dynamic RTP codepoints */
|
||||
#define NETEQ_CODEC_ILBC_PT 102
|
||||
#define NETEQ_CODEC_ISAC_PT 103
|
||||
#define NETEQ_CODEC_ISACSWB_PT 104
|
||||
#define NETEQ_CODEC_AVT_PT 106
|
||||
#define NETEQ_CODEC_OPUS_PT 111
|
||||
#define NETEQ_CODEC_RED_PT 117
|
||||
#define NETEQ_CODEC_CN_WB_PT 105
|
||||
#define NETEQ_CODEC_CN_SWB_PT 126
|
||||
#define NETEQ_CODEC_PCM16B_PT 93
|
||||
#define NETEQ_CODEC_PCM16B_WB_PT 94
|
||||
#define NETEQ_CODEC_PCM16B_SWB32KHZ_PT 95
|
||||
#define NETEQ_CODEC_PCM16B_SWB48KHZ_PT 96
|
||||
File diff suppressed because it is too large
Load Diff
@ -15,7 +15,8 @@
|
||||
namespace webrtc {
|
||||
namespace test {
|
||||
|
||||
InputAudioFile::InputAudioFile(const std::string file_name) {
|
||||
InputAudioFile::InputAudioFile(const std::string file_name, bool loop_at_end)
|
||||
: loop_at_end_(loop_at_end) {
|
||||
fp_ = fopen(file_name.c_str(), "rb");
|
||||
}
|
||||
|
||||
@ -27,6 +28,9 @@ bool InputAudioFile::Read(size_t samples, int16_t* destination) {
|
||||
}
|
||||
size_t samples_read = fread(destination, sizeof(int16_t), samples, fp_);
|
||||
if (samples_read < samples) {
|
||||
if (!loop_at_end_) {
|
||||
return false;
|
||||
}
|
||||
// Rewind and read the missing samples.
|
||||
rewind(fp_);
|
||||
size_t missing_samples = samples - samples_read;
|
||||
@ -54,7 +58,11 @@ bool InputAudioFile::Seek(int samples) {
|
||||
long new_pos = current_pos + sizeof(int16_t) * samples; // Samples to bytes.
|
||||
RTC_CHECK_GE(new_pos, 0)
|
||||
<< "Trying to move to before the beginning of the file";
|
||||
if (loop_at_end_) {
|
||||
new_pos = new_pos % file_size; // Wrap around the end of the file.
|
||||
} else {
|
||||
new_pos = new_pos > file_size ? file_size : new_pos; // Don't loop.
|
||||
}
|
||||
// Move to new position relative to the beginning of the file.
|
||||
RTC_CHECK_EQ(0, fseek(fp_, new_pos, SEEK_SET));
|
||||
return true;
|
||||
|
||||
@ -24,7 +24,7 @@ namespace test {
|
||||
// Class for handling a looping input audio file.
|
||||
class InputAudioFile {
|
||||
public:
|
||||
explicit InputAudioFile(const std::string file_name);
|
||||
explicit InputAudioFile(const std::string file_name, bool loop_at_end = true);
|
||||
|
||||
virtual ~InputAudioFile();
|
||||
|
||||
@ -50,6 +50,7 @@ class InputAudioFile {
|
||||
|
||||
private:
|
||||
FILE* fp_;
|
||||
const bool loop_at_end_;
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(InputAudioFile);
|
||||
};
|
||||
|
||||
|
||||
355
modules/audio_coding/neteq/tools/rtp_encode.cc
Normal file
355
modules/audio_coding/neteq/tools/rtp_encode.cc
Normal file
@ -0,0 +1,355 @@
|
||||
/*
|
||||
* Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <winsock2.h>
|
||||
#endif
|
||||
#ifdef WEBRTC_LINUX
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "api/audio_codecs/L16/audio_encoder_L16.h"
|
||||
#include "api/audio_codecs/g711/audio_encoder_g711.h"
|
||||
#include "api/audio_codecs/g722/audio_encoder_g722.h"
|
||||
#include "api/audio_codecs/ilbc/audio_encoder_ilbc.h"
|
||||
#include "api/audio_codecs/isac/audio_encoder_isac.h"
|
||||
#include "api/audio_codecs/opus/audio_encoder_opus.h"
|
||||
#include "modules/audio_coding/codecs/cng/audio_encoder_cng.h"
|
||||
#include "modules/audio_coding/include/audio_coding_module.h"
|
||||
#include "modules/audio_coding/neteq/tools/input_audio_file.h"
|
||||
#include "rtc_base/flags.h"
|
||||
#include "rtc_base/numerics/safe_conversions.h"
|
||||
#include "rtc_base/ptr_util.h"
|
||||
#include "typedefs.h" // NOLINT(build/include)
|
||||
|
||||
namespace webrtc {
|
||||
namespace test {
|
||||
namespace {
|
||||
|
||||
// Define command line flags.
|
||||
DEFINE_bool(list_codecs, false, "Enumerate all codecs");
|
||||
DEFINE_string(codec, "opus", "Codec to use");
|
||||
DEFINE_int(frame_len, 0, "Frame length in ms; 0 indicates codec default value");
|
||||
DEFINE_int(bitrate, 0, "Bitrate in kbps; 0 indicates codec default value");
|
||||
DEFINE_int(payload_type,
|
||||
-1,
|
||||
"RTP payload type; -1 indicates codec default value");
|
||||
DEFINE_int(cng_payload_type,
|
||||
-1,
|
||||
"RTP payload type for CNG; -1 indicates default value");
|
||||
DEFINE_int(ssrc, 0, "SSRC to write to the RTP header");
|
||||
DEFINE_bool(dtx, false, "Use DTX/CNG");
|
||||
DEFINE_int(sample_rate, 48000, "Sample rate of the input file");
|
||||
DEFINE_bool(help, false, "Print this message");
|
||||
|
||||
// Add new codecs here, and to the map below.
|
||||
enum class CodecType {
|
||||
kOpus,
|
||||
kPcmU,
|
||||
kPcmA,
|
||||
kG722,
|
||||
kPcm16b8,
|
||||
kPcm16b16,
|
||||
kPcm16b32,
|
||||
kPcm16b48,
|
||||
kIlbc,
|
||||
kIsac
|
||||
};
|
||||
|
||||
struct CodecTypeAndInfo {
|
||||
CodecType type;
|
||||
int default_payload_type;
|
||||
bool internal_dtx;
|
||||
};
|
||||
|
||||
// List all supported codecs here. This map defines the command-line parameter
|
||||
// value (the key string) for selecting each codec, together with information
|
||||
// whether it is using internal or external DTX/CNG.
|
||||
const std::map<std::string, CodecTypeAndInfo>& CodecList() {
|
||||
static const auto* const codec_list =
|
||||
new std::map<std::string, CodecTypeAndInfo>{
|
||||
{"opus", {CodecType::kOpus, 111, true}},
|
||||
{"pcmu", {CodecType::kPcmU, 0, false}},
|
||||
{"pcma", {CodecType::kPcmA, 8, false}},
|
||||
{"g722", {CodecType::kG722, 9, false}},
|
||||
{"pcm16b_8", {CodecType::kPcm16b8, 93, false}},
|
||||
{"pcm16b_16", {CodecType::kPcm16b16, 94, false}},
|
||||
{"pcm16b_32", {CodecType::kPcm16b32, 95, false}},
|
||||
{"pcm16b_48", {CodecType::kPcm16b48, 96, false}},
|
||||
{"ilbc", {CodecType::kIlbc, 102, false}},
|
||||
{"isac", {CodecType::kIsac, 103, false}}};
|
||||
return *codec_list;
|
||||
}
|
||||
|
||||
// This class will receive callbacks from ACM when a packet is ready, and write
|
||||
// it to the output file.
|
||||
class Packetizer : public AudioPacketizationCallback {
|
||||
public:
|
||||
Packetizer(FILE* out_file, uint32_t ssrc, int timestamp_rate_hz)
|
||||
: out_file_(out_file),
|
||||
ssrc_(ssrc),
|
||||
timestamp_rate_hz_(timestamp_rate_hz) {}
|
||||
|
||||
int32_t SendData(FrameType frame_type,
|
||||
uint8_t payload_type,
|
||||
uint32_t timestamp,
|
||||
const uint8_t* payload_data,
|
||||
size_t payload_len_bytes,
|
||||
const RTPFragmentationHeader* fragmentation) override {
|
||||
RTC_CHECK(!fragmentation);
|
||||
RTC_DCHECK_GT(payload_len_bytes, 0);
|
||||
|
||||
constexpr size_t kRtpHeaderLength = 12;
|
||||
constexpr size_t kRtpDumpHeaderLength = 8;
|
||||
const uint16_t length = htons(rtc::checked_cast<uint16_t>(
|
||||
kRtpHeaderLength + kRtpDumpHeaderLength + payload_len_bytes));
|
||||
const uint16_t plen = htons(
|
||||
rtc::checked_cast<uint16_t>(kRtpHeaderLength + payload_len_bytes));
|
||||
const uint32_t offset = htonl(timestamp / (timestamp_rate_hz_ / 1000));
|
||||
RTC_CHECK_EQ(fwrite(&length, sizeof(uint16_t), 1, out_file_), 1);
|
||||
RTC_CHECK_EQ(fwrite(&plen, sizeof(uint16_t), 1, out_file_), 1);
|
||||
RTC_CHECK_EQ(fwrite(&offset, sizeof(uint32_t), 1, out_file_), 1);
|
||||
|
||||
const uint8_t rtp_header[] = {0x80,
|
||||
static_cast<uint8_t>(payload_type & 0x7F),
|
||||
static_cast<uint8_t>(sequence_number_ >> 8),
|
||||
static_cast<uint8_t>(sequence_number_),
|
||||
static_cast<uint8_t>(timestamp >> 24),
|
||||
static_cast<uint8_t>(timestamp >> 16),
|
||||
static_cast<uint8_t>(timestamp >> 8),
|
||||
static_cast<uint8_t>(timestamp),
|
||||
static_cast<uint8_t>(ssrc_ >> 24),
|
||||
static_cast<uint8_t>(ssrc_ >> 16),
|
||||
static_cast<uint8_t>(ssrc_ >> 8),
|
||||
static_cast<uint8_t>(ssrc_)};
|
||||
static_assert(sizeof(rtp_header) == kRtpHeaderLength, "");
|
||||
RTC_CHECK_EQ(
|
||||
fwrite(rtp_header, sizeof(uint8_t), kRtpHeaderLength, out_file_),
|
||||
kRtpHeaderLength);
|
||||
++sequence_number_; // Intended to wrap on overflow.
|
||||
|
||||
RTC_CHECK_EQ(
|
||||
fwrite(payload_data, sizeof(uint8_t), payload_len_bytes, out_file_),
|
||||
payload_len_bytes);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
FILE* const out_file_;
|
||||
const uint32_t ssrc_;
|
||||
const int timestamp_rate_hz_;
|
||||
uint16_t sequence_number_ = 0;
|
||||
};
|
||||
|
||||
void SetFrameLenIfFlagIsPositive(int* config_frame_len) {
|
||||
if (FLAG_frame_len > 0) {
|
||||
*config_frame_len = FLAG_frame_len;
|
||||
}
|
||||
}
|
||||
|
||||
AudioEncoderL16::Config Pcm16bConfig(CodecType codec_type) {
|
||||
AudioEncoderL16::Config config;
|
||||
SetFrameLenIfFlagIsPositive(&config.frame_size_ms);
|
||||
switch (codec_type) {
|
||||
case CodecType::kPcm16b8:
|
||||
config.sample_rate_hz = 8000;
|
||||
return config;
|
||||
case CodecType::kPcm16b16:
|
||||
config.sample_rate_hz = 16000;
|
||||
return config;
|
||||
case CodecType::kPcm16b32:
|
||||
config.sample_rate_hz = 32000;
|
||||
return config;
|
||||
case CodecType::kPcm16b48:
|
||||
config.sample_rate_hz = 48000;
|
||||
return config;
|
||||
default:
|
||||
RTC_NOTREACHED();
|
||||
return config;
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<AudioEncoder> CreateEncoder(CodecType codec_type,
|
||||
int payload_type) {
|
||||
switch (codec_type) {
|
||||
case CodecType::kOpus: {
|
||||
AudioEncoderOpusConfig config;
|
||||
if (FLAG_bitrate > 0) {
|
||||
config.bitrate_bps = FLAG_bitrate;
|
||||
}
|
||||
config.dtx_enabled = FLAG_dtx;
|
||||
SetFrameLenIfFlagIsPositive(&config.frame_size_ms);
|
||||
RTC_CHECK(config.IsOk());
|
||||
return AudioEncoderOpus::MakeAudioEncoder(config, payload_type);
|
||||
}
|
||||
|
||||
case CodecType::kPcmU:
|
||||
case CodecType::kPcmA: {
|
||||
AudioEncoderG711::Config config;
|
||||
SetFrameLenIfFlagIsPositive(&config.frame_size_ms);
|
||||
config.type = codec_type == CodecType::kPcmU
|
||||
? AudioEncoderG711::Config::Type::kPcmU
|
||||
: AudioEncoderG711::Config::Type::kPcmA;
|
||||
RTC_CHECK(config.IsOk());
|
||||
return AudioEncoderG711::MakeAudioEncoder(config, payload_type);
|
||||
}
|
||||
|
||||
case CodecType::kG722: {
|
||||
AudioEncoderG722Config config;
|
||||
SetFrameLenIfFlagIsPositive(&config.frame_size_ms);
|
||||
RTC_CHECK(config.IsOk());
|
||||
return AudioEncoderG722::MakeAudioEncoder(config, payload_type);
|
||||
}
|
||||
|
||||
case CodecType::kPcm16b8:
|
||||
case CodecType::kPcm16b16:
|
||||
case CodecType::kPcm16b32:
|
||||
case CodecType::kPcm16b48: {
|
||||
return AudioEncoderL16::MakeAudioEncoder(Pcm16bConfig(codec_type),
|
||||
payload_type);
|
||||
}
|
||||
|
||||
case CodecType::kIlbc: {
|
||||
AudioEncoderIlbcConfig config;
|
||||
SetFrameLenIfFlagIsPositive(&config.frame_size_ms);
|
||||
RTC_CHECK(config.IsOk());
|
||||
return AudioEncoderIlbc::MakeAudioEncoder(config, payload_type);
|
||||
}
|
||||
|
||||
case CodecType::kIsac: {
|
||||
AudioEncoderIsac::Config config;
|
||||
SetFrameLenIfFlagIsPositive(&config.frame_size_ms);
|
||||
RTC_CHECK(config.IsOk());
|
||||
return AudioEncoderIsac::MakeAudioEncoder(config, payload_type);
|
||||
}
|
||||
}
|
||||
RTC_NOTREACHED();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AudioEncoderCng::Config GetCngConfig(int sample_rate_hz) {
|
||||
AudioEncoderCng::Config cng_config;
|
||||
const auto default_payload_type = [&] {
|
||||
switch (sample_rate_hz) {
|
||||
case 8000: return 13;
|
||||
case 16000: return 98;
|
||||
case 32000: return 99;
|
||||
case 48000: return 100;
|
||||
default: RTC_NOTREACHED();
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
cng_config.payload_type = FLAG_cng_payload_type != -1
|
||||
? FLAG_cng_payload_type
|
||||
: default_payload_type();
|
||||
return cng_config;
|
||||
}
|
||||
|
||||
int RunRtpEncode(int argc, char* argv[]) {
|
||||
const std::string program_name = argv[0];
|
||||
const std::string usage =
|
||||
"Tool for generating an RTP dump file from audio input.\n"
|
||||
"Run " +
|
||||
program_name +
|
||||
" --help for usage.\n"
|
||||
"Example usage:\n" +
|
||||
program_name + " input.pcm output.rtp --codec=[codec] " +
|
||||
"--frame_len=[frame_len] --bitrate=[bitrate]\n\n";
|
||||
if (rtc::FlagList::SetFlagsFromCommandLine(&argc, argv, true) || FLAG_help ||
|
||||
(!FLAG_list_codecs && argc != 3)) {
|
||||
printf("%s", usage.c_str());
|
||||
if (FLAG_help) {
|
||||
rtc::FlagList::Print(nullptr, false);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (FLAG_list_codecs) {
|
||||
printf("The following arguments are valid --codec parameters:\n");
|
||||
for (const auto& c : CodecList()) {
|
||||
printf(" %s\n", c.first.c_str());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto codec_it = CodecList().find(FLAG_codec);
|
||||
if (codec_it == CodecList().end()) {
|
||||
printf("%s is not a valid codec name.\n", FLAG_codec);
|
||||
printf("Use argument --list_codecs to see all valid codec names.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Create the codec.
|
||||
const int payload_type = FLAG_payload_type == -1
|
||||
? codec_it->second.default_payload_type
|
||||
: FLAG_payload_type;
|
||||
std::unique_ptr<AudioEncoder> codec =
|
||||
CreateEncoder(codec_it->second.type, payload_type);
|
||||
|
||||
// Create an external VAD/CNG encoder if needed.
|
||||
if (FLAG_dtx && codec_it->second.internal_dtx) {
|
||||
AudioEncoderCng::Config cng_config = GetCngConfig(codec->SampleRateHz());
|
||||
RTC_DCHECK(codec);
|
||||
cng_config.speech_encoder = std::move(codec);
|
||||
codec = rtc::MakeUnique<AudioEncoderCng>(std::move(cng_config));
|
||||
}
|
||||
RTC_DCHECK(codec);
|
||||
|
||||
// Set up ACM.
|
||||
const int timestamp_rate_hz = codec->RtpTimestampRateHz();
|
||||
AudioCodingModule::Config config;
|
||||
std::unique_ptr<AudioCodingModule> acm(AudioCodingModule::Create(config));
|
||||
acm->SetEncoder(std::move(codec));
|
||||
|
||||
// Open files.
|
||||
printf("Input file: %s\n", argv[1]);
|
||||
InputAudioFile input_file(argv[1], false); // Open input in non-looping mode.
|
||||
FILE* out_file = fopen(argv[2], "wb");
|
||||
RTC_CHECK(out_file) << "Could not open file " << argv[2] << " for writing";
|
||||
printf("Output file: %s\n", argv[2]);
|
||||
fprintf(out_file, "#!rtpplay1.0 \n"); //,
|
||||
// Write 3 32-bit values followed by 2 16-bit values, all set to 0. This means
|
||||
// a total of 16 bytes.
|
||||
const uint8_t file_header[16] = {0};
|
||||
RTC_CHECK_EQ(fwrite(file_header, sizeof(file_header), 1, out_file), 1);
|
||||
|
||||
// Create and register the packetizer, which will write the packets to file.
|
||||
Packetizer packetizer(out_file, FLAG_ssrc, timestamp_rate_hz);
|
||||
RTC_DCHECK_EQ(acm->RegisterTransportCallback(&packetizer), 0);
|
||||
|
||||
AudioFrame audio_frame;
|
||||
audio_frame.samples_per_channel_ = FLAG_sample_rate / 100; // 10 ms
|
||||
audio_frame.sample_rate_hz_ = FLAG_sample_rate;
|
||||
audio_frame.num_channels_ = 1;
|
||||
|
||||
while (input_file.Read(audio_frame.samples_per_channel_,
|
||||
audio_frame.mutable_data())) {
|
||||
RTC_CHECK_GE(acm->Add10MsData(audio_frame), 0);
|
||||
audio_frame.timestamp_ += audio_frame.samples_per_channel_;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace test
|
||||
} // namespace webrtc
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
return webrtc::test::RunRtpEncode(argc, argv);
|
||||
}
|
||||
Reference in New Issue
Block a user