1370fff98827d37f4fac0f37582b546d59a7509d
[dcpomatic.git] / hacks / make_dummy_files
1 #!/usr/bin/python
2
3 import sys
4 import os
5 import ntpath
6 import tempfile
7 import shutil
8 import hashlib
9 import xml.etree.ElementTree as ET
10
11 if len(sys.argv) < 2:
12     print('Syntax: %s <film>' % sys.argv[1])
13     sys.exit(1)
14
15 metadata_xml = os.path.join(sys.argv[1], 'metadata.xml');
16 tree = ET.parse(metadata_xml)
17
18 def digest_head_tail(filename, size=1000000):
19     m = hashlib.md5()
20     f = open(filename, 'rb')
21     m.update(f.read(size))
22     f.seek(size, 2)
23     m.update(f.read(size))
24     f.close()
25     return m.hexdigest() + str(os.path.getsize(filename))
26
27
28 try:
29     os.makedirs(os.path.join(sys.argv[1], 'dummy'))
30 except:
31     pass
32
33 root = tree.getroot()
34
35 for c in root.find('Playlist').findall('Content'):
36     type = c.find('Type').text
37     if type == 'DCP':
38         # Find the ASSETMAP
39         assetmap_file = None
40         for p in c.findall('Path'):
41             if os.path.basename(p.text) == 'ASSETMAP':
42                 interop = True
43             elif os.path.basename(p.text) == 'ASSETMAP.xml':
44                 interop = False
45                 assetmap_file = p.text
46
47         assert(assetmap_file is not None)
48         dir = os.path.dirname(assetmap_file)
49
50         assets = {}
51
52         assetmap = ET.parse(assetmap_file)
53         ns = {'am': 'http://www.digicine.com/PROTO-ASDCP-AM-20040311#'} if interop else {'am': 'http://www.smpte-ra.org/schemas/429-9/2007/AM'}
54         for a in assetmap.getroot().find('am:AssetList', ns).findall('am:Asset', ns):
55             assets[a.find('am:Id', ns).text[9:]] = a.find('am:ChunkList', ns).find('am:Chunk', ns).find('am:Path', ns).text
56
57         cpl_id = None
58         cpl_ns = 'http://www.digicine.com/PROTO-ASDCP-CPL-20040511#}' if interop else 'http://www.smpte-ra.org/schemas/429-7/2006/CPL'
59         for k, v in assets.items():
60             try:
61                 e = ET.parse(os.path.join(dir, v))
62                 print(e.getroot().tag)
63                 if e.getroot().tag == "{" + cpl_ns + "}CompositionPlaylist":
64                     cpl_id = k
65             except:
66                 pass
67
68         assert(cpl_id is not None)
69         cpl = ET.parse(os.path.join(dir, assets[cpl_id]))
70
71         ns = {'cpl': cpl_ns}
72         for r in cpl.find('cpl:ReelList', ns).findall('cpl:Reel', ns):
73             for a in r.find('cpl:AssetList', ns).iter():
74                 if a.tag == '{%s}MainPicture' % ns['cpl']:
75                     id = a.find('cpl:Id', ns).text[9:]
76                     duration = int(a.find('cpl:IntrinsicDuration', ns).text)
77                     black_png = tempfile.NamedTemporaryFile('wb', suffix='.png')
78                     black_j2cs = []
79                     black_j2c = tempfile.NamedTemporaryFile('wb', suffix='.j2c')
80                     os.system('convert -size 1998x1080 xc:black %s' % black_png.name)
81                     os.system('opj_compress -i %s -o %s' % (black_png.name, black_j2c.name))
82                     j2c_dir = tempfile.mkdtemp()
83                     for i in range(0, duration):
84                         try:
85                             os.link(black_j2c.name, os.path.join(j2c_dir, '%06d.j2c' % i))
86                         except OSError as e:
87                             if e.errno == 31:
88                                 # Too many links
89                                 black_j2cs.append(black_j2c)
90                                 black_j2c = tempfile.NamedTemporaryFile('wb', suffix='.j2c')
91                                 os.link(black_j2c.name, os.path.join(j2c_dir, '%06d.j2c' % i))
92                             else:
93                                 raise
94                     print('=> wrap it')
95                     os.system('asdcp-wrap -a %s %s %s' % (id, j2c_dir, os.path.join(sys.argv[1], 'dummy', assets[id])))
96                 elif a.tag == '{%s}MainSound' % ns['cpl']:
97                     wav = tempfile.NamedTemporaryFile('wb', suffix='.wav')
98                     id = a.find('cpl:Id', ns).text[9:]
99                     duration = int(a.find('cpl:IntrinsicDuration', ns).text)
100                     edit_rate = int(a.find('cpl:EditRate', ns).text.split()[0])
101                     os.system('sox -n -r 48000 -c 6 %s trim 0.0 %f' % (wav.name, float(duration) / edit_rate))
102                     os.system('asdcp-wrap -a %s %s %s' % (id, wav.name, os.path.join(sys.argv[1], 'dummy', assets[id])))
103     elif type == 'Sndfile':
104         audio_frame_rate = int(c.find('AudioFrameRate').text)
105         channels = int(c.find('AudioMapping').find('InputChannels').text)
106         path = os.path.join(sys.argv[1], 'dummy', ntpath.basename(c.find('Path').text))
107         audio_length = int(c.find('AudioLength').text)
108         os.system('sox -n -r %d -c %d %s trim 0.0 %f' % (audio_frame_rate, channels, path, float(audio_length) / audio_frame_rate))
109     elif type == 'FFmpeg':
110         video_cmd = ''
111         audio_cmd = ''
112         path = os.path.join(sys.argv[1], 'dummy', ntpath.basename(c.find('Path').text))
113         if c.find('VideoFrameRate') is not None:
114             video_frame_rate = float(c.find('VideoFrameRate').text)
115             video_length = int(c.find('VideoLength').text)
116             video_cmd = '-s qcif -f rawvideo -pix_fmt rgb24 -r %d -i /dev/zero' % video_frame_rate
117         if c.find('AudioStream') is not None:
118             audio_channels = int(c.find('AudioStream').find('Mapping').find('InputChannels').text)
119             audio_frame_rate = int(c.find('AudioStream').find('FrameRate').text)
120             names = { 1: 'mono', 2: 'stereo', 3: '3.0', 4: '4.0', 5: '4.1', 6: '5.1', 7: '6.1', 8: '7.1' }
121             audio_cmd = '-f lavfi -i anullsrc=channel_layout=%s:sample_rate=%d' % (names[audio_channels], audio_frame_rate)
122         os.system('ffmpeg -t %d %s %s -shortest "%s"' % (float(video_length) / video_frame_rate, video_cmd, audio_cmd, path))
123         c.find('Path').text = path
124         c.find('Digest').text = digest_head_tail(path)
125     elif type == 'Image':
126         width = int(c.find('VideoWidth').text)
127         height = int(c.find('VideoHeight').text)
128         path = os.path.join(sys.argv[1], 'dummy', ntpath.basename(c.find('Path').text))
129         os.system('convert -size %dx%d xc:black "%s"' % (width, height, path))
130     else:
131         print('Skipped %s' % type)
132
133
134 shutil.move(metadata_xml, metadata_xml + '.bak')
135 r = open(metadata_xml, 'w')
136 r.write(ET.tostring(root).decode('UTF-8'))
137 r.close()
138