| /* |
| * 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. |
| */ |
| |
| #include <assert.h> |
| #include <stdio.h> |
| #include <vector> |
| |
| #include "google/gflags.h" |
| #include "webrtc/base/scoped_ptr.h" |
| #include "webrtc/modules/audio_coding/neteq/tools/packet.h" |
| #include "webrtc/modules/audio_coding/neteq/tools/rtp_file_source.h" |
| |
| // Flag validator. |
| static bool ValidatePayloadType(const char* flagname, int32_t value) { |
| if (value >= 0 && value <= 127) // Value is ok. |
| return true; |
| printf("Invalid value for --%s: %d\n", flagname, static_cast<int>(value)); |
| return false; |
| } |
| static bool ValidateExtensionId(const char* flagname, int32_t value) { |
| if (value > 0 && value <= 255) // Value is ok. |
| return true; |
| printf("Invalid value for --%s: %d\n", flagname, static_cast<int>(value)); |
| return false; |
| } |
| |
| // Define command line flags. |
| DEFINE_int32(red, 117, "RTP payload type for RED"); |
| static const bool red_dummy = |
| google::RegisterFlagValidator(&FLAGS_red, &ValidatePayloadType); |
| DEFINE_int32(audio_level, 1, "Extension ID for audio level (RFC 6464)"); |
| static const bool audio_level_dummy = |
| google::RegisterFlagValidator(&FLAGS_audio_level, &ValidateExtensionId); |
| DEFINE_int32(abs_send_time, 3, "Extension ID for absolute sender time"); |
| static const bool abs_send_time_dummy = |
| google::RegisterFlagValidator(&FLAGS_abs_send_time, &ValidateExtensionId); |
| |
| int main(int argc, char* argv[]) { |
| std::string program_name = argv[0]; |
| std::string usage = |
| "Tool for parsing an RTP dump file to text output.\n" |
| "Run " + |
| program_name + |
| " --helpshort for usage.\n" |
| "Example usage:\n" + |
| program_name + " input.rtp output.txt\n\n" + |
| "Output is sent to stdout if no output file is given." + |
| "Note that this tool can read files with our without payloads."; |
| google::SetUsageMessage(usage); |
| google::ParseCommandLineFlags(&argc, &argv, true); |
| |
| if (argc != 2 && argc != 3) { |
| // Print usage information. |
| printf("%s", google::ProgramUsage()); |
| return 0; |
| } |
| |
| printf("Input file: %s\n", argv[1]); |
| rtc::scoped_ptr<webrtc::test::RtpFileSource> file_source( |
| webrtc::test::RtpFileSource::Create(argv[1])); |
| assert(file_source.get()); |
| // Set RTP extension IDs. |
| bool print_audio_level = false; |
| if (!google::GetCommandLineFlagInfoOrDie("audio_level").is_default) { |
| print_audio_level = true; |
| file_source->RegisterRtpHeaderExtension(webrtc::kRtpExtensionAudioLevel, |
| FLAGS_audio_level); |
| } |
| bool print_abs_send_time = false; |
| if (!google::GetCommandLineFlagInfoOrDie("abs_send_time").is_default) { |
| print_abs_send_time = true; |
| file_source->RegisterRtpHeaderExtension( |
| webrtc::kRtpExtensionAbsoluteSendTime, FLAGS_abs_send_time); |
| } |
| |
| FILE* out_file; |
| if (argc == 3) { |
| out_file = fopen(argv[2], "wt"); |
| if (!out_file) { |
| printf("Cannot open output file %s\n", argv[2]); |
| return -1; |
| } |
| printf("Output file: %s\n\n", argv[2]); |
| } else { |
| out_file = stdout; |
| } |
| |
| // Print file header. |
| fprintf(out_file, "SeqNo TimeStamp SendTime Size PT M SSRC"); |
| if (print_audio_level) { |
| fprintf(out_file, " AuLvl (V)"); |
| } |
| if (print_abs_send_time) { |
| fprintf(out_file, " AbsSendTime"); |
| } |
| fprintf(out_file, "\n"); |
| |
| uint32_t max_abs_send_time = 0; |
| int cycles = -1; |
| rtc::scoped_ptr<webrtc::test::Packet> packet; |
| while (true) { |
| packet.reset(file_source->NextPacket()); |
| if (!packet.get()) { |
| // End of file reached. |
| break; |
| } |
| // Write packet data to file. Use virtual_packet_length_bytes so that the |
| // correct packet sizes are printed also for RTP header-only dumps. |
| fprintf(out_file, |
| "%5u %10u %10u %5i %5i %2i %#08X", |
| packet->header().sequenceNumber, |
| packet->header().timestamp, |
| static_cast<unsigned int>(packet->time_ms()), |
| static_cast<int>(packet->virtual_packet_length_bytes()), |
| packet->header().payloadType, |
| packet->header().markerBit, |
| packet->header().ssrc); |
| if (print_audio_level && packet->header().extension.hasAudioLevel) { |
| // |audioLevel| consists of one bit for "V" and then 7 bits level. |
| fprintf(out_file, |
| " %5u (%1i)", |
| packet->header().extension.audioLevel & 0x7F, |
| (packet->header().extension.audioLevel & 0x80) == 0 ? 0 : 1); |
| } |
| if (print_abs_send_time && packet->header().extension.hasAbsoluteSendTime) { |
| if (cycles == -1) { |
| // Initialize. |
| max_abs_send_time = packet->header().extension.absoluteSendTime; |
| cycles = 0; |
| } |
| // Abs sender time is 24 bit 6.18 fixed point. Shift by 8 to normalize to |
| // 32 bits (unsigned). Calculate the difference between this packet's |
| // send time and the maximum observed. Cast to signed 32-bit to get the |
| // desired wrap-around behavior. |
| if (static_cast<int32_t>( |
| (packet->header().extension.absoluteSendTime << 8) - |
| (max_abs_send_time << 8)) >= 0) { |
| // The difference is non-negative, meaning that this packet is newer |
| // than the previously observed maximum absolute send time. |
| if (packet->header().extension.absoluteSendTime < max_abs_send_time) { |
| // Wrap detected. |
| cycles++; |
| } |
| max_abs_send_time = packet->header().extension.absoluteSendTime; |
| } |
| // Abs sender time is 24 bit 6.18 fixed point. Divide by 2^18 to convert |
| // to floating point representation. |
| double send_time_seconds = |
| static_cast<double>(packet->header().extension.absoluteSendTime) / |
| 262144 + |
| 64.0 * cycles; |
| fprintf(out_file, " %11f", send_time_seconds); |
| } |
| fprintf(out_file, "\n"); |
| |
| if (packet->header().payloadType == FLAGS_red) { |
| std::list<webrtc::RTPHeader*> red_headers; |
| packet->ExtractRedHeaders(&red_headers); |
| while (!red_headers.empty()) { |
| webrtc::RTPHeader* red = red_headers.front(); |
| assert(red); |
| fprintf(out_file, |
| "* %5u %10u %10u %5i\n", |
| red->sequenceNumber, |
| red->timestamp, |
| static_cast<unsigned int>(packet->time_ms()), |
| red->payloadType); |
| red_headers.pop_front(); |
| delete red; |
| } |
| } |
| } |
| |
| fclose(out_file); |
| |
| return 0; |
| } |