/*---------------------------------------------------------------------- | main +---------------------------------------------------------------------*/ int main(int argc, char** argv) { if (argc == 1) PrintUsageAndExit(); // parse options const char* kms_uri = NULL; enum Method method = METHOD_NONE; const char* input_filename = NULL; const char* output_filename = NULL; const char* fragments_info_filename = NULL; AP4_ProtectionKeyMap key_map; AP4_TrackPropertyMap property_map; bool show_progress = false; bool strict = false; AP4_Array<AP4_PsshAtom*> pssh_atoms; AP4_DataBuffer kids; unsigned int kid_count = 0; AP4_Result result; // parse the command line arguments char* arg; while ((arg = *++argv)) { if (!strcmp(arg, "--method")) { arg = *++argv; if (arg == NULL) { fprintf(stderr, "ERROR: missing argument for --method option\n"); return 1; } if (!strcmp(arg, "OMA-PDCF-CBC")) { method = METHOD_OMA_PDCF_CBC; } else if (!strcmp(arg, "OMA-PDCF-CTR")) { method = METHOD_OMA_PDCF_CTR; } else if (!strcmp(arg, "MARLIN-IPMP-ACBC")) { method = METHOD_MARLIN_IPMP_ACBC; } else if (!strcmp(arg, "MARLIN-IPMP-ACGK")) { method = METHOD_MARLIN_IPMP_ACGK; } else if (!strcmp(arg, "PIFF-CBC")) { method = METHOD_PIFF_CBC; } else if (!strcmp(arg, "PIFF-CTR")) { method = METHOD_PIFF_CTR; } else if (!strcmp(arg, "MPEG-CENC")) { method = METHOD_MPEG_CENC; } else if (!strcmp(arg, "ISMA-IAEC")) { method = METHOD_ISMA_AES; } else { fprintf(stderr, "ERROR: invalid value for --method argument\n"); return 1; } } else if (!strcmp(arg, "--fragments-info")) { arg = *++argv; if (arg == NULL) { fprintf(stderr, "ERROR: missing argument for --fragments-info option\n"); return 1; } fragments_info_filename = arg; } else if (!strcmp(arg, "--pssh") || !strcmp(arg, "--pssh-v1")) { bool v1 = (strcmp(arg, "--pssh-v1") == 0); arg = *++argv; if (arg == NULL) { fprintf(stderr, "ERROR: missing argument for --pssh\n"); return 1; } if (AP4_StringLength(arg) < 32+1 || arg[32] != ':') { fprintf(stderr, "ERROR: invalid argument syntax for --pssh\n"); return 1; } unsigned char system_id[16]; arg[32] = '\0'; result = AP4_ParseHex(arg, system_id, 16); if (AP4_FAILED(result)) { fprintf(stderr, "ERROR: invalid argument syntax for --pssh\n"); return 1; } const char* pssh_filename = arg+33; // load the pssh payload AP4_DataBuffer pssh_payload; if (pssh_filename[0]) { AP4_ByteStream* pssh_input = NULL; result = AP4_FileByteStream::Create(pssh_filename, AP4_FileByteStream::STREAM_MODE_READ, pssh_input); if (AP4_FAILED(result)) { fprintf(stderr, "ERROR: cannot open pssh payload file (%d)\n", result); return 1; } AP4_LargeSize pssh_payload_size = 0; pssh_input->GetSize(pssh_payload_size); pssh_payload.SetDataSize((AP4_Size)pssh_payload_size); result = pssh_input->Read(pssh_payload.UseData(), (AP4_Size)pssh_payload_size); if (AP4_FAILED(result)) { fprintf(stderr, "ERROR: cannot read pssh payload from file (%d)\n", result); return 1; } } AP4_PsshAtom* pssh; if (v1) { if (kid_count) { pssh = new AP4_PsshAtom(system_id, kids.GetData(), kid_count); } else { pssh = new AP4_PsshAtom(system_id); } } else { pssh = new AP4_PsshAtom(system_id); } if (pssh_payload.GetDataSize()) { pssh->SetData(pssh_payload.GetData(), pssh_payload.GetDataSize()); } pssh_atoms.Append(pssh); } else if (!strcmp(arg, "--kms-uri")) { arg = *++argv; if (arg == NULL) { fprintf(stderr, "ERROR: missing argument for --kms-uri option\n"); return 1; } if (method != METHOD_ISMA_AES) { fprintf(stderr, "ERROR: --kms-uri only applies to method ISMA-IAEC\n"); return 1; } kms_uri = arg; } else if (!strcmp(arg, "--show-progress")) { show_progress = true; } else if (!strcmp(arg, "--strict")) { strict = true; } else if (!strcmp(arg, "--key")) { if (method == METHOD_NONE) { fprintf(stderr, "ERROR: --method argument must appear before --key\n"); return 1; } arg = *++argv; if (arg == NULL) { fprintf(stderr, "ERROR: missing argument for --key option\n"); return 1; } char* track_ascii = NULL; char* key_ascii = NULL; char* iv_ascii = NULL; if (AP4_FAILED(AP4_SplitArgs(arg, track_ascii, key_ascii, iv_ascii))) { fprintf(stderr, "ERROR: invalid argument for --key option\n"); return 1; } unsigned int track = strtoul(track_ascii, NULL, 10); // parse the key value unsigned char key[16]; AP4_SetMemory(key, 0, sizeof(key)); if (AP4_CompareStrings(key_ascii, "random") == 0) { result = AP4_System_GenerateRandomBytes(key, 16); if (AP4_FAILED(result)) { fprintf(stderr, "ERROR: failed to generate random key (%d)\n", result); return 1; } char key_hex[32+1]; key_hex[32] = '\0'; AP4_FormatHex(key, 16, key_hex); printf("KEY.%d=%s\n", track, key_hex); } else { if (AP4_ParseHex(key_ascii, key, 16)) { fprintf(stderr, "ERROR: invalid hex format for key\n"); return 1; } } // parse the iv unsigned char iv[16]; AP4_SetMemory(iv, 0, sizeof(iv)); if (AP4_CompareStrings(iv_ascii, "random") == 0) { result = AP4_System_GenerateRandomBytes(iv, 16); if (AP4_FAILED(result)) { fprintf(stderr, "ERROR: failed to generate random key (%d)\n", result); return 1; } iv[0] &= 0x7F; // always set the MSB to 0 so we don't have wraparounds } else { unsigned int iv_size = (unsigned int)AP4_StringLength(iv_ascii)/2; if (AP4_ParseHex(iv_ascii, iv, iv_size)) { fprintf(stderr, "ERROR: invalid hex format for iv\n"); return 1; } } switch (method) { case METHOD_OMA_PDCF_CTR: case METHOD_ISMA_AES: case METHOD_PIFF_CTR: case METHOD_MPEG_CENC: // truncate the IV AP4_SetMemory(&iv[8], 0, 8); break; default: break; } // check that the key is not already there if (key_map.GetKey(track)) { fprintf(stderr, "ERROR: key already set for track %d\n", track); return 1; } // set the key in the map key_map.SetKey(track, key, 16, iv, 16); } else if (!strcmp(arg, "--property")) { char* track_ascii = NULL; char* name = NULL; char* value = NULL; if (method != METHOD_OMA_PDCF_CBC && method != METHOD_OMA_PDCF_CTR && method != METHOD_MARLIN_IPMP_ACBC && method != METHOD_MARLIN_IPMP_ACGK && method != METHOD_PIFF_CBC && method != METHOD_PIFF_CTR && method != METHOD_MPEG_CENC) { fprintf(stderr, "ERROR: this method does not use properties\n"); return 1; } arg = *++argv; if (arg == NULL) { fprintf(stderr, "ERROR: missing argument for --property option\n"); return 1; } if (AP4_FAILED(AP4_SplitArgs(arg, track_ascii, name, value))) { fprintf(stderr, "ERROR: invalid argument for --property option\n"); return 1; } unsigned int track = strtoul(track_ascii, NULL, 10); // check that the property is not already set if (property_map.GetProperty(track, name)) { fprintf(stderr, "ERROR: property %s already set for track %d\n", name, track); return 1; } // set the property in the map property_map.SetProperty(track, name, value); // special treatment for KID properties if (!strcmp(name, "KID")) { if (AP4_StringLength(value) != 32) { fprintf(stderr, "ERROR: invalid size for KID property (must be 32 hex chars)\n"); return 1; } AP4_UI08 kid[16]; if (AP4_FAILED(AP4_ParseHex(value, kid, 16))) { fprintf(stderr, "ERROR: invalid syntax for KID property (must be 32 hex chars)\n"); return 1; } // check if we already have this KID bool kid_already_present = false; for (unsigned int i=0; i<kid_count; i++) { if (AP4_CompareMemory(kids.GetData()+(i*16), kid, 16) == 0) { kid_already_present = true; break; } } if (!kid_already_present) { ++kid_count; kids.AppendData(kid, 16); } } } else if (!strcmp(arg, "--global-option")) { arg = *++argv; char* name = NULL; char* value = NULL; if (arg == NULL) { fprintf(stderr, "ERROR: missing argument for --global-option option\n"); return 1; } if (AP4_FAILED(AP4_SplitArgs(arg, name, value))) { fprintf(stderr, "ERROR: invalid argument for --global-option option\n"); return 1; } AP4_GlobalOptions::SetString(name, value); } else if (input_filename == NULL) { input_filename = arg; } else if (output_filename == NULL) { output_filename = arg; } else { fprintf(stderr, "ERROR: unexpected argument (%s)\n", arg); return 1; } } // check the arguments if (method == METHOD_NONE) { fprintf(stderr, "ERROR: missing --method argument\n"); return 1; } if (input_filename == NULL) { fprintf(stderr, "ERROR: missing input filename\n"); return 1; } if (output_filename == NULL) { fprintf(stderr, "ERROR: missing output filename\n"); return 1; } // create an encrypting processor AP4_Processor* processor = NULL; if (method == METHOD_ISMA_AES) { if (kms_uri == NULL) { fprintf(stderr, "ERROR: method ISMA-IAEC requires --kms-uri\n"); return 1; } AP4_IsmaEncryptingProcessor* isma_processor = new AP4_IsmaEncryptingProcessor(kms_uri); isma_processor->GetKeyMap().SetKeys(key_map); processor = isma_processor; } else if (method == METHOD_MARLIN_IPMP_ACBC || method == METHOD_MARLIN_IPMP_ACGK) { bool use_group_key = (method == METHOD_MARLIN_IPMP_ACGK); if (use_group_key) { // check that the group key is set if (key_map.GetKey(0) == NULL) { fprintf(stderr, "ERROR: method MARLIN-IPMP-ACGK requires a group key\n"); return 1; } } AP4_MarlinIpmpEncryptingProcessor* marlin_processor = new AP4_MarlinIpmpEncryptingProcessor(use_group_key); marlin_processor->GetKeyMap().SetKeys(key_map); marlin_processor->GetPropertyMap().SetProperties(property_map); processor = marlin_processor; } else if (method == METHOD_OMA_PDCF_CTR || method == METHOD_OMA_PDCF_CBC) { AP4_OmaDcfEncryptingProcessor* oma_processor = new AP4_OmaDcfEncryptingProcessor(method == METHOD_OMA_PDCF_CTR? AP4_OMA_DCF_CIPHER_MODE_CTR : AP4_OMA_DCF_CIPHER_MODE_CBC); oma_processor->GetKeyMap().SetKeys(key_map); oma_processor->GetPropertyMap().SetProperties(property_map); processor = oma_processor; } else if (method == METHOD_PIFF_CTR || method == METHOD_PIFF_CBC || method == METHOD_MPEG_CENC) { AP4_CencVariant variant = AP4_CENC_VARIANT_MPEG; switch (method) { case METHOD_PIFF_CBC: variant = AP4_CENC_VARIANT_PIFF_CBC; break; case METHOD_PIFF_CTR: variant = AP4_CENC_VARIANT_PIFF_CTR; break; case METHOD_MPEG_CENC: variant = AP4_CENC_VARIANT_MPEG; break; default: break; } AP4_CencEncryptingProcessor* cenc_processor = new AP4_CencEncryptingProcessor(variant); cenc_processor->GetKeyMap().SetKeys(key_map); cenc_processor->GetPropertyMap().SetProperties(property_map); for (unsigned int i=0; i<pssh_atoms.ItemCount(); i++) { cenc_processor->GetPsshAtoms().Append(pssh_atoms[i]); } processor = cenc_processor; } // create the input stream AP4_ByteStream* input = NULL; result = AP4_FileByteStream::Create(input_filename, AP4_FileByteStream::STREAM_MODE_READ, input); if (AP4_FAILED(result)) { fprintf(stderr, "ERROR: cannot open input file (%s)\n", input_filename); return 1; } // create the output stream AP4_ByteStream* output = NULL; result = AP4_FileByteStream::Create(output_filename, AP4_FileByteStream::STREAM_MODE_WRITE, output); if (AP4_FAILED(result)) { fprintf(stderr, "ERROR: cannot open output file (%s)\n", output_filename); return 1; } // create the fragments info stream if needed AP4_ByteStream* fragments_info = NULL; if (fragments_info_filename) { result = AP4_FileByteStream::Create(fragments_info_filename, AP4_FileByteStream::STREAM_MODE_READ, fragments_info); if (AP4_FAILED(result)) { fprintf(stderr, "ERROR: cannot open fragments info file (%s)\n", fragments_info_filename); return 1; } } // process/decrypt the file ProgressListener listener; if (fragments_info) { bool check = CheckWarning(*fragments_info, key_map, method); if (strict && check) return 1; result = processor->Process(*input, *output, *fragments_info, show_progress?&listener:NULL); } else { bool check = CheckWarning(*input, key_map, method); if (strict && check) return 1; result = processor->Process(*input, *output, show_progress?&listener:NULL); } if (AP4_FAILED(result)) { fprintf(stderr, "ERROR: failed to process the file (%d)\n", result); } // cleanup delete processor; input->Release(); output->Release(); if (fragments_info) fragments_info->Release(); for (unsigned int i=0; i<pssh_atoms.ItemCount(); i++) { delete pssh_atoms[i]; } return 0; }
/*---------------------------------------------------------------------- | AP4_AtomFactory::CreateAtomFromStream +---------------------------------------------------------------------*/ AP4_Result AP4_AtomFactory::CreateAtomFromStream(AP4_ByteStream& stream, AP4_UI32 type, AP4_UI32 size_32, AP4_UI64 size_64, AP4_Atom*& atom) { bool atom_is_large = (size_32 == 1); bool force_64 = (size_32==1 && ((size_64>>32) == 0)); // create the atom if (GetContext() == AP4_ATOM_TYPE_STSD) { // sample entry if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; switch (type) { case AP4_ATOM_TYPE_MP4A: atom = new AP4_Mp4aSampleEntry(size_32, stream, *this); break; case AP4_ATOM_TYPE_MP4V: atom = new AP4_Mp4vSampleEntry(size_32, stream, *this); break; case AP4_ATOM_TYPE_MP4S: atom = new AP4_Mp4sSampleEntry(size_32, stream, *this); break; case AP4_ATOM_TYPE_ENCA: atom = new AP4_EncaSampleEntry(size_32, stream, *this); break; case AP4_ATOM_TYPE_ENCV: atom = new AP4_EncvSampleEntry(size_32, stream, *this); break; case AP4_ATOM_TYPE_DRMS: atom = new AP4_DrmsSampleEntry(size_32, stream, *this); break; case AP4_ATOM_TYPE_DRMI: atom = new AP4_DrmiSampleEntry(size_32, stream, *this); break; case AP4_ATOM_TYPE_AVC1: case AP4_ATOM_TYPE_AVC2: case AP4_ATOM_TYPE_AVC3: case AP4_ATOM_TYPE_AVC4: atom = new AP4_AvcSampleEntry(type, size_32, stream, *this); break; case AP4_ATOM_TYPE_HEV1: case AP4_ATOM_TYPE_HVC1: atom = new AP4_HevcSampleEntry(type, size_32, stream, *this); break; case AP4_ATOM_TYPE_ALAC: case AP4_ATOM_TYPE_AC_3: case AP4_ATOM_TYPE_EC_3: case AP4_ATOM_TYPE_DTSC: case AP4_ATOM_TYPE_DTSH: case AP4_ATOM_TYPE_DTSL: case AP4_ATOM_TYPE_DTSE: atom = new AP4_AudioSampleEntry(type, size_32, stream, *this); break; case AP4_ATOM_TYPE_RTP_: atom = new AP4_RtpHintSampleEntry(size_32, stream, *this); break; case AP4_ATOM_TYPE_STPP: atom = new AP4_SubtitleSampleEntry(type, size_32, stream, *this); break; default: { // try all the external type handlers AP4_List<TypeHandler>::Item* handler_item = m_TypeHandlers.FirstItem(); while (handler_item) { TypeHandler* handler = handler_item->GetData(); if (AP4_SUCCEEDED(handler->CreateAtom(type, size_32, stream, GetContext(), atom))) { break; } handler_item = handler_item->GetNext(); } // no custom handler, create a generic entry if (atom == NULL) { atom = new AP4_UnknownSampleEntry(type, (AP4_UI32)size_64, stream); } break; } } } else { // regular atom switch (type) { case AP4_ATOM_TYPE_MOOV: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_MoovAtom::Create(size_32, stream, *this); break; case AP4_ATOM_TYPE_MVHD: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_MvhdAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_MEHD: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_MehdAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_MFHD: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_MfhdAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_TRAK: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_TrakAtom::Create(size_32, stream, *this); break; case AP4_ATOM_TYPE_TREX: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_TrexAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_HDLR: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_HdlrAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_TKHD: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_TkhdAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_TFHD: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_TfhdAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_TRUN: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_TrunAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_TFRA: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_TfraAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_MFRO: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_MfroAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_MDHD: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_MdhdAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_STSD: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_StsdAtom::Create(size_32, stream, *this); break; case AP4_ATOM_TYPE_STSC: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_StscAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_STCO: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_StcoAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_CO64: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_Co64Atom::Create(size_32, stream); break; case AP4_ATOM_TYPE_STSZ: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_StszAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_STZ2: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_Stz2Atom::Create(size_32, stream); break; case AP4_ATOM_TYPE_STTS: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_SttsAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_CTTS: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_CttsAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_STSS: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_StssAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_IODS: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_IodsAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_ESDS: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_EsdsAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_AVCC: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_AvccAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_HVCC: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_HvccAtom::Create(size_32, stream); break; #if !defined(AP4_CONFIG_MINI_BUILD) case AP4_ATOM_TYPE_UUID: { AP4_UI08 uuid[16]; AP4_Result result = stream.Read(uuid, 16); if (AP4_FAILED(result)) return result; if (AP4_CompareMemory(uuid, AP4_UUID_PIFF_TRACK_ENCRYPTION_ATOM, 16) == 0) { atom = AP4_PiffTrackEncryptionAtom::Create((AP4_UI32)size_64, stream); } else if (AP4_CompareMemory(uuid, AP4_UUID_PIFF_SAMPLE_ENCRYPTION_ATOM, 16) == 0) { atom = AP4_PiffSampleEncryptionAtom::Create((AP4_UI32)size_64, stream); } else { atom = new AP4_UnknownUuidAtom(size_64, uuid, stream); } break; } case AP4_ATOM_TYPE_8ID_: atom = new AP4_NullTerminatedStringAtom(type, size_64, stream); break; case AP4_ATOM_TYPE_8BDL: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_8bdlAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_DREF: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_DrefAtom::Create(size_32, stream, *this); break; case AP4_ATOM_TYPE_URL: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_UrlAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_ELST: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_ElstAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_VMHD: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_VmhdAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_SMHD: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_SmhdAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_NMHD: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_NmhdAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_STHD: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_SthdAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_HMHD: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_HmhdAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_FRMA: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_FrmaAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_SCHM: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_SchmAtom::Create(size_32, &m_ContextStack, stream); break; case AP4_ATOM_TYPE_FTYP: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_FtypAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_TIMS: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_TimsAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_SDP_: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_SdpAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_IKMS: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_IkmsAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_ISFM: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_IsfmAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_ISLT: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_IsltAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_ODHE: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_OdheAtom::Create(size_32, stream, *this); break; case AP4_ATOM_TYPE_OHDR: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_OhdrAtom::Create(size_32, stream, *this); break; case AP4_ATOM_TYPE_ODDA: atom = AP4_OddaAtom::Create(size_64, stream); break; case AP4_ATOM_TYPE_ODAF: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_OdafAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_GRPI: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_GrpiAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_IPRO: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_IproAtom::Create(size_32, stream, *this); break; case AP4_ATOM_TYPE_RTP_: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_RtpAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_TFDT: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_TfdtAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_TENC: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_TencAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_SENC: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_SencAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_SAIZ: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_SaizAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_SAIO: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_SaioAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_PDIN: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_PdinAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_BLOC: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_BlocAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_AINF: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_AinfAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_PSSH: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_PsshAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_SIDX: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_SidxAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_SBGP: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_SbgpAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_SGPD: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_SgpdAtom::Create(size_32, stream); break; case AP4_ATOM_TYPE_MKID: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; if (GetContext() == AP4_ATOM_TYPE_MARL) { atom = AP4_MkidAtom::Create(size_32, stream); } break; case AP4_ATOM_TYPE_DEC3: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; if (GetContext() == AP4_ATOM_TYPE_EC_3) { atom = AP4_Dec3Atom::Create(size_32, stream); } break; case AP4_ATOM_TYPE_XML: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_XmlAtom::Create(size_32, stream); break; // track ref types case AP4_ATOM_TYPE_HINT: case AP4_ATOM_TYPE_CDSC: case AP4_ATOM_TYPE_SYNC: case AP4_ATOM_TYPE_MPOD: case AP4_ATOM_TYPE_DPND: case AP4_ATOM_TYPE_IPIR: case AP4_ATOM_TYPE_ALIS: case AP4_ATOM_TYPE_CHAP: if (GetContext() == AP4_ATOM_TYPE_TREF) { if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_TrefTypeAtom::Create(type, size_32, stream); } break; #endif // AP4_CONFIG_MINI_BUILD // container atoms case AP4_ATOM_TYPE_MOOF: case AP4_ATOM_TYPE_MVEX: case AP4_ATOM_TYPE_TRAF: case AP4_ATOM_TYPE_TREF: case AP4_ATOM_TYPE_MFRA: case AP4_ATOM_TYPE_HNTI: case AP4_ATOM_TYPE_STBL: case AP4_ATOM_TYPE_MDIA: case AP4_ATOM_TYPE_DINF: case AP4_ATOM_TYPE_MINF: case AP4_ATOM_TYPE_SCHI: case AP4_ATOM_TYPE_SINF: case AP4_ATOM_TYPE_UDTA: case AP4_ATOM_TYPE_ILST: case AP4_ATOM_TYPE_EDTS: case AP4_ATOM_TYPE_MDRI: case AP4_ATOM_TYPE_WAVE: if (atom_is_large) return AP4_ERROR_INVALID_FORMAT; atom = AP4_ContainerAtom::Create(type, size_64, false, force_64, stream, *this); break; // containers, only at the top case AP4_ATOM_TYPE_MARL: if (GetContext() == 0) { atom = AP4_ContainerAtom::Create(type, size_64, false, force_64, stream, *this); } break; // full container atoms case AP4_ATOM_TYPE_META: case AP4_ATOM_TYPE_ODRM: case AP4_ATOM_TYPE_ODKM: atom = AP4_ContainerAtom::Create(type, size_64, true, force_64, stream, *this); break; case AP4_ATOM_TYPE_FREE: case AP4_ATOM_TYPE_WIDE: case AP4_ATOM_TYPE_MDAT: // generic atoms break; default: { // try all the external type handlers AP4_List<TypeHandler>::Item* handler_item = m_TypeHandlers.FirstItem(); while (handler_item) { TypeHandler* handler = handler_item->GetData(); if (AP4_SUCCEEDED(handler->CreateAtom(type, size_32, stream, GetContext(), atom))) { break; } handler_item = handler_item->GetNext(); } break; } } } return AP4_SUCCESS; }