/* * 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 "video_processing_impl.h" #include "critical_section_wrapper.h" #include "trace.h" #include namespace webrtc { namespace { void SetSubSampling(VideoProcessingModule::FrameStats& stats, const WebRtc_Word32 width, const WebRtc_Word32 height) { if (width * height >= 640 * 480) { stats.subSamplWidth = 3; stats.subSamplHeight = 3; } else if (width * height >= 352 * 288) { stats.subSamplWidth = 2; stats.subSamplHeight = 2; } else if (width * height >= 176 * 144) { stats.subSamplWidth = 1; stats.subSamplHeight = 1; } else { stats.subSamplWidth = 0; stats.subSamplHeight = 0; } } } VideoProcessingModule* VideoProcessingModule::Create(const WebRtc_Word32 id) { WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoPreocessing, id, "VideoProcessingModule::Create()"); return new VideoProcessingModuleImpl(id); } void VideoProcessingModule::Destroy(VideoProcessingModule* module) { if (module) { WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoPreocessing, static_cast(module)->Id(), "VideoProcessingModule::destroy()"); delete static_cast(module); } } WebRtc_Word32 VideoProcessingModuleImpl::ChangeUniqueId(const WebRtc_Word32 id) { CriticalSectionScoped mutex(_mutex); WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoPreocessing, _id, "ChangeUniqueId(new id:%d)", id); _id = id; _brightnessDetection.ChangeUniqueId(id); _deflickering.ChangeUniqueId(id); _denoising.ChangeUniqueId(id); _framePreProcessor.ChangeUniqueId(id); return VPM_OK; } WebRtc_Word32 VideoProcessingModuleImpl::Version(WebRtc_Word8* version, WebRtc_UWord32& remainingBufferInBytes, WebRtc_UWord32& position) const { CriticalSectionScoped mutex(_mutex); WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoPreocessing, _id, "Version(bufferLength:%d)", remainingBufferInBytes); return GetVersion(version, remainingBufferInBytes, position); } WebRtc_Word32 VideoProcessingModuleImpl::Id() const { CriticalSectionScoped mutex(_mutex); return _id; } WebRtc_Word32 VideoProcessingModule::GetVersion(WebRtc_Word8* version, WebRtc_UWord32& remainingBufferInBytes, WebRtc_UWord32& position) { if (version == NULL) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoPreocessing, -1, "Null version pointer"); return -1; } WebRtc_Word8 ourVersion[] = "VideoProcessingModule 1.1.0"; WebRtc_UWord32 ourLength = (WebRtc_UWord32)sizeof(ourVersion); // Includes null termination. if (remainingBufferInBytes < ourLength) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoPreocessing, -1, "Buffer of insufficient length"); return VPM_PARAMETER_ERROR; } memcpy(&version[position], ourVersion, ourLength); remainingBufferInBytes -= ourLength; position += ourLength; return VPM_OK; } VideoProcessingModuleImpl::VideoProcessingModuleImpl(const WebRtc_Word32 id) : _id(id), _mutex(*CriticalSectionWrapper::CreateCriticalSection()) { _brightnessDetection.ChangeUniqueId(id); _deflickering.ChangeUniqueId(id); _denoising.ChangeUniqueId(id); _framePreProcessor.ChangeUniqueId(id); WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideoPreocessing, _id, "Created"); } VideoProcessingModuleImpl::~VideoProcessingModuleImpl() { WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideoPreocessing, _id, "Destroyed"); delete &_mutex; } void VideoProcessingModuleImpl::Reset() { CriticalSectionScoped mutex(_mutex); _deflickering.Reset(); _denoising.Reset(); _brightnessDetection.Reset(); _framePreProcessor.Reset(); } WebRtc_Word32 VideoProcessingModule::GetFrameStats(FrameStats& stats, const VideoFrame& frame) { return GetFrameStats(stats, frame.Buffer(), frame.Width(), frame.Height()); } WebRtc_Word32 VideoProcessingModule::GetFrameStats(FrameStats& stats, const WebRtc_UWord8* frame, const WebRtc_UWord32 width, const WebRtc_UWord32 height) { if (frame == NULL) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoPreocessing, -1, "Null frame pointer"); return VPM_PARAMETER_ERROR; } if (width == 0 || height == 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoPreocessing, -1, "Invalid frame size"); return VPM_PARAMETER_ERROR; } ClearFrameStats(stats); // The histogram needs to be zeroed out. SetSubSampling(stats, width, height); // Compute histogram and sum of frame for (WebRtc_UWord32 i = 0; i < height; i += (1 << stats.subSamplHeight)) { WebRtc_Word32 k = i * width; for (WebRtc_UWord32 j = 0; j < width; j += (1 << stats.subSamplWidth)) { stats.hist[frame[k + j]]++; stats.sum += frame[k + j]; } } stats.numPixels = (width * height) / ((1 << stats.subSamplWidth) * (1 << stats.subSamplHeight)); assert(stats.numPixels > 0); // Compute mean value of frame stats.mean = stats.sum / stats.numPixels; return VPM_OK; } bool VideoProcessingModule::ValidFrameStats(const FrameStats& stats) { if (stats.numPixels == 0) { return false; } return true; } void VideoProcessingModule::ClearFrameStats(FrameStats& stats) { stats.mean = 0; stats.sum = 0; stats.numPixels = 0; stats.subSamplWidth = 0; stats.subSamplHeight = 0; memset(stats.hist, 0, sizeof(stats.hist)); } WebRtc_Word32 VideoProcessingModule::ColorEnhancement(VideoFrame& frame) { return ColorEnhancement(frame.Buffer(), frame.Width(), frame.Height()); } WebRtc_Word32 VideoProcessingModule::ColorEnhancement(WebRtc_UWord8* frame, const WebRtc_UWord32 width, const WebRtc_UWord32 height) { return VideoProcessing::ColorEnhancement(frame, width, height); } WebRtc_Word32 VideoProcessingModuleImpl::Deflickering(VideoFrame& frame, FrameStats& stats) { return Deflickering(frame.Buffer(), frame.Width(), frame.Height(), frame.TimeStamp(), stats); } WebRtc_Word32 VideoProcessingModuleImpl::Deflickering(WebRtc_UWord8* frame, const WebRtc_UWord32 width, const WebRtc_UWord32 height, const WebRtc_UWord32 timestamp, FrameStats& stats) { CriticalSectionScoped mutex(_mutex); return _deflickering.ProcessFrame(frame, width, height, timestamp, stats); } WebRtc_Word32 VideoProcessingModuleImpl::Denoising(VideoFrame& frame) { return Denoising(frame.Buffer(), frame.Width(), frame.Height()); } WebRtc_Word32 VideoProcessingModuleImpl::Denoising(WebRtc_UWord8* frame, const WebRtc_UWord32 width, const WebRtc_UWord32 height) { CriticalSectionScoped mutex(_mutex); return _denoising.ProcessFrame(frame, width, height); } WebRtc_Word32 VideoProcessingModuleImpl::BrightnessDetection(const VideoFrame& frame, const FrameStats& stats) { return BrightnessDetection(frame.Buffer(), frame.Width(), frame.Height(), stats); } WebRtc_Word32 VideoProcessingModuleImpl::BrightnessDetection(const WebRtc_UWord8* frame, const WebRtc_UWord32 width, const WebRtc_UWord32 height, const FrameStats& stats) { CriticalSectionScoped mutex(_mutex); return _brightnessDetection.ProcessFrame(frame, width, height, stats); } void VideoProcessingModuleImpl::EnableTemporalDecimation(bool enable) { CriticalSectionScoped mutex(_mutex); _framePreProcessor.EnableTemporalDecimation(enable); } void VideoProcessingModuleImpl::SetInputFrameResampleMode(VideoFrameResampling resamplingMode) { CriticalSectionScoped cs(_mutex); _framePreProcessor.SetInputFrameResampleMode(resamplingMode); } WebRtc_Word32 VideoProcessingModuleImpl::SetMaxFrameRate(WebRtc_UWord32 maxFrameRate) { CriticalSectionScoped cs(_mutex); return _framePreProcessor.SetMaxFrameRate(maxFrameRate); } WebRtc_Word32 VideoProcessingModuleImpl::SetTargetResolution(WebRtc_UWord32 width, WebRtc_UWord32 height, WebRtc_UWord32 frameRate) { CriticalSectionScoped cs(_mutex); return _framePreProcessor.SetTargetResolution(width, height, frameRate); } WebRtc_UWord32 VideoProcessingModuleImpl::DecimatedFrameRate() { CriticalSectionScoped cs(_mutex); return _framePreProcessor.DecimatedFrameRate(); } WebRtc_UWord32 VideoProcessingModuleImpl::DecimatedWidth() const { CriticalSectionScoped cs(_mutex); return _framePreProcessor.DecimatedWidth(); } WebRtc_UWord32 VideoProcessingModuleImpl::DecimatedHeight() const { CriticalSectionScoped cs(_mutex); return _framePreProcessor.DecimatedHeight(); } WebRtc_Word32 VideoProcessingModuleImpl::PreprocessFrame(const VideoFrame *frame, VideoFrame **processedFrame) { CriticalSectionScoped mutex(_mutex); return _framePreProcessor.PreprocessFrame(frame, processedFrame); } VideoContentMetrics* VideoProcessingModuleImpl::ContentMetrics() const { CriticalSectionScoped mutex(_mutex); return _framePreProcessor.ContentMetrics(); } void VideoProcessingModuleImpl::EnableContentAnalysis(bool enable) { CriticalSectionScoped mutex(_mutex); _framePreProcessor.EnableContentAnalysis(enable); } } //namespace