/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "webrtc/modules/video_coding/main/test/vcm_payload_sink_factory.h" #include #include #include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h" #include "webrtc/modules/video_coding/main/test/test_util.h" #include "webrtc/system_wrappers/include/clock.h" #include "webrtc/system_wrappers/include/critical_section_wrapper.h" namespace webrtc { namespace rtpplayer { class VcmPayloadSinkFactory::VcmPayloadSink : public PayloadSinkInterface, public VCMPacketRequestCallback { public: VcmPayloadSink(VcmPayloadSinkFactory* factory, RtpStreamInterface* stream, rtc::scoped_ptr* vcm, rtc::scoped_ptr* frame_receiver) : factory_(factory), stream_(stream), vcm_(), frame_receiver_() { assert(factory); assert(stream); assert(vcm); assert(vcm->get()); assert(frame_receiver); assert(frame_receiver->get()); vcm_.swap(*vcm); frame_receiver_.swap(*frame_receiver); vcm_->RegisterPacketRequestCallback(this); vcm_->RegisterReceiveCallback(frame_receiver_.get()); } virtual ~VcmPayloadSink() { factory_->Remove(this); } // PayloadSinkInterface int32_t OnReceivedPayloadData(const uint8_t* payload_data, const size_t payload_size, const WebRtcRTPHeader* rtp_header) override { return vcm_->IncomingPacket(payload_data, payload_size, *rtp_header); } bool OnRecoveredPacket(const uint8_t* packet, size_t packet_length) override { // We currently don't handle FEC. return true; } // VCMPacketRequestCallback int32_t ResendPackets(const uint16_t* sequence_numbers, uint16_t length) override { stream_->ResendPackets(sequence_numbers, length); return 0; } int DecodeAndProcess(bool should_decode, bool decode_dual_frame) { if (should_decode) { if (vcm_->Decode() < 0) { return -1; } } return Process() ? 0 : -1; } bool Process() { if (vcm_->TimeUntilNextProcess() <= 0) { if (vcm_->Process() < 0) { return false; } } return true; } bool Decode() { vcm_->Decode(10000); return true; } private: VcmPayloadSinkFactory* factory_; RtpStreamInterface* stream_; rtc::scoped_ptr vcm_; rtc::scoped_ptr frame_receiver_; RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(VcmPayloadSink); }; VcmPayloadSinkFactory::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) : base_out_filename_(base_out_filename), clock_(clock), protection_enabled_(protection_enabled), protection_method_(protection_method), rtt_ms_(rtt_ms), render_delay_ms_(render_delay_ms), min_playout_delay_ms_(min_playout_delay_ms), null_event_factory_(new NullEventFactory()), crit_sect_(CriticalSectionWrapper::CreateCriticalSection()), sinks_() { assert(clock); assert(crit_sect_.get()); } VcmPayloadSinkFactory::~VcmPayloadSinkFactory() { assert(sinks_.empty()); } PayloadSinkInterface* VcmPayloadSinkFactory::Create( RtpStreamInterface* stream) { assert(stream); CriticalSectionScoped cs(crit_sect_.get()); rtc::scoped_ptr vcm( VideoCodingModule::Create(clock_, null_event_factory_.get())); if (vcm.get() == NULL) { return NULL; } const PayloadTypes& plt = stream->payload_types(); for (PayloadTypesIterator it = plt.begin(); it != plt.end(); ++it) { if (it->codec_type() != kVideoCodecULPFEC && it->codec_type() != kVideoCodecRED) { VideoCodec codec; if (VideoCodingModule::Codec(it->codec_type(), &codec) < 0) { return NULL; } codec.plType = it->payload_type(); if (vcm->RegisterReceiveCodec(&codec, 1) < 0) { return NULL; } } } vcm->SetChannelParameters(0, 0, rtt_ms_); vcm->SetVideoProtection(protection_method_, protection_enabled_); vcm->SetRenderDelay(render_delay_ms_); vcm->SetMinimumPlayoutDelay(min_playout_delay_ms_); vcm->SetNackSettings(kMaxNackListSize, kMaxPacketAgeToNack, 0); rtc::scoped_ptr frame_receiver( new FileOutputFrameReceiver(base_out_filename_, stream->ssrc())); rtc::scoped_ptr sink( new VcmPayloadSink(this, stream, &vcm, &frame_receiver)); sinks_.push_back(sink.get()); return sink.release(); } int VcmPayloadSinkFactory::DecodeAndProcessAll(bool decode_dual_frame) { CriticalSectionScoped cs(crit_sect_.get()); assert(clock_); bool should_decode = (clock_->TimeInMilliseconds() % 5) == 0; for (Sinks::iterator it = sinks_.begin(); it != sinks_.end(); ++it) { if ((*it)->DecodeAndProcess(should_decode, decode_dual_frame) < 0) { return -1; } } return 0; } bool VcmPayloadSinkFactory::ProcessAll() { CriticalSectionScoped cs(crit_sect_.get()); for (Sinks::iterator it = sinks_.begin(); it != sinks_.end(); ++it) { if (!(*it)->Process()) { return false; } } return true; } bool VcmPayloadSinkFactory::DecodeAll() { CriticalSectionScoped cs(crit_sect_.get()); for (Sinks::iterator it = sinks_.begin(); it != sinks_.end(); ++it) { if (!(*it)->Decode()) { return false; } } return true; } void VcmPayloadSinkFactory::Remove(VcmPayloadSink* sink) { assert(sink); CriticalSectionScoped cs(crit_sect_.get()); Sinks::iterator it = std::find(sinks_.begin(), sinks_.end(), sink); assert(it != sinks_.end()); sinks_.erase(it); } } // namespace rtpplayer } // namespace webrtc