// TileAVI.cpp : Tile AVI file frames in a single bitmap. // #include #include #include #include #include #include #define OUTPUT_WIDTH 512 #pragma comment(lib, "winmm.lib") #pragma comment(lib, "vfw32.lib") BOOL TileAVI(LPCTSTR lpFilename) { TCHAR sOut[MAX_PATH]; _tcscpy(sOut, lpFilename); _tcscat(sOut, _T(".bmp")); IAVIFile *pIn; IAVIStream *pStream; HRESULT h; h = AVIFileOpen(&pIn, lpFilename, OF_SHARE_DENY_WRITE, 0L); if (FAILED(h)) { _tprintf(_T(" %s not found!\n"), lpFilename); return FALSE; } // Load the first video stream. h = AVIFileGetStream(pIn, &pStream, streamtypeVIDEO, 0L); if (FAILED(h)) { pIn->Release(); _tprintf(_T(" %s is not an AVI file!\n"), lpFilename); return FALSE; } BITMAPINFOHEADER bih; AVISTREAMINFOW asi; long cb; pStream->Info(&asi, sizeof(asi)); // We only understand scale = 1, since this means dwLength = number of frames. // This is compatible with 3D Studio MAX. if (asi.dwScale != 1) { pStream->Release(); pIn->Release(); _tprintf(_T(" %s has an unsupported time scale!\n"), lpFilename); return FALSE; } cb = sizeof(bih); pStream->ReadFormat(0, &bih, &cb); // We only support RGB (uncompressed) files. if (bih.biCompression != BI_RGB) { pStream->Release(); pIn->Release(); _tprintf(_T(" %s is a compressed AVI file!\n"), lpFilename); return FALSE; } if (bih.biWidth > OUTPUT_WIDTH) { pStream->Release(); pIn->Release(); _tprintf(_T(" %s is a too large (%dx%d)!\n"), lpFilename, bih.biWidth, bih.biHeight); return FALSE; } // 24-bit files only. if (bih.biBitCount != 24) { pStream->Release(); pIn->Release(); _tprintf(_T(" %s is a %d-bit bitmap, should be 24-bit!\n"), lpFilename, bih.biBitCount); return FALSE; } long nSamples, cbRead, nWidthBytes, nFrameSize; // DIB scan lines are padded to a multiple of 4 bytes. nWidthBytes = ((bih.biWidth * 3) + 3) & ~3; nFrameSize = nWidthBytes * bih.biHeight; LPBYTE lpData = new BYTE[nFrameSize * asi.dwLength]; // Read *all* the frames from the file. for (DWORD i = 0; i < asi.dwLength; i++) { h = pStream->Read(i, 1, &lpData[nFrameSize * i], nFrameSize, &cbRead, &nSamples); if (FAILED(h) || (cbRead < nFrameSize) || (nSamples < 1)) { pStream->Release(); pIn->Release(); delete [] lpData; _tprintf(_T(" Could not read frame %d from %s!\n"), i, lpFilename); return FALSE; } } pStream->Release(); pIn->Release(); FILE *fOut = fopen(sOut, "wb"); if (fOut == NULL) { delete [] lpData; _tprintf(_T(" Could not create output file %s!\n"), sOut); return FALSE; } BITMAPINFOHEADER bihOut; BITMAPFILEHEADER bifOut; DWORD nFramesPerLine, nLines; nFramesPerLine = OUTPUT_WIDTH / bih.biWidth; nLines = (asi.dwLength + (nFramesPerLine - 1)) / nFramesPerLine; // Fill the bitmap headers. bihOut.biSize = sizeof(BITMAPINFOHEADER); bihOut.biWidth = OUTPUT_WIDTH; bihOut.biHeight = nLines * bih.biHeight; bihOut.biPlanes = 1; bihOut.biBitCount = 24; bihOut.biCompression = BI_RGB; bihOut.biSizeImage = bihOut.biWidth * bihOut.biHeight * bihOut.biBitCount / 8; bihOut.biXPelsPerMeter = bihOut.biYPelsPerMeter = 4000; bihOut.biClrUsed = bih.biClrImportant = 0; bifOut.bfType = ('M' << 8) | 'B'; bifOut.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPFILEHEADER) + bih.biSizeImage; bifOut.bfReserved1 = bifOut.bfReserved2 = 0; bifOut.bfOffBits = sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER); fwrite(&bifOut, sizeof(BITMAPFILEHEADER), 1, fOut); fwrite(&bihOut, sizeof(BITMAPINFOHEADER), 1, fOut); // Build the file from the frames. for (int yFrame = nLines - 1; yFrame >= 0; yFrame--) { for (UINT y = 0; y < (DWORD)bih.biHeight; y++) { UINT xFrame; for (xFrame = 0; xFrame < nFramesPerLine; xFrame++) { if ((xFrame + yFrame * nFramesPerLine) >= asi.dwLength) { for (int i = 0; i < bih.biWidth; i++) { fputc(0, fOut); fputc(0, fOut); fputc(0, fOut); } } else fwrite(&lpData[nFrameSize * (xFrame + yFrame * nFramesPerLine) + y * nWidthBytes], bih.biWidth, 3, fOut); } // Black pixels at right-hand side for (UINT i = xFrame * bih.biWidth; i < OUTPUT_WIDTH; i++) { fputc(0, fOut); fputc(0, fOut); fputc(0, fOut); } } } delete [] lpData; fclose(fOut); return TRUE; } int _tmain(int argc, TCHAR* argv[], TCHAR* []) { _tprintf(_T("TileAVI v1.0\n Copyright © David McCabe, 2001.\n\n")); if (argc < 2) { _tprintf(_T("Usage: TileAVI file.avi\n")); return 2; } AVIFileInit(); for (int i = 1; i < argc; i++) { _tprintf(_T("%s:\n"), argv[i]); TileAVI(argv[i]); } AVIFileExit(); return 0; }