1 /*
2  * This file is part of libbluray
3  * Copyright (C) 2009-2010  John Stebbins
4  * Copyright (C) 2012-2013  Petri Hintukainen <phintuka@users.sourceforge.net>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library 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 GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library. If not, see
18  * <http://www.gnu.org/licenses/>.
19  */
20 
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <inttypes.h>
25 
26 #include "bluray.h"
27 #include "bdnav/clpi_data.h"
28 
29 #include "util.h"
30 #include "strings.h"
31 
32 static int verbose;
33 
34 
35 const VALUE_MAP video_aspect_map[] = {
36     {0, "Reserved1"},
37     {1, "Reserved2"},
38     {2, "4:3"},
39     {3, "16:9"},
40     {0, NULL}
41 };
42 
43 const VALUE_MAP application_type_map[] = {
44     {1, "Main TS for a main-path of Movie"},
45     {2, "Main TS for a main-path of Time based slide show"},
46     {3, "Main TS for a main-path of Browsable slide show"},
47     {4, "Sub TS for a sub-path of Browsable slide show"},
48     {5, "Sub TS for a sub-path of Interactive Graphics menu"},
49     {6, "Sub TS for a sub-path of Text subtitle"},
50     {7, "Sub TS for a sub-path of one or more elementary streams path"},
51     {8, "Sub TS for a main-path of Enhanced LR View"},
52     {0, NULL},
53 };
54 
55 static void
_show_stream(CLPI_PROG_STREAM * ss,int level)56 _show_stream(CLPI_PROG_STREAM *ss, int level)
57 {
58     indent_printf(level, "Codec (%04x): %s", ss->coding_type,
59                     _lookup_str(codec_map, ss->coding_type));
60     indent_printf(level, "PID: %04x", ss->pid);
61     switch (ss->coding_type) {
62         case 0x01:
63         case 0x02:
64         case 0xea:
65         case 0x1b:
66         case 0x20:
67         case 0x24:
68             indent_printf(level, "Format %02x: %s", ss->format,
69                         _lookup_str(video_format_map, ss->format));
70             indent_printf(level, "Rate %02x: %s", ss->rate,
71                         _lookup_str(video_rate_map, ss->rate));
72             indent_printf(level, "Aspect %02x: %s", ss->aspect,
73                         _lookup_str(video_aspect_map, ss->aspect));
74             indent_printf(level, "oc_flag %02x", ss->oc_flag);
75             if (ss->coding_type == 0x24) {
76                 indent_printf(level, "cr_flag %02x", ss->cr_flag);
77                 indent_printf(level, "Dynamic Range type %02x: %s", ss->dynamic_range_type,
78                             _lookup_str(dynamic_range_type_map, ss->dynamic_range_type));
79                 indent_printf(level, "Color Space %02x: %s", ss->color_space,
80                             _lookup_str(color_space_map, ss->color_space));
81                 indent_printf(level, "HDR10+ %02x: %s", ss->hdr_plus_flag,
82                             ss->hdr_plus_flag ? "Yes" : "No");
83             }
84             break;
85 
86         case 0x03:
87         case 0x04:
88         case 0x80:
89         case 0x81:
90         case 0x82:
91         case 0x83:
92         case 0x84:
93         case 0x85:
94         case 0x86:
95         case 0xa1:
96         case 0xa2:
97             indent_printf(level, "Format %02x: %s", ss->format,
98                         _lookup_str(audio_format_map, ss->format));
99             indent_printf(level, "Rate %02x: %s", ss->rate,
100                         _lookup_str(audio_rate_map, ss->rate));
101             indent_printf(level, "Language: %s", ss->lang);
102             break;
103 
104         case 0x90:
105         case 0x91:
106         case 0xa0:
107             indent_printf(level, "Language: %s", ss->lang);
108             break;
109 
110         case 0x92:
111             indent_printf(level, "Char Code: %02x", ss->char_code);
112             indent_printf(level, "Language: %s", ss->lang);
113             break;
114 
115         default:
116             fprintf(stderr, "unrecognized coding type %02x\n", ss->coding_type);
117             break;
118     };
119 }
120 
121 static void
_show_clip_info(CLPI_CL * cl,int level)122 _show_clip_info(CLPI_CL *cl, int level)
123 {
124     CLPI_CLIP_INFO *ci = &cl->clip;
125     int ii;
126 
127     indent_printf(level, "Clip Info");
128     indent_printf(level+1, "Clip Stream Type: %02x", ci->clip_stream_type);
129     indent_printf(level+1, "Clip Application Type (%02x): %s",
130                   ci->application_type, _lookup_str(application_type_map, ci->application_type));
131     indent_printf(level+1, "is_ATC_delta: %s", ci->is_atc_delta ? "True" : "False");
132     indent_printf(level+1, "ATC delta count: %d", ci->atc_delta_count);
133     indent_printf(level+1, "TS Recording Rate: %u", ci->ts_recording_rate);
134     indent_printf(level+1, "Number Source Packets: %u", ci->num_source_packets);
135     // Show ts type info
136     indent_printf(level+1, "TS Type Info");
137     indent_printf(level+2, "Validity Flags %02x", ci->ts_type_info.validity);
138     indent_printf(level+2, "Format Id %s", ci->ts_type_info.format_id);
139     // Show cc5 thing
140     for (ii = 0; ii < ci->atc_delta_count; ii++) {
141         indent_printf(level+1, "ATC delta[ %d ]", ii);
142         indent_printf(level+2, "Delta %08x", ci->atc_delta[ii].delta);
143         indent_printf(level+2, "File Id %s", ci->atc_delta[ii].file_id);
144         indent_printf(level+2, "File Code %s", ci->atc_delta[ii].file_code);
145     }
146     // show fonts
147     if (cl->clip.font_info.font_count) {
148         indent_printf(level+1, "Font files");
149         for (ii = 0; ii < cl->clip.font_info.font_count; ii++) {
150             indent_printf(level+2, "Font file %d: %s.otf", ii+1, cl->clip.font_info.font[ii].file_id);
151         }
152     }
153 
154     printf("\n");
155 }
156 
157 static void
_show_seq_info(CLPI_SEQ_INFO * si,int level)158 _show_seq_info(CLPI_SEQ_INFO *si, int level)
159 {
160     CLPI_ATC_SEQ *atc;
161     CLPI_STC_SEQ *stc;
162     int ii, jj;
163 
164     indent_printf(level, "Sequence Info");
165     indent_printf(level+1, "Number ATC Sequences: %d", si->num_atc_seq);
166     for (ii = 0; ii < si->num_atc_seq; ii++) {
167         atc = &si->atc_seq[ii];
168         indent_printf(level+1, "ATC Sequence %d", ii);
169         indent_printf(level+2, "SPN ATC Start: %u", atc->spn_atc_start);
170         indent_printf(level+2, "Offset STC Id: %d", atc->offset_stc_id);
171         indent_printf(level+2, "Number STC Sequences: %d", atc->num_stc_seq);
172         for (jj = 0; jj < atc->num_stc_seq; jj++) {
173             stc = &atc->stc_seq[jj];
174             indent_printf(level+2, "ATC Sequence %d", jj);
175             indent_printf(level+3, "SPN STC Start: %u", stc->spn_stc_start);
176             indent_printf(level+3, "PCR PID: %04x", stc->pcr_pid);
177             indent_printf(level+3, "Presentation Start: %u",
178                             stc->presentation_start_time);
179             indent_printf(level+3, "Presentation End: %u",
180                             stc->presentation_end_time);
181         }
182     }
183 }
184 
185 static void
_show_prog_info(CLPI_PROG_INFO * pi,int level)186 _show_prog_info(CLPI_PROG_INFO *pi, int level)
187 {
188     CLPI_PROG *prog;
189     int ii, jj;
190 
191     indent_printf(level, "Program Info");
192     indent_printf(level+1, "Number Programs: %d", pi->num_prog);
193     for (ii = 0; ii < pi->num_prog; ii++) {
194         prog = &pi->progs[ii];
195         indent_printf(level+1, "Program %d", ii);
196         indent_printf(level+2, "SPN Program Sequence Start: %d",
197                         prog->spn_program_sequence_start);
198         indent_printf(level+2, "Program Map PID: %d", prog->program_map_pid);
199         indent_printf(level+2, "Number Streams: %d", prog->num_streams);
200         indent_printf(level+2, "Number Groups: %d", prog->num_groups);
201         for (jj = 0; jj < prog->num_streams; jj++) {
202             indent_printf(level+2, "Stream %d", jj);
203             _show_stream(&prog->streams[jj], level+3);
204         }
205     }
206 }
207 
208 static void
_show_extent_start(CLPI_EXTENT_START * es,int level)209 _show_extent_start(CLPI_EXTENT_START *es, int level)
210 {
211     unsigned int ii;
212 
213     indent_printf(level, "Extension data: Extent Start Point");
214 
215     if (!es->num_point) {
216         indent_printf(level+1, "(no data)");
217 
218     } else {
219         indent_printf(level+1, "Number of Start Points: %d", es->num_point);
220 
221         if (verbose) {
222             for (ii = 0; ii < es->num_point; ii++) {
223                 indent_printf(level+1, "Extent %5d: SPN 0x%08X", ii, es->point[ii]);
224             }
225         }
226     }
227 }
228 
229 static void
_show_cpi_info(CLPI_CPI * cpi,int level)230 _show_cpi_info(CLPI_CPI *cpi, int level)
231 {
232     CLPI_EP_MAP_ENTRY *entry;
233     CLPI_EP_COARSE *coarse;
234     CLPI_EP_FINE *fine;
235     int ii, jj, kk;
236 
237     indent_printf(level, "CPI");
238     indent_printf(level+1, "Number Stream PID: %d", cpi->num_stream_pid);
239     for (ii = 0; ii < cpi->num_stream_pid; ii++) {
240         entry = &cpi->entry[ii];
241         indent_printf(level+1, "Stream: %d", ii);
242         indent_printf(level+2, "PID: %04x", entry->pid);
243         indent_printf(level+2, "EP Stream Type: %d", entry->ep_stream_type);
244         indent_printf(level+2, "Number EP Coarse: %d", entry->num_ep_coarse);
245         indent_printf(level+2, "Number EP Fine: %d", entry->num_ep_fine);
246         indent_printf(level+2, "EP Map Start: %d",
247                         entry->ep_map_stream_start_addr);
248         for (jj = 0; jj < entry->num_ep_coarse; jj++) {
249             coarse = &entry->coarse[jj];
250             indent_printf(level+2, "Coarse: %d", jj);
251             indent_printf(level+3, "Ref EP Fine: %d", coarse->ref_ep_fine_id);
252             indent_printf(level+3, "PTS EP: %d", coarse->pts_ep);
253             indent_printf(level+3, "SPN EP: %d", coarse->spn_ep);
254         }
255         for (jj = 0; jj < entry->num_ep_fine; jj++) {
256             fine = &entry->fine[jj];
257             indent_printf(level+2, "Fine: %d", jj);
258             indent_printf(level+3, "Angle Change Point: %s",
259                 fine->is_angle_change_point ? "True":"False");
260             indent_printf(level+3, "I End Offset: %d",
261                 fine->i_end_position_offset);
262             indent_printf(level+3, "PTS EP: %d", fine->pts_ep);
263             indent_printf(level+3, "SPN EP: %d", fine->spn_ep);
264         }
265         if (verbose) {
266             uint64_t pts;
267             uint32_t spn;
268 
269             indent_printf(level+2, "PTS - SPN Map");
270             for (jj = 0; jj < entry->num_ep_coarse; jj++) {
271                 int start, end;
272 
273                 indent_printf(level+3, "Coarse: %d", jj);
274                 coarse = &entry->coarse[jj];
275                 start = coarse->ref_ep_fine_id;
276                 if (jj < entry->num_ep_coarse - 1) {
277                     end = entry->coarse[jj+1].ref_ep_fine_id;
278                 } else {
279                     end = entry->num_ep_fine;
280                 }
281                 for (kk = start; kk < end; kk++) {
282                     fine = &entry->fine[kk];
283                     pts = ((uint64_t) (coarse->pts_ep & ~0x01) << 19) +
284                             ((uint64_t)fine->pts_ep << 9);
285                     spn = (coarse->spn_ep & ~0x1FFFF) + fine->spn_ep;
286                     indent_printf(level+4, "PTS %8" PRIu64 "/%8" PRIu64 " -- SPN %u",
287                         pts, pts >> 1, spn);
288                 }
289             }
290         }
291     }
292 }
293 
294 
295 static void
_usage(char * cmd)296 _usage(char *cmd)
297 {
298     fprintf(stderr,
299 "Usage: %s -vcspi <clpi file> [<clpi file> ...]\n"
300 "With no options, produces no output (not very useful)\n"
301 "Options:\n"
302 "    v - Verbose output.\n"
303 "    c - Shows the Clip Info structure\n"
304 "    s - Shows the Sequence Info structure\n"
305 "    p - Shows the Program Info structure\n"
306 "    i - Shows the CPI. PTS to SPN map\n"
307 "    e - Shows Extent Start Table\n"
308 , cmd);
309 
310     exit(EXIT_FAILURE);
311 }
312 
313 #define OPTS "vcspie"
314 
315 int
main(int argc,char * argv[])316 main(int argc, char *argv[])
317 {
318     CLPI_CL *cl;
319     int opt;
320     int opt_clip_info = 0, opt_seq_info = 0, opt_prog_info = 0;
321     int opt_cpi_info = 0, opt_extent_start = 0;
322     int ii;
323 
324     do {
325         opt = getopt(argc, argv, OPTS);
326         switch (opt) {
327             case -1: break;
328 
329             case 'v':
330                 verbose = 1;
331                 break;
332 
333             case 's':
334                 opt_seq_info = 1;
335                 break;
336 
337             case 'i':
338                 opt_cpi_info = 1;
339                 break;
340 
341             case 'c':
342                 opt_clip_info = 1;
343                 break;
344 
345             case 'p':
346                 opt_prog_info = 1;
347                 break;
348 
349             case 'e':
350                 opt_extent_start = 1;
351                 break;
352 
353             default:
354                 _usage(argv[0]);
355                 break;
356         }
357     } while (opt != -1);
358 
359     if (optind >= argc) {
360         _usage(argv[0]);
361     }
362 
363     for (ii = optind; ii < argc; ii++) {
364         cl = bd_read_clpi(argv[ii]);
365         if (cl == NULL) {
366             fprintf(stderr, "Parsing %s failed\n", argv[ii]);
367             continue;
368         }
369         if (opt_clip_info) {
370             // Show clip info
371             _show_clip_info(cl, 1);
372         }
373         if (opt_seq_info) {
374             // Show sequence info
375             _show_seq_info(&cl->sequence, 1);
376         }
377         if (opt_prog_info) {
378             // Show program info
379             _show_prog_info(&cl->program, 1);
380         }
381         if (opt_cpi_info) {
382             // Show cpi
383             _show_cpi_info(&cl->cpi, 1);
384         }
385 
386         if (opt_prog_info) {
387             if (cl->program_ss.num_prog) {
388                 printf("\n");
389                 indent_printf(1, "Extension: Program Info SS");
390                 _show_prog_info(&cl->program_ss, 1);
391             }
392         }
393         if (opt_cpi_info) {
394             if (cl->program_ss.num_prog) {
395                 printf("\n");
396                 indent_printf(1, "Extension: CPI SS");
397                 _show_cpi_info(&cl->cpi_ss, 1);
398             }
399         }
400         if (opt_extent_start) {
401             // Show extent start point
402             if (cl->extent_start.num_point > 0) {
403                 _show_extent_start(&cl->extent_start, 1);
404             }
405         }
406 
407         bd_free_clpi(cl);
408     }
409     return 0;
410 }
411 
412