2

Unfortuately kdenlive does not provide a way to add chapters to an MKV file, only to DVD's.

How can I add chapters?

2 Answers2

1

In 2012, ^rooker posted a solution to this problem which uses an outdated kdenlive schema. Unfortunately registration is disabled on his forum, or I would have posted it there.

I updated the file, now you can apply this XSLT to any .kdenlive file and get back usable chapters. All you need is xsltproc and mkvmerge (part of mkvtoolnix).

Add markers in kdenlive and save it first.

My updated XSLT

<?xml version="1.0"?>
<xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">
  <Chapters>
  <EditionEntry>

      <xsl:for-each select="mlt/playlist/property[contains(@name, 'marker')]">
        <xsl:variable name="step1" select="translate(@name, 'kdenlive:marker', '')"/>
        <xsl:variable name="time" select="substring($step1, 3, string-length($step1) - 3)"/>

        <xsl:variable name="seconds" select="$time mod 60" />
        <xsl:variable name="minutes" select="floor($time div 60) mod 60" />
        <xsl:variable name="hours" select="floor(($time div 60) div 60)" />
        <!-- hh:mm:ss.msec -->
        <xsl:variable name="timecode">
          <xsl:value-of select="format-number($hours, '00')"/>:<xsl:value-of select="format-number($minutes, '00')"/>:<xsl:value-of select="format-number($seconds, '00.000')"/>
        </xsl:variable>

        <ChapterAtom>
          <ChapterDisplay>
            <ChapterString>
              <xsl:value-of select="text()"/>
            </ChapterString>
          </ChapterDisplay>
          <ChapterFlagHidden>0</ChapterFlagHidden>
          <ChapterFlagEnabled>1</ChapterFlagEnabled>
          <ChapterTimeStart>
            <xsl:value-of select="$timecode"/>
          </ChapterTimeStart>
        </ChapterAtom>
      </xsl:for-each>


  </EditionEntry>
  </Chapters>
</xsl:template>
</xsl:stylesheet>

Make chapters

xsltproc 4subs.xslt 4subs.kdenlive > chaps

Merge chapters to file

mkvmerge --chapters chaps -o cm2.mkv cm.mkv
0

since 20.08.0 the format of the kdenlive profile file has changed (again). Added difficulty: the marker information is now encoded as JSON inside the XML. Hence the following stylesheet requires XSLT-3.0 , so good 'ole xsltproc won't cut it anymore. Needs Saxon >= 9.7. The mkvmerge is unchanged. Yours, Steffen

java -jar /usr/share/java/Saxon-HE-9.9.1.5.jar -s:4subs.kdenlive -xsl:4subs.xslt -o:chaps

<?xml version="1.0"?>
<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:math="http://www.w3.org/2005/xpath-functions/math"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs math" version="3.0">

<!-- Convert kdenlive guide markers into MKV chapters.

This works with Generation 4: Comma / Point Project files used in kdenlive 20.08.0 onwards. https://community.kde.org/Kdenlive/Development/File_format Earlier versions were different. --> <xsl:output indent="yes"/> <xsl:mode on-no-match="shallow-skip"/>

<xsl:template match="property[@name='kdenlive:docproperties.guides']" > <Chapters> <EditionEntry> <xsl:apply-templates select="parse-json(.)?*"> <xsl:sort data-type="number" select="?pos"/> </xsl:apply-templates> </EditionEntry> </Chapters> </xsl:template>

<xsl:template match=".[. instance of map(xs:string, item())]"> <xsl:variable name="chaptername" select="?comment"/> <xsl:variable name="time" select="?pos"/>

&lt;xsl:variable name=&quot;milliseconds&quot; select=&quot;$time mod 50&quot; /&gt;
&lt;xsl:variable name=&quot;seconds&quot; select=&quot;($time - $milliseconds) div 50&quot; /&gt;

&lt;xsl:variable name=&quot;timecode&quot;&gt;
  &lt;xsl:value-of select=&quot;format-number(floor( ($seconds div 60) div 60 ) mod 60 , '00')&quot;/&gt;
  &lt;xsl:text&gt;:&lt;/xsl:text&gt;
  &lt;xsl:value-of select=&quot;format-number(floor($seconds div 60) mod 60 , '00')&quot;/&gt;
  &lt;xsl:text&gt;:&lt;/xsl:text&gt;
  &lt;xsl:value-of select=&quot;format-number($seconds mod 60 , '00')&quot;/&gt;
  &lt;xsl:text&gt;:&lt;/xsl:text&gt;
  &lt;xsl:value-of select=&quot;format-number($milliseconds mod 60 , '00')&quot;/&gt;
&lt;/xsl:variable&gt;

&lt;ChapterAtom&gt;
  &lt;ChapterDisplay&gt;
    &lt;ChapterString&gt;
      &lt;xsl:value-of select=&quot;$chaptername&quot;/&gt;
    &lt;/ChapterString&gt;
    &lt;ChapterLanguage&gt;ger&lt;/ChapterLanguage&gt;
  &lt;/ChapterDisplay&gt;
  &lt;ChapterFlagHidden&gt;0&lt;/ChapterFlagHidden&gt;
  &lt;ChapterFlagEnabled&gt;1&lt;/ChapterFlagEnabled&gt;
  &lt;ChapterTimeStart&gt;
    &lt;xsl:value-of select=&quot;$timecode&quot;/&gt;
  &lt;/ChapterTimeStart&gt;
&lt;/ChapterAtom&gt;

</xsl:template>

</xsl:stylesheet>