Initial commit

This commit is contained in:
Thastertyn committed 2024-06-07 00:47:07 +02:00
commit 262601edb8
2025 files changed
+218754

No files matched your search

File diff suppressed because it is too large. Load diff
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7a8e6a8de22731125a98a64d230c668f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+606
View File
@@ -0,0 +1,606 @@
//
// Box.cs: Provides a generic implementation of a ISO/IEC 14496-12 box.
//
// Author:
// Brian Nickel (brian.nickel@gmail.com)
//
// Copyright (C) 2006-2007 Brian Nickel
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License version
// 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
//
using System;
using System.Collections.Generic;
namespace TagLib.Mpeg4
{
/// <summary>
/// This abstract class provides a generic implementation of a
/// ISO/IEC 14496-12 box.
/// </summary>
public class Box
{
#region Private Fields
/// <summary>
/// Contains the box header.
/// </summary>
BoxHeader header;
/// <summary>
/// Contains the position of the box data.
/// </summary>
readonly long data_position;
#endregion
#region Constructors
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="Box" /> with a specified header and handler.
/// </summary>
/// <param name="header">
/// A <see cref="BoxHeader" /> object describing the new
/// instance.
/// </param>
/// <param name="handler">
/// A <see cref="IsoHandlerBox" /> object containing the
/// handler that applies to the new instance, or <see
/// langword="null" /> if no handler applies.
/// </param>
protected Box (BoxHeader header, IsoHandlerBox handler)
{
this.header = header;
data_position = header.Position + header.HeaderSize;
Handler = handler;
}
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="Box" /> with a specified header.
/// </summary>
/// <param name="header">
/// A <see cref="BoxHeader" /> object describing the new
/// instance.
/// </param>
protected Box (BoxHeader header)
: this (header, null)
{
}
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="Box" /> with a specified box type.
/// </summary>
/// <param name="type">
/// A <see cref="ByteVector" /> object containing the box
/// type to use for the new instance.
/// </param>
protected Box (ByteVector type)
: this (new BoxHeader (type))
{
}
#endregion
#region Public Properties
/// <summary>
/// Gets the MPEG-4 box type of the current instance.
/// </summary>
/// <value>
/// A <see cref="ByteVector" /> object containing the four
/// byte box type of the current instance.
/// </value>
public virtual ByteVector BoxType {
get { return header.BoxType; }
}
/// <summary>
/// Gets the total size of the current instance as it last
/// appeared on disk.
/// </summary>
/// <value>
/// A <see cref="int" /> value containing the total size of
/// the current instance as it last appeared on disk.
/// </value>
public virtual int Size {
get { return (int)header.TotalBoxSize; }
}
/// <summary>
/// Gets and sets the data contained in the current instance.
/// </summary>
/// <value>
/// A <see cref="ByteVector" /> object containing the data
/// contained in the current instance.
/// </value>
public virtual ByteVector Data {
get { return null; }
set { }
}
/// <summary>
/// Gets the children of the current instance.
/// </summary>
/// <value>
/// A <see cref="T:System.Collections.Generic.IEnumerable`1" /> object enumerating the
/// children of the current instance.
/// </value>
public virtual IEnumerable<Box> Children {
get { return null; }
}
/// <summary>
/// Gets the handler box that applies to the current
/// instance.
/// </summary>
/// <value>
/// A <see cref="IsoHandlerBox" /> object containing the
/// handler that applies to the current instance, or <see
/// langword="null" /> if no handler applies.
/// </value>
public IsoHandlerBox Handler { get; private set; }
#endregion
#region Public Methods
/// <summary>
/// Renders the current instance, including its children, to
/// a new <see cref="ByteVector" /> object.
/// </summary>
/// <returns>
/// A <see cref="ByteVector" /> object containing the
/// rendered version of the current instance.
/// </returns>
public ByteVector Render ()
{
return Render (new ByteVector ());
}
/// <summary>
/// Gets a child box from the current instance by finding
/// a matching box type.
/// </summary>
/// <param name="type">
/// A <see cref="ByteVector" /> object containing the box
/// type to match.
/// </param>
/// <returns>
/// A <see cref="Box" /> object containing the matched box,
/// or <see langword="null" /> if no matching box was found.
/// </returns>
public Box GetChild (ByteVector type)
{
if (Children == null)
return null;
foreach (Box box in Children)
if (box.BoxType == type)
return box;
return null;
}
/// <summary>
/// Gets all child boxes from the current instance by finding
/// a matching box type.
/// </summary>
/// <param name="type">
/// A <see cref="ByteVector" /> object containing the box
/// type to match.
/// </param>
/// <returns>
/// A List of <see cref="Box" /> objects containing the matched box,
/// or <see langword="null" /> if no matching boxes was found.
/// </returns>
public List<Box> GetChildren (ByteVector type)
{
if (Children == null)
return null;
List<Box> boxes = new List<Box> ();
foreach (Box box in Children)
if (box.BoxType == type)
boxes.Add (box);
if (boxes.Count > 0)
return boxes;
return null;
}
/*
/// <summary>
/// Gets a child box from the current instance by finding
/// a matching object type.
/// </summary>
/// <param name="type">
/// A <see cref="System.Type" /> object containing the object
/// type to match.
/// </param>
/// <returns>
/// A <see cref="Box" /> object containing the matched box,
/// or <see langword="null" /> if no matching box was found.
/// </returns>
public Box GetChild (System.Type type)
{
if (Children == null)
return null;
foreach (Box box in Children)
if (box.GetType () == type)
return box;
return null;
}
*/
/// <summary>
/// Gets a child box from the current instance by finding
/// a matching box type, searching recursively.
/// </summary>
/// <param name="type">
/// A <see cref="ByteVector" /> object containing the box
/// type to match.
/// </param>
/// <returns>
/// A <see cref="Box" /> object containing the matched box,
/// or <see langword="null" /> if no matching box was found.
/// </returns>
public Box GetChildRecursively (ByteVector type)
{
if (Children == null)
return null;
foreach (Box box in Children)
if (box.BoxType == type)
return box;
foreach (Box box in Children) {
Box child_box = box.GetChildRecursively (type);
if (child_box != null)
return child_box;
}
return null;
}
/*
/// <summary>
/// Gets a child box from the current instance by finding
/// a matching object type, searching recursively.
/// </summary>
/// <param name="type">
/// A <see cref="System.Type" /> object containing the object
/// type to match.
/// </param>
/// <returns>
/// A <see cref="Box" /> object containing the matched box,
/// or <see langword="null" /> if no matching box was found.
/// </returns>
public Box GetChildRecursively (System.Type type)
{
if (Children == null)
return null;
foreach (Box box in Children)
if (box.GetType () == type)
return box;
foreach (Box box in Children) {
Box child_box = box.GetChildRecursively (type);
if (child_box != null)
return child_box;
}
return null;
}
*/
/// <summary>
/// Removes all children with a specified box type from the
/// current instance.
/// </summary>
/// <param name="type">
/// A <see cref="ByteVector" /> object containing the box
/// type to remove.
/// </param>
public void RemoveChild (ByteVector type)
{
if (!(Children is ICollection<Box> children))
return;
foreach (Box b in new List<Box> (children))
if (b.BoxType == type)
children.Remove (b);
}
/*
/// <summary>
/// Removes all children with a specified box type from the
/// current instance.
/// </summary>
/// <param name="type">
/// A <see cref="ByteVector" /> object containing the box
/// type to remove.
/// </param>
public void RemoveChild (System.Type type)
{
ICollection<Box> children = Children as ICollection<Box>;
if (children == null)
return;
foreach (Box b in new List<Box> (children))
if (b.GetType () == type)
children.Remove (b);
}
*/
/// <summary>
/// Removes a specified box from the current instance.
/// </summary>
/// <param name="box">
/// A <see cref="Box" /> object to remove from the current
/// instance.
/// </param>
public void RemoveChild (Box box)
{
if (Children is ICollection<Box> children)
children.Remove (box);
}
/// <summary>
/// Adds a specified box to the current instance.
/// </summary>
/// <param name="box">
/// A <see cref="Box" /> object to add to the current
/// instance.
/// </param>
public void AddChild (Box box)
{
if (Children is ICollection<Box> children)
children.Add (box);
}
/// <summary>
/// Removes all children from the current instance.
/// </summary>
public void ClearChildren ()
{
if (Children is ICollection<Box> children)
children.Clear ();
}
/// <summary>
/// Gets whether or not the current instance has children.
/// </summary>
/// <value>
/// A <see cref="bool" /> value indicating whether or not the
/// current instance has any children.
/// </value>
public bool HasChildren {
get {
return Children is ICollection<Box> children && children.Count > 0;
}
}
#endregion
#region Protected Properties
/// <summary>
/// Gets the size of the data contained in the current
/// instance, minux the size of any box specific headers.
/// </summary>
/// <value>
/// A <see cref="long" /> value containing the size of
/// the data contained in the current instance.
/// </value>
protected int DataSize {
get {
return (int)(header.DataSize + data_position -
DataPosition);
}
}
/// <summary>
/// Gets the position of the data contained in the current
/// instance, after any box specific headers.
/// </summary>
/// <value>
/// A <see cref="long" /> value containing the position of
/// the data contained in the current instance.
/// </value>
protected virtual long DataPosition {
get { return data_position; }
}
/// <summary>
/// Gets the header of the current instance.
/// </summary>
/// <value>
/// A <see cref="BoxHeader" /> object containing the header
/// of the current instance.
/// </value>
protected BoxHeader Header {
get { return header; }
}
#endregion
#region Protected Methods
/// <summary>
/// Loads the children of the current instance from a
/// specified file using the internal data position and size.
/// </summary>
/// <param name="file">
/// The <see cref="TagLib.File" /> from which the current
/// instance was read and from which to read the children.
/// </param>
/// <returns>
/// A <see cref="T:System.Collections.Generic.IEnumerable`1" /> object enumerating the
/// boxes read from the file.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="file" /> is <see langword="null" />.
/// </exception>
protected IEnumerable<Box> LoadChildren (TagLib.File file)
{
if (file == null)
throw new ArgumentNullException (nameof (file));
var children = new List<Box> ();
long position = DataPosition;
long end = position + DataSize;
header.Box = this;
while (position < end) {
Box child = BoxFactory.CreateBox (file, position, header, Handler, children.Count);
if (child.Size == 0)
break;
children.Add (child);
position += child.Size;
}
header.Box = null;
return children;
}
/// <summary>
/// Loads the data of the current instance from a specified
/// file using the internal data position and size.
/// </summary>
/// <param name="file">
/// The <see cref="TagLib.File" /> from which the current
/// instance was read and from which to read the data.
/// </param>
/// <returns>
/// A <see cref="ByteVector" /> object containing the data
/// read from the file.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="file" /> is <see langword="null" />.
/// </exception>
protected ByteVector LoadData (TagLib.File file)
{
if (file == null)
throw new ArgumentNullException (nameof (file));
file.Seek (DataPosition);
return file.ReadBlock (DataSize);
}
/// <summary>
/// Renders the current instance, including its children, to
/// a new <see cref="ByteVector" /> object, preceeding the
/// contents with a specified block of data.
/// </summary>
/// <param name="topData">
/// A <see cref="ByteVector" /> object containing box
/// specific header data to preceed the content.
/// </param>
/// <returns>
/// A <see cref="ByteVector" /> object containing the
/// rendered version of the current instance.
/// </returns>
protected virtual ByteVector Render (ByteVector topData)
{
bool free_found = false;
var output = new ByteVector ();
if (Children != null)
foreach (Box box in Children)
if (box.GetType () == typeof (
IsoFreeSpaceBox))
free_found = true;
else
output.Add (box.Render ());
else if (Data != null)
output.Add (Data);
// If there was a free, don't take it away, and let meta
// be a special case.
if (free_found || BoxType == Mpeg4.BoxType.Meta) {
long size_difference = DataSize - output.Count;
// If we have room for free space, add it so we
// don't have to resize the file.
if (header.DataSize != 0 && size_difference >= 8)
output.Add ((new IsoFreeSpaceBox (size_difference)).Render ());
// If we're getting bigger, get a lot bigger so
// we might not have to again.
else
output.Add ((new IsoFreeSpaceBox (2048)).Render ());
}
// Adjust the header's data size to match the content.
header.DataSize = topData.Count + output.Count;
// Render the full box.
output.Insert (0, topData);
output.Insert (0, header.Render ());
return output;
}
#endregion
/*
#region Internal Methods
/// <summary>
/// Dumps the child tree of the current instance to the
/// console.
/// </summary>
/// <param name="start">
/// A <see cref="string" /> object to preface each line with.
/// </param>
internal void DumpTree (string start)
{
if (BoxType == BoxType.Data)
Console.WriteLine ("{0}{1} {2}", start,
BoxType.ToString (),
(this as AppleDataBox).Text);
else
Console.WriteLine ("{0}{1}", start,
BoxType.ToString ());
if (Children != null)
foreach (Box child in Children)
child.DumpTree (start + " ");
}
#endregion
*/
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 94cea67188e625da6aff7fd2abdce53e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+251
View File
@@ -0,0 +1,251 @@
//
// BoxFactory.cs: Provides support for reading boxes from a file.
//
// Author:
// Brian Nickel (brian.nickel@gmail.com)
//
// Copyright (C) 2006-2007 Brian Nickel
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License version
// 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
//
namespace TagLib.Mpeg4
{
/// <summary>
/// This static class provides support for reading boxes from a file.
/// </summary>
public static class BoxFactory
{
/// <summary>
/// Creates a box by reading it from a file given its header,
/// parent header, handler, and index in its parent.
/// </summary>
/// <param name="file">
/// A <see cref="TagLib.File" /> object containing the file
/// to read from.
/// </param>
/// <param name="header">
/// A <see cref="BoxHeader" /> object containing the header
/// of the box to create.
/// </param>
/// <param name="parent">
/// A <see cref="BoxHeader" /> object containing the header
/// of the parent box.
/// </param>
/// <param name="handler">
/// A <see cref="IsoHandlerBox" /> object containing the
/// handler that applies to the new box.
/// </param>
/// <param name="index">
/// A <see cref="int" /> value containing the index of the
/// new box in its parent.
/// </param>
/// <returns>
/// A newly created <see cref="Box" /> object.
/// </returns>
static Box CreateBox (TagLib.File file,
BoxHeader header,
BoxHeader parent,
IsoHandlerBox handler,
int index)
{
// The first few children of an "stsd" are sample
// entries.
if (parent.BoxType == BoxType.Stsd &&
parent.Box is IsoSampleDescriptionBox &&
index < (parent.Box as IsoSampleDescriptionBox).EntryCount) {
if (handler != null && handler.HandlerType == BoxType.Soun)
return new IsoAudioSampleEntry (header, file, handler);
if (handler != null && handler.HandlerType == BoxType.Vide)
return new IsoVisualSampleEntry (header, file, handler);
if (handler != null && handler.HandlerType == BoxType.Alis) {
if (header.BoxType == BoxType.Text)
return new TextBox (header, file, handler);
if (header.BoxType == BoxType.Url)
return new UrlBox (header, file, handler);
// This could be anything, so just parse it
return new UnknownBox (header, file, handler);
}
return new IsoSampleEntry (header, file, handler);
}
// Standard items...
ByteVector type = header.BoxType;
if (type == BoxType.Mvhd)
return new IsoMovieHeaderBox (header, file, handler);
else if (type == BoxType.Stbl)
return new IsoSampleTableBox (header, file, handler);
else if (type == BoxType.Stsd)
return new IsoSampleDescriptionBox (header, file, handler);
else if (type == BoxType.Stco)
return new IsoChunkOffsetBox (header, file, handler);
else if (type == BoxType.Co64)
return new IsoChunkLargeOffsetBox (header, file, handler);
else if (type == BoxType.Hdlr)
return new IsoHandlerBox (header, file, handler);
else if (type == BoxType.Udta)
return new IsoUserDataBox (header, file, handler);
else if (type == BoxType.Meta)
return new IsoMetaBox (header, file, handler);
else if (type == BoxType.Ilst)
return new AppleItemListBox (header, file, handler);
else if (type == BoxType.Data)
return new AppleDataBox (header, file, handler);
else if (type == BoxType.Esds)
return new AppleElementaryStreamDescriptor (header, file, handler);
else if (type == BoxType.Free || type == BoxType.Skip)
return new IsoFreeSpaceBox (header, file, handler);
else if (type == BoxType.Mean || type == BoxType.Name)
return new AppleAdditionalInfoBox (header, file, handler);
// If we still don't have a tag, and we're inside an
// ItemListBox, load the box as an AnnotationBox
// (Apple tag item).
if (parent.BoxType == BoxType.Ilst)
return new AppleAnnotationBox (header, file, handler);
// Nothing good. Go generic.
return new UnknownBox (header, file, handler);
}
/// <summary>
/// Creates a box by reading it from a file given its
/// position in the file, parent header, handler, and index
/// in its parent.
/// </summary>
/// <param name="file">
/// A <see cref="TagLib.File" /> object containing the file
/// to read from.
/// </param>
/// <param name="position">
/// A <see cref="long" /> value specifying at what seek
/// position in <paramref name="file" /> to start reading.
/// </param>
/// <param name="parent">
/// A <see cref="BoxHeader" /> object containing the header
/// of the parent box.
/// </param>
/// <param name="handler">
/// A <see cref="IsoHandlerBox" /> object containing the
/// handler that applies to the new box.
/// </param>
/// <param name="index">
/// A <see cref="int" /> value containing the index of the
/// new box in its parent.
/// </param>
/// <returns>
/// A newly created <see cref="Box" /> object.
/// </returns>
internal static Box CreateBox (TagLib.File file, long position, BoxHeader parent, IsoHandlerBox handler, int index)
{
BoxHeader header = new BoxHeader (file, position);
return CreateBox (file, header, parent, handler, index);
}
/// <summary>
/// Creates a box by reading it from a file given its
/// position in the file and handler.
/// </summary>
/// <param name="file">
/// A <see cref="TagLib.File" /> object containing the file
/// to read from.
/// </param>
/// <param name="position">
/// A <see cref="long" /> value specifying at what seek
/// position in <paramref name="file" /> to start reading.
/// </param>
/// <param name="handler">
/// A <see cref="IsoHandlerBox" /> object containing the
/// handler that applies to the new box.
/// </param>
/// <returns>
/// A newly created <see cref="Box" /> object.
/// </returns>
public static Box CreateBox (TagLib.File file, long position, IsoHandlerBox handler)
{
return CreateBox (file, position, BoxHeader.Empty, handler, -1);
}
/// <summary>
/// Creates a box by reading it from a file given its
/// position in the file.
/// </summary>
/// <param name="file">
/// A <see cref="TagLib.File" /> object containing the file
/// to read from.
/// </param>
/// <param name="position">
/// A <see cref="long" /> value specifying at what seek
/// position in <paramref name="file" /> to start reading.
/// </param>
/// <returns>
/// A newly created <see cref="Box" /> object.
/// </returns>
public static Box CreateBox (TagLib.File file, long position)
{
return CreateBox (file, position, null);
}
/// <summary>
/// Creates a box by reading it from a file given its header
/// and handler.
/// </summary>
/// <param name="file">
/// A <see cref="TagLib.File" /> object containing the file
/// to read from.
/// </param>
/// <param name="header">
/// A <see cref="BoxHeader" /> object containing the header
/// of the box to create.
/// </param>
/// <param name="handler">
/// A <see cref="IsoHandlerBox" /> object containing the
/// handler that applies to the new box.
/// </param>
/// <returns>
/// A newly created <see cref="Box" /> object.
/// </returns>
public static Box CreateBox (TagLib.File file, BoxHeader header, IsoHandlerBox handler)
{
return CreateBox (file, header, BoxHeader.Empty,
handler, -1);
}
/// <summary>
/// Creates a box by reading it from a file given its header
/// and handler.
/// </summary>
/// <param name="file">
/// A <see cref="TagLib.File" /> object containing the file
/// to read from.
/// </param>
/// <param name="header">
/// A <see cref="BoxHeader" /> object containing the header
/// of the box to create.
/// </param>
/// <returns>
/// A newly created <see cref="Box" /> object.
/// </returns>
public static Box CreateBox (TagLib.File file, BoxHeader header)
{
return CreateBox (file, header, null);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7591bce13aac7742e9d3c970f3557929
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+402
View File
@@ -0,0 +1,402 @@
//
// BoxHeader.cs: Provides support for reading and writing headers for ISO/IEC
// 14496-12 boxes.
//
// Author:
// Brian Nickel (brian.nickel@gmail.com)
//
// Copyright (C) 2006-2007 Brian Nickel
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License version
// 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
//
using System;
namespace TagLib.Mpeg4
{
/// <summary>
/// This structure provides support for reading and writing headers
/// for ISO/IEC 14496-12 boxes.
/// </summary>
public struct BoxHeader
{
#region Private Fields
/// <summary>
/// Contains the box size.
/// </summary>
ulong box_size;
/// <summary>
/// Contains the header size.
/// </summary>
uint header_size;
/// <summary>
/// Contains the position of the header.
/// </summary>
readonly long position;
/// <summary>
/// Indicated that the header was read from a file.
/// </summary>
readonly bool from_disk;
#endregion
#region Public Fields
/// <summary>
/// An empty box header.
/// </summary>
public static readonly BoxHeader Empty = new BoxHeader ("xxxx");
#endregion
#region Constructors
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="BoxHeader" /> by reading it from a specified seek
/// position in a specified file.
/// </summary>
/// <param name="file">
/// A <see cref="TagLib.File" /> object to read the new
/// instance from.
/// </param>
/// <param name="position">
/// A <see cref="long" /> value specifiying the seek position
/// in <paramref name="file" /> at which to start reading.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="file" /> is <see langword="null" />.
/// </exception>
/// <exception cref="CorruptFileException">
/// There isn't enough data in the file to read the complete
/// header.
/// </exception>
public BoxHeader (TagLib.File file, long position)
{
if (file == null)
throw new ArgumentNullException (nameof (file));
Box = null;
from_disk = true;
this.position = position;
file.Seek (position);
ByteVector data = file.ReadBlock (32);
int offset = 0;
if (data.Count < 8 + offset)
throw new CorruptFileException ("Not enough data in box header.");
header_size = 8;
box_size = data.Mid (offset, 4).ToUInt ();
BoxType = data.Mid (offset + 4, 4);
// If the size is 1, that just tells us we have a
// massive ULONG size waiting for us in the next 8
// bytes.
if (box_size == 1) {
if (data.Count < 8 + offset)
throw new CorruptFileException ("Not enough data in box header.");
header_size += 8;
offset += 8;
box_size = data.Mid (offset, 8).ToULong ();
}
// UUID has a special header with 16 extra bytes.
if (BoxType == Mpeg4.BoxType.Uuid) {
if (data.Count < 16 + offset)
throw new CorruptFileException ("Not enough data in box header.");
header_size += 16;
ExtendedType = data.Mid (offset, 16);
} else
ExtendedType = null;
if (box_size > (ulong)(file.Length - position)) {
throw new CorruptFileException (
$"Box header specified a size of {box_size} bytes but only {file.Length - position} bytes left in the file");
}
}
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="BoxHeader" /> with a specified box type.
/// </summary>
/// <param name="type">
/// A <see cref="ByteVector" /> object containing the four
/// byte box type.
/// </param>
/// <remarks>
/// <see cref="BoxHeader(ByteVector,ByteVector)" /> must be
/// used to create a header of type "<c>uuid</c>".
/// </remarks>
/// <exception cref="ArgumentNullException">
/// <paramref name="type" /> is <see langword="null" /> or is
/// equal to "<c>uuid</c>".
/// </exception>
/// <exception cref="ArgumentException">
/// <paramref name="type" /> isn't exactly 4 bytes long.
/// </exception>
public BoxHeader (ByteVector type) : this (type, null)
{
}
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="BoxHeader" /> with a specified box type and
/// optionally extended type.
/// </summary>
/// <param name="type">
/// A <see cref="ByteVector" /> object containing the four
/// byte box type.
/// </param>
/// <param name="extendedType">
/// A <see cref="ByteVector" /> object containing the four
/// byte box type.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="type" /> is <see langword="null" /> - or -
/// <paramref name="type" /> is equal to "<c>uuid</c>" and
/// <paramref name="extendedType" /> is <see langword="null"
/// />.
/// </exception>
/// <exception cref="ArgumentException">
/// <paramref name="type" /> isn't exactly 4 bytes long - or
/// - <paramref name="type" /> isn't "<c>uuid</c>" but
/// <paramref name="extendedType" /> isn't <see
/// langword="null" /> - or - paramref name="type" /> is
/// "<c>uuid</c>" but <paramref name="extendedType" /> isn't
/// exactly 16 bytes long.
/// </exception>
public BoxHeader (ByteVector type, ByteVector extendedType)
{
position = -1;
Box = null;
from_disk = false;
BoxType = type;
if (type == null)
throw new ArgumentNullException (nameof (type));
if (type.Count != 4)
throw new ArgumentException ("Box type must be 4 bytes in length.", nameof (type));
box_size = header_size = 8;
if (type != "uuid") {
if (extendedType != null)
throw new ArgumentException ("Extended type only permitted for 'uuid'.", nameof (extendedType));
ExtendedType = extendedType;
return;
}
if (extendedType == null)
throw new ArgumentNullException (nameof (extendedType));
if (extendedType.Count != 16)
throw new ArgumentException (
"Extended type must be 16 bytes in length.",
nameof (extendedType));
box_size = header_size = 24;
ExtendedType = extendedType;
}
#endregion
#region Public Properties
/// <summary>
/// Gets the type of box represented by the current instance.
/// </summary>
/// <value>
/// A <see cref="ByteVector" /> object containing the 4 byte
/// box type.
/// </value>
public ByteVector BoxType { get; private set; }
/// <summary>
/// Gets the extended type of the box represented by the
/// current instance.
/// </summary>
/// <value>
/// A <see cref="ByteVector" /> object containing the 16 byte
/// extended type, or <see langword="null" /> if <see
/// cref="BoxType" /> is not "<c>uuid</c>".
/// </value>
public ByteVector ExtendedType { get; private set; }
/// <summary>
/// Gets the size of the header represented by the current
/// instance.
/// </summary>
/// <value>
/// A <see cref="long" /> value containing the size of the
/// header represented by the current instance.
/// </value>
public long HeaderSize {
get { return header_size; }
}
/// <summary>
/// Gets and sets the size of the data in the box described
/// by the current instance.
/// </summary>
/// <value>
/// A <see cref="long" /> value containing the size of the
/// data in the box described by the current instance.
/// </value>
public long DataSize {
get { return (long)(box_size - header_size); }
set { box_size = (ulong)value + header_size; }
}
/// <summary>
/// Gets the offset of the box data from the position of the
/// header.
/// </summary>
/// <value>
/// A <see cref="long" /> value containing the offset of the
/// box data from the position of the header.
/// </value>
[Obsolete ("Use HeaderSize")]
public long DataOffset {
get { return header_size; }
}
/// <summary>
/// Gets the total size of the box described by the current
/// instance.
/// </summary>
/// <value>
/// A <see cref="long" /> value containing the total size of
/// the box described by the current instance.
/// </value>
public long TotalBoxSize {
get { return (long)box_size; }
}
/// <summary>
/// Gets the position box represented by the current instance
/// in the file it comes from.
/// </summary>
/// <value>
/// A <see cref="long" /> value containing the position box
/// represented by the current instance in the file it comes
/// from.
/// </value>
public long Position {
get { return from_disk ? position : -1; }
}
#endregion
#region Public Methods
/// <summary>
/// Overwrites the header on disk, updating it to include a
/// change in the size of the box.
/// </summary>
/// <param name="file">
/// A <see cref="TagLib.File" /> object containing the file
/// from which the box originates.
/// </param>
/// <param name="sizeChange">
/// A <see cref="long" /> value indicating the change in the
/// size of the box described by the current instance.
/// </param>
/// <returns>
/// The size change encountered by the box that parents the
/// box described the the current instance, equal to the
/// size change of the box plus any size change that should
/// happen in the header.
/// </returns>
public long Overwrite (TagLib.File file, long sizeChange)
{
if (file == null)
throw new ArgumentNullException (nameof (file));
if (!from_disk)
throw new InvalidOperationException ("Cannot overwrite headers not on disk.");
long old_header_size = HeaderSize;
DataSize += sizeChange;
file.Insert (Render (), position, old_header_size);
return sizeChange + HeaderSize - old_header_size;
}
/// <summary>
/// Renders the header represented by the current instance.
/// </summary>
/// <returns>
/// A <see cref="ByteVector" /> object containing the
/// rendered version of the current instance.
/// </returns>
public ByteVector Render ()
{
// Enlarge for size if necessary.
if ((header_size == 8 || header_size == 24) && box_size > uint.MaxValue) {
header_size += 8;
box_size += 8;
}
// Add the box size and type to the output.
ByteVector output = ByteVector.FromUInt (
(header_size == 8 || header_size == 24) ?
(uint)box_size : 1);
output.Add (BoxType);
// If the box size is 16 or 32, we must have more a
// large header to append.
if (header_size == 16 || header_size == 32)
output.Add (ByteVector.FromULong (box_size));
// The only reason for such a big size is an extended
// type. Extend!!!
if (header_size >= 24)
output.Add (ExtendedType);
return output;
}
#endregion
#region Internal Properties
/// <summary>
/// Gets and sets the box represented by the current instance
/// as a means of temporary storage for internal uses.
/// </summary>
internal Box Box { get; set; }
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b97e0d4d07d086e4ea9bef8a36f38e08
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+103
View File
@@ -0,0 +1,103 @@
//
// BoxTypes.cs: Contains common box names.
//
// Author:
// Brian Nickel (brian.nickel@gmail.com)
//
// Copyright (C) 2006-2007 Brian Nickel
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License version
// 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
//
namespace TagLib.Mpeg4
{
/// <summary>
/// <see cref="BoxType" /> provides references to different box types
/// used by the library.
/// </summary>
/// <remarks>
/// <para>This class is used to severely reduce the number of times
/// these types are created in <see cref="AppleTag" />, greatly
/// improving the speed at which warm files are read.</para>
/// <para>The reason it is marked as internal is because I'm not sure
/// I like the way the fields are named, and it is really
/// unneccessary for external uses. While the library may use
/// <c>DataBoxes (BoxType.Gen, BoxType.Gnre);</c>, an external user
/// could use <c>tag.DataBoxes ("gen", "gnre");</c> with the same
/// result.</para>
/// <see url="https://picard.musicbrainz.org/docs/mappings/"/>
/// </remarks>
static class BoxType
{
public static readonly ReadOnlyByteVector Aart = "aART";
public static readonly ReadOnlyByteVector Alb = AppleTag.FixId ("alb");
public static readonly ReadOnlyByteVector Art = AppleTag.FixId ("ART");
public static readonly ReadOnlyByteVector Cmt = AppleTag.FixId ("cmt");
public static readonly ReadOnlyByteVector Cond = "cond";
public static readonly ReadOnlyByteVector Covr = "covr";
public static readonly ReadOnlyByteVector Co64 = "co64";
public static readonly ReadOnlyByteVector Cpil = "cpil";
public static readonly ReadOnlyByteVector Cprt = "cprt";
public static readonly ReadOnlyByteVector Data = "data";
public static readonly ReadOnlyByteVector Day = AppleTag.FixId ("day");
public static readonly ReadOnlyByteVector Desc = "desc";
public static readonly ReadOnlyByteVector Disk = "disk";
public static readonly ReadOnlyByteVector Dtag = "dtag";
public static readonly ReadOnlyByteVector Esds = "esds";
public static readonly ReadOnlyByteVector Ilst = "ilst";
public static readonly ReadOnlyByteVector Free = "free";
public static readonly ReadOnlyByteVector Gen = AppleTag.FixId ("gen");
public static readonly ReadOnlyByteVector Gnre = "gnre";
public static readonly ReadOnlyByteVector Grp = AppleTag.FixId ("grp");
public static readonly ReadOnlyByteVector Hdlr = "hdlr";
public static readonly ReadOnlyByteVector Lyr = AppleTag.FixId ("lyr");
public static readonly ReadOnlyByteVector Mdat = "mdat";
public static readonly ReadOnlyByteVector Mdia = "mdia";
public static readonly ReadOnlyByteVector Meta = "meta";
public static readonly ReadOnlyByteVector Mean = "mean";
public static readonly ReadOnlyByteVector Minf = "minf";
public static readonly ReadOnlyByteVector Moov = "moov";
public static readonly ReadOnlyByteVector Mvhd = "mvhd";
public static readonly ReadOnlyByteVector Nam = AppleTag.FixId ("nam");
public static readonly ReadOnlyByteVector Name = "name";
public static readonly ReadOnlyByteVector Role = "role";
public static readonly ReadOnlyByteVector Skip = "skip";
public static readonly ReadOnlyByteVector Soaa = "soaa"; // Album Artist Sort
public static readonly ReadOnlyByteVector Soar = "soar"; // Performer Sort
public static readonly ReadOnlyByteVector Soco = "soco"; // Composer Sort
public static readonly ReadOnlyByteVector Sonm = "sonm"; // Track Title Sort
public static readonly ReadOnlyByteVector Soal = "soal"; // Album Title Sort
public static readonly ReadOnlyByteVector Stbl = "stbl";
public static readonly ReadOnlyByteVector Stco = "stco";
public static readonly ReadOnlyByteVector Stsd = "stsd";
public static readonly ReadOnlyByteVector Subt = "Subt";
public static readonly ReadOnlyByteVector Text = "text";
public static readonly ReadOnlyByteVector Tmpo = "tmpo";
public static readonly ReadOnlyByteVector Trak = "trak";
public static readonly ReadOnlyByteVector Trkn = "trkn";
public static readonly ReadOnlyByteVector Udta = "udta";
public static readonly ReadOnlyByteVector Url = AppleTag.FixId ("url");
public static readonly ReadOnlyByteVector Uuid = "uuid";
public static readonly ReadOnlyByteVector Wrt = AppleTag.FixId ("wrt");
public static readonly ReadOnlyByteVector DASH = "----";
// Handler types.
public static readonly ReadOnlyByteVector Soun = "soun";
public static readonly ReadOnlyByteVector Vide = "vide";
// Another handler type, found in wild in audio file ripped using iTunes
public static readonly ReadOnlyByteVector Alis = "alis";
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: adcf753dd486a5dd18b8630838fa4e14
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c3d7613a8f16e0d90b1b09f05ae96ba1
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,119 @@
//
// AppleAdditionalInfoBox.cs: Provides an implementation of an Apple
// AdditionalInfoBox.
//
// Author:
// Brian Nickel (brian.nickel@gmail.com)
//
// Copyright (C) 2006-2007 Brian Nickel
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License version
// 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
//
using System;
namespace TagLib.Mpeg4
{
/// <summary>
/// This class extends <see cref="FullBox" /> to provide an
/// implementation of an Apple AdditionalInfoBox.
/// </summary>
public class AppleAdditionalInfoBox : FullBox
{
#region Private Fields
/// <summary>
/// Contains the box data.
/// </summary>
ByteVector data;
#endregion
#region Constructors
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="AppleAdditionalInfoBox" /> with a provided header
/// and handler by reading the contents from a specified
/// file.
/// </summary>
/// <param name="header">
/// A <see cref="BoxHeader" /> object containing the header
/// to use for the new instance.
/// </param>
/// <param name="file">
/// A <see cref="TagLib.File" /> object to read the contents
/// of the box from.
/// </param>
/// <param name="handler">
/// A <see cref="IsoHandlerBox" /> object containing the
/// handler that applies to the new instance.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="file" /> is <see langword="null" />.
/// </exception>
public AppleAdditionalInfoBox (BoxHeader header, TagLib.File file, IsoHandlerBox handler)
: base (header, file, handler)
{
// We do not care what is in this custom data section
// see: https://developer.apple.com/library/mac/#documentation/QuickTime/QTFF/QTFFChap2/qtff2.html
Data = file.ReadBlock (DataSize > 0 ? DataSize : 0);
}
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="AppleAdditionalInfoBox" /> using specified header, version and flags
/// </summary>
/// <param name="header">defines the header data</param>
/// <param name="version"></param>
/// <param name="flags"></param>
public AppleAdditionalInfoBox (ByteVector header, byte version, uint flags) : base (header, version, flags)
{
}
#endregion
#region Public Properties
/// <summary>
/// Gets and sets the data contained in the current instance.
/// </summary>
/// <value>
/// A <see cref="ByteVector" /> object containing the data
/// contained in the current instance.
/// </value>
public override ByteVector Data {
get { return data; }
set { data = value ?? new ByteVector (); }
}
/// <summary>
/// Gets and sets the text contained in the current instance.
/// </summary>
/// <value>
/// A <see cref="string" /> object containing the text
/// contained in the current instance.
/// </value>
public string Text {
get { return Data.ToString (StringType.Latin1).TrimStart ('\0'); }
set { Data = ByteVector.FromString (value, StringType.Latin1); }
}
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 25ff95a004e56b4e79c632e60c49ec0c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,98 @@
//
// AppleAnnotationBox.cs: Provides an implementation of an Apple AnnotationBox.
//
// Author:
// Brian Nickel (brian.nickel@gmail.com)
//
// Copyright (C) 2006-2007 Brian Nickel
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License version
// 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
//
using System;
using System.Collections.Generic;
namespace TagLib.Mpeg4
{
/// <summary>
/// This class extends <see cref="Box" /> to provide an
/// implementation of an Apple AnnotationBox.
/// </summary>
public class AppleAnnotationBox : Box
{
#region Constructors
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="AppleAnnotationBox" /> with a provided header and
/// handler by reading the contents from a specified file.
/// </summary>
/// <param name="header">
/// A <see cref="BoxHeader" /> object containing the header
/// to use for the new instance.
/// </param>
/// <param name="file">
/// A <see cref="TagLib.File" /> object to read the contents
/// of the box from.
/// </param>
/// <param name="handler">
/// A <see cref="IsoHandlerBox" /> object containing the
/// handler that applies to the new instance.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="file" /> is <see langword="null" />.
/// </exception>
public AppleAnnotationBox (BoxHeader header, TagLib.File file, IsoHandlerBox handler)
: base (header, handler)
{
if (file == null)
throw new ArgumentNullException (nameof (file));
Children = LoadChildren (file);
}
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="AppleAnnotationBox" /> of specified type with no
/// children.
/// </summary>
/// <param name="type">
/// A <see cref="ByteVector" /> object containing a 4-byte
/// box type.
/// </param>
public AppleAnnotationBox (ByteVector type)
: base (type)
{
Children = new List<Box> ();
}
#endregion
#region Public Properties
/// <summary>
/// Gets the children of the current instance.
/// </summary>
/// <value>
/// A <see cref="T:System.Collections.Generic.IEnumerable`1" /> object enumerating the
/// children of the current instance.
/// </value>
public override IEnumerable<Box> Children { get; }
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4e048a50f4a5ab35bb7cc862e7f30529
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,212 @@
//
// AppleDataBox.cs: Provides an implementation of an Apple DataBox.
//
// Author:
// Brian Nickel (brian.nickel@gmail.com)
//
// Copyright (C) 2006-2007 Brian Nickel
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License version
// 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
//
using System;
namespace TagLib.Mpeg4
{
/// <summary>
/// This class extends <see cref="FullBox" /> to provide an
/// implementation of an Apple DataBox.
/// </summary>
public class AppleDataBox : FullBox
{
#region Enums
/// <summary>
/// Specifies the type of data contained in a box.
/// </summary>
public enum FlagType
{
/// <summary>
/// The box contains UTF-8 text.
/// </summary>
ContainsText = 0x01,
/// <summary>
/// The box contains binary data.
/// </summary>
ContainsData = 0x00,
/// <summary>
/// The box contains data for a tempo box.
/// </summary>
ForTempo = 0x15,
/// <summary>
/// The box contains a raw JPEG image.
/// </summary>
ContainsJpegData = 0x0D,
/// <summary>
/// The box contains a raw PNG image.
/// </summary>
ContainsPngData = 0x0E,
/// <summary>
/// The box contains a raw BMP image.
/// </summary>
ContainsBmpData = 0x1B
}
#endregion
#region Private Fields
/// <summary>
/// Contains the box data.
/// </summary>
ByteVector data;
#endregion
#region Constructors
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="AppleDataBox" /> with a provided header and handler
/// by reading the contents from a specified file.
/// </summary>
/// <param name="header">
/// A <see cref="BoxHeader" /> object containing the header
/// to use for the new instance.
/// </param>
/// <param name="file">
/// A <see cref="TagLib.File" /> object to read the contents
/// of the box from.
/// </param>
/// <param name="handler">
/// A <see cref="IsoHandlerBox" /> object containing the
/// handler that applies to the new instance.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="file" /> is <see langword="null" />.
/// </exception>
public AppleDataBox (BoxHeader header, TagLib.File file, IsoHandlerBox handler)
: base (header, file, handler)
{
Data = LoadData (file);
}
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="AppleDataBox" /> with specified data and flags.
/// </summary>
/// <param name="data">
/// A <see cref="ByteVector" /> object containing the data to
/// store in the new instance.
/// </param>
/// <param name="flags">
/// A <see cref="uint" /> value containing flags to use for
/// the new instance.
/// </param>
public AppleDataBox (ByteVector data, uint flags)
: base ("data", 0, flags)
{
Data = data;
}
#endregion
#region Public Properties
/// <summary>
/// Gets the position of the data contained in the current
/// instance, after any box specific headers.
/// </summary>
/// <value>
/// A <see cref="long" /> value containing the position of
/// the data contained in the current instance.
/// </value>
protected override long DataPosition {
get { return base.DataPosition + 4; }
}
/// <summary>
/// Gets and sets the data contained in the current instance.
/// </summary>
/// <value>
/// A <see cref="ByteVector" /> object containing the data
/// contained in the current instance.
/// </value>
public override ByteVector Data {
get { return data; }
set { data = value ?? new ByteVector (); }
}
/// <summary>
/// Gets and sets the text contained in the current instance.
/// </summary>
/// <value>
/// A <see cref="string" /> object containing the text
/// contained in the current instance, or <see
/// langword="null" /> if the box is not flagged as
/// containing text.
/// </value>
public string Text {
get {
return ((Flags & (int)FlagType.ContainsText) != 0) ? Data.ToString (StringType.UTF8) : null;
}
set {
Flags = (int)FlagType.ContainsText;
Data = ByteVector.FromString (value, StringType.UTF8);
}
}
#endregion
#region Protected Methods
/// <summary>
/// Renders the current instance, including its children, to
/// a new <see cref="ByteVector" /> object, preceeding the
/// contents with a specified block of data.
/// </summary>
/// <param name="topData">
/// A <see cref="ByteVector" /> object containing box
/// specific header data to preceed the content.
/// </param>
/// <returns>
/// A <see cref="ByteVector" /> object containing the
/// rendered version of the current instance.
/// </returns>
protected override ByteVector Render (ByteVector topData)
{
var output = new ByteVector (4) {
topData
};
return base.Render (output);
}
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0b2e8b5da62b154548412a411227a170
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,435 @@
//
// AppleElementaryStreamDescriptor.cs: Provides an implementation of an Apple
// ItemListBox.
//
// Author:
// Brian Nickel (brian.nickel@gmail.com)
// RBoy1
//
// Copyright (C) 2006-2007 Brian Nickel
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License version
// 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
//
using System;
namespace TagLib.Mpeg4
{
/// <summary>
/// This class extends <see cref="FullBox" /> to provide an
/// implementation of an Apple ElementaryStreamDescriptor.
/// </summary>
/// <remarks>
/// This box may appear as a child of a <see
/// cref="IsoAudioSampleEntry" /> and provided further information
/// about an audio stream.
/// </remarks>
public class AppleElementaryStreamDescriptor : FullBox
{
#region Private Fields
/// <summary>
/// Descriptor Tags
/// </summary>
enum DescriptorTag
{
Forbidden_00 = 0,
ObjectDescrTag = 1,
InitialObjectDescrTag = 2,
ES_DescrTag = 3,
DecoderConfigDescrTag = 4,
DecSpecificInfoTag = 5,
SLConfigDescrTag = 6,
ContentIdentDescrTag = 7,
SupplContentIdentDescrTag = 8,
IPI_DescrPointerTag = 9,
IPMP_DescrPointerTag = 10,
IPMP_DescrTag = 11,
QoS_DescrTag = 12,
RegistrationDescrTag = 13,
ES_ID_IncTag = 14,
ES_ID_RefTag = 15,
MP4_IOD_Tag = 16,
MP4_OD_Tag = 17,
IPL_DescrPointerRefTag = 18,
ExtensionProfileLevelDescrTag = 19,
profileLevelIndicationIndexDescrTag = 20,
ReservedForFutureISOUse_15_TO_3F = 21,
ContentClassificationDescrTag = 64,
KeyWordDescrTag = 65,
RatingDescrTag = 66,
LanguageDescrTag = 67,
ShortTextualDescrTag = 68,
ExpandedTextualDescrTag = 69,
ContentCreatorNameDescrTag = 70,
ContentCreationDateDescrTag = 71,
OCICreatorNameDescrTag = 72,
OCICreationDateDescrTag = 73,
SmpteCameraPositionDescrTag = 74,
SegmentDescrTag = 75,
MediaTimeDescrTag = 76,
ReservedForFutureISOUseOCI = 77,
IPMP_ToolsListDescrTag = 96,
IPMP_ToolTag = 97,
M4MuxTimingDescrTag = 98,
M4MuxCodeTableDescrTag = 99,
ExtSLConfigDescrTag = 100,
M4MuxBufferSizeDescrTag = 101,
M4MuxIdentDescrTag = 102,
DependencyPointerTag = 103,
DependencyMarkerTag = 104,
M4MuxChannelDescrTag = 105,
ReservedForFutureISO_6A_TO_BF = 106,
UserPrivate = 192,
Forbidden_FF = 255,
}
/// <summary>
/// the ES_ID of another elementary stream on which this elementary stream depends
/// </summary>
ushort dependsOn_ES_ID;
/// <summary>
/// Indicates that a dependsOn_ES_ID will follow
/// </summary>
readonly bool stream_dependence_flag;
/// <summary>
/// OCR Stream Flag
/// </summary>
readonly bool ocr_stream_flag;
/// <summary>
/// OCR ES_ID
/// </summary>
ushort OCR_ES_Id;
/// <summary>
/// Indicates that a URLstring will follow
/// </summary>
readonly bool URL_flag;
/// <summary>
/// Length of URL String
/// </summary>
readonly byte URLlength;
/// <summary>
/// URL String of URLlength, contains a URL that shall point to the location of an SL-packetized stream by name
/// </summary>
string URLstring;
/// <summary>
/// Indicates that this stream is used for upstream information
/// </summary>
bool upStream;
/// <summary>
/// Contains the maximum bitrate.
/// </summary>
readonly uint max_bitrate;
/// <summary>
/// Contains the average bitrate.
/// </summary>
readonly uint average_bitrate;
#endregion
#region Constructors
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="AppleElementaryStreamDescriptor" /> with a provided
/// header and handler by reading the contents from a
/// specified file.
/// </summary>
/// <param name="header">
/// A <see cref="BoxHeader" /> object containing the header
/// to use for the new instance.
/// </param>
/// <param name="file">
/// A <see cref="TagLib.File" /> object to read the contents
/// of the box from.
/// </param>
/// <param name="handler">
/// A <see cref="IsoHandlerBox" /> object containing the
/// handler that applies to the new instance.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="file" /> is <see langword="null" />.
/// </exception>
/// <exception cref="CorruptFileException">
/// Valid data could not be read.
/// </exception>
public AppleElementaryStreamDescriptor (BoxHeader header, TagLib.File file, IsoHandlerBox handler)
: base (header, file, handler)
{
/* ES_Descriptor Specifications
* Section 7.2.6.5 http://ecee.colorado.edu/~ecen5653/ecen5653/papers/ISO%2014496-1%202004.PDF
*/
ByteVector box_data = file.ReadBlock (DataSize);
DecoderConfig = new ByteVector ();
int offset = 0;
// Elementary Stream Descriptor Tag
if ((DescriptorTag)box_data[offset++] != DescriptorTag.ES_DescrTag)
throw new CorruptFileException ("Invalid Elementary Stream Descriptor, missing tag.");
// We have a descriptor tag. Check that the remainder of the tag is at least [Base (3 bytes) + DecoderConfigDescriptor (15 bytes) + SLConfigDescriptor (3 bytes) + OtherDescriptors] bytes long
uint es_length = ReadLength (box_data, ref offset);
uint min_es_length = 3 + 15 + 3; // Base minimum length
if (es_length < min_es_length)
throw new CorruptFileException ("Insufficient data present.");
StreamId = box_data.Mid (offset, 2).ToUShort ();
offset += 2; // Done with ES_ID
stream_dependence_flag = ((byte)((box_data[offset] >> 7) & 0x1) == 0x1 ? true : false); // 1st bit
URL_flag = ((byte)((box_data[offset] >> 6) & 0x1) == 0x1 ? true : false); // 2nd bit
ocr_stream_flag = ((byte)((box_data[offset] >> 5) & 0x1) == 0x1 ? true : false); // 3rd bit
StreamPriority = (byte)(box_data[offset++] & 0x1F); // Last 5 bits and we're done with this byte
if (stream_dependence_flag) {
min_es_length += 2; // We need 2 more bytes
if (es_length < min_es_length)
throw new CorruptFileException ("Insufficient data present.");
dependsOn_ES_ID = box_data.Mid (offset, 2).ToUShort ();
offset += 2; // Done with stream dependence
}
if (URL_flag) {
min_es_length += 2; // We need 1 more byte
if (es_length < min_es_length)
throw new CorruptFileException ("Insufficient data present.");
URLlength = box_data[offset++]; // URL Length
min_es_length += URLlength; // We need URLength more bytes
if (es_length < min_es_length)
throw new CorruptFileException ("Insufficient data present.");
URLstring = box_data.Mid (offset, URLlength).ToString (); // URL name
offset += URLlength; // Done with URL name
}
if (ocr_stream_flag) {
min_es_length += 2; // We need 2 more bytes
if (es_length < min_es_length)
throw new CorruptFileException ("Insufficient data present.");
OCR_ES_Id = box_data.Mid (offset, 2).ToUShort ();
offset += 2; // Done with OCR
}
while (offset < DataSize) // Loop through all trailing Descriptors Tags
{
DescriptorTag tag = (DescriptorTag)box_data[offset++];
switch (tag) {
case DescriptorTag.DecoderConfigDescrTag: // DecoderConfigDescriptor
{
// Check that the remainder of the tag is at least 13 bytes long (13 + DecoderSpecificInfo[] + profileLevelIndicationIndexDescriptor[])
if (ReadLength (box_data, ref offset) < 13)
throw new CorruptFileException ("Could not read data. Too small.");
// Read a lot of good info.
ObjectTypeId = box_data[offset++];
StreamType = (byte)(box_data[offset] >> 2); // First 6 bits
upStream = ((byte)((box_data[offset++] >> 1) & 0x1) == 0x1 ? true : false); // 7th bit and we're done with the stream bits
BufferSizeDB = box_data.Mid (offset, 3).ToUInt ();
offset += 3; // Done with bufferSizeDB
max_bitrate = box_data.Mid (offset, 4).ToUInt ();
offset += 4; // Done with maxBitrate
average_bitrate = box_data.Mid (offset, 4).ToUInt ();
offset += 4; // Done with avgBitrate
// If there's a DecoderSpecificInfo[] array at the end it'll pick it up in the while loop
}
break;
case DescriptorTag.DecSpecificInfoTag: // DecoderSpecificInfo
{
// The rest of the info is decoder specific.
uint length = ReadLength (box_data, ref offset);
DecoderConfig = box_data.Mid (offset, (int)length);
offset += (int)length; // We're done with the config
}
break;
case DescriptorTag.SLConfigDescrTag: // SLConfigDescriptor
{
// The rest of the info is SL specific.
uint length = ReadLength (box_data, ref offset);
offset += (int)length; // Skip the rest of the descriptor as reported in the length so we can move onto the next one
}
break;
case DescriptorTag.Forbidden_00:
case DescriptorTag.Forbidden_FF:
throw new CorruptFileException ("Invalid Descriptor tag.");
default: {
/* TODO: Should we handle other optional descriptor tags?
* ExtensionDescriptor extDescr[0 .. 255];
LanguageDescriptor langDescr[0 .. 1];
IPI_DescPointer ipiPtr[0 .. 1];
IP_IdentificationDataSet ipIDS[0 .. 1];
QoS_Descriptor qosDescr[0 .. 1];
*/
uint length = ReadLength (box_data, ref offset); // Every descriptor starts with a length
offset += (int)length; // Skip the rest of the descriptor as reported in the length so we can move onto the next one
break;
}
}
}
}
#endregion
#region Public Properties
/// <summary>
/// Gets the ID of the stream described by the current
/// instance.
/// </summary>
/// <value>
/// A <see cref="ushort" /> value containing the ID of the
/// stream described by the current instance.
/// </value>
public ushort StreamId { get; }
/// <summary>
/// Gets the priority of the stream described by the current
/// instance.
/// </summary>
/// <value>
/// A <see cref="byte" /> value containing the priority of
/// the stream described by the current instance.
/// </value>
public byte StreamPriority { get; }
/// <summary>
/// Gets the object type ID of the stream described by the
/// current instance.
/// </summary>
/// <value>
/// A <see cref="byte" /> value containing the object type ID
/// of the stream described by the current instance.
/// </value>
public byte ObjectTypeId { get; }
/// <summary>
/// Gets the type the stream described by the current
/// instance.
/// </summary>
/// <value>
/// A <see cref="byte" /> value containing the type the
/// stream described by the current instance.
/// </value>
public byte StreamType { get; }
/// <summary>
/// Gets the buffer size DB value the stream described by the
/// current instance.
/// </summary>
/// <value>
/// A <see cref="uint" /> value containing the buffer size DB
/// value the stream described by the current instance.
/// </value>
public uint BufferSizeDB { get; }
/// <summary>
/// Gets the maximum bitrate the stream described by the
/// current instance.
/// </summary>
/// <value>
/// A <see cref="uint" /> value containing the maximum
/// bitrate the stream described by the current instance.
/// </value>
public uint MaximumBitrate { get { return max_bitrate / 1000; } }
/// <summary>
/// Gets the maximum average the stream described by the
/// current instance.
/// </summary>
/// <value>
/// A <see cref="uint" /> value containing the average
/// bitrate the stream described by the current instance.
/// </value>
public uint AverageBitrate { get { return average_bitrate / 1000; } }
/// <summary>
/// Gets the decoder config data of stream described by the
/// current instance.
/// </summary>
/// <value>
/// A <see cref="ByteVector" /> object containing the decoder
/// config data of the stream described by the current
/// instance.
/// </value>
public ByteVector DecoderConfig { get; }
#endregion
#region Private Methods
/// <summary>
/// Reads a section length and updates the offset to the end
/// of of the length block.
/// </summary>
/// <param name="data">
/// A <see cref="ByteVector" /> object to read from.
/// </param>
/// <param name="offset">
/// A <see cref="int" /> value reference specifying the
/// offset at which to read. This value gets updated to the
/// position following the size data.
/// </param>
/// <returns>
/// A <see cref="uint" /> value containing the length that
/// was read.
/// </returns>
static uint ReadLength (ByteVector data, ref int offset)
{
byte b;
int end = offset + 4;
uint length = 0;
do {
b = data[offset++];
length = (uint)(length << 7) | (uint)(b & 0x7f);
} while ((b & 0x80) != 0 && offset <= end); // The Length could be between 1 and 4 bytes for each descriptor
return length;
}
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 01db5a51c2f9ebccb80b8b8c7c857ec1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,92 @@
//
// AppleItemListBox.cs: Provides an implementation of an Apple ItemListBox.
//
// Author:
// Brian Nickel (brian.nickel@gmail.com)
//
// Copyright (C) 2006-2007 Brian Nickel
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License version
// 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
//
using System;
using System.Collections.Generic;
namespace TagLib.Mpeg4
{
/// <summary>
/// This class extends <see cref="Box" /> to provide an
/// implementation of an Apple ItemListBox.
/// </summary>
public class AppleItemListBox : Box
{
#region Constructors
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="AppleItemListBox" /> with a provided header and
/// handler by reading the contents from a specified file.
/// </summary>
/// <param name="header">
/// A <see cref="BoxHeader" /> object containing the header
/// to use for the new instance.
/// </param>
/// <param name="file">
/// A <see cref="TagLib.File" /> object to read the contents
/// of the box from.
/// </param>
/// <param name="handler">
/// A <see cref="IsoHandlerBox" /> object containing the
/// handler that applies to the new instance.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="file" /> is <see langword="null" />.
/// </exception>
public AppleItemListBox (BoxHeader header, TagLib.File file, IsoHandlerBox handler)
: base (header, handler)
{
if (file == null)
throw new ArgumentNullException (nameof (file));
Children = LoadChildren (file);
}
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="AppleItemListBox" /> with no children.
/// </summary>
public AppleItemListBox () : base ("ilst")
{
Children = new List<Box> ();
}
#endregion
#region Public Properties
/// <summary>
/// Gets the children of the current instance.
/// </summary>
/// <value>
/// A <see cref="T:System.Collections.Generic.IEnumerable`1" /> object enumerating the
/// children of the current instance.
/// </value>
public override IEnumerable<Box> Children { get; }
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 67b229427379dec19804cd115530bd73
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+203
View File
@@ -0,0 +1,203 @@
//
// FullBox.cs: Provides an implementation of a ISO/IEC 14496-12 FullBox.
//
// Author:
// Brian Nickel (brian.nickel@gmail.com)
//
// Copyright (C) 2006-2007 Brian Nickel
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License version
// 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
//
using System;
namespace TagLib.Mpeg4
{
/// <summary>
/// This class extends <see cref="Box" /> to provide an
/// implementation of a ISO/IEC 14496-12 FullBox.
/// </summary>
public abstract class FullBox : Box
{
#region Private Fields
/// <summary>
/// Contains the box version.
/// </summary>
byte version;
#endregion
#region Constructors
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="FullBox" /> with a provided header and handler by
/// reading the contents from a specified file.
/// </summary>
/// <param name="header">
/// A <see cref="BoxHeader" /> object containing the header
/// to use for the new instance.
/// </param>
/// <param name="file">
/// A <see cref="TagLib.File" /> object to read the contents
/// of the box from.
/// </param>
/// <param name="handler">
/// A <see cref="IsoHandlerBox" /> object containing the
/// handler that applies to the new instance.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="file" /> is <see langword="null" />.
/// </exception>
protected FullBox (BoxHeader header, TagLib.File file, IsoHandlerBox handler)
: base (header, handler)
{
if (file == null)
throw new ArgumentNullException (nameof (file));
file.Seek (base.DataPosition);
ByteVector header_data = file.ReadBlock (4);
version = header_data[0];
Flags = header_data.Mid (1, 3).ToUInt ();
}
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="FullBox" /> with a provided header, version, and
/// flags.
/// </summary>
/// <param name="header">
/// A <see cref="BoxHeader" /> object containing the header
/// to use for the new instance.
/// </param>
/// <param name="version">
/// A <see cref="byte" /> value containing the version of the
/// new instance.
/// </param>
/// <param name="flags">
/// A <see cref="byte" /> value containing the flags for the
/// new instance.
/// </param>
protected FullBox (BoxHeader header, byte version, uint flags)
: base (header)
{
this.version = version;
Flags = flags;
}
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="FullBox" /> with a provided header, version, and
/// flags.
/// </summary>
/// <param name="type">
/// A <see cref="ByteVector" /> object containing the four
/// byte box type.
/// </param>
/// <param name="version">
/// A <see cref="byte" /> value containing the version of the
/// new instance.
/// </param>
/// <param name="flags">
/// A <see cref="byte" /> value containing the flags for the
/// new instance.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="type" /> is <see langword="null" /> of
/// equal to "<c>uuid</c>".
/// </exception>
/// <exception cref="ArgumentException">
/// <paramref name="type" /> isn't exactly 4 bytes long.
/// </exception>
protected FullBox (ByteVector type, byte version, uint flags)
: this (new BoxHeader (type), version, flags)
{
}
#endregion
#region Public Properties
/// <summary>
/// Gets the position of the data contained in the current
/// instance, after any box specific headers.
/// </summary>
/// <value>
/// A <see cref="long" /> value containing the position of
/// the data contained in the current instance.
/// </value>
protected override long DataPosition {
get { return base.DataPosition + 4; }
}
/// <summary>
/// Gets and sets the version number of the current instance.
/// </summary>
/// <value>
/// A <see cref="byte" /> value containing the version
/// number of the current instance.
/// </value>
public uint Version {
get { return version; }
set { version = (byte)value; }
}
/// <summary>
/// Gets and sets the flags that apply to the current
/// instance.
/// </summary>
/// <value>
/// A <see cref="uint" /> value containing the flags that
/// apply to the current instance.
/// </value>
public uint Flags { get; set; }
#endregion
#region Protected Methods
/// <summary>
/// Renders the current instance, including its children, to
/// a new <see cref="ByteVector" /> object, preceeding the
/// contents with a specified block of data.
/// </summary>
/// <param name="topData">
/// A <see cref="ByteVector" /> object containing box
/// specific header data to preceed the content.
/// </param>
/// <returns>
/// A <see cref="ByteVector" /> object containing the
/// rendered version of the current instance.
/// </returns>
protected override ByteVector Render (ByteVector topData)
{
var output = new ByteVector (version) {
ByteVector.FromUInt (Flags).Mid (1, 3),
topData
};
return base.Render (output);
}
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 34757a28f0c3382fe90faa1055a948ee
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,231 @@
//
// IsoAudioSampleEntry.cs: Provides an implementation of a ISO/IEC 14496-12
// AudioSampleEntry and support for reading MPEG-4 video properties.
//
// Author:
// Brian Nickel (brian.nickel@gmail.com)
//
// Copyright (C) 2006-2007 Brian Nickel
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License version
// 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
//
using System;
using System.Collections.Generic;
using System.Globalization;
namespace TagLib.Mpeg4
{
/// <summary>
/// This class extends <see cref="IsoSampleEntry" /> and implements
/// <see cref="IAudioCodec" /> to provide an implementation of a
/// ISO/IEC 14496-12 AudioSampleEntry and support for reading MPEG-4
/// video properties.
/// </summary>
public class IsoAudioSampleEntry : IsoSampleEntry, IAudioCodec
{
#region Private Fields
/// <summary>
/// Contains the channel count.
/// </summary>
readonly ushort channel_count;
/// <summary>
/// Contains the sample size.
/// </summary>
readonly ushort sample_size;
/// <summary>
/// Contains the sample rate.
/// </summary>
readonly uint sample_rate;
/// <summary>
/// Contains the children of the box.
/// </summary>
readonly IEnumerable<Box> children;
#endregion
#region Constructors
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="IsoVisualSampleEntry" /> with a provided header and
/// handler by reading the contents from a specified file.
/// </summary>
/// <param name="header">
/// A <see cref="BoxHeader" /> object containing the header
/// to use for the new instance.
/// </param>
/// <param name="file">
/// A <see cref="TagLib.File" /> object to read the contents
/// of the box from.
/// </param>
/// <param name="handler">
/// A <see cref="IsoHandlerBox" /> object containing the
/// handler that applies to the new instance.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="file" /> is <see langword="null" />.
/// </exception>
public IsoAudioSampleEntry (BoxHeader header, TagLib.File file, IsoHandlerBox handler)
: base (header, file, handler)
{
if (file == null)
throw new ArgumentNullException (nameof (file));
file.Seek (base.DataPosition + 8);
channel_count = file.ReadBlock (2).ToUShort ();
sample_size = file.ReadBlock (2).ToUShort ();
file.Seek (base.DataPosition + 16);
sample_rate = file.ReadBlock (4).ToUInt ();
children = LoadChildren (file);
}
#endregion
#region Public Properties
/// <summary>
/// Gets the position of the data contained in the current
/// instance, after any box specific headers.
/// </summary>
/// <value>
/// A <see cref="long" /> value containing the position of
/// the data contained in the current instance.
/// </value>
protected override long DataPosition {
get { return base.DataPosition + 20; }
}
/// <summary>
/// Gets the children of the current instance.
/// </summary>
/// <value>
/// A <see cref="T:System.Collections.Generic.IEnumerable`1" /> object enumerating the
/// children of the current instance.
/// </value>
public override IEnumerable<Box> Children {
get { return children; }
}
#endregion
#region IAudioCodec Properties
/// <summary>
/// Gets the duration of the media represented by the current
/// instance.
/// </summary>
/// <value>
/// Always <see cref="TimeSpan.Zero" />.
/// </value>
public TimeSpan Duration {
get { return TimeSpan.Zero; }
}
/// <summary>
/// Gets the types of media represented by the current
/// instance.
/// </summary>
/// <value>
/// Always <see cref="MediaTypes.Video" />.
/// </value>
public MediaTypes MediaTypes {
get { return MediaTypes.Audio; }
}
/// <summary>
/// Gets a text description of the media represented by the
/// current instance.
/// </summary>
/// <value>
/// A <see cref="string" /> object containing a description
/// of the media represented by the current instance.
/// </value>
public string Description {
get {
return string.Format (CultureInfo.InvariantCulture, "MPEG-4 Audio ({0})", BoxType);
}
}
/// <summary>
/// Gets the bitrate of the audio represented by the current
/// instance.
/// </summary>
/// <value>
/// A <see cref="int" /> value containing a bitrate of the
/// audio represented by the current instance.
/// </value>
public int AudioBitrate {
get {
// If we don't have an stream descriptor, we
// don't know what's what.
if (!(GetChildRecursively ("esds") is AppleElementaryStreamDescriptor esds))
return 0;
// Return from the elementary stream descriptor.
return (int)esds.AverageBitrate;
}
}
/// <summary>
/// Gets the sample rate of the audio represented by the
/// current instance.
/// </summary>
/// <value>
/// A <see cref="int" /> value containing the sample rate of
/// the audio represented by the current instance.
/// </value>
public int AudioSampleRate {
get { return (int)(sample_rate >> 16); }
}
/// <summary>
/// Gets the number of channels in the audio represented by
/// the current instance.
/// </summary>
/// <value>
/// A <see cref="int" /> value containing the number of
/// channels in the audio represented by the current
/// instance.
/// </value>
public int AudioChannels {
get { return channel_count; }
}
/// <summary>
/// Gets the sample size of the audio represented by the
/// current instance.
/// </summary>
/// <value>
/// A <see cref="int" /> value containing the sample size of
/// the audio represented by the current instance.
/// </value>
public int AudioSampleSize {
get { return sample_size; }
}
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 985d1265608f9adbda1c1dbe038bd412
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,169 @@
//
// IsoChunkLargeOffsetBox.cs: Provides an implementation of a ISO/IEC 14496-12
// ChunkLargeOffsetBox.
//
// Author:
// Brian Nickel (brian.nickel@gmail.com)
//
// Copyright (C) 2006-2007 Brian Nickel
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License version
// 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
//
using System;
namespace TagLib.Mpeg4
{
/// <summary>
/// This class extends <see cref="FullBox" /> to provide an
/// implementation of a ISO/IEC 14496-12 ChunkLargeOffsetBox.
/// </summary>
/// <remarks>
/// <see cref="IsoChunkOffsetBox" /> and <see
/// cref="IsoChunkLargeOffsetBox" /> contain offsets of media data
/// within the file. As such, if the file changes by even one byte,
/// these values are devalidatated and the box will have to be
/// overwritten to maintain playability.
/// </remarks>
public class IsoChunkLargeOffsetBox : FullBox
{
#region Constructors
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="IsoChunkLargeOffsetBox" /> with a provided header
/// and handler by reading the contents from a specified
/// file.
/// </summary>
/// <param name="header">
/// A <see cref="BoxHeader" /> object containing the header
/// to use for the new instance.
/// </param>
/// <param name="file">
/// A <see cref="TagLib.File" /> object to read the contents
/// of the box from.
/// </param>
/// <param name="handler">
/// A <see cref="IsoHandlerBox" /> object containing the
/// handler that applies to the new instance.
/// </param>
public IsoChunkLargeOffsetBox (BoxHeader header, TagLib.File file, IsoHandlerBox handler)
: base (header, file, handler)
{
ByteVector box_data = file.ReadBlock (DataSize);
Offsets = new ulong[(int)
box_data.Mid (0, 4).ToUInt ()];
for (int i = 0; i < Offsets.Length; i++)
Offsets[i] = box_data.Mid (4 + i * 8, 8).ToULong ();
}
#endregion
#region Public Properties
/// <summary>
/// Gets and sets the data contained in the current instance.
/// </summary>
/// <value>
/// A <see cref="ByteVector" /> object containing the data
/// contained in the current instance.
/// </value>
public override ByteVector Data {
get {
ByteVector output = ByteVector.FromUInt ((uint)Offsets.Length);
for (int i = 0; i < Offsets.Length; i++)
output.Add (ByteVector.FromULong (Offsets[i]));
return output;
}
}
/// <summary>
/// Gets the offset table contained in the current instance.
/// </summary>
/// <value>
/// A <see cref="T:ulong[]" /> containing the offset table
/// contained in the current instance.
/// </value>
public ulong[] Offsets { get; private set; }
#endregion
#region Public Methods
/// <summary>
/// Overwrites the existing box in the file after updating
/// the table for a size change.
/// </summary>
/// <param name="file">
/// A <see cref="File" /> object containing the file to which
/// the current instance belongs and wo which modifications
/// must be applied.
/// </param>
/// <param name="sizeDifference">
/// A <see cref="long" /> value containing the size
/// change that occurred in the file.
/// </param>
/// <param name="after">
/// A <see cref="long" /> value containing the position in
/// the file after which offsets will be invalidated. If an
/// offset is before this point, it won't be updated.
/// </param>
/// <exception cref="ArgumentNullException">
/// <see param="file" /> is <see langword="null" />.
/// </exception>
public void Overwrite (File file, long sizeDifference, long after)
{
if (file == null)
throw new ArgumentNullException (nameof (file));
file.Insert (Render (sizeDifference, after), Header.Position, Size);
}
/// <summary>
/// Renders the current instance after updating the table for
/// a size change.
/// </summary>
/// <param name="sizeDifference">
/// A <see cref="long" /> value containing the size
/// change that occurred in the file.
/// </param>
/// <param name="after">
/// A <see cref="long" /> value containing the position in
/// the file after which offsets will be invalidated. If an
/// offset is before this point, it won't be updated.
/// </param>
/// <returns>
/// A <see cref="ByteVector" /> object containing the
/// rendered version of the file.
/// </returns>
public ByteVector Render (long sizeDifference, long after)
{
for (int i = 0; i < Offsets.Length; i++)
if (Offsets[i] >= (ulong)after)
Offsets[i] = (ulong)((long)Offsets[i] + sizeDifference);
return Render ();
}
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d0ca89970f2030b84926ebeebcbce72a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,168 @@
//
// IsoChunkOffsetBox.cs: Provides an implementation of a ISO/IEC 14496-12
// ChunkOffsetBox.
//
// Author:
// Brian Nickel (brian.nickel@gmail.com)
//
// Copyright (C) 2006-2007 Brian Nickel
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License version
// 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
//
using System;
namespace TagLib.Mpeg4
{
/// <summary>
/// This class extends <see cref="FullBox" /> to provide an
/// implementation of a ISO/IEC 14496-12 ChunkOffsetBox.
/// </summary>
/// <remarks>
/// <see cref="IsoChunkOffsetBox" /> and <see
/// cref="IsoChunkLargeOffsetBox" /> contain offsets of media data
/// within the file. As such, if the file changes by even one byte,
/// these values are devalidatated and the box will have to be
/// overwritten to maintain playability.
/// </remarks>
public class IsoChunkOffsetBox : FullBox
{
#region Constructors
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="IsoChunkOffsetBox" /> with a provided header and
/// handler by reading the contents from a specified file.
/// </summary>
/// <param name="header">
/// A <see cref="BoxHeader" /> object containing the header
/// to use for the new instance.
/// </param>
/// <param name="file">
/// A <see cref="TagLib.File" /> object to read the contents
/// of the box from.
/// </param>
/// <param name="handler">
/// A <see cref="IsoHandlerBox" /> object containing the
/// handler that applies to the new instance.
/// </param>
public IsoChunkOffsetBox (BoxHeader header, TagLib.File file, IsoHandlerBox handler)
: base (header, file, handler)
{
ByteVector box_data = file.ReadBlock (DataSize);
Offsets = new uint[(int)box_data.Mid (0, 4).ToUInt ()];
for (int i = 0; i < Offsets.Length; i++)
Offsets[i] = box_data.Mid (4 + i * 4, 4).ToUInt ();
}
#endregion
#region Public Properties
/// <summary>
/// Gets and sets the data contained in the current instance.
/// </summary>
/// <value>
/// A <see cref="ByteVector" /> object containing the data
/// contained in the current instance.
/// </value>
public override ByteVector Data {
get {
ByteVector output = ByteVector.FromUInt ((uint)Offsets.Length);
for (int i = 0; i < Offsets.Length; i++)
output.Add (ByteVector.FromUInt (Offsets[i]));
return output;
}
}
/// <summary>
/// Gets the offset table contained in the current instance.
/// </summary>
/// <value>
/// A <see cref="T:uint[]" /> containing the offset table
/// contained in the current instance.
/// </value>
public uint[] Offsets { get; private set; }
#endregion
#region Public Methods
/// <summary>
/// Overwrites the existing box in the file after updating
/// the table for a size change.
/// </summary>
/// <param name="file">
/// A <see cref="File" /> object containing the file to which
/// the current instance belongs and wo which modifications
/// must be applied.
/// </param>
/// <param name="sizeDifference">
/// A <see cref="long" /> value containing the size
/// change that occurred in the file.
/// </param>
/// <param name="after">
/// A <see cref="long" /> value containing the position in
/// the file after which offsets will be invalidated. If an
/// offset is before this point, it won't be updated.
/// </param>
/// <exception cref="ArgumentNullException">
/// <see param="file" /> is <see langword="null" />.
/// </exception>
public void Overwrite (File file, long sizeDifference, long after)
{
if (file == null)
throw new ArgumentNullException (nameof (file));
file.Insert (Render (sizeDifference, after), Header.Position, Size);
}
/// <summary>
/// Renders the current instance after updating the table for
/// a size change.
/// </summary>
/// <param name="sizeDifference">
/// A <see cref="long" /> value containing the size
/// change that occurred in the file.
/// </param>
/// <param name="after">
/// A <see cref="long" /> value containing the position in
/// the file after which offsets will be invalidated. If an
/// offset is before this point, it won't be updated.
/// </param>
/// <returns>
/// A <see cref="ByteVector" /> object containing the
/// rendered version of the file.
/// </returns>
public ByteVector Render (long sizeDifference, long after)
{
for (int i = 0; i < Offsets.Length; i++)
if (Offsets[i] >= (uint)after)
Offsets[i] = (uint)
(Offsets[i] + sizeDifference);
return Render ();
}
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d43ea3e18f67dbd899b0e0090caaa74c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,116 @@
//
// IsoFreeSpaceBox.cs: Provides an implementation of a ISO/IEC 14496-12
// FreeSpaceBox.
//
// Author:
// Brian Nickel (brian.nickel@gmail.com)
//
// Copyright (C) 2006-2007 Brian Nickel
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License version
// 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
//
namespace TagLib.Mpeg4
{
/// <summary>
/// This class extends <see cref="Box" /> to provide an
/// implementation of a ISO/IEC 14496-12 FreeSpaceBox.
/// </summary>
public class IsoFreeSpaceBox : Box
{
#region Private Fields
/// <summary>
/// Contains the size of the padding.
/// </summary>
long padding;
#endregion
#region Constructors
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="IsoMetaBox" /> with a provided header and
/// handler by reading the contents from a specified file.
/// </summary>
/// <param name="header">
/// A <see cref="BoxHeader" /> object containing the header
/// to use for the new instance.
/// </param>
/// <param name="file">
/// A <see cref="TagLib.File" /> object to read the contents
/// of the box from.
/// </param>
/// <param name="handler">
/// A <see cref="IsoHandlerBox" /> object containing the
/// handler that applies to the new instance.
/// </param>
public IsoFreeSpaceBox (BoxHeader header, TagLib.File file, IsoHandlerBox handler)
: base (header, handler)
{
padding = DataSize;
}
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="IsoFreeSpaceBox" /> to occupy a specified number of
/// bytes.
/// </summary>
/// <param name="padding">
/// A <see cref="long" /> value specifying the number of
/// bytes the new instance should occupy when rendered.
/// </param>
public IsoFreeSpaceBox (long padding) : base ("free")
{
PaddingSize = padding;
}
#endregion
#region Public Properties
/// <summary>
/// Gets and sets the data contained in the current instance.
/// </summary>
/// <value>
/// A <see cref="ByteVector" /> object containing the data
/// contained in the current instance.
/// </value>
public override ByteVector Data {
get { return new ByteVector ((int)padding); }
set { padding = (value != null) ? value.Count : 0; }
}
/// <summary>
/// Gets and sets the size the current instance will occupy
/// when rendered.
/// </summary>
/// <value>
/// A <see cref="long" /> value containing the size the
/// current instance will occupy when rendered.
/// </value>
public long PaddingSize {
get { return padding + 8; }
set { padding = value - 8; }
}
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 989139d0574affb60983d4b835fa07a9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,155 @@
//
// IsoHandlerBox.cs: Provides an implementation of a ISO/IEC 14496-12
// HandlerBox.
//
// Author:
// Brian Nickel (brian.nickel@gmail.com)
//
// Copyright (C) 2006-2007 Brian Nickel
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License version
// 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
//
using System;
namespace TagLib.Mpeg4
{
/// <summary>
/// This class extends <see cref="FullBox" /> to provide an
/// implementation of a ISO/IEC 14496-12 FullBox.
/// </summary>
public class IsoHandlerBox : FullBox
{
#region Constructors
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="IsoHandlerBox" /> with a provided header and
/// handler by reading the contents from a specified file.
/// </summary>
/// <param name="header">
/// A <see cref="BoxHeader" /> object containing the header
/// to use for the new instance.
/// </param>
/// <param name="file">
/// A <see cref="TagLib.File" /> object to read the contents
/// of the box from.
/// </param>
/// <param name="handler">
/// A <see cref="IsoHandlerBox" /> object containing the
/// handler that applies to the new instance.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="file" /> is <see langword="null" />.
/// </exception>
public IsoHandlerBox (BoxHeader header, TagLib.File file, IsoHandlerBox handler)
: base (header, file, handler)
{
if (file == null)
throw new ArgumentNullException (nameof (file));
file.Seek (DataPosition + 4);
ByteVector box_data = file.ReadBlock (DataSize - 4);
HandlerType = box_data.Mid (0, 4);
int end = box_data.Find ((byte)0, 16);
if (end < 16)
end = box_data.Count;
Name = end > 16 ? box_data.ToString (StringType.UTF8, 16, end - 16) : string.Empty;
}
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="IsoHandlerBox" /> with a specified type and name.
/// </summary>
/// <param name="handlerType">
/// A <see cref="ByteVector" /> object specifying a 4 byte
/// handler type.
/// </param>
/// <param name="name">
/// A <see cref="string" /> object specifying the handler
/// name.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="handlerType" /> is <see langword="null"
/// />.
/// </exception>
/// <exception cref="ArgumentException">
/// <paramref name="handlerType" /> is less than 4 bytes
/// long.
/// </exception>
public IsoHandlerBox (ByteVector handlerType, string name)
: base ("hdlr", 0, 0)
{
if (handlerType == null)
throw new ArgumentNullException (nameof (handlerType));
if (handlerType.Count < 4)
throw new ArgumentException ("The handler type must be four bytes long.",
nameof (handlerType));
HandlerType = handlerType.Mid (0, 4);
Name = name;
}
#endregion
#region Public Properties
/// <summary>
/// Gets the data contained in the current instance.
/// </summary>
/// <value>
/// A <see cref="ByteVector" /> object containing the
/// rendered version of the data contained in the current
/// instance.
/// </value>
public override ByteVector Data {
get {
var output = new ByteVector (4) {
HandlerType,
new ByteVector (12),
ByteVector.FromString (Name,
StringType.UTF8),
new ByteVector (2)
};
return output;
}
}
/// <summary>
/// Gets the handler type of the current instance.
/// </summary>
/// <value>
/// A <see cref="ByteVector" /> object containing the
/// handler type of the current instance.
/// </value>
public ByteVector HandlerType { get; private set; }
/// <summary>
/// Gets the name of the current instance.
/// </summary>
/// <value>
/// A <see cref="string" /> object containing the name of the
/// current instance.
/// </value>
public string Name { get; private set; }
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5c2babf0b4360f99d974d9b7a8578846
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,113 @@
//
// IsoMetaBox.cs: Provides an implementation of a ISO/IEC 14496-12 MetaBox.
//
// Author:
// Brian Nickel (brian.nickel@gmail.com)
//
// Copyright (C) 2006-2007 Brian Nickel
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License version
// 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
//
using System;
using System.Collections.Generic;
namespace TagLib.Mpeg4
{
/// <summary>
/// This class extends <see cref="FullBox" /> to provide an
/// implementation of a ISO/IEC 14496-12 MetaBox.
/// </summary>
public class IsoMetaBox : FullBox
{
#region Constructors
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="IsoMetaBox" /> with a provided header and
/// handler by reading the contents from a specified file.
/// </summary>
/// <param name="header">
/// A <see cref="BoxHeader" /> object containing the header
/// to use for the new instance.
/// </param>
/// <param name="file">
/// A <see cref="TagLib.File" /> object to read the contents
/// of the box from.
/// </param>
/// <param name="handler">
/// A <see cref="IsoHandlerBox" /> object containing the
/// handler that applies to the new instance.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="file" /> is <see langword="null" />.
/// </exception>
public IsoMetaBox (BoxHeader header, TagLib.File file, IsoHandlerBox handler)
: base (header, file, handler)
{
Children = LoadChildren (file);
}
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="IsoMetaBox" /> with a specified handler.
/// </summary>
/// <param name="handlerType">
/// A <see cref="ByteVector" /> object specifying a 4 byte
/// handler type.
/// </param>
/// <param name="handlerName">
/// A <see cref="string" /> object specifying the handler
/// name.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="handlerType" /> is <see langword="null"
/// />.
/// </exception>
/// <exception cref="ArgumentException">
/// <paramref name="handlerType" /> is less than 4 bytes
/// long.
/// </exception>
public IsoMetaBox (ByteVector handlerType, string handlerName)
: base ("meta", 0, 0)
{
if (handlerType == null)
throw new ArgumentNullException (nameof (handlerType));
if (handlerType.Count < 4)
throw new ArgumentException ("The handler type must be four bytes long.", nameof (handlerType));
Children = new List<Box> ();
AddChild (new IsoHandlerBox (handlerType, handlerName));
}
#endregion
#region Public Properties
/// <summary>
/// Gets the children of the current instance.
/// </summary>
/// <value>
/// A <see cref="T:System.Collections.Generic.IEnumerable`1" /> object enumerating the
/// children of the current instance.
/// </value>
public override IEnumerable<Box> Children { get; }
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 44fce7ebbf90e84a8931eb530441db21
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,238 @@
//
// IsoMovieHeaderBox.cs: Provides an implementation of a ISO/IEC 14496-12
// MovieHeaderBox.
//
// Author:
// Brian Nickel (brian.nickel@gmail.com)
//
// Copyright (C) 2006-2007 Brian Nickel
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License version
// 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
//
using System;
namespace TagLib.Mpeg4
{
/// <summary>
/// This class extends <see cref="FullBox" /> to provide an
/// implementation of a ISO/IEC 14496-12 MovieHeaderBox.
/// </summary>
public class IsoMovieHeaderBox : FullBox
{
#region Private Fields
/// <summary>
/// Contains the creation time of the movie.
/// </summary>
readonly ulong creation_time;
/// <summary>
/// Contains the modification time of the movie.
/// </summary>
readonly ulong modification_time;
/// <summary>
/// Contains the timescale.
/// </summary>
readonly uint timescale;
/// <summary>
/// Contains the duration.
/// </summary>
readonly ulong duration;
/// <summary>
/// Contains the rate.
/// </summary>
readonly uint rate;
/// <summary>
/// Contains the volume.
/// </summary>
readonly ushort volume;
#endregion
#region Constructors
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="IsoMovieHeaderBox" /> with a provided header and
/// handler by reading the contents from a specified file.
/// </summary>
/// <param name="header">
/// A <see cref="BoxHeader" /> object containing the header
/// to use for the new instance.
/// </param>
/// <param name="file">
/// A <see cref="TagLib.File" /> object to read the contents
/// of the box from.
/// </param>
/// <param name="handler">
/// A <see cref="IsoHandlerBox" /> object containing the
/// handler that applies to the new instance.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="file" /> is <see langword="null" />.
/// </exception>
public IsoMovieHeaderBox (BoxHeader header, TagLib.File file, IsoHandlerBox handler)
: base (header, file, handler)
{
if (file == null)
throw new ArgumentNullException (nameof (file));
int bytes_remaining = DataSize;
ByteVector data;
if (Version == 1) {
// Read version one (large integers).
data = file.ReadBlock (Math.Min (28,
bytes_remaining));
if (data.Count >= 8)
creation_time = data.Mid (0,
8).ToULong ();
if (data.Count >= 16)
modification_time = data.Mid (8,
8).ToULong ();
if (data.Count >= 20)
timescale = data.Mid (16, 4).ToUInt ();
if (data.Count >= 28)
duration = data.Mid (20, 8).ToULong ();
bytes_remaining -= 28;
} else {
// Read version zero (normal integers).
data = file.ReadBlock (Math.Min (16,
bytes_remaining));
if (data.Count >= 4)
creation_time = data.Mid (0,
4).ToUInt ();
if (data.Count >= 8)
modification_time = data.Mid (4,
4).ToUInt ();
if (data.Count >= 12)
timescale = data.Mid (8, 4).ToUInt ();
if (data.Count >= 16)
duration = data.Mid (12, 4).ToUInt ();
bytes_remaining -= 16;
}
data = file.ReadBlock (Math.Min (6, bytes_remaining));
if (data.Count >= 4)
rate = data.Mid (0, 4).ToUInt ();
if (data.Count >= 6)
volume = data.Mid (4, 2).ToUShort ();
file.Seek (file.Tell + 70);
bytes_remaining -= 76;
data = file.ReadBlock (Math.Min (4,
bytes_remaining));
if (data.Count >= 4)
NextTrackId = data.Mid (0, 4).ToUInt ();
}
#endregion
#region Public Properties
/// <summary>
/// Gets the creation time of movie represented by the
/// current instance.
/// </summary>
/// <value>
/// A <see cref="DateTime" /> value containing the creation
/// time of the movie represented by the current instance.
/// </value>
public DateTime CreationTime {
get {
return new DateTime (1904, 1, 1, 0, 0,
0).AddTicks ((long)(10000000 * creation_time));
}
}
/// <summary>
/// Gets the modification time of movie represented by the
/// current instance.
/// </summary>
/// <value>
/// A <see cref="DateTime" /> value containing the
/// modification time of the movie represented by the current
/// instance.
/// </value>
public DateTime ModificationTime {
get {
return new DateTime (1904, 1, 1, 0, 0,
0).AddTicks ((long)(10000000 * modification_time));
}
}
/// <summary>
/// Gets the duration of the movie represented by the current
/// instance.
/// </summary>
/// <value>
/// A <see cref="TimeSpan" /> value containing the duration
/// of the movie represented by the current instance.
/// </value>
public TimeSpan Duration {
get {
// The length is the number of ticks divided by
// ticks per second.
return TimeSpan.FromSeconds (duration / (double)timescale);
}
}
/// <summary>
/// Gets the playback rate of the movie represented by the
/// current instance.
/// </summary>
/// <value>
/// A <see cref="double" /> value containing the playback
/// rate of the movie represented by the current instance.
/// </value>
public double Rate {
get { return rate / ((double)0x10000); }
}
/// <summary>
/// Gets the playback volume of the movie represented by the
/// current instance.
/// </summary>
/// <value>
/// A <see cref="double" /> value containing the playback
/// volume of the movie represented by the current instance.
/// </value>
public double Volume {
get { return volume / ((double)0x100); }
}
/// <summary>
/// Gets the ID of the next track in the movie represented by
/// the current instance.
/// </summary>
/// <value>
/// A <see cref="uint" /> value containing the ID of the next
/// track in the movie represented by the current instance.
/// </value>
public uint NextTrackId { get; }
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cbdf1fa58c6e4ee8f90050b4ba200e1b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,109 @@
//
// IsoSampleDescriptionBox.cs: Provides an implementation of a ISO/IEC 14496-12
// SampleDescriptionBox.
//
// Author:
// Brian Nickel (brian.nickel@gmail.com)
//
// Copyright (C) 2006-2007 Brian Nickel
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License version
// 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
//
using System;
using System.Collections.Generic;
namespace TagLib.Mpeg4
{
/// <summary>
/// This class extends <see cref="FullBox" /> to provide an
/// implementation of a ISO/IEC 14496-12 SampleDescriptionBox.
/// </summary>
public class IsoSampleDescriptionBox : FullBox
{
#region Constructors
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="IsoSampleDescriptionBox" /> with a provided header
/// and handler by reading the contents from a specified
/// file.
/// </summary>
/// <param name="header">
/// A <see cref="BoxHeader" /> object containing the header
/// to use for the new instance.
/// </param>
/// <param name="file">
/// A <see cref="TagLib.File" /> object to read the contents
/// of the box from.
/// </param>
/// <param name="handler">
/// A <see cref="IsoHandlerBox" /> object containing the
/// handler that applies to the new instance.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="file" /> is <see langword="null" />.
/// </exception>
public IsoSampleDescriptionBox (BoxHeader header, TagLib.File file, IsoHandlerBox handler)
: base (header, file, handler)
{
if (file == null)
throw new ArgumentNullException (nameof (file));
EntryCount = file.ReadBlock (4).ToUInt ();
Children = LoadChildren (file);
}
#endregion
#region Public Properties
/// <summary>
/// Gets the position of the data contained in the current
/// instance, after any box specific headers.
/// </summary>
/// <value>
/// A <see cref="long" /> value containing the position of
/// the data contained in the current instance.
/// </value>
protected override long DataPosition {
get { return base.DataPosition + 4; }
}
/// <summary>
/// Gets the number of boxes at the begining of the children
/// that will be stored as <see cref="IsoAudioSampleEntry" />
/// of <see cref="IsoVisualSampleEntry" /> objects, depending
/// on the handler.
/// </summary>
/// <value>
/// A <see cref="uint" /> value containing the number of
/// children that will appear as sample entries.
/// </value>
public uint EntryCount { get; }
/// <summary>
/// Gets the children of the current instance.
/// </summary>
/// <value>
/// A <see cref="T:System.Collections.Generic.IEnumerable`1" /> object enumerating the
/// children of the current instance.
/// </value>
public override IEnumerable<Box> Children { get; }
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 63519246ddd625dc09d803ea727347f1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,96 @@
//
// IsoSampleEntry.cs: Provides an implementation of a ISO/IEC 14496-12
// SampleEntry.
//
// Author:
// Brian Nickel (brian.nickel@gmail.com)
//
// Copyright (C) 2006-2007 Brian Nickel
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License version
// 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
//
using System;
namespace TagLib.Mpeg4
{
/// <summary>
/// This class extends <see cref="Box" /> to provide an
/// implementation of a ISO/IEC 14496-12 SampleEntry.
/// </summary>
public class IsoSampleEntry : Box
{
#region Constructors
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="IsoSampleEntry" /> with a provided header and
/// handler by reading the contents from a specified file.
/// </summary>
/// <param name="header">
/// A <see cref="BoxHeader" /> object containing the header
/// to use for the new instance.
/// </param>
/// <param name="file">
/// A <see cref="TagLib.File" /> object to read the contents
/// of the box from.
/// </param>
/// <param name="handler">
/// A <see cref="IsoHandlerBox" /> object containing the
/// handler that applies to the new instance.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="file" /> is <see langword="null" />.
/// </exception>
public IsoSampleEntry (BoxHeader header, TagLib.File file, IsoHandlerBox handler)
: base (header, handler)
{
if (file == null)
throw new ArgumentNullException (nameof (file));
file.Seek (base.DataPosition + 6);
DataReferenceIndex = file.ReadBlock (2).ToUShort ();
}
#endregion
#region Public Properties
/// <summary>
/// Gets the position of the data contained in the current
/// instance, after any box specific headers.
/// </summary>
/// <value>
/// A <see cref="long" /> value containing the position of
/// the data contained in the current instance.
/// </value>
protected override long DataPosition {
get { return base.DataPosition + 8; }
}
/// <summary>
/// Gets the data reference index of the current instance.
/// </summary>
/// <value>
/// A <see cref="ushort" /> value containing the data
/// reference index of the current instance.
/// </value>
public ushort DataReferenceIndex { get; private set; }
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a5118d3397eaabd6396f8c7420c3bb9f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,90 @@
//
// IsoSampleTableBox.cs: Provides an implementation of a ISO/IEC 14496-12
// SampleTableBox.
//
// Author:
// Brian Nickel (brian.nickel@gmail.com)
//
// Copyright (C) 2006-2007 Brian Nickel
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License version
// 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
//
using System;
using System.Collections.Generic;
namespace TagLib.Mpeg4
{
/// <summary>
/// This class extends <see cref="Box" /> to provide an
/// implementation of a ISO/IEC 14496-12 SampleTableBox.
/// </summary>
public class IsoSampleTableBox : Box
{
#region Private Fields
#endregion
#region Constructors
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="IsoSampleTableBox" /> with a provided header and
/// handler by reading the contents from a specified file.
/// </summary>
/// <param name="header">
/// A <see cref="BoxHeader" /> object containing the header
/// to use for the new instance.
/// </param>
/// <param name="file">
/// A <see cref="TagLib.File" /> object to read the contents
/// of the box from.
/// </param>
/// <param name="handler">
/// A <see cref="IsoHandlerBox" /> object containing the
/// handler that applies to the new instance.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="file" /> is <see langword="null" />.
/// </exception>
public IsoSampleTableBox (BoxHeader header, TagLib.File file, IsoHandlerBox handler)
: base (header, handler)
{
if (file == null)
throw new ArgumentNullException (nameof (file));
Children = LoadChildren (file);
}
#endregion
#region Public Properties
/// <summary>
/// Gets the children of the current instance.
/// </summary>
/// <value>
/// A <see cref="T:System.Collections.Generic.IEnumerable`1" /> object enumerating the
/// children of the current instance.
/// </value>
public override IEnumerable<Box> Children { get; }
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ea0ba1a02fe1b62b2881512be697e629
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,105 @@
//
// IsoUserDataBox.cs: Provides an implementation of a ISO/IEC 14496-12
// UserDataBox.
//
// Author:
// Brian Nickel (brian.nickel@gmail.com)
//
// Copyright (C) 2006-2007 Brian Nickel
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License version
// 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
//
using System;
using System.Collections.Generic;
namespace TagLib.Mpeg4
{
/// <summary>
/// This class extends <see cref="Box" /> to provide an
/// implementation of a ISO/IEC 14496-12 UserDataBox.
/// </summary>
public class IsoUserDataBox : Box
{
#region Constructors
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="IsoUserDataBox" /> with a provided header and
/// handler by reading the contents from a specified file.
/// </summary>
/// <param name="header">
/// A <see cref="BoxHeader" /> object containing the header
/// to use for the new instance.
/// </param>
/// <param name="file">
/// A <see cref="TagLib.File" /> object to read the contents
/// of the box from.
/// </param>
/// <param name="handler">
/// A <see cref="IsoHandlerBox" /> object containing the
/// handler that applies to the new instance.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="file" /> is <see langword="null" />.
/// </exception>
public IsoUserDataBox (BoxHeader header, TagLib.File file, IsoHandlerBox handler)
: base (header, handler)
{
if (file == null)
throw new ArgumentNullException (nameof (file));
Children = LoadChildren (file);
}
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="IsoUserDataBox" /> with no children.
/// </summary>
public IsoUserDataBox () : base ("udta")
{
Children = new List<Box> ();
}
#endregion
#region Public Properties
/// <summary>
/// Gets the children of the current instance.
/// </summary>
/// <value>
/// A <see cref="T:System.Collections.Generic.IEnumerable`1" /> object enumerating the
/// children of the current instance.
/// </value>
public override IEnumerable<Box> Children { get; }
/// <summary>
/// Gets the box headers for the current "<c>udta</c>" box and
/// all parent boxes up to the top of the file.
/// </summary>
/// <value>
/// A <see cref="T:BoxHeader[]" /> containing the headers for
/// the current "<c>udta</c>" box and its parent boxes up to
/// the top of the file, in the order they appear, or <see
/// langword="null" /> if none is present.
/// </value>
public BoxHeader[] ParentTree { get; set; }
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d443e2d449f2857a5b6e79db0ad53dc5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,196 @@
//
// IsoVisualSampleEntry.cs: Provides an implementation of a ISO/IEC 14496-12
// VisualSampleEntry and support for reading MPEG-4 video properties.
//
// Author:
// Brian Nickel (brian.nickel@gmail.com)
//
// Copyright (C) 2006-2007 Brian Nickel
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License version
// 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
//
using System;
using System.Globalization;
namespace TagLib.Mpeg4
{
/// <summary>
/// This class extends <see cref="IsoSampleEntry" /> and implements
/// <see cref="IVideoCodec" /> to provide an implementation of a
/// ISO/IEC 14496-12 VisualSampleEntry and support for reading MPEG-4
/// video properties.
/// </summary>
public class IsoVisualSampleEntry : IsoSampleEntry, IVideoCodec
{
#region Private Fields
/// <summary>
/// Contains the width of the visual.
/// </summary>
readonly ushort width;
/// <summary>
/// Contains the height of the visual.
/// </summary>
readonly ushort height;
/*
/// <summary>
/// Contains the children of the box.
/// </summary>
private BoxList children;
*/
#endregion
#region Constructors
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="IsoVisualSampleEntry" /> with a provided header and
/// handler by reading the contents from a specified file.
/// </summary>
/// <param name="header">
/// A <see cref="BoxHeader" /> object containing the header
/// to use for the new instance.
/// </param>
/// <param name="file">
/// A <see cref="TagLib.File" /> object to read the contents
/// of the box from.
/// </param>
/// <param name="handler">
/// A <see cref="IsoHandlerBox" /> object containing the
/// handler that applies to the new instance.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="file" /> is <see langword="null" />.
/// </exception>
public IsoVisualSampleEntry (BoxHeader header, TagLib.File file,
IsoHandlerBox handler)
: base (header, file, handler)
{
file.Seek (base.DataPosition + 16);
width = file.ReadBlock (2).ToUShort ();
height = file.ReadBlock (2).ToUShort ();
/*
TODO: What are the children anyway?
children = LoadChildren (file);
*/
}
#endregion
#region Public Properties
/// <summary>
/// Gets the position of the data contained in the current
/// instance, after any box specific headers.
/// </summary>
/// <value>
/// A <see cref="long" /> value containing the position of
/// the data contained in the current instance.
/// </value>
protected override long DataPosition {
get { return base.DataPosition + 62; }
}
/*
/// <summary>
/// Gets the children of the current instance.
/// </summary>
/// <value>
/// A <see cref="IEnumerable{T}" /> object enumerating the
/// children of the current instance.
/// </value>
public override BoxList Children {
get {return children;}
}
*/
#endregion
#region IVideoCodec Properties
/// <summary>
/// Gets the duration of the media represented by the current
/// instance.
/// </summary>
/// <value>
/// Always <see cref="TimeSpan.Zero" />.
/// </value>
public TimeSpan Duration {
get { return TimeSpan.Zero; }
}
/// <summary>
/// Gets the types of media represented by the current
/// instance.
/// </summary>
/// <value>
/// Always <see cref="MediaTypes.Video" />.
/// </value>
public MediaTypes MediaTypes {
get { return MediaTypes.Video; }
}
/// <summary>
/// Gets a text description of the media represented by the
/// current instance.
/// </summary>
/// <value>
/// A <see cref="string" /> object containing a description
/// of the media represented by the current instance.
/// </value>
public string Description {
get {
return string.Format (CultureInfo.InvariantCulture, "MPEG-4 Video ({0})", BoxType);
}
}
/// <summary>
/// Gets the width of the video represented by the current
/// instance.
/// </summary>
/// <value>
/// A <see cref="int" /> containing the width of the video
/// represented by the current instance.
/// </value>
public int VideoWidth {
get { return width; }
}
/// <summary>
/// Gets the height of the video represented by the current
/// instance.
/// </summary>
/// <value>
/// A <see cref="int" /> containing the height of the video
/// represented by the current instance.
/// </value>
public int VideoHeight {
get { return height; }
}
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b2683606c312126038bc7840ea8af72c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,96 @@
//
// TextBox.cs
//
// Author:
// Alan McGovern <alan.mcgovern@gmail.com>
//
// Copyright (c) 2012 Alan McGovern
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
using System;
using TagLib.Mpeg4;
namespace TagLib
{
/// <summary>
/// Represent an MP4 text box
/// </summary>
public class TextBox : Box
{
#region Private Fields
/// <summary>
/// Contains the box's data.
/// </summary>
ByteVector data;
#endregion
#region Constructors
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="UnknownBox" /> with a provided header and handler
/// by reading the contents from a specified file.
/// </summary>
/// <param name="header">
/// A <see cref="BoxHeader" /> object containing the header
/// to use for the new instance.
/// </param>
/// <param name="file">
/// A <see cref="TagLib.File" /> object to read the contents
/// of the box from.
/// </param>
/// <param name="handler">
/// A <see cref="IsoHandlerBox" /> object containing the
/// handler that applies to the new instance.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="file" /> is <see langword="null" />.
/// </exception>
public TextBox (BoxHeader header, File file, IsoHandlerBox handler)
: base (header, handler)
{
if (file == null)
throw new ArgumentNullException (nameof (file));
data = LoadData (file);
}
#endregion
#region Public Properties
/// <summary>
/// Gets and sets the box data contained in the current
/// instance.
/// </summary>
/// <value>
/// A <see cref="ByteVector" /> object containing the box
/// data contained in the current instance.
/// </value>
public override ByteVector Data {
get { return data; }
set { data = value; }
}
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 41c315eb322c671bd9ed59b891d2094b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,96 @@
//
// UnknownBox.cs: Provides a simple implementation of a box of unknown type.
//
// Author:
// Brian Nickel (brian.nickel@gmail.com)
//
// Copyright (C) 2006-2007 Brian Nickel
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License version
// 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
//
using System;
namespace TagLib.Mpeg4
{
/// <summary>
/// This class extends <see cref="Box" /> to provide a simple
/// implementation of a box of unknown type.
/// </summary>
public class UnknownBox : Box
{
#region Private Fields
/// <summary>
/// Contains the box's data.
/// </summary>
ByteVector data;
#endregion
#region Constructors
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="UnknownBox" /> with a provided header and handler
/// by reading the contents from a specified file.
/// </summary>
/// <param name="header">
/// A <see cref="BoxHeader" /> object containing the header
/// to use for the new instance.
/// </param>
/// <param name="file">
/// A <see cref="TagLib.File" /> object to read the contents
/// of the box from.
/// </param>
/// <param name="handler">
/// A <see cref="IsoHandlerBox" /> object containing the
/// handler that applies to the new instance.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="file" /> is <see langword="null" />.
/// </exception>
public UnknownBox (BoxHeader header, TagLib.File file, IsoHandlerBox handler) : base (header, handler)
{
if (file == null)
throw new ArgumentNullException (nameof (file));
data = file.ReadBlock (DataSize > 0 ? DataSize : 0);
}
#endregion
#region Public Properties
/// <summary>
/// Gets and sets the box data contained in the current
/// instance.
/// </summary>
/// <value>
/// A <see cref="ByteVector" /> object containing the box
/// data contained in the current instance.
/// </value>
public override ByteVector Data {
get { return data; }
set { data = value; }
}
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3061613889bb6748db8f631a7e1fbf49
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+96
View File
@@ -0,0 +1,96 @@
//
// UrlBox.cs
//
// Author:
// Alan McGovern <alan.mcgovern@gmail.com>
//
// Copyright (c) 2012 Alan McGovern
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
using System;
using TagLib.Mpeg4;
namespace TagLib
{
/// <summary>
/// Represent a MP4 URL box
/// </summary>
public class UrlBox : Box
{
#region Private Fields
/// <summary>
/// Contains the box's data.
/// </summary>
ByteVector data;
#endregion
#region Constructors
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="UnknownBox" /> with a provided header and handler
/// by reading the contents from a specified file.
/// </summary>
/// <param name="header">
/// A <see cref="BoxHeader" /> object containing the header
/// to use for the new instance.
/// </param>
/// <param name="file">
/// A <see cref="TagLib.File" /> object to read the contents
/// of the box from.
/// </param>
/// <param name="handler">
/// A <see cref="IsoHandlerBox" /> object containing the
/// handler that applies to the new instance.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="file" /> is <see langword="null" />.
/// </exception>
public UrlBox (BoxHeader header, File file, IsoHandlerBox handler)
: base (header, handler)
{
if (file == null)
throw new ArgumentNullException (nameof (file));
data = LoadData (file);
}
#endregion
#region Public Properties
/// <summary>
/// Gets and sets the box data contained in the current
/// instance.
/// </summary>
/// <value>
/// A <see cref="ByteVector" /> object containing the box
/// data contained in the current instance.
/// </value>
public override ByteVector Data {
get { return data; }
set { data = value; }
}
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 57b4e67ab7e85f6988b741084a6db2bc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+455
View File
@@ -0,0 +1,455 @@
//
// File.cs: Provides tagging and properties support for MPEG-4 files.
//
// Author:
// Brian Nickel (brian.nickel@gmail.com)
//
// Copyright (C) 2006-2007 Brian Nickel
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License version
// 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
//
using System;
using System.Collections.Generic;
using System.Linq;
namespace TagLib.Mpeg4
{
/// <summary>
/// This class extends <see cref="TagLib.File" /> to provide tagging
/// and properties support for MPEG-4 files.
/// </summary>
[SupportedMimeType ("taglib/m4a", "m4a")]
[SupportedMimeType ("taglib/m4b", "m4b")]
[SupportedMimeType ("taglib/m4v", "m4v")]
[SupportedMimeType ("taglib/m4p", "m4p")]
[SupportedMimeType ("taglib/mp4", "mp4")]
[SupportedMimeType ("audio/mp4")]
[SupportedMimeType ("audio/x-m4a")]
[SupportedMimeType ("video/mp4")]
[SupportedMimeType ("video/x-m4v")]
public class File : TagLib.File
{
#region Private Fields
/// <summary>
/// Contains the Apple tag.
/// </summary>
AppleTag apple_tag;
/// <summary>
/// Contains the combined tag.
/// </summary>
/// <remarks>
/// TODO: Add support for ID3v2 tags.
/// </remarks>
CombinedTag tag;
/// <summary>
/// Contains the media properties.
/// </summary>
Properties properties;
#endregion
#region Constructors
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="File" /> for a specified path in the local file
/// system and specified read style.
/// </summary>
/// <param name="path">
/// A <see cref="string" /> object containing the path of the
/// file to use in the new instance.
/// </param>
/// <param name="propertiesStyle">
/// A <see cref="ReadStyle" /> value specifying at what level
/// of accuracy to read the media properties, or <see
/// cref="ReadStyle.None" /> to ignore the properties.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="path" /> is <see langword="null" />.
/// </exception>
public File (string path, ReadStyle propertiesStyle)
: base (path)
{
Read (propertiesStyle);
}
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="File" /> for a specified path in the local file
/// system with an average read style.
/// </summary>
/// <param name="path">
/// A <see cref="string" /> object containing the path of the
/// file to use in the new instance.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="path" /> is <see langword="null" />.
/// </exception>
public File (string path)
: this (path, ReadStyle.Average)
{
}
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="File" /> for a specified file abstraction and
/// specified read style.
/// </summary>
/// <param name="abstraction">
/// A <see cref="TagLib.File.IFileAbstraction" /> object to use when
/// reading from and writing to the file.
/// </param>
/// <param name="propertiesStyle">
/// A <see cref="ReadStyle" /> value specifying at what level
/// of accuracy to read the media properties, or <see
/// cref="ReadStyle.None" /> to ignore the properties.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="abstraction" /> is <see langword="null"
/// />.
/// </exception>
public File (IFileAbstraction abstraction, ReadStyle propertiesStyle)
: base (abstraction)
{
Read (propertiesStyle);
}
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="File" /> for a specified file abstraction with an
/// average read style.
/// </summary>
/// <param name="abstraction">
/// A <see cref="TagLib.File.IFileAbstraction" /> object to use when
/// reading from and writing to the file.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="abstraction" /> is <see langword="null"
/// />.
/// </exception>
public File (IFileAbstraction abstraction)
: this (abstraction, ReadStyle.Average)
{
}
#endregion
#region Public Properties
/// <summary>
/// Gets a abstract representation of all tags stored in the
/// current instance.
/// </summary>
/// <value>
/// A <see cref="TagLib.Tag" /> object representing all tags
/// stored in the current instance.
/// </value>
public override Tag Tag {
get { return tag; }
}
/// <summary>
/// Gets the media properties of the file represented by the
/// current instance.
/// </summary>
/// <value>
/// A <see cref="TagLib.Properties" /> object containing the
/// media properties of the file represented by the current
/// instance.
/// </value>
public override Properties Properties {
get { return properties; }
}
/// <summary>
/// Get the UDTA Boxes
/// </summary>
protected List<IsoUserDataBox> UdtaBoxes { get; } = new List<IsoUserDataBox> ();
#endregion
#region Public Methods
/// <summary>
/// Saves the changes made in the current instance to the
/// file it represents.
/// </summary>
public override void Save ()
{
// Boilerplate
PreSave ();
if (UdtaBoxes.Count == 0) {
var udtaBox = new IsoUserDataBox ();
UdtaBoxes.Add (udtaBox);
}
// Try to get into write mode.
Mode = AccessMode.Write;
try {
var parser = new FileParser (this);
parser.ParseBoxHeaders ();
InvariantStartPosition = parser.MdatStartPosition;
InvariantEndPosition = parser.MdatEndPosition;
long size_change = 0;
long write_position = 0;
// To avoid rewriting udta blocks which might not have been modified,
// the code here will work correctly if:
// 1. There is a single udta for the entire file
// - OR -
// 2. There are multiple utdtas, but only 1 of them contains the Apple ILST box.
// We should be OK in the vast majority of cases
IsoUserDataBox udtaBox = FindAppleTagUdta ();
if (null == udtaBox)
udtaBox = new IsoUserDataBox ();
ByteVector tag_data = udtaBox.Render ();
// If we don't have a "udta" box to overwrite...
if (udtaBox.ParentTree == null ||
udtaBox.ParentTree.Length == 0) {
// Stick the box at the end of the moov box.
BoxHeader moov_header = parser.MoovTree[parser.MoovTree.Length - 1];
size_change = tag_data.Count;
write_position = moov_header.Position + moov_header.TotalBoxSize;
Insert (tag_data, write_position, 0);
// Overwrite the parent box sizes.
for (int i = parser.MoovTree.Length - 1; i >= 0; i--)
size_change = parser.MoovTree[i].Overwrite (this, size_change);
} else {
// Overwrite the old box.
BoxHeader udta_header = udtaBox.ParentTree[udtaBox.ParentTree.Length - 1];
size_change = tag_data.Count - udta_header.TotalBoxSize;
write_position = udta_header.Position;
Insert (tag_data, write_position, udta_header.TotalBoxSize);
// Overwrite the parent box sizes.
for (int i = udtaBox.ParentTree.Length - 2; i >= 0; i--)
size_change = udtaBox.ParentTree[i].Overwrite (this, size_change);
}
// If we've had a size change, we may need to adjust
// chunk offsets.
if (size_change != 0) {
// We may have moved the offset boxes, so we
// need to reread.
parser.ParseChunkOffsets ();
InvariantStartPosition = parser.MdatStartPosition;
InvariantEndPosition = parser.MdatEndPosition;
foreach (Box box in parser.ChunkOffsetBoxes) {
if (box is IsoChunkLargeOffsetBox co64) {
co64.Overwrite (this, size_change, write_position);
continue;
}
if (box is IsoChunkOffsetBox stco) {
stco.Overwrite (this, size_change, write_position);
continue;
}
}
}
TagTypesOnDisk = TagTypes;
} finally {
Mode = AccessMode.Closed;
}
}
/// <summary>
/// Gets a tag of a specified type from the current instance,
/// optionally creating a new tag if possible.
/// </summary>
/// <param name="type">
/// A <see cref="TagLib.TagTypes" /> value indicating the
/// type of tag to read.
/// </param>
/// <param name="create">
/// A <see cref="bool" /> value specifying whether or not to
/// try and create the tag if one is not found.
/// </param>
/// <returns>
/// A <see cref="Tag" /> object containing the tag that was
/// found in or added to the current instance. If no
/// matching tag was found and none was created, <see
/// langword="null" /> is returned.
/// </returns>
/// <remarks>
/// At the time of this writing, only <see cref="AppleTag" />
/// is supported. All other tag types will be ignored.
/// </remarks>
public override Tag GetTag (TagTypes type, bool create)
{
if (type == TagTypes.Apple) {
if (apple_tag == null && create) {
IsoUserDataBox udtaBox = FindAppleTagUdta ();
if (null == udtaBox) {
udtaBox = new IsoUserDataBox ();
}
apple_tag = new AppleTag (udtaBox);
tag.SetTags (apple_tag);
}
return apple_tag;
}
return null;
}
/// <summary>
/// Removes a set of tag types from the current instance.
/// </summary>
/// <param name="types">
/// A bitwise combined <see cref="TagLib.TagTypes" /> value
/// containing tag types to be removed from the file.
/// </param>
/// <remarks>
/// In order to remove all tags from a file, pass <see
/// cref="TagTypes.AllTags" /> as <paramref name="types" />.
/// </remarks>
public override void RemoveTags (TagTypes types)
{
if ((types & TagTypes.Apple) != TagTypes.Apple || apple_tag == null)
return;
apple_tag.DetachIlst ();
apple_tag = null;
tag.SetTags ();
}
#endregion
#region Private Methods
/// <summary>
/// Reads the file with a specified read style.
/// </summary>
/// <param name="propertiesStyle">
/// A <see cref="ReadStyle" /> value specifying at what level
/// of accuracy to read the media properties, or <see
/// cref="ReadStyle.None" /> to ignore the properties.
/// </param>
void Read (ReadStyle propertiesStyle)
{
// TODO: Support Id3v2 boxes!!!
tag = new CombinedTag ();
Mode = AccessMode.Read;
try {
var parser = new FileParser (this);
if ((propertiesStyle & ReadStyle.Average) == 0)
parser.ParseTag ();
else
parser.ParseTagAndProperties ();
InvariantStartPosition = parser.MdatStartPosition;
InvariantEndPosition = parser.MdatEndPosition;
UdtaBoxes.AddRange (parser.UserDataBoxes);
// Ensure our collection contains at least a single empty box
if (UdtaBoxes.Count == 0) {
var dummy = new IsoUserDataBox ();
UdtaBoxes.Add (dummy);
}
// Check if a udta with ILST actually exists
if (IsAppleTagUdtaPresent ())
TagTypesOnDisk |= TagTypes.Apple; //There is an udta present with ILST info
// Find the udta box with the Apple Tag ILST
IsoUserDataBox udtaBox = FindAppleTagUdta ();
if (null == udtaBox) {
udtaBox = new IsoUserDataBox ();
}
apple_tag = new AppleTag (udtaBox);
tag.SetTags (apple_tag);
// If we're not reading properties, we're done.
if ((propertiesStyle & ReadStyle.Average) == 0) {
Mode = AccessMode.Closed;
return;
}
// Get the movie header box.
var mvhd_box = parser.MovieHeaderBox;
if (mvhd_box == null) {
Mode = AccessMode.Closed;
throw new CorruptFileException ("mvhd box not found.");
}
var audio_sample_entry = parser.AudioSampleEntry;
var visual_sample_entry = parser.VisualSampleEntry;
// Read the properties.
properties = new Properties (mvhd_box.Duration, audio_sample_entry, visual_sample_entry);
} finally {
Mode = AccessMode.Closed;
}
}
/// <summary>
/// Find the udta box within our collection that contains the Apple ILST data.
/// </summary>
/// <remarks>
/// If there is a single udta in a file, we return that.
/// If there are multiple udtas, we search for the one that contains the ILST box.
/// </remarks>
IsoUserDataBox FindAppleTagUdta ()
{
if (UdtaBoxes.Count == 1)
return UdtaBoxes[0]; //Single udta - just return it
// multiple udta : pick out the shallowest node which has an ILst tag
var udtaBox = UdtaBoxes
.Where (box => box.GetChildRecursively (BoxType.Ilst) != null)
.OrderBy (box => box.ParentTree.Length)
.FirstOrDefault ();
return udtaBox;
}
/// <summary>
/// Returns true if there is a udta with ILST present in our collection
/// </summary>
bool IsAppleTagUdtaPresent ()
{
foreach (var udtaBox in UdtaBoxes) {
if (udtaBox.GetChild (BoxType.Meta) != null && udtaBox.GetChild (BoxType.Meta).GetChild (BoxType.Ilst) != null)
return true;
}
return false;
}
#endregion
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 94a393d23a72f232488c3771e55ef837
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+606
View File
@@ -0,0 +1,606 @@
//
// FileParser.cs: Provides methods for reading important information from an
// MPEG-4 file.
//
// Author:
// Brian Nickel (brian.nickel@gmail.com)
//
// Copyright (C) 2006-2007 Brian Nickel
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License version
// 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
//
using System;
using System.Collections.Generic;
namespace TagLib.Mpeg4
{
/// <summary>
/// This class provides methods for reading important information
/// from an MPEG-4 file.
/// </summary>
public class FileParser
{
#region Private Fields
/// <summary>
/// Contains the file to read from.
/// </summary>
readonly TagLib.File file;
/// <summary>
/// Contains the first header found in the file.
/// </summary>
readonly BoxHeader first_header;
/// <summary>
/// Contains the ISO movie header box.
/// </summary>
IsoMovieHeaderBox mvhd_box;
/// <summary>
/// Contains the ISO user data boxes.
/// </summary>
readonly List<IsoUserDataBox> udta_boxes = new List<IsoUserDataBox> ();
/// <summary>
/// Contains the box headers from the top of the file to the
/// "moov" box.
/// </summary>
BoxHeader[] moov_tree;
/// <summary>
/// Contains the box headers from the top of the file to the
/// "udta" box.
/// </summary>
BoxHeader[] udta_tree;
/// <summary>
/// Contains the "stco" boxes found in the file.
/// </summary>
readonly List<Box> stco_boxes = new List<Box> ();
/// <summary>
/// Contains the "stsd" boxes found in the file.
/// </summary>
readonly List<Box> stsd_boxes = new List<Box> ();
/// <summary>
/// Contains the position at which the "mdat" box starts.
/// </summary>
long mdat_start = -1;
/// <summary>
/// Contains the position at which the "mdat" box ends.
/// </summary>
long mdat_end = -1;
#endregion
#region Constructors
/// <summary>
/// Constructs and initializes a new instance of <see
/// cref="FileParser" /> for a specified file.
/// </summary>
/// <param name="file">
/// A <see cref="TagLib.File" /> object to perform operations
/// on.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="file" /> is <see langword="null" />.
/// </exception>
/// <exception cref="CorruptFileException">
/// <paramref name="file" /> does not start with a
/// "<c>ftyp</c>" box.
/// </exception>
public FileParser (TagLib.File file)
{
if (file == null)
throw new ArgumentNullException (nameof (file));
this.file = file;
first_header = new BoxHeader (file, 0);
if (first_header.BoxType != "ftyp")
throw new CorruptFileException ("File does not start with 'ftyp' box.");
}
#endregion
#region Public Properties
/// <summary>
/// Gets the movie header box read by the current instance.
/// </summary>
/// <value>
/// A <see cref="IsoMovieHeaderBox" /> object read by the
/// current instance, or <see langword="null" /> if not found.
/// </value>
/// <remarks>
/// This value will only be set by calling <see
/// cref="ParseTagAndProperties()" />.
/// </remarks>
public IsoMovieHeaderBox MovieHeaderBox {
get { return mvhd_box; }
}
/// <summary>
/// Gets all user data boxes read by the current instance.
/// </summary>
/// <value>
/// A <see cref="IsoUserDataBox" /> array read by the
/// current instance.
/// </value>
/// <remarks>
/// This value will only be set by calling <see
/// cref="ParseTag()" /> and <see
/// cref="ParseTagAndProperties()" />.
/// </remarks>
public IsoUserDataBox[] UserDataBoxes {
get { return udta_boxes.ToArray (); }
}
/// <summary>
/// Get the User Data Box
/// </summary>
public IsoUserDataBox UserDataBox {
get { return UserDataBoxes.Length == 0 ? null : UserDataBoxes[0]; }
}
/// <summary>
/// Gets the audio sample entry read by the current instance.
/// </summary>
/// <value>
/// A <see cref="IsoAudioSampleEntry" /> object read by the
/// current instance, or <see langword="null" /> if not found.
/// </value>
/// <remarks>
/// This value will only be set by calling <see
/// cref="ParseTagAndProperties()" />.
/// </remarks>
public IsoAudioSampleEntry AudioSampleEntry {
get {
foreach (IsoSampleDescriptionBox box in stsd_boxes)
foreach (Box sub in box.Children) {
if (sub is IsoAudioSampleEntry entry)
return entry;
}
return null;
}
}
/// <summary>
/// Gets the visual sample entry read by the current
/// instance.
/// </summary>
/// <value>
/// A <see cref="IsoVisualSampleEntry" /> object read by the
/// current instance, or <see langword="null" /> if not found.
/// </value>
/// <remarks>
/// This value will only be set by calling <see
/// cref="ParseTagAndProperties()" />.
/// </remarks>
public IsoVisualSampleEntry VisualSampleEntry {
get {
foreach (IsoSampleDescriptionBox box in stsd_boxes)
foreach (Box sub in box.Children) {
if (sub is IsoVisualSampleEntry entry)
return entry;
}
return null;
}
}
/// <summary>
/// Gets the box headers for the first "<c>moov</c>" box and
/// all parent boxes up to the top of the file as read by the
/// current instance.
/// </summary>
/// <value>
/// A <see cref="T:BoxHeader[]" /> containing the headers for
/// the first "<c>moov</c>" box and its parent boxes up to
/// the top of the file, in the order they appear, or <see
/// langword="null" /> if none is present.
/// </value>
/// <remarks>
/// This value is useful for overwriting box headers, and is
/// only be set by calling <see cref="ParseBoxHeaders()" />.
/// </remarks>
public BoxHeader[] MoovTree {
get { return moov_tree; }
}
/// <summary>
/// Gets the box headers for the first "<c>udta</c>" box and
/// all parent boxes up to the top of the file as read by the
/// current instance.
/// </summary>
/// <value>
/// A <see cref="T:BoxHeader[]" /> containing the headers for
/// the first "<c>udta</c>" box and its parent boxes up to
/// the top of the file, in the order they appear, or <see
/// langword="null" /> if none is present.
/// </value>
/// <remarks>
/// This value is useful for overwriting box headers, and is
/// only be set by calling <see cref="ParseBoxHeaders()" />.
/// </remarks>
public BoxHeader[] UdtaTree {
get { return udta_tree; }
}
/// <summary>
/// Gets all chunk offset boxes read by the current instance.
/// </summary>
/// <value>
/// A <see cref="T:Box[]" /> containing all chunk offset boxes
/// read by the current instance.
/// </value>
/// <remarks>
/// These boxes contain offset information for media data in
/// the current instance and can be devalidated by size
/// change operations, in which case they need to be
/// corrected. This value will only be set by calling <see
/// cref="ParseChunkOffsets()" />.
/// </remarks>
public Box[] ChunkOffsetBoxes {
get { return stco_boxes.ToArray (); }
}
/// <summary>
/// Gets the position at which the "<c>mdat</c>" box starts.
/// </summary>
/// <value>
/// A <see cref="long" /> value containing the seek position
/// at which the "<c>mdat</c>" box starts.
/// </value>
/// <remarks>
/// The "<c>mdat</c>" box contains the media data for the
/// file and is used for estimating the invariant data
/// portion of the file.
/// </remarks>
public long MdatStartPosition {
get { return mdat_start; }
}
/// <summary>
/// Gets the position at which the "<c>mdat</c>" box ends.
/// </summary>
/// <value>
/// A <see cref="long" /> value containing the seek position
/// at which the "<c>mdat</c>" box ends.
/// </value>
/// <remarks>
/// The "<c>mdat</c>" box contains the media data for the
/// file and is used for estimating the invariant data
/// portion of the file.
/// </remarks>
public long MdatEndPosition {
get { return mdat_end; }
}
#endregion
#region Public Methods
/// <summary>
/// Parses the file referenced by the current instance,
/// searching for box headers that will be useful in saving
/// the file.
/// </summary>
public void ParseBoxHeaders ()
{
try {
ResetFields ();
ParseBoxHeaders (first_header.TotalBoxSize, file.Length, null);
} catch (CorruptFileException e) {
file.MarkAsCorrupt (e.Message);
}
}
/// <summary>
/// Parses the file referenced by the current instance,
/// searching for tags.
/// </summary>
public void ParseTag ()
{
try {
ResetFields ();
ParseTag (first_header.TotalBoxSize, file.Length, null);
} catch (CorruptFileException e) {
file.MarkAsCorrupt (e.Message);
}
}
/// <summary>
/// Parses the file referenced by the current instance,
/// searching for tags and properties.
/// </summary>
public void ParseTagAndProperties ()
{
try {
ResetFields ();
ParseTagAndProperties (first_header.TotalBoxSize, file.Length, null, null);
} catch (CorruptFileException e) {
file.MarkAsCorrupt (e.Message);
}
}
/// <summary>
/// Parses the file referenced by the current instance,
/// searching for chunk offset boxes.
/// </summary>
public void ParseChunkOffsets ()
{
try {
ResetFields ();
ParseChunkOffsets (first_header.TotalBoxSize, file.Length);
} catch (CorruptFileException e) {
file.MarkAsCorrupt (e.Message);
}
}
#endregion
#region Private Methods
/// <summary>
/// Parses boxes for a specified range, looking for headers.
/// </summary>
/// <param name="start">
/// A <see cref="long" /> value specifying the seek position
/// at which to start reading.
/// </param>
/// <param name="end">
/// A <see cref="long" /> value specifying the seek position
/// at which to stop reading.
/// </param>
/// <param name="parents">
/// A <see cref="T:System.Collections.Generic.List`1" /> object containing all the parent
/// handlers that apply to the range.
/// </param>
void ParseBoxHeaders (long start, long end, List<BoxHeader> parents)
{
BoxHeader header;
for (long position = start; position < end; position += header.TotalBoxSize) {
header = new BoxHeader (file, position);
if (moov_tree == null && header.BoxType == BoxType.Moov) {
List<BoxHeader> new_parents = AddParent (parents, header);
moov_tree = new_parents.ToArray ();
ParseBoxHeaders (header.HeaderSize + position, header.TotalBoxSize + position, new_parents);
} else if (header.BoxType == BoxType.Mdia ||
header.BoxType == BoxType.Minf ||
header.BoxType == BoxType.Stbl ||
header.BoxType == BoxType.Trak) {
ParseBoxHeaders (header.HeaderSize + position, header.TotalBoxSize + position, AddParent (parents, header));
} else if (udta_tree == null &&
header.BoxType == BoxType.Udta) {
// For compatibility, we still store the tree to the first udta
// block. The proper way to get this info is from the individual
// IsoUserDataBox.ParentTree member.
udta_tree = AddParent (parents, header).ToArray ();
} else if (header.BoxType == BoxType.Mdat) {
mdat_start = position;
mdat_end = position + header.TotalBoxSize;
}
if (header.TotalBoxSize == 0)
break;
}
}
/// <summary>
/// Parses boxes for a specified range, looking for tags.
/// </summary>
/// <param name="start">
/// A <see cref="long" /> value specifying the seek position
/// at which to start reading.
/// </param>
/// <param name="end">
/// A <see cref="long" /> value specifying the seek position
/// at which to stop reading.
/// </param>
/// <param name="parents">
/// A <see cref="T:List" /> of <see cref="BoxHeader" /> parents.
/// </param>
void ParseTag (long start, long end, List<BoxHeader> parents)
{
BoxHeader header;
for (long position = start; position < end; position += header.TotalBoxSize) {
header = new BoxHeader (file, position);
if (header.BoxType == BoxType.Moov) {
ParseTag (header.HeaderSize + position, header.TotalBoxSize + position, AddParent (parents, header));
} else if (header.BoxType == BoxType.Mdia ||
header.BoxType == BoxType.Minf ||
header.BoxType == BoxType.Stbl ||
header.BoxType == BoxType.Trak) {
ParseTag (header.HeaderSize + position, header.TotalBoxSize + position, AddParent (parents, header));
} else if (header.BoxType == BoxType.Udta) {
var udtaBox = BoxFactory.CreateBox (file, header) as IsoUserDataBox;
// Since we can have multiple udta boxes, save the parent for each one
List<BoxHeader> new_parents = AddParent (parents, header);
udtaBox.ParentTree = new_parents.ToArray ();
udta_boxes.Add (udtaBox);
} else if (header.BoxType == BoxType.Mdat) {
mdat_start = position;
mdat_end = position + header.TotalBoxSize;
}
if (header.TotalBoxSize == 0)
break;
}
}
/// <summary>
/// Parses boxes for a specified range, looking for tags and
/// properties.
/// </summary>
/// <param name="start">
/// A <see cref="long" /> value specifying the seek position
/// at which to start reading.
/// </param>
/// <param name="end">
/// A <see cref="long" /> value specifying the seek position
/// at which to stop reading.
/// </param>
/// <param name="handler">
/// A <see cref="IsoHandlerBox" /> object that applied to the
/// range being searched.
/// </param>
/// <param name="parents">
/// A <see cref="T:List" /> of <see cref="BoxHeader" /> parents.
/// </param>
void ParseTagAndProperties (long start, long end, IsoHandlerBox handler, List<BoxHeader> parents)
{
BoxHeader header;
for (long position = start; position < end; position += header.TotalBoxSize) {
header = new BoxHeader (file, position);
ByteVector type = header.BoxType;
if (type == BoxType.Moov) {
ParseTagAndProperties (header.HeaderSize + position, header.TotalBoxSize + position, handler, AddParent (parents, header));
} else if (type == BoxType.Mdia ||
type == BoxType.Minf ||
type == BoxType.Stbl ||
type == BoxType.Trak) {
ParseTagAndProperties (header.HeaderSize + position, header.TotalBoxSize + position, handler, AddParent (parents, header));
} else if (type == BoxType.Stsd) {
stsd_boxes.Add (BoxFactory.CreateBox (file, header, handler));
} else if (type == BoxType.Hdlr) {
handler = BoxFactory.CreateBox (file, header, handler) as IsoHandlerBox;
} else if (mvhd_box == null &&
type == BoxType.Mvhd) {
mvhd_box = BoxFactory.CreateBox (file, header, handler) as IsoMovieHeaderBox;
} else if (type == BoxType.Udta) {
var udtaBox = BoxFactory.CreateBox (file, header, handler) as IsoUserDataBox;
// Since we can have multiple udta boxes, save the parent for each one
List<BoxHeader> new_parents = AddParent (parents, header);
udtaBox.ParentTree = new_parents.ToArray ();
udta_boxes.Add (udtaBox);
} else if (type == BoxType.Mdat) {
mdat_start = position;
mdat_end = position + header.TotalBoxSize;
}
if (header.TotalBoxSize == 0)
break;
}
}
/// <summary>
/// Parses boxes for a specified range, looking for chunk
/// offset boxes.
/// </summary>
/// <param name="start">
/// A <see cref="long" /> value specifying the seek position
/// at which to start reading.
/// </param>
/// <param name="end">
/// A <see cref="long" /> value specifying the seek position
/// at which to stop reading.
/// </param>
void ParseChunkOffsets (long start, long end)
{
BoxHeader header;
for (long position = start; position < end; position += header.TotalBoxSize) {
header = new BoxHeader (file, position);
if (header.BoxType == BoxType.Moov) {
ParseChunkOffsets (header.HeaderSize + position, header.TotalBoxSize + position);
} else if (header.BoxType == BoxType.Moov ||
header.BoxType == BoxType.Mdia ||
header.BoxType == BoxType.Minf ||
header.BoxType == BoxType.Stbl ||
header.BoxType == BoxType.Trak) {
ParseChunkOffsets (header.HeaderSize + position, header.TotalBoxSize + position);
} else if (header.BoxType == BoxType.Stco ||
header.BoxType == BoxType.Co64) {
stco_boxes.Add (BoxFactory.CreateBox (file, header));
} else if (header.BoxType == BoxType.Mdat) {
mdat_start = position;
mdat_end = position + header.TotalBoxSize;
}
if (header.TotalBoxSize == 0)
break;
}
}
/// <summary>
/// Resets all internal fields.
/// </summary>
void ResetFields ()
{
mvhd_box = null;
udta_boxes.Clear ();
moov_tree = null;
udta_tree = null;
stco_boxes.Clear ();
stsd_boxes.Clear ();
mdat_start = -1;
mdat_end = -1;
}
#endregion
#region Private Static Methods
/// <summary>
/// Adds a parent to the end of an existing list of parents.
/// </summary>
/// <param name="parents">
/// A <see cref="T:System.Collections.Generic.List`1" /> object containing an existing
/// list of parents.
/// </param>
/// <param name="current">
/// A <see cref="BoxHeader" /> object to add to the list.
/// </param>
/// <returns>
/// A new <see cref="T:System.Collections.Generic.List`1" /> object containing the list
/// of parents, including the added header.
/// </returns>
static List<BoxHeader> AddParent (List<BoxHeader> parents,
BoxHeader current)
{
var boxes = new List<BoxHeader> ();
if (parents != null)
boxes.AddRange (parents);
boxes.Add (current);
return boxes;
}
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4127087987d48cdcdab867448633fd84
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: