|  | /* | 
|  | *  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/test/vcm_payload_sink_factory.h" | 
|  |  | 
|  | #include <assert.h> | 
|  |  | 
|  | #include <algorithm> | 
|  |  | 
|  | #include "webrtc/base/constructormagic.h" | 
|  | #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h" | 
|  | #include "webrtc/modules/video_coding/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, | 
|  | std::unique_ptr<VideoCodingModule>* vcm, | 
|  | std::unique_ptr<FileOutputFrameReceiver>* 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, | 
|  | 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) { | 
|  | vcm_->Process(); | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool Decode() { | 
|  | vcm_->Decode(10000); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | private: | 
|  | VcmPayloadSinkFactory* factory_; | 
|  | RtpStreamInterface* stream_; | 
|  | std::unique_ptr<VideoCodingModule> vcm_; | 
|  | std::unique_ptr<FileOutputFrameReceiver> 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()); | 
|  |  | 
|  | std::unique_ptr<VideoCodingModule> 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; | 
|  | VideoCodingModule::Codec(it->codec_type(), &codec); | 
|  | 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); | 
|  |  | 
|  | std::unique_ptr<FileOutputFrameReceiver> frame_receiver( | 
|  | new FileOutputFrameReceiver(base_out_filename_, stream->ssrc())); | 
|  | std::unique_ptr<VcmPayloadSink> 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 |