📄 dsmcc.h
字号:
#ifndef DSMCC_H#define DSMCC_H
#include <qmap.h>
#include "config.h"
#include "dsmcc_storage.h"
#include "dsmcc_biop.h"
#define DSM_CC_STRICT
// Master switch
//#define DSM_CC_TRACE_ON
// Granular tracing
#define DSM_CC_TRACE_CAROUSELTRACKER
#define DSM_CC_TRACE_DOWNLOADTRACKER
#define DSM_CC_TRACE_MODULETRACKER
#define DSM_CC_TRACE_STORAGE
// Making it work all together
#ifdef DSM_CC_TRACE_ON
# include <stdio.h>
# define dsmcc_trace printf
# define DSM_CC_TRACE_NUM(context, message, value, padto) printf("[DSMCC::" context "] " message " = %d (0x%0" padto "x)\n", (value), (value))
# define DSM_CC_TRACE_STR(context, message, value) printf("[DSMCC::" context "] " message " = \"%s\"\n", (value))
# define DSM_CC_TRACE_DUMP(context, message, buffer, length) if(length) printf("[DSMCC::" context "] " message " dump follows:\n"); DSM_CC::Private::hexdump(buffer, length)
# define DSM_CC_TRACE_GENERAL(context, message) printf("[DSMCC::" context "] " message "\n");
#else
# define dsmcc_trace DSM_CC::sink
# define DSM_CC_TRACE_NUM(context, message, value, padto)
# define DSM_CC_TRACE_STR(context, message, value)
# define DSM_CC_TRACE_DUMP(context, message, buffer, length)
# define DSM_CC_TRACE_GENERAL(context, message)
# undef DSM_CC_TRACE_CAROUSELTRACKER
# undef DSM_CC_TRACE_DOWNLOADTRACKER
# undef DSM_CC_TRACE_MODULETRACKER
# undef DSM_CC_TRACE_STORAGE
#endif
// From the MHEG profile
#define DSM_CC_MAX_BLOCK_SIZE 4066
#ifdef CONFIG_ZLIB#include <zlib.h>#endif
namespace DSM_CC {
namespace Private {
void hexdump(uint8_t* buffer, uint32_t length);
}
// The headers for DII and DDB messages are identical,
// but the semantics of one field changes. Luckily, the
// data type is the same in both cases, so we can make
// it all a union and treat it the same way everywhere.
typedef struct {
uint8_t protocol_discriminator;
uint8_t dsmcc_type;
uint16_t message_id;
union {
uint32_t download_id;
uint32_t transaction_id;
};
uint8_t adaptation_length;
uint16_t message_length;
uint32_t flat_size() {
return 12; // 11 + 1 for the reserved field which isn't shown here
}
} MessageHeader;
typedef struct {
MessageHeader header;
uint8_t* payload_pointer;
uint16_t module_id;
uint8_t module_version;
uint16_t block_number;
uint16_t payload_size;
} DownloadDataBlock;
typedef struct {
MessageHeader header;
uint32_t download_id;
uint16_t block_size;
uint16_t num_modules;
uint32_t flat_size() {
return header.flat_size() + 20;
}
} DownloadInfoIndication;
typedef struct {
uint16_t module_id;
uint8_t module_version;
uint32_t module_size;
uint32_t num_blocks;
uint16_t block_size;
uint8_t z_compression_method;
uint32_t z_original_size;
} tracked_module_t;
class ModuleTracker {
public:
ModuleTracker();
~ModuleTracker();
bool InterestedInObject(uint32_t object_key, uint8_t object_key_length);
void MarkObject(uint32_t object_key, uint8_t object_key_length, bool mark);
void SetParameters(const tracked_module_t& module);
bool HaveParameters() const {return have_module_info;}
tracked_module_t GetParameters() const {return tracked_module;}
bool ProcessDDB(const DownloadDataBlock& block);
bool Completed() const {return have_module_info && (received_blocks_count == tracked_module.num_blocks);}
uint8_t* Buffer() {return contents;}
private:
// Disabled
ModuleTracker(const ModuleTracker&);
ModuleTracker& operator = (const ModuleTracker&);
// Data
bool have_module_info;
tracked_module_t tracked_module;
uint32_t received_blocks_count;
uint32_t* received_blocks;
uint8_t* contents;
std::vector<uint64_t> interesting_objects;
};
class DownloadTracker {
public:
DownloadTracker(uint32_t id);
~DownloadTracker();
bool TrackModule(uint16_t module_id);
bool UntrackModule(uint16_t module_id);
bool ProcessDDB(const DownloadDataBlock& block);
bool ProcessDII(const DownloadInfoIndication& indication, const BIOP::DIIModuleLoopItem& mitem);
bool Completed() const {return num_modules_tracked == num_modules_completed;}
bool CompletedModule(uint16_t module_id) const {return module_trackers.contains(module_id) && module_trackers[module_id]->Completed();}
uint8_t* ModuleGetBuffer(uint16_t module_id) const {return CompletedModule(module_id) ? module_trackers[module_id]->Buffer() : 0;}
bool ModuleHaveParameters(uint16_t module_id) const {return module_trackers.contains(module_id) ? module_trackers[module_id]->HaveParameters() : false;}
tracked_module_t ModuleGetParameters(uint16_t module_id) const {return module_trackers.contains(module_id) ? module_trackers[module_id]->GetParameters() : tracked_module_t();}
bool ModuleSetParameters(const tracked_module_t& module);
void MarkObject(uint16_t module_id, uint32_t object_key, uint8_t object_key_length, bool mark);
bool InterestedInObject(uint16_t module_id, uint32_t object_key, uint8_t key_length);
private:
// Disabled
DownloadTracker();
DownloadTracker(const ModuleTracker&);
DownloadTracker& operator = (const ModuleTracker&);
typedef QMap<uint16_t, ModuleTracker*> module_tracker_map;
// Data
uint32_t download_id;
uint16_t num_modules_tracked;
uint16_t num_modules_completed;
module_tracker_map module_trackers;
uint32_t allocated_memory;
};
class DownloadControlTracker {
public:
void SetStatus(uint32_t transaction_id, uint8_t status) {
uint16_t id = (transaction_id & 0xffff) | 1;
uint16_t version = (transaction_id & 0xffff0000) >> 16;
tr_id_info_t info = {version, status};
transaction_ids[id] = info;
}
uint8_t GetStatus(uint32_t transaction_id) {
uint16_t id = (transaction_id & 0xffff) | 1;
if(!transaction_ids.contains(id)) {
return BIOP::UNKNOWN;
}
return transaction_ids[id].status;
}
uint16_t GetVersion(uint32_t transaction_id) {
uint16_t id = (transaction_id & 0xffff) | 1;
if(!transaction_ids.contains(id)) {
return 0;
}
return transaction_ids[id].version;
}
private:
typedef struct tr_id_info {
uint16_t version; // 2 MSB of transaction_id
uint8_t status; // are we interested in it or what?
} tr_id_info_t;
typedef QMap<uint16_t, tr_id_info_t> tr_id_info_map;
tr_id_info_map transaction_ids;
};
template<class StoragePolicy>
class CarouselTracker : public StoragePolicy {
public:
CarouselTracker() : data_message_trackers(new uint8_t[256]) {
if(data_message_trackers == 0) throw std::exception(); memset(data_message_trackers, BIOP::UNKNOWN, 256);
}
~CarouselTracker() {
typename download_tracker_map::const_iterator i;
for (i = download_trackers.begin(); i != download_trackers.end(); ++i) {
delete download_trackers[i.key()];
}
delete[] data_message_trackers;
}
void Clear() { typename download_tracker_map::const_iterator i;
for (i = download_trackers.begin(); i != download_trackers.end(); ++i) {
delete download_trackers[i.key()];
} download_trackers.clear(); download_stats.clear(); memset(data_message_trackers, BIOP::UNKNOWN, 256); }
bool CompletedDownload(uint32_t download_id) const {return download_trackers.contains(download_id) && download_trackers[download_id]->Completed();}
bool CompletedModule(uint32_t download_id, uint16_t module_id) const {return download_trackers.contains(download_id) && download_trackers[download_id]->CompletedModule(module_id);}
bool ProcessDownloadData(uint8_t component_tag, uint16_t table_id_ext, uint8_t* buffer) {
(void) table_id_ext;
// DDB messages are different from download control messages: they carry no transaction_id, // because only DDB messages from a single carousel may be present on the same stream. // Therefore, we shall just check if the stream we are receiving the DDB message from // contains data from a carousel we are interested in before trying to parse the DDB. if(!InterestedInDownloadData(component_tag)) { return true; } DownloadDataBlock datablock; if(!parse(datablock, buffer)) { return false; } if(!ProcessDDB(component_tag, datablock)) { return false; }
return true;
}
bool ProcessDownloadControl(uint8_t component_tag, uint16_t table_id_ext, uint8_t* buffer) {
MessageHeader header; parse(header, buffer);
// If this is not an ISO/IEC 13818-6 IS download message, no go
if(header.dsmcc_type != 0x03) {
return false;
}
// First of all, check if the transaction_id of this message could contain // anything we are interested in. Otherwise, no point in processing further.
if(!InterestedInDownloadControl(component_tag, header.transaction_id)) { return true; }
switch(header.message_id) { case 0x1002: // DownloadInfoIndication
DownloadInfoIndication dii; if(!parse(dii, buffer)) {
return false; }
// Reposition buffer to read groupinfo structures buffer += dii.flat_size(); BIOP::DIIModuleLoopItem mitem; for(uint16_t i = 0; i < dii.num_modules; ++i) { if(!parse(mitem, buffer)) {
return false; } buffer += (8 + mitem.module_info_length);
if(!ProcessDII(component_tag, dii, mitem)) {
return false;
} } break; case 0x1006: // DownloadServerInitiate // We should do a little parsing here, mainly to decide if this message // belongs to a Data Carousel or an Object Carousel. Otherwise, some of // this could be moved into BIOP::parse(ServiceGatewayInfo&, uint_8t*)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -