1 /*
2  * Copyright (C) 2009-2017 the xine project
3  *
4  * This file is part of xine, a free video player.
5  *
6  * xine is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * xine is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
19  *
20  * demultiplexer for matroska streams: chapter handling
21  *
22  * TODO:
23  *  - nested chapters
24  *
25  * Authors:
26  *  Nicos Gollan <gtdev@spearhead.de>
27  */
28 
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32 
33 #define LOG_MODULE "demux_matroska_chapters"
34 #define LOG_VERBOSE
35 /*
36 #define LOG
37 */
38 
39 #include <xine/xine_internal.h>
40 #include <xine/xineutils.h>
41 #include <xine/demux.h>
42 
43 #include "ebml.h"
44 #include "matroska.h"
45 #include "demux_matroska.h"
46 
47 /* TODO: this only handles one single (title, language, country) tuple.
48  *  See the header for information. */
parse_chapter_display(demux_matroska_t * this,matroska_chapter_t * chap,int level)49 static int parse_chapter_display(demux_matroska_t *this, matroska_chapter_t *chap, int level) {
50   ebml_parser_t *ebml = this->ebml;
51   int next_level = level+1;
52   char* tmp_name = NULL;
53   char* tmp_lang = NULL;
54   char* tmp_country = NULL;
55 
56   while (next_level == level+1) {
57     ebml_elem_t elem;
58 
59     if (!ebml_read_elem_head(ebml, &elem))
60       return 0;
61 
62     switch (elem.id) {
63 
64       case MATROSKA_ID_CH_STRING:
65         tmp_name = ebml_alloc_read_ascii(ebml, &elem);
66         break;
67 
68       case MATROSKA_ID_CH_LANGUAGE:
69         tmp_lang = ebml_alloc_read_ascii(ebml, &elem);
70         break;
71 
72       case MATROSKA_ID_CH_COUNTRY:
73         tmp_country = ebml_alloc_read_ascii(ebml, &elem);
74         break;
75 
76       default:
77         lprintf("Unhandled ID (inside ChapterDisplay): 0x%x\n", elem.id);
78         if (!ebml_skip(ebml, &elem))
79           return 0;
80     }
81 
82     next_level = ebml_get_next_level(ebml, &elem);
83   }
84 
85   if (NULL != chap->title) {
86     chap->title = tmp_name;
87 
88     free(chap->language);
89     chap->language = tmp_lang;
90 
91     free(chap->country);
92     chap->country = tmp_country;
93   } else if (tmp_lang != NULL && !strcmp("eng", tmp_lang) && (chap->language == NULL || strcmp("eng", chap->language))) {
94     free(chap->title);
95     chap->title = tmp_name;
96 
97     free(chap->language);
98     chap->language = tmp_lang;
99 
100     free(chap->country);
101     chap->country = tmp_country;
102   } else {
103     free(tmp_name);
104     free(tmp_lang);
105     free(tmp_country);
106   }
107 
108   return 1;
109 }
110 
parse_chapter_atom(demux_matroska_t * this,matroska_chapter_t * chap,int level)111 static int parse_chapter_atom(demux_matroska_t *this, matroska_chapter_t *chap, int level) {
112   ebml_parser_t *ebml = this->ebml;
113   int next_level = level+1;
114   uint64_t num;
115 
116   chap->time_start = 0;
117   chap->time_end = 0;
118   chap->hidden = 0;
119   chap->enabled = 1;
120 
121   while (next_level == level+1) {
122     ebml_elem_t elem;
123 
124     if (!ebml_read_elem_head(ebml, &elem)) {
125       lprintf("invalid head\n");
126       return 0;
127     }
128 
129     switch (elem.id) {
130       case MATROSKA_ID_CH_UID:
131         if (!ebml_read_uint(ebml, &elem, &chap->uid)) {
132           lprintf("invalid UID\n");
133           return 0;
134         }
135         break;
136 
137       case MATROSKA_ID_CH_TIMESTART:
138         if (!ebml_read_uint(ebml, &elem, &chap->time_start)) {
139           lprintf("invalid start time\n");
140           return 0;
141         }
142         /* convert to xine timing: Matroska timestamps are in nanoseconds,
143          * xine's PTS are in 1/90,000s */
144         chap->time_start /= 100000;
145         chap->time_start *= 9;
146         break;
147 
148       case MATROSKA_ID_CH_TIMEEND:
149         if (!ebml_read_uint(ebml, &elem, &chap->time_end)) {
150           lprintf("invalid end time\n");
151           return 0;
152         }
153         /* convert to xine timing */
154         chap->time_end /= 100000;
155         chap->time_end *= 9;
156         break;
157 
158       case MATROSKA_ID_CH_DISPLAY:
159         if (!ebml_read_master(ebml, &elem))
160           return 0;
161 
162         lprintf("ChapterDisplay\n");
163         if(!parse_chapter_display(this, chap, level+1)) {
164           lprintf("invalid display information\n");
165           return 0;
166         }
167         break;
168 
169       case MATROSKA_ID_CH_HIDDEN:
170         if (!ebml_read_uint(ebml, &elem, &num))
171           return 0;
172         chap->hidden = (int)num;
173         break;
174 
175       case MATROSKA_ID_CH_ENABLED:
176         if (!ebml_read_uint(ebml, &elem, &num))
177           return 0;
178         chap->enabled = (int)num;
179         break;
180 
181       case MATROSKA_ID_CH_ATOM: /* TODO */
182         xprintf(this->stream->xine, XINE_VERBOSITY_NONE,
183             LOG_MODULE ": Warning: Nested chapters are not supported, playback may suffer!\n");
184         if (!ebml_skip(ebml, &elem))
185           return 0;
186         break;
187 
188       case MATROSKA_ID_CH_TRACK: /* TODO */
189         xprintf(this->stream->xine, XINE_VERBOSITY_NONE,
190             LOG_MODULE ": Warning: Specific track information in chapters is not supported, playback may suffer!\n");
191         if (!ebml_skip(ebml, &elem))
192           return 0;
193         break;
194 
195       default:
196         lprintf("Unhandled ID (inside ChapterAtom): 0x%x\n", elem.id);
197         if (!ebml_skip(ebml, &elem))
198           return 0;
199     }
200 
201     next_level = ebml_get_next_level(ebml, &elem);
202   }
203 
204   /* fallback information */
205   /* FIXME: check allocations! */
206   if (NULL == chap->title) {
207     chap->title = strdup("No title");
208   }
209 
210   if (NULL == chap->language) {
211     chap->language = strdup("unk");
212   }
213 
214   if (NULL == chap->country) {
215     chap->country = strdup("XX");
216   }
217 
218   lprintf( "Chapter 0x%" PRIx64 ": %" PRIu64 "-%" PRIu64 "(pts), %s (%s). %shidden, %senabled.\n",
219       chap->uid, chap->time_start, chap->time_end,
220       chap->title, chap->language,
221       (chap->hidden ? "" : "not "),
222       (chap->enabled ? "" : "not "));
223 
224   return 1;
225 }
226 
free_chapter(matroska_chapter_t * chap)227 static void free_chapter(matroska_chapter_t *chap) {
228   free(chap->title);
229   free(chap->language);
230   free(chap->country);
231 
232   free(chap);
233 }
234 
parse_edition_entry(demux_matroska_t * this,matroska_edition_t * ed)235 static int parse_edition_entry(demux_matroska_t *this, matroska_edition_t *ed) {
236   ebml_parser_t *ebml = this->ebml;
237   int next_level = 3;
238   uint64_t num;
239   int i;
240 
241   ed->hidden = 0;
242   ed->is_default = 0;
243   ed->ordered = 0;
244 
245   while (next_level == 3) {
246     ebml_elem_t elem;
247 
248     if (!ebml_read_elem_head(ebml, &elem))
249       return 0;
250 
251     switch (elem.id) {
252       case MATROSKA_ID_CH_ED_UID:
253         if (!ebml_read_uint(ebml, &elem, &ed->uid))
254           return 0;
255         break;
256 
257       case MATROSKA_ID_CH_ED_HIDDEN:
258         if (!ebml_read_uint(ebml, &elem, &num))
259           return 0;
260         ed->hidden = (int)num;
261         break;
262 
263       case MATROSKA_ID_CH_ED_DEFAULT:
264         if (!ebml_read_uint(ebml, &elem, &num))
265           return 0;
266         ed->is_default = (int)num;
267         break;
268 
269       case MATROSKA_ID_CH_ED_ORDERED:
270         if (!ebml_read_uint(ebml, &elem, &num))
271           return 0;
272         ed->ordered = (int)num;
273         break;
274 
275       case MATROSKA_ID_CH_ATOM:
276         {
277           matroska_chapter_t *chapter = calloc(1, sizeof(matroska_chapter_t));
278           if (NULL == chapter)
279             return 0;
280 
281           lprintf("ChapterAtom\n");
282           if (!ebml_read_master(ebml, &elem)) {
283             free_chapter(chapter);
284             return 0;
285           }
286 
287           if (!parse_chapter_atom(this, chapter, next_level)) {
288             free_chapter(chapter);
289             return 0;
290           }
291 
292           /* resize chapters array if necessary */
293           if (ed->num_chapters >= ed->cap_chapters) {
294             matroska_chapter_t** old_chapters = ed->chapters;
295             ed->cap_chapters += 10;
296             ed->chapters = realloc(ed->chapters, ed->cap_chapters * sizeof(matroska_chapter_t*));
297 
298             if (NULL == ed->chapters) {
299               ed->chapters = old_chapters;
300               ed->cap_chapters -= 10;
301               free_chapter(chapter);
302               return 0;
303             }
304           }
305 
306           ed->chapters[ed->num_chapters] = chapter;
307           ++ed->num_chapters;
308 
309           break;
310         }
311 
312       default:
313         lprintf("Unhandled ID (inside EditionEntry): 0x%x\n", elem.id);
314         if (!ebml_skip(ebml, &elem))
315           return 0;
316     }
317 
318     next_level = ebml_get_next_level(ebml, &elem);
319   }
320 
321   xprintf( this->stream->xine, XINE_VERBOSITY_LOG,
322       LOG_MODULE ": Edition 0x%" PRIx64 ": %shidden, %sdefault, %sordered. %d chapters:\n",
323       ed->uid,
324       (ed->hidden ? "" : "not "),
325       (ed->is_default ? "" : "not "),
326       (ed->ordered ? "" : "not "),
327       ed->num_chapters );
328 
329   for (i=0; i<ed->num_chapters; ++i) {
330     matroska_chapter_t* chap = ed->chapters[i];
331     xprintf( this->stream->xine, XINE_VERBOSITY_LOG,
332         LOG_MODULE ":  Chapter %d: %" PRIu64 "-%" PRIu64 "(pts), %s (%s). %shidden, %senabled.\n",
333         i+1, chap->time_start, chap->time_end,
334         chap->title, chap->language,
335         (chap->hidden ? "" : "not "),
336         (chap->enabled ? "" : "not "));
337   }
338 
339   return 1;
340 }
341 
free_edition(matroska_edition_t * ed)342 static void free_edition(matroska_edition_t *ed) {
343   int i;
344 
345   for(i=0; i<ed->num_chapters; ++i) {
346     free_chapter(ed->chapters[i]);
347   }
348   free(ed->chapters);
349   free(ed);
350 }
351 
matroska_parse_chapters(demux_matroska_t * this)352 int matroska_parse_chapters(demux_matroska_t *this) {
353   ebml_parser_t *ebml = this->ebml;
354   int next_level = 2;
355 
356   while (next_level == 2) {
357     ebml_elem_t elem;
358 
359     if (!ebml_read_elem_head(ebml, &elem))
360       return 0;
361 
362     switch (elem.id) {
363       case MATROSKA_ID_CH_EDITIONENTRY:
364         {
365           matroska_edition_t *edition = calloc(1, sizeof(matroska_edition_t));
366           if (NULL == edition)
367             return 0;
368 
369           lprintf("EditionEntry\n");
370           if (!ebml_read_master(ebml, &elem)) {
371             free_edition(edition);
372             return 0;
373           }
374 
375           if (!parse_edition_entry(this, edition)) {
376             free_edition(edition);
377             return 0;
378           }
379 
380           /* resize editions array if necessary */
381           if (this->num_editions >= this->cap_editions) {
382             matroska_edition_t** old_editions = this->editions;
383             this->cap_editions += 10;
384             this->editions = realloc(this->editions, this->cap_editions * sizeof(matroska_edition_t*));
385 
386             if (NULL == this->editions) {
387               this->editions = old_editions;
388               this->cap_editions -= 10;
389               free_edition(edition);
390               return 0;
391             }
392           }
393 
394           this->editions[this->num_editions] = edition;
395           ++this->num_editions;
396 
397           break;
398         }
399 
400       default:
401         lprintf("Unhandled ID: 0x%x\n", elem.id);
402         if (!ebml_skip(ebml, &elem))
403           return 0;
404     }
405 
406     next_level = ebml_get_next_level(ebml, &elem);
407   }
408 
409   return 1;
410 }
411 
matroska_free_editions(demux_matroska_t * this)412 void matroska_free_editions(demux_matroska_t *this) {
413   int i;
414 
415   for(i=0; i<this->num_editions; ++i) {
416     free_edition(this->editions[i]);
417   }
418   free(this->editions);
419   this->num_editions = 0;
420   this->cap_editions = 0;
421 }
422 
matroska_get_chapter(demux_matroska_t * this,uint64_t tc,matroska_edition_t ** ed)423 int matroska_get_chapter(demux_matroska_t *this, uint64_t tc, matroska_edition_t** ed) {
424   uint64_t block_pts = (tc * this->timecode_scale) / 100000 * 9;
425   int chapter_idx = 0;
426 
427   if (this->num_editions < 1)
428     return -1;
429 
430   while (chapter_idx < (*ed)->num_chapters && block_pts > (*ed)->chapters[chapter_idx]->time_start)
431     ++chapter_idx;
432 
433   if (chapter_idx > 0)
434     --chapter_idx;
435 
436   return chapter_idx;
437 }
438