summaryrefslogtreecommitdiffstats
path: root/src/mpeg.c
diff options
context:
space:
mode:
authorMatthias (think) <matthias@mpb.li>2012-07-11 11:49:12 +0200
committerMatthias (think) <matthias@mpb.li>2012-07-11 11:49:12 +0200
commitbbab73a63b8c7b50e8a8cb228999d45024fad984 (patch)
tree81a822aa9bd33cae8a5fb8ade4faa83b652316d9 /src/mpeg.c
downloaddabmux-bbab73a63b8c7b50e8a8cb228999d45024fad984.tar.gz
dabmux-bbab73a63b8c7b50e8a8cb228999d45024fad984.tar.bz2
dabmux-bbab73a63b8c7b50e8a8cb228999d45024fad984.zip
added unmodified mmbtools
Diffstat (limited to 'src/mpeg.c')
-rw-r--r--src/mpeg.c221
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;
+}