Hi Erik,
I published my small tool on github, I hope it’s okay to link it here: https://github.com/felixrupp/comskipCutsConverter
To the format:
.cuts is a binary Textfile, constructed as follows (and asCatMan already stated above):
One Big Endian 64bit unsigned long long (the PTS), followed by one Big Endian 32bit unsigned int (the type).
Reading the .cuts file is in C-code is demonstrated in the Enigma core (https://github.com/openatv/enigma2/blob/fff9a170b68b8ba5d44b3a046b51b63f2ad9b8c6/lib/service/servicemp3.cpp#L3470):
Code:
FILE *f = fopen(filename.c_str(), "rb"); // Read bytewise
if (f)
{
while (1)
{
unsigned long long where;
unsigned int what;
if (!fread(&where, sizeof(where), 1, f))
break;
if (!fread(&what, sizeof(what), 1, f))
break;
where = be64toh(where);
what = ntohl(what);
if (what < 4)
m_cue_entries.insert(cueEntry(where, what));
}
fclose(f);
eDebug("[eServiceMP3] cuts file has %zd entries", m_cue_entries.size());
}
else
eDebug("[eServiceMP3] cutfile not found!");
The two functions used here, be64toh() and ntohl() are used to decode the big endian byte order to the machine’s byte order.
be64toh(): Converts a big endian 64bit unsigned long long to machine byte order 64bit.
ntohl(): Converts a big endian 32bit unsigned int to machine byte order 32bit.
In PHP or Python these conversions can be done by using the unpack() (to decode) and pack() (to encode) functions with according options.
To write the .cuts file, the following can be done in C-code:
Code:
FILE *f = fopen(filename.c_str(), "wb"); // Write bytewise
if (f)
{
signed long long where = 0;
guint what = 0;
for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
{
if (where == i->where && what == i->what)
/* ignore double entries */
continue;
else
{
where = htobe64(i->where);
what = htonl(i->what);
fwrite(&where, sizeof(where), 1, f);
fwrite(&what, sizeof(what), 1, f);
/* temorary save for comparing */
where = i->where;
what = i->what;
}
}
fclose(f);
eDebug("[eServiceMP3] cuts file has been write");
}
htobe64(): Converts unsigned long long from 64bit machine byte order to 64bit big endian
htonl(): Converts unsigned int 31bit machine byte order to 32bit big endian
This is a code snippet from my tool where the both values are being converted (packed) in PHP:
Code:
$where = pack("J", intval($cutsEntry[0])); // Format value 'J' means: convert to unsigned long long (always 64 bit, big endian byte order)
$what = pack("N", intval($cutsEntry[1])); // Format value 'N' means: convert to unsigned long (always 32 bit, big endian byte order)
fwrite($fileHandle, $where, (64 / 8)); // 64bit / 8 = 8 Byte, because fwrite needs the parameter to be represented as bytes not bits
fwrite($fileHandle, $what, (32 / 8)); // 32bit / 8 = 4 Byte, because fwrite needs the parameter to be represented as bytes not bits
As CatMan stated in his post, these types of markers are known by Enigma2’s .cuts format (https://github.com/libo/Enigma2/blob/master/doc/FILEFORMAT):
type 0 = in (only for editing the files)
type 1 = out (only for editing the files)
type 2 = mark (most likely only for viewing the files and jumping)
type 3 = last play position (only set by the player-frontend)
Type 2 is basically the most interesting marker for me, because, that’s the one you will need to skip over commercials when using the playback plugin (in my case EnhancedMovieCenter -> EMC).
Type 0 and 1 are only interesting if the user has a plugin for actually editing the recorded files on his Enigma2 set-top-box, like CutlistEditor and/or moviecut, so I decided to only write out Type 2 markers for jumping over the commercials while viewing them for now.
In the end it would be nice to have all three types combined. So we need a type 0 (in) at frame 0 and when a commercial starts, we set a type 1 (out) and a type 2 (marker). Commercial ends, we set a type 0 (in) and a type 2 (marker), and so on.
As stated before, I used the .plist output by comskip, because of the easy handling of XML in PHP, as the base for converting the values into the .cuts format. My tool also takes the default .cuts files from Enigma2 and merges the markers (because Enigma2 sets up markers at the beginning of the show and the end).
I hope that this brings some light into how .cuts format is build up. Would love to hear/see a native .cuts output in comskip!
If not, I would be happy to get feedback on my small tool, so I can cover all necessary functions you all need.
Regards,
Felix