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: 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 49 virtual ~VcmPayloadSink() { 50 factory_->Remove(this); 51 } 52 53 // PayloadSinkInterface 54 virtual int32_t OnReceivedPayloadData( 55 const uint8_t* payload_data, 56 const uint16_t payload_size, 57 const WebRtcRTPHeader* rtp_header) OVERRIDE { 58 return vcm_->IncomingPacket(payload_data, payload_size, *rtp_header); 59 } 60 61 virtual bool OnRecoveredPacket(const uint8_t* packet, 62 int packet_length) OVERRIDE { 63 // We currently don't handle FEC. 64 return true; 65 } 66 67 // VCMPacketRequestCallback 68 virtual int32_t ResendPackets(const uint16_t* sequence_numbers, 69 uint16_t length) OVERRIDE { 70 stream_->ResendPackets(sequence_numbers, length); 71 return 0; 72 } 73 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 85 bool Process() { 86 if (vcm_->TimeUntilNextProcess() <= 0) { 87 if (vcm_->Process() < 0) { 88 return false; 89 } 90 } 91 return true; 92 } 93 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 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 132 VcmPayloadSinkFactory::~VcmPayloadSinkFactory() { 133 assert(sinks_.empty()); 134 } 135 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 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 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 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 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