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