Home | History | Annotate | Download | only in common_video
      1 /*
      2  *  Copyright (c) 2012 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/common_video/include/incoming_video_stream.h"
     12 
     13 #include <assert.h>
     14 
     15 #if defined(_WIN32)
     16 #include <windows.h>
     17 #elif defined(WEBRTC_LINUX)
     18 #include <sys/time.h>
     19 #include <time.h>
     20 #else
     21 #include <sys/time.h>
     22 #endif
     23 
     24 #include "webrtc/base/platform_thread.h"
     25 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
     26 #include "webrtc/common_video/video_render_frames.h"
     27 #include "webrtc/system_wrappers/include/critical_section_wrapper.h"
     28 #include "webrtc/system_wrappers/include/event_wrapper.h"
     29 #include "webrtc/system_wrappers/include/tick_util.h"
     30 #include "webrtc/system_wrappers/include/trace.h"
     31 #include "webrtc/video_renderer.h"
     32 
     33 namespace webrtc {
     34 
     35 IncomingVideoStream::IncomingVideoStream(uint32_t stream_id,
     36                                          bool disable_prerenderer_smoothing)
     37     : stream_id_(stream_id),
     38       disable_prerenderer_smoothing_(disable_prerenderer_smoothing),
     39       stream_critsect_(CriticalSectionWrapper::CreateCriticalSection()),
     40       thread_critsect_(CriticalSectionWrapper::CreateCriticalSection()),
     41       buffer_critsect_(CriticalSectionWrapper::CreateCriticalSection()),
     42       incoming_render_thread_(),
     43       deliver_buffer_event_(EventTimerWrapper::Create()),
     44       running_(false),
     45       external_callback_(nullptr),
     46       render_callback_(nullptr),
     47       render_buffers_(new VideoRenderFrames()),
     48       incoming_rate_(0),
     49       last_rate_calculation_time_ms_(0),
     50       num_frames_since_last_calculation_(0),
     51       last_render_time_ms_(0),
     52       temp_frame_(),
     53       start_image_(),
     54       timeout_image_(),
     55       timeout_time_() {}
     56 
     57 IncomingVideoStream::~IncomingVideoStream() {
     58   Stop();
     59 }
     60 
     61 VideoRenderCallback* IncomingVideoStream::ModuleCallback() {
     62   CriticalSectionScoped cs(stream_critsect_.get());
     63   return this;
     64 }
     65 
     66 int32_t IncomingVideoStream::RenderFrame(const uint32_t stream_id,
     67                                          const VideoFrame& video_frame) {
     68   CriticalSectionScoped csS(stream_critsect_.get());
     69 
     70   if (!running_) {
     71     return -1;
     72   }
     73 
     74   // Rate statistics.
     75   num_frames_since_last_calculation_++;
     76   int64_t now_ms = TickTime::MillisecondTimestamp();
     77   if (now_ms >= last_rate_calculation_time_ms_ + kFrameRatePeriodMs) {
     78     incoming_rate_ =
     79         static_cast<uint32_t>(1000 * num_frames_since_last_calculation_ /
     80                               (now_ms - last_rate_calculation_time_ms_));
     81     num_frames_since_last_calculation_ = 0;
     82     last_rate_calculation_time_ms_ = now_ms;
     83   }
     84 
     85   // Hand over or insert frame.
     86   if (disable_prerenderer_smoothing_) {
     87     DeliverFrame(video_frame);
     88   } else {
     89     CriticalSectionScoped csB(buffer_critsect_.get());
     90     if (render_buffers_->AddFrame(video_frame) == 1) {
     91       deliver_buffer_event_->Set();
     92     }
     93   }
     94   return 0;
     95 }
     96 
     97 int32_t IncomingVideoStream::SetStartImage(const VideoFrame& video_frame) {
     98   CriticalSectionScoped csS(thread_critsect_.get());
     99   return start_image_.CopyFrame(video_frame);
    100 }
    101 
    102 int32_t IncomingVideoStream::SetTimeoutImage(const VideoFrame& video_frame,
    103                                              const uint32_t timeout) {
    104   CriticalSectionScoped csS(thread_critsect_.get());
    105   timeout_time_ = timeout;
    106   return timeout_image_.CopyFrame(video_frame);
    107 }
    108 
    109 void IncomingVideoStream::SetRenderCallback(
    110     VideoRenderCallback* render_callback) {
    111   CriticalSectionScoped cs(thread_critsect_.get());
    112   render_callback_ = render_callback;
    113 }
    114 
    115 int32_t IncomingVideoStream::SetExpectedRenderDelay(
    116     int32_t delay_ms) {
    117   CriticalSectionScoped csS(stream_critsect_.get());
    118   if (running_) {
    119     return -1;
    120   }
    121   CriticalSectionScoped cs(buffer_critsect_.get());
    122   return render_buffers_->SetRenderDelay(delay_ms);
    123 }
    124 
    125 void IncomingVideoStream::SetExternalCallback(
    126     VideoRenderCallback* external_callback) {
    127   CriticalSectionScoped cs(thread_critsect_.get());
    128   external_callback_ = external_callback;
    129 }
    130 
    131 int32_t IncomingVideoStream::Start() {
    132   CriticalSectionScoped csS(stream_critsect_.get());
    133   if (running_) {
    134     return 0;
    135   }
    136 
    137   if (!disable_prerenderer_smoothing_) {
    138     CriticalSectionScoped csT(thread_critsect_.get());
    139     assert(incoming_render_thread_ == NULL);
    140 
    141     incoming_render_thread_.reset(new rtc::PlatformThread(
    142         IncomingVideoStreamThreadFun, this, "IncomingVideoStreamThread"));
    143     if (!incoming_render_thread_) {
    144       return -1;
    145     }
    146 
    147     incoming_render_thread_->Start();
    148     incoming_render_thread_->SetPriority(rtc::kRealtimePriority);
    149     deliver_buffer_event_->StartTimer(false, kEventStartupTimeMs);
    150   }
    151 
    152   running_ = true;
    153   return 0;
    154 }
    155 
    156 int32_t IncomingVideoStream::Stop() {
    157   CriticalSectionScoped cs_stream(stream_critsect_.get());
    158 
    159   if (!running_) {
    160     return 0;
    161   }
    162 
    163   rtc::PlatformThread* thread = NULL;
    164   {
    165     CriticalSectionScoped cs_thread(thread_critsect_.get());
    166     if (incoming_render_thread_) {
    167       // Setting the incoming render thread to NULL marks that we're performing
    168       // a shutdown and will make IncomingVideoStreamProcess abort after wakeup.
    169       thread = incoming_render_thread_.release();
    170       deliver_buffer_event_->StopTimer();
    171       // Set the event to allow the thread to wake up and shut down without
    172       // waiting for a timeout.
    173       deliver_buffer_event_->Set();
    174     }
    175   }
    176   if (thread) {
    177     thread->Stop();
    178     delete thread;
    179   }
    180   running_ = false;
    181   return 0;
    182 }
    183 
    184 int32_t IncomingVideoStream::Reset() {
    185   CriticalSectionScoped cs_buffer(buffer_critsect_.get());
    186   render_buffers_->ReleaseAllFrames();
    187   return 0;
    188 }
    189 
    190 uint32_t IncomingVideoStream::StreamId() const {
    191   return stream_id_;
    192 }
    193 
    194 uint32_t IncomingVideoStream::IncomingRate() const {
    195   CriticalSectionScoped cs(stream_critsect_.get());
    196   return incoming_rate_;
    197 }
    198 
    199 bool IncomingVideoStream::IncomingVideoStreamThreadFun(void* obj) {
    200   return static_cast<IncomingVideoStream*>(obj)->IncomingVideoStreamProcess();
    201 }
    202 
    203 bool IncomingVideoStream::IncomingVideoStreamProcess() {
    204   if (kEventError != deliver_buffer_event_->Wait(kEventMaxWaitTimeMs)) {
    205     CriticalSectionScoped cs(thread_critsect_.get());
    206     if (incoming_render_thread_ == NULL) {
    207       // Terminating
    208       return false;
    209     }
    210 
    211     // Get a new frame to render and the time for the frame after this one.
    212     VideoFrame frame_to_render;
    213     uint32_t wait_time;
    214     {
    215       CriticalSectionScoped cs(buffer_critsect_.get());
    216       frame_to_render = render_buffers_->FrameToRender();
    217       wait_time = render_buffers_->TimeToNextFrameRelease();
    218     }
    219 
    220     // Set timer for next frame to render.
    221     if (wait_time > kEventMaxWaitTimeMs) {
    222       wait_time = kEventMaxWaitTimeMs;
    223     }
    224     deliver_buffer_event_->StartTimer(false, wait_time);
    225 
    226     DeliverFrame(frame_to_render);
    227   }
    228   return true;
    229 }
    230 
    231 void IncomingVideoStream::DeliverFrame(const VideoFrame& video_frame) {
    232   CriticalSectionScoped cs(thread_critsect_.get());
    233   if (video_frame.IsZeroSize()) {
    234     if (render_callback_) {
    235       if (last_render_time_ms_ == 0 && !start_image_.IsZeroSize()) {
    236         // We have not rendered anything and have a start image.
    237         temp_frame_.CopyFrame(start_image_);
    238         render_callback_->RenderFrame(stream_id_, temp_frame_);
    239       } else if (!timeout_image_.IsZeroSize() &&
    240                  last_render_time_ms_ + timeout_time_ <
    241                      TickTime::MillisecondTimestamp()) {
    242         // Render a timeout image.
    243         temp_frame_.CopyFrame(timeout_image_);
    244         render_callback_->RenderFrame(stream_id_, temp_frame_);
    245       }
    246     }
    247 
    248     // No frame.
    249     return;
    250   }
    251 
    252   // Send frame for rendering.
    253   if (external_callback_) {
    254     external_callback_->RenderFrame(stream_id_, video_frame);
    255   } else if (render_callback_) {
    256     render_callback_->RenderFrame(stream_id_, video_frame);
    257   }
    258 
    259   // We're done with this frame.
    260   last_render_time_ms_ = video_frame.render_time_ms();
    261 }
    262 
    263 }  // namespace webrtc
    264