You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					189 lines
				
				7.0 KiB
			
		
		
			
		
	
	
					189 lines
				
				7.0 KiB
			| 
								 
											6 years ago
										 
									 | 
							
								#!/usr/bin/env python
							 | 
						||
| 
								 | 
							
								import sys
							 | 
						||
| 
								 | 
							
								import random
							 | 
						||
| 
								 | 
							
								import math
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# Simple hacky Matroska generator
							 | 
						||
| 
								 | 
							
								# Reads mp3 file "q.mp3" and jpeg images from img/0.jpg, img/1.jpg and so on and 
							 | 
						||
| 
								 | 
							
								# writes Matroska file with mjpeg and mp3 to stdout
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# License=MIT
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# unsigned
							 | 
						||
| 
								 | 
							
								def big_endian_number(number):
							 | 
						||
| 
								 | 
							
								    if(number<0x100):
							 | 
						||
| 
								 | 
							
								        return chr(number)
							 | 
						||
| 
								 | 
							
								    return big_endian_number(number>>8) + chr(number&0xFF)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								ben=big_endian_number
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def ebml_encode_number(number):
							 | 
						||
| 
								 | 
							
								    def trailing_bits(rest_of_number, number_of_bits):
							 | 
						||
| 
								 | 
							
								        # like big_endian_number, but can do padding zeroes
							 | 
						||
| 
								 | 
							
								        if number_of_bits==8:
							 | 
						||
| 
								 | 
							
								            return chr(rest_of_number&0xFF);
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								            return trailing_bits(rest_of_number>>8, number_of_bits-8) + chr(rest_of_number&0xFF)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if number == -1:
							 | 
						||
| 
								 | 
							
								        return chr(0xFF)
							 | 
						||
| 
								 | 
							
								    if number < 2**7 - 1:
							 | 
						||
| 
								 | 
							
								        return chr(number|0x80)
							 | 
						||
| 
								 | 
							
								    if number < 2**14 - 1:
							 | 
						||
| 
								 | 
							
								        return chr(0x40 | (number>>8)) + trailing_bits(number, 8)
							 | 
						||
| 
								 | 
							
								    if number < 2**21 - 1:
							 | 
						||
| 
								 | 
							
								        return chr(0x20 | (number>>16)) + trailing_bits(number, 16)
							 | 
						||
| 
								 | 
							
								    if number < 2**28 - 1:
							 | 
						||
| 
								 | 
							
								        return chr(0x10 | (number>>24)) + trailing_bits(number, 24)
							 | 
						||
| 
								 | 
							
								    if number < 2**35 - 1:
							 | 
						||
| 
								 | 
							
								        return chr(0x08 | (number>>32)) + trailing_bits(number, 32)
							 | 
						||
| 
								 | 
							
								    if number < 2**42 - 1:
							 | 
						||
| 
								 | 
							
								        return chr(0x04 | (number>>40)) + trailing_bits(number, 40)
							 | 
						||
| 
								 | 
							
								    if number < 2**49 - 1:
							 | 
						||
| 
								 | 
							
								        return chr(0x02 | (number>>48)) + trailing_bits(number, 48)
							 | 
						||
| 
								 | 
							
								    if number < 2**56 - 1:
							 | 
						||
| 
								 | 
							
								        return chr(0x01) + trailing_bits(number, 56)
							 | 
						||
| 
								 | 
							
								    raise Exception("NUMBER TOO BIG")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def ebml_element(element_id, data, length=None):
							 | 
						||
| 
								 | 
							
								    if length==None:
							 | 
						||
| 
								 | 
							
								        length = len(data)
							 | 
						||
| 
								 | 
							
								    return big_endian_number(element_id) + ebml_encode_number(length) + data
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def write_ebml_header(f, content_type, version, read_version):
							 | 
						||
| 
								 | 
							
								    f.write(
							 | 
						||
| 
								 | 
							
								        ebml_element(0x1A45DFA3, "" # EBML
							 | 
						||
| 
								 | 
							
								            + ebml_element(0x4286, ben(1))   # EBMLVersion
							 | 
						||
| 
								 | 
							
								            + ebml_element(0x42F7, ben(1))   # EBMLReadVersion
							 | 
						||
| 
								 | 
							
								            + ebml_element(0x42F2, ben(4))   # EBMLMaxIDLength
							 | 
						||
| 
								 | 
							
								            + ebml_element(0x42F3, ben(8))   # EBMLMaxSizeLength
							 | 
						||
| 
								 | 
							
								            + ebml_element(0x4282, content_type) # DocType
							 | 
						||
| 
								 | 
							
								            + ebml_element(0x4287, ben(version))   # DocTypeVersion
							 | 
						||
| 
								 | 
							
								            + ebml_element(0x4285, ben(read_version))   # DocTypeReadVersion
							 | 
						||
| 
								 | 
							
								            ))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def write_infinite_segment_header(f):
							 | 
						||
| 
								 | 
							
								    # write segment element header
							 | 
						||
| 
								 | 
							
								    f.write(ebml_element(0x18538067,"",-1)) # Segment (unknown length)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def random_uid():
							 | 
						||
| 
								 | 
							
								    def rint():
							 | 
						||
| 
								 | 
							
								        return int(random.random()*(0x100**4))
							 | 
						||
| 
								 | 
							
								    return ben(rint()) + ben(rint()) + ben(rint()) + ben(rint())
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def example():
							 | 
						||
| 
								 | 
							
								    write_ebml_header(sys.stdout, "matroska", 2, 2)
							 | 
						||
| 
								 | 
							
								    write_infinite_segment_header(sys.stdout)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # write segment info (optional)
							 | 
						||
| 
								 | 
							
								    sys.stdout.write(ebml_element(0x1549A966, "" # SegmentInfo
							 | 
						||
| 
								 | 
							
								        + ebml_element(0x73A4, random_uid()) # SegmentUID
							 | 
						||
| 
								 | 
							
								        + ebml_element(0x7BA9, "mkvgen.py test") # Title
							 | 
						||
| 
								 | 
							
								        + ebml_element(0x4D80, "mkvgen.py") # MuxingApp
							 | 
						||
| 
								 | 
							
								        + ebml_element(0x5741, "mkvgen.py") # WritingApp
							 | 
						||
| 
								 | 
							
								        ))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # write trans data (codecs etc.)
							 | 
						||
| 
								 | 
							
								    sys.stdout.write(ebml_element(0x1654AE6B, "" # Tracks
							 | 
						||
| 
								 | 
							
								        + ebml_element(0xAE, "" # TrackEntry
							 | 
						||
| 
								 | 
							
								            + ebml_element(0xD7, ben(1)) # TrackNumber
							 | 
						||
| 
								 | 
							
								            + ebml_element(0x73C5, ben(0x77)) # TrackUID
							 | 
						||
| 
								 | 
							
								            + ebml_element(0x83, ben(0x01)) # TrackType
							 | 
						||
| 
								 | 
							
								                #0x01 track is a video track
							 | 
						||
| 
								 | 
							
								                #0x02 track is an audio track
							 | 
						||
| 
								 | 
							
								                #0x03 track is a complex track, i.e. a combined video and audio track
							 | 
						||
| 
								 | 
							
								                #0x10 track is a logo track
							 | 
						||
| 
								 | 
							
								                #0x11 track is a subtitle track
							 | 
						||
| 
								 | 
							
								                #0x12 track is a button track
							 | 
						||
| 
								 | 
							
								                #0x20 track is a control track
							 | 
						||
| 
								 | 
							
								            + ebml_element(0x536E, "mjpeg data") # Name
							 | 
						||
| 
								 | 
							
								            + ebml_element(0x86, "V_MJPEG") # CodecID
							 | 
						||
| 
								 | 
							
								            #+ ebml_element(0x23E383, ben(100000000)) # DefaultDuration (opt.), nanoseconds
							 | 
						||
| 
								 | 
							
								            #+ ebml_element(0x6DE7, ben(100)) # MinCache
							 | 
						||
| 
								 | 
							
								            + ebml_element(0xE0, "" # Video
							 | 
						||
| 
								 | 
							
								                + ebml_element(0xB0, ben(640)) # PixelWidth
							 | 
						||
| 
								 | 
							
								                + ebml_element(0xBA, ben(480)) # PixelHeight
							 | 
						||
| 
								 | 
							
								                )
							 | 
						||
| 
								 | 
							
								            )
							 | 
						||
| 
								 | 
							
								        + ebml_element(0xAE, "" # TrackEntry
							 | 
						||
| 
								 | 
							
								            + ebml_element(0xD7, ben(2)) # TrackNumber
							 | 
						||
| 
								 | 
							
								            + ebml_element(0x73C5, ben(0x78)) # TrackUID
							 | 
						||
| 
								 | 
							
								            + ebml_element(0x83, ben(0x02)) # TrackType
							 | 
						||
| 
								 | 
							
								                #0x01 track is a video track
							 | 
						||
| 
								 | 
							
								                #0x02 track is an audio track
							 | 
						||
| 
								 | 
							
								                #0x03 track is a complex track, i.e. a combined video and audio track
							 | 
						||
| 
								 | 
							
								                #0x10 track is a logo track
							 | 
						||
| 
								 | 
							
								                #0x11 track is a subtitle track
							 | 
						||
| 
								 | 
							
								                #0x12 track is a button track
							 | 
						||
| 
								 | 
							
								                #0x20 track is a control track
							 | 
						||
| 
								 | 
							
								            + ebml_element(0x536E, "content of mp3 file") # Name
							 | 
						||
| 
								 | 
							
								            #+ ebml_element(0x6DE7, ben(100)) # MinCache
							 | 
						||
| 
								 | 
							
								            + ebml_element(0x86, "A_MPEG/L3") # CodecID
							 | 
						||
| 
								 | 
							
								            #+ ebml_element(0xE1, "") # Audio
							 | 
						||
| 
								 | 
							
								         )
							 | 
						||
| 
								 | 
							
								        ))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    mp3file = open("q.mp3", "rb")
							 | 
						||
| 
								 | 
							
								    mp3file.read(500000);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def mp3framesgenerator(f):
							 | 
						||
| 
								 | 
							
								        debt=""
							 | 
						||
| 
								 | 
							
								        while True:
							 | 
						||
| 
								 | 
							
								            for i in xrange(0,len(debt)+1):
							 | 
						||
| 
								 | 
							
								                if i >= len(debt)-1:
							 | 
						||
| 
								 | 
							
								                    debt = debt + f.read(8192)
							 | 
						||
| 
								 | 
							
								                    break
							 | 
						||
| 
								 | 
							
								                #sys.stderr.write("i="+str(i)+" len="+str(len(debt))+"\n")
							 | 
						||
| 
								 | 
							
								                if ord(debt[i])==0xFF and (ord(debt[i+1]) & 0xF0)==0XF0 and i>700:
							 | 
						||
| 
								 | 
							
								                    if i>0:
							 | 
						||
| 
								 | 
							
								                        yield debt[0:i]
							 | 
						||
| 
								 | 
							
								                        #   sys.stderr.write("len="+str(i)+"\n")
							 | 
						||
| 
								 | 
							
								                        debt = debt[i:]
							 | 
						||
| 
								 | 
							
								                        break
							 | 
						||
| 
								 | 
							
								                    
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    mp3 = mp3framesgenerator(mp3file)
							 | 
						||
| 
								 | 
							
								    mp3.next()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    for i in xrange(0,530):
							 | 
						||
| 
								 | 
							
								        framefile = open("img/"+str(i)+".jpg", "rb")
							 | 
						||
| 
								 | 
							
								        framedata = framefile.read()
							 | 
						||
| 
								 | 
							
								        framefile.close()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # write cluster (actual video data)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if random.random()<1:
							 | 
						||
| 
								 | 
							
								            sys.stdout.write(ebml_element(0x1F43B675, "" # Cluster
							 | 
						||
| 
								 | 
							
								                + ebml_element(0xE7, ben(int(i*26*4))) # TimeCode, uint, milliseconds
							 | 
						||
| 
								 | 
							
								                # + ebml_element(0xA7, ben(0)) # Position, uint
							 | 
						||
| 
								 | 
							
								                + ebml_element(0xA3, "" # SimpleBlock
							 | 
						||
| 
								 | 
							
								                    + ebml_encode_number(1) # track number
							 | 
						||
| 
								 | 
							
								                    + chr(0x00) + chr(0x00) # timecode, relative to Cluster timecode, sint16, in milliseconds
							 | 
						||
| 
								 | 
							
								                    + chr(0x00) # flags
							 | 
						||
| 
								 | 
							
								                    + framedata
							 | 
						||
| 
								 | 
							
								                    )))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        for u in xrange(0,4):
							 | 
						||
| 
								 | 
							
								            mp3f=mp3.next()
							 | 
						||
| 
								 | 
							
								            if random.random()<1:
							 | 
						||
| 
								 | 
							
								                sys.stdout.write(ebml_element(0x1F43B675, "" # Cluster
							 | 
						||
| 
								 | 
							
								                    + ebml_element(0xE7, ben(i*26*4+u*26)) # TimeCode, uint, milliseconds
							 | 
						||
| 
								 | 
							
								                    + ebml_element(0xA3, "" # SimpleBlock
							 | 
						||
| 
								 | 
							
								                        + ebml_encode_number(2) # track number
							 | 
						||
| 
								 | 
							
								                        + chr(0x00) + chr(0x00) # timecode, relative to Cluster timecode, sint16, in milliseconds
							 | 
						||
| 
								 | 
							
								                        + chr(0x00) # flags
							 | 
						||
| 
								 | 
							
								                        + mp3f
							 | 
						||
| 
								 | 
							
								                        )))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								if __name__ == '__main__':
							 | 
						||
| 
								 | 
							
								    example()
							 |