mirror of
				https://github.com/hyperion-project/hyperion.ng.git
				synced 2025-03-01 10:33:28 +00: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:
		
							
								
								
									
										5
									
								
								.github/workflows/push-master.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								.github/workflows/push-master.yml
									
									
									
									
										vendored
									
									
								
							@@ -134,6 +134,11 @@ jobs:
 | 
			
		||||
        run: |
 | 
			
		||||
          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
 | 
			
		||||
        shell: cmd
 | 
			
		||||
        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",
 | 
			
		||||
      "type": "cppdbg",
 | 
			
		||||
      "request": "launch",
 | 
			
		||||
      "program": "${workspaceFolder}/build/bin/hyperiond",
 | 
			
		||||
      "program": "${command:cmake.launchTargetDirectory}/hyperiond",
 | 
			
		||||
      "args": ["-d"],
 | 
			
		||||
      "stopAtEntry": false,
 | 
			
		||||
      "cwd": "${workspaceFolder}",
 | 
			
		||||
@@ -27,7 +27,7 @@
 | 
			
		||||
      "name": "(Windows) hyperiond",
 | 
			
		||||
      "type": "cppvsdbg",
 | 
			
		||||
      "request": "launch",
 | 
			
		||||
      "program": "${workspaceFolder}/build/bin/Debug/hyperiond.exe",
 | 
			
		||||
      "program": "${command:cmake.launchTargetDirectory}/hyperiond",
 | 
			
		||||
      "args": ["-d"],
 | 
			
		||||
      "stopAtEntry": false,
 | 
			
		||||
      "cwd": "${workspaceFolder}",
 | 
			
		||||
 
 | 
			
		||||
@@ -46,8 +46,7 @@ private:
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_TURBO_JPEG
 | 
			
		||||
	tjhandle 	_decompress;
 | 
			
		||||
	int _scalingFactorsCount = 0;
 | 
			
		||||
	tjscalingfactor* _scalingFactors = nullptr;
 | 
			
		||||
	tjscalingfactor* _scalingFactors;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	static volatile bool _isActive;
 | 
			
		||||
@@ -57,6 +56,7 @@ private:
 | 
			
		||||
	PixelFormat          _pixelFormat;
 | 
			
		||||
	uint8_t*             _localData;
 | 
			
		||||
	int                  _localDataSize;
 | 
			
		||||
	int                  _scalingFactorsCount;
 | 
			
		||||
	int                  _size;
 | 
			
		||||
	int                  _width;
 | 
			
		||||
	int                  _height;
 | 
			
		||||
@@ -78,16 +78,7 @@ class MFThreadManager : public QObject
 | 
			
		||||
public:
 | 
			
		||||
	MFThreadManager() : _threads(nullptr)
 | 
			
		||||
	{
 | 
			
		||||
		int select = QThread::idealThreadCount();
 | 
			
		||||
 | 
			
		||||
		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);
 | 
			
		||||
		_maxThreads = qBound(1, ((QThread::idealThreadCount() * 3) / 2), 12);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	~MFThreadManager()
 | 
			
		||||
@@ -100,6 +91,7 @@ public:
 | 
			
		||||
					_threads[i]->deleteLater();
 | 
			
		||||
					_threads[i] = nullptr;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
			delete[] _threads;
 | 
			
		||||
			_threads = nullptr;
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -9,12 +9,13 @@ class ImageResampler
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	ImageResampler();
 | 
			
		||||
	~ImageResampler();
 | 
			
		||||
	~ImageResampler() {}
 | 
			
		||||
 | 
			
		||||
	void setHorizontalPixelDecimation(int decimator);
 | 
			
		||||
	void setVerticalPixelDecimation(int decimator);
 | 
			
		||||
	void setHorizontalPixelDecimation(int decimator) { _horizontalDecimation = decimator; }
 | 
			
		||||
	void setVerticalPixelDecimation(int decimator) { _verticalDecimation = decimator; }
 | 
			
		||||
	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;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
@@ -25,5 +26,6 @@ private:
 | 
			
		||||
	int _cropTop;
 | 
			
		||||
	int _cropBottom;
 | 
			
		||||
	VideoMode _videoMode;
 | 
			
		||||
	FlipMode _flipMode;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,8 @@ enum class PixelFormat {
 | 
			
		||||
	BGR24,
 | 
			
		||||
	RGB32,
 | 
			
		||||
	BGR32,
 | 
			
		||||
	NV12,
 | 
			
		||||
	I420,
 | 
			
		||||
#ifdef HAVE_JPEG_DECODER
 | 
			
		||||
	MJPEG,
 | 
			
		||||
#endif
 | 
			
		||||
@@ -47,6 +49,14 @@ inline PixelFormat parsePixelFormat(const QString& pixelFormat)
 | 
			
		||||
	{
 | 
			
		||||
		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
 | 
			
		||||
	else if (format.compare("mjpeg")  == 0)
 | 
			
		||||
	{
 | 
			
		||||
@@ -63,35 +73,97 @@ inline QString pixelFormatToString(const PixelFormat& pixelFormat)
 | 
			
		||||
 | 
			
		||||
	if ( pixelFormat == PixelFormat::YUYV)
 | 
			
		||||
	{
 | 
			
		||||
		return "yuyv";
 | 
			
		||||
		return "YUYV";
 | 
			
		||||
	}
 | 
			
		||||
	else if (pixelFormat == PixelFormat::UYVY)
 | 
			
		||||
	{
 | 
			
		||||
		return "uyvy";
 | 
			
		||||
		return "UYVY";
 | 
			
		||||
	}
 | 
			
		||||
	else if (pixelFormat == PixelFormat::BGR16)
 | 
			
		||||
	{
 | 
			
		||||
		return "bgr16";
 | 
			
		||||
		return "BGR16";
 | 
			
		||||
	}
 | 
			
		||||
	else if (pixelFormat == PixelFormat::BGR24)
 | 
			
		||||
	{
 | 
			
		||||
		return "bgr24";
 | 
			
		||||
		return "BGR24";
 | 
			
		||||
	}
 | 
			
		||||
	else if (pixelFormat == PixelFormat::RGB32)
 | 
			
		||||
	{
 | 
			
		||||
		return "rgb32";
 | 
			
		||||
		return "RGB32";
 | 
			
		||||
	}
 | 
			
		||||
	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
 | 
			
		||||
	else if (pixelFormat == PixelFormat::MJPEG)
 | 
			
		||||
	{
 | 
			
		||||
		return "mjpeg";
 | 
			
		||||
		return "MJPEG";
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	// return the default 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)
 | 
			
		||||
{
 | 
			
		||||
	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_UYVY)) return PixelFormat::UYVY;
 | 
			
		||||
	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;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -40,7 +43,7 @@ MFGrabber::MFGrabber(const QString & device, unsigned width, unsigned height, un
 | 
			
		||||
	setInput(input);
 | 
			
		||||
	setWidthHeight(width, height);
 | 
			
		||||
	setFramerate(fps);
 | 
			
		||||
	// setDeviceVideoStandard(device, videoStandard);
 | 
			
		||||
	// setDeviceVideoStandard(device, videoStandard); // TODO
 | 
			
		||||
 | 
			
		||||
	CoInitializeEx(0, COINIT_MULTITHREADED);
 | 
			
		||||
	_hr = MFStartup(MF_VERSION, MFSTARTUP_NOSOCKET);
 | 
			
		||||
@@ -134,7 +137,7 @@ bool MFGrabber::init()
 | 
			
		||||
					continue;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (strict)
 | 
			
		||||
			if (strict && (val.fps <= 60 || _fps != 15))
 | 
			
		||||
				foundIndex = i;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -394,16 +397,32 @@ bool MFGrabber::init_device(QString deviceName, DevicePropertiesItem props)
 | 
			
		||||
			}
 | 
			
		||||
			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;
 | 
			
		||||
			}
 | 
			
		||||
			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;
 | 
			
		||||
		}
 | 
			
		||||
@@ -499,6 +518,8 @@ void MFGrabber::enumVideoCaptureDevices()
 | 
			
		||||
												di.pf = pixelformat;
 | 
			
		||||
												di.guid = format;
 | 
			
		||||
												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);
 | 
			
		||||
				if (SUCCEEDED(hrStatus))
 | 
			
		||||
				{
 | 
			
		||||
 | 
			
		||||
					BYTE* data = nullptr;
 | 
			
		||||
					DWORD maxLength = 0, currentLength = 0;
 | 
			
		||||
 | 
			
		||||
@@ -89,11 +88,11 @@ public:
 | 
			
		||||
					else
 | 
			
		||||
						error = QString("buffer->Lock failed => %1").arg(hrStatus);
 | 
			
		||||
 | 
			
		||||
					SAFE_RELEASE(buffer);
 | 
			
		||||
				}
 | 
			
		||||
				else
 | 
			
		||||
					error = QString("pSample->ConvertToContiguousBuffer failed => %1").arg(hrStatus);
 | 
			
		||||
 | 
			
		||||
				SAFE_RELEASE(buffer);
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
				error = "pSample is NULL";
 | 
			
		||||
 
 | 
			
		||||
@@ -3,13 +3,15 @@
 | 
			
		||||
 | 
			
		||||
volatile bool MFThread::_isActive = false;
 | 
			
		||||
 | 
			
		||||
MFThread::MFThread():
 | 
			
		||||
		_localData(nullptr),
 | 
			
		||||
		_localDataSize(0),
 | 
			
		||||
		_decompress(nullptr),
 | 
			
		||||
		_isBusy(false),
 | 
			
		||||
		_semaphore(1),
 | 
			
		||||
		_imageResampler()
 | 
			
		||||
MFThread::MFThread()
 | 
			
		||||
	: _localData(nullptr)
 | 
			
		||||
	, _localDataSize(0)
 | 
			
		||||
	, _decompress(nullptr)
 | 
			
		||||
	, _scalingFactorsCount(0)
 | 
			
		||||
	, _scalingFactors(nullptr)
 | 
			
		||||
	, _isBusy(false)
 | 
			
		||||
	, _semaphore(1)
 | 
			
		||||
	, _imageResampler()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -50,6 +52,7 @@ void MFThread::setup(
 | 
			
		||||
	_imageResampler.setCropping(cropLeft, cropRight, cropTop, cropBottom);
 | 
			
		||||
	_imageResampler.setHorizontalPixelDecimation(_pixelDecimation);
 | 
			
		||||
	_imageResampler.setVerticalPixelDecimation(_pixelDecimation);
 | 
			
		||||
	_imageResampler.setFlipMode(FlipMode::HORIZONTAL);
 | 
			
		||||
 | 
			
		||||
	if (size > _localDataSize)
 | 
			
		||||
	{
 | 
			
		||||
@@ -110,6 +113,7 @@ void MFThread::processImageMjpeg()
 | 
			
		||||
	{
 | 
			
		||||
		_decompress = tjInitDecompress();
 | 
			
		||||
		_scalingFactors = tjGetScalingFactors (&_scalingFactorsCount);
 | 
			
		||||
		tjhandle handle=NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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* dest = (unsigned char*)destImage.memptr() + y*destImage.width()*3;
 | 
			
		||||
			memcpy(dest, source, destImage.width()*3);
 | 
			
		||||
			free(source);
 | 
			
		||||
			free(dest);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
    	// emit
 | 
			
		||||
 
 | 
			
		||||
@@ -10,23 +10,10 @@ ImageResampler::ImageResampler()
 | 
			
		||||
	, _cropTop(0)
 | 
			
		||||
	, _cropBottom(0)
 | 
			
		||||
	, _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)
 | 
			
		||||
{
 | 
			
		||||
	_cropLeft   = cropLeft;
 | 
			
		||||
@@ -35,15 +22,12 @@ void ImageResampler::setCropping(int cropLeft, int cropRight, int cropTop, int c
 | 
			
		||||
	_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
 | 
			
		||||
{
 | 
			
		||||
	int cropRight  = _cropRight;
 | 
			
		||||
	int cropBottom = _cropBottom;
 | 
			
		||||
	int xDestFlip = 0, yDestFlip = 0;
 | 
			
		||||
	int uOffset, vOffset;
 | 
			
		||||
 | 
			
		||||
	// handle 3D mode
 | 
			
		||||
	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)
 | 
			
		||||
	{
 | 
			
		||||
		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)
 | 
			
		||||
		{
 | 
			
		||||
			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)
 | 
			
		||||
			{
 | 
			
		||||
				case PixelFormat::UYVY:
 | 
			
		||||
@@ -124,6 +137,25 @@ void ImageResampler::processImage(const uint8_t * data, int width, int height, i
 | 
			
		||||
					rgb.red   = data[index+2];
 | 
			
		||||
				}
 | 
			
		||||
				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
 | 
			
		||||
				case PixelFormat::MJPEG:
 | 
			
		||||
				break;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user