2
$\begingroup$

I have a number of different MP4 files. I want to create a Blender project file that has these files in a set order and each video stream starting at a set start time.

I know the files, I know the order and I know the start time I would like. Can I use a script that generates this project file or a script to setup Blender to then save as a project file?

$\endgroup$
  • 1
    $\begingroup$ Of course. You only have to make sure that blender supports all your different codecs / container formats 'by hand'. This answer from @zachman should be a solid starting point. $\endgroup$ – p2or Sep 3 '15 at 12:55
2
$\begingroup$

I use the following script to import my mts video files into a new project.

Use it like: blender --factory-startup --python script.py -- --save="path\project.blend" -m="folder_with_mts_files_relative_to_blend_file" -n="optional_second_folder".

It imports a "Textmarken.txt" (Audacity Text Labels) as well if existing and sets up the view in Blender as well as some Video Properties for my project as I need them. It should help you well to see what's possible and adapt it to your needs. It most likely does more than what you want to achieve, but it will for sure guide you into a proper way...

import bpy
import os
bpy.context.user_preferences.view.show_splash = False
channel = 1


def read_labels_data(filepath):
    f = open(filepath, 'r', encoding='utf-8')
    data = f.readlines()
    data = [w.replace(',', '.') for w in data]
    f.close()

    scene = bpy.context.scene
    default_frame = scene.frame_current

    override = {'region': bpy.context.window_manager.windows[0].screen.areas[2].regions[0], 'blend_data': bpy.context.blend_data, 'scene': bpy.data.scenes['Scene'], 'window': bpy.context.window_manager.windows[0], 'screen': bpy.data.screens['Video Editing'], 'area': bpy.data.screens['Video Editing'].areas[1]}

    bpy.data.screens['Video Editing'].areas[1].type = ('TIMELINE')

    print('---Import Audacity Labels to Timeline Markers---')
    for i in range(0, len(data)):
        seconds = data[i].split()
        frame = bpy.utils.time_to_frame(float(seconds[0]), fps=None, fps_base=None)
        scene.frame_current = (frame)
        bpy.ops.marker.add(override)

    bpy.ops.marker.select_all(override, action='TOGGLE')
    scene.frame_current = default_frame

    return {'FINISHED'}


def import_function(save_path, mts_path1, mts_path2):
    scene = bpy.context.scene
    base_path = os.path.split(save_path)[0]

    # Clear existing objects.
    scene.camera = None
    for obj in scene.objects:
        scene.objects.unlink(obj)

    if save_path:
        save_path = os.path.abspath(save_path)
        try:
            f = open(save_path, 'w')
            f.close()
            ok = True
        except:
            print("Cannot save to path %r" % save_path)
            import traceback
            traceback.print_exc()
        if ok:
            bpy.ops.wm.save_as_mainfile(filepath=save_path)

    # Set up GUI - open screen "Video Editing"
    bpy.ops.screen.screen_set(delta=1)
    bpy.ops.screen.screen_set(delta=1)
    bpy.ops.screen.screen_set(delta=1)
    bpy.ops.screen.screen_set(delta=1)
    bpy.ops.screen.screen_set(delta=1)
    #bpy.data.screens['Video Editing'].areas[0].type = 'INFO'
    #bpy.data.screens['Video Editing'].areas[1].type = 'TIMELINE'
    #bpy.data.screens['Video Editing'].areas[2].type = 'SEQUENCE_EDITOR'
    # Change Graph-Editor into Properties:
    bpy.data.screens['Video Editing'].areas[3].type = 'PROPERTIES'
    #bpy.data.screens['Video Editing'].areas[4].type = 'SEQUENCE_EDITOR'

    # PROPERTIES - Area
    override = {'region': bpy.context.window_manager.windows[0].screen.areas[2].regions[0], 'blend_data': bpy.context.blend_data, 'scene': bpy.data.scenes['Scene'], 'window': bpy.context.window_manager.windows[0], 'screen': bpy.data.screens['Video Editing'], 'area': bpy.data.screens['Video Editing'].areas[3]}
    presets   = bpy.utils.script_paths()[1] + "\\presets"

    # Set Video-Properties
    bpy.ops.script.python_file_run(override, filepath= presets + "\\render\\HDTV_720p.py")
    #bpy.context.scene.render.resolution_percentage = 100
    bpy.ops.script.python_file_run(override, filepath= presets + "\\framerate\\25.py")
    bpy.context.scene.render.antialiasing_samples = '16'
    bpy.context.scene.render.filepath = "//out"
    bpy.data.scenes['Scene'].render.image_settings.file_format = 'H264'
    bpy.data.scenes['Scene'].render.image_settings.color_mode = 'RGB'
    bpy.ops.script.python_file_run(override, filepath= presets + "\\ffmpeg\\h264.py")
    bpy.data.scenes['Scene'].render.ffmpeg.use_lossless_output = False
    bpy.data.scenes['Scene'].render.ffmpeg.video_bitrate = 4500
    bpy.data.scenes['Scene'].render.ffmpeg.gopsize = 25
    bpy.data.scenes['Scene'].render.ffmpeg.maxrate = 7000
    bpy.data.scenes['Scene'].render.ffmpeg.audio_codec = 'MP3'
    bpy.data.scenes['Scene'].render.ffmpeg.audio_bitrate = 64
    bpy.context.scene.render.engine = 'CYCLES'


    # Playback-Settings
    bpy.context.scene.use_audio_scrub = True
    bpy.context.scene.use_frame_drop = True
    bpy.context.scene.sync_mode = 'AUDIO_SYNC'
    bpy.data.screens["Video Editing"].use_follow = True

    # If existing, read "Textmarken.txt"
    marken = base_path + "\\Textmarken.txt"
    if os.path.exists(marken):
        read_labels_data(marken)

    # Sequencer Area
    override = {'region': bpy.context.window_manager.windows[0].screen.areas[2].regions[0], 'blend_data': bpy.context.blend_data, 'scene': bpy.data.scenes['Scene'], 'window': bpy.context.window_manager.windows[0], 'screen': bpy.data.screens['Video Editing'], 'area': bpy.data.screens['Video Editing'].areas[2]}

    if mts_path1:
        import_from(override, base_path + "\\" + mts_path1)
    if mts_path2:
        import_from(override, base_path + "\\" + mts_path2, True)
    bpy.ops.wm.save_mainfile()

    for name in os.listdir(base_path):
        if '.wav' in name or '.WAV' in name:
            print(name)
            # add all further wave files
            bpy.ops.sequencer.sound_strip_add(override, filepath=base_path + "\\" + name, frame_start=1, channel=channel*2)
            #bpy.data.sounds[name].use_memory_cache = True
            bpy.data.scenes['Scene'].sequence_editor.sequences_all[name].show_waveform = True

    #bpy.ops.sequencer.view_all(override)
    # deselect all strips
    for seq in bpy.data.scenes['Scene'].sequence_editor.sequences_all:
        seq.select = False


def import_from(override, mts_path, muted=False):
    global channel
    print(channel)

    names = os.listdir(mts_path)
    frame = 1
    #print(names)
    names = sorted(names)
    for name in names:
        if 'MTS' in name and not '.lwi' in name:
            print(name)
            base = os.path.splitext(name)[0]
            avi = base + ".avi"

            # add original video strip to get the audio and delete the video again (you might omit the delete)
            bpy.ops.sequencer.movie_strip_add(override, filepath=mts_path + "\\" + name, frame_start=frame, channel=7 + channel*2)
            for seq in bpy.data.scenes['Scene'].sequence_editor.sequences_all:
                seq.select = False
            bpy.data.scenes['Scene'].sequence_editor.sequences_all[base + ".001"].select = True
            bpy.ops.sequencer.delete()
            bpy.data.scenes['Scene'].sequence_editor.sequences_all[name].mute = True

            # Add AVI files from AVS-folder (you might not need this)
            bpy.ops.sequencer.movie_strip_add(override, filepath=mts_path + "\\" + base + ".avs\\" + avi, frame_start=frame, channel=7)
            bpy.data.scenes['Scene'].sequence_editor.sequences_all[avi].mute = muted
            bpy.data.scenes['Scene'].sequence_editor.sequences_all[avi].channel = channel
            frame += bpy.data.scenes['Scene'].sequence_editor.sequences_all[avi].frame_duration

    # move first audio strip back down
    for name in names:
        if 'MTS' in name and not '.lwi' in name:
            print(name)
            bpy.data.scenes['Scene'].sequence_editor.sequences_all[name].channel = 2*channel+1
            #bpy.data.sounds[name].use_memory_cache = True
            bpy.data.scenes['Scene'].sequence_editor.sequences_all[name].show_waveform = True
            break

    if not muted:
        bpy.data.scenes['Scene'].frame_end = frame

    # deselect all strips
    for seq in bpy.data.scenes['Scene'].sequence_editor.sequences_all:
        seq.select = False
    channel += 1


def main():
    import sys       # to get command line args
    import argparse  # to parse options for us and print a nice help message

    # get the args passed to blender after "--", all of which are ignored by
    # blender so scripts may receive their own arguments
    argv = sys.argv

    if "--" not in argv:
        argv = []  # as if no args are passed
    else:
        argv = argv[argv.index("--") + 1:]  # get all args after "--"

    # When --help or no args are given, print this help
    usage_text = \
    "Run blender in background mode with this script:"
    "  blender --background --python " + __file__ + " -- [options]"

    parser = argparse.ArgumentParser(description=usage_text)

    parser.add_argument("-s", "--save", dest="save_path", metavar='FILE',
            help="Save the generated file to the specified path")

    parser.add_argument("-m", "--mts_path1", dest="mts_path1", metavar='FILE',
            help="Open all MTS-Files from this path")

    parser.add_argument("-n", "--mts_path2", dest="mts_path2", metavar='FILE',
            help="Open all MTS-Files from this path")

    args = parser.parse_args(argv)  # In this example we wont use the args

    if not argv:
        parser.print_help()
        return

    # Run the import_function
    import_function(args.save_path, args.mts_path1, args.mts_path2)

    print("batch job finished, done")


if __name__ == "__main__":
    main()
$\endgroup$
  • 3
    $\begingroup$ Thanks for sharing, but you should mention that this script only works with Windows. I'd recommend using os.path.join() for platform independent python, see: stackoverflow.com/questions/10918682/… $\endgroup$ – p2or Nov 18 '15 at 11:51
  • $\begingroup$ Well yeah, I only used and developed it on Windows as I use avfs and Pismo File Mount as well. If there's only little change required, feel free to update the code, I've got no experience with Blender on other platforms yet... $\endgroup$ – Samoth Nov 18 '15 at 11:53
  • 2
    $\begingroup$ There is a VSE logging editing addon available here easy-logging.net it allows you to allocate start and finish times to media, then sort those clips in the desired manner. $\endgroup$ – 3pointedit Nov 18 '15 at 12:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.