You can download ADV202 DAT files here:
Note that these DAT files require to use the -old switch.
// // DAT2AVI.cpp : ADV202 NTSC/PAL/1080i/720p DAT/BIN to AVI file converter. // // Copyright Morgan-Multimedia 1990-2005. // // Warnings: // - Uses VFW API, limited to 2GB AVI files. // - If AVI output file exists it will be overwriten. // - Input filename with complete path must be 255 car. max. // - Does not work with all ADV202 DAT/BIN files. // // Usage: DAT2AVI [-old|-bin] <datfile> // -old Use old DAT file header format. // -bin Read BIN file format. // #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers #include <windows.h> #include <vfw.h> #include <stdio.h> #include "JPEG2000.h" #pragma warning( disable : 556 ) // Disable warning due to BYTE aligned access to DWORD aligned buffers. // // From ADV202 JPEG2000 Video Processor User’s Guide - Revision 2.1, December 03, 2004 // // TABLE A-5. ADV202 COMPRESSED FIELD HEADERS // typedef struct OLD_ADV202_COMPRESSED_FIELD_HEADERtag { DWORD dwField; // 0xFFFFFFF0 (even field delimiter) // 0xFFFFFFF1 (odd field delimiter) BYTE cVideoStandard; // Video Standard // 0 = NTSC 4:2:2 // 1 = PAL 4:2:2 // 2 = 1080i Luminance // 3 = 1080i Chrominance // 4 = Custom // 5 = 1720/60p Luminance // 6 = 1080i Chrominance BYTE fStreamFormat; // Output Code Stream Format // COD STYLE[2..0] // 00 = ADV202 Raw Format // 01 = J2C Format // 10 = JP2 Format (required for YCbCr 4:2:2 images) // COD STYLE[3] // Selects the option to “disable” the output of the 16 byte ADV202 Header at the start of every compressed image. // 0 = enable header output // 1 = disable header output // COD STYLE[7..4] // Only valid with J2C or JP2 Format, otherwise must all be 0. // bit 7 = Enable PPT 0 = packet headers with packet body, 1 = use PPT // bit 6 = Enable PLT (0 = no PLT, 1 = include PLT) // bit 5 = Enable SOP (0 = no SOP, 1 = include SOP) // bit 4 = Enable EPH (0 = no EPH, 1 = include EPH) BYTE cHeaderVersion; // Header version code (0x02 for encode firmware with Application ID = 0xFF82) BYTE bReserved; // reserved (0x00) DWORD dwImageIdx; // Compressed image index in stream. Starting with 0 and incrementing for each successive image DWORD dwLenBy4; // Number of 32 bit words in compressed data and attribute data. // This does not include the four 32 bit words (16 bytes) in this header } OLD_ADV202_COMPRESSED_FIELD_HEADER, *POLD_ADV202_COMPRESSED_FIELD_HEADER; typedef struct ADV202_COMPRESSED_FIELD_HEADERtag { DWORD dwField; // 0xFFFFFFF0 (even field delimiter) // 0xFFFFFFF1 (odd field delimiter) DWORD dwImageIdx; // Compressed image index in stream. Starting with 0 and incrementing for each successive image BYTE fStreamFormat; // Output Code Stream Format // COD STYLE[2..0] // 00 = ADV202 Raw Format // 01 = J2C Format // 10 = JP2 Format (required for YCbCr 4:2:2 images) // COD STYLE[3] // Selects the option to “disable” the output of the 16 byte ADV202 Header at the start of every compressed image. // 0 = enable header output // 1 = disable header output // COD STYLE[7..4] // Only valid with J2C or JP2 Format, otherwise must all be 0. // bit 7 = Enable PPT 0 = packet headers with packet body, 1 = use PPT // bit 6 = Enable PLT (0 = no PLT, 1 = include PLT) // bit 5 = Enable SOP (0 = no SOP, 1 = include SOP) // bit 4 = Enable EPH (0 = no EPH, 1 = include EPH) BYTE cVideoStandard; // Video Standard // 0 = NTSC 4:2:2 // 1 = PAL 4:2:2 // 2 = 1080i Luminance // 3 = 1080i Chrominance // 4 = Custom // 5 = 720/60p Luminance // 6 = 720/60p Chrominance BYTE bReserved; // reserved (0x00) BYTE cHeaderVersion; // Header version code (0x02 for encode firmware with Application ID = 0xFF82) DWORD dwLenBy4; // Number of 32 bit words in compressed data and attribute data. // This does not include the four 32 bit words (16 bytes) in this header } ADV202_COMPRESSED_FIELD_HEADER, *PADV202_COMPRESSED_FIELD_HEADER; #define FieldHdr_ADV2_LEN sizeof(ADV202_COMPRESSED_FIELD_HEADER) #define FIELD_EVEN 0xFFFFFFF0 #define FIELD_ODD 0xFFFFFFF1 // Output Code Stream Format #define ADV2_FMT_MASK 0x3 #define ADV2_FMT_RAW 0x0 #define ADV2_FMT_J2C 0x1 #define ADV2_FMT_JP2 0x2 #define ADV2_PPT_MASK (1 << 7) #define ADV2_PLT_MASK (1 << 6) #define ADV2_SOP_MASK (1 << 5) #define ADV2_EPH_MASK (1 << 4) // Video Standard enum ADV2_VSTD { ADV2_VSTD_NTSC, ADV2_VSTD_PAL, ADV2_VSTD_1080i_Y, ADV2_VSTD_1080i_CbCr, ADV2_VSTD_Custom, ADV2_VSTD_1720_60p_Y, ADV2_VSTD_720_60p_Y = ADV2_VSTD_1720_60p_Y, ADV2_VSTD_1080i_CbCr_2, ADV2_VSTD_720_60p_CbCr = ADV2_VSTD_1080i_CbCr_2 }; typedef struct BIN_FILE_HEADERtag { DWORD dwTag; DWORD dwExtra; } BIN_FILE_HEADER, *PBIN_FILE_HEADER; typedef struct BIN_IMAGE_HEADERtag { DWORD dwTag; DWORD dwSize; } BIN_IMAGE_HEADER, *PBIN_IMAGE_HEADER; // ADV2 struct typedef struct ADV2tag { HANDLE hFile; // File handle ADV202_COMPRESSED_FIELD_HEADER FieldHdr; // ADV2 format description BOOL bOld; BOOL bBin; BIN_FILE_HEADER BinFileHdr; BIN_IMAGE_HEADER BinImgHdr; BYTE cFmt; int nWidth; int nHeight; BOOL bPPT; BOOL bPLT; BOOL bSOP; BOOL bEPH; } ADV2, *PADV2; DWORD Init() { // Init AVIFile functions AVIFileInit(); return 0; } DWORD Done() { // Exit AVIFile functions AVIFileExit(); return 0; }; DWORD ReadADV2(PADV2 pADV2, PBYTE pBuffer, BOOL bImgHdr) { // Read ADV2 Field Header ADV202_COMPRESSED_FIELD_HEADER FieldHdr; DWORD dwBytesRead; // First read & BIN, read BIN file header if (!pBuffer && pADV2->bBin) { if (!ReadFile(pADV2->hFile, &pADV2->BinFileHdr, sizeof(pADV2->BinFileHdr), &dwBytesRead, NULL) || dwBytesRead < sizeof(pADV2->BinFileHdr)) return 0; } // BIN, read BIN image header if (bImgHdr && pADV2->bBin) { if (!ReadFile(pADV2->hFile, &pADV2->BinImgHdr, sizeof(pADV2->BinImgHdr), &dwBytesRead, NULL) || dwBytesRead < sizeof(pADV2->BinImgHdr)) return 0; } if (!ReadFile(pADV2->hFile, &FieldHdr, FieldHdr_ADV2_LEN, &dwBytesRead, NULL) || dwBytesRead < FieldHdr_ADV2_LEN) return 0; // Old Header style ? if (pADV2->bOld) { OLD_ADV202_COMPRESSED_FIELD_HEADER OldFieldHdr; CopyMemory(&OldFieldHdr, &FieldHdr, FieldHdr_ADV2_LEN); FieldHdr.dwField = OldFieldHdr.dwField; FieldHdr.dwImageIdx = OldFieldHdr.dwImageIdx; FieldHdr.fStreamFormat = OldFieldHdr.fStreamFormat; FieldHdr.cVideoStandard = OldFieldHdr.cVideoStandard; FieldHdr.bReserved = OldFieldHdr.bReserved; FieldHdr.cHeaderVersion = OldFieldHdr.cHeaderVersion; FieldHdr.dwLenBy4 = OldFieldHdr.dwLenBy4; } FieldHdr.dwField = FCC(FieldHdr.dwField); FieldHdr.dwImageIdx = FCC(FieldHdr.dwImageIdx); FieldHdr.dwLenBy4 = FCC(FieldHdr.dwLenBy4); pADV2->FieldHdr = FieldHdr; // Get ADV2 format pADV2->cFmt = pADV2->FieldHdr.fStreamFormat & ADV2_FMT_MASK; pADV2->bPPT = (pADV2->FieldHdr.fStreamFormat & ADV2_PPT_MASK) == ADV2_PPT_MASK; pADV2->bPLT = (pADV2->FieldHdr.fStreamFormat & ADV2_PLT_MASK) == ADV2_PLT_MASK; pADV2->bSOP = (pADV2->FieldHdr.fStreamFormat & ADV2_SOP_MASK) == ADV2_SOP_MASK; pADV2->bEPH = (pADV2->FieldHdr.fStreamFormat & ADV2_PPT_MASK) == ADV2_EPH_MASK; // First read, try to parse a bit J2C/JP2 headers... if (!pBuffer) { BYTE tmpBuf[0x2000]; PBYTE pJ2C = tmpBuf; PBYTE pLimit = pJ2C + 0x2000; if (ReadFile(pADV2->hFile, tmpBuf, 0x2000, &dwBytesRead, NULL) && dwBytesRead == 0x2000) { switch (pADV2->cFmt) { case ADV2_FMT_RAW: break; case ADV2_FMT_J2C: // Extract width and height from J2C header if (((PWORD)pJ2C)[1] == SIZ) // Be sure we have a SIZ marker here { pADV2->nWidth = FCC(((PDWORD)pJ2C)[2]); pADV2->nHeight = FCC(((PDWORD)pJ2C)[3]); } break; case ADV2_FMT_JP2: // Skip JP2 header while (*(PDWORD)pJ2C != 0x51FF4FFF && ++pJ2C < pLimit); if (pJ2C < pLimit) { // Extract width and height from J2C header if (((PWORD)pJ2C)[1] == SIZ) // Be sure we have a SIZ marker here { pADV2->nWidth = FCC(((PDWORD)pJ2C)[2]); pADV2->nHeight = FCC(((PDWORD)pJ2C)[3]); } } break; } switch ((ADV2_VSTD)pADV2->FieldHdr.cVideoStandard) { case ADV2_VSTD_NTSC: pADV2->nHeight *= 2; break; case ADV2_VSTD_PAL: pADV2->nHeight *= 2; break; case ADV2_VSTD_1080i_Y: case ADV2_VSTD_1080i_CbCr: pADV2->nHeight *= 2; break; case ADV2_VSTD_Custom: return 0; case ADV2_VSTD_720_60p_Y: case ADV2_VSTD_720_60p_CbCr: break; } } } if (pBuffer) { DWORD dwLen = pADV2->FieldHdr.dwLenBy4 * 4; if (!ReadFile(pADV2->hFile, pBuffer, dwLen, &dwBytesRead, NULL)) return 0; if (dwBytesRead < dwLen) pADV2->FieldHdr.dwLenBy4 = dwBytesRead / 4; } return dwBytesRead; } DWORD Convert(PCHAR szFileName, PADV2 pAdv2) { // AVI char szAVIFileName[256]; PAVIFILE pfile; // Pointer to the AVI file PAVISTREAM pavivideo; // Pointer to the AVI stream AVISTREAMINFO sivideo; // AVI stream informations LONG lIndex; // Frame Index in the AVI stream LONG lFrames = 0; // Number of frames in the AVI stream DWORD dwScale; DWORD dwRate; // MJ2C PBITMAPINFOHEADER pMJ2CFmt; // Pointer to the Morgan's MJ2C format description PJPEG2000INFOHEADER2 pJP2Fmt; LONG lFmtLength; // Length of the Morgan's MJ2C format description PBYTE pMJ2CBuffer = NULL; // Pointer to the MJ2C data WORD wBitCount; // ADV2 PBYTE pADV2Buffer = NULL; // ADV2 raw data buffer DWORD dwADV2BufSize = 0; // Open ADV2 file pAdv2->hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (pAdv2->hFile==INVALID_HANDLE_VALUE) { printf("Can't open input file.\n"); return GetLastError(); } // Read first ADV2 frame/field if (!ReadADV2(pAdv2, NULL, TRUE)) { printf("Can't read first field header in input file.\n"); goto done; } // Seek ADV2 file to first field if (pAdv2->bBin) SetFilePointer(pAdv2->hFile, sizeof(BIN_FILE_HEADER), NULL, FILE_BEGIN); else SetFilePointer(pAdv2->hFile, 0, NULL, FILE_BEGIN); // (Almost) guess the format ... switch ((ADV2_VSTD)pAdv2->FieldHdr.cVideoStandard) { case ADV2_VSTD_NTSC: if (!pAdv2->nWidth) pAdv2->nWidth = 720; if (!pAdv2->nHeight) pAdv2->nHeight = 486; dwScale = 1001; dwRate = 30000; wBitCount = 16; printf("NTSC\n"); break; case ADV2_VSTD_PAL: if (!pAdv2->nWidth) pAdv2->nWidth = 720; if (!pAdv2->nHeight) pAdv2->nHeight = 576; dwScale = 1; dwRate = 25; wBitCount = 16; printf("PAL\n"); break; case ADV2_VSTD_1080i_Y: case ADV2_VSTD_1080i_CbCr: if (!pAdv2->nWidth) pAdv2->nWidth = 1920; if (!pAdv2->nHeight) pAdv2->nHeight = 1080; dwScale = 1001; dwRate = 30000; wBitCount = 16; printf("1080i\n"); break; case ADV2_VSTD_Custom: printf("Input file video standard 4 \"Custom\" not supported.\n"); goto done; case ADV2_VSTD_720_60p_Y: case ADV2_VSTD_720_60p_CbCr: //case ADV2_VSTD_1720_60p_Y: //case ADV2_VSTD_1080i_CbCr_2: if (pAdv2->bOld) { printf("Input file video standard 5 and 6 not supported.\n"); goto done; } else { if (!pAdv2->nWidth) pAdv2->nWidth = 1280; if (!pAdv2->nHeight) pAdv2->nHeight = 720; dwScale = 1001; dwRate = 60000; wBitCount = 16; printf("720p\n"); } break; } if (pAdv2->bEPH) printf("EPH enabled\n"); if (pAdv2->bPLT) printf("PLT enabled\n"); if (pAdv2->bPPT) printf("PPT enabled\n"); if (pAdv2->bSOP) printf("SOP enabled\n"); if (pAdv2->cFmt == ADV2_FMT_RAW) printf("ADV202 RAW format\n"); if (pAdv2->cFmt == ADV2_FMT_J2C) printf("J2C format\n"); if (pAdv2->cFmt == ADV2_FMT_JP2) printf("JP2 format\n"); // Allocate ADV2 data buffer dwADV2BufSize = ((pAdv2->nWidth*wBitCount)/8) * pAdv2->nHeight; pADV2Buffer = (PBYTE)malloc(dwADV2BufSize); if (!pADV2Buffer) { printf("Can't allocate ADV2 buffer.\n"); goto done; } // Create compatible MJ2C format lFmtLength = sizeof(BITMAPINFOHEADER) + sizeof(JPEG2000INFOHEADER2); pMJ2CFmt = (PBITMAPINFOHEADER)malloc(lFmtLength); pJP2Fmt = (PJPEG2000INFOHEADER2)(pMJ2CFmt + 1); // Zero'd BITMAPINFOHEADER and JPEG2000INFOHEADER2 ZeroMemory(pMJ2CFmt, lFmtLength); // Init BITMAPINFOHEADER pMJ2CFmt->biSize = lFmtLength; pMJ2CFmt->biWidth = pAdv2->nWidth; pMJ2CFmt->biHeight = pAdv2->nHeight; pMJ2CFmt->biPlanes = 1; pMJ2CFmt->biBitCount = 16; pMJ2CFmt->biCompression = MJ2C; // Init JPEG2000INFOHEADER2 { InitJP2KHdrYUV422(pJP2Fmt); // 720p if (pAdv2->FieldHdr.cVideoStandard == ADV2_VSTD_720_60p_Y || pAdv2->FieldHdr.cVideoStandard == ADV2_VSTD_720_60p_CbCr) { pJP2Fmt->InterlaceFlags = 0; } else { BOOL bEvenFieldFirst = pAdv2->FieldHdr.dwField == FIELD_EVEN; if (bEvenFieldFirst) printf("Even field first\n"); else printf("Odd field first\n"); pJP2Fmt->InterlaceFlags = JP2K_IsInterlaced | (bEvenFieldFirst ? JP2K_Field1First : 0); } } // Create AVI filename { strcpy(szAVIFileName, szFileName); char *pPoint = strrchr(szAVIFileName, '.'); if (pPoint) *pPoint = NULL; strcat(szAVIFileName, ".avi"); } // Delete the old AVI file DeleteFile(szAVIFileName); // Create and open the new AVI file AVIFileOpen(&pfile, szAVIFileName, OF_CREATE | OF_WRITE | OF_SHARE_DENY_NONE, NULL); printf("%s\n",szAVIFileName); // Set the AVI stream information ZeroMemory(&sivideo, sizeof(sivideo)); sivideo.fccType = streamtypeVIDEO; sivideo.fccHandler = MJ2C; sivideo.dwScale = dwScale; sivideo.dwRate = dwRate; sivideo.dwQuality = (DWORD)-1; // Create the AVI stream AVIFileCreateStream(pfile, &pavivideo, &sivideo); // Set the MJ2C format in the AVI stream AVIStreamSetFormat(pavivideo, 0, pMJ2CFmt, lFmtLength); // Get the current frame index in the AVI stream (0) lIndex = AVIStreamLength(pavivideo); // Allocate the MJ2C data buffer pMJ2CBuffer = (PBYTE)malloc(((pAdv2->nWidth*wBitCount)/8) * pAdv2->nHeight); // Let's go ! { // Init what we need to find next DWORD dwFieldNeed = pAdv2->FieldHdr.dwField; DWORD dwImgIdxNeed = pAdv2->FieldHdr.dwImageIdx; BYTE cVidStdNeed = pAdv2->FieldHdr.cVideoStandard; // PAL/NTSC/720p int nFieldsNeed = 2; // 1080i if (pAdv2->FieldHdr.cVideoStandard == ADV2_VSTD_1080i_Y || pAdv2->FieldHdr.cVideoStandard == ADV2_VSTD_1080i_CbCr) nFieldsNeed = 4; PBYTE pY = NULL; // Pointer to the ADV2 Y data in ADV2 Buffer DWORD dwY = 0; PBYTE pCbCr = NULL; // Pointer to the ADV2 CbCr data in ADV2 Buffer DWORD dwCbCr = 0; PWORD pY_SIZ = NULL; PWORD pY_SOT = NULL; PWORD pY_SOD = NULL; PWORD pCbCr_SIZ = NULL; PWORD pCbCr_SOT = NULL; PWORD pCbCr_SOD = NULL; PWORD pY_PPT = NULL; PWORD pCbCr_PPT = NULL; // First video standard we found BYTE cVidStdFirst = cVidStdNeed; // Init Input and Output buffers positions LPBYTE pIn = pADV2Buffer; LPBYTE pOut = pMJ2CBuffer; pMJ2CFmt->biSizeImage = 0; // Init Number of Fields we get so far int nFields = 0; while (ReadADV2(pAdv2, pIn, nFields == 0 || nFields == 2)) { if (//pAdv2->FieldHdr.dwImageIdx != dwImgIdxNeed || pAdv2->FieldHdr.cVideoStandard != cVidStdNeed || pAdv2->FieldHdr.dwField != dwFieldNeed) { // Check field/component skip/inversion later printf("Unexpected field encountered in input file.\n"); goto done; } // Length of this field DWORD dwFieldLen = pAdv2->FieldHdr.dwLenBy4 * 4; // Next field/component/video standard expected DWORD dwField = pAdv2->FieldHdr.dwField; BYTE cVidStd = pAdv2->FieldHdr.cVideoStandard; if (nFieldsNeed != 1 && (cVidStd == ADV2_VSTD_1080i_CbCr || cVidStd == ADV2_VSTD_1080i_Y || cVidStd == ADV2_VSTD_720_60p_CbCr || cVidStd == ADV2_VSTD_720_60p_Y)) { if (cVidStd == ADV2_VSTD_1080i_CbCr || cVidStd == ADV2_VSTD_720_60p_CbCr) { pCbCr = pIn; dwCbCr = dwFieldLen; } else { pY = pIn; dwY = dwFieldLen; } pIn += dwFieldLen; // Next video standard expected if (cVidStd == ADV2_VSTD_1080i_CbCr || cVidStd == ADV2_VSTD_1080i_Y) { cVidStdNeed = (cVidStd == ADV2_VSTD_1080i_CbCr) ? ADV2_VSTD_1080i_Y : ADV2_VSTD_1080i_CbCr; } else { cVidStdNeed = (cVidStd == ADV2_VSTD_720_60p_CbCr) ? ADV2_VSTD_720_60p_Y : ADV2_VSTD_720_60p_CbCr; } if (cVidStdNeed == cVidStdFirst) { if (cVidStd != ADV2_VSTD_720_60p_CbCr && cVidStd != ADV2_VSTD_720_60p_Y) dwFieldNeed = (dwField == FIELD_EVEN) ? FIELD_ODD : FIELD_EVEN; pIn = pADV2Buffer; } } else dwFieldNeed = (dwField == FIELD_EVEN) ? FIELD_ODD : FIELD_EVEN; // We've consumed one more field nFields++; // PAL/NTSC if (cVidStd == ADV2_VSTD_PAL || cVidStd == ADV2_VSTD_NTSC) { CopyMemory(pOut, pIn, dwFieldLen); pOut += dwFieldLen; pMJ2CFmt->biSizeImage += dwFieldLen; } // 1080i/720p else if (nFields == 2 || nFields == 4) { /* Method used to merge Y and CbCr codestreams : Y_SOC Y_SIZ (CHANGE = Csiz changed from 1 component to 3 and Sziz, Xrsiz, YRsiz added for Cb and Cr components, and of course Lsiz added with 6 bytes) Y_COD Y_QCD Y_SOT POC (aka POD ={POC,size}{0,0,1,6,1,Porder}{0,1,1,6,3,Porder}) Y_SOD Y_DATA CbCr_DATA CbCr_EOC */ // Find interesting marker pos in Y PWORD pLimit = (PWORD)(pY + dwY); // Main header PWORD pw = pY_SIZ = (PWORD)(pY + 2); pw = (PWORD)((PBYTE)pw + TCC(pw[1]) + 2); if (*pw != COD) goto done; pw = (PWORD)((PBYTE)pw + TCC(pw[1]) + 2); if (*pw == COC) pw = (PWORD)((PBYTE)pw + TCC(pw[1]) + 2); if (*pw != QCD) goto done; pw = (PWORD)((PBYTE)pw + TCC(pw[1]) + 2); if (*pw == QCC) pw = (PWORD)((PBYTE)pw + TCC(pw[1]) + 2); if (*pw == RGN) pw = (PWORD)((PBYTE)pw + TCC(pw[1]) + 2); if (*pw == POC) goto done; //pw = (PBYTE)pw + TCC(pw[1]) + 2; Already a POC !!! if (*pw == PPM) pw = (PWORD)((PBYTE)pw + TCC(pw[1]) + 2); if (*pw == TLM) pw = (PWORD)((PBYTE)pw + TCC(pw[1]) + 2); if (*pw == PLM) pw = (PWORD)((PBYTE)pw + TCC(pw[1]) + 2); if (*pw == COM) pw = (PWORD)((PBYTE)pw + TCC(pw[1]) + 2); // EOF Main header if (*pw != SOT) goto done; // Tile-part headers pY_SOT = pw; while ((*pw & 0xFF == 0xFF) && (*pw != SOD) && (pw < pLimit)) { pw = (PWORD)((PBYTE)pw + TCC(pw[1]) + 2); // There a PPT in Y Tile-part header, keep it if (*pw == PPT) pY_PPT = pw; } /*if (*pw != SOD) goto done;*/ pY_SOD = pw; // pY_SOD ??? // Find interesting marker pos in CbCr pLimit = (PWORD)pCbCr + dwCbCr; // Main header pw = pCbCr_SIZ = (PWORD)(pCbCr + 2); pw = (PWORD)((PBYTE)pw + TCC(pw[1]) + 2); if (*pw != COD) goto done; // Store progression order of Cb and Cr PBYTE pOrder = (PBYTE)pw; pOrder += 5; // skip COD, Lcod and Scod BYTE CrOrder = pOrder[0]; BYTE CbOrder = pOrder[0]; // Assuming Porder(Cr) = Porder(Cb) pw = (PWORD)((PBYTE)pw + TCC(pw[1]) + 2); if (*pw == COC) pw = (PWORD)((PBYTE)pw + TCC(pw[1]) + 2); if (*pw != QCD) goto done; pw = (PWORD)((PBYTE)pw + TCC(pw[1]) + 2); if (*pw == QCC) pw = (PWORD)((PBYTE)pw + TCC(pw[1]) + 2); if (*pw == RGN) pw = (PWORD)((PBYTE)pw + TCC(pw[1]) + 2); if (*pw == POC) goto done; //pw = (PBYTE)pw + TCC(pw[1]) + 2; Already a POC !!! if (*pw == PPM) pw = (PWORD)((PBYTE)pw + TCC(pw[1]) + 2); if (*pw == TLM) pw = (PWORD)((PBYTE)pw + TCC(pw[1]) + 2); if (*pw == PLM) pw = (PWORD)((PBYTE)pw + TCC(pw[1]) + 2); if (*pw == COM) pw = (PWORD)((PBYTE)pw + TCC(pw[1]) + 2); // EOF Main header if (*pw != SOT) goto done; // Tile-part headers pCbCr_SOT = pw; while ((*pw & 0xFF == 0xFF) && (*pw != SOD) && (pw < pLimit)) { pw = (PWORD)((PBYTE)pw + TCC(pw[1]) + 2); // There a PPT in CbCr Tile-part header, keep it if (*pw == PPT) pCbCr_PPT = pw; } /*if (*pw != SOD) goto done;*/ pCbCr_SOD = pw; // Save pOut PBYTE pOutStart = pOut; // Copy Y_SOC to Y_SIZ DWORD dw = 2; CopyMemory(pOut, pY, dw); pOut += dw; // Change Y_Lsiz WORD Y_Lsiz = TCC(pY_SIZ[1]) + 6; pY_SIZ[1] = TCC(Y_Lsiz); // Change Y_Csiz pY_SIZ[19] = TCC(3); // Copy Y_SIZ dw = Y_Lsiz + 2 - 6; CopyMemory(pOut, pY_SIZ, dw); pOut += dw; // Add end of CbCr_SIZ WORD Lsiz = TCC(pCbCr_SIZ[1]); PBYTE p = (PBYTE)pCbCr_SIZ; p += Lsiz + 2 - 6; // Copy end of CbCr_SIZ dw = 6; CopyMemory(pOut, p, dw); pOut += dw; // Copy from end of Y_SIZ to Y_SOT p = (PBYTE)pY_SIZ + Y_Lsiz + 2 - 6; dw = (PBYTE)pY_SOT - p; CopyMemory(pOut, p, dw); pOut += dw; // {POC,size}{0,0,1w,6,1,LRCP}{0,1,1w,6,3,LRCP}) BYTE mPOC[] = {0xFF,POC>>8, 0,2+7*2, 0, 0, 0,1, 6, 1, 0, 0, 1, 0,1, 6, 3, 0}; // Change progression order (LRCP,..,CPRL). mPOC[10] = CrOrder; mPOC[17] = CbOrder; // Copy POC dw = sizeof(mPOC); CopyMemory(pOut, mPOC, dw); pOut += dw; // PPT not in both Y and CbCr Tile-parts headers !!! ouch ... if ((pY_PPT && !pCbCr_PPT) || (!pY_PPT && pCbCr_PPT)) { printf("PPT not in both Y and CbCr Tile-parts headers\n"); goto done; } else { // Copy from Y_SOT to Y_SOD dw = (PBYTE)pY_SOD - (PBYTE)pY_SOT; CopyMemory(pOut, pY_SOT, dw); pOut += dw; } // PPT in Tile-parts headers if (pCbCr_PPT && pCbCr_PPT) { p = (PBYTE)pCbCr_PPT + 4; *p = 2; dw = TCC(pCbCr_PPT[1]) + 2; CopyMemory(pOut, pCbCr_PPT, dw); pOut += dw; } // SOD missing if (*pY_SOD != SOD) { dw = 2; WORD w = SOD; CopyMemory(pOut, &w, dw); pOut += dw; } // Copy Y_SOD + Y_DATA - EOC p = pY+dwY; while (*(PWORD)(p--) != EOC && p >= (PBYTE)pY_SOD); p++; if (p == (PBYTE)pY_SOD) p = pY+dwY; dw = p - (PBYTE)pY_SOD; CopyMemory(pOut, pY_SOD, dw); pOut += dw; // SOD missing if (*pCbCr_SOD != SOD) pCbCr_SOD--; // Copy CbCr_DATA + CbCr_EOC dw = pCbCr+dwCbCr - (PBYTE)(pCbCr_SOD + 1); CopyMemory(pOut, pCbCr_SOD + 1, dw); pOut += dw; // Update image size pMJ2CFmt->biSizeImage += pOut - pOutStart; pCbCr_PPT = NULL; pY_PPT = NULL; } // Save this frame in the AVI stream if (nFields == nFieldsNeed) { AVIStreamWrite(pavivideo, lIndex++, 1, pMJ2CBuffer, pMJ2CFmt->biSizeImage, AVIIF_KEYFRAME, NULL, NULL); lFrames++; dwImgIdxNeed++; // Re-init output pOut = pMJ2CBuffer; pMJ2CFmt->biSizeImage = 0; nFields = 0; } } } done: CloseHandle(pAdv2->hFile); if (pMJ2CBuffer) free(pMJ2CBuffer); if (pADV2Buffer) free(pADV2Buffer); // Release the AVI stream and file AVIStreamRelease(pavivideo); AVIFileRelease(pfile); printf("%i frames\n",lFrames); return 0; }; int main(int argc, char* argv[]) { printf("ADV202 NTSC/PAL/1080i/720p DAT/BIN to AVI file converter.\n"); printf("\n"); printf("Copyright Morgan-Multimedia 1990-2005.\n"); printf("\n"); printf("Warnings:\n"); printf(" - Uses VFW API, limited to 2GB AVI files.\n"); printf(" - If AVI output file exists it will be overwriten.\n"); printf(" - Input filename with complete path must be 255 car. max.\n"); printf(" - Does not work with all ADV202 DAT/BIN files.\n"); printf("\n"); printf("Usage: DAT2AVI [-old|-bin] <datfile>\n"); printf("\t-old Use old DAT file header format.\n"); printf("\t-bin Read BIN file format.\n"); printf("\n"); if (argv[1]) { Init(); int n = 1; ADV2 Adv2; ZeroMemory(&Adv2, sizeof(Adv2)); if (stricmp(argv[n], "-old") == 0) { Adv2.bOld = TRUE; n++; } if (stricmp(argv[n], "-bin") == 0) { Adv2.bBin = TRUE; n++; } printf(argv[n]); printf("\n"); Convert(argv[n], &Adv2); Done(); } return 0; }
|
© Morgan Multimedia 1990-2005 |