fix timelines for items with many parts

- use durations from streams not from timelines
 - don't accumulate timeline drift
This commit is contained in:
j 2016-03-19 18:58:48 +01:00
parent f0b8b2b81e
commit 94b940436f
2 changed files with 37 additions and 24 deletions

View file

@ -1364,8 +1364,12 @@ class Item(models.Model):
def make_timeline(self): def make_timeline(self):
streams = self.streams() streams = self.streams()
if streams.count() > 1: if streams.count() > 1:
timelines = [s.timeline_prefix for s in self.streams()] timelines = []
join_tiles(timelines, self.timeline_prefix) durations = []
for s in self.streams():
timelines.append(s.timeline_prefix)
durations.append(s.duration)
join_tiles(timelines, durations, self.timeline_prefix)
else: else:
#remove joined timeline if it was created at some point #remove joined timeline if it was created at some point
for f in glob(os.path.join(settings.MEDIA_ROOT, self.path(), 'timeline*.jpg')): for f in glob(os.path.join(settings.MEDIA_ROOT, self.path(), 'timeline*.jpg')):

View file

@ -10,7 +10,7 @@ import Image
from ox.utils import json from ox.utils import json
def join_tiles(source_paths, target_path): def join_tiles(source_paths, durations, target_path):
''' '''
This is an implementation of a join_tiles function for new-style timelines. This is an implementation of a join_tiles function for new-style timelines.
Timelines of files will be read from source_paths, the timeline of the item will Timelines of files will be read from source_paths, the timeline of the item will
@ -104,24 +104,31 @@ def join_tiles(source_paths, target_path):
modes = ['antialias', 'slitscan', 'keyframes', 'keyframeswide', 'audio'] modes = ['antialias', 'slitscan', 'keyframes', 'keyframeswide', 'audio']
source_files = {} source_files = {}
for mode in modes: for mode in modes:
source_files[mode] = [] source_files[mode] = {}
# read files # read files
durations = [0] * len(source_paths)
frame_n = 0 frame_n = 0
offset = 0
for i, path in enumerate(source_paths): for i, path in enumerate(source_paths):
file_info = map(get_file_info, os.listdir(path)) file_info = map(get_file_info, os.listdir(path))
file_info = filter(lambda x: x != None, file_info) file_info = filter(lambda x: x != None, file_info)
files = {}
for mode in modes:
files[mode] = []
for info in sorted(file_info, key=lambda x: x['index']): for info in sorted(file_info, key=lambda x: x['index']):
mode = info['mode'] mode = info['mode']
source_files[mode].append(path + info['file']) files[mode].append(path + info['file'])
if i:
offset = int(sum(durations[:i]) * 25)
for mode in files:
source_files[mode][offset] = files[mode]
modes = [m for m in modes if source_files[m]] modes = [m for m in modes if source_files[m]]
for i, path in enumerate(source_paths): offsets = sorted(source_files[modes[0]])
for f in source_files[modes[0]]: last_offset = max(offsets)
if f.startswith(path): frame_n = last_offset
width = Image.open(f).size[0] for f in source_files[modes[0]][last_offset]:
durations[i] += width / fps width = Image.open(f).size[0]
frame_n += width frame_n += width
large_tile_n = int(math.ceil(frame_n / large_tile_w)) large_tile_n = int(math.ceil(frame_n / large_tile_w))
large_tile_last_w = frame_n % large_tile_w or 60 large_tile_last_w = frame_n % large_tile_w or 60
small_tile_n = int(math.ceil(frame_n / fps / small_tile_w)) small_tile_n = int(math.ceil(frame_n / fps / small_tile_w))
@ -149,19 +156,21 @@ def join_tiles(source_paths, target_path):
data['target_images'] = {'large': None, 'small': None, 'full': full_tile_image} data['target_images'] = {'large': None, 'small': None, 'full': full_tile_image}
for mode in modes: for mode in modes:
target_w = 0 target_w = 0
for source_file in source_files[mode]: for offset in sorted(source_files[mode]):
source_image = Image.open(source_file) target_w = offset
source_w = source_image.size[0] for source_file in source_files[mode][offset]:
target_x = target_w % large_tile_w source_image = Image.open(source_file)
if target_x == 0: source_w = source_image.size[0]
save_and_open(data) target_x = target_w % large_tile_w
data['target_images']['large'].paste(source_image, (target_x, 0)) if target_x == 0:
target_w += source_w save_and_open(data)
if target_x + source_w > large_tile_w:
# target tile overflows into next source tile
save_and_open(data)
target_x -= large_tile_w
data['target_images']['large'].paste(source_image, (target_x, 0)) data['target_images']['large'].paste(source_image, (target_x, 0))
target_w += source_w
if target_x + source_w > large_tile_w:
# target tile overflows into next source tile
save_and_open(data)
target_x -= large_tile_w
data['target_images']['large'].paste(source_image, (target_x, 0))
# save_and_open saves previous tile and opens tile at target_w # save_and_open saves previous tile and opens tile at target_w
# increase target_w to be in next tile # increase target_w to be in next tile
target_w += large_tile_w target_w += large_tile_w