webrtc/modules/video_capture/main/test/testAPI/testCameraEncoder.cpp

335 lines
12 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 "testCameraEncoder.h"
#include "trace.h"
#include "tick_util.h"
namespace webrtc
{
#ifndef _DEBUG
#undef assert
#define assert(_a) { \
if(!(_a)) \
{ \
LOG("Failed %s",#_a); \
} \
}
#endif
testCameraEncoder::testCameraEncoder(void)
{
Trace::CreateTrace();
Trace::SetLevelFilter(webrtc::kTraceAll);
Trace::SetTraceFile("testCameraEncoder.txt");
_captureInfo=VideoCaptureModule::CreateDeviceInfo(5);
#ifdef RENDER_PREVIEW
_renderer=NULL;
_videoCoding=webrtc::VideoCodingModule::Createwebrtc::VideoCodingModule(5);
#endif
}
testCameraEncoder::~testCameraEncoder(void)
{
VideoCaptureModule::DestroyDeviceInfo(_captureInfo);
#ifdef RENDER_PREVIEW
if(_renderer)
delete _renderer;
if(_videoCoding)
{
webrtc::VideoCodingModule::Destroywebrtc::VideoCodingModule(_videoCoding);
}
#endif
Trace::ReturnTrace();
}
int testCameraEncoder::DoTest()
{
#ifdef RENDER_PREVIEW
if(!_renderer)
{
_renderer=new Renderer(true);
}
if(_videoCoding)
{
webrtc::VideoCodec inst;
memset(&inst,0,sizeof(inst));
inst.plType=122;
inst.width=640;
inst.height=480;
inst.codecType=webrtc::kVideoCodecH264;
strcpy(inst.plName,"H264");
_videoCoding->InitializeReceiver();
_videoCoding->RegisterReceiveCallback(this);
assert(_videoCoding->RegisterReceiveCodec(&inst,1,false)==0);
}
#endif
// Test one camera at the time
LOG("\n\nTesting Camera encoder\n");
for (WebRtc_UWord32 i=0;i<_captureInfo->NumberOfDevices();++i)
{
WebRtc_UWord8 name[256];
WebRtc_UWord8 uniqueID[256];
WebRtc_UWord8 productId[256];
_captureInfo->GetDeviceName(i,name,256,uniqueID,256,productId,256);
_captureModule= VideoCaptureModule::Create(0,uniqueID);
_captureModule->RegisterCaptureDataCallback(*this);
VideoCaptureCapability capability;
LOG("Encoder support for device %s",uniqueID);
for (int capIndex=0;capIndex<
_captureInfo->NumberOfCapabilities(uniqueID);++capIndex)
{
assert(_captureInfo->GetCapability(uniqueID,capIndex,capability)==0);
if(capability.codecType==webrtc::kVideoCodecH264)
{
testCapability(capability);
}
else if(capability.codecType!=webrtc::kVideoCodecUnknown)
{
LOG("type %d width %d, height %d, framerate %d\n",
capability.codecType,capability.width,capability.height,capability.maxFPS);
testCapability(capability);
}
}
VideoCaptureModule::Destroy(_captureModule);
}
return 0;
}
int testCameraEncoder::testCapability(VideoCaptureCapability& capability)
{
webrtc::VideoCodec codec;
codec.height=(unsigned short)capability.height;
codec.width=(unsigned short) capability.width;
float bitrate=(float)(capability.height*capability.width*3)/1000; //3bits per pixel
codec.startBitrate=(unsigned int)bitrate;
codec.maxBitrate=codec.startBitrate*10;
codec.codecType=webrtc::kVideoCodecH264;
codec.codecSpecific.H264.profile=webrtc::kProfileBase;
_encodeInterface=NULL;
_encodeInterface=_captureModule->GetEncodeInterface(codec);
if(_encodeInterface)
assert(_encodeInterface);
_captureSettings.ResetAll();
_captureSettings.capability=capability;
assert(capability.width);
assert(capability.height);
assert(capability.maxFPS);
assert(capability.expectedCaptureDelay);
_captureSettings.lastRenderTimeMS=0;
_captureSettings.captureDelay=50;
WebRtc_UWord32 maxPayloadSize=1460;
LOG("\n\nTesting H264 width %d, height %d, framerate %d bitrate %d\n",
capability.width,capability.height,capability.maxFPS,codec.startBitrate);
_captureSettings.initStartTime=TickTime::MillisecondTimestamp();
assert(_captureModule->StartCapture(capability)==0);
_captureSettings.startTime=TickTime::MillisecondTimestamp();
_captureSettings.initStopTime=TickTime::MillisecondTimestamp();
if(_encodeInterface)
assert(_encodeInterface->ConfigureEncoder(codec,maxPayloadSize)==0);
WebRtc_Word32 testTime=10000;
while(TickTime::MillisecondTimestamp()-_captureSettings.startTime<testTime
&& _captureSettings.incomingFrames<200)
{
SLEEP(200);
}
int noIncomingFrames=_captureSettings.incomingFrames;
_captureSettings.bitrateMeasureTime=TickTime::MillisecondTimestamp();
WebRtc_UWord32 actualbitrate=(_captureSettings.noOfBytes*8)/
(WebRtc_UWord32)(_captureSettings.bitrateMeasureTime-_captureSettings.firstCapturedFrameTime);
_captureSettings.noOfBytes=0;
LOG("Current set bitrate %d, actual bitrate %d\n", codec.startBitrate,actualbitrate);
for(int bitRateChange=1;bitRateChange< 11;bitRateChange=bitRateChange*2)
{
float bitrate=(float)(capability.height*
capability.width*
(bitRateChange))/1000; //3bits per pixel
codec.startBitrate=(WebRtc_Word32) bitrate;
LOG("Changing bitrate to %d (%d bits per pixel/s)\n",
codec.startBitrate,bitRateChange);
assert(_encodeInterface->SetRates(codec.startBitrate,codec.maxFramerate)==0);
testTime=2000;
while(TickTime::MillisecondTimestamp()-
_captureSettings.bitrateMeasureTime<testTime)
{
SLEEP(200);
}
noIncomingFrames=_captureSettings.incomingFrames;
WebRtc_UWord32 actualbitrate=(_captureSettings.noOfBytes*8)/
(WebRtc_UWord32)(TickTime::MillisecondTimestamp()-
_captureSettings.bitrateMeasureTime);
_captureSettings.bitrateMeasureTime=TickTime::MillisecondTimestamp();
_captureSettings.noOfBytes=0;
LOG("Current set bitrate %d, actual bitrate %d\n",
codec.startBitrate,actualbitrate);
assert((actualbitrate<(1.2* codec.startBitrate))
&& (actualbitrate>0.8*codec.startBitrate));
}
_captureSettings.stopTime=TickTime::MillisecondTimestamp();
_captureSettings.stopStartTime=TickTime::MillisecondTimestamp();
assert(_captureModule->StopCapture()==0);
_captureSettings.stopStopTime=TickTime::MillisecondTimestamp();
EvaluateTestResult();
return 0;
}
void testCameraEncoder::OnIncomingCapturedFrame(const WebRtc_Word32 id,
VideoFrame& videoFrame,
webrtc::VideoCodecType codecType)
{
_captureSettings.incomingFrames++;
_captureSettings.noOfBytes+=videoFrame.Length();
assert(videoFrame.Height()==_captureSettings.capability.height);
assert(videoFrame.Width()==_captureSettings.capability.width);
assert(videoFrame.RenderTimeMs()>=(TickTime::MillisecondTimestamp()-30)); // RenderTimstamp should be the time now
if((videoFrame.RenderTimeMs()>_captureSettings.lastRenderTimeMS
+(1000*1.2)/_captureSettings.capability.maxFPS
&& _captureSettings.lastRenderTimeMS>0)
||
(videoFrame.RenderTimeMs()<_captureSettings.lastRenderTimeMS+(1000*0.8)
/_captureSettings.capability.maxFPS && _captureSettings.lastRenderTimeMS>0))
{
_captureSettings.timingWarnings++;
}
if(_captureSettings.lastRenderTimeMS==0)
{
_captureSettings.firstCapturedFrameTime=TickTime::MillisecondTimestamp();
}
_captureSettings.lastRenderTimeMS=videoFrame.RenderTimeMs();
if(codecType==webrtc::kVideoCodecH264)
{
WebRtc_UWord8* ptrBuffer=videoFrame.Buffer();
if(ptrBuffer[0]!=0 || ptrBuffer[1]!=0 || ptrBuffer[2]!=0 || ptrBuffer[3]!=1)
{
assert(!"frame does not start with NALU header");
}
if(ptrBuffer[4]==0x67)
{
_captureSettings.idrFrames++;
LOG("Got IDR frame frame no %d. total number of IDR frames %d \n",
_captureSettings.incomingFrames,_captureSettings.idrFrames);
}
}
#ifdef RENDER_PREVIEW
if(codecType==webrtc::kVideoCodecH264)
{
VideoEncodedData encodedFrame;
memset(&encodedFrame,0,sizeof(encodedFrame));
encodedFrame.codec=webrtc::kVideoCodecH264;
encodedFrame.encodedHeight=videoFrame.Height();
encodedFrame.encodedWidth=videoFrame.Width();
encodedFrame.renderTimeMs=videoFrame.RenderTimeMs();
encodedFrame.timeStamp=90* (WebRtc_UWord32) videoFrame.RenderTimeMs();
encodedFrame.payloadData=(WebRtc_UWord8*) malloc(videoFrame.Length());
memcpy(encodedFrame.payloadData,videoFrame.Buffer(),videoFrame.Length());
encodedFrame.payloadSize=videoFrame.Length();
encodedFrame.bufferSize=videoFrame.Length();
encodedFrame.payloadType=122;
_videoCoding->DecodeFromStorage(encodedFrame);
}
if(codecType==webrtc::kVideoCodecUnknown)
{
_renderer->RenderFrame(videoFrame);
}
#endif
}
void testCameraEncoder::OnCaptureDelayChanged(const WebRtc_Word32 id,
const WebRtc_Word32 delay)
{
_captureSettings.captureDelay=delay;
}
#ifdef RENDER_PREVIEW
WebRtc_Word32 testCameraEncoder::FrameToRender(VideoFrame& videoFrame)
{
_renderer->RenderFrame(videoFrame);
return 0;
}
#endif
void testCameraEncoder::EvaluateTestResult()
{
CaptureSetting& captureResult=_captureSettings;
WebRtc_UWord64 timeToFirstFrame=captureResult.firstCapturedFrameTime-captureResult.startTime;
WebRtc_UWord64 timeToStart=captureResult.initStopTime-captureResult.initStartTime;
WebRtc_UWord64 timeToStop=captureResult.stopStopTime-captureResult.stopStartTime;
assert(timeToStart<4000);
assert(timeToStop<3000);
assert((timeToFirstFrame<3500) && (timeToFirstFrame>0)); // Assert if it takes more than 3500ms to start.
WebRtc_Word64 expectedNumberOfFrames=((captureResult.stopTime
-captureResult.startTime
-timeToFirstFrame)
*captureResult.capability.maxFPS)/1000;
assert(captureResult.incomingFrames>0.6*expectedNumberOfFrames); // Make sure at least 60% of the expected frames have been received from the camera
LOG(" No Captured %d,expected %d, \n timingWarnings %d, time to first %lu\n"
" time to start %lu, time to stop %lu\n idr frames %u\n",
captureResult.incomingFrames,(int)(expectedNumberOfFrames),
captureResult.timingWarnings,
(long) timeToFirstFrame,
(long) timeToStart,
(long) timeToStop,
_captureSettings.idrFrames);
captureResult.ResetSettings();
}
} // namespace webrtc