diff options
| author | Matthias P. Braendli <matthias.braendli@mpb.li> | 2016-10-30 16:28:27 +0100 | 
|---|---|---|
| committer | Matthias P. Braendli <matthias.braendli@mpb.li> | 2016-10-30 16:28:27 +0100 | 
| commit | 804fe1979f9ed7bef7badaf0aa08e35e09874772 (patch) | |
| tree | 93ae4728de598391ce6e72712676260831b0ecb2 | |
| parent | 128768f7fd719eb455a946a0f716d7128b4ded63 (diff) | |
| download | dabmux-804fe1979f9ed7bef7badaf0aa08e35e09874772.tar.gz dabmux-804fe1979f9ed7bef7badaf0aa08e35e09874772.tar.bz2 dabmux-804fe1979f9ed7bef7badaf0aa08e35e09874772.zip | |
Add rudimentary file input
No nonblock support yet
| -rw-r--r-- | src/ConfigParser.cpp | 11 | ||||
| -rw-r--r-- | src/Makefile.am | 1 | ||||
| -rw-r--r-- | src/dabInputMpegFile.cpp | 31 | ||||
| -rw-r--r-- | src/input/File.cpp | 227 | ||||
| -rw-r--r-- | src/input/File.h | 69 | ||||
| -rw-r--r-- | src/input/Prbs.h | 4 | ||||
| -rw-r--r-- | src/input/Zmq.cpp | 9 | ||||
| -rw-r--r-- | src/input/Zmq.h | 7 | ||||
| -rw-r--r-- | src/input/inputs.h | 52 | ||||
| -rw-r--r-- | src/mpeg.c | 26 | ||||
| -rw-r--r-- | src/mpeg.h | 7 | 
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() {} +}; + +}; + @@ -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; +} + @@ -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 | 
