| /* |
| * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #include "vie_frame_provider_base.h" |
| #include "critical_section_wrapper.h" |
| #include "tick_util.h" |
| #include "trace.h" |
| #include "vie_defines.h" |
| |
| namespace webrtc { |
| |
| ViEFrameProviderBase::ViEFrameProviderBase(int Id, int engineId): |
| _id(Id), |
| _engineId(engineId), |
| _frameCallbackMap(), |
| _providerCritSect(*CriticalSectionWrapper::CreateCriticalSection()), |
| _ptrExtraFrame(NULL), |
| _frameDelay(0) |
| { |
| } |
| |
| ViEFrameProviderBase::~ViEFrameProviderBase() |
| { |
| if(_frameCallbackMap.Size()>0) |
| { |
| WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, ViEId(_engineId,_id), "FramCallbacks still exist when Provider deleted %d",_frameCallbackMap.Size()); |
| } |
| for(MapItem* item=_frameCallbackMap.First();item!=NULL;item=_frameCallbackMap.Next(item)) |
| { |
| static_cast<ViEFrameCallback*>(item->GetItem())->ProviderDestroyed(_id); |
| } |
| |
| while(_frameCallbackMap.Erase(_frameCallbackMap.First()) == 0) |
| ; |
| |
| delete &_providerCritSect; |
| delete _ptrExtraFrame; |
| } |
| |
| int ViEFrameProviderBase::Id() |
| { |
| return _id; |
| } |
| |
| void ViEFrameProviderBase::DeliverFrame(webrtc::VideoFrame& videoFrame,int numCSRCs, |
| const WebRtc_UWord32 CSRC[kRtpCsrcSize]) |
| { |
| #ifdef _DEBUG |
| const TickTime startProcessTime=TickTime::Now(); |
| #endif |
| CriticalSectionScoped cs(_providerCritSect); |
| |
| // Deliver the frame to all registered callbacks |
| if (_frameCallbackMap.Size() > 0) |
| { |
| if(_frameCallbackMap.Size()==1) |
| { |
| ViEFrameCallback* frameObserver = static_cast<ViEFrameCallback*>(_frameCallbackMap.First()->GetItem()); |
| frameObserver->DeliverFrame(_id,videoFrame,numCSRCs,CSRC); |
| } |
| else |
| { |
| // Make a copy of the frame for all callbacks |
| for (MapItem* mapItem = _frameCallbackMap.First(); |
| mapItem != NULL; |
| mapItem = _frameCallbackMap.Next(mapItem)) |
| { |
| if (_ptrExtraFrame == NULL) |
| { |
| _ptrExtraFrame = new webrtc::VideoFrame(); |
| } |
| if (mapItem != NULL) |
| { |
| ViEFrameCallback* frameObserver = static_cast<ViEFrameCallback*>(mapItem->GetItem()); |
| if (frameObserver != NULL) |
| { |
| // We must copy the frame each time since the previous receiver might swap it... |
| _ptrExtraFrame->CopyFrame(videoFrame); |
| frameObserver->DeliverFrame(_id, *_ptrExtraFrame,numCSRCs,CSRC); |
| } |
| } |
| } |
| } |
| } |
| |
| #ifdef _DEBUG |
| const int processTime=(int) (TickTime::Now()-startProcessTime).Milliseconds(); |
| if(processTime>25) // Warn If the delivery time is too long. |
| { |
| WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, ViEId(_engineId,_id), "%s Too long time: %ums",__FUNCTION__,processTime); |
| } |
| #endif |
| } |
| |
| void ViEFrameProviderBase::SetFrameDelay(int frameDelay) |
| { |
| |
| CriticalSectionScoped cs(_providerCritSect); |
| _frameDelay=frameDelay; |
| |
| for (MapItem* mapItem = _frameCallbackMap.First(); |
| mapItem != NULL; |
| mapItem = _frameCallbackMap.Next(mapItem)) |
| { |
| ViEFrameCallback* frameObserver = static_cast<ViEFrameCallback*>(mapItem->GetItem()); |
| assert(frameObserver); |
| frameObserver->DelayChanged(_id,frameDelay); |
| } |
| |
| } |
| |
| int ViEFrameProviderBase::FrameDelay() |
| { |
| return _frameDelay; |
| } |
| |
| int ViEFrameProviderBase::GetBestFormat(int& bestWidth, |
| int& bestHeight, |
| int& bestFrameRate) |
| { |
| |
| int largestWidth = 0; |
| int largestHeight = 0; |
| int highestFrameRate = 0; |
| |
| CriticalSectionScoped cs(_providerCritSect); |
| |
| // Check if this one already exists... |
| for (MapItem* mapItem = _frameCallbackMap.First(); |
| mapItem != NULL; |
| mapItem = _frameCallbackMap.Next(mapItem)) |
| { |
| |
| |
| int preferedWidth=0; |
| int preferedHeight=0; |
| int preferedFrameRate=0; |
| |
| ViEFrameCallback* callbackObject = static_cast<ViEFrameCallback*>(mapItem->GetItem()); |
| assert(callbackObject); |
| if(callbackObject->GetPreferedFrameSettings(preferedWidth,preferedHeight,preferedFrameRate)==0) |
| { |
| if (preferedWidth > largestWidth) |
| { |
| largestWidth = preferedWidth; |
| } |
| if (preferedHeight > largestHeight) |
| { |
| largestHeight = preferedHeight; |
| } |
| if (preferedFrameRate > highestFrameRate) |
| { |
| highestFrameRate = preferedFrameRate; |
| } |
| } |
| } |
| |
| bestWidth = largestWidth; |
| bestHeight = largestHeight; |
| bestFrameRate = highestFrameRate; |
| |
| return 0; |
| } |
| |
| int ViEFrameProviderBase::RegisterFrameCallback(int observerId,ViEFrameCallback* callbackObject) |
| { |
| if (callbackObject == NULL) |
| { |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _id), |
| "%s: No argument", __FUNCTION__); |
| return -1; |
| } |
| WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _id), |
| "%s(0x%p)", callbackObject); |
| |
| { |
| CriticalSectionScoped cs(_providerCritSect); |
| |
| // Check if this one already exists... |
| for (MapItem* mapItem = _frameCallbackMap.First(); |
| mapItem != NULL; |
| mapItem = _frameCallbackMap.Next(mapItem)) |
| { |
| const ViEFrameCallback* observer=static_cast<ViEFrameCallback*> (mapItem->GetItem()); |
| if (observer == callbackObject) |
| { |
| // This callback is already registered |
| WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, ViEId(_engineId, _id), |
| "%s 0x%p already registered", __FUNCTION__, callbackObject); |
| |
| assert("!frameObserver already registered"); |
| return -1; |
| } |
| } |
| |
| if (_frameCallbackMap.Insert(observerId,callbackObject) != 0) |
| { |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _id), |
| "%s: Could not add 0x%p to list", __FUNCTION__, callbackObject); |
| return -1; |
| } |
| } |
| // Report current capture delay |
| callbackObject->DelayChanged(_id,_frameDelay); |
| |
| FrameCallbackChanged(); // Notify implementer of this class that the callback list have changed |
| return 0; |
| |
| |
| } |
| |
| |
| // ---------------------------------------------------------------------------- |
| // DeregisterFrameCallback |
| // ---------------------------------------------------------------------------- |
| |
| int ViEFrameProviderBase::DeregisterFrameCallback(const ViEFrameCallback* callbackObject) |
| { |
| if (callbackObject == NULL) |
| { |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _id), |
| "%s: No argument", __FUNCTION__); |
| return -1; |
| } |
| WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _id), |
| "%s(0x%p)", callbackObject); |
| |
| |
| { |
| CriticalSectionScoped cs(_providerCritSect); |
| bool itemFound=false; |
| |
| |
| // Try to find the callback in our list |
| for (MapItem* mapItem = _frameCallbackMap.First(); |
| mapItem != NULL; |
| mapItem = _frameCallbackMap.Next(mapItem)) |
| { |
| const ViEFrameCallback* observer=static_cast<ViEFrameCallback*> (mapItem->GetItem()); |
| if (observer == callbackObject) |
| { |
| // We found it, remove it! |
| _frameCallbackMap.Erase(mapItem); |
| WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _id), |
| "%s 0x%p deregistered", __FUNCTION__, callbackObject); |
| itemFound=true; |
| break; |
| } |
| } |
| if(!itemFound) |
| { |
| WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideo, ViEId(_engineId, _id), |
| "%s 0x%p not found", __FUNCTION__, callbackObject); |
| return -1; |
| } |
| } |
| |
| FrameCallbackChanged(); // Notify implementer of this class that the callback list have changed |
| return 0; |
| } |
| |
| // ---------------------------------------------------------------------------- |
| // IsFrameCallbackRegistered |
| // ---------------------------------------------------------------------------- |
| |
| bool ViEFrameProviderBase::IsFrameCallbackRegistered(const ViEFrameCallback* callbackObject) |
| { |
| if (callbackObject == NULL) |
| { |
| WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _id), |
| "%s: No argument", __FUNCTION__); |
| return false; |
| } |
| WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _id), |
| "%s(0x%p)", callbackObject); |
| |
| for (MapItem* mapItem = _frameCallbackMap.First(); |
| mapItem != NULL; |
| mapItem = _frameCallbackMap.Next(mapItem)) |
| { |
| if (callbackObject == mapItem->GetItem()) |
| { |
| // We found the callback |
| WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _id), |
| "%s 0x%p is registered", __FUNCTION__, callbackObject); |
| return true; |
| } |
| } |
| WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId, _id), |
| "%s 0x%p not registered", __FUNCTION__, callbackObject); |
| return false; |
| } |
| |
| // ---------------------------------------------------------------------------- |
| // NumberOfRegistersFrameCallbacks |
| // ---------------------------------------------------------------------------- |
| |
| int ViEFrameProviderBase::NumberOfRegistersFrameCallbacks() |
| { |
| CriticalSectionScoped cs(_providerCritSect); |
| return _frameCallbackMap.Size(); |
| } |
| } // namespac webrtc |