aboutsummaryrefslogtreecommitdiffstats
path: root/mvc/qtfaststart
diff options
context:
space:
mode:
Diffstat (limited to 'mvc/qtfaststart')
-rw-r--r--mvc/qtfaststart/__init__.py1
-rw-r--r--mvc/qtfaststart/exceptions.py5
-rwxr-xr-xmvc/qtfaststart/processor.py215
3 files changed, 0 insertions, 221 deletions
diff --git a/mvc/qtfaststart/__init__.py b/mvc/qtfaststart/__init__.py
deleted file mode 100644
index f985b5c..0000000
--- a/mvc/qtfaststart/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-VERSION = "1.6"
diff --git a/mvc/qtfaststart/exceptions.py b/mvc/qtfaststart/exceptions.py
deleted file mode 100644
index f0767e1..0000000
--- a/mvc/qtfaststart/exceptions.py
+++ /dev/null
@@ -1,5 +0,0 @@
-class FastStartException(Exception):
- """
- Raised when something bad happens during processing.
- """
- pass \ No newline at end of file
diff --git a/mvc/qtfaststart/processor.py b/mvc/qtfaststart/processor.py
deleted file mode 100755
index df2a900..0000000
--- a/mvc/qtfaststart/processor.py
+++ /dev/null
@@ -1,215 +0,0 @@
-"""
- The guts that actually do the work. This is available here for the
- 'qtfaststart' script and for your application's direct use.
-"""
-
-import logging
-import os
-import struct
-
-#from StringIO import StringIO
-try:
- from StringIO import StringIO
-except ImportError:
- from io import StringIO
-
-from mvc.qtfaststart.exceptions import FastStartException
-
-CHUNK_SIZE = 8192
-
-log = logging.getLogger("qtfaststart")
-
-# Older versions of Python require this to be defined
-if not hasattr(os, 'SEEK_CUR'):
- os.SEEK_CUR = 1
-
-def read_atom(datastream):
- """
- Read an atom and return a tuple of (size, type) where size is the size
- in bytes (including the 8 bytes already read) and type is a "fourcc"
- like "ftyp" or "moov".
- """
- return struct.unpack(">L4s", datastream.read(8))
-
-
-def get_index(datastream):
- """
- Return an index of top level atoms, their absolute byte-position in the
- file and their size in a list:
-
- index = [
- ("ftyp", 0, 24),
- ("moov", 25, 2658),
- ("free", 2683, 8),
- ...
- ]
-
- The tuple elements will be in the order that they appear in the file.
- """
- index = []
-
- log.debug("Getting index of top level atoms...")
-
- # Read atoms until we catch an error
- while(datastream):
- try:
- skip = 8
- atom_size, atom_type = read_atom(datastream)
- if atom_size == 1:
- atom_size = struct.unpack(">Q", datastream.read(8))[0]
- skip = 16
- log.debug("%s: %s" % (atom_type, atom_size))
- except:
- break
-
- index.append((atom_type, datastream.tell() - skip, atom_size))
-
- if atom_size == 0:
- # Some files may end in mdat with no size set, which generally
- # means to seek to the end of the file. We can just stop indexing
- # as no more entries will be found!
- break
-
- datastream.seek(atom_size - skip, os.SEEK_CUR)
-
- # Make sure the atoms we need exist
- top_level_atoms = set([item[0] for item in index])
- for key in ["moov", "mdat"]:
- if key not in top_level_atoms:
- log.error("%s atom not found, is this a valid MOV/MP4 file?" % key)
- raise FastStartException()
-
- return index
-
-
-def find_atoms(size, datastream):
- """
- This function is a generator that will yield either "stco" or "co64"
- when either atom is found. datastream can be assumed to be 8 bytes
- into the stco or co64 atom when the value is yielded.
-
- It is assumed that datastream will be at the end of the atom after
- the value has been yielded and processed.
-
- size is the number of bytes to the end of the atom in the datastream.
- """
- stop = datastream.tell() + size
-
- while datastream.tell() < stop:
- try:
- atom_size, atom_type = read_atom(datastream)
- except:
- log.exception("Error reading next atom!")
- raise FastStartException()
-
- if atom_type in ["trak", "mdia", "minf", "stbl"]:
- # Known ancestor atom of stco or co64, search within it!
- for atype in find_atoms(atom_size - 8, datastream):
- yield atype
- elif atom_type in ["stco", "co64"]:
- yield atom_type
- else:
- # Ignore this atom, seek to the end of it.
- datastream.seek(atom_size - 8, os.SEEK_CUR)
-
-
-def process(infilename, outfilename, limit=0):
- """
- Convert a Quicktime/MP4 file for streaming by moving the metadata to
- the front of the file. This method writes a new file.
-
- If limit is set to something other than zero it will be used as the
- number of bytes to write of the atoms following the moov atom. This
- is very useful to create a small sample of a file with full headers,
- which can then be used in bug reports and such.
- """
- datastream = open(infilename, "rb")
-
- # Get the top level atom index
- index = get_index(datastream)
-
- mdat_pos = 999999
- free_size = 0
-
- # Make sure moov occurs AFTER mdat, otherwise no need to run!
- for atom, pos, size in index:
- # The atoms are guaranteed to exist from get_index above!
- if atom == "moov":
- moov_pos = pos
- moov_size = size
- elif atom == "mdat":
- mdat_pos = pos
- elif atom == "free" and pos < mdat_pos:
- # This free atom is before the mdat!
- free_size += size
- log.info("Removing free atom at %d (%d bytes)" % (pos, size))
-
- # Offset to shift positions
- offset = moov_size - free_size
-
- if moov_pos < mdat_pos:
- # moov appears to be in the proper place, don't shift by moov size
- offset -= moov_size
- if not free_size:
- # No free atoms and moov is correct, we are done!
- log.error("This file appears to already be setup for streaming!")
- raise FastStartException()
-
- # Read and fix moov
- datastream.seek(moov_pos)
- moov = StringIO(datastream.read(moov_size))
-
- # Ignore moov identifier and size, start reading children
- moov.seek(8)
-
- for atom_type in find_atoms(moov_size - 8, moov):
- # Read either 32-bit or 64-bit offsets
- ctype, csize = atom_type == "stco" and ("L", 4) or ("Q", 8)
-
- # Get number of entries
- version, entry_count = struct.unpack(">2L", moov.read(8))
-
- log.info("Patching %s with %d entries" % (atom_type, entry_count))
-
- # Read entries
- entries = struct.unpack(">" + ctype * entry_count,
- moov.read(csize * entry_count))
-
- # Patch and write entries
- moov.seek(-csize * entry_count, os.SEEK_CUR)
- moov.write(struct.pack(">" + ctype * entry_count,
- *[entry + offset for entry in entries]))
-
- log.info("Writing output...")
- outfile = open(outfilename, "wb")
-
- # Write ftype
- for atom, pos, size in index:
- if atom == "ftyp":
- datastream.seek(pos)
- outfile.write(datastream.read(size))
-
- # Write moov
- moov.seek(0)
- outfile.write(moov.read())
-
- # Write the rest
- written = 0
- atoms = [item for item in index if item[0] not in ["ftyp", "moov", "free"]]
- for atom, pos, size in atoms:
- datastream.seek(pos)
-
- # Write in chunks to not use too much memory
- for x in range(size / CHUNK_SIZE):
- outfile.write(datastream.read(CHUNK_SIZE))
- written += CHUNK_SIZE
- if limit and written >= limit:
- # A limit was set and we've just passed it, stop writing!
- break
-
- if size % CHUNK_SIZE:
- outfile.write(datastream.read(size % CHUNK_SIZE))
- written += (size % CHUNK_SIZE)
- if limit and written >= limit:
- # A limit was set and we've just passed it, stop writing!
- break