Home | History | Annotate | Download | only in video
      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/video/video_receive_stream.h"
     12 
     13 #include <assert.h>
     14 #include <stdlib.h>
     15 
     16 #include <string>
     17 
     18 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
     19 #include "webrtc/system_wrappers/interface/clock.h"
     20 #include "webrtc/system_wrappers/interface/logging.h"
     21 #include "webrtc/video/receive_statistics_proxy.h"
     22 #include "webrtc/video_engine/include/vie_base.h"
     23 #include "webrtc/video_engine/include/vie_capture.h"
     24 #include "webrtc/video_engine/include/vie_codec.h"
     25 #include "webrtc/video_engine/include/vie_external_codec.h"
     26 #include "webrtc/video_engine/include/vie_image_process.h"
     27 #include "webrtc/video_engine/include/vie_network.h"
     28 #include "webrtc/video_engine/include/vie_render.h"
     29 #include "webrtc/video_engine/include/vie_rtp_rtcp.h"
     30 #include "webrtc/video_receive_stream.h"
     31 
     32 namespace webrtc {
     33 namespace internal {
     34 
     35 VideoReceiveStream::VideoReceiveStream(webrtc::VideoEngine* video_engine,
     36                                        const VideoReceiveStream::Config& config,
     37                                        newapi::Transport* transport,
     38                                        webrtc::VoiceEngine* voice_engine,
     39                                        int base_channel)
     40     : transport_adapter_(transport),
     41       encoded_frame_proxy_(config.pre_decode_callback),
     42       config_(config),
     43       clock_(Clock::GetRealTimeClock()),
     44       channel_(-1) {
     45   video_engine_base_ = ViEBase::GetInterface(video_engine);
     46   video_engine_base_->CreateReceiveChannel(channel_, base_channel);
     47   assert(channel_ != -1);
     48 
     49   rtp_rtcp_ = ViERTP_RTCP::GetInterface(video_engine);
     50   assert(rtp_rtcp_ != NULL);
     51 
     52   // TODO(pbos): This is not fine grained enough...
     53   rtp_rtcp_->SetNACKStatus(channel_, config_.rtp.nack.rtp_history_ms > 0);
     54   rtp_rtcp_->SetKeyFrameRequestMethod(channel_, kViEKeyFrameRequestPliRtcp);
     55   SetRtcpMode(config_.rtp.rtcp_mode);
     56 
     57   assert(config_.rtp.remote_ssrc != 0);
     58   // TODO(pbos): What's an appropriate local_ssrc for receive-only streams?
     59   assert(config_.rtp.local_ssrc != 0);
     60   assert(config_.rtp.remote_ssrc != config_.rtp.local_ssrc);
     61 
     62   rtp_rtcp_->SetLocalSSRC(channel_, config_.rtp.local_ssrc);
     63   // TODO(pbos): Support multiple RTX, per video payload.
     64   Config::Rtp::RtxMap::const_iterator it = config_.rtp.rtx.begin();
     65   if (it != config_.rtp.rtx.end()) {
     66     assert(it->second.ssrc != 0);
     67     assert(it->second.payload_type != 0);
     68 
     69     rtp_rtcp_->SetRemoteSSRCType(channel_, kViEStreamTypeRtx, it->second.ssrc);
     70     rtp_rtcp_->SetRtxReceivePayloadType(channel_, it->second.payload_type);
     71   }
     72 
     73   rtp_rtcp_->SetRembStatus(channel_, false, config_.rtp.remb);
     74 
     75   for (size_t i = 0; i < config_.rtp.extensions.size(); ++i) {
     76     const std::string& extension = config_.rtp.extensions[i].name;
     77     int id = config_.rtp.extensions[i].id;
     78     if (extension == RtpExtension::kTOffset) {
     79       if (rtp_rtcp_->SetReceiveTimestampOffsetStatus(channel_, true, id) != 0)
     80         abort();
     81     } else if (extension == RtpExtension::kAbsSendTime) {
     82       if (rtp_rtcp_->SetReceiveAbsoluteSendTimeStatus(channel_, true, id) != 0)
     83         abort();
     84     } else {
     85       abort();  // Unsupported extension.
     86     }
     87   }
     88 
     89   network_ = ViENetwork::GetInterface(video_engine);
     90   assert(network_ != NULL);
     91 
     92   network_->RegisterSendTransport(channel_, transport_adapter_);
     93 
     94   codec_ = ViECodec::GetInterface(video_engine);
     95 
     96   if (config_.rtp.fec.ulpfec_payload_type != -1) {
     97     // ULPFEC without RED doesn't make sense.
     98     assert(config_.rtp.fec.red_payload_type != -1);
     99     VideoCodec codec;
    100     memset(&codec, 0, sizeof(codec));
    101     codec.codecType = kVideoCodecULPFEC;
    102     strcpy(codec.plName, "ulpfec");
    103     codec.plType = config_.rtp.fec.ulpfec_payload_type;
    104     if (codec_->SetReceiveCodec(channel_, codec) != 0) {
    105       LOG(LS_ERROR) << "Could not set ULPFEC codec. This shouldn't happen.";
    106       abort();
    107     }
    108   }
    109   if (config_.rtp.fec.red_payload_type != -1) {
    110     VideoCodec codec;
    111     memset(&codec, 0, sizeof(codec));
    112     codec.codecType = kVideoCodecRED;
    113     strcpy(codec.plName, "red");
    114     codec.plType = config_.rtp.fec.red_payload_type;
    115     if (codec_->SetReceiveCodec(channel_, codec) != 0) {
    116       LOG(LS_ERROR) << "Could not set RED codec. This shouldn't happen.";
    117       abort();
    118     }
    119   }
    120 
    121   assert(!config_.codecs.empty());
    122   for (size_t i = 0; i < config_.codecs.size(); ++i) {
    123     if (codec_->SetReceiveCodec(channel_, config_.codecs[i]) != 0) {
    124       // TODO(pbos): Abort gracefully, this can be a runtime error.
    125       //             Factor out to an Init() method.
    126       abort();
    127     }
    128   }
    129 
    130   stats_proxy_.reset(new ReceiveStatisticsProxy(
    131       config_.rtp.local_ssrc, clock_, rtp_rtcp_, codec_, channel_));
    132 
    133   if (rtp_rtcp_->RegisterReceiveChannelRtcpStatisticsCallback(
    134           channel_, stats_proxy_.get()) != 0)
    135     abort();
    136 
    137   if (rtp_rtcp_->RegisterReceiveChannelRtpStatisticsCallback(
    138           channel_, stats_proxy_.get()) != 0)
    139     abort();
    140 
    141   if (codec_->RegisterDecoderObserver(channel_, *stats_proxy_) != 0)
    142     abort();
    143 
    144   external_codec_ = ViEExternalCodec::GetInterface(video_engine);
    145   for (size_t i = 0; i < config_.external_decoders.size(); ++i) {
    146     const ExternalVideoDecoder& decoder = config_.external_decoders[i];
    147     if (external_codec_->RegisterExternalReceiveCodec(
    148             channel_,
    149             decoder.payload_type,
    150             decoder.decoder,
    151             decoder.renderer,
    152             decoder.expected_delay_ms) != 0) {
    153       // TODO(pbos): Abort gracefully? Can this be a runtime error?
    154       abort();
    155     }
    156   }
    157 
    158   render_ = ViERender::GetInterface(video_engine);
    159   assert(render_ != NULL);
    160 
    161   render_->AddRenderCallback(channel_, this);
    162 
    163   if (voice_engine) {
    164     video_engine_base_->SetVoiceEngine(voice_engine);
    165     video_engine_base_->ConnectAudioChannel(channel_, config_.audio_channel_id);
    166   }
    167 
    168   image_process_ = ViEImageProcess::GetInterface(video_engine);
    169   if (config.pre_decode_callback) {
    170     image_process_->RegisterPreDecodeImageCallback(channel_,
    171                                                    &encoded_frame_proxy_);
    172   }
    173   image_process_->RegisterPreRenderCallback(channel_, this);
    174 
    175   if (config.rtp.rtcp_xr.receiver_reference_time_report) {
    176     rtp_rtcp_->SetRtcpXrRrtrStatus(channel_, true);
    177   }
    178 }
    179 
    180 VideoReceiveStream::~VideoReceiveStream() {
    181   image_process_->DeRegisterPreRenderCallback(channel_);
    182   image_process_->DeRegisterPreDecodeCallback(channel_);
    183 
    184   render_->RemoveRenderer(channel_);
    185 
    186   for (size_t i = 0; i < config_.external_decoders.size(); ++i) {
    187     external_codec_->DeRegisterExternalReceiveCodec(
    188         channel_, config_.external_decoders[i].payload_type);
    189   }
    190 
    191   network_->DeregisterSendTransport(channel_);
    192 
    193   video_engine_base_->SetVoiceEngine(NULL);
    194   image_process_->Release();
    195   video_engine_base_->Release();
    196   external_codec_->Release();
    197   codec_->DeregisterDecoderObserver(channel_);
    198   rtp_rtcp_->DeregisterReceiveChannelRtpStatisticsCallback(channel_,
    199                                                            stats_proxy_.get());
    200   rtp_rtcp_->DeregisterReceiveChannelRtcpStatisticsCallback(channel_,
    201                                                             stats_proxy_.get());
    202   codec_->Release();
    203   network_->Release();
    204   render_->Release();
    205   rtp_rtcp_->Release();
    206 }
    207 
    208 void VideoReceiveStream::Start() {
    209   transport_adapter_.Enable();
    210   if (render_->StartRender(channel_) != 0)
    211     abort();
    212   if (video_engine_base_->StartReceive(channel_) != 0)
    213     abort();
    214 }
    215 
    216 void VideoReceiveStream::Stop() {
    217   if (render_->StopRender(channel_) != 0)
    218     abort();
    219   if (video_engine_base_->StopReceive(channel_) != 0)
    220     abort();
    221   transport_adapter_.Disable();
    222 }
    223 
    224 VideoReceiveStream::Stats VideoReceiveStream::GetStats() const {
    225   return stats_proxy_->GetStats();
    226 }
    227 
    228 void VideoReceiveStream::GetCurrentReceiveCodec(VideoCodec* receive_codec) {
    229   // TODO(pbos): Implement
    230 }
    231 
    232 bool VideoReceiveStream::DeliverRtcp(const uint8_t* packet, size_t length) {
    233   return network_->ReceivedRTCPPacket(
    234              channel_, packet, static_cast<int>(length)) == 0;
    235 }
    236 
    237 bool VideoReceiveStream::DeliverRtp(const uint8_t* packet, size_t length) {
    238   return network_->ReceivedRTPPacket(
    239              channel_, packet, static_cast<int>(length), PacketTime()) == 0;
    240 }
    241 
    242 void VideoReceiveStream::FrameCallback(I420VideoFrame* video_frame) {
    243   stats_proxy_->OnDecodedFrame();
    244 
    245   if (config_.pre_render_callback)
    246     config_.pre_render_callback->FrameCallback(video_frame);
    247 }
    248 
    249 int32_t VideoReceiveStream::RenderFrame(const uint32_t stream_id,
    250                                         I420VideoFrame& video_frame) {
    251   if (config_.renderer != NULL)
    252     config_.renderer->RenderFrame(
    253         video_frame,
    254         video_frame.render_time_ms() - clock_->TimeInMilliseconds());
    255 
    256   stats_proxy_->OnRenderedFrame();
    257 
    258   return 0;
    259 }
    260 
    261 void VideoReceiveStream::SignalNetworkState(Call::NetworkState state) {
    262   if (state == Call::kNetworkUp)
    263     SetRtcpMode(config_.rtp.rtcp_mode);
    264   network_->SetNetworkTransmissionState(channel_, state == Call::kNetworkUp);
    265   if (state == Call::kNetworkDown)
    266     rtp_rtcp_->SetRTCPStatus(channel_, kRtcpNone);
    267 }
    268 
    269 void VideoReceiveStream::SetRtcpMode(newapi::RtcpMode mode) {
    270   switch (mode) {
    271     case newapi::kRtcpCompound:
    272       rtp_rtcp_->SetRTCPStatus(channel_, kRtcpCompound_RFC4585);
    273       break;
    274     case newapi::kRtcpReducedSize:
    275       rtp_rtcp_->SetRTCPStatus(channel_, kRtcpNonCompound_RFC5506);
    276       break;
    277   }
    278 }
    279 }  // namespace internal
    280 }  // namespace webrtc
    281