Skip to content

Parsing media files

mitshell edited this page Feb 27, 2024 · 1 revision

How to parse media files

Media modules

All the multimedia-related pycrate modules are provided in the pycrate_media/ directory. They are intended to help decoding multimedia files into sub-structures, to help understanding their digital formats and analyzing their content.

Therer is no specific routines to encode easily entire multimedia files from scratch, as this highly depends on options selected by the developer.

Some test medias are provided in the test/res/ directory. We will use them to show how pycrate decomposes media files and helps with their inner structures.

PNG

PNG has a very simple file structure, this makes an ideal case for starting this section about media files. We will see how to parse the test image, modify it (in a rather blind way...) and regenerate it.

>>> from pycrate_media import PNG
>>> imgbuf = open('./test/res/xkcd_wireless_signal.png', 'rb').read()
>>> P = PNG.PNG()
>>> P.from_bytes(imgbuf)
>>> print(P.show())
### PNG ###
 <sig [PNG signature] : b'\x89PNG\r\n\x1a\n'>
     ### PNGBody ###
      ### PNGChunk ###
       <len : 13>
       <type : b'IHDR'>
       ### IHDR ###
        <width : 238>
        <height : 415>
        <depth [bit depth] : 8>
        <color [color type] : 0 (Greyscale)>
        <comp [compression method] : 0 (inflate/deflate with sliding window)>
        <filter [filter method] : 0 (no interlace)>
        <interlace [interlace method] : 0 (no interlace)>
       <crc : 0x7d8cb12e>
      ### PNGChunk ###
       <len : 9>
       <type : b'pHYs'>
       <data :
        00 00 0c 4e 00 00 0c 4e 01                      | b'\x00\x00\x0cN\x00\x00\x0cN\x01'>
       <crc : 0x7f778c23>
      ### PNGChunk ###
       <len : 792>
       <type : b'iCCP'>
       <data :
        50 68 6f 74 6f 73 68 6f 70 20 49 43 43 20 70 72 | b'Photoshop ICC pr'
        6f 66 69 6c 65 00 00 78 da 63 60 60 9e e0 e8 e2 | b'ofile\x00\x00x\xdac``\x9e\xe0\xe8\xe2'
        e4 ca 24 c0 c0 50 50 54 52 e4 1e e4 18 19 11 19 | b'\xe4\xca$\xc0\xc0PPTR\xe4\x1e\xe4\x18\x19\x11\x19'
        a5 c0 7e 9e 81 8d 81 99 81 81 81 81 81 21 31 b9 | b'\xa5\xc0~\x9e\x81\x8d\x81\x99\x81\x81\x81\x81\x81!1\xb9'
        b8 c0 31 20 c0 87 81 81 81 21 2f 3f 2f 95 01 15 | b'\xb8\xc01 \xc0\x87\x81\x81\x81!/?/\x95\x01\x15'
        30 32 30 7c bb c6 c0 c8 c0 c0 c0 70 59 d7 d1 c5 | b'020|\xbb\xc6\xc0\xc8\xc0\xc0\xc0pY\xd7\xd1\xc5'
        c9 95 81 34 c0 9a 5c 50 54 c2 c0 c0 70 80 81 81 | b'\xc9\x95\x814\xc0\x9a\\PT\xc2\xc0\xc0p\x80\x81\x81'
        c1 28 25 b5 38 99 81 81 e1 0b 03 03 43 7a 79 49 | b'\xc1(%\xb58\x99\x81\x81\xe1\x0b\x03\x03CzyI'
        41 09 03 03 63 0c 03 03 83 48 52 76 41 09 03 03 | b'A\t\x03\x03c\x0c\x03\x03\x83HRvA\t\x03\x03'
        63 01 03 03 83 48 76 48 90 33 03 03 63 0b 03 03 | b'c\x01\x03\x03\x83HvH\x903\x03\x03c\x0b\x03\x03'
        13 4f 49 6a 45 09 03 03 03 83 73 7e 41 65 51 66 | b'\x13OIjE\t\x03\x03\x03\x83s~AeQf'
        7a 46 89 82 a1 a5 a5 a5 82 63 4a 7e 52 aa 42 70 | b'zF\x89\x82\xa1\xa5\xa5\xa5\x82cJ~R\xaaBp'
        65 71 49 6a 6e b1 82 67 5e 72 7e 51 41 7e 51 62 | b'eqIjn\xb1\x82g^r~QA~Qb'
        49 6a 0a 03 03 03 d4 0e 06 06 06 06 5e 97 fc 12 | b'Ij\n\x03\x03\x03\xd4\x0e\x06\x06\x06\x06^\x97\xfc\x12'
        05 f7 c4 cc 3c 05 23 03 55 06 2a 83 88 c8 28 05 | b'\x05\xf7\xc4\xcc<\x05#\x03U\x06*\x83\x88\xc8(\x05'
        08 0b 11 3e 08 31 04 48 2e 2d 2a 83 07 25 03 83 | b'\x08\x0b\x11>\x081\x04H.-*\x83\x07%\x03\x83'
        ...>
       <crc : 0xfa96f15d>
      ### PNGChunk ###
       <len : 32>
       <type : b'cHRM'>
       <data :
        00 00 6e 27 00 00 73 af 00 00 df f2 00 00 83 30 | b"\x00\x00n'\x00\x00s\xaf\x00\x00\xdf\xf2\x00\x00\x830"
        00 00 77 43 00 00 c8 0a 00 00 34 95 00 00 2e dc | b'\x00\x00wC\x00\x00\xc8\n\x00\x004\x95\x00\x00.\xdc'>
       <crc : 0x20bf171a>
      ### PNGChunk ###
       <len : 21130>
       <type : b'IDAT'>
       <data :
        78 da ed bd 79 50 8d fd 1f ff ff bc ce 39 73 4e | b'x\xda\xed\xbdyP\x8d\xfd\x1f\xff\xff\xbc\xce9sN'
        db b4 37 95 32 b4 19 94 06 2d 7e 11 26 b2 fc 10 | b'\xdb\xb47\x952\xb4\x19\x94\x06-~\x11&\xb2\xfc\x10'
        46 22 23 61 90 65 ec 3f 64 f9 d9 bf c8 32 f6 41 | b'F"#a\x90e\xec?d\xf9\xd9\xbf\xc82\xf6A'
        dc 8d 7d 90 65 ec 83 dc 8c fd 77 13 19 b2 0c 92 | b'\xdc\x8d}\x90e\xec\x83\xdc\x8c\xfdw\x13\x19\xb2\x0c\x92'
        26 a9 a6 bd 69 3d 73 ce 79 fe fe b8 ae 93 4a e9 | b'&\xa9\xa6\xbdi=s\xcey\xfe\xfe\xb8\xae\x93J\xe9'
        94 ea be ef cf ed fd 8f e3 5c 57 d7 b9 1e d7 f5 | b'\x94\xea\xbe\xef\xcf\xed\xfd\x8f\xe3\\W\xd7\xb9\x1e\xd7\xf5'
        5e 5e fb 1b 81 f8 0f b5 ff 0b 90 59 fd 67 9a 1c | b'^^\xfb\x1b\x81\xf8\x0f\xb5\xff\x0b\x90Y\xfdg\x9a\x1c'
        80 2b ff 33 cd e7 37 ee 6f dc df b8 bf 71 7f e3 | b'\x80+\xff3\xcd\xe77\xeeo\xdc\xdf\xb8\xbfq\x7f\xe3'
        fe c6 fd 8d fb 1b f7 37 6e cb e2 ae 8b fc f1 bb | b'\xfe\xc6\xfd\x8d\xfb\x1b\xf77n\xcb\xe2\xae\x8b\xfc\xf1\xbb'
        0b f3 35 35 fe 5f 7a 78 42 77 af be 1b 72 ea be | b'\x0b\xf355\xfe_zxBw\xaf\xbe\x1br\xea\xbe'
        42 f9 eb fa 7f 38 f7 c5 b7 9f dd 57 f6 e5 93 8f | b'B\xf9\xeb\xfa\x7f8\xf7\xc5\xb7\x9f\xddW\xf6\xe5\x93\x8f'
        b4 35 bf 7a a5 23 c9 a2 c4 94 ea bf 3f f7 64 f5 | b'\xb45\xbfz\xa5#\xc9\xa2\xc4\x94\xea\xbf?\xf7d\xf5'
        53 34 b7 2a aa 3e 67 cc 5e 5a d4 18 5c 77 73 5d | b'S4\xb7*\xaa>g\xcc^Z\xd4\x18\\ws]'
        81 f8 a9 e4 40 ae f8 e1 8b b5 7d 25 49 26 38 f8 | b'\x81\xf8\xa9\xe4@\xae\xf8\xe1\x8b\xb5}%I&8\xf8'
        a6 90 e4 05 7b 98 f9 06 39 a1 7b e2 c6 b9 a3 7b | b'\xa6\x90\xe4\x05{\x98\xf9\x069\xa1{\xe2\xc6\xb9\xa3{'
        74 71 73 0c ac ac 7e 85 85 f2 37 f5 d0 3c ed 21 | b'tqs\x0c\xac\xac~\x85\x85\xf27\xf5\xd0<\xed!'
        ...>
       <crc : 0xa9fbdd38>
      ### PNGChunk ###
       <len : 0>
       <type : b'IEND'>
       <data : >
       <crc : 0xae426082>
>>> P.reautomate() # this is to reautomate the chunk length and CRC32 calculation
>>> P.to_bytes() == imgbuf
True
>>> # regenerating the image buffer from the parsed structure is OK
>>> for chk in P['PNGBody']: print(chk['type'])
<type : b'IHDR'>
<type : b'pHYs'>
<type : b'iCCP'>
<type : b'cHRM'>
<type : b'IDAT'>
<type : b'IEND'>
>>> P['PNGBody'][4]['data'].get_len()
21130
>>> # the compressed image is actually in the IDAT chunk, 21130 bytes long
>>> P['PNGBody'][2]['data']()[:32] # spotting the Photoshop signature
b'Photoshop ICC profile\x00\x00x\xdac``\x9e\xe0\xe8\xe2'
>>> P['PNGBody'][0]['IHDR']['color']
<color [color type] : 0 (Greyscale)>
>>> P['PNGBody'][0]['IHDR']['color']._dic
{0: 'Greyscale',
 2: 'Truecolour',
 3: 'Indexed-colour',
 4: 'Greyscale with alpha',
 6: 'Truecolour with alpha'}
>>> P['PNGBody'][0]['IHDR']['color'].set_val(2)
>>> open('./crappy_png.png', 'wb').write( P.to_bytes() )
Out[55]: 22056
>>> # now enjoy the crappy coloured PNG !

BMP

BMP is also quite simple, as its ultimate goal is just to provide an array of pixels. The pycrate BMP class proposes two flavors to represent a BMP image:

  • one with the pixels' array decomposed into rows of pixels, using the structure in the attribute BMP._GEN_LBUF as generator
  • a second with the pixels' array decomposed into pixels, using the structure in the attribute BMP._GEN_LPIX as generator

The second one is much slower when parsing a file, because each pixel's value is stored into a specific array element. Moreover, the BMP format enables to use arbitrary number of bits to encode each pixel (e.g. 5 bits per pixel !), hopefully, most of the image processing libraries do not use (neither support) this kind of case...

Let's see how the BMP class parses and represents the BMP file in the test directory:

>>> from pycrate_media import BMP
>>> B = BMP.BMP()
>>> B._GEN == B._GEN_LBUF # using the pixel row representation
True
>>> imgbuf = open('./test/res/bmp_test.bmp', 'rb').read()
>>> B.from_bytes(imgbuf)
>>> print(B.show())
### BMP ###
 ### FileHeader ###
  <Signature : b'BM'>
  <Size : 27382>
  <Reserved : 0x00000000>
  <Offset : 54>
     ### DIBHeader ###
      <DIBHeaderSize : 40>
      <Width : 149>
      <Height : 61>
      <Planes : 1>
      <BitsPerPixel : 24>
      <Comp : 0>
      <ImageSize : 27328>
      <XPixelsPerMeter : 0>
      <YPixelsPerMeter : 0>
      <ColorsInColorTable : 0>
      <ImportantColorCount : 0>
      <RedChannelBitmask [transparent] : 0x>
      <GreenChannelBitmask [transparent] : 0x>
      <BlueChannelBitmask [transparent] : 0x>
      <AlphaChannelBitmask [transparent] : 0x>
      <ColorSpaceType [transparent] : 0>
      <ColorSpaceEndpoints [transparent] : 0>
      <GammaRed [transparent] : 0>
      <GammaGreen [transparent] : 0>
      <GammaBlue [transparent] : 0>
      <Intent [transparent] : 0>
      <ICCProfileData [transparent] : 0>
      <ICCProfileSize [transparent] : 0>
      <Reserved [transparent] : 0x>
         ### ColorTable ###
         <padding : >
         ### PixelArrayBuf ###
          <PixelRowBuf :
           cc 48 3f cc 48 3f cc 48 3f cc 48 3f cc 48 3f cc | b'\xccH?\xccH?\xccH?\xccH?\xccH?\xcc'
           48 3f cc 48 3f cc 48 3f cc 48 3f cc 48 3f cc 48 | b'H?\xccH?\xccH?\xccH?\xccH?\xccH'
           3f cc 48 3f cc 48 3f cc 48 3f cc 48 3f cc 48 3f | b'?\xccH?\xccH?\xccH?\xccH?\xccH?'
           cc 48 3f cc 48 3f cc 48 3f cc 48 3f cc 48 3f cc | b'\xccH?\xccH?\xccH?\xccH?\xccH?\xcc'
           48 3f cc 48 3f cc 48 3f cc 48 3f cc 48 3f cc 48 | b'H?\xccH?\xccH?\xccH?\xccH?\xccH'
           3f cc 48 3f cc 48 3f cc 48 3f cc 48 3f cc 48 3f | b'?\xccH?\xccH?\xccH?\xccH?\xccH?'
           cc 48 3f cc 48 3f cc 48 3f cc 48 3f cc 48 3f cc | b'\xccH?\xccH?\xccH?\xccH?\xccH?\xcc'
           48 3f cc 48 3f cc 48 3f cc 48 3f cc 48 3f cc 48 | b'H?\xccH?\xccH?\xccH?\xccH?\xccH'
           3f cc 48 3f cc 48 3f cc 48 3f cc 48 3f cc 48 3f | b'?\xccH?\xccH?\xccH?\xccH?\xccH?'
           cc 48 3f cc 48 3f cc 48 3f cc 48 3f cc 48 3f cc | b'\xccH?\xccH?\xccH?\xccH?\xccH?\xcc'
           48 3f cc 48 3f cc 48 3f cc 48 3f cc 48 3f cc 48 | b'H?\xccH?\xccH?\xccH?\xccH?\xccH'
           3f cc 48 3f cc 48 3f cc 48 3f cc 48 3f cc 48 3f | b'?\xccH?\xccH?\xccH?\xccH?\xccH?'
           cc 48 3f cc 48 3f cc 48 3f cc 48 3f cc 48 3f cc | b'\xccH?\xccH?\xccH?\xccH?\xccH?\xcc'
           48 3f cc 48 3f cc 48 3f 00 00 00 00 00 00 00 00 | b'H?\xccH?\xccH?\x00\x00\x00\x00\x00\x00\x00\x00'
           00 00 00 00 00 00 00 7f 7f 7f 7f 7f 7f 7f 7f 7f | b'\x00\x00\x00\x00\x00\x00\x00\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f'
           7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f | b'\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f'
           ...>
          <PixelRowBuf :
           cc 48 3f cc 48 3f cc 48 3f cc 48 3f cc 48 3f cc | b'\xccH?\xccH?\xccH?\xccH?\xccH?\xcc'
           48 3f cc 48 3f cc 48 3f cc 48 3f cc 48 3f cc 48 | b'H?\xccH?\xccH?\xccH?\xccH?\xccH'
          
          [...]
          
           3f cc 48 3f cc 48 3f cc 48 3f cc 48 3f cc 48 3f | b'?\xccH?\xccH?\xccH?\xccH?\xccH?'
           cc 48 3f cc 48 3f cc 48 3f cc 48 3f cc 48 3f cc | b'\xccH?\xccH?\xccH?\xccH?\xccH?\xcc'
           48 3f cc 48 3f cc 48 3f 00 00 00 00 00 00 00 00 | b'H?\xccH?\xccH?\x00\x00\x00\x00\x00\x00\x00\x00'
           00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
           00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
           ...>
          <PixelRowBuf :
           00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
           00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
           00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
           00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
           00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
           00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
           00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
           00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
           00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
           00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
           00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
           00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
           00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
           00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
           00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
           00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
           ...>
          <PixelRowBuf :
           00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
           00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
          
          [...]
          
           00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
           00 00 00 00 00 00 00 24 1c ed 24 1c ed 24 1c ed | b'\x00\x00\x00\x00\x00\x00\x00$\x1c\xed$\x1c\xed$\x1c\xed'
           24 1c ed 24 1c ed 24 1c ed 24 1c ed 24 1c ed 24 | b'$\x1c\xed$\x1c\xed$\x1c\xed$\x1c\xed$\x1c\xed$'
           ...>
          <PixelRowBuf :
           4c b1 22 4c b1 22 4c b1 22 4c b1 22 4c b1 22 4c | b'L\xb1"L\xb1"L\xb1"L\xb1"L\xb1"L'
           b1 22 4c b1 22 4c b1 22 4c b1 22 4c b1 22 4c b1 | b'\xb1"L\xb1"L\xb1"L\xb1"L\xb1"L\xb1'
           22 4c b1 22 4c b1 22 4c b1 22 4c b1 22 4c b1 22 | b'"L\xb1"L\xb1"L\xb1"L\xb1"L\xb1"'
           4c b1 22 4c b1 22 4c b1 22 4c b1 22 4c b1 22 4c | b'L\xb1"L\xb1"L\xb1"L\xb1"L\xb1"L'
           b1 22 4c b1 22 4c b1 22 4c b1 22 4c b1 22 4c b1 | b'\xb1"L\xb1"L\xb1"L\xb1"L\xb1"L\xb1'
           22 4c b1 22 4c b1 22 4c b1 22 4c b1 22 4c b1 22 | b'"L\xb1"L\xb1"L\xb1"L\xb1"L\xb1"'
           4c b1 22 4c b1 22 4c b1 22 4c b1 22 4c b1 22 4c | b'L\xb1"L\xb1"L\xb1"L\xb1"L\xb1"L'
           
          [...]
          
           22 4c b1 22 4c b1 22 4c b1 22 4c b1 22 4c b1 22 | b'"L\xb1"L\xb1"L\xb1"L\xb1"L\xb1"'
           4c b1 22 4c b1 22 4c b1 22 4c b1 22 4c b1 22 4c | b'L\xb1"L\xb1"L\xb1"L\xb1"L\xb1"L'
           b1 22 4c b1 22 4c b1 22 00 00 00 00 00 00 00 00 | b'\xb1"L\xb1"L\xb1"\x00\x00\x00\x00\x00\x00\x00\x00'
           00 00 00 00 00 00 00 24 1c ed 24 1c ed 24 1c ed | b'\x00\x00\x00\x00\x00\x00\x00$\x1c\xed$\x1c\xed$\x1c\xed'
           24 1c ed 24 1c ed 24 1c ed 24 1c ed 24 1c ed 24 | b'$\x1c\xed$\x1c\xed$\x1c\xed$\x1c\xed$\x1c\xed$'
           ...>
>>> B.reautomate()
>>> B.to_bytes() == imgbuf
True
>>> # regenerating the image buffer from the parsed structure is OK
>>> # let's modify the number of bits per pixel
>>> B['DIBHeader']['BitsPerPixel'].set_val(16) # instead of 24
>>> B['DIBHeader']['Height'].set_val(int(61*3/2))
>>> open('./crappy_bmp.bmp', 'wb').write( B.to_bytes() )
27382
>>> # let's try the representation of the structure when parsing each pixel value
>>> BMP.BMP._GEN = BMP.BMP._GEN_LPIX
>>> B = BMP.BMP()
>>> B.from_bytes(imgbuf)
>>> print(B.show())
### BMP ###
 ### FileHeader ###
  <Signature : b'BM'>
  <Size : 27382>
  <Reserved : 0x00000000>
  <Offset : 54>
     ### DIBHeader ###
      <DIBHeaderSize : 40>
      <Width : 149>
      <Height : 61>
      <Planes : 1>
      <BitsPerPixel : 24>
      <Comp : 0>
      <ImageSize : 27328>
      <XPixelsPerMeter : 0>
      <YPixelsPerMeter : 0>
      <ColorsInColorTable : 0>
      <ImportantColorCount : 0>
      <RedChannelBitmask [transparent] : 0x>
      <GreenChannelBitmask [transparent] : 0x>
      <BlueChannelBitmask [transparent] : 0x>
      <AlphaChannelBitmask [transparent] : 0x>
      <ColorSpaceType [transparent] : 0>
      <ColorSpaceEndpoints [transparent] : 0>
      <GammaRed [transparent] : 0>
      <GammaGreen [transparent] : 0>
      <GammaBlue [transparent] : 0>
      <Intent [transparent] : 0>
      <ICCProfileData [transparent] : 0>
      <ICCProfileSize [transparent] : 0>
      <Reserved [transparent] : 0x>
         ### ColorTable ###
         <padding : >
         ### PixelArray ###
          ### PixelRowPad ###
           ### PixelRow ###
            <Pixel : 0xcc483f>
            <Pixel : 0xcc483f>
            <Pixel : 0xcc483f>
            <Pixel : 0xcc483f>
            
            [...]
            
            <Pixel : 0x241ced>
            <Pixel : 0x241ced>
            <Pixel : 0x241ced>
            <Pixel : 0x241ced>
            <Pixel : 0x241ced>
            <Pixel : 0x241ced>
           <padding : 0x00>

JPEG

The JPEG file format is a little more complex than previous cases. It is decomposed into a sequence of segments: some of them are holding metadata, some others are holding JPEG compression-related information (e.g. quantization tables, huffman tables), and finally the compressed byte-stream corresponding to the image itself is appended to the Start Of Scan segment.

Here is the representation of the JPEG file in the test directory:

>>> from pycrate_media import JPEG
>>> J = JPEG.JPEG()
>>> imgbuf = open('./test/res/ESP8266.jpg', 'rb').read()
>>> J.from_bytes(imgbuf)
>>> J.reautomate()
>>> J.to_bytes() == imgbuf
True
>>> print(J.show())
### JPEG ###
 ### Segment ###
  <mark : 0xff>
  <type : 216 (Start Of Image)>
  <len [transparent] : 2>
  <pay [transparent] : b''>
 ### Segment ###
  <mark : 0xff>
  <type : 224 (APP0)>
  <len : 16>
  <pay : b'JFIF\x00\x01\x01\x01\x00H\x00H\x00\x00'>
 ### Segment ###
  <mark : 0xff>
  <type : 254 (Comment)>
  <len : 52>
  <pay : b'File source: https://nurdspace.nl/File:ESP8266.jpg'>
 ### Segment ###
  <mark : 0xff>
  <type : 219 (Define Quantization Table(s))>
  <len : 67>
  ### DQT ###
   <Pq : 0>
   <Tq : 0>
   ### QT ###
    <QTe [Quantization table element] : 6>
    <QTe [Quantization table element] : 4>
    
    [...]
    
    <QTe [Quantization table element] : 41>
    <QTe [Quantization table element] : 40>
 ### Segment ###
  <mark : 0xff>
  <type : 219 (Define Quantization Table(s))>
  <len : 67>
  ### DQT ###
   <Pq : 0>
   <Tq : 1>
   ### QT ###
    <QTe [Quantization table element] : 7>
    <QTe [Quantization table element] : 7>
    
    [...]
    
    <QTe [Quantization table element] : 40>
    <QTe [Quantization table element] : 40>
 ### Segment ###
  <mark : 0xff>
  <type : 192 (Start Of Frame (Baseline DCT))>
  <len : 17>
  ### SOF ###
   <P [Sample Precision] : 8>
   <Y [Number of lines] : 195>
   <X [Number of sample per line] : 260>
   <Nf [Number of image components in frame] : 3>
   ### SOFComponents ###
    ### SOFComponent ###
     <C [Component identifier] : 1>
     <H [Horizontal sampling factor] : 2>
     <V [Vertical sampling factor] : 2>
     <Tq [Quantization table destination selector] : 0>
    ### SOFComponent ###
     <C [Component identifier] : 2>
     <H [Horizontal sampling factor] : 1>
     <V [Vertical sampling factor] : 1>
     <Tq [Quantization table destination selector] : 1>
    ### SOFComponent ###
     <C [Component identifier] : 3>
     <H [Horizontal sampling factor] : 1>
     <V [Vertical sampling factor] : 1>
     <Tq [Quantization table destination selector] : 1>
 ### Segment ###
  <mark : 0xff>
  <type : 196 (Define Huffman Table(s))>
  <len : 28>
  ### DHT ###
   <Tc [Huffman table class] : 0>
   <Th [Huffman table destination identifier] : 0>
   <HCL1 [Number of huffman codes of length 1] : 1>
   <HCL2 [Number of huffman codes of length 2] : 0>
   <HCL3 [Number of huffman codes of length 3] : 1>
   <HCL4 [Number of huffman codes of length 4] : 5>
   <HCL5 [Number of huffman codes of length 5] : 1>
   <HCL6 [Number of huffman codes of length 6] : 1>
   <HCL7 [Number of huffman codes of length 7] : 0>
   <HCL8 [Number of huffman codes of length 8] : 0>
   <HCL9 [Number of huffman codes of length 9] : 0>
   <HCL10 [Number of huffman codes of length 10] : 0>
   <HCL11 [Number of huffman codes of length 11] : 0>
   <HCL12 [Number of huffman codes of length 12] : 0>
   <HCL13 [Number of huffman codes of length 13] : 0>
   <HCL14 [Number of huffman codes of length 14] : 0>
   <HCL15 [Number of huffman codes of length 15] : 0>
   <HCL16 [Number of huffman codes of length 16] : 0>
   ### HCV ###
    <HCL1_HCV1 [Value 1 for HCL1] : 0>
    <HCL3_HCV1 [Value 1 for HCL3] : 7>
    <HCL4_HCV1 [Value 1 for HCL4] : 3>
    <HCL4_HCV2 [Value 2 for HCL4] : 4>
    <HCL4_HCV3 [Value 3 for HCL4] : 5>
    <HCL4_HCV4 [Value 4 for HCL4] : 6>
    <HCL4_HCV5 [Value 5 for HCL4] : 8>
    <HCL5_HCV1 [Value 1 for HCL5] : 1>
    <HCL6_HCV1 [Value 1 for HCL6] : 2>
 ### Segment ###
  <mark : 0xff>
  <type : 196 (Define Huffman Table(s))>
  <len : 76>
  ### DHT ###
   <Tc [Huffman table class] : 1>
   <Th [Huffman table destination identifier] : 0>
   <HCL1 [Number of huffman codes of length 1] : 0>
   <HCL2 [Number of huffman codes of length 2] : 1>
   <HCL3 [Number of huffman codes of length 3] : 3>
   <HCL4 [Number of huffman codes of length 4] : 3>
   <HCL5 [Number of huffman codes of length 5] : 2>
   <HCL6 [Number of huffman codes of length 6] : 3>
   <HCL7 [Number of huffman codes of length 7] : 5>
   <HCL8 [Number of huffman codes of length 8] : 4>
   <HCL9 [Number of huffman codes of length 9] : 5>
   <HCL10 [Number of huffman codes of length 10] : 7>
   <HCL11 [Number of huffman codes of length 11] : 9>
   <HCL12 [Number of huffman codes of length 12] : 4>
   <HCL13 [Number of huffman codes of length 13] : 11>
   <HCL14 [Number of huffman codes of length 14] : 0>
   <HCL15 [Number of huffman codes of length 15] : 0>
   <HCL16 [Number of huffman codes of length 16] : 0>
   ### HCV ###
    <HCL2_HCV1 [Value 1 for HCL2] : 1>
    <HCL3_HCV1 [Value 1 for HCL3] : 0>
    
    [...]
    
    <HCL13_HCV10 [Value 10 for HCL13] : 194>
    <HCL13_HCV11 [Value 11 for HCL13] : 240>
 ### Segment ###
  <mark : 0xff>
  <type : 196 (Define Huffman Table(s))>
  <len : 26>
  ### DHT ###
   <Tc [Huffman table class] : 0>
   <Th [Huffman table destination identifier] : 1>
   <HCL1 [Number of huffman codes of length 1] : 1>
   <HCL2 [Number of huffman codes of length 2] : 0>
   <HCL3 [Number of huffman codes of length 3] : 3>
   <HCL4 [Number of huffman codes of length 4] : 1>
   <HCL5 [Number of huffman codes of length 5] : 1>
   <HCL6 [Number of huffman codes of length 6] : 1>
   <HCL7 [Number of huffman codes of length 7] : 0>
   <HCL8 [Number of huffman codes of length 8] : 0>
   <HCL9 [Number of huffman codes of length 9] : 0>
   <HCL10 [Number of huffman codes of length 10] : 0>
   <HCL11 [Number of huffman codes of length 11] : 0>
   <HCL12 [Number of huffman codes of length 12] : 0>
   <HCL13 [Number of huffman codes of length 13] : 0>
   <HCL14 [Number of huffman codes of length 14] : 0>
   <HCL15 [Number of huffman codes of length 15] : 0>
   <HCL16 [Number of huffman codes of length 16] : 0>
   ### HCV ###
    <HCL1_HCV1 [Value 1 for HCL1] : 0>
    <HCL3_HCV1 [Value 1 for HCL3] : 3>
    <HCL3_HCV2 [Value 2 for HCL3] : 4>
    <HCL3_HCV3 [Value 3 for HCL3] : 5>
    <HCL4_HCV1 [Value 1 for HCL4] : 1>
    <HCL5_HCV1 [Value 1 for HCL5] : 2>
    <HCL6_HCV1 [Value 1 for HCL6] : 6>
 ### Segment ###
  <mark : 0xff>
  <type : 196 (Define Huffman Table(s))>
  <len : 55>
  ### DHT ###
   <Tc [Huffman table class] : 1>
   <Th [Huffman table destination identifier] : 1>
   <HCL1 [Number of huffman codes of length 1] : 0>
   <HCL2 [Number of huffman codes of length 2] : 2>
   <HCL3 [Number of huffman codes of length 3] : 2>
   <HCL4 [Number of huffman codes of length 4] : 1>
   <HCL5 [Number of huffman codes of length 5] : 2>
   <HCL6 [Number of huffman codes of length 6] : 3>
   <HCL7 [Number of huffman codes of length 7] : 6>
   <HCL8 [Number of huffman codes of length 8] : 3>
   <HCL9 [Number of huffman codes of length 9] : 6>
   <HCL10 [Number of huffman codes of length 10] : 4>
   <HCL11 [Number of huffman codes of length 11] : 7>
   <HCL12 [Number of huffman codes of length 12] : 0>
   <HCL13 [Number of huffman codes of length 13] : 0>
   <HCL14 [Number of huffman codes of length 14] : 0>
   <HCL15 [Number of huffman codes of length 15] : 0>
   <HCL16 [Number of huffman codes of length 16] : 0>
   ### HCV ###
    <HCL2_HCV1 [Value 1 for HCL2] : 0>
    <HCL2_HCV2 [Value 2 for HCL2] : 1>
    
    [...]
    
    <HCL11_HCV6 [Value 6 for HCL11] : 177>
    <HCL11_HCV7 [Value 7 for HCL11] : 240>
 ### Segment ###
  <mark : 0xff>
  <type : 218 (Start Of Scan)>
  <len : 12>
  ### SOS ###
   <Nf [Number of image components in frame] : 3>
   ### SOSComponents ###
    ### SOSComponent ###
     <Cs [Scan component selector] : 1>
     <Td [DC entropy coding table destination selector] : 0>
     <Ta [AC entropy coding table destination selector] : 0>
    ### SOSComponent ###
     <Cs [Scan component selector] : 2>
     <Td [DC entropy coding table destination selector] : 1>
     <Ta [AC entropy coding table destination selector] : 1>
    ### SOSComponent ###
     <Cs [Scan component selector] : 3>
     <Td [DC entropy coding table destination selector] : 1>
     <Ta [AC entropy coding table destination selector] : 1>
   <Ss [Start of spectral or predictor selection] : 0>
   <Se [End of spectral selection] : 63>
   <Ah [Successive approximation bit position high] : 0>
   <Al [Successive approximation bit position low] : 0>
  <Data :
   ea 85 e8 44 40 11 11 00 44 44 01 11 10 04 44 40 | b'\xea\x85\xe8D@\x11\x11\x00DD\x01\x11\x10\x04D@'
   11 11 00 44 44 01 11 10 04 44 40 11 11 00 44 44 | b'\x11\x11\x00DD\x01\x11\x10\x04D@\x11\x11\x00DD'
   01 11 10 04 44 40 11 11 00 44 44 01 11 10 04 44 | b'\x01\x11\x10\x04D@\x11\x11\x00DD\x01\x11\x10\x04D'
   40 11 11 00 44 44 01 11 10 04 44 40 11 11 00 44 | b'@\x11\x11\x00DD\x01\x11\x10\x04D@\x11\x11\x00D'
   44 01 11 10 04 44 40 11 11 00 44 44 01 11 10 04 | b'D\x01\x11\x10\x04D@\x11\x11\x00DD\x01\x11\x10\x04'
   44 40 11 11 00 44 44 01 11 10 04 44 40 11 11 00 | b'D@\x11\x11\x00DD\x01\x11\x10\x04D@\x11\x11\x00'
   44 44 01 11 10 04 44 40 11 11 00 44 44 01 11 10 | b'DD\x01\x11\x10\x04D@\x11\x11\x00DD\x01\x11\x10'
   04 44 40 11 11 00 44 44 01 11 10 04 44 40 11 11 | b'\x04D@\x11\x11\x00DD\x01\x11\x10\x04D@\x11\x11'
   00 44 44 01 11 10 04 44 40 11 11 00 44 44 01 11 | b'\x00DD\x01\x11\x10\x04D@\x11\x11\x00DD\x01\x11'
   10 04 44 40 10 f4 28 85 01 12 df b8 d1 45 69 bb | b'\x10\x04D@\x10\xf4(\x85\x01\x12\xdf\xb8\xd1Ei\xbb'
   56 d0 1b 44 f2 ba 96 67 c2 5f db 35 a1 c5 a7 19 | b'V\xd0\x1bD\xf2\xba\x96g\xc2_\xdb5\xa1\xc5\xa7\x19'
   03 1e 8b 14 78 fd 46 3f ee 39 bf 68 6f e0 a3 39 | b'\x03\x1e\x8b\x14x\xfdF?\xee9\xbfho\xe0\xa39'
   6c 67 54 f1 36 fb 40 ea b3 4a c6 d4 54 4a e9 1b | b'lgT\xf16\xfb@\xea\xb3J\xc6\xd4TJ\xe9\x1b'
   19 91 d8 12 63 01 a3 ae 49 0b 43 bf d3 ba d5 77 | b'\x19\x91\xd8\x12c\x01\xa3\xaeI\x0bC\xbf\xd3\xba\xd5w'
   aa a2 ed 44 a2 27 96 87 81 8e 61 e0 71 e0 b7 a9 | b"\xaa\xa2\xedD\xa2'\x96\x87\x81\x8ea\xe0q\xe0\xb7\xa9"
   d3 68 a5 28 d4 fe 7d aa 4f 9b f1 30 e7 6e b1 27 | b"\xd3h\xa5(\xd4\xfe}\xaaO\x9b\xf10\xe7n\xb1'"
   ...>
 ### Segment ###
  <mark : 0xff>
  <type : 217 (End Of Image)>
  <len [transparent] : 2>
  <pay [transparent] : b''>
>>> J[2] # checking the metadata
<Segment : <mark : 0xff><type : 254 (Comment)><len : 52><pay : b'File source: https://nurdspace.nl/File:ESP8266.jpg'>>
>>> J[3]['type']
<type : 219 (Define Quantization Table(s))>
>>> J[4]['type']
<type : 219 (Define Quantization Table(s))>
>>> let's corrupt the quantization tables
>>> J[3]['DQT']['QT'].set_val( 64*[220] )
>>> J[4]['DQT']['QT'].set_val( 64*[5] )
>>> open('./crappy_jpeg.jpg', 'wb').write( J.to_bytes() )
6786

GIF

GIF is not only an image format, it can also contain animation, non-rectangular images and transparency area... The test file provided is actually an animated GIF (an animated nyancat, more exactly).

The GIF encoding consists in providing a global screen descriptor and color table (a common palette for all frames of the animated GIF) and then a sequence of frames, each consisting in a local header with some control parameters and a serie of 255-bytes data sub-blocks containing a slightly compressed representation of each image of the animation.

Let's check how it works in pycrate:

>>> from pycrate_media import GIF
>>> G = GIF.GIF()
>>> imgbuf = open('./test/res/nyancat.gif', 'rb').read()
>>> G.from_bytes(imgbuf)
>>> G.reautomate()
>>> G.to_bytes() == imgbuf
True
>>> print(G.show())
### GIF ###
 ### GIFHeader ###
  ### Header ###
   <Signature : b'GIF'>
   <Version : b'89a'>
  ### LogicalScreenDescriptor ###
   <Width : 240>
   <Height : 152>
   <GlobalColorTableFlag : 1>
   <ColorResolution : 7>
   <SortFlag : 0>
   <SizeOfGlobalColorTable : 7>
   <BackgroundColorIndex : 255>
   <PixelAspectRatio : 0>
  ### GlobalColorTable ###
   ### ColorTriplet ###
    <Red : 69>
    <Green : 254>
    <Blue : 7>
   ### ColorTriplet ###
    <Red : 56>
    <Green : 255>
    <Blue : 8>
    
   [...] 
    
   ### ColorTriplet ###
    <Red : 14>
    <Green : 69>
    <Blue : 114>
   ### ColorTriplet ###
    <Red : 255>
    <Green : 255>
    <Blue : 255>
     ### ApplicationExtension ###
      <ExtensionIntroducer : 33>
      <ExtensionLabel : 255>
      <BlockSize : 11>
      <ApplicationIdentifier : b'NETSCAPE'>
      <ApplicationAuthenticationCode : b'2.0'>
      ### ApplicationData ###
       ### DataSubBlock ###
        <Size : 3>
        <DataValues :
         01 00 00                                        | b'\x01\x00\x00'>
       ### DataSubBlock ###
        <Size : 0>
        <DataValues : >
     ### ApplicationExtension ###
      <ExtensionIntroducer : 33>
      <ExtensionLabel : 255>
      <BlockSize : 11>
      <ApplicationIdentifier : b'XMP Data'>
      <ApplicationAuthenticationCode : b'XMP'>
      ### ApplicationData ###
       ### DataSubBlock ###
        <Size : 60>
        <DataValues :
         3f 78 70 61 63 6b 65 74 20 62 65 67 69 6e 3d 22 | b'?xpacket begin="'
         ef bb bf 22 20 69 64 3d 22 57 35 4d 30 4d 70 43 | b'\xef\xbb\xbf" id="W5M0MpC'
         65 68 69 48 7a 72 65 53 7a 4e 54 63 7a 6b 63 39 | b'ehiHzreSzNTczkc9'
         64 22 3f 3e 20 3c 78 3a 78 6d 70 6d             | b'd"?> <x:xmpm'>
       ### DataSubBlock ###
        <Size : 101>
        <DataValues :
         74 61 20 78 6d 6c 6e 73 3a 78 3d 22 61 64 6f 62 | b'ta xmlns:x="adob'
         65 3a 6e 73 3a 6d 65 74 61 2f 22 20 78 3a 78 6d | b'e:ns:meta/" x:xm'
         70 74 6b 3d 22 41 64 6f 62 65 20 58 4d 50 20 43 | b'ptk="Adobe XMP C'
         6f 72 65 20 35 2e 30 2d 63 30 36 30 20 36 31 2e | b'ore 5.0-c060 61.'
         31 33 34 37 37 37 2c 20 32 30 31 30 2f 30 32 2f | b'134777, 2010/02/'
         31 32 2d 31 37 3a 33 32 3a 30 30 20 20 20 20 20 | b'12-17:32:00     '
         20 20 20 22 3e                                  | b'   ">'>
    
       [...]
    
       ### DataSubBlock ###
        <Size : 0>
        <DataValues : >
     ### GraphicControlExtension ###
      <ExtensionIntroducer : 33>
      <GraphicControlLabel : 249>
      <BlockSize : 4>
      <Reserved : 0>
      <DisposalMethod : 1>
      <UserInputFlag : 0>
      <TransparentColorFlag : 1>
      <DelayTime : 5>
      <TransparentColorIndex : 255>
      <BlockTerminator : 0>
     ### GIFImage ###
      ### ImageDescriptor ###
       <ImageSeparator : 44>
       <ImageLeftPosition : 0>
       <ImageTopPosition : 0>
       <ImageWidth : 240>
       <ImageHeight : 152>
       <LocalColorTableFlag : 0>
       <InterlaceFlag : 0>
       <SortFlag : 0>
       <Reserved : 0b00>
       <SizeOfLocalColorTable : 0>
      ### LocalColorTable [transparent] ###
      ### TableBasedImageData ###
       <LZWMinimumCodeSize : 8>
       ### ImageData ###
        ### DataSubBlock ###
         <Size : 255>
         <DataValues :
          00 1b 08 f0 47 90 e0 c0 65 fe 04 28 5c 28 80 9f | b'\x00\x1b\x08\xf0G\x90\xe0\xc0e\xfe\x04(\\(\x80\x9f'
          c3 86 0f f9 35 14 20 82 e1 c0 82 18 33 6a dc c8 | b'\xc3\x86\x0f\xf95\x14 \x82\xe1\xc0\x82\x183j\xdc\xc8'
          b1 23 46 8b 12 1d f2 f3 d8 51 a2 80 0e 0b 06 a8 | b'\xb1#F\x8b\x12\x1d\xf2\xf3\xd8Q\xa2\x80\x0e\x0b\x06\xa8'
          1c 70 62 00 9e 4f 15 5e b5 9c c9 f2 95 08 93 16 | b'\x1cpb\x00\x9eO\x15^\xb5\x9c\xc9\xf2\x95\x08\x93\x16'
          15 92 34 c8 30 a3 c5 9d 40 35 2a 1c 19 74 a7 4e | b'\x15\x924\xc80\xa3\xc5\x9d@5*\x1c\x19t\xa7N'
          7f 0d 1a 74 1c b8 90 c6 40 7e ef 46 4a 4d d8 e0 | b'\x7f\r\x1at\x1c\xb8\x90\xc6@~\xefFJM\xd8\xe0'
          26 c5 85 44 8b 6a 0d 8a f3 a6 bf a9 5b bf 26 44 | b'&\xc5\x85D\x8bj\r\x8a\xf3\xa6\xbf\xa9[\xbf&D'
          b9 72 e5 84 58 15 1a 94 5d 69 53 80 40 81 0a 2b | b'\xb9r\xe5\x84X\x15\x1a\x94]iS\x80@\x81\n+'
          16 bd 2a c2 67 cf b0 40 2f e2 e5 78 30 57 83 ac | b'\x16\xbd*\xc2g\xcf\xb0@/\xe2\xe5x0W\x83\xac'
          06 13 26 cc 69 52 a4 c8 89 38 8f ee 5d fc 31 24 | b'\x06\x13&\xcciR\xa4\xc8\x898\x8f\xee]\xfc1$'
          c4 90 78 45 76 98 40 81 c2 8f ca 14 14 4c c0 53 | b'\xc4\x90xEv\x98@\x81\xc2\x8f\xca\x14\x14L\xc0S'
          e6 72 65 6f 96 5f f1 71 7c 18 b0 c7 9c 88 15 52 | b'\xe6reo\x96_\xf1q|\x18\xb0\xc7\x9c\x88\x15R'
          d3 49 4d 30 63 8c 26 5f 7f 1c 38 2e a9 52 8d ef | b'\xd3IM0c\x8c&_\x7f\x1c8.\xa9R\x8d\xef'
          0c e6 5a f8 4e 40 ef a8 c0 1f 56 8d db 50 b6 ec | b'\x0c\xe6Z\xf8N@\xef\xa8\xc0\x1fV\x8d\xdbP\xb6\xec'
          a9 c8 23 7f e5 d7 a1 79 87 0a 43 2a 40 50 09 01 | b'\xa9\xc8#\x7f\xe5\xd7\xa1y\x87\nC*@P\t\x01'
          66 87 5f cf 9d 0a cc 25 32 6c e2 ab 0a 7f fb    | b'f\x87_\xcf\x9d\n\xcc%2l\xe2\xab\n\x7f\xfb'>
        ### DataSubBlock ###
         <Size : 255>
         <DataValues :
          1e df db 78 60 f3 06 73 27 d5 1b 18 a1 45 a7 0c | b"\x1e\xdf\xdbx`\xf3\x06s'\xd5\x1b\x18\xa1E\xa7\x0c"
          4b 4f ac 78 17 bd f7 90 11 1d 46 9e 48 9c 1f 4c | b'KO\xacx\x17\xbd\xf7\x90\x11\x1dF\x9eH\x9c\x1fL'
        
         [...]
        
          05 58 e6 eb b1 46 e7 de c5 ec 33 19 02 80 2c 30 | b'\x05X\xe6\xeb\xb1F\xe7\xde\xc5\xec3\x19\x02\x80,0'
          d8 0e 6b 96 66 d5 da 9e 51 d0 ae 6d 4e 0d 08    | b'\xd8\x0ek\x96f\xd5\xda\x9eQ\xd0\xaemN\r\x08'>
        ### DataSubBlock ###
         <Size : 0>
         <DataValues : >
     ### GraphicControlExtension ###
      <ExtensionIntroducer : 33>
      <GraphicControlLabel : 249>
      <BlockSize : 4>
      <Reserved : 0>
      <DisposalMethod : 1>
      <UserInputFlag : 0>
      <TransparentColorFlag : 1>
      <DelayTime : 10>
      <TransparentColorIndex : 255>
      <BlockTerminator : 0>
     ### GIFImage ###
      ### ImageDescriptor ###
       <ImageSeparator : 44>
       <ImageLeftPosition : 0>
       <ImageTopPosition : 0>
       <ImageWidth : 240>
       <ImageHeight : 152>
       <LocalColorTableFlag : 0>
       <InterlaceFlag : 0>
       <SortFlag : 0>
       <Reserved : 0b00>
       <SizeOfLocalColorTable : 0>
      ### LocalColorTable [transparent] ###
      ### TableBasedImageData ###
       <LZWMinimumCodeSize : 8>
       ### ImageData ###
        ### DataSubBlock ###
         <Size : 255>
         <DataValues :
          00 ff 09 1c 48 b0 e0 40 7f 08 ff 21 4c 68 b0 a1 | b'\x00\xff\t\x1cH\xb0\xe0@\x7f\x08\xff!Lh\xb0\xa1'
          c3 87 10 23 12 14 20 e2 d3 ab 13 27 06 64 d4 f8 | b"\xc3\x87\x10#\x12\x14 \xe2\xd3\xab\x13'\x06d\xd4\xf8"
         
         [...]
>>> # Let's make the nyancat GIF black and white !
>>> G['GIFHeader']['GlobalColorTable'].set_val( 128*[[0, 0, 0]] + 128*[[255, 255, 255]] )
>>> open('./crappy_gif.gif', 'wb').write( G.to_bytes() )
75416

TIFF

The TIFF format is rather old, and under the property of Adobe. It can embed almsot any kind of data, even if it is used for storing images. The structure of a TIFF file is not linear: there is an initial header which indicates the endianness of the file (yep, you can do LE or BE TIFF files), a signature (42), and an offset to an area in the file which contains a list of IFD entries. Each IFD corresponds to an image parameter or to metadata, the value can be set sequentially, or on offset can refer to another area in the file (for large IFD values). Finally, IFD with tag 273 (strips offsets) and 279 (strips size) defines area in the file were the so-called strips are stores.

The strips themselves contain the data corresponding to the image. Several IFDs can be stored into a file, hence defining several series of strips, themselves containing several images, frames or whatever...

>>> from pycrate_media import TIFF
>>> T = TIFF.TIFF()
>>> imgbuf = open('./test/res/xkcd_phone_2.tiff', 'rb').read()
>>> T.from_bytes(imgbuf)
>>> T.reautomate()
>>> T.to_bytes() == imgbuf
True
>>> print(T.show())
### TIFF ###
 ### Header_LE ###
  <BO [byte order] : b'II' (little endian)>
  <FourtyTwo : 42>
  <IFDOffset [ImageFileDir offset] : 44188>
 <IFD0_Strip0 :
  78 9c ed 5c 79 4c 14 c9 db 7e 7a 66 32 1c 43 80 | b'x\x9c\xed\\yL\x14\xc9\xdb~zf2\x1cC\x80'
  11 08 08 f2 81 c8 12 b9 0c 82 e8 87 72 44 05 31 | b'\x11\x08\x08\xf2\x81\xc8\x12\xb9\x0c\x82\xe8\x87rD\x051'
  a2 60 40 50 e3 81 86 05 8f 88 ab 1b 15 d1 28 1e | b'\xa2`@P\xe3\x81\x86\x05\x8f\x88\xab\x1b\x15\xd1(\x1e'
  df 2a b2 66 f1 8a 88 c7 0f 45 8d c8 2e c6 3b de | b'\xdf*\xb2f\xf1\x8a\x88\xc7\x0fE\x8d\xc8.\xc6;\xde'
  46 45 8d 8a 47 50 d4 a8 08 1b 04 31 ca 19 41 20 | b'FE\x8d\x8aGP\xd4\xa8\x08\x1b\x041\xca\x19A '
  c3 d4 57 55 3d 83 e2 ae cb 70 ac fb 5b e1 f9 a3 | b'\xc3\xd4WU=\x83\xe2\xae\xcbp\xac\xfb[\xe1\xf9\xa3'
  ab ba 8e ee ea 7a aa ea 7d df 3a da 17 3d e8 16 | b'\xab\xba\x8e\xee\xeaz\xaa\xea}\xdf:\xda\x17=\xe8\x16'
  f8 5f 48 94 3d e8 06 90 02 0e a4 07 dd 00 5e 3d | b'\xf8_H\x94=\xe8\x06\x90\x02\x0e\xa4\x07\xdd\x00^='
  4c 77 13 f4 30 dd 5d d0 c3 74 77 41 0f d3 dd 05 | b'Lw\x13\xf40\xdd]\xd0\xc3twA\x0f\xd3\xdd\x05'
  3d 4c 77 17 f4 30 dd 5d d0 c3 74 77 41 0f d3 dd | b'=Lw\x17\xf40\xdd]\xd0\xc3twA\x0f\xd3\xdd'
  05 3d 4c 77 17 f4 30 dd 5d d0 c3 74 77 41 0f d3 | b'\x05=Lw\x17\xf40\xdd]\xd0\xc3twA\x0f\xd3'
  dd 05 3d 4c 77 17 f4 30 dd 5d d0 c3 74 77 41 0f | b'\xdd\x05=Lw\x17\xf40\xdd]\xd0\xc3twA\x0f'
  d3 1d 45 d1 85 dc da 7f ba 0c ed 41 17 31 5d 7f | b'\xd3\x1dE\xd1\x85\xdc\xda\x7f\xba\x0c\xedA\x171]\x7f'
  ee 4d 17 3c e5 9f 43 ed 85 f4 e4 8c 73 ef 75 4e | b'\xeeM\x17<\xe5\x9fC\xed\x85\xf4\xe4\x8cs\xefuN'
  5f b1 cc 11 80 6c a9 9a 90 f2 ec 35 09 69 15 7f | b'_\xb1\xcc\x11\x80l\xa9\x9a\x90\xf2\xec5\ti\x15\x7f'
  63 d9 ba 08 5d c3 f4 4b 5b e8 6f e7 be 33 45 ad | b'c\xd9\xba\x08]\xc3\xf4K[\xe8o\xe7\xbe3E\xad'
  ...>
 <IFD0_Strip1 :
  78 9c dd 5d 79 4c 14 c9 db 7e e6 08 77 18 66 80 | b'x\x9c\xdd]yL\x14\xc9\xdb~\xe6\x08w\x18f\x80'
  80 22 01 41 08 22 12 14 8f 08 22 c1 1d c1 08 8a | b'\x80"\x01A\x08"\x12\x14\x8f\x08"\xc1\x1d\xc1\x08\x8a'
 
 [...]
 
  de 8f 53 d4 b5 95 f2 42 e9 d5 46 af 5e 65 1a ed | b'\xde\x8fS\xd4\xb5\x95\xf2B\xe9\xd5F\xaf^e\x1a\xed'
  50 a3 63 ac a3 9f bb 27 e4 1a 69 c2 5a 4f aa b0 | b"P\xa3c\xac\xa3\x9f\xbb'\xe4\x1ai\xc2ZO\xaa\xb0"
  ...>
 <IFD0_Strip8 :
  78 9c ed d1 41 0d 00 20 0c 04 c1 7b 90 e0 a3 16 | b'x\x9c\xed\xd1A\r\x00 \x0c\x04\xc1{\x90\xe0\xa3\x16'
  1a 12 fc 1b 83 fa d8 1d 0b 93 7a 02 e8 c4 69 04 | b'\x1a\x12\xfc\x1b\x83\xfa\xd8\x1d\x0b\x93z\x02\xe8\xc4i\x04'
  a7 29 9c a6 70 9a c2 69 0a a7 29 9c a6 98 e9 55 | b'\xa7)\x9c\xa6p\x9a\xc2i\n\xa7)\x9c\xa6\x98\xe9U'
  02 d8 b9 11 c2 f9 af bd 65 5e                   | b'\x02\xd8\xb9\x11\xc2\xf9\xaf\xbde^'>
 ### IFD0_LE ###
  <Num : 17>
  ### IFDEntries ###
   ### IFDEntry_LE ###
    <Tag : 254 (NewSubfileType)>
    <Type : 4 (LONG)>
    <Count : 1>
    ### Val ###
     <LONG : 0>
   ### IFDEntry_LE ###
    <Tag : 256 (ImageWidth)>
    <Type : 3 (SHORT)>
    <Count : 1>
    ### Val ###
     <SHORT : 490>
    <Undef : 0x0000>
   ### IFDEntry_LE ###
    <Tag : 257 (ImageLength)>
    <Type : 3 (SHORT)>
    <Count : 1>
    ### Val ###
     <SHORT : 522>
    <Undef : 0x0000>
   ### IFDEntry_LE ###
    <Tag : 258 (BitsPerSample)>
    <Type : 3 (SHORT)>
    <Count : 1>
    ### Val ###
     <SHORT : 8>
    <Undef : 0x0000>
   ### IFDEntry_LE ###
    <Tag : 259 (Compression)>
    <Type : 3 (SHORT)>
    <Count : 1>
    ### Val ###
     <SHORT : 8>
    <Undef : 0x0000>
   ### IFDEntry_LE ###
    <Tag : 262 (PhotometricInterpretation)>
    <Type : 3 (SHORT)>
    <Count : 1>
    ### Val ###
     <SHORT : 1>
    <Undef : 0x0000>
   ### IFDEntry_LE ###
    <Tag : 269>
    <Type : 2 (ASCII)>
    <Count : 46>
    <ValRef : 44486>
   ### IFDEntry_LE ###
    <Tag : 273 (StripOffsets)>
    <Type : 4 (LONG)>
    <Count : 9>
    <ValRef : 44450>
   ### IFDEntry_LE ###
    <Tag : 274 (Orientation)>
    <Type : 3 (SHORT)>
    <Count : 1>
    ### Val ###
     <SHORT : 1>
    <Undef : 0x0000>
   ### IFDEntry_LE ###
    <Tag : 277 (SamplesPerPixel)>
    <Type : 3 (SHORT)>
    <Count : 1>
    ### Val ###
     <SHORT : 1>
    <Undef : 0x0000>
   ### IFDEntry_LE ###
    <Tag : 278 (RowsPerStrip)>
    <Type : 3 (SHORT)>
    <Count : 1>
    ### Val ###
     <SHORT : 64>
    <Undef : 0x0000>
   ### IFDEntry_LE ###
    <Tag : 279 (StripByteCounts)>
    <Type : 4 (LONG)>
    <Count : 9>
    <ValRef : 44414>
   ### IFDEntry_LE ###
    <Tag : 282 (XResolution)>
    <Type : 5 (RATIONAL)>
    <Count : 1>
    <ValRef : 44398>
   ### IFDEntry_LE ###
    <Tag : 283 (YResolution)>
    <Type : 5 (RATIONAL)>
    <Count : 1>
    <ValRef : 44406>
   ### IFDEntry_LE ###
    <Tag : 284 (PlanarConfiguration)>
    <Type : 3 (SHORT)>
    <Count : 1>
    ### Val ###
     <SHORT : 1>
    <Undef : 0x0000>
   ### IFDEntry_LE ###
    <Tag : 296 (ResolutionUnit)>
    <Type : 3 (SHORT)>
    <Count : 1>
    ### Val ###
     <SHORT : 2>
    <Undef : 0x0000>
   ### IFDEntry_LE ###
    <Tag : 34675>
    <Type : 7 (UNDEFINED)>
    <Count : 912>
    <ValRef : 44532>
  <NextIFDOffset : 0>
 ### IFD0_Tag282_Val ###
  ### RATIONAL ###
   <num : 4294967295>
   <den : 53680379>
 ### IFD0_Tag283_Val ###
  ### RATIONAL ###
   <num : 4294967295>
   <den : 53680379>
 ### IFD0_Tag279_Val ###
  <LONG : 5793>
  <LONG : 5363>
  <LONG : 6574>
  <LONG : 4640>
  <LONG : 4922>
  <LONG : 7093>
  <LONG : 3297>
  <LONG : 6440>
  <LONG : 58>
 ### IFD0_Tag273_Val ###
  <LONG : 8>
  <LONG : 5801>
  <LONG : 11164>
  <LONG : 17738>
  <LONG : 22378>
  <LONG : 27300>
  <LONG : 34393>
  <LONG : 37690>
  <LONG : 44130>
 <IFD0_Tag269_Val [ASCII buffer] : b'/home/omer/Downloads/images/xkcd_phone_2.tiff\x00'>
 <IFD0_Tag34675_Val [UNDEFINED buffer] :
  00 00 03 90 41 44 42 45 02 10 00 00 70 72 74 72 | b'\x00\x00\x03\x90ADBE\x02\x10\x00\x00prtr'
  47 52 41 59 58 59 5a 20 07 cf 00 06 00 03 00 00 | b'GRAYXYZ \x07\xcf\x00\x06\x00\x03\x00\x00'
  
 [...]
 
  74 65 78 74 00 00 00 00 43 6f 70 79 72 69 67 68 | b'text\x00\x00\x00\x00Copyrigh'
  74 20 31 39 39 39 20 41 64 6f 62 65 20 53 79 73 | b't 1999 Adobe Sys'
  74 65 6d 73 20 49 6e 63 6f 72 70 6f 72 61 74 65 | b'tems Incorporate'
  64 00 00 00 64 65 73 63 00 00 00 00 00 00 00 0d | b'd\x00\x00\x00desc\x00\x00\x00\x00\x00\x00\x00\r'
  ...>
>>> T['IFD0_LE']['IFDEntries'][8]
<IFDEntry_LE : <Tag : 274 (Orientation)><Type : 3 (SHORT)><Count : 1><Val : <SHORT : 1>><Undef : 0x0000>>
>>> T['IFD0_LE']['IFDEntries'][8]['Val'].CLASS
'Array'
>>> T['IFD0_LE']['IFDEntries'][8]['Val']()
[1]
>>> # let's revert the image
>>> T['IFD0_LE']['IFDEntries'][8]['Val'].set_val( [2] )
>>> open('./reverted_tiff.tiff', 'wb').write( T.to_bytes() )
45444

MP3

MP3 has won the battle of compressed audio formats at the end of the 90's, and is still broadly used for storing music. The MP3 file format is built with streaming in mind: an MP3 file is a simple sequence of frames. Each frame is made of an header with information about the type of frame and compression used, and a block of data containing the compressed audio.

There is not much to say about the MP3 format itself. What is much more tricky is how metadata are inserted into MP3 files through ID3 tags. There are two versions of them:

  • ID3v1 and v1 extended
  • ID3v2

Both versions are made so that they can be introduced into a sequence of audio frames: there is a global frame delimiter that enables to distinguish audio frames, ID3v1, v1 extended and v2 frames. The ID3v2 format can lead to complex parsing. It is also made of an header and a block of data containing ID3v2 subframes, each one corresponding to a kind of metadata that can be edited quite freely.

>>> from pycrate_media import MP3
>>> M = MP3.MP3()
>>> audiobuf = open('./test/res/snare.mp3', 'rb').read()
>>> M.from_bytes(audiobuf)
>>> M.reautomate()
>>> M.to_bytes() == audiobuf
True
>>> print(M.show())
### MP3 ###
 ### ID3V2 ###
  ### ID3V2Header ###
   <ID3 : b'ID3'>
   <Version : 0x0300>
   <Unsynchronisation : 0>
   <ExtendedHeader : 0>
   <ExperimentalIndicator : 0>
   <Footer : 0>
   <Undefined : 0>
   <Size : 1124>
      ### ID3V2Frames ###
       ### ID3V2Frame ###
        <FrameID : b'TRCK'>
        <Size : 5>
        <Flags : 0b0000000000000000>
        <Data :
         01 ff fe 31 00                                  | b'\x01\xff\xfe1\x00'>
       ### ID3V2Frame ###
        <FrameID : b'TCON'>
        <Size : 15>
        <Flags : 0b0000000000000000>
        <Data :
         01 ff fe 73 00 6f 00 75 00 6e 00 64 00 73 00    | b'\x01\xff\xfes\x00o\x00u\x00n\x00d\x00s\x00'>
       ### ID3V2Frame ###
        <FrameID : b'COMM'>
        <Size : 50>
        <Flags : 0b0000000000000000>
        <Data :
         01 66 72 61 ff fe 00 00 ff fe 77 00 77 00 77 00 | b'\x01fra\xff\xfe\x00\x00\xff\xfew\x00w\x00w\x00'
         2e 00 64 00 76 00 64 00 76 00 69 00 64 00 65 00 | b'.\x00d\x00v\x00d\x00v\x00i\x00d\x00e\x00'
         6f 00 73 00 6f 00 66 00 74 00 2e 00 63 00 6f 00 | b'o\x00s\x00o\x00f\x00t\x00.\x00c\x00o\x00'
         6d 00                                           | b'm\x00'>
      <ID3V2Padding :
       00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
       00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
       
       [...]
       
       00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
       00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
       ...>
 ### MPEGFrame ###
  ### Header ###
   <FrameSync : 0xffe>
   <Version : 3 (MPEG version 1)>
   <Layer : 1 (Layer III)>
   <CRCBit : 1>
   <Bitrate : 14 (320)>
   <SamplingRate : 1 (48000)>
   <PaddingBit : 0>
   <PrivateBit : 0>
   <ChannelMode : 1 (Joint stereo)>
   <ModeExtension : 2>
   <Copyright : 0>
   <Original : 1>
   <Emphasis : 0 (None)>
      <Data :
       00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
       00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
       49 6e 66 6f 00 00 00 0f 00 00 00 08 00 00 21 c0 | b'Info\x00\x00\x00\x0f\x00\x00\x00\x08\x00\x00!\xc0'
       00 20 20 20 20 20 20 20 20 20 20 20 20 40 40 40 | b'\x00            @@@'
       40 40 40 40 40 40 40 40 40 60 60 60 60 60 60 60 | b'@@@@@@@@@```````'
       60 60 60 60 60 60 80 80 80 80 80 80 80 80 80 80 | b'``````\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80'
       80 80 a0 a0 a0 a0 a0 a0 a0 a0 a0 a0 a0 a0 a0 c0 | b'\x80\x80\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xc0'
       c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 e0 e0 e0 e0 e0 | b'\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xe0\xe0\xe0\xe0\xe0'
       e0 e0 e0 e0 e0 e0 e0 e0 ff ff ff ff ff ff ff ff | b'\xe0\xe0\xe0\xe0\xe0\xe0\xe0\xe0\xff\xff\xff\xff\xff\xff\xff\xff'
       ff ff ff ff 00 00 00 39 4c 41 4d 45 33 2e 39 39 | b'\xff\xff\xff\xff\x00\x00\x009LAME3.99'
       72 01 cd 00 00 00 00 00 00 00 00 34 ff 24 00 00 | b'r\x01\xcd\x00\x00\x00\x00\x00\x00\x00\x004\xff$\x00\x00'
       8d 00 01 40 00 00 21 c0 a4 0b 5b d2 00 00 00 00 | b'\x8d\x00\x01@\x00\x00!\xc0\xa4\x0b[\xd2\x00\x00\x00\x00'
       00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
       
       [...]
       
       00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
       00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
       ...>
 
 [...]
 
 ### MPEGFrame ###
  ### Header ###
   <FrameSync : 0xffe>
   <Version : 3 (MPEG version 1)>
   <Layer : 1 (Layer III)>
   <CRCBit : 1>
   <Bitrate : 14 (320)>
   <SamplingRate : 1 (48000)>
   <PaddingBit : 0>
   <PrivateBit : 0>
   <ChannelMode : 1 (Joint stereo)>
   <ModeExtension : 2>
   <Copyright : 0>
   <Original : 1>
   <Emphasis : 0 (None)>
      <Data :
       27 87 fa 19 60 47 a3 7a cb 70 81 ae e8 15 0c 23 | b"'\x87\xfa\x19`G\xa3z\xcbp\x81\xae\xe8\x15\x0c#"
       26 6a b5 df 02 ad 67 0f ca 15 bc 20 40 33 0e 71 | b'&j\xb5\xdf\x02\xadg\x0f\xca\x15\xbc @3\x0eq'
       [...]
       12 b6 93 fc 86 43 60 33 18 11 26 54 d0 2e 19 a8 | b'\x12\xb6\x93\xfc\x86C`3\x18\x11&T\xd0.\x19\xa8'
       08 10 33 68 04 c8 36 d4 4c 50 32 03 93 0e 88 4d | b'\x08\x103h\x04\xc86\xd4LP2\x03\x93\x0e\x88M'
       ...>
 ### ID3V1 ###
  <TAG : b'TAG'>
  <Title : b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'>
  <Artist : b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'>
  <Album : b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'>
  <Year : b'\x00\x00\x00\x00'>
  <Comment : b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'>
  <Genre : b'\xff'>
>>> for frame in M[1:-1]: print(frame['Header']['Bitrate'])
<Bitrate : 14 (320)>
<Bitrate : 14 (320)>
<Bitrate : 14 (320)>
<Bitrate : 14 (320)>
<Bitrate : 14 (320)>
<Bitrate : 14 (320)>
<Bitrate : 14 (320)>
<Bitrate : 14 (320)>
<Bitrate : 14 (320)>
>>> # let's downgrade the bitrate of all audio frames
>>> for frame in M[1:-1]: frame['Header']['Bitrate'].set_val(1)
>>> for frame in M[1:-1]: print(frame['Header']['Bitrate'])
<Bitrate : 1 (32)>
<Bitrate : 1 (32)>
<Bitrate : 1 (32)>
<Bitrate : 1 (32)>
<Bitrate : 1 (32)>
<Bitrate : 1 (32)>
<Bitrate : 1 (32)>
<Bitrate : 1 (32)>
<Bitrate : 1 (32)>
>>> open('./crappy_snare.mp3', 'wb').write( M.to_bytes() )
9902

MPEG4

MPEG4 is a multimedia container format associated with compression methods for audio and video. An MPEG4 file is a sequence of Atoms, in the form size-type-data, where atoms can embed atoms recursively... Many atoms' types exist, identified by 4 letters acronyms (e.g. ftyp, moov, sync, mdat, ...).

The mdat atom contains the compressed media. The moov atom contains several embedded atoms, 3 of them beeing trak atoms for our example file, corresponding to one video track and two other tracks (identified by the media handler sdsm and odsm). Moreover, within each trak atom, we will find the minf atom which contains information to extract the media from the mdat atom, in particular the stbl atom (which stands for sample table) which can contain the stsz (for sample size) and stco (for chunk offset) atoms. This enables to extract each track from the mdat atom properly.

>>> from pycrate_media import MPEG4
>>> M = MPEG4.MPEG4()
>>> videobuf = open('./test/res/Simulation_of_Kepler_Supernova_Explosion.mp4', 'rb').read()
>>> M.from_bytes(videobuf)
>>> M.reautomate()
>>> M.to_bytes() == videobuf
>>> print(M.show())
### MPEG4 ###
 ### Atom ###
  <size : 40>
  <type : b'ftyp'>
  <data :
   6d 70 34 32 00 00 00 01 69 73 6f 6d 69 73 6f 32 | b'mp42\x00\x00\x00\x01isomiso2'
   61 76 63 31 6d 70 34 31 6d 70 34 32 33 67 70 35 | b'avc1mp41mp423gp5'>
 ### Atom ###
  <size : 6467>
  <type : b'moov'>
  ### data ###
   ### Atom ###
    <size : 108>
    <type : b'mvhd'>
    <data :
     00 00 00 00 7c 25 b0 80 7c 25 b0 80 00 00 03 e8 | b'\x00\x00\x00\x00|%\xb0\x80|%\xb0\x80\x00\x00\x03\xe8'
     00 00 33 6f 00 01 00 00 01 00 00 00 00 00 00 00 | b'\x00\x003o\x00\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00'
     00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
     00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
     00 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00 | b'\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
     00 00 00 c9                                     | b'\x00\x00\x00\xc9'>
   ### Atom ###
    <size : 33>
    <type : b'iods'>
    <data :
     00 00 00 00 10 13 00 4f 01 01 fe fe 01 0e 04 00 | b'\x00\x00\x00\x00\x10\x13\x00O\x01\x01\xfe\xfe\x01\x0e\x04\x00'
     00 00 01 0e 04 00 00 00 02                      | b'\x00\x00\x01\x0e\x04\x00\x00\x00\x02'>
   ### Atom ###
    <size : 5341>
    <type : b'trak'>
    ### data ###
     ### Atom ###
      <size : 92>
      <type : b'tkhd'>
      <data :
       00 00 00 0f 7c 25 b0 80 cd 6b 88 22 00 00 00 c9 | b'\x00\x00\x00\x0f|%\xb0\x80\xcdk\x88"\x00\x00\x00\xc9'
       00 00 00 00 00 00 33 6f 00 00 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x003o\x00\x00\x00\x00\x00\x00\x00\x00'
       00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00'
       00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00'
       00 00 00 00 00 00 00 00 40 00 00 00 02 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x02\x00\x00\x00'
       01 80 00 00                                     | b'\x01\x80\x00\x00'>
     ### Atom ###
      <size : 20>
      <type : b'tref'>
      ### data ###
       ### Atom ###
        <size : 12>
        <type : b'sync'>
        <data :
         00 00 00 01                                     | b'\x00\x00\x00\x01'>
     ### Atom ###
      <size : 36>
      <type : b'edts'>
      ### data ###
       ### Atom ###
        <size : 28>
        <type : b'elst'>
        <data :
         00 00 00 00 00 00 00 01 00 00 33 6f 00 00 00 02 | b'\x00\x00\x00\x00\x00\x00\x00\x01\x00\x003o\x00\x00\x00\x02'
         00 01 00 00                                     | b'\x00\x01\x00\x00'>
     ### Atom ###
      <size : 5185>
      <type : b'mdia'>
      ### data ###
       ### Atom ###
        <size : 32>
        <type : b'mdhd'>
        <data :
         00 00 00 00 7c 25 b0 80 cd 6b 88 22 00 00 00 1e | b'\x00\x00\x00\x00|%\xb0\x80\xcdk\x88"\x00\x00\x00\x1e'
         00 00 01 8b 15 c7 00 00                         | b'\x00\x00\x01\x8b\x15\xc7\x00\x00'>
       ### Atom ###
        <size : 45>
        <type : b'hdlr'>
        <data :
         00 00 00 00 00 00 00 00 76 69 64 65 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00vide\x00\x00\x00\x00'
         00 00 00 00 00 00 00 00 56 69 64 65 6f 48 61 6e | b'\x00\x00\x00\x00\x00\x00\x00\x00VideoHan'
         64 6c 65 72 00                                  | b'dler\x00'>
       ### Atom ###
        <size : 5100>
        <type : b'minf'>
        ### data ###
         ### Atom ###
          <size : 20>
          <type : b'vmhd'>
          <data :
           00 00 00 01 00 00 00 00 00 00 00 00             | b'\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00'>
         ### Atom ###
          <size : 36>
          <type : b'dinf'>
          ### data ###
           ### Atom ###
            <size : 28>
            <type : b'dref'>
            <data :
             00 00 00 00 00 00 00 01 00 00 00 0c 75 72 6c 20 | b'\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0curl '
             00 00 00 01                                     | b'\x00\x00\x00\x01'>
         ### Atom ###
          <size : 5036>
          <type : b'stbl'>
          ### data ###
           ### Atom ###
            <size : 172>
            <type : b'stsd'>
            <data :
             00 00 00 00 00 00 00 01 00 00 00 9c 61 76 63 31 | b'\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x9cavc1'
             00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00'
             00 00 00 00 00 00 00 00 02 00 01 80 00 48 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x01\x80\x00H\x00\x00'
             00 48 00 00 00 00 00 00 00 01 00 00 00 00 00 00 | b'\x00H\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00'
             00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
             00 00 00 00 00 00 00 00 00 00 00 18 ff ff 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18\xff\xff\x00\x00'
             00 32 61 76 63 43 01 64 00 1e ff e1 00 1a 67 64 | b'\x002avcC\x01d\x00\x1e\xff\xe1\x00\x1agd'
             00 1e ac 72 14 08 03 1b 01 10 00 00 03 00 10 00 | b'\x00\x1e\xacr\x14\x08\x03\x1b\x01\x10\x00\x00\x03\x00\x10\x00'
             00 03 03 c0 f1 62 d9 60 01 00 05 68 e9 2b 2c 8b | b'\x00\x03\x03\xc0\xf1b\xd9`\x01\x00\x05h\xe9+,\x8b'
             00 00 00 14 62 74 72 74 00 00 00 00 00 00 00 00 | b'\x00\x00\x00\x14btrt\x00\x00\x00\x00\x00\x00\x00\x00'
             00 00 00 00                                     | b'\x00\x00\x00\x00'>
           ### Atom ###
            <size : 24>
            <type : b'stts'>
            <data :
             00 00 00 00 00 00 00 01 00 00 01 8b 00 00 00 01 | b'\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x01\x8b\x00\x00\x00\x01'>
           ### Atom ###
            <size : 2984>
            <type : b'ctts'>
            <data :
             00 00 00 00 00 00 01 73 00 00 00 01 00 00 00 02 | b'\x00\x00\x00\x00\x00\x00\x01s\x00\x00\x00\x01\x00\x00\x00\x02'
             00 00 00 01 00 00 00 06 00 00 00 01 00 00 00 03 | b'\x00\x00\x00\x01\x00\x00\x00\x06\x00\x00\x00\x01\x00\x00\x00\x03'
             
            [...]
             
             00 00 00 01 00 00 00 02 00 00 00 01 00 00 00 00 | b'\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x00'
             00 00 00 01 00 00 00 01 00 00 00 01 00 00 00 06 | b'\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x06'
             ...>
           ### Atom ###
            <size : 72>
            <type : b'stss'>
            <data :
             00 00 00 00 00 00 00 0e 00 00 00 01 00 00 00 1f | b'\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00\x01\x00\x00\x00\x1f'
             00 00 00 3d 00 00 00 5b 00 00 00 79 00 00 00 97 | b'\x00\x00\x00=\x00\x00\x00[\x00\x00\x00y\x00\x00\x00\x97'
             00 00 00 b5 00 00 00 d3 00 00 00 f1 00 00 01 0f | b'\x00\x00\x00\xb5\x00\x00\x00\xd3\x00\x00\x00\xf1\x00\x00\x01\x0f'
             00 00 01 2d 00 00 01 4b 00 00 01 69 00 00 01 87 | b'\x00\x00\x01-\x00\x00\x01K\x00\x00\x01i\x00\x00\x01\x87'>
           ### Atom ###
            <size : 52>
            <type : b'stsc'>
            <data :
             00 00 00 00 00 00 00 03 00 00 00 01 00 00 00 10 | b'\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x01\x00\x00\x00\x10'
             00 00 00 01 00 00 00 02 00 00 00 0f 00 00 00 01 | b'\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x0f\x00\x00\x00\x01'
             00 00 00 1b 00 00 00 04 00 00 00 01             | b'\x00\x00\x00\x1b\x00\x00\x00\x04\x00\x00\x00\x01'>
           ### Atom ###
            <size : 1600>
            <type : b'stsz'>
            <data :
             00 00 00 00 00 00 00 00 00 00 01 8b 00 00 00 98 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x8b\x00\x00\x00\x98'
             00 00 00 5c 00 00 00 18 00 00 00 13 00 00 00 13 | b'\x00\x00\x00\\\x00\x00\x00\x18\x00\x00\x00\x13\x00\x00\x00\x13'
             
            [...]
             
             00 00 11 1b 00 00 10 ce 00 00 0a bb 00 00 2a 27 | b"\x00\x00\x11\x1b\x00\x00\x10\xce\x00\x00\n\xbb\x00\x00*'"
             00 00 1c c8 00 00 0f d3 00 00 0a e2 00 00 0a ff | b'\x00\x00\x1c\xc8\x00\x00\x0f\xd3\x00\x00\n\xe2\x00\x00\n\xff'
             ...>
           ### Atom ###
            <size : 124>
            <type : b'stco'>
            <data :
             00 00 00 00 00 00 00 1b 00 00 19 73 00 00 1e e5 | b'\x00\x00\x00\x00\x00\x00\x00\x1b\x00\x00\x19s\x00\x00\x1e\xe5'
             00 00 46 46 00 00 9b d3 00 01 16 d7 00 01 b8 cd | b'\x00\x00FF\x00\x00\x9b\xd3\x00\x01\x16\xd7\x00\x01\xb8\xcd'
             00 02 86 7f 00 03 6c 0f 00 04 66 6e 00 05 68 58 | b'\x00\x02\x86\x7f\x00\x03l\x0f\x00\x04fn\x00\x05hX'
             00 06 90 b1 00 07 a5 46 00 08 c5 df 00 09 ca d5 | b'\x00\x06\x90\xb1\x00\x07\xa5F\x00\x08\xc5\xdf\x00\t\xca\xd5'
             00 0a fc 35 00 0b fb 8e 00 0d 04 f7 00 0d f1 13 | b'\x00\n\xfc5\x00\x0b\xfb\x8e\x00\r\x04\xf7\x00\r\xf1\x13'
             00 0e f5 ac 00 0f cd c8 00 10 e0 6a 00 11 a7 9d | b'\x00\x0e\xf5\xac\x00\x0f\xcd\xc8\x00\x10\xe0j\x00\x11\xa7\x9d'
             00 12 b6 66 00 13 6f 43 00 14 61 a4 00 15 10 f2 | b'\x00\x12\xb6f\x00\x13oC\x00\x14a\xa4\x00\x15\x10\xf2'
             00 15 e3 ac                                     | b'\x00\x15\xe3\xac'>
   ### Atom ###
    <size : 452>
    <type : b'trak'>
    ### data ###
     ### Atom ###
      <size : 92>
      <type : b'tkhd'>
      <data :
       00 00 00 01 cd 6b 88 22 cd 6b 88 22 00 00 00 02 | b'\x00\x00\x00\x01\xcdk\x88"\xcdk\x88"\x00\x00\x00\x02'
       00 00 00 00 00 00 03 e8 00 00 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x03\xe8\x00\x00\x00\x00\x00\x00\x00\x00'
       00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00'
       00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00'
       00 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x00'
       00 00 00 00                                     | b'\x00\x00\x00\x00'>
     ### Atom ###
      <size : 32>
      <type : b'tref'>
      ### data ###
       ### Atom ###
        <size : 12>
        <type : b'sync'>
        <data :
         00 00 00 01                                     | b'\x00\x00\x00\x01'>
       ### Atom ###
        <size : 12>
        <type : b'mpod'>
        <data :
         00 00 00 c9                                     | b'\x00\x00\x00\xc9'>
     ### Atom ###
      <size : 320>
      <type : b'mdia'>
      ### data ###
       ### Atom ###
        <size : 32>
        <type : b'mdhd'>
        <data :
         00 00 00 00 cd 6b 88 22 cd 6b 88 22 00 00 03 e8 | b'\x00\x00\x00\x00\xcdk\x88"\xcdk\x88"\x00\x00\x03\xe8'
         00 00 03 e8 55 c4 00 00                         | b'\x00\x00\x03\xe8U\xc4\x00\x00'>
       ### Atom ###
        <size : 55>
        <type : b'hdlr'>
        <data :
         00 00 00 00 00 00 00 00 6f 64 73 6d 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00odsm\x00\x00\x00\x00'
         00 00 00 00 00 00 00 00 47 50 41 43 20 4d 50 45 | b'\x00\x00\x00\x00\x00\x00\x00\x00GPAC MPE'
         47 2d 34 20 4f 44 20 48 61 6e 64 6c 65 72 00    | b'G-4 OD Handler\x00'>
       ### Atom ###
        <size : 225>
        <type : b'minf'>
        ### data ###
         ### Atom ###
          <size : 12>
          <type : b'nmhd'>
          <data :
           00 00 00 00                                     | b'\x00\x00\x00\x00'>
         ### Atom ###
          <size : 36>
          <type : b'dinf'>
          ### data ###
           ### Atom ###
            <size : 28>
            <type : b'dref'>
            <data :
             00 00 00 00 00 00 00 01 00 00 00 0c 75 72 6c 20 | b'\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0curl '
             00 00 00 01                                     | b'\x00\x00\x00\x01'>
         ### Atom ###
          <size : 169>
          <type : b'stbl'>
          ### data ###
           ### Atom ###
            <size : 69>
            <type : b'stsd'>
            <data :
             00 00 00 00 00 00 00 01 00 00 00 35 6d 70 34 73 | b'\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x005mp4s'
             00 00 00 00 00 00 00 01 00 00 00 25 65 73 64 73 | b'\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00%esds'
             00 00 00 00 03 17 00 00 00 04 0f 01 05 00 00 5f | b'\x00\x00\x00\x00\x03\x17\x00\x00\x00\x04\x0f\x01\x05\x00\x00_'
             00 00 00 00 00 00 00 00 05 00 06 01 02          | b'\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x06\x01\x02'>
           ### Atom ###
            <size : 24>
            <type : b'stts'>
            <data :
             00 00 00 00 00 00 00 01 00 00 00 01 00 00 03 e8 | b'\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x03\xe8'>
           ### Atom ###
            <size : 28>
            <type : b'stsc'>
            <data :
             00 00 00 00 00 00 00 01 00 00 00 01 00 00 00 01 | b'\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x01'
             00 00 00 01                                     | b'\x00\x00\x00\x01'>
           ### Atom ###
            <size : 20>
            <type : b'stsz'>
            <data :
             00 00 00 00 00 00 00 0a 00 00 00 01             | b'\x00\x00\x00\x00\x00\x00\x00\n\x00\x00\x00\x01'>
           ### Atom ###
            <size : 20>
            <type : b'stco'>
            <data :
             00 00 00 00 00 00 00 01 00 00 1e d0             | b'\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x1e\xd0'>
   ### Atom ###
    <size : 429>
    <type : b'trak'>
    ### data ###
     ### Atom ###
      <size : 92>
      <type : b'tkhd'>
      <data :
       00 00 00 01 cd 6b 88 22 cd 6b 88 22 00 00 00 01 | b'\x00\x00\x00\x01\xcdk\x88"\xcdk\x88"\x00\x00\x00\x01'
       00 00 00 00 00 00 03 e8 00 00 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x03\xe8\x00\x00\x00\x00\x00\x00\x00\x00'
       00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00'
       00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00'
       00 00 00 00 00 00 00 00 40 00 00 00 02 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x02\x00\x00\x00'
       01 80 00 00                                     | b'\x01\x80\x00\x00'>
     ### Atom ###
      <size : 329>
      <type : b'mdia'>
      ### data ###
       ### Atom ###
        <size : 32>
        <type : b'mdhd'>
        <data :
         00 00 00 00 cd 6b 88 22 cd 6b 88 22 00 00 03 e8 | b'\x00\x00\x00\x00\xcdk\x88"\xcdk\x88"\x00\x00\x03\xe8'
         00 00 03 e8 55 c4 00 00                         | b'\x00\x00\x03\xe8U\xc4\x00\x00'>
       ### Atom ###
        <size : 57>
        <type : b'hdlr'>
        <data :
         00 00 00 00 00 00 00 00 73 64 73 6d 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00sdsm\x00\x00\x00\x00'
         00 00 00 00 00 00 00 00 47 50 41 43 20 4d 50 45 | b'\x00\x00\x00\x00\x00\x00\x00\x00GPAC MPE'
         47 2d 34 20 42 49 46 53 20 48 61 6e 64 6c 65 72 | b'G-4 BIFS Handler'
         00                                              | b'\x00'>
       ### Atom ###
        <size : 232>
        <type : b'minf'>
        ### data ###
         ### Atom ###
          <size : 12>
          <type : b'nmhd'>
          <data :
           00 00 00 00                                     | b'\x00\x00\x00\x00'>
         ### Atom ###
          <size : 36>
          <type : b'dinf'>
          ### data ###
           ### Atom ###
            <size : 28>
            <type : b'dref'>
            <data :
             00 00 00 00 00 00 00 01 00 00 00 0c 75 72 6c 20 | b'\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0curl '
             00 00 00 01                                     | b'\x00\x00\x00\x01'>
         ### Atom ###
          <size : 176>
          <type : b'stbl'>
          ### data ###
           ### Atom ###
            <size : 76>
            <type : b'stsd'>
            <data :
             00 00 00 00 00 00 00 01 00 00 00 3c 6d 70 34 73 | b'\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00<mp4s'
             00 00 00 00 00 00 00 01 00 00 00 2c 65 73 64 73 | b'\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00,esds'
             00 00 00 00 03 1e 00 00 00 04 16 02 0d 00 00 03 | b'\x00\x00\x00\x00\x03\x1e\x00\x00\x00\x04\x16\x02\r\x00\x00\x03'
             00 00 00 00 00 00 00 00 05 07 00 00 70 20 00 18 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x05\x07\x00\x00p \x00\x18'
             00 06 01 02                                     | b'\x00\x06\x01\x02'>
           ### Atom ###
            <size : 24>
            <type : b'stts'>
            <data :
             00 00 00 00 00 00 00 01 00 00 00 01 00 00 03 e8 | b'\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x03\xe8'>
           ### Atom ###
            <size : 28>
            <type : b'stsc'>
            <data :
             00 00 00 00 00 00 00 01 00 00 00 01 00 00 00 01 | b'\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x01'
             00 00 00 01                                     | b'\x00\x00\x00\x01'>
           ### Atom ###
            <size : 20>
            <type : b'stsz'>
            <data :
             00 00 00 00 00 00 00 0b 00 00 00 01             | b'\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x01'>
           ### Atom ###
            <size : 20>
            <type : b'stco'>
            <data :
             00 00 00 00 00 00 00 01 00 00 1e da             | b'\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x1e\xda'>
   ### Atom ###
    <size : 96>
    <type : b'udta'>
    ### data ###
     ### Atom ###
      <size : 88>
      <type : b'meta'>
      <data :
       00 00 00 00 00 00 00 21 68 64 6c 72 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00!hdlr\x00\x00\x00\x00'
       00 00 00 00 6d 64 69 72 61 70 70 6c 00 00 00 00 | b'\x00\x00\x00\x00mdirappl\x00\x00\x00\x00'
       00 00 00 00 00 00 00 00 2b 69 6c 73 74 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00+ilst\x00\x00\x00'
       23 a9 74 6f 6f 00 00 00 1b 64 61 74 61 00 00 00 | b'#\xa9too\x00\x00\x00\x1bdata\x00\x00\x00'
       01 00 00 00 00 4c 61 76 66 35 32 2e 36 32 2e 30 | b'\x01\x00\x00\x00\x00Lavf52.62.0'>
 ### Atom ###
  <size : 1432556>
  <type : b'mdat'>
  <data :
   00 00 00 15 06 05 11 dc 45 e9 bd e6 d9 48 b7 96 | b'\x00\x00\x00\x15\x06\x05\x11\xdcE\xe9\xbd\xe6\xd9H\xb7\x96'
   2c d8 20 d9 23 ee ef 00 80 00 00 00 7b 65 88 81 | b',\xd8 \xd9#\xee\xef\x00\x80\x00\x00\x00{e\x88\x81'
   
   [...]
   
   ef 00 03 08 82 72 b4 8d bf 01 77 00 00 00 10 01 | b'\xef\x00\x03\x08\x82r\xb4\x8d\xbf\x01w\x00\x00\x00\x10\x01'
   9e 29 0d 48 af 00 02 77 b7 43 a1 63 62 c2 da 00 | b'\x9e)\rH\xaf\x00\x02w\xb7C\xa1cb\xc2\xda\x00'
   ...>
 ### Atom ###
  <size : 8>
  <type : b'free'>
  <data : >
 ### Atom ###
  <size : 47>
  <type : b'free'>
  <data :
   49 73 6f 4d 65 64 69 61 20 46 69 6c 65 20 50 72 | b'IsoMedia File Pr'
   6f 64 75 63 65 64 20 77 69 74 68 20 47 50 41 43 | b'oduced with GPAC'
   20 30 2e 34 2e 34 00                            | b' 0.4.4\x00'>
>>> for atom in M: print(atom['type'])
<type : b'ftyp'>
<type : b'moov'>
<type : b'mdat'>
<type : b'free'>
<type : b'free'>
>>> for atom in M[1]['data']: print(atom['type']) # content of the moov atom
<type : b'mvhd'>
<type : b'iods'>
<type : b'trak'>
<type : b'trak'>
<type : b'trak'>
<type : b'udta'>
>>> for atom in M[1]['data'][2]['data']: print(atom['type']) # content of the 2nd trak atom
<type : b'tkhd'>
<type : b'tref'>
<type : b'edts'>
<type : b'mdia'>
>>> for atom in M[1]['data'][2]['data'][3]['data']: print(atom['type']) # content of the mdia atom
<type : b'mdhd'>
<type : b'hdlr'>
<type : b'minf'>
>>> # the hdlr contains information about the type of media for the trak atom
>>> # let's see the handlers for the 3 different tracks
>>> for i in (2, 3, 4): print(M[1]['data'][i]['data'][-1]['data'][1])
<Atom : <size : 45><type : b'hdlr'><data :
 00 00 00 00 00 00 00 00 76 69 64 65 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00vide\x00\x00\x00\x00'
 00 00 00 00 00 00 00 00 56 69 64 65 6f 48 61 6e | b'\x00\x00\x00\x00\x00\x00\x00\x00VideoHan'
 64 6c 65 72 00                                  | b'dler\x00'>>
<Atom : <size : 55><type : b'hdlr'><data :
 00 00 00 00 00 00 00 00 6f 64 73 6d 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00odsm\x00\x00\x00\x00'
 00 00 00 00 00 00 00 00 47 50 41 43 20 4d 50 45 | b'\x00\x00\x00\x00\x00\x00\x00\x00GPAC MPE'
 47 2d 34 20 4f 44 20 48 61 6e 64 6c 65 72 00    | b'G-4 OD Handler\x00'>>
<Atom : <size : 57><type : b'hdlr'><data :
 00 00 00 00 00 00 00 00 73 64 73 6d 00 00 00 00 | b'\x00\x00\x00\x00\x00\x00\x00\x00sdsm\x00\x00\x00\x00'
 00 00 00 00 00 00 00 00 47 50 41 43 20 4d 50 45 | b'\x00\x00\x00\x00\x00\x00\x00\x00GPAC MPE'
 47 2d 34 20 42 49 46 53 20 48 61 6e 64 6c 65 72 | b'G-4 BIFS Handler'
 00                                              | b'\x00'>>
>>> M[1]['data'][2]['data'][-1]['data'][2]['data'][2]['data'][1]
<Atom : <size : 24><type : b'stts'><data : 0x00000000000000010000018b00000001>>
>>> # let's change the time-to-sample of the video track
>>> stts = M[1]['data'][2]['data'][-1]['data'][2]['data'][2]['data'][1]['data']()
>>> M[1]['data'][2]['data'][-1]['data'][2]['data'][2]['data'][1]['data'].set_val( stts[:-4] + b'\x00\x00\x00\x03' )
>>> open('./slow_mp4.mp4', 'wb').write( M.to_bytes() )
1439118