Files
Bento4/Source/C++/Core/Ap4Utils.cpp
Gilles Boccon-Gibod c7ca299757 fix #162
2017-12-16 16:54:44 -08:00

569 lines
18 KiB
C++

/*****************************************************************
|
| AP4 - Utilities
|
| Copyright 2002-2008 Axiomatic Systems, LLC
|
|
| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
|
| Unless you have obtained Bento4 under a difference license,
| this version of Bento4 is Bento4|GPL.
| Bento4|GPL is free software; you can redistribute it and/or modify
| it under the terms of the GNU General Public License as published by
| the Free Software Foundation; either version 2, or (at your option)
| any later version.
|
| Bento4|GPL is distributed in the hope that it will be useful,
| but WITHOUT ANY WARRANTY; without even the implied warranty of
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
| GNU General Public License for more details.
|
| You should have received a copy of the GNU General Public License
| along with Bento4|GPL; see the file COPYING. If not, write to the
| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
| 02111-1307, USA.
|
****************************************************************/
/*----------------------------------------------------------------------
| includes
+---------------------------------------------------------------------*/
#include "Ap4Utils.h"
/*----------------------------------------------------------------------
| AP4_GlobalOptions::g_Entry
+---------------------------------------------------------------------*/
AP4_List<AP4_GlobalOptions::Entry>* AP4_GlobalOptions::g_Entries = NULL;
/*----------------------------------------------------------------------
| AP4_GlobalOptions::GetEntry
+---------------------------------------------------------------------*/
AP4_GlobalOptions::Entry*
AP4_GlobalOptions::GetEntry(const char* name, bool autocreate)
{
if (g_Entries == NULL) {
g_Entries = new AP4_List<Entry>;
}
for (AP4_List<Entry>::Item* item = g_Entries->FirstItem();
item;
item = item->GetNext()) {
if (item->GetData()->m_Name == name) return item->GetData();
}
if (autocreate) {
Entry* new_entry = new Entry();
new_entry->m_Name = name;
g_Entries->Add(new_entry);
return new_entry;
} else {
return NULL;
}
}
/*----------------------------------------------------------------------
| AP4_GlobalOptions::SetBool
+---------------------------------------------------------------------*/
void
AP4_GlobalOptions::SetBool(const char* name, bool value)
{
Entry* entry = GetEntry(name, true);
entry->m_Value = value?"true":"false";
}
/*----------------------------------------------------------------------
| AP4_GlobalOptions::GetBool
+---------------------------------------------------------------------*/
bool
AP4_GlobalOptions::GetBool(const char* name)
{
Entry* entry = GetEntry(name, false);
if (entry) {
return entry->m_Value == "true";
} else {
return false;
}
}
/*----------------------------------------------------------------------
| AP4_GlobalOptions::SetString
+---------------------------------------------------------------------*/
void
AP4_GlobalOptions::SetString(const char* name, const char* value)
{
Entry* entry = GetEntry(name, true);
entry->m_Value = value;
}
/*----------------------------------------------------------------------
| AP4_GlobalOptions::GetString
+---------------------------------------------------------------------*/
const char*
AP4_GlobalOptions::GetString(const char* name)
{
Entry* entry = GetEntry(name, false);
if (entry) {
return entry->m_Value.GetChars();
} else {
return NULL;
}
}
/*----------------------------------------------------------------------
| AP4_BytesToDoubleBE
+---------------------------------------------------------------------*/
double
AP4_BytesToDoubleBE(const unsigned char* bytes)
{
AP4_UI64 i_value = AP4_BytesToUInt64BE(bytes);
void* v_value = reinterpret_cast<void*>(&i_value);
double* d_value = reinterpret_cast<double*>(v_value);
return *d_value;
}
/*----------------------------------------------------------------------
| AP4_BytesToUInt64BE
+---------------------------------------------------------------------*/
AP4_UI64
AP4_BytesToUInt64BE(const unsigned char* bytes)
{
return
( ((AP4_UI64)bytes[0])<<56 ) |
( ((AP4_UI64)bytes[1])<<48 ) |
( ((AP4_UI64)bytes[2])<<40 ) |
( ((AP4_UI64)bytes[3])<<32 ) |
( ((AP4_UI64)bytes[4])<<24 ) |
( ((AP4_UI64)bytes[5])<<16 ) |
( ((AP4_UI64)bytes[6])<<8 ) |
( ((AP4_UI64)bytes[7]) );
}
/*----------------------------------------------------------------------
| AP4_BytesFromDoubleBE
+---------------------------------------------------------------------*/
void
AP4_BytesFromDoubleBE(unsigned char* bytes, double value)
{
void* v_value = reinterpret_cast<void*>(&value);
AP4_UI64* i_value = reinterpret_cast<AP4_UI64*>(v_value);
AP4_BytesFromUInt64BE(bytes, *i_value);
}
/*----------------------------------------------------------------------
| AP4_BytesFromUInt64BE
+---------------------------------------------------------------------*/
void
AP4_BytesFromUInt64BE(unsigned char* bytes, AP4_UI64 value)
{
bytes[0] = (unsigned char)((value >> 56) & 0xFF);
bytes[1] = (unsigned char)((value >> 48) & 0xFF);
bytes[2] = (unsigned char)((value >> 40) & 0xFF);
bytes[3] = (unsigned char)((value >> 32) & 0xFF);
bytes[4] = (unsigned char)((value >> 24) & 0xFF);
bytes[5] = (unsigned char)((value >> 16) & 0xFF);
bytes[6] = (unsigned char)((value >> 8) & 0xFF);
bytes[7] = (unsigned char)((value ) & 0xFF);
}
/*----------------------------------------------------------------------
| AP4_DurationMsFromUnits
+---------------------------------------------------------------------*/
AP4_UI32
AP4_DurationMsFromUnits(AP4_UI64 units, AP4_UI32 units_per_second)
{
if (units_per_second == 0) return 0;
return (AP4_UI32)(((double)units*1000.0)/(double)units_per_second);
}
/*----------------------------------------------------------------------
| AP4_ConvertTime
+---------------------------------------------------------------------*/
AP4_UI64
AP4_ConvertTime(AP4_UI64 time_value,
AP4_UI32 from_time_scale,
AP4_UI32 to_time_scale)
{
if (from_time_scale == 0) return 0;
double ratio = (double)to_time_scale/(double)from_time_scale;
return ((AP4_UI64)(0.5+(double)time_value*ratio));
}
/*----------------------------------------------------------------------
| AP4_FormatFourChars
+---------------------------------------------------------------------*/
void
AP4_FormatFourChars(char* str, AP4_UI32 value) {
str[0] = (value >> 24) & 0xFF;
str[1] = (value >> 16) & 0xFF;
str[2] = (value >> 8) & 0xFF;
str[3] = (value ) & 0xFF;
str[4] = '\0';
}
/*----------------------------------------------------------------------
| AP4_FormatFourCharsPrintable
+---------------------------------------------------------------------*/
void
AP4_FormatFourCharsPrintable(char* str, AP4_UI32 value) {
AP4_FormatFourChars(str, value);
for (int i=0; i<4; i++) {
if (str[i]<' ' || str[i] >= 127) {
str[i] = '.';
}
}
}
/*----------------------------------------------------------------------
| AP4_SplitArgs
+---------------------------------------------------------------------*/
AP4_Result
AP4_SplitArgs(char* arg, char*& arg0, char*& arg1)
{
arg0 = arg;
char* c = arg;
while (*c != 0 && *c != ':') {
c++;
}
if (*c == ':') {
*c++ = '\0';
arg1 = c;
return AP4_SUCCESS;
} else {
return AP4_FAILURE;
}
}
/*----------------------------------------------------------------------
| AP4_SplitArgs
+---------------------------------------------------------------------*/
AP4_Result
AP4_SplitArgs(char* arg, char*& arg0, char*& arg1, char*& arg2)
{
AP4_Result result = AP4_SplitArgs(arg, arg0, arg1);
if (AP4_FAILED(result)) return result;
return AP4_SplitArgs(arg1, arg1, arg2);
}
/*----------------------------------------------------------------------
| AP4_HexNibble
+---------------------------------------------------------------------*/
unsigned char
AP4_HexNibble(char c)
{
switch (c) {
case '0': return 0;
case '1': return 1;
case '2': return 2;
case '3': return 3;
case '4': return 4;
case '5': return 5;
case '6': return 6;
case '7': return 7;
case '8': return 8;
case '9': return 9;
case 'a': case 'A': return 10;
case 'b': case 'B': return 11;
case 'c': case 'C': return 12;
case 'd': case 'D': return 13;
case 'e': case 'E': return 14;
case 'f': case 'F': return 15;
default: return 0;
}
}
/*----------------------------------------------------------------------
| AP4_NibbleHex
+---------------------------------------------------------------------*/
char
AP4_NibbleHex(unsigned int nibble)
{
if (nibble < 10) {
return (char)('0'+nibble);
} else if (nibble < 16) {
return (char)('A'+(nibble-10));
} else {
return ' ';
}
}
/*----------------------------------------------------------------------
| AP4_ParseHex
+---------------------------------------------------------------------*/
AP4_Result
AP4_ParseHex(const char* hex, unsigned char* bytes, unsigned int count)
{
if (AP4_StringLength(hex) < 2*count) return AP4_ERROR_INVALID_PARAMETERS;
for (unsigned int i=0; i<count; i++) {
bytes[i] = (AP4_HexNibble(hex[2*i]) << 4) | (AP4_HexNibble(hex[2*i+1]));
}
return AP4_SUCCESS;
}
/*----------------------------------------------------------------------
| AP4_FormatHex
+---------------------------------------------------------------------*/
AP4_Result
AP4_FormatHex(const AP4_UI08* data, unsigned int data_size, char* hex)
{
for (unsigned int i=0; i<data_size; i++) {
*hex++ = AP4_NibbleHex(data[i]>>4);
*hex++ = AP4_NibbleHex(data[i]&0x0F);
}
return AP4_SUCCESS;
}
/*----------------------------------------------------------------------
| AP4_BitWriter::Write
+---------------------------------------------------------------------*/
void
AP4_BitWriter::Write(AP4_UI32 bits, unsigned int bit_count)
{
unsigned char* data = m_Data;
if (m_BitCount+bit_count > m_DataSize*8) return;
data += m_BitCount/8;
unsigned int space = 8-(m_BitCount%8);
while (bit_count) {
unsigned int mask = bit_count==32 ? 0xFFFFFFFF : ((1<<bit_count)-1);
if (bit_count <= space) {
*data |= ((bits&mask) << (space-bit_count));
m_BitCount += bit_count;
return;
} else {
*data |= ((bits&mask) >> (bit_count-space));
++data;
m_BitCount += space;
bit_count -= space;
space = 8;
}
}
}
/*----------------------------------------------------------------------
| AP4_ParseIntegerU
+---------------------------------------------------------------------*/
AP4_UI32
AP4_ParseIntegerU(const char* str)
{
if (str == NULL) {
return 0;
}
// parse the digits
AP4_UI32 value = 0;
while (char c = *str++) {
if (c >= '0' && c <= '9') {
value = 10*value + (c-'0');
} else {
return 0;
}
}
return value;
}
/*----------------------------------------------------------------------
| types and macros
+---------------------------------------------------------------------*/
#define AP4_WORD_BITS 32
#define AP4_WORD_BYTES 4
#define AP4_BIT_MASK(_n) ((1<<(_n))-1)
#if AP4_WORD_BITS != 32
#error unsupported word size /* 64 and other word size not yet implemented */
#endif
/*----------------------------------------------------------------------
| AP4_BitReader::AP4_BitReader
+---------------------------------------------------------------------*/
AP4_BitReader::AP4_BitReader(const AP4_UI08* data, unsigned int data_size) :
m_Position(0),
m_Cache(0),
m_BitsCached(0)
{
// make the buffer an integral mulitple of the word size
m_Buffer.SetBufferSize(AP4_WORD_BYTES*((data_size+AP4_WORD_BYTES-1)/AP4_WORD_BYTES));
m_Buffer.SetData(data, data_size);
if (m_Buffer.GetDataSize() != m_Buffer.GetBufferSize()) {
AP4_SetMemory(m_Buffer.UseData()+m_Buffer.GetDataSize(), 0, m_Buffer.GetBufferSize()-m_Buffer.GetDataSize());
}
}
/*----------------------------------------------------------------------
| AP4_BitReader::~AP4_BitReader
+---------------------------------------------------------------------*/
AP4_BitReader::~AP4_BitReader()
{
}
/*----------------------------------------------------------------------
| AP4_BitReader::Reset
+---------------------------------------------------------------------*/
AP4_Result
AP4_BitReader::Reset()
{
m_Position = 0;
m_Cache = 0;
m_BitsCached = 0;
return AP4_SUCCESS;
}
/*----------------------------------------------------------------------
| AP4_BitReader::GetBitsRead
+---------------------------------------------------------------------*/
unsigned int
AP4_BitReader::GetBitsRead()
{
return 8*m_Position - m_BitsCached;
}
/*----------------------------------------------------------------------
| AP4_BitReader::ReadCache
+---------------------------------------------------------------------*/
AP4_BitReader::BitsWord
AP4_BitReader::ReadCache() const
{
const AP4_UI08* out_ptr = m_Buffer.GetData()+m_Position;
return (((AP4_BitReader::BitsWord) out_ptr[0]) << 24) |
(((AP4_BitReader::BitsWord) out_ptr[1]) << 16) |
(((AP4_BitReader::BitsWord) out_ptr[2]) << 8) |
(((AP4_BitReader::BitsWord) out_ptr[3]) );
}
/*----------------------------------------------------------------------
| AP4_BitReader::ReadBits
+---------------------------------------------------------------------*/
AP4_UI32
AP4_BitReader::ReadBits(unsigned int n)
{
if (n == 0) return 0;
AP4_BitReader::BitsWord result;
if (m_BitsCached >= n) {
/* we have enough bits in the cache to satisfy the request */
m_BitsCached -= n;
result = (m_Cache >> m_BitsCached) & AP4_BIT_MASK(n);
} else {
/* not enough bits in the cache */
AP4_BitReader::BitsWord word = ReadCache();
m_Position += AP4_WORD_BYTES;
/* combine the new word and the cache, and update the state */
AP4_BitReader::BitsWord cache = m_Cache & AP4_BIT_MASK(m_BitsCached);
n -= m_BitsCached;
m_BitsCached = AP4_WORD_BITS - n;
result = m_BitsCached ? (word >> m_BitsCached) | (cache << n) : word;
m_Cache = word;
}
return result;
}
/*----------------------------------------------------------------------
| AP4_BitReader::ReadBit
+---------------------------------------------------------------------*/
int
AP4_BitReader::ReadBit()
{
AP4_BitReader::BitsWord result;
if (m_BitsCached == 0) {
/* the cache is empty */
/* read the next word into the cache */
m_Cache = ReadCache();
m_Position += AP4_WORD_BYTES;
m_BitsCached = AP4_WORD_BITS - 1;
/* return the first bit */
result = m_Cache >> (AP4_WORD_BITS - 1);
} else {
/* get the bit from the cache */
result = (m_Cache >> (--m_BitsCached)) & 1;
}
return result;
}
/*----------------------------------------------------------------------
| AP4_BitReader::PeekBits
+---------------------------------------------------------------------*/
AP4_UI32
AP4_BitReader::PeekBits(unsigned int n)
{
/* we have enough bits in the cache to satisfy the request */
if (m_BitsCached >= n) {
return (m_Cache >> (m_BitsCached - n)) & AP4_BIT_MASK(n);
} else {
/* not enough bits in the cache, read the next word */
AP4_BitReader::BitsWord word = ReadCache();
/* combine the new word and the cache, and update the state */
AP4_BitReader::BitsWord cache = m_Cache & AP4_BIT_MASK(m_BitsCached);
n -= m_BitsCached;
return (word >> (AP4_WORD_BITS - n)) | (cache << n);
}
}
/*----------------------------------------------------------------------
| AP4_BitReader::PeekBit
+---------------------------------------------------------------------*/
int
AP4_BitReader::PeekBit()
{
/* the cache is empty */
if (m_BitsCached == 0) {
/* read the next word into the cache */
AP4_BitReader::BitsWord cache = ReadCache();
/* return the first bit */
return cache >> (AP4_WORD_BITS - 1);
} else {
/* get the bit from the cache */
return (m_Cache >> (m_BitsCached-1)) & 1;
}
}
/*----------------------------------------------------------------------
| AP4_BitReader::SkipBits
+---------------------------------------------------------------------*/
void
AP4_BitReader::SkipBits(unsigned int n)
{
if (n <= m_BitsCached) {
m_BitsCached -= n;
} else {
n -= m_BitsCached;
while (n >= AP4_WORD_BITS) {
m_Position += AP4_WORD_BYTES;
n -= AP4_WORD_BITS;
}
if (n) {
m_Cache = ReadCache();
m_BitsCached = AP4_WORD_BITS-n;
m_Position += AP4_WORD_BYTES;
} else {
m_BitsCached = 0;
m_Cache = 0;
}
}
}
/*----------------------------------------------------------------------
| AP4_BitReader::SkipBit
+---------------------------------------------------------------------*/
void
AP4_BitReader::SkipBit()
{
if (m_BitsCached == 0) {
m_Cache = ReadCache();
m_Position += AP4_WORD_BYTES;
m_BitsCached = AP4_WORD_BITS - 1;
} else {
--m_BitsCached;
}
}