/*---------------------------------------------------------------------- | AP4_OmaDcfAtomDecrypter::DecryptAtoms +---------------------------------------------------------------------*/ AP4_Result AP4_OmaDcfAtomDecrypter::DecryptAtoms(AP4_AtomParent& atoms, AP4_Processor::ProgressListener* /*listener*/, AP4_BlockCipherFactory* block_cipher_factory, AP4_ProtectionKeyMap& key_map) { // default factory if (block_cipher_factory == NULL) { block_cipher_factory = &AP4_DefaultBlockCipherFactory::Instance; } unsigned int index = 1; for (AP4_List<AP4_Atom>::Item* item = atoms.GetChildren().FirstItem(); item; item = item->GetNext()) { AP4_Atom* atom = item->GetData(); if (atom->GetType() != AP4_ATOM_TYPE_ODRM) continue; // check that we have the key const AP4_DataBuffer* key = key_map.GetKey(index++); if (key == NULL) return AP4_ERROR_INVALID_PARAMETERS; // check that we have all the atoms we need AP4_ContainerAtom* odrm = AP4_DYNAMIC_CAST(AP4_ContainerAtom, atom); if (odrm == NULL) continue; // not enough info AP4_OdheAtom* odhe = AP4_DYNAMIC_CAST(AP4_OdheAtom, odrm->GetChild(AP4_ATOM_TYPE_ODHE)); if (odhe == NULL) continue; // not enough info AP4_OddaAtom* odda = AP4_DYNAMIC_CAST(AP4_OddaAtom, odrm->GetChild(AP4_ATOM_TYPE_ODDA));; if (odda == NULL) continue; // not enough info AP4_OhdrAtom* ohdr = AP4_DYNAMIC_CAST(AP4_OhdrAtom, odhe->GetChild(AP4_ATOM_TYPE_OHDR)); if (ohdr == NULL) continue; // not enough info // do nothing if the atom is not encrypted if (ohdr->GetEncryptionMethod() == AP4_OMA_DCF_ENCRYPTION_METHOD_NULL) { continue; } // create the byte stream AP4_ByteStream* cipher_stream = NULL; AP4_Result result = CreateDecryptingStream(*odrm, key->GetData(), key->GetDataSize(), block_cipher_factory, cipher_stream); if (AP4_SUCCEEDED(result)) { // replace the odda atom's payload with the decrypted stream odda->SetEncryptedPayload(*cipher_stream, ohdr->GetPlaintextLength()); cipher_stream->Release(); // the atom will now be in the clear ohdr->SetEncryptionMethod(AP4_OMA_DCF_ENCRYPTION_METHOD_NULL); ohdr->SetPaddingScheme(AP4_OMA_DCF_PADDING_SCHEME_NONE); } } return AP4_SUCCESS; }
/*---------------------------------------------------------------------- | DumpTrackData +---------------------------------------------------------------------*/ void DumpTrackData(const char* mp4_filename, AP4_File& mp4_file, const AP4_Array<AP4_Ordinal>& tracks_to_dump, const AP4_ProtectionKeyMap& key_map) { // dump all the tracks that need to be dumped AP4_Cardinal tracks_to_dump_count = tracks_to_dump.ItemCount(); for (AP4_Ordinal i=0; i<tracks_to_dump_count; i++) { // get the track AP4_Ordinal track_id = tracks_to_dump[i]; AP4_Track* track = mp4_file.GetMovie()->GetTrack(track_id); if (track == NULL) { fprintf(stderr, "track not found (id = %d)", track_id); return; } // get the sample description AP4_SampleDescription* sample_description = track->GetSampleDescription(0); if (sample_description == NULL) { fprintf(stderr, "WARNING: unable to parse sample description\n"); } // get the dump data byte stream AP4_ByteStream* dump = CreateTrackDumpByteStream(mp4_filename, track_id); if (dump == NULL) return; printf("\nDumping data for track %d:\n", track_id); switch(sample_description ? sample_description->GetType() : AP4_SampleDescription::TYPE_UNKNOWN) { case AP4_SampleDescription::TYPE_PROTECTED: { const AP4_DataBuffer* key = key_map.GetKey(track_id); if (key == NULL) { fprintf(stderr, "WARNING: No key found for encrypted track %d... " "dumping encrypted samples\n", track_id); DumpSamples(track, dump); } else { DecryptAndDumpSamples(track, sample_description, key->GetData(), key->GetDataSize(), dump); } } break; default: DumpSamples(track, dump); } dump->Release(); } }
/*---------------------------------------------------------------------- | CheckWarning +---------------------------------------------------------------------*/ static bool CheckWarning(AP4_ByteStream& stream, AP4_ProtectionKeyMap& key_map, Method method) { AP4_File file(stream, AP4_DefaultAtomFactory::Instance, true); AP4_Movie* movie = file.GetMovie(); if (!movie) { if (method != METHOD_MPEG_CENC && method != METHOD_PIFF_CBC && method != METHOD_PIFF_CTR) { fprintf(stderr, "WARNING: no movie atom found in input file\n"); return false; } } bool warning = false; switch (method) { case METHOD_MPEG_CENC: case METHOD_PIFF_CBC: case METHOD_PIFF_CTR: if (movie && !movie->HasFragments()) { fprintf(stderr, "WARNING: MPEG-CENC method only applies to fragmented files\n"); warning = true; } break; default: break; } if (movie) { for (unsigned int i=0; i<movie->GetTracks().ItemCount(); i++) { AP4_Track* track; AP4_Result result = movie->GetTracks().Get(i, track); if (AP4_FAILED(result)) return false; const AP4_DataBuffer* key = key_map.GetKey(track->GetId()); if (key == NULL) { fprintf(stderr, "WARNING: track ID %d will not be encrypted\n", track->GetId()); warning = true; } } } stream.Seek(0); return warning; }