369 lines
10 KiB
C++
369 lines
10 KiB
C++
/*
|
|
* 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 <cassert>
|
|
|
|
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<VideoProcessingModuleImpl*>(module)->Id(),
|
|
"VideoProcessingModule::destroy()");
|
|
delete static_cast<VideoProcessingModuleImpl*>(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
|