diff --git a/cfg-common.h b/cfg-common.h index 0a65621673..08567933d1 100644 --- a/cfg-common.h +++ b/cfg-common.h @@ -65,8 +65,8 @@ {"stereo", &fakemono, CONF_TYPE_INT, CONF_RANGE, 0, 2}, #endif - {"afm", &audio_family, CONF_TYPE_INT, CONF_RANGE, 0, 13}, // keep ranges in sync - {"vfm", &video_family, CONF_TYPE_INT, CONF_RANGE, 0, 10}, // with codec-cfg.c + {"afm", &audio_family, CONF_TYPE_INT, CONF_MIN, 0, 13}, // keep ranges in sync + {"vfm", &video_family, CONF_TYPE_INT, CONF_MIN, 0, 10}, // with codec-cfg.c {"ac", &audio_codec, CONF_TYPE_STRING, 0, 0, 0}, {"vc", &video_codec, CONF_TYPE_STRING, 0, 0, 0}, diff --git a/codec-cfg.c b/codec-cfg.c index 32195306f5..ee5e0b8bf2 100644 --- a/codec-cfg.c +++ b/codec-cfg.c @@ -223,6 +223,7 @@ static short get_driver(char *s,int audioflag) "raw", "rle", "xanim", + "msvidc", NULL }; char **drv=audioflag?audiodrv:videodrv; diff --git a/codec-cfg.h b/codec-cfg.h index 01e77953b6..319ff31207 100644 --- a/codec-cfg.h +++ b/codec-cfg.h @@ -42,6 +42,7 @@ #define VFM_RAW 8 #define VFM_RLE 9 #define VFM_XANIM 10 +#define VFM_MSVIDC 11 #ifndef GUID_TYPE #define GUID_TYPE diff --git a/dec_video.c b/dec_video.c index 16d313b3e4..caef76dd90 100644 --- a/dec_video.c +++ b/dec_video.c @@ -86,6 +86,23 @@ int divx_quality=0; void AVI_Decode_RLE8(char *image,char *delta,int tdsize, unsigned int *map,int imagex,int imagey,unsigned char x11_bytes_pixel); +void AVI_Decode_Video1_16( + char *encoded, + int encoded_size, + char *decoded, + int width, + int height, + int bytes_per_pixel); + +void AVI_Decode_Video1_8( + char *encoded, + int encoded_size, + char *decoded, + int width, + int height, + unsigned char *palette_map, + int bytes_per_pixel); + //**************************************************************************// // The OpenDivX stuff: //**************************************************************************// @@ -251,7 +268,7 @@ sh_video->our_out_buffer=NULL; switch(sh_video->codec->driver){ case VFM_XANIM: { #ifdef USE_XANIM - int ret=xacodec_init_video(sh_video,out_fmt); + int ret=xacodec_init_video(sh_video,out_fmt); if(!ret) return 0; #else // mp_msg(MSGT_DECVIDEO, MSGL_ERR, MSGTR_NoXAnimSupport); @@ -450,6 +467,12 @@ switch(sh_video->codec->driver){ } } break; + case VFM_MSVIDC: { + int bpp=((out_fmt&255)+7)/8; // RGB only + sh_video->our_out_buffer = + (char*)memalign(64, sh_video->disp_w*sh_video->disp_h*bpp); // FIXME!!! + } + break; } } sh_video->inited=1; @@ -681,6 +704,19 @@ if(verbose>1){ sh_video->disp_w,sh_video->disp_h,((out_fmt&255)+7)/8); blit_frame=3; break; + case VFM_MSVIDC: + if (sh_video->bih->biBitCount == 16) + AVI_Decode_Video1_16( + start, in_size, sh_video->our_out_buffer, + sh_video->disp_w, sh_video->disp_h, + ((out_fmt&255)+7)/8); + else + AVI_Decode_Video1_8( + start, in_size, sh_video->our_out_buffer, + sh_video->disp_w, sh_video->disp_h, + (char *)sh_video->bih+40, ((out_fmt&255)+7)/8); + blit_frame = 3; + break; } // switch //------------------------ frame decoded. -------------------- @@ -727,3 +763,4 @@ case 2: return blit_frame; } + diff --git a/msvidc.c b/msvidc.c new file mode 100644 index 0000000000..d02e9d5932 --- /dev/null +++ b/msvidc.c @@ -0,0 +1,351 @@ + +#define LE_16(x) *(unsigned short *)(x) + +#define DECODE_BGR555_TO_BGR888(x) \ + x.c1_b = (x.c1 >> 7) & 0xF8; \ + x.c1_g = (x.c1 >> 2) & 0xF8; \ + x.c1_r = (x.c1 << 3) & 0xF8; \ + x.c2_b = (x.c2 >> 7) & 0xF8; \ + x.c2_g = (x.c2 >> 2) & 0xF8; \ + x.c2_r = (x.c2 << 3) & 0xF8; + +#define DECODE_PALETTE_TO_BGR888(x) \ + x.c1_b = palette_map[x.c1 * 4 + 2]; \ + x.c1_g = palette_map[x.c1 * 4 + 1]; \ + x.c1_r = palette_map[x.c1 * 4 + 0]; \ + x.c2_b = palette_map[x.c2 * 4 + 2]; \ + x.c2_g = palette_map[x.c2 * 4 + 1]; \ + x.c2_r = palette_map[x.c2 * 4 + 0]; + +struct +{ + unsigned short c1, c2; + unsigned char c1_r, c1_g, c1_b; + unsigned char c2_r, c2_g, c2_b; +} quad[2][2]; + +void AVI_Decode_Video1_16( + char *encoded, + int encoded_size, + char *decoded, + int width, + int height, + int bytes_per_pixel) +{ + int block_ptr, pixel_ptr; + int pixel_x, pixel_y; // pixel width and height iterators + int block_x, block_y; // block width and height iterators + int blocks_wide, blocks_high; // width and height in 4x4 blocks + int block_inc; + int row_dec; + + // decoding parameters + int stream_ptr; + unsigned char byte_a, byte_b; + unsigned short flags; + int skip_blocks; + + stream_ptr = 0; + skip_blocks = 0; + blocks_wide = width / 4; + blocks_high = height / 4; + block_inc = 4 * bytes_per_pixel; + row_dec = (width + 4) * bytes_per_pixel; + + for (block_y = blocks_high; block_y > 0; block_y--) + { + block_ptr = ((block_y * 4) - 1) * (width * bytes_per_pixel); + for (block_x = blocks_wide; block_x > 0; block_x--) + { + // check if this block should be skipped + if (skip_blocks) + { + block_ptr += block_inc; + skip_blocks--; + continue; + } + + pixel_ptr = block_ptr; + + // get the next two bytes in the encoded data stream + byte_a = encoded[stream_ptr++]; + byte_b = encoded[stream_ptr++]; + + // check if the decode is finished + if ((byte_a == 0) && (byte_b == 0)) + return; + + // check if this is a skip code + else if ((byte_b & 0xFC) == 0x84) + { + // but don't count the current block + skip_blocks = ((byte_b - 0x84) << 8) + byte_a - 1; + } + + // check if this is in the 2- or 8-color classes + else if (byte_b < 0x80) + { + flags = (byte_b << 8) | byte_a; + + quad[0][0].c1 = LE_16(&encoded[stream_ptr]); + stream_ptr += 2; + quad[0][0].c2 = LE_16(&encoded[stream_ptr]); + stream_ptr += 2; + + DECODE_BGR555_TO_BGR888(quad[0][0]); + + if (quad[0][0].c1 & 0x8000) + { + // 8-color encoding + quad[1][0].c1 = LE_16(&encoded[stream_ptr]); + stream_ptr += 2; + quad[1][0].c2 = LE_16(&encoded[stream_ptr]); + stream_ptr += 2; + quad[0][1].c1 = LE_16(&encoded[stream_ptr]); + stream_ptr += 2; + quad[0][1].c2 = LE_16(&encoded[stream_ptr]); + stream_ptr += 2; + quad[1][1].c1 = LE_16(&encoded[stream_ptr]); + stream_ptr += 2; + quad[1][1].c2 = LE_16(&encoded[stream_ptr]); + stream_ptr += 2; + + DECODE_BGR555_TO_BGR888(quad[0][1]); + DECODE_BGR555_TO_BGR888(quad[1][0]); + DECODE_BGR555_TO_BGR888(quad[1][1]); + + for (pixel_y = 0; pixel_y < 4; pixel_y++) + { + for (pixel_x = 0; pixel_x < 4; pixel_x++) + { + if (flags & 1) + { + decoded[pixel_ptr++] = quad[pixel_x >> 1][pixel_y >> 1].c1_r; + decoded[pixel_ptr++] = quad[pixel_x >> 1][pixel_y >> 1].c1_g; + decoded[pixel_ptr++] = quad[pixel_x >> 1][pixel_y >> 1].c1_b; + } + else + { + decoded[pixel_ptr++] = quad[pixel_x >> 1][pixel_y >> 1].c2_r; + decoded[pixel_ptr++] = quad[pixel_x >> 1][pixel_y >> 1].c2_g; + decoded[pixel_ptr++] = quad[pixel_x >> 1][pixel_y >> 1].c2_b; + } + + // get the next flag ready to go + flags >>= 1; + } + pixel_ptr -= row_dec; + } + } + else + { + // 2-color encoding + for (pixel_y = 0; pixel_y < 4; pixel_y++) + { + for (pixel_x = 0; pixel_x < 4; pixel_x++) + { + if (flags & 1) + { + decoded[pixel_ptr++] = quad[0][0].c1_r; + decoded[pixel_ptr++] = quad[0][0].c1_g; + decoded[pixel_ptr++] = quad[0][0].c1_b; + } + else + { + decoded[pixel_ptr++] = quad[0][0].c2_r; + decoded[pixel_ptr++] = quad[0][0].c2_g; + decoded[pixel_ptr++] = quad[0][0].c2_b; + } + + // get the next flag ready to go + flags >>= 1; + } + pixel_ptr -= row_dec; + } + } + } + + // otherwise, it's a 1-color block + else + { + quad[0][0].c1 = (byte_b << 8) | byte_a; + DECODE_BGR555_TO_BGR888(quad[0][0]); + + for (pixel_y = 0; pixel_y < 4; pixel_y++) + { + for (pixel_x = 0; pixel_x < 4; pixel_x++) + { + decoded[pixel_ptr++] = quad[0][0].c1_r; + decoded[pixel_ptr++] = quad[0][0].c1_g; + decoded[pixel_ptr++] = quad[0][0].c1_b; + } + pixel_ptr -= row_dec; + } + } + + block_ptr += block_inc; + } + } +} + +void AVI_Decode_Video1_8( + char *encoded, + int encoded_size, + char *decoded, + int width, + int height, + unsigned char *palette_map, + int bytes_per_pixel) +{ + int block_ptr, pixel_ptr; + int pixel_x, pixel_y; // pixel width and height iterators + int block_x, block_y; // block width and height iterators + int blocks_wide, blocks_high; // width and height in 4x4 blocks + int block_inc; + int row_dec; + + // decoding parameters + int stream_ptr; + unsigned char byte_a, byte_b; + unsigned short flags; + int skip_blocks; + + stream_ptr = 0; + skip_blocks = 0; + blocks_wide = width / 4; + blocks_high = height / 4; + block_inc = 4 * bytes_per_pixel; + row_dec = (width + 4) * bytes_per_pixel; + + for (block_y = blocks_high; block_y > 0; block_y--) + { + block_ptr = ((block_y * 4) - 1) * (width * bytes_per_pixel); + for (block_x = blocks_wide; block_x > 0; block_x--) + { + // check if this block should be skipped + if (skip_blocks) + { + block_ptr += block_inc; + skip_blocks--; + continue; + } + + pixel_ptr = block_ptr; + + // get the next two bytes in the encoded data stream + byte_a = encoded[stream_ptr++]; + byte_b = encoded[stream_ptr++]; + + // check if the decode is finished + if ((byte_a == 0) && (byte_b == 0)) + return; + + // check if this is a skip code + else if ((byte_b & 0xFC) == 0x84) + { + // but don't count the current block + skip_blocks = ((byte_b - 0x84) << 8) + byte_a - 1; + } + + // check if this is a 2-color block + else if (byte_b < 0x80) + { + flags = (byte_b << 8) | byte_a; + + quad[0][0].c1 = (unsigned char)encoded[stream_ptr++]; + quad[0][0].c2 = (unsigned char)encoded[stream_ptr++]; + + DECODE_PALETTE_TO_BGR888(quad[0][0]); + + // 2-color encoding + for (pixel_y = 0; pixel_y < 4; pixel_y++) + { + for (pixel_x = 0; pixel_x < 4; pixel_x++) + { + if (flags & 1) + { + decoded[pixel_ptr++] = quad[0][0].c1_r; + decoded[pixel_ptr++] = quad[0][0].c1_g; + decoded[pixel_ptr++] = quad[0][0].c1_b; + } + else + { + decoded[pixel_ptr++] = quad[0][0].c2_r; + decoded[pixel_ptr++] = quad[0][0].c2_g; + decoded[pixel_ptr++] = quad[0][0].c2_b; + } + + // get the next flag ready to go + flags >>= 1; + } + pixel_ptr -= row_dec; + } + } + + // check if it's an 8-color block + else if (byte_b >= 0x90) + { + // 8-color encoding + quad[0][0].c1 = (unsigned char)encoded[stream_ptr++]; + quad[0][0].c2 = (unsigned char)encoded[stream_ptr++]; + quad[1][0].c1 = (unsigned char)encoded[stream_ptr++]; + quad[1][0].c2 = (unsigned char)encoded[stream_ptr++]; + + quad[0][1].c1 = (unsigned char)encoded[stream_ptr++]; + quad[0][1].c2 = (unsigned char)encoded[stream_ptr++]; + quad[1][1].c1 = (unsigned char)encoded[stream_ptr++]; + quad[1][1].c2 = (unsigned char)encoded[stream_ptr++]; + + DECODE_PALETTE_TO_BGR888(quad[0][0]); + DECODE_PALETTE_TO_BGR888(quad[0][1]); + DECODE_PALETTE_TO_BGR888(quad[1][0]); + DECODE_PALETTE_TO_BGR888(quad[1][1]); + + for (pixel_y = 0; pixel_y < 4; pixel_y++) + { + for (pixel_x = 0; pixel_x < 4; pixel_x++) + { + if (flags & 1) + { + decoded[pixel_ptr++] = quad[pixel_x >> 1][pixel_y >> 1].c1_r; + decoded[pixel_ptr++] = quad[pixel_x >> 1][pixel_y >> 1].c1_g; + decoded[pixel_ptr++] = quad[pixel_x >> 1][pixel_y >> 1].c1_b; + } + else + { + decoded[pixel_ptr++] = quad[pixel_x >> 1][pixel_y >> 1].c2_r; + decoded[pixel_ptr++] = quad[pixel_x >> 1][pixel_y >> 1].c2_g; + decoded[pixel_ptr++] = quad[pixel_x >> 1][pixel_y >> 1].c2_b; + } + + // get the next flag ready to go + flags >>= 1; + } + pixel_ptr -= row_dec; + } + } + + // otherwise, it's a 1-color block + else + { + // init c2 along with c1 just so c2 is a known value for macro + quad[0][0].c1 = quad[0][0].c2 = byte_a; + DECODE_PALETTE_TO_BGR888(quad[0][0]); + + for (pixel_y = 0; pixel_y < 4; pixel_y++) + { + for (pixel_x = 0; pixel_x < 4; pixel_x++) + { + decoded[pixel_ptr++] = quad[0][0].c1_r; + decoded[pixel_ptr++] = quad[0][0].c1_g; + decoded[pixel_ptr++] = quad[0][0].c1_b; + } + pixel_ptr -= row_dec; + } + } + + block_ptr += block_inc; + } + } +} +