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/video_engine/vie_frame_provider_base.h" 12 13 #include <algorithm> 14 15 #include "webrtc/common_video/interface/i420_video_frame.h" 16 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h" 17 #include "webrtc/system_wrappers/interface/logging.h" 18 #include "webrtc/system_wrappers/interface/tick_util.h" 19 #include "webrtc/video_engine/vie_defines.h" 20 21 namespace webrtc { 22 23 ViEFrameProviderBase::ViEFrameProviderBase(int Id, int engine_id) 24 : id_(Id), 25 engine_id_(engine_id), 26 provider_cs_(CriticalSectionWrapper::CreateCriticalSection()), 27 frame_delay_(0) { 28 } 29 30 ViEFrameProviderBase::~ViEFrameProviderBase() { 31 if (frame_callbacks_.size() > 0) { 32 LOG_F(LS_WARNING) << "FrameCallbacks still exist when Provider deleted: " 33 << frame_callbacks_.size(); 34 } 35 36 for (FrameCallbacks::iterator it = frame_callbacks_.begin(); 37 it != frame_callbacks_.end(); ++it) { 38 (*it)->ProviderDestroyed(id_); 39 } 40 frame_callbacks_.clear(); 41 } 42 43 int ViEFrameProviderBase::Id() { 44 return id_; 45 } 46 47 void ViEFrameProviderBase::DeliverFrame( 48 I420VideoFrame* video_frame, 49 int num_csrcs, 50 const uint32_t CSRC[kRtpCsrcSize]) { 51 #ifdef DEBUG_ 52 const TickTime start_process_time = TickTime::Now(); 53 #endif 54 CriticalSectionScoped cs(provider_cs_.get()); 55 56 // Deliver the frame to all registered callbacks. 57 if (frame_callbacks_.size() > 0) { 58 if (frame_callbacks_.size() == 1) { 59 // We don't have to copy the frame. 60 frame_callbacks_.front()->DeliverFrame(id_, video_frame, num_csrcs, CSRC); 61 } else { 62 for (FrameCallbacks::iterator it = frame_callbacks_.begin(); 63 it != frame_callbacks_.end(); ++it) { 64 if (video_frame->native_handle() != NULL) { 65 (*it)->DeliverFrame(id_, video_frame, num_csrcs, CSRC); 66 } else { 67 // Make a copy of the frame for all callbacks. 68 if (!extra_frame_.get()) { 69 extra_frame_.reset(new I420VideoFrame()); 70 } 71 extra_frame_->CopyFrame(*video_frame); 72 (*it)->DeliverFrame(id_, extra_frame_.get(), num_csrcs, CSRC); 73 } 74 } 75 } 76 } 77 #ifdef DEBUG_ 78 const int process_time = 79 static_cast<int>((TickTime::Now() - start_process_time).Milliseconds()); 80 if (process_time > 25) { 81 // Warn if the delivery time is too long. 82 LOG(LS_WARNING) << "Too long time delivering frame " << process_time; 83 } 84 #endif 85 } 86 87 void ViEFrameProviderBase::SetFrameDelay(int frame_delay) { 88 CriticalSectionScoped cs(provider_cs_.get()); 89 frame_delay_ = frame_delay; 90 91 for (FrameCallbacks::iterator it = frame_callbacks_.begin(); 92 it != frame_callbacks_.end(); ++it) { 93 (*it)->DelayChanged(id_, frame_delay); 94 } 95 } 96 97 int ViEFrameProviderBase::FrameDelay() { 98 return frame_delay_; 99 } 100 101 int ViEFrameProviderBase::GetBestFormat(int* best_width, 102 int* best_height, 103 int* best_frame_rate) { 104 int largest_width = 0; 105 int largest_height = 0; 106 int highest_frame_rate = 0; 107 108 CriticalSectionScoped cs(provider_cs_.get()); 109 for (FrameCallbacks::iterator it = frame_callbacks_.begin(); 110 it != frame_callbacks_.end(); ++it) { 111 int prefered_width = 0; 112 int prefered_height = 0; 113 int prefered_frame_rate = 0; 114 if ((*it)->GetPreferedFrameSettings(&prefered_width, &prefered_height, 115 &prefered_frame_rate) == 0) { 116 if (prefered_width > largest_width) { 117 largest_width = prefered_width; 118 } 119 if (prefered_height > largest_height) { 120 largest_height = prefered_height; 121 } 122 if (prefered_frame_rate > highest_frame_rate) { 123 highest_frame_rate = prefered_frame_rate; 124 } 125 } 126 } 127 *best_width = largest_width; 128 *best_height = largest_height; 129 *best_frame_rate = highest_frame_rate; 130 return 0; 131 } 132 133 int ViEFrameProviderBase::RegisterFrameCallback( 134 int observer_id, ViEFrameCallback* callback_object) { 135 assert(callback_object); 136 { 137 CriticalSectionScoped cs(provider_cs_.get()); 138 if (std::find(frame_callbacks_.begin(), frame_callbacks_.end(), 139 callback_object) != frame_callbacks_.end()) { 140 assert(false && "frameObserver already registered"); 141 return -1; 142 } 143 frame_callbacks_.push_back(callback_object); 144 } 145 // Report current capture delay. 146 callback_object->DelayChanged(id_, frame_delay_); 147 148 // Notify implementer of this class that the callback list have changed. 149 FrameCallbackChanged(); 150 return 0; 151 } 152 153 int ViEFrameProviderBase::DeregisterFrameCallback( 154 const ViEFrameCallback* callback_object) { 155 assert(callback_object); 156 CriticalSectionScoped cs(provider_cs_.get()); 157 158 FrameCallbacks::iterator it = std::find(frame_callbacks_.begin(), 159 frame_callbacks_.end(), 160 callback_object); 161 if (it == frame_callbacks_.end()) { 162 return -1; 163 } 164 frame_callbacks_.erase(it); 165 166 // Notify implementer of this class that the callback list have changed. 167 FrameCallbackChanged(); 168 return 0; 169 } 170 171 bool ViEFrameProviderBase::IsFrameCallbackRegistered( 172 const ViEFrameCallback* callback_object) { 173 assert(callback_object); 174 175 CriticalSectionScoped cs(provider_cs_.get()); 176 return std::find(frame_callbacks_.begin(), frame_callbacks_.end(), 177 callback_object) != frame_callbacks_.end(); 178 } 179 180 int ViEFrameProviderBase::NumberOfRegisteredFrameCallbacks() { 181 CriticalSectionScoped cs(provider_cs_.get()); 182 return frame_callbacks_.size(); 183 } 184 } // namespac webrtc 185