int mxf_read_next_nonfiller_kl(MXFFile *mxfFile, mxfKey *key, uint8_t *llen, uint64_t *len) { mxfKey tkey; uint8_t tllen; uint64_t tlen; CHK_ORET(mxf_read_kl(mxfFile, &tkey, &tllen, &tlen)); while (mxf_is_filler(&tkey)) { CHK_ORET(mxf_skip(mxfFile, (int64_t)tlen)); CHK_ORET(mxf_read_kl(mxfFile, &tkey, &tllen, &tlen)); } *key = tkey; *llen = tllen; *len = tlen; return 1; }
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; }
/* Read primer pack followed by sets. The inputs pkey, pllen, plen must correspond to that for the primer pack */ int mxf_read_filtered_header_metadata(MXFFile* mxfFile, MXFReadFilter* filter, MXFHeaderMetadata* headerMetadata, uint64_t headerByteCount, const mxfKey* pkey, uint8_t pllen, uint64_t plen) { mxfKey key; uint8_t llen; uint64_t len; int skip = 0; MXFMetadataSet* newSet = NULL; uint64_t count = 0; int result; CHK_ORET(headerByteCount != 0); /* check that input pkey is as expected, and assume pllen and plen are also ok */ CHK_ORET(mxf_is_primer_pack(pkey)); count += mxfKey_extlen + pllen; if (headerMetadata->primerPack != NULL) { mxf_free_primer_pack(&headerMetadata->primerPack); } CHK_ORET(mxf_read_primer_pack(mxfFile, &headerMetadata->primerPack)); count += plen; while (count < headerByteCount) { CHK_ORET(mxf_read_kl(mxfFile, &key, &llen, &len)); count += mxfKey_extlen + llen; if (mxf_is_filler(&key)) { CHK_ORET(mxf_skip(mxfFile, len)); } else { if (filter != NULL) { /* signal before read */ skip = 0; if (filter->before_set_read != NULL) { CHK_ORET(filter->before_set_read(filter->privateData, headerMetadata, &key, llen, len, &skip)); } if (!skip) { CHK_ORET((result = mxf_read_and_return_set(mxfFile, &key, len, headerMetadata, 0, &newSet)) > 0); if (result == 1) /* set was read and returned in "set" parameter */ { /* signal after read */ skip = 0; if (filter->after_set_read != NULL) { CHK_OFAIL(filter->after_set_read(filter->privateData, headerMetadata, newSet, &skip)); } if (!skip) { CHK_OFAIL(mxf_add_set(headerMetadata, newSet)); } else { mxf_free_set(&newSet); } } } else { CHK_ORET(mxf_skip(mxfFile, len)); } } else { CHK_ORET(mxf_read_set(mxfFile, &key, len, headerMetadata, 1) > 0); } } count += len; } CHK_ORET(count == headerByteCount); return 1; fail: mxf_free_set(&newSet); return 0; }
static int ns_read_content_package(MXFReader *reader, int skip, MXFReaderListener *listener) { MXFFile *mxfFile = reader->mxfFile; EssenceReader *essenceReader = reader->essenceReader; EssenceReaderData *data = essenceReader->data; NSFileIndex *nsIndex = &data->nsIndex; EssenceTrack *essenceTrack; uint8_t *buffer; mxfKey key; uint8_t llen; uint64_t len; uint64_t cpCount; int trackIndex; /* must be positioned at start of a content package */ CHK_ORET(mxf_equals_key(&nsIndex->nextKey, &nsIndex->startContentPackageKey)); /* get KL read previously */ key = nsIndex->nextKey; llen = nsIndex->nextLLen; len = nsIndex->nextLen; cpCount = mxfKey_extlen + llen; /* process essence elements in content package */ while (nsIndex->contentPackageLen == 0 || cpCount <= nsIndex->contentPackageLen) { if (!skip && mxf_is_gc_essence_element(&key)) { if (get_essence_track_with_tracknumber(essenceReader, mxf_get_track_number(&key), &essenceTrack, &trackIndex)) { /* send data to listener */ if (accept_frame(listener, trackIndex)) { if (listener && listener->allocate_buffer(listener, trackIndex, &buffer, len)) { CHK_ORET(mxf_file_read(mxfFile, buffer, len) == len); CHK_ORET(send_frame(reader, listener, trackIndex, buffer, len)); } else { CHK_ORET(mxf_skip(mxfFile, len)); } } else { CHK_ORET(mxf_skip(mxfFile, len)); } cpCount += len; } else if (element_is_known_system_item(&key)) { CHK_ORET(extract_system_item_info(reader, &key, len, reader->essenceReader->data->nsIndex.currentPosition)); cpCount += len; } else { CHK_ORET(mxf_skip(mxfFile, len)); cpCount += len; } } else { CHK_ORET(mxf_skip(mxfFile, len)); cpCount += len; } if (!mxf_read_kl(mxfFile, &key, &llen, &len)) { CHK_ORET(mxf_file_eof(mxfFile)); ns_set_next_kl(nsIndex, &g_Null_Key, 0, 0); break; } ns_set_next_kl(nsIndex, &key, llen, len); cpCount += mxfKey_extlen + llen; /* if don't know the length of the content package then look out for the first element key or the start of a new partition */ if (nsIndex->contentPackageLen == 0 && (mxf_is_partition_pack(&key) || mxf_equals_key(&key, &nsIndex->startContentPackageKey))) { break; } } CHK_ORET(nsIndex->contentPackageLen == 0 || cpCount == nsIndex->contentPackageLen + mxfKey_extlen + llen); /* set content package length if it was unknown */ if (nsIndex->contentPackageLen == 0) { nsIndex->contentPackageLen = cpCount - mxfKey_extlen - llen; } return 1; }
static int read_content_package(MXFReader *reader, int skip, MXFReaderListener *listener) { MXFFile *mxfFile = reader->mxfFile; EssenceReader *essenceReader = reader->essenceReader; EssenceReaderData *data = essenceReader->data; FileIndex *index = data->index; EssenceTrack *essenceTrack; uint8_t *buffer; uint64_t bufferSize; mxfKey key; uint8_t llen; uint64_t len; uint64_t cpLen; uint64_t cpCount; int trackIndex; get_next_kl(index, &key, &llen, &len); cpLen = get_cp_len(index); cpCount = mxfKey_extlen + llen; /* process essence elements in content package */ while (cpCount <= cpLen) { if (!skip && mxf_is_gc_essence_element(&key)) { /* send data to listener */ if (get_essence_track_with_tracknumber(essenceReader, mxf_get_track_number(&key), &essenceTrack, &trackIndex)) { if (accept_frame(listener, trackIndex)) { CHK_ORET(read_frame(reader, listener, trackIndex, len, &buffer, &bufferSize)); CHK_ORET(send_frame(reader, listener, trackIndex, buffer, bufferSize)); } else { CHK_ORET(mxf_skip(mxfFile, len)); } cpCount += len; } else if (element_is_known_system_item(&key)) { CHK_ORET(extract_system_item_info(reader, &key, len, get_current_position(reader->essenceReader->data->index))); cpCount += len; } else { CHK_ORET(mxf_skip(mxfFile, len)); cpCount += len; } } else { CHK_ORET(mxf_skip(mxfFile, len)); cpCount += len; } if (!mxf_read_kl(mxfFile, &key, &llen, &len)) { CHK_ORET(mxf_file_eof(mxfFile)); set_next_kl(index, &g_Null_Key, 0, 0); break; } set_next_kl(index, &key, llen, len); cpCount += mxfKey_extlen + llen; } CHK_ORET(cpCount == cpLen + mxfKey_extlen + llen); return 1; }
static int ns_pos_at_next_frame(MXFReader *reader) { MXFFile *mxfFile = reader->mxfFile; EssenceReader *essenceReader = reader->essenceReader; EssenceReaderData *data = essenceReader->data; NSFileIndex *nsIndex = &data->nsIndex; MXFPartition *partition = NULL; mxfKey key; uint8_t llen; uint64_t len; int atEOF; /* move to next partition if at end of current partition */ if (mxf_is_partition_pack(&nsIndex->nextKey)) { key = nsIndex->nextKey; llen = nsIndex->nextLLen; len = nsIndex->nextLen; atEOF = 0; while (!atEOF) { /* read partition pack and check if it contains essence */ CHK_OFAIL(mxf_read_partition(mxfFile, &key, &partition)); if (data->bodySID == partition->bodySID) { CHK_OFAIL(ns_position_at_first_frame(reader)); mxf_free_partition(&partition); break; } mxf_free_partition(&partition); /* skip this partition */ while (!atEOF) { if (!mxf_read_kl(mxfFile, &key, &llen, &len)) { /* if we fail to read then we must be at eof */ CHK_OFAIL(mxf_file_eof(mxfFile)); atEOF = 1; ns_set_next_kl(nsIndex, &g_Null_Key, 0, 0); break; } ns_set_next_kl(nsIndex, &key, llen, len); if (mxf_is_partition_pack(&key)) { break; } CHK_OFAIL(mxf_skip(mxfFile, len)); } } CHK_ORET(atEOF || mxf_equals_key(&key, &nsIndex->startContentPackageKey)); } return 1; fail: mxf_free_partition(&partition); return 0; }
static int ns_position_at_first_frame(MXFReader *reader) { MXFFile *mxfFile = reader->mxfFile; EssenceReader *essenceReader = reader->essenceReader; EssenceReaderData *data = essenceReader->data; NSFileIndex *nsIndex = &data->nsIndex; MXFPartition *partition = data->headerPartition; mxfKey key; uint8_t llen; uint64_t len; /* move to the first partition that contains essence data */ while (data->bodySID != partition->bodySID) { if (!mxf_read_kl(mxfFile, &key, &llen, &len)) { CHK_OFAIL(mxf_file_eof(mxfFile)); ns_set_next_kl(nsIndex, &g_Null_Key, 0, 0); return 1; } while (!mxf_is_partition_pack(&key)) { CHK_OFAIL(mxf_skip(mxfFile, len)); if (!mxf_read_kl(mxfFile, &key, &llen, &len)) { CHK_OFAIL(mxf_file_eof(mxfFile)); ns_set_next_kl(nsIndex, &g_Null_Key, 0, 0); return 1; } } if (partition != NULL && partition != data->headerPartition) { mxf_free_partition(&partition); } CHK_OFAIL(mxf_read_partition(mxfFile, &key, &partition)); } /* move to start of essence data in partition */ /* if we are in the header partition then the file is positioned after the header metadata, otherwise we are positioned after the partition pack that was just read */ if (partition != data->headerPartition) { /* skip initial filler which is not included in any header or index byte counts */ if (!mxf_read_next_nonfiller_kl(mxfFile, &key, &llen, &len)) { CHK_ORET(mxf_file_eof(mxfFile)); ns_set_next_kl(nsIndex, &g_Null_Key, 0, 0); return 1; } /* skip header metadata */ if (partition->headerByteCount > 0) { CHK_ORET(mxf_skip(mxfFile, partition->headerByteCount - mxfKey_extlen - llen)); if (!mxf_read_kl(mxfFile, &key, &llen, &len)) { CHK_ORET(mxf_file_eof(mxfFile)); ns_set_next_kl(nsIndex, &g_Null_Key, 0, 0); return 1; } } else { CHK_ORET(!mxf_is_header_metadata(&key)); } } else { if (!mxf_read_kl(mxfFile, &key, &llen, &len)) { CHK_ORET(mxf_file_eof(mxfFile)); ns_set_next_kl(nsIndex, &g_Null_Key, 0, 0); return 1; } } /* skip index table segments. Note: we are not checking for segment key because it could be non-standard, eg. MXF V10 indexes */ if (partition->indexByteCount > 0) { CHK_ORET(mxf_skip(mxfFile, partition->indexByteCount - mxfKey_extlen - llen)); if (!mxf_read_kl(mxfFile, &key, &llen, &len)) { CHK_ORET(mxf_file_eof(mxfFile)); ns_set_next_kl(nsIndex, &g_Null_Key, 0, 0); return 1; } } /* check the first essence element KL and position after */ CHK_ORET(mxf_is_gc_essence_element(&key)); if (mxf_equals_key(&nsIndex->startContentPackageKey, &g_Null_Key)) { nsIndex->startContentPackageKey = key; nsIndex->currentPosition = 0; } else { CHK_ORET(mxf_equals_key(&nsIndex->startContentPackageKey, &key)); } ns_set_next_kl(nsIndex, &key, llen, len); if (partition != NULL && partition != data->headerPartition) { mxf_free_partition(&partition); } return 1; fail: if (partition != NULL && partition != data->headerPartition) { mxf_free_partition(&partition); } 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; }