various duration issues, prepare for double vo special case
This commit is contained in:
parent
c47e6a5e15
commit
f8cbbd55c7
2 changed files with 92 additions and 28 deletions
105
render.py
105
render.py
|
|
@ -61,6 +61,7 @@ def compose(clips, fragment, target=150, base=1024, voice_over=None, options=Non
|
||||||
},
|
},
|
||||||
'audio-center': {
|
'audio-center': {
|
||||||
'A1': [],
|
'A1': [],
|
||||||
|
'A2': [],
|
||||||
},
|
},
|
||||||
'audio-front': {
|
'audio-front': {
|
||||||
'A1': [],
|
'A1': [],
|
||||||
|
|
@ -132,7 +133,9 @@ def compose(clips, fragment, target=150, base=1024, voice_over=None, options=Non
|
||||||
next_length = length + clip['duration']
|
next_length = length + clip['duration']
|
||||||
if target - next_length < -target*0.1:
|
if target - next_length < -target*0.1:
|
||||||
break
|
break
|
||||||
clip_duration = int(clip['duration'] * fps) / fps
|
clip_duration = format_duration(clip['duration'], fps)
|
||||||
|
if clip['duration'] != clip_duration:
|
||||||
|
print("WTF", clip, clip['duration'], clip_duration)
|
||||||
length += clip_duration
|
length += clip_duration
|
||||||
|
|
||||||
# 50/50 source or ai
|
# 50/50 source or ai
|
||||||
|
|
@ -145,13 +148,13 @@ def compose(clips, fragment, target=150, base=1024, voice_over=None, options=Non
|
||||||
print('%07.3f-%07.3f %07.3f %s (%s)' % (
|
print('%07.3f-%07.3f %07.3f %s (%s)' % (
|
||||||
length-clip_duration,
|
length-clip_duration,
|
||||||
length,
|
length,
|
||||||
clip['duration'],
|
clip_duration,
|
||||||
os.path.basename(clip['source']),
|
os.path.basename(clip['source']),
|
||||||
src.split('/')[-2]
|
src.split('/')[-2]
|
||||||
))
|
))
|
||||||
|
|
||||||
scene['front']['V2'].append({
|
scene['front']['V2'].append({
|
||||||
'duration': clip['duration'],
|
'duration': clip_duration,
|
||||||
'src': src,
|
'src': src,
|
||||||
"filter": {
|
"filter": {
|
||||||
}
|
}
|
||||||
|
|
@ -181,10 +184,21 @@ def compose(clips, fragment, target=150, base=1024, voice_over=None, options=Non
|
||||||
'fadein': '00:00:00.125'
|
'fadein': '00:00:00.125'
|
||||||
}
|
}
|
||||||
scene['audio-front']['A2'].append({
|
scene['audio-front']['A2'].append({
|
||||||
'duration': clip['duration'],
|
'duration': clip_duration,
|
||||||
'src': audio,
|
'src': audio,
|
||||||
'filter': audio_filter.copy()
|
'filter': audio_filter.copy()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
length = format_duration(length, fps)
|
||||||
|
ad = get_scene_duration(scene, track='audio-front:A2')
|
||||||
|
vd = get_scene_duration(scene, track='front:V2')
|
||||||
|
if ad == vd and abs(ad-length) > 1/48:
|
||||||
|
print('v: ', vd, 'ad', ad, 'length:', length, 'fixup')
|
||||||
|
length = ad
|
||||||
|
if abs(length -vd) > 1/48 or abs(length - ad) > 1/48 or ad != vd:
|
||||||
|
print('vd: ', vd, 'ad', ad, 'length:', length)
|
||||||
|
print(clip)
|
||||||
|
sys.exit(-1)
|
||||||
used.append(clip)
|
used.append(clip)
|
||||||
if not clips and target - length > 0:
|
if not clips and target - length > 0:
|
||||||
print("not enough clips, need to reset")
|
print("not enough clips, need to reset")
|
||||||
|
|
@ -200,7 +214,7 @@ def compose(clips, fragment, target=150, base=1024, voice_over=None, options=Non
|
||||||
if "ai" in clip:
|
if "ai" in clip:
|
||||||
clip["use_ai"] = True
|
clip["use_ai"] = True
|
||||||
|
|
||||||
scene_duration = int(get_scene_duration(scene) * fps)
|
scene_duration = int(round(get_scene_duration(scene) * fps))
|
||||||
voice_overs = []
|
voice_overs = []
|
||||||
sub_offset = 0
|
sub_offset = 0
|
||||||
subs = []
|
subs = []
|
||||||
|
|
@ -216,11 +230,13 @@ def compose(clips, fragment, target=150, base=1024, voice_over=None, options=Non
|
||||||
gap = format_duration(gap, fps)
|
gap = format_duration(gap, fps)
|
||||||
if int((sub_offset + gap) * fps) > scene_duration:
|
if int((sub_offset + gap) * fps) > scene_duration:
|
||||||
gap = format_duration((scene_duration - int(sub_offset * fps)) / fps, fps)
|
gap = format_duration((scene_duration - int(sub_offset * fps)) / fps, fps)
|
||||||
scene['audio-center']['A1'].append({
|
for tl, track in (
|
||||||
'blank': True,
|
('audio-center', 'A1'),
|
||||||
'duration': gap
|
('audio-center', 'A2'),
|
||||||
})
|
('audio-rear', 'A1'),
|
||||||
scene['audio-rear']['A1'].append({
|
('audio-rear', 'A2'),
|
||||||
|
):
|
||||||
|
scene[tl][track].append({
|
||||||
'blank': True,
|
'blank': True,
|
||||||
'duration': gap
|
'duration': gap
|
||||||
})
|
})
|
||||||
|
|
@ -230,6 +246,10 @@ def compose(clips, fragment, target=150, base=1024, voice_over=None, options=Non
|
||||||
vo_key = random_choice(seq, vo_keys, pop=True)
|
vo_key = random_choice(seq, vo_keys, pop=True)
|
||||||
variant = random_int(seq, len(voice_over[vo_key]))
|
variant = random_int(seq, len(voice_over[vo_key]))
|
||||||
vo = voice_over[vo_key][variant]
|
vo = voice_over[vo_key][variant]
|
||||||
|
if isinstance(vo, list):
|
||||||
|
vo, vo_b = vo
|
||||||
|
else:
|
||||||
|
vo_b = None
|
||||||
while int((vo['duration'] + sub_offset) * fps) > scene_duration:
|
while int((vo['duration'] + sub_offset) * fps) > scene_duration:
|
||||||
if not vo_keys:
|
if not vo_keys:
|
||||||
vo = None
|
vo = None
|
||||||
|
|
@ -237,6 +257,10 @@ def compose(clips, fragment, target=150, base=1024, voice_over=None, options=Non
|
||||||
vo_key = random_choice(seq, vo_keys, pop=True)
|
vo_key = random_choice(seq, vo_keys, pop=True)
|
||||||
variant = random_int(seq, len(voice_over[vo_key]))
|
variant = random_int(seq, len(voice_over[vo_key]))
|
||||||
vo = voice_over[vo_key][variant]
|
vo = voice_over[vo_key][variant]
|
||||||
|
if isinstance(vo, list):
|
||||||
|
vo, vo_b = vo
|
||||||
|
else:
|
||||||
|
vo_b = None
|
||||||
if vo is None:
|
if vo is None:
|
||||||
break
|
break
|
||||||
print('%07.3f-%07.3f %07.3f' % (sub_offset, sub_offset+vo["duration"], vo["duration"]), vo["src"].split('/')[-1])
|
print('%07.3f-%07.3f %07.3f' % (sub_offset, sub_offset+vo["duration"], vo["duration"]), vo["src"].split('/')[-1])
|
||||||
|
|
@ -255,13 +279,29 @@ def compose(clips, fragment, target=150, base=1024, voice_over=None, options=Non
|
||||||
sub["in"] += sub_offset
|
sub["in"] += sub_offset
|
||||||
sub["out"] += sub_offset
|
sub["out"] += sub_offset
|
||||||
subs.append(sub)
|
subs.append(sub)
|
||||||
|
if vo_b:
|
||||||
|
vo_b = vo_b.copy()
|
||||||
|
vo_b['filter'] = {'volume': a}
|
||||||
|
scene['audio-center']['A2'].append(vo_b)
|
||||||
|
vo_b = vo_b.copy()
|
||||||
|
vo_b['filter'] = {'volume': b}
|
||||||
|
scene['audio-rear']['A1'].append(vo_b)
|
||||||
|
else:
|
||||||
|
for tl, track in (
|
||||||
|
('audio-center', 'A2'),
|
||||||
|
('audio-rear', 'A2'),
|
||||||
|
):
|
||||||
|
scene[tl][track].append({
|
||||||
|
'blank': True,
|
||||||
|
'duration': voc["duration"]
|
||||||
|
})
|
||||||
sub_offset += voc["duration"]
|
sub_offset += voc["duration"]
|
||||||
if subs:
|
if subs:
|
||||||
scene["subtitles"] = subs
|
scene["subtitles"] = subs
|
||||||
|
sub_offset = format_duration(sub_offset, fps)
|
||||||
|
|
||||||
sub_offset = int(sub_offset * fps)
|
if sub_offset < scene_duration/fps:
|
||||||
if sub_offset < scene_duration:
|
gap = scene_duration/fps - sub_offset
|
||||||
gap = format_duration((scene_duration - sub_offset) / fps, fps)
|
|
||||||
print('%07.3f-%07.3f %07.3f' % (sub_offset, sub_offset+gap, gap), 'silence')
|
print('%07.3f-%07.3f %07.3f' % (sub_offset, sub_offset+gap, gap), 'silence')
|
||||||
scene['audio-center']['A1'].append({
|
scene['audio-center']['A1'].append({
|
||||||
'blank': True,
|
'blank': True,
|
||||||
|
|
@ -272,7 +312,18 @@ def compose(clips, fragment, target=150, base=1024, voice_over=None, options=Non
|
||||||
'duration': gap
|
'duration': gap
|
||||||
})
|
})
|
||||||
sub_offset += gap
|
sub_offset += gap
|
||||||
print("scene duration %0.3f (target: %0.3f)" % (length, target))
|
'''
|
||||||
|
print("scene duration: %0.3f vo: %0.3f (length: %0.3f, target: %0.3f)" % (
|
||||||
|
get_scene_duration(scene),
|
||||||
|
sub_offset,
|
||||||
|
length,
|
||||||
|
target
|
||||||
|
))
|
||||||
|
'''
|
||||||
|
print("scene duration: %0.3f (target: %0.3f)" % (
|
||||||
|
get_scene_duration(scene),
|
||||||
|
target
|
||||||
|
))
|
||||||
return scene, used
|
return scene, used
|
||||||
|
|
||||||
def write_subtitles(data, folder, options):
|
def write_subtitles(data, folder, options):
|
||||||
|
|
@ -560,10 +611,14 @@ def render_all(options):
|
||||||
|
|
||||||
for a, b in (
|
for a, b in (
|
||||||
("front-mixed.mp4", "front.mp4"),
|
("front-mixed.mp4", "front.mp4"),
|
||||||
|
("audio-center.wav", "front.mp4"),
|
||||||
|
("audio-rear.wav", "front.mp4"),
|
||||||
|
("audio-front.wav", "front.mp4"),
|
||||||
|
("audio-5.1.mp4", "front.mp4"),
|
||||||
):
|
):
|
||||||
duration_a = ox.avinfo(str(fragment_prefix / a))['duration']
|
duration_a = ox.avinfo(str(fragment_prefix / a))['duration']
|
||||||
duration_b = ox.avinfo(str(fragment_prefix / b))['duration']
|
duration_b = ox.avinfo(str(fragment_prefix / b))['duration']
|
||||||
if duration_a != duration_b:
|
if abs(duration_a - duration_b) > 1/48:
|
||||||
print('!!', duration_a, fragment_prefix / a)
|
print('!!', duration_a, fragment_prefix / a)
|
||||||
print('!!', duration_b, fragment_prefix / b)
|
print('!!', duration_b, fragment_prefix / b)
|
||||||
sys.exit(-1)
|
sys.exit(-1)
|
||||||
|
|
@ -854,6 +909,7 @@ def generate_clips(options):
|
||||||
import item.models
|
import item.models
|
||||||
import itemlist.models
|
import itemlist.models
|
||||||
|
|
||||||
|
fps = 24
|
||||||
options = load_defaults(options)
|
options = load_defaults(options)
|
||||||
prefix = options['prefix']
|
prefix = options['prefix']
|
||||||
lang, tlang = parse_lang(options["lang"])
|
lang, tlang = parse_lang(options["lang"])
|
||||||
|
|
@ -873,7 +929,8 @@ def generate_clips(options):
|
||||||
continue
|
continue
|
||||||
if not e.files.filter(selected=True).exists():
|
if not e.files.filter(selected=True).exists():
|
||||||
continue
|
continue
|
||||||
source = e.files.filter(selected=True)[0].data.path
|
selected = e.files.filter(selected=True)[0]
|
||||||
|
source = selected.data.path
|
||||||
ext = os.path.splitext(source)[1]
|
ext = os.path.splitext(source)[1]
|
||||||
type_ = e.data['type'][0].lower()
|
type_ = e.data['type'][0].lower()
|
||||||
if type_.startswith('ai:'):
|
if type_.startswith('ai:'):
|
||||||
|
|
@ -885,7 +942,7 @@ def generate_clips(options):
|
||||||
ai_type = '%s-%s' % (type_[3:], n)
|
ai_type = '%s-%s' % (type_[3:], n)
|
||||||
n += 1
|
n += 1
|
||||||
clip['ai'][ai_type] = target
|
clip['ai'][ai_type] = target
|
||||||
type_ = ai_type
|
type_ = 'ai:' + ai_type
|
||||||
target = os.path.join(prefix, 'video', type_, i.data['title'] + ext)
|
target = os.path.join(prefix, 'video', type_, i.data['title'] + ext)
|
||||||
if type_ == "source":
|
if type_ == "source":
|
||||||
source_target = target
|
source_target = target
|
||||||
|
|
@ -898,19 +955,22 @@ def generate_clips(options):
|
||||||
if os.path.islink(target):
|
if os.path.islink(target):
|
||||||
os.unlink(target)
|
os.unlink(target)
|
||||||
os.symlink(source, target)
|
os.symlink(source, target)
|
||||||
durations.append(e.files.filter(selected=True)[0].duration)
|
durations.append(selected.duration)
|
||||||
if not durations:
|
if not durations:
|
||||||
print(i.public_id, 'no duration!', clip)
|
print(i.public_id, 'no duration!', clip)
|
||||||
continue
|
continue
|
||||||
clip["duration"] = min(durations)
|
if len(set(durations)) > 1:
|
||||||
|
print(clip, durations)
|
||||||
|
|
||||||
|
clip["duration"] = min(durations) - 1/24
|
||||||
# trim to a multiple of the output fps
|
# trim to a multiple of the output fps
|
||||||
d1 = int(clip["duration"] * 24) / 24
|
d1 = format_duration(clip["duration"], fps)
|
||||||
if d1 != clip["duration"]:
|
if d1 != clip["duration"]:
|
||||||
clip["duration"] = d1
|
clip["duration"] = d1
|
||||||
if not clip["duration"]:
|
if not clip["duration"]:
|
||||||
print('!!', durations, clip)
|
print('!!', durations, clip)
|
||||||
continue
|
continue
|
||||||
cd = format_duration(clip["duration"], 24)
|
cd = format_duration(clip["duration"], fps)
|
||||||
clip["duration"] = cd
|
clip["duration"] = cd
|
||||||
clip['tags'] = i.data.get('tags', [])
|
clip['tags'] = i.data.get('tags', [])
|
||||||
adjust_volume = i.data.get('adjustvolume', '')
|
adjust_volume = i.data.get('adjustvolume', '')
|
||||||
|
|
@ -971,7 +1031,8 @@ def generate_clips(options):
|
||||||
voice_over[fragment][type].append({
|
voice_over[fragment][type].append({
|
||||||
"variant": variant,
|
"variant": variant,
|
||||||
"src": target,
|
"src": target,
|
||||||
"duration": format_duration(source.duration, 24),
|
#"duration": format_duration(source.duration, fps, True),
|
||||||
|
"duration": source.duration,
|
||||||
"subs": subs
|
"subs": subs
|
||||||
})
|
})
|
||||||
with open(os.path.join(prefix, 'voice_over.json'), 'w') as fd:
|
with open(os.path.join(prefix, 'voice_over.json'), 'w') as fd:
|
||||||
|
|
|
||||||
5
utils.py
5
utils.py
|
|
@ -57,6 +57,9 @@ def write_if_new(path, data, mode=''):
|
||||||
with open(path, write_mode) as fd:
|
with open(path, write_mode) as fd:
|
||||||
fd.write(data)
|
fd.write(data)
|
||||||
|
|
||||||
def format_duration(duration, fps):
|
def format_duration(duration, fps, audio=False):
|
||||||
|
if audio:
|
||||||
|
return float('%0.5f' % (int(duration * fps) / fps))
|
||||||
|
else:
|
||||||
return float('%0.5f' % (round(duration * fps) / fps))
|
return float('%0.5f' % (round(duration * fps) / fps))
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue