[Scummvm-git-logs] scummvm master -> 237cb4d52a314386402a01c236dc7c95bed025ca

bluegr noreply at scummvm.org
Mon Jun 19 05:43:43 UTC 2023


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
237cb4d52a VIDEO: Add YUV422 and YUV444 to Theora decoder


Commit: 237cb4d52a314386402a01c236dc7c95bed025ca
    https://github.com/scummvm/scummvm/commit/237cb4d52a314386402a01c236dc7c95bed025ca
Author: Walter Agazzi (walter.agazzi at protonmail.com)
Date: 2023-06-19T08:43:40+03:00

Commit Message:
VIDEO: Add YUV422 and YUV444 to Theora decoder

Changed paths:
    graphics/yuv_to_rgb.cpp
    graphics/yuv_to_rgb.h
    video/theora_decoder.cpp
    video/theora_decoder.h


diff --git a/graphics/yuv_to_rgb.cpp b/graphics/yuv_to_rgb.cpp
index ce42a547743..d68217bce1f 100644
--- a/graphics/yuv_to_rgb.cpp
+++ b/graphics/yuv_to_rgb.cpp
@@ -252,6 +252,58 @@ void YUVToRGBManager::convert444(Graphics::Surface *dst, YUVToRGBManager::Lumina
 		convertYUV444ToRGB<uint32>((byte *)dst->getPixels(), dst->pitch, lookup, _colorTab, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch);
 }
 
+template<typename PixelInt>
+void convertYUV422ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup, int16 *colorTab, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) {
+	int halfWidth = yWidth >> 1;
+
+	// Keep the tables in pointers here to avoid a dereference on each pixel
+	const int16 *Cr_r_tab = colorTab;
+	const int16 *Cr_g_tab = Cr_r_tab + 256;
+	const int16 *Cb_g_tab = Cr_g_tab + 256;
+	const int16 *Cb_b_tab = Cb_g_tab + 256;
+	const uint32 *rgbToPix = lookup->getRGBToPix();
+
+	for (int h = 0; h < yHeight; h++) {
+		for (int w = 0; w < halfWidth; w++) {
+			const uint32 *L;
+
+			int16 cr_r  = Cr_r_tab[*vSrc];
+			int16 crb_g = Cr_g_tab[*vSrc] + Cb_g_tab[*uSrc];
+			int16 cb_b  = Cb_b_tab[*uSrc];
+			++uSrc;
+			++vSrc;
+
+			PUT_PIXEL(*ySrc, dstPtr);
+			ySrc++;
+			dstPtr += sizeof(PixelInt);
+			PUT_PIXEL(*ySrc, dstPtr);
+			ySrc++;
+			dstPtr += sizeof(PixelInt);
+		}
+
+		dstPtr += dstPitch - yWidth * sizeof(PixelInt);
+		ySrc += yPitch  - yWidth;
+		uSrc += uvPitch - halfWidth;
+		vSrc += uvPitch - halfWidth;
+	}
+}
+
+void YUVToRGBManager::convert422(Graphics::Surface *dst, YUVToRGBManager::LuminanceScale scale, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) {
+	// Sanity checks
+	assert(dst && dst->getPixels());
+	assert(dst->format.bytesPerPixel == 2 || dst->format.bytesPerPixel == 4);
+	assert(ySrc && uSrc && vSrc);
+	assert((yWidth & 1) == 0);
+
+	const YUVToRGBLookup *lookup = getLookup(dst->format, scale);
+
+	// Use a templated function to avoid an if check on every pixel
+	if (dst->format.bytesPerPixel == 2)
+		convertYUV422ToRGB<uint16>((byte *)dst->getPixels(), dst->pitch, lookup, _colorTab, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch);
+	else
+		convertYUV422ToRGB<uint32>((byte *)dst->getPixels(), dst->pitch, lookup, _colorTab, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch);
+}
+
 template<typename PixelInt>
 void convertYUV420ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup, int16 *colorTab, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) {
 	int halfHeight = yHeight >> 1;
diff --git a/graphics/yuv_to_rgb.h b/graphics/yuv_to_rgb.h
index 75c98ceb061..c0d28c809ad 100644
--- a/graphics/yuv_to_rgb.h
+++ b/graphics/yuv_to_rgb.h
@@ -68,6 +68,21 @@ public:
 	 */
 	void convert444(Graphics::Surface *dst, LuminanceScale scale, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch);
 
+	/**
+	 * Convert a YUV422 image to an RGB surface
+	 *
+	 * @param dst     the destination surface
+	 * @param scale   the scale of the luminance values
+	 * @param ySrc    the source of the y component
+	 * @param uSrc    the source of the u component
+	 * @param vSrc    the source of the v component
+	 * @param yWidth  the width of the y surface (must be divisible by 2)
+	 * @param yHeight the height of the y surface
+	 * @param yPitch  the pitch of the y surface
+	 * @param uvPitch the pitch of the u and v surfaces
+	 */
+	void convert422(Graphics::Surface *dst, LuminanceScale scale, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch);
+
 	/**
 	 * Convert a YUV420 image to an RGB surface
 	 *
diff --git a/video/theora_decoder.cpp b/video/theora_decoder.cpp
index dca4b82a450..d42b483d3b5 100644
--- a/video/theora_decoder.cpp
+++ b/video/theora_decoder.cpp
@@ -257,8 +257,9 @@ Common::Rational TheoraDecoder::getFrameRate() const {
 TheoraDecoder::TheoraVideoTrack::TheoraVideoTrack(th_info &theoraInfo, th_setup_info *theoraSetup) {
 	_theoraDecode = th_decode_alloc(&theoraInfo, theoraSetup);
 
-	if (theoraInfo.pixel_fmt != TH_PF_420)
-		error("Only theora YUV420 is supported");
+	if (theoraInfo.pixel_fmt != TH_PF_420 && theoraInfo.pixel_fmt != TH_PF_422 && theoraInfo.pixel_fmt != TH_PF_444) {
+		error("Found unknown Theora format (must be YUV420, YUV422 or YUV444)");
+	}
 
 	int postProcessingMax;
 	th_decode_ctl(_theoraDecode, TH_DECCTL_GET_PPLEVEL_MAX, &postProcessingMax, sizeof(postProcessingMax));
@@ -272,6 +273,7 @@ TheoraDecoder::TheoraVideoTrack::TheoraVideoTrack(th_info &theoraInfo, th_setup_
 	_surfaceHeight = theoraInfo.frame_height;
 
 	_pixelFormat = g_system->getScreenFormat();
+	_theoraPixelFormat = theoraInfo.pixel_fmt;
 
 	// Default to a 32bpp format, if in 8bpp mode
 	if (_pixelFormat.bytesPerPixel == 1)
@@ -342,11 +344,11 @@ void TheoraDecoder::TheoraVideoTrack::translateYUVtoRGBA(th_ycbcr_buffer &YUVBuf
 	assert((YUVBuffer[kBufferU].width & 1) == 0);
 	assert((YUVBuffer[kBufferV].width & 1) == 0);
 
-	// UV images have to have a quarter of the Y image resolution
-	assert(YUVBuffer[kBufferU].width == YUVBuffer[kBufferY].width >> 1);
-	assert(YUVBuffer[kBufferV].width == YUVBuffer[kBufferY].width >> 1);
-	assert(YUVBuffer[kBufferU].height == YUVBuffer[kBufferY].height >> 1);
-	assert(YUVBuffer[kBufferV].height == YUVBuffer[kBufferY].height >> 1);
+	// UV components must be half or equal the Y component
+	assert((YUVBuffer[kBufferU].width == YUVBuffer[kBufferY].width >> 1) || (YUVBuffer[kBufferU].width == YUVBuffer[kBufferY].width));
+	assert((YUVBuffer[kBufferV].width == YUVBuffer[kBufferY].width >> 1) || (YUVBuffer[kBufferV].width == YUVBuffer[kBufferY].width));
+	assert((YUVBuffer[kBufferU].height == YUVBuffer[kBufferY].height >> 1) || (YUVBuffer[kBufferU].height == YUVBuffer[kBufferY].height));
+	assert((YUVBuffer[kBufferV].height == YUVBuffer[kBufferY].height >> 1) || (YUVBuffer[kBufferV].height == YUVBuffer[kBufferY].height));
 
 	if (!_surface) {
 		_surface = new Graphics::Surface();
@@ -360,7 +362,19 @@ void TheoraDecoder::TheoraVideoTrack::translateYUVtoRGBA(th_ycbcr_buffer &YUVBuf
 		                      _surface->getBasePtr(_x, _y), _surface->format);
 	}
 
-	YUVToRGBMan.convert420(_surface, Graphics::YUVToRGBManager::kScaleITU, YUVBuffer[kBufferY].data, YUVBuffer[kBufferU].data, YUVBuffer[kBufferV].data, YUVBuffer[kBufferY].width, YUVBuffer[kBufferY].height, YUVBuffer[kBufferY].stride, YUVBuffer[kBufferU].stride);
+	switch (_theoraPixelFormat) {
+	case TH_PF_420:
+		YUVToRGBMan.convert420(_surface, Graphics::YUVToRGBManager::kScaleITU, YUVBuffer[kBufferY].data, YUVBuffer[kBufferU].data, YUVBuffer[kBufferV].data, YUVBuffer[kBufferY].width, YUVBuffer[kBufferY].height, YUVBuffer[kBufferY].stride, YUVBuffer[kBufferU].stride);
+		break;
+	case TH_PF_422:
+		YUVToRGBMan.convert422(_surface, Graphics::YUVToRGBManager::kScaleITU, YUVBuffer[kBufferY].data, YUVBuffer[kBufferU].data, YUVBuffer[kBufferV].data, YUVBuffer[kBufferY].width, YUVBuffer[kBufferY].height, YUVBuffer[kBufferY].stride, YUVBuffer[kBufferU].stride);
+		break;
+	case TH_PF_444:
+		YUVToRGBMan.convert444(_surface, Graphics::YUVToRGBManager::kScaleITU, YUVBuffer[kBufferY].data, YUVBuffer[kBufferU].data, YUVBuffer[kBufferV].data, YUVBuffer[kBufferY].width, YUVBuffer[kBufferY].height, YUVBuffer[kBufferY].stride, YUVBuffer[kBufferU].stride);
+		break;
+	default:
+		error("Unsupported Theora pixel format");
+	}
 }
 
 static vorbis_info *info = 0;
diff --git a/video/theora_decoder.h b/video/theora_decoder.h
index 6adf2123cec..a0f0a2e2703 100644
--- a/video/theora_decoder.h
+++ b/video/theora_decoder.h
@@ -112,6 +112,7 @@ private:
 		uint16 _surfaceHeight;
 
 		th_dec_ctx *_theoraDecode;
+		th_pixel_fmt _theoraPixelFormat;
 
 		void translateYUVtoRGBA(th_ycbcr_buffer &YUVBuffer);
 	};




More information about the Scummvm-git-logs mailing list