tictacsync 0.82a0__py3-none-any.whl → 0.95a0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tictacsync/device_scanner.py +64 -32
- tictacsync/entry.py +111 -69
- tictacsync/multi2polywav.py +1 -1
- tictacsync/timeline.py +123 -77
- tictacsync/yaltc.py +139 -152
- {tictacsync-0.82a0.dist-info → tictacsync-0.95a0.dist-info}/METADATA +1 -1
- tictacsync-0.95a0.dist-info/RECORD +15 -0
- tictacsync-0.82a0.dist-info/RECORD +0 -15
- {tictacsync-0.82a0.dist-info → tictacsync-0.95a0.dist-info}/LICENSE +0 -0
- {tictacsync-0.82a0.dist-info → tictacsync-0.95a0.dist-info}/WHEEL +0 -0
- {tictacsync-0.82a0.dist-info → tictacsync-0.95a0.dist-info}/entry_points.txt +0 -0
- {tictacsync-0.82a0.dist-info → tictacsync-0.95a0.dist-info}/top_level.txt +0 -0
tictacsync/timeline.py
CHANGED
|
@@ -237,7 +237,6 @@ def _sox_mono2stereo(temp_file) -> tempfile.NamedTemporaryFile:
|
|
|
237
237
|
sys.exit(1)
|
|
238
238
|
return stereo_tempfile
|
|
239
239
|
|
|
240
|
-
|
|
241
240
|
def _sox_mix_files(temp_files_to_mix:list) -> tempfile.NamedTemporaryFile:
|
|
242
241
|
"""
|
|
243
242
|
Mix files referred by the list of Path into a new temporary files passed on
|
|
@@ -303,9 +302,10 @@ class AudioStitcherVideoMerger:
|
|
|
303
302
|
"""
|
|
304
303
|
Typically each found video is associated with an AudioStitcherVideoMerger
|
|
305
304
|
instance. AudioStitcherVideoMerger does the actual audio-video file
|
|
306
|
-
processing of merging
|
|
307
|
-
files in
|
|
308
|
-
object (
|
|
305
|
+
processing of merging AudioStitcherVideoMerger.videoclip (gen. a video)
|
|
306
|
+
with all audio files in AudioStitcherVideoMerger.soxed_audio as
|
|
307
|
+
determined by the Matcher object (Matcher instanciates and manages
|
|
308
|
+
AudioStitcherVideoMerger objects).
|
|
309
309
|
|
|
310
310
|
All audio file edits are done using pysox and video+audio merging with
|
|
311
311
|
ffmpeg. When necessary, clock drift is corrected for all overlapping audio
|
|
@@ -317,58 +317,64 @@ class AudioStitcherVideoMerger:
|
|
|
317
317
|
project.
|
|
318
318
|
|
|
319
319
|
|
|
320
|
+
Class attribute
|
|
321
|
+
|
|
322
|
+
tempoed_recs : dict as {Recording : path}
|
|
323
|
+
|
|
324
|
+
a cache for already time-stretched audio files. Keys are elements
|
|
325
|
+
of matched_audio_recordings and the value are tuples:
|
|
326
|
+
(factor, file_handle), the file_handle points to the precedently
|
|
327
|
+
produced NamedTemporaryFile; factor is the value that was used in
|
|
328
|
+
the sox tempo transform.
|
|
329
|
+
|
|
320
330
|
Attributes:
|
|
321
331
|
|
|
322
332
|
videoclip : a Recording instance
|
|
323
333
|
The video to which audio files are synced
|
|
324
334
|
|
|
325
|
-
|
|
326
|
-
keys are elements of matched_audio_recordings
|
|
327
|
-
|
|
328
|
-
audio (trimmed , padded or time stretched). Before building the
|
|
329
|
-
audio_montage, path points to the initial
|
|
330
|
-
Recording.valid_sound
|
|
335
|
+
soxed_audio : dict as {Recording : path}
|
|
336
|
+
keys are elements of matched_audio_recordings and the value are
|
|
337
|
+
the Pathlib path of the eventual edited audio(trimmed or padded).
|
|
331
338
|
|
|
332
339
|
synced_clip_dir : Path
|
|
333
340
|
where synced clips are written
|
|
334
341
|
|
|
335
342
|
"""
|
|
343
|
+
tempoed_recs = {}
|
|
336
344
|
|
|
337
345
|
def __init__(self, video_clip):
|
|
338
346
|
self.videoclip = video_clip
|
|
339
347
|
# self.matched_audio_recordings = []
|
|
340
|
-
self.
|
|
348
|
+
self.soxed_audio = {}
|
|
341
349
|
logger.debug('instantiating AudioStitcherVideoMerger for %s'%
|
|
342
350
|
video_clip)
|
|
343
351
|
|
|
344
352
|
def add_matched_audio(self, audio_rec):
|
|
345
353
|
"""
|
|
346
|
-
Populates
|
|
354
|
+
Populates AudioStitcherVideoMerger.soxed_audio,
|
|
355
|
+
a dict as {Recording : path}
|
|
347
356
|
|
|
348
|
-
|
|
357
|
+
This fct is called
|
|
349
358
|
within Matcher.scan_audio_for_each_videoclip()
|
|
350
359
|
|
|
351
|
-
Returns nothing, fills self.
|
|
360
|
+
Returns nothing, fills self.soxed_audio dict with
|
|
352
361
|
matched audio.
|
|
353
362
|
|
|
354
363
|
"""
|
|
355
|
-
self.
|
|
364
|
+
self.soxed_audio[audio_rec] = audio_rec.AVpath
|
|
356
365
|
"""
|
|
357
|
-
Here at this point, self.
|
|
358
|
-
after a call to _edit_audio_file(),
|
|
359
|
-
a new file and
|
|
360
|
-
AudioStitcherVideoMerger instance to another
|
|
361
|
-
audio_rec.valid_sound doesn't need to be reinitialized since
|
|
362
|
-
it stays unchanged)
|
|
366
|
+
Here at this point, self.soxed_audio[audio_rec] is unedited but
|
|
367
|
+
after a call to _edit_audio_file(), soxed_audio[audio_rec] points to
|
|
368
|
+
a new file and audio_rec.AVpath is unchanged.
|
|
363
369
|
"""
|
|
364
370
|
return
|
|
365
371
|
|
|
366
372
|
def get_matched_audio_recs(self):
|
|
367
373
|
"""
|
|
368
374
|
Returns audio recordings that overlap self.videoclip.
|
|
369
|
-
Simply keys of self.
|
|
375
|
+
Simply keys of self.soxed_audio dict
|
|
370
376
|
"""
|
|
371
|
-
return list(self.
|
|
377
|
+
return list(self.soxed_audio.keys())
|
|
372
378
|
|
|
373
379
|
def _get_audio_devices(self):
|
|
374
380
|
devices = set([r.device for r in self.get_matched_audio_recs()])
|
|
@@ -384,59 +390,77 @@ class AudioStitcherVideoMerger:
|
|
|
384
390
|
return recs
|
|
385
391
|
|
|
386
392
|
def _dedrift_rec(self, rec):
|
|
387
|
-
#
|
|
388
|
-
|
|
389
|
-
_pathname(rec.valid_sound))
|
|
390
|
-
sox_transform = sox.Transformer()
|
|
391
|
-
# tempo_scale_factor = rec.device_relative_speed
|
|
393
|
+
# instanciates a sox.Transformer() with tempo() effect
|
|
394
|
+
# add applies it via a call to _edit_audio_file(rec, sox_transform)
|
|
392
395
|
tempo_scale_factor = rec.device_relative_speed
|
|
393
396
|
audio_dev = rec.device.name
|
|
394
397
|
video_dev = self.videoclip.device.name
|
|
398
|
+
print('when merging with [gold1]%s[/gold1].'%self.videoclip)
|
|
395
399
|
if tempo_scale_factor > 1:
|
|
396
|
-
print('[gold1]%s[/gold1] clock too fast relative to [gold1]%s[/gold1]
|
|
400
|
+
print('Because [gold1]%s[/gold1] clock too fast relative to [gold1]%s[/gold1]: file is too long by a %.12f factor;'%
|
|
397
401
|
(audio_dev, video_dev, tempo_scale_factor))
|
|
398
402
|
else:
|
|
399
|
-
print('[gold1]%s[/gold1] clock too slow relative to [gold1]%s[/gold1]
|
|
403
|
+
print('Because [gold1]%s[/gold1] clock too slow relative to [gold1]%s[/gold1]: file is short by a %.12f factor'%
|
|
400
404
|
(audio_dev, video_dev, tempo_scale_factor))
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
405
|
+
logger.debug('tempoed_recs dict:%s'%AudioStitcherVideoMerger.tempoed_recs)
|
|
406
|
+
if rec in AudioStitcherVideoMerger.tempoed_recs:
|
|
407
|
+
logger.debug('%s already tempoed'%rec)
|
|
408
|
+
cached_factor, cached_file = AudioStitcherVideoMerger.tempoed_recs[rec]
|
|
409
|
+
error_factor = tempo_scale_factor/cached_factor
|
|
410
|
+
logger.debug('tempo factors, needed: %f cached %f'%(tempo_scale_factor,cached_factor))
|
|
411
|
+
delta_cache = abs((1 - error_factor)*rec.get_original_duration())
|
|
412
|
+
logger.debug('error if cache is used: %f ms'%(delta_cache*1e3))
|
|
413
|
+
delta_cache_is_ok = delta_cache < yaltc.MAXDRIFT
|
|
414
|
+
else:
|
|
415
|
+
delta_cache_is_ok = False
|
|
416
|
+
if delta_cache_is_ok:
|
|
417
|
+
logger.debug('ok, will use %s'%cached_file)
|
|
418
|
+
self.soxed_audio[rec] = cached_file
|
|
419
|
+
else:
|
|
420
|
+
logger.debug('%s not tempoed yet'%rec)
|
|
421
|
+
sox_transform = sox.Transformer()
|
|
422
|
+
sox_transform.tempo(tempo_scale_factor)
|
|
423
|
+
# scaled_file = self._get_soxed_file(rec, sox_transform)
|
|
424
|
+
logger.debug('sox_transform %s'%sox_transform.effects)
|
|
425
|
+
soxed_fh = self._edit_audio_file(rec, sox_transform)
|
|
426
|
+
scaled_file_name = _pathname(soxed_fh)
|
|
427
|
+
AudioStitcherVideoMerger.tempoed_recs[rec] = (tempo_scale_factor, soxed_fh)
|
|
428
|
+
new_duration = sox.file_info.duration(scaled_file_name)
|
|
429
|
+
initial_duration = sox.file_info.duration(
|
|
430
|
+
_pathname(rec.AVpath))
|
|
431
|
+
logger.debug('Verif: initial_duration %.12f new_duration %.12f ratio:%.12f'%(
|
|
432
|
+
initial_duration, new_duration, initial_duration/new_duration))
|
|
433
|
+
logger.debug('delta duration %f ms'%((new_duration-initial_duration)*1e3))
|
|
410
434
|
|
|
411
435
|
def _get_concatenated_audiofile_for(self, device):
|
|
412
436
|
"""
|
|
413
437
|
return a handle for the final audio file formed by all detected
|
|
414
|
-
overlapping recordings, produced by the same
|
|
438
|
+
overlapping recordings, produced by the same audio recorder.
|
|
415
439
|
|
|
416
440
|
"""
|
|
417
441
|
logger.debug('concatenating device %s'%str(device))
|
|
418
|
-
|
|
442
|
+
audio_recs = self._get_all_recordings_for(device)
|
|
419
443
|
# [TODO here] Check if all unidentified device files are not
|
|
420
444
|
# overlapping because they are considered produced by the same
|
|
421
445
|
# device. If some overlap then necessarily they're from different
|
|
422
446
|
# ones. List the files and warn the user there is a risk of error if
|
|
423
447
|
# they're not from the same device.
|
|
424
448
|
|
|
425
|
-
logger.debug('%i audio files for videoclip %s:'%(len(
|
|
449
|
+
logger.debug('%i audio files for videoclip %s:'%(len(audio_recs),
|
|
426
450
|
self.videoclip))
|
|
427
|
-
for r in
|
|
451
|
+
for r in audio_recs:
|
|
428
452
|
logger.debug(' %s'%r)
|
|
453
|
+
# ratio between real samplerates of audio and videoclip
|
|
429
454
|
speeds = numpy.array([rec.get_speed_ratio(self.videoclip)
|
|
430
|
-
for rec in
|
|
455
|
+
for rec in audio_recs])
|
|
431
456
|
mean_speed = numpy.mean(speeds)
|
|
432
|
-
for
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
logger.debug('
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
r.time_position, self.videoclip))
|
|
457
|
+
for audio in audio_recs:
|
|
458
|
+
audio.device_relative_speed = mean_speed
|
|
459
|
+
logger.debug('set device_relative_speed for %s'%audio)
|
|
460
|
+
logger.debug(' value: %f'%audio.device_relative_speed)
|
|
461
|
+
audio.set_time_position_to(self.videoclip)
|
|
462
|
+
logger.debug('time_position for %s: %fs relative to %s'%(audio,
|
|
463
|
+
audio.time_position, self.videoclip))
|
|
440
464
|
# st_dev_speeds just to check for anomalous situation
|
|
441
465
|
st_dev_speeds = numpy.std(speeds)
|
|
442
466
|
logger.debug('mean speed for %s: %.6f std dev: %.0e'%(device,
|
|
@@ -461,7 +485,7 @@ class AudioStitcherVideoMerger:
|
|
|
461
485
|
|
|
462
486
|
# process first element 'by hand' outside the loop
|
|
463
487
|
# first_audio is a Recording, not a path nor filehandle
|
|
464
|
-
first_audio =
|
|
488
|
+
first_audio = audio_recs[0]
|
|
465
489
|
needs_dedrift, delta = first_audio.needs_dedrifting()
|
|
466
490
|
logger.debug('first audio is %s'%first_audio)
|
|
467
491
|
logger.debug('checking drift, first audio: delta of %0.2f ms'%(
|
|
@@ -473,8 +497,8 @@ class AudioStitcherVideoMerger:
|
|
|
473
497
|
self._pad_or_trim_first_audio(first_audio)
|
|
474
498
|
# loop for the other files
|
|
475
499
|
# growing_file = first_audio.edited_version
|
|
476
|
-
growing_file = self.
|
|
477
|
-
for i, rec in enumerate(
|
|
500
|
+
growing_file = self.soxed_audio[first_audio]
|
|
501
|
+
for i, rec in enumerate(audio_recs[1:]):
|
|
478
502
|
logger.debug('Padding and joining for %s'%rec)
|
|
479
503
|
needs_dedrift, delta = rec.needs_dedrifting()
|
|
480
504
|
logger.debug('next audio is %s'%rec)
|
|
@@ -497,7 +521,7 @@ class AudioStitcherVideoMerger:
|
|
|
497
521
|
(rec,rec.time_position,end_time))
|
|
498
522
|
self._pad_file(rec, pad_duration)
|
|
499
523
|
# new_file = rec.edited_version
|
|
500
|
-
new_file = self.
|
|
524
|
+
new_file = self.soxed_audio[rec]
|
|
501
525
|
growing_file = self._concatenate_audio_files(growing_file, new_file)
|
|
502
526
|
end_time = sox.file_info.duration(growing_file.name)
|
|
503
527
|
logger.debug('total edited audio duration %.2f s'%end_time)
|
|
@@ -510,7 +534,7 @@ class AudioStitcherVideoMerger:
|
|
|
510
534
|
TODO: check if first_rec is a Recording or tempfile (maybe a tempfile if dedrifted)
|
|
511
535
|
NO: will change tempo after trimming/padding
|
|
512
536
|
|
|
513
|
-
Store (into Recording.
|
|
537
|
+
Store (into Recording.soxed_audio dict) the handle of the sox processed
|
|
514
538
|
first recording, padded or chopped according to AudioStitcherVideoMerger.videoclip
|
|
515
539
|
starting time. Length of the written file can differ from length of the
|
|
516
540
|
submitted Recording object if drift is corrected with sox tempo
|
|
@@ -574,22 +598,25 @@ class AudioStitcherVideoMerger:
|
|
|
574
598
|
def _edit_audio_file(self, audio_rec, sox_transform):
|
|
575
599
|
"""
|
|
576
600
|
Apply the specified sox_transform onto the audio_rec and update
|
|
577
|
-
self.
|
|
601
|
+
self.soxed_audio dict with the result (with audio_rec as the key)
|
|
602
|
+
Returns the filehandle of the result.
|
|
578
603
|
"""
|
|
579
604
|
output_fh = tempfile.NamedTemporaryFile(suffix='.wav', delete=DEL_TEMP)
|
|
580
605
|
logger.debug('transform: %s'%sox_transform.effects)
|
|
581
|
-
recording_fh = self.
|
|
606
|
+
recording_fh = self.soxed_audio[audio_rec]
|
|
582
607
|
logger.debug('for recording %s, matching %s'%(audio_rec,
|
|
583
608
|
self.videoclip))
|
|
584
609
|
input_file = _pathname(recording_fh)
|
|
585
|
-
logger.debug('AudioStitcherVideoMerger.
|
|
610
|
+
logger.debug('AudioStitcherVideoMerger.soxed_audio[audio_rec]: %s'%
|
|
586
611
|
input_file)
|
|
587
612
|
out_file = _pathname(output_fh)
|
|
588
613
|
logger.debug('sox in and out files: %s %s'%(input_file, out_file))
|
|
614
|
+
logger.debug('calling sox_transform.build()')
|
|
589
615
|
status = sox_transform.build(input_file, out_file, return_output=True )
|
|
590
616
|
logger.debug('sox.build exit code %s'%str(status))
|
|
591
617
|
# audio_rec.edited_version = output_fh
|
|
592
|
-
self.
|
|
618
|
+
self.soxed_audio[audio_rec] = output_fh
|
|
619
|
+
return output_fh
|
|
593
620
|
|
|
594
621
|
def _write_ISOs(self, edited_audio_all_devices):
|
|
595
622
|
"""
|
|
@@ -740,9 +767,10 @@ class AudioStitcherVideoMerger:
|
|
|
740
767
|
(device.ttc, device.tracks.ttc))
|
|
741
768
|
if device.ttc + 1 != device.tracks.ttc: # warn and quit
|
|
742
769
|
print('Error: TicTacCode channel detected is [gold1]%i[/gold1]'%
|
|
743
|
-
device.ttc
|
|
744
|
-
print('and the
|
|
745
|
-
(device_scanner.TRACKSFN,
|
|
770
|
+
(device.ttc), end=' ')
|
|
771
|
+
print('and [gold1]%s[/gold1] for the device [gold1]%s[/gold1] specifies channel [gold1]%i[/gold1],'%
|
|
772
|
+
(device_scanner.TRACKSFN,
|
|
773
|
+
device.name, device.tracks.ttc-1))
|
|
746
774
|
print('Please correct the discrepancy and rerun. Quitting.')
|
|
747
775
|
sys.exit(1)
|
|
748
776
|
if device.tracks.mix == [] and device.tracks.stereomics == []:
|
|
@@ -799,10 +827,12 @@ class AudioStitcherVideoMerger:
|
|
|
799
827
|
logger.debug('stereo_mic_idx_flat %s'%stereo_mic_idx_flat)
|
|
800
828
|
mono_tracks = [i for i in range(1, device.n_chan + 1)
|
|
801
829
|
if i not in stereo_mic_idx_flat]
|
|
802
|
-
logger.debug('mono_tracks: %s'%mono_tracks)
|
|
830
|
+
logger.debug('mono_tracks (with ttc+zeroed included): %s'%mono_tracks)
|
|
803
831
|
# remove TTC track number
|
|
804
|
-
|
|
805
|
-
|
|
832
|
+
to_remove = device.tracks.unused + [device.ttc+1]# unused is sox idx
|
|
833
|
+
[mono_tracks.remove(t) for t in to_remove]
|
|
834
|
+
# mono_tracks.remove(device.ttc + 1)
|
|
835
|
+
logger.debug('mono_tracks (ttc+zeroed removed)%s'%mono_tracks)
|
|
806
836
|
mono_files = [_sox_keep(multichan_tmpfl, [chan]) for chan
|
|
807
837
|
in mono_tracks]
|
|
808
838
|
new_stereo_files = [_sox_mono2stereo(f) for f in mono_files]
|
|
@@ -990,7 +1020,7 @@ class AudioStitcherVideoMerger:
|
|
|
990
1020
|
"""
|
|
991
1021
|
synced_clip_file = self.videoclip.final_synced_file
|
|
992
1022
|
video_path = self.videoclip.AVpath
|
|
993
|
-
timecode = self.videoclip.
|
|
1023
|
+
timecode = self.videoclip.get_start_timecode_string()
|
|
994
1024
|
# self.videoclip.synced_audio = audio_path
|
|
995
1025
|
audio_path = self.videoclip.synced_audio
|
|
996
1026
|
vid_only_handle = self._keep_VIDEO_only(video_path)
|
|
@@ -1138,20 +1168,28 @@ class Matcher:
|
|
|
1138
1168
|
case4 = R1 < A2 < R2
|
|
1139
1169
|
return case1 or case2 or case3 or case4
|
|
1140
1170
|
|
|
1141
|
-
def shrink_gaps_between_takes(self, with_gap=CLUSTER_GAP):
|
|
1171
|
+
def shrink_gaps_between_takes(self, CLI_offset, with_gap=CLUSTER_GAP):
|
|
1142
1172
|
"""
|
|
1143
1173
|
for single cam shootings this simply sets the gap between takes,
|
|
1144
1174
|
tweaking each vid timecode metadata to distribute them next to each
|
|
1145
|
-
other along NLE timeline.
|
|
1175
|
+
other along NLE timeline.
|
|
1176
|
+
|
|
1177
|
+
Moves clusters at the timelineoffset
|
|
1178
|
+
|
|
1179
|
+
For multicam takes, shifts are computed so
|
|
1146
1180
|
video clusters are near but dont overlap, ex:
|
|
1147
1181
|
|
|
1148
|
-
Cluster 1
|
|
1149
|
-
1111111111111
|
|
1150
|
-
11111111111[
|
|
1182
|
+
Cluster 1 Cluster 2
|
|
1183
|
+
1111111111111 2222222222 (cam A)
|
|
1184
|
+
11111111111[inserted gap]222222222 (cam B)
|
|
1151
1185
|
|
|
1152
1186
|
or
|
|
1153
|
-
1111111111111
|
|
1154
|
-
1111111
|
|
1187
|
+
1111111111111[inserted 222222 (cam A)
|
|
1188
|
+
1111111 gap]222222222 (cam B)
|
|
1189
|
+
|
|
1190
|
+
argument:
|
|
1191
|
+
CLI_offset (str), option from command-line
|
|
1192
|
+
with_gap (float), the gap duration in seconds
|
|
1155
1193
|
|
|
1156
1194
|
Returns nothing, changes are done in the video files metadata
|
|
1157
1195
|
(each referenced by Recording.final_synced_file)
|
|
@@ -1212,17 +1250,25 @@ class Matcher:
|
|
|
1212
1250
|
cummulative_offsets = [td.total_seconds() for td in cummulative_offsets]
|
|
1213
1251
|
logger.debug('cummulative_offsets: %s'%cummulative_offsets)
|
|
1214
1252
|
time_of_first = clusters[0]['start']
|
|
1253
|
+
# compute CLI_offset_in_seconds from HH:MM:SS:FF in CLI_offset
|
|
1254
|
+
h, m, s, f = [float(s) for s in CLI_offset[0].split(':')]
|
|
1255
|
+
logger.debug('CLI_offset float values %s'%[h,m,s,f])
|
|
1256
|
+
CLI_offset_in_seconds = 3600*h + 60*m + s + f/vids[0].get_framerate()
|
|
1257
|
+
logger.debug('CLI_offset in seconds %f'%CLI_offset_in_seconds)
|
|
1215
1258
|
offset_for_all_clips = - from_midnight(time_of_first).total_seconds()
|
|
1259
|
+
offset_for_all_clips += CLI_offset_in_seconds
|
|
1216
1260
|
logger.debug('time_of_first: %s'%time_of_first)
|
|
1217
1261
|
logger.debug('offset_for_all_clips: %s'%offset_for_all_clips)
|
|
1218
1262
|
for cluster, offset in zip(clusters, cummulative_offsets):
|
|
1263
|
+
# first one starts at 00:00:00:00
|
|
1219
1264
|
total_offset = offset + offset_for_all_clips
|
|
1220
1265
|
logger.debug('for %s offset in sec: %f'%(cluster['vids'],
|
|
1221
1266
|
total_offset))
|
|
1222
1267
|
for vid in cluster['vids']:
|
|
1223
|
-
tc = vid.
|
|
1268
|
+
# tc = vid.get_start_timecode_string(CLI_offset, with_offset=total_offset)
|
|
1269
|
+
tc = vid.get_start_timecode_string(with_offset=total_offset)
|
|
1224
1270
|
logger.debug('for %s old tc: %s new tc %s'%(vid,
|
|
1225
|
-
vid.
|
|
1271
|
+
vid.get_start_timecode_string(), tc))
|
|
1226
1272
|
vid.write_file_timecode(tc)
|
|
1227
1273
|
return
|
|
1228
1274
|
|