diff --git a/apps/bmxtranswrap/bmxtranswrap.cpp b/apps/bmxtranswrap/bmxtranswrap.cpp index bc9d07dd..987e0a62 100644 --- a/apps/bmxtranswrap/bmxtranswrap.cpp +++ b/apps/bmxtranswrap/bmxtranswrap.cpp @@ -541,6 +541,9 @@ static void usage(const char *cmd) printf("\n"); printf(" as02/as11op1a/op1a/rdd9/as10:\n"); printf(" --part Video essence partition interval in frames in input edit rate units, or (floating point) seconds with 's' suffix. Default single partition\n"); + printf(" rdd9:\n"); + printf(" --fixed-part Force each partition to have the exact same partition interval in frames, except the last partition\n"); + printf(" New partitions are started if the frame count has been reached, even if the next partition does not begin with the start of a GOP\n"); printf("\n"); printf(" as11op1a/as11d10/as11rdd9:\n"); printf(" --dm Set descriptive framework property. is 'as11' or 'dpp'\n"); @@ -801,6 +804,7 @@ int main(int argc, const char** argv) const char *partition_interval_str = 0; int64_t partition_interval = 0; bool partition_interval_set = false; + bool fixed_partition_interval = false; const char *shim_name = 0; const char *shim_id = 0; const char *shim_annot = 0; @@ -2004,6 +2008,10 @@ int main(int argc, const char** argv) partition_interval_str = argv[cmdln_index + 1]; cmdln_index++; } + else if (strcmp(argv[cmdln_index], "--fixed-part") == 0) + { + fixed_partition_interval = true; + } else if (strcmp(argv[cmdln_index], "--dm") == 0) { if (cmdln_index + 3 >= argc) @@ -3801,6 +3809,7 @@ int main(int argc, const char** argv) if (partition_interval_set) rdd9_clip->SetPartitionInterval(partition_interval); + rdd9_clip->SetFixedPartitionInterval(fixed_partition_interval); rdd9_clip->SetOutputStartOffset(- precharge); rdd9_clip->SetOutputEndOffset(- rollout); diff --git a/apps/raw2bmx/raw2bmx.cpp b/apps/raw2bmx/raw2bmx.cpp index 27a94c73..74eecf3e 100644 --- a/apps/raw2bmx/raw2bmx.cpp +++ b/apps/raw2bmx/raw2bmx.cpp @@ -486,6 +486,9 @@ static void usage(const char *cmd) printf("\n"); printf(" as02/as11op1a/op1a/rdd9/as10:\n"); printf(" --part Video essence partition interval in frames, or (floating point) seconds with 's' suffix. Default single partition\n"); + printf(" rdd9:\n"); + printf(" --fixed-part Force each partition to have the exact same partition interval in frames, except the last partition\n"); + printf(" New partitions are started if the frame count has been reached, even if the next partition does not begin with the start of a GOP\n"); printf("\n"); printf(" as11op1a/as11d10:\n"); printf(" --dm Set descriptive framework property. is 'as11' or 'dpp'\n"); @@ -891,6 +894,7 @@ int main(int argc, const char** argv) const char *partition_interval_str = 0; int64_t partition_interval = 0; bool partition_interval_set = false; + bool fixed_partition_interval = false; const char *shim_name = 0; const char *shim_id = 0; const char *shim_annot = 0; @@ -1310,6 +1314,10 @@ int main(int argc, const char** argv) partition_interval_str = argv[cmdln_index + 1]; cmdln_index++; } + else if (strcmp(argv[cmdln_index], "--fixed-part") == 0) + { + fixed_partition_interval = true; + } else if (strcmp(argv[cmdln_index], "--dm") == 0) { if (cmdln_index + 3 >= argc) @@ -5079,6 +5087,7 @@ int main(int argc, const char** argv) if (partition_interval_set) rdd9_clip->SetPartitionInterval(partition_interval); + rdd9_clip->SetFixedPartitionInterval(fixed_partition_interval); rdd9_clip->SetOutputStartOffset(output_start_offset); rdd9_clip->SetOutputEndOffset(- output_end_offset); diff --git a/include/bmx/rdd9_mxf/RDD9File.h b/include/bmx/rdd9_mxf/RDD9File.h index c988c52b..18e96aaa 100644 --- a/include/bmx/rdd9_mxf/RDD9File.h +++ b/include/bmx/rdd9_mxf/RDD9File.h @@ -75,6 +75,7 @@ class RDD9File void SetFileSourcePackageUID(mxfUMID package_uid); // default generated void ReserveHeaderMetadataSpace(uint32_t min_bytes); // default 8192 void SetPartitionInterval(int64_t frame_count); // default 10sec + void SetFixedPartitionInterval(bool enable); // default false void SetValidator(RDD9Validator *validator); public: @@ -152,6 +153,7 @@ class RDD9File bool mFirstWrite; int64_t mPartitionInterval; + bool mFixedPartitionInterval; int64_t mPartitionFrameCount; std::vector mTracks; diff --git a/include/bmx/rdd9_mxf/RDD9IndexTable.h b/include/bmx/rdd9_mxf/RDD9IndexTable.h index 10d49f9c..fc22ece6 100644 --- a/include/bmx/rdd9_mxf/RDD9IndexTable.h +++ b/include/bmx/rdd9_mxf/RDD9IndexTable.h @@ -200,6 +200,7 @@ class RDD9IndexTable std::vector mIndexSegments; int64_t mDuration; int64_t mStreamOffset; + int64_t mFirstIndexSegmentCount; std::vector mWrittenIndexSegments; }; diff --git a/src/rdd9_mxf/RDD9File.cpp b/src/rdd9_mxf/RDD9File.cpp index 0d2f26c2..5a856302 100644 --- a/src/rdd9_mxf/RDD9File.cpp +++ b/src/rdd9_mxf/RDD9File.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -59,6 +60,22 @@ static const uint32_t MEMORY_WRITE_CHUNK_SIZE = 8192; +typedef struct +{ + Rational frame_rate; + int64_t partition_interval; +} RDD9PartitionInterval; + +static const RDD9PartitionInterval RDD9_PARTITION_INTERVAL[] = +{ + {{24000, 1001}, 240}, + {{25, 1}, 240}, + {{30000, 1001}, 300}, + {{50, 1}, 480}, + {{60000, 1001}, 600} +}; + + static bool compare_track(RDD9Track *left, RDD9Track *right) { return left->GetDataDef() < right->GetDataDef(); @@ -109,11 +126,22 @@ RDD9File::RDD9File(int flavour, File *mxf_file, Rational frame_rate) mMaterialPackage = 0; mFileSourcePackage = 0; mFirstWrite = true; - mPartitionInterval = 10 * frame_rate.numerator / frame_rate.denominator; + mPartitionInterval = 0; + mFixedPartitionInterval = false; mValidator = 0; mPartitionFrameCount = 0; mMXFChecksumFile = 0; + // Target 10 seconds partition duration and use the "should" values from + // RDD 9 2013, Table B.2 if a compliant frame rate is set. + mPartitionInterval = 10 * frame_rate.numerator / frame_rate.denominator; + for (size_t i = 0; i < BMX_ARRAY_SIZE(RDD9_PARTITION_INTERVAL); i++) { + if (frame_rate == RDD9_PARTITION_INTERVAL[i].frame_rate) { + mPartitionInterval = RDD9_PARTITION_INTERVAL[i].partition_interval; + break; + } + } + mTrackIdHelper.SetId("TimecodeTrack", 1); mTrackIdHelper.SetStartId(MXF_PICTURE_DDEF, 2); mTrackIdHelper.SetStartId(MXF_SOUND_DDEF, 4); @@ -228,6 +256,11 @@ void RDD9File::SetPartitionInterval(int64_t frame_count) mPartitionInterval = frame_count; } +void RDD9File::SetFixedPartitionInterval(bool enable) +{ + mFixedPartitionInterval = enable; +} + void RDD9File::SetValidator(RDD9Validator *validator) { delete mValidator; @@ -766,7 +799,8 @@ void RDD9File::WriteContentPackages(bool final_write) // start body partition at first write or when # frames per partition close to exceeding maximum if (mFirstWrite || (mPartitionInterval > 0 && mPartitionFrameCount > 0 && - mPartitionFrameCount + MAX_GOP_SIZE >= mPartitionInterval && mIndexTable->CanStartPartition())) + mPartitionFrameCount >= mPartitionInterval && + (mFixedPartitionInterval || mIndexTable->CanStartPartition()))) { mMXFFile->openMemoryFile(MEMORY_WRITE_CHUNK_SIZE); diff --git a/src/rdd9_mxf/RDD9IndexTable.cpp b/src/rdd9_mxf/RDD9IndexTable.cpp index 98e4460c..c71574a9 100644 --- a/src/rdd9_mxf/RDD9IndexTable.cpp +++ b/src/rdd9_mxf/RDD9IndexTable.cpp @@ -237,6 +237,7 @@ RDD9IndexTable::RDD9IndexTable(uint32_t index_sid, uint32_t body_sid, Rational e mIndexEntrySize = 0; mDuration = 0; mStreamOffset = 0; + mFirstIndexSegmentCount = 0; } RDD9IndexTable::~RDD9IndexTable() @@ -479,6 +480,8 @@ void RDD9IndexTable::WriteVBESegments(File *mxf_file, Partition *partition, vect { size_t i; for (i = 0; i < segments.size(); i++) { + int64_t segment_start_file_pos = mxf_file->tell(); + IndexTableSegment *segment = segments[i]->GetSegment(); ByteArray *entries = segments[i]->GetEntries(); @@ -498,7 +501,20 @@ void RDD9IndexTable::WriteVBESegments(File *mxf_file, Partition *partition, vect segment->writeIndexEntryArrayHeader(mxf_file, mSliceCount, 0, (uint32_t)segment->getIndexDuration()); mxf_file->write(entries->GetBytes(), entries->GetSize()); - partition->fillToKag(mxf_file); + // The index byte count for all index segments should all be equal. + // The index durations for all index segments, except the last, should all be equal. + // The last index segment may have a shorter index duration and the code below should + // ensure that it has the same index byte count (as the first index segment). + if (mFirstIndexSegmentCount == 0) { + mFirstIndexSegmentCount = mxf_file->tell() - segment_start_file_pos; + partition->fillToKag(mxf_file); + } else { + int64_t current_count = mxf_file->tell() - segment_start_file_pos; + if (current_count < mFirstIndexSegmentCount) + partition->allocateSpaceToKag(mxf_file, mFirstIndexSegmentCount - current_count); + else + partition->fillToKag(mxf_file); + } } } diff --git a/test/as10/test_as10.cmake b/test/as10/test_as10.cmake index b71e2c2f..35705fe7 100644 --- a/test/as10/test_as10.cmake +++ b/test/as10/test_as10.cmake @@ -35,7 +35,7 @@ set(create_command ${RAW2BMX} -f 25 -y 22:22:22:22 --single-pass - --part 25 + --part 12 -o ${output_file_1} --dm-file as10 ${TEST_SOURCE_DIR}/as10_core_framework.txt --shim-name high_hd_2014 diff --git a/test/rdd9_mxf/mpeg2lg_422p_hl_1080i_fixed_part.md5 b/test/rdd9_mxf/mpeg2lg_422p_hl_1080i_fixed_part.md5 new file mode 100644 index 00000000..ead57ea2 --- /dev/null +++ b/test/rdd9_mxf/mpeg2lg_422p_hl_1080i_fixed_part.md5 @@ -0,0 +1 @@ +864b5a1e6b9e1cc4e539dd48a5862d70 \ No newline at end of file diff --git a/test/rdd9_mxf/test_common.cmake b/test/rdd9_mxf/test_common.cmake index 80c32754..c96b0366 100644 --- a/test/rdd9_mxf/test_common.cmake +++ b/test/rdd9_mxf/test_common.cmake @@ -1,7 +1,7 @@ include("${TEST_SOURCE_DIR}/../testing.cmake") -function(run_test test frame_rate duration) +function(run_test test frame_rate part fixed_part duration) if(frame_rate STREQUAL "x") set(frame_rate) set(rate_opt) @@ -9,17 +9,25 @@ function(run_test test frame_rate duration) set(rate_opt -f ${frame_rate}) endif() + if(fixed_part STREQUAL "true") + set(fixed_part_opt --fixed-part) + set(output_suffix _fixed_part) + else() + set(fixed_part_opt) + set(output_suffix) + endif() + if(TEST_MODE STREQUAL "check") - set(output_file test_${test}${frame_rate}.mxf) + set(output_file test_${test}${frame_rate}${output_suffix}.mxf) elseif(TEST_MODE STREQUAL "samples") file(MAKE_DIRECTORY ${BMX_TEST_SAMPLES_DIR}) - set(output_file ${BMX_TEST_SAMPLES_DIR}/test_${test}${frame_rate}.mxf) + set(output_file ${BMX_TEST_SAMPLES_DIR}/test_${test}${frame_rate}${output_suffix}.mxf) else() - set(output_file test_${test}${frame_rate}.mxf) + set(output_file test_${test}${frame_rate}${output_suffix}.mxf) endif() - set(checksum_file ${test}${frame_rate}.md5) + set(checksum_file ${test}${frame_rate}${output_suffix}.md5) set(create_test_audio ${CREATE_TEST_ESSENCE} -t 1 @@ -33,7 +41,8 @@ function(run_test test frame_rate duration) -y 10:11:12:13 ${rate_opt} --clip test - --part 12 + --part ${part} + ${fixed_part_opt} -o ${output_file} -a 16:9 --${test} video_${test} -q 16 --locked true --pcm audio_${test} @@ -59,24 +68,30 @@ endfunction() function(run_tests tests duration) list(LENGTH tests len_tests) - math(EXPR max_index "(${len_tests} / 3) - 1") + math(EXPR max_index "(${len_tests} / 5) - 1") foreach(index RANGE ${max_index}) - math(EXPR test_index "${index} * 3") + math(EXPR test_index "${index} * 5") list(GET tests ${test_index} test) - math(EXPR test_ess_type_index "${index} * 3 + 1") + math(EXPR test_ess_type_index "${index} * 5 + 1") list(GET tests ${test_ess_type_index} test_ess_type) - math(EXPR test_frame_rate_index "${index} * 3 + 2") + math(EXPR test_frame_rate_index "${index} * 5 + 2") list(GET tests ${test_frame_rate_index} test_frame_rate) + math(EXPR test_part_index "${index} * 5 + 3") + list(GET tests ${test_part_index} test_part) + + math(EXPR test_fixed_part_index "${index} * 5 + 4") + list(GET tests ${test_fixed_part_index} test_fixed_part) + set(create_test_video ${CREATE_TEST_ESSENCE} -t ${test_ess_type} -d ${duration} video_${test} ) - run_test(${test} ${test_frame_rate} ${duration}) + run_test(${test} ${test_frame_rate} ${test_part} ${test_fixed_part} ${duration}) endforeach() endfunction() diff --git a/test/rdd9_mxf/test_mpeg2lg.cmake b/test/rdd9_mxf/test_mpeg2lg.cmake index e04ce29a..997ea96c 100644 --- a/test/rdd9_mxf/test_mpeg2lg.cmake +++ b/test/rdd9_mxf/test_mpeg2lg.cmake @@ -3,9 +3,10 @@ include("${TEST_SOURCE_DIR}/test_common.cmake") set(tests - mpeg2lg_422p_hl_1080i 14 "x" - mpeg2lg_mp_h14_1080i 15 "x" - mpeg2lg_mp_hl_1920_1080i 16 "x" + mpeg2lg_422p_hl_1080i 14 "x" "12" "false" + mpeg2lg_mp_h14_1080i 15 "x" "12" "false" + mpeg2lg_mp_hl_1920_1080i 16 "x" "12" "false" + mpeg2lg_422p_hl_1080i 14 "x" "6" "true" ) run_tests("${tests}" 24)