/* * UAE - The Un*x Amiga Emulator * * CD32 FMV video genlock * * Copyright 2014 Toni Wilen * */ #include "sysconfig.h" #include "sysdeps.h" #include "options.h" #include "memory.h" #include "cd32_fmv.h" #include "custom.h" #include "xwin.h" static uae_u8 *mpeg_out_buffer; static int mpeg_width, mpeg_height, mpeg_depth; static uae_u32 fmv_border_color; static uae_u16 fmv_border_color_16; int cd32_fmv_active; // According to schematics there is at least 3 (possible more) // "genlock modes" but they seem to be unused, at least ROM // mpeg player software never sets any genlock bits. // this is probably not how it actually works. #define GENLOCK_VAL_32 0x20 #define GENLOCK_VAL_16 0x03 #define MPEG_PIXBYTES_32 4 #define MPEG_PIXBYTES_16 2 #define MAX_MPEG_WIDTH 352 #define MAX_MPEG_HEIGHT 288 void cd32_fmv_new_border_color(uae_u32 bordercolor) { fmv_border_color = bordercolor; fmv_border_color_16 = (((bordercolor >> (16 + 3)) & 31) << 11); fmv_border_color_16 |= (((bordercolor >> ( 8 + 2)) & 63) << 5); fmv_border_color_16 |= (((bordercolor >> ( 0 + 3)) & 31) << 0); } void cd32_fmv_new_image(int w, int h, int d, uae_u8 *s) { if (!mpeg_out_buffer) mpeg_out_buffer = xmalloc(uae_u8, MAX_MPEG_WIDTH * MAX_MPEG_HEIGHT * MPEG_PIXBYTES_32); if (s == NULL || w > MAX_MPEG_WIDTH || h > MAX_MPEG_HEIGHT) { memset(mpeg_out_buffer, 0, MAX_MPEG_WIDTH * MAX_MPEG_HEIGHT * MPEG_PIXBYTES_32); mpeg_width = MAX_MPEG_WIDTH; mpeg_height = MAX_MPEG_HEIGHT; return; } memcpy(mpeg_out_buffer, s, w * h * d); mpeg_width = w; mpeg_height = h; mpeg_depth = d; } void cd32_fmv_state(int state) { cd32_fmv_active = state; } // slow software method but who cares. static void genlock_32(struct vidbuffer *vbin, struct vidbuffer *vbout, int w, int h, int d, int hoffset, int voffset, int mult) { for (int hh = 0, sh = -voffset; hh < h; sh++, hh += mult) { for (int h2 = 0; h2 < mult; h2++) { uae_u8 *d8 = vbout->bufmem + vbout->rowbytes * (hh + h2 + voffset); uae_u32 *d32 = (uae_u32*)d8; uae_u8 *s8 = vbin->bufmem + vbin->rowbytes * (hh + h2 + voffset) ; uae_u32 *srcp = NULL; if (sh >= 0 && sh < mpeg_height) srcp = (uae_u32*)(mpeg_out_buffer + sh * mpeg_width * MPEG_PIXBYTES_32); for (int ww = 0, sw = -hoffset; ww < w; sw++, ww += mult) { uae_u32 sv = fmv_border_color; if (sw >= 0 && sw < mpeg_width && srcp) sv = srcp[sw]; for (int w2 = 0; w2 < mult; w2++) { uae_u32 v; if (s8[0] >= GENLOCK_VAL_32) { v = *((uae_u32*)s8); } else { v = sv; } *d32++ = v; s8 += d; } } } } } static void genlock_16(struct vidbuffer *vbin, struct vidbuffer *vbout, int w, int h, int d, int hoffset, int voffset, int mult) { for (int hh = 0, sh = -voffset; hh < h; sh++, hh += mult) { for (int h2 = 0; h2 < mult; h2++) { uae_u8 *d8 = vbout->bufmem + vbout->rowbytes * (hh + h2 + voffset); uae_u16 *d16 = (uae_u16*)d8; uae_u8 *s8 = vbin->bufmem + vbin->rowbytes * (hh + h2 + voffset) ; uae_u16 *srcp = NULL; if (sh >= 0 && sh < mpeg_height) srcp = (uae_u16*)(mpeg_out_buffer + sh * mpeg_width * MPEG_PIXBYTES_16); for (int ww = 0, sw = -hoffset; ww < w; sw++, ww += mult) { uae_u16 sv = fmv_border_color_16; if (sw >= 0 && sw < mpeg_width && srcp) sv = srcp[sw]; for (int w2 = 0; w2 < mult; w2++) { uae_u32 v; if ((((uae_u16*)s8)[0] >> 11) >= GENLOCK_VAL_16) { v = *((uae_u16*)s8); } else { v = sv; } *d16++ = v; s8 += d; } } } } } static void genlock_16_nomult(struct vidbuffer *vbin, struct vidbuffer *vbout, int w, int h, int d, int hoffset, int voffset) { for (int hh = 0, sh = -voffset; hh < h; sh++, hh++) { uae_u8 *d8 = vbout->bufmem + vbout->rowbytes * (hh + voffset); uae_u16 *d16 = (uae_u16*)d8; uae_u8 *s8 = vbin->bufmem + vbin->rowbytes * (hh + voffset) ; uae_u16 *srcp = NULL; if (sh >= 0 && sh < mpeg_height) srcp = (uae_u16*)(mpeg_out_buffer + sh * mpeg_width * MPEG_PIXBYTES_16); for (int ww = 0, sw = -hoffset; ww < w; sw++, ww++) { uae_u16 sv = fmv_border_color_16; if (sw >= 0 && sw < mpeg_width && srcp) sv = srcp[sw]; uae_u32 v; if ((((uae_u16*)s8)[0] >> 11) >= GENLOCK_VAL_16) { v = *((uae_u16*)s8); } else { v = sv; } *d16++ = v; s8 += d; } } } void cd32_fmv_genlock(struct vidbuffer *vbin, struct vidbuffer *vbout) { int hoffset, voffset, mult; int w = vbin->outwidth; int h = vbin->outheight; int d = vbin->pixbytes; if (!mpeg_out_buffer) return; mult = 1; for (;;) { if (mult < 4 && mpeg_width * (mult << 1) <= w + 8 && mpeg_height * (mult << 1) <= h + 8) { mult <<= 1; } else { break; } } hoffset = (w / mult - mpeg_width) / 2; voffset = (h / mult - mpeg_height) / 2; if (hoffset < 0) hoffset = 0; if (voffset < 0) voffset = 0; if (mpeg_depth == 2) { if(mult == 1) genlock_16_nomult(vbin, vbout, w, h, d, hoffset, voffset); else genlock_16(vbin, vbout, w, h, d, hoffset, voffset, mult); } else genlock_32(vbin, vbout, w, h, d, hoffset, voffset, mult); }