int test_read(const char* filename) { MXFFile* mxfFile = NULL; mxfKey key; uint8_t llen; uint64_t len; mxfLocalTag tag; uint8_t indata[256]; uint8_t valueu8; uint16_t valueu16; uint32_t valueu32; uint64_t valueu64; int8_t value8; int16_t value16; int32_t value32; int64_t value64; mxfUL ul; mxfUID uid; mxfUUID uuid; uint32_t ablen; uint32_t abelen; if (!mxf_disk_file_open_read(filename, &mxfFile)) { mxf_log_error("Failed to open '%s'" LOG_LOC_FORMAT, filename, LOG_LOC_PARAMS); return 0; } /* TEST */ CHK_OFAIL(mxf_file_read(mxfFile, indata, 100) == 100); CHK_OFAIL(memcmp(data, indata, 100) == 0); CHK_OFAIL(mxf_file_getc(mxfFile) == 0xff); CHK_OFAIL(mxf_file_getc(mxfFile) == 0xff); CHK_OFAIL(mxf_read_uint8(mxfFile, &valueu8)); CHK_OFAIL(valueu8 == 0x0f); CHK_OFAIL(mxf_read_uint16(mxfFile, &valueu16)); CHK_OFAIL(valueu16 == 0x0f00); CHK_OFAIL(mxf_read_uint32(mxfFile, &valueu32)); CHK_OFAIL(valueu32 == 0x0f000000); CHK_OFAIL(mxf_read_uint64(mxfFile, &valueu64)); CHK_OFAIL(valueu64 == 0x0f00000000000000LL); CHK_OFAIL(mxf_read_int8(mxfFile, &value8)); CHK_OFAIL(value8 == -0x0f); CHK_OFAIL(mxf_read_int16(mxfFile, &value16)); CHK_OFAIL(value16 == -0x0f00); CHK_OFAIL(mxf_read_int32(mxfFile, &value32)); CHK_OFAIL(value32 == -0x0f000000); CHK_OFAIL(mxf_read_int64(mxfFile, &value64)); CHK_OFAIL(value64 == -0x0f00000000000000LL); CHK_OFAIL(mxf_read_local_tag(mxfFile, &tag)); CHK_OFAIL(tag == 0xffaa); CHK_OFAIL(mxf_read_k(mxfFile, &key)); CHK_OFAIL(mxf_equals_key(&key, &someKey)); CHK_OFAIL(mxf_read_l(mxfFile, &llen, &len)); CHK_OFAIL(llen == 1 && len == 0x01); CHK_OFAIL(mxf_read_l(mxfFile, &llen, &len)); CHK_OFAIL(llen == 2 && len == 0x80); CHK_OFAIL(mxf_read_l(mxfFile, &llen, &len)); CHK_OFAIL(llen == 3 && len == 0x8000); CHK_OFAIL(mxf_read_l(mxfFile, &llen, &len)); CHK_OFAIL(llen == 4 && len == 0x800000); CHK_OFAIL(mxf_read_l(mxfFile, &llen, &len)); CHK_OFAIL(llen == 5 && len == 0x80000000); CHK_OFAIL(mxf_read_l(mxfFile, &llen, &len)); CHK_OFAIL(llen == 6 && len == 0x8000000000LL); CHK_OFAIL(mxf_read_l(mxfFile, &llen, &len)); CHK_OFAIL(llen == 7 && len == 0x800000000000LL); CHK_OFAIL(mxf_read_l(mxfFile, &llen, &len)); CHK_OFAIL(llen == 8 && len == 0x80000000000000LL); CHK_OFAIL(mxf_read_l(mxfFile, &llen, &len)); CHK_OFAIL(llen == 9 && len == 0x8000000000000000LL); CHK_OFAIL(mxf_read_kl(mxfFile, &key, &llen, &len)); CHK_OFAIL(mxf_equals_key(&key, &someKey)); CHK_OFAIL(llen == 3 && len == 0xf100); CHK_OFAIL(mxf_read_l(mxfFile, &llen, &len)); CHK_OFAIL(llen == 8 && len == 0x10); CHK_OFAIL(mxf_read_l(mxfFile, &llen, &len)); CHK_OFAIL(llen == 4 && len == 0x10); CHK_OFAIL(mxf_read_kl(mxfFile, &key, &llen, &len)); CHK_OFAIL(mxf_equals_key(&key, &someKey)); CHK_OFAIL(llen == 8 && len == 0x1000); CHK_OFAIL(mxf_read_ul(mxfFile, &ul)); CHK_OFAIL(mxf_equals_ul(&ul, &someUL)); CHK_OFAIL(mxf_read_uid(mxfFile, &uid)); CHK_OFAIL(mxf_equals_uid(&uid, &someUID)); CHK_OFAIL(mxf_read_uuid(mxfFile, &uuid)); CHK_OFAIL(mxf_equals_uuid(&uuid, &someUUID)); CHK_OFAIL(mxf_read_batch_header(mxfFile, &ablen, &abelen)); CHK_OFAIL(ablen == 2 && abelen == 16); CHK_OFAIL(mxf_read_array_header(mxfFile, &ablen, &abelen)); CHK_OFAIL(ablen == 4 && abelen == 32); mxf_file_close(&mxfFile); /* test reading from a byte buffer */ const uint8_t data[5] = {1, 2, 3, 4, 5}; if (!mxf_byte_array_wrap_read(data, sizeof(data), &mxfFile)) { mxf_log_error("Failed to open byte array as MXF file" LOG_LOC_FORMAT, LOG_LOC_PARAMS); return 0; } CHK_OFAIL(mxf_file_tell(mxfFile) == 0); CHK_OFAIL(mxf_file_getc(mxfFile) == 1); CHK_OFAIL(mxf_file_tell(mxfFile) == 1); CHK_OFAIL(mxf_file_read(mxfFile, indata, 4)); CHK_OFAIL(indata[0] == 2 && indata[1] == 3 && indata[2] == 4 && indata[3] == 5); CHK_OFAIL(mxf_file_tell(mxfFile) == 5); CHK_OFAIL(mxf_file_eof(mxfFile)); CHK_OFAIL(mxf_file_getc(mxfFile) == EOF); CHK_OFAIL(mxf_file_seek(mxfFile, 0, SEEK_SET)); CHK_OFAIL(mxf_file_tell(mxfFile) == 0); CHK_OFAIL(mxf_file_getc(mxfFile) == 1); CHK_OFAIL(mxf_file_seek(mxfFile, 2, SEEK_CUR)); CHK_OFAIL(mxf_file_tell(mxfFile) == 3); CHK_OFAIL(mxf_file_getc(mxfFile) == 4); CHK_OFAIL(mxf_file_seek(mxfFile, 0, SEEK_END)); CHK_OFAIL(mxf_file_tell(mxfFile) == 4); CHK_OFAIL(mxf_file_getc(mxfFile) == 5); CHK_OFAIL(!mxf_file_seek(mxfFile, 5, SEEK_END)); /* should fail */ CHK_OFAIL(mxf_file_tell(mxfFile) == 5); mxf_file_close(&mxfFile); return 1; fail: mxf_file_close(&mxfFile); return 0; }
int main() { MXFPageFile *mxfPageFile; MXFFile *mxfFile; uint8_t *data; int i; data = malloc(DATA_SIZE); remove_test_files(); CHECK(mxf_page_file_open_new(g_testFile, PAGE_SIZE, &mxfPageFile)); mxfFile = mxf_page_file_get_file(mxfPageFile); memset(data, 0, DATA_SIZE); CHECK(mxf_file_write(mxfFile, data, DATA_SIZE) == DATA_SIZE); mxf_file_close(&mxfFile); CHECK(mxf_page_file_open_modify(g_testFile, PAGE_SIZE, &mxfPageFile)); mxfFile = mxf_page_file_get_file(mxfPageFile); memset(data, 1, DATA_SIZE); CHECK(mxf_file_size(mxfFile) == DATA_SIZE); CHECK(mxf_file_read(mxfFile, data, DATA_SIZE) == DATA_SIZE); CHECK(mxf_file_eof(mxfFile)); CHECK(mxf_file_tell(mxfFile) == DATA_SIZE); CHECK(mxf_file_write(mxfFile, data, DATA_SIZE) == DATA_SIZE); CHECK(mxf_file_eof(mxfFile)); CHECK(mxf_file_tell(mxfFile) == DATA_SIZE * 2); CHECK(mxf_file_seek(mxfFile, 0, SEEK_SET)); CHECK(mxf_file_tell(mxfFile) == 0); CHECK(mxf_file_write(mxfFile, data, DATA_SIZE) == DATA_SIZE); mxf_file_close(&mxfFile); CHECK(mxf_page_file_open_read(g_testFile, &mxfPageFile)); mxfFile = mxf_page_file_get_file(mxfPageFile); memset(data, 1, DATA_SIZE); CHECK(mxf_file_size(mxfFile) == DATA_SIZE * 2); CHECK(mxf_file_read(mxfFile, data, DATA_SIZE) == DATA_SIZE); CHECK(mxf_file_tell(mxfFile) == DATA_SIZE); CHECK(mxf_file_read(mxfFile, data, DATA_SIZE) == DATA_SIZE); CHECK(mxf_file_eof(mxfFile)); CHECK(mxf_file_tell(mxfFile) == DATA_SIZE * 2); CHECK(mxf_file_seek(mxfFile, 0, SEEK_SET)); CHECK(mxf_file_tell(mxfFile) == 0); CHECK(mxf_file_read(mxfFile, data, DATA_SIZE) == DATA_SIZE); CHECK(mxf_file_tell(mxfFile) == DATA_SIZE); CHECK(mxf_file_seek(mxfFile, DATA_SIZE + 1, SEEK_SET)); CHECK(mxf_file_read(mxfFile, data, DATA_SIZE - 1) == DATA_SIZE - 1); CHECK(mxf_file_tell(mxfFile) == DATA_SIZE * 2); CHECK(mxf_file_seek(mxfFile, DATA_SIZE - 1, SEEK_SET)); CHECK(mxf_file_tell(mxfFile) == DATA_SIZE - 1); CHECK(mxf_file_seek(mxfFile, DATA_SIZE * 2, SEEK_SET)); CHECK(mxf_file_tell(mxfFile) == DATA_SIZE * 2); CHECK(mxf_file_seek(mxfFile, 0, SEEK_END)); CHECK(mxf_file_tell(mxfFile) == DATA_SIZE * 2); CHECK(mxf_file_seek(mxfFile, -DATA_SIZE * 2, SEEK_END)); CHECK(mxf_file_tell(mxfFile) == 0); CHECK(mxf_file_seek(mxfFile, DATA_SIZE - 5, SEEK_CUR)); CHECK(mxf_file_tell(mxfFile) == DATA_SIZE - 5); CHECK(mxf_file_read(mxfFile, data, DATA_SIZE) == DATA_SIZE); mxf_file_close(&mxfFile); CHECK(mxf_page_file_open_new("pagetest_out__%d.mxf", PAGE_SIZE, &mxfPageFile)); mxfFile = mxf_page_file_get_file(mxfPageFile); CHECK(mxf_file_write(mxfFile, data, DATA_SIZE) == DATA_SIZE); mxf_file_close(&mxfFile); CHECK(mxf_page_file_remove("pagetest_out__%d.mxf")); /* test forward truncate */ CHECK(mxf_page_file_open_new(g_testFile, PAGE_SIZE, &mxfPageFile)); mxfFile = mxf_page_file_get_file(mxfPageFile); memset(data, 0, DATA_SIZE); for (i = 0; i < 10; i++) { CHECK(mxf_file_write(mxfFile, data, DATA_SIZE) == DATA_SIZE); } mxf_file_close(&mxfFile); CHECK(mxf_page_file_open_modify(g_testFile, PAGE_SIZE, &mxfPageFile)); mxfFile = mxf_page_file_get_file(mxfPageFile); memset(data, 1, DATA_SIZE); CHECK(mxf_page_file_forward_truncate(mxfPageFile)); for (i = 0; i < 5; i++) { CHECK(mxf_file_read(mxfFile, data, DATA_SIZE) == DATA_SIZE); } CHECK(mxf_page_file_forward_truncate(mxfPageFile)); for (i = 0; i < 4; i++) { CHECK(mxf_file_read(mxfFile, data, DATA_SIZE) == DATA_SIZE); } CHECK(mxf_page_file_forward_truncate(mxfPageFile)); CHECK(mxf_file_read(mxfFile, data, DATA_SIZE) == DATA_SIZE); CHECK(mxf_page_file_forward_truncate(mxfPageFile)); mxf_file_close(&mxfFile); CHECK(mxf_page_file_remove(g_testFile)); free(data); 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; }