1543 lines
40 KiB
C++
1543 lines
40 KiB
C++
#pragma once
|
||
|
||
#include "Types.h"
|
||
|
||
namespace Jpeg2000
|
||
{
|
||
//-------------------------------------------------------------------------------------------------------------------------------
|
||
// Данные функции предназначены для чтения Motion JPEG 2000 (MJ2)
|
||
//-------------------------------------------------------------------------------------------------------------------------------
|
||
|
||
static bool Mj2_ReadBoxHeader(Mj2_Box* pBox, CReader * pStream)
|
||
{
|
||
if (!pBox)
|
||
return false;
|
||
|
||
pBox->nInitPos = pStream->Tell();
|
||
pBox->nLength = pStream->Read(4);
|
||
pBox->nType = pStream->Read(4);
|
||
|
||
if (1 == pBox->nLength)
|
||
{
|
||
if (0 != pStream->Read(4))
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Cannot handle box sizes higher than 2^32\n");
|
||
return false;
|
||
}
|
||
pBox->nLength = pStream->Read(4);
|
||
if (0 == pBox->nLength)
|
||
pBox->nLength = pStream->GetLeftSize() + 12;
|
||
}
|
||
else if (0 == pBox->nLength)
|
||
{
|
||
int nBytesLeft = pStream->GetLeftSize();
|
||
if (0 == nBytesLeft)
|
||
return false;
|
||
|
||
pBox->nLength = nBytesLeft + 8;
|
||
}
|
||
return true;
|
||
}
|
||
static bool Mj2_ReadJP(CReader * pStream)
|
||
{
|
||
Mj2_Box oBox;
|
||
Mj2_ReadBoxHeader(&oBox, pStream);
|
||
|
||
if (oBox.nType != MJ2_JP)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Expected JP Marker\n");
|
||
return false;
|
||
}
|
||
if (0x0d0a870a != pStream->Read(4)) // read the 0x0d0a870a required in a JP box
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with JP Marker\n");
|
||
return false;
|
||
}
|
||
if (pStream->Tell() - oBox.nInitPos != oBox.nLength)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with JP Box size \n");
|
||
return false;
|
||
}
|
||
return true;
|
||
|
||
}
|
||
|
||
static bool Mj2_ReadFTYP(Mj2_Movie* pMovie, CReader * pStream)
|
||
{
|
||
Mj2_Box oBox;
|
||
Mj2_ReadBoxHeader(&oBox, pStream);
|
||
|
||
if (MJ2_FTYP != oBox.nType)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Expected FTYP Marker\n");
|
||
return false;
|
||
}
|
||
|
||
pMovie->unBrand = pStream->Read(4); // BR
|
||
pMovie->unMinVersion = pStream->Read(4); // MinV
|
||
pMovie->nCompListLength = (oBox.nLength - 16) / 4;
|
||
pMovie->pCompList = (unsigned int*)Malloc(pMovie->nCompListLength * sizeof(unsigned int));
|
||
|
||
for (int nIndex = pMovie->nCompListLength - 1; nIndex > -1; nIndex--)
|
||
{
|
||
pMovie->pCompList[nIndex] = pStream->Read(4); // CLi
|
||
}
|
||
|
||
if (pStream->Tell() - oBox.nInitPos != oBox.nLength)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with FTYP Box\n");
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
static bool Mj2_ReadMDAT(Mj2_Movie* pMovie, CReader * pStream, Image** ppImage, Mj2_Box oBox)
|
||
{
|
||
if (MJ2_MDAT != oBox.nType)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Expected FTYP Marker\n");
|
||
return false;
|
||
}
|
||
|
||
int nStartPos = pStream->Tell();
|
||
|
||
|
||
//>>>>
|
||
|
||
// Достаем первую картинку в потоке MDAT
|
||
Jp2Box oTempBox;
|
||
Jp2_ReadBoxHeader(pMovie->pCodecInfo, pStream, &oTempBox);
|
||
do
|
||
{
|
||
if (JP2_JP2C != oTempBox.nType)
|
||
{
|
||
pStream->Skip(oTempBox.nLength - 8);
|
||
|
||
if (pStream->GetLeftSize() < 0)
|
||
return false;
|
||
|
||
if (!Jp2_ReadBoxHeader(pMovie->pCodecInfo, pStream, &oTempBox))
|
||
return false;
|
||
}
|
||
} while (JP2_JP2C != oTempBox.nType);
|
||
|
||
int nJ2kCodestreamOffset = pStream->Tell();
|
||
int nJ2kCodestreamLength = oTempBox.nLength - 8;
|
||
|
||
// Декодируем J2K
|
||
*ppImage = J2k_Decode(pMovie->pJ2k, pStream);
|
||
if (!*ppImage)
|
||
{
|
||
Event_Message(EVT_ERROR, "Failed to decode J2K image\n");
|
||
return false;
|
||
}
|
||
|
||
//<<<<<<
|
||
|
||
int nReaded = pStream->Tell() - nStartPos;
|
||
|
||
pStream->Skip(oBox.nLength - nReaded - 8);
|
||
if (pStream->GetLeftSize() < 0)
|
||
return false;
|
||
|
||
|
||
return true;
|
||
}
|
||
static bool Mj2_ReadMVHD(Mj2_Movie* pMovie, CReader * pStream)
|
||
{
|
||
Mj2_Box oBox;
|
||
Mj2_ReadBoxHeader(&oBox, pStream);
|
||
if (MJ2_MVHD != oBox.nType)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Expected MVHD Marker\n");
|
||
return false;
|
||
}
|
||
|
||
|
||
if (0 != pStream->Read(4)) // Version = 0, flags = 0
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Only Version 0 handled in MVHD box\n");
|
||
}
|
||
|
||
// TO DO: Здесь в зависимости от версии разное число байт должно читаться
|
||
// см. fcd15444-3.pdf стр.15
|
||
|
||
pMovie->unCreationTime = pStream->Read(4); // Creation Time
|
||
pMovie->unModificationTime = pStream->Read(4); // Modification Time
|
||
pMovie->nTimescale = pStream->Read(4); // Timescale
|
||
pMovie->unDuration = pStream->Read(4); // Duration
|
||
|
||
pMovie->nRate = pStream->Read(4); // Rate
|
||
pMovie->nVolume = pStream->Read(2); // Volume
|
||
|
||
pStream->Skip(10); // const bit(16) reserved = 0 + const unsigned int(32)[2] reserved = 0
|
||
|
||
pMovie->anTransMatrix[0] = pStream->Read(4); // Transformation matrix
|
||
pMovie->anTransMatrix[1] = pStream->Read(4); //
|
||
pMovie->anTransMatrix[2] = pStream->Read(4); //
|
||
pMovie->anTransMatrix[3] = pStream->Read(4); //
|
||
pMovie->anTransMatrix[4] = pStream->Read(4); //
|
||
pMovie->anTransMatrix[5] = pStream->Read(4); //
|
||
pMovie->anTransMatrix[6] = pStream->Read(4); //
|
||
pMovie->anTransMatrix[7] = pStream->Read(4); //
|
||
pMovie->anTransMatrix[8] = pStream->Read(4); //
|
||
|
||
pStream->Skip(24); // bit(32)[6] pre-defined = 0;
|
||
|
||
pMovie->nNextTrackId = pStream->Read(4); // ID of Next track to be added
|
||
|
||
if (pStream->Tell() - oBox.nInitPos != oBox.nLength)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with MVHD Box Size\n");
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
|
||
static bool Mj2_ReadTKHD(Mj2_TrackParams* pTrack, CReader * pStream)
|
||
{
|
||
Mj2_Box oBox;
|
||
Mj2_ReadBoxHeader(&oBox, pStream);
|
||
|
||
if (MJ2_TKHD != oBox.nType)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Expected TKHD Marker\n");
|
||
return false;
|
||
}
|
||
|
||
// TO DO: Здесь в зависимости от версии разное число байт должно читаться
|
||
// см. fcd15444-3.pdf стр.16
|
||
|
||
if (0 != pStream->Read(1)) // Version = 0
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Only Version 0 handled in TKHD box\n");
|
||
return false;
|
||
}
|
||
|
||
int nFlag = pStream->Read(3);
|
||
|
||
if (!(1 == nFlag || 2 == nFlag || 3 == nFlag || 4 == nFlag)) // nFlags = 1, 2, 3 или 4
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with flag in TKHD box: Expected flag 1,2,3 or 4\n");
|
||
return false;
|
||
}
|
||
|
||
pTrack->unCreationTime = pStream->Read(4); // Creation Time
|
||
pTrack->unModificationTime = pStream->Read(4); // Modification Time
|
||
pTrack->nTrackID = pStream->Read(4); // Track ID
|
||
pStream->Skip(4); // const unsigned int(32) reserved = 0;
|
||
pTrack->nDuration = pStream->Read(4); // Duration
|
||
|
||
pStream->Skip(8); // const unsigned int(32)[2] reserved = 0;
|
||
|
||
pTrack->nLayer = pStream->Read(2); // Layer
|
||
pStream->Read(2); // int(16) pre-defined = 0;
|
||
pTrack->nVolume = pStream->Read(2); // Volume
|
||
pStream->Skip(2); // const unsigned int(16) reserved = 0;
|
||
|
||
pTrack->anTransMatrix[0] = pStream->Read(4); // Transformation matrix for track */
|
||
pTrack->anTransMatrix[1] = pStream->Read(4); //
|
||
pTrack->anTransMatrix[2] = pStream->Read(4); //
|
||
pTrack->anTransMatrix[3] = pStream->Read(4); //
|
||
pTrack->anTransMatrix[4] = pStream->Read(4); //
|
||
pTrack->anTransMatrix[5] = pStream->Read(4); //
|
||
pTrack->anTransMatrix[6] = pStream->Read(4); //
|
||
pTrack->anTransMatrix[7] = pStream->Read(4); //
|
||
pTrack->anTransMatrix[8] = pStream->Read(4); //
|
||
|
||
pTrack->nVisualWidth = pStream->Read(4); // Image Visual Width
|
||
pTrack->nVisualHeight = pStream->Read(4); // Image Visual Height
|
||
|
||
if (pStream->Tell() - oBox.nInitPos != oBox.nLength)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with TKHD Box size\n");
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
static bool Mj2_ReadMDHD(Mj2_TrackParams* pTrack, CReader * pStream)
|
||
{
|
||
Mj2_Box oBox;
|
||
Mj2_ReadBoxHeader(&oBox, pStream);
|
||
|
||
if (!(MJ2_MHDR == oBox.nType || MJ2_MDHD == oBox.nType)) // Kakadu writes MHDR instead of MDHD
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Expected MDHD Marker\n");
|
||
return 1;
|
||
}
|
||
|
||
// TO DO: Сделать поодержку Version = 1
|
||
if (0 != pStream->Read(1)) // Version = 0
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Only Version 0 handled in MDHD box\n");
|
||
return false;
|
||
}
|
||
|
||
if (0 != pStream->Read(3)) // Flags = 0
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with flag in MDHD box. Expected flag 0\n");
|
||
return false;
|
||
}
|
||
|
||
pTrack->unCreationTime = pStream->Read(4); // Creation Time
|
||
pTrack->unModificationTime = pStream->Read(4); // Modification Time
|
||
pTrack->nTimescale = pStream->Read(4); // Timescale
|
||
pTrack->nDuration = pStream->Read(4); // Duration
|
||
|
||
pTrack->nLanguage = pStream->Read(2); // Language
|
||
pStream->Skip(2); // unsigned int(16) pre-defined = 0;
|
||
|
||
if (pStream->Tell() - oBox.nInitPos != oBox.nLength)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with MDHD Box size\n");
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
static bool Mj2_ReadHDLR(Mj2_TrackParams* pTrack, CReader * pStream)
|
||
{
|
||
Mj2_Box oBox;
|
||
Mj2_ReadBoxHeader(&oBox, pStream);
|
||
|
||
if (MJ2_HDLR != oBox.nType)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Expected HDLR Marker\n");
|
||
return false;
|
||
}
|
||
|
||
if (0 != pStream->Read(1)) // Version = 0
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Only Version 0 handled in HDLR box\n");
|
||
return false;
|
||
}
|
||
|
||
if (0 != pStream->Read(3)) // Flags = 0
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with flag in HDLR box. Expected flag 0\n");
|
||
return false;
|
||
}
|
||
|
||
pStream->Skip(4); // unsigned int(32) pre-defined = 0;
|
||
pTrack->nHandlerType = pStream->Read(4); // handler-type
|
||
pStream->Skip(12); // const unsigned int(32)[3] reserved = 0;
|
||
|
||
pTrack->nNameSize = oBox.nLength - 32;
|
||
pTrack->sName = (char*)Malloc(pTrack->nNameSize * sizeof(char));
|
||
|
||
for (int nIndex = 0; nIndex < pTrack->nNameSize; nIndex++)
|
||
{
|
||
pTrack->sName[nIndex] = pStream->Read(1); // Name
|
||
}
|
||
|
||
if (pStream->Tell() - oBox.nInitPos != oBox.nLength)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with HDLR Box size\n");
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
static bool Mj2_ReadVMHD(Mj2_TrackParams* pTrack, CReader * pStream)
|
||
{
|
||
Mj2_Box oBox;
|
||
Mj2_ReadBoxHeader(&oBox, pStream);
|
||
if (MJ2_VMHD != oBox.nType)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Expected VMHD Marker\n");
|
||
return false;
|
||
}
|
||
|
||
if (0 != pStream->Read(1)) // Version = 0
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Only Version 0 handled in VMHD box\n");
|
||
return false;
|
||
}
|
||
|
||
if (1 != pStream->Read(3)) // Flags = 1
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with flag in VMHD box. Expected flag 1\n");
|
||
return false;
|
||
}
|
||
|
||
pTrack->nTrackType = 0;
|
||
pTrack->nGraphicsMode = pStream->Read(2); // graphicsmode
|
||
pTrack->anOpColor[0] = pStream->Read(2); // opcolor
|
||
pTrack->anOpColor[1] = pStream->Read(2); //
|
||
pTrack->anOpColor[2] = pStream->Read(2); //
|
||
|
||
if (pStream->Tell() - oBox.nInitPos != oBox.nLength)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with VMHD Box size\n");
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
static bool Mj2_ReadSMHD(Mj2_TrackParams* pTrack, CReader * pStream)
|
||
{
|
||
Mj2_Box oBox;
|
||
Mj2_ReadBoxHeader(&oBox, pStream);
|
||
if (MJ2_SMHD != oBox.nType)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Expected SMHD Marker\n");
|
||
return false;
|
||
}
|
||
|
||
if (0 != pStream->Read(1)) // Version = 0
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Only Version 0 handled in SMHD box\n");
|
||
return false;
|
||
}
|
||
|
||
if (0 != pStream->Read(3)) // Flags = 0
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with flag in SMHD box. Expected flag 0\n");
|
||
return false;
|
||
}
|
||
|
||
pTrack->nTrackType = 1;
|
||
pTrack->nBalance = pStream->Read(2);
|
||
|
||
// Init variables to zero to avoid problems when freeeing memory
|
||
// The values will possibly be overidded when decoding the track structure
|
||
pTrack->nNumBr = 0;
|
||
pTrack->nNumUrl = 0;
|
||
pTrack->nNumUrn = 0;
|
||
pTrack->unNumChunks = 0;
|
||
pTrack->nNumTimeToSample = 0;
|
||
pTrack->nNumSamplesToChunk = 0;
|
||
pTrack->unNumSamples = 0;
|
||
|
||
pStream->Skip(2); // Reserved
|
||
|
||
if (pStream->Tell() - oBox.nInitPos != oBox.nLength)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with SMHD Box size\n");
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
static bool Mj2_ReadHMHD(Mj2_TrackParams* pTrack, CReader * pStream)
|
||
{
|
||
Mj2_Box oBox;
|
||
Mj2_ReadBoxHeader(&oBox, pStream);
|
||
|
||
if (MJ2_HMHD != oBox.nType)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Expected HMHD Marker\n");
|
||
return false;
|
||
}
|
||
|
||
if (0 != pStream->Read(1)) // Version = 0
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Only Version 0 handled in HMHD box\n");
|
||
return false;
|
||
}
|
||
|
||
if (0 != pStream->Read(3)) // Flags = 0
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with flag in HMHD box. Expected flag 0\n");
|
||
return false;
|
||
}
|
||
|
||
pTrack->nTrackType = 2;
|
||
pTrack->nMaxPDUsize = pStream->Read(2); // maxPDUsize
|
||
pTrack->nAvgPDUsize = pStream->Read(2); // avgPDUsize
|
||
pTrack->nMaxBitrate = pStream->Read(4); // maxbitrate
|
||
pTrack->nAvgBitrate = pStream->Read(4); // avgbitrate
|
||
pTrack->nSlidingAvgBitrate = pStream->Read(4); // slidingavgbitrate
|
||
|
||
// Init variables to zero to avoid problems when freeeing memory
|
||
// The values will possibly be overidded when decoding the track structure
|
||
pTrack->nNumBr = 0;
|
||
pTrack->nNumUrl = 0;
|
||
pTrack->nNumUrn = 0;
|
||
pTrack->unNumChunks = 0;
|
||
pTrack->nNumTimeToSample = 0;
|
||
pTrack->nNumSamplesToChunk = 0;
|
||
pTrack->unNumSamples = 0;
|
||
|
||
|
||
if (pStream->Tell() - oBox.nInitPos != oBox.nLength)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with HMHD Box size\n");
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
static bool Mj2_ReadURL(Mj2_TrackParams* pTrack, CReader * pStream, int nUrlNum)
|
||
{
|
||
Mj2_Box oBox;
|
||
Mj2_ReadBoxHeader(&oBox, pStream);
|
||
if (MJ2_URL != oBox.nType)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Expected URL Marker\n");
|
||
return false;
|
||
}
|
||
|
||
if (0 != pStream->Read(1)) // Version = 0
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Only Version 0 handled in URL box\n");
|
||
return false;
|
||
}
|
||
|
||
if (1 != pStream->Read(3)) // Если flags = 1, то медиа данные в файле
|
||
{
|
||
// TO DO: Сделать нормальное чтение строк
|
||
pTrack->pUrl[nUrlNum].anLocation[0] = pStream->Read(4);
|
||
pTrack->pUrl[nUrlNum].anLocation[1] = pStream->Read(4);
|
||
pTrack->pUrl[nUrlNum].anLocation[2] = pStream->Read(4);
|
||
pTrack->pUrl[nUrlNum].anLocation[3] = pStream->Read(4);
|
||
}
|
||
else
|
||
{
|
||
pTrack->nNumUrl--;
|
||
}
|
||
|
||
|
||
if (pStream->Tell() - oBox.nInitPos != oBox.nLength)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with URL Box size\n");
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
static bool Mj2_ReadURN(Mj2_TrackParams* pTrack, CReader * pStream, int nUrnNum)
|
||
{
|
||
Mj2_Box oBox;
|
||
Mj2_ReadBoxHeader(&oBox, pStream);
|
||
|
||
if (MJ2_URN != oBox.nType)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Expected URN Marker\n");
|
||
return false;
|
||
}
|
||
|
||
if (0 != pStream->Read(1)) // Version = 0
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Only Version 0 handled in URN box\n");
|
||
return false;
|
||
}
|
||
|
||
if (1 != pStream->Read(3)) // Если flags = 1, то медиа данные в файле
|
||
{
|
||
// TO DO: Сделать нормальное чтение строк
|
||
pTrack->pUrn[nUrnNum].anName[0] = pStream->Read(4);
|
||
pTrack->pUrn[nUrnNum].anName[1] = pStream->Read(4);
|
||
pTrack->pUrn[nUrnNum].anName[2] = pStream->Read(4);
|
||
pTrack->pUrn[nUrnNum].anName[3] = pStream->Read(4);
|
||
pTrack->pUrn[nUrnNum].anLocation[0] = pStream->Read(4);
|
||
pTrack->pUrn[nUrnNum].anLocation[1] = pStream->Read(4);
|
||
pTrack->pUrn[nUrnNum].anLocation[2] = pStream->Read(4);
|
||
pTrack->pUrn[nUrnNum].anLocation[3] = pStream->Read(4);
|
||
}
|
||
|
||
|
||
if (pStream->Tell() - oBox.nInitPos != oBox.nLength)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with URN Box size\n");
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
|
||
static bool Mj2_ReadDREF(Mj2_TrackParams* pTrack, CReader * pStream)
|
||
{
|
||
Mj2_Box oBox;
|
||
Mj2_ReadBoxHeader(&oBox, pStream);
|
||
if (MJ2_DREF != oBox.nType)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Expected DREF Marker\n");
|
||
return false;
|
||
}
|
||
|
||
if (0 != pStream->Read(1)) // Version = 0
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Only Version 0 handled in DREF box\n");
|
||
return false;
|
||
}
|
||
|
||
if (0 != pStream->Read(3)) // Flags = 0
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with flag in DREF box. Expected flag 0\n");
|
||
return 1;
|
||
}
|
||
|
||
int nEntryCount = pStream->Read(4); // entry-count
|
||
|
||
pTrack->nNumUrl = 0;
|
||
pTrack->nNumUrn = 0;
|
||
|
||
for (int nIndex = 0; nIndex < nEntryCount; nIndex++)
|
||
{
|
||
pStream->Skip(4);
|
||
int nMarker = pStream->Read(4);
|
||
|
||
if (MJ2_URL == nMarker)
|
||
{
|
||
pStream->Skip(-8);
|
||
pTrack->nNumUrl++;
|
||
|
||
if (!Mj2_ReadURL(pTrack, pStream, pTrack->nNumUrl))
|
||
return false;
|
||
|
||
}
|
||
else if (MJ2_URN == nMarker)
|
||
{
|
||
pStream->Skip(-8);
|
||
pTrack->nNumUrn++;
|
||
|
||
if (!Mj2_ReadURN(pTrack, pStream, pTrack->nNumUrn))
|
||
return false;
|
||
}
|
||
else
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with in DREF box. Expected URN or URL box\n");
|
||
return false;
|
||
}
|
||
|
||
}
|
||
|
||
|
||
if (pStream->Tell() - oBox.nInitPos != oBox.nLength)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with DREF Box size\n");
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
static bool Mj2_ReadDINF(Mj2_TrackParams* pTrack, CReader * pStream)
|
||
{
|
||
Mj2_Box oBox;
|
||
Mj2_ReadBoxHeader(&oBox, pStream);
|
||
if (MJ2_DINF != oBox.nType)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Expected DINF Marker\n");
|
||
return false;
|
||
}
|
||
|
||
if (!Mj2_ReadDREF(pTrack, pStream))
|
||
return false;
|
||
|
||
if (pStream->Tell() - oBox.nInitPos != oBox.nLength)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with DINF Box size\n");
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
static void Mj2_DecompatTTS(Mj2_TrackParams* pTrack)
|
||
{
|
||
pTrack->unNumSamples = 0;
|
||
for (int nIndex = 0; nIndex < pTrack->nNumTimeToSample; nIndex++)
|
||
{
|
||
pTrack->unNumSamples += pTrack->pTimeToSample[nIndex].nSampleCount;
|
||
}
|
||
|
||
pTrack->pSample = (Mj2_Sample*)Malloc(pTrack->unNumSamples * sizeof(Mj2_Sample));
|
||
for (int nIndexTTS = 0; nIndexTTS < pTrack->nNumTimeToSample; nIndexTTS++)
|
||
{
|
||
for (int nIndexSample = 0; nIndexSample < pTrack->pTimeToSample[nIndexTTS].nSampleCount; nIndexSample++)
|
||
{
|
||
pTrack->pSample[nIndexSample].unSampleDelta = pTrack->pTimeToSample[nIndexTTS].nSampleDelta;
|
||
}
|
||
}
|
||
}
|
||
static void Mj2_DecompatSTSC(Mj2_TrackParams* pTrack)
|
||
{
|
||
if (1 == pTrack->nNumSamplesToChunk)
|
||
{
|
||
pTrack->unNumChunks = (unsigned int)ceil((double)pTrack->unNumSamples / (double)pTrack->pSampleToChunk[0].nSamplesPerChunk);
|
||
pTrack->pChunk = (Mj2_Chunk*)Malloc(pTrack->unNumChunks * sizeof(Mj2_Chunk));
|
||
|
||
for (unsigned int unIndex = 0; unIndex < pTrack->unNumChunks; unIndex++)
|
||
{
|
||
pTrack->pChunk[unIndex].nNumSamples = pTrack->pSampleToChunk[0].nSamplesPerChunk;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
pTrack->pChunk = (Mj2_Chunk*)Malloc(pTrack->unNumChunks * sizeof(Mj2_Chunk));
|
||
pTrack->unNumChunks = 0;
|
||
|
||
int nSampleNum = 0;
|
||
for (int nIndexSTC = 0; nIndexSTC < pTrack->nNumSamplesToChunk - 1; nIndexSTC++)
|
||
{
|
||
for (int nIndexChunk = pTrack->pSampleToChunk[nIndexSTC].nFirstChunk - 1; nIndexChunk < pTrack->pSampleToChunk[nIndexSTC + 1].nFirstChunk - 1; nIndexChunk++)
|
||
{
|
||
pTrack->pChunk[nIndexChunk].nNumSamples = pTrack->pSampleToChunk[nIndexSTC].nSamplesPerChunk;
|
||
pTrack->unNumChunks++;
|
||
nSampleNum += pTrack->pChunk[nIndexChunk].nNumSamples;
|
||
}
|
||
}
|
||
|
||
long unNumChunksOld = pTrack->unNumChunks;
|
||
pTrack->unNumChunks += (int)(pTrack->unNumSamples - nSampleNum) / pTrack->pSampleToChunk[pTrack->nNumSamplesToChunk - 1].nSamplesPerChunk;
|
||
for (unsigned int unIndex = pTrack->pSampleToChunk[pTrack->nNumSamplesToChunk - 1].nFirstChunk - 1; unIndex < pTrack->unNumChunks; unIndex++)
|
||
{
|
||
pTrack->pChunk[unIndex].nNumSamples = pTrack->pSampleToChunk[pTrack->nNumSamplesToChunk - 1].nSamplesPerChunk;
|
||
}
|
||
Mj2_Chunk* pChunk_new = (Mj2_Chunk*)Malloc(pTrack->unNumChunks * sizeof(Mj2_Chunk));
|
||
if (pChunk_new)
|
||
{
|
||
memcpy(pChunk_new, pTrack->pChunk, unNumChunksOld * sizeof(Mj2_Chunk));
|
||
Free(pTrack->pChunk);
|
||
pTrack->pChunk = pChunk_new;
|
||
}
|
||
else
|
||
{
|
||
}
|
||
}
|
||
}
|
||
static void Mj2_DecompatSTCO(Mj2_TrackParams* pTrack)
|
||
{
|
||
for (unsigned int unChunk = 0; unChunk < pTrack->unNumChunks; unChunk++)
|
||
{
|
||
int nIntraChunkOffset = 0;
|
||
int nSample2 = 0;
|
||
for (int nSample = 0; nSample < pTrack->pChunk[unChunk].nNumSamples; nSample++)
|
||
{
|
||
pTrack->pSample[nSample2].unOffset = nIntraChunkOffset + pTrack->pChunk[unChunk].nOffset;
|
||
nIntraChunkOffset += pTrack->pSample[nSample2].unSampleSize;
|
||
nSample2++;
|
||
}
|
||
}
|
||
}
|
||
|
||
static bool Mj2_ReadSTTS(Mj2_TrackParams* pTrack, CReader * pStream)
|
||
{
|
||
Mj2_Box oBox;
|
||
Mj2_ReadBoxHeader(&oBox, pStream);
|
||
if (MJ2_STTS != oBox.nType)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Expected STTS Marker\n");
|
||
return false;
|
||
}
|
||
|
||
if (0 != pStream->Read(1)) // Version
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Only Version 0 handled in STTS box\n");
|
||
return false;
|
||
}
|
||
|
||
if (0 != pStream->Read(3)) // Flags = 0
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with flag in STTS box. Expected flag 0\n");
|
||
return false;
|
||
}
|
||
|
||
pTrack->nNumTimeToSample = pStream->Read(4); // entry-count
|
||
pTrack->pTimeToSample = (Mj2_TimeToSample*)Malloc(pTrack->nNumTimeToSample * sizeof(Mj2_TimeToSample));
|
||
|
||
for (int nIndex = 0; nIndex < pTrack->nNumTimeToSample; nIndex++)
|
||
{
|
||
pTrack->pTimeToSample[nIndex].nSampleCount = pStream->Read(4); // sample-count
|
||
pTrack->pTimeToSample[nIndex].nSampleDelta = pStream->Read(4); // sample-delta
|
||
}
|
||
|
||
Mj2_DecompatTTS(pTrack);
|
||
|
||
if (pStream->Tell() - oBox.nInitPos != oBox.nLength)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with STTS Box size\n");
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
static bool Mj2_ReadSTSZ(Mj2_TrackParams* pTrack, CReader * pStream)
|
||
{
|
||
Mj2_Box oBox;
|
||
Mj2_ReadBoxHeader(&oBox, pStream);
|
||
if (MJ2_STSZ != oBox.nType)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Expected STSZ Marker\n");
|
||
return false;
|
||
}
|
||
|
||
if (0 != pStream->Read(1)) // Version = 0
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Only Version 0 handled in STSZ box\n ");
|
||
return false;
|
||
}
|
||
|
||
if (0 != pStream->Read(3)) // Flags = 0
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with flag in STSZ box. Expected flag 0\n ");
|
||
return false;
|
||
}
|
||
|
||
int nSampleSize = pStream->Read(4); // SampleSize
|
||
|
||
if (0 != nSampleSize) // У всех самплов одинаковый размер
|
||
{
|
||
pTrack->unSameSampleSize = 1;
|
||
|
||
for (unsigned int unIndex = 0; unIndex < pTrack->unNumSamples; unIndex++)
|
||
{
|
||
pTrack->pSample[unIndex].unSampleSize = nSampleSize;
|
||
}
|
||
pStream->Skip(4); // sample-count
|
||
}
|
||
else
|
||
{
|
||
pTrack->unSameSampleSize = 0;
|
||
|
||
if (pTrack->unNumSamples != pStream->Read(4)) // sample-count
|
||
{
|
||
Event_Message(EVT_ERROR, "Error in STSZ box. Expected that sample-count is number of samples in track\n ");
|
||
return false;
|
||
}
|
||
for (unsigned int unIndex = 0; unIndex < pTrack->unNumSamples; unIndex++)
|
||
{
|
||
pTrack->pSample[unIndex].unSampleSize = pStream->Read(4); // entry-size
|
||
}
|
||
}
|
||
|
||
if (pStream->Tell() - oBox.nInitPos != oBox.nLength)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with STSZ Box size\n ");
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
|
||
}
|
||
|
||
static bool Mj2_ReadSTSC(Mj2_TrackParams* pTrack, CReader * pStream)
|
||
{
|
||
Mj2_Box oBox;
|
||
Mj2_ReadBoxHeader(&oBox, pStream);
|
||
if (MJ2_STSC != oBox.nType)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Expected STSC Marker\n");
|
||
return false;
|
||
}
|
||
|
||
if (0 != pStream->Read(1)) // Version = 0
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Only Version 0 handled in STSC box\n");
|
||
return false;
|
||
}
|
||
|
||
if (0 != pStream->Read(3)) // Flags = 0
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with flag in STSC box. Expected flag 0\n");
|
||
return false;
|
||
}
|
||
|
||
pTrack->nNumSamplesToChunk = pStream->Read(4); // entry-count
|
||
pTrack->pSampleToChunk = (Mj2_SampleToChunk*)Malloc(pTrack->nNumSamplesToChunk * sizeof(Mj2_SampleToChunk));
|
||
|
||
for (int nIndex = 0; nIndex < pTrack->nNumSamplesToChunk; nIndex++)
|
||
{
|
||
pTrack->pSampleToChunk[nIndex].nFirstChunk = pStream->Read(4); // first-chunk
|
||
pTrack->pSampleToChunk[nIndex].nSamplesPerChunk = pStream->Read(4); // samples-per-chunk
|
||
pTrack->pSampleToChunk[nIndex].nSampleDescriptionIndex = pStream->Read(4); // sample-description-index
|
||
}
|
||
|
||
Mj2_DecompatSTSC(pTrack); // decompact sample to chunk box
|
||
|
||
if (pStream->Tell() - oBox.nInitPos != oBox.nLength)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with STSC Box size\n");
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
static bool Mj2_ReadSTCO(Mj2_TrackParams* pTrack, CReader * pStream)
|
||
{
|
||
// TO DO: Сделать чтение 'co64'
|
||
Mj2_Box oBox;
|
||
Mj2_ReadBoxHeader(&oBox, pStream);
|
||
if (MJ2_STCO != oBox.nType)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Expected STCO Marker\n");
|
||
return false;
|
||
}
|
||
|
||
if (0 != pStream->Read(1)) // Version = 0
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Only Version 0 handled in STCO box\n");
|
||
return false;
|
||
}
|
||
|
||
if (0 != pStream->Read(3)) // Flags = 0
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with flag in STCO box. Expected flag 0\n");
|
||
return false;
|
||
}
|
||
|
||
if (pStream->Read(4) != pTrack->unNumChunks) // entry-count
|
||
{
|
||
Event_Message(EVT_ERROR, "Error in STCO box: expecting same amount of entry-count as chunks \n");
|
||
return false;
|
||
}
|
||
else
|
||
{
|
||
for (unsigned int unIndex = 0; unIndex < pTrack->unNumChunks; unIndex++)
|
||
{
|
||
pTrack->pChunk[unIndex].nOffset = pStream->Read(4); // chunk-offset
|
||
}
|
||
}
|
||
|
||
Mj2_DecompatSTCO(pTrack);
|
||
|
||
if (pStream->Tell() - oBox.nInitPos != oBox.nLength)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with STCO Box size\n");
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
static bool Mj2_ReadFIEL(Mj2_TrackParams* pTrack, CReader * pStream)
|
||
{
|
||
Mj2_Box oBox;
|
||
Mj2_ReadBoxHeader(&oBox, pStream);
|
||
if (MJ2_FIEL != oBox.nType)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Expected FIEL Marker\n");
|
||
return false;
|
||
}
|
||
|
||
pTrack->unFieldCount = pStream->Read(1);
|
||
pTrack->unFieldOrder = pStream->Read(1);
|
||
|
||
if (pStream->Tell() - oBox.nInitPos != oBox.nLength)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with FIEL Box size\n");
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
static bool Mj2_ReadJP2P(Mj2_TrackParams* pTrack, CReader * pStream)
|
||
{
|
||
Mj2_Box oBox;
|
||
Mj2_ReadBoxHeader(&oBox, pStream);
|
||
if (MJ2_JP2P != oBox.nType)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Expected JP2P Marker\n");
|
||
return false;
|
||
}
|
||
|
||
if (0 != pStream->Read(1)) // Version = 0
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Only Version 0 handled in JP2P box\n");
|
||
return false;
|
||
}
|
||
|
||
if (0 != pStream->Read(3)) // Flags = 0
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with flag in JP2P box. Expected flag 0\n");
|
||
return false;
|
||
}
|
||
|
||
pTrack->nNumBr = (oBox.nLength - 12) / 4;
|
||
pTrack->pBr = (unsigned int*)Malloc(pTrack->nNumBr * sizeof(unsigned int));
|
||
|
||
for (int nIndex = 0; nIndex < pTrack->nNumBr; nIndex++)
|
||
{
|
||
pTrack->pBr[nIndex] = pStream->Read(4);
|
||
}
|
||
|
||
if (pStream->Tell() - oBox.nInitPos != oBox.nLength)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with JP2P Box size\n");
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
static bool Mj2_ReadJP2X(Mj2_TrackParams* pTrack, CReader * pStream)
|
||
{
|
||
Mj2_Box oBox;
|
||
Mj2_ReadBoxHeader(&oBox, pStream);
|
||
if (MJ2_JP2X != oBox.nType)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Expected JP2X Marker\n");
|
||
return false;
|
||
}
|
||
|
||
pTrack->unNumJp2x = (oBox.nLength - 8);
|
||
pTrack->pJp2xData = (unsigned char*)Malloc(pTrack->unNumJp2x * sizeof(unsigned char));
|
||
|
||
for (unsigned int unIndex = 0; unIndex < pTrack->unNumJp2x; unIndex++)
|
||
{
|
||
pTrack->pJp2xData[unIndex] = pStream->Read(1);
|
||
}
|
||
|
||
if (pStream->Tell() - oBox.nInitPos != oBox.nLength)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with JP2X Box size\n");
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
static bool Mj2_ReadJSUB(Mj2_TrackParams* pTrack, CReader * pStream)
|
||
{
|
||
Mj2_Box oBox;
|
||
Mj2_ReadBoxHeader(&oBox, pStream);
|
||
if (MJ2_JSUB != oBox.nType)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Expected JSUB Marker\n");
|
||
return false;
|
||
}
|
||
|
||
pTrack->unHsub = pStream->Read(1);
|
||
pTrack->unVsub = pStream->Read(1);
|
||
pTrack->unHoff = pStream->Read(1);
|
||
pTrack->unVoff = pStream->Read(1);
|
||
|
||
if (pStream->Tell() - oBox.nInitPos != oBox.nLength)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with JSUB Box size\n");
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
static bool Mj2_ReadORFO(Mj2_TrackParams* pTrack, CReader * pStream)
|
||
{
|
||
Mj2_Box oBox;
|
||
Mj2_ReadBoxHeader(&oBox, pStream);
|
||
if (MJ2_ORFO != oBox.nType)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Expected ORFO Marker\n");
|
||
return false;
|
||
}
|
||
|
||
pTrack->unOr_FieldCount = pStream->Read(1);
|
||
pTrack->unOr_FieldOrder = pStream->Read(1);
|
||
|
||
if (pStream->Tell() - oBox.nInitPos != oBox.nLength)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with ORFO Box size\n");
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
static bool Mj2_ReadSMJ2(Mj2_TrackParams* pTrack, Image* pImage, CReader * pStream)
|
||
{
|
||
Mj2_Box oBox;
|
||
Mj2_ReadBoxHeader(&oBox, pStream);
|
||
if (MJ2_MJ2 != oBox.nType)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error in SMJ2 box: Expected MJ2 Marker\n");
|
||
return false;
|
||
}
|
||
|
||
if (0 != pStream->Read(1)) // Version = 0
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Only Version 0 handled in MJP2 box\n");
|
||
return false;
|
||
}
|
||
|
||
if (0 != pStream->Read(3)) // Flags = 0
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with flag in MJP2 box. Expected flag 0\n");
|
||
return false;
|
||
}
|
||
|
||
pStream->Skip(4);
|
||
pStream->Skip(2); // Pre-defined
|
||
pStream->Skip(2); // Reserved
|
||
pStream->Skip(4); // Pre-defined
|
||
pStream->Skip(4); // Pre-defined
|
||
pStream->Skip(4); // Pre-defined
|
||
|
||
pTrack->nWidth = pStream->Read(2); // Width
|
||
pTrack->nHeight = pStream->Read(2); // Height
|
||
pTrack->nHorResolution = pStream->Read(4); // Horizontal resolution
|
||
pTrack->nVerResolution = pStream->Read(4); // Vertical resolution
|
||
|
||
pStream->Skip(4); // Reserved
|
||
pStream->Skip(2); // Pre-defined = 1
|
||
|
||
pTrack->anCompressorName[0] = pStream->Read(4); // Compressor Name
|
||
pTrack->anCompressorName[1] = pStream->Read(4); //
|
||
pTrack->anCompressorName[2] = pStream->Read(4); //
|
||
pTrack->anCompressorName[3] = pStream->Read(4); //
|
||
pTrack->anCompressorName[4] = pStream->Read(4); //
|
||
pTrack->anCompressorName[5] = pStream->Read(4); //
|
||
pTrack->anCompressorName[6] = pStream->Read(4); //
|
||
pTrack->anCompressorName[7] = pStream->Read(4); //
|
||
|
||
pTrack->nDepth = pStream->Read(2); // Depth
|
||
|
||
pStream->Skip(2); // Pre-defined = -1
|
||
|
||
pTrack->unNumJp2x = 0;
|
||
pTrack->unFieldCount = 1;
|
||
pTrack->unFieldOrder = 0;
|
||
pTrack->unOr_FieldCount = 1;
|
||
pTrack->unOr_FieldOrder = 0;
|
||
|
||
if (!Jp2_ReadJP2H(&pTrack->oJp2, pStream))
|
||
{
|
||
Event_Message(EVT_ERROR, "Error reading JP2H Box\n");
|
||
return false;
|
||
}
|
||
|
||
pTrack->oJp2.pComponents = (Jp2Component*)Malloc(pTrack->oJp2.nComponentsCount * sizeof(Jp2Component));
|
||
pTrack->oJp2.pCompList = (unsigned int*)Malloc(sizeof(unsigned int));
|
||
|
||
pTrack->nNumBr = 0;
|
||
pTrack->unNumJp2x = 0;
|
||
|
||
for (int nIndex = 0; pStream->Tell() - oBox.nInitPos < oBox.nLength; nIndex++)
|
||
{
|
||
Mj2_Box oBox2;
|
||
Mj2_ReadBoxHeader(&oBox2, pStream);
|
||
pStream->Seek(oBox2.nInitPos);
|
||
|
||
switch (oBox2.nType)
|
||
{
|
||
case MJ2_FIEL:
|
||
|
||
if (!Mj2_ReadFIEL(pTrack, pStream))
|
||
return false;
|
||
|
||
break;
|
||
|
||
case MJ2_JP2P:
|
||
|
||
if (!Mj2_ReadJP2P(pTrack, pStream))
|
||
return false;
|
||
|
||
break;
|
||
|
||
case MJ2_JP2X:
|
||
|
||
if (!Mj2_ReadJP2X(pTrack, pStream))
|
||
return false;
|
||
|
||
break;
|
||
|
||
case MJ2_JSUB:
|
||
|
||
if (!Mj2_ReadJSUB(pTrack, pStream))
|
||
return false;
|
||
|
||
break;
|
||
|
||
case MJ2_ORFO:
|
||
|
||
if (!Mj2_ReadORFO(pTrack, pStream))
|
||
return false;
|
||
|
||
break;
|
||
|
||
default:
|
||
|
||
Event_Message(EVT_ERROR, "Error with MJP2 Box size\n");
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
|
||
static bool Mj2_ReadSTSD(Mj2_TrackParams* pTrack, Image* pImage, CReader * pStream)
|
||
{
|
||
Mj2_Box oBox;
|
||
Mj2_ReadBoxHeader(&oBox, pStream);
|
||
if (MJ2_STSD != oBox.nType)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Expected STSD Marker\n");
|
||
return false;
|
||
}
|
||
|
||
if (0 != pStream->Read(1)) // Version = 0
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Only Version 0 handled in STSD box\n");
|
||
return false;
|
||
}
|
||
|
||
if (0 != pStream->Read(3)) // Flags = 0
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with flag in STSD box. Expected flag 0\n");
|
||
return false;
|
||
}
|
||
|
||
int nEntryCount = pStream->Read(4);
|
||
|
||
if (0 == pTrack->nTrackType)
|
||
{
|
||
for (int nIndex = 0; nIndex < nEntryCount; nIndex++)
|
||
{
|
||
if (!Mj2_ReadSMJ2(pTrack, pImage, pStream))
|
||
return false;
|
||
}
|
||
}
|
||
else if (1 == pTrack->nTrackType)
|
||
{
|
||
// TO DO: Релизовать
|
||
int nSkipLen = pStream->Read(4);
|
||
pStream->Skip(nSkipLen - 4);
|
||
}
|
||
else if (2 == pTrack->nTrackType)
|
||
{
|
||
// TO DO: Реализовать
|
||
int nSkipLen = pStream->Read(4);
|
||
pStream->Skip(nSkipLen - 4);
|
||
}
|
||
|
||
|
||
if (pStream->Tell() - oBox.nInitPos != oBox.nLength)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with STSD Box size\n");
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
static bool Mj2_ReadSTBL(Mj2_TrackParams* pTrack, Image* pImage, CReader * pStream)
|
||
{
|
||
Mj2_Box oBox;
|
||
Mj2_ReadBoxHeader(&oBox, pStream);
|
||
if (MJ2_STBL != oBox.nType)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Expected STBL Marker\n");
|
||
return false;
|
||
}
|
||
|
||
if (!Mj2_ReadSTSD(pTrack, pImage, pStream))
|
||
return false;
|
||
if (!Mj2_ReadSTTS(pTrack, pStream))
|
||
return false;
|
||
if (!Mj2_ReadSTSC(pTrack, pStream))
|
||
return false;
|
||
if (!Mj2_ReadSTSZ(pTrack, pStream))
|
||
return false;
|
||
if (!Mj2_ReadSTCO(pTrack, pStream))
|
||
return false;
|
||
|
||
if (pStream->Tell() - oBox.nInitPos != oBox.nLength)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with STBL Box size\n");
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
static bool Mj2_ReadMINF(Mj2_TrackParams* pTrack, Image* pImage, CReader * pStream)
|
||
{
|
||
Mj2_Box oBox;
|
||
Mj2_ReadBoxHeader(&oBox, pStream);
|
||
|
||
if (MJ2_MINF != oBox.nType)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Expected MINF Marker\n");
|
||
return false;
|
||
}
|
||
|
||
pStream->Skip(4);
|
||
|
||
unsigned int unBoxType = pStream->Read(4);
|
||
pStream->Skip(-8);
|
||
|
||
if (MJ2_VMHD == unBoxType)
|
||
{
|
||
if (!Mj2_ReadVMHD(pTrack, pStream))
|
||
return false;
|
||
}
|
||
else if (MJ2_SMHD == unBoxType)
|
||
{
|
||
if (!Mj2_ReadSMHD(pTrack, pStream))
|
||
return false;
|
||
}
|
||
else if (MJ2_HMHD == unBoxType)
|
||
{
|
||
if (!Mj2_ReadHMHD(pTrack, pStream))
|
||
return false;
|
||
}
|
||
else
|
||
{
|
||
Event_Message(EVT_ERROR, "Error in MINF box expected vmhd, smhd or hmhd\n");
|
||
return false;
|
||
}
|
||
|
||
if (!Mj2_ReadDINF(pTrack, pStream))
|
||
return false;
|
||
|
||
if (!Mj2_ReadSTBL(pTrack, pImage, pStream))
|
||
return false;
|
||
|
||
if (pStream->Tell() - oBox.nInitPos != oBox.nLength)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with MINF Box size\n");
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
static bool Mj2_ReadMDIA(Mj2_TrackParams* pTrack, Image* pImage, CReader * pStream)
|
||
{
|
||
Mj2_Box oBox;
|
||
Mj2_ReadBoxHeader(&oBox, pStream);
|
||
|
||
if (MJ2_MDIA != oBox.nType)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Expected MDIA Marker\n");
|
||
return false;
|
||
}
|
||
|
||
if (!Mj2_ReadMDHD(pTrack, pStream))
|
||
return false;
|
||
|
||
if (!Mj2_ReadHDLR(pTrack, pStream))
|
||
return false;
|
||
|
||
if (!Mj2_ReadMINF(pTrack, pImage, pStream))
|
||
return false;
|
||
|
||
if (pStream->Tell() - oBox.nInitPos != oBox.nLength)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with MDIA Box size\n");
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
static bool Mj2_ReadTRAK(Mj2_TrackParams* pTrack, Image* pImage, CReader * pStream)
|
||
{
|
||
Mj2_Box oBox;
|
||
Mj2_ReadBoxHeader(&oBox, pStream);
|
||
if (MJ2_TRAK != oBox.nType)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Expected TRAK Marker\n");
|
||
return false;
|
||
}
|
||
|
||
if (!Mj2_ReadTKHD(pTrack, pStream))
|
||
return false;
|
||
|
||
if (!Mj2_ReadMDIA(pTrack, pImage, pStream))
|
||
return false;
|
||
|
||
if (pStream->Tell() - oBox.nInitPos != oBox.nLength)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with TRAK Box\n");
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
static bool Mj2_ReadMOOV(Mj2_Movie* pMovie, CReader * pStream, Image* pImage, Mj2_Box oBox)
|
||
{
|
||
if (MJ2_MOOV != oBox.nType)
|
||
{
|
||
Event_Message(EVT_ERROR, "Error: Expected FTYP Marker\n");
|
||
return false;
|
||
}
|
||
|
||
if (!Mj2_ReadMVHD(pMovie, pStream))
|
||
return false;
|
||
|
||
pMovie->pTrack = (Mj2_TrackParams*)Malloc((pMovie->nNextTrackId - 1) * sizeof(Mj2_TrackParams));
|
||
|
||
Mj2_Box oBox2;
|
||
|
||
for (unsigned int unIndex = 0; pStream->Tell() - oBox.nInitPos < oBox.nLength; unIndex++)
|
||
{
|
||
Mj2_TrackParams* pTrack = &pMovie->pTrack[unIndex];
|
||
pTrack->pCodecInfo = pMovie->pCodecInfo;
|
||
|
||
Mj2_ReadBoxHeader(&oBox2, pStream);
|
||
|
||
if (MJ2_TRAK == oBox2.nType)
|
||
{
|
||
pStream->Seek(oBox2.nInitPos);
|
||
if (!Mj2_ReadTRAK(pTrack, pImage, pStream))
|
||
return false;
|
||
|
||
if (0 == pTrack->nTrackType)
|
||
pMovie->nNumVtk++;
|
||
else if (1 == pTrack->nTrackType)
|
||
pMovie->nNumStk++;
|
||
else if (2 == pTrack->nTrackType)
|
||
pMovie->nNumHtk++;
|
||
|
||
}
|
||
else if (MJ2_MVEX == oBox2.nType)
|
||
{
|
||
pStream->Seek(oBox2.nInitPos);
|
||
pStream->Skip(oBox2.nLength);
|
||
unIndex--;
|
||
}
|
||
else
|
||
{
|
||
Event_Message(EVT_ERROR, "Error with MOOV Box: Expected TRAK or MVEX box\n");
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
static bool Mj2_ReadStruct(Mj2_Movie* pMovie, CReader * pStream, Image **ppImage)
|
||
{
|
||
if (!Mj2_ReadJP(pStream))
|
||
return false;
|
||
|
||
if (!Mj2_ReadFTYP(pMovie, pStream))
|
||
return false;
|
||
|
||
Mj2_Box oBox;
|
||
oBox.nType = 0;
|
||
Mj2_ReadBoxHeader(&oBox, pStream);
|
||
|
||
while (MJ2_MOOV != oBox.nType)
|
||
{
|
||
switch (oBox.nType)
|
||
{
|
||
case MJ2_MDAT:
|
||
|
||
// TO DO: Связать данные в MDAT с данными MOOV
|
||
if (!Mj2_ReadMDAT(pMovie, pStream, ppImage, oBox))
|
||
return false;
|
||
|
||
break;
|
||
|
||
case MJ2_MOOF:
|
||
case MJ2_FREE:
|
||
case MJ2_SKIP:
|
||
|
||
pStream->Skip(oBox.nLength);
|
||
if (pStream->GetLeftSize() < 0)
|
||
return false;
|
||
|
||
break;
|
||
|
||
default:
|
||
|
||
Event_Message(EVT_ERROR, "Unknown box in MJ2 stream\n");
|
||
pStream->Skip(oBox.nLength);
|
||
if (pStream->GetLeftSize() < 0)
|
||
return false;
|
||
break;
|
||
}
|
||
|
||
if (!Mj2_ReadBoxHeader(&oBox, pStream))
|
||
return false;
|
||
}
|
||
|
||
Image oImage;
|
||
if (!Mj2_ReadMOOV(pMovie, pStream, &oImage, oBox))
|
||
return false;
|
||
|
||
return true;
|
||
}
|
||
|
||
//-------------------------------------------------------------------------------------------------------------------------------
|
||
// Декодирование потока Mj2
|
||
//-------------------------------------------------------------------------------------------------------------------------------
|
||
void Mj2_DestroyDecompress(Mj2_Movie* pMovie)
|
||
{
|
||
if (pMovie)
|
||
{
|
||
Mj2_TrackParams* pTrack = NULL;
|
||
|
||
if (pMovie->pCodecInfo->pJ2k)
|
||
J2k_DestroyCompress(pMovie->pJ2k);
|
||
|
||
//if ( pMovie->nCompListLength != 0 )
|
||
Free(pMovie->pCompList);
|
||
|
||
for (int nIndex = 0; nIndex < pMovie->nNumVtk + pMovie->nNumStk + pMovie->nNumHtk; nIndex++)
|
||
{
|
||
pTrack = &pMovie->pTrack[nIndex];
|
||
|
||
//if ( pTrack->nNameSize != 0 )
|
||
Free(pTrack->sName);
|
||
if (pTrack->nTrackType == 0)
|
||
{
|
||
Free(pTrack->oJp2.pComponents);
|
||
Free(pTrack->oJp2.pCompList);
|
||
Free(pTrack->pJp2xData);
|
||
}
|
||
//if ( pTrack->nNumUrl != 0 )
|
||
Free(pTrack->pUrl);
|
||
//if ( pTrack->nNumUrn != 0 )
|
||
Free(pTrack->pUrn);
|
||
//if ( pTrack->nNumBr != 0 )
|
||
Free(pTrack->pBr);
|
||
//if ( pTrack->nNumTimeToSample != 0 )
|
||
Free(pTrack->pTimeToSample);
|
||
//if ( pTrack->unNumChunks != 0 )
|
||
Free(pTrack->pChunk);
|
||
//if ( pTrack->nNumSamplesToChunk != 0 )
|
||
Free(pTrack->pSampleToChunk);
|
||
//if ( pTrack->unNumSamples != 0 )
|
||
Free(pTrack->pSample);
|
||
|
||
Free(pTrack);
|
||
}
|
||
|
||
Free(pMovie);
|
||
}
|
||
}
|
||
|
||
|
||
Mj2_Movie* Mj2_CreateDecompress(PCommon pCodecInfo)
|
||
{
|
||
Mj2_Movie* pMj2 = (Mj2_Movie*)Malloc(sizeof(Mj2_Movie));
|
||
if (pMj2)
|
||
{
|
||
pMj2->pCodecInfo = (PCommon)pCodecInfo;
|
||
pMj2->pJ2k = J2k_CreateDecompress(pCodecInfo);
|
||
|
||
if (NULL == pMj2->pJ2k)
|
||
{
|
||
pCodecInfo->nErrorCode = JP2_ERROR_NOT_ENOUGH_MEMORY;
|
||
Mj2_DestroyDecompress(pMj2);
|
||
return NULL;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
pCodecInfo->nErrorCode = JP2_ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
|
||
return pMj2;
|
||
}
|
||
|
||
void Mj2_SetupDecoder(Mj2_Movie* pMovie, DecoderParams *pParameters)
|
||
{
|
||
pMovie->nNumVtk = 0;
|
||
pMovie->nNumStk = 0;
|
||
pMovie->nNumHtk = 0;
|
||
|
||
J2k_SetupDecoder((J2kCodestream*)pMovie->pCodecInfo->pJ2k, pParameters);
|
||
}
|
||
|
||
Image* Mj2_Decode(Mj2_Movie* pMovie, CReader * pStream)
|
||
{
|
||
if (!pMovie || !pStream)
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
PCommon pCodecInfo = pMovie->pCodecInfo;
|
||
|
||
Image *pImage = NULL;
|
||
// Декодируем JP2
|
||
if (!Mj2_ReadStruct(pMovie, pStream, &pImage))
|
||
{
|
||
Event_Message(EVT_ERROR, "Failed to decode jp2 structure\n");
|
||
return NULL;
|
||
}
|
||
|
||
return pImage;
|
||
}
|
||
} |