Module mp4_file
[hide private]
[frames] | no frames]

Source Code for Module mp4_file

  1  ### BITPIM 
  2  ### 
  3  ### Copyright (C) 2009 Nathan Hjelm <hjelmn@users.sourceforge.net> 
  4  ### 
  5  ### This program is free software; you can redistribute it and/or modify 
  6  ### it under the terms of the BitPim license as detailed in the LICENSE file. 
  7  ### 
  8  ### 
  9   
 10  """ Deal with MPEG4 file format""" 
 11   
 12  # System modules 
 13  import struct 
 14   
 15  # BitPim modules 
 16   
 17  # constants 
 18  MP4_File_Type_Header = "ftyp" 
 19  MP4_STSZ_Atom_Tag    = "stsz" 
 20  MP4_MDHD_Atom_Tag    = "mdhd" 
 21  MP4_META_Atom_Tag    = "meta" 
 22   
 23  #------------------------------------------------------------------------------- 
24 -class MP4_STSZ_Atom(object):
25 - def __init__ (self, data):
26 if data[4:8] != MP4_STSZ_Atom_Tag: 27 raise 28 if struct.unpack ('>L', data[0:4])[0] < 0x14: 29 raise 30 31 self.numSamples = struct.unpack ('>L', data[16:20])[0] 32 self.average = 0.0 33 self.audibleSamples = None 34 35 _silentSamples = 0 36 37 # 8 for atom header + 12 for sample count and other stuff 38 _dataOffset = 20 39 for i in range (self.numSamples): 40 _sampleSize = struct.unpack ('>L', data[_dataOffset:_dataOffset+4])[0] 41 42 if _sampleSize == 7: 43 _silentSamples += 1 44 else: 45 self.average += float(_sampleSize) 46 47 _dataOffset += 4 48 49 self.audibleSamples = self.numSamples - _silentSamples 50 self.average = self.average * 8.0/float(self.audibleSamples)
51
52 - def getBitrate(self, timescale):
53 _bitrate = int((self.average * float(timescale)/1000.0)/1000.0) 54 _lossless = None 55 56 if _bitrate - 32 > 320: 57 # handle lossless files 58 self.average *= 1000.0/4096.0; 59 _bitrate = int((self.average * float(timescale)/1000.0)/1000.0) 60 61 return _bitrate
62
63 -class MP4_Media_Header(object):
64 - def __init__ (self, data):
65 if data[4:8] != MP4_MDHD_Atom_Tag: 66 raise 67 68 self.timeScale = struct.unpack ('>L', data[20:24])[0] 69 # song duration is in Hz/second 70 self.duration = struct.unpack ('>L', data[24:28])[0]
71
72 - def getTimescale (self):
73 return self.timeScale
74
75 - def getDuration (self):
76 return self.duration/self.timeScale
77
78 -class MP4_Meta_Data(object):
79 - def __init__ (self, data):
80 if data[4:8] != MP4_META_Atom_Tag: 81 raise 82 83 self.title = None 84 self.album = None 85 self.artist = None 86 87 _offset = 12 88 while 1: 89 _size = struct.unpack ('>L', data[offset:offset + 4])[0] 90 _tag = data[offset+5:offset+8] 91 _tag1 = data[offset+4:offset+8] 92 93 _dataSize = struct.unpack ('>L', data[offset + 8:offset + 12])[0] 94 _tagData = data[offset + 24:offset + 8 + _dataSize] 95 96 if _tag1 == "free": 97 break 98 if _tag == "nam": 99 self.title = _tagData 100 if _tag == "ART": 101 self.artist = _tagData 102 if _tag == "alb": 103 self.album = _tagData
104
105 - def getTitle (self):
106 return self.title
107
108 - def getArtist (self):
109 return self.artist
110
111 - def getAlbum (self):
112 return self.album
113 #-------------------------------------------------------------------------------
114 -class MP4_File(object):
115 - def __init__(self, file_wrapper):
116 global Object_Table, ASF_Header_Object_GUID 117 self.valid=False 118 119 self.duration = None 120 self.bitrate = None 121 self.samplerate = None 122 self.title = None 123 self.artist = None 124 self.album = None 125 126 self.STSZAtom = None 127 self.mediaHeader = None 128 self.metaData = None 129 130 if file_wrapper.size<24 or file_wrapper.GetBytes(4,4)!=MP4_File_Type_Header: 131 return 132 133 type_id = file_wrapper.GetBytes(8,4) 134 135 if type_id != 'M4A ' and type_id != "mp42" and type_id != "isom": 136 return 137 138 # initial file offset (skipping the FTYP atom) 139 _offset = struct.unpack ('>L', file_wrapper.GetBytes(0, 4))[0]; 140 while 1: 141 try: 142 _size = struct.unpack ('>L', file_wrapper.GetBytes(_offset, 4))[0]; 143 _type = file_wrapper.GetBytes(_offset + 4, 4); 144 except: 145 break 146 147 if _size == 0: 148 break 149 150 try: 151 if _type == MP4_STSZ_Atom_Tag and self.STSZAtom == None: 152 self.STSZAtom = MP4_STSZ_Atom (file_wrapper.GetBytes (_offset, _size)) 153 elif _type == MP4_MDHD_Atom_Tag and self.mediaHeader == None: 154 self.mediaHeader = MP4_Media_Header (file_wrapper.GetBytes (_offset, _size)) 155 elif _type == MP4_META_Atom_Tag: 156 self.metaData = MP4_Meta_Data (file_wrapper.GetBytes (_offset, _size)) 157 except: 158 pass 159 160 if not self.isContainerAtom(_type): 161 _offset = _offset + _size 162 else: 163 _offset = _offset + 8 164 165 if self.mediaHeader: 166 self.duration = self.mediaHeader.getDuration () 167 self.samplerate = self.mediaHeader.getTimescale () 168 if self.STSZAtom: 169 self.STSZAtom.getBitrate (self.mediaHeader.getTimescale ()) 170 self.valid = True 171 172 if self.metaData: 173 self.artist = self.metaData.getArtist () 174 self.album = self.metaData.getAlbum () 175 self.title = self.metaData.getTitle ()
176
177 - def isContainerAtom (self, _type):
178 return (_type == "trak" or _type == "mdia" or _type == "moov" or 179 _type == "stbl" or _type == "minf" or _type == "dinf" or 180 _type == "udta")
181