+// Write one or more plaintext ACES codestreams to a plaintext AS-02 file
+// Write one or more plaintext ACES codestreams to a ciphertext AS-02 file
+//
+Result_t
+write_ACES_file(CommandOptions& Options)
+{
+ AESEncContext* Context = 0;
+ HMACContext* HMAC = 0;
+ AS_02::ACES::MXFWriter Writer;
+ AS_02::ACES::FrameBuffer FrameBuffer(Options.fb_size);
+ AS_02::ACES::SequenceParser Parser;
+ byte_t IV_buf[CBC_BLOCK_SIZE];
+ Kumu::FortunaRNG RNG;
+ ASDCP::MXF::FileDescriptor *essence_descriptor = 0;
+ ASDCP::MXF::InterchangeObject_list_t essence_sub_descriptors;
+ AS_02::ACES::PictureDescriptor PDesc;
+ AS_02::ACES::ResourceList_t resource_list_t;
+
+ // set up essence parser
+ //Result_t result = Parser.OpenRead(Options.filenames.front().c_str(), Options.j2c_aces_pedantic);
+ // set up essence parser
+ std::list<std::string> target_frame_file_list;
+ if (Options.target_frame_subdescriptor_flag)
+ {
+ Kumu::DirScannerEx dir_reader;
+ Kumu::DirectoryEntryType_t ft;
+ std::string next_item;
+ Result_t result = dir_reader.Open(Options.target_frame_directory);
+ if ( KM_SUCCESS(result) )
+ {
+ while ( KM_SUCCESS(dir_reader.GetNext(next_item, ft)) )
+ {
+ if ( next_item[0] == '.' ) continue; // no hidden files
+ std::string tmp_path = Kumu::PathJoin(Options.target_frame_directory, next_item);
+ target_frame_file_list.push_back(tmp_path);
+ }
+ }
+ }
+ Result_t result = Parser.OpenRead(Options.filenames.front().c_str(), Options.j2c_pedantic, target_frame_file_list);
+
+ // set up MXF writer
+ if (ASDCP_SUCCESS(result))
+ {
+ Parser.FillPictureDescriptor(PDesc);
+ Parser.FillResourceList(resource_list_t);
+ PDesc.EditRate = Options.edit_rate;
+
+ if (Options.verbose_flag)
+ {
+ fprintf(stderr, "ACES pictures\n");
+ fputs("PictureDescriptor:\n", stderr);
+ fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
+ AS_02::ACES::PictureDescriptorDump(PDesc);
+ }
+
+ ASDCP::MXF::RGBAEssenceDescriptor* tmp_dscr = new ASDCP::MXF::RGBAEssenceDescriptor(g_dict);
+ Kumu::GenRandomValue(tmp_dscr->InstanceUID);
+ ASDCP::MXF::ACESPictureSubDescriptor* aces_picture_subdescriptor = new ASDCP::MXF::ACESPictureSubDescriptor(g_dict);
+ Kumu::GenRandomValue(aces_picture_subdescriptor->InstanceUID);
+ result = AS_02::ACES::ACES_PDesc_to_MD(PDesc, *g_dict, *tmp_dscr);
+
+ if (ASDCP_SUCCESS(result))
+ {
+ if (Options.aspect_ratio_flag) tmp_dscr->AspectRatio = Options.aspect_ratio;
+
+ if (Options.aces_picture_subdescriptor_flag)
+ {
+ if (Options.aces_authoring_information_flag) aces_picture_subdescriptor->ACESAuthoringInformation = Options.aces_authoring_information;
+ if (Options.md_primaries.HasValue())
+ {
+ aces_picture_subdescriptor->ACESMasteringDisplayPrimaries = Options.md_primaries;
+ aces_picture_subdescriptor->ACESMasteringDisplayWhitePointChromaticity = Options.md_white_point;
+ }
+ if (Options.md_min_luminance && Options.md_max_luminance)
+ {
+ aces_picture_subdescriptor->ACESMasteringDisplayMinimumLuminance = Options.md_min_luminance;
+ aces_picture_subdescriptor->ACESMasteringDisplayMaximumLuminance = Options.md_max_luminance;
+ }
+ essence_sub_descriptors.push_back(aces_picture_subdescriptor);
+ }
+
+ if (Options.target_frame_subdescriptor_flag)
+ {
+ AS_02::ACES::ResourceList_t::iterator it;
+ ui32_t EssenceStreamID = 10; //start with 10, same value in AncillaryResourceWriter
+ for (it = resource_list_t.begin(); it != resource_list_t.end(); it++ )
+ {
+ ASDCP::MXF::TargetFrameSubDescriptor* target_frame_subdescriptor = new ASDCP::MXF::TargetFrameSubDescriptor(g_dict);
+ Kumu::GenRandomValue(target_frame_subdescriptor->InstanceUID);
+ target_frame_subdescriptor->TargetFrameAncillaryResourceID.Set(it->ResourceID);
+ target_frame_subdescriptor->MediaType.assign(AS_02::ACES::MIME2str(it->Type));
+ target_frame_subdescriptor->TargetFrameEssenceStreamID = EssenceStreamID++;
+ if (Options.target_frame_index_flag)
+ {
+ if (Options.target_frame_index_list.size() > 0)
+ {
+ target_frame_subdescriptor->TargetFrameIndex = Options.target_frame_index_list.front();
+ Options.target_frame_index_list.pop_front();
+ } else
+ {
+ fprintf(stderr, "Insufficient number of Target Frame Index values provided\n");
+ fprintf(stderr, "Number of Target Frames (%lu) should match number of Target Frame Index values\n", resource_list_t.size());
+ }
+ }
+ if (Options.target_frame_transfer_characteristics_flag) target_frame_subdescriptor->TargetFrameTransferCharacteristic = Options.target_frame_transfer_characteristics;
+ if (Options.target_frame_color_primaries_flag) target_frame_subdescriptor->TargetFrameColorPrimaries = Options.target_frame_color_primaries;
+ if (Options.target_frame_min_max_ref_flag)
+ {
+ target_frame_subdescriptor->TargetFrameComponentMinRef = Options.target_frame_min_ref;
+ target_frame_subdescriptor->TargetFrameComponentMaxRef = Options.target_frame_max_ref;
+ }
+ if (Options.aces_picture_subdescriptor_flag) target_frame_subdescriptor->ACESPictureSubDescriptorInstanceID = aces_picture_subdescriptor->InstanceUID;
+ essence_sub_descriptors.push_back(target_frame_subdescriptor);
+ }
+ }
+
+ essence_descriptor = static_cast<ASDCP::MXF::FileDescriptor*>(tmp_dscr);
+ if (Options.line_map_flag) tmp_dscr->VideoLineMap = Options.line_map;
+ }
+ }
+
+ if (ASDCP_SUCCESS(result) && !Options.no_write_flag)
+ {
+ WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
+ Info.LabelSetType = LS_MXF_SMPTE;
+
+ if (Options.asset_id_flag)
+ memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
+ else
+ Kumu::GenRandomUUID(Info.AssetUUID);
+
+ // configure encryption
+ if (Options.key_flag)
+ {
+ Kumu::GenRandomUUID(Info.ContextID);
+ Info.EncryptedEssence = true;
+
+ if (Options.key_id_flag)
+ {
+ memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
+ }
+ else
+ {
+ create_random_uuid(Info.CryptographicKeyID);
+ }
+
+ Context = new AESEncContext;
+ result = Context->InitKey(Options.key_value);
+
+ if (ASDCP_SUCCESS(result))
+ result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
+
+ if (ASDCP_SUCCESS(result) && Options.write_hmac)
+ {
+ Info.UsesHMAC = true;
+ HMAC = new HMACContext;
+ result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
+ }
+ }
+
+ if (ASDCP_SUCCESS(result))
+ {
+ result = Writer.OpenWrite(Options.out_file, Info, essence_descriptor, essence_sub_descriptors,
+ Options.edit_rate, AS_02::ACES::ResourceList_t(), Options.mxf_header_size, Options.index_strategy, Options.partition_space);
+ }
+ }
+
+ if (ASDCP_SUCCESS(result))
+ {
+ ui32_t duration = 0;
+ result = Parser.Reset();
+
+ while (ASDCP_SUCCESS(result) && duration++ < Options.duration)
+ {
+ result = Parser.ReadFrame(FrameBuffer);
+
+ if (ASDCP_SUCCESS(result))
+ {
+ if (Options.verbose_flag)
+ FrameBuffer.Dump(stderr, Options.fb_dump_size);
+
+ if (Options.key_flag && Options.encrypt_header_flag)
+ FrameBuffer.PlaintextOffset(0);
+ }
+
+ if (ASDCP_SUCCESS(result) && !Options.no_write_flag)
+ {
+ result = Writer.WriteFrame(FrameBuffer, Context, HMAC);
+
+ // The Writer class will forward the last block of ciphertext
+ // to the encryption context for use as the IV for the next
+ // frame. If you want to use non-sequitur IV values, un-comment
+ // the following line of code.
+ // if ( ASDCP_SUCCESS(result) && Options.key_flag )
+ // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
+ }
+ }
+
+ if (result == RESULT_ENDOFFILE)
+ result = RESULT_OK;
+ }
+ AS_02::ACES::ResourceList_t::const_iterator ri;
+ for ( ri = resource_list_t.begin() ; ri != resource_list_t.end() && ASDCP_SUCCESS(result); ri++ )
+ {
+ result = Parser.ReadAncillaryResource((*ri).filePath, FrameBuffer);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ if ( Options.verbose_flag )
+ FrameBuffer.Dump(stderr, Options.fb_dump_size);
+
+ if ( ! Options.no_write_flag )
+ {
+ result = Writer.WriteAncillaryResource(FrameBuffer, Context, HMAC);
+
+ // The Writer class will forward the last block of ciphertext
+ // to the encryption context for use as the IV for the next
+ // frame. If you want to use non-sequitur IV values, un-comment
+ // the following line of code.
+ // if ( ASDCP_SUCCESS(result) && Options.key_flag )
+ // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
+ }
+ }
+
+ if ( result == RESULT_ENDOFFILE )
+ result = RESULT_OK;
+ }
+
+
+
+ if (ASDCP_SUCCESS(result) && !Options.no_write_flag)
+ result = Writer.Finalize();
+
+ return result;
+}
+
+
+
+
+//------------------------------------------------------------------------------------------
+// PCM essence