Browse Source

Merge pull request #26051 from 20kdc/videofix

webm/theora/yuv2rgb/libsimplewebm: Fix colour issues I could find.
Rémi Verschelde 6 years ago
parent
commit
12cc760538

+ 3 - 3
modules/theora/video_stream_theora.cpp

@@ -94,15 +94,15 @@ void VideoStreamPlaybackTheora::video_write(void) {
 
 		if (px_fmt == TH_PF_444) {
 
-			yuv444_2_rgb8888((uint8_t *)dst, (uint8_t *)yuv[0].data, (uint8_t *)yuv[1].data, (uint8_t *)yuv[2].data, size.x, size.y, yuv[0].stride, yuv[1].stride, size.x << 2, 0);
+			yuv444_2_rgb8888((uint8_t *)dst, (uint8_t *)yuv[0].data, (uint8_t *)yuv[1].data, (uint8_t *)yuv[2].data, size.x, size.y, yuv[0].stride, yuv[1].stride, size.x << 2);
 
 		} else if (px_fmt == TH_PF_422) {
 
-			yuv422_2_rgb8888((uint8_t *)dst, (uint8_t *)yuv[0].data, (uint8_t *)yuv[1].data, (uint8_t *)yuv[2].data, size.x, size.y, yuv[0].stride, yuv[1].stride, size.x << 2, 0);
+			yuv422_2_rgb8888((uint8_t *)dst, (uint8_t *)yuv[0].data, (uint8_t *)yuv[1].data, (uint8_t *)yuv[2].data, size.x, size.y, yuv[0].stride, yuv[1].stride, size.x << 2);
 
 		} else if (px_fmt == TH_PF_420) {
 
-			yuv420_2_rgb8888((uint8_t *)dst, (uint8_t *)yuv[0].data, (uint8_t *)yuv[2].data, (uint8_t *)yuv[1].data, size.x, size.y, yuv[0].stride, yuv[1].stride, size.x << 2, 0);
+			yuv420_2_rgb8888((uint8_t *)dst, (uint8_t *)yuv[0].data, (uint8_t *)yuv[1].data, (uint8_t *)yuv[2].data, size.x, size.y, yuv[0].stride, yuv[1].stride, size.x << 2);
 		};
 
 		format = Image::FORMAT_RGBA8;

+ 23 - 4
modules/webm/video_stream_webm.cpp

@@ -32,6 +32,7 @@
 
 #include "OpusVorbisDecoder.hpp"
 #include "VPXDecoder.hpp"
+#include <vpx/vpx_image.h>
 
 #include "mkvparser/mkvparser.h"
 
@@ -314,19 +315,37 @@ void VideoStreamPlaybackWebm::update(float p_delta) {
 						PoolVector<uint8_t>::Write w = frame_data.write();
 						bool converted = false;
 
-						if (image.chromaShiftW == 1 && image.chromaShiftH == 1) {
+						if (image.chromaShiftW == 0 && image.chromaShiftH == 0 && image.cs == VPX_CS_SRGB) {
+
+							uint8_t *wp = w.ptr();
+							unsigned char *rRow = image.planes[2];
+							unsigned char *gRow = image.planes[0];
+							unsigned char *bRow = image.planes[1];
+							for (size_t i = 0; i < image.h; i++) {
+								for (size_t j = 0; j < image.w; j++) {
+									*wp++ = rRow[j];
+									*wp++ = gRow[j];
+									*wp++ = bRow[j];
+									*wp++ = 255;
+								}
+								rRow += image.linesize[2];
+								gRow += image.linesize[0];
+								bRow += image.linesize[1];
+							}
+							converted = true;
+						} else if (image.chromaShiftW == 1 && image.chromaShiftH == 1) {
 
-							yuv420_2_rgb8888(w.ptr(), image.planes[0], image.planes[2], image.planes[1], image.w, image.h, image.linesize[0], image.linesize[1], image.w << 2, 0);
+							yuv420_2_rgb8888(w.ptr(), image.planes[0], image.planes[1], image.planes[2], image.w, image.h, image.linesize[0], image.linesize[1], image.w << 2);
 							// 								libyuv::I420ToARGB(image.planes[0], image.linesize[0], image.planes[2], image.linesize[2], image.planes[1], image.linesize[1], w.ptr(), image.w << 2, image.w, image.h);
 							converted = true;
 						} else if (image.chromaShiftW == 1 && image.chromaShiftH == 0) {
 
-							yuv422_2_rgb8888(w.ptr(), image.planes[0], image.planes[2], image.planes[1], image.w, image.h, image.linesize[0], image.linesize[1], image.w << 2, 0);
+							yuv422_2_rgb8888(w.ptr(), image.planes[0], image.planes[1], image.planes[2], image.w, image.h, image.linesize[0], image.linesize[1], image.w << 2);
 							// 								libyuv::I422ToARGB(image.planes[0], image.linesize[0], image.planes[2], image.linesize[2], image.planes[1], image.linesize[1], w.ptr(), image.w << 2, image.w, image.h);
 							converted = true;
 						} else if (image.chromaShiftW == 0 && image.chromaShiftH == 0) {
 
-							yuv444_2_rgb8888(w.ptr(), image.planes[0], image.planes[2], image.planes[1], image.w, image.h, image.linesize[0], image.linesize[1], image.w << 2, 0);
+							yuv444_2_rgb8888(w.ptr(), image.planes[0], image.planes[1], image.planes[2], image.w, image.h, image.linesize[0], image.linesize[1], image.w << 2);
 							// 								libyuv::I444ToARGB(image.planes[0], image.linesize[0], image.planes[2], image.linesize[2], image.planes[1], image.linesize[1], w.ptr(), image.w << 2, image.w, image.h);
 							converted = true;
 						} else if (image.chromaShiftW == 2 && image.chromaShiftH == 0) {

+ 7 - 4
thirdparty/README.md

@@ -185,18 +185,21 @@ Files extracted from upstream source:
 ## libsimplewebm
 
 - Upstream: https://github.com/zaps166/libsimplewebm
-- Version: git (05cfdc2, 2016)
-- License: MIT, BSD-3-Clause
+- Version: git (fe57fd3, 2019)
+- License: MIT (main), BSD-3-Clause (libwebm)
+
+This contains libwebm, but the version in use is updated from the one used by libsimplewebm,
+and may have *unmarked* alterations from that.
 
 Files extracted from upstream source:
 
-TODO.
+- all the .cpp, .hpp files in the main folder except `example.cpp`
+- LICENSE
 
 Important: Some files have Godot-made changes.
 They are marked with `// -- GODOT start --` and `// -- GODOT end --`
 comments.
 
-
 ## libtheora
 
 - Upstream: https://www.theora.org

+ 2 - 0
thirdparty/libsimplewebm/OpusVorbisDecoder.cpp

@@ -122,6 +122,7 @@ bool OpusVorbisDecoder::getPCMS16(WebMFrame &frame, short *buffer, int &numOutSa
 	return false;
 }
 
+// -- GODOT begin --
 bool OpusVorbisDecoder::getPCMF(WebMFrame &frame, float *buffer, int &numOutSamples) {
 	if (m_vorbis) {
 		m_vorbis->op.packet = frame.buffer;
@@ -158,6 +159,7 @@ bool OpusVorbisDecoder::getPCMF(WebMFrame &frame, float *buffer, int &numOutSamp
 	}
 	return false;
 }
+// -- GODOT end --
 
 bool OpusVorbisDecoder::openVorbis(const WebMDemuxer &demuxer)
 {

+ 3 - 1
thirdparty/libsimplewebm/OpusVorbisDecoder.hpp

@@ -44,8 +44,10 @@ public:
 	{
 		return m_numSamples;
 	}
-	bool getPCMF(WebMFrame &frame, float *buffer, int &numOutSamples);
 	bool getPCMS16(WebMFrame &frame, short *buffer, int &numOutSamples);
+// -- GODOT begin --
+	bool getPCMF(WebMFrame &frame, float *buffer, int &numOutSamples);
+// -- GODOT end --
 
 private:
 	bool openVorbis(const WebMDemuxer &demuxer);

+ 13 - 1
thirdparty/libsimplewebm/VPXDecoder.cpp

@@ -33,7 +33,8 @@
 VPXDecoder::VPXDecoder(const WebMDemuxer &demuxer, unsigned threads) :
 	m_ctx(NULL),
 	m_iter(NULL),
-	m_delay(0)
+	m_delay(0),
+	m_last_space(VPX_CS_UNKNOWN)
 {
 	if (threads > 8)
 		threads = 8;
@@ -86,6 +87,11 @@ VPXDecoder::IMAGE_ERROR VPXDecoder::getImage(Image &image)
 	IMAGE_ERROR err = NO_FRAME;
 	if (vpx_image_t *img = vpx_codec_get_frame(m_ctx, &m_iter))
 	{
+		// It seems to be a common problem that UNKNOWN comes up a lot, yet FFMPEG is somehow getting accurate colour-space information.
+		// After checking FFMPEG code, *they're* getting colour-space information, so I'm assuming something like this is going on.
+		// It appears to work, at least.
+		if (img->cs != VPX_CS_UNKNOWN)
+			m_last_space = img->cs;
 		if ((img->fmt & VPX_IMG_FMT_PLANAR) && !(img->fmt & (VPX_IMG_FMT_HAS_ALPHA | VPX_IMG_FMT_HIGHBITDEPTH)))
 		{
 			if (img->stride[0] && img->stride[1] && img->stride[2])
@@ -95,6 +101,7 @@ VPXDecoder::IMAGE_ERROR VPXDecoder::getImage(Image &image)
 
 				image.w = img->d_w;
 				image.h = img->d_h;
+				image.cs = m_last_space;
 				image.chromaShiftW = img->x_chroma_shift;
 				image.chromaShiftH = img->y_chroma_shift;
 
@@ -119,7 +126,9 @@ VPXDecoder::IMAGE_ERROR VPXDecoder::getImage(Image &image)
 
 /**/
 
+// -- GODOT begin --
 #if 0
+// -- GODOT end --
 
 static inline int ceilRshift(int val, int shift)
 {
@@ -139,4 +148,7 @@ int VPXDecoder::Image::getHeight(int plane) const
 	return ceilRshift(h, chromaShiftH);
 }
 
+// -- GODOT begin --
 #endif
+// -- GODOT end --
+

+ 6 - 0
thirdparty/libsimplewebm/VPXDecoder.hpp

@@ -37,12 +37,17 @@ public:
 	class Image
 	{
 	public:
+// -- GODOT begin --
 #if 0
+// -- GODOT end --
 		int getWidth(int plane) const;
 		int getHeight(int plane) const;
+// -- GODOT begin --
 #endif
+// -- GODOT end --
 
 		int w, h;
+		int cs;
 		int chromaShiftW, chromaShiftH;
 		unsigned char *planes[3];
 		int linesize[3];
@@ -75,6 +80,7 @@ private:
 	vpx_codec_ctx *m_ctx;
 	const void *m_iter;
 	int m_delay;
+	int m_last_space;
 };
 
 #endif // VPXDECODER_HPP

+ 39 - 82
thirdparty/misc/yuv2rgb.h

@@ -24,6 +24,14 @@ does not infringe any patents that apply in your area before you
 ship it.
 */
 
+/*
+ * Please note that this version has been modified for various reasons:
+ * 1. Using the Godot core typedefs
+ * 2. At some point or another the code relied on the byte order of a uint32_t, this has been fixed
+ * 3. Output has been reordered to struct { uint8_t r, g, b, a; } precisely in accordance with the function names
+ * 4. Removing unused 'dither' parameter
+ */
+
 #ifndef YUV2RGB_H
 #define YUV2RGB_H
 
@@ -803,6 +811,8 @@ static const uint32_t tables[256*3] = {
 	0xE6365800U
 };
 
+/* -- Common -- */
+
 #define FLAGS 0x40080100
 #define READUV(U,V) (tables[256 + (U)] + tables[512 + (V)])
 #define READY(Y)    tables[Y]
@@ -820,12 +830,14 @@ do {                             \
 
 #define STORE(Y,DSTPTR)         \
 do {                            \
-    *(DSTPTR)++ = (Y);          \
-    *(DSTPTR)++ = (Y)>>22;      \
     *(DSTPTR)++ = (Y)>>11;      \
-    *(DSTPTR)++ = 255;            \
+    *(DSTPTR)++ = (Y)>>22;       \
+    *(DSTPTR)++ = (Y);          \
+	*(DSTPTR)++ = 255;           \
 } while (0 == 1)
 
+/* -- End Common -- */
+
 static void yuv422_2_rgb8888(uint8_t  *dst_ptr,
 		const uint8_t  *y_ptr,
 		const uint8_t  *u_ptr,
@@ -834,8 +846,7 @@ static void yuv422_2_rgb8888(uint8_t  *dst_ptr,
 		      int32_t   height,
 		      int32_t   y_span,
 		      int32_t   uv_span,
-		      int32_t   dst_span,
-		      int32_t   dither)
+		      int32_t   dst_span)
 {
     height -= 1;
     while (height > 0)
@@ -909,35 +920,7 @@ static void yuv422_2_rgb8888(uint8_t  *dst_ptr,
     }
 }
 
-
-#undef FLAGS
-#undef READUV
-#undef READY
-#undef FIXUP
-#undef STORE
-
-
-#define FLAGS 0x40080100
-#define READUV(U,V) (tables[256 + (U)] + tables[512 + (V)])
-#define READY(Y)    tables[Y]
-#define FIXUP(Y)                 \
-do {                             \
-    int tmp = (Y) & FLAGS;       \
-    if (tmp != 0)                \
-    {                            \
-	tmp  -= tmp>>8;          \
-	(Y)  |= tmp;             \
-	tmp   = FLAGS & ~(Y>>1); \
-	(Y)  += tmp>>8;          \
-    }                            \
-} while (0 == 1)
-
-#define STORE(Y,DSTPTR)     \
-do {                        \
-    (DSTPTR) = 0xFF000000 | (Y & 0xFF) | (0xFF00 & (Y>>14)) | (0xFF0000 & (Y<<5));\
-} while (0 == 1)
-
-static void yuv420_2_rgb8888(uint8_t  *dst_ptr_,
+static void yuv420_2_rgb8888(uint8_t  *dst_ptr,
 		const uint8_t  *y_ptr,
 		const uint8_t  *u_ptr,
 		const uint8_t  *v_ptr,
@@ -945,12 +928,9 @@ static void yuv420_2_rgb8888(uint8_t  *dst_ptr_,
 		      int32_t   height,
 		      int32_t   y_span,
 		      int32_t   uv_span,
-		      int32_t   dst_span,
-		      int32_t   dither)
+		      int32_t   dst_span)
 {
-    uint32_t *dst_ptr = (uint32_t *)(void *)dst_ptr_;
-    dst_span >>= 2;
-
+    /* The 'dst_ptr as uint32_t' thing is not endianness-aware, so that's been removed. */
     height -= 1;
     while (height > 0)
     {
@@ -960,36 +940,38 @@ static void yuv420_2_rgb8888(uint8_t  *dst_ptr_,
 	{
 	    /* Do 2 column pairs */
 	    uint32_t uv, y0, y1;
+        uint8_t * dst_ptr_1span = dst_ptr + dst_span;
 
 	    uv  = READUV(*u_ptr++,*v_ptr++);
 	    y1  = uv + READY(y_ptr[y_span]);
 	    y0  = uv + READY(*y_ptr++);
 	    FIXUP(y1);
 	    FIXUP(y0);
-	    STORE(y1, dst_ptr[dst_span]);
-	    STORE(y0, *dst_ptr++);
+	    STORE(y1, dst_ptr_1span);
+	    STORE(y0, dst_ptr);
 	    y1  = uv + READY(y_ptr[y_span]);
 	    y0  = uv + READY(*y_ptr++);
 	    FIXUP(y1);
 	    FIXUP(y0);
-	    STORE(y1, dst_ptr[dst_span]);
-	    STORE(y0, *dst_ptr++);
+	    STORE(y1, dst_ptr_1span);
+	    STORE(y0, dst_ptr);
 	    height += (2<<16);
 	}
 	if ((height>>16) == 0)
 	{
 	    /* Trailing column pair */
 	    uint32_t uv, y0, y1;
+        uint8_t * dst_ptr_1span = dst_ptr + dst_span;
 
 	    uv = READUV(*u_ptr,*v_ptr);
 	    y1 = uv + READY(y_ptr[y_span]);
 	    y0 = uv + READY(*y_ptr++);
 	    FIXUP(y1);
 	    FIXUP(y0);
-	    STORE(y0, dst_ptr[dst_span]);
-	    STORE(y1, *dst_ptr++);
+	    STORE(y0, dst_ptr_1span);
+	    STORE(y1, dst_ptr);
 	}
-	dst_ptr += dst_span*2-width;
+	dst_ptr += (dst_span * 2) - (width * 4);
 	y_ptr   += y_span*2-width;
 	u_ptr   += uv_span-(width>>1);
 	v_ptr   += uv_span-(width>>1);
@@ -1011,8 +993,8 @@ static void yuv420_2_rgb8888(uint8_t  *dst_ptr_,
 	    y0  = uv + READY(*y_ptr++);
 	    FIXUP(y1);
 	    FIXUP(y0);
-	    STORE(y1, *dst_ptr++);
-	    STORE(y0, *dst_ptr++);
+	    STORE(y1, dst_ptr);
+	    STORE(y0, dst_ptr);
 	    height += (2<<16);
 	}
 	if ((height>>16) == 0)
@@ -1023,42 +1005,11 @@ static void yuv420_2_rgb8888(uint8_t  *dst_ptr_,
 	    uv = READUV(*u_ptr++,*v_ptr++);
 	    y0 = uv + READY(*y_ptr++);
 	    FIXUP(y0);
-	    STORE(y0, *dst_ptr++);
+	    STORE(y0, dst_ptr);
 	}
     }
 }
 
-
-
-#undef FLAGS
-#undef READUV
-#undef READY
-#undef FIXUP
-#undef STORE
-
-#define FLAGS 0x40080100
-#define READUV(U,V) (tables[256 + (U)] + tables[512 + (V)])
-#define READY(Y)    tables[Y]
-#define FIXUP(Y)                 \
-do {                             \
-    int tmp = (Y) & FLAGS;       \
-    if (tmp != 0)                \
-    {                            \
-	tmp  -= tmp>>8;          \
-	(Y)  |= tmp;             \
-	tmp   = FLAGS & ~(Y>>1); \
-	(Y)  += tmp>>8;          \
-    }                            \
-} while (0 == 1)
-
-#define STORE(Y,DSTPTR)         \
-do {                            \
-    *(DSTPTR)++ = (Y);          \
-    *(DSTPTR)++ = (Y)>>22;      \
-    *(DSTPTR)++ = (Y)>>11;      \
-	*(DSTPTR)++ = 255;           \
-} while (0 == 1)
-
 static void yuv444_2_rgb8888(uint8_t  *dst_ptr,
 		const uint8_t  *y_ptr,
 		const uint8_t  *u_ptr,
@@ -1067,8 +1018,7 @@ static void yuv444_2_rgb8888(uint8_t  *dst_ptr,
 		      int32_t   height,
 		      int32_t   y_span,
 		      int32_t   uv_span,
-		      int32_t   dst_span,
-		      int32_t   dither)
+		      int32_t   dst_span)
 {
     height -= 1;
     while (height > 0)
@@ -1143,4 +1093,11 @@ static void yuv444_2_rgb8888(uint8_t  *dst_ptr,
 	height -= 1;
     }
 }
+
+#undef FLAGS
+#undef READUV
+#undef READY
+#undef FIXUP
+#undef STORE
+
 #endif // YUV2RGB_H