Edit strip with compositor


(TMW) #21

I gues it would want to be something like this for the camera:

for objects in bpy.data.scenes[strip.name]:
    if bpy.objects.camera = True:
        pass
    else bpy.ops.object.camera_add()

However, this doesn’t seem to work.

Thanks
Tom


(peddie) #22

OK, camera solved by linking original camera to new scenes.

import bpy
 
class CompPanel(bpy.types.Panel):
    bl_space_type = "SEQUENCE_EDITOR"
    bl_region_type = "UI"
    bl_label = "Edit strip with Compositor"
 
    def draw(self, context):
        scn = bpy.context.scene
        layout = self.layout
        row = layout.row()
        col = row.column()
 
 
        col.operator( "bpt.sample_op" )
 
 
class CompOperator(bpy.types.Operator):
 
    bl_idname = "bpt.sample_op"
    bl_label = "Edit strip with Compositor"
 
    def invoke(self, context, event ):
        
            import bpy
            
            # Get selected strips
            sel_strips = bpy.context.selected_sequences
            
            # Get current scene
            cur_scene = bpy.context.scene
            
            # Get current camera, used for linking with other scenes
            cur_camera = cur_scene.camera
            
            # Loop selected strips                         
            for strip in sel_strips:
            
              # Check if strip is a movie
              if (strip.type == 'MOVIE'):

                # Creates new scene but doesn't set it as active.
                new_scene = bpy.data.scenes.new(strip.name)
                
                # Change render settings for new scene to match original scene
                new_scene.render.resolution_x = cur_scene.render.resolution_x
                new_scene.render.resolution_y = cur_scene.render.resolution_y
                new_scene.render.resolution_percentage = cur_scene.render.resolution_percentage
                new_scene.render.fps  = cur_scene.render.fps 
                
                # Select original active camera
                for object in bpy.data.objects:
                    object.select = False
                cur_camera.select = True
                bpy.context.scene.objects.active = cur_camera
                
                # Link camera to new scene
                bpy.ops.object.make_links_scene(scene=new_scene.name)           

                # Change new scene EndFrame to match strip length            
                new_scene.frame_end = strip.frame_final_duration
                
                # Setup nodes
                new_scene.use_nodes = True
                tree = new_scene.node_tree
                
                # Clear default nodes
                for n in tree.nodes:
                    tree.nodes.remove(n)
                    
                # Create input node
                rl = tree.nodes.new('IMAGE')      
                rl.location = 0,0 
                
                #Get source of strip
                StripPath = bpy.path.resolve_ncase(strip.filepath)
                StripSource = bpy.data.images.load(StripPath)
                StripSource.source= strip.type
                
                # Add strip path
                rl.image = StripSource
                
                # Update scene 
                new_scene.update()
                StripSource.update()
                new_scene.frame_current = 2                
                
                # Other input settings
                rl.use_cyclic = False
                rl.use_auto_refresh = True
                rl.frame_duration = strip.frame_final_duration
                rl.frame_offset = strip.frame_offset_start                
                
                # create output node
                comp = tree.nodes.new('COMPOSITE')   
                comp.location = 400,0
            
                # Link nodes
                links = tree.links
                link = links.new(rl.outputs[0],comp.inputs[0])    
                
                # Change current scene to original                                    
                data_context = {"blend_data": bpy.context.blend_data, "Scene": new_scene}
                bpy.context.screen.scene.update()
                
                # Add newly created scene                                           
                bpy.ops.sequencer.scene_strip_add(frame_start=strip.frame_final_start, channel=strip.channel + 1, replace_sel=False, scene=new_scene.name)                                
                # Edit the strip length to match original strip                                                  
                bpy.context.sequences[0].frame_final_end = strip.frame_final_end
                
                self.report( "INFO", "DONE!" )
            return {'FINISHED'}
 
 
def register():
    bpy.utils.register_class( CompPanel )
    bpy.utils.register_class( CompOperator )
 
 
def unregister():
    bpy.utils.register_class( CompPanel )
    bpy.utils.register_class( CompOperator )
 
 
if __name__ == "__main__":
    register()

To make the new scene-strip not render black, you first have to render it from it’s own scene (Not the original with the sequencer). I can’t figure out how to solve that…


(TMW) #23

This seems to have solved the problem:

import bpy
 
class CompPanel(bpy.types.Panel):
    bl_space_type = "SEQUENCE_EDITOR"
    bl_region_type = "UI"
    bl_label = "Edit strip with Compositor"
 
    def draw(self, context):
        scn = bpy.context.scene
        layout = self.layout
        row = layout.row()
        col = row.column()
 
 
        col.operator( "bpt.sample_op" )
 
 
class CompOperator(bpy.types.Operator):
 
    bl_idname = "bpt.sample_op"
    bl_label = "Edit strip with Compositor"
 
    def invoke(self, context, event ):
        
            import bpy
            
            # Get selected strips
            sel_strips = bpy.context.selected_sequences
            
            # Get current scene
            cur_scene = bpy.context.scene
            
            # Get current camera, used for linking with other scenes
            cur_camera = cur_scene.camera
            
            # Loop selected strips                         
            for strip in sel_strips:
            
              # Check if strip is a movie
              if (strip.type == 'MOVIE'):
                # Creates new scene but doesn't set it as active.
                new_name = '{}{}'.format(strip.name, '_Comp')
                new_scene = bpy.data.scenes.new(new_name)
                
                # Change render settings for new scene to match original scene
                new_scene.render.resolution_x = cur_scene.render.resolution_x
                new_scene.render.resolution_y = cur_scene.render.resolution_y
                new_scene.render.resolution_percentage = cur_scene.render.resolution_percentage
                new_scene.render.fps  = cur_scene.render.fps 
                
                
                
                # Link camera to new scene
                #bpy.ops.object.make_links_scene(scene=new_scene.name)           
                # Change new scene EndFrame to match strip length            
                new_scene.frame_end = strip.frame_final_duration
                
                # Setup nodes
                new_scene.use_nodes = True
                tree = new_scene.node_tree
                
                # Clear default nodes
                for n in tree.nodes:
                    tree.nodes.remove(n)
                    
                # Create input node
                rl = tree.nodes.new('IMAGE')      
                rl.location = 0,0 
                
                #Get source of strip
                StripPath = bpy.path.resolve_ncase(strip.filepath)
                StripSource = bpy.data.images.load(StripPath)
                StripSource.source= strip.type
                
                # Add strip path
                rl.image = StripSource
                
                # Update scene 
                new_scene.update()
                StripSource.update()
                new_scene.frame_current = 2                
                
                # Other input settings
                rl.use_cyclic = False
                rl.use_auto_refresh = True
                rl.frame_duration = strip.frame_final_duration
                rl.frame_offset = strip.frame_offset_start                
                
                # create output node
                comp = tree.nodes.new('COMPOSITE')   
                comp.location = 400,0
            
                # Link nodes
                links = tree.links
                link = links.new(rl.outputs[0],comp.inputs[0])    
                
                # Change current scene to original                                    
                data_context = {"blend_data": bpy.context.blend_data, "Scene": new_scene}
                bpy.context.screen.scene.update()
                
                # Add newly created scene                                           
                bpy.ops.sequencer.scene_strip_add(frame_start=strip.frame_final_start, channel=strip.channel + 1, replace_sel=False, scene=new_scene.name) 
                
                print(new_scene.name)
                
                #Camera override
                bpy.context.scene.sequence_editor.active_strip = bpy.data.scenes["Scene"].sequence_editor.sequences_all[new_scene.name]
                bpy.data.scenes['Scene'].sequence_editor.active_strip.scene_camera = bpy.data.objects['Camera']
                                               
                # Edit the strip length to match original strip                                                  
                bpy.context.sequences[0].frame_final_end = strip.frame_final_end
                
                self.report( "INFO", "DONE!" )
            return {'FINISHED'}
 
 
def register():
    bpy.utils.register_class( CompPanel )
    bpy.utils.register_class( CompOperator )
 
 
def unregister():
    bpy.utils.register_class( CompPanel )
    bpy.utils.register_class( CompOperator )
 
 
if __name__ == "__main__":
    register()

However it doesn’t appear in the sequencer preview window, it only renders. This uses the camera override function.

Thanks
Tom


(peddie) #24

Here is the same code with some minor fixes for scene-strip positioning which was wrong:

import bpy
 
class CompPanel(bpy.types.Panel):
    bl_space_type = "SEQUENCE_EDITOR"
    bl_region_type = "UI"
    bl_label = "Edit strip with Compositor"
 
    def draw(self, context):
        scn = bpy.context.scene
        layout = self.layout
        row = layout.row()
        col = row.column()
 
 
        col.operator( "bpt.sample_op" )
 
 
class CompOperator(bpy.types.Operator):
 
    bl_idname = "bpt.sample_op"
    bl_label = "Edit strip with Compositor"
 
    def invoke(self, context, event ):
        
            import bpy
            
            # Get selected strips
            sel_strips = bpy.context.selected_sequences
            
            # Get current scene
            cur_scene = bpy.context.scene
            
            # Get current camera, used for linking with other scenes
            cur_camera = cur_scene.camera
            
            # Loop selected strips                         
            for strip in sel_strips:
            
              # Check if strip is a movie
              if (strip.type == 'MOVIE'):
                # Creates new scene but doesn't set it as active.
                new_name = '{}{}'.format(strip.name, '_Comp')
                new_scene = bpy.data.scenes.new(new_name)
                
                # Change render settings for new scene to match original scene
                new_scene.render.resolution_x = cur_scene.render.resolution_x
                new_scene.render.resolution_y = cur_scene.render.resolution_y
                new_scene.render.resolution_percentage = cur_scene.render.resolution_percentage
                new_scene.render.fps  = cur_scene.render.fps 
                
                
                
                # Link camera to new scene
                #bpy.ops.object.make_links_scene(scene=new_scene.name)           
                # Change new scene EndFrame to match strip length            
                new_scene.frame_end = strip.frame_final_duration
                
                # Setup nodes
                new_scene.use_nodes = True
                tree = new_scene.node_tree
                
                # Clear default nodes
                for n in tree.nodes:
                    tree.nodes.remove(n)
                    
                # Create input node
                rl = tree.nodes.new('IMAGE')      
                rl.location = 0,0 
                
                #Get source of strip
                StripPath = bpy.path.resolve_ncase(strip.filepath)
                StripSource = bpy.data.images.load(StripPath)
                StripSource.source= strip.type
                
                # Add strip path
                rl.image = StripSource
                
                # Update scene 
                new_scene.update()
                StripSource.update()
                new_scene.frame_current = 2                
                
                # Other input settings
                rl.use_cyclic = False
                rl.use_auto_refresh = True
                rl.frame_duration = strip.frame_final_duration
                rl.frame_offset = strip.frame_offset_start                
                
                # create output node
                comp = tree.nodes.new('COMPOSITE')   
                comp.location = 400,0
            
                # Link nodes
                links = tree.links
                link = links.new(rl.outputs[0],comp.inputs[0])    
                
                # Change current scene to original                                    
                data_context = {"blend_data": bpy.context.blend_data, "Scene": new_scene}
                bpy.context.screen.scene.update()
                
                # Add newly created scene                                           
                bpy.ops.sequencer.scene_strip_add(frame_start=strip.frame_final_start, channel=strip.channel + 1, replace_sel=False, scene=new_scene.name) 
                                
                #Camera override
                bpy.context.scene.sequence_editor.active_strip = bpy.data.scenes["Scene"].sequence_editor.sequences_all[new_scene.name]
                bpy.data.scenes['Scene'].sequence_editor.active_strip.scene_camera = cur_camera
                                               
                # Edit the strip length to match original strip                                                  
                bpy.context.scene.sequence_editor.active_strip.frame_final_end = strip.frame_final_end
                
                self.report( "INFO", "DONE!" )
            return {'FINISHED'}
 
 
def register():
    bpy.utils.register_class( CompPanel )
    bpy.utils.register_class( CompOperator )
 
 
def unregister():
    bpy.utils.register_class( CompPanel )
    bpy.utils.register_class( CompOperator )
 
 
if __name__ == "__main__":
    register()

It’s sad that it’s impossible to get a live feedback from the compositor in the VSE.

Well, I think that the script is usable at last. Lots of improvements could be made but for now I’m quite happy.

Examples of things to improve:

  • Live preview from the compositor to the VSE.
  • Copy the effects from the original footage to the scene-strip.
  • Match the dimensions of the original footage instead of the original scene.
  • Make it work with stills (I think it already does, just have to add it to the IF type=).
  • Come up with a better handling for the channels.

Thanks again Tom!


(TMW) #25

Okay, I’ll sse what I can do. Would it be worth making it a propper addon?

Thanks
Tom


(peddie) #26

Great Tom!

I really don’t know if it’s current state has what it takes to be a proper addon… Also, there doesn’t seem to be much interest in this feature, but maybe I’m wrong…

Maybe, the best thing would be to implement it as a feature in Blenders C source, solving the live preview and more on the way.

Right now the script feels a little hackish, especially if we were to do the improvements from my list above.

What do you think?

Thanks
Niclas


(3pointEdit) #27

I think its a great idea but blenders proccessing speed is a killer. How does the composited strip come back? It would be helpfull if they could stack over the original so you coud switch it of for performance. Also do all the scenes render concurently or do they match the time in the master timeline?


(carlos padial) #28

@peddie & tom: you made a great work with this. Thanks.
Even without the live preview is a lot helpful operator.

anyway, the live preview works… but a little instable…

If i add a scene strip in the vse of the composite-node scene , then i can see the preview in the first scene…

it works without render

you cannot do this in the script, as you cannot edit other scene neither switch between scenes while running the script (i think it’s done as a rule to avoid accidentally change something in the wrong scene, you can only execute operators in the current scene, but i dont know how to create strips with other method)

sometimes it doesn work, but i save the file, restart blender and then the preview is there again, alt+a makes it play (so, slow, but working)

also if i stop the playback with ‘esc’ the preview becomes black, and i need to restart blender to recover it. But if i use only alt+a to stop the playback it still work… it also happens when i press esc after rendering, but if i swich from image panel to vse panel without pressing ‘esc’, the preview survive…

keep the good work and i’ll try to help with this


(TMW) #29

Finaly, got round to looking at this again, I’ve worked out a way to get the new strip to copy the origional ones settings (insert after line 102)

 #Copy Settings
                bpy.data.scenes['Scene'].sequence_editor.sequences[new_name].use_flip_x =  bpy.data.scenes['Scene'].sequence_editor.sequences_all[strip.name].use_flip_x

but it would require writing something similar to this for each setting. Is this the best way?

Thanks
Tom


(TMW) #30

I’ve tried to update the UI a bit to give the user more options, and I’ve got it to copy all the settings. The new UI should let the user choose which settings to copy. I’m having trouble with getting the bolean prop tick box thing to work, does anyone have any ideas?

The script s attached.Composite Strip_.zip (2.12 KB)

Thanks
Tom


(3pointEdit) #31

Tom I was just wondering if this script could be modified to produce a Temp render strip for a master/edit sequence?

Reason: Often playing Strip effects in the timeline can slow playback. But a rendered version plays ok.

Suggestion: Instead of creating a Compositor scene, for sending the strip (or stack of effects strips) too, we could send them to their own VSE timeline (sort of like pre-composing in AE). Then Blender could render that in the background while you continue working. The sticking point is re-importing the result and using it to play back at the appropriate place on the timeline.

Perhaps it could be Meta-stripped with the pseudo or scene strip, or it could just go at the top with the scene name. And I’m not sure that you can ask Blender to render another scene in the background while you work in a different scene anyway.


(TMW) #32

Okay so do you mean:

  • Create a new scene for the clip.
  • Do your effects.
  • Do a background (low res?) render
  • import that into the master edit.
    One problem with this is it would be hard to do quick changes as you would have to rerender all the time.

One way to background render may be through the console with a seperate Blender running (I think you can)?

Thanks
Tom


(3pointEdit) #33

Hmmm. I tried rendering another VSE scene but could not scrub the master scene at the same time. But pushing to another Blender in Background would work. Proxy rendering seems to do something similar (but without the application instance).

I wonder if its possible to:

  1. bundle the effects you want to temp render into a Meta-strip
  2. copy meta-strip
  3. un-meta in master scene (return to normal)
  4. paste Meta-strip in another “Temp render” scene (at same frame location), save scene.
  5. render that “Temp render” scene, possibly in another Blender (via command line?)
  6. Import “Temp render” to the frame range it was exported from (to line up with effect).

I believe that Meta strips retain the correct frame location from the master timeline too. All this copying metas and accessing frames was available in the jump to cut script too.

Does it sound at all practical? Thanks for your time thinking about such a crazy idea.

EDIT:
Thinking about it all sounds like a lot of work. All I really need to do is command line render that portion from the saved master .blend scene. If you do that in the background then you wouldn’t have to send strips to scenes. Just getting the strip back automatically would be cool. So it looks like I have pestered you for nothing. Sorry. Can I ask if you think that you can get a script to run another instance of Blender externally? Or could I use another Blender as a frame serve renderer?


(TMW) #34

Okay, we could use his to do a background render and then save it to a special project folder, and then load that into the sequencer.

import bpy
import os
os.system('blender -h')

I guess the workflow would be:

  • press a button hat makes a new scene with nodes in
  • do your compositing
  • press another botton to do a background render and add it to your master edit strip.
    Or we could possibly have each composition as a seperate .blend using
os.system('blender')

These only work if you have Blender installed as a enviroment variable.

Thanks
Tom


(3pointEdit) #35

Would be great if Sergey could add proxy render to scene strips. It’s there but wont generate anything :frowning: then we could have a preview render in VSE rendered in the background.


(3pointEdit) #36

Just had another play with the updated version of this script. I LOVE IT. Thankyou so much to the people that built it.

I wondered if there would be a way to send 2 or 3 strips that are layered (for timing) to the same composite? For example keying requires a background layer a top layer and sometimes an alpha channel. They all need to be lined up the same though, in the same comp.

EDIT:
I just noticed that the VSE resizes non-scene sized footage, but the compositor of course doesn’t. I have to add a node to stretch the VSE clip out correctly. Also I find that with a UV Image viewer open I can rapidly update from a compositor clip :slight_smile:


(3pointEdit) #37


Here is the fault that I encountered when sending the strip. But it seemed to work ok. I just don’t know what I am missing.


(TMW) #38

Hi,

I haven’t looked into this for a while, but I have and idea that I’ll try. If we used command line to background render comp scen in the same blend file (as the open one), and then imported that into the comp scenes VSE it might work for live playback? Also I’ll think about the sending of multiple strips, but that shouldn’t be to hard.

Thanks
Tom


(3pointEdit) #39

Oh wow those wold be cool fixes. Thankyou


(TMW) #40

Okay, the script now has a new button that allows you to create a new comp with multilpe strips in it. The first strip you select, is the master strip (i.e. the name of the comp scene and the input initialy connected to the comp node). Is this what you meant?

Composite Strip_1.zip (2.6 KB)

Thanks
Tom