comparison dvdnav.c @ 114:b6834e6359cf src

big libdvdnav cleanup, quoting the ChangeLog: * some bugfixes * code cleanup * build process polishing * more sensible event order in get_next_block to ensure useful event delivery * VOBU level resume * fixed: seeking in a multiangle feature briefly showed the wrong angle
author mroi
date Thu, 20 Feb 2003 15:32:21 +0000
parents e984044bbe7b
children b527b7cbfb19
comparison
equal deleted inserted replaced
113:ec2df154be56 114:b6834e6359cf
28 /* 28 /*
29 #define LOG_DEBUG 29 #define LOG_DEBUG
30 */ 30 */
31 31
32 #include <pthread.h> 32 #include <pthread.h>
33 #include <dvdnav.h>
34 #include "dvdnav_internal.h" 33 #include "dvdnav_internal.h"
35 #include "read_cache.h" 34 #include "read_cache.h"
36 35
37 #include <dvdread/nav_read.h> 36 #include <dvdread/nav_read.h>
38 37
40 #include <stdio.h> 39 #include <stdio.h>
41 #include <sys/time.h> 40 #include <sys/time.h>
42 41
43 #include "remap.h" 42 #include "remap.h"
44 43
45 /* 44 static dvdnav_status_t dvdnav_clear(dvdnav_t * this) {
46 * NOTE: 45 /* clear everything except file, vm, mutex, readahead */
47 * All NLCK_*() function are not mutex locked, this made them reusable in 46
48 * a locked context. Take care.
49 *
50 */
51
52 /* Current domain (backend to dvdnav_is_domain_() funcs) */
53 static int8_t NLCK_dvdnav_is_domain(dvdnav_t *this, domain_t domain) {
54 dvd_state_t *state;
55
56 if((!this) || (!this->started) || (!this->vm))
57 return -1;
58
59 state = &(this->vm->state);
60
61 if(!state)
62 return -1;
63
64 return (state->domain == domain) ? 1 : 0;
65 }
66
67 static int8_t _dvdnav_is_domain(dvdnav_t *this, domain_t domain) {
68 int8_t retval;
69
70 pthread_mutex_lock(&this->vm_lock);
71 retval = NLCK_dvdnav_is_domain(this, domain);
72 pthread_mutex_unlock(&this->vm_lock);
73
74 return retval;
75 }
76
77 static int8_t NCLK_dvdnav_get_audio_logical_stream(dvdnav_t *this, uint8_t audio_num) {
78 dvd_state_t *state;
79 int8_t logical = -1;
80
81 if(!NLCK_dvdnav_is_domain(this, VTS_DOMAIN))
82 audio_num = 0;
83
84 state = &(this->vm->state);
85
86 if(audio_num < 8) {
87 if(state->pgc->audio_control[audio_num] & (1 << 15)) {
88 logical = (state->pgc->audio_control[audio_num] >> 8) & 0x07;
89 }
90 }
91
92 return logical;
93 }
94
95 static int8_t NCLK_dvdnav_get_spu_logical_stream(dvdnav_t *this, uint8_t subp_num) {
96 dvd_state_t *state;
97 ifo_handle_t *vtsi;
98
99 if(!this)
100 return -1;
101
102 state = &(this->vm->state);
103 vtsi = this->vm->vtsi;
104
105 if(subp_num >= vtsi->vtsi_mat->nr_of_vts_subp_streams)
106 return -1;
107
108 return vm_get_subp_stream(this->vm, subp_num, 0);
109 }
110
111 static int8_t NLCK_dvdnav_get_active_spu_stream(dvdnav_t *this) {
112 dvd_state_t *state;
113 int8_t subp_num;
114 int stream_num;
115
116 state = &(this->vm->state);
117 subp_num = state->SPST_REG & ~0x40;
118 stream_num = NCLK_dvdnav_get_spu_logical_stream(this, subp_num);
119
120 if(stream_num == -1)
121 for(subp_num = 0; subp_num < 32; subp_num++)
122 if(state->pgc->subp_control[subp_num] & (1 << 31)) {
123 stream_num = NCLK_dvdnav_get_spu_logical_stream(this, subp_num);
124 break;
125 }
126
127 return stream_num;
128 }
129
130 uint8_t dvdnav_get_video_aspect(dvdnav_t *this) {
131 uint8_t retval;
132
133 pthread_mutex_lock(&this->vm_lock);
134 retval = (uint8_t) vm_get_video_aspect(this->vm);
135 pthread_mutex_unlock(&this->vm_lock);
136
137 return retval;
138 }
139
140 uint8_t dvdnav_get_video_scale_permission(dvdnav_t *this) {
141 uint8_t retval;
142
143 pthread_mutex_lock(&this->vm_lock);
144 retval = (uint8_t) vm_get_video_scale_permission(this->vm);
145 pthread_mutex_unlock(&this->vm_lock);
146
147 return retval;
148 }
149
150 dvdnav_status_t dvdnav_clear(dvdnav_t * this) {
151 if (!this) {
152 printerr("Passed a NULL pointer");
153 return S_ERR;
154 }
155 /* clear everything except path, file, vm, mutex, readahead */
156
157 /* path */
158 if (this->file) DVDCloseFile(this->file); 47 if (this->file) DVDCloseFile(this->file);
159 this->file = NULL; 48 this->file = NULL;
160 this->open_vtsN = -1; 49 this->open_vtsN = -1;
161 this->open_domain = -1; 50 this->open_domain = -1;
162 51
164 memset(&this->dsi,0,sizeof(this->dsi)); 53 memset(&this->dsi,0,sizeof(this->dsi));
165 54
166 /* Set initial values of flags */ 55 /* Set initial values of flags */
167 this->position_current.still = 0; 56 this->position_current.still = 0;
168 this->skip_still = 0; 57 this->skip_still = 0;
169 this->stop = 0;
170 this->spu_clut_changed = 0; 58 this->spu_clut_changed = 0;
171 this->started=0; 59 this->started = 0;
172 /* this->use_read_ahead */
173 60
174 dvdnav_read_cache_clear(this->cache); 61 dvdnav_read_cache_clear(this->cache);
175 62
176 return S_OK; 63 return S_OK;
177 } 64 }
178 65
179 dvdnav_status_t dvdnav_open(dvdnav_t** dest, char *path) { 66 dvdnav_status_t dvdnav_open(dvdnav_t** dest, const char *path) {
180 dvdnav_t *this; 67 dvdnav_t *this;
181 struct timeval time; 68 struct timeval time;
182 69
183 /* Create a new structure */ 70 /* Create a new structure */
184 fprintf(MSG_OUT, "libdvdnav: Using dvdnav version %s from http://dvd.sf.net\n", VERSION); 71 fprintf(MSG_OUT, "libdvdnav: Using dvdnav version %s from http://dvd.sf.net\n", VERSION);
185 72
186 (*dest) = NULL; 73 (*dest) = NULL;
187 this = (dvdnav_t*)malloc(sizeof(dvdnav_t)); 74 this = (dvdnav_t*)malloc(sizeof(dvdnav_t));
188 if(!this) 75 if(!this)
189 return S_ERR; 76 return S_ERR;
190 memset(this, 0, (sizeof(dvdnav_t) ) ); /* Make sure this structure is clean */ 77 memset(this, 0, (sizeof(dvdnav_t) ) ); /* Make sure this structure is clean */
191 (*dest) = this; 78
192
193 pthread_mutex_init(&this->vm_lock, NULL); 79 pthread_mutex_init(&this->vm_lock, NULL);
194 /* Initialise the error string */ 80 /* Initialise the error string */
195 printerr(""); 81 printerr("");
196 82
197 /* Initialise the VM */ 83 /* Initialise the VM */
198 this->vm = vm_new_vm(); 84 this->vm = vm_new_vm();
199 if(!this->vm) { 85 if(!this->vm) {
200 printerr("Error initialising the DVD VM"); 86 printerr("Error initialising the DVD VM.");
201 pthread_mutex_destroy(&this->vm_lock); 87 pthread_mutex_destroy(&this->vm_lock);
202 free(this); 88 free(this);
203 return S_ERR; 89 return S_ERR;
204 } 90 }
205 if(vm_reset(this->vm, path) == -1) { 91 if(!vm_reset(this->vm, path)) {
206 printerr("Error starting the VM / opening the DVD device"); 92 printerr("Error starting the VM / opening the DVD device.");
207 pthread_mutex_destroy(&this->vm_lock); 93 pthread_mutex_destroy(&this->vm_lock);
208 vm_free_vm(this->vm); 94 vm_free_vm(this->vm);
209 free(this); 95 free(this);
210 return S_ERR; 96 return S_ERR;
211 } 97 }
212 98
213 /* Set the path. FIXME: Is a deep copy 'right' */ 99 /* Set the path. FIXME: Is a deep copy 'right' */
214 strncpy(this->path, path, MAX_PATH_LEN); 100 strncpy(this->path, path, MAX_PATH_LEN);
215 101
216 dvdnav_clear(this);
217
218 /* Pre-open and close a file so that the CSS-keys are cached. */ 102 /* Pre-open and close a file so that the CSS-keys are cached. */
219 this->file = DVDOpenFile(vm_get_dvd_reader(this->vm), 0, DVD_READ_MENU_VOBS); 103 this->file = DVDOpenFile(vm_get_dvd_reader(this->vm), 0, DVD_READ_MENU_VOBS);
220 if (this->file) DVDCloseFile(this->file);
221 this->file = NULL;
222 104
223 /* Start the read-ahead cache. */ 105 /* Start the read-ahead cache. */
224 this->cache = dvdnav_read_cache_new(this); 106 this->cache = dvdnav_read_cache_new(this);
225 107
226 /* Seed the random numbers. So that the DVD VM Command rand()i 108 /* Seed the random numbers. So that the DVD VM Command rand()
227 * gives a different start value each time a DVD is played. 109 * gives a different start value each time a DVD is played. */
228 */ 110 gettimeofday(&time, NULL);
229 gettimeofday(&time,NULL);
230 srand(time.tv_usec); 111 srand(time.tv_usec);
231 112
113 dvdnav_clear(this);
114
115 (*dest) = this;
232 return S_OK; 116 return S_OK;
233 } 117 }
234 118
235 dvdnav_status_t dvdnav_close(dvdnav_t *this) { 119 dvdnav_status_t dvdnav_close(dvdnav_t *this) {
120
121 #ifdef LOG_DEBUG
122 fprintf(MSG_OUT, "libdvdnav: close:called\n");
123 #endif
124
236 if(!this) { 125 if(!this) {
237 printerr("Passed a NULL pointer"); 126 printerr("Passed a NULL pointer.");
238 return S_ERR; 127 return S_ERR;
239 } 128 }
240 #ifdef LOG_DEBUG
241 fprintf(MSG_OUT, "libdvdnav: close:called\n");
242 #endif
243 129
244 if (this->file) { 130 if (this->file) {
245 DVDCloseFile(this->file); 131 DVDCloseFile(this->file);
246 #ifdef LOG_DEBUG 132 #ifdef LOG_DEBUG
247 fprintf(MSG_OUT, "libdvdnav: close:file closing\n"); 133 fprintf(MSG_OUT, "libdvdnav: close:file closing\n");
248 #endif 134 #endif
249 this->file = NULL; 135 this->file = NULL;
250 } 136 }
251 137
252 /* Free the VM */ 138 /* Free the VM */
253 if(this->vm) { 139 if(this->vm)
254 vm_free_vm(this->vm); 140 vm_free_vm(this->vm);
255 } 141
256 if (this->file) {
257 DVDCloseFile(this->file);
258 #ifdef LOG_DEBUG
259 fprintf(MSG_OUT, "libdvdnav: close2:file closing\n");
260 #endif
261 this->file = NULL;
262 }
263 pthread_mutex_destroy(&this->vm_lock); 142 pthread_mutex_destroy(&this->vm_lock);
264 143
265 /* We leave the final freeing of the entire structure to the cache, 144 /* We leave the final freeing of the entire structure to the cache,
266 * because we don't know, if there are still buffers out in the wild, 145 * because we don't know, if there are still buffers out in the wild,
267 * that must return first. */ 146 * that must return first. */
268 if(this->cache) { 147 if(this->cache)
269 dvdnav_read_cache_free(this->cache); 148 dvdnav_read_cache_free(this->cache);
270 } else free(this); 149 else
150 free(this);
271 151
272 return S_OK; 152 return S_OK;
273 } 153 }
274 154
275 dvdnav_status_t dvdnav_reset(dvdnav_t *this) { 155 dvdnav_status_t dvdnav_reset(dvdnav_t *this) {
276 dvdnav_status_t result; 156 dvdnav_status_t result;
277 157
278 #ifdef LOG_DEBUG 158 #ifdef LOG_DEBUG
279 fprintf(MSG_OUT, "libdvdnav: reset:called\n"); 159 fprintf(MSG_OUT, "libdvdnav: reset:called\n");
280 #endif 160 #endif
161
281 if(!this) { 162 if(!this) {
282 printerr("Passed a NULL pointer"); 163 printerr("Passed a NULL pointer.");
283 return S_ERR; 164 return S_ERR;
284 } 165 }
285 #ifdef LOG_DEBUG 166
286 fprintf(MSG_OUT, "libdvdnav: getting lock\n");
287 #endif
288 pthread_mutex_lock(&this->vm_lock); 167 pthread_mutex_lock(&this->vm_lock);
168
289 #ifdef LOG_DEBUG 169 #ifdef LOG_DEBUG
290 fprintf(MSG_OUT, "libdvdnav: reseting vm\n"); 170 fprintf(MSG_OUT, "libdvdnav: reseting vm\n");
291 #endif 171 #endif
292 if(vm_reset(this->vm, NULL) == -1) { 172 if(!vm_reset(this->vm, NULL)) {
293 printerr("Error restarting the VM"); 173 printerr("Error restarting the VM.");
294 pthread_mutex_unlock(&this->vm_lock); 174 pthread_mutex_unlock(&this->vm_lock);
295 return S_ERR; 175 return S_ERR;
296 } 176 }
297 #ifdef LOG_DEBUG 177 #ifdef LOG_DEBUG
298 fprintf(MSG_OUT, "libdvdnav: clearing dvdnav\n"); 178 fprintf(MSG_OUT, "libdvdnav: clearing dvdnav\n");
299 #endif 179 #endif
300 result=dvdnav_clear(this); 180 result = dvdnav_clear(this);
301 #ifdef LOG_DEBUG 181
302 fprintf(MSG_OUT, "libdvdnav: unlocking\n");
303 #endif
304 pthread_mutex_unlock(&this->vm_lock); 182 pthread_mutex_unlock(&this->vm_lock);
305 return result; 183 return result;
306 } 184 }
307 185
308 dvdnav_status_t dvdnav_path(dvdnav_t *this, char** path) { 186 dvdnav_status_t dvdnav_path(dvdnav_t *this, const char** path) {
309 if(!this || !path || !(*path)) { 187
310 return S_ERR; 188 if(!this || !path) {
311 } 189 printerr("Passed a NULL pointer.");
312 190 return S_ERR;
313 /* FIXME: Is shallow copy 'right'? */ 191 }
192
314 (*path) = this->path; 193 (*path) = this->path;
315 194
316 return S_OK; 195 return S_OK;
317 } 196 }
318 197
319 char* dvdnav_err_to_string(dvdnav_t *this) { 198 const char* dvdnav_err_to_string(dvdnav_t *this) {
320 if(!this) { 199
321 /* Shold this be "passed a NULL pointer?" */ 200 if(!this)
322 return "Hey! You gave me a NULL pointer you naughty person!"; 201 return "Hey! You gave me a NULL pointer you naughty person!";
323 }
324 202
325 return this->err_str; 203 return this->err_str;
326 } 204 }
327 205
328 /** 206 /*
329 * Returns 1 if block contains NAV packet, 0 otherwise. 207 * Returns 1 if block contains NAV packet, 0 otherwise.
330 * Precesses said NAV packet if present. 208 * Precesses said NAV packet if present.
331 * 209 *
332 * Most of the code in here is copied from xine's MPEG demuxer 210 * Most of the code in here is copied from xine's MPEG demuxer
333 * so any bugs which are found in that should be corrected here also. 211 * so any bugs which are found in that should be corrected here also.
334 */ 212 */
335 int dvdnav_decode_packet(dvdnav_t *this, uint8_t *p, dsi_t* nav_dsi, pci_t* nav_pci) { 213 static int dvdnav_decode_packet(dvdnav_t *this, uint8_t *p, dsi_t *nav_dsi, pci_t *nav_pci) {
336 int bMpeg1=0; 214 int bMpeg1 = 0;
337 uint32_t nHeaderLen; 215 uint32_t nHeaderLen;
338 uint32_t nPacketLen; 216 uint32_t nPacketLen;
339 uint32_t nStreamID; 217 uint32_t nStreamID;
340 /* uint8_t *p_start=p; */
341
342
343 if (p==NULL) {
344 fprintf(MSG_OUT, "libdvdnav: Passed a NULL pointer.\n");
345 return 0;
346 }
347
348 /* dprint("Checking packet...\n"); */
349 218
350 if (p[3] == 0xBA) { /* program stream pack header */ 219 if (p[3] == 0xBA) { /* program stream pack header */
351
352 int nStuffingBytes; 220 int nStuffingBytes;
353 221
354 /* xprintf (VERBOSE|DEMUX, "program stream pack header\n"); */
355
356 bMpeg1 = (p[4] & 0x40) == 0; 222 bMpeg1 = (p[4] & 0x40) == 0;
357 223
358 if (bMpeg1) { 224 if (bMpeg1) {
359 p += 12; 225 p += 12;
360 } else { /* mpeg2 */ 226 } else { /* mpeg2 */
361 nStuffingBytes = p[0xD] & 0x07; 227 nStuffingBytes = p[0xD] & 0x07;
362 p += 14 + nStuffingBytes; 228 p += 14 + nStuffingBytes;
363 } 229 }
364 } 230 }
365 231
366
367 if (p[3] == 0xbb) { /* program stream system header */ 232 if (p[3] == 0xbb) { /* program stream system header */
368 int nHeaderLen;
369
370 nHeaderLen = (p[4] << 8) | p[5]; 233 nHeaderLen = (p[4] << 8) | p[5];
371 p += 6 + nHeaderLen; 234 p += 6 + nHeaderLen;
372 } 235 }
373 236
374 /* we should now have a PES packet here */ 237 /* we should now have a PES packet here */
375
376 if (p[0] || p[1] || (p[2] != 1)) { 238 if (p[0] || p[1] || (p[2] != 1)) {
377 fprintf(MSG_OUT, "libdvdnav: demux error! %02x %02x %02x (should be 0x000001) \n",p[0],p[1],p[2]); 239 fprintf(MSG_OUT, "libdvdnav: demux error! %02x %02x %02x (should be 0x000001) \n",p[0],p[1],p[2]);
378 return 0; 240 return 0;
379 } 241 }
380 242
383 245
384 nHeaderLen = 6; 246 nHeaderLen = 6;
385 p += nHeaderLen; 247 p += nHeaderLen;
386 248
387 if (nStreamID == 0xbf) { /* Private stream 2 */ 249 if (nStreamID == 0xbf) { /* Private stream 2 */
388 /* 250 #if 0
389 * int i; 251 int i;
390 * fprintf(MSG_OUT, "libdvdnav: nav packet=%u\n",p-p_start-6); 252 fprintf(MSG_OUT, "libdvdnav: nav packet=%u\n",p-p_start-6);
391 * for(i=0;i<80;i++) { 253 for(i=0;i<80;i++)
392 * fprintf(MSG_OUT, "%02x ",p[i-6]); 254 fprintf(MSG_OUT, "%02x ",p[i-6]);
393 * } 255 fprintf(MSG_OUT, "\n");
394 * fprintf(MSG_OUT, "\n"); 256 #endif
395 */ 257
396 if(p[0] == 0x00) { 258 if(p[0] == 0x00) {
397 navRead_PCI(nav_pci, p+1); 259 navRead_PCI(nav_pci, p+1);
398 } 260 }
399 261
400 p += nPacketLen; 262 p += nPacketLen;
401 263
402 /* We should now have a DSI packet. */ 264 /* We should now have a DSI packet. */
403 if(p[6] == 0x01) { 265 if(p[6] == 0x01) {
404 nPacketLen = p[4] << 8 | p[5]; 266 nPacketLen = p[4] << 8 | p[5];
405 p += 6; 267 p += 6;
406 /* dprint("NAV DSI packet\n"); */
407 navRead_DSI(nav_dsi, p+1); 268 navRead_DSI(nav_dsi, p+1);
408
409 } 269 }
410 return 1; 270 return 1;
411 } 271 }
412 return 0; 272 return 0;
413 } 273 }
414 274
415 /* DSI is used for most angle stuff. 275 /* DSI is used for most angle stuff.
416 * PCI is used for only non-seemless angle stuff 276 * PCI is used for only non-seemless angle stuff
417 */ 277 */
418 int dvdnav_get_vobu(dvdnav_t *self, dsi_t* nav_dsi, pci_t* nav_pci, dvdnav_vobu_t* vobu) { 278 static int dvdnav_get_vobu(dvdnav_t *this, dsi_t *nav_dsi, pci_t *nav_pci, dvdnav_vobu_t *vobu) {
419 uint32_t next; 279 uint32_t next;
420 int angle, num_angle; 280 int angle, num_angle;
421 281
422 vobu->vobu_start = nav_dsi->dsi_gi.nv_pck_lbn; /* Absolute offset from start of disk */ 282 vobu->vobu_start = nav_dsi->dsi_gi.nv_pck_lbn; /* Absolute offset from start of disk */
423 vobu->vobu_length = nav_dsi->dsi_gi.vobu_ea; /* Relative offset from vobu_start */ 283 vobu->vobu_length = nav_dsi->dsi_gi.vobu_ea; /* Relative offset from vobu_start */
432 * vobu_next is an offset value, 0x3fffffff = SRI_END_OF_CELL 292 * vobu_next is an offset value, 0x3fffffff = SRI_END_OF_CELL
433 * DVDs are about 6 Gigs, which is only up to 0x300000 blocks 293 * DVDs are about 6 Gigs, which is only up to 0x300000 blocks
434 * Should really assert if bit 31 != 1 294 * Should really assert if bit 31 != 1
435 */ 295 */
436 296
437 /* Relative offset from vobu_start */ 297 #if 0
438 vobu->vobu_next = ( nav_dsi->vobu_sri.next_vobu & 0x3fffffff ); 298 /* Old code -- may still be useful one day */
439
440 /* Old code -- may still be sueful one day
441 if(nav_dsi->vobu_sri.next_vobu != SRI_END_OF_CELL ) { 299 if(nav_dsi->vobu_sri.next_vobu != SRI_END_OF_CELL ) {
442 vobu->vobu_next = ( nav_dsi->vobu_sri.next_vobu & 0x3fffffff ); 300 vobu->vobu_next = ( nav_dsi->vobu_sri.next_vobu & 0x3fffffff );
443 } else { 301 } else {
444 vobu->vobu_next = vobu->vobu_length; 302 vobu->vobu_next = vobu->vobu_length;
445 } */ 303 }
446 304 #else
447 dvdnav_get_angle_info(self, &angle, &num_angle); 305 /* Relative offset from vobu_start */
306 vobu->vobu_next = ( nav_dsi->vobu_sri.next_vobu & 0x3fffffff );
307 #endif
308
309 vm_get_angle_info(this->vm, &angle, &num_angle);
310
311 /* FIMXE: The angle reset doesn't work for some reason for the moment */
448 #if 0 312 #if 0
449 /* FIMXE: The angle reset doesn't work for some reason for the moment */
450
451 if((num_angle < angle) && (angle != 1)) { 313 if((num_angle < angle) && (angle != 1)) {
452 printf("OOOOOOO angle ends!\n"); 314 fprintf(MSG_OUT, "libdvdnav: angle ends!\n");
453 315
454 /* This is to switch back to angle one when we 316 /* This is to switch back to angle one when we
455 * finish with angles. */ 317 * finish with angles. */
456 dvdnav_angle_change(self, 1); 318 dvdnav_angle_change(this, 1);
457 } 319 }
458 #endif 320 #endif
459 321
460 if(num_angle != 0) { 322 if(num_angle != 0) {
461 next = nav_pci->nsml_agli.nsml_agl_dsta[angle-1];
462 323
463 if(next != 0) { 324 if((next = nav_pci->nsml_agli.nsml_agl_dsta[angle-1]) != 0) {
464 if((next & 0x3fffffff) != 0) { 325 if((next & 0x3fffffff) != 0) {
465 if(next & 0x80000000) { 326 if(next & 0x80000000)
466 vobu->vobu_next = - (int32_t)(next & 0x3fffffff); 327 vobu->vobu_next = - (int32_t)(next & 0x3fffffff);
467 } else { 328 else
468 vobu->vobu_next = + (int32_t)(next & 0x3fffffff); 329 vobu->vobu_next = + (int32_t)(next & 0x3fffffff);
469 }
470 } 330 }
471 331 } else if((next = nav_dsi->sml_agli.data[angle-1].address) != 0) {
472 } else if( nav_dsi->sml_agli.data[angle-1].address != 0 ) {
473 next = nav_dsi->sml_agli.data[angle-1].address;
474 vobu->vobu_length = nav_dsi->sml_pbi.ilvu_ea; 332 vobu->vobu_length = nav_dsi->sml_pbi.ilvu_ea;
475 333
476 if((next & 0x80000000) && (next != 0x7fffffff)) { 334 if((next & 0x80000000) && (next != 0x7fffffff))
477 vobu->vobu_next = - (int32_t)(next & 0x3fffffff); 335 vobu->vobu_next = - (int32_t)(next & 0x3fffffff);
478 } else { 336 else
479 vobu->vobu_next = + (int32_t)(next & 0x3fffffff); 337 vobu->vobu_next = + (int32_t)(next & 0x3fffffff);
480 }
481 } 338 }
482 } 339 }
483 340
484 return 1; 341 return 1;
485 } 342 }
486 343
487 /* This is the main get_next_block function which actually gets the media stream video and audio etc. 344 /*
488 * The use of this function is optional, with the application programmer 345 * These are the main get_next_block function which actually get the media stream video and audio etc.
489 * free to implement their own version of this function 346 *
490 * FIXME: Make the function calls from here public API calls. 347 * There are two versions: The second one is using the zero-copy read ahead cache and therefore
348 * hands out pointers targetting directly into the cache.
349 * The first one uses a memcopy to fill this cache block into the application provided memory.
350 * The benefit of this first one is that no special memory management is needed. The application is
351 * the only one responsible of allocating and freeing the memory associated with the pointer.
352 * The drawback is the additional memcopy.
491 */ 353 */
492 354
493 dvdnav_status_t dvdnav_get_next_block(dvdnav_t *this, unsigned char *buf, 355 dvdnav_status_t dvdnav_get_next_block(dvdnav_t *this, unsigned char *buf,
494 int *event, int *len) { 356 int *event, int *len) {
495 unsigned char *block; 357 unsigned char *block;
496 dvdnav_status_t status; 358 dvdnav_status_t status;
497 359
498 block = buf; 360 block = buf;
499 status = dvdnav_get_next_cache_block(this, &block, event, len); 361 status = dvdnav_get_next_cache_block(this, &block, event, len);
500 if (block != buf) { 362 if (status == S_OK && block != buf) {
501 /* we received a block from the cache, copy it, so we can give it back */ 363 /* we received a block from the cache, copy it, so we can give it back */
502 memcpy(buf, block, DVD_VIDEO_LB_LEN); 364 memcpy(buf, block, DVD_VIDEO_LB_LEN);
503 dvdnav_free_cache_block(this, block); 365 dvdnav_free_cache_block(this, block);
504 } 366 }
505 return status; 367 return status;
506 } 368 }
507 369
508 dvdnav_status_t dvdnav_get_next_cache_block(dvdnav_t *this, unsigned char **buf, 370 dvdnav_status_t dvdnav_get_next_cache_block(dvdnav_t *this, unsigned char **buf,
509 int *event, int *len) { 371 int *event, int *len) {
510 dvd_state_t *state; 372 dvd_state_t *state;
511 int result; 373 int result;
374
512 if(!this || !event || !len || !buf || !*buf) { 375 if(!this || !event || !len || !buf || !*buf) {
513 printerr("Passed a NULL pointer"); 376 printerr("Passed a NULL pointer.");
514 return S_ERR; 377 return S_ERR;
515 } 378 }
516 pthread_mutex_lock(&this->vm_lock); 379
380 pthread_mutex_lock(&this->vm_lock);
517 381
518 if(!this->started) { 382 if(!this->started) {
519 /* Start the VM */ 383 /* Start the VM */
520 vm_start(this->vm); 384 vm_start(this->vm);
521 this->started = 1; 385 this->started = 1;
524 state = &(this->vm->state); 388 state = &(this->vm->state);
525 (*event) = DVDNAV_NOP; 389 (*event) = DVDNAV_NOP;
526 (*len) = 0; 390 (*len) = 0;
527 391
528 /* Check the STOP flag */ 392 /* Check the STOP flag */
529 if(this->stop) { 393 if(this->vm->stopped) {
530 (*event) = DVDNAV_STOP; 394 (*event) = DVDNAV_STOP;
395 this->started = 0;
531 pthread_mutex_unlock(&this->vm_lock); 396 pthread_mutex_unlock(&this->vm_lock);
532 return S_OK; 397 return S_OK;
533 } 398 }
534 399
535 /* Check the STILLFRAME flag */ 400 vm_position_get(this->vm, &this->position_next);
536 /* FIXME: Still cell, not still frame */ 401
537 if(this->position_current.still != 0) { 402 #ifdef TRACE
538 dvdnav_still_event_t still_event; 403 fprintf(MSG_OUT, "libdvdnav: POS-NEXT ");
539 404 vm_position_print(this->vm, &this->position_next);
540 still_event.length = this->position_current.still; 405 fprintf(MSG_OUT, "libdvdnav: POS-CUR ");
541 406 vm_position_print(this->vm, &this->position_current);
542 (*event) = DVDNAV_STILL_FRAME; 407 #endif
543 (*len) = sizeof(dvdnav_still_event_t); 408
544 memcpy(*buf, &(still_event), sizeof(dvdnav_still_event_t)); 409 /* did we hop? */
545
546 pthread_mutex_unlock(&this->vm_lock);
547 return S_OK;
548 }
549
550 vm_position_get(this->vm,&this->position_next);
551 /**********
552 fprintf(MSG_OUT, "libdvdnav: POS-NEXT ");
553 vm_position_print(this->vm, &this->position_next);
554 fprintf(MSG_OUT, "libdvdnav: POS-CUR ");
555 vm_position_print(this->vm, &this->position_current);
556 **********/
557
558 if(this->position_current.hop_channel != this->position_next.hop_channel) { 410 if(this->position_current.hop_channel != this->position_next.hop_channel) {
411 (*event) = DVDNAV_HOP_CHANNEL;
412 #ifdef LOG_DEBUG
413 fprintf(MSG_OUT, "libdvdnav: HOP_CHANNEL\n");
414 #endif
415 if (this->position_next.hop_channel > HOP_SEEK) {
416 int num_angles = 0, current;
417
418 /* we seeked -> check for multiple angles */
419 vm_get_angle_info(this->vm, &current, &num_angles);
420 if (num_angles > 1) {
421 int result, block;
422 /* we have to skip the first VOBU when seeking in a multiangle feature,
423 * because it might belong to the wrong angle */
424 block = this->position_next.cell_start + this->position_next.block;
425 result = dvdnav_read_cache_block(this->cache, block, 1, buf);
426 if(result <= 0) {
427 printerr("Error reading NAV packet.");
428 pthread_mutex_unlock(&this->vm_lock);
429 return S_ERR;
430 }
431 /* Decode nav into pci and dsi. Then get next VOBU info. */
432 if(!dvdnav_decode_packet(this, *buf, &this->dsi, &this->pci)) {
433 printerr("Expected NAV packet but none found.");
434 pthread_mutex_unlock(&this->vm_lock);
435 return S_ERR;
436 }
437 dvdnav_get_vobu(this, &this->dsi, &this->pci, &this->vobu);
438 /* skip to next, if there is a next */
439 if (this->vobu.vobu_next != SRI_END_OF_CELL) {
440 this->vobu.vobu_start += this->vobu.vobu_next;
441 this->vobu.vobu_next = 0;
442 }
443 /* update VM state */
444 this->vm->state.blockN = this->vobu.vobu_start - this->position_next.cell_start;
445 }
446 }
559 this->position_current.hop_channel = this->position_next.hop_channel; 447 this->position_current.hop_channel = this->position_next.hop_channel;
560 (*event) = DVDNAV_HOP_CHANNEL; 448 /* Make blockN > vobu_length to do expected_nav */
561 (*len) = 0; 449 this->vobu.vobu_length = 0;
562 pthread_mutex_unlock(&this->vm_lock); 450 this->vobu.blockN = 1;
563 return S_OK;
564 }
565
566
567
568 if(this->spu_clut_changed) {
569 (*event) = DVDNAV_SPU_CLUT_CHANGE;
570 #ifdef LOG_DEBUG
571 fprintf(MSG_OUT, "libdvdnav: SPU_CLUT_CHANGE\n");
572 #endif
573 (*len) = 16 * sizeof(uint32_t);
574 memcpy(*buf, &(state->pgc->palette), 16 * sizeof(uint32_t));
575 this->spu_clut_changed = 0;
576 #ifdef LOG_DEBUG
577 fprintf(MSG_OUT, "libdvdnav: SPU_CLUT_CHANGE returning S_OK\n");
578 #endif
579 pthread_mutex_unlock(&this->vm_lock);
580 return S_OK;
581 }
582
583 if(this->position_current.spu_channel != this->position_next.spu_channel) {
584 dvdnav_spu_stream_change_event_t stream_change;
585 (*event) = DVDNAV_SPU_STREAM_CHANGE;
586 #ifdef LOG_DEBUG
587 fprintf(MSG_OUT, "libdvdnav: SPU_STREAM_CHANGE\n");
588 #endif
589 (*len) = sizeof(dvdnav_spu_stream_change_event_t);
590 stream_change.physical_wide = vm_get_subp_active_stream(this->vm, 0);
591 stream_change.physical_letterbox = vm_get_subp_active_stream(this->vm, 1);
592 stream_change.physical_pan_scan = vm_get_subp_active_stream(this->vm, 2);
593 memcpy(*buf, &(stream_change), sizeof( dvdnav_spu_stream_change_event_t));
594 this->position_current.spu_channel = this->position_next.spu_channel;
595 #ifdef LOG_DEBUG
596 fprintf(MSG_OUT, "libdvdnav: SPU_STREAM_CHANGE stream_id_wide=%d\n",stream_change.physical_wide);
597 fprintf(MSG_OUT, "libdvdnav: SPU_STREAM_CHANGE stream_id_letterbox=%d\n",stream_change.physical_letterbox);
598 fprintf(MSG_OUT, "libdvdnav: SPU_STREAM_CHANGE stream_id_pan_scan=%d\n",stream_change.physical_pan_scan);
599 #endif
600 if (stream_change.physical_wide != -1 &&
601 stream_change.physical_letterbox != -1 &&
602 stream_change.physical_pan_scan != -1) {
603 #ifdef LOG_DEBUG
604 fprintf(MSG_OUT, "libdvdnav: SPU_STREAM_CHANGE returning S_OK\n");
605 #endif
606 pthread_mutex_unlock(&this->vm_lock);
607 return S_OK;
608 }
609 }
610
611 if(this->position_current.audio_channel != this->position_next.audio_channel) {
612 dvdnav_audio_stream_change_event_t stream_change;
613 (*event) = DVDNAV_AUDIO_STREAM_CHANGE;
614 #ifdef LOG_DEBUG
615 fprintf(MSG_OUT, "libdvdnav: AUDIO_STREAM_CHANGE\n");
616 #endif
617 (*len) = sizeof(dvdnav_audio_stream_change_event_t);
618 stream_change.physical= vm_get_audio_active_stream( this->vm );
619 memcpy(*buf, &(stream_change), sizeof( dvdnav_audio_stream_change_event_t));
620 this->position_current.audio_channel = this->position_next.audio_channel;
621 #ifdef LOG_DEBUG
622 fprintf(MSG_OUT, "libdvdnav: AUDIO_STREAM_CHANGE stream_id=%d returning S_OK\n",stream_change.physical);
623 #endif
624 pthread_mutex_unlock(&this->vm_lock);
625 return S_OK;
626 }
627
628 /* Check the HIGHLIGHT flag */
629 /* FIXME: Use BUTTON instead of HIGHLIGHT. */
630 if(this->position_current.button != this->position_next.button) {
631 dvdnav_highlight_event_t hevent;
632
633 hevent.display = 1;
634 hevent.buttonN = this->position_next.button;
635
636 this->position_current.button = this->position_next.button;
637
638 (*event) = DVDNAV_HIGHLIGHT;
639 (*len) = sizeof(hevent);
640 memcpy(*buf, &(hevent), sizeof(hevent));
641 pthread_mutex_unlock(&this->vm_lock); 451 pthread_mutex_unlock(&this->vm_lock);
642 return S_OK; 452 return S_OK;
643 } 453 }
644 454
645 /* Check to see if we need to change the currently opened VOB */ 455 /* Check to see if we need to change the currently opened VOB */
648 dvd_read_domain_t domain; 458 dvd_read_domain_t domain;
649 int vtsN; 459 int vtsN;
650 dvdnav_vts_change_event_t vts_event; 460 dvdnav_vts_change_event_t vts_event;
651 461
652 if(this->file) { 462 if(this->file) {
653 dvdnav_read_cache_clear(this->cache);
654 DVDCloseFile(this->file); 463 DVDCloseFile(this->file);
655 this->file = NULL; 464 this->file = NULL;
656 } 465 }
657 466
658 vts_event.old_vtsN = this->open_vtsN; 467 vts_event.old_vtsN = this->open_vtsN;
659 vts_event.old_domain = this->open_domain; 468 vts_event.old_domain = this->open_domain;
660 469
661 /* Use the current DOMAIN to find whether to open menu or title VOBs */ 470 /* Use the DOMAIN to find whether to open menu or title VOBs */
662 switch(this->position_next.domain) { 471 switch(this->position_next.domain) {
663 case FP_DOMAIN: 472 case FP_DOMAIN:
664 case VMGM_DOMAIN: 473 case VMGM_DOMAIN:
665 domain = DVD_READ_MENU_VOBS; 474 domain = DVD_READ_MENU_VOBS;
666 vtsN = 0; 475 vtsN = 0;
667 break; 476 break;
668 case VTSM_DOMAIN: 477 case VTSM_DOMAIN:
669 domain = DVD_READ_MENU_VOBS; 478 domain = DVD_READ_MENU_VOBS;
670 vtsN = this->position_next.vts; 479 vtsN = this->position_next.vts;
671 break; 480 break;
672 case VTS_DOMAIN: 481 case VTS_DOMAIN:
673 domain = DVD_READ_TITLE_VOBS; 482 domain = DVD_READ_TITLE_VOBS;
674 vtsN = this->position_next.vts; 483 vtsN = this->position_next.vts;
675 break; 484 break;
676 default: 485 default:
677 printerr("Unknown domain when changing VTS."); 486 printerr("Unknown domain when changing VTS.");
678 pthread_mutex_unlock(&this->vm_lock); 487 pthread_mutex_unlock(&this->vm_lock);
679 return S_ERR; 488 return S_ERR;
680 } 489 }
681 490
693 return S_ERR; 502 return S_ERR;
694 } 503 }
695 504
696 /* File opened successfully so return a VTS change event */ 505 /* File opened successfully so return a VTS change event */
697 (*event) = DVDNAV_VTS_CHANGE; 506 (*event) = DVDNAV_VTS_CHANGE;
507 #ifdef LOG_DEBUG
508 fprintf(MSG_OUT, "libdvdnav: VTS_CHANGE\n");
509 #endif
510 (*len) = sizeof(vts_event);
698 memcpy(*buf, &(vts_event), sizeof(vts_event)); 511 memcpy(*buf, &(vts_event), sizeof(vts_event));
699 (*len) = sizeof(vts_event); 512
700
701 /* On a VTS change, we want to disable any highlights which
702 * may have been shown (FIXME: is this valid?) */
703 this->spu_clut_changed = 1; 513 this->spu_clut_changed = 1;
704 this->position_current.cell = -1; /* Force an update */ 514 this->position_current.cell = -1; /* Force an update */
705 this->position_current.spu_channel = -1; /* Force an update */ 515 this->position_current.spu_channel = -1; /* Force an update */
706 this->position_current.audio_channel = -1; /* Force an update */; 516 this->position_current.audio_channel = -1; /* Force an update */;
707 517
708 pthread_mutex_unlock(&this->vm_lock); 518 pthread_mutex_unlock(&this->vm_lock);
709 return S_OK; 519 return S_OK;
710 } 520 }
711 /* FIXME: Don't really need "cell", we only need vobu_start */ 521
522 /* Check if the cell changed */
712 if( (this->position_current.cell != this->position_next.cell) || 523 if( (this->position_current.cell != this->position_next.cell) ||
713 (this->position_current.cell_restart != this->position_next.cell_restart) || 524 (this->position_current.cell_restart != this->position_next.cell_restart) ||
714 (this->position_current.vobu_start != this->position_next.vobu_start) || 525 (this->position_current.cell_start != this->position_next.cell_start) ) {
715 (this->position_current.vobu_next != this->position_next.vobu_next) ) { 526
716 this->position_current.cell = this->position_next.cell; 527 (*event) = DVDNAV_CELL_CHANGE;
528 #ifdef LOG_DEBUG
529 fprintf(MSG_OUT, "libdvdnav: CELL_CHANGE\n");
530 #endif
531 (*len) = 0;
532
533 this->position_current.cell = this->position_next.cell;
717 this->position_current.cell_restart = this->position_next.cell_restart; 534 this->position_current.cell_restart = this->position_next.cell_restart;
718 /* vobu_start changes when PGC or PG changes. */ 535 this->position_current.cell_start = this->position_next.cell_start;
719 this->position_current.vobu_start = this->position_next.vobu_start; 536 this->position_current.block = this->position_next.block;
720 this->position_current.vobu_next = this->position_next.vobu_next; 537
721 /* FIXME: Need to set vobu_start, vobu_next */ 538 /* vobu info is used for mid cell resumes */
722 this->vobu.vobu_start = this->position_next.vobu_start; 539 this->vobu.vobu_start = this->position_next.cell_start + this->position_next.block;
723 /* vobu_next is use for mid cell resumes */ 540 this->vobu.vobu_next = 0;
724 this->vobu.vobu_next = this->position_next.vobu_next; 541 /* Make blockN > vobu_length to do expected_nav */
725 this->vobu.vobu_length = 0; 542 this->vobu.vobu_length = 0;
726 this->vobu.blockN = this->vobu.vobu_length + 1; 543 this->vobu.blockN = 1;
727 /* Make blockN > vobu_lenght to do expected_nav */ 544
728 (*event) = DVDNAV_CELL_CHANGE; 545 /* update the spu palette at least on PGC changes */
729 (*len) = 0; 546 this->spu_clut_changed = 1;
547 this->position_current.spu_channel = -1; /* Force an update */
548 this->position_current.audio_channel = -1; /* Force an update */
549
730 pthread_mutex_unlock(&this->vm_lock); 550 pthread_mutex_unlock(&this->vm_lock);
731 return S_OK; 551 return S_OK;
732 } 552 }
733 553
734 554 /* has the CLUT changed? */
735 if (this->vobu.blockN > this->vobu.vobu_length) { 555 if(this->spu_clut_changed) {
736 /* End of VOBU */ 556 (*event) = DVDNAV_SPU_CLUT_CHANGE;
737 557 #ifdef LOG_DEBUG
558 fprintf(MSG_OUT, "libdvdnav: SPU_CLUT_CHANGE\n");
559 #endif
560 (*len) = 16 * sizeof(uint32_t);
561 memcpy(*buf, &(state->pgc->palette), 16 * sizeof(uint32_t));
562 this->spu_clut_changed = 0;
563 pthread_mutex_unlock(&this->vm_lock);
564 return S_OK;
565 }
566
567 /* has the SPU channel changed? */
568 if(this->position_current.spu_channel != this->position_next.spu_channel) {
569 dvdnav_spu_stream_change_event_t stream_change;
570
571 (*event) = DVDNAV_SPU_STREAM_CHANGE;
572 #ifdef LOG_DEBUG
573 fprintf(MSG_OUT, "libdvdnav: SPU_STREAM_CHANGE\n");
574 #endif
575 (*len) = sizeof(dvdnav_spu_stream_change_event_t);
576 stream_change.physical_wide = vm_get_subp_active_stream(this->vm, 0);
577 stream_change.physical_letterbox = vm_get_subp_active_stream(this->vm, 1);
578 stream_change.physical_pan_scan = vm_get_subp_active_stream(this->vm, 2);
579 memcpy(*buf, &(stream_change), sizeof(dvdnav_spu_stream_change_event_t));
580 this->position_current.spu_channel = this->position_next.spu_channel;
581 #ifdef LOG_DEBUG
582 fprintf(MSG_OUT, "libdvdnav: SPU_STREAM_CHANGE stream_id_wide=%d\n",stream_change.physical_wide);
583 fprintf(MSG_OUT, "libdvdnav: SPU_STREAM_CHANGE stream_id_letterbox=%d\n",stream_change.physical_letterbox);
584 fprintf(MSG_OUT, "libdvdnav: SPU_STREAM_CHANGE stream_id_pan_scan=%d\n",stream_change.physical_pan_scan);
585 #endif
586 if (stream_change.physical_wide != -1 &&
587 stream_change.physical_letterbox != -1 &&
588 stream_change.physical_pan_scan != -1) {
589 #ifdef LOG_DEBUG
590 fprintf(MSG_OUT, "libdvdnav: SPU_STREAM_CHANGE returning S_OK\n");
591 #endif
592 pthread_mutex_unlock(&this->vm_lock);
593 return S_OK;
594 }
595 }
596
597 /* has the audio channel changed? */
598 if(this->position_current.audio_channel != this->position_next.audio_channel) {
599 dvdnav_audio_stream_change_event_t stream_change;
600
601 (*event) = DVDNAV_AUDIO_STREAM_CHANGE;
602 #ifdef LOG_DEBUG
603 fprintf(MSG_OUT, "libdvdnav: AUDIO_STREAM_CHANGE\n");
604 #endif
605 (*len) = sizeof(dvdnav_audio_stream_change_event_t);
606 stream_change.physical = vm_get_audio_active_stream( this->vm );
607 memcpy(*buf, &(stream_change), sizeof( dvdnav_audio_stream_change_event_t));
608 this->position_current.audio_channel = this->position_next.audio_channel;
609 #ifdef LOG_DEBUG
610 fprintf(MSG_OUT, "libdvdnav: AUDIO_STREAM_CHANGE stream_id=%d returning S_OK\n",stream_change.physical);
611 #endif
612 pthread_mutex_unlock(&this->vm_lock);
613 return S_OK;
614 }
615
616 /* Check the HIGHLIGHT flag */
617 if(this->position_current.button != this->position_next.button) {
618 dvdnav_highlight_event_t hevent;
619
620 (*event) = DVDNAV_HIGHLIGHT;
621 #ifdef LOG_DEBUG
622 fprintf(MSG_OUT, "libdvdnav: HIGHLIGHT\n");
623 #endif
624 (*len) = sizeof(hevent);
625 hevent.display = 1;
626 hevent.buttonN = this->position_next.button;
627 memcpy(*buf, &(hevent), sizeof(hevent));
628 this->position_current.button = this->position_next.button;
629 pthread_mutex_unlock(&this->vm_lock);
630 return S_OK;
631 }
632
633 /* Check the STILLFRAME flag */
634 if(this->position_current.still != 0) {
635 dvdnav_still_event_t still_event;
636
637 (*event) = DVDNAV_STILL_FRAME;
638 #ifdef LOG_DEBUG
639 fprintf(MSG_OUT, "libdvdnav: STILL_FRAME\n");
640 #endif
641 (*len) = sizeof(dvdnav_still_event_t);
642 still_event.length = this->position_current.still;
643 memcpy(*buf, &(still_event), sizeof(dvdnav_still_event_t));
644 pthread_mutex_unlock(&this->vm_lock);
645 return S_OK;
646 }
647
648 /* Have we reached the end of a VOBU? */
649 if (this->vobu.blockN >= this->vobu.vobu_length) {
650
651 /* Have we reached the end of a cell? */
738 if(this->vobu.vobu_next == SRI_END_OF_CELL) { 652 if(this->vobu.vobu_next == SRI_END_OF_CELL) {
739 /* End of Cell from NAV DSI info */ 653 /* End of Cell from NAV DSI info */
740 #ifdef LOG_DEBUG 654 #ifdef LOG_DEBUG
741 fprintf(MSG_OUT, "libdvdnav: Still set to %x\n", this->position_next.still); 655 fprintf(MSG_OUT, "libdvdnav: Still set to %x\n", this->position_next.still);
742 #endif 656 #endif
743 this->position_current.still = this->position_next.still; 657 this->position_current.still = this->position_next.still;
744 658
745 if( this->position_current.still == 0 || this->skip_still ) { 659 if( this->position_current.still == 0 || this->skip_still ) {
746 vm_get_next_cell(this->vm); 660 /* no active cell still -> get us to the next cell */
747 vm_position_get(this->vm,&this->position_next); 661 vm_get_next_cell(this->vm);
748 /* FIXME: Need to set vobu_start, vobu_next */ 662 this->position_current.still = 0; /* still gets activated at end of cell */
749 this->position_current.still = 0; /* still gets activated at end of cell */ 663 this->skip_still = 0;
750 this->skip_still = 0;
751 this->position_current.cell = this->position_next.cell;
752 this->position_current.vobu_start = this->position_next.vobu_start;
753 this->position_current.vobu_next = this->position_next.vobu_next;
754 this->vobu.vobu_start = this->position_next.vobu_start;
755 /* vobu_next is use for mid cell resumes */
756 this->vobu.vobu_next = this->position_next.vobu_next;
757 this->vobu.vobu_length = 0;
758 this->vobu.blockN = this->vobu.vobu_length + 1;
759 /* Make blockN > vobu_next to do expected_nav */
760 /* update the spu palette on PGC changes */
761 this->spu_clut_changed = 1;
762 this->position_current.spu_channel = -1; /* Force an update */
763 this->position_current.audio_channel = -1; /* Force an update */;
764 (*event) = DVDNAV_CELL_CHANGE;
765 (*len) = 0;
766 pthread_mutex_unlock(&this->vm_lock);
767 return S_OK;
768 } else {
769 dvdnav_still_event_t still_event;
770 still_event.length = this->position_current.still;
771 (*event) = DVDNAV_STILL_FRAME;
772 (*len) = sizeof(dvdnav_still_event_t);
773 memcpy(*buf, &(still_event), sizeof(dvdnav_still_event_t));
774 pthread_mutex_unlock(&this->vm_lock);
775 return S_OK;
776 } 664 }
777 665 /* handle related state changes in next iteration */
778 /* Only set still after whole VOBU has been output. */ 666 (*event) = DVDNAV_NOP;
779 /* 667 (*len) = 0;
780 if(this->position_next.still != 0) { 668 pthread_mutex_unlock(&this->vm_lock);
781 this->position_current.still = this->position_next.still; 669 return S_OK;
782 }
783 */
784
785 } 670 }
786 /* Perform the jump if necessary (this is always a 671
672 /* Perform remapping jump if necessary (this is always a
787 * VOBU boundary). */ 673 * VOBU boundary). */
788 674 if (this->vm->map) {
789 if (this->vm->map) { 675 this->vobu.vobu_next = remap_block( this->vm->map,
790 this->vobu.vobu_next = remap_block( this->vm->map, 676 this->vm->state.domain, this->vm->state.TTN_REG,
791 this->vm->state.domain, this->vm->state.TTN_REG, 677 this->vm->state.pgN,
792 this->vm->state.pgN, 678 this->vobu.vobu_start, this->vobu.vobu_next);
793 this->vobu.vobu_start, this->vobu.vobu_next); 679 }
794 } 680
795 681 /* at the start of the next VOBU -> expecting NAV packet */
796
797 /* result = DVDReadBlocks(this->file, this->vobu.vobu_start + this->vobu.vobu_next, 1, buf); */
798 result = dvdnav_read_cache_block(this->cache, this->vobu.vobu_start + this->vobu.vobu_next, 1, buf); 682 result = dvdnav_read_cache_block(this->cache, this->vobu.vobu_start + this->vobu.vobu_next, 1, buf);
799 683
800 if(result <= 0) { 684 if(result <= 0) {
801 printerr("Error reading NAV packet."); 685 printerr("Error reading NAV packet.");
802 pthread_mutex_unlock(&this->vm_lock); 686 pthread_mutex_unlock(&this->vm_lock);
803 return S_ERR; 687 return S_ERR;
804 } 688 }
805 /* Decode nav into pci and dsi. */ 689 /* Decode nav into pci and dsi. Then get next VOBU info. */
806 /* Then get next VOBU info. */ 690 if(!dvdnav_decode_packet(this, *buf, &this->dsi, &this->pci)) {
807 if(dvdnav_decode_packet(this, *buf, &this->dsi, &this->pci) == 0) {
808 printerr("Expected NAV packet but none found."); 691 printerr("Expected NAV packet but none found.");
809 pthread_mutex_unlock(&this->vm_lock); 692 pthread_mutex_unlock(&this->vm_lock);
810 return S_ERR; 693 return S_ERR;
811 } 694 }
812 dvdnav_get_vobu(this, &this->dsi,&this->pci, &this->vobu); 695 /* We need to update the vm state->blockN with which VOBU we are in.
813 this->vobu.blockN=1; 696 * This is so RSM resumes to the VOBU level and not just the CELL level.
814 /* FIXME: We need to update the vm state->blockN with which VOBU we are in.
815 * This is so RSM resumes to the VOBU level and not just the CELL level.
816 * This should be implemented with a new Public API call.
817 */ 697 */
818 /* We cache one past the end of the VOBU, 698 this->vm->state.blockN = this->vobu.vobu_start - this->position_current.cell_start;
819 * in the hope it might catch the next NAV packet as well. 699
820 * This reduces the amount of read commands sent to the DVD device. 700 dvdnav_get_vobu(this, &this->dsi, &this->pci, &this->vobu);
821 * A cache miss will only happen for 3 reasons. 701 this->vobu.blockN = 0;
822 * 1) Seeking 702 /* Give the cache a hint about the size of next VOBU.
823 * 2) Menu change 703 * This improves pre-caching, because the VOBU will almost certainly be read entirely.
824 * 3) The next VOBU does not immeadiately follow the current one. E.g. Multi Angles, ILVU.
825 */ 704 */
826 dvdnav_pre_cache_blocks(this->cache, this->vobu.vobu_start+1, this->vobu.vobu_length+1); 705 dvdnav_pre_cache_blocks(this->cache, this->vobu.vobu_start+1, this->vobu.vobu_length+1);
827 706
828 /* Successfully got a NAV packet */ 707 /* Successfully got a NAV packet */
829 (*event) = DVDNAV_NAV_PACKET; 708 (*event) = DVDNAV_NAV_PACKET;
709 #ifdef LOG_DEBUG
710 fprintf(MSG_OUT, "libdvdnav: NAV_PACKET\n");
711 #endif
830 (*len) = 2048; 712 (*len) = 2048;
831 pthread_mutex_unlock(&this->vm_lock); 713 pthread_mutex_unlock(&this->vm_lock);
832 return S_OK; 714 return S_OK;
833 } 715 }
834 716
835 /* If we've got here, it must just be a normal block. */ 717 /* If we've got here, it must just be a normal block. */
836 if(!this->file) { 718 if(!this->file) {
837 printerr("Attempting to read without opening file"); 719 printerr("Attempting to read without opening file.");
838 pthread_mutex_unlock(&this->vm_lock); 720 pthread_mutex_unlock(&this->vm_lock);
839 return S_ERR; 721 return S_ERR;
840 } 722 }
841 723
724 this->vobu.blockN++;
842 result = dvdnav_read_cache_block(this->cache, this->vobu.vobu_start + this->vobu.blockN, 1, buf); 725 result = dvdnav_read_cache_block(this->cache, this->vobu.vobu_start + this->vobu.blockN, 1, buf);
843 if(result <= 0) { 726 if(result <= 0) {
844 printerr("Error reading from DVD."); 727 printerr("Error reading from DVD.");
845 pthread_mutex_unlock(&this->vm_lock); 728 pthread_mutex_unlock(&this->vm_lock);
846 return S_ERR; 729 return S_ERR;
847 } 730 }
848 this->vobu.blockN++; 731 (*event) = DVDNAV_BLOCK_OK;
849 (*len) = 2048; 732 (*len) = 2048;
850 (*event) = DVDNAV_BLOCK_OK;
851 733
852 pthread_mutex_unlock(&this->vm_lock); 734 pthread_mutex_unlock(&this->vm_lock);
853 return S_OK; 735 return S_OK;
736 }
737
738 dvdnav_status_t dvdnav_get_title_string(dvdnav_t *this, const char **title_str) {
739
740 if(!this || !title_str) {
741 printerr("Passed a NULL pointer.");
742 return S_ERR;
743 }
744
745 (*title_str) = this->vm->dvd_name;
746 return S_OK;
747 }
748
749 uint8_t dvdnav_get_video_aspect(dvdnav_t *this) {
750 uint8_t retval;
751
752 if(!this)
753 return -1;
754
755 pthread_mutex_lock(&this->vm_lock);
756 retval = (uint8_t)vm_get_video_aspect(this->vm);
757 pthread_mutex_unlock(&this->vm_lock);
758
759 return retval;
760 }
761
762 uint8_t dvdnav_get_video_scale_permission(dvdnav_t *this) {
763 uint8_t retval;
764
765 if(!this)
766 return -1;
767
768 pthread_mutex_lock(&this->vm_lock);
769 retval = (uint8_t)vm_get_video_scale_permission(this->vm);
770 pthread_mutex_unlock(&this->vm_lock);
771
772 return retval;
854 } 773 }
855 774
856 uint16_t dvdnav_audio_stream_to_lang(dvdnav_t *this, uint8_t stream) { 775 uint16_t dvdnav_audio_stream_to_lang(dvdnav_t *this, uint8_t stream) {
857 audio_attr_t attr; 776 audio_attr_t attr;
858 777
867 return 0xffff; 786 return 0xffff;
868 787
869 return attr.lang_code; 788 return attr.lang_code;
870 } 789 }
871 790
872 int8_t dvdnav_get_audio_logical_stream(dvdnav_t *this, uint8_t audio_num) {
873 int8_t retval;
874
875 if(!this)
876 return -1;
877
878 pthread_mutex_lock(&this->vm_lock);
879 retval = NCLK_dvdnav_get_audio_logical_stream(this, audio_num);
880 pthread_mutex_unlock(&this->vm_lock);
881
882 return retval;
883 }
884
885 uint16_t dvdnav_spu_stream_to_lang(dvdnav_t *this, uint8_t stream) { 791 uint16_t dvdnav_spu_stream_to_lang(dvdnav_t *this, uint8_t stream) {
886 subp_attr_t attr; 792 subp_attr_t attr;
887 793
888 if(!this) 794 if(!this)
889 return -1; 795 return -1;
896 return 0xffff; 802 return 0xffff;
897 803
898 return attr.lang_code; 804 return attr.lang_code;
899 } 805 }
900 806
807 int8_t dvdnav_get_audio_logical_stream(dvdnav_t *this, uint8_t audio_num) {
808 int8_t retval;
809
810 if(!this)
811 return -1;
812
813 pthread_mutex_lock(&this->vm_lock);
814 if (!this->vm->state.pgc) {
815 pthread_mutex_unlock(&this->vm_lock);
816 return -1;
817 }
818 retval = vm_get_audio_stream(this->vm, audio_num);
819 pthread_mutex_unlock(&this->vm_lock);
820
821 return retval;
822 }
823
901 int8_t dvdnav_get_spu_logical_stream(dvdnav_t *this, uint8_t subp_num) { 824 int8_t dvdnav_get_spu_logical_stream(dvdnav_t *this, uint8_t subp_num) {
902 int8_t retval; 825 int8_t retval;
903 826
904 if(!this) 827 if(!this)
905 return -1; 828 return -1;
906 829
830 pthread_mutex_lock(&this->vm_lock);
831 if (!this->vm->state.pgc) {
832 pthread_mutex_unlock(&this->vm_lock);
833 return -1;
834 }
835 retval = vm_get_subp_stream(this->vm, subp_num, 0);
836 pthread_mutex_unlock(&this->vm_lock);
837
838 return retval;
839 }
840
841 int8_t dvdnav_get_active_audio_stream(dvdnav_t *this) {
842 int8_t retval;
843
844 if(!this)
845 return -1;
846
907 pthread_mutex_lock(&this->vm_lock); 847 pthread_mutex_lock(&this->vm_lock);
908 retval = NCLK_dvdnav_get_spu_logical_stream(this, subp_num); 848 if (!this->vm->state.pgc) {
849 pthread_mutex_unlock(&this->vm_lock);
850 return -1;
851 }
852 retval = vm_get_audio_active_stream(this->vm);
909 pthread_mutex_unlock(&this->vm_lock); 853 pthread_mutex_unlock(&this->vm_lock);
910 854
911 return retval; 855 return retval;
912 } 856 }
913 857
914 int8_t dvdnav_get_active_spu_stream(dvdnav_t *this) { 858 int8_t dvdnav_get_active_spu_stream(dvdnav_t *this) {
915 int8_t retval; 859 int8_t retval;
916 860
917 if(!this) 861 if(!this)
918 return -1; 862 return -1;
919 863
920 pthread_mutex_lock(&this->vm_lock); 864 pthread_mutex_lock(&this->vm_lock);
921 retval = NLCK_dvdnav_get_active_spu_stream(this); 865 if (!this->vm->state.pgc) {
866 pthread_mutex_unlock(&this->vm_lock);
867 return -1;
868 }
869 retval = vm_get_subp_active_stream(this->vm, 0);
922 pthread_mutex_unlock(&this->vm_lock); 870 pthread_mutex_unlock(&this->vm_lock);
871
872 return retval;
873 }
874
875 static int8_t dvdnav_is_domain(dvdnav_t *this, domain_t domain) {
876 int8_t retval;
877
878 if (!this || !this->started)
879 return -1;
880
881 pthread_mutex_lock(&this->vm_lock);
882 retval = (this->vm->state.domain == domain);
883 pthread_mutex_unlock(&this->vm_lock);
923 884
924 return retval; 885 return retval;
925 } 886 }
926 887
927 /* First Play domain. (Menu) */ 888 /* First Play domain. (Menu) */
928 int8_t dvdnav_is_domain_fp(dvdnav_t *this) { 889 int8_t dvdnav_is_domain_fp(dvdnav_t *this) {
929 return _dvdnav_is_domain(this, FP_DOMAIN); 890 return dvdnav_is_domain(this, FP_DOMAIN);
930 } 891 }
931 /* Video management Menu domain. (Menu) */ 892 /* Video management Menu domain. (Menu) */
932 int8_t dvdnav_is_domain_vmgm(dvdnav_t *this) { 893 int8_t dvdnav_is_domain_vmgm(dvdnav_t *this) {
933 return _dvdnav_is_domain(this, VMGM_DOMAIN); 894 return dvdnav_is_domain(this, VMGM_DOMAIN);
934 } 895 }
935 /* Video Title Menu domain (Menu) */ 896 /* Video Title Menu domain (Menu) */
936 int8_t dvdnav_is_domain_vtsm(dvdnav_t *this) { 897 int8_t dvdnav_is_domain_vtsm(dvdnav_t *this) {
937 return _dvdnav_is_domain(this, VTSM_DOMAIN); 898 return dvdnav_is_domain(this, VTSM_DOMAIN);
938 } 899 }
939 /* Video Title domain (playing movie). */ 900 /* Video Title domain (playing movie). */
940 int8_t dvdnav_is_domain_vts(dvdnav_t *this) { 901 int8_t dvdnav_is_domain_vts(dvdnav_t *this) {
941 return _dvdnav_is_domain(this, VTS_DOMAIN); 902 return dvdnav_is_domain(this, VTS_DOMAIN);
942 } 903 }
943 904
944 /* Generally delegate angle information handling to 905 /* Generally delegate angle information handling to VM */
945 * VM */
946 dvdnav_status_t dvdnav_angle_change(dvdnav_t *this, int angle) { 906 dvdnav_status_t dvdnav_angle_change(dvdnav_t *this, int angle) {
947 int num, current; 907 int num, current;
948 908
949 if(!this) { 909 if(!this) {
950 return S_ERR; 910 printerr("Passed a NULL pointer.");
951 } 911 return S_ERR;
952 912 }
953 if(dvdnav_get_angle_info(this, &current, &num) != S_OK) { 913
954 printerr("Error getting angle info"); 914 pthread_mutex_lock(&this->vm_lock);
955 return S_ERR; 915 vm_get_angle_info(this->vm, &current, &num);
956 }
957
958 /* Set angle SPRM if valid */ 916 /* Set angle SPRM if valid */
959 if((angle > 0) && (angle <= num)) { 917 if((angle > 0) && (angle <= num)) {
960 this->vm->state.AGL_REG = angle; 918 this->vm->state.AGL_REG = angle;
961 } else { 919 } else {
962 printerr("Passed an invalid angle number"); 920 printerr("Passed an invalid angle number.");
963 return S_ERR; 921 pthread_mutex_unlock(&this->vm_lock);
964 } 922 return S_ERR;
923 }
924 pthread_mutex_unlock(&this->vm_lock);
965 925
966 return S_OK; 926 return S_OK;
967 } 927 }
968 /* FIXME: change order of current_angle, number_of_angles */ 928
969 dvdnav_status_t dvdnav_get_angle_info(dvdnav_t *this, int* current_angle, 929 dvdnav_status_t dvdnav_get_angle_info(dvdnav_t *this, int *current_angle,
970 int *number_of_angles) { 930 int *number_of_angles) {
971 if(!this || !this->vm) { 931 if(!this || !current_angle || !number_of_angles) {
972 return S_ERR; 932 printerr("Passed a NULL pointer.");
973 } 933 return S_ERR;
974 934 }
975 if(!current_angle || !number_of_angles) { 935
976 printerr("Passed a NULL pointer"); 936 pthread_mutex_lock(&this->vm_lock);
977 return S_ERR; 937 vm_get_angle_info(this->vm, current_angle, number_of_angles);
978 } 938 pthread_mutex_unlock(&this->vm_lock);
979
980 vm_get_angle_info(this->vm, number_of_angles, current_angle);
981 939
982 return S_OK; 940 return S_OK;
983 } 941 }
984 942
985 dvdnav_status_t dvdnav_get_cell_info(dvdnav_t *this, int* current_angle,
986 int *number_of_angles) {
987 if(!this || !this->vm) {
988 return S_ERR;
989 }
990 *current_angle=this->position_next.cell;
991 return S_OK;
992 }
993
994 pci_t* dvdnav_get_current_nav_pci(dvdnav_t *this) { 943 pci_t* dvdnav_get_current_nav_pci(dvdnav_t *this) {
995 if(!this || !this->vm) return 0; 944 if(!this) return 0;
996 return &this->pci; 945 return &this->pci;
997 } 946 }
998 947
999 dsi_t* dvdnav_get_current_nav_dsi(dvdnav_t *this) { 948 dsi_t* dvdnav_get_current_nav_dsi(dvdnav_t *this) {
1000 if(!this || !this->vm) return 0; 949 if(!this) return 0;
1001 return &this->dsi; 950 return &this->dsi;
1002 } 951 }
1003 952
1004 uint32_t dvdnav_get_next_still_flag(dvdnav_t *this) { 953 uint32_t dvdnav_get_next_still_flag(dvdnav_t *this) {
1005 if(!this || !this->vm) { 954 if(!this) return -1;
1006 return S_ERR;
1007 }
1008 return this->position_next.still; 955 return this->position_next.still;
1009 } 956 }
1010 957
1011 /* 958 /*
1012 * $Log$ 959 * $Log$
960 * Revision 1.40 2003/02/20 15:32:15 mroi
961 * big libdvdnav cleanup, quoting the ChangeLog:
962 * * some bugfixes
963 * * code cleanup
964 * * build process polishing
965 * * more sensible event order in get_next_block to ensure useful event delivery
966 * * VOBU level resume
967 * * fixed: seeking in a multiangle feature briefly showed the wrong angle
968 *
1013 * Revision 1.39 2002/10/23 11:38:09 mroi 969 * Revision 1.39 2002/10/23 11:38:09 mroi
1014 * port Stephen's comment fixing to avoid problems when syncing xine-lib's copy of 970 * port Stephen's comment fixing to avoid problems when syncing xine-lib's copy of
1015 * libdvdnav 971 * libdvdnav
1016 * 972 *
1017 * Revision 1.38 2002/09/19 04:48:28 jcdutton 973 * Revision 1.38 2002/09/19 04:48:28 jcdutton