aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2016-10-30 16:28:27 +0100
committerMatthias P. Braendli <matthias.braendli@mpb.li>2016-10-30 16:28:27 +0100
commit804fe1979f9ed7bef7badaf0aa08e35e09874772 (patch)
tree93ae4728de598391ce6e72712676260831b0ecb2
parent128768f7fd719eb455a946a0f716d7128b4ded63 (diff)
downloaddabmux-804fe1979f9ed7bef7badaf0aa08e35e09874772.tar.gz
dabmux-804fe1979f9ed7bef7badaf0aa08e35e09874772.tar.bz2
dabmux-804fe1979f9ed7bef7badaf0aa08e35e09874772.zip
Add rudimentary file input
No nonblock support yet
-rw-r--r--src/ConfigParser.cpp11
-rw-r--r--src/Makefile.am1
-rw-r--r--src/dabInputMpegFile.cpp31
-rw-r--r--src/input/File.cpp227
-rw-r--r--src/input/File.h69
-rw-r--r--src/input/Prbs.h4
-rw-r--r--src/input/Zmq.cpp9
-rw-r--r--src/input/Zmq.h7
-rw-r--r--src/input/inputs.h52
-rw-r--r--src/mpeg.c26
-rw-r--r--src/mpeg.h7
11 files changed, 393 insertions, 51 deletions
diff --git a/src/ConfigParser.cpp b/src/ConfigParser.cpp
index bdc2099..2a8d3da 100644
--- a/src/ConfigParser.cpp
+++ b/src/ConfigParser.cpp
@@ -55,6 +55,7 @@
#include "input/Prbs.h"
#include "input/Zmq.h"
+#include "input/File.h"
#ifdef _WIN32
@@ -930,6 +931,16 @@ static void setup_subchannel_from_ptree(DabSubchannel* subchan,
if (nonblock) {
// TODO
}
+
+ if (type == "audio") {
+ subchan->input = make_shared<Inputs::MPEGFile>();
+ }
+ else if (type == "dabplus") {
+ subchan->input = make_shared<Inputs::DABPlusFile>();
+ }
+ else {
+ throw logic_error("Incomplete handling of file input");
+ }
}
else if (proto == "tcp" ||
proto == "epgm" ||
diff --git a/src/Makefile.am b/src/Makefile.am
index b8de4e8..b356566 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -50,6 +50,7 @@ odr_dabmux_SOURCES =DabMux.cpp DabMux.h \
input/inputs.h \
input/Prbs.cpp input/Prbs.h \
input/Zmq.cpp input/Zmq.h \
+ input/File.cpp input/File.h \
dabOutput/dabOutput.h \
dabOutput/dabOutputFile.cpp \
dabOutput/dabOutputFifo.cpp \
diff --git a/src/dabInputMpegFile.cpp b/src/dabInputMpegFile.cpp
index 804ea29..6f24f32 100644
--- a/src/dabInputMpegFile.cpp
+++ b/src/dabInputMpegFile.cpp
@@ -47,37 +47,6 @@ struct dabInputOperations dabInputMpegFileOperations = {
};
-#define MPEG_FREQUENCY -2
-#define MPEG_PADDING -3
-#define MPEG_COPYRIGHT -4
-#define MPEG_ORIGINAL -5
-#define MPEG_EMPHASIS -6
-int checkDabMpegFrame(void* data) {
- mpegHeader* header = (mpegHeader*)data;
- unsigned long* headerData = (unsigned long*)data;
- if ((*headerData & 0x0f0ffcff) == 0x0004fcff) return 0;
- if ((*headerData & 0x0f0ffcff) == 0x0004f4ff) return 0;
- if (getMpegFrequency(header) != 48000) {
- if (getMpegFrequency(header) != 24000) {
- return MPEG_FREQUENCY;
- }
- }
- if (header->padding != 0) {
- return MPEG_PADDING;
- }
- if (header->copyright != 0) {
- return MPEG_COPYRIGHT;
- }
- if (header->original != 0) {
- return MPEG_ORIGINAL;
- }
- if (header->emphasis != 0) {
- return MPEG_EMPHASIS;
- }
- return -1;
-}
-
-
int dabInputMpegFileRead(dabInputOperations* ops, void* args, void* buffer, int size)
{
dabInputFileData* data = (dabInputFileData*)args;
diff --git a/src/input/File.cpp b/src/input/File.cpp
new file mode 100644
index 0000000..9721b97
--- /dev/null
+++ b/src/input/File.cpp
@@ -0,0 +1,227 @@
+/*
+ Copyright (C) 2009 Her Majesty the Queen in Right of Canada (Communications
+ Research Center Canada)
+
+ Copyright (C) 2016 Matthias P. Braendli
+ http://www.opendigitalradio.org
+
+ */
+/*
+ This file is part of ODR-DabMux.
+
+ ODR-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.
+
+ ODR-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 ODR-DabMux. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sstream>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#ifndef _WIN32
+# define O_BINARY 0
+#endif
+
+#include "input/File.h"
+#include "mpeg.h"
+
+namespace Inputs {
+
+int FileBase::open(const std::string& name)
+{
+ m_fd = ::open(name.c_str(), O_RDONLY | O_BINARY);
+ if (m_fd == -1) {
+ std::stringstream ss;
+ ss << "Could not open input file " << name << ": " <<
+ strerror(errno);
+ throw std::runtime_error(ss.str());
+ }
+ return 0;
+}
+
+int FileBase::close()
+{
+ if (m_fd != -1) {
+ ::close(m_fd);
+ m_fd = -1;
+ }
+ return 0;
+}
+
+int FileBase::rewind()
+{
+ return ::lseek(m_fd, 0, SEEK_SET);
+}
+
+int MPEGFile::readFrame(void* buffer, int size)
+{
+ int result;
+ bool do_rewind = false;
+READ_SUBCHANNEL:
+ if (m_parity) {
+ result = readData(m_fd, buffer, size, 2);
+ m_parity = false;
+ return 0;
+ } else {
+ result = readMpegHeader(m_fd, buffer, size);
+ if (result > 0) {
+ result = readMpegFrame(m_fd, buffer, size);
+ if (result < 0 && getMpegFrequency(buffer) == 24000) {
+ m_parity = true;
+ result = size;
+ }
+ }
+ }
+ switch (result) {
+ case MPEG_BUFFER_UNDERFLOW:
+ etiLog.log(warn, "data underflow -> frame muted\n");
+ goto MUTE_SUBCHANNEL;
+ case MPEG_BUFFER_OVERFLOW:
+ etiLog.log(warn, "bitrate too high -> frame muted\n");
+ goto MUTE_SUBCHANNEL;
+ case MPEG_FILE_EMPTY:
+ if (do_rewind) {
+ etiLog.log(error, "file rewinded and still empty "
+ "-> frame muted\n");
+ goto MUTE_SUBCHANNEL;
+ }
+ else {
+ etiLog.log(info, "reach end of file -> rewinding\n");
+ rewind();
+ goto READ_SUBCHANNEL;
+ }
+ case MPEG_FILE_ERROR:
+ etiLog.log(alert, "can't read file (%i) -> frame muted\n", errno);
+ perror("");
+ goto MUTE_SUBCHANNEL;
+ case MPEG_SYNC_NOT_FOUND:
+ etiLog.log(alert, "mpeg sync not found, maybe is not a valid file "
+ "-> frame muted\n");
+ goto MUTE_SUBCHANNEL;
+ case MPEG_INVALID_FRAME:
+ etiLog.log(alert, "file is not a valid mpeg file "
+ "-> frame muted\n");
+ goto MUTE_SUBCHANNEL;
+ default:
+ if (result < 0) {
+ etiLog.log(alert,
+ "unknown error (code = %i) -> frame muted\n",
+ result);
+MUTE_SUBCHANNEL:
+ memset(buffer, 0, size);
+ }
+ else {
+ if (result < size) {
+ etiLog.log(warn, "bitrate too low from file "
+ "-> frame padded\n");
+ memset((char*)buffer + result, 0, size - result);
+ }
+
+ result = checkDabMpegFrame(buffer);
+ switch (result) {
+ case MPEG_FREQUENCY:
+ etiLog.log(error, "file has a frame with an invalid "
+ "frequency: %i, should be 48000 or 24000\n",
+ getMpegFrequency(buffer));
+ break;
+ case MPEG_PADDING:
+ etiLog.log(warn,
+ "file has a frame with padding bit set\n");
+ break;
+ case MPEG_COPYRIGHT:
+ result = 0;
+ break;
+ case MPEG_ORIGINAL:
+ result = 0;
+ break;
+ case MPEG_EMPHASIS:
+ etiLog.log(warn,
+ "file has a frame with emphasis bits set\n");
+ break;
+ default:
+ if (result < 0) {
+ etiLog.log(alert, "mpeg file has an invalid DAB "
+ "mpeg frame (unknown reason: %i)\n", result);
+ }
+ break;
+ }
+ }
+ }
+ return result;
+}
+
+int MPEGFile::setBitrate(int bitrate)
+{
+ if (bitrate == 0) {
+ char buffer[4];
+
+ if (readFrame(buffer, 4) == 0) {
+ bitrate = getMpegBitrate(buffer);
+ }
+ else {
+ bitrate = -1;
+ }
+ rewind();
+ }
+ return bitrate;
+}
+
+
+int DABPlusFile::readFrame(void* buffer, int size)
+{
+ uint8_t* dataOut = reinterpret_cast<uint8_t*>(buffer);
+
+ ssize_t ret = read(m_fd, dataOut, size);
+
+ if (ret == -1) {
+ etiLog.log(alert, "ERROR: Can't read file\n");
+ perror("");
+ return -1;
+ }
+
+ if (ret < size) {
+ ssize_t sizeOut = ret;
+ etiLog.log(info, "reach end of file -> rewinding\n");
+ if (rewind() == -1) {
+ etiLog.log(alert, "ERROR: Can't rewind file\n");
+ return -1;
+ }
+
+ ret = read(m_fd, dataOut + sizeOut, size - sizeOut);
+ if (ret == -1) {
+ etiLog.log(alert, "ERROR: Can't read file\n");
+ perror("");
+ return -1;
+ }
+
+ if (ret < size) {
+ etiLog.log(alert, "ERROR: Not enough data in file\n");
+ return -1;
+ }
+ }
+
+ return size;
+}
+
+int DABPlusFile::setBitrate(int bitrate)
+{
+ if (bitrate <= 0) {
+ etiLog.log(error, "Invalid bitrate (%i)\n", bitrate);
+ return -1;
+ }
+
+ return bitrate;
+}
+
+};
diff --git a/src/input/File.h b/src/input/File.h
new file mode 100644
index 0000000..61be8b1
--- /dev/null
+++ b/src/input/File.h
@@ -0,0 +1,69 @@
+/*
+ Copyright (C) 2009 Her Majesty the Queen in Right of Canada (Communications
+ Research Center Canada)
+
+ Copyright (C) 2016 Matthias P. Braendli
+ http://www.opendigitalradio.org
+
+ */
+/*
+ This file is part of ODR-DabMux.
+
+ ODR-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.
+
+ ODR-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 ODR-DabMux. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <vector>
+#include <string>
+#include <stdint.h>
+#include "input/inputs.h"
+#include "ManagementServer.h"
+
+namespace Inputs {
+
+class FileBase : public InputBase {
+ public:
+ virtual int open(const std::string& name);
+ virtual int readFrame(void* buffer, int size) = 0;
+ virtual int setBitrate(int bitrate) = 0;
+ virtual int close();
+
+ /* Rewind the file
+ * Returns -1 on failure, 0 on success
+ */
+ virtual int rewind();
+ protected:
+ // We use unix open() instead of fopen() because
+ // we want to do non-blocking I/O
+ int m_fd = -1;
+};
+
+class MPEGFile : public FileBase {
+ public:
+ virtual int readFrame(void* buffer, int size);
+ virtual int setBitrate(int bitrate);
+
+ private:
+ bool m_parity = false;
+};
+
+class DABPlusFile : public FileBase {
+ public:
+ virtual int readFrame(void* buffer, int size);
+ virtual int setBitrate(int bitrate);
+};
+
+
+};
diff --git a/src/input/Prbs.h b/src/input/Prbs.h
index 47b52ad..1ad5047 100644
--- a/src/input/Prbs.h
+++ b/src/input/Prbs.h
@@ -28,10 +28,6 @@
#pragma once
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
#include <string>
#include "input/inputs.h"
diff --git a/src/input/Zmq.cpp b/src/input/Zmq.cpp
index 6ef5fce..985fad3 100644
--- a/src/input/Zmq.cpp
+++ b/src/input/Zmq.cpp
@@ -41,13 +41,6 @@
#include "input/Zmq.h"
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#ifdef HAVE_INPUT_ZEROMQ
-
-#include "zmq.hpp"
#include <cstdio>
#include <cstdlib>
#include <list>
@@ -621,5 +614,3 @@ const string ZmqBase::get_parameter(const string& parameter) const
};
-#endif
-
diff --git a/src/input/Zmq.h b/src/input/Zmq.h
index d1dd2d5..02fce3a 100644
--- a/src/input/Zmq.h
+++ b/src/input/Zmq.h
@@ -43,12 +43,6 @@
#pragma once
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#ifdef HAVE_INPUT_ZEROMQ
-
#include <list>
#include <string>
#include <stdint.h>
@@ -266,6 +260,5 @@ class ZmqAAC : public ZmqBase {
};
};
-#endif // HAVE_INPUT_ZMQ
diff --git a/src/input/inputs.h b/src/input/inputs.h
new file mode 100644
index 0000000..3bc1fa4
--- /dev/null
+++ b/src/input/inputs.h
@@ -0,0 +1,52 @@
+/*
+ Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Her Majesty the Queen in
+ Right of Canada (Communications Research Center Canada)
+
+ Copyright (C) 2016
+ Matthias P. Braendli, matthias.braendli@mpb.li
+
+ http://www.opendigitalradio.org
+ */
+/*
+ This file is part of ODR-DabMux.
+
+ ODR-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.
+
+ ODR-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 ODR-DabMux. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include "Log.h"
+#include "RemoteControl.h"
+#include <string>
+
+namespace Inputs {
+
+/* New input object base */
+class InputBase {
+ public:
+ virtual int open(const std::string& name) = 0;
+ virtual int readFrame(void* buffer, int size) = 0;
+ virtual int setBitrate(int bitrate) = 0;
+ virtual int close() = 0;
+
+ virtual ~InputBase() {}
+ protected:
+ InputBase() {}
+};
+
+};
+
diff --git a/src/mpeg.c b/src/mpeg.c
index f7aed34..fb6591a 100644
--- a/src/mpeg.c
+++ b/src/mpeg.c
@@ -219,3 +219,29 @@ int readMpegFrame(int file, void* data, int size)
}
return framelength;
}
+
+int checkDabMpegFrame(void* data) {
+ mpegHeader* header = (mpegHeader*)data;
+ unsigned long* headerData = (unsigned long*)data;
+ if ((*headerData & 0x0f0ffcff) == 0x0004fcff) return 0;
+ if ((*headerData & 0x0f0ffcff) == 0x0004f4ff) return 0;
+ if (getMpegFrequency(header) != 48000) {
+ if (getMpegFrequency(header) != 24000) {
+ return MPEG_FREQUENCY;
+ }
+ }
+ if (header->padding != 0) {
+ return MPEG_PADDING;
+ }
+ if (header->copyright != 0) {
+ return MPEG_COPYRIGHT;
+ }
+ if (header->original != 0) {
+ return MPEG_ORIGINAL;
+ }
+ if (header->emphasis != 0) {
+ return MPEG_EMPHASIS;
+ }
+ return -1;
+}
+
diff --git a/src/mpeg.h b/src/mpeg.h
index aa7cfb6..15b9b80 100644
--- a/src/mpeg.h
+++ b/src/mpeg.h
@@ -75,6 +75,13 @@ ssize_t readData(int file, void* data, size_t size, unsigned int tries);
int readMpegHeader(int file, void* data, int size);
int readMpegFrame(int file, void* data, int size);
+#define MPEG_FREQUENCY -2
+#define MPEG_PADDING -3
+#define MPEG_COPYRIGHT -4
+#define MPEG_ORIGINAL -5
+#define MPEG_EMPHASIS -6
+int checkDabMpegFrame(void* data);
+
#ifdef __cplusplus
}
#endif