diff options
Diffstat (limited to 'src/mpeg.c')
-rw-r--r-- | src/mpeg.c | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/src/mpeg.c b/src/mpeg.c new file mode 100644 index 0000000..57f4231 --- /dev/null +++ b/src/mpeg.c @@ -0,0 +1,221 @@ +/* + 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 <http://www.gnu.org/licenses/>. + */ + +#include "mpeg.h" + +#include <stdio.h> +#include <errno.h> + + +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; +} |