[4] | 1 | #if 0 |
---|
| 2 | # $Id: riffinfo.py,v 1.33 2005/03/15 17:50:45 dischi Exp $ |
---|
| 3 | # $Log: riffinfo.py,v $ |
---|
| 4 | # Revision 1.33 2005/03/15 17:50:45 dischi |
---|
| 5 | # check for corrupt avi |
---|
| 6 | # |
---|
| 7 | # Revision 1.32 2005/03/04 17:41:29 dischi |
---|
| 8 | # handle broken avi files |
---|
| 9 | # |
---|
| 10 | # Revision 1.31 2004/12/13 10:19:07 dischi |
---|
| 11 | # more debug, support LIST > 20000 (new max is 80000) |
---|
| 12 | # |
---|
| 13 | # Revision 1.30 2004/08/25 16:18:14 dischi |
---|
| 14 | # detect aspect ratio |
---|
| 15 | # |
---|
| 16 | # Revision 1.29 2004/05/24 16:17:09 dischi |
---|
| 17 | # Small changes for future updates |
---|
| 18 | # |
---|
| 19 | # Revision 1.28 2004/01/31 12:23:46 dischi |
---|
| 20 | # remove bad chars from table (e.g. char 0 is True) |
---|
| 21 | # |
---|
| 22 | # Revision 1.27 2003/10/04 14:30:08 dischi |
---|
| 23 | # add audio delay for avi |
---|
| 24 | # |
---|
| 25 | # Revision 1.26 2003/07/10 11:18:11 the_krow |
---|
| 26 | # few more attributes added |
---|
| 27 | # |
---|
| 28 | # Revision 1.25 2003/07/07 21:36:44 dischi |
---|
| 29 | # make fps a float and round it to two digest after the comma |
---|
| 30 | # |
---|
| 31 | # Revision 1.24 2003/07/05 19:36:37 the_krow |
---|
| 32 | # length fixed |
---|
| 33 | # fps introduced |
---|
| 34 | # |
---|
| 35 | # Revision 1.23 2003/07/02 11:17:30 the_krow |
---|
| 36 | # language is now part of the table key |
---|
| 37 | # |
---|
| 38 | # Revision 1.22 2003/07/01 21:06:50 dischi |
---|
| 39 | # no need to import factory (and when, use "from mmpython import factory" |
---|
| 40 | # |
---|
| 41 | # Revision 1.21 2003/06/30 13:17:20 the_krow |
---|
| 42 | # o Refactored mediainfo into factory, synchronizedobject |
---|
| 43 | # o Parsers now register directly at mmpython not at mmpython.mediainfo |
---|
| 44 | # o use mmpython.Factory() instead of mmpython.mediainfo.get_singleton() |
---|
| 45 | # o Bugfix in PNG parser |
---|
| 46 | # o Renamed disc.AudioInfo into disc.AudioDiscInfo |
---|
| 47 | # o Renamed disc.DataInfo into disc.DataDiscInfo |
---|
| 48 | # |
---|
| 49 | # Revision 1.20 2003/06/23 20:48:11 the_krow |
---|
| 50 | # width + height fixes for OGM files |
---|
| 51 | # |
---|
| 52 | # Revision 1.19 2003/06/23 20:38:04 the_krow |
---|
| 53 | # Support for larger LIST chunks because some files did not work. |
---|
| 54 | # |
---|
| 55 | # Revision 1.18 2003/06/20 19:17:22 dischi |
---|
| 56 | # remove filename again and use file.name |
---|
| 57 | # |
---|
| 58 | # Revision 1.17 2003/06/20 19:05:56 dischi |
---|
| 59 | # scan for subtitles |
---|
| 60 | # |
---|
| 61 | # Revision 1.16 2003/06/20 15:29:42 the_krow |
---|
| 62 | # Metadata Mapping |
---|
| 63 | # |
---|
| 64 | # Revision 1.15 2003/06/20 14:43:57 the_krow |
---|
| 65 | # Putting Metadata into MediaInfo from AVIInfo Table |
---|
| 66 | # |
---|
| 67 | # Revision 1.14 2003/06/09 16:10:52 dischi |
---|
| 68 | # error handling |
---|
| 69 | # |
---|
| 70 | # Revision 1.13 2003/06/08 19:53:21 dischi |
---|
| 71 | # also give the filename to init for additional data tests |
---|
| 72 | # |
---|
| 73 | # Revision 1.12 2003/06/08 13:44:58 dischi |
---|
| 74 | # Changed all imports to use the complete mmpython path for mediainfo |
---|
| 75 | # |
---|
| 76 | # Revision 1.11 2003/06/08 13:11:38 dischi |
---|
| 77 | # removed print at the end and moved it into register |
---|
| 78 | # |
---|
| 79 | # Revision 1.10 2003/06/07 23:10:50 the_krow |
---|
| 80 | # Changed mp3 into new format. |
---|
| 81 | # |
---|
| 82 | # Revision 1.9 2003/06/07 22:30:22 the_krow |
---|
| 83 | # added new avinfo structure |
---|
| 84 | # |
---|
| 85 | # Revision 1.8 2003/06/07 21:48:47 the_krow |
---|
| 86 | # Added Copying info |
---|
| 87 | # started changing riffinfo to new AV stuff |
---|
| 88 | # |
---|
| 89 | # Revision 1.7 2003/05/13 12:31:43 the_krow |
---|
| 90 | # + Copyright Notice |
---|
| 91 | # |
---|
| 92 | # |
---|
| 93 | # MMPython - Media Metadata for Python |
---|
| 94 | # Copyright (C) 2003 Thomas Schueppel, Dirk Meyer |
---|
| 95 | # |
---|
| 96 | # This program is free software; you can redistribute it and/or modify |
---|
| 97 | # it under the terms of the GNU General Public License as published by |
---|
| 98 | # the Free Software Foundation; either version 2 of the License, or |
---|
| 99 | # (at your option) any later version. |
---|
| 100 | # |
---|
| 101 | # This program is distributed in the hope that it will be useful, but |
---|
| 102 | # WITHOUT ANY WARRANTY; without even the implied warranty of MER- |
---|
| 103 | # CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General |
---|
| 104 | # Public License for more details. |
---|
| 105 | # |
---|
| 106 | # You should have received a copy of the GNU General Public License along |
---|
| 107 | # with this program; if not, write to the Free Software Foundation, Inc., |
---|
| 108 | # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
| 109 | # |
---|
| 110 | # ----------------------------------------------------------------------- |
---|
| 111 | #endif |
---|
| 112 | |
---|
| 113 | import re |
---|
| 114 | import struct |
---|
| 115 | import string |
---|
| 116 | import fourcc |
---|
| 117 | # import factory |
---|
| 118 | |
---|
| 119 | import mmpython |
---|
| 120 | from mmpython import mediainfo |
---|
| 121 | |
---|
| 122 | |
---|
| 123 | # List of tags |
---|
| 124 | # http://kibus1.narod.ru/frames_eng.htm?sof/abcavi/infotags.htm |
---|
| 125 | # http://www.divx-digest.com/software/avitags_dll.html |
---|
| 126 | # File Format |
---|
| 127 | # http://www.taenam.co.kr/pds/documents/odmlff2.pdf |
---|
| 128 | |
---|
| 129 | _print = mediainfo._debug |
---|
| 130 | |
---|
| 131 | AVIINFO_tags = { 'title': 'INAM', |
---|
| 132 | 'artist': 'IART', |
---|
| 133 | 'product': 'IPRD', |
---|
| 134 | 'date': 'ICRD', |
---|
| 135 | 'comment': 'ICMT', |
---|
| 136 | 'language': 'ILNG', |
---|
| 137 | 'keywords': 'IKEY', |
---|
| 138 | 'trackno': 'IPRT', |
---|
| 139 | 'trackof': 'IFRM', |
---|
| 140 | 'producer': 'IPRO', |
---|
| 141 | 'writer': 'IWRI', |
---|
| 142 | 'genre': 'IGNR', |
---|
| 143 | 'copyright': 'ICOP', |
---|
| 144 | 'trackno': 'IPRT', |
---|
| 145 | 'trackof': 'IFRM', |
---|
| 146 | 'comment': 'ICMT', |
---|
| 147 | } |
---|
| 148 | |
---|
| 149 | |
---|
| 150 | |
---|
| 151 | class RiffInfo(mediainfo.AVInfo): |
---|
| 152 | def __init__(self,file): |
---|
| 153 | mediainfo.AVInfo.__init__(self) |
---|
| 154 | # read the header |
---|
| 155 | h = file.read(12) |
---|
| 156 | if h[:4] != "RIFF" and h[:4] != 'SDSS': |
---|
| 157 | self.valid = 0 |
---|
| 158 | return |
---|
| 159 | self.valid = 1 |
---|
| 160 | self.mime = 'application/x-wave' |
---|
| 161 | self.has_idx = False |
---|
| 162 | self.header = {} |
---|
| 163 | self.junkStart = None |
---|
| 164 | self.infoStart = None |
---|
| 165 | self.type = h[8:12] |
---|
| 166 | self.tag_map = { ('AVIINFO', 'en') : AVIINFO_tags } |
---|
| 167 | if self.type == 'AVI ': |
---|
| 168 | self.mime = 'video/avi' |
---|
| 169 | elif self.type == 'WAVE': |
---|
| 170 | self.mime = 'application/x-wave' |
---|
| 171 | try: |
---|
| 172 | while self.parseRIFFChunk(file): |
---|
| 173 | pass |
---|
| 174 | except IOError: |
---|
| 175 | if mediainfo.DEBUG: |
---|
| 176 | print 'error in file, stop parsing' |
---|
| 177 | |
---|
| 178 | self.find_subtitles(file.name) |
---|
| 179 | |
---|
| 180 | # Copy Metadata from tables into the main set of attributes |
---|
| 181 | for k in self.tag_map.keys(): |
---|
| 182 | map(lambda x:self.setitem(x,self.gettable(k[0],k[1]),self.tag_map[k][x]), |
---|
| 183 | self.tag_map[k].keys()) |
---|
| 184 | if not self.has_idx: |
---|
| 185 | _print('WARNING: avi has no index') |
---|
| 186 | self.corrupt = 1 |
---|
| 187 | self.keys.append('corrupt') |
---|
| 188 | |
---|
| 189 | |
---|
| 190 | def _extractHeaderString(self,h,offset,len): |
---|
| 191 | return h[offset:offset+len] |
---|
| 192 | |
---|
| 193 | def parseAVIH(self,t): |
---|
| 194 | retval = {} |
---|
| 195 | v = struct.unpack('<IIIIIIIIIIIIII',t[0:56]) |
---|
| 196 | ( retval['dwMicroSecPerFrame'], |
---|
| 197 | retval['dwMaxBytesPerSec'], |
---|
| 198 | retval['dwPaddingGranularity'], |
---|
| 199 | retval['dwFlags'], |
---|
| 200 | retval['dwTotalFrames'], |
---|
| 201 | retval['dwInitialFrames'], |
---|
| 202 | retval['dwStreams'], |
---|
| 203 | retval['dwSuggestedBufferSize'], |
---|
| 204 | retval['dwWidth'], |
---|
| 205 | retval['dwHeight'], |
---|
| 206 | retval['dwScale'], |
---|
| 207 | retval['dwRate'], |
---|
| 208 | retval['dwStart'], |
---|
| 209 | retval['dwLength'] ) = v |
---|
| 210 | if retval['dwMicroSecPerFrame'] == 0: |
---|
| 211 | _print("ERROR: Corrupt AVI") |
---|
| 212 | self.valid = 0 |
---|
| 213 | return {} |
---|
| 214 | return retval |
---|
| 215 | |
---|
| 216 | def parseSTRH(self,t): |
---|
| 217 | retval = {} |
---|
| 218 | retval['fccType'] = t[0:4] |
---|
| 219 | _print("parseSTRH(%s) : %d bytes" % ( retval['fccType'], len(t))) |
---|
| 220 | if retval['fccType'] != 'auds': |
---|
| 221 | retval['fccHandler'] = t[4:8] |
---|
| 222 | v = struct.unpack('<IHHIIIIIIIII',t[8:52]) |
---|
| 223 | ( retval['dwFlags'], |
---|
| 224 | retval['wPriority'], |
---|
| 225 | retval['wLanguage'], |
---|
| 226 | retval['dwInitialFrames'], |
---|
| 227 | retval['dwScale'], |
---|
| 228 | retval['dwRate'], |
---|
| 229 | retval['dwStart'], |
---|
| 230 | retval['dwLength'], |
---|
| 231 | retval['dwSuggestedBufferSize'], |
---|
| 232 | retval['dwQuality'], |
---|
| 233 | retval['dwSampleSize'], |
---|
| 234 | retval['rcFrame'], ) = v |
---|
| 235 | else: |
---|
| 236 | try: |
---|
| 237 | v = struct.unpack('<IHHIIIIIIIII',t[8:52]) |
---|
| 238 | ( retval['dwFlags'], |
---|
| 239 | retval['wPriority'], |
---|
| 240 | retval['wLanguage'], |
---|
| 241 | retval['dwInitialFrames'], |
---|
| 242 | retval['dwScale'], |
---|
| 243 | retval['dwRate'], |
---|
| 244 | retval['dwStart'], |
---|
| 245 | retval['dwLength'], |
---|
| 246 | retval['dwSuggestedBufferSize'], |
---|
| 247 | retval['dwQuality'], |
---|
| 248 | retval['dwSampleSize'], |
---|
| 249 | retval['rcFrame'], ) = v |
---|
| 250 | self.delay = float(retval['dwStart']) / \ |
---|
| 251 | (float(retval['dwRate']) / retval['dwScale']) |
---|
| 252 | except: |
---|
| 253 | pass |
---|
| 254 | |
---|
| 255 | return retval |
---|
| 256 | |
---|
| 257 | def parseSTRF(self,t,strh): |
---|
| 258 | fccType = strh['fccType'] |
---|
| 259 | retval = {} |
---|
| 260 | if fccType == 'auds': |
---|
| 261 | ( retval['wFormatTag'], |
---|
| 262 | retval['nChannels'], |
---|
| 263 | retval['nSamplesPerSec'], |
---|
| 264 | retval['nAvgBytesPerSec'], |
---|
| 265 | retval['nBlockAlign'], |
---|
| 266 | retval['nBitsPerSample'], |
---|
| 267 | ) = struct.unpack('<HHHHHH',t[0:12]) |
---|
| 268 | ai = mediainfo.AudioInfo() |
---|
| 269 | ai.samplerate = retval['nSamplesPerSec'] |
---|
| 270 | ai.channels = retval['nChannels'] |
---|
| 271 | ai.samplebits = retval['nBitsPerSample'] |
---|
| 272 | ai.bitrate = retval['nAvgBytesPerSec'] * 8 |
---|
| 273 | # TODO: set code if possible |
---|
| 274 | # http://www.stats.uwa.edu.au/Internal/Specs/DXALL/FileSpec/Languages |
---|
| 275 | # ai.language = strh['wLanguage'] |
---|
| 276 | try: |
---|
| 277 | ai.codec = fourcc.RIFFWAVE[retval['wFormatTag']] |
---|
| 278 | except: |
---|
| 279 | ai.codec = "Unknown" |
---|
| 280 | self.audio.append(ai) |
---|
| 281 | elif fccType == 'vids': |
---|
| 282 | v = struct.unpack('<IIIHH',t[0:16]) |
---|
| 283 | ( retval['biSize'], |
---|
| 284 | retval['biWidth'], |
---|
| 285 | retval['biHeight'], |
---|
| 286 | retval['biPlanes'], |
---|
| 287 | retval['biBitCount'], ) = v |
---|
| 288 | retval['fourcc'] = t[16:20] |
---|
| 289 | v = struct.unpack('IIIII',t[20:40]) |
---|
| 290 | ( retval['biSizeImage'], |
---|
| 291 | retval['biXPelsPerMeter'], |
---|
| 292 | retval['biYPelsPerMeter'], |
---|
| 293 | retval['biClrUsed'], |
---|
| 294 | retval['biClrImportant'], ) = v |
---|
| 295 | vi = mediainfo.VideoInfo() |
---|
| 296 | try: |
---|
| 297 | vi.codec = fourcc.RIFFCODEC[t[16:20]] |
---|
| 298 | except: |
---|
| 299 | vi.codec = "Unknown" |
---|
| 300 | vi.width = retval['biWidth'] |
---|
| 301 | vi.height = retval['biHeight'] |
---|
| 302 | vi.bitrate = strh['dwRate'] |
---|
| 303 | vi.fps = round(float(strh['dwRate'] * 100) / strh['dwScale']) / 100 |
---|
| 304 | vi.length = strh['dwLength'] / vi.fps |
---|
| 305 | self.video.append(vi) |
---|
| 306 | return retval |
---|
| 307 | |
---|
| 308 | |
---|
| 309 | def parseSTRL(self,t): |
---|
| 310 | retval = {} |
---|
| 311 | size = len(t) |
---|
| 312 | i = 0 |
---|
| 313 | key = t[i:i+4] |
---|
| 314 | sz = struct.unpack('<I',t[i+4:i+8])[0] |
---|
| 315 | i+=8 |
---|
| 316 | value = t[i:] |
---|
| 317 | |
---|
| 318 | if key == 'strh': |
---|
| 319 | retval[key] = self.parseSTRH(value) |
---|
| 320 | i += sz |
---|
| 321 | else: |
---|
| 322 | _print("parseSTRL: Error") |
---|
| 323 | key = t[i:i+4] |
---|
| 324 | sz = struct.unpack('<I',t[i+4:i+8])[0] |
---|
| 325 | i+=8 |
---|
| 326 | value = t[i:] |
---|
| 327 | |
---|
| 328 | if key == 'strf': |
---|
| 329 | retval[key] = self.parseSTRF(value, retval['strh']) |
---|
| 330 | i += sz |
---|
| 331 | return ( retval, i ) |
---|
| 332 | |
---|
| 333 | |
---|
| 334 | def parseODML(self,t): |
---|
| 335 | retval = {} |
---|
| 336 | size = len(t) |
---|
| 337 | i = 0 |
---|
| 338 | key = t[i:i+4] |
---|
| 339 | sz = struct.unpack('<I',t[i+4:i+8])[0] |
---|
| 340 | i += 8 |
---|
| 341 | value = t[i:] |
---|
| 342 | if key == 'dmlh': |
---|
| 343 | pass |
---|
| 344 | else: |
---|
| 345 | _print("parseODML: Error") |
---|
| 346 | |
---|
| 347 | i += sz - 8 |
---|
| 348 | return ( retval, i ) |
---|
| 349 | |
---|
| 350 | |
---|
| 351 | def parseVPRP(self,t): |
---|
| 352 | retval = {} |
---|
| 353 | v = struct.unpack('<IIIIIIIIII',t[:4*10]) |
---|
| 354 | |
---|
| 355 | ( retval['VideoFormat'], |
---|
| 356 | retval['VideoStandard'], |
---|
| 357 | retval['RefreshRate'], |
---|
| 358 | retval['HTotalIn'], |
---|
| 359 | retval['VTotalIn'], |
---|
| 360 | retval['FrameAspectRatio'], |
---|
| 361 | retval['wPixel'], |
---|
| 362 | retval['hPixel'] ) = v[1:-1] |
---|
| 363 | |
---|
| 364 | # I need an avi with more informations |
---|
| 365 | # enum {FORMAT_UNKNOWN, FORMAT_PAL_SQUARE, FORMAT_PAL_CCIR_601, |
---|
| 366 | # FORMAT_NTSC_SQUARE, FORMAT_NTSC_CCIR_601,...} VIDEO_FORMAT; |
---|
| 367 | # enum {STANDARD_UNKNOWN, STANDARD_PAL, STANDARD_NTSC, STANDARD_SECAM} |
---|
| 368 | # VIDEO_STANDARD; |
---|
| 369 | # |
---|
| 370 | r = retval['FrameAspectRatio'] |
---|
| 371 | r = float(r >> 16) / (r & 0xFFFF) |
---|
| 372 | retval['FrameAspectRatio'] = r |
---|
| 373 | if self.video: |
---|
| 374 | map(lambda v: setattr(v, 'aspect', r), self.video) |
---|
| 375 | return ( retval, v[0] ) |
---|
| 376 | |
---|
| 377 | |
---|
| 378 | def parseLIST(self,t): |
---|
| 379 | retval = {} |
---|
| 380 | i = 0 |
---|
| 381 | size = len(t) |
---|
| 382 | |
---|
| 383 | while i < size-8: |
---|
| 384 | # skip zero |
---|
| 385 | if ord(t[i]) == 0: i += 1 |
---|
| 386 | key = t[i:i+4] |
---|
| 387 | sz = 0 |
---|
| 388 | |
---|
| 389 | if key == 'LIST': |
---|
| 390 | sz = struct.unpack('<I',t[i+4:i+8])[0] |
---|
| 391 | _print("-> SUBLIST: len: %d, %d" % ( sz, i+4 )) |
---|
| 392 | i+=8 |
---|
| 393 | key = "LIST:"+t[i:i+4] |
---|
| 394 | value = self.parseLIST(t[i:i+sz]) |
---|
| 395 | _print("<-") |
---|
| 396 | if key == 'strl': |
---|
| 397 | for k in value.keys(): |
---|
| 398 | retval[k] = value[k] |
---|
| 399 | else: |
---|
| 400 | retval[key] = value |
---|
| 401 | i+=sz |
---|
| 402 | elif key == 'avih': |
---|
| 403 | _print("SUBAVIH") |
---|
| 404 | sz = struct.unpack('<I',t[i+4:i+8])[0] |
---|
| 405 | i += 8 |
---|
| 406 | value = self.parseAVIH(t[i:i+sz]) |
---|
| 407 | i += sz |
---|
| 408 | retval[key] = value |
---|
| 409 | elif key == 'strl': |
---|
| 410 | i += 4 |
---|
| 411 | (value, sz) = self.parseSTRL(t[i:]) |
---|
| 412 | _print("SUBSTRL: len: %d" % sz) |
---|
| 413 | key = value['strh']['fccType'] |
---|
| 414 | i += sz |
---|
| 415 | retval[key] = value |
---|
| 416 | elif key == 'odml': |
---|
| 417 | i += 4 |
---|
| 418 | (value, sz) = self.parseODML(t[i:]) |
---|
| 419 | _print("ODML: len: %d" % sz) |
---|
| 420 | i += sz |
---|
| 421 | elif key == 'vprp': |
---|
| 422 | i += 4 |
---|
| 423 | (value, sz) = self.parseVPRP(t[i:]) |
---|
| 424 | _print("VPRP: len: %d" % sz) |
---|
| 425 | retval[key] = value |
---|
| 426 | i += sz |
---|
| 427 | elif key == 'JUNK': |
---|
| 428 | sz = struct.unpack('<I',t[i+4:i+8])[0] |
---|
| 429 | i += sz + 8 |
---|
| 430 | _print("Skipping %d bytes of Junk" % sz) |
---|
| 431 | else: |
---|
| 432 | sz = struct.unpack('<I',t[i+4:i+8])[0] |
---|
| 433 | _print("Unknown Key: %s, len: %d" % (key,sz)) |
---|
| 434 | i+=8 |
---|
| 435 | value = self._extractHeaderString(t,i,sz) |
---|
| 436 | value = value.replace('\0', '').lstrip().rstrip() |
---|
| 437 | if value: |
---|
| 438 | retval[key] = value |
---|
| 439 | i+=sz |
---|
| 440 | return retval |
---|
| 441 | |
---|
| 442 | |
---|
| 443 | def parseRIFFChunk(self,file): |
---|
| 444 | h = file.read(8) |
---|
| 445 | if len(h) < 4: |
---|
| 446 | return False |
---|
| 447 | name = h[:4] |
---|
| 448 | size = struct.unpack('<I',h[4:8])[0] |
---|
| 449 | |
---|
| 450 | if name == 'LIST' and size < 80000: |
---|
| 451 | pos = file.tell() - 8 |
---|
| 452 | t = file.read(size) |
---|
| 453 | key = t[:4] |
---|
| 454 | _print('parse RIFF LIST: %d bytes' % (size)) |
---|
| 455 | value = self.parseLIST(t[4:]) |
---|
| 456 | self.header[key] = value |
---|
| 457 | if key == 'INFO': |
---|
| 458 | self.infoStart = pos |
---|
| 459 | self.appendtable( 'AVIINFO', value ) |
---|
| 460 | elif key == 'MID ': |
---|
| 461 | self.appendtable( 'AVIMID', value ) |
---|
| 462 | elif key in ('hdrl', ): |
---|
| 463 | # no need to add this info to a table |
---|
| 464 | pass |
---|
| 465 | else: |
---|
| 466 | _print('Skipping table info %s' % key) |
---|
| 467 | |
---|
| 468 | elif name == 'JUNK': |
---|
| 469 | self.junkStart = file.tell() - 8 |
---|
| 470 | self.junkSize = size |
---|
| 471 | file.seek(size, 1) |
---|
| 472 | elif name == 'idx1': |
---|
| 473 | self.has_idx = True |
---|
| 474 | _print('idx1: %s bytes' % size) |
---|
| 475 | # no need to parse this |
---|
| 476 | t = file.seek(size,1) |
---|
| 477 | elif name == 'LIST': |
---|
| 478 | _print('RIFF LIST to long to parse: %s bytes' % size) |
---|
| 479 | # no need to parse this |
---|
| 480 | t = file.seek(size,1) |
---|
| 481 | elif name == 'RIFF': |
---|
| 482 | _print("New RIFF chunk, extended avi [%i]" % size) |
---|
| 483 | type = file.read(4) |
---|
| 484 | if type != 'AVIX': |
---|
| 485 | _print("Second RIFF chunk is %s, not AVIX, skipping", type) |
---|
| 486 | file.seek(size-4, 1) |
---|
| 487 | # that's it, no new informations should be in AVIX |
---|
| 488 | return False |
---|
| 489 | elif not name.strip(string.printable + string.whitespace): |
---|
| 490 | # check if name is something usefull at all, maybe it is no |
---|
| 491 | # avi or broken |
---|
| 492 | t = file.seek(size,1) |
---|
| 493 | _print("Skipping %s [%i]" % (name,size)) |
---|
| 494 | else: |
---|
| 495 | # bad avi |
---|
| 496 | _print("Bad or broken avi") |
---|
| 497 | return False |
---|
| 498 | return True |
---|
| 499 | |
---|
| 500 | def buildTag(self,key,value): |
---|
| 501 | text = value + '\0' |
---|
| 502 | l = len(text) |
---|
| 503 | return struct.pack('<4sI%ds'%l, key[:4], l, text[:l]) |
---|
| 504 | |
---|
| 505 | |
---|
| 506 | def setInfo(self,file,hash): |
---|
| 507 | if self.junkStart == None: |
---|
| 508 | raise "junkstart missing" |
---|
| 509 | tags = [] |
---|
| 510 | size = 4 # Length of 'INFO' |
---|
| 511 | # Build String List and compute req. size |
---|
| 512 | for key in hash.keys(): |
---|
| 513 | tag = self.buildTag( key, hash[key] ) |
---|
| 514 | if (len(tag))%2 == 1: tag += '\0' |
---|
| 515 | tags.append(tag) |
---|
| 516 | size += len(tag) |
---|
| 517 | _print("Tag [%i]: %s" % (len(tag),tag)) |
---|
| 518 | if self.infoStart != None: |
---|
| 519 | _print("Infostart found. %i" % (self.infoStart)) |
---|
| 520 | # Read current info size |
---|
| 521 | file.seek(self.infoStart,0) |
---|
| 522 | s = file.read(12) |
---|
| 523 | (list, oldsize, info) = struct.unpack('<4sI4s',s) |
---|
| 524 | self.junkSize += oldsize + 8 |
---|
| 525 | else: |
---|
| 526 | self.infoStart = self.junkStart |
---|
| 527 | _print("Infostart computed. %i" % (self.infoStart)) |
---|
| 528 | file.seek(self.infoStart,0) |
---|
| 529 | if ( size > self.junkSize - 8 ): |
---|
| 530 | raise "Too large" |
---|
| 531 | file.write( "LIST" + struct.pack('<I',size) + "INFO" ) |
---|
| 532 | for tag in tags: |
---|
| 533 | file.write( tag ) |
---|
| 534 | _print("Junksize %i" % (self.junkSize-size-8)) |
---|
| 535 | file.write( "JUNK" + struct.pack('<I',self.junkSize-size-8) ) |
---|
| 536 | |
---|
| 537 | |
---|
| 538 | |
---|
| 539 | mmpython.registertype( 'video/avi', ('avi',), mediainfo.TYPE_AV, RiffInfo ) |
---|