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
22namespace webrtc {
23namespace rtpplayer {
24
25class 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
110VcmPayloadSinkFactory::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
132VcmPayloadSinkFactory::~VcmPayloadSinkFactory() {
133  assert(sinks_.empty());
134}
135
136PayloadSinkInterface* 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
181int 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
193bool 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
203bool 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
213void 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