/*
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
Her Majesty the Queen in Right of Canada (Communications Research
Center Canada)
Copyrigth (C) 2018
Matthias P. Braendli, matthias.braendli@mpb.li
Input module for reading the ETI data from file or pipe, or ZeroMQ.
Supported file formats: RAW, FRAMED, STREAMED
Supports re-sync to RAW ETI file
*/
/*
This file is part of ODR-DabMod.
ODR-DabMod 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-DabMod 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-DabMod. If not, see .
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include
#include
#include
#include
#include
#include
#include "InputReader.h"
#include "PcDebug.h"
int InputFileReader::Open(std::string filename, bool loop)
{
filename_ = filename;
loop_ = loop;
FILE* fd = fopen(filename_.c_str(), "r");
if (fd == nullptr) {
etiLog.level(error) << "Unable to open input file!";
perror(filename_.c_str());
return -1;
}
inputfile_.reset(fd);
return IdentifyType();
}
int InputFileReader::Rewind()
{
rewind(inputfile_.get()); // Also clears the EOF flag
return IdentifyType();
}
int InputFileReader::IdentifyType()
{
EtiStreamType streamType = EtiStreamType::None;
struct stat inputFileStat;
fstat(fileno(inputfile_.get()), &inputFileStat);
inputfilelength_ = inputFileStat.st_size;
uint32_t sync;
uint32_t nbFrames;
uint16_t frameSize;
char discard_buffer[6144];
if (fread(&sync, sizeof(sync), 1, inputfile_.get()) != 1) {
etiLog.level(error) << "Unable to read sync in input file!";
perror(filename_.c_str());
return -1;
}
if ((sync == 0x49c5f8ff) || (sync == 0xb63a07ff)) {
streamType = EtiStreamType::Raw;
if (inputfilelength_ > 0) {
nbframes_ = inputfilelength_ / 6144;
}
else {
nbframes_ = ~0;
}
if (fseek(inputfile_.get(), -sizeof(sync), SEEK_CUR) != 0) {
// if the seek fails, consume the rest of the frame
if (fread(discard_buffer, 6144 - sizeof(sync), 1, inputfile_.get())
!= 1) {
etiLog.level(error) << "Unable to read from input file!";
perror(filename_.c_str());
return -1;
}
}
this->streamtype_ = streamType;
return 0;
}
nbFrames = sync;
if (fread(&frameSize, sizeof(frameSize), 1, inputfile_.get()) != 1) {
etiLog.level(error) << "Unable to read frame size in input file!";
perror(filename_.c_str());
return -1;
}
sync >>= 16;
sync &= 0xffff;
sync |= ((uint32_t)frameSize) << 16;
if ((sync == 0x49c5f8ff) || (sync == 0xb63a07ff)) {
streamType = EtiStreamType::Streamed;
frameSize = nbFrames & 0xffff;
if (inputfilelength_ > 0) {
nbframes_ = inputfilelength_ / (frameSize + 2);
}
else {
nbframes_ = ~0;
}
if (fseek(inputfile_.get(), -6, SEEK_CUR) != 0) {
// if the seek fails, consume the rest of the frame
if (fread(discard_buffer, frameSize - 4, 1, inputfile_.get())
!= 1) {
etiLog.level(error) << "Unable to read from input file!";
perror(filename_.c_str());
return -1;
}
}
this->streamtype_ = streamType;
return 0;
}
if (fread(&sync, sizeof(sync), 1, inputfile_.get()) != 1) {
etiLog.level(error) << "Unable to read nb frame in input file!";
perror(filename_.c_str());
return -1;
}
if ((sync == 0x49c5f8ff) || (sync == 0xb63a07ff)) {
streamType = EtiStreamType::Framed;
if (fseek(inputfile_.get(), -6, SEEK_CUR) != 0) {
// if the seek fails, consume the rest of the frame
if (fread(discard_buffer, frameSize - 4, 1, inputfile_.get())
!= 1) {
etiLog.level(error) << "Unable to read from input file!";
perror(filename_.c_str());
return -1;
}
}
this->streamtype_ = streamType;
nbframes_ = ~0;
return 0;
}
// Search for the sync marker byte by byte
for (size_t i = 10; i < 6144 + 10; ++i) {
sync >>= 8;
sync &= 0xffffff;
if (fread((uint8_t*)&sync + 3, 1, 1, inputfile_.get()) != 1) {
etiLog.level(error) << "Unable to read from input file!";
perror(filename_.c_str());
return -1;
}
if ((sync == 0x49c5f8ff) || (sync == 0xb63a07ff)) {
streamType = EtiStreamType::Raw;
if (inputfilelength_ > 0) {
nbframes_ = (inputfilelength_ - i) / 6144;
}
else {
nbframes_ = ~0;
}
if (fseek(inputfile_.get(), -sizeof(sync), SEEK_CUR) != 0) {
if (fread(discard_buffer, 6144 - sizeof(sync), 1, inputfile_.get())
!= 1) {
etiLog.level(error) << "Unable to read from input file!";
perror(filename_.c_str());
return -1;
}
}
this->streamtype_ = streamType;
return 0;
}
}
etiLog.level(error) << "Bad input file format!";
return -1;
}
std::string InputFileReader::GetPrintableInfo() const
{
std::string info = "Input file format: ";
switch (streamtype_) {
case EtiStreamType::Raw:
info += "raw";
break;
case EtiStreamType::Streamed:
info += "streamed";
break;
case EtiStreamType::Framed:
info += "framed";
break;
default:
info += "unknown!";
break;
}
info += ", length: " + std::to_string(inputfilelength_);
if (~nbframes_ != 0) {
info += ", nb frames: " + std::to_string(nbframes_);
}
else {
info += ", nb frames: endless";
}
return info;
}
int InputFileReader::GetNextFrame(void* buffer)
{
uint16_t frameSize;
if (streamtype_ == EtiStreamType::Raw) {
frameSize = 6144;
}
else {
if (fread(&frameSize, sizeof(frameSize), 1, inputfile_.get()) != 1) {
etiLog.level(error) << "Reached end of file.";
if (loop_) {
if (Rewind() == 0) {
if (fread(&frameSize, sizeof(frameSize), 1, inputfile_.get()) != 1) {
PDEBUG("Error after rewinding file!\n");
etiLog.level(error) << "Error after rewinding file!";
return -1;
}
}
else {
PDEBUG("Impossible to rewind file!\n");
etiLog.level(error) << "Impossible to rewind file!";
return -1;
}
}
else {
return 0;
}
}
}
if (frameSize > 6144) { // there might be a better limit
etiLog.level(error) << "Wrong frame size " << frameSize << " in ETI file!";
return -1;
}
PDEBUG("Frame size: %u\n", frameSize);
size_t read_bytes = fread(buffer, 1, frameSize, inputfile_.get());
if ( loop_ &&
streamtype_ == EtiStreamType::Raw && //implies frameSize == 6144
read_bytes == 0 && feof(inputfile_.get())) {
// in case of an EOF from a RAW that we loop, rewind
// otherwise, we won't tolerate it
if (Rewind() == 0) {
read_bytes = fread(buffer, 1, frameSize, inputfile_.get());
}
else {
PDEBUG("Impossible to rewind file!\n");
etiLog.level(error) << "Impossible to rewind file!";
return -1;
}
}
if (read_bytes != frameSize) {
// A short read of a frame (i.e. reading an incomplete frame)
// is not tolerated. Input files must not contain incomplete frames
if (read_bytes != 0) {
etiLog.level(error) <<
"Unable to read a complete frame of " << frameSize << " data bytes from input file!";
return -1;
}
else {
return 0;
}
}
memset(&((uint8_t*)buffer)[frameSize], 0x55, 6144 - frameSize);
return 6144;
}