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
22namespace webrtc {
23namespace rtpplayer {
24
25class 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
98VcmPayloadSinkFactory::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
120VcmPayloadSinkFactory::~VcmPayloadSinkFactory() {
121  assert(sinks_.empty());
122}
123
124PayloadSinkInterface* 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
163int 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
175bool 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
185bool 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
195void 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