/* Copyright (C) 2009, 2011 Her Majesty the Queen in Right of Canada (Communications Research Center Canada) */ /* 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 . */ #include "dabInputPacketFile.h" #include "dabInputFile.h" #include "dabInputFifo.h" #include "ReedSolomon.h" #ifdef HAVE_FORMAT_PACKET # ifdef HAVE_INPUT_FILE #include #include #include #ifdef _WIN32 # pragma pack(push, 1) #endif struct packetHeader { unsigned char addressHigh:2; unsigned char last:1; unsigned char first:1; unsigned char continuityIndex:2; unsigned char packetLength:2; unsigned char addressLow; unsigned char dataLength:7; unsigned char command; } #ifdef _WIN32 # pragma pack(pop) #else __attribute((packed)) #endif ; struct dabInputOperations dabInputPacketFileOperations = { dabInputFileInit, dabInputFileOpen, dabInputSetbuf, dabInputFileRead, NULL, NULL, dabInputPacketFileRead, dabInputSetbitrate, dabInputFileClose, dabInputFileClean, dabInputFileRewind }; int dabInputPacketFileRead(dabInputOperations* ops, void* args, void* buffer, int size) { dabInputFileData* data = (dabInputFileData*)args; unsigned char* dataBuffer = (unsigned char*)buffer; int written = 0; int length; packetHeader* header; int indexRow; int indexCol; while (written < size) { if (data->enhancedPacketWaiting > 0) { *dataBuffer = 192 - data->enhancedPacketWaiting; *dataBuffer /= 22; *dataBuffer <<= 2; *(dataBuffer++) |= 0x03; *(dataBuffer++) = 0xfe; indexCol = 188; indexCol += (192 - data->enhancedPacketWaiting) / 12; indexRow = 0; indexRow += (192 - data->enhancedPacketWaiting) % 12; for (int j = 0; j < 22; ++j) { if (data->enhancedPacketWaiting == 0) { *(dataBuffer++) = 0; } else { *(dataBuffer++) = data->enhancedPacketData[indexRow][indexCol]; if (++indexRow == 12) { indexRow = 0; ++indexCol; } --data->enhancedPacketWaiting; } } written += 24; if (data->enhancedPacketWaiting == 0) { data->enhancedPacketLength = 0; } } else if (data->packetLength != 0) { header = (packetHeader*)data->packetData; if (written + data->packetLength > (unsigned)size) { memset(dataBuffer, 0, 22); dataBuffer[22] = 0x60; dataBuffer[23] = 0x4b; length = 24; } else if (data->enhancedPacketData != NULL) { if (data->enhancedPacketLength + data->packetLength > (12 * 188)) { memset(dataBuffer, 0, 22); dataBuffer[22] = 0x60; dataBuffer[23] = 0x4b; length = 24; } else { memcpy(dataBuffer, data->packetData, data->packetLength); length = data->packetLength; data->packetLength = 0; } } else { memcpy(dataBuffer, data->packetData, data->packetLength); length = data->packetLength; data->packetLength = 0; } if (data->enhancedPacketData != NULL) { indexCol = data->enhancedPacketLength / 12; indexRow = data->enhancedPacketLength % 12; // TODO Check if always 0 for (int j = 0; j < length; ++j) { data->enhancedPacketData[indexRow][indexCol] = dataBuffer[j]; if (++indexRow == 12) { indexRow = 0; ++indexCol; } } data->enhancedPacketLength += length; if (data->enhancedPacketLength >= (12 * 188)) { data->enhancedPacketLength = (12 * 188); ReedSolomon encoder(204, 188); for (int j = 0; j < 12; ++j) { encoder.encode(data->enhancedPacketData[j], 188); } data->enhancedPacketWaiting = 192; } } written += length; dataBuffer += length; } else { int nbBytes = ops->read(args, dataBuffer, 3); header = (packetHeader*)dataBuffer; if (nbBytes == -1) { if (errno == EAGAIN) goto END_PACKET; perror("Packet file"); return -1; } else if (nbBytes == 0) { if (ops->rewind(args) == -1) { goto END_PACKET; } continue; } else if (nbBytes < 3) { etiLog.log(error, "Error while reading file for packet header; " "read %i out of 3 bytes\n", nbBytes); break; } length = header->packetLength * 24 + 24; if (written + length > size) { memcpy(data->packetData, header, 3); ops->read(args, &data->packetData[3], length - 3); data->packetLength = length; continue; } if (data->enhancedPacketData != NULL) { if (data->enhancedPacketLength + length > (12 * 188)) { memcpy(data->packetData, header, 3); ops->read(args, &data->packetData[3], length - 3); data->packetLength = length; continue; } } nbBytes = ops->read(args, dataBuffer + 3, length - 3); if (nbBytes == -1) { perror("Packet file"); return -1; } else if (nbBytes == 0) { etiLog.log(info, "Packet header read, but no data!\n"); if (ops->rewind(args) == -1) { goto END_PACKET; } continue; } else if (nbBytes < length - 3) { etiLog.log(error, "Error while reading packet file; " "read %i out of %i bytes\n", nbBytes, length - 3); break; } if (data->enhancedPacketData != NULL) { indexCol = data->enhancedPacketLength / 12; indexRow = data->enhancedPacketLength % 12; // TODO Check if always 0 for (int j = 0; j < length; ++j) { data->enhancedPacketData[indexRow][indexCol] = dataBuffer[j]; if (++indexRow == 12) { indexRow = 0; ++indexCol; } } data->enhancedPacketLength += length; if (data->enhancedPacketLength >= (12 * 188)) { if (data->enhancedPacketLength > (12 * 188)) { etiLog.log(error, "Error, too much enhanced packet data!\n"); } ReedSolomon encoder(204, 188); for (int j = 0; j < 12; ++j) { encoder.encode(data->enhancedPacketData[j], 188); } data->enhancedPacketWaiting = 192; } } written += length; dataBuffer += length; } } END_PACKET: if (ops->read == dabInputFifoRead) { dabInputFifoData* fifoData = (dabInputFifoData*)args; dabInputFifoStats* fifoStats = (dabInputFifoStats*)&fifoData->stats; fifoStats->frameRecords[fifoStats->frameCount].curSize = written; fifoStats->frameRecords[fifoStats->frameCount].maxSize = size; if (++fifoStats->frameCount == NB_RECORDS) { etiLog.log(info, "Packet subchannel usage: (%i)", fifoStats->id); for (int i = 0; i < fifoStats->frameCount; ++i) { etiLog.log(info, " %i/%i", fifoStats->frameRecords[i].curSize, fifoStats->frameRecords[i].maxSize); } etiLog.log(info, "\n"); fifoStats->frameCount = 0; } } while (written < size) { memset(dataBuffer, 0, 22); dataBuffer[22] = 0x60; dataBuffer[23] = 0x4b; dataBuffer += 24; written += 24; } return written; } # endif #endif