Main Page | Modules | Class Hierarchy | Data Structures | File List | Data Fields | Globals | Related Pages | Examples

dat2avi.cpp

ADV202 NTSC/PAL/1080i/720p DAT/BIN to AVI file converter.

You can download ADV202 DAT files here:

Note that these DAT files require to use the -old switch.

See also:
ADV202 on Analog Devices web site
//
// 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