9 import xml.etree.ElementTree as ET
12 print('Syntax: %s <film>' % sys.argv[1])
15 metadata_xml = os.path.join(sys.argv[1], 'metadata.xml');
16 tree = ET.parse(metadata_xml)
18 def digest_head_tail(filename, size=1000000):
20 f = open(filename, 'rb')
21 m.update(f.read(size))
23 m.update(f.read(size))
25 return m.hexdigest() + str(os.path.getsize(filename))
33 os.makedirs(os.path.join(sys.argv[1], 'dummy'))
39 for c in root.find('Playlist').findall('Content'):
40 type = c.find('Type').text
44 for p in c.findall('Path'):
45 if os.path.basename(p.text) == 'ASSETMAP':
46 assetmap_file = p.text
48 assert(assetmap_file is not None)
49 dir = os.path.dirname(assetmap_file)
53 assetmap = ET.parse(assetmap_file)
54 ns = {'am': 'http://www.digicine.com/PROTO-ASDCP-AM-20040311#'}
55 for a in assetmap.getroot().find('am:AssetList', ns).findall('am:Asset', ns):
56 assets[a.find('am:Id', ns).text[9:]] = a.find('am:ChunkList', ns).find('am:Chunk', ns).find('am:Path', ns).text
59 for k, v in assets.items():
61 e = ET.parse(os.path.join(dir, v))
62 if e.getroot().tag == '{http://www.digicine.com/PROTO-ASDCP-CPL-20040511#}CompositionPlaylist':
67 assert(cpl_id is not None)
68 cpl = ET.parse(os.path.join(dir, assets[cpl_id]))
70 ns = {'cpl': 'http://www.digicine.com/PROTO-ASDCP-CPL-20040511#'}
71 for r in cpl.find('cpl:ReelList', ns).findall('cpl:Reel', ns):
72 for a in r.find('cpl:AssetList', ns).iter():
73 if a.tag == '{%s}MainPicture' % ns['cpl']:
74 id = a.find('cpl:Id', ns).text[9:]
75 duration = int(a.find('cpl:IntrinsicDuration', ns).text)
76 black_png = tempfile.NamedTemporaryFile('wb', suffix='.png')
77 black_j2c = tempfile.NamedTemporaryFile('wb', suffix='.j2c')
78 os.system('convert -size 1998x1080 xc:black %s' % black_png.name)
79 os.system('image_to_j2k -i %s -o %s' % (black_png.name, black_j2c.name))
80 j2c_dir = tempfile.mkdtemp()
81 for i in range(0, duration):
82 shutil.copyfile(black_j2c.name, os.path.join(j2c_dir, '%06d.j2c' % i))
83 os.system('asdcp-wrap -a %s %s %s' % (id, j2c_dir, os.path.join(sys.argv[1], 'dummy', assets[id])))
84 elif a.tag == '{%s}MainSound' % ns['cpl']:
85 wav = tempfile.NamedTemporaryFile('wb', suffix='.wav')
86 id = a.find('cpl:Id', ns).text[9:]
87 duration = int(a.find('cpl:IntrinsicDuration', ns).text)
88 edit_rate = int(a.find('cpl:EditRate', ns).text.split()[0])
89 os.system('sox -n -r 48000 -c 6 %s trim 0.0 %f' % (wav.name, float(duration) / edit_rate))
90 os.system('asdcp-wrap -a %s %s %s' % (id, wav.name, os.path.join(sys.argv[1], 'dummy', assets[id])))
91 elif type == 'Sndfile':
92 audio_frame_rate = int(c.find('AudioFrameRate').text)
93 channels = int(c.find('AudioMapping').find('InputChannels').text)
94 path = os.path.join(sys.argv[1], 'dummy', ntpath.basename(c.find('Path').text))
95 audio_length = int(c.find('AudioLength').text)
96 os.system('sox -n -r %d -c %d %s trim 0.0 %f' % (audio_frame_rate, channels, path, float(audio_length) / audio_frame_rate))
97 elif type == 'FFmpeg':
100 path = os.path.join(sys.argv[1], 'dummy', ntpath.basename(c.find('Path').text))
101 if c.find('VideoFrameRate') is not None:
102 video_frame_rate = float(c.find('VideoFrameRate').text)
103 video_length = int(c.find('VideoLength').text)
105 command(f"ffmpeg -t {float(video_length) / video_frame_rate} -s qcif -f rawvideo -pix_fmt rgb24 -r {video_frame_rate} -i /dev/zero video.mkv")
106 if c.find('AudioStream') is not None:
107 audio_channels = int(c.find('AudioStream').find('Mapping').find('InputChannels').text)
108 audio_length = int(c.find('AudioStream').find('Length').text)
109 audio_frame_rate = int(c.find('AudioStream').find('FrameRate').text)
110 names = { 1: 'mono', 2: 'stereo', 3: '3.0', 4: '4.0', 5: '4.1', 6: '5.1', 7: '6.1', 8: '7.1' }
112 print(f"audio_length={audio_length} frame_rate={audio_frame_rate}")
113 command(f'sox -n -r 48000 -c {audio_channels} audio.wav trim 0.0 {audio_length}s')
114 if have_video and have_audio:
115 command(f"ffmpeg -i video.mkv -i audio.wav {path}")
117 shutil.move("video.mkv", path)
119 shutil.move("audio.wav", path)
121 os.remove("video.mkv")
122 os.remove("audio.mkv")
125 c.find('Path').text = path
126 c.find('Digest').text = digest_head_tail(path)
127 elif type == 'Image':
128 width = int(c.find('VideoWidth').text)
129 height = int(c.find('VideoHeight').text)
130 path = os.path.join(sys.argv[1], 'dummy', ntpath.basename(c.find('Path').text))
131 os.system('convert -size %dx%d xc:black "%s"' % (width, height, path))
133 print('Skipped %s' % type)
136 shutil.move(metadata_xml, metadata_xml + '.bak')
137 r = open(metadata_xml, 'w')
138 r.write(ET.tostring(root).decode('UTF-8'))