JD2022-TU1/main/extern/mkclean/custom/libmatroska2/matroskablock.c

376 lines
16 KiB
C

/*
* $Id: matroskablock.c 728 2011-04-02 15:06:52Z robux4 $
* Copyright (c) 2010-2011, Matroska (non-profit organisation)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the Matroska assocation nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY the Matroska association ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL The Matroska Foundation BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "matroska/matroska.h"
#include "matroska/matroska_sem.h"
#include "matroska/matroska_internal.h"
#if defined(CONFIG_CODEC_HELPER)
#include "ivorbiscodec.h"
#include "codec_internal.h"
#include "misc.h"
#endif
static int A_MPEG_freq[4][4] =
{
// v2.5 * v2 v1
{11025, 0, 22050, 44100},
{12000, 0, 24000, 48000},
{ 8000, 0, 16000, 32000},
{ 0, 0, 0, 0}
};
static int A_MPEG_samples[4][4] =
{
// v2.5 * v2 v1
{ 0, 0, 0, 0}, // unknown layer
{ 576, 0, 576, 1152}, // layer III
{1152, 0, 1152, 1152}, // layer II
{ 384, 0, 384, 384} // layer I
};
static const int A_AC3_freq[3][4] =
{
{48000, 44100, 32000, 0}, // EEEE<=8
{24000, 22050, 16000, 0}, // EEEE=9
{12000, 11025, 8000, 0}, // EEEE=10
};
static const int A_EAC3_freq[6] = { 48000, 44100, 32000, 24000, 22050, 16000 };
static const int A_EAC3_samples[4] = { 256, 512, 768, 1536 };
static const int A_DTS_freq[16] = {
0, 8000, 16000, 32000, 0, 0, 11025, 22050, 44100, 0, 0, 12000, 24000, 48000, 0, 0
};
err_t MATROSKA_BlockProcessFrameDurations(matroska_block *Block, stream *Input)
{
ebml_master *Track=NULL;
ebml_element *Elt;
tchar_t CodecID[MAXPATH];
err_t Err;
bool_t ReadData;
uint8_t *Cursor;
size_t Frame;
int Version, Layer, SampleRate, Samples, fscod, fscod2;
Err = Node_GET(Block,MATROSKA_BLOCK_READ_TRACK,&Track);
if (Err==ERR_NONE)
{
assert(Track!=NULL);
Elt = EBML_MasterFindChild(Track,&MATROSKA_ContextTrackType);
if (!Elt || EBML_IntegerValue((ebml_integer*)Elt)!=TRACK_TYPE_AUDIO) // other track types not supported for now
Err = ERR_INVALID_DATA;
else
{
if (Block->FirstFrameLocation==0)
Err = ERR_READ;
else
{
Elt = EBML_MasterFindChild(Track,&MATROSKA_ContextCodecID);
if (!Elt) // missing codec ID
Err = ERR_INVALID_DATA;
else
{
EBML_StringGet((ebml_string*)Elt,CodecID,TSIZEOF(CodecID));
ReadData = 0;
if (!ArraySize(&Block->Data))
{
Err = MATROSKA_BlockReadData(Block,Input);
if (Err!=ERR_NONE)
goto exit;
ReadData = 1;
}
if (tcsisame_ascii(CodecID,T("A_MPEG/L3")) || tcsisame_ascii(CodecID,T("A_MPEG/L2")) || tcsisame_ascii(CodecID,T("A_MPEG/L1")))
{
Block->IsKeyframe = 1; // safety
ArrayResize(&Block->Durations,sizeof(timecode_t)*ARRAYCOUNT(Block->SizeList,int32_t),0);
Cursor = ARRAYBEGIN(Block->Data,uint8_t);
for (Frame=0;Frame<ARRAYCOUNT(Block->SizeList,int32_t);++Frame)
{
Version = (Cursor[1] >> 3) & 3;
Layer = (Cursor[1] >> 1) & 3;
SampleRate = (Cursor[2] >> 2) & 3;
Samples = A_MPEG_samples[Layer][Version];
SampleRate = A_MPEG_freq[SampleRate][Version];
if (SampleRate!=0 && Samples!=0)
ARRAYBEGIN(Block->Durations,timecode_t)[Frame] = Scale64(1000000000,Samples,SampleRate);
else
{
Err = ERR_INVALID_DATA;
ARRAYBEGIN(Block->Durations,timecode_t)[Frame] = INVALID_TIMECODE_T;
//goto exit;
}
Cursor += ARRAYBEGIN(Block->SizeList,int32_t)[Frame];
}
}
else if (tcsisame_ascii(CodecID,T("A_AC3")))
{
Block->IsKeyframe = 1; // safety
ArrayResize(&Block->Durations,sizeof(timecode_t)*ARRAYCOUNT(Block->SizeList,int32_t),0);
Cursor = ARRAYBEGIN(Block->Data,uint8_t);
for (Frame=0;Frame<ARRAYCOUNT(Block->SizeList,int32_t);++Frame)
{
fscod = Cursor[5] >> 3;
SampleRate = Cursor[4] >> 6;
if (fscod > 10 || fscod < 8)
{
Err = ERR_INVALID_DATA;
ARRAYBEGIN(Block->Durations,timecode_t)[Frame] = INVALID_TIMECODE_T;
//goto exit;
}
else
{
SampleRate = A_AC3_freq[fscod-8][SampleRate];
ARRAYBEGIN(Block->Durations,timecode_t)[Frame] = Scale64(1000000000,1536,SampleRate);
}
Cursor += ARRAYBEGIN(Block->SizeList,int32_t)[Frame];
}
}
else if (tcsisame_ascii(CodecID,T("A_EAC3")))
{
Block->IsKeyframe = 1; // safety
ArrayResize(&Block->Durations,sizeof(timecode_t)*ARRAYCOUNT(Block->SizeList,int32_t),0);
Cursor = ARRAYBEGIN(Block->Data,uint8_t);
for (Frame=0;Frame<ARRAYCOUNT(Block->SizeList,int32_t);++Frame)
{
fscod = Cursor[4] >> 6;
fscod2 = (Cursor[4] >> 4) & 0x03;
if ((0x03 == fscod) && (0x03 == fscod2))
{
Err = ERR_INVALID_DATA;
ARRAYBEGIN(Block->Durations,timecode_t)[Frame] = INVALID_TIMECODE_T;
//goto exit;
}
else
{
SampleRate = A_EAC3_freq[0x03 == fscod ? 3 + fscod2 : fscod];
Samples = (0x03 == fscod) ? 1536 : A_EAC3_samples[fscod2];
ARRAYBEGIN(Block->Durations,timecode_t)[Frame] = Scale64(1000000000,Samples,SampleRate);
}
Cursor += ARRAYBEGIN(Block->SizeList,int32_t)[Frame];
}
}
else if (tcsisame_ascii(CodecID,T("A_DTS")))
{
Block->IsKeyframe = 1; // safety
ArrayResize(&Block->Durations,sizeof(timecode_t)*ARRAYCOUNT(Block->SizeList,int32_t),0);
Cursor = ARRAYBEGIN(Block->Data,uint8_t);
for (Frame=0;Frame<ARRAYCOUNT(Block->SizeList,int32_t);++Frame)
{
Samples = (((Cursor[4] & 1) << 7) + (Cursor[5] >> 2) + 1) * 32;
// TODO: handle the frame termination
SampleRate = A_DTS_freq[(Cursor[8] >> 2) & 0x0F];
if (Samples==0 || SampleRate==0)
{
Err = ERR_INVALID_DATA;
ARRAYBEGIN(Block->Durations,timecode_t)[Frame] = INVALID_TIMECODE_T;
//goto exit;
}
else
ARRAYBEGIN(Block->Durations,timecode_t)[Frame] = Scale64(1000000000,Samples,SampleRate);
Cursor += ARRAYBEGIN(Block->SizeList,int32_t)[Frame];
}
}
else if (tcsisame_ascii(CodecID,T("A_AAC")) || tcsncmp(CodecID,T("A_AAC/"),6)==0)
{
Block->IsKeyframe = 1; // safety
Elt = EBML_MasterFindChild(Track,&MATROSKA_ContextAudio);
if (Elt)
{
Elt = EBML_MasterFindChild((ebml_master*)Elt,&MATROSKA_ContextSamplingFrequency);
if (Elt)
{
ArrayResize(&Block->Durations,sizeof(timecode_t)*ARRAYCOUNT(Block->SizeList,int32_t),0);
Samples = 1024;
SampleRate = (int)((ebml_float*)Elt)->Value;
for (Frame=0;Frame<ARRAYCOUNT(Block->SizeList,int32_t);++Frame)
ARRAYBEGIN(Block->Durations,timecode_t)[Frame] = Scale64(1000000000,Samples,SampleRate);
}
}
}
#if defined(CONFIG_CODEC_HELPER)
else if (tcsisame_ascii(CodecID,T("A_VORBIS")))
{
Block->IsKeyframe = 1; // safety
Elt = EBML_MasterFindChild(Track,&MATROSKA_ContextCodecPrivate);
if (Elt)
{
vorbis_info vi;
vorbis_comment vc;
ogg_packet OggPacket;
ogg_reference OggRef;
ogg_buffer OggBuffer;
int n,i,j;
codec_setup_info *ci;
vorbis_info_init(&vi);
vorbis_comment_init(&vc);
memset(&OggPacket,0,sizeof(ogg_packet));
OggBuffer.data = (uint8_t*)EBML_BinaryGetData((ebml_binary*)Elt);
OggBuffer.size = (long)Elt->DataSize;
OggBuffer.refcount = 1;
memset(&OggRef,0,sizeof(OggRef));
OggRef.buffer = &OggBuffer;
OggRef.next = NULL;
OggPacket.packet = &OggRef;
OggPacket.packetno = -1;
n = OggBuffer.data[0];
i = 1+n;
j = 1;
while (OggPacket.packetno < 3 && n>=j)
{
OggRef.begin = i;
OggRef.length = 0;
do
{
OggRef.length += OggBuffer.data[j];
}
while (OggBuffer.data[j++] == 255 && n>=j);
i += OggRef.length;
if (i > OggBuffer.size)
return ERR_INVALID_DATA;
++OggPacket.packetno;
OggPacket.b_o_s = OggPacket.packetno == 0;
OggPacket.bytes = OggPacket.packet->length;
if (!(vorbis_synthesis_headerin(&vi,&vc,&OggPacket) >= 0) && OggPacket.packetno==0)
return ERR_INVALID_DATA;
}
if (OggPacket.packetno < 3)
{
OggRef.begin = i;
OggRef.length = OggBuffer.size - i;
++OggPacket.packetno;
OggPacket.b_o_s = OggPacket.packetno == 0;
OggPacket.bytes = OggPacket.packet->length;
if (!(vorbis_synthesis_headerin(&vi,&vc,&OggPacket) >= 0) && OggPacket.packetno==0)
return ERR_INVALID_DATA;
}
SampleRate = vi.rate;
ArrayResize(&Block->Durations,sizeof(timecode_t)*ARRAYCOUNT(Block->SizeList,int32_t),0);
Cursor = ARRAYBEGIN(Block->Data,uint8_t);
ci = vi.codec_setup;
for (Frame=0;Frame<ARRAYCOUNT(Block->SizeList,int32_t);++Frame)
{
fscod = _ilog(ci->modes-1);
fscod = (Cursor[0] & 0x7F) >> (7-fscod);
if (fscod > ci->modes)
{
Err = ERR_INVALID_DATA;
ARRAYBEGIN(Block->Durations,timecode_t)[Frame] = INVALID_TIMECODE_T;
//goto exit;
}
else
{
Samples = ci->blocksizes[ci->mode_param[fscod]->blockflag];
ARRAYBEGIN(Block->Durations,timecode_t)[Frame] = Scale64(1000000000,Samples,SampleRate);
}
Cursor += ARRAYBEGIN(Block->SizeList,int32_t)[Frame];
}
vorbis_comment_clear(&vc);
vorbis_info_clear(&vi);
}
}
#endif
if (ReadData)
{
ArrayClear(&Block->Data);
Block->Base.Base.bValueIsSet = 0;
}
}
}
}
}
exit:
return Err;
}
size_t MATROSKA_BlockGetFrameCount(const matroska_block *Block)
{
return ARRAYCOUNT(Block->SizeList,int32_t);
}
size_t MATROSKA_BlockGetLength(const matroska_block *Block, size_t FrameNum)
{
if (FrameNum >= ARRAYCOUNT(Block->SizeList,int32_t))
return 0;
return ARRAYBEGIN(Block->SizeList,int32_t)[FrameNum];
}
timecode_t MATROSKA_BlockGetFrameDuration(const matroska_block *Block, size_t FrameNum)
{
if (FrameNum >= ARRAYCOUNT(Block->Durations,timecode_t))
return INVALID_TIMECODE_T;
return ARRAYBEGIN(Block->Durations,timecode_t)[FrameNum];
}
timecode_t MATROSKA_BlockGetFrameStart(const matroska_block *Block, size_t FrameNum)
{
if (FrameNum >= ARRAYCOUNT(Block->Durations,timecode_t))
return INVALID_TIMECODE_T;
else
{
size_t i;
timecode_t Start = MATROSKA_BlockTimecode((matroska_block*)Block);
if (Start!=INVALID_TIMECODE_T)
{
for (i=0;i<FrameNum;++i)
{
if (ARRAYBEGIN(Block->Durations,timecode_t)[i]==INVALID_TIMECODE_T)
return INVALID_TIMECODE_T;
Start += ARRAYBEGIN(Block->Durations,timecode_t)[i];
}
}
return Start;
}
}
timecode_t MATROSKA_BlockGetFrameEnd(const matroska_block *Block, size_t FrameNum)
{
timecode_t Result = MATROSKA_BlockGetFrameStart(Block,FrameNum), a;
if (Result==INVALID_TIMECODE_T)
return INVALID_TIMECODE_T;
a = MATROSKA_BlockGetFrameDuration(Block,FrameNum);
if (a==INVALID_TIMECODE_T)
return INVALID_TIMECODE_T;
return Result + a;
}