| Index: talk/media/base/capturemanager.cc
|
| diff --git a/talk/media/base/capturemanager.cc b/talk/media/base/capturemanager.cc
|
| deleted file mode 100644
|
| index 78ca99d39c80635cdade7d92ed57d82b7f51a62e..0000000000000000000000000000000000000000
|
| --- a/talk/media/base/capturemanager.cc
|
| +++ /dev/null
|
| @@ -1,406 +0,0 @@
|
| -/*
|
| - * libjingle
|
| - * Copyright 2012 Google Inc.
|
| - *
|
| - * Redistribution and use in source and binary forms, with or without
|
| - * modification, are permitted provided that the following conditions are met:
|
| - *
|
| - * 1. Redistributions of source code must retain the above copyright notice,
|
| - * this list of conditions and the following disclaimer.
|
| - * 2. Redistributions in binary form must reproduce the above copyright notice,
|
| - * this list of conditions and the following disclaimer in the documentation
|
| - * and/or other materials provided with the distribution.
|
| - * 3. The name of the author may not be used to endorse or promote products
|
| - * derived from this software without specific prior written permission.
|
| - *
|
| - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
| - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
| - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
| - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
| - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
| - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
| - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
| - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
| - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| - */
|
| -
|
| -#include "talk/media/base/capturemanager.h"
|
| -
|
| -#include <algorithm>
|
| -
|
| -#include "talk/media/base/videocapturer.h"
|
| -#include "webrtc/base/checks.h"
|
| -#include "webrtc/base/logging.h"
|
| -
|
| -namespace cricket {
|
| -
|
| -// CaptureManager helper class.
|
| -class VideoCapturerState {
|
| - public:
|
| - static const VideoFormatPod kDefaultCaptureFormat;
|
| -
|
| - static VideoCapturerState* Create(VideoCapturer* video_capturer);
|
| - ~VideoCapturerState() {}
|
| -
|
| - void AddCaptureResolution(const VideoFormat& desired_format);
|
| - bool RemoveCaptureResolution(const VideoFormat& format);
|
| - VideoFormat GetHighestFormat(VideoCapturer* video_capturer) const;
|
| -
|
| - int IncCaptureStartRef();
|
| - int DecCaptureStartRef();
|
| - CaptureRenderAdapter* adapter() {
|
| - RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
| - return adapter_.get();
|
| - }
|
| - VideoCapturer* GetVideoCapturer() {
|
| - RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
| - return adapter()->video_capturer();
|
| - }
|
| -
|
| - int start_count() const {
|
| - RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
| - return start_count_;
|
| - }
|
| -
|
| - private:
|
| - struct CaptureResolutionInfo {
|
| - VideoFormat video_format;
|
| - int format_ref_count;
|
| - };
|
| - typedef std::vector<CaptureResolutionInfo> CaptureFormats;
|
| -
|
| - explicit VideoCapturerState(CaptureRenderAdapter* adapter);
|
| -
|
| - rtc::ThreadChecker thread_checker_;
|
| - rtc::scoped_ptr<CaptureRenderAdapter> adapter_;
|
| -
|
| - int start_count_;
|
| - CaptureFormats capture_formats_;
|
| -};
|
| -
|
| -const VideoFormatPod VideoCapturerState::kDefaultCaptureFormat = {
|
| - 640, 360, FPS_TO_INTERVAL(30), FOURCC_ANY
|
| -};
|
| -
|
| -VideoCapturerState::VideoCapturerState(CaptureRenderAdapter* adapter)
|
| - : adapter_(adapter), start_count_(1) {}
|
| -
|
| -// static
|
| -VideoCapturerState* VideoCapturerState::Create(VideoCapturer* video_capturer) {
|
| - CaptureRenderAdapter* adapter = CaptureRenderAdapter::Create(video_capturer);
|
| - if (!adapter) {
|
| - return NULL;
|
| - }
|
| - return new VideoCapturerState(adapter);
|
| -}
|
| -
|
| -void VideoCapturerState::AddCaptureResolution(
|
| - const VideoFormat& desired_format) {
|
| - RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
| - for (CaptureFormats::iterator iter = capture_formats_.begin();
|
| - iter != capture_formats_.end(); ++iter) {
|
| - if (desired_format == iter->video_format) {
|
| - ++(iter->format_ref_count);
|
| - return;
|
| - }
|
| - }
|
| - CaptureResolutionInfo capture_resolution = { desired_format, 1 };
|
| - capture_formats_.push_back(capture_resolution);
|
| -}
|
| -
|
| -bool VideoCapturerState::RemoveCaptureResolution(const VideoFormat& format) {
|
| - RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
| - for (CaptureFormats::iterator iter = capture_formats_.begin();
|
| - iter != capture_formats_.end(); ++iter) {
|
| - if (format == iter->video_format) {
|
| - --(iter->format_ref_count);
|
| - if (iter->format_ref_count == 0) {
|
| - capture_formats_.erase(iter);
|
| - }
|
| - return true;
|
| - }
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -VideoFormat VideoCapturerState::GetHighestFormat(
|
| - VideoCapturer* video_capturer) const {
|
| - RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
| - VideoFormat highest_format(0, 0, VideoFormat::FpsToInterval(1), FOURCC_ANY);
|
| - if (capture_formats_.empty()) {
|
| - VideoFormat default_format(kDefaultCaptureFormat);
|
| - return default_format;
|
| - }
|
| - for (CaptureFormats::const_iterator iter = capture_formats_.begin();
|
| - iter != capture_formats_.end(); ++iter) {
|
| - if (iter->video_format.width > highest_format.width) {
|
| - highest_format.width = iter->video_format.width;
|
| - }
|
| - if (iter->video_format.height > highest_format.height) {
|
| - highest_format.height = iter->video_format.height;
|
| - }
|
| - if (iter->video_format.interval < highest_format.interval) {
|
| - highest_format.interval = iter->video_format.interval;
|
| - }
|
| - }
|
| - return highest_format;
|
| -}
|
| -
|
| -int VideoCapturerState::IncCaptureStartRef() {
|
| - RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
| - return ++start_count_;
|
| -}
|
| -
|
| -int VideoCapturerState::DecCaptureStartRef() {
|
| - RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
| - if (start_count_ > 0) {
|
| - // Start count may be 0 if a capturer was added but never started.
|
| - --start_count_;
|
| - }
|
| - return start_count_;
|
| -}
|
| -
|
| -CaptureManager::CaptureManager() {
|
| - // Allowing construction of manager in any thread as long as subsequent calls
|
| - // are all from the same thread.
|
| - thread_checker_.DetachFromThread();
|
| -}
|
| -
|
| -CaptureManager::~CaptureManager() {
|
| - RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - // Since we don't own any of the capturers, all capturers should have been
|
| - // cleaned up before we get here. In fact, in the normal shutdown sequence,
|
| - // all capturers *will* be shut down by now, so trying to stop them here
|
| - // will crash. If we're still tracking any, it's a dangling pointer.
|
| - // TODO(hbos): RTC_DCHECK instead of RTC_CHECK until we figure out why
|
| - // capture_states_ is not always empty here.
|
| - RTC_DCHECK(capture_states_.empty());
|
| -}
|
| -
|
| -bool CaptureManager::StartVideoCapture(VideoCapturer* video_capturer,
|
| - const VideoFormat& desired_format) {
|
| - RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
| - if (desired_format.width == 0 || desired_format.height == 0) {
|
| - return false;
|
| - }
|
| - if (!video_capturer) {
|
| - return false;
|
| - }
|
| - VideoCapturerState* capture_state = GetCaptureState(video_capturer);
|
| - if (capture_state) {
|
| - const int ref_count = capture_state->IncCaptureStartRef();
|
| - if (ref_count < 1) {
|
| - ASSERT(false);
|
| - }
|
| - // VideoCapturer has already been started. Don't start listening to
|
| - // callbacks since that has already been done.
|
| - capture_state->AddCaptureResolution(desired_format);
|
| - return true;
|
| - }
|
| - if (!RegisterVideoCapturer(video_capturer)) {
|
| - return false;
|
| - }
|
| - capture_state = GetCaptureState(video_capturer);
|
| - ASSERT(capture_state != NULL);
|
| - capture_state->AddCaptureResolution(desired_format);
|
| - if (!StartWithBestCaptureFormat(capture_state, video_capturer)) {
|
| - UnregisterVideoCapturer(capture_state);
|
| - return false;
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -bool CaptureManager::StopVideoCapture(VideoCapturer* video_capturer,
|
| - const VideoFormat& format) {
|
| - RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
| - VideoCapturerState* capture_state = GetCaptureState(video_capturer);
|
| - if (!capture_state) {
|
| - return false;
|
| - }
|
| - if (!capture_state->RemoveCaptureResolution(format)) {
|
| - return false;
|
| - }
|
| -
|
| - if (capture_state->DecCaptureStartRef() == 0) {
|
| - // Unregistering cannot fail as capture_state is not NULL.
|
| - UnregisterVideoCapturer(capture_state);
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -bool CaptureManager::RestartVideoCapture(
|
| - VideoCapturer* video_capturer,
|
| - const VideoFormat& previous_format,
|
| - const VideoFormat& desired_format,
|
| - CaptureManager::RestartOptions options) {
|
| - RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
| - if (!IsCapturerRegistered(video_capturer)) {
|
| - LOG(LS_ERROR) << "RestartVideoCapture: video_capturer is not registered.";
|
| - return false;
|
| - }
|
| - // Start the new format first. This keeps the capturer running.
|
| - if (!StartVideoCapture(video_capturer, desired_format)) {
|
| - LOG(LS_ERROR) << "RestartVideoCapture: unable to start video capture with "
|
| - "desired_format=" << desired_format.ToString();
|
| - return false;
|
| - }
|
| - // Stop the old format.
|
| - if (!StopVideoCapture(video_capturer, previous_format)) {
|
| - LOG(LS_ERROR) << "RestartVideoCapture: unable to stop video capture with "
|
| - "previous_format=" << previous_format.ToString();
|
| - // Undo the start request we just performed.
|
| - StopVideoCapture(video_capturer, desired_format);
|
| - return false;
|
| - }
|
| -
|
| - switch (options) {
|
| - case kForceRestart: {
|
| - VideoCapturerState* capture_state = GetCaptureState(video_capturer);
|
| - ASSERT(capture_state && capture_state->start_count() > 0);
|
| - // Try a restart using the new best resolution.
|
| - VideoFormat highest_asked_format =
|
| - capture_state->GetHighestFormat(video_capturer);
|
| - VideoFormat capture_format;
|
| - if (video_capturer->GetBestCaptureFormat(highest_asked_format,
|
| - &capture_format)) {
|
| - if (!video_capturer->Restart(capture_format)) {
|
| - LOG(LS_ERROR) << "RestartVideoCapture: Restart failed.";
|
| - }
|
| - } else {
|
| - LOG(LS_WARNING)
|
| - << "RestartVideoCapture: Couldn't find a best capture format for "
|
| - << highest_asked_format.ToString();
|
| - }
|
| - break;
|
| - }
|
| - case kRequestRestart:
|
| - // TODO(ryanpetrie): Support restart requests. Should this
|
| - // to-be-implemented logic be used for {Start,Stop}VideoCapture as well?
|
| - break;
|
| - default:
|
| - LOG(LS_ERROR) << "Unknown/unimplemented RestartOption";
|
| - break;
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -void CaptureManager::AddVideoSink(VideoCapturer* video_capturer,
|
| - rtc::VideoSinkInterface<VideoFrame>* sink) {
|
| - RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
| - // TODO(nisse): Do we really need to tolerate NULL inputs?
|
| - if (!video_capturer || !sink) {
|
| - return;
|
| - }
|
| - CaptureRenderAdapter* adapter = GetAdapter(video_capturer);
|
| - if (!adapter) {
|
| - return;
|
| - }
|
| - adapter->AddSink(sink);
|
| -}
|
| -
|
| -void CaptureManager::RemoveVideoSink(
|
| - VideoCapturer* video_capturer,
|
| - rtc::VideoSinkInterface<VideoFrame>* sink) {
|
| - RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
| - if (!video_capturer || !sink) {
|
| - return;
|
| - }
|
| - CaptureRenderAdapter* adapter = GetAdapter(video_capturer);
|
| - if (!adapter) {
|
| - return;
|
| - }
|
| - adapter->RemoveSink(sink);
|
| -}
|
| -
|
| -bool CaptureManager::IsCapturerRegistered(VideoCapturer* video_capturer) const {
|
| - RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
| - return GetCaptureState(video_capturer) != NULL;
|
| -}
|
| -
|
| -bool CaptureManager::RegisterVideoCapturer(VideoCapturer* video_capturer) {
|
| - RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
| - VideoCapturerState* capture_state =
|
| - VideoCapturerState::Create(video_capturer);
|
| - if (!capture_state) {
|
| - return false;
|
| - }
|
| - capture_states_[video_capturer] = capture_state;
|
| - SignalCapturerStateChange.repeat(video_capturer->SignalStateChange);
|
| - return true;
|
| -}
|
| -
|
| -void CaptureManager::UnregisterVideoCapturer(
|
| - VideoCapturerState* capture_state) {
|
| - RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
| - VideoCapturer* video_capturer = capture_state->GetVideoCapturer();
|
| - capture_states_.erase(video_capturer);
|
| - delete capture_state;
|
| -
|
| - // When unregistering a VideoCapturer, the CaptureManager needs to unregister
|
| - // from all state change callbacks from the VideoCapturer. E.g. to avoid
|
| - // problems with multiple callbacks if registering the same VideoCapturer
|
| - // multiple times. The VideoCapturer will update the capturer state. However,
|
| - // this is done through Post-calls which means it may happen at any time. If
|
| - // the CaptureManager no longer is listening to the VideoCapturer it will not
|
| - // receive those callbacks. Here it is made sure that the the callback is
|
| - // indeed sent by letting the ChannelManager do the signaling. The downside is
|
| - // that the callback may happen before the VideoCapturer is stopped. However,
|
| - // for the CaptureManager it doesn't matter as it will no longer receive any
|
| - // frames from the VideoCapturer.
|
| - SignalCapturerStateChange.stop(video_capturer->SignalStateChange);
|
| - if (video_capturer->IsRunning()) {
|
| - video_capturer->Stop();
|
| - SignalCapturerStateChange(video_capturer, CS_STOPPED);
|
| - }
|
| -}
|
| -
|
| -bool CaptureManager::StartWithBestCaptureFormat(
|
| - VideoCapturerState* capture_state, VideoCapturer* video_capturer) {
|
| - RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
| - VideoFormat highest_asked_format =
|
| - capture_state->GetHighestFormat(video_capturer);
|
| - VideoFormat capture_format;
|
| - if (!video_capturer->GetBestCaptureFormat(highest_asked_format,
|
| - &capture_format)) {
|
| - LOG(LS_WARNING) << "Unsupported format:"
|
| - << " width=" << highest_asked_format.width
|
| - << " height=" << highest_asked_format.height
|
| - << ". Supported formats are:";
|
| - const std::vector<VideoFormat>* formats =
|
| - video_capturer->GetSupportedFormats();
|
| - ASSERT(formats != NULL);
|
| - for (std::vector<VideoFormat>::const_iterator i = formats->begin();
|
| - i != formats->end(); ++i) {
|
| - const VideoFormat& format = *i;
|
| - LOG(LS_WARNING) << " " << GetFourccName(format.fourcc)
|
| - << ":" << format.width << "x" << format.height << "x"
|
| - << format.framerate();
|
| - }
|
| - return false;
|
| - }
|
| - return video_capturer->StartCapturing(capture_format);
|
| -}
|
| -
|
| -VideoCapturerState* CaptureManager::GetCaptureState(
|
| - VideoCapturer* video_capturer) const {
|
| - RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
| - CaptureStates::const_iterator iter = capture_states_.find(video_capturer);
|
| - if (iter == capture_states_.end()) {
|
| - return NULL;
|
| - }
|
| - return iter->second;
|
| -}
|
| -
|
| -CaptureRenderAdapter* CaptureManager::GetAdapter(
|
| - VideoCapturer* video_capturer) const {
|
| - RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
| - VideoCapturerState* capture_state = GetCaptureState(video_capturer);
|
| - if (!capture_state) {
|
| - return NULL;
|
| - }
|
| - return capture_state->adapter();
|
| -}
|
| -
|
| -} // namespace cricket
|
|
|