public Mpeg4AppleTag(Mpeg4AppleItemListBox box, Mpeg4File file) : base() { // Hold onto the ilst_box and file. If the box doesn'type exist, create // one. listBox = (box == null) ? new Mpeg4AppleItemListBox() : box; this.file = file; }
// Save the file. public void Save() { if (listBox == null) { throw new TagLibException(TagLibError.Mpeg4TagSaveFailed); } //InvalidOperationException("Could not save AppleTag: listBox is not defined"); // Try to get into write mode. try { file.Mode = FileAccessMode.Write; } catch (TagLibException) { return; } // Make a file box. Mpeg4FileBox fileBox = new Mpeg4FileBox(file); // Get the MovieBox. Mpeg4IsoMovieBox moovBox = (Mpeg4IsoMovieBox)fileBox.FindChildDeep("moov"); // If we have a movie box... if (moovBox != null) { // Set up how much, where, and what to replace, and who to tell // about it. ulong originalSize = 0; long position = -1; ByteVector data = null; Mpeg4Box parent = null; // Get the old ItemList (the one we're replacing. Mpeg4AppleItemListBox old_ilst_box = (Mpeg4AppleItemListBox)moovBox.FindChildDeep("ilst"); // If it exists. if (old_ilst_box != null) { // We stick ourself in the meta box and slate to overwrite it. parent = old_ilst_box.Parent; originalSize = parent.BoxSize; position = parent.NextBoxPosition - (long)originalSize; parent.ReplaceChild(old_ilst_box, listBox); data = parent.Render(); parent = parent.Parent; } else { // There is not old ItemList. See if we can get a MetaBox. Mpeg4IsoMetaBox metaBox = (Mpeg4IsoMetaBox)moovBox.FindChildDeep("meta"); //If we can... if (metaBox != null) { // Stick the child in here and slate to overwrite... metaBox.AddChild(listBox); originalSize = metaBox.BoxSize; position = metaBox.NextBoxPosition - (long)originalSize; data = metaBox.Render(); parent = metaBox.Parent; } else { // There'field no MetaBox. Create one and add the ItemList. metaBox = new Mpeg4IsoMetaBox("hdlr", null); metaBox.AddChild(listBox); // See if we can get a UserDataBox. Mpeg4IsoUserDataBox udtaBox = (Mpeg4IsoUserDataBox)moovBox.FindChildDeep("udta"); // If we can... if (udtaBox != null) { // We'll stick the MetaBox at the end and overwrite it. originalSize = 0; position = udtaBox.NextBoxPosition; data = metaBox.Render(); parent = udtaBox; } else { // If not even the UserDataBox exists, create it and add // our MetaBox. udtaBox = new Mpeg4IsoUserDataBox(); udtaBox.AddChild(metaBox); // Since UserDataBox is a child of MovieBox, we'll just // insert it at the end. originalSize = 0; position = moovBox.NextBoxPosition; data = udtaBox.Render(); parent = moovBox; } } } // If we have data and somewhere to put it.. if (data != null && position >= 0) { // Figure out the size difference. long sizeDifference = (long)data.Count - (long)originalSize; // Insert the new data. file.Insert(data, position, (long)(originalSize)); // If there is a size difference, resize all parent headers. if (sizeDifference != 0) { while (parent != null) { parent.OverwriteHeader(sizeDifference); parent = parent.Parent; } // ALSO, VERY IMPORTANTLY, YOU MUST UPDATE EVERY 'stco'. foreach (Mpeg4Box box in moovBox.Children) { if (box.BoxType == "trak") { Mpeg4IsoChunkLargeOffsetBox co64Box = (Mpeg4IsoChunkLargeOffsetBox)box.FindChildDeep("co64"); if (co64Box != null) { co64Box.UpdateOffset(sizeDifference); } Mpeg4IsoChunkOffsetBox stcoBox = (Mpeg4IsoChunkOffsetBox)box.FindChildDeep("stco"); if (stcoBox != null) { stcoBox.UpdateOffset((int)sizeDifference); } } } } // Be nice and close the stream. file.Mode = FileAccessMode.Closed; return; } } else { throw new TagLibException(TagLibError.Mpeg4StreamDoesNotHaveMoovTag); } //new ApplicationException("stream does not have MOOV tag"); // We're at the end. Close the stream and admit defeat. file.Mode = FileAccessMode.Closed; throw new TagLibException(TagLibError.Mpeg4CouldNotSaveAppleTag); //ApplicationException("Could not complete AppleTag save"); }
// Read the file. private void Read(ReadStyle propertiesStyle) { // Create a dummie outer box, as perscribed by the specs. Mpeg4FileBox file_box = new Mpeg4FileBox(this); // Find the movie box and item text. If the movie box doen'type exist, an // exception will be thrown on the next call, but if there is no movie // box, the file can'type possibly be valid. Mpeg4IsoMovieBox moov_box = (Mpeg4IsoMovieBox)file_box.FindChildDeep("moov"); Mpeg4AppleItemListBox ilst_box = (Mpeg4AppleItemListBox)moov_box.FindChildDeep("ilst"); // If we have a ItemListBox, deparent it. if (ilst_box != null) { ilst_box.RemoveFromParent(); } // Create the tag. tag = new Mpeg4AppleTag(ilst_box, this); // If we're not reading properties, we're done. if (propertiesStyle == ReadStyle.None) { return; } // Get the movie header box. Mpeg4IsoMovieHeaderBox mvhd_box = (Mpeg4IsoMovieHeaderBox)moov_box.FindChildDeep("mvhd"); Mpeg4IsoAudioSampleEntry sample_entry = null; // Find a TrackBox with a sound Handler. foreach (Mpeg4Box box in moov_box.Children) { if (box.BoxType == "trak") { // If the handler isn'type sound, it could be metadata or video or // any number of other things. Mpeg4IsoHandlerBox hdlr_box = (Mpeg4IsoHandlerBox)box.FindChildDeep("hdlr"); if (hdlr_box == null || hdlr_box.HandlerType != "soun") { continue; } // This track SHOULD contain at least one sample entry. sample_entry = (Mpeg4IsoAudioSampleEntry)box.FindChildDeep(typeof(Mpeg4IsoAudioSampleEntry)); break; } } // If we have a MovieHeaderBox, deparent it. if (mvhd_box != null) { mvhd_box.RemoveFromParent(); } // If we have a SampleEntry, deparent it. if (sample_entry != null) { sample_entry.RemoveFromParent(); } // Read the properties. properties = new Mpeg4Properties(mvhd_box, sample_entry, propertiesStyle); }