Browse Source

libobs: Fix right edge for "video scaler"

FFmpeg YUV to RGB conversions require extra destination padding.

This code only appears to be exercised for DeckLink.
jpark37 5 years ago
parent
commit
d9fa5de572
1 changed files with 43 additions and 2 deletions
  1. 43 2
      libobs/media-io/video-scaler-ffmpeg.c

+ 43 - 2
libobs/media-io/video-scaler-ffmpeg.c

@@ -18,11 +18,15 @@
 #include "../util/bmem.h"
 #include "../util/bmem.h"
 #include "video-scaler.h"
 #include "video-scaler.h"
 
 
+#include <libavutil/imgutils.h>
 #include <libswscale/swscale.h>
 #include <libswscale/swscale.h>
 
 
 struct video_scaler {
 struct video_scaler {
 	struct SwsContext *swscale;
 	struct SwsContext *swscale;
 	int src_height;
 	int src_height;
+	int dst_height;
+	uint8_t *dst_pointers[4];
+	int dst_linesizes[4];
 };
 };
 
 
 static inline enum AVPixelFormat
 static inline enum AVPixelFormat
@@ -138,6 +142,15 @@ int video_scaler_create(video_scaler_t **scaler_out,
 
 
 	scaler = bzalloc(sizeof(struct video_scaler));
 	scaler = bzalloc(sizeof(struct video_scaler));
 	scaler->src_height = src->height;
 	scaler->src_height = src->height;
+	scaler->dst_height = dst->height;
+
+	ret = av_image_alloc(scaler->dst_pointers, scaler->dst_linesizes,
+			     dst->width, dst->height, format_dst, 32);
+	if (ret < 0) {
+		blog(LOG_WARNING,
+		     "video_scaler_create: av_image_alloc failed: %d", ret);
+		goto fail;
+	}
 
 
 	scaler->swscale = sws_getCachedContext(NULL, src->width, src->height,
 	scaler->swscale = sws_getCachedContext(NULL, src->width, src->height,
 					       format_src, dst->width,
 					       format_src, dst->width,
@@ -169,6 +182,10 @@ void video_scaler_destroy(video_scaler_t *scaler)
 {
 {
 	if (scaler) {
 	if (scaler) {
 		sws_freeContext(scaler->swscale);
 		sws_freeContext(scaler->swscale);
+
+		if (scaler->dst_pointers[0])
+			av_freep(scaler->dst_pointers);
+
 		bfree(scaler);
 		bfree(scaler);
 	}
 	}
 }
 }
@@ -182,13 +199,37 @@ bool video_scaler_scale(video_scaler_t *scaler, uint8_t *output[],
 		return false;
 		return false;
 
 
 	int ret = sws_scale(scaler->swscale, input, (const int *)in_linesize, 0,
 	int ret = sws_scale(scaler->swscale, input, (const int *)in_linesize, 0,
-			    scaler->src_height, output,
-			    (const int *)out_linesize);
+			    scaler->src_height, scaler->dst_pointers,
+			    scaler->dst_linesizes);
 	if (ret <= 0) {
 	if (ret <= 0) {
 		blog(LOG_ERROR, "video_scaler_scale: sws_scale failed: %d",
 		blog(LOG_ERROR, "video_scaler_scale: sws_scale failed: %d",
 		     ret);
 		     ret);
 		return false;
 		return false;
 	}
 	}
 
 
+	const size_t height = scaler->dst_height;
+	for (size_t plane = 0; plane < 4; ++plane) {
+		if (!scaler->dst_pointers[plane])
+			continue;
+
+		const size_t scaled_linesize = scaler->dst_linesizes[plane];
+		const size_t plane_linesize = out_linesize[plane];
+		uint8_t *dst = output[plane];
+		const uint8_t *src = scaler->dst_pointers[plane];
+		if (scaled_linesize == plane_linesize) {
+			memcpy(dst, src, scaled_linesize * height);
+		} else {
+			size_t linesize = scaled_linesize;
+			if (linesize > plane_linesize)
+				linesize = plane_linesize;
+
+			for (size_t y = 0; y < height; y++) {
+				memcpy(dst, src, linesize);
+				dst += plane_linesize;
+				src += scaled_linesize;
+			}
+		}
+	}
+
 	return true;
 	return true;
 }
 }