418 lines
9.0 KiB
C++
418 lines
9.0 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_source.h"
|
||
|
#include "vplib.h"
|
||
|
#include <cassert>
|
||
|
#include <stdio.h>
|
||
|
|
||
|
VideoSource::VideoSource()
|
||
|
:
|
||
|
_fileName("../../../../testFiles/foreman.yuv"),
|
||
|
_width(352),
|
||
|
_height(288),
|
||
|
_type(webrtc::kI420),
|
||
|
_frameRate(30)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
VideoSource::VideoSource(std::string fileName, VideoSize size,
|
||
|
int frameRate /*= 30*/, webrtc::VideoType type /*= webrtc::kI420*/)
|
||
|
:
|
||
|
_fileName(fileName),
|
||
|
_type(type),
|
||
|
_frameRate(frameRate)
|
||
|
{
|
||
|
assert(size != kUndefined && size != kNumberOfVideoSizes);
|
||
|
assert(type != webrtc::kUnknown);
|
||
|
assert(frameRate > 0);
|
||
|
assert(GetWidthHeight(size, _width, _height) == 0);
|
||
|
}
|
||
|
|
||
|
VideoSource::VideoSource(std::string fileName, int width, int height,
|
||
|
int frameRate /*= 30*/, webrtc::VideoType type /*= webrtc::kI420*/)
|
||
|
:
|
||
|
_fileName(fileName),
|
||
|
_width(width),
|
||
|
_height(height),
|
||
|
_type(type),
|
||
|
_frameRate(frameRate)
|
||
|
{
|
||
|
assert(width > 0);
|
||
|
assert(height > 0);
|
||
|
assert(type != webrtc::kUnknown);
|
||
|
assert(frameRate > 0);
|
||
|
}
|
||
|
|
||
|
VideoSize
|
||
|
VideoSource::GetSize() const
|
||
|
{
|
||
|
return GetSize(_width, _height);
|
||
|
}
|
||
|
|
||
|
VideoSize
|
||
|
VideoSource::GetSize(WebRtc_UWord16 width, WebRtc_UWord16 height)
|
||
|
{
|
||
|
if(width == 128 && height == 96)
|
||
|
{
|
||
|
return kSQCIF;
|
||
|
}else if(width == 160 && height == 120)
|
||
|
{
|
||
|
return kQQVGA;
|
||
|
}else if(width == 176 && height == 144)
|
||
|
{
|
||
|
return kQCIF;
|
||
|
}else if(width == 320 && height == 240)
|
||
|
{
|
||
|
return kQVGA;
|
||
|
}else if(width == 352 && height == 288)
|
||
|
{
|
||
|
return kCIF;
|
||
|
}else if(width == 640 && height == 480)
|
||
|
{
|
||
|
return kVGA;
|
||
|
}else if(width == 720 && height == 480)
|
||
|
{
|
||
|
return kNTSC;
|
||
|
}else if(width == 704 && height == 576)
|
||
|
{
|
||
|
return k4CIF;
|
||
|
}else if(width == 800 && height == 600)
|
||
|
{
|
||
|
return kSVGA;
|
||
|
}else if(width == 960 && height == 720)
|
||
|
{
|
||
|
return kHD;
|
||
|
}else if(width == 1024 && height == 768)
|
||
|
{
|
||
|
return kXGA;
|
||
|
}else if(width == 1440 && height == 1080)
|
||
|
{
|
||
|
return kFullHD;
|
||
|
}else if(width == 400 && height == 240)
|
||
|
{
|
||
|
return kWQVGA;
|
||
|
}else if(width == 800 && height == 480)
|
||
|
{
|
||
|
return kWVGA;
|
||
|
}else if(width == 1280 && height == 720)
|
||
|
{
|
||
|
return kWHD;
|
||
|
}else if(width == 1920 && height == 1080)
|
||
|
{
|
||
|
return kWFullHD;
|
||
|
}
|
||
|
return kUndefined;
|
||
|
}
|
||
|
|
||
|
unsigned int
|
||
|
VideoSource::GetFrameLength() const
|
||
|
{
|
||
|
return webrtc::CalcBufferSize(_type, _width, _height);
|
||
|
}
|
||
|
|
||
|
const char*
|
||
|
VideoSource::GetMySizeString() const
|
||
|
{
|
||
|
return VideoSource::GetSizeString(GetSize());
|
||
|
}
|
||
|
|
||
|
const char*
|
||
|
VideoSource::GetSizeString(VideoSize size)
|
||
|
{
|
||
|
switch (size)
|
||
|
{
|
||
|
case kSQCIF:
|
||
|
return "SQCIF";
|
||
|
case kQQVGA:
|
||
|
return "QQVGA";
|
||
|
case kQCIF:
|
||
|
return "QCIF";
|
||
|
case kQVGA:
|
||
|
return "QVGA";
|
||
|
case kCIF:
|
||
|
return "CIF";
|
||
|
case kVGA:
|
||
|
return "VGA";
|
||
|
case kNTSC:
|
||
|
return "NTSC";
|
||
|
case k4CIF:
|
||
|
return "4CIF";
|
||
|
case kSVGA:
|
||
|
return "SVGA";
|
||
|
case kHD:
|
||
|
return "HD";
|
||
|
case kXGA:
|
||
|
return "XGA";
|
||
|
case kFullHD:
|
||
|
return "Full_HD";
|
||
|
case kWQVGA:
|
||
|
return "WQVGA";
|
||
|
case kWHD:
|
||
|
return "WHD";
|
||
|
case kWFullHD:
|
||
|
return "WFull_HD";
|
||
|
default:
|
||
|
return "Undefined";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
std::string
|
||
|
VideoSource::GetFilePath() const
|
||
|
{
|
||
|
size_t slashPos = _fileName.find_last_of("/\\");
|
||
|
if (slashPos == std::string::npos)
|
||
|
{
|
||
|
return ".";
|
||
|
}
|
||
|
|
||
|
return _fileName.substr(0, slashPos);
|
||
|
}
|
||
|
|
||
|
std::string
|
||
|
VideoSource::GetName() const
|
||
|
{
|
||
|
// Remove path.
|
||
|
size_t slashPos = _fileName.find_last_of("/\\");
|
||
|
if (slashPos == std::string::npos)
|
||
|
{
|
||
|
slashPos = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
slashPos++;
|
||
|
}
|
||
|
|
||
|
// Remove extension and underscored suffix if it exists.
|
||
|
return _fileName.substr(slashPos, std::min(_fileName.find_last_of("_"),
|
||
|
_fileName.find_last_of(".")) - slashPos);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
VideoSource::Convert(const VideoSource &target, bool force /* = false */) const
|
||
|
{
|
||
|
// Ensure target rate is less than or equal to source
|
||
|
// (i.e. we are only temporally downsampling).
|
||
|
assert(target.GetFrameRate() <= _frameRate);
|
||
|
// Only supports YUV420 currently.
|
||
|
assert(_type == webrtc::kI420 && target.GetType() == webrtc::kI420);
|
||
|
if (!force && (FileExists(target.GetFileName().c_str()) ||
|
||
|
(target.GetWidth() == _width && target.GetHeight() == _height && target.GetFrameRate() == _frameRate)))
|
||
|
{
|
||
|
// Assume that the filename uniquely defines the content.
|
||
|
// If the file already exists, it is the correct file.
|
||
|
return;
|
||
|
}
|
||
|
FILE *inFile = NULL;
|
||
|
FILE *outFile = NULL;
|
||
|
|
||
|
inFile = fopen(_fileName.c_str(), "rb");
|
||
|
assert(inFile != NULL);
|
||
|
|
||
|
outFile = fopen(target.GetFileName().c_str(), "wb");
|
||
|
assert(outFile != NULL);
|
||
|
|
||
|
FrameDropper fd;
|
||
|
fd.SetFrameRate(target.GetFrameRate(), _frameRate);
|
||
|
|
||
|
const size_t lengthOutFrame = webrtc::CalcBufferSize(target.GetType(),
|
||
|
target.GetWidth(), target.GetHeight());
|
||
|
assert(lengthOutFrame > 0);
|
||
|
unsigned char *outFrame = new unsigned char[lengthOutFrame];
|
||
|
|
||
|
const size_t lengthInFrame = webrtc::CalcBufferSize(_type, _width, _height);
|
||
|
assert(lengthInFrame > 0);
|
||
|
unsigned char *inFrame = new unsigned char[lengthInFrame];
|
||
|
|
||
|
while (fread(inFrame, 1, lengthInFrame, inFile) == lengthInFrame)
|
||
|
{
|
||
|
if (!fd.DropFrame())
|
||
|
{
|
||
|
assert(target.GetWidth() == _width &&
|
||
|
target.GetHeight() == _height); // Add video interpolator here!
|
||
|
fwrite(outFrame, 1, lengthOutFrame, outFile);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
delete inFrame;
|
||
|
delete outFrame;
|
||
|
fclose(inFile);
|
||
|
fclose(outFile);
|
||
|
}
|
||
|
|
||
|
bool VideoSource::FileExists(const char* fileName)
|
||
|
{
|
||
|
FILE* fp = NULL;
|
||
|
fp = fopen(fileName, "rb");
|
||
|
if(fp != NULL)
|
||
|
{
|
||
|
fclose(fp);
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
int
|
||
|
VideoSource::GetWidthHeight( VideoSize size, int & width, int& height)
|
||
|
{
|
||
|
switch(size)
|
||
|
{
|
||
|
case kSQCIF:
|
||
|
width = 128;
|
||
|
height = 96;
|
||
|
return 0;
|
||
|
case kQQVGA:
|
||
|
width = 160;
|
||
|
height = 120;
|
||
|
return 0;
|
||
|
case kQCIF:
|
||
|
width = 176;
|
||
|
height = 144;
|
||
|
return 0;
|
||
|
case kCGA:
|
||
|
width = 320;
|
||
|
height = 200;
|
||
|
return 0;
|
||
|
case kQVGA:
|
||
|
width = 320;
|
||
|
height = 240;
|
||
|
return 0;
|
||
|
case kSIF:
|
||
|
width = 352;
|
||
|
height = 240;
|
||
|
return 0;
|
||
|
case kWQVGA:
|
||
|
width = 400;
|
||
|
height = 240;
|
||
|
return 0;
|
||
|
case kCIF:
|
||
|
width = 352;
|
||
|
height = 288;
|
||
|
return 0;
|
||
|
case kW288p:
|
||
|
width = 512;
|
||
|
height = 288;
|
||
|
return 0;
|
||
|
case k448p:
|
||
|
width = 576;
|
||
|
height = 448;
|
||
|
return 0;
|
||
|
case kVGA:
|
||
|
width = 640;
|
||
|
height = 480;
|
||
|
return 0;
|
||
|
case k432p:
|
||
|
width = 720;
|
||
|
height = 432;
|
||
|
return 0;
|
||
|
case kW432p:
|
||
|
width = 768;
|
||
|
height = 432;
|
||
|
return 0;
|
||
|
case k4SIF:
|
||
|
width = 704;
|
||
|
height = 480;
|
||
|
return 0;
|
||
|
case kW448p:
|
||
|
width = 768;
|
||
|
height = 448;
|
||
|
return 0;
|
||
|
case kNTSC:
|
||
|
width = 720;
|
||
|
height = 480;
|
||
|
return 0;
|
||
|
case kFW448p:
|
||
|
width = 800;
|
||
|
height = 448;
|
||
|
return 0;
|
||
|
case kWVGA:
|
||
|
width = 800;
|
||
|
height = 480;
|
||
|
return 0;
|
||
|
case k4CIF:
|
||
|
width = 704;
|
||
|
height = 576;
|
||
|
return 0;
|
||
|
case kSVGA:
|
||
|
width = 800;
|
||
|
height = 600;
|
||
|
return 0;
|
||
|
case kW544p:
|
||
|
width = 960;
|
||
|
height = 544;
|
||
|
return 0;
|
||
|
case kW576p:
|
||
|
width = 1024;
|
||
|
height = 576;
|
||
|
return 0;
|
||
|
case kHD:
|
||
|
width = 960;
|
||
|
height = 720;
|
||
|
return 0;
|
||
|
case kXGA:
|
||
|
width = 1024;
|
||
|
height = 768;
|
||
|
return 0;
|
||
|
case kFullHD:
|
||
|
width = 1440;
|
||
|
height = 1080;
|
||
|
return 0;
|
||
|
case kWHD:
|
||
|
width = 1280;
|
||
|
height = 720;
|
||
|
return 0;
|
||
|
case kWFullHD:
|
||
|
width = 1920;
|
||
|
height = 1080;
|
||
|
return 0;
|
||
|
default:
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
FrameDropper::FrameDropper()
|
||
|
:
|
||
|
_dropsBetweenRenders(0),
|
||
|
_frameCounter(0)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
FrameDropper::DropFrame()
|
||
|
{
|
||
|
_frameCounter++;
|
||
|
if (_frameCounter > _dropsBetweenRenders)
|
||
|
{
|
||
|
_frameCounter = 0;
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
unsigned int
|
||
|
FrameDropper::DropsBetweenRenders()
|
||
|
{
|
||
|
return _dropsBetweenRenders;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
FrameDropper::SetFrameRate(double frameRate, double maxFrameRate)
|
||
|
{
|
||
|
if (frameRate >= 1.0)
|
||
|
{
|
||
|
_dropsBetweenRenders = static_cast<unsigned int>(maxFrameRate / frameRate + 0.5) - 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_dropsBetweenRenders = 0;
|
||
|
}
|
||
|
}
|