<s> """<STR_LIT>""" <EOL> import shutil <EOL> import logging <EOL> import os <EOL> import struct <EOL> import collections <EOL> import io <EOL> from qtfaststart . exceptions import FastStartSetupError <EOL> from qtfaststart . exceptions import MalformedFileError <EOL> from qtfaststart . exceptions import UnsupportedFormatError <EOL> from qtfaststart . exceptions import FastStartException <EOL> CHUNK_SIZE = <NUM_LIT> <EOL> log = logging . getLogger ( "<STR_LIT>" ) <EOL> if not hasattr ( os , '<STR_LIT>' ) : <EOL> os . SEEK_CUR = <NUM_LIT:1> <EOL> Atom = collections . namedtuple ( '<STR_LIT>' , '<STR_LIT>' ) <EOL> def read_atom ( datastream ) : <EOL> """<STR_LIT>""" <EOL> size , type = struct . unpack ( "<STR_LIT>" , datastream . read ( <NUM_LIT:8> ) ) <EOL> type = type . decode ( '<STR_LIT:ascii>' ) <EOL> return size , type <EOL> def _read_atom_ex ( datastream ) : <EOL> """<STR_LIT>""" <EOL> pos = datastream . tell ( ) <EOL> atom_size , atom_type = read_atom ( datastream ) <EOL> if atom_size == <NUM_LIT:1> : <EOL> atom_size , = struct . unpack ( "<STR_LIT>" , datastream . read ( <NUM_LIT:8> ) ) <EOL> return Atom ( atom_type , pos , atom_size ) <EOL> def get_index ( datastream ) : <EOL> """<STR_LIT>""" <EOL> log . debug ( "<STR_LIT>" ) <EOL> index = list ( _read_atoms ( datastream ) ) <EOL> _ensure_valid_index ( index ) <EOL> return index <EOL> def _read_atoms ( datastream ) : <EOL> """<STR_LIT>""" <EOL> while datastream : <EOL> try : <EOL> atom = _read_atom_ex ( datastream ) <EOL> log . debug ( "<STR_LIT>" % ( atom . name , atom . size ) ) <EOL> except : <EOL> break <EOL> yield atom <EOL> if atom . size == <NUM_LIT:0> : <EOL> if atom . name == "<STR_LIT>" : <EOL> break <EOL> else : <EOL> continue <EOL> datastream . seek ( atom . position + atom . size ) <EOL> def _ensure_valid_index ( index ) : <EOL> """<STR_LIT>""" <EOL> top_level_atoms = set ( [ item . name for item in index ] ) <EOL> for key in [ "<STR_LIT>" , "<STR_LIT>" ] : <EOL> if key not in top_level_atoms : <EOL> msg = "<STR_LIT>" % key <EOL> log . warn ( msg ) <EOL> raise MalformedFileError ( msg ) <EOL> def find_atoms ( size , datastream ) : <EOL> """<STR_LIT>""" <EOL> fake_parent = Atom ( '<STR_LIT>' , datastream . tell ( ) - <NUM_LIT:8> , size + <NUM_LIT:8> ) <EOL> for atom in _find_atoms_ex ( fake_parent , datastream ) : <EOL> yield atom . name <EOL> def _find_atoms_ex ( parent_atom , datastream ) : <EOL> """<STR_LIT>""" <EOL> stop = parent_atom . position + parent_atom . size <EOL> while datastream . tell ( ) < stop : <EOL> try : <EOL> atom = _read_atom_ex ( datastream ) <EOL> except : <EOL> msg = "<STR_LIT>" <EOL> log . exception ( msg ) <EOL> raise MalformedFileError ( msg ) <EOL> if atom . name in [ "<STR_LIT>" , "<STR_LIT>" , "<STR_LIT>" , "<STR_LIT>" ] : <EOL> for res in _find_atoms_ex ( atom , datastream ) : <EOL> yield res <EOL> elif atom . name in [ "<STR_LIT>" , "<STR_LIT>" ] : <EOL> yield atom <EOL> else : <EOL> datastream . seek ( atom . position + atom . size ) <EOL> def _moov_is_compressed ( datastream , moov_atom ) : <EOL> """<STR_LIT>""" <EOL> datastream . seek ( moov_atom . position + <NUM_LIT:8> ) <EOL> stop = moov_atom . position + moov_atom . size <EOL> while datastream . tell ( ) < stop : <EOL> child_atom = _read_atom_ex ( datastream ) <EOL> datastream . seek ( datastream . tell ( ) + child_atom . size - <NUM_LIT:8> ) <EOL> if child_atom . name == '<STR_LIT>' : <EOL> return True <EOL> return False <EOL> def process ( infilename , outfilename , limit = float ( '<STR_LIT>' ) , to_end = False , <EOL> cleanup = True ) : <EOL> """<STR_LIT>""" <EOL> datastream = open ( infilename , "<STR_LIT:rb>" ) <EOL> index = get_index ( datastream ) <EOL> mdat_pos = <NUM_LIT> <EOL> free_size = <NUM_LIT:0> <EOL> for atom in index : <EOL> if atom . name == "<STR_LIT>" : <EOL> moov_atom = atom <EOL> moov_pos = atom . position <EOL> elif atom . name == "<STR_LIT>" : <EOL> mdat_pos = atom . position <EOL> elif atom . name == "<STR_LIT>" and atom . position < mdat_pos and cleanup : <EOL> free_size += atom . size <EOL> log . info ( "<STR_LIT>" % <EOL> ( atom . position , atom . size ) ) <EOL> elif ( atom . name == "<STR_LIT>" and atom . position < mdat_pos ) : <EOL> free_size += <NUM_LIT:8> <EOL> log . info ( "<STR_LIT>" % <EOL> atom . position ) <EOL> offset = - free_size <EOL> if moov_pos < mdat_pos : <EOL> if to_end : <EOL> offset -= moov_atom . size <EOL> else : <EOL> if not to_end : <EOL> offset += moov_atom . size <EOL> if offset == <NUM_LIT:0> : <EOL> msg = "<STR_LIT>" <EOL> log . error ( msg ) <EOL> raise FastStartSetupError ( msg ) <EOL> is_compressed = _moov_is_compressed ( datastream , moov_atom ) <EOL> if is_compressed : <EOL> msg = "<STR_LIT>" <EOL> log . error ( msg ) <EOL> raise UnsupportedFormatError ( msg ) <EOL> moov = _patch_moov ( datastream , moov_atom , offset ) <EOL> log . info ( "<STR_LIT>" ) <EOL> outfile = open ( outfilename , "<STR_LIT:wb>" ) <EOL> for atom in index : <EOL> if atom . name == "<STR_LIT>" : <EOL> log . debug ( "<STR_LIT>" % atom . size ) <EOL> datastream . seek ( atom . position ) <EOL> outfile . write ( datastream . read ( atom . size ) ) <EOL> if not to_end : <EOL> _write_moov ( moov , outfile ) <EOL> skip_atom_types = [ "<STR_LIT>" , "<STR_LIT>" ] <EOL> if cleanup : <EOL> skip_atom_types += [ "<STR_LIT>" ] <EOL> atoms = [ item for item in index if item . name not in skip_atom_types ] <EOL> for atom in atoms : <EOL> log . debug ( "<STR_LIT>" % ( atom . name , atom . size ) ) <EOL> datastream . seek ( atom . position ) <EOL> cur_limit = limit or float ( '<STR_LIT>' ) <EOL> cur_limit = min ( cur_limit , atom . size ) <EOL> for chunk in get_chunks ( datastream , CHUNK_SIZE , cur_limit ) : <EOL> outfile . write ( chunk ) <EOL> if to_end : <EOL> _write_moov ( moov , outfile ) <EOL> outfile . close ( ) <EOL> try : <EOL> shutil . copymode ( infilename , outfilename ) <EOL> except : <EOL> log . warn ( "<STR_LIT>" ) <EOL> def _write_moov ( moov , outfile ) : <EOL> bytes = moov . getvalue ( ) <EOL> log . debug ( "<STR_LIT>" % len ( bytes ) ) <EOL> outfile . write ( bytes ) <EOL> def _patch_moov ( datastream , atom , offset ) : <EOL> datastream . seek ( atom . position ) <EOL> moov = io . BytesIO ( datastream . read ( atom . size ) ) <EOL> atom = _read_atom_ex ( moov ) <EOL> for atom in _find_atoms_ex ( atom , moov ) : <EOL> ctype , csize = dict ( <EOL> stco = ( '<STR_LIT:L>' , <NUM_LIT:4> ) , <EOL> co64 = ( '<STR_LIT>' , <NUM_LIT:8> ) , <EOL> ) [ atom . name ] <EOL> version , entry_count = struct . unpack ( "<STR_LIT>" , moov . read ( <NUM_LIT:8> ) ) <EOL> log . info ( "<STR_LIT>" % ( atom . name , entry_count ) ) <EOL> entries_pos = moov . tell ( ) <EOL> struct_fmt = "<STR_LIT>" % vars ( ) <EOL> entries = struct . unpack ( struct_fmt , moov . read ( csize * entry_count ) ) <EOL> offset_entries = [ entry + offset for entry in entries ] <EOL> moov . seek ( entries_pos ) <EOL> moov . write ( struct . pack ( struct_fmt , * offset_entries ) ) <EOL> return moov <EOL> def get_chunks ( stream , chunk_size , limit ) : <EOL> remaining = limit <EOL> while remaining : <EOL> chunk = stream . read ( min ( remaining , chunk_size ) ) <EOL> if not chunk : <EOL> return <EOL> remaining -= len ( chunk ) <EOL> yield chunk </s>
