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