vmware-svga/examples/video-formats/main.c
2009-04-13 07:05:42 +00:00

298 lines
6.9 KiB
C

/*
* video-formats -- Demonstrate all supported video overlay formats.
*
* XXX: There are some known bugs in the currently released VMware
* products, which are exposed by this test:
*
* 1. The very first VideoFlush may not appear. In this test,
* the bug manifests as "No Overlay" for test #1.
*
* 2. Software emulated scaling is very low quality.
*
* 3. If the host is using hardware video overlay rather than
* its software fallback, it assumes that colorkey is always
* enabled. This means our video will only draw in the black
* portions of the background image (inside the "X", and
* the box around the "No overlay" text.)
*
* Copyright (C) 2008-2009 VMware, Inc. Licensed under the MIT
* License, please see the README.txt. All rights reserved.
*/
#include "svga.h"
#include "png.h"
#include "intr.h"
#include "datafile.h"
/*
* This is our video test card, in UYVY format.
*
* It's a 720x576 pixel 4:3 aspect test card designed by Barney
* Wol. (http://www.barney-wol.net/testpatterns)
*/
DECLARE_DATAFILE(testCardFile, wols4x3_yuv_z);
#define TESTCARD_WIDTH 720
#define TESTCARD_HEIGHT 576
/*
* Our background image, in PNG format.
*
* This has 'cutouts' where we're supposed to display the test
* pattern. Each of these are described by the table of overlay
* settings below.
*/
DECLARE_DATAFILE(screenPNGFile, screen_png);
#define OFFSET_YUY2 0x400000
#define OFFSET_UYVY 0x500000
#define OFFSET_YV12 0x600000
static SVGAOverlayUnit overlays[] = {
// #0 - YUY2 Large
{
.enabled = TRUE,
.format = VMWARE_FOURCC_YUY2,
.width = TESTCARD_WIDTH,
.height = TESTCARD_HEIGHT,
.srcWidth = TESTCARD_WIDTH,
.srcHeight = TESTCARD_HEIGHT,
.dstX = 109,
.dstY = 407,
.dstWidth = 320,
.dstHeight = 240,
.pitches[0] = TESTCARD_WIDTH * 2,
.dataOffset = OFFSET_YUY2,
},
// #1 - YV12 Large
{
.enabled = TRUE,
.format = VMWARE_FOURCC_YV12,
.width = TESTCARD_WIDTH,
.height = TESTCARD_HEIGHT,
.srcWidth = TESTCARD_WIDTH,
.srcHeight = TESTCARD_HEIGHT,
.dstX = 564,
.dstY = 58,
.dstWidth = 320,
.dstHeight = 240,
.pitches[0] = TESTCARD_WIDTH,
.pitches[1] = TESTCARD_WIDTH / 2,
.pitches[2] = TESTCARD_WIDTH / 2,
.dataOffset = OFFSET_YV12,
},
// #2 - UYVY Large
{
.enabled = TRUE,
.format = VMWARE_FOURCC_UYVY,
.width = TESTCARD_WIDTH,
.height = TESTCARD_HEIGHT,
.srcWidth = TESTCARD_WIDTH,
.srcHeight = TESTCARD_HEIGHT,
.dstX = 564,
.dstY = 407,
.dstWidth = 320,
.dstHeight = 240,
.pitches[0] = TESTCARD_WIDTH * 2,
.dataOffset = OFFSET_UYVY,
},
// #3 - YUY2 Small
{
.enabled = TRUE,
.format = VMWARE_FOURCC_YUY2,
.width = TESTCARD_WIDTH,
.height = TESTCARD_HEIGHT,
.srcX = 34,
.srcY = 31,
.srcWidth = 76,
.srcHeight = 79,
.dstX = 109,
.dstY = 652,
.dstWidth = 64,
.dstHeight = 64,
.pitches[0] = TESTCARD_WIDTH * 2,
.dataOffset = OFFSET_YUY2,
},
// #4 - YV12 Small
{
.enabled = TRUE,
.format = VMWARE_FOURCC_YV12,
.width = TESTCARD_WIDTH,
.height = TESTCARD_HEIGHT,
.srcX = 34,
.srcY = 31,
.srcWidth = 76,
.srcHeight = 79,
.dstX = 564,
.dstY = 303,
.dstWidth = 64,
.dstHeight = 64,
.pitches[0] = TESTCARD_WIDTH,
.pitches[1] = TESTCARD_WIDTH / 2,
.pitches[2] = TESTCARD_WIDTH / 2,
.dataOffset = OFFSET_YV12,
},
// #5 - UYVY Small
{
.enabled = TRUE,
.format = VMWARE_FOURCC_UYVY,
.width = TESTCARD_WIDTH,
.height = TESTCARD_HEIGHT,
.srcX = 34,
.srcY = 31,
.srcWidth = 76,
.srcHeight = 79,
.dstX = 564,
.dstY = 652,
.dstWidth = 64,
.dstHeight = 64,
.pitches[0] = TESTCARD_WIDTH * 2,
.dataOffset = OFFSET_UYVY,
},
};
/*
* convertUYVYtoYUY2 --
*
* Convert the test card image from UYVY format to YUY2.
* Both of these are packed-pixel formats, they just use
* different byte orders.
*/
static void
convertUYVYtoYUY2(uint8 *src, // IN
uint8 *dest) // OUT
{
uint32 numWords = TESTCARD_WIDTH / 2 * TESTCARD_HEIGHT;
while (numWords--) {
uint8 u = *(src++);
uint8 y1 = *(src++);
uint8 v = *(src++);
uint8 y2 = *(src++);
*(dest++) = y1;
*(dest++) = u;
*(dest++) = y2;
*(dest++) = v;
}
}
/*
* convertUYVYtoYV12 --
*
* Convert the test card image from UYVY format (packed pixel) to
* YV12 (planar). This vertically decimates the chroma planes by
* 1/2.
*/
static void
convertUYVYtoYV12(uint8 *src, // IN
uint8 *dest) // OUT
{
/*
* Y plane, full resolution.
*/
uint8 *s = src;
uint32 numWords = TESTCARD_WIDTH / 2 * TESTCARD_HEIGHT;
while (numWords--) {
s++; // U
*(dest++) = *(s++); // Y1
s++; // V
*(dest++) = *(s++); // Y2
}
/*
* U and V planes, at 1/2 height.
*/
uint32 x, y;
const uint32 pitch = TESTCARD_WIDTH * 2;
uint8 *line1 = src;
uint8 *v = dest;
uint8 *u = v + (TESTCARD_WIDTH * TESTCARD_HEIGHT) / 4;
for (y = TESTCARD_HEIGHT/2; y; y--) {
uint8 *line2 = line1 + pitch;
for (x = TESTCARD_WIDTH/2; x; x--) {
uint8 u1 = *(line1)++; // U
line1++; // Y1
uint8 v1 = *(line1)++; // V
line1++; // Y2
uint8 u2 = *(line2)++; // U
line2++; // Y1
uint8 v2 = *(line2)++; // V
line2++; // Y2
*(u++) = ((int)u1 + (int)u2) >> 1;
*(v++) = ((int)v1 + (int)v2) >> 1;
}
line1 = line2;
}
}
/*
* main --
*
* Set up the virtual hardware, decompress the YUV images, and
* program the overlay units.
*/
int
main(void)
{
PNGChunkIHDR *screenPNG = PNG_Header(screenPNGFile->ptr);
uint32 width = bswap32(screenPNG->width);
uint32 height = bswap32(screenPNG->height);
uint32 streamId;
Intr_Init();
Intr_SetFaultHandlers(SVGA_DefaultFaultHandler);
SVGA_Init();
SVGA_SetMode(width, height, 32);
/*
* Draw the background image
*/
PNG_DecompressBGRX(screenPNG, (uint32*) gSVGA.fbMem, gSVGA.pitch);
SVGA_Update(0, 0, width, height);
/*
* Decompress the YUY2 image, and use it to generate UYVY and YV12 versions.
*/
DataFile_Decompress(testCardFile, gSVGA.fbMem + OFFSET_UYVY, 0x100000);
convertUYVYtoYUY2(gSVGA.fbMem + OFFSET_UYVY, gSVGA.fbMem + OFFSET_YUY2);
convertUYVYtoYV12(gSVGA.fbMem + OFFSET_UYVY, gSVGA.fbMem + OFFSET_YV12);
/*
* Program the overlay units
*/
for (streamId = 0; streamId < arraysize(overlays); streamId++) {
SVGA_VideoSetAllRegs(streamId, &overlays[streamId], SVGA_VIDEO_PITCH_3);
SVGA_VideoFlush(streamId);
}
return 0;
}