From e15f643b8fcd897edd56a52aa4429d995b79879a Mon Sep 17 00:00:00 2001
From: gocha <gochaism@gmail.com>
Date: Sat, 5 Feb 2011 00:00:51 +0900
Subject: [PATCH] avi output support interlace
---
win32/win32.cpp | 79 ++++++++++++++++++++++++++++++++++++-------------------
1 files changed, 52 insertions(+), 27 deletions(-)
diff --git a/win32/win32.cpp b/win32/win32.cpp
index 1f1dad1..fc0e919 100644
--- a/win32/win32.cpp
+++ b/win32/win32.cpp
@@ -202,12 +202,8 @@
//#define DEBUGGER
#include <math.h>
-#ifndef max
-#define max(a, b) (((a) > (b)) ? (a) : (b))
-#endif
-#ifndef min
-#define min(a, b) (((a) < (b)) ? (a) : (b))
-#endif
+
+#include <algorithm>
BYTE *ScreenBuf1 = NULL;
BYTE *ScreenBuffer = NULL;
@@ -1129,20 +1125,24 @@ void BuildAVIVideoFrame1X (void)
{
const int snesWidth = IPPU.RenderedScreenWidth;
const int snesHeight = IPPU.RenderedScreenHeight;
- const int width = min(snesWidth, avi_width);
- const int height = min(snesHeight, avi_height);
+ const bool snesInterlaced = (snesHeight > SNES_HEIGHT_EXTENDED);
+ const int snesVerticalScale = snesInterlaced ? 2 : 1;
+ const int width = std::min(snesWidth, avi_width);
+ const int height = std::min(snesHeight / snesVerticalScale, avi_height);
const int pitch = GFX.Pitch;
#ifdef LSB_FIRST
const bool order_is_rgb = (GUI.RedShift < GUI.BlueShift);
#else
const bool order_is_rgb = (GUI.RedShift > GUI.BlueShift);
#endif
- const int src_step = pitch - width * 2;
+ const int src_step = (pitch - width * 2) + (snesInterlaced ? pitch : 0);
const int dst_step = -(avi_pitch + width * 3);
const int image_offset = (avi_height - height) * avi_pitch;
uint16 *s = GFX.Screen;
uint8 *d = &avi_buffer[(avi_height - 1) * avi_pitch];
+ // TODO: vertical blend for interlace
+
for(int y = 0; y < height; y++)
{
for(int x = 0; x < width; x++)
@@ -1150,7 +1150,10 @@ void BuildAVIVideoFrame1X (void)
if(order_is_rgb)
{
// Order is RGB
- uint32 pixel = *s++;
+ uint32 pixel = s[0];
+ if (snesInterlaced)
+ pixel = Interp(pixel,s[pitch]);
+ s++;
*(d + 0) = (pixel >> (11 - 3)) & 0xf8;
*(d + 1) = (pixel >> (6 - 3)) & 0xf8;
*(d + 2) = (pixel & 0x1f) << 3;
@@ -1159,7 +1162,10 @@ void BuildAVIVideoFrame1X (void)
else
{
// Order is BGR
- uint32 pixel = *s++;
+ uint32 pixel = s[0];
+ if (snesInterlaced)
+ pixel = Interp(pixel,s[pitch]);
+ s++;
*(d + 0) = (pixel & 0x1f) << 3;
*(d + 1) = (pixel >> (6 - 3)) & 0xf8;
*(d + 2) = (pixel >> (11 - 3)) & 0xf8;
@@ -1181,21 +1187,23 @@ void BuildAVIVideoFrame2X (void)
{
const int snesWidth = IPPU.RenderedScreenWidth;
const int snesHeight = IPPU.RenderedScreenHeight;
- const int width = min(snesWidth, avi_width / 2);
- const int height = min(snesHeight, avi_height / 2);
+ const bool snesInterlaced = (snesHeight > SNES_HEIGHT_EXTENDED);
+ const int snesVerticalScale = snesInterlaced ? 2 : 1;
+ const int width = std::min(snesWidth, avi_width / 2);
+ const int height = std::min(snesHeight * 2 / snesVerticalScale, avi_height);
const int pitch = GFX.Pitch;
#ifdef LSB_FIRST
const bool order_is_rgb = (GUI.RedShift < GUI.BlueShift);
#else
const bool order_is_rgb = (GUI.RedShift > GUI.BlueShift);
#endif
- const int src_step[2] = { -width * 2, pitch - width * 2 };
+ const int src_step[2] = { -width * 2 + (snesInterlaced ? pitch : 0), -width * 2 + pitch };
const int dst_step = -(avi_pitch + width * 3 * 2);
- const int image_offset = (avi_height - height * 2) * avi_pitch;
+ const int image_offset = (avi_height - height) * avi_pitch;
uint16 *s = GFX.Screen;
uint8 *d = &avi_buffer[(avi_height - 1) * avi_pitch];
- for(int y = 0; y < height * 2; y++)
+ for(int y = 0; y < height; y++)
{
for(int x = 0; x < width; x++)
{
@@ -1233,15 +1241,17 @@ void BuildAVIVideoFrame1XHiRes (void)
{
const int snesWidth = IPPU.RenderedScreenWidth;
const int snesHeight = IPPU.RenderedScreenHeight;
- const int width = min(snesWidth / 2, avi_width);
- const int height = min(snesHeight, avi_height);
+ const bool snesInterlaced = (snesHeight > SNES_HEIGHT_EXTENDED);
+ const int snesVerticalScale = snesInterlaced ? 2 : 1;
+ const int width = std::min(snesWidth / 2, avi_width);
+ const int height = std::min(snesHeight / snesVerticalScale, avi_height);
const int pitch = GFX.Pitch;
#ifdef LSB_FIRST
const bool order_is_rgb = (GUI.RedShift < GUI.BlueShift);
#else
const bool order_is_rgb = (GUI.RedShift > GUI.BlueShift);
#endif
- const int src_step = pitch - width * 2 * 2;
+ const int src_step = (pitch - width * 2 * 2) + (snesInterlaced ? pitch : 0);
const int dst_step = -(avi_pitch + width * 3);
const int image_offset = (avi_height - height) * avi_pitch;
uint16 *s = GFX.Screen;
@@ -1260,6 +1270,11 @@ void BuildAVIVideoFrame1XHiRes (void)
{
// Order is RGB
uint32 pixel = Interp(s[0],s[1]);
+ if (snesInterlaced)
+ {
+ uint32 pixel2 = Interp(s[pitch],s[pitch + 1]);
+ pixel = Interp(pixel,pixel2);
+ }
s += 2;
*(d + 0) = (pixel >> (11 - 3)) & 0xf8;
*(d + 1) = (pixel >> (6 - 3)) & 0xf8;
@@ -1270,6 +1285,11 @@ void BuildAVIVideoFrame1XHiRes (void)
{
// Order is BGR
uint32 pixel = Interp(s[0],s[1]);
+ if (snesInterlaced)
+ {
+ uint32 pixel2 = Interp(s[pitch],s[pitch + 1]);
+ pixel = Interp(pixel,pixel2);
+ }
s += 2;
*(d + 0) = (pixel & 0x1f) << 3;
*(d + 1) = (pixel >> (6 - 3)) & 0xf8;
@@ -1292,21 +1312,23 @@ void BuildAVIVideoFrame2XHiRes (void)
{
const int snesWidth = IPPU.RenderedScreenWidth;
const int snesHeight = IPPU.RenderedScreenHeight;
- const int width = min(snesWidth, avi_width);
- const int height = min(snesHeight, avi_height / 2);
+ const bool snesInterlaced = (snesHeight > SNES_HEIGHT_EXTENDED);
+ const int snesVerticalScale = snesInterlaced ? 2 : 1;
+ const int width = std::min(snesWidth, avi_width);
+ const int height = std::min(snesHeight * 2 / snesVerticalScale, avi_height);
const int pitch = GFX.Pitch;
#ifdef LSB_FIRST
const bool order_is_rgb = (GUI.RedShift < GUI.BlueShift);
#else
const bool order_is_rgb = (GUI.RedShift > GUI.BlueShift);
#endif
- const int src_step[2] = { -width * 2, pitch - width * 2 };
+ const int src_step[2] = { -width * 2 + (snesInterlaced ? pitch : 0), -width * 2 + pitch };
const int dst_step = -(avi_pitch + width * 3);
- const int image_offset = (avi_height - height * 2) * avi_pitch;
+ const int image_offset = (avi_height - height) * avi_pitch;
uint16 *s = GFX.Screen;
uint8 *d = &avi_buffer[(avi_height - 1) * avi_pitch];
- for(int y = 0; y < height * 2; y++)
+ for(int y = 0; y < height; y++)
{
for(int x = 0; x < width; x++)
{
@@ -1371,11 +1393,15 @@ void DoAVIOpen(const TCHAR* filename)
avi_skip_frames = Settings.SkipFrames;
if(GUI.AVIHiRes && avi_width <= SNES_WIDTH)
- avi_width = SNES_WIDTH*2;
+ avi_width = SNES_WIDTH * 2;
else if(!GUI.AVIHiRes && avi_width > SNES_WIDTH)
avi_width = SNES_WIDTH;
- if(GUI.HeightExtend && avi_height < SNES_HEIGHT_EXTENDED)
+ if (avi_height > SNES_HEIGHT_EXTENDED)
+ avi_height /= 2;
+ if(GUI.HeightExtend)
avi_height = SNES_HEIGHT_EXTENDED;
+ else
+ avi_height = std::max(SNES_HEIGHT, avi_height);
if(GUI.AVIHiRes)
avi_height *= 2;
if(avi_height % 2 != 0) // most codecs can't handle odd-height images
@@ -1492,7 +1518,6 @@ void DoAVIVideoFrame(SSurface* source_surface)
// convert to bitdepth 24
const int snesWidth = IPPU.RenderedScreenWidth;
- const int snesHeight = IPPU.RenderedScreenHeight;
if(snesWidth < SNES_WIDTH*2) // normal
{
if(avi_width < snesWidth*2) // 1x
--
1.7.3.1.msysgit.0