1 /*
2  *  Copyright (c) 2013 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 "webrtc/modules/video_coding/test/vcm_payload_sink_factory.h"
12 
13 #include <assert.h>
14 
15 #include <algorithm>
16 
17 #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h"
18 #include "webrtc/modules/video_coding/test/test_util.h"
19 #include "webrtc/system_wrappers/include/clock.h"
20 #include "webrtc/system_wrappers/include/critical_section_wrapper.h"
21 
22 namespace webrtc {
23 namespace rtpplayer {
24 
25 class VcmPayloadSinkFactory::VcmPayloadSink : public PayloadSinkInterface,
26                                               public VCMPacketRequestCallback {
27  public:
VcmPayloadSink(VcmPayloadSinkFactory * factory,RtpStreamInterface * stream,rtc::scoped_ptr<VideoCodingModule> * vcm,rtc::scoped_ptr<FileOutputFrameReceiver> * frame_receiver)28   VcmPayloadSink(VcmPayloadSinkFactory* factory,
29                  RtpStreamInterface* stream,
30                  rtc::scoped_ptr<VideoCodingModule>* vcm,
31                  rtc::scoped_ptr<FileOutputFrameReceiver>* frame_receiver)
32       : factory_(factory), stream_(stream), vcm_(), frame_receiver_() {
33     assert(factory);
34     assert(stream);
35     assert(vcm);
36     assert(vcm->get());
37     assert(frame_receiver);
38     assert(frame_receiver->get());
39     vcm_.swap(*vcm);
40     frame_receiver_.swap(*frame_receiver);
41     vcm_->RegisterPacketRequestCallback(this);
42     vcm_->RegisterReceiveCallback(frame_receiver_.get());
43   }
44 
~VcmPayloadSink()45   virtual ~VcmPayloadSink() { factory_->Remove(this); }
46 
47   // PayloadSinkInterface
OnReceivedPayloadData(const uint8_t * payload_data,const size_t payload_size,const WebRtcRTPHeader * rtp_header)48   int32_t OnReceivedPayloadData(const uint8_t* payload_data,
49                                 const size_t payload_size,
50                                 const WebRtcRTPHeader* rtp_header) override {
51     return vcm_->IncomingPacket(payload_data, payload_size, *rtp_header);
52   }
53 
OnRecoveredPacket(const uint8_t * packet,size_t packet_length)54   bool OnRecoveredPacket(const uint8_t* packet, size_t packet_length) override {
55     // We currently don't handle FEC.
56     return true;
57   }
58 
59   // VCMPacketRequestCallback
ResendPackets(const uint16_t * sequence_numbers,uint16_t length)60   int32_t ResendPackets(const uint16_t* sequence_numbers,
61                         uint16_t length) override {
62     stream_->ResendPackets(sequence_numbers, length);
63     return 0;
64   }
65 
DecodeAndProcess(bool should_decode,bool decode_dual_frame)66   int DecodeAndProcess(bool should_decode, bool decode_dual_frame) {
67     if (should_decode) {
68       if (vcm_->Decode() < 0) {
69         return -1;
70       }
71     }
72     return Process() ? 0 : -1;
73   }
74 
Process()75   bool Process() {
76     if (vcm_->TimeUntilNextProcess() <= 0) {
77       if (vcm_->Process() < 0) {
78         return false;
79       }
80     }
81     return true;
82   }
83 
Decode()84   bool Decode() {
85     vcm_->Decode(10000);
86     return true;
87   }
88 
89  private:
90   VcmPayloadSinkFactory* factory_;
91   RtpStreamInterface* stream_;
92   rtc::scoped_ptr<VideoCodingModule> vcm_;
93   rtc::scoped_ptr<FileOutputFrameReceiver> frame_receiver_;
94 
95   RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(VcmPayloadSink);
96 };
97 
VcmPayloadSinkFactory(const std::string & base_out_filename,Clock * clock,bool protection_enabled,VCMVideoProtection protection_method,int64_t rtt_ms,uint32_t render_delay_ms,uint32_t min_playout_delay_ms)98 VcmPayloadSinkFactory::VcmPayloadSinkFactory(
99     const std::string& base_out_filename,
100     Clock* clock,
101     bool protection_enabled,
102     VCMVideoProtection protection_method,
103     int64_t rtt_ms,
104     uint32_t render_delay_ms,
105     uint32_t min_playout_delay_ms)
106     : base_out_filename_(base_out_filename),
107       clock_(clock),
108       protection_enabled_(protection_enabled),
109       protection_method_(protection_method),
110       rtt_ms_(rtt_ms),
111       render_delay_ms_(render_delay_ms),
112       min_playout_delay_ms_(min_playout_delay_ms),
113       null_event_factory_(new NullEventFactory()),
114       crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
115       sinks_() {
116   assert(clock);
117   assert(crit_sect_.get());
118 }
119 
~VcmPayloadSinkFactory()120 VcmPayloadSinkFactory::~VcmPayloadSinkFactory() {
121   assert(sinks_.empty());
122 }
123 
Create(RtpStreamInterface * stream)124 PayloadSinkInterface* VcmPayloadSinkFactory::Create(
125     RtpStreamInterface* stream) {
126   assert(stream);
127   CriticalSectionScoped cs(crit_sect_.get());
128 
129   rtc::scoped_ptr<VideoCodingModule> vcm(
130       VideoCodingModule::Create(clock_, null_event_factory_.get()));
131   if (vcm.get() == NULL) {
132     return NULL;
133   }
134 
135   const PayloadTypes& plt = stream->payload_types();
136   for (PayloadTypesIterator it = plt.begin(); it != plt.end(); ++it) {
137     if (it->codec_type() != kVideoCodecULPFEC &&
138         it->codec_type() != kVideoCodecRED) {
139       VideoCodec codec;
140       VideoCodingModule::Codec(it->codec_type(), &codec);
141       codec.plType = it->payload_type();
142       if (vcm->RegisterReceiveCodec(&codec, 1) < 0) {
143         return NULL;
144       }
145     }
146   }
147 
148   vcm->SetChannelParameters(0, 0, rtt_ms_);
149   vcm->SetVideoProtection(protection_method_, protection_enabled_);
150   vcm->SetRenderDelay(render_delay_ms_);
151   vcm->SetMinimumPlayoutDelay(min_playout_delay_ms_);
152   vcm->SetNackSettings(kMaxNackListSize, kMaxPacketAgeToNack, 0);
153 
154   rtc::scoped_ptr<FileOutputFrameReceiver> frame_receiver(
155       new FileOutputFrameReceiver(base_out_filename_, stream->ssrc()));
156   rtc::scoped_ptr<VcmPayloadSink> sink(
157       new VcmPayloadSink(this, stream, &vcm, &frame_receiver));
158 
159   sinks_.push_back(sink.get());
160   return sink.release();
161 }
162 
DecodeAndProcessAll(bool decode_dual_frame)163 int VcmPayloadSinkFactory::DecodeAndProcessAll(bool decode_dual_frame) {
164   CriticalSectionScoped cs(crit_sect_.get());
165   assert(clock_);
166   bool should_decode = (clock_->TimeInMilliseconds() % 5) == 0;
167   for (Sinks::iterator it = sinks_.begin(); it != sinks_.end(); ++it) {
168     if ((*it)->DecodeAndProcess(should_decode, decode_dual_frame) < 0) {
169       return -1;
170     }
171   }
172   return 0;
173 }
174 
ProcessAll()175 bool VcmPayloadSinkFactory::ProcessAll() {
176   CriticalSectionScoped cs(crit_sect_.get());
177   for (Sinks::iterator it = sinks_.begin(); it != sinks_.end(); ++it) {
178     if (!(*it)->Process()) {
179       return false;
180     }
181   }
182   return true;
183 }
184 
DecodeAll()185 bool VcmPayloadSinkFactory::DecodeAll() {
186   CriticalSectionScoped cs(crit_sect_.get());
187   for (Sinks::iterator it = sinks_.begin(); it != sinks_.end(); ++it) {
188     if (!(*it)->Decode()) {
189       return false;
190     }
191   }
192   return true;
193 }
194 
Remove(VcmPayloadSink * sink)195 void VcmPayloadSinkFactory::Remove(VcmPayloadSink* sink) {
196   assert(sink);
197   CriticalSectionScoped cs(crit_sect_.get());
198   Sinks::iterator it = std::find(sinks_.begin(), sinks_.end(), sink);
199   assert(it != sinks_.end());
200   sinks_.erase(it);
201 }
202 
203 }  // namespace rtpplayer
204 }  // namespace webrtc
205