/*
Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Her Majesty
the Queen in Right of Canada (Communications Research Center Canada)
*/
/*
This file is part of CRC-DabMux.
CRC-DabMux 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 3 of the
License, or (at your option) any later version.
CRC-DabMux 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 CRC-DabMux. If not, see .
*/
#include "mpeg.h"
#include
#include
const static short bitrateArray[4][4][16] = {
{ // MPEG 2.5
{ -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1 }, // layer invalid
{ 0, 8, 16, 24, 32, 40, 48, 56,
64, 80, 96, 112, 128, 144, 160, -1 }, // layer 3
{ 0, 8, 16, 24, 32, 40, 48, 56,
64, 80, 96, 112, 128, 144, 160, -1 }, // layer 2
{ 0, 32, 48, 56, 64, 80, 96, 112,
128, 144, 160, 176, 192, 224, 256, -1 } // layer 1
},
{
{ -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1 }, // MPEG invalid
{ -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1 },
{ -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1 },
{ -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1 }
},
{
{ -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1 }, // MPEG 2
{ 0, 8, 16, 24, 32, 40, 48, 56,
64, 80, 96, 112, 128, 144, 160, -1 },
{ 0, 8, 16, 24, 32, 40, 48, 56,
64, 80, 96, 112, 128, 144, 160, -1 },
{ 0, 32, 48, 56, 64, 80, 96, 112,
128, 144, 160, 176, 192, 224, 256, -1 }
},
{
{ -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1 }, // MPEG 1
{ 0, 32, 40, 48, 56, 64, 80, 96,
112, 128, 160, 192, 224, 256, 320, -1 },
{ 0, 32, 48, 56, 64, 80, 96, 112,
128, 160, 192, 224, 256, 320, 384, -1 },
{ 0, 32, 64, 96, 128, 160, 192, 224,
256, 288, 320, 352, 384, 416, 448, -1 }
}
};
const static int samplingrateArray[4][4] = {
{ 11025, 12000, 8000, 0 }, // MPEG 2.5
{ -1, -1, -1, -1 }, // MPEG invalid
{ 22050, 24000, 16000, 0 }, // MPEG 2
{ 44100, 48000, 32000, 0 } // MPEG 1
};
short getMpegBitrate(void* data)
{
mpegHeader* header = (mpegHeader*)data;
return bitrateArray[header->id][header->layer][header->bitrate];
}
int getMpegFrequency(void* data)
{
mpegHeader* header = (mpegHeader*)data;
return samplingrateArray[header->id][header->samplingrate];
}
int getMpegFrameLength(mpegHeader* header)
{
short bitrate = getMpegBitrate(header);
int samplingrate = getMpegFrequency(header);
int framelength = -1;
if (bitrate <= 0) {
return -1;
}
if (samplingrate <= 0) {
return -1;
}
switch (header->layer) {
case 1: // layer III
case 2: // layer II
framelength = (int)144000 * bitrate / samplingrate + header->padding;
break;
case 3: // layer I
framelength = (12 * bitrate / samplingrate + header->padding) * 4;
break;
default:
framelength = -1;
}
return framelength;
}
/**
* This function replace the read function by trying many times a reading.
* It tries to read until all bytes are read. Very useful when reading from a
* pipe because sometimes 2 pass is necessary to read all bytes.
* @param file File descriptor.
* @param data Address of the buffer to write data into.
* @param size Number of bytes to read.
* @param tries Max number of tries to read.
* @return Same as read function:
* Nb of bytes read.
* -1 if error.
*/
ssize_t readData(int file, void* data, size_t size, unsigned int tries)
{
ssize_t result;
size_t offset = 0;
if (size == 0) return 0;
if (tries == 0) return 0;
result = read(file, data, size);
if (result == -1) {
if (errno == EAGAIN) {
return readData(file, data, size, tries - 1);
}
return -1;
}
offset = result;
size -= offset;
data = (char*)data + offset;
result = readData(file, data, size, tries - 1);
if (result == -1) {
return -1;
}
offset += result;
return offset;
}
int readMpegHeader(int file, void* data, int size)
{
// Max byte reading for searching sync
unsigned int flagmax = 0;
unsigned long* syncword = (unsigned long*)data;
int result;
if (size < 4) return MPEG_BUFFER_OVERFLOW;
// Mpeg header reading
result = readData(file, data, 4, 2);
if (result == 0) return MPEG_FILE_EMPTY;
if (result == -1) {
fprintf(stderr, "header\n");
return MPEG_FILE_ERROR;
}
if (result < 4) {
return MPEG_BUFFER_UNDERFLOW;
}
while ((*syncword & 0xe0ff) != 0xe0ff) {
*syncword >>= 8;
result = readData(file, (char*)data + 3, 1, 2);
if (result == 0) {
return MPEG_FILE_EMPTY;
} else if (result == -1) {
return MPEG_FILE_ERROR;
}
if (++flagmax > 1200) {
return MPEG_SYNC_NOT_FOUND;
}
}
return 4;
}
int readMpegFrame(int file, void* data, int size)
{
mpegHeader* header = (mpegHeader*)data;
int framelength;
int result;
framelength = getMpegFrameLength(header);
if (framelength < 0) return MPEG_INVALID_FRAME;
if (framelength > size) {
//lseek(file, framelength - 4, SEEK_CUR);
//return MPEG_BUFFER_OVERFLOW;
result = readData(file, ((char*)data) + 4, size - 4, 2);
if (size == 4) {
lseek(file, framelength - size, SEEK_CUR);
result = framelength - 4;
}
} else {
result = readData(file, ((char*)data) + 4, framelength - 4, 2);
}
if (result == 0) return MPEG_FILE_EMPTY;
if (result == -1) {
return MPEG_FILE_ERROR;
}
if (result < framelength - 4) {
return MPEG_BUFFER_UNDERFLOW;
}
return framelength;
}