mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2023-10-10 13:36:59 +02:00
- Image format NV12 and I420 added
- Flip mode - Scaling factor for MJPEG - VSCode (compile before run) - CI (push) dependency libjpeg-turbo added
This commit is contained in:
parent
545b29ed27
commit
4a79d3f143
5
.github/workflows/push-master.yml
vendored
5
.github/workflows/push-master.yml
vendored
@ -134,6 +134,11 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
choco install --no-progress python nsis openssl directx-sdk -y
|
choco install --no-progress python nsis openssl directx-sdk -y
|
||||||
|
|
||||||
|
- name: Install libjpeg-turbo
|
||||||
|
run: |
|
||||||
|
Invoke-WebRequest https://netcologne.dl.sourceforge.net/project/libjpeg-turbo/2.0.6/libjpeg-turbo-2.0.6-vc64.exe -OutFile libjpeg-turbo.exe
|
||||||
|
.\libjpeg-turbo /S
|
||||||
|
|
||||||
- name: Set up x64 build architecture environment
|
- name: Set up x64 build architecture environment
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: call "${{env.VCINSTALLDIR}}\Auxiliary\Build\vcvars64.bat"
|
run: call "${{env.VCINSTALLDIR}}\Auxiliary\Build\vcvars64.bat"
|
||||||
|
4
.vscode/launch.json
vendored
4
.vscode/launch.json
vendored
@ -8,7 +8,7 @@
|
|||||||
"name": "(Linux) hyperiond",
|
"name": "(Linux) hyperiond",
|
||||||
"type": "cppdbg",
|
"type": "cppdbg",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "${workspaceFolder}/build/bin/hyperiond",
|
"program": "${command:cmake.launchTargetDirectory}/hyperiond",
|
||||||
"args": ["-d"],
|
"args": ["-d"],
|
||||||
"stopAtEntry": false,
|
"stopAtEntry": false,
|
||||||
"cwd": "${workspaceFolder}",
|
"cwd": "${workspaceFolder}",
|
||||||
@ -27,7 +27,7 @@
|
|||||||
"name": "(Windows) hyperiond",
|
"name": "(Windows) hyperiond",
|
||||||
"type": "cppvsdbg",
|
"type": "cppvsdbg",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "${workspaceFolder}/build/bin/Debug/hyperiond.exe",
|
"program": "${command:cmake.launchTargetDirectory}/hyperiond",
|
||||||
"args": ["-d"],
|
"args": ["-d"],
|
||||||
"stopAtEntry": false,
|
"stopAtEntry": false,
|
||||||
"cwd": "${workspaceFolder}",
|
"cwd": "${workspaceFolder}",
|
||||||
|
@ -46,8 +46,7 @@ private:
|
|||||||
|
|
||||||
#ifdef HAVE_TURBO_JPEG
|
#ifdef HAVE_TURBO_JPEG
|
||||||
tjhandle _decompress;
|
tjhandle _decompress;
|
||||||
int _scalingFactorsCount = 0;
|
tjscalingfactor* _scalingFactors;
|
||||||
tjscalingfactor* _scalingFactors = nullptr;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static volatile bool _isActive;
|
static volatile bool _isActive;
|
||||||
@ -57,6 +56,7 @@ private:
|
|||||||
PixelFormat _pixelFormat;
|
PixelFormat _pixelFormat;
|
||||||
uint8_t* _localData;
|
uint8_t* _localData;
|
||||||
int _localDataSize;
|
int _localDataSize;
|
||||||
|
int _scalingFactorsCount;
|
||||||
int _size;
|
int _size;
|
||||||
int _width;
|
int _width;
|
||||||
int _height;
|
int _height;
|
||||||
@ -78,16 +78,7 @@ class MFThreadManager : public QObject
|
|||||||
public:
|
public:
|
||||||
MFThreadManager() : _threads(nullptr)
|
MFThreadManager() : _threads(nullptr)
|
||||||
{
|
{
|
||||||
int select = QThread::idealThreadCount();
|
_maxThreads = qBound(1, ((QThread::idealThreadCount() * 3) / 2), 12);
|
||||||
|
|
||||||
if (select >= 2 && select <= 3)
|
|
||||||
select = 2;
|
|
||||||
else if (select > 3 && select <= 5)
|
|
||||||
select = 3;
|
|
||||||
else if (select > 5)
|
|
||||||
select = 4;
|
|
||||||
|
|
||||||
_maxThreads = qMax(select, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~MFThreadManager()
|
~MFThreadManager()
|
||||||
@ -100,6 +91,7 @@ public:
|
|||||||
_threads[i]->deleteLater();
|
_threads[i]->deleteLater();
|
||||||
_threads[i] = nullptr;
|
_threads[i] = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
delete[] _threads;
|
delete[] _threads;
|
||||||
_threads = nullptr;
|
_threads = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -9,12 +9,13 @@ class ImageResampler
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ImageResampler();
|
ImageResampler();
|
||||||
~ImageResampler();
|
~ImageResampler() {}
|
||||||
|
|
||||||
void setHorizontalPixelDecimation(int decimator);
|
void setHorizontalPixelDecimation(int decimator) { _horizontalDecimation = decimator; }
|
||||||
void setVerticalPixelDecimation(int decimator);
|
void setVerticalPixelDecimation(int decimator) { _verticalDecimation = decimator; }
|
||||||
void setCropping(int cropLeft, int cropRight, int cropTop, int cropBottom);
|
void setCropping(int cropLeft, int cropRight, int cropTop, int cropBottom);
|
||||||
void setVideoMode(VideoMode mode);
|
void setVideoMode(VideoMode mode) { _videoMode = mode; }
|
||||||
|
void setFlipMode(FlipMode mode) { _flipMode = mode; }
|
||||||
void processImage(const uint8_t * data, int width, int height, int lineLength, PixelFormat pixelFormat, Image<ColorRgb> & outputImage) const;
|
void processImage(const uint8_t * data, int width, int height, int lineLength, PixelFormat pixelFormat, Image<ColorRgb> & outputImage) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -25,5 +26,6 @@ private:
|
|||||||
int _cropTop;
|
int _cropTop;
|
||||||
int _cropBottom;
|
int _cropBottom;
|
||||||
VideoMode _videoMode;
|
VideoMode _videoMode;
|
||||||
|
FlipMode _flipMode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -12,6 +12,8 @@ enum class PixelFormat {
|
|||||||
BGR24,
|
BGR24,
|
||||||
RGB32,
|
RGB32,
|
||||||
BGR32,
|
BGR32,
|
||||||
|
NV12,
|
||||||
|
I420,
|
||||||
#ifdef HAVE_JPEG_DECODER
|
#ifdef HAVE_JPEG_DECODER
|
||||||
MJPEG,
|
MJPEG,
|
||||||
#endif
|
#endif
|
||||||
@ -47,6 +49,14 @@ inline PixelFormat parsePixelFormat(const QString& pixelFormat)
|
|||||||
{
|
{
|
||||||
return PixelFormat::BGR32;
|
return PixelFormat::BGR32;
|
||||||
}
|
}
|
||||||
|
else if (format.compare("i420") == 0)
|
||||||
|
{
|
||||||
|
return PixelFormat::I420;
|
||||||
|
}
|
||||||
|
else if (format.compare("nv12") == 0)
|
||||||
|
{
|
||||||
|
return PixelFormat::NV12;
|
||||||
|
}
|
||||||
#ifdef HAVE_JPEG_DECODER
|
#ifdef HAVE_JPEG_DECODER
|
||||||
else if (format.compare("mjpeg") == 0)
|
else if (format.compare("mjpeg") == 0)
|
||||||
{
|
{
|
||||||
@ -63,35 +73,97 @@ inline QString pixelFormatToString(const PixelFormat& pixelFormat)
|
|||||||
|
|
||||||
if ( pixelFormat == PixelFormat::YUYV)
|
if ( pixelFormat == PixelFormat::YUYV)
|
||||||
{
|
{
|
||||||
return "yuyv";
|
return "YUYV";
|
||||||
}
|
}
|
||||||
else if (pixelFormat == PixelFormat::UYVY)
|
else if (pixelFormat == PixelFormat::UYVY)
|
||||||
{
|
{
|
||||||
return "uyvy";
|
return "UYVY";
|
||||||
}
|
}
|
||||||
else if (pixelFormat == PixelFormat::BGR16)
|
else if (pixelFormat == PixelFormat::BGR16)
|
||||||
{
|
{
|
||||||
return "bgr16";
|
return "BGR16";
|
||||||
}
|
}
|
||||||
else if (pixelFormat == PixelFormat::BGR24)
|
else if (pixelFormat == PixelFormat::BGR24)
|
||||||
{
|
{
|
||||||
return "bgr24";
|
return "BGR24";
|
||||||
}
|
}
|
||||||
else if (pixelFormat == PixelFormat::RGB32)
|
else if (pixelFormat == PixelFormat::RGB32)
|
||||||
{
|
{
|
||||||
return "rgb32";
|
return "RGB32";
|
||||||
}
|
}
|
||||||
else if (pixelFormat == PixelFormat::BGR32)
|
else if (pixelFormat == PixelFormat::BGR32)
|
||||||
{
|
{
|
||||||
return "bgr32";
|
return "BGR32";
|
||||||
|
}
|
||||||
|
else if (pixelFormat == PixelFormat::I420)
|
||||||
|
{
|
||||||
|
return "I420";
|
||||||
|
}
|
||||||
|
else if (pixelFormat == PixelFormat::NV12)
|
||||||
|
{
|
||||||
|
return "NV12";
|
||||||
}
|
}
|
||||||
#ifdef HAVE_JPEG_DECODER
|
#ifdef HAVE_JPEG_DECODER
|
||||||
else if (pixelFormat == PixelFormat::MJPEG)
|
else if (pixelFormat == PixelFormat::MJPEG)
|
||||||
{
|
{
|
||||||
return "mjpeg";
|
return "MJPEG";
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// return the default NO_CHANGE
|
// return the default NO_CHANGE
|
||||||
return "NO_CHANGE";
|
return "NO_CHANGE";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enumeration of the possible flip modes
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum class FlipMode
|
||||||
|
{
|
||||||
|
HORIZONTAL = 1,
|
||||||
|
VERTICAL = 2,
|
||||||
|
BOTH = HORIZONTAL | VERTICAL,
|
||||||
|
NO_CHANGE = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
inline FlipMode parseFlipMode(const QString& flipMode)
|
||||||
|
{
|
||||||
|
// convert to lower case
|
||||||
|
QString mode = flipMode.toLower();
|
||||||
|
|
||||||
|
if (flipMode.compare("horizontal") == 0)
|
||||||
|
{
|
||||||
|
return FlipMode::HORIZONTAL;
|
||||||
|
}
|
||||||
|
else if (flipMode.compare("vertical") == 0)
|
||||||
|
{
|
||||||
|
return FlipMode::VERTICAL;
|
||||||
|
}
|
||||||
|
else if (flipMode.compare("both") == 0)
|
||||||
|
{
|
||||||
|
return FlipMode::BOTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the default NO_CHANGE
|
||||||
|
return FlipMode::NO_CHANGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QString flipModeToString(const FlipMode& flipMode)
|
||||||
|
{
|
||||||
|
|
||||||
|
if ( flipMode == FlipMode::HORIZONTAL)
|
||||||
|
{
|
||||||
|
return "horizontal";
|
||||||
|
}
|
||||||
|
else if (flipMode == FlipMode::VERTICAL)
|
||||||
|
{
|
||||||
|
return "vertical";
|
||||||
|
}
|
||||||
|
else if (flipMode == FlipMode::BOTH)
|
||||||
|
{
|
||||||
|
return "both";
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the default NO_CHANGE
|
||||||
|
return "NO_CHANGE";
|
||||||
|
}
|
||||||
|
@ -4,9 +4,12 @@
|
|||||||
static PixelFormat GetPixelFormatForGuid(const GUID guid)
|
static PixelFormat GetPixelFormatForGuid(const GUID guid)
|
||||||
{
|
{
|
||||||
if (IsEqualGUID(guid, MFVideoFormat_RGB32)) return PixelFormat::RGB32;
|
if (IsEqualGUID(guid, MFVideoFormat_RGB32)) return PixelFormat::RGB32;
|
||||||
|
if (IsEqualGUID(guid, MFVideoFormat_RGB24)) return PixelFormat::BGR24;
|
||||||
if (IsEqualGUID(guid, MFVideoFormat_YUY2)) return PixelFormat::YUYV;
|
if (IsEqualGUID(guid, MFVideoFormat_YUY2)) return PixelFormat::YUYV;
|
||||||
if (IsEqualGUID(guid, MFVideoFormat_UYVY)) return PixelFormat::UYVY;
|
if (IsEqualGUID(guid, MFVideoFormat_UYVY)) return PixelFormat::UYVY;
|
||||||
if (IsEqualGUID(guid, MFVideoFormat_MJPG)) return PixelFormat::MJPEG;
|
if (IsEqualGUID(guid, MFVideoFormat_MJPG)) return PixelFormat::MJPEG;
|
||||||
|
if (IsEqualGUID(guid, MFVideoFormat_NV12)) return PixelFormat::NV12;
|
||||||
|
if (IsEqualGUID(guid, MFVideoFormat_I420)) return PixelFormat::I420;
|
||||||
return PixelFormat::NO_CHANGE;
|
return PixelFormat::NO_CHANGE;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -40,7 +43,7 @@ MFGrabber::MFGrabber(const QString & device, unsigned width, unsigned height, un
|
|||||||
setInput(input);
|
setInput(input);
|
||||||
setWidthHeight(width, height);
|
setWidthHeight(width, height);
|
||||||
setFramerate(fps);
|
setFramerate(fps);
|
||||||
// setDeviceVideoStandard(device, videoStandard);
|
// setDeviceVideoStandard(device, videoStandard); // TODO
|
||||||
|
|
||||||
CoInitializeEx(0, COINIT_MULTITHREADED);
|
CoInitializeEx(0, COINIT_MULTITHREADED);
|
||||||
_hr = MFStartup(MF_VERSION, MFSTARTUP_NOSOCKET);
|
_hr = MFStartup(MF_VERSION, MFSTARTUP_NOSOCKET);
|
||||||
@ -134,7 +137,7 @@ bool MFGrabber::init()
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strict)
|
if (strict && (val.fps <= 60 || _fps != 15))
|
||||||
foundIndex = i;
|
foundIndex = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -394,16 +397,32 @@ bool MFGrabber::init_device(QString deviceName, DevicePropertiesItem props)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PixelFormat::RGB32:
|
case PixelFormat::BGR24:
|
||||||
|
case PixelFormat::MJPEG:
|
||||||
{
|
{
|
||||||
_frameByteSize = props.x * props.y * 4;
|
_frameByteSize = props.x * props.y * 3;
|
||||||
_lineLength = props.x * 3;
|
_lineLength = props.x * 3;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PixelFormat::MJPEG:
|
case PixelFormat::RGB32:
|
||||||
{
|
{
|
||||||
_lineLength = props.x * 3;
|
_frameByteSize = props.x * props.y * 4;
|
||||||
|
_lineLength = props.x * 4;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PixelFormat::NV12:
|
||||||
|
{
|
||||||
|
_frameByteSize = (6 * props.x * props.y) / 4;
|
||||||
|
_lineLength = props.x;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PixelFormat::I420:
|
||||||
|
{
|
||||||
|
_frameByteSize = (6 * props.x * props.y) / 4;
|
||||||
|
_lineLength = props.x;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -499,6 +518,8 @@ void MFGrabber::enumVideoCaptureDevices()
|
|||||||
di.pf = pixelformat;
|
di.pf = pixelformat;
|
||||||
di.guid = format;
|
di.guid = format;
|
||||||
properties.valid.append(di);
|
properties.valid.append(di);
|
||||||
|
|
||||||
|
Debug(_log, "%s %d x %d @ %d fps (%s)", QSTRING_CSTR(dev), di.x, di.y, di.fps, QSTRING_CSTR(pixelFormatToString(di.pf)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +74,6 @@ public:
|
|||||||
hrStatus = pSample->ConvertToContiguousBuffer(&buffer);
|
hrStatus = pSample->ConvertToContiguousBuffer(&buffer);
|
||||||
if (SUCCEEDED(hrStatus))
|
if (SUCCEEDED(hrStatus))
|
||||||
{
|
{
|
||||||
|
|
||||||
BYTE* data = nullptr;
|
BYTE* data = nullptr;
|
||||||
DWORD maxLength = 0, currentLength = 0;
|
DWORD maxLength = 0, currentLength = 0;
|
||||||
|
|
||||||
@ -89,11 +88,11 @@ public:
|
|||||||
else
|
else
|
||||||
error = QString("buffer->Lock failed => %1").arg(hrStatus);
|
error = QString("buffer->Lock failed => %1").arg(hrStatus);
|
||||||
|
|
||||||
SAFE_RELEASE(buffer);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
error = QString("pSample->ConvertToContiguousBuffer failed => %1").arg(hrStatus);
|
error = QString("pSample->ConvertToContiguousBuffer failed => %1").arg(hrStatus);
|
||||||
|
|
||||||
|
SAFE_RELEASE(buffer);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
error = "pSample is NULL";
|
error = "pSample is NULL";
|
||||||
|
@ -3,13 +3,15 @@
|
|||||||
|
|
||||||
volatile bool MFThread::_isActive = false;
|
volatile bool MFThread::_isActive = false;
|
||||||
|
|
||||||
MFThread::MFThread():
|
MFThread::MFThread()
|
||||||
_localData(nullptr),
|
: _localData(nullptr)
|
||||||
_localDataSize(0),
|
, _localDataSize(0)
|
||||||
_decompress(nullptr),
|
, _decompress(nullptr)
|
||||||
_isBusy(false),
|
, _scalingFactorsCount(0)
|
||||||
_semaphore(1),
|
, _scalingFactors(nullptr)
|
||||||
_imageResampler()
|
, _isBusy(false)
|
||||||
|
, _semaphore(1)
|
||||||
|
, _imageResampler()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,6 +52,7 @@ void MFThread::setup(
|
|||||||
_imageResampler.setCropping(cropLeft, cropRight, cropTop, cropBottom);
|
_imageResampler.setCropping(cropLeft, cropRight, cropTop, cropBottom);
|
||||||
_imageResampler.setHorizontalPixelDecimation(_pixelDecimation);
|
_imageResampler.setHorizontalPixelDecimation(_pixelDecimation);
|
||||||
_imageResampler.setVerticalPixelDecimation(_pixelDecimation);
|
_imageResampler.setVerticalPixelDecimation(_pixelDecimation);
|
||||||
|
_imageResampler.setFlipMode(FlipMode::HORIZONTAL);
|
||||||
|
|
||||||
if (size > _localDataSize)
|
if (size > _localDataSize)
|
||||||
{
|
{
|
||||||
@ -110,6 +113,7 @@ void MFThread::processImageMjpeg()
|
|||||||
{
|
{
|
||||||
_decompress = tjInitDecompress();
|
_decompress = tjInitDecompress();
|
||||||
_scalingFactors = tjGetScalingFactors (&_scalingFactorsCount);
|
_scalingFactors = tjGetScalingFactors (&_scalingFactorsCount);
|
||||||
|
tjhandle handle=NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tjDecompressHeader2(_decompress, _localData, _size, &_width, &_height, &_subsamp) != 0)
|
if (tjDecompressHeader2(_decompress, _localData, _size, &_width, &_height, &_subsamp) != 0)
|
||||||
@ -167,6 +171,8 @@ void MFThread::processImageMjpeg()
|
|||||||
unsigned char* source = (unsigned char*)srcImage.memptr() + (y + _cropTop)*srcImage.width()*3 + _cropLeft*3;
|
unsigned char* source = (unsigned char*)srcImage.memptr() + (y + _cropTop)*srcImage.width()*3 + _cropLeft*3;
|
||||||
unsigned char* dest = (unsigned char*)destImage.memptr() + y*destImage.width()*3;
|
unsigned char* dest = (unsigned char*)destImage.memptr() + y*destImage.width()*3;
|
||||||
memcpy(dest, source, destImage.width()*3);
|
memcpy(dest, source, destImage.width()*3);
|
||||||
|
free(source);
|
||||||
|
free(dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
// emit
|
// emit
|
||||||
|
@ -10,23 +10,10 @@ ImageResampler::ImageResampler()
|
|||||||
, _cropTop(0)
|
, _cropTop(0)
|
||||||
, _cropBottom(0)
|
, _cropBottom(0)
|
||||||
, _videoMode(VideoMode::VIDEO_2D)
|
, _videoMode(VideoMode::VIDEO_2D)
|
||||||
|
, _flipMode(FlipMode::NO_CHANGE)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageResampler::~ImageResampler()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImageResampler::setHorizontalPixelDecimation(int decimator)
|
|
||||||
{
|
|
||||||
_horizontalDecimation = decimator;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImageResampler::setVerticalPixelDecimation(int decimator)
|
|
||||||
{
|
|
||||||
_verticalDecimation = decimator;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImageResampler::setCropping(int cropLeft, int cropRight, int cropTop, int cropBottom)
|
void ImageResampler::setCropping(int cropLeft, int cropRight, int cropTop, int cropBottom)
|
||||||
{
|
{
|
||||||
_cropLeft = cropLeft;
|
_cropLeft = cropLeft;
|
||||||
@ -35,15 +22,12 @@ void ImageResampler::setCropping(int cropLeft, int cropRight, int cropTop, int c
|
|||||||
_cropBottom = cropBottom;
|
_cropBottom = cropBottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageResampler::setVideoMode(VideoMode mode)
|
|
||||||
{
|
|
||||||
_videoMode = mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImageResampler::processImage(const uint8_t * data, int width, int height, int lineLength, PixelFormat pixelFormat, Image<ColorRgb> &outputImage) const
|
void ImageResampler::processImage(const uint8_t * data, int width, int height, int lineLength, PixelFormat pixelFormat, Image<ColorRgb> &outputImage) const
|
||||||
{
|
{
|
||||||
int cropRight = _cropRight;
|
int cropRight = _cropRight;
|
||||||
int cropBottom = _cropBottom;
|
int cropBottom = _cropBottom;
|
||||||
|
int xDestFlip = 0, yDestFlip = 0;
|
||||||
|
int uOffset, vOffset;
|
||||||
|
|
||||||
// handle 3D mode
|
// handle 3D mode
|
||||||
switch (_videoMode)
|
switch (_videoMode)
|
||||||
@ -67,11 +51,40 @@ void ImageResampler::processImage(const uint8_t * data, int width, int height, i
|
|||||||
for (int yDest = 0, ySource = _cropTop + (_verticalDecimation >> 1); yDest < outputHeight; ySource += _verticalDecimation, ++yDest)
|
for (int yDest = 0, ySource = _cropTop + (_verticalDecimation >> 1); yDest < outputHeight; ySource += _verticalDecimation, ++yDest)
|
||||||
{
|
{
|
||||||
int yOffset = lineLength * ySource;
|
int yOffset = lineLength * ySource;
|
||||||
|
if (pixelFormat == PixelFormat::NV12)
|
||||||
|
{
|
||||||
|
uOffset = (height + ySource / 2) * lineLength;
|
||||||
|
}
|
||||||
|
else if (pixelFormat == PixelFormat::I420)
|
||||||
|
{
|
||||||
|
uOffset = height * lineLength + ((ySource * lineLength) / 4);
|
||||||
|
vOffset = ((5 * height * lineLength) * 4) + ((ySource * lineLength) / 4);
|
||||||
|
}
|
||||||
|
|
||||||
for (int xDest = 0, xSource = _cropLeft + (_horizontalDecimation >> 1); xDest < outputWidth; xSource += _horizontalDecimation, ++xDest)
|
for (int xDest = 0, xSource = _cropLeft + (_horizontalDecimation >> 1); xDest < outputWidth; xSource += _horizontalDecimation, ++xDest)
|
||||||
{
|
{
|
||||||
ColorRgb & rgb = outputImage(xDest, yDest);
|
switch (_flipMode)
|
||||||
|
{
|
||||||
|
case FlipMode::HORIZONTAL:
|
||||||
|
|
||||||
|
xDestFlip = xDest;
|
||||||
|
yDestFlip = outputHeight-yDest-1;
|
||||||
|
break;
|
||||||
|
case FlipMode::VERTICAL:
|
||||||
|
xDestFlip = outputWidth-xDest-1;
|
||||||
|
yDestFlip = yDest;
|
||||||
|
break;
|
||||||
|
case FlipMode::BOTH:
|
||||||
|
xDestFlip = outputWidth-xDest-1;
|
||||||
|
yDestFlip = outputHeight-yDest-1;
|
||||||
|
break;
|
||||||
|
case FlipMode::NO_CHANGE:
|
||||||
|
xDestFlip = xDest;
|
||||||
|
yDestFlip = yDest;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ColorRgb &rgb = outputImage(xDestFlip, yDestFlip);
|
||||||
switch (pixelFormat)
|
switch (pixelFormat)
|
||||||
{
|
{
|
||||||
case PixelFormat::UYVY:
|
case PixelFormat::UYVY:
|
||||||
@ -124,6 +137,25 @@ void ImageResampler::processImage(const uint8_t * data, int width, int height, i
|
|||||||
rgb.red = data[index+2];
|
rgb.red = data[index+2];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case PixelFormat::NV12:
|
||||||
|
{
|
||||||
|
int index = yOffset + xSource;
|
||||||
|
uint8_t y = data[index];
|
||||||
|
uint8_t u = data[uOffset + ((xSource >> 1) << 1)];
|
||||||
|
uint8_t v = data[uOffset + ((xSource >> 1) << 1) + 1];
|
||||||
|
ColorSys::yuv2rgb(y, u, v, rgb.red, rgb.green, rgb.blue);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PixelFormat::I420:
|
||||||
|
{
|
||||||
|
int index = yOffset + xSource;
|
||||||
|
uint8_t y = data[index];
|
||||||
|
uint8_t u = data[uOffset + (xSource >> 1)];
|
||||||
|
uint8_t v = data[vOffset + (xSource >> 1)];
|
||||||
|
ColorSys::yuv2rgb(y, u, v, rgb.red, rgb.green, rgb.blue);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
#ifdef HAVE_JPEG_DECODER
|
#ifdef HAVE_JPEG_DECODER
|
||||||
case PixelFormat::MJPEG:
|
case PixelFormat::MJPEG:
|
||||||
break;
|
break;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user