1

How do I correctly write a synchronization tag for two videos in a KVA file?

<?xml version="1.0" encoding="utf-8"?>
<KinoveaWorkspace>
  <FormatVersion>1.0</FormatVersion>
  <Name>CompareTwoVideos</Name>
  <Id>00000000-0000-0000-0000-000000000000</Id>

  <ScreenDescriptionPlayback>
    <FullPath>%file1%</FullPath>
    <Autoplay>true</Autoplay>
    <SpeedPercentage>100</SpeedPercentage>
    <Stretch>false</Stretch>
    <IsReplayWatcher>false</IsReplayWatcher>
  </ScreenDescriptionPlayback>

  <ScreenDescriptionPlayback>
    <FullPath>%file2%</FullPath>
    <Autoplay>true</Autoplay>
    <SpeedPercentage>100</SpeedPercentage>
    <Stretch>false</Stretch>
    <IsReplayWatcher>false</IsReplayWatcher>
  </ScreenDescriptionPlayback>

  <Synchronization>
    <SyncPair screenA="0" keyframeIndexA="0" screenB="1" keyframeIndexB="0" />
  </Synchronization>
</KinoveaWorkspace>

That is, so that it can be run as follows —

"C:\Program Files\Kinovea\Kinovea.exe" -workspace "C:\Temp\compare.kva"

And see the following in the program that opens? —

https://s1.hostingkartinok.com/uploads/thumbs/2025/10/87537edf1c6c056974fa2ee8c6811ad9.png

2

Hi,
Synchronization works via the "time origin" annotation and is saved in KVA files. So the way to do this would be to have a KVA file for each video with a time origin set a the timestamp of the sync point.

Please note that this workspace file format will be obsolete in the next version as the multi-window system has been rewritten and better integrated in the program, and furthermore "workspace" means a different thing now.

Are you generating these files from code or are you editing manually? The timestamps are not in seconds or frames they are in a unit that depends on the video file so it's a bit more complicated.

3 (edited by peterverhovensky 2025-10-02 21:17:53)

Hi!
I generated these files from code—a simple AHK script that opens the selected video pair in the program with the F6 key—

; Kinovea Loader
; Works with selected files in Explorer:
; 1 file  → opens one screen
; 2 files → comparison in two screens
; >2 files → the first two are taken

#NoEnv
#SingleInstance Force
SetWorkingDir %A_ScriptDir%

f6::
{
    files := Explorer_GetSelection()
    files := StrSplit(files, "`n")
    count := files.MaxIndex()
    if (count == "")
        count := 0

    ;MsgBox, %files%`n`n%count%

    if (count < 1) {
        MsgBox, 48, Error, No file selected!
        return
    }

    if (count > 2) {
        MsgBox, 64, Attention, More than two files selected. The first two will be used.
        count := 2
    }

    tempFile := A_Temp "\compare.kva"

    if (count = 1) {
        ; One file — single screen
        file1 := files[1]
        xml =
        (
<?xml version="1.0" encoding="utf-8"?>
<KinoveaWorkspace>
  <FormatVersion>1.0</FormatVersion>
  <Name>SingleVideo</Name>
  <Id>00000000-0000-0000-0000-000000000000</Id>

  <ScreenDescriptionPlayback>
    <FullPath>%file1%</FullPath>
    <Autoplay>true</Autoplay>
    <SpeedPercentage>100</SpeedPercentage>
    <Stretch>false</Stretch>
    <IsReplayWatcher>false</IsReplayWatcher>
  </ScreenDescriptionPlayback>

</KinoveaWorkspace>
        )
    }
    else if (count = 2) {
        ; Two files — comparison
        file1 := files[1]
        file2 := files[2]
        xml =
        (
<?xml version="1.0" encoding="utf-8"?>
<KinoveaWorkspace>
  <FormatVersion>1.0</FormatVersion>
  <Name>CompareTwoVideos</Name>
  <Id>00000000-0000-0000-0000-000000000000</Id>

  <ScreenDescriptionPlayback>
    <FullPath>%file1%</FullPath>
    <Autoplay>true</Autoplay>
    <SpeedPercentage>100</SpeedPercentage>
    <Stretch>false</Stretch>
    <IsReplayWatcher>false</IsReplayWatcher>
  </ScreenDescriptionPlayback>

  <ScreenDescriptionPlayback>
    <FullPath>%file2%</FullPath>
    <Autoplay>true</Autoplay>
    <SpeedPercentage>100</SpeedPercentage>
    <Stretch>false</Stretch>
    <IsReplayWatcher>false</IsReplayWatcher>
  </ScreenDescriptionPlayback>

  <Synchronization>
    <SyncPair screenA="0" keyframeIndexA="0" screenB="1" keyframeIndexB="0" />
  </Synchronization>
</KinoveaWorkspace>
        )
    }

    FileDelete, %tempFile%
    FileAppend, %xml%, %tempFile%, UTF-8

    Run, "C:\Program Files\Kinovea\Kinovea.exe" -workspace "%tempFile%"
}
return

Explorer_GetSelection(hwnd="") { 
    WinGet, process, processName, % "ahk_id" hwnd := hwnd? hwnd:WinExist("A") 
    WinGetClass class, ahk_id %hwnd% 
    if (process = "explorer.exe") 
        if (class ~= "Progman|WorkerW") { 
            ControlGet, files, List, Selected Col1, SysListView321, ahk_class %class% 
            Loop, Parse, files, `n, `r 
                ToReturn .= A_Desktop "\" A_LoopField "`n" 
        } else if (class ~= "(Cabinet|Explore)WClass") { 
            for window in ComObjCreate("Shell.Application").Windows 
                if (window.hwnd==hwnd) 
                    sel := window.Document.SelectedItems 
            for item in sel 
                ToReturn .= item.path "`n" 
        } 
    return Trim(ToReturn,"`n") 
}

Since there is a need to view identical videos, the idea arose to use ffmpeg to create screenshots of each video before opening the video files and synchronize them according to the first non-black images. But since you are planning to make changes, I will think about it later.
Thank you!

4

Thanks, very interesting. It shows me something I haven't really taken into account in the new system I think.

The new system uses a concept of "windows", that is conceptually similar to the old workspace, they contain the 1 or 2 screens with the content in it. But the XML for these is stored in the application data folder and managed by the program. So now the way to start on a specific screen configuration from the command line is to pass the window id or name, instead of the path to an external file. All the existing windows are listed in the UI so it's easy to reload old ones but creating new ones is also done from the UI.

This means something appears to be missing compared to what you want to do, you would have to create/modify the window xml stored in app data which is doable but not ideal. It would be much simpler if you could pass the paths to the two videos on the command line no?

For a single video you can directly pass the path to the command line or use the -video parameter, no need to create a window or workspace file. Maybe there should be a -video2 parameter that let you start in compare mode directly.

5 (edited by peterverhovensky 2025-10-07 19:35:52)

Indeed, a second parameter for video would be useful and would extend the command line functionality for the second program window. If you find it possible to add this, ideally, it would also be useful to be able to pass a common synchronization mark for both videos in the command line to automate this process. Thank you!

6

I added a `-video2` parameter. For the synchronization mark it's more complicated because it's not a property of the screen but an annotation on the video so it's handled differently.

Since you are processing the videos with ffmpeg and looking for black frames I wonder if you could trim the beginning of the video directly with ffmpeg without re-encoding. https://superuser.com/questions/258032/ … of-a-video