static uint32_t disk_file_read(FileDescriptor *fileDesc, uint8_t *data, uint32_t count) { uint32_t result = (uint32_t)fread(data, 1, count, fileDesc->file); if (result != count && ferror(fileDesc->file)) mxf_log_error("fread failed: %s\n", strerror(errno)); return result; }
static uint32_t disk_file_write(FileDescriptor *fileDesc, const uint8_t *data, uint32_t count) { uint32_t result = (uint32_t)fwrite(data, 1, count, fileDesc->file); if (result != count) mxf_log_error("fwrite failed: %s\n", strerror(errno)); return result; }
static int extend_mem_file(MXFFileSysData *sysData, uint32_t minSize) { uint32_t i; Chunk *newChunks; uint32_t numExtendChunks; int64_t chunkRemainder; assert(!sysData->readOnly); if (sysData->numChunks == 0) { chunkRemainder = 0; } else { chunkRemainder = sysData->chunks[sysData->numChunks - 1].allocSize - sysData->chunks[sysData->numChunks - 1].size; } if (minSize <= chunkRemainder) return 1; numExtendChunks = (uint32_t)((minSize - chunkRemainder + sysData->chunkSize - 1) / sysData->chunkSize); newChunks = (Chunk*)realloc(sysData->chunks, (sysData->numChunks + numExtendChunks) * sizeof(Chunk)); if (!newChunks) { mxf_log_error("Failed to reallocate memory file chunks" LOG_LOC_FORMAT, LOG_LOC_PARAMS); return 0; } sysData->chunks = newChunks; for (i = 0; i < numExtendChunks; i++) { CHK_MALLOC_ARRAY_ORET(sysData->chunks[sysData->numChunks].data, unsigned char, sysData->chunkSize); sysData->chunks[sysData->numChunks].allocSize = sysData->chunkSize; sysData->chunks[sysData->numChunks].size = 0; sysData->numChunks++; } return 1; }
int test_modify(const char* filename) { MXFFile* mxfFile = NULL; if (!mxf_disk_file_open_modify(filename, &mxfFile)) { mxf_log_error("Failed to open modify '%s'" LOG_LOC_FORMAT, filename, LOG_LOC_PARAMS); return 0; } /* TEST */ CHK_OFAIL(do_write(mxfFile)); mxf_file_close(&mxfFile); CHK_OFAIL(test_read(filename)); return 1; fail: mxf_file_close(&mxfFile); return 0; }
unsigned char* mxf_mem_file_get_chunk_data(MXFMemoryFile *mxfMemFile, size_t chunkIndex) { if (chunkIndex >= mxfMemFile->mxfFile->sysData->numChunks) { mxf_log_error("Invalid chunk index value %"PRIszt""LOG_LOC_FORMAT, chunkIndex, LOG_LOC_PARAMS); return NULL; } return mxfMemFile->mxfFile->sysData->chunks[chunkIndex].data; }
int64_t mxf_mem_file_get_chunk_size(MXFMemoryFile *mxfMemFile, size_t chunkIndex) { if (chunkIndex >= mxfMemFile->mxfFile->sysData->numChunks) { mxf_log_error("Invalid chunk index value %"PRIszt""LOG_LOC_FORMAT, chunkIndex, LOG_LOC_PARAMS); return 0; } return mxfMemFile->mxfFile->sysData->chunks[chunkIndex].size; }
int mxf_page_file_open_new(const char *filenameTemplate, int64_t pageSize, MXFPageFile **mxfPageFile) { MXFFile *newMXFFile = NULL; if (strstr(filenameTemplate, "%d") == NULL) { mxf_log_error("Filename template '%s' doesn't contain %%d\n", filenameTemplate); return 0; } CHK_MALLOC_ORET(newMXFFile, MXFFile); memset(newMXFFile, 0, sizeof(*newMXFFile)); newMXFFile->close = page_file_close; newMXFFile->read = page_file_read; newMXFFile->write = page_file_write; newMXFFile->get_char = page_file_getchar; newMXFFile->put_char = page_file_putchar; newMXFFile->eof = page_file_eof; newMXFFile->seek = page_file_seek; newMXFFile->tell = page_file_tell; newMXFFile->is_seekable = page_file_is_seekable; newMXFFile->size = page_file_size; newMXFFile->free_sys_data = free_page_file; CHK_MALLOC_OFAIL(newMXFFile->sysData, MXFFileSysData); memset(newMXFFile->sysData, 0, sizeof(*newMXFFile->sysData)); CHK_OFAIL((newMXFFile->sysData->filenameTemplate = strdup(filenameTemplate)) != NULL); newMXFFile->sysData->pageSize = pageSize; newMXFFile->sysData->mode = WRITE_MODE; newMXFFile->sysData->mxfPageFile.mxfFile = newMXFFile; *mxfPageFile = &newMXFFile->sysData->mxfPageFile; return 1; fail: if (newMXFFile != NULL) { mxf_file_close(&newMXFFile); } return 0; }
int xml_writer_open(const char* filename, XMLWriter** writer) { XMLWriter* newWriter; CHK_MALLOC_ORET(newWriter, XMLWriter); memset(newWriter, 0, sizeof(XMLWriter)); newWriter->previousWrite = ELEMENT_END; if ((newWriter->file = fopen(filename, "wb")) == NULL) { mxf_log_error("Failed to open xml file '%s'" LOG_LOC_FORMAT, filename, LOG_LOC_PARAMS); goto fail; } CHK_OFAIL(fprintf(newWriter->file, "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>") > 0); *writer = newWriter; return 1; fail: SAFE_FREE(&newWriter); return 0; }
int test_create_and_write(const char *filename) { MXFFile *mxfFile = NULL; uint8_t runin[RUNIN_LEN]; MXFFilePartitions partitions; MXFPartition *headerPartition = NULL; MXFPartition *bodyPartition1 = NULL; MXFPartition *bodyPartition2 = NULL; MXFPartition *footerPartition = NULL; if (!mxf_disk_file_open_new(filename, &mxfFile)) { mxf_log_error("Failed to create '%s'" LOG_LOC_FORMAT, filename, LOG_LOC_PARAMS); return 0; } mxf_initialise_file_partitions(&partitions); /* TEST */ /* write 8 bytes of runin */ memset(runin, 0, RUNIN_LEN); CHK_OFAIL(mxf_file_write(mxfFile, runin, RUNIN_LEN) == RUNIN_LEN); /* write the header pp */ CHK_OFAIL(mxf_append_new_partition(&partitions, &headerPartition)); headerPartition->key = MXF_PP_K(ClosedComplete, Header); headerPartition->indexSID = 1; CHK_OFAIL(mxf_append_partition_esscont_label(headerPartition, &MXF_EC_L(SD_Unc_625_50i_422_135_FrameWrapped))); CHK_OFAIL(mxf_append_partition_esscont_label(headerPartition, &MXF_EC_L(BWFFrameWrapped))); CHK_OFAIL(mxf_write_partition(mxfFile, headerPartition)); /* write empty header metadata */ CHK_OFAIL(mxf_mark_header_start(mxfFile, headerPartition)); CHK_OFAIL(mxf_allocate_space(mxfFile, 1024)); CHK_OFAIL(mxf_mark_header_end(mxfFile, headerPartition)); /* write the body pp 1 */ CHK_OFAIL(mxf_append_new_from_partition(&partitions, headerPartition, &bodyPartition1)); bodyPartition1->key = MXF_PP_K(ClosedComplete, Body); bodyPartition1->bodySID = 2; CHK_OFAIL(mxf_write_partition(mxfFile, bodyPartition1)); /* write the body pp 2, with KAG 256 */ CHK_OFAIL(mxf_append_new_from_partition(&partitions, headerPartition, &bodyPartition2)); bodyPartition2->key = MXF_PP_K(ClosedComplete, Body); bodyPartition2->bodySID = 3; bodyPartition2->kagSize = 256; CHK_OFAIL(mxf_write_partition(mxfFile, bodyPartition2)); CHK_OFAIL(mxf_fill_to_kag(mxfFile, bodyPartition2)); /* write the footer pp */ CHK_OFAIL(mxf_append_new_from_partition(&partitions, headerPartition, &footerPartition)); footerPartition->key = MXF_PP_K(ClosedComplete, Footer); footerPartition->indexSID = 1; CHK_OFAIL(mxf_write_partition(mxfFile, footerPartition)); /* write RIP */ CHK_OFAIL(mxf_write_rip(mxfFile, &partitions)); /* update the partitions */ CHK_OFAIL(mxf_update_partitions(mxfFile, &partitions)); mxf_file_close(&mxfFile); mxf_clear_file_partitions(&partitions); return 1; fail: mxf_file_close(&mxfFile); mxf_clear_file_partitions(&partitions); return 0; }
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; }
static int process_metadata(MXFReader *reader, MXFPartition *partition) { MXFFile *mxfFile = reader->mxfFile; EssenceReader *essenceReader = reader->essenceReader; EssenceReaderData *data = essenceReader->data; mxfKey key; uint8_t llen; uint64_t len; MXFMetadataSet *essContainerDataSet; MXFMetadataSet *sourcePackageSet; MXFMetadataSet *sourcePackageTrackSet; MXFMetadataSet *materialPackageSet; MXFMetadataSet *materialPackageTrackSet; MXFMetadataSet *descriptorSet; MXFArrayItemIterator arrayIter; mxfUL dataDefUL; MXFTrack *track; EssenceTrack *essenceTrack; MXFList wrappedTracks; MXFList sortedWrappedTracks; WrappedTrack *newWrappedTrack = NULL; WrappedTrack *wrappedTrack; WrappedTrack *sortedWrappedTrack; WrappedTrack *prevSortedWrappedTrack; WrappedTrack *firstSortedWrappedTrack; MXFListIterator listIter; MXFListIterator sortedListIter; int wasInserted; int haveZeroTrackNumber; uint32_t trackID; mxf_initialise_list(&wrappedTracks, free); mxf_initialise_list(&sortedWrappedTracks, NULL); /* create and read the header metadata */ CHK_OFAIL(mxf_read_next_nonfiller_kl(mxfFile, &key, &llen, &len)); CHK_OFAIL(mxf_is_header_metadata(&key)); CHK_OFAIL(mxf_create_header_metadata(&data->headerMetadata, reader->dataModel)); CHK_OFAIL(mxf_read_header_metadata(mxfFile, data->headerMetadata, partition->headerByteCount, &key, llen, len)); /* check for metadata only files */ if (!mxf_find_singular_set_by_key(data->headerMetadata, &MXF_SET_K(EssenceContainerData), &essContainerDataSet)) { reader->isMetadataOnly = 1; return 1; } /* get the body and index SID from the (single essence container; external essence not supported) */ CHK_OFAIL(mxf_get_uint32_item(essContainerDataSet, &MXF_ITEM_K(EssenceContainerData, BodySID), &data->bodySID)); if (mxf_have_item(essContainerDataSet, &MXF_ITEM_K(EssenceContainerData, IndexSID))) { CHK_OFAIL(mxf_get_uint32_item(essContainerDataSet, &MXF_ITEM_K(EssenceContainerData, IndexSID), &data->indexSID)); } else { data->indexSID = 0; } /* get the clip duration */ CHK_OFAIL(get_clip_duration(data->headerMetadata, &reader->clip, 0)); /* get the tracks from the (single) material package */ haveZeroTrackNumber = 0; CHK_OFAIL(mxf_find_singular_set_by_key(data->headerMetadata, &MXF_SET_K(MaterialPackage), &materialPackageSet)); CHK_OFAIL(mxf_uu_get_package_tracks(materialPackageSet, &arrayIter)); while (mxf_uu_next_track(data->headerMetadata, &arrayIter, &materialPackageTrackSet)) { /* CHK_OFAIL(mxf_uu_get_track_datadef(materialPackageTrackSet, &dataDefUL)); */ /* NOTE: not failing because files from Omneon were found to have a missing DataDefinition item in the Sequence and DMSourceClip referenced by a static DM Track */ if (!mxf_uu_get_track_datadef(materialPackageTrackSet, &dataDefUL)) { continue; } if (mxf_is_picture(&dataDefUL) || mxf_is_sound(&dataDefUL)) { CHK_MALLOC_OFAIL(newWrappedTrack, WrappedTrack); memset(newWrappedTrack, 0, sizeof(WrappedTrack)); CHK_OFAIL(mxf_append_list_element(&wrappedTracks, newWrappedTrack)); wrappedTrack = newWrappedTrack; newWrappedTrack = NULL; /* assigned to list so set to NULL so not free'ed in fail */ CHK_OFAIL(add_track(reader, &track)); wrappedTrack->track = track; if (mxf_have_item(materialPackageTrackSet, &MXF_ITEM_K(GenericTrack, TrackNumber))) { CHK_OFAIL(mxf_get_uint32_item(materialPackageTrackSet, &MXF_ITEM_K(GenericTrack, TrackNumber), &wrappedTrack->trackNumber)); } else { wrappedTrack->trackNumber = 0; } CHK_OFAIL(mxf_get_uint32_item(materialPackageTrackSet, &MXF_ITEM_K(GenericTrack, TrackID), &wrappedTrack->trackID)); CHK_OFAIL(mxf_get_rational_item(materialPackageTrackSet, &MXF_ITEM_K(Track, EditRate), &wrappedTrack->editRate)); CHK_OFAIL(mxf_uu_get_track_duration(materialPackageTrackSet, &wrappedTrack->duration)); CHK_OFAIL(mxf_uu_get_track_reference(materialPackageTrackSet, &wrappedTrack->sourcePackageUID, &wrappedTrack->sourceTrackID)); wrappedTrack->isVideo = mxf_is_picture(&dataDefUL); track->isVideo = wrappedTrack->isVideo; track->materialTrackID = wrappedTrack->trackID; track->materialTrackNumber = wrappedTrack->trackNumber; if (wrappedTrack->isVideo) { track->video.frameRate = wrappedTrack->editRate; } if (wrappedTrack->trackNumber == 0) { haveZeroTrackNumber = 1; } } } /* sort the tracks; use trackNumber if != 0 else use the trackID; video track is always first */ mxf_initialise_list_iter(&listIter, &wrappedTracks); while (mxf_next_list_iter_element(&listIter)) { wrappedTrack = (WrappedTrack*)mxf_get_iter_element(&listIter); wasInserted = 0; mxf_initialise_list_iter(&sortedListIter, &sortedWrappedTracks); while (mxf_next_list_iter_element(&sortedListIter)) { sortedWrappedTrack = (WrappedTrack*)mxf_get_iter_element(&sortedListIter); if ((wrappedTrack->track->isVideo && !sortedWrappedTrack->track->isVideo) || (wrappedTrack->track->isVideo == sortedWrappedTrack->track->isVideo && ((!haveZeroTrackNumber && wrappedTrack->trackNumber < sortedWrappedTrack->trackNumber) || (haveZeroTrackNumber && wrappedTrack->trackID < sortedWrappedTrack->trackID)))) { CHK_OFAIL(mxf_insert_list_element(&sortedWrappedTracks, mxf_get_list_iter_index(&sortedListIter), 1, wrappedTrack)); wasInserted = 1; break; } } if (!wasInserted) { CHK_OFAIL(mxf_append_list_element(&sortedWrappedTracks, wrappedTrack)); } } /* set the MXFTracks to the same order */ prevSortedWrappedTrack = NULL; firstSortedWrappedTrack = NULL; mxf_initialise_list_iter(&sortedListIter, &sortedWrappedTracks); while (mxf_next_list_iter_element(&sortedListIter)) { sortedWrappedTrack = (WrappedTrack*)mxf_get_iter_element(&sortedListIter); if (firstSortedWrappedTrack == NULL) { firstSortedWrappedTrack = sortedWrappedTrack; } if (prevSortedWrappedTrack != NULL) { prevSortedWrappedTrack->track->next = sortedWrappedTrack->track; } prevSortedWrappedTrack = sortedWrappedTrack; } if (prevSortedWrappedTrack != NULL) { prevSortedWrappedTrack->track->next = NULL; } if (firstSortedWrappedTrack != NULL) { reader->clip.tracks = firstSortedWrappedTrack->track; } /* process source package tracks and linked descriptors */ mxf_initialise_list_iter(&sortedListIter, &sortedWrappedTracks); while (mxf_next_list_iter_element(&sortedListIter)) { sortedWrappedTrack = (WrappedTrack*)mxf_get_iter_element(&sortedListIter); CHK_OFAIL(mxf_uu_get_referenced_track(data->headerMetadata, &sortedWrappedTrack->sourcePackageUID, sortedWrappedTrack->sourceTrackID, &sourcePackageTrackSet)); CHK_OFAIL(add_essence_track(essenceReader, &essenceTrack)); essenceTrack->isVideo = sortedWrappedTrack->isVideo; if (mxf_have_item(sourcePackageTrackSet, &MXF_ITEM_K(GenericTrack, TrackNumber))) { CHK_OFAIL(mxf_get_uint32_item(sourcePackageTrackSet, &MXF_ITEM_K(GenericTrack, TrackNumber), &essenceTrack->trackNumber)); } else { essenceTrack->trackNumber = 0; } CHK_OFAIL(mxf_get_uint32_item(sourcePackageTrackSet, &MXF_ITEM_K(GenericTrack, TrackID), &trackID)); essenceTrack->frameRate = reader->clip.frameRate; essenceTrack->playoutDuration = reader->clip.duration; essenceTrack->indexSID = data->indexSID; essenceTrack->bodySID = data->bodySID; /* process the descriptor */ CHK_OFAIL(mxf_uu_get_referenced_package(data->headerMetadata, &sortedWrappedTrack->sourcePackageUID, &sourcePackageSet)); CHK_OFAIL(mxf_uu_get_track_descriptor(sourcePackageSet, trackID, &descriptorSet)); if (mxf_is_subclass_of(data->headerMetadata->dataModel, &descriptorSet->key, &MXF_SET_K(CDCIEssenceDescriptor))) { CHK_OFAIL(process_cdci_descriptor(descriptorSet, sortedWrappedTrack->track, essenceTrack)); } else if (mxf_is_subclass_of(data->headerMetadata->dataModel, &descriptorSet->key, &MXF_SET_K(WaveAudioDescriptor))) { CHK_OFAIL(process_wav_descriptor(descriptorSet, sortedWrappedTrack->track, essenceTrack)); } else if (mxf_is_subclass_of(data->headerMetadata->dataModel, &descriptorSet->key, &MXF_SET_K(GenericSoundEssenceDescriptor))) { CHK_OFAIL(process_sound_descriptor(descriptorSet, track, essenceTrack)); } else { mxf_log_error("Unsupported file descriptor" LOG_LOC_FORMAT, LOG_LOC_PARAMS); return 0; } } /* initialise the playout timecode */ if (!initialise_playout_timecode(reader, materialPackageSet)) { CHK_ORET(initialise_default_playout_timecode(reader)); } /* initialise the source timecodes */ initialise_source_timecodes(reader, sourcePackageSet); mxf_clear_list(&wrappedTracks); mxf_clear_list(&sortedWrappedTracks); return 1; fail: SAFE_FREE(newWrappedTrack); mxf_clear_list(&wrappedTracks); mxf_clear_list(&sortedWrappedTracks); 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; }
int mxf_page_file_open_modify(const char *filenameTemplate, int64_t pageSize, MXFPageFile **mxfPageFile) { MXFFile *newMXFFile = NULL; int pageCount; int allocatedPages; char filename[4096]; FILE *file; int64_t fileSize; if (strstr(filenameTemplate, "%d") == NULL) { mxf_log_error("Filename template '%s' doesn't contain %%d\n", filenameTemplate); return 0; } /* count number of page files */ pageCount = 0; for(;;) { mxf_snprintf(filename, sizeof(filename), filenameTemplate, pageCount); if ((file = fopen(filename, "rb")) == NULL) { break; } fclose(file); pageCount++; } if (pageCount == 0) { /* file not found */ return 0; } /* check the size of the first file equals the pageSize */ if (pageCount > 1) { mxf_snprintf(filename, sizeof(filename), filenameTemplate, 0); fileSize = disk_file_size(filename); if (fileSize < 0) { mxf_log_error("Failed to stat file '%s': %s\n", filename, strerror(errno)); return 0; } if (pageSize != fileSize) { mxf_log_error("Size of first file '%s' (%"PRId64" does not equal page size %"PRId64"\n", filename, fileSize, pageSize); return 0; } } CHK_MALLOC_ORET(newMXFFile, MXFFile); memset(newMXFFile, 0, sizeof(*newMXFFile)); newMXFFile->close = page_file_close; newMXFFile->read = page_file_read; newMXFFile->write = page_file_write; newMXFFile->get_char = page_file_getchar; newMXFFile->put_char = page_file_putchar; newMXFFile->eof = page_file_eof; newMXFFile->seek = page_file_seek; newMXFFile->tell = page_file_tell; newMXFFile->is_seekable = page_file_is_seekable; newMXFFile->size = page_file_size; newMXFFile->free_sys_data = free_page_file; CHK_MALLOC_OFAIL(newMXFFile->sysData, MXFFileSysData); memset(newMXFFile->sysData, 0, sizeof(*newMXFFile->sysData)); CHK_OFAIL((newMXFFile->sysData->filenameTemplate = strdup(filenameTemplate)) != NULL); newMXFFile->sysData->pageSize = pageSize; newMXFFile->sysData->mode = MODIFY_MODE; newMXFFile->sysData->mxfPageFile.mxfFile = newMXFFile; /* allocate pages */ allocatedPages = (pageCount < PAGE_ALLOC_INCR) ? PAGE_ALLOC_INCR : pageCount; CHK_MALLOC_ARRAY_ORET(newMXFFile->sysData->pages, Page, allocatedPages); memset(newMXFFile->sysData->pages, 0, allocatedPages * sizeof(Page)); newMXFFile->sysData->numPages = pageCount; newMXFFile->sysData->numPagesAllocated = allocatedPages; for (pageCount = 0; pageCount < newMXFFile->sysData->numPages; pageCount++) { newMXFFile->sysData->pages[pageCount].index = pageCount; newMXFFile->sysData->pages[pageCount].size = pageSize; } /* set the files size of the last file, which could have size < pageSize */ mxf_snprintf(filename, sizeof(filename), filenameTemplate, newMXFFile->sysData->numPages - 1); fileSize = disk_file_size(filename); if (fileSize < 0) { mxf_log_error("Failed to stat file '%s': %s\n", filename, strerror(errno)); goto fail; } newMXFFile->sysData->pages[newMXFFile->sysData->numPages - 1].size = fileSize; *mxfPageFile = &newMXFFile->sysData->mxfPageFile; return 1; fail: if (newMXFFile != NULL) { mxf_file_close(&newMXFFile); } return 0; }
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; }
static int get_file_partitions(MXFFile *mxfFile, MXFPartition *headerPartition, MXFList *partitions) { mxfKey key; uint8_t llen; uint64_t len; MXFPartition *partition = NULL; MXFPartition *partitionRef; uint64_t thisPartition; MXFRIP rip; MXFRIPEntry *ripEntry; MXFListIterator iter; mxf_initialise_list(partitions, free_partition_in_list); memset(&rip, 0, sizeof(MXFRIP)); /* use the RIP if there is one */ if (mxf_read_rip(mxfFile, &rip)) { mxf_initialise_list_iter(&iter, &rip.entries); while (mxf_next_list_iter_element(&iter)) { ripEntry = (MXFRIPEntry*)mxf_get_iter_element(&iter); /* seek to partition and read and add to list */ CHK_OFAIL(mxf_file_seek(mxfFile, mxf_get_runin_len(mxfFile) + ripEntry->thisPartition, SEEK_SET)); CHK_OFAIL(mxf_read_kl(mxfFile, &key, &llen, &len)); CHK_OFAIL(mxf_is_partition_pack(&key)); CHK_OFAIL(mxf_read_partition(mxfFile, &key, &partition)); CHK_OFAIL(mxf_append_list_element(partitions, partition)); partition = NULL; /* owned by list */ } } /* start from footer partition and index back to the header partition */ else { if (headerPartition->footerPartition == 0) { /* no footer partition or at unknown position, so we only index the header partition */ goto fail; } thisPartition = headerPartition->footerPartition; do { /* seek to partition and read and add to list */ CHK_OFAIL(mxf_file_seek(mxfFile, mxf_get_runin_len(mxfFile) + thisPartition, SEEK_SET)); CHK_OFAIL(mxf_read_kl(mxfFile, &key, &llen, &len)); CHK_OFAIL(mxf_is_partition_pack(&key)); CHK_OFAIL(mxf_read_partition(mxfFile, &key, &partition)); CHK_OFAIL(mxf_prepend_list_element(partitions, partition)); partitionRef = partition; partition = NULL; /* owned by list */ thisPartition = partitionRef->previousPartition; } while (partitionRef->thisPartition != partitionRef->previousPartition); } mxf_clear_rip(&rip); return 1; fail: /* if something failed then just add the header partition Note: some Omneon files had references to a footer partition which was not actually present in the file */ mxf_clear_list(partitions); mxf_free_partition(&partition); mxf_clear_rip(&rip); /* create copy of header partition pack */ CHK_ORET(mxf_create_from_partition(headerPartition, &partition)); partition->key = headerPartition->key; partition->majorVersion = headerPartition->majorVersion; partition->minorVersion = headerPartition->minorVersion; partition->kagSize = headerPartition->kagSize; partition->thisPartition = headerPartition->thisPartition; partition->previousPartition = headerPartition->previousPartition; partition->footerPartition = headerPartition->footerPartition; partition->headerByteCount = headerPartition->headerByteCount; partition->indexByteCount = headerPartition->indexByteCount; partition->indexSID = headerPartition->indexSID; partition->bodyOffset = headerPartition->bodyOffset; partition->bodySID = headerPartition->bodySID; /* add partition to list */ if (!mxf_append_list_element(partitions, partition)) { mxf_free_partition(&partition); mxf_log_error("Failed to append header partition to list" LOG_LOC_FORMAT, LOG_LOC_PARAMS); return 0; } return 1; }
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; }
int test_read(const char *filename) { MXFFile *mxfFile = NULL; MXFFilePartitions partitions; MXFPartition *headerPartition = NULL; MXFPartition *bodyPartition1 = NULL; MXFPartition *bodyPartition2 = NULL; MXFPartition *footerPartition = NULL; MXFListIterator iter; mxfKey key; uint8_t llen; uint64_t len; int i; MXFRIP rip; if (!mxf_disk_file_open_read(filename, &mxfFile)) { mxf_log_error("Failed to open '%s'" LOG_LOC_FORMAT, filename, LOG_LOC_PARAMS); return 0; } mxf_initialise_file_partitions(&partitions); /* TEST */ /* read RIP */ CHK_OFAIL(mxf_read_rip(mxfFile, &rip)); CHK_OFAIL(mxf_get_list_length(&rip.entries) == 4); CHK_OFAIL(mxf_file_seek(mxfFile, 0, SEEK_SET)); mxf_initialise_list_iter(&iter, &rip.entries); i = 0; while (mxf_next_list_iter_element(&iter)) { MXFRIPEntry *entry = (MXFRIPEntry*)mxf_get_iter_element(&iter); if (i == 0) { CHK_OFAIL(entry->bodySID == 0); CHK_OFAIL(entry->thisPartition == RUNIN_LEN); } else if (i == 1) { CHK_OFAIL(entry->bodySID == 2); CHK_OFAIL(entry->thisPartition == RUNIN_LEN + 1161); } else if (i == 2) { CHK_OFAIL(entry->bodySID == 3); CHK_OFAIL(entry->thisPartition == RUNIN_LEN + 1298); } else { CHK_OFAIL(entry->bodySID == 0); CHK_OFAIL(entry->thisPartition == RUNIN_LEN + 1554); } i++; } /* read header pp, allowing for runin */ CHK_OFAIL(mxf_read_header_pp_kl_with_runin(mxfFile, &key, &llen, &len)); CHK_OFAIL(mxf_read_partition(mxfFile, &key, &headerPartition)); CHK_OFAIL(mxf_append_partition(&partitions, headerPartition)); CHK_OFAIL(headerPartition->indexSID == 1); CHK_OFAIL(headerPartition->bodySID == 0); CHK_OFAIL(mxf_get_list_length(&headerPartition->essenceContainers) == 2); mxf_initialise_list_iter(&iter, &headerPartition->essenceContainers); i = 0; while (mxf_next_list_iter_element(&iter)) { mxfUL *label = (mxfUL*)mxf_get_iter_element(&iter); if (i == 0) { CHK_OFAIL(mxf_equals_ul(label, &MXF_EC_L(SD_Unc_625_50i_422_135_FrameWrapped))); } else { CHK_OFAIL(mxf_equals_ul(label, &MXF_EC_L(BWFFrameWrapped))); } i++; } /* skip filler and read body pp 1 */ CHK_OFAIL(mxf_read_next_nonfiller_kl(mxfFile, &key, &llen, &len)); CHK_OFAIL(mxf_is_partition_pack(&key)); CHK_OFAIL(mxf_read_partition(mxfFile, &key, &bodyPartition1)); CHK_OFAIL(bodyPartition1->indexSID == 0); CHK_OFAIL(bodyPartition1->bodySID == 2); CHK_OFAIL(mxf_append_partition(&partitions, bodyPartition1)); /* skip filler and read body pp 2 */ CHK_OFAIL(mxf_read_next_nonfiller_kl(mxfFile, &key, &llen, &len)); CHK_OFAIL(mxf_is_partition_pack(&key)); CHK_OFAIL(mxf_read_partition(mxfFile, &key, &bodyPartition2)); CHK_OFAIL(bodyPartition2->indexSID == 0); CHK_OFAIL(bodyPartition2->bodySID == 3); CHK_OFAIL(mxf_append_partition(&partitions, bodyPartition2)); /* skip filler and read footer pp */ CHK_OFAIL(mxf_read_next_nonfiller_kl(mxfFile, &key, &llen, &len)); CHK_OFAIL(mxf_is_partition_pack(&key)); CHK_OFAIL(mxf_read_partition(mxfFile, &key, &footerPartition)); CHK_OFAIL(footerPartition->bodySID == 0); CHK_OFAIL(footerPartition->indexSID == 1); CHK_OFAIL(mxf_append_partition(&partitions, footerPartition)); mxf_initialise_list_iter(&iter, &footerPartition->essenceContainers); i = 0; while (mxf_next_list_iter_element(&iter)) { mxfUL *label = (mxfUL*)mxf_get_iter_element(&iter); if (i == 0) { CHK_OFAIL(mxf_equals_ul(label, &MXF_EC_L(SD_Unc_625_50i_422_135_FrameWrapped))); } else { CHK_OFAIL(mxf_equals_ul(label, &MXF_EC_L(BWFFrameWrapped))); } i++; } mxf_clear_rip(&rip); mxf_file_close(&mxfFile); mxf_clear_file_partitions(&partitions); return 1; fail: mxf_clear_rip(&rip); mxf_file_close(&mxfFile); mxf_clear_file_partitions(&partitions); return 0; }
int test_create_and_write(const char *filename) { MXFFile *mxfFile = NULL; MXFFilePartitions partitions; MXFPartition *headerPartition = NULL; MXFPartition *bodyPartition1 = NULL; MXFPartition *bodyPartition2 = NULL; MXFPartition *footerPartition = NULL; MXFEssenceElement *essenceElement = NULL; uint8_t essenceData[1024]; memset(essenceData, 0, 1024); if (!mxf_disk_file_open_new(filename, &mxfFile)) { mxf_log_error("Failed to create '%s'" LOG_LOC_FORMAT, filename, LOG_LOC_PARAMS); return 0; } mxf_initialise_file_partitions(&partitions); /* TEST */ /* write the header pp */ CHK_OFAIL(mxf_append_new_partition(&partitions, &headerPartition)); headerPartition->key = MXF_PP_K(ClosedComplete, Header); headerPartition->bodySID = 1; CHK_OFAIL(mxf_append_partition_esscont_label(headerPartition, &MXF_EC_L(BWFFrameWrapped))); CHK_OFAIL(mxf_append_partition_esscont_label(headerPartition, &MXF_EC_L(BWFClipWrapped))); CHK_OFAIL(mxf_write_partition(mxfFile, headerPartition)); /* write essence element directly */ CHK_OFAIL(mxf_write_fixed_kl(mxfFile, &g_bwfFrameWrappedEEKey, 4, 256)); CHK_OFAIL(mxf_file_write(mxfFile, essenceData, 256)); /* write the body pp 1 */ CHK_OFAIL(mxf_append_new_from_partition(&partitions, headerPartition, &bodyPartition1)); bodyPartition1->key = MXF_PP_K(ClosedComplete, Body); bodyPartition1->bodySID = 2; CHK_OFAIL(mxf_write_partition(mxfFile, bodyPartition1)); /* write using MXFEssenceElement with known length */ CHK_OFAIL(mxf_open_essence_element_write(mxfFile, &g_bwfClipWrappedEEKey, 8, 1024, &essenceElement)); CHK_OFAIL(mxf_write_essence_element_data(mxfFile, essenceElement, essenceData, 1024)); mxf_close_essence_element(&essenceElement); /* write the body pp 2 */ CHK_OFAIL(mxf_append_new_from_partition(&partitions, headerPartition, &bodyPartition2)); bodyPartition2->key = MXF_PP_K(ClosedComplete, Body); bodyPartition2->bodySID = 3; CHK_OFAIL(mxf_write_partition(mxfFile, bodyPartition2)); /* write using MXFEssenceElement with uknown length */ CHK_OFAIL(mxf_open_essence_element_write(mxfFile, &g_bwfClipWrappedEEKey, 8, 0, &essenceElement)); CHK_OFAIL(mxf_write_essence_element_data(mxfFile, essenceElement, essenceData, 256)); CHK_OFAIL(mxf_write_essence_element_data(mxfFile, essenceElement, essenceData, 512)); CHK_OFAIL(mxf_write_essence_element_data(mxfFile, essenceElement, essenceData, 256)); CHK_ORET(mxf_finalize_essence_element_write(mxfFile, essenceElement)); mxf_close_essence_element(&essenceElement); /* write the footer pp */ CHK_OFAIL(mxf_append_new_from_partition(&partitions, headerPartition, &footerPartition)); footerPartition->key = MXF_PP_K(ClosedComplete, Footer); CHK_OFAIL(mxf_write_partition(mxfFile, footerPartition)); /* update the partitions */ CHK_OFAIL(mxf_update_partitions(mxfFile, &partitions)); mxf_file_close(&mxfFile); mxf_clear_file_partitions(&partitions); mxf_close_essence_element(&essenceElement); return 1; fail: mxf_file_close(&mxfFile); mxf_clear_file_partitions(&partitions); mxf_close_essence_element(&essenceElement); return 0; }
int test_read(const char *filename) { MXFFile *mxfFile = NULL; MXFFilePartitions partitions; MXFPartition *headerPartition = NULL; mxfKey key; uint8_t llen; uint64_t len; int i; int k; MXFIndexTableSegment *indexSegment = NULL; MXFDeltaEntry *deltaEntry; MXFIndexEntry *indexEntry; if (!mxf_disk_file_open_read(filename, &mxfFile)) { mxf_log_error("Failed to open '%s'" LOG_LOC_FORMAT, filename, LOG_LOC_PARAMS); return 0; } mxf_initialise_file_partitions(&partitions); /* read header pp */ CHK_OFAIL(mxf_read_header_pp_kl(mxfFile, &key, &llen, &len)); CHK_OFAIL(mxf_read_partition(mxfFile, &key, len, &headerPartition)); CHK_OFAIL(mxf_append_partition(&partitions, headerPartition)); /* TEST */ /* read index table segment */ CHK_OFAIL(mxf_read_next_nonfiller_kl(mxfFile, &key, &llen, &len)); CHK_OFAIL(mxf_is_index_table_segment(&key)); CHK_OFAIL(mxf_read_index_table_segment(mxfFile, len, &indexSegment)); CHK_OFAIL(indexSegment->indexEditRate.numerator == 25 && indexSegment->indexEditRate.denominator == 1); CHK_OFAIL(indexSegment->indexStartPosition == 0); CHK_OFAIL(indexSegment->indexDuration == 0x64); CHK_OFAIL(indexSegment->editUnitByteCount == 0x100); CHK_OFAIL(indexSegment->indexSID == 1); CHK_OFAIL(indexSegment->bodySID == 2); CHK_OFAIL(indexSegment->sliceCount == 0); CHK_OFAIL(indexSegment->posTableCount == 0); CHK_OFAIL(indexSegment->extStartOffset == 0); CHK_OFAIL(indexSegment->vbeByteCount == 0); CHK_OFAIL(indexSegment->singleIndexLocation == MXF_OPT_BOOL_NOT_PRESENT); CHK_OFAIL(indexSegment->singleEssenceLocation == MXF_OPT_BOOL_NOT_PRESENT); CHK_OFAIL(indexSegment->forwardIndexDirection == MXF_OPT_BOOL_NOT_PRESENT); CHK_OFAIL(indexSegment->deltaEntryArray != 0); CHK_OFAIL(indexSegment->indexEntryArray == 0); deltaEntry = indexSegment->deltaEntryArray; for (i = 0; i < 4; i++) { CHK_OFAIL(deltaEntry != 0); CHK_OFAIL(deltaEntry->posTableIndex == i); CHK_OFAIL(deltaEntry->slice == i); CHK_OFAIL((int)deltaEntry->elementData == i); deltaEntry = deltaEntry->next; } mxf_free_index_table_segment(&indexSegment); /* read index table segment */ CHK_OFAIL(mxf_read_next_nonfiller_kl(mxfFile, &key, &llen, &len)); CHK_OFAIL(mxf_is_index_table_segment(&key)); CHK_OFAIL(mxf_read_index_table_segment(mxfFile, len, &indexSegment)); CHK_OFAIL(indexSegment->indexEditRate.numerator == 25 && indexSegment->indexEditRate.denominator == 1); CHK_OFAIL(indexSegment->indexStartPosition == 0); CHK_OFAIL(indexSegment->indexDuration == 0x0a); CHK_OFAIL(indexSegment->editUnitByteCount == 0); CHK_OFAIL(indexSegment->indexSID == 1); CHK_OFAIL(indexSegment->bodySID == 2); CHK_OFAIL(indexSegment->sliceCount == 2); CHK_OFAIL(indexSegment->posTableCount == 2); CHK_OFAIL(indexSegment->extStartOffset == 0); CHK_OFAIL(indexSegment->vbeByteCount == 1); CHK_OFAIL(indexSegment->singleIndexLocation == MXF_OPT_BOOL_NOT_PRESENT); CHK_OFAIL(indexSegment->singleEssenceLocation == MXF_OPT_BOOL_TRUE); CHK_OFAIL(indexSegment->forwardIndexDirection == MXF_OPT_BOOL_FALSE); CHK_OFAIL(indexSegment->deltaEntryArray == 0); CHK_OFAIL(indexSegment->indexEntryArray != 0); indexEntry = indexSegment->indexEntryArray; for (i = 0; i < indexSegment->indexDuration; i++) { CHK_OFAIL(indexEntry != 0); CHK_OFAIL(indexEntry->temporalOffset == i); CHK_OFAIL(indexEntry->keyFrameOffset == i); CHK_OFAIL(indexEntry->flags == i); CHK_OFAIL((int)indexEntry->streamOffset == i); for (k = 0; k < indexSegment->sliceCount; k++) { CHK_OFAIL((int)indexEntry->sliceOffset[k] == i); } for (k = 0; k < indexSegment->posTableCount; k++) { CHK_OFAIL(indexEntry->posTable[k].numerator == i); CHK_OFAIL(indexEntry->posTable[k].denominator == i + 1); } indexEntry = indexEntry->next; } mxf_free_index_table_segment(&indexSegment); mxf_file_close(&mxfFile); mxf_clear_file_partitions(&partitions); return 1; fail: mxf_free_index_table_segment(&indexSegment); mxf_file_close(&mxfFile); mxf_clear_file_partitions(&partitions); return 0; }
int test_create_and_write(const char *filename) { MXFFile *mxfFile = NULL; MXFFilePartitions partitions; MXFPartition *headerPartition = NULL; MXFIndexTableSegment *indexSegment = NULL; uint32_t sliceOffset[2]; mxfRational posTable[2]; const mxfRational editRate = {25, 1}; int i; int k; if (!mxf_disk_file_open_new(filename, &mxfFile)) { mxf_log_error("Failed to create '%s'" LOG_LOC_FORMAT, filename, LOG_LOC_PARAMS); return 0; } mxf_initialise_file_partitions(&partitions); /* TEST */ /* write the header pp */ CHK_OFAIL(mxf_append_new_partition(&partitions, &headerPartition)); headerPartition->key = MXF_PP_K(ClosedComplete, Header); headerPartition->kagSize = 256; CHK_OFAIL(mxf_write_partition(mxfFile, headerPartition)); /* write index table segment */ CHK_OFAIL(mxf_mark_index_start(mxfFile, headerPartition)); CHK_OFAIL(mxf_create_index_table_segment(&indexSegment)); mxf_generate_uuid(&indexSegment->instanceUID); indexSegment->indexEditRate = editRate; indexSegment->indexDuration = 0x64; indexSegment->editUnitByteCount = 0x100; indexSegment->indexSID = 1; indexSegment->bodySID = 2; for (i = 0; i < 4; i++) { CHK_OFAIL(mxf_default_add_delta_entry(NULL, 0, indexSegment, i, i, i)); } CHK_OFAIL(mxf_write_index_table_segment(mxfFile, indexSegment)); CHK_OFAIL(mxf_fill_to_kag(mxfFile, headerPartition)); CHK_OFAIL(mxf_mark_index_end(mxfFile, headerPartition)); mxf_free_index_table_segment(&indexSegment); /* write index table segment */ CHK_OFAIL(mxf_mark_index_start(mxfFile, headerPartition)); CHK_OFAIL(mxf_create_index_table_segment(&indexSegment)); mxf_generate_uuid(&indexSegment->instanceUID); indexSegment->indexEditRate = editRate; indexSegment->indexDuration = 0x0a; indexSegment->editUnitByteCount = 0; indexSegment->indexSID = 1; indexSegment->bodySID = 2; indexSegment->sliceCount = 2; indexSegment->posTableCount = 2; indexSegment->vbeByteCount = 1; indexSegment->singleEssenceLocation = MXF_OPT_BOOL_TRUE; indexSegment->forwardIndexDirection = MXF_OPT_BOOL_FALSE; for (i = 0; i < indexSegment->indexDuration; i++) { for (k = 0; k < indexSegment->sliceCount; k++) { sliceOffset[k] = i; } for (k = 0; k < indexSegment->posTableCount; k++) { posTable[k].numerator = i; posTable[k].denominator = i + 1; } CHK_OFAIL(mxf_default_add_index_entry(NULL, 0, indexSegment, i, i, i, i, sliceOffset, posTable)); } CHK_OFAIL(mxf_write_index_table_segment(mxfFile, indexSegment)); CHK_OFAIL(mxf_fill_to_kag(mxfFile, headerPartition)); CHK_OFAIL(mxf_mark_index_end(mxfFile, headerPartition)); /* update the partitions */ CHK_OFAIL(mxf_update_partitions(mxfFile, &partitions)); mxf_file_close(&mxfFile); mxf_clear_file_partitions(&partitions); mxf_free_index_table_segment(&indexSegment); return 1; fail: mxf_file_close(&mxfFile); mxf_clear_file_partitions(&partitions); mxf_free_index_table_segment(&indexSegment); return 0; }
int test_read(const char *filename) { MXFFile *mxfFile = NULL; MXFFilePartitions partitions; MXFPartition *headerPartition = NULL; MXFPartition *bodyPartition1 = NULL; MXFPartition *bodyPartition2 = NULL; MXFPartition *footerPartition = NULL; mxfKey key; uint8_t llen; uint64_t len; uint8_t essenceData[1024]; MXFEssenceElement *essenceElement = NULL; uint32_t numRead; if (!mxf_disk_file_open_read(filename, &mxfFile)) { mxf_log_error("Failed to open '%s'" LOG_LOC_FORMAT, filename, LOG_LOC_PARAMS); return 0; } mxf_initialise_file_partitions(&partitions); /* TEST */ /* read header pp */ CHK_OFAIL(mxf_read_header_pp_kl(mxfFile, &key, &llen, &len)); CHK_OFAIL(mxf_read_partition(mxfFile, &key, &headerPartition)); CHK_OFAIL(mxf_append_partition(&partitions, headerPartition)); /* read essence data directly */ CHK_OFAIL(mxf_read_next_nonfiller_kl(mxfFile, &key, &llen, &len)); CHK_OFAIL(mxf_is_gc_essence_element(&key)); CHK_OFAIL(llen == 4 && len == 256); CHK_OFAIL(mxf_file_read(mxfFile, essenceData, (uint32_t)len)); /* read body pp 1 */ CHK_OFAIL(mxf_read_next_nonfiller_kl(mxfFile, &key, &llen, &len)); CHK_OFAIL(mxf_is_partition_pack(&key)); CHK_OFAIL(mxf_read_partition(mxfFile, &key, &bodyPartition1)); CHK_OFAIL(mxf_append_partition(&partitions, bodyPartition1)); /* read essence data using MXFEssenceElement */ CHK_OFAIL(mxf_read_next_nonfiller_kl(mxfFile, &key, &llen, &len)); CHK_OFAIL(mxf_open_essence_element_read(mxfFile, &key, llen, len, &essenceElement)); CHK_OFAIL(llen == 8 && len == 1024); CHK_OFAIL(mxf_read_essence_element_data(mxfFile, essenceElement, (uint32_t)len, essenceData, &numRead)); CHK_OFAIL(numRead == len); mxf_close_essence_element(&essenceElement); /* read body pp 2 */ CHK_OFAIL(mxf_read_next_nonfiller_kl(mxfFile, &key, &llen, &len)); CHK_OFAIL(mxf_is_partition_pack(&key)); CHK_OFAIL(mxf_read_partition(mxfFile, &key, &bodyPartition2)); CHK_OFAIL(mxf_append_partition(&partitions, bodyPartition2)); /* read essence data using MXFEssenceElement */ CHK_OFAIL(mxf_read_next_nonfiller_kl(mxfFile, &key, &llen, &len)); CHK_OFAIL(mxf_open_essence_element_read(mxfFile, &key, llen, len, &essenceElement)); CHK_OFAIL(llen == 8 && len == 1024); CHK_OFAIL(mxf_read_essence_element_data(mxfFile, essenceElement, 256, essenceData, &numRead)); CHK_OFAIL(numRead == 256); CHK_OFAIL(mxf_read_essence_element_data(mxfFile, essenceElement, 768, &essenceData[256], &numRead)); CHK_OFAIL(numRead == 768); mxf_close_essence_element(&essenceElement); /* read footer pp */ CHK_OFAIL(mxf_read_next_nonfiller_kl(mxfFile, &key, &llen, &len)); CHK_OFAIL(mxf_is_partition_pack(&key)); CHK_OFAIL(mxf_read_partition(mxfFile, &key, &footerPartition)); CHK_OFAIL(mxf_append_partition(&partitions, footerPartition)); mxf_file_close(&mxfFile); mxf_clear_file_partitions(&partitions); mxf_close_essence_element(&essenceElement); return 1; fail: mxf_file_close(&mxfFile); mxf_clear_file_partitions(&partitions); mxf_close_essence_element(&essenceElement); 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 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); return 1; fail: mxf_file_close(&mxfFile); return 0; }