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