Skip to content

Commit 26a14aa

Browse files
DeltaMikeCharlieFlole998
authored andcommitted
MKV Tags - Change rating label. Add Sub-title and Comment.
1 parent 7e1f9ca commit 26a14aa

1 file changed

Lines changed: 78 additions & 29 deletions

File tree

src/muxer/muxer_mkv.c

Lines changed: 78 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#include "parsers/parser_hevc.h"
4444
#include "muxer_mkv.h"
4545

46+
#include "epggrab.h" //Needed to see if global processing of parental rating labels is enabled.
4647

4748
extern int dvr_iov_max;
4849

@@ -229,17 +230,17 @@ mk_build_segment_info(mk_muxer_t *mk)
229230
snprintf(app, sizeof(app), "Tvheadend %s", tvheadend_version);
230231

231232
if(!mk->webm)
232-
ebml_append_bin(q, 0x73a4, mk->uuid, sizeof(mk->uuid));
233+
ebml_append_bin(q, 0x73a4, mk->uuid, sizeof(mk->uuid)); //0x73a4 = SegmentUUID
233234

234235
if(!mk->webm)
235-
ebml_append_string(q, 0x7ba9, mk->title);
236+
ebml_append_string(q, 0x7ba9, mk->title); //0x7ba9 = Title
236237

237-
ebml_append_string(q, 0x4d80, "Tvheadend Matroska muxer");
238-
ebml_append_string(q, 0x5741, app);
239-
ebml_append_uint(q, 0x2ad7b1, MATROSKA_TIMESCALE);
238+
ebml_append_string(q, 0x4d80, "Tvheadend Matroska muxer"); //0x4d80 = MuxingApp
239+
ebml_append_string(q, 0x5741, app); //0x5741 = WritingApp
240+
ebml_append_uint(q, 0x2ad7b1, MATROSKA_TIMESCALE); //0x2ad7b1 = TimestampScale
240241

241242
if(mk->totduration)
242-
ebml_append_float(q, 0x4489, (float)mk->totduration);
243+
ebml_append_float(q, 0x4489, (float)mk->totduration); //0x4489 = Duration
243244
else
244245
ebml_append_pad(q, 7); // Must be equal to floatingpoint duration
245246
return q;
@@ -677,7 +678,7 @@ mk_write_chapters(mk_muxer_t *mk)
677678
return;
678679

679680
mk->chapters_pos = mk->fdpos;
680-
mk_write_master(mk, 0x1043a770, mk_build_chapters(mk));
681+
mk_write_master(mk, 0x1043a770, mk_build_chapters(mk)); //0x1043a770 = Chapters
681682
}
682683

683684

@@ -692,18 +693,18 @@ build_tag_string(const char *name, const char *value, const char *lang,
692693
htsbuf_queue_t *st = htsbuf_queue_alloc(0);
693694

694695
htsbuf_queue_t *t = htsbuf_queue_alloc(0);
695-
ebml_append_uint(t, 0x68ca, targettype ?: 50);
696+
ebml_append_uint(t, 0x68ca, targettype ?: 50); //0x68ca = TargetTypeValue
696697

697698
if(targettypename)
698-
ebml_append_string(t, 0x63ca, targettypename);
699-
ebml_append_master(q, 0x63c0, t);
699+
ebml_append_string(t, 0x63ca, targettypename); //0x63ca = TargetType
700+
ebml_append_master(q, 0x63c0, t); //0x63c0 = Targets
700701

701-
ebml_append_string(st, 0x45a3, name);
702-
ebml_append_string(st, 0x4487, value);
703-
ebml_append_uint(st, 0x4484, 1);
704-
ebml_append_string(st, 0x447a, lang ?: "und");
702+
ebml_append_string(st, 0x45a3, name); //0x45a3 = TagName
703+
ebml_append_string(st, 0x4487, value); //0x4487 = TagString
704+
ebml_append_uint(st, 0x4484, 1); //0x4484 = TagDefault
705+
ebml_append_string(st, 0x447a, lang ?: "und"); //0x447a = TagLanguage
705706

706-
ebml_append_master(q, 0x67c8, st);
707+
ebml_append_master(q, 0x67c8, st); //0x67c8 = SimpleTag
707708
return q;
708709
}
709710

@@ -738,19 +739,22 @@ static htsbuf_queue_t *
738739
_mk_build_metadata(const dvr_entry_t *de, const epg_broadcast_t *ebc,
739740
const char *comment)
740741
{
742+
743+
//Note: May 2025 DMC - If the recording is manual or from a timer
744+
//then only the 'comment' will be available, 'de' and 'ebc' will be null.
745+
741746
htsbuf_queue_t *q = htsbuf_queue_alloc(0);
742-
char datestr[64], ctype[100];
747+
char datestr[64], ctype[100], temp_rating[128];
743748
const epg_genre_t *eg = NULL;
744749
epg_genre_t eg0;
745750
struct tm tm;
746751
time_t t;
747752
channel_t *ch = ebc ? ebc->channel : NULL;
748-
lang_str_t *ls = NULL, *ls2 = NULL;
753+
lang_str_t *ls = NULL, *ls2 = NULL, *ls3 = NULL;
749754
const char *lang;
750755
const lang_code_list_t *langs;
751756
epg_episode_num_t num;
752-
int tmp_age;
753-
757+
754758
if (de || ebc) {
755759
localtime_r(de ? &de->de_start : &ebc->start, &tm);
756760
} else {
@@ -780,14 +784,32 @@ _mk_build_metadata(const dvr_entry_t *de, const epg_broadcast_t *ebc,
780784
if(eg && epg_genre_get_str(eg, 1, 0, ctype, 100, NULL))
781785
addtag(q, build_tag_string("CONTENT_TYPE", ctype, NULL, 0, NULL));
782786

783-
//TODO - MKV The spec suggests that this tag can consist of multiple value types.
784-
//https://www.matroska.org/technical/tagging.html
785-
//==> Depending on the COUNTRY it’s the format of the rating of a movie
786-
//==> (P, R, X in the USA, an age in other countries or a URI defining a logo).
787-
if(ebc) {
788-
tmp_age = ebc->age_rating;
789-
addtag(q, build_tag_int("LAW_RATING", tmp_age, 0, NULL));
790-
}
787+
//Only add the 'LAW_RATING' tag if 1) rating label processing is enabled globally
788+
//AND 2) this EPG entry has a rating label worth adding.
789+
if(epggrab_conf.epgdb_processparentallabels && ebc && ebc->rating_label)
790+
{
791+
//If the rating label for this event is enabled AND it has a display_label.
792+
if(ebc->rating_label->rl_enabled && ebc->rating_label->rl_display_label)
793+
{
794+
//Build a fallback string with only the rating label.
795+
snprintf(temp_rating, sizeof(temp_rating), "%s", ebc->rating_label->rl_display_label);
796+
797+
//If there is a country code, build a string that includes the country code
798+
//eg: 'PG (AUS)'
799+
if(ebc->rating_label->rl_enabled && ebc->rating_label->rl_country)
800+
{
801+
snprintf(temp_rating, sizeof(temp_rating), "%s (%s)", ebc->rating_label->rl_display_label, ebc->rating_label->rl_country);
802+
}
803+
//Otherwise, if there is a authority name, build a string that includes the authority
804+
//eg: 'PG (ACMA)'
805+
else if (ebc->rating_label->rl_enabled && ebc->rating_label->rl_authority)
806+
{
807+
snprintf(temp_rating, sizeof(temp_rating), "%s (%s)", ebc->rating_label->rl_display_label, ebc->rating_label->rl_authority);
808+
}
809+
810+
addtag(q, build_tag_string("LAW_RATING", temp_rating, NULL, 0, NULL));
811+
}
812+
}//END we got a rating label from the EPG
791813

792814
if(ch)
793815
addtag(q, build_tag_string("TVCHANNEL",
@@ -800,6 +822,11 @@ _mk_build_metadata(const dvr_entry_t *de, const epg_broadcast_t *ebc,
800822
else if (ebc && ebc->description)
801823
ls2 = ebc->description;
802824

825+
if(de && de->de_subtitle)
826+
ls3 = de->de_subtitle;
827+
else if (ebc && ebc->subtitle)
828+
ls3 = ebc->subtitle;
829+
803830
if (!ls)
804831
ls = ls2;
805832

@@ -814,7 +841,13 @@ _mk_build_metadata(const dvr_entry_t *de, const epg_broadcast_t *ebc,
814841
RB_FOREACH(e, ls2, link)
815842
addtag(q, build_tag_string("DESCRIPTION", e->str, e->lang, 0, NULL));
816843
}
817-
844+
845+
if (ls3) {
846+
lang_str_ele_t *e;
847+
RB_FOREACH(e, ls3, link)
848+
addtag(q, build_tag_string("SUBTITLE", e->str, e->lang, 0, NULL));
849+
}
850+
818851
epg_broadcast_get_epnum(ebc, &num);
819852
if(num.e_num)
820853
addtag(q, build_tag_int("PART_NUMBER", num.e_num,
@@ -834,9 +867,25 @@ _mk_build_metadata(const dvr_entry_t *de, const epg_broadcast_t *ebc,
834867
if ((langs = lang_code_split(NULL)) != NULL) {
835868
lang = tvh_strdupa(langs->codes[0]->code2b);
836869
}
837-
838870
addtag(q, build_tag_string("COMMENT", comment, lang, 0, NULL));
839871
}
872+
else if (de && de->de_comment) { //Add the DVR recording comment if one exists and an explicit comment is omitted
873+
//If the DVR entry has a Title, 'borrow' the language code(s) for the comment
874+
if (de->de_title) {
875+
lang_str_ele_t *e;
876+
RB_FOREACH(e, de->de_title, link)
877+
addtag(q, build_tag_string("COMMENT", de->de_comment, e->lang, 0, NULL));
878+
}
879+
else //Otherwise, just use 'eng' as the default.
880+
{
881+
lang = "eng";
882+
if ((langs = lang_code_split(NULL)) != NULL) {
883+
lang = tvh_strdupa(langs->codes[0]->code2b);
884+
}
885+
886+
addtag(q, build_tag_string("COMMENT", de->de_comment, lang, 0, NULL));
887+
}
888+
}//END extra comment
840889

841890
return q;
842891
}

0 commit comments

Comments
 (0)