• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
3  *
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
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "test/rtp_file_reader.h"
12 
13 #include <assert.h>
14 #include <stdio.h>
15 
16 #include <map>
17 #include <string>
18 #include <vector>
19 
20 #include "modules/rtp_rtcp/source/rtp_utility.h"
21 #include "rtc_base/checks.h"
22 #include "rtc_base/constructor_magic.h"
23 #include "rtc_base/format_macros.h"
24 #include "rtc_base/logging.h"
25 #include "rtc_base/system/arch.h"
26 
27 namespace webrtc {
28 namespace test {
29 
30 static const size_t kFirstLineLength = 80;
31 static uint16_t kPacketHeaderSize = 8;
32 
33 #define TRY(expr)                           \
34   do {                                      \
35     if (!(expr)) {                          \
36       RTC_LOG(LS_INFO) << "Failed to read"; \
37       return false;                         \
38     }                                       \
39   } while (0)
40 
ReadUint32(uint32_t * out,FILE * file)41 bool ReadUint32(uint32_t* out, FILE* file) {
42   *out = 0;
43   for (size_t i = 0; i < 4; ++i) {
44     *out <<= 8;
45     uint8_t tmp;
46     if (fread(&tmp, 1, sizeof(uint8_t), file) != sizeof(uint8_t))
47       return false;
48     *out |= tmp;
49   }
50   return true;
51 }
52 
ReadUint16(uint16_t * out,FILE * file)53 bool ReadUint16(uint16_t* out, FILE* file) {
54   *out = 0;
55   for (size_t i = 0; i < 2; ++i) {
56     *out <<= 8;
57     uint8_t tmp;
58     if (fread(&tmp, 1, sizeof(uint8_t), file) != sizeof(uint8_t))
59       return false;
60     *out |= tmp;
61   }
62   return true;
63 }
64 
65 class RtpFileReaderImpl : public RtpFileReader {
66  public:
67   virtual bool Init(FILE* file, const std::set<uint32_t>& ssrc_filter) = 0;
68 };
69 
70 class InterleavedRtpFileReader : public RtpFileReaderImpl {
71  public:
~InterleavedRtpFileReader()72   ~InterleavedRtpFileReader() override {
73     if (file_ != nullptr) {
74       fclose(file_);
75       file_ = nullptr;
76     }
77   }
78 
Init(FILE * file,const std::set<uint32_t> & ssrc_filter)79   bool Init(FILE* file, const std::set<uint32_t>& ssrc_filter) override {
80     file_ = file;
81     return true;
82   }
83 
NextPacket(RtpPacket * packet)84   bool NextPacket(RtpPacket* packet) override {
85     assert(file_ != nullptr);
86     packet->length = RtpPacket::kMaxPacketBufferSize;
87     uint32_t len = 0;
88     TRY(ReadUint32(&len, file_));
89     if (packet->length < len) {
90       FATAL() << "Packet is too large to fit: " << len << " bytes vs "
91               << packet->length
92               << " bytes allocated. Consider increasing the buffer "
93                  "size";
94     }
95     if (fread(packet->data, 1, len, file_) != len)
96       return false;
97 
98     packet->length = len;
99     packet->original_length = len;
100     packet->time_ms = time_ms_;
101     time_ms_ += 5;
102     return true;
103   }
104 
105  private:
106   FILE* file_ = nullptr;
107   int64_t time_ms_ = 0;
108 };
109 
110 // Read RTP packets from file in rtpdump format, as documented at:
111 // http://www.cs.columbia.edu/irt/software/rtptools/
112 class RtpDumpReader : public RtpFileReaderImpl {
113  public:
RtpDumpReader()114   RtpDumpReader() : file_(nullptr) {}
~RtpDumpReader()115   ~RtpDumpReader() override {
116     if (file_ != nullptr) {
117       fclose(file_);
118       file_ = nullptr;
119     }
120   }
121 
Init(FILE * file,const std::set<uint32_t> & ssrc_filter)122   bool Init(FILE* file, const std::set<uint32_t>& ssrc_filter) override {
123     file_ = file;
124 
125     char firstline[kFirstLineLength + 1] = {0};
126     if (fgets(firstline, kFirstLineLength, file_) == nullptr) {
127       RTC_LOG(LS_INFO) << "Can't read from file";
128       return false;
129     }
130     if (strncmp(firstline, "#!rtpplay", 9) == 0) {
131       if (strncmp(firstline, "#!rtpplay1.0", 12) != 0) {
132         RTC_LOG(LS_INFO) << "Wrong rtpplay version, must be 1.0";
133         return false;
134       }
135     } else if (strncmp(firstline, "#!RTPencode", 11) == 0) {
136       if (strncmp(firstline, "#!RTPencode1.0", 14) != 0) {
137         RTC_LOG(LS_INFO) << "Wrong RTPencode version, must be 1.0";
138         return false;
139       }
140     } else {
141       RTC_LOG(LS_INFO) << "Wrong file format of input file";
142       return false;
143     }
144 
145     uint32_t start_sec;
146     uint32_t start_usec;
147     uint32_t source;
148     uint16_t port;
149     uint16_t padding;
150     TRY(ReadUint32(&start_sec, file_));
151     TRY(ReadUint32(&start_usec, file_));
152     TRY(ReadUint32(&source, file_));
153     TRY(ReadUint16(&port, file_));
154     TRY(ReadUint16(&padding, file_));
155 
156     return true;
157   }
158 
NextPacket(RtpPacket * packet)159   bool NextPacket(RtpPacket* packet) override {
160     uint8_t* rtp_data = packet->data;
161     packet->length = RtpPacket::kMaxPacketBufferSize;
162 
163     uint16_t len;
164     uint16_t plen;
165     uint32_t offset;
166     TRY(ReadUint16(&len, file_));
167     TRY(ReadUint16(&plen, file_));
168     TRY(ReadUint32(&offset, file_));
169 
170     // Use 'len' here because a 'plen' of 0 specifies rtcp.
171     len -= kPacketHeaderSize;
172     if (packet->length < len) {
173       RTC_LOG(LS_ERROR) << "Packet is too large to fit: " << len << " bytes vs "
174                         << packet->length
175                         << " bytes allocated. Consider increasing the buffer "
176                            "size";
177       return false;
178     }
179     if (fread(rtp_data, 1, len, file_) != len) {
180       return false;
181     }
182 
183     packet->length = len;
184     packet->original_length = plen;
185     packet->time_ms = offset;
186     return true;
187   }
188 
189  private:
190   FILE* file_;
191 
192   RTC_DISALLOW_COPY_AND_ASSIGN(RtpDumpReader);
193 };
194 
195 enum {
196   kResultFail = -1,
197   kResultSuccess = 0,
198   kResultSkip = 1,
199 
200   kPcapVersionMajor = 2,
201   kPcapVersionMinor = 4,
202   kLinktypeNull = 0,
203   kLinktypeEthernet = 1,
204   kBsdNullLoopback1 = 0x00000002,
205   kBsdNullLoopback2 = 0x02000000,
206   kEthernetIIHeaderMacSkip = 12,
207   kEthertypeIp = 0x0800,
208   kIpVersion4 = 4,
209   kMinIpHeaderLength = 20,
210   kFragmentOffsetClear = 0x0000,
211   kFragmentOffsetDoNotFragment = 0x4000,
212   kProtocolTcp = 0x06,
213   kProtocolUdp = 0x11,
214   kUdpHeaderLength = 8,
215   kMaxReadBufferSize = 4096
216 };
217 
218 const uint32_t kPcapBOMSwapOrder = 0xd4c3b2a1UL;
219 const uint32_t kPcapBOMNoSwapOrder = 0xa1b2c3d4UL;
220 
221 #define TRY_PCAP(expr)                                               \
222   do {                                                               \
223     int r = (expr);                                                  \
224     if (r == kResultFail) {                                          \
225       RTC_LOG(LS_INFO) << "FAIL at " << __FILE__ << ":" << __LINE__; \
226       return kResultFail;                                            \
227     } else if (r == kResultSkip) {                                   \
228       return kResultSkip;                                            \
229     }                                                                \
230   } while (0)
231 
232 // Read RTP packets from file in tcpdump/libpcap format, as documented at:
233 // http://wiki.wireshark.org/Development/LibpcapFileFormat
234 class PcapReader : public RtpFileReaderImpl {
235  public:
PcapReader()236   PcapReader()
237       : file_(nullptr),
238         swap_pcap_byte_order_(false),
239 #ifdef WEBRTC_ARCH_BIG_ENDIAN
240         swap_network_byte_order_(false),
241 #else
242         swap_network_byte_order_(true),
243 #endif
244         read_buffer_(),
245         packets_by_ssrc_(),
246         packets_(),
247         next_packet_it_() {
248   }
249 
~PcapReader()250   ~PcapReader() override {
251     if (file_ != nullptr) {
252       fclose(file_);
253       file_ = nullptr;
254     }
255   }
256 
Init(FILE * file,const std::set<uint32_t> & ssrc_filter)257   bool Init(FILE* file, const std::set<uint32_t>& ssrc_filter) override {
258     return Initialize(file, ssrc_filter) == kResultSuccess;
259   }
260 
Initialize(FILE * file,const std::set<uint32_t> & ssrc_filter)261   int Initialize(FILE* file, const std::set<uint32_t>& ssrc_filter) {
262     file_ = file;
263 
264     if (ReadGlobalHeader() < 0) {
265       return kResultFail;
266     }
267 
268     int total_packet_count = 0;
269     uint32_t stream_start_ms = 0;
270     int32_t next_packet_pos = ftell(file_);
271     for (;;) {
272       TRY_PCAP(fseek(file_, next_packet_pos, SEEK_SET));
273       int result = ReadPacket(&next_packet_pos, stream_start_ms,
274                               ++total_packet_count, ssrc_filter);
275       if (result == kResultFail) {
276         break;
277       } else if (result == kResultSuccess && packets_.size() == 1) {
278         assert(stream_start_ms == 0);
279         PacketIterator it = packets_.begin();
280         stream_start_ms = it->time_offset_ms;
281         it->time_offset_ms = 0;
282       }
283     }
284 
285     if (feof(file_) == 0) {
286       printf("Failed reading file!\n");
287       return kResultFail;
288     }
289 
290     printf("Total packets in file: %d\n", total_packet_count);
291     printf("Total RTP/RTCP packets: %" RTC_PRIuS "\n", packets_.size());
292 
293     for (SsrcMapIterator mit = packets_by_ssrc_.begin();
294          mit != packets_by_ssrc_.end(); ++mit) {
295       uint32_t ssrc = mit->first;
296       const std::vector<uint32_t>& packet_indices = mit->second;
297       uint8_t pt = packets_[packet_indices[0]].rtp_header.payloadType;
298       printf("SSRC: %08x, %" RTC_PRIuS " packets, pt=%d\n", ssrc,
299              packet_indices.size(), pt);
300     }
301 
302     // TODO(solenberg): Better validation of identified SSRC streams.
303     //
304     // Since we're dealing with raw network data here, we will wrongly identify
305     // some packets as RTP. When these packets are consumed by RtpPlayer, they
306     // are unlikely to cause issues as they will ultimately be filtered out by
307     // the RtpRtcp module. However, we should really do better filtering here,
308     // which we can accomplish in a number of ways, e.g.:
309     //
310     // - Verify that the time stamps and sequence numbers for RTP packets are
311     //   both increasing/decreasing. If they move in different directions, the
312     //   SSRC is likely bogus and can be dropped. (Normally they should be inc-
313     //   reasing but we must allow packet reordering).
314     // - If RTP sequence number is not changing, drop the stream.
315     // - Can also use srcip:port->dstip:port pairs, assuming few SSRC collisions
316     //   for up/down streams.
317 
318     next_packet_it_ = packets_.begin();
319     return kResultSuccess;
320   }
321 
NextPacket(RtpPacket * packet)322   bool NextPacket(RtpPacket* packet) override {
323     uint32_t length = RtpPacket::kMaxPacketBufferSize;
324     if (NextPcap(packet->data, &length, &packet->time_ms) != kResultSuccess)
325       return false;
326     packet->length = static_cast<size_t>(length);
327     packet->original_length = packet->length;
328     return true;
329   }
330 
NextPcap(uint8_t * data,uint32_t * length,uint32_t * time_ms)331   virtual int NextPcap(uint8_t* data, uint32_t* length, uint32_t* time_ms) {
332     assert(data);
333     assert(length);
334     assert(time_ms);
335 
336     if (next_packet_it_ == packets_.end()) {
337       return -1;
338     }
339     if (*length < next_packet_it_->payload_length) {
340       return -1;
341     }
342     TRY_PCAP(fseek(file_, next_packet_it_->pos_in_file, SEEK_SET));
343     TRY_PCAP(Read(data, next_packet_it_->payload_length));
344     *length = next_packet_it_->payload_length;
345     *time_ms = next_packet_it_->time_offset_ms;
346     next_packet_it_++;
347 
348     return 0;
349   }
350 
351  private:
352   // A marker of an RTP packet within the file.
353   struct RtpPacketMarker {
354     uint32_t packet_number;  // One-based index (like in WireShark)
355     uint32_t time_offset_ms;
356     uint32_t source_ip;
357     uint32_t dest_ip;
358     uint16_t source_port;
359     uint16_t dest_port;
360     RTPHeader rtp_header;
361     int32_t pos_in_file;  // Byte offset of payload from start of file.
362     uint32_t payload_length;
363   };
364 
365   typedef std::vector<RtpPacketMarker>::iterator PacketIterator;
366   typedef std::map<uint32_t, std::vector<uint32_t> > SsrcMap;
367   typedef std::map<uint32_t, std::vector<uint32_t> >::iterator SsrcMapIterator;
368 
ReadGlobalHeader()369   int ReadGlobalHeader() {
370     uint32_t magic;
371     TRY_PCAP(Read(&magic, false));
372     if (magic == kPcapBOMSwapOrder) {
373       swap_pcap_byte_order_ = true;
374     } else if (magic == kPcapBOMNoSwapOrder) {
375       swap_pcap_byte_order_ = false;
376     } else {
377       return kResultFail;
378     }
379 
380     uint16_t version_major;
381     uint16_t version_minor;
382     TRY_PCAP(Read(&version_major, false));
383     TRY_PCAP(Read(&version_minor, false));
384     if (version_major != kPcapVersionMajor ||
385         version_minor != kPcapVersionMinor) {
386       return kResultFail;
387     }
388 
389     int32_t this_zone;  // GMT to local correction.
390     uint32_t sigfigs;   // Accuracy of timestamps.
391     uint32_t snaplen;   // Max length of captured packets, in octets.
392     uint32_t network;   // Data link type.
393     TRY_PCAP(Read(&this_zone, false));
394     TRY_PCAP(Read(&sigfigs, false));
395     TRY_PCAP(Read(&snaplen, false));
396     TRY_PCAP(Read(&network, false));
397 
398     // Accept only LINKTYPE_NULL and LINKTYPE_ETHERNET.
399     // See: http://www.tcpdump.org/linktypes.html
400     if (network != kLinktypeNull && network != kLinktypeEthernet) {
401       return kResultFail;
402     }
403 
404     return kResultSuccess;
405   }
406 
ReadPacket(int32_t * next_packet_pos,uint32_t stream_start_ms,uint32_t number,const std::set<uint32_t> & ssrc_filter)407   int ReadPacket(int32_t* next_packet_pos,
408                  uint32_t stream_start_ms,
409                  uint32_t number,
410                  const std::set<uint32_t>& ssrc_filter) {
411     assert(next_packet_pos);
412 
413     uint32_t ts_sec;    // Timestamp seconds.
414     uint32_t ts_usec;   // Timestamp microseconds.
415     uint32_t incl_len;  // Number of octets of packet saved in file.
416     uint32_t orig_len;  // Actual length of packet.
417     TRY_PCAP(Read(&ts_sec, false));
418     TRY_PCAP(Read(&ts_usec, false));
419     TRY_PCAP(Read(&incl_len, false));
420     TRY_PCAP(Read(&orig_len, false));
421 
422     *next_packet_pos = ftell(file_) + incl_len;
423 
424     RtpPacketMarker marker = {0};
425     marker.packet_number = number;
426     marker.time_offset_ms = CalcTimeDelta(ts_sec, ts_usec, stream_start_ms);
427     TRY_PCAP(ReadPacketHeader(&marker));
428     marker.pos_in_file = ftell(file_);
429 
430     if (marker.payload_length > sizeof(read_buffer_)) {
431       printf("Packet too large!\n");
432       return kResultFail;
433     }
434     TRY_PCAP(Read(read_buffer_, marker.payload_length));
435 
436     RtpUtility::RtpHeaderParser rtp_parser(read_buffer_, marker.payload_length);
437     if (rtp_parser.RTCP()) {
438       rtp_parser.ParseRtcp(&marker.rtp_header);
439       packets_.push_back(marker);
440     } else {
441       if (!rtp_parser.Parse(&marker.rtp_header, nullptr)) {
442         RTC_LOG(LS_INFO) << "Not recognized as RTP/RTCP";
443         return kResultSkip;
444       }
445 
446       uint32_t ssrc = marker.rtp_header.ssrc;
447       if (ssrc_filter.empty() || ssrc_filter.find(ssrc) != ssrc_filter.end()) {
448         packets_by_ssrc_[ssrc].push_back(
449             static_cast<uint32_t>(packets_.size()));
450         packets_.push_back(marker);
451       } else {
452         return kResultSkip;
453       }
454     }
455 
456     return kResultSuccess;
457   }
458 
ReadPacketHeader(RtpPacketMarker * marker)459   int ReadPacketHeader(RtpPacketMarker* marker) {
460     int32_t file_pos = ftell(file_);
461 
462     // Check for BSD null/loopback frame header. The header is just 4 bytes in
463     // native byte order, so we check for both versions as we don't care about
464     // the header as such and will likely fail reading the IP header if this is
465     // something else than null/loopback.
466     uint32_t protocol;
467     TRY_PCAP(Read(&protocol, true));
468     if (protocol == kBsdNullLoopback1 || protocol == kBsdNullLoopback2) {
469       int result = ReadXxpIpHeader(marker);
470       RTC_LOG(LS_INFO) << "Recognized loopback frame";
471       if (result != kResultSkip) {
472         return result;
473       }
474     }
475 
476     TRY_PCAP(fseek(file_, file_pos, SEEK_SET));
477 
478     // Check for Ethernet II, IP frame header.
479     uint16_t type;
480     TRY_PCAP(Skip(kEthernetIIHeaderMacSkip));  // Source+destination MAC.
481     TRY_PCAP(Read(&type, true));
482     if (type == kEthertypeIp) {
483       int result = ReadXxpIpHeader(marker);
484       RTC_LOG(LS_INFO) << "Recognized ethernet 2 frame";
485       if (result != kResultSkip) {
486         return result;
487       }
488     }
489 
490     return kResultSkip;
491   }
492 
CalcTimeDelta(uint32_t ts_sec,uint32_t ts_usec,uint32_t start_ms)493   uint32_t CalcTimeDelta(uint32_t ts_sec, uint32_t ts_usec, uint32_t start_ms) {
494     // Round to nearest ms.
495     uint64_t t2_ms =
496         ((static_cast<uint64_t>(ts_sec) * 1000000) + ts_usec + 500) / 1000;
497     uint64_t t1_ms = static_cast<uint64_t>(start_ms);
498     if (t2_ms < t1_ms) {
499       return 0;
500     } else {
501       return t2_ms - t1_ms;
502     }
503   }
504 
ReadXxpIpHeader(RtpPacketMarker * marker)505   int ReadXxpIpHeader(RtpPacketMarker* marker) {
506     assert(marker);
507 
508     uint16_t version;
509     uint16_t length;
510     uint16_t id;
511     uint16_t fragment;
512     uint16_t protocol;
513     uint16_t checksum;
514     TRY_PCAP(Read(&version, true));
515     TRY_PCAP(Read(&length, true));
516     TRY_PCAP(Read(&id, true));
517     TRY_PCAP(Read(&fragment, true));
518     TRY_PCAP(Read(&protocol, true));
519     TRY_PCAP(Read(&checksum, true));
520     TRY_PCAP(Read(&marker->source_ip, true));
521     TRY_PCAP(Read(&marker->dest_ip, true));
522 
523     if (((version >> 12) & 0x000f) != kIpVersion4) {
524       RTC_LOG(LS_INFO) << "IP header is not IPv4";
525       return kResultSkip;
526     }
527 
528     if (fragment != kFragmentOffsetClear &&
529         fragment != kFragmentOffsetDoNotFragment) {
530       RTC_LOG(LS_INFO) << "IP fragments cannot be handled";
531       return kResultSkip;
532     }
533 
534     // Skip remaining fields of IP header.
535     uint16_t header_length = (version & 0x0f00) >> (8 - 2);
536     assert(header_length >= kMinIpHeaderLength);
537     TRY_PCAP(Skip(header_length - kMinIpHeaderLength));
538 
539     protocol = protocol & 0x00ff;
540     if (protocol == kProtocolTcp) {
541       RTC_LOG(LS_INFO) << "TCP packets are not handled";
542       return kResultSkip;
543     } else if (protocol == kProtocolUdp) {
544       uint16_t length;
545       uint16_t checksum;
546       TRY_PCAP(Read(&marker->source_port, true));
547       TRY_PCAP(Read(&marker->dest_port, true));
548       TRY_PCAP(Read(&length, true));
549       TRY_PCAP(Read(&checksum, true));
550       marker->payload_length = length - kUdpHeaderLength;
551     } else {
552       RTC_LOG(LS_INFO) << "Unknown transport (expected UDP or TCP)";
553       return kResultSkip;
554     }
555 
556     return kResultSuccess;
557   }
558 
Read(uint32_t * out,bool expect_network_order)559   int Read(uint32_t* out, bool expect_network_order) {
560     uint32_t tmp = 0;
561     if (fread(&tmp, 1, sizeof(uint32_t), file_) != sizeof(uint32_t)) {
562       return kResultFail;
563     }
564     if ((!expect_network_order && swap_pcap_byte_order_) ||
565         (expect_network_order && swap_network_byte_order_)) {
566       tmp = ((tmp >> 24) & 0x000000ff) | (tmp << 24) |
567             ((tmp >> 8) & 0x0000ff00) | ((tmp << 8) & 0x00ff0000);
568     }
569     *out = tmp;
570     return kResultSuccess;
571   }
572 
Read(uint16_t * out,bool expect_network_order)573   int Read(uint16_t* out, bool expect_network_order) {
574     uint16_t tmp = 0;
575     if (fread(&tmp, 1, sizeof(uint16_t), file_) != sizeof(uint16_t)) {
576       return kResultFail;
577     }
578     if ((!expect_network_order && swap_pcap_byte_order_) ||
579         (expect_network_order && swap_network_byte_order_)) {
580       tmp = ((tmp >> 8) & 0x00ff) | (tmp << 8);
581     }
582     *out = tmp;
583     return kResultSuccess;
584   }
585 
Read(uint8_t * out,uint32_t count)586   int Read(uint8_t* out, uint32_t count) {
587     if (fread(out, 1, count, file_) != count) {
588       return kResultFail;
589     }
590     return kResultSuccess;
591   }
592 
Read(int32_t * out,bool expect_network_order)593   int Read(int32_t* out, bool expect_network_order) {
594     int32_t tmp = 0;
595     if (fread(&tmp, 1, sizeof(uint32_t), file_) != sizeof(uint32_t)) {
596       return kResultFail;
597     }
598     if ((!expect_network_order && swap_pcap_byte_order_) ||
599         (expect_network_order && swap_network_byte_order_)) {
600       tmp = ((tmp >> 24) & 0x000000ff) | (tmp << 24) |
601             ((tmp >> 8) & 0x0000ff00) | ((tmp << 8) & 0x00ff0000);
602     }
603     *out = tmp;
604     return kResultSuccess;
605   }
606 
Skip(uint32_t length)607   int Skip(uint32_t length) {
608     if (fseek(file_, length, SEEK_CUR) != 0) {
609       return kResultFail;
610     }
611     return kResultSuccess;
612   }
613 
614   FILE* file_;
615   bool swap_pcap_byte_order_;
616   const bool swap_network_byte_order_;
617   uint8_t read_buffer_[kMaxReadBufferSize];
618 
619   SsrcMap packets_by_ssrc_;
620   std::vector<RtpPacketMarker> packets_;
621   PacketIterator next_packet_it_;
622 
623   RTC_DISALLOW_COPY_AND_ASSIGN(PcapReader);
624 };
625 
CreateReaderForFormat(RtpFileReader::FileFormat format)626 RtpFileReaderImpl* CreateReaderForFormat(RtpFileReader::FileFormat format) {
627   RtpFileReaderImpl* reader = nullptr;
628   switch (format) {
629     case RtpFileReader::kPcap:
630       reader = new PcapReader();
631       break;
632     case RtpFileReader::kRtpDump:
633       reader = new RtpDumpReader();
634       break;
635     case RtpFileReader::kLengthPacketInterleaved:
636       reader = new InterleavedRtpFileReader();
637       break;
638   }
639   return reader;
640 }
641 
Create(FileFormat format,const uint8_t * data,size_t size,const std::set<uint32_t> & ssrc_filter)642 RtpFileReader* RtpFileReader::Create(FileFormat format,
643                                      const uint8_t* data,
644                                      size_t size,
645                                      const std::set<uint32_t>& ssrc_filter) {
646   std::unique_ptr<RtpFileReaderImpl> reader(CreateReaderForFormat(format));
647 
648   FILE* file = tmpfile();
649   if (file == nullptr) {
650     printf("ERROR: Can't open file from memory buffer\n");
651     return nullptr;
652   }
653 
654   if (fwrite(reinterpret_cast<const void*>(data), sizeof(uint8_t), size,
655              file) != size) {
656     return nullptr;
657   }
658   rewind(file);
659 
660   if (!reader->Init(file, ssrc_filter)) {
661     return nullptr;
662   }
663   return reader.release();
664 }
665 
Create(FileFormat format,const std::string & filename,const std::set<uint32_t> & ssrc_filter)666 RtpFileReader* RtpFileReader::Create(FileFormat format,
667                                      const std::string& filename,
668                                      const std::set<uint32_t>& ssrc_filter) {
669   RtpFileReaderImpl* reader = CreateReaderForFormat(format);
670   FILE* file = fopen(filename.c_str(), "rb");
671   if (file == nullptr) {
672     printf("ERROR: Can't open file: %s\n", filename.c_str());
673     return nullptr;
674   }
675 
676   if (!reader->Init(file, ssrc_filter)) {
677     delete reader;
678     return nullptr;
679   }
680   return reader;
681 }
682 
Create(FileFormat format,const std::string & filename)683 RtpFileReader* RtpFileReader::Create(FileFormat format,
684                                      const std::string& filename) {
685   return RtpFileReader::Create(format, filename, std::set<uint32_t>());
686 }
687 
688 }  // namespace test
689 }  // namespace webrtc
690