]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
mkv: added support for chapter insertion
authorJohn Törnblom <john.tornblom@gmail.com>
Tue, 8 Jan 2013 14:29:21 +0000 (15:29 +0100)
committerJohn Törnblom <john.tornblom@gmail.com>
Tue, 8 Jan 2013 21:33:04 +0000 (22:33 +0100)
src/muxer/tvh/mkmux.c
src/muxer/tvh/mkmux.h

index da6a34ba8e997aa9af012e645bfb2f1f4bc649d5..9293b03d0d8de1cf1248efc4c8751a63b167f82f 100644 (file)
@@ -34,6 +34,7 @@
 extern int dvr_iov_max;
 
 TAILQ_HEAD(mk_cue_queue, mk_cue);
+TAILQ_HEAD(mk_chapter_queue, mk_chapter);
 
 #define MATROSKA_TIMESCALE 1000000 // in nS
 
@@ -61,6 +62,15 @@ struct mk_cue {
   off_t cluster_pos;
 };
 
+/**
+ *
+ */
+struct mk_chapter {
+  TAILQ_ENTRY(mk_chapter) link;
+  int uuid;
+  int64_t ts;
+};
+
 /**
  *
  */
@@ -90,10 +100,12 @@ struct mk_mux {
   off_t trackinfo_pos;
   off_t metadata_pos;
   off_t cue_pos;
+  off_t chapters_pos;
 
   int addcue;
 
   struct mk_cue_queue cues;
+  struct mk_chapter_queue chapters;
 
   char uuid[16];
   char *title;
@@ -412,6 +424,70 @@ mk_write_segment_header(mk_mux_t *mkm, int64_t size)
 }
 
 
+/**
+ *
+ */
+static htsbuf_queue_t *
+mk_build_one_chapter(struct mk_chapter *ch)
+{
+  htsbuf_queue_t *q = htsbuf_queue_alloc(0);
+
+  ebml_append_uint(q, 0x73C4, ch->uuid);
+  ebml_append_uint(q, 0x91, ch->ts * MATROSKA_TIMESCALE);
+  ebml_append_uint(q, 0x98, 0); //ChapterFlagHidden
+  ebml_append_uint(q, 0x4598, 1); //ChapterFlagEnabled
+
+  return q;
+}
+
+
+/**
+ *
+ */
+static htsbuf_queue_t *
+mk_build_edition_entry(mk_mux_t *mkm)
+{
+  struct mk_chapter *ch;
+  htsbuf_queue_t *q = htsbuf_queue_alloc(0);
+
+  ebml_append_uint(q, 0x45bd, 0); //EditionFlagHidden
+  ebml_append_uint(q, 0x45db, 1); //EditionFlagDefault
+
+  TAILQ_FOREACH(ch, &mkm->chapters, link) {
+    ebml_append_master(q, 0xB6, mk_build_one_chapter(ch));
+  }
+
+  return q;
+}
+
+
+/**
+ *
+ */
+static htsbuf_queue_t *
+mk_build_chapters(mk_mux_t *mkm)
+{
+  htsbuf_queue_t *q = htsbuf_queue_alloc(0);
+
+  ebml_append_master(q, 0x45b9, mk_build_edition_entry(mkm));
+
+  return q;
+}
+
+/**
+ *
+ */
+static void
+mk_write_chapters(mk_mux_t *mkm)
+{
+  if(TAILQ_FIRST(&mkm->chapters) == NULL)
+    return;
+
+  mkm->chapters_pos = mkm->fdpos;
+  mk_write_master(mkm, 0x1043a770, mk_build_chapters(mkm));
+}
+
+
 /**
  *
  */
@@ -581,6 +657,11 @@ mk_build_metaseek(mk_mux_t *mkm)
     ebml_append_master(q, 0x4dbb, 
                       mk_build_one_metaseek(mkm, 0x1c53bb6b,
                                             mkm->cue_pos));
+
+  if(mkm->chapters_pos)
+    ebml_append_master(q, 0x4dbb, 
+                      mk_build_one_metaseek(mkm, 0x1043a770,
+                                            mkm->chapters_pos));
   return q;
 }
 
@@ -657,6 +738,29 @@ addcue(mk_mux_t *mkm, int64_t pts, int tracknum)
 }
 
 
+/**
+ *
+ */
+static void
+mk_add_chapter(mk_mux_t *mkm, int64_t ts)
+{
+  struct mk_chapter *ch;
+  int uuid;
+
+  ch = TAILQ_LAST(&mkm->chapters, mk_chapter_queue);
+  if(ch)
+    uuid = ch->uuid + 1;
+  else
+    uuid = 1;
+
+  ch = malloc(sizeof(struct mk_chapter));
+
+  ch->uuid = uuid;
+  ch->ts = ts;
+
+  TAILQ_INSERT_TAIL(&mkm->chapters, ch, link);
+}
+
 /**
  *
  */
@@ -863,6 +967,7 @@ mk_mux_init(mk_mux_t *mkm, const char *title, const struct streaming_start *ss)
     mkm->title = strdup(mkm->filename);
 
   TAILQ_INIT(&mkm->cues);
+  TAILQ_INIT(&mkm->chapters);
 
   htsbuf_queue_init(&q, 0);
 
@@ -901,7 +1006,7 @@ mk_mux_write_pkt(mk_mux_t *mkm, struct th_pkt *pkt)
       pkt = pkt_merge_header(pkt);
     mk_write_frame_i(mkm, t, pkt);
   }
-  
+
   pkt_ref_dec(pkt);
 
   return mkm->error;
@@ -928,6 +1033,19 @@ mk_mux_write_meta(mk_mux_t *mkm, const dvr_entry_t *de,
 }
 
 
+/**
+ * Insert a new chapter at the current location
+ */
+int
+mk_mux_insert_chapter(mk_mux_t *mkm)
+{
+  if(mkm->totduration != PTS_UNSET)
+    mk_add_chapter(mkm, mkm->totduration);
+
+  return mkm->error;
+}
+
+
 /**
  * Close the muxer
  */
@@ -937,6 +1055,7 @@ mk_mux_close(mk_mux_t *mkm)
   int64_t totsize;
   mk_close_cluster(mkm);
   mk_write_cues(mkm);
+  mk_write_chapters(mkm);
 
   mk_write_metaseek(mkm, 0);
   totsize = mkm->fdpos;
@@ -977,6 +1096,12 @@ mk_mux_close(mk_mux_t *mkm)
 void
 mk_mux_destroy(mk_mux_t *mkm)
 {
+  struct mk_chapter *ch;
+
+  while((ch = TAILQ_FIRST(&mkm->chapters)) != NULL) {
+    free(ch);
+  }
+
   free(mkm->filename);
   free(mkm->tracks);
   free(mkm->title);
index ddb4a8667bc5688efeaa596220c05ae3bb0b8566..8b44145dfe48362a4b9503b89e321a418730e487 100644 (file)
@@ -40,6 +40,8 @@ int mk_mux_write_pkt (mk_mux_t *mkm, struct th_pkt *pkt);
 int mk_mux_write_meta(mk_mux_t *mkm, const struct dvr_entry *de,
                      const struct epg_broadcast *eb);
 
+int mk_mux_insert_chapter(mk_mux_t *mkm);
+
 int  mk_mux_close  (mk_mux_t *mkm);
 void mk_mux_destroy(mk_mux_t *mkm);