Home | History | Annotate | Download | only in test
      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:
     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 
     45   virtual ~VcmPayloadSink() { factory_->Remove(this); }
     46 
     47   // PayloadSinkInterface
     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 
     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
     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 
     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 
     75   bool Process() {
     76     if (vcm_->TimeUntilNextProcess() <= 0) {
     77       if (vcm_->Process() < 0) {
     78         return false;
     79       }
     80     }
     81     return true;
     82   }
     83 
     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 
     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 
    120 VcmPayloadSinkFactory::~VcmPayloadSinkFactory() {
    121   assert(sinks_.empty());
    122 }
    123 
    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 
    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 
    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 
    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 
    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