Welcome to WSL!

New to the forum? Please read this and this.

Resolve Scripting Essentials

User avatar
Posts: 1768
Joined: Fri Apr 03, 2015 3:20 pm
Answers: 11
Location: West Dover, Nova Scotia, Canada
Been thanked: 39 times

Re: Resolve Scripting Essentials


Post by AndrewHazelden »

pixelstuff wrote: Thu Dec 13, 2018 3:31 pmReally 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

		body { background-image: url('grid.png') }

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
Posts: 47
Joined: Sun Jul 15, 2018 11:50 am

Re: Resolve Scripting Essentials


Post by pixelstuff »


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
Posts: 2
Joined: Mon Jan 07, 2019 3:41 pm

Re: Resolve Scripting Essentials


Post by ConorBowes »

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
Posts: 1
Joined: Thu Mar 21, 2019 3:46 am

Re: Resolve Scripting Essentials


Post by MrPingouin »

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
Posts: 2384
Joined: Tue Aug 05, 2014 10:04 am
Answers: 12
Real name: Eric Westphal
Been thanked: 4 times

Re: Resolve Scripting Essentials


Post by SirEdric »

SirEdric wrote: Wed Apr 11, 2018 10:58 pmNow 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
Posts: 8
Joined: Thu May 23, 2019 8:42 am

Grading nodes


Post by llamafilm »

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
Posts: 3
Joined: Tue Jul 02, 2019 2:31 am

Re: Resolve Scripting Essentials


Post by AskoK »


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

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

Re: Resolve Scripting Essentials


Post by kir3d »

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: 56
Joined: Mon Apr 16, 2018 11:17 pm
Answers: 1
Location: Los Angeles
Been thanked: 1 time

Re: Resolve Scripting Essentials


Post by Igor Ridanovic »

Timeline append example about 7:20 in.

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

Re: Resolve Scripting Essentials


Post by kir3d »

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: 56
Joined: Mon Apr 16, 2018 11:17 pm
Answers: 1
Location: Los Angeles
Been thanked: 1 time

Re: Resolve Scripting Essentials


Post by Igor Ridanovic »

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
Posts: 5
Joined: Sun Oct 11, 2015 10:49 am

Re: Resolve Scripting Essentials


Post by kir3d »

Thank you Igor!

User avatar
Posts: 23
Joined: Wed May 02, 2018 4:27 am
Been thanked: 2 times

Re: Resolve Scripting Essentials


Post by roger »

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.


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
  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"
  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()
  16. assert(timeline, "You need a timeline to run this script.")
  18. -- The Color page has to be open or we won't get a thumbnail
  19. resolve:OpenPage("color")
  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
  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 = {}
  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
  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
  55.     -- Each scanline length should be divisible by 4
  56.     local scanlineLength = math.ceil(bitsPerPixel * thumbnail.width / 32) * 4
  57.     local scanlines = {}
  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
  62.         local scanline = data:sub(1 + i * scanlineLength, (1 + i) * scanlineLength)
  63.         local bgrPixels = {}
  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
  70.         scanlines[#scanlines+1] = table.concat(bgrPixels)
  71.     end
  73.     bmp[#bmp+1] = table.concat(scanlines)
  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
  79. local function create_window()
  80.     local window = dispatcher:AddWindow(
  81.     {
  82.         ID = "ThumbnailWindow",
  83.         WindowTitle = "Current Thumbnail",
  84.         Margin = 4,
  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.     })
  96.     if (ffi.os == "OSX") then
  97.         window:Resize({ 594, 368 })
  98.     else
  99.         window:Resize({ 306, 208 })
  100.     end
  102.     local windowItems = window:GetItems()
  103.     load_thumbnail(windowItems.TextEditImage)
  105.     -- Event listeners
  106.     window.On.UpdateButton.Clicked = function(ev)
  107.         load_thumbnail(windowItems.TextEditImage)
  108.     end
  110.     window.On.ThumbnailWindow.Close = function(ev)
  111.         dispatcher:ExitLoop()
  112.     end
  114.     return window
  115. end
  117. local window = create_window()
  118. window:Show()
  119. dispatcher:RunLoop()
  120. window:Hide()

User avatar
Posts: 47
Joined: Sun Jul 15, 2018 11:50 am

Re: Opening External URLs, Files, and Folders


Post by pixelstuff »

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
Posts: 2172
Joined: Wed Nov 26, 2014 8:04 pm
Answers: 28
Location: Los Angeles, CA, USA
Been thanked: 41 times

Re: Resolve Scripting Essentials


Post by Midgardsormr »

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.")
-- function for reading in a binary file
function readAll(file)
	local f = io.open(file, "rb")
	if not f then
    local content = f:read("*all")
    return content