Welcome to WSL!

Make yourself at home, but before posting, please may I ask you to read the following topics.


Posting 101
Server space, screenshots, and you

Thank you!

PS. please pretty please:


Image

Resolve Scripting Essentials

User avatar
AndrewHazelden
Fusionator
Posts: 1597
Joined: Fri Apr 03, 2015 3:20 pm
Answers: 9
Location: West Dover, Nova Scotia, Canada
Been thanked: 7 times
Contact:

Re: Resolve Scripting Essentials

#61

Post by AndrewHazelden » Thu Dec 13, 2018 4:45 pm

pixelstuff wrote:
Thu Dec 13, 2018 3:31 pm
Really useful, I will play with some of those color options, I didn't think about html.
@pixelstuff I just uploaded an HTML based rendering tech demo called the PipePixelFont to the WSL UI manager thread. I posted this example so you can see how the CSS background-image tag can be used to add style tags in real-time to your ui:TextEdit UI elements.

If you look at the code in the "UI-Manager-PipePixelFont-GUI-Demo.zip" demo you might notice that the resizable background "node view" like grid texture was done using old-school HTML + CSS with a "background-image" tag:

Code: Select all

	<style>
		body { background-image: url('grid.png') }
	</style>

This approach unlocks some really cool things like multi-layered graphics in a GUI that a lot of people might never have expected to be possible inside of UI Manager. It also shows how UI Manager is a big step up from the previous IUP GUI building system in Fusion 7. :)

User avatar
pixelstuff
Posts: 46
Joined: Sun Jul 15, 2018 11:50 am
Been thanked: 1 time

Re: Resolve Scripting Essentials

#62

Post by pixelstuff » Sun Jan 27, 2019 12:14 pm

fu:ToggleUtility('SVGImport')


Thanks for providing these examples really helped. Is there a way to prevent the file open browser and directly reference a file or does this command link to a separate script? and would that script be available to see the lua code? to be able to update it in this way?

User avatar
ConorBowes
Posts: 2
Joined: Mon Jan 07, 2019 3:41 pm

Re: Resolve Scripting Essentials

#63

Post by ConorBowes » Mon Feb 04, 2019 4:26 pm

Does anyone know of a way to add a job to the render queue for Deliver tab for remote rendering? I have been able to get the job added quite easily, but I cannot find a way to make it added with the remote renderer.

User avatar
MrPingouin
Posts: 1
Joined: Thu Mar 21, 2019 3:46 am

Re: Resolve Scripting Essentials

#64

Post by MrPingouin » Fri Mar 22, 2019 3:05 am

Hello World !

I'm new to DaVinci Resolve (since yesterday actually).

The Help browser helped me A LOT (I'm quite used to finding informations this way, I wrote a lot of scripts for After FX using ExtendScript toolkit object browser).

However, there's a Track information that would help me a lot in my tools, but I can't manage to reach it by script : a track's name.
  1. local timeline = p:GetCurrentTimeline() -- this is ok
  2. local trackCount = timeline:GetTrackCount("video") -- this is ok
  3. local trackItems = timeline:GetItemsInTrack("video",5)) -- let's say we take the items in video track 5, this is ok
Does someone know a way to access track names ?

Best regards, and thanks for again for this helpful thread.

User avatar
SirEdric
Fusionator
Posts: 2310
Joined: Tue Aug 05, 2014 10:04 am
Answers: 12
Real name: Eric Westphal
Been thanked: 42 times
Contact:

Re: Resolve Scripting Essentials

#65

Post by SirEdric » Mon Apr 15, 2019 1:13 am

SirEdric wrote:
Wed Apr 11, 2018 10:58 pm
Now if one only could do something like fu:ToggleUtility('FBXImport', 'p:\ath\to\file.obj', autoImport = true)
Quoting myself here....:-)
Does anybody have new information on this topic for F16?
Is there a way now to import fbx via script?

User avatar
llamafilm
Posts: 8
Joined: Thu May 23, 2019 8:42 am

Grading nodes

#66

Post by llamafilm » Thu Jun 20, 2019 7:13 pm

Is there any way to read/write data from grading nodes in Resolve's color page with a script? I haven't found anything in the documentation. Why should Fusion users get to have all the fun?

User avatar
AskoK
Posts: 3
Joined: Tue Jul 02, 2019 2:31 am

Re: Resolve Scripting Essentials

#67

Post by AskoK » Wed Jul 03, 2019 7:04 am

Hey,

Does anyone know if altering timeline is possible via python script? Like cutting 5 seconds from beginning and ending?

User avatar
kir3d
Posts: 5
Joined: Sun Oct 11, 2015 10:49 am

Re: Resolve Scripting Essentials

#68

Post by kir3d » Mon Dec 16, 2019 8:24 am

Macos 10.15.1, DVR 16.1 Studio, Python 3.7.3 with DVR API.
I can import: mediaStorage.AddItemsToMediaPool(name)
Can create empty timeline: mediaPool.CreateEmptyTimeline(name)
But don't understand how to CreateTimelineFromClips or AppendToTimeline(name).
Can show examples of use?

User avatar
Igor Ridanovic
Posts: 37
Joined: Mon Apr 16, 2018 11:17 pm
Location: Los Angeles
Been thanked: 2 times
Contact:

Re: Resolve Scripting Essentials

#69

Post by Igor Ridanovic » Wed Jan 08, 2020 12:29 pm

Timeline append example about 7:20 in.


User avatar
kir3d
Posts: 5
Joined: Sun Oct 11, 2015 10:49 am

Re: Resolve Scripting Essentials

#70

Post by kir3d » Sun Jan 12, 2020 3:28 pm

Thank you Igor! I also make:
mediaPool.CreateTimelineFromClips(name, mediaPool.GetCurrentFolder().GetClips()[index])

Now I don't understand how to append audio to second track and Fusion comp to second track. May be Fusion comp like Template with publishing text fields for changing. I tried make edl with structure - only one track, tried male fcpxml - ignored Fusion composition :(

P.S. I seen you video about dynamic text. This and other very nice and helpful tutorials!

User avatar
Igor Ridanovic
Posts: 37
Joined: Mon Apr 16, 2018 11:17 pm
Location: Los Angeles
Been thanked: 2 times
Contact:

Re: Resolve Scripting Essentials

#71

Post by Igor Ridanovic » Mon Jan 13, 2020 10:26 am

I think you can currently only append to the bottom track. If you're thinking using the XML or AAF route you may want to look into OpenTimelineIO. https://github.com/PixarAnimationStudios/OpenTimelineIO

User avatar
kir3d
Posts: 5
Joined: Sun Oct 11, 2015 10:49 am

Re: Resolve Scripting Essentials

#72

Post by kir3d » Tue Jan 14, 2020 10:00 am

Thank you Igor!

User avatar
roger
Posts: 18
Joined: Wed May 02, 2018 4:27 am
Been thanked: 8 times

Re: Resolve Scripting Essentials

#73

Post by roger » Mon Jan 27, 2020 4:08 pm

In the Resolve scripting documentation they list a function called GetCurrentClipThumbnailImage(). An example for Python is provided, but the example for Lua doesn't actually show the thumbnail image. I thought I would fix that.

The thumbnail image that Resolve provides is a base64 encoded "raw" RGB bitmap. Raw in this context meaning it's just pixel data without a container. If we put that data in a Microsoft .bmp container it will be upside down and the RGB components will be in the wrong order. Bmp wants it reversed to BGR.

So what we need to do is:
  • Get the data from Resolve
  • Base64 decode the data
  • Flip the image vertically
  • Flip the pixel components
  • Put the altered data in a bmp container
  • Base64 encode the bmp
  • Show the thumbnail
As far as I can tell, there's no module in Resolve/Fusion for base64 encoding/decoding. There's a public domain pure Lua implementation of it available here that I will use. Put it in one of the folders where Resolve looks for modules, like %AppData%\Blackmagic Design\DaVinci Resolve\Support\Fusion\Modules\Lua\ on Windows or /Users/[username]/Library/Application Support/Blackmagic Design/DaVinci Resolve/Fusion/Modules/Lua/ on macOS.

Flipping the image and pixel components is just a matter of copying the bytes in the correct order to another Lua table. The way I have implemented it is not very efficient but it doesn't really matter for a single small thumbnail that won't be auto-updating.

One funny thing I noticed, the thumbnail is rendered at a much higher resolution on macOS. I don't know if it's because it detects the retina screen or if it always does that. Anyway, I made the window larger when the script is executed on a Mac. If it depends on the available screen resolution it might look completely different on your system.

So, why this long post for something that doesn't seem very useful with the current API?

Well, I'd just like to draw attention to the fact that it would be extremely useful with a built-in proper base64 module in Resolve written in C. Also, a binary packer/unpacker like struct or lpack so we can read/write binary files easily. They all have the same license as Lua and could be included in Resolve/Fusion just like lj2curl or several other modules already are. Struct is even made by the creator of Lua. Later versions of Lua has alternatives for this built-in, but it's not available in the version used by Resolve/Fusion.

Image

Here's the code. You can put it in the scripts folder or just paste it in the console, just remember it needs the base64.lua file mentioned above in the modules folder.
Code: [Select all] [Expand/Collapse] [Download] (Thumbnail.lua)
  1. -- Thumbnail.lua example for the Color Page in DaVinci Resolve v16
  2. -- roger.magnusson@gmail.com
  3.  
  4. -- Use base64, a public domain pure Lua implementation of base64 encode/decode
  5. -- Available at https://raw.github.com/iskolbin/lbase64/master/base64.lua
  6. local base64 = require "base64"
  7.  
  8. local fu = Fusion()
  9. local ui = fu.UIManager
  10. local dispatcher = bmd.UIDispatcher(ui)
  11. local resolve = Resolve()
  12. local projectManager = resolve:GetProjectManager()
  13. local project = projectManager:GetCurrentProject()
  14. local timeline = project:GetCurrentTimeline()
  15.  
  16. assert(timeline, "You need a timeline to run this script.")
  17.  
  18. -- The Color page has to be open or we won't get a thumbnail
  19. resolve:OpenPage("color")
  20.  
  21. -- Converts C style unsigned integers to binary
  22. local function int_to_bin(val, type)
  23.     local len = { char = 1, short = 2, int = 4, long = 8 }
  24.     return ffi.string(ffi.new(string.format("unsigned %s[?]", type), 1, val), len[type])
  25. end
  26.  
  27. local function load_thumbnail(textEditWidget)
  28.     local thumbnail = timeline:GetCurrentClipThumbnailImage()
  29.     assert(thumbnail, "Clip not found. Note that generators are not supported unless you make them into a compound clip.")
  30.     local data = base64.decode(thumbnail.data)
  31.     local pixelComponents = 3 -- Three components to each pixel, as in R, G and B
  32.     local bitsPerPixel = pixelComponents * 8 -- thumbnail.format is "RGB 8 bit"
  33.     local bmp = {}
  34.  
  35.     -- Header, 14 bytes
  36.     bmp[#bmp+1] = "BM" -- 2,                            -- Header.Signature
  37.     bmp[#bmp+1] = int_to_bin(14 + 40 + #data, "int")    -- Header.FileSize
  38.     bmp[#bmp+1] = int_to_bin(0, "short")                -- Header.Reserved1
  39.     bmp[#bmp+1] = int_to_bin(0, "short")                -- Header.Reserved1
  40.     bmp[#bmp+1] = int_to_bin(14 + 40, "int")            -- Header.DataOffset
  41.    
  42.     -- InfoHeader, 40 bytes
  43.     bmp[#bmp+1] = int_to_bin(40, "int")                 -- InfoHeader.Size
  44.     bmp[#bmp+1] = int_to_bin(thumbnail.width, "int")    -- InfoHeader.Width
  45.     bmp[#bmp+1] = int_to_bin(thumbnail.height, "int")   -- InfoHeader.Height
  46.     bmp[#bmp+1] = int_to_bin(1, "short")                -- InfoHeader.Planes
  47.     bmp[#bmp+1] = int_to_bin(bitsPerPixel, "short")     -- InfoHeader.BitsPerPixel
  48.     bmp[#bmp+1] = int_to_bin(0, "int")                  -- InfoHeader.Compression
  49.     bmp[#bmp+1] = int_to_bin(0, "int")                  -- InfoHeader.ImageSize
  50.     bmp[#bmp+1] = int_to_bin(0, "int")                  -- InfoHeader.XPixelsPerM
  51.     bmp[#bmp+1] = int_to_bin(0, "int")                  -- InfoHeader.YPixelsPerM
  52.     bmp[#bmp+1] = int_to_bin(0, "int")                  -- InfoHeader.ColorsUsed
  53.     bmp[#bmp+1] = int_to_bin(0, "int")                  -- InfoHeader.ImportantColors
  54.  
  55.     -- Each scanline length should be divisible by 4
  56.     local scanlineLength = math.ceil(bitsPerPixel * thumbnail.width / 32) * 4
  57.     local scanlines = {}
  58.  
  59.     for i = thumbnail.height - 1, 0, -1 do
  60.         -- We're starting at the last scanline and going backwards since we need to flip the image vertically
  61.  
  62.         local scanline = data:sub(1 + i * scanlineLength, (1 + i) * scanlineLength)
  63.         local bgrPixels = {}
  64.  
  65.         for j = 0, thumbnail.width - 1 do
  66.             -- The Resolve thumbnail pixel component order is RGB, we need to flip it to BGR for displaying as a bmp
  67.             bgrPixels[#bgrPixels+1] = string.reverse(scanline:sub(1 + j * pixelComponents, pixelComponents + j * pixelComponents))
  68.         end
  69.  
  70.         scanlines[#scanlines+1] = table.concat(bgrPixels)
  71.     end
  72.  
  73.     bmp[#bmp+1] = table.concat(scanlines)
  74.  
  75.     -- Populate the TextEdit widget with HTML and the base64 encoded bmp file
  76.     textEditWidget.HTML = string.format("<img src='data:image/bmp;base64,%s' />", base64.encode(table.concat(bmp)))
  77. end
  78.  
  79. local function create_window()
  80.     local window = dispatcher:AddWindow(
  81.     {
  82.         ID = "ThumbnailWindow",
  83.         WindowTitle = "Current Thumbnail",
  84.         Margin = 4,
  85.    
  86.         ui:VGroup
  87.         {
  88.             ui:TextEdit { ID = "TextEditImage", ReadOnly = true },
  89.             ui:HGroup
  90.             {
  91.                 ui:HGap {}, ui:Button { ID = "UpdateButton", Text = "Update", Weight = 0 }, Weight = 0,
  92.             }
  93.         }
  94.     })
  95.  
  96.     if (ffi.os == "OSX") then
  97.         window:Resize({ 594, 368 })
  98.     else
  99.         window:Resize({ 306, 208 })
  100.     end
  101.  
  102.     local windowItems = window:GetItems()
  103.     load_thumbnail(windowItems.TextEditImage)
  104.  
  105.     -- Event listeners
  106.     window.On.UpdateButton.Clicked = function(ev)
  107.         load_thumbnail(windowItems.TextEditImage)
  108.     end
  109.  
  110.     window.On.ThumbnailWindow.Close = function(ev)
  111.         dispatcher:ExitLoop()
  112.     end
  113.  
  114.     return window
  115. end
  116.  
  117. local window = create_window()
  118. window:Show()
  119. dispatcher:RunLoop()
  120. window:Hide()

User avatar
pixelstuff
Posts: 46
Joined: Sun Jul 15, 2018 11:50 am
Been thanked: 1 time

Re: Opening External URLs, Files, and Folders

#74

Post by pixelstuff » Sun Feb 09, 2020 6:56 am

Hi does anyone know why bmd.openfileexternal('Open', path) works when run from the console(or script) but will error when run from within a .fuse. Is the syntax different, a bug or just doesn't work this way?

error: attempt to index global 'comp' (a nil value)

*admin snip*

User avatar
Midgardsormr
Fusionator
Posts: 1757
Joined: Wed Nov 26, 2014 8:04 pm
Answers: 14
Location: Los Angeles, CA, USA
Been thanked: 89 times
Contact:

Re: Resolve Scripting Essentials

#75

Post by Midgardsormr » Sun Feb 09, 2020 7:29 am

You need to first define what comp means. Within the context of Fusion's Console, or a script running from within Fusion, that variable is part of the environment. The Fuse doesn't get access to the Fusion scripting environment, though, so you need to set it up first.

However, it's probably easier and safer to use the built-in features of the Fuse API—a FileControl will open the file browser, and Lua's native file handling features can be used to read. These lines are lifted from the SuckLessAudio Fuse:

Code: Select all

-- For the Create() function
InFile = self:AddInput("Wave File", "WaveFile", {
	LINKID_DataType = "Text",
	INPID_InputControl =  "FileControl",
	FC_ClipBrowse = true,
	INP_DoNotifyChanged  = true,
	})
	
	
-- In the Process() function
local infile = InFile:GetValue(req).Value
if not filedata or infiledup ~= infile then
--	print ("loading")
	filedata = readAll(infile)
	infiledup = infile
	if not filedata then
		print("Please load an audio file.")
		return
	end
end
	
	
-- function for reading in a binary file
function readAll(file)
	local f = io.open(file, "rb")
	if not f then
		return
	end
    local content = f:read("*all")
    f:close()
    return content
end