📄 dsmcc.h
字号:
// Skip first 22 bytes: the first 20 bytes must be 0xff, 21 and 22 must be 0x00 // Skip next two bytes: they hold the message length, our parser doesn't need it // Next 4 bytes (24 - 27) hold the datatype_id_length. Not relevant to us here. // What we want to do is check the first (and if it's an OC, only) 4 bytes of // the datatype_id, and decide if this is an OC. Normally this would not be needed // if enough descriptors were being given for the streams, but I 've seen many // cases where they are not.
buffer += header.flat_size(); uint32_t datatype_id = (buffer[28] << 24) | (buffer[29] << 16) | (buffer[30] << 8) | buffer[31]; // TR 101 202 specifies that in an Object Carousel, the identifier here will be // the null-terminated string "srg" ALWAYS, so the check is quite simple. if (datatype_id != BIOP_ALIAS_TYPE_ID_SRG) { return false; } else { BIOP::ServiceGatewayInfo sgi; if(!parse(sgi, &buffer[24])) {
return false; }
if(!ProcessDSI(component_tag, sgi, table_id_ext)) {
return false;
} } break; }
return true; }
bool StreamNeeded() {
return !streams_needed.empty();
}
uint8_t StreamTag() {
if(!StreamNeeded()) {
return 0;
}
uint8_t tag = streams_needed.back();
streams_needed.pop_back();
return tag;
}
private:
bool Track(uint32_t download_id, uint16_t table_id_ext) {
if(download_trackers.contains(download_id)) {
return false;
}
dsmcc_trace("[CarouselTracker] Now tracking download_id = 0x%08x, current table_id_ext is 0x%04x\n", download_id, table_id_ext);
download_trackers[download_id] = new DownloadTracker(download_id);
download_stats[download_id].last_table_id_ext = table_id_ext;
return true;
}
bool Untrack(uint32_t download_id) {
if(!download_trackers.contains(download_id)) {
return false;
}
delete download_trackers[download_id];
download_trackers.remove(download_id);
download_stats.remove(download_id);
return true;
}
bool Reset(uint32_t download_id, uint16_t table_id_ext) {
if(Untrack(download_id)) {
return Track(download_id, table_id_ext);
}
else {
return false;
}
}
uint8_t* ModuleGetBuffer(uint32_t download_id, uint16_t module_id) const {
return CompletedModule(download_id, module_id) ? download_trackers[download_id]->ModuleGetBuffer(module_id) : 0;
}
tracked_module_t ModuleGetParameters(uint32_t download_id, uint16_t module_id) const {
return download_trackers.contains(download_id) ? download_trackers[download_id]->ModuleGetParameters(module_id) : DSM_CC::tracked_module_t();
}
bool ModuleHaveParameters(uint32_t download_id, uint16_t module_id) const {
return download_trackers.contains(download_id) ? download_trackers[download_id]->ModuleHaveParameters(module_id) : false;
}
uint8_t* CopyModuleContents(uint32_t download_id, uint16_t module_id) const {
uint8_t* data(0);
if(!download_trackers.contains(download_id)) {
return data;
}
uint8_t* source = ModuleGetBuffer(download_id, module_id);
if(source == 0 || !ModuleHaveParameters(download_id, module_id)) {
return data;
}
tracked_module_t module = ModuleGetParameters(download_id, module_id);
if(module.z_compression_method == 0) {
// That's easy
data = new uint8_t[module.module_size];
if(data == 0) {
return data;
}
memcpy(data, source, module.module_size);
return data;
}
#ifdef Z_OK
data = new uint8_t[module.z_original_size];
if(data == 0) {
return data;
}
z_stream zstream;
zstream.next_in = source;
zstream.avail_in = module.module_size;
zstream.next_out = data;
zstream.avail_out = module.z_original_size;
zstream.zalloc = Z_NULL;
zstream.zfree = Z_NULL;
zstream.opaque = Z_NULL;
int status = inflateInit(&zstream);
if(status != Z_OK) {
delete[] data;
return data = 0;
}
status = inflate(&zstream, Z_FINISH);
if(status != Z_STREAM_END) {
delete[] data;
return data = 0;
}
status = inflateEnd(&zstream);
if(status != Z_OK) {
delete[] data;
return data = 0;
}
return data;
#endif
// This is reached if zlib is not included when building MythTV
// Tough luck, only uncompressed modules can be processed if so
return data;
}
bool ProcessDDB(uint8_t component_tag, const DownloadDataBlock& block) {
(void)component_tag;
if(!download_trackers.contains(block.header.download_id)) {
dsmcc_trace("[CarouselTracker] Rejected DDB for unknown download_id = 0x%08x\n", block.header.download_id);
return false;
}
// If the module has been completed, we don't need to do anything
if(CompletedModule(block.header.download_id, block.module_id)) { return true; }
if(!download_trackers[block.header.download_id]->ProcessDDB(block)) {
return false;
}
bool success = true;
// Now, maybe receiving this block resulted in the module becoming complete?
if(CompletedModule(block.header.download_id, block.module_id)) { tracked_module_t module = ModuleGetParameters(block.header.download_id, block.module_id); uint8_t* data = CopyModuleContents(block.header.download_id, block.module_id);
uint32_t size = module.z_compression_method ? module.z_original_size : module.module_size; if(data == 0) {
#ifdef DSM_CC_TRACE_CAROUSELTRACKER
DSM_CC_TRACE_NUM("CarouselTracker", "Failed to allocate memory for completed module with id", block.module_id, "4");
#endif
return false;
}
// One by one, process the BIOP messages in this module uint8_t* currentmessage = data;
while(currentmessage < data + size) { BIOP::MessageHeader header; BIOP::parse(header, currentmessage); uint32_t currentsize = header.flat_size() + header.message_body_length; switch(header.object_kind) { case BIOP_ALIAS_TYPE_ID_SRG: { BIOP::ServiceGateway srg; BIOP::parse(srg, currentmessage); success = ObjectArrived(block.header.download_id, block.module_id, srg); break; } case BIOP_ALIAS_TYPE_ID_DIR: { BIOP::DirectoryMessage dm; BIOP::parse(dm, currentmessage); success = ObjectArrived(block.header.download_id, block.module_id, dm); break; } case BIOP_ALIAS_TYPE_ID_FIL: { BIOP::FileMessage fm; BIOP::parse(fm, currentmessage); success = ObjectArrived(block.header.download_id, block.module_id, fm); break; }
case BIOP_ALIAS_TYPE_ID_STR: { BIOP::StreamMessage str; BIOP::parse(str, currentmessage); success = ObjectArrived(block.header.download_id, block.module_id, str); break; }
case BIOP_ALIAS_TYPE_ID_STE: { BIOP::StreamEventMessage ste; BIOP::parse(ste, currentmessage); success = ObjectArrived(block.header.download_id, block.module_id, ste); break; } default:
#ifdef DSM_CC_TRACE_CAROUSELTRACKER
DSM_CC_TRACE_NUM("CarouselTracker", "Unknown BIOP object kind", header.object_kind, "8");
#endif
success = false; }
if(!success) {
break;
}
currentmessage += currentsize; } delete[] data; }
//return true;
return success;
}
bool ProcessDII(uint8_t component_tag, const DownloadInfoIndication& indication, const BIOP::DIIModuleLoopItem& mitem) {
if(!download_trackers.contains(indication.download_id)) {
return false;
}
if(download_trackers[indication.download_id]->ProcessDII(indication, mitem)) {
#ifdef DSM_CC_TRACE_CAROUSELTRACKER
DSM_CC_TRACE_NUM("CarouselTracker", "Accepted from DII module_id", mitem.module_id, "8");
#endif
// The download tracker has accepted it as interesting, therefore we must begin
// accepting DDBs for this module. Also, mark the current version of the download
// control message as already available (not interesting anymore)
MarkDownloadData(mitem.module_info.tap.assoc_tag, BIOP::REQUESTED);
MarkDownloadControl(component_tag, indication.header.transaction_id, BIOP::AVAILABLE);
return true;
}
return false;
}
bool ProcessDSI(uint8_t component_tag, const BIOP::ServiceGatewayInfo& sgi, uint16_t table_id_ext) {
#ifdef DSM_CC_STRICT
if(component_tag == 0) {
DSM_CC_TRACE_GENERAL("CarouselTracker", "ERROR: Incoming DSI message has no component_tag identity");
return false;
}
#endif
if(sgi.ior.profiles[0].id_tag != BIOP_PROFILE_ID_BIOP) {
return false;
}
const BIOP::BIOPProfile& profile = sgi.ior.profiles[0].biop;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -