view menus.c @ 5:ec2f201219ff

add start title parameter
author paulo@twcdns.fastsearch.net
date Mon, 27 Sep 2010 23:13:24 -0700
parents ffbf478b80c2
children 3fd49361fcc8
line source
1 /*
2 * Copyright (C) 2003 by the libdvdnav project
3 *
4 * This file is part of libdvdnav, a DVD navigation library.
5 *
6 * libdvdnav 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 * libdvdnav 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 *
20 * $Id: menus.c 1135 2008-09-06 21:55:51Z rathann $
21 *
22 */
24 #include <stdio.h>
25 #include <unistd.h>
26 #include <inttypes.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include "dvd_types.h"
31 #include <dvdread/dvd_reader.h>
32 #include <dvdread/nav_types.h>
33 #include <dvdread/ifo_types.h> /* For vm_cmd_t */
34 #include "dvdnav.h"
35 #include "dvdnav_events.h"
37 /* shall we use libdvdnav's read ahead cache? */
38 #define DVD_READ_CACHE 1
40 /* which is the default language for menus/audio/subpictures? */
41 #define DVD_LANGUAGE "en"
43 #ifdef WIN32
44 #define S_IRWXG 0
45 #endif
47 int main(int argc, char **argv) {
48 dvdnav_t *dvdnav;
49 uint8_t mem[DVD_VIDEO_LB_LEN];
50 int finished = 0;
51 int output_fd = 0;
52 int dump = 0, tt_dump = 0, tt_skip = 0;
54 /* open dvdnav handle */
55 printf("Opening DVD...\n");
56 if (dvdnav_open(&dvdnav, "/dev/dvd") != DVDNAV_STATUS_OK) {
57 printf("Error on dvdnav_open\n");
58 return 1;
59 }
61 /* set read ahead cache usage */
62 if (dvdnav_set_readahead_flag(dvdnav, DVD_READ_CACHE) != DVDNAV_STATUS_OK) {
63 printf("Error on dvdnav_set_readahead_flag: %s\n", dvdnav_err_to_string(dvdnav));
64 return 2;
65 }
67 /* set the language */
68 if (dvdnav_menu_language_select(dvdnav, DVD_LANGUAGE) != DVDNAV_STATUS_OK ||
69 dvdnav_audio_language_select(dvdnav, DVD_LANGUAGE) != DVDNAV_STATUS_OK ||
70 dvdnav_spu_language_select(dvdnav, DVD_LANGUAGE) != DVDNAV_STATUS_OK) {
71 printf("Error on setting languages: %s\n", dvdnav_err_to_string(dvdnav));
72 return 2;
73 }
75 /* set the PGC positioning flag to have position information relatively to the
76 * whole feature instead of just relatively to the current chapter */
77 if (dvdnav_set_PGC_positioning_flag(dvdnav, 1) != DVDNAV_STATUS_OK) {
78 printf("Error on dvdnav_set_PGC_positioning_flag: %s\n", dvdnav_err_to_string(dvdnav));
79 return 2;
80 }
82 /* start at title, if specified */
83 if (argc > 1) {
84 int start_title = atoi(argv[1]);
85 dvdnav_title_play(dvdnav, start_title);
86 }
88 /* the read loop which regularly calls dvdnav_get_next_block
89 * and handles the returned events */
90 printf("Reading...\n");
91 while (!finished) {
92 int result, event, len;
93 uint8_t *buf = mem;
95 /* the main reading function */
96 #if DVD_READ_CACHE
97 result = dvdnav_get_next_cache_block(dvdnav, &buf, &event, &len);
98 #else
99 result = dvdnav_get_next_block(dvdnav, buf, &event, &len);
100 #endif
102 if (result == DVDNAV_STATUS_ERR) {
103 printf("Error getting next block: %s\n", dvdnav_err_to_string(dvdnav));
104 return 3;
105 }
107 switch (event) {
108 case DVDNAV_BLOCK_OK:
109 /* We have received a regular block of the currently playing MPEG stream.
110 * A real player application would now pass this block through demuxing
111 * and decoding. We simply write it to disc here. */
113 if (!output_fd && (dump || tt_dump)) {
114 printf("Opening output...\n");
115 output_fd = open("libdvdnav.mpg", O_CREAT | O_WRONLY | O_APPEND, S_IRWXU | S_IRWXG);
116 if (output_fd == -1) {
117 printf("Error opening output\n");
118 return 4;
119 }
120 }
122 if (dump || tt_dump)
123 write(output_fd, buf, len);
125 break;
126 case DVDNAV_NOP:
127 /* Nothing to do here. */
128 break;
129 case DVDNAV_STILL_FRAME:
130 /* We have reached a still frame. A real player application would wait
131 * the amount of time specified by the still's length while still handling
132 * user input to make menus and other interactive stills work.
133 * A length of 0xff means an indefinite still which has to be skipped
134 * indirectly by some user interaction. */
135 {
136 dvdnav_still_event_t *still_event = (dvdnav_still_event_t *)buf;
137 if (still_event->length < 0xff)
138 printf("Skipping %d seconds of still frame\n", still_event->length);
139 else
140 printf("Skipping indefinite length still frame\n");
141 dvdnav_still_skip(dvdnav);
142 }
143 break;
144 case DVDNAV_WAIT:
145 /* We have reached a point in DVD playback, where timing is critical.
146 * Player application with internal fifos can introduce state
147 * inconsistencies, because libdvdnav is always the fifo's length
148 * ahead in the stream compared to what the application sees.
149 * Such applications should wait until their fifos are empty
150 * when they receive this type of event. */
151 printf("Skipping wait condition\n");
152 dvdnav_wait_skip(dvdnav);
153 break;
154 case DVDNAV_SPU_CLUT_CHANGE:
155 /* Player applications should pass the new colour lookup table to their
156 * SPU decoder */
157 break;
158 case DVDNAV_SPU_STREAM_CHANGE:
159 /* Player applications should inform their SPU decoder to switch channels */
160 break;
161 case DVDNAV_AUDIO_STREAM_CHANGE:
162 /* Player applications should inform their audio decoder to switch channels */
163 break;
164 case DVDNAV_HIGHLIGHT:
165 /* Player applications should inform their overlay engine to highlight the
166 * given button */
167 {
168 dvdnav_highlight_event_t *highlight_event = (dvdnav_highlight_event_t *)buf;
169 printf("Selected button %d\n", highlight_event->buttonN);
170 }
171 break;
172 case DVDNAV_VTS_CHANGE:
173 /* Some status information like video aspect and video scale permissions do
174 * not change inside a VTS. Therefore this event can be used to query such
175 * information only when necessary and update the decoding/displaying
176 * accordingly. */
177 break;
178 case DVDNAV_CELL_CHANGE:
179 /* Some status information like the current Title and Part numbers do not
180 * change inside a cell. Therefore this event can be used to query such
181 * information only when necessary and update the decoding/displaying
182 * accordingly. */
183 {
184 int32_t tt = 0, ptt = 0;
185 uint32_t pos, len;
186 char input = '\0';
188 dvdnav_current_title_info(dvdnav, &tt, &ptt);
189 dvdnav_get_position(dvdnav, &pos, &len);
190 printf("Cell change: Title %d, Chapter %d\n", tt, ptt);
191 printf("At position %.0f%% inside the feature\n", 100 * (double)pos / (double)len);
193 dump = 0;
194 if (tt_dump && tt != tt_dump)
195 tt_dump = 0;
197 if (tt_skip && tt != tt_skip)
198 tt_skip = 0;
200 if (output_fd && !tt_dump) {
201 printf("Closing output...\n");
202 output_fd = close(output_fd);
203 }
205 if (!dump && !tt_dump && !tt_skip) {
206 fflush(stdin);
207 while ((input != 'a') && (input != 's') && (input != 'q') && (input != 't') && (input != 'l')) {
208 printf("(a)ppend cell to output\n(s)kip cell\nappend until end of (t)itle\nskip tit(l)e\n(q)uit\n");
209 scanf("%c", &input);
210 }
212 switch (input) {
213 case 'a':
214 dump = 1;
215 break;
216 case 't':
217 tt_dump = tt;
218 break;
219 case 'l':
220 tt_skip = tt;
221 break;
222 case 'q':
223 finished = 1;
224 }
225 }
226 }
227 break;
228 case DVDNAV_NAV_PACKET:
229 /* A NAV packet provides PTS discontinuity information, angle linking information and
230 * button definitions for DVD menus. Angles are handled completely inside libdvdnav.
231 * For the menus to work, the NAV packet information has to be passed to the overlay
232 * engine of the player so that it knows the dimensions of the button areas. */
233 {
234 pci_t *pci;
236 /* Applications with fifos should not use these functions to retrieve NAV packets,
237 * they should implement their own NAV handling, because the packet you get from these
238 * functions will already be ahead in the stream which can cause state inconsistencies.
239 * Applications with fifos should therefore pass the NAV packet through the fifo
240 * and decoding pipeline just like any other data. */
241 pci = dvdnav_get_current_nav_pci(dvdnav);
242 dvdnav_get_current_nav_dsi(dvdnav);
244 if(pci->hli.hl_gi.btn_ns > 0) {
245 int button;
247 printf("Found %i DVD menu buttons...\n", pci->hli.hl_gi.btn_ns);
249 for (button = 0; button < pci->hli.hl_gi.btn_ns; button++) {
250 btni_t *btni = &(pci->hli.btnit[button]);
251 printf("Button %i top-left @ (%i,%i), bottom-right @ (%i,%i)\n",
252 button + 1, btni->x_start, btni->y_start,
253 btni->x_end, btni->y_end);
254 }
256 button = 0;
257 while ((button <= 0) || (button > pci->hli.hl_gi.btn_ns)) {
258 printf("Which button (1 to %i): ", pci->hli.hl_gi.btn_ns);
259 scanf("%i", &button);
260 }
262 printf("Selecting button %i...\n", button);
263 /* This is the point where applications with fifos have to hand in a NAV packet
264 * which has traveled through the fifos. See the notes above. */
265 dvdnav_button_select_and_activate(dvdnav, pci, button);
266 }
267 }
268 break;
269 case DVDNAV_HOP_CHANNEL:
270 /* This event is issued whenever a non-seamless operation has been executed.
271 * Applications with fifos should drop the fifos content to speed up responsiveness. */
272 break;
273 case DVDNAV_STOP:
274 /* Playback should end here. */
275 finished = 1;
276 break;
277 default:
278 printf("Unknown event (%i)\n", event);
279 finished = 1;
280 break;
281 }
282 #if DVD_READ_CACHE
283 dvdnav_free_cache_block(dvdnav, buf);
284 #endif
285 }
287 /* destroy dvdnav handle */
288 if (dvdnav_close(dvdnav) != DVDNAV_STATUS_OK) {
289 printf("Error on dvdnav_close: %s\n", dvdnav_err_to_string(dvdnav));
290 return 5;
291 }
292 close(output_fd);
294 return 0;
295 }