/* 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; }