253 lines
11 KiB
Python
253 lines
11 KiB
Python
|
#!/usr/bin/python
|
||
|
# -*- coding: utf-8 -*-
|
||
|
# vi:si:et:sw=4:sts=4:ts=4
|
||
|
from __future__ import division, with_statement
|
||
|
import os
|
||
|
import sys
|
||
|
import json
|
||
|
|
||
|
import ox
|
||
|
|
||
|
MIN_DURATION = 2
|
||
|
|
||
|
profiles = {
|
||
|
'pal': '<profile width="720" display_aspect_den="3" colorspace="601" frame_rate_den="1" description="DV/DVD PAL" height="576" display_aspect_num="4" frame_rate_num="25" progressive="0" sample_aspect_num="16" sample_aspect_den="15"/>'
|
||
|
}
|
||
|
|
||
|
class Video:
|
||
|
position = 0
|
||
|
playlist = []
|
||
|
producers = {}
|
||
|
|
||
|
template = '''<?xml version='1.0' encoding='utf-8'?>
|
||
|
<mlt title="%(title)s" version="0.8.0" root="%(root)s" LC_NUMERIC="en_US.UTF-8">
|
||
|
%(profile)s
|
||
|
<producer in="0" out="72869" id="black">
|
||
|
<property name="mlt_type">producer</property>
|
||
|
<property name="length">72870</property>
|
||
|
<property name="eof">pause</property>
|
||
|
<property name="resource">black</property>
|
||
|
<property name="aspect_ratio">0</property>
|
||
|
<property name="mlt_service">colour</property>
|
||
|
</producer>
|
||
|
<playlist id="black_track">
|
||
|
<entry in="0" out="12047" producer="black"/>
|
||
|
</playlist>
|
||
|
<playlist id="playlist1"/>
|
||
|
<playlist id="playlist2"/>
|
||
|
<playlist id="playlist3"/>
|
||
|
|
||
|
%(producers)s
|
||
|
|
||
|
<playlist id="playlist4">
|
||
|
%(playlist)s
|
||
|
</playlist>
|
||
|
<playlist id="playlist5"/>
|
||
|
<tractor title="%(title)s" global_feed="1" in="0" out="12047" id="maintractor">
|
||
|
<property name="meta.volume">1</property>
|
||
|
<track producer="black_track"/>
|
||
|
<track hide="video" producer="playlist1"/>
|
||
|
<track hide="video" producer="playlist2"/>
|
||
|
<track producer="playlist3"/>
|
||
|
<track producer="playlist4"/>
|
||
|
<track producer="playlist5"/>
|
||
|
<transition id="transition0">
|
||
|
<property name="a_track">1</property>
|
||
|
<property name="b_track">2</property>
|
||
|
<property name="mlt_type">transition</property>
|
||
|
<property name="mlt_service">mix</property>
|
||
|
<property name="always_active">1</property>
|
||
|
<property name="combine">1</property>
|
||
|
<property name="internal_added">237</property>
|
||
|
</transition>
|
||
|
<transition id="transition1">
|
||
|
<property name="a_track">1</property>
|
||
|
<property name="b_track">3</property>
|
||
|
<property name="mlt_type">transition</property>
|
||
|
<property name="mlt_service">mix</property>
|
||
|
<property name="always_active">1</property>
|
||
|
<property name="combine">1</property>
|
||
|
<property name="internal_added">237</property>
|
||
|
</transition>
|
||
|
<transition id="transition2">
|
||
|
<property name="a_track">1</property>
|
||
|
<property name="b_track">4</property>
|
||
|
<property name="mlt_type">transition</property>
|
||
|
<property name="mlt_service">mix</property>
|
||
|
<property name="always_active">1</property>
|
||
|
<property name="combine">1</property>
|
||
|
<property name="internal_added">237</property>
|
||
|
</transition>
|
||
|
<transition id="transition3">
|
||
|
<property name="a_track">1</property>
|
||
|
<property name="b_track">5</property>
|
||
|
<property name="mlt_type">transition</property>
|
||
|
<property name="mlt_service">mix</property>
|
||
|
<property name="always_active">1</property>
|
||
|
<property name="combine">1</property>
|
||
|
<property name="internal_added">237</property>
|
||
|
</transition>
|
||
|
</tractor>
|
||
|
<kdenlivedoc profile="dv_pal" kdenliveversion="0.9.2" version="0.88" projectfolder="%(root)s">
|
||
|
<customeffects/>
|
||
|
<documentproperties proxyimageminsize="2000" zonein="0" enableproxy="0" zoneout="100" generateproxy="0" zoom="9" verticalzoom="1" proxyextension="ts" position="1" documentid="1353193897205" generateimageproxy="0" proxyminsize="1000" proxyparams="-f mpegts -acodec libmp3lame -ac 2 -ab 128k -ar 48000 -vcodec mpeg2video -g 5 -deinterlace -s 480x270 -vb 400k"/>
|
||
|
<documentmetadata/>
|
||
|
<documentnotes><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||
|
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||
|
p, li { white-space: pre-wrap; }
|
||
|
</style></head><body style=" font-family:'Sans Serif'; font-size:8pt; font-weight:400; font-style:normal;">
|
||
|
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html></documentnotes>
|
||
|
<profileinfo width="720" display_aspect_den="3" frame_rate_den="1" description="DV/DVD PAL" height="576" frame_rate_num="25" display_aspect_num="4" progressive="0" sample_aspect_num="16" sample_aspect_den="15"/>
|
||
|
<tracksinfo>
|
||
|
<trackinfo blind="1" mute="0" locked="0" trackname="Audio 2" type="audio"/>
|
||
|
<trackinfo blind="1" mute="0" locked="0" trackname="Audio 1" type="audio"/>
|
||
|
<trackinfo blind="0" mute="0" locked="0" trackname="Video 3"/>
|
||
|
<trackinfo blind="0" mute="0" locked="0" trackname="Video 2"/>
|
||
|
<trackinfo blind="0" mute="0" locked="0" trackname="Video 1"/>
|
||
|
</tracksinfo>
|
||
|
%(kdenlive_producers)s
|
||
|
<markers/>
|
||
|
<groups/>
|
||
|
</kdenlivedoc>
|
||
|
</mlt>
|
||
|
'''
|
||
|
|
||
|
def __init__(self, data, title, url, root):
|
||
|
files = []
|
||
|
items = []
|
||
|
for c in data:
|
||
|
files.append(c['path'])
|
||
|
items.append(c['id'])
|
||
|
|
||
|
files = list(set(files))
|
||
|
items = list(set(items))
|
||
|
self.files = files
|
||
|
self.clips = data
|
||
|
|
||
|
self.fps = 25
|
||
|
profile = profiles[self.fps == 25 and 'pal' or 'ntsc']
|
||
|
|
||
|
self.info = {
|
||
|
'profile': profile,
|
||
|
'root': root,
|
||
|
'title': title,
|
||
|
'url': url,
|
||
|
'producers': '',
|
||
|
'kdenlive_producers': '',
|
||
|
'duration': 0,
|
||
|
'stats': '%d clips from %d films' % (len(self.clips), len(items))
|
||
|
}
|
||
|
self.add_title()
|
||
|
for clip in self.clips:
|
||
|
path = clip['path']
|
||
|
if not path.startswith('/'):
|
||
|
path = os.path.join('/data/Cinema', clip['path'])
|
||
|
out = clip['out']
|
||
|
if out-clip['in'] < MIN_DURATION:
|
||
|
out = clip['in'] + MIN_DURATION
|
||
|
duration = int((out-clip['in']) * self.fps)
|
||
|
self.add_clip(path, clip['in'], out)
|
||
|
self.info['duration'] += duration
|
||
|
|
||
|
def render(self, output):
|
||
|
xml = output
|
||
|
with open(xml, 'w') as f:
|
||
|
self.info['playlist'] = '\n'.join(self.playlist)
|
||
|
data = self.template % self.info
|
||
|
f.write(data.strip())
|
||
|
#os.system('melt -progress "%s" -consumer "avformat:%s"'%(xml, output))
|
||
|
|
||
|
def add_title(self):
|
||
|
self.info['duration'] = 5*self.fps
|
||
|
self.info['producers'] += '''
|
||
|
<producer in="0" out="%(duration)s" id="1">
|
||
|
<property name="mlt_type">producer</property>
|
||
|
<property name="length">%(duration)s</property>
|
||
|
<property name="eof">pause</property>
|
||
|
<property name="resource"/>
|
||
|
<property name="mlt_service">kdenlivetitle</property>
|
||
|
<property name="xmldata"><kdenlivetitle width="768" height="576" out="125" LC_NUMERIC="en_US.UTF-8">
|
||
|
<item z-index="2" type="QGraphicsTextItem">
|
||
|
<position x="86" y="123">
|
||
|
<transform>1,0,0,0,1,0,0,0,1</transform>
|
||
|
</position>
|
||
|
<content font-color="255,255,255,255" font-outline-color="0,0,0,255" font-pixel-size="151" font-italic="0" alignment="4" font-underline="0" font-weight="50" font="Arial Black" font-outline="0.5">%(title)s</content>
|
||
|
</item>
|
||
|
<item z-index="1" type="QGraphicsTextItem">
|
||
|
<position x="79" y="321">
|
||
|
<transform>1,0,0,0,1,0,0,0,1</transform>
|
||
|
</position>
|
||
|
<content font-color="255,255,255,255" font-outline-color="0,0,0,255" font-pixel-size="24" font-italic="0" alignment="4" font-underline="0" font-weight="50" font="Arial Black" font-outline="0.5">%(url)s
|
||
|
%(stats)s</content>
|
||
|
</item>
|
||
|
<startviewport rect="0,0,768,576"/>
|
||
|
<endviewport rect="0,0,768,576"/>
|
||
|
<background color="0,0,0,0"/>
|
||
|
</kdenlivetitle>
|
||
|
</property>
|
||
|
<property name="force_reload">0</property>
|
||
|
</producer>
|
||
|
''' % self.info
|
||
|
self.playlist.append('<entry in="%s" out="%s" producer="1"/>' % (0, self.info['duration']))
|
||
|
self.info['kdenlive_producers'] += '''
|
||
|
<kdenlive_producer audio_max="0" id="1" default_video="0" xmldata="<kdenlivetitle width="768" height="576" out="125" LC_NUMERIC="en_US.UTF-8">
 <item z-index="2" type="QGraphicsTextItem">
 <position x="86" y="123">
 <transform>1,0,0,0,1,0,0,0,1</transform>
 </position>
 <content font-color="255,255,255,255" font-outline-color="0,0,0,255" font-pixel-size="151" font-italic="0" alignment="4" font-underline="0" font-weight="50" font="Arial Black" font-outline="0.5">%(title)s</content>
 </item>
 <item z-index="1" type="QGraphicsTextItem">
 <position x="79" y="321">
 <transform>1,0,0,0,1,0,0,0,1</transform>
 </position>
 <content font-color="255,255,255,255" font-outline-color="0,0,0,255" font-pixel-size="24" font-italic="0" alignment="4" font-underline="0" font-weight="50" font="Arial Black" font-outline="0.5">%(url)s
%(stats)s</content>
 </item>
 <startviewport rect="0,0,768,576"/>
 <endviewport rect="0,0,768,576"/>
 <background color="0,0,0,0"/>
</kdenlivetitle>
" name="Title" in="0" thumbnail="100" transparency="1" default_audio="0" duration="125" aspect_ratio="0.000000" channels="0" frequency="0" out="125" video_max="0" progressive="0" type="6" frame_size="720x576"/>
|
||
|
''' % self.info
|
||
|
def add_producer(self, uri):
|
||
|
c = len(self.producers.keys()) + 2
|
||
|
self.producers[uri] = c
|
||
|
info = ox.avinfo(uri)
|
||
|
i = {
|
||
|
'id': c,
|
||
|
'duration': int(info['duration'] * self.fps),
|
||
|
'filename': uri.encode('utf-8'),
|
||
|
'basename': os.path.basename(uri).encode('utf-8')
|
||
|
}
|
||
|
i['out'] = i['duration'] - 1
|
||
|
self.info['producers'] += '''
|
||
|
<producer in="0" out="%(out)s" id="%(id)s_1">
|
||
|
<property name="mlt_type">producer</property>
|
||
|
<property name="length">%(duration)s</property>
|
||
|
<property name="eof">pause</property>
|
||
|
<property name="resource">%(filename)s</property>
|
||
|
<property name="seekable">1</property>
|
||
|
<property name="mlt_service">avformat</property>
|
||
|
</producer>
|
||
|
''' % i
|
||
|
self.info['kdenlive_producers'] += '''
|
||
|
<kdenlive_producer
|
||
|
id="%(id)s"
|
||
|
name="%(basename)s"
|
||
|
resource="%(filename)s"
|
||
|
/>
|
||
|
''' % i
|
||
|
|
||
|
def get_producer(self, uri):
|
||
|
if not uri in self.producers:
|
||
|
self.add_producer(uri)
|
||
|
return self.producers[uri]
|
||
|
|
||
|
def add_clip(self, uri, start, end):
|
||
|
start = int(start * self.fps)
|
||
|
end = int(end * self.fps) - 1
|
||
|
o = '<entry in="%s" out="%s" producer="%d_1"/>' % (start, end, self.get_producer(uri))
|
||
|
self.playlist.append(o)
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
|
||
|
if len(sys.argv) != 5:
|
||
|
print 'usage: %s <json input> <video prefix> <output> <title>' % sys.argv[0]
|
||
|
sys.exit(1)
|
||
|
json_input = sys.argv[1]
|
||
|
video_prefix = sys.argv[2]
|
||
|
root = sys.argv[3]
|
||
|
title = sys.argv[4]
|
||
|
output = json_input + '.kdenlive'
|
||
|
url = 'http://pan.do/ra'
|
||
|
|
||
|
data = json.load(open(json_input))
|
||
|
c = Video(data,
|
||
|
title,
|
||
|
url,
|
||
|
root)
|
||
|
c.render(output)
|