int mxf_read_partition(MXFFile *mxfFile, const mxfKey *key, uint64_t len, MXFPartition **partition) { MXFPartition *newPartition; uint32_t numLabels; uint32_t labelLen; mxfUL label; uint64_t expectedLen; uint32_t i; CHK_ORET(len >= 88 && len <= INT64_MAX); CHK_ORET(mxf_create_partition(&newPartition)); newPartition->key = *key; CHK_OFAIL(mxf_read_uint16(mxfFile, &newPartition->majorVersion)); CHK_OFAIL(mxf_read_uint16(mxfFile, &newPartition->minorVersion)); CHK_OFAIL(mxf_read_uint32(mxfFile, &newPartition->kagSize)); CHK_OFAIL(mxf_read_uint64(mxfFile, &newPartition->thisPartition)); CHK_OFAIL(mxf_read_uint64(mxfFile, &newPartition->previousPartition)); CHK_OFAIL(mxf_read_uint64(mxfFile, &newPartition->footerPartition)); CHK_OFAIL(mxf_read_uint64(mxfFile, &newPartition->headerByteCount)); CHK_OFAIL(mxf_read_uint64(mxfFile, &newPartition->indexByteCount)); CHK_OFAIL(mxf_read_uint32(mxfFile, &newPartition->indexSID)); CHK_OFAIL(mxf_read_uint64(mxfFile, &newPartition->bodyOffset)); CHK_OFAIL(mxf_read_uint32(mxfFile, &newPartition->bodySID)); CHK_OFAIL(mxf_read_ul(mxfFile, &newPartition->operationalPattern)); CHK_OFAIL(mxf_read_batch_header(mxfFile, &numLabels, &labelLen)); CHK_OFAIL(numLabels == 0 || labelLen == 16); expectedLen = 88 + (uint64_t)numLabels * labelLen; CHK_OFAIL(len >= expectedLen); for (i = 0; i < numLabels; i++) { CHK_OFAIL(mxf_read_ul(mxfFile, &label)); CHK_OFAIL(mxf_append_partition_esscont_label(newPartition, &label)); } if (len > expectedLen) { mxf_log_warn("Partition pack len %" PRIu64 " is larger than expected len %" PRIu64 "\n", len, expectedLen); CHK_OFAIL(mxf_file_seek(mxfFile, (int64_t)(len - expectedLen), SEEK_CUR)); } *partition = newPartition; return 1; fail: mxf_free_partition(&newPartition); return 0; }
int mxf_read_and_return_set(MXFFile* mxfFile, const mxfKey* key, uint64_t len, MXFHeaderMetadata* headerMetadata, int addToHeaderMetadata, MXFMetadataSet** set) { MXFMetadataSet* newSet = NULL; MXFSetDef* setDef = NULL; uint64_t totalLen = 0; mxfLocalTag itemTag; uint16_t itemLen; int haveInstanceUID = 0; mxfKey itemKey; MXFItemDef* itemDef = NULL; MXFMetadataItem* newItem; assert(headerMetadata->primerPack != NULL); /* only read sets with known definitions */ if (mxf_find_set_def(headerMetadata->dataModel, key, &setDef)) { CHK_ORET(create_empty_set(key, &newSet)); /* read each item in the set*/ haveInstanceUID = 0; do { CHK_OFAIL(mxf_read_item_tl(mxfFile, &itemTag, &itemLen)); /* check the item tag is registered in the primer */ if (mxf_get_item_key(headerMetadata->primerPack, itemTag, &itemKey)) { /* only read items with known definition */ if (mxf_find_item_def_in_set_def(&itemKey, setDef, &itemDef)) { CHK_OFAIL(mxf_create_item(newSet, &itemKey, itemTag, &newItem)); newItem->isPersistent = 1; CHK_OFAIL(mxf_read_item(mxfFile, newItem, itemLen)); if (mxf_equals_key(&MXF_ITEM_K(InterchangeObject, InstanceUID), &itemKey)) { mxf_get_uuid(newItem->value, &newSet->instanceUID); haveInstanceUID = 1; } } /* skip items with unknown definition */ else { CHK_OFAIL(mxf_skip(mxfFile, (int64_t)itemLen)); } } /* skip items not registered in the primer. Log warning because the file is invalid */ else { mxf_log_warn("Encountered item with tag %d not registered in the primer" LOG_LOC_FORMAT, itemTag, LOG_LOC_PARAMS); CHK_OFAIL(mxf_skip(mxfFile, (int64_t)itemLen)); } totalLen += 4 + itemLen; } while (totalLen < len); if (totalLen != len) { mxf_log_error("Incorrect metadata set length encountered" LOG_LOC_FORMAT, LOG_LOC_PARAMS); goto fail; } if (!haveInstanceUID) { mxf_log_error("Metadata set does not have InstanceUID item" LOG_LOC_FORMAT, LOG_LOC_PARAMS); goto fail; } /* ok to add set */ if (addToHeaderMetadata) { CHK_OFAIL(mxf_add_set(headerMetadata, newSet)); } *set = newSet; return 1; } /* skip the set if the def is unknown */ CHK_ORET(mxf_skip(mxfFile, (int64_t)len)); *set = NULL; return 2; fail: mxf_free_set(&newSet); return 0; }
int mxf_page_file_forward_truncate(MXFPageFile *mxfPageFile) { MXFFileSysData *sysData = mxfPageFile->mxfFile->sysData; int page = (int)(sysData->position / sysData->pageSize); int i; char filename[4096]; #if defined(_WIN32) int fileid; #endif if (sysData->mode == READ_MODE) { mxf_log_error("Cannot forward truncate read-only mxf page file\n"); return 0; } /* close and truncate to zero length page files before the current one */ for (i = 0; i < page; i++) { if (sysData->pages[i].wasRemoved) { continue; } if (sysData->pages[i].fileDescriptor != NULL) { /* close the file */ disk_file_close(sysData->pages[i].fileDescriptor); /* remove the file descriptor from the list */ if (sysData->fileDescriptorHead == sysData->pages[i].fileDescriptor) { sysData->fileDescriptorHead = sysData->fileDescriptorHead->next; } else { sysData->pages[i].fileDescriptor->prev->next = sysData->pages[i].fileDescriptor->next; } if (sysData->fileDescriptorTail == sysData->pages[i].fileDescriptor) { sysData->fileDescriptorTail = sysData->fileDescriptorTail->prev; } else { sysData->pages[i].fileDescriptor->next->prev = sysData->pages[i].fileDescriptor->prev; } SAFE_FREE(sysData->pages[i].fileDescriptor); } /* truncate the file to zero length */ mxf_snprintf(filename, sizeof(filename), sysData->filenameTemplate, sysData->pages[i].index); #if defined(_WIN32) /* WIN32 does not have truncate() so open the file with _O_TRUNC then close it */ if ((fileid = _open(filename, _O_CREAT | _O_TRUNC, _S_IWRITE)) == -1 || _close(fileid) == -1) #else if (truncate(filename, 0) != 0) #endif { mxf_log_warn("Failed to truncate '%s' to zero length: %s\n", filename, strerror(errno)); } sysData->pages[i].wasRemoved = 1; } return 1; }
static int open_file(MXFFileSysData *sysData, Page *page) { FILE *newFile = NULL; char filename[4096]; FileDescriptor *newFileDescriptor = NULL; if (page->wasRemoved) { mxf_log_warn("Failed to open mxf page file which was removed after truncation\n"); return 0; } /* move file descriptor to tail if already open, and return */ if (page->fileDescriptor != NULL) { if (page->fileDescriptor == sysData->fileDescriptorTail) { return 1; } /* extract file descriptor */ if (page->fileDescriptor->next != NULL) { page->fileDescriptor->next->prev = page->fileDescriptor->prev; } if (page->fileDescriptor->prev != NULL) { page->fileDescriptor->prev->next = page->fileDescriptor->next; } if (sysData->fileDescriptorHead == page->fileDescriptor) { sysData->fileDescriptorHead = page->fileDescriptor->next; } /* put file descriptor at tail */ page->fileDescriptor->next = NULL; page->fileDescriptor->prev = sysData->fileDescriptorTail; if (sysData->fileDescriptorTail != NULL) { sysData->fileDescriptorTail->next = page->fileDescriptor; } sysData->fileDescriptorTail = page->fileDescriptor; return 1; } /* close the least used file descriptor (the head) if too many file descriptors are open */ if (sysData->numFileDescriptors >= MAX_FILE_DESCRIPTORS) { if (sysData->fileDescriptorTail == sysData->fileDescriptorHead) { /* single file descriptor */ sysData->fileDescriptorHead->page->fileDescriptor = NULL; disk_file_close(sysData->fileDescriptorHead); SAFE_FREE(sysData->fileDescriptorHead); sysData->fileDescriptorHead = NULL; sysData->fileDescriptorTail = NULL; sysData->numFileDescriptors--; } else { /* multiple file descriptors */ FileDescriptor *newHead = sysData->fileDescriptorHead->next; sysData->fileDescriptorHead->page->fileDescriptor = NULL; disk_file_close(sysData->fileDescriptorHead); SAFE_FREE(sysData->fileDescriptorHead); sysData->fileDescriptorHead = newHead; newHead->prev = NULL; sysData->numFileDescriptors--; } } /* open the file */ mxf_snprintf(filename, sizeof(filename), sysData->filenameTemplate, page->index); switch (sysData->mode) { case READ_MODE: newFile = fopen(filename, "rb"); break; case WRITE_MODE: if (!page->wasOpenedBefore) { newFile = fopen(filename, "w+b"); } else { newFile = fopen(filename, "r+b"); } break; case MODIFY_MODE: newFile = fopen(filename, "r+b"); if (newFile == NULL) { newFile = fopen(filename, "w+b"); } break; } if (newFile == NULL) { mxf_log_error("Failed to open paged mxf file '%s': %s\n", filename, strerror(errno)); return 0; } /* create the new file descriptor */ CHK_MALLOC_OFAIL(newFileDescriptor, FileDescriptor); memset(newFileDescriptor, 0, sizeof(*newFileDescriptor)); newFileDescriptor->file = newFile; newFile = NULL; newFileDescriptor->page = page; page->fileDescriptor = newFileDescriptor; page->wasOpenedBefore = 1; page->offset = 0; if (sysData->fileDescriptorTail != NULL) { sysData->fileDescriptorTail->next = newFileDescriptor; } newFileDescriptor->prev = sysData->fileDescriptorTail; sysData->fileDescriptorTail = newFileDescriptor; if (sysData->fileDescriptorHead == NULL) { sysData->fileDescriptorHead = newFileDescriptor; } sysData->numFileDescriptors++; return 1; fail: if (newFile != NULL) { fclose(newFile); } return 0; }
int op1a_initialise_reader(MXFReader *reader, MXFPartition **headerPartition) { MXFFile *mxfFile = reader->mxfFile; EssenceReader *essenceReader = reader->essenceReader; EssenceReaderData *data; size_t i; size_t numPartitions; MXFPartition *partition; mxfKey key; uint8_t llen; uint64_t len; essenceReader->data = NULL; /* init essence reader */ CHK_MALLOC_OFAIL(essenceReader->data, EssenceReaderData); memset(essenceReader->data, 0, sizeof(EssenceReaderData)); essenceReader->data->headerPartition = *headerPartition; essenceReader->close = op1a_close; essenceReader->position_at_frame = op1a_position_at_frame; essenceReader->skip_next_frame = op1a_skip_next_frame; essenceReader->read_next_frame = op1a_read_next_frame; essenceReader->get_next_frame_number = op1a_get_next_frame_number; essenceReader->get_last_written_frame_number = op1a_get_last_written_frame_number; essenceReader->get_header_metadata = op1a_get_header_metadata; essenceReader->have_footer_metadata = op1a_have_footer_metadata; essenceReader->set_frame_rate = op1a_set_frame_rate; data = essenceReader->data; if (mxf_file_is_seekable(mxfFile)) { /* get the file partitions */ CHK_OFAIL(get_file_partitions(mxfFile, data->headerPartition, &data->partitions)); /* process the last instance of header metadata */ numPartitions = mxf_get_list_length(&data->partitions); for (i = numPartitions; i > 0; i--) { partition = (MXFPartition*)mxf_get_list_element(&data->partitions, i - 1); if (partition->headerByteCount != 0) { if (!mxf_partition_is_closed(&partition->key)) { mxf_log_warn("No closed partition with header metadata found" LOG_LOC_FORMAT, LOG_LOC_PARAMS); } if (!mxf_partition_is_complete(&partition->key)) { mxf_log_warn("No complete partition with header metadata found" LOG_LOC_FORMAT, LOG_LOC_PARAMS); } /* seek to start of partition and skip the partition pack */ CHK_OFAIL(mxf_file_seek(mxfFile, partition->thisPartition, SEEK_SET)); CHK_OFAIL(mxf_read_kl(mxfFile, &key, &llen, &len)); CHK_OFAIL(mxf_skip(mxfFile, len)); CHK_OFAIL(process_metadata(reader, partition)); if (mxf_is_footer_partition_pack(&partition->key)) { data->haveFooterMetadata = 1; } break; } } if (i == 0) { mxf_log_error("No partition with header metadata found" LOG_LOC_FORMAT, LOG_LOC_PARAMS); goto fail; } if (!reader->isMetadataOnly) { /* create file index */ CHK_OFAIL(create_index(mxfFile, &data->partitions, data->indexSID, data->bodySID, &data->index)); /* position at start of essence */ CHK_OFAIL(set_position(mxfFile, data->index, 0)); } } else { essenceReader->data->nsIndex.currentPosition = -1; /* process the header metadata */ if (!mxf_partition_is_closed(&data->headerPartition->key)) { mxf_log_warn("Header partition is not closed" LOG_LOC_FORMAT, LOG_LOC_PARAMS); } if (!mxf_partition_is_complete(&data->headerPartition->key)) { mxf_log_warn("Header partition is incomplete" LOG_LOC_FORMAT, LOG_LOC_PARAMS); } CHK_OFAIL(process_metadata(reader, data->headerPartition)); if (!reader->isMetadataOnly) { /* position at start of essence */ CHK_OFAIL(ns_position_at_first_frame(reader)); } } *headerPartition = NULL; /* take ownership */ return 1; fail: reader->essenceReader->data->headerPartition = NULL; /* release ownership */ /* essenceReader->close() will be called when closing the reader */ return 0; }