Diff of /src/dvdnav.c [267417] .. [52d456]  Maximize  Restore

Switch to unified view

a/src/dvdnav.c b/src/dvdnav.c
1
/*
1
/* 
2
 * Copyright (C) 2000 Rich Wareham <richwareham@users.sourceforge.net>
2
 * Copyright (C) 2000 Rich Wareham <richwareham@users.sourceforge.net>
3
 *
3
 * 
4
 * This file is part of libdvdnav, a DVD navigation library.
4
 * This file is part of libdvdnav, a DVD navigation library.
5
 *
5
 * 
6
 * libdvdnav is free software; you can redistribute it and/or modify
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
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
8
 * the Free Software Foundation; either version 2 of the License, or
9
 * (at your option) any later version.
9
 * (at your option) any later version.
10
 *
10
 * 
11
 * libdvdnav is distributed in the hope that it will be useful,
11
 * libdvdnav is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
14
 * GNU General Public License for more details.
15
 *
15
 * 
16
 * You should have received a copy of the GNU General Public License along
16
 * You should have received a copy of the GNU General Public License
17
 * with libdvdnav; if not, write to the Free Software Foundation, Inc.,
17
 * along with this program; if not, write to the Free Software
18
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
19
 *
20
 * $Id$
21
 *
19
 */
22
 */
20
23
21
#ifdef HAVE_CONFIG_H
24
#ifdef HAVE_CONFIG_H
22
#include "config.h"
25
#include "config.h"
23
#endif
26
#endif
24
27
25
/*
28
#include <pthread.h>
26
#define LOG_DEBUG
29
#include <dvdnav.h>
27
*/
30
#include "dvdnav_internal.h"
31
#include "read_cache.h"
28
32
29
#include <inttypes.h>
33
#include <dvdread/nav_read.h>
34
30
#include <stdlib.h>
35
#include <stdlib.h>
31
#include <stdio.h>
36
#include <stdio.h>
32
#include <unistd.h>
33
#include <limits.h>
34
#include <string.h>
35
#include <sys/time.h>
36
#include "dvdnav/dvdnav.h"
37
#include <dvdread/dvd_reader.h>
38
#include <dvdread/nav_types.h>
39
#include <dvdread/ifo_types.h> /* For vm_cmd_t */
40
#include "remap.h"
41
#include "vm/decoder.h"
42
#include "vm/vm.h"
43
#include "dvdnav_internal.h"
44
#include "read_cache.h"
45
#include <dvdread/nav_read.h>
46
#include "remap.h"
47
37
48
static dvdnav_status_t dvdnav_clear(dvdnav_t * this) {
49
  /* clear everything except file, vm, mutex, readahead */
50
51
  pthread_mutex_lock(&this->vm_lock);
52
  if (this->file) DVDCloseFile(this->file);
53
  this->file = NULL;
54
55
  memset(&this->pci,0,sizeof(this->pci));
56
  memset(&this->dsi,0,sizeof(this->dsi));
57
  this->last_cmd_nav_lbn = SRI_END_OF_CELL;
58
59
  /* Set initial values of flags */
60
  this->position_current.still = 0;
61
  this->skip_still = 0;
62
  this->sync_wait = 0;
63
  this->sync_wait_skip = 0;
64
  this->spu_clut_changed = 0;
65
  this->started = 0;
66
  this->cur_cell_time = 0;
67
68
  dvdnav_read_cache_clear(this->cache);
69
  pthread_mutex_unlock(&this->vm_lock);
70
71
  return DVDNAV_STATUS_OK;
72
}
73
74
dvdnav_status_t dvdnav_open(dvdnav_t** dest, const char *path) {
38
dvdnav_status_t dvdnav_open(dvdnav_t** dest, char *path) {
75
  dvdnav_t *this;
39
  dvdnav_t *self;
76
  struct timeval time;
40
  
77
78
  /* Create a new structure */
41
  /* Create a new structure */
79
  fprintf(MSG_OUT, "libdvdnav: Using dvdnav version %s\n", VERSION);
80
81
  (*dest) = NULL;
42
  (*dest) = NULL;
82
  this = (dvdnav_t*)malloc(sizeof(dvdnav_t));
43
  self = (dvdnav_t*)malloc(sizeof(dvdnav_t));
83
  if(!this)
44
  if(!self)
84
    return DVDNAV_STATUS_ERR;
45
   return S_ERR;
85
  memset(this, 0, (sizeof(dvdnav_t) ) ); /* Make sure this structure is clean */
46
  memset(self, 0, (sizeof(dvdnav_t) ) ); /* Make sure self structure is clean */
86
47
87
  pthread_mutex_init(&this->vm_lock, NULL);
48
  pthread_mutex_init(&self->vm_lock, NULL);
88
  /* Initialise the error string */
49
  /* Initialise the error string */
89
  printerr("");
50
  printerr("");
90
51
91
  /* Initialise the VM */
52
  /* Initialise the VM */
92
  this->vm = vm_new_vm();
53
  self->vm = vm_new_vm();
93
  if(!this->vm) {
54
  if(!self->vm) {
94
    printerr("Error initialising the DVD VM.");
55
    printerr("Error initialising the DVD VM");
95
    pthread_mutex_destroy(&this->vm_lock);
96
    free(this);
97
    return DVDNAV_STATUS_ERR;
56
    return S_ERR;
98
  }
57
  }
99
  if(!vm_reset(this->vm, path)) {
58
  if(vm_reset(self->vm, path) == -1) {
100
    printerr("Error starting the VM / opening the DVD device.");
59
    printerr("Error starting the VM / opening the DVD device");
101
    pthread_mutex_destroy(&this->vm_lock);
102
    vm_free_vm(this->vm);
103
    free(this);
104
    return DVDNAV_STATUS_ERR;
60
    return S_ERR;
105
  }
61
  }
106
62
107
  /* Set the path. FIXME: Is a deep copy 'right' */
63
  /* Set the path. FIXME: Is a deep copy 'right' */
108
  strncpy(this->path, path, MAX_PATH_LEN - 1);
64
  strncpy(self->path, path, MAX_PATH_LEN);
109
  this->path[MAX_PATH_LEN - 1] = '\0';
110
65
66
  /* Set initial values of flags */
67
  self->expecting_nav_packet = 1;
68
  self->started = 0;
69
  
70
  self->open_vtsN = -1;
71
  self->open_domain = -1;
72
  self->file = NULL;
73
  self->cell = NULL;
74
  self->at_soc = 1;
75
  self->jumping = 0;
76
  self->seeking = 0;
77
  self->still_frame = -1;
78
  self->cache_buffer = NULL;
79
  self->cache_start_sector = -1;
80
  self->cache_block_count = 0;
81
  self->cache_valid = 0;
82
  self->use_read_ahead = 1;
83
  self->stop = 0;
84
  self->highlight_changed = 0;
85
  self->spu_clut_changed = 0;
86
87
  self->vobu_start = self->vobu_length = 0;
88
 
111
  /* Pre-open and close a file so that the CSS-keys are cached. */
89
  /* Pre-open and close a file so that the CSS-keys are cached. */
112
  this->file = DVDOpenFile(vm_get_dvd_reader(this->vm), 0, DVD_READ_MENU_VOBS);
90
  self->file = DVDOpenFile(vm_get_dvd_reader(self->vm), 0, DVD_READ_MENU_VOBS);
91
  if (self->file) DVDCloseFile(self->file);
92
  self->file = NULL;
93
    
94
  if(!self->started) {
95
    /* Start the VM */
96
    vm_start(self->vm);
97
    self->started = 1;
98
  }
113
99
114
  /* Start the read-ahead cache. */
115
  this->cache = dvdnav_read_cache_new(this);
116
117
  /* Seed the random numbers. So that the DVD VM Command rand()
118
   * gives a different start value each time a DVD is played. */
119
  gettimeofday(&time, NULL);
120
  srand(time.tv_usec);
121
122
  dvdnav_clear(this);
123
124
  (*dest) = this;
100
  (*dest) = self;
125
  return DVDNAV_STATUS_OK;
101
  return S_OK;
126
}
102
}
127
103
128
dvdnav_status_t dvdnav_close(dvdnav_t *this) {
104
dvdnav_status_t dvdnav_close(dvdnav_t *self) {
129
105
  if(!self) {
130
#ifdef LOG_DEBUG
106
    printerr("Passed a NULL pointer");
107
    return S_ERR;
108
  }
131
  fprintf(MSG_OUT, "libdvdnav: close:called\n");
109
  printf("dvdnav:close:called\n");
132
#endif
133
134
  if (this->file) {
110
  if (self->file) {
135
    pthread_mutex_lock(&this->vm_lock);
136
    DVDCloseFile(this->file);
111
    DVDCloseFile(self->file);
137
#ifdef LOG_DEBUG
138
    fprintf(MSG_OUT, "libdvdnav: close:file closing\n");
112
    printf("dvdnav:close:file closing\n");
139
#endif
140
    this->file = NULL;
113
    self->file = NULL;
141
    pthread_mutex_unlock(&this->vm_lock);
142
  }
114
  }
143
115
144
  /* Free the VM */
116
  /* Free the VM */
145
  if(this->vm)
117
  if(self->vm) {
146
    vm_free_vm(this->vm);
118
    vm_free_vm(self->vm);
147
119
  }
120
  if (self->file) {
121
    DVDCloseFile(self->file);
122
    printf("dvdnav:close2:file closing\n");
123
    self->file = NULL;
124
  }
148
  pthread_mutex_destroy(&this->vm_lock);
125
  pthread_mutex_destroy(&self->vm_lock);
149
126
  /* Finally free the entire structure */
150
  /* We leave the final freeing of the entire structure to the cache,
127
  free(self);
151
   * because we don't know, if there are still buffers out in the wild,
152
   * that must return first. */
153
  if(this->cache)
154
    dvdnav_read_cache_free(this->cache);
155
  else
156
    free(this);
157
158
  return DVDNAV_STATUS_OK;
159
}
160
161
dvdnav_status_t dvdnav_reset(dvdnav_t *this) {
162
  dvdnav_status_t result;
163
164
#ifdef LOG_DEBUG
165
  fprintf(MSG_OUT, "libdvdnav: reset:called\n");
166
#endif
167
168
  pthread_mutex_lock(&this->vm_lock);
169
170
#ifdef LOG_DEBUG
171
  fprintf(MSG_OUT, "libdvdnav: reseting vm\n");
172
#endif
173
  if(!vm_reset(this->vm, NULL)) {
174
    printerr("Error restarting the VM.");
175
    pthread_mutex_unlock(&this->vm_lock);
176
    return DVDNAV_STATUS_ERR;
177
  }
128
  
178
#ifdef LOG_DEBUG
129
  return S_OK;
179
  fprintf(MSG_OUT, "libdvdnav: clearing dvdnav\n");
180
#endif
181
  result = dvdnav_clear(this);
182
183
  pthread_mutex_unlock(&this->vm_lock);
184
  return result;
185
}
130
}
186
131
187
dvdnav_status_t dvdnav_path(dvdnav_t *this, const char** path) {
132
dvdnav_status_t dvdnav_path(dvdnav_t *self, char** path) {
133
  if(!self || !path || !(*path)) {
134
    return S_ERR;
135
  }
136
137
  /* FIXME: Is shallow copy 'right'? */
188
  (*path) = this->path;
138
  (*path) = self->path;
189
139
190
  return DVDNAV_STATUS_OK;
140
  return S_OK;
191
}
141
}
192
142
193
const char* dvdnav_err_to_string(dvdnav_t *this) {
143
char* dvdnav_err_to_string(dvdnav_t *self) {
194
144
  if(!self) {
195
  if(!this)
145
    /* Shold this be "passed a NULL pointer?" */
196
    return "Hey! You gave me a NULL pointer you naughty person!";
146
    return NULL;
197
147
  }
148
  
198
  return this->err_str;
149
  return self->err_str;
199
}
150
}
200
151
201
/* converts a dvd_time_t to PTS ticks */
202
int64_t dvdnav_convert_time(dvd_time_t *time) {
203
  int64_t result;
204
  int64_t frames;
205
206
  result  = (time->hour    >> 4  ) * 10 * 60 * 60 * 90000;
207
  result += (time->hour    & 0x0f)      * 60 * 60 * 90000;
208
  result += (time->minute  >> 4  )      * 10 * 60 * 90000;
209
  result += (time->minute  & 0x0f)           * 60 * 90000;
210
  result += (time->second  >> 4  )           * 10 * 90000;
211
  result += (time->second  & 0x0f)                * 90000;
212
213
  frames  = ((time->frame_u & 0x30) >> 4) * 10;
214
  frames += ((time->frame_u & 0x0f)     )     ;
215
216
  if (time->frame_u & 0x80)
217
    result += frames * 3000;
218
  else
219
    result += frames * 3600;
220
221
  return result;
222
}
223
224
/*
152
/**
225
 * Returns 1 if block contains NAV packet, 0 otherwise.
153
 * Returns 1 if block contains NAV packet, 0 otherwise.
226
 * Processes said NAV packet if present.
154
 * Precesses said NAV packet if present.
227
 *
155
 *
228
 * Most of the code in here is copied from xine's MPEG demuxer
156
 * Most of the code in here is copied from xine's MPEG demuxer
229
 * so any bugs which are found in that should be corrected here also.
157
 * so any bugs which are found in that should be corrected here also.
230
 */
158
 */
231
static int32_t dvdnav_decode_packet(dvdnav_t *this, uint8_t *p, dsi_t *nav_dsi, pci_t *nav_pci) {
159
int dvdnav_check_packet(dvdnav_t *self, uint8_t *p) {
232
  int32_t        bMpeg1 = 0;
160
  int            bMpeg1=0;
233
  uint32_t       nHeaderLen;
161
  uint32_t       nHeaderLen;
234
  uint32_t       nPacketLen;
162
  uint32_t       nPacketLen;
235
  uint32_t       nStreamID;
163
  uint32_t       nStreamID;
164
/* uint8_t       *p_start=p; */
165
166
167
  if (p==NULL) {
168
    printf("Passed a NULL pointer.\n");
169
    return 0;
170
  }
171
172
  /* dprint("Checking packet...\n"); */
236
173
237
  if (p[3] == 0xBA) { /* program stream pack header */
174
  if (p[3] == 0xBA) { /* program stream pack header */
175
238
    int32_t nStuffingBytes;
176
    int nStuffingBytes;
177
178
    /* xprintf (VERBOSE|DEMUX, "program stream pack header\n"); */
239
179
240
    bMpeg1 = (p[4] & 0x40) == 0;
180
    bMpeg1 = (p[4] & 0x40) == 0;
241
181
242
    if (bMpeg1) {
182
    if (bMpeg1) {
243
      p += 12;
183
      p   += 12;
244
    } else { /* mpeg2 */
184
    } else { /* mpeg2 */
245
      nStuffingBytes = p[0xD] & 0x07;
185
      nStuffingBytes = p[0xD] & 0x07;
246
      p += 14 + nStuffingBytes;
186
      p += 14 + nStuffingBytes;
247
    }
187
    }
248
  }
188
  }
249
189
190
250
  if (p[3] == 0xbb) { /* program stream system header */
191
  if (p[3] == 0xbb) { /* program stream system header */
192
    int nHeaderLen;
193
251
    nHeaderLen = (p[4] << 8) | p[5];
194
    nHeaderLen = (p[4] << 8) | p[5];
252
    p += 6 + nHeaderLen;
195
    p += 6 + nHeaderLen;
253
  }
196
  }
254
197
255
  /* we should now have a PES packet here */
198
  /* we should now have a PES packet here */
199
256
  if (p[0] || p[1] || (p[2] != 1)) {
200
  if (p[0] || p[1] || (p[2] != 1)) {
257
    fprintf(MSG_OUT, "libdvdnav: demux error! %02x %02x %02x (should be 0x000001) \n",p[0],p[1],p[2]);
201
    printf("demux error! %02x %02x %02x (should be 0x000001) \n",p[0],p[1],p[2]);
258
    return 0;
202
    return 0;
259
  }
203
  }
260
204
261
  nPacketLen = p[4] << 8 | p[5];
205
  nPacketLen = p[4] << 8 | p[5];
262
  nStreamID  = p[3];
206
  nStreamID  = p[3];
263
207
264
  nHeaderLen = 6;
208
  nHeaderLen = 6;
265
  p += nHeaderLen;
209
  p += nHeaderLen;
266
210
267
  if (nStreamID == 0xbf) { /* Private stream 2 */
211
  if (nStreamID == 0xbf) { /* Private stream 2 */
268
#if 0
212
/*
269
    int32_t i;
213
 *   int i;
270
    fprintf(MSG_OUT, "libdvdnav: nav packet=%u\n",p-p_start-6);
214
 *    printf("dvdnav:nav packet=%u\n",p-p_start-6);
271
    for(i=0;i<80;i++)
215
 *   for(i=0;i<80;i++) {
272
      fprintf(MSG_OUT, "%02x ",p[i-6]);
216
 *     printf("%02x ",p[i-6]);
273
    fprintf(MSG_OUT, "\n");
217
 *   }
218
 *   printf("\n");
219
 */
220
    if(p[0] == 0x00) {
221
#ifdef HAVE_DVDREAD9
222
      navRead_PCI(&(self->pci), p+1);
223
#else
224
      navRead_PCI(&(self->pci), p+1, nPacketLen - 1);
274
#endif
225
#endif
275
276
    if(p[0] == 0x00) {
277
      navRead_PCI(nav_pci, p+1);
278
    }
226
    }
279
227
280
    p += nPacketLen;
228
    p += nPacketLen;
281
229
282
    /* We should now have a DSI packet. */
230
    /* We should now have a DSI packet. */
283
    if(p[6] == 0x01) {
231
    if(p[6] == 0x01) {
232
      int num=0, current=0;
233
284
      nPacketLen = p[4] << 8 | p[5];
234
      nPacketLen = p[4] << 8 | p[5];
285
      p += 6;
235
      p += 6;
236
      /* dprint("NAV DSI packet\n");  */
237
#ifdef HAVE_DVDREAD9
286
      navRead_DSI(nav_dsi, p+1);
238
      navRead_DSI(&(self->dsi), p+1);
239
#else
240
      navRead_DSI(&(self->dsi), p+1, sizeof(dsi_t));
241
#endif
242
243
      self->vobu_start = self->dsi.dsi_gi.nv_pck_lbn;
244
      self->vobu_length = self->dsi.dsi_gi.vobu_ea;
245
      
246
      /**
247
       * If we're not at the end of this cell, we can determine the next
248
       * VOBU to display using the VOBU_SRI information section of the
249
       * DSI.  Using this value correctly follows the current angle,
250
       * avoiding the doubled scenes in The Matrix, and makes our life
251
       * really happy.
252
       *
253
       * Otherwise, we set our next address past the end of this cell to
254
       * force the code above to go to the next cell in the program.
255
       */
256
      if( self->dsi.vobu_sri.next_vobu != SRI_END_OF_CELL ) {
257
  self->next_vobu = self->dsi.dsi_gi.nv_pck_lbn 
258
           + ( self->dsi.vobu_sri.next_vobu & 0x7fffffff );
259
      } else {
260
        self->next_vobu = self->vobu_start + self->vobu_length;
261
      }
262
      
263
      dvdnav_get_angle_info(self, &current, &num);
264
      if(num == 1) {
265
  /* This is to switch back to angle one when we
266
   * finish */
267
  dvdnav_angle_change(self, 1);
268
      }
269
      
270
      if(num != 0) {
271
  uint32_t next = self->pci.nsml_agli.nsml_agl_dsta[current-1];
272
273
          if(next != 0) {
274
    int dir = 0;
275
    if(next & 0x80000000) {
276
      dir = -1;
277
      next = next & 0x3fffffff;
278
    } else {
279
      dir = 1;
280
    }
281
282
    if(next != 0) {
283
      self->next_vobu = self->vobu_start + dir * next;
284
    }
285
  } else if( self->dsi.sml_agli.data[current-1].address != 0 ) {
286
    next = self->dsi.sml_agli.data[current-1].address;
287
    self->vobu_length = self->dsi.sml_pbi.ilvu_ea;
288
289
    if((next & 0x80000000) && (next != 0x7fffffff)) {
290
      self->next_vobu = self->dsi.dsi_gi.nv_pck_lbn - (next & 0x7fffffff);
291
    } else {
292
      self->next_vobu = self->dsi.dsi_gi.nv_pck_lbn + next;
293
    }
294
  }
295
      }
287
    }
296
    }
288
    return 1;
297
    return 1;
289
  }
298
  }
299
290
  return 0;
300
  return 0;
291
}
301
}
292
302
293
/* DSI is used for most angle stuff.
294
 * PCI is used for only non-seemless angle stuff
295
 */
296
static int32_t dvdnav_get_vobu(dvdnav_t *this, dsi_t *nav_dsi, pci_t *nav_pci, dvdnav_vobu_t *vobu) {
297
  uint32_t next;
298
  int32_t angle, num_angle;
299
300
  vobu->vobu_start = nav_dsi->dsi_gi.nv_pck_lbn; /* Absolute offset from start of disk */
301
  vobu->vobu_length = nav_dsi->dsi_gi.vobu_ea; /* Relative offset from vobu_start */
302
303
  /*
304
   * If we're not at the end of this cell, we can determine the next
305
   * VOBU to display using the VOBU_SRI information section of the
306
   * DSI.  Using this value correctly follows the current angle,
307
   * avoiding the doubled scenes in The Matrix, and makes our life
308
   * really happy.
309
   *
310
   * vobu_next is an offset value, 0x3fffffff = SRI_END_OF_CELL
311
   * DVDs are about 6 Gigs, which is only up to 0x300000 blocks
312
   * Should really assert if bit 31 != 1
313
   */
314
315
#if 0
316
  /* Old code -- may still be useful one day */
317
  if(nav_dsi->vobu_sri.next_vobu != SRI_END_OF_CELL ) {
318
    vobu->vobu_next = ( nav_dsi->vobu_sri.next_vobu & 0x3fffffff );
319
  } else {
320
    vobu->vobu_next = vobu->vobu_length;
321
  }
322
#else
323
  /* Relative offset from vobu_start */
324
  vobu->vobu_next = ( nav_dsi->vobu_sri.next_vobu & 0x3fffffff );
325
#endif
326
327
  vm_get_angle_info(this->vm, &angle, &num_angle);
328
329
  /* FIMXE: The angle reset doesn't work for some reason for the moment */
330
#if 0
331
  if((num_angle < angle) && (angle != 1)) {
332
    fprintf(MSG_OUT, "libdvdnav: angle ends!\n");
333
334
    /* This is to switch back to angle one when we
335
     * finish with angles. */
336
    dvdnav_angle_change(this, 1);
337
  }
338
#endif
339
340
  if(num_angle != 0) {
341
342
    if((next = nav_pci->nsml_agli.nsml_agl_dsta[angle-1]) != 0) {
343
      if((next & 0x3fffffff) != 0) {
344
  if(next & 0x80000000)
345
    vobu->vobu_next = - (int32_t)(next & 0x3fffffff);
346
  else
347
    vobu->vobu_next = + (int32_t)(next & 0x3fffffff);
348
      }
349
    } else if((next = nav_dsi->sml_agli.data[angle-1].address) != 0) {
350
      vobu->vobu_length = nav_dsi->sml_pbi.ilvu_ea;
351
352
      if((next & 0x80000000) && (next != 0x7fffffff))
353
  vobu->vobu_next =  - (int32_t)(next & 0x3fffffff);
354
      else
355
  vobu->vobu_next =  + (int32_t)(next & 0x3fffffff);
356
    }
357
  }
358
359
  return 1;
360
}
361
362
/*
363
 * These are the main get_next_block function which actually get the media stream video and audio etc.
364
 *
365
 * There are two versions: The second one is using the zero-copy read ahead cache and therefore
366
 * hands out pointers targetting directly into the cache.
367
 * The first one uses a memcopy to fill this cache block into the application provided memory.
368
 * The benefit of this first one is that no special memory management is needed. The application is
369
 * the only one responsible of allocating and freeing the memory associated with the pointer.
370
 * The drawback is the additional memcopy.
371
 */
372
373
dvdnav_status_t dvdnav_get_next_block(dvdnav_t *this, uint8_t *buf,
303
dvdnav_status_t dvdnav_get_next_block(dvdnav_t *self, unsigned char *buf,
374
                      int32_t *event, int32_t *len) {
304
                       int *event, int *len) {
375
  unsigned char *block;
376
  dvdnav_status_t status;
377
378
  block = buf;
379
  status = dvdnav_get_next_cache_block(this, &block, event, len);
380
  if (status == DVDNAV_STATUS_OK && block != buf) {
381
    /* we received a block from the cache, copy it, so we can give it back */
382
    memcpy(buf, block, DVD_VIDEO_LB_LEN);
383
    dvdnav_free_cache_block(this, block);
384
  }
385
  return status;
386
}
387
388
int64_t dvdnav_get_current_time(dvdnav_t *this) {
389
  int i;
390
  int64_t tm=0;
391
  dvd_state_t *state = &this->vm->state;
392
393
  for(i=0; i<state->cellN-1; i++) {
394
    if(!
395
        (state->pgc->cell_playback[i].block_type == BLOCK_TYPE_ANGLE_BLOCK &&
396
         state->pgc->cell_playback[i].block_mode != BLOCK_MODE_FIRST_CELL)
397
    )
398
      tm += dvdnav_convert_time(&state->pgc->cell_playback[i].playback_time);
399
  }
400
  tm += this->cur_cell_time;
401
402
  return tm;
403
}
404
405
dvdnav_status_t dvdnav_get_next_cache_block(dvdnav_t *this, uint8_t **buf,
406
                      int32_t *event, int32_t *len) {
407
  dvd_state_t *state;
305
  dvd_state_t *state;
408
  int32_t result;
306
  int result;
409
307
  if(!self || !event || !len || !buf) {
308
    printerr("Passed a NULL pointer");
309
    return S_ERR;
310
  }
410
  pthread_mutex_lock(&this->vm_lock);
311
  pthread_mutex_lock(&self->vm_lock); 
411
312
  
412
  if(!this->started) {
313
  if(!self->started) {
413
    /* Start the VM */
314
    /* Start the VM */
414
    if (!vm_start(this->vm)) {
315
    vm_start(self->vm);
415
      printerr("Encrypted or faulty DVD");
416
      pthread_mutex_unlock(&this->vm_lock);
417
      return DVDNAV_STATUS_ERR;
418
    }
419
    this->started = 1;
316
    self->started = 1;
420
  }
317
  }
421
318
422
  state = &(this->vm->state);
319
  state = &(self->vm->state);
423
  (*event) = DVDNAV_NOP;
320
  (*event) = DVDNAV_NOP;
424
  (*len) = 0;
321
  (*len) = 0;
425
322
 
426
  /* Check the STOP flag */
323
  /* Check the STOP flag */
427
  if(this->vm->stopped) {
324
  if(self->stop) {
428
    vm_stop(this->vm);
429
    (*event) = DVDNAV_STOP;
325
    (*event) = DVDNAV_STOP;
430
    this->started = 0;
431
    pthread_mutex_unlock(&this->vm_lock);
326
    pthread_mutex_unlock(&self->vm_lock); 
432
    return DVDNAV_STATUS_OK;
327
    return S_OK;
433
  }
328
  }
434
329
435
  vm_position_get(this->vm, &this->position_next);
330
  if(self->spu_clut_changed) {
436
437
#ifdef LOG_DEBUG
438
  fprintf(MSG_OUT, "libdvdnav: POS-NEXT ");
439
  vm_position_print(this->vm, &this->position_next);
440
  fprintf(MSG_OUT, "libdvdnav: POS-CUR  ");
441
  vm_position_print(this->vm, &this->position_current);
442
#endif
443
444
  /* did we hop? */
445
  if(this->position_current.hop_channel != this->position_next.hop_channel) {
446
    (*event) = DVDNAV_HOP_CHANNEL;
331
    (*event) = DVDNAV_SPU_CLUT_CHANGE;
447
#ifdef LOG_DEBUG
448
    fprintf(MSG_OUT, "libdvdnav: HOP_CHANNEL\n");
332
    printf("libdvdnav:SPU_CLUT_CHANGE\n");
449
#endif
333
    (*len) = sizeof(dvdnav_still_event_t);
450
    if (this->position_next.hop_channel - this->position_current.hop_channel >= HOP_SEEK) {
334
    memcpy(buf, &(state->pgc->palette), 16 * sizeof(uint32_t));
451
      int32_t num_angles = 0, current;
335
    self->spu_clut_changed = 0;
452
336
    printf("libdvdnav:SPU_CLUT_CHANGE returning S_OK\n");
453
      /* we seeked -> check for multiple angles */
454
      vm_get_angle_info(this->vm, &current, &num_angles);
455
      if (num_angles > 1) {
456
        int32_t result, block;
457
  /* we have to skip the first VOBU when seeking in a multiangle feature,
458
   * because it might belong to the wrong angle */
459
  block = this->position_next.cell_start + this->position_next.block;
460
  result = dvdnav_read_cache_block(this->cache, block, 1, buf);
461
  if(result <= 0) {
462
    printerr("Error reading NAV packet.");
463
    pthread_mutex_unlock(&this->vm_lock);
464
    return DVDNAV_STATUS_ERR;
465
  }
466
  /* Decode nav into pci and dsi. Then get next VOBU info. */
467
  if(!dvdnav_decode_packet(this, *buf, &this->dsi, &this->pci)) {
468
    printerr("Expected NAV packet but none found.");
469
    pthread_mutex_unlock(&this->vm_lock);
470
    return DVDNAV_STATUS_ERR;
471
  }
472
  dvdnav_get_vobu(this, &this->dsi, &this->pci, &this->vobu);
473
  /* skip to next, if there is a next */
474
  if (this->vobu.vobu_next != SRI_END_OF_CELL) {
475
    this->vobu.vobu_start += this->vobu.vobu_next;
476
    this->vobu.vobu_next   = 0;
477
  }
478
  /* update VM state */
479
  this->vm->state.blockN = this->vobu.vobu_start - this->position_next.cell_start;
480
      }
481
    }
482
    this->position_current.hop_channel = this->position_next.hop_channel;
483
    /* update VOBU info */
484
    this->vobu.vobu_start  = this->position_next.cell_start + this->position_next.block;
485
    this->vobu.vobu_next   = 0;
486
    /* Make blockN == vobu_length to do expected_nav */
487
    this->vobu.vobu_length = 0;
488
    this->vobu.blockN      = 0;
489
    this->sync_wait        = 0;
490
    pthread_mutex_unlock(&this->vm_lock);
337
    pthread_mutex_unlock(&self->vm_lock); 
491
    return DVDNAV_STATUS_OK;
338
    return S_OK;
339
  }
492
  }
340
  
493
341
  if(self->spu_stream_changed) {
342
    dvdnav_stream_change_event_t stream_change;
343
    (*event) = DVDNAV_SPU_STREAM_CHANGE;
344
    printf("libdvdnav:SPU_STREAM_CHANGE\n");
345
    (*len) = sizeof(dvdnav_stream_change_event_t);
346
    stream_change.physical= vm_get_subp_active_stream( self->vm );
347
    memcpy(buf, &(stream_change), sizeof( dvdnav_stream_change_event_t));
348
    self->spu_stream_changed = 0;
349
    printf("libdvdnav:SPU_STREAM_CHANGE stream_id=%d returning S_OK\n",stream_change.physical);
350
    pthread_mutex_unlock(&self->vm_lock); 
351
    return S_OK;
352
  }
353
  
354
  if(self->audio_stream_changed) {
355
    dvdnav_stream_change_event_t stream_change;
356
    (*event) = DVDNAV_AUDIO_STREAM_CHANGE;
357
    printf("libdvdnav:AUDIO_STREAM_CHANGE\n");
358
    (*len) = sizeof(dvdnav_stream_change_event_t);
359
    stream_change.physical= vm_get_audio_active_stream( self->vm );
360
    memcpy(buf, &(stream_change), sizeof( dvdnav_stream_change_event_t));
361
    self->audio_stream_changed = 0;
362
    printf("libdvdnav:AUDIO_STREAM_CHANGE stream_id=%d returning S_OK\n",stream_change.physical);
363
    pthread_mutex_unlock(&self->vm_lock); 
364
    return S_OK;
365
  }
366
     
494
  /* Check the HIGHLIGHT flag */
367
  /* Check the HIGHLIGHT flag */
495
  if(this->position_current.button != this->position_next.button) {
368
  if(self->highlight_changed) {
496
    dvdnav_highlight_event_t *hevent = (dvdnav_highlight_event_t *)*buf;
369
    dvdnav_highlight_event_t hevent;
370
   
371
    /* Fill in highlight struct with appropriate values */
372
    if(self->hli_state != 0) {
373
      hevent.display = 1;
497
374
375
      /* Copy current button bounding box. */
376
      hevent.sx = self->hli_bbox[0];
377
      hevent.sy = self->hli_bbox[1];
378
      hevent.ex = self->hli_bbox[2];
379
      hevent.ey = self->hli_bbox[3];
380
381
      hevent.palette = self->hli_clut;
382
      hevent.pts = self->hli_pts;
383
      hevent.buttonN = self->hli_buttonN;
384
385
    } else {
386
      hevent.display = 0;
387
    }
388
    
498
    (*event) = DVDNAV_HIGHLIGHT;
389
    (*event) = DVDNAV_HIGHLIGHT;
499
#ifdef LOG_DEBUG
390
    memcpy(buf, &(hevent), sizeof(hevent));
500
    fprintf(MSG_OUT, "libdvdnav: HIGHLIGHT\n");
501
#endif
502
    (*len) = sizeof(dvdnav_highlight_event_t);
391
    (*len) = sizeof(hevent);
503
    hevent->display = 1;
392
    
504
    hevent->buttonN = this->position_next.button;
393
    self->highlight_changed = 0;
505
    this->position_current.button = this->position_next.button;
394
    
506
    pthread_mutex_unlock(&this->vm_lock);
395
    pthread_mutex_unlock(&self->vm_lock); 
507
    return DVDNAV_STATUS_OK;
396
    return S_OK;
508
  }
397
  }
509
398
510
  /* Check the WAIT flag */
511
  if(this->sync_wait) {
512
    (*event) = DVDNAV_WAIT;
513
#ifdef LOG_DEBUG
514
    fprintf(MSG_OUT, "libdvdnav: WAIT\n");
515
#endif
516
    (*len) = 0;
517
    pthread_mutex_unlock(&this->vm_lock);
518
    return DVDNAV_STATUS_OK;
519
  }
520
521
  /* Check to see if we need to change the currently opened VOB */
399
  /* Check to see if we need to change the curently opened VOB */
522
  if((this->position_current.vts != this->position_next.vts) ||
400
  if((self->open_vtsN != state->vtsN) || 
523
     (this->position_current.domain != this->position_next.domain)) {
401
     (self->open_domain != state->domain)) {
524
    dvd_read_domain_t domain;
402
    dvd_read_domain_t domain;
525
    int32_t vtsN;
403
    int vtsN;
526
    dvdnav_vts_change_event_t *vts_event = (dvdnav_vts_change_event_t *)*buf;
404
    dvdnav_vts_change_event_t vts_event;
527
528
    if(this->file) {
529
      DVDCloseFile(this->file);
530
      this->file = NULL;
531
    }
405
    
406
    if(self->file) {
407
      dvdnav_read_cache_clear(self);
408
      DVDCloseFile(self->file);
409
      self->file = NULL;
410
    }
532
411
533
    vts_event->old_vtsN = this->position_current.vts;
412
    vts_event.old_vtsN = self->open_vtsN;
534
    vts_event->old_domain = this->position_current.domain;
413
    vts_event.old_domain = self->open_domain;
535
414
     
536
    /* Use the DOMAIN to find whether to open menu or title VOBs */
415
    /* Use the current DOMAIN to find whether to open menu or title VOBs */
537
    switch(this->position_next.domain) {
416
    switch(state->domain) {
538
    case FP_DOMAIN:
417
     case FP_DOMAIN:
539
    case VMGM_DOMAIN:
418
     case VMGM_DOMAIN:
540
      domain = DVD_READ_MENU_VOBS;
419
      domain = DVD_READ_MENU_VOBS;
541
      vtsN = 0;
420
      vtsN = 0;
542
      break;
421
      break;
543
    case VTSM_DOMAIN:
422
     case VTSM_DOMAIN:
544
      domain = DVD_READ_MENU_VOBS;
423
      domain = DVD_READ_MENU_VOBS;
545
      vtsN = this->position_next.vts;
424
      vtsN = state->vtsN;
546
      break;
425
      break;
547
    case VTS_DOMAIN:
426
     case VTS_DOMAIN:
548
      domain = DVD_READ_TITLE_VOBS;
427
      domain = DVD_READ_TITLE_VOBS;
549
      vtsN = this->position_next.vts;
428
      vtsN = state->vtsN;
550
      break;
429
      break;
551
    default:
430
     default:
552
      printerr("Unknown domain when changing VTS.");
431
      printerr("Unknown domain when changing VTS.");
553
      pthread_mutex_unlock(&this->vm_lock);
432
      pthread_mutex_unlock(&self->vm_lock); 
554
      return DVDNAV_STATUS_ERR;
433
      return S_ERR;
434
    }
555
    }
435
    
556
436
    self->open_domain = state->domain;
557
    this->position_current.vts = this->position_next.vts;
437
    self->open_vtsN = state->vtsN;
558
    this->position_current.domain = this->position_next.domain;
559
    dvdnav_read_cache_clear(this->cache);
438
    dvdnav_read_cache_clear(self);
560
    this->file = DVDOpenFile(vm_get_dvd_reader(this->vm), vtsN, domain);
439
    self->file = DVDOpenFile(vm_get_dvd_reader(self->vm), vtsN, domain);
561
    vts_event->new_vtsN = this->position_next.vts;
440
    vts_event.new_vtsN = self->open_vtsN;
562
    vts_event->new_domain = this->position_next.domain;
441
    vts_event.new_domain = self->open_domain;
563
442
564
    /* If couldn't open the file for some reason, moan */
443
    /* If couldn't open the file for some reason, moan */
565
    if(this->file == NULL) {
444
    if(self->file == NULL) {
566
      printerrf("Error opening vtsN=%i, domain=%i.", vtsN, domain);
445
      printerrf("Error opening vtsN=%i, domain=%i.", vtsN, domain);
567
      pthread_mutex_unlock(&this->vm_lock);
446
      pthread_mutex_unlock(&self->vm_lock); 
568
      return DVDNAV_STATUS_ERR;
447
      return S_ERR;
569
    }
448
    }
570
449
571
    /* File opened successfully so return a VTS change event */
450
    /* File opened successfully so return a VTS change event */
572
    (*event) = DVDNAV_VTS_CHANGE;
451
    (*event) = DVDNAV_VTS_CHANGE;
573
#ifdef LOG_DEBUG
452
    memcpy(buf, &(vts_event), sizeof(vts_event));
574
    fprintf(MSG_OUT, "libdvdnav: VTS_CHANGE\n");
575
#endif
576
    (*len) = sizeof(dvdnav_vts_change_event_t);
453
    (*len) = sizeof(vts_event);
577
454
455
    /* On a VTS change, we want to disable any highlights which
456
     * may have been shown (FIXME: is this valid?) */
457
    self->highlight_changed = 1;
578
    this->spu_clut_changed = 1;
458
    self->spu_clut_changed = 1;
579
    this->position_current.cell = -1; /* Force an update */
459
    self->spu_stream_changed = 1;
580
    this->position_current.spu_channel = -1; /* Force an update */
460
    self->audio_stream_changed = 1;
581
    this->position_current.audio_channel = -1; /* Force an update */;
461
    self->hli_state = 0; /* Hide */
582
462
    self->expecting_nav_packet = 1;
463
     
583
    pthread_mutex_unlock(&this->vm_lock);
464
    pthread_mutex_unlock(&self->vm_lock); 
584
    return DVDNAV_STATUS_OK;
465
    return S_OK;
585
  }
466
  }
467
 
468
  /* Check the STILLFRAME flag */
469
  if(self->still_frame != -1) {
470
    dvdnav_still_event_t still_event;
586
471
587
  /* Check if the cell changed */
472
    still_event.length = self->still_frame;
588
  if( (this->position_current.cell != this->position_next.cell) ||
589
      (this->position_current.cell_restart != this->position_next.cell_restart) ||
590
      (this->position_current.cell_start != this->position_next.cell_start) ) {
591
    dvdnav_cell_change_event_t *cell_event = (dvdnav_cell_change_event_t *)*buf;
592
    int32_t first_cell_nr, last_cell_nr, i;
593
    dvd_state_t *state = &this->vm->state;
594
473
595
    this->cur_cell_time = 0;
474
    (*event) = DVDNAV_STILL_FRAME;
475
    (*len) = sizeof(dvdnav_still_event_t);
476
    memcpy(buf, &(still_event), sizeof(dvdnav_still_event_t));
477
 
478
    pthread_mutex_unlock(&self->vm_lock); 
479
    return S_OK;
480
  }
481
482
  if(self->at_soc) {
483
    dvdnav_cell_change_event_t cell_event;
484
    cell_playback_t *cell = &(state->pgc->cell_playback[state->cellN - 1]);
485
    
486
    cell_event.old_cell = self->cell;
487
    self->vobu_start = cell->first_sector;
488
    self->cell = cell;
489
    cell_event.new_cell = self->cell;
490
     
491
    self->at_soc = 0;
492
596
    (*event) = DVDNAV_CELL_CHANGE;
493
    (*event) = DVDNAV_CELL_CHANGE;
597
#ifdef LOG_DEBUG
598
    fprintf(MSG_OUT, "libdvdnav: CELL_CHANGE\n");
599
#endif
600
    (*len) = sizeof(dvdnav_cell_change_event_t);
494
    (*len) = sizeof(dvdnav_cell_change_event_t);
495
    memcpy(buf, &(cell_event), sizeof(dvdnav_cell_change_event_t));
601
496
602
    cell_event->cellN = state->cellN;
603
    cell_event->pgN   = state->pgN;
604
    cell_event->cell_length =
605
      dvdnav_convert_time(&state->pgc->cell_playback[state->cellN-1].playback_time);
606
607
    cell_event->pg_length = 0;
608
    /* Find start cell of program. */
609
    first_cell_nr = state->pgc->program_map[state->pgN-1];
610
    /* Find end cell of program */
611
    if(state->pgN < state->pgc->nr_of_programs)
612
      last_cell_nr = state->pgc->program_map[state->pgN] - 1;
613
    else
614
      last_cell_nr = state->pgc->nr_of_cells;
615
    for (i = first_cell_nr; i <= last_cell_nr; i++)
616
      cell_event->pg_length +=
617
        dvdnav_convert_time(&state->pgc->cell_playback[i - 1].playback_time);
618
    cell_event->pgc_length = dvdnav_convert_time(&state->pgc->playback_time);
619
620
    cell_event->cell_start = 0;
621
    for (i = 1; i < state->cellN; i++)
622
      cell_event->cell_start +=
623
        dvdnav_convert_time(&state->pgc->cell_playback[i - 1].playback_time);
624
625
    cell_event->pg_start = 0;
626
    for (i = 1; i < state->pgc->program_map[state->pgN-1]; i++)
627
      cell_event->pg_start +=
628
        dvdnav_convert_time(&state->pgc->cell_playback[i - 1].playback_time);
629
630
    this->position_current.cell         = this->position_next.cell;
631
    this->position_current.cell_restart = this->position_next.cell_restart;
632
    this->position_current.cell_start   = this->position_next.cell_start;
633
    this->position_current.block        = this->position_next.block;
634
635
    /* vobu info is used for mid cell resumes */
636
    this->vobu.vobu_start               = this->position_next.cell_start + this->position_next.block;
637
    this->vobu.vobu_next                = 0;
638
    /* Make blockN == vobu_length to do expected_nav */
639
    this->vobu.vobu_length = 0;
640
    this->vobu.blockN      = 0;
641
642
    /* update the spu palette at least on PGC changes */
643
    this->spu_clut_changed = 1;
644
    this->position_current.spu_channel = -1; /* Force an update */
645
    this->position_current.audio_channel = -1; /* Force an update */
646
647
    pthread_mutex_unlock(&this->vm_lock);
497
    pthread_mutex_unlock(&self->vm_lock); 
648
    return DVDNAV_STATUS_OK;
498
    return S_OK;
649
  }
499
  }
650
500
651
  /* has the CLUT changed? */
501
  if(self->expecting_nav_packet) {
652
  if(this->spu_clut_changed) {
502
    dvdnav_nav_packet_event_t nav_event;
653
    (*event) = DVDNAV_SPU_CLUT_CHANGE;
654
#ifdef LOG_DEBUG
655
    fprintf(MSG_OUT, "libdvdnav: SPU_CLUT_CHANGE\n");
656
#endif
657
    (*len) = 16 * sizeof(uint32_t);
658
    memcpy(*buf, &(state->pgc->palette), 16 * sizeof(uint32_t));
659
    this->spu_clut_changed = 0;
660
    pthread_mutex_unlock(&this->vm_lock);
661
    return DVDNAV_STATUS_OK;
662
  }
663
503
664
  /* has the SPU channel changed? */
504
    /* Perform the jump if necessary (this is always a 
665
  if(this->position_current.spu_channel != this->position_next.spu_channel) {
505
     * VOBU boundary). */
666
    dvdnav_spu_stream_change_event_t *stream_change = (dvdnav_spu_stream_change_event_t *)*buf;
667
506
668
    (*event) = DVDNAV_SPU_STREAM_CHANGE;
507
    if(self->seeking) {
669
#ifdef LOG_DEBUG
508
      /* FIXME:Need to handle seeking outside current cell. */
670
    fprintf(MSG_OUT, "libdvdnav: SPU_STREAM_CHANGE\n");
509
      vobu_admap_t *admap = NULL;
671
#endif
672
    (*len) = sizeof(dvdnav_spu_stream_change_event_t);
673
    stream_change->physical_wide      = vm_get_subp_active_stream(this->vm, 0);
674
    stream_change->physical_letterbox = vm_get_subp_active_stream(this->vm, 1);
675
    stream_change->physical_pan_scan  = vm_get_subp_active_stream(this->vm, 2);
676
    this->position_current.spu_channel = this->position_next.spu_channel;
677
#ifdef LOG_DEBUG
678
    fprintf(MSG_OUT, "libdvdnav: SPU_STREAM_CHANGE stream_id_wide=%d\n",stream_change->physical_wide);
679
    fprintf(MSG_OUT, "libdvdnav: SPU_STREAM_CHANGE stream_id_letterbox=%d\n",stream_change->physical_letterbox);
680
    fprintf(MSG_OUT, "libdvdnav: SPU_STREAM_CHANGE stream_id_pan_scan=%d\n",stream_change->physical_pan_scan);
681
    fprintf(MSG_OUT, "libdvdnav: SPU_STREAM_CHANGE returning DVDNAV_STATUS_OK\n");
682
#endif
683
    pthread_mutex_unlock(&this->vm_lock);
684
    return DVDNAV_STATUS_OK;
685
  }
686
687
  /* has the audio channel changed? */
688
  if(this->position_current.audio_channel != this->position_next.audio_channel) {
689
    dvdnav_audio_stream_change_event_t *stream_change = (dvdnav_audio_stream_change_event_t *)*buf;
690
691
    (*event) = DVDNAV_AUDIO_STREAM_CHANGE;
692
#ifdef LOG_DEBUG
693
    fprintf(MSG_OUT, "libdvdnav: AUDIO_STREAM_CHANGE\n");
694
#endif
695
    (*len) = sizeof(dvdnav_audio_stream_change_event_t);
696
    stream_change->physical = vm_get_audio_active_stream( this->vm );
697
    stream_change->logical = this->position_next.audio_channel;
698
    this->position_current.audio_channel = this->position_next.audio_channel;
699
#ifdef LOG_DEBUG
700
    fprintf(MSG_OUT, "libdvdnav: AUDIO_STREAM_CHANGE stream_id=%d returning DVDNAV_STATUS_OK\n",stream_change->physical);
701
#endif
702
    pthread_mutex_unlock(&this->vm_lock);
703
    return DVDNAV_STATUS_OK;
704
  }
705
706
  /* Check the STILLFRAME flag */
707
  if(this->position_current.still != 0) {
708
    dvdnav_still_event_t *still_event = (dvdnav_still_event_t *)*buf;
709
710
    (*event) = DVDNAV_STILL_FRAME;
711
#ifdef LOG_DEBUG
712
    fprintf(MSG_OUT, "libdvdnav: STILL_FRAME\n");
713
#endif
714
    (*len) = sizeof(dvdnav_still_event_t);
715
    still_event->length = this->position_current.still;
716
    pthread_mutex_unlock(&this->vm_lock);
717
    return DVDNAV_STATUS_OK;
718
  }
719
720
  /* Have we reached the end of a VOBU? */
721
  if (this->vobu.blockN >= this->vobu.vobu_length) {
722
723
    /* Have we reached the end of a cell? */
724
    if(this->vobu.vobu_next == SRI_END_OF_CELL) {
725
      /* End of Cell from NAV DSI info */
726
#ifdef LOG_DEBUG
727
      fprintf(MSG_OUT, "libdvdnav: Still set to %x\n", this->position_next.still);
728
#endif
729
      this->position_current.still = this->position_next.still;
730
731
      /* we are about to leave a cell, so a lot of state changes could occur;
732
       * under certain conditions, the application should get in sync with us before this,
733
       * otherwise it might show stills or menus too shortly */
734
      if ((this->position_current.still || this->pci.hli.hl_gi.hli_ss) && !this->sync_wait_skip) {
735
        this->sync_wait = 1;
736
      } else {
737
  if( this->position_current.still == 0 || this->skip_still ) {
738
    /* no active cell still -> get us to the next cell */
739
    vm_get_next_cell(this->vm);
740
    this->position_current.still = 0; /* still gets activated at end of cell */
741
    this->skip_still = 0;
742
    this->sync_wait_skip = 0;
743
    }
510
    
511
      printf("Seeking to target %u ...\n",
512
              self->seekto_block);
513
514
      /* Search through the VOBU_ADMAP for the nearest VOBU
515
       * to the target block */
516
      switch(state->domain) {
517
        case FP_DOMAIN:
518
        case VMGM_DOMAIN:
519
          //ifo = vm_get_vmgi();
520
          //ifoRead_VOBU_ADMAP(ifo);
521
          admap = self->vm->vmgi->menu_vobu_admap;
522
          break;
523
        case VTSM_DOMAIN:
524
          //ifo = vm_get_vtsi();
525
          //ifoRead_VOBU_ADMAP(ifo);
526
          admap = self->vm->vtsi->menu_vobu_admap;
527
          break;
528
        case VTS_DOMAIN:
529
          //ifo = vm_get_vtsi();
530
          //ifoRead_TITLE_VOBU_ADMAP(ifo);
531
          admap = self->vm->vtsi->vts_vobu_admap;
532
          break;
533
        default:
534
          printf("Error: Unknown domain for seeking seek.\n");
744
      }
535
      }
745
      /* handle related state changes in next iteration */
536
746
      (*event) = DVDNAV_NOP;
537
      if(admap) {
747
      (*len) = 0;
538
        uint32_t address = 0;
748
      pthread_mutex_unlock(&this->vm_lock);
539
        uint32_t vobu_start, next_vobu;
749
      return DVDNAV_STATUS_OK;
540
        int found = 0;
541
  
542
        /* Search through ADMAP for best sector */
543
        vobu_start = 0x3fffffff;
544
   
545
        while((!found) && ((address<<2) < admap->last_byte)) {
546
          next_vobu = admap->vobu_start_sectors[address];
547
548
          /* printf("Found block %u\n", next_vobu); */
750
    }
549
    
751
550
          if(vobu_start <= self->seekto_block && 
752
    /* Perform remapping jump if necessary (this is always a
551
                 next_vobu > self->seekto_block) {
753
     * VOBU boundary). */
552
            found = 1;
754
    if (this->vm->map) {
553
          } else {
755
      this->vobu.vobu_next = remap_block( this->vm->map,
554
            vobu_start = next_vobu;
756
        this->vm->state.domain, this->vm->state.TTN_REG,
555
          }
757
        this->vm->state.pgN,
758
        this->vobu.vobu_start, this->vobu.vobu_next);
759
    }
556
    
760
557
          address ++;
761
    /* at the start of the next VOBU -> expecting NAV packet */
558
        }
762
    result = dvdnav_read_cache_block(this->cache, this->vobu.vobu_start + this->vobu.vobu_next, 1, buf);
559
        if(found) {
560
          self->vobu_start = vobu_start;
561
          self->blockN = 0;
562
          self->seeking = 0;
563
          //self->at_soc = 1;
564
          (*event) = DVDNAV_SEEK_DONE;
565
          (*len) = 0;
566
          pthread_mutex_unlock(&self->vm_lock); 
567
          return S_OK;
568
        } else {
569
          printf("Could not locate block\n");
570
          return -1;
571
        }
572
      }
573
    }   
574
    if(self->jumping) {
575
      printf("doing jumping\n");
576
      self->vobu_start = self->jmp_vobu_start;
577
      self->blockN = self->jmp_blockN;
578
      self->jumping = 0;
579
      self->at_soc = 1;
580
    }
581
    
582
    result = DVDReadBlocks(self->file, self->vobu_start + self->blockN, 1, buf);
763
583
764
    if(result <= 0) {
584
    if(result <= 0) {
765
      printerr("Error reading NAV packet.");
585
      printerr("Error reading NAV packet.");
766
      pthread_mutex_unlock(&this->vm_lock);
586
      pthread_mutex_unlock(&self->vm_lock); 
767
      return DVDNAV_STATUS_ERR;
587
      return S_ERR;
768
    }
588
    }
769
    /* Decode nav into pci and dsi. Then get next VOBU info. */
589
770
    if(!dvdnav_decode_packet(this, *buf, &this->dsi, &this->pci)) {
590
    if(dvdnav_check_packet(self, buf) == 0) {
771
      printerr("Expected NAV packet but none found.");
591
      printerr("Expected NAV packet but none found.");
772
      pthread_mutex_unlock(&this->vm_lock);
592
      pthread_mutex_unlock(&self->vm_lock); 
773
      return DVDNAV_STATUS_ERR;
593
      return S_ERR;
594
    }
774
    }
595
    
775
    /* We need to update the vm state->blockN with which VOBU we are in.
596
    self->blockN++;
776
     * This is so RSM resumes to the VOBU level and not just the CELL level.
597
    self->expecting_nav_packet = 0;
598
599
    dvdnav_pre_cache_blocks(self, self->vobu_start, self->vobu_length+1);
777
     */
600
    
778
    this->vm->state.blockN = this->vobu.vobu_start - this->position_current.cell_start;
779
780
    dvdnav_get_vobu(this, &this->dsi, &this->pci, &this->vobu);
781
    this->vobu.blockN = 0;
782
    /* Give the cache a hint about the size of next VOBU.
783
     * This improves pre-caching, because the VOBU will almost certainly be read entirely.
784
     */
785
    dvdnav_pre_cache_blocks(this->cache, this->vobu.vobu_start+1, this->vobu.vobu_length+1);
786
787
    /* release NAV menu filter, when we reach the same NAV packet again */
788
    if (this->last_cmd_nav_lbn == this->pci.pci_gi.nv_pck_lbn)
789
      this->last_cmd_nav_lbn = SRI_END_OF_CELL;
790
791
    /* Successfully got a NAV packet */
601
    /* Successfully got a NAV packet */
602
    nav_event.pci = &(self->pci);
603
    nav_event.dsi = &(self->dsi);
604
792
    (*event) = DVDNAV_NAV_PACKET;
605
    (*event) = DVDNAV_NAV_PACKET;
793
#ifdef LOG_DEBUG
606
    //memcpy(buf, &(nav_event), sizeof(dvdnav_nav_packet_event_t));
794
    fprintf(MSG_OUT, "libdvdnav: NAV_PACKET\n");
607
    //(*len) = sizeof(dvdnav_nav_packet_event_t);
795
#endif
796
    (*len) = 2048;
608
    (*len) = 2048;
797
    this->cur_cell_time = dvdnav_convert_time(&this->dsi.dsi_gi.c_eltm);
798
    pthread_mutex_unlock(&this->vm_lock);
609
    pthread_mutex_unlock(&self->vm_lock); 
799
    return DVDNAV_STATUS_OK;
610
    return S_OK;
611
  }
800
  }
612
  
801
802
  /* If we've got here, it must just be a normal block. */
613
  /* If we've got here, it must just be a normal block. */
803
  if(!this->file) {
614
  if(!self->file) {
804
    printerr("Attempting to read without opening file.");
615
    printerr("Attempting to read without opening file");
805
    pthread_mutex_unlock(&this->vm_lock);
616
    pthread_mutex_unlock(&self->vm_lock); 
806
    return DVDNAV_STATUS_ERR;
617
    return S_ERR;
807
  }
618
  }
808
619
809
  this->vobu.blockN++;
810
  result = dvdnav_read_cache_block(this->cache, this->vobu.vobu_start + this->vobu.blockN, 1, buf);
620
  result = dvdnav_read_cache_block(self, self->vobu_start + self->blockN, 1, buf);
811
  if(result <= 0) {
621
  if(result <= 0) {
812
    printerr("Error reading from DVD.");
622
    printerr("Error reading from DVD.");
813
    pthread_mutex_unlock(&this->vm_lock);
623
    pthread_mutex_unlock(&self->vm_lock); 
814
    return DVDNAV_STATUS_ERR;
624
    return S_ERR;
815
  }
625
  }
626
  self->blockN++;
627
  (*len) = 2048;
816
  (*event) = DVDNAV_BLOCK_OK;
628
  (*event) = DVDNAV_BLOCK_OK;
817
  (*len) = 2048;
818
629
630
  if(self->blockN > self->vobu_length) {
631
    self->vobu_start = self->next_vobu;
632
    self->blockN = 0;
633
    self->expecting_nav_packet = 1;
634
635
    if(self->dsi.vobu_sri.next_vobu == SRI_END_OF_CELL) {
636
      cell_playback_t *cell = &(state->pgc->cell_playback[state->cellN - 1]);
637
638
      if(cell->still_time != 0xff) {
639
        vm_get_next_cell(self->vm);
640
      }
641
642
      if(cell->still_time != 0) {
643
  self->still_frame = cell->still_time;
644
      }
645
646
      self->at_soc = 1;
647
    }
648
  }
649
  
819
  pthread_mutex_unlock(&this->vm_lock);
650
  pthread_mutex_unlock(&self->vm_lock); 
820
  return DVDNAV_STATUS_OK;
651
  return S_OK;
821
}
652
}
822
653
823
dvdnav_status_t dvdnav_get_title_string(dvdnav_t *this, const char **title_str) {
654
uint16_t dvdnav_audio_stream_to_lang(dvdnav_t *self, uint8_t stream) {
824
  (*title_str) = this->vm->dvd_name;
655
  ifo_handle_t *vtsi;
825
  return DVDNAV_STATUS_OK;
656
  dvd_state_t  *state;
826
}
657
  
827
658
  if(!self)
828
dvdnav_status_t dvdnav_get_serial_string(dvdnav_t *this, const char **serial_str) {
829
  (*serial_str) = this->vm->dvd_serial;
830
  return DVDNAV_STATUS_OK;
831
}
832
833
uint8_t dvdnav_get_video_aspect(dvdnav_t *this) {
834
  uint8_t         retval;
835
836
  if(!this->started) {
837
    printerr("Virtual DVD machine not started.");
838
    return -1;
659
    return -1;
839
  }
660
  
840
841
  pthread_mutex_lock(&this->vm_lock);
661
  pthread_mutex_lock(&self->vm_lock); 
842
  retval = (uint8_t)vm_get_video_aspect(this->vm);
662
663
  vtsi = self->vm->vtsi;
664
  state = &(self->vm->state);
665
666
  if((vtsi == NULL) || (state == NULL) || (state->domain != VTS_DOMAIN))
667
    goto __failed;
668
  
669
  if(stream >= vtsi->vtsi_mat->nr_of_vts_audio_streams)
670
    goto __failed;
671
  
672
  if(vtsi->vtsi_mat->vts_audio_attr[stream].lang_type != 1)
673
    goto __failed;
674
  
843
  pthread_mutex_unlock(&this->vm_lock);
675
  pthread_mutex_unlock(&self->vm_lock); 
844
676
  return vtsi->vtsi_mat->vts_audio_attr[stream].lang_code;
845
  return retval;
677
  
678
 __failed:
679
  pthread_mutex_unlock(&self->vm_lock); 
680
  return 0xffff;
846
}
681
}
847
682
848
uint8_t dvdnav_get_video_scale_permission(dvdnav_t *this) {
683
int8_t dvdnav_audio_logical_to_physical(dvdnav_t *self, uint8_t logical) {
849
  uint8_t         retval;
684
  audio_status_t *audio_status;
850
685
  dvd_state_t    *state;
851
  if(!this->started) {
686
  int             i = 0;
852
    printerr("Virtual DVD machine not started.");
687
  
688
  if(!self)
853
    return -1;
689
    return -1;
854
  }
690
  
855
856
  pthread_mutex_lock(&this->vm_lock);
691
  pthread_mutex_lock(&self->vm_lock); 
857
  retval = (uint8_t)vm_get_video_scale_permission(this->vm);
692
  
693
  state = &(self->vm->state);
694
  
695
  if((!state) || (!state->pgc) || (!state->pgc->audio_control))
696
    goto __failed;
697
  
698
  if(logical > 7) {
699
    fprintf(stderr, "Invalid logical audio channel: %i\n", logical);
700
    goto __failed;
701
  }
702
703
  while (i < 8) {
704
    audio_status = (audio_status_t*) &(state->pgc->audio_control[i]);
705
706
    if(!audio_status)
707
      goto __failed;
708
709
    if(audio_status->available)
710
      break;
711
    
712
    i++;
713
  }
714
  
715
  if (i > 7)
716
    goto __failed;
717
718
  if ((logical+i) > 7)
719
    goto __failed;
720
  
721
  audio_status = (audio_status_t*) &(state->pgc->audio_control[logical+i]);
722
723
  if(!audio_status)
724
    goto __failed;
725
  
726
  if(audio_status->available) {
727
    /* Stream is available */
728
    pthread_mutex_unlock(&self->vm_lock); 
729
    return audio_status->stream_number; 
730
  }
731
  
732
 __failed:
858
  pthread_mutex_unlock(&this->vm_lock);
733
  pthread_mutex_unlock(&self->vm_lock); 
859
734
  return -1;
860
  return retval;
861
}
735
}
862
736
863
uint16_t dvdnav_audio_stream_to_lang(dvdnav_t *this, uint8_t stream) {
737
int8_t dvdnav_audio_physical_to_logical(dvdnav_t *self, uint8_t physical) {
864
  audio_attr_t  attr;
738
  int8_t logical = -1;
865
739
  int    i       = 0; 
866
  if(!this->started) {
740
  
867
    printerr("Virtual DVD machine not started.");
741
  if((!self) || (physical > 7))
868
    return -1;
742
    return -1;
869
  }
743
  
744
  do {
745
    if(dvdnav_audio_logical_to_physical(self, i) == physical) 
746
      logical = i;
747
    
748
    i++;
749
  } while((i<8) && (logical == -1));
870
750
871
  pthread_mutex_lock(&this->vm_lock);
751
  return logical;
872
  attr = vm_get_audio_attr(this->vm, stream);
873
  pthread_mutex_unlock(&this->vm_lock);
874
875
  if(attr.lang_type != 1)
876
    return 0xffff;
877
878
  return attr.lang_code;
879
}
752
}
880
753
881
uint16_t dvdnav_audio_stream_format(dvdnav_t *this, uint8_t stream) {
882
  audio_attr_t  attr;
883
  uint16_t format;
884
885
  if(!this->started) {
886
    printerr("Virtual DVD machine not started.");
887
    return -1; /* 0xffff */
888
  }
889
890
  pthread_mutex_lock(&this->vm_lock);
891
  attr = vm_get_audio_attr(this->vm, stream);
892
  pthread_mutex_unlock(&this->vm_lock);
893
894
  switch(attr.audio_format) {
895
  case 0:
896
    format = DVDNAV_FORMAT_AC3;
897
    break;
898
  case 2: /* MPEG-1 or MPEG-2 without extension bitstream. */
899
  case 3: /* MPEG-2 with extension bitstream. */
900
    format = DVDNAV_FORMAT_MPEGAUDIO;
901
    break;
902
  case 4:
903
    format = DVDNAV_FORMAT_LPCM;
904
    break;
905
  case 6:
906
    format = DVDNAV_FORMAT_DTS;
907
    break;
908
  case 7:
909
    format = DVDNAV_FORMAT_SDDS;
910
    break;
911
  default:
912
    format = 0xffff;
913
    break;
914
  }
915
916
  return format;
917
}
918
919
uint16_t dvdnav_audio_stream_channels(dvdnav_t *this, uint8_t stream) {
920
  audio_attr_t  attr;
921
922
  if(!this->started) {
923
    printerr("Virtual DVD machine not started.");
924
    return -1; /* 0xffff */
925
  }
926
927
  pthread_mutex_lock(&this->vm_lock);
928
  attr = vm_get_audio_attr(this->vm, stream);
929
  pthread_mutex_unlock(&this->vm_lock);
930
931
  return attr.channels + 1;
932
}
933
934
uint16_t dvdnav_spu_stream_to_lang(dvdnav_t *this, uint8_t stream) {
754
uint16_t dvdnav_spu_stream_to_lang(dvdnav_t *self, uint8_t stream) {
935
  subp_attr_t  attr;
755
  ifo_handle_t *vtsi;
756
  dvd_state_t  *state;
936
757
937
  if(!this->started) {
758
  if(!self)
938
    printerr("Virtual DVD machine not started.");
939
    return -1;
759
    return -1;
940
  }
760
  
941
942
  pthread_mutex_lock(&this->vm_lock);
761
  pthread_mutex_lock(&self->vm_lock); 
943
  attr = vm_get_subp_attr(this->vm, stream);
762
  
763
  vtsi = self->vm->vtsi;
764
  state = &(self->vm->state);
765
766
  if((vtsi == NULL) || (state == NULL) || (state->domain != VTS_DOMAIN)) {
767
    goto __failed;
768
  }
769
770
  if(stream >= vtsi->vtsi_mat->nr_of_vts_subp_streams) {
771
    goto __failed;
772
  }
773
774
  if(vtsi->vtsi_mat->vts_subp_attr[stream].type != 1) {
775
    goto __failed;
776
  }
777
  
944
  pthread_mutex_unlock(&this->vm_lock);
778
  pthread_mutex_unlock(&self->vm_lock); 
945
779
  return vtsi->vtsi_mat->vts_subp_attr[stream].lang_code;
946
  if(attr.type != 1)
780
  
781
 __failed:
782
  pthread_mutex_unlock(&self->vm_lock); 
947
    return 0xffff;
783
  return 0xffff;
948
949
  return attr.lang_code;
950
}
784
}
951
785
952
int8_t dvdnav_get_audio_logical_stream(dvdnav_t *this, uint8_t audio_num) {
786
int8_t dvdnav_spu_logical_to_physical(dvdnav_t *self, uint8_t logical) {
953
  int8_t       retval;
787
  spu_status_t *spu_status;
954
788
  dvd_state_t  *state;
955
  if(!this->started) {
789
  ifo_handle_t *vtsi;
956
    printerr("Virtual DVD machine not started.");
790
 
791
  if(!self)
957
    return -1;
792
    return -1;
958
  }
793
  
959
960
  pthread_mutex_lock(&this->vm_lock);
794
  pthread_mutex_lock(&self->vm_lock); 
961
  if (!this->vm->state.pgc) {
795
  
962
    printerr("No current PGC.");
796
  vtsi = self->vm->vtsi;
797
  state = &(self->vm->state);
798
  
799
  if((!state) || (!vtsi))
800
    goto __failed;
801
802
  if(logical > 31) {
803
    fprintf(stderr, "Invalid logical spu channel: %i\n", logical);
804
    goto __failed;
805
  }
806
  
807
  spu_status = (spu_status_t*) &(state->pgc->subp_control[logical]);
808
  
809
  if(!spu_status)
810
    goto __failed;
811
  
812
  if(spu_status->available) {
813
    int8_t        logical = -1;
814
    video_attr_t *attr;
815
    
816
    attr = &(vtsi->vtsi_mat->vtsm_video_attr);
817
  
818
    if(!attr)
819
      goto __failed;
820
821
    /* Stream is available */
822
    switch(attr->display_aspect_ratio) {
823
    case 0: /* 4:3 */
824
      logical = spu_status->stream_number_4_3;
825
      break;
826
    case 3: /* 16:9 */
827
      logical = spu_status->stream_number_letterbox;
828
      break;
829
    }
963
    pthread_mutex_unlock(&this->vm_lock);
830
    pthread_mutex_unlock(&self->vm_lock); 
831
    return logical; 
832
  }
833
  
834
 __failed:
835
  pthread_mutex_unlock(&self->vm_lock); 
836
  return -1;
837
}
838
839
int8_t dvdnav_spu_physical_to_logical(dvdnav_t *self, uint8_t physical) {
840
  int8_t logical = -1;
841
  int    i       = 0;
842
  
843
  if(physical > 31)
964
    return -1;
844
    return -1;
845
846
  do {
847
    if(dvdnav_spu_logical_to_physical(self, i) == physical) 
848
      logical = i;
849
    
850
    i++;
851
  } while((i<32) && (logical == -1));
852
853
  return logical;
854
}
855
856
/* Current domain (backend to dvdnav_is_domain_() funcs) */
857
static int8_t _dvdnav_is_domain(dvdnav_t *self, domain_t domain) {
858
  dvd_state_t  *state;
965
  }
859
  
966
  retval = vm_get_audio_stream(this->vm, audio_num);
860
  if((!self) || (!self->started) || (!self->vm))
967
  pthread_mutex_unlock(&this->vm_lock);
968
969
  return retval;
970
}
971
972
dvdnav_status_t dvdnav_get_audio_attr(dvdnav_t *this, uint8_t audio_num, audio_attr_t *audio_attr) {
973
  if(!this->started) {
974
    printerr("Virtual DVD machine not started.");
975
    return -1;
861
    return -1;
976
  }
862
  
977
  pthread_mutex_lock(&this->vm_lock);
863
  pthread_mutex_lock(&self->vm_lock); 
978
  if (!this->vm->state.pgc) {
864
  state = &(self->vm->state);
979
    printerr("No current PGC.");
980
    pthread_mutex_unlock(&this->vm_lock);
865
  pthread_mutex_unlock(&self->vm_lock);
866
867
  if(!state)
981
    return -1;
868
    return -1;
982
  }
983
  *audio_attr=vm_get_audio_attr(this->vm, audio_num);
984
  pthread_mutex_unlock(&this->vm_lock);
985
869
986
  return DVDNAV_STATUS_OK;
870
  return (state->domain == domain) ? 1 : 0;
987
}
988
989
int8_t dvdnav_get_spu_logical_stream(dvdnav_t *this, uint8_t subp_num) {
990
  int8_t       retval;
991
992
  if(!this->started) {
993
    printerr("Virtual DVD machine not started.");
994
    return -1;
995
  }
996
997
  pthread_mutex_lock(&this->vm_lock);
998
  if (!this->vm->state.pgc) {
999
    printerr("No current PGC.");
1000
    pthread_mutex_unlock(&this->vm_lock);
1001
    return -1;
1002
  }
1003
  retval = vm_get_subp_stream(this->vm, subp_num, 0);
1004
  pthread_mutex_unlock(&this->vm_lock);
1005
1006
  return retval;
1007
}
1008
1009
dvdnav_status_t dvdnav_get_spu_attr(dvdnav_t *this, uint8_t audio_num, subp_attr_t *subp_attr) {
1010
  if(!this->started) {
1011
    printerr("Virtual DVD machine not started.");
1012
    return -1;
1013
  }
1014
  pthread_mutex_lock(&this->vm_lock);
1015
  if (!this->vm->state.pgc) {
1016
    printerr("No current PGC.");
1017
    pthread_mutex_unlock(&this->vm_lock);
1018
    return -1;
1019
  }
1020
  *subp_attr=vm_get_subp_attr(this->vm, audio_num);
1021
  pthread_mutex_unlock(&this->vm_lock);
1022
  return DVDNAV_STATUS_OK;
1023
}
1024
1025
int8_t dvdnav_get_active_audio_stream(dvdnav_t *this) {
1026
  int8_t        retval;
1027
1028
  if(!this->started) {
1029
    printerr("Virtual DVD machine not started.");
1030
    return -1;
1031
  }
1032
1033
  pthread_mutex_lock(&this->vm_lock);
1034
  if (!this->vm->state.pgc) {
1035
    printerr("No current PGC.");
1036
    pthread_mutex_unlock(&this->vm_lock);
1037
    return -1;
1038
  }
1039
  retval = vm_get_audio_active_stream(this->vm);
1040
  pthread_mutex_unlock(&this->vm_lock);
1041
1042
  return retval;
1043
}
1044
1045
int8_t dvdnav_get_active_spu_stream(dvdnav_t *this) {
1046
  int8_t        retval;
1047
1048
  if(!this->started) {
1049
    printerr("Virtual DVD machine not started.");
1050
    return -1;
1051
  }
1052
1053
  pthread_mutex_lock(&this->vm_lock);
1054
  if (!this->vm->state.pgc) {
1055
    printerr("No current PGC.");
1056
    pthread_mutex_unlock(&this->vm_lock);
1057
    return -1;
1058
  }
1059
  retval = vm_get_subp_active_stream(this->vm, 0);
1060
  pthread_mutex_unlock(&this->vm_lock);
1061
1062
  return retval;
1063
}
1064
1065
static int8_t dvdnav_is_domain(dvdnav_t *this, domain_t domain) {
1066
  int8_t        retval;
1067
1068
  if(!this->started) {
1069
    printerr("Virtual DVD machine not started.");
1070
    return -1;
1071
  }
1072
1073
  pthread_mutex_lock(&this->vm_lock);
1074
  retval = (this->vm->state.domain == domain);
1075
  pthread_mutex_unlock(&this->vm_lock);
1076
1077
  return retval;
1078
}
871
}
1079
872
1080
/* First Play domain. (Menu) */
873
/* First Play domain. (Menu) */
1081
int8_t dvdnav_is_domain_fp(dvdnav_t *this) {
874
int8_t dvdnav_is_domain_fp(dvdnav_t *self) {
1082
  return dvdnav_is_domain(this, FP_DOMAIN);
875
  return _dvdnav_is_domain(self, FP_DOMAIN);
1083
}
876
}
1084
/* Video management Menu domain. (Menu) */
877
/* Video management Menu domain. (Menu) */
1085
int8_t dvdnav_is_domain_vmgm(dvdnav_t *this) {
878
int8_t dvdnav_is_domain_vmgm(dvdnav_t *self) {
1086
  return dvdnav_is_domain(this, VMGM_DOMAIN);
879
  return _dvdnav_is_domain(self, VMGM_DOMAIN);
1087
}
880
}
1088
/* Video Title Menu domain (Menu) */
881
/* Video Title Menu domain (Menu) */
1089
int8_t dvdnav_is_domain_vtsm(dvdnav_t *this) {
882
int8_t dvdnav_is_domain_vtsm(dvdnav_t *self) {
1090
  return dvdnav_is_domain(this, VTSM_DOMAIN);
883
  return _dvdnav_is_domain(self, VTSM_DOMAIN);
1091
}
884
}
1092
/* Video Title domain (playing movie). */
885
/* Video Title domain (playing movie). */
1093
int8_t dvdnav_is_domain_vts(dvdnav_t *this) {
886
int8_t dvdnav_is_domain_vts(dvdnav_t *self) { 
1094
  return dvdnav_is_domain(this, VTS_DOMAIN);
887
  return _dvdnav_is_domain(self, VTS_DOMAIN);
1095
}
888
}
1096
889
1097
/* Generally delegate angle information handling to VM */
890
/* Generally delegate angle information handling to 
891
 * VM */
1098
dvdnav_status_t dvdnav_angle_change(dvdnav_t *this, int32_t angle) {
892
dvdnav_status_t dvdnav_angle_change(dvdnav_t *self, int angle) {
1099
  int32_t num, current;
893
  int num, current;
894
  
895
  if(!self) {
896
    return S_ERR;
897
  }
1100
898
1101
  pthread_mutex_lock(&this->vm_lock);
899
  if(dvdnav_get_angle_info(self, &current, &num) != S_OK) {
1102
  vm_get_angle_info(this->vm, &current, &num);
900
    printerr("Error getting angle info");
901
    return S_ERR;
902
  }
903
  
1103
  /* Set angle SPRM if valid */
904
  /* Set angle SPRM if valid */
1104
  if((angle > 0) && (angle <= num)) {
905
  if((angle > 0) && (angle <= num)) {
1105
    this->vm->state.AGL_REG = angle;
906
    self->vm->state.AGL_REG = angle;
1106
  } else {
907
  } else {
1107
    printerr("Passed an invalid angle number.");
908
    printerr("Passed an invalid angle number");
1108
    pthread_mutex_unlock(&this->vm_lock);
1109
    return DVDNAV_STATUS_ERR;
909
    return S_ERR;
1110
  }
910
  }
1111
  pthread_mutex_unlock(&this->vm_lock);
1112
911
1113
  return DVDNAV_STATUS_OK;
912
  return S_OK;
1114
}
913
}
1115
914
1116
dvdnav_status_t dvdnav_get_angle_info(dvdnav_t *this, int32_t *current_angle,
915
dvdnav_status_t dvdnav_get_angle_info(dvdnav_t *self, int* current_angle,
1117
                      int32_t *number_of_angles) {
916
                     int *number_of_angles) {
1118
  pthread_mutex_lock(&this->vm_lock);
917
  if(!self || !self->vm) {
1119
  vm_get_angle_info(this->vm, current_angle, number_of_angles);
918
    return S_ERR;
1120
  pthread_mutex_unlock(&this->vm_lock);
919
  }
1121
920
1122
  return DVDNAV_STATUS_OK;
921
  if(!current_angle || !number_of_angles) {
1123
}
922
    printerr("Passed a NULL pointer");
923
    return S_ERR;
924
  }
1124
925
1125
pci_t* dvdnav_get_current_nav_pci(dvdnav_t *this) {
926
  vm_get_angle_info(self->vm, number_of_angles, current_angle);
1126
  if(!this) return 0;
1127
  return &this->pci;
1128
}
1129
927
1130
dsi_t* dvdnav_get_current_nav_dsi(dvdnav_t *this) {
928
  return S_OK;
1131
  if(!this) return 0;
1132
  return &this->dsi;
1133
}
929
}
1134
930
1135
uint32_t dvdnav_get_next_still_flag(dvdnav_t *this) {
1136
  if(!this) return -1;
1137
  return this->position_next.still;
1138
}
1139
931
1140
user_ops_t dvdnav_get_restrictions(dvdnav_t* this) {
1141
  /*
932
/*
1142
   * user_ops_t is a structure of 32 bits.  We want to compute
933
 * $Log$
1143
   * the union of two of those bitfields so to make this quicker
934
 * Revision 1.1  2002/03/12 19:45:57  richwareham
1144
   * than performing 32 ORs, we will access them as 32bits words.
935
 * Initial revision
936
 *
937
 * Revision 1.28  2002/02/02 23:26:20  richwareham
938
 * Restored title selection
939
 *
940
 * Revision 1.27  2002/02/01 15:48:10  richwareham
941
 * Re-implemented angle selection and title/chapter display
942
 *
943
 * Revision 1.26  2002/01/31 16:53:49  richwareham
944
 * Big patch from Daniel Caujolle-Bert to (re)implement SPU/Audio language display
945
 *
946
 * Revision 1.25  2002/01/24 20:53:50  richwareham
947
 * Added option to _not_ use DVD read-ahead to options
948
 *
949
 * Revision 1.24  2002/01/20 15:54:59  jcdutton
950
 * Implement seeking.
951
 * It is still a bit buggy, but works sometimes.
952
 * I need to find out how to make the jump clean.
953
 * At the moment, some corruption of the mpeg2 stream occurs, 
954
 * which causes libmpeg2 to crash.
955
 *
956
 * Revision 1.23  2002/01/18 00:23:52  jcdutton
957
 * Support Ejecting of DVD.
958
 * It will first un-mount the DVD, then eject it.
959
 *
960
 * Revision 1.22  2002/01/17 14:50:32  jcdutton
961
 * Fix corruption of stream during menu transitions.
962
 * Menu transitions are now clean.
963
 *
964
 * Revision 1.21  2002/01/15 00:37:03  jcdutton
965
 * Just a few cleanups, and a assert fix. (memset fixed it)
966
 *
967
 * Revision 1.20  2002/01/13 22:17:57  jcdutton
968
 * Change logging.
969
 *
970
 *
1145
   */
971
 */
1146
  union {
1147
    user_ops_t ops_struct;
1148
    uint32_t   ops_int;
1149
  } ops;
1150
1151
  ops.ops_int = 0;
1152
1153
  if(!this->started) {
1154
    printerr("Virtual DVD machine not started.");
1155
    return ops.ops_struct;
1156
  }
1157
1158
  pthread_mutex_lock(&this->vm_lock);
1159
  ops.ops_int |= *(uint32_t*)&this->pci.pci_gi.vobu_uop_ctl;
1160
1161
  if(this->vm && this->vm->state.pgc)
1162
    ops.ops_int |= *(uint32_t*)&this->vm->state.pgc->prohibited_ops;
1163
  pthread_mutex_unlock(&this->vm_lock);
1164
1165
  return ops.ops_struct;
1166
}

Get latest updates about Open Source Projects, Conferences and News.

Sign up for the SourceForge newsletter:





No, thanks