annotate menus.c @ 8:12c17225098e

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