DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/libs/zmbv/zmbv_vfw.cpp
00001 /*
00002  *  Copyright (C) 2002-2013  The DOSBox Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  */
00018 //
00019 // Zipped Motion Block Video
00020 //
00021 // Based on Huffyuv by Ben Rudiak-Gould.
00022 // which was based on MSYUV sample code, which is:
00023 // Copyright (c) 1993 Microsoft Corporation.
00024 // All Rights Reserved.
00025 //
00026 
00027 #include "zmbv_vfw.h"
00028 #include "resource.h"
00029 
00030 #include <crtdbg.h>
00031 #include <string.h>
00032 
00033 TCHAR szDescription[] = TEXT("Zipped Motion Block Video v0.1");
00034 TCHAR szName[]        = TEXT(CODEC_4CC);
00035 
00036 #define VERSION         0x00000001      // 0.1
00037 
00038 /********************************************************************
00039 ********************************************************************/
00040 
00041 CodecInst *encode_table_owner, *decode_table_owner;
00042 
00043 /********************************************************************
00044 ********************************************************************/
00045 
00046 void Msg(const char fmt[], ...) {
00047   DWORD written;
00048   char buf[2000];
00049   va_list val;
00050   
00051   va_start(val, fmt);
00052   wvsprintf(buf, fmt, val);
00053 
00054   const COORD _80x50 = {80,50};
00055   static BOOL startup = (AllocConsole(), SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), _80x50));
00056   WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), buf, lstrlen(buf), &written, 0);
00057 }
00058 
00059 
00060 /********************************************************************
00061 ********************************************************************/
00062 
00063 CodecInst::CodecInst() {
00064         codec = 0;
00065 }
00066 
00067 CodecInst* Open(ICOPEN* icinfo) {
00068   if (icinfo && icinfo->fccType != ICTYPE_VIDEO)
00069       return NULL;
00070 
00071   CodecInst* pinst = new CodecInst();
00072 
00073   if (icinfo) icinfo->dwError = pinst ? ICERR_OK : ICERR_MEMORY;
00074 
00075   return pinst;
00076 }
00077 
00078 DWORD Close(CodecInst* pinst) {
00079 //    delete pinst;       // this caused problems when deleting at app close time
00080     return 1;
00081 }
00082 
00083 /********************************************************************
00084 ********************************************************************/
00085 
00086 
00087 /********************************************************************
00088 ********************************************************************/
00089 
00090 BOOL CodecInst::QueryAbout() { return TRUE; }
00091 
00092 static BOOL CALLBACK AboutDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
00093   if (uMsg == WM_COMMAND) {
00094     switch (LOWORD(wParam)) {
00095     case IDOK:
00096       EndDialog(hwndDlg, 0);
00097       break;
00098     case IDC_HOMEPAGE:
00099       ShellExecute(NULL, NULL, "http://www.dosbox.com", NULL, NULL, SW_SHOW);
00100       break;
00101     case IDC_EMAIL:
00102       ShellExecute(NULL, NULL, "mailto:dosbox.crew@gmail.com", NULL, NULL, SW_SHOW);
00103       break;
00104     }
00105   }
00106   return FALSE;
00107 }
00108 DWORD CodecInst::About(HWND hwnd) {
00109   DialogBox(hmoduleCodec, MAKEINTRESOURCE(IDD_ABOUT), hwnd, AboutDialogProc);
00110   return ICERR_OK;
00111 }
00112 
00113 static BOOL CALLBACK ConfigureDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
00114 
00115   if (uMsg == WM_INITDIALOG) {
00116 
00117   } else if (uMsg == WM_COMMAND) {
00118 
00119     switch (LOWORD(wParam)) {
00120 
00121     case IDOK:
00122 
00123     case IDCANCEL:
00124       EndDialog(hwndDlg, 0);
00125       break;
00126 
00127     default:
00128       return AboutDialogProc(hwndDlg, uMsg, wParam, lParam);    // handle email and home-page buttons
00129     }
00130   }
00131   return FALSE;
00132 }
00133 
00134 BOOL CodecInst::QueryConfigure() { return TRUE; }
00135 
00136 DWORD CodecInst::Configure(HWND hwnd) {
00137   DialogBox(hmoduleCodec, MAKEINTRESOURCE(IDD_CONFIGURE), hwnd, ConfigureDialogProc);
00138   return ICERR_OK;
00139 }
00140 
00141 
00142 /********************************************************************
00143 ********************************************************************/
00144 
00145 
00146 // we have no state information which needs to be stored
00147 
00148 DWORD CodecInst::GetState(LPVOID pv, DWORD dwSize) { return 0; }
00149 
00150 DWORD CodecInst::SetState(LPVOID pv, DWORD dwSize) { return 0; }
00151 
00152 
00153 DWORD CodecInst::GetInfo(ICINFO* icinfo, DWORD dwSize) {
00154   if (icinfo == NULL)
00155     return sizeof(ICINFO);
00156 
00157   if (dwSize < sizeof(ICINFO))
00158     return 0;
00159 
00160   icinfo->dwSize            = sizeof(ICINFO);
00161   icinfo->fccType           = ICTYPE_VIDEO;
00162   memcpy(&icinfo->fccHandler,CODEC_4CC, 4);
00163   icinfo->dwFlags           = VIDCF_FASTTEMPORALC | VIDCF_FASTTEMPORALD | VIDCF_TEMPORAL;
00164 
00165   icinfo->dwVersion         = VERSION;
00166   icinfo->dwVersionICM      = ICVERSION;
00167   MultiByteToWideChar(CP_ACP, 0, szDescription, -1, icinfo->szDescription, sizeof(icinfo->szDescription)/sizeof(WCHAR));
00168   MultiByteToWideChar(CP_ACP, 0, szName, -1, icinfo->szName, sizeof(icinfo->szName)/sizeof(WCHAR));
00169 
00170   return sizeof(ICINFO);
00171 }
00172 
00173 /********************************************************************
00174 ****************************************************************/
00175 
00176 static int GetInputBitDepth(const BITMAPINFOHEADER *lpbiIn) {
00177         if (lpbiIn->biCompression == BI_RGB) {
00178                 if (lpbiIn->biPlanes != 1)
00179                         return -1;
00180 
00181                 switch(lpbiIn->biBitCount) {
00182                         case 8:
00183                                 return 8;
00184                         case 16:
00185                                 return 15;              // Standard Windows 16-bit RGB is 1555.
00186                         case 32:
00187                                 return 32;
00188                 }
00189 
00190         } else if (lpbiIn->biCompression == BI_BITFIELDS) {
00191                 // BI_BITFIELDS RGB masks lie right after the BITMAPINFOHEADER structure,
00192                 // at (ptr+40). This is true even for a BITMAPV4HEADER or BITMAPV5HEADER.
00193                 const DWORD *masks = (const DWORD *)(lpbiIn + 1);
00194 
00195                 if (lpbiIn->biBitCount == 16) {
00196                         // Test for 16 (555)
00197                         if (masks[0] == 0x7C00 && masks[1] == 0x03E0 && masks[2] == 0x001F)
00198                                 return 15;
00199 
00200                         // Test for 16 (565)
00201                         if (masks[0] == 0xF800 && masks[1] == 0x07E0 && masks[2] == 0x001F)
00202                                 return 16;
00203                 } else if (lpbiIn->biBitCount == 32) {
00204                         if (masks[0] == 0xFF0000 && masks[1] == 0x00FF00 && masks[2] == 0x0000FF)
00205                                 return 32;
00206                 }
00207         }
00208 
00209         return -1;
00210 }
00211 
00212 static bool CanCompress(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut, bool requireOutput) {
00213         if (lpbiIn) {
00214                 if (GetInputBitDepth(lpbiIn) < 0)
00215                         return false;
00216         } else return false;
00217         if (lpbiOut) {
00218                 if (memcmp(&lpbiOut->biCompression,CODEC_4CC, 4))
00219                         return false;
00220         } else return !requireOutput;
00221         return true;
00222 }
00223 
00224 /********************************************************************
00225 ****************************************************************/
00226 
00227 DWORD CodecInst::CompressQuery(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) {
00228         if (CanCompress(lpbiIn,lpbiOut,false)) return ICERR_OK;
00229         return ICERR_BADFORMAT;
00230 }
00231 
00232 DWORD CodecInst::CompressGetFormat(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) {
00233         if (!lpbiOut)
00234                 return sizeof(BITMAPINFOHEADER);
00235         lpbiOut->biSize                 = sizeof(BITMAPINFOHEADER);
00236         lpbiOut->biWidth                = lpbiIn->biWidth;
00237         lpbiOut->biHeight               = lpbiIn->biHeight;
00238         lpbiOut->biPlanes               = 1;
00239         lpbiOut->biCompression  = *(const DWORD *)CODEC_4CC;
00240         lpbiOut->biBitCount             = lpbiIn->biBitCount;
00241         lpbiOut->biSizeImage    = lpbiIn->biWidth * lpbiIn->biHeight * lpbiIn->biBitCount/8 + 1024;
00242         lpbiOut->biXPelsPerMeter = lpbiIn->biXPelsPerMeter;
00243         lpbiOut->biYPelsPerMeter = lpbiIn->biYPelsPerMeter;
00244         lpbiOut->biClrUsed              = 0;
00245         lpbiOut->biClrImportant = 0;
00246         return ICERR_OK;
00247 }
00248 
00249 DWORD CodecInst::CompressBegin(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) {
00250         CompressEnd();  // free resources if necessary
00251         if (!CanCompress(lpbiIn, lpbiOut, true))
00252                 return ICERR_BADFORMAT;
00253         codec = new VideoCodec();
00254         if (!codec)
00255                 return ICERR_MEMORY;
00256         if (!codec->SetupCompress( lpbiIn->biWidth, lpbiIn->biHeight))
00257                 return ICERR_MEMORY;
00258         return ICERR_OK;
00259 }
00260 
00261 DWORD CodecInst::CompressGetSize(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) {
00262         if (!CanCompress(lpbiIn, lpbiOut, true))
00263                 return ICERR_BADFORMAT;
00264         return lpbiIn->biWidth * lpbiIn->biHeight * lpbiIn->biBitCount/8 + 1024;
00265 }
00266 
00267 DWORD CodecInst::Compress(ICCOMPRESS* icinfo, DWORD dwSize) {
00268         int i, pitch;
00269         zmbv_format_t format;
00270         LPBITMAPINFOHEADER lpbiIn=icinfo->lpbiInput;
00271         LPBITMAPINFOHEADER lpbiOut=icinfo->lpbiOutput;
00272         if (!CanCompress(lpbiIn, lpbiOut, true))
00273                 return ICERR_BADFORMAT;
00274         if (!icinfo->lpInput || !icinfo->lpOutput)
00275                 return ICERR_ABORT;
00276         switch (GetInputBitDepth(lpbiIn)) {
00277         case 8:
00278                 format = ZMBV_FORMAT_8BPP;
00279                 pitch = lpbiIn->biWidth;
00280                 break;
00281         case 15:
00282                 format = ZMBV_FORMAT_15BPP;
00283                 pitch = lpbiIn->biWidth * 2;
00284                 break;
00285         case 16:
00286                 format = ZMBV_FORMAT_16BPP;
00287                 pitch = lpbiIn->biWidth * 2;
00288                 break;
00289         case 32:
00290                 format = ZMBV_FORMAT_32BPP;
00291                 pitch = lpbiIn->biWidth * 4;
00292                 break;
00293         }
00294 
00295         // DIB scanlines for RGB formats are always aligned to DWORD.
00296         pitch = (pitch + 3) & ~3;
00297 
00298         // force a key frame if requested by the client
00299         int flags = 0;
00300         if (icinfo->dwFlags & ICCOMPRESS_KEYFRAME)
00301                 flags |= 1;
00302 
00303         codec->PrepareCompressFrame( flags, format, 0, icinfo->lpOutput, 99999999);
00304         char *readPt = (char *)icinfo->lpInput + pitch*(lpbiIn->biHeight - 1);
00305         for(i = 0;i<lpbiIn->biHeight;i++) {
00306                 codec->CompressLines(1, (void **)&readPt );
00307                 readPt -= pitch;
00308         }
00309         lpbiOut->biSizeImage = codec->FinishCompressFrame();
00310 
00311         if (flags & 1)
00312                 *icinfo->lpdwFlags = AVIIF_KEYFRAME;
00313         else
00314                 *icinfo->lpdwFlags = 0;
00315 
00316         return ICERR_OK;
00317 }
00318 
00319 
00320 DWORD CodecInst::CompressEnd() {
00321         if (codec) 
00322                 delete codec;
00323         codec = 0;
00324         return ICERR_OK;
00325 }
00326 
00327 /********************************************************************
00328 ********************************************************************/
00329 
00330 static bool CanDecompress(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) {
00331         if (memcmp(&lpbiIn->biCompression,CODEC_4CC,4))
00332                 return false;
00333         if (lpbiOut) {
00334                 if (lpbiOut->biCompression!=0) return false;
00335                 if (lpbiOut->biBitCount != 24) return false;
00336                 if (lpbiIn->biWidth!=lpbiOut->biWidth || lpbiIn->biHeight!=lpbiOut->biHeight)
00337             return false;
00338         }
00339         return true;
00340 }
00341 
00342 /********************************************************************
00343 ********************************************************************/
00344 
00345 
00346 DWORD CodecInst::DecompressQuery(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) {
00347         return CanDecompress(lpbiIn, lpbiOut) ? ICERR_OK : ICERR_BADFORMAT;
00348 }
00349 
00350 DWORD CodecInst::DecompressGetFormat(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) {
00351         if (memcmp(&lpbiIn->biCompression,CODEC_4CC,4))
00352                  return ICERR_BADFORMAT;
00353         if (!lpbiOut) return sizeof(BITMAPINFOHEADER);
00354         *lpbiOut = *lpbiIn;
00355         lpbiOut->biPlanes               = 1;
00356         lpbiOut->biSize                 = sizeof(BITMAPINFOHEADER);
00357         lpbiOut->biBitCount             = 24;
00358         lpbiOut->biSizeImage    = ((lpbiOut->biWidth*3 + 3) & ~3) * lpbiOut->biHeight;
00359         lpbiOut->biCompression  = BI_RGB;
00360         lpbiOut->biClrUsed              = 0;
00361         lpbiOut->biClrImportant = 0;
00362         return ICERR_OK;
00363 }
00364 
00365 DWORD CodecInst::DecompressBegin(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) {
00366         DecompressEnd();  // free resources if necessary
00367         if (!CanDecompress(lpbiIn, lpbiOut))
00368                 return ICERR_BADFORMAT;
00369         codec=new VideoCodec();
00370         if (!codec)
00371                 return ICERR_MEMORY;
00372         if (!codec->SetupDecompress( lpbiIn->biWidth, lpbiIn->biHeight))
00373                 return ICERR_MEMORY;
00374         return ICERR_OK;
00375 }
00376 
00377 DWORD CodecInst::Decompress(ICDECOMPRESS* icinfo, DWORD dwSize) {
00378         if (!codec || !icinfo)
00379                 return ICERR_ABORT;
00380         if (codec->DecompressFrame( icinfo->lpInput, icinfo->lpbiInput->biSizeImage)) {
00381                 codec->Output_UpsideDown_24(icinfo->lpOutput);
00382         } else return ICERR_DONTDRAW;
00383         return ICERR_OK;
00384 }
00385 
00386 
00387 // palette-mapped output only
00388 DWORD CodecInst::DecompressGetPalette(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) {
00389         return ICERR_BADFORMAT;
00390 }
00391 
00392 DWORD CodecInst::DecompressEnd() {
00393         if (codec) 
00394                 delete codec;
00395         codec = 0;
00396         return ICERR_OK;
00397 }