OSDN Git Service

Fixed dvd_seek for titles which are not linear
[handbrake-jp/handbrake-jp-git.git] / libhb / ports.c
1 /* $Id: ports.c,v 1.15 2005/10/15 18:05:03 titer Exp $
2
3    This file is part of the HandBrake source code.
4    Homepage: <http://handbrake.m0k.org/>.
5    It may be used under the terms of the GNU General Public License. */
6
7 #include <time.h> 
8 #include <sys/time.h>
9
10 #if defined( SYS_BEOS )
11 #include <OS.h>
12 #include <signal.h>
13 #elif defined( SYS_DARWIN ) || defined( SYS_LINUX ) || defined( SYS_FREEBSD )
14 #include <pthread.h>
15 #elif defined( SYS_CYGWIN )
16 #include <windows.h>
17 #endif
18
19 #ifdef SYS_CYGWIN
20 #include <winsock2.h>
21 #include <ws2tcpip.h>
22 #else
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <netdb.h>
26 #include <netinet/in.h>
27 #endif
28
29 #include "hb.h"
30
31 /************************************************************************
32  * hb_get_date()
33  ************************************************************************
34  * Returns the current date in milliseconds.
35  * On Win32, we implement a gettimeofday emulation here because
36  * libdvdread and libmp4v2 use it without checking.
37  ************************************************************************/
38 #ifdef SYS_CYGWIN
39 struct timezone
40 {
41 };
42
43 int gettimeofday( struct timeval * tv, struct timezone * tz )
44 {
45     int tick;
46     tick        = GetTickCount();
47     tv->tv_sec  = tick / 1000;
48     tv->tv_usec = ( tick % 1000 ) * 1000;
49     return 0;
50 }
51 #endif
52
53 uint64_t hb_get_date()
54 {
55     struct timeval tv;
56     gettimeofday( &tv, NULL );
57     return( (uint64_t) tv.tv_sec * 1000 + (uint64_t) tv.tv_usec / 1000 );
58 }
59
60 /************************************************************************
61  * hb_snooze()
62  ************************************************************************
63  * Waits <delay> milliseconds.
64  ************************************************************************/
65 void hb_snooze( int delay )
66 {
67     if( delay < 1 )
68     {
69         return;
70     }
71 #if defined( SYS_BEOS )
72     snooze( 1000 * delay );
73 #elif defined( SYS_DARWIN ) || defined( SYS_LINUX ) || defined( SYS_FREEBSD )
74     usleep( 1000 * delay );
75 #elif defined( SYS_CYGWIN )
76     Sleep( delay );
77 #endif
78 }
79
80 /************************************************************************
81  * hb_get_cpu_count()
82  ************************************************************************
83  * Whenever possible, returns the number of CPUs on the current
84  * computer. Returns 1 otherwise.
85  * The detection is actually only performed on the first call.
86  ************************************************************************/
87 int hb_get_cpu_count()
88 {
89     static int cpu_count = 0;
90
91     if( cpu_count )
92     {
93         return cpu_count;
94     }
95     cpu_count = 1;
96
97 #if defined( SYS_BEOS )
98     {
99         system_info info;
100         get_system_info( &info );
101         cpu_count = info.cpu_count;
102     }
103
104 #elif defined( SYS_DARWIN ) || defined( SYS_FREEBSD )
105     FILE * info;
106     char   buffer[16];
107
108     if( ( info = popen( "/usr/sbin/sysctl hw.ncpu", "r" ) ) )
109     {
110         memset( buffer, 0, 16 );
111         if( fgets( buffer, 15, info ) )
112         {
113             if( sscanf( buffer, "hw.ncpu: %d", &cpu_count ) != 1 )
114             {
115                 cpu_count = 1;
116             }
117         }
118         fclose( info );
119     }
120
121 #elif defined( SYS_LINUX )
122     {
123         FILE * info;
124         char   buffer[8];
125
126         if( ( info = popen( "grep -c '^processor' /proc/cpuinfo",
127                             "r" ) ) )
128         {
129             memset( buffer, 0, 8 );
130             if( fgets( buffer, 7, info ) )
131             {
132                 if( sscanf( buffer, "%d", &cpu_count ) != 1 )
133                 {
134                     cpu_count = 1;
135                 }
136             }
137             fclose( info );
138         }
139     }
140
141 #elif defined( SYS_CYGWIN )
142     SYSTEM_INFO cpuinfo;
143     GetSystemInfo( &cpuinfo );
144     cpu_count = cpuinfo.dwNumberOfProcessors;
145 #endif
146
147     cpu_count = MAX( 1, cpu_count );
148     cpu_count = MIN( cpu_count, 8 );
149
150     return cpu_count;
151 }
152
153 /************************************************************************
154  * Get a tempory directory for HB
155  ***********************************************************************/
156 void hb_get_tempory_directory( hb_handle_t * h, char path[512] )
157 {
158     char base[512];
159
160     /* Create the base */
161 #ifdef SYS_CYGWIN
162     char *p;
163     int i_size = GetTempPath( 512, base );
164     if( i_size <= 0 || i_size >= 512 )
165     {
166         if( getcwd( base, 512 ) == NULL )
167             strcpy( base, "c:" ); /* Bad fallback but ... */
168     }
169
170     /* c:/path/ works like a charm under cygwin(win32?) so use it */
171     while( ( p = strchr( base, '\\' ) ) )
172         *p = '/';
173 #else
174     strcpy( base, "/tmp" );
175 #endif
176     /* I prefer to remove evntual last '/' (for cygwin) */
177     if( base[strlen(base)-1] == '/' )
178         base[strlen(base)-1] = '\0';
179
180     snprintf( path, 512, "%s/hb.%d", base, hb_get_pid( h ) );
181 }
182
183 /************************************************************************
184  * Get a tempory filename for HB
185  ***********************************************************************/
186 void hb_get_tempory_filename( hb_handle_t * h, char name[1024],
187                               char *fmt, ... )
188 {
189     va_list args;
190
191     hb_get_tempory_directory( h, name );
192     strcat( name, "/" );
193     
194     va_start( args, fmt );
195     vsnprintf( &name[strlen(name)], 1024 - strlen(name), fmt, args );
196     va_end( args );
197 }
198
199 /************************************************************************
200  * hb_mkdir
201  ************************************************************************
202  * Wrapper to the real mkdir, needed only because it doesn't take a
203  * second argument on Win32. Grrr.
204  ***********************************************************************/
205 void hb_mkdir( char * name )
206 {
207 #ifdef SYS_CYGWIN
208     mkdir( name );
209 #else
210     mkdir( name, 0755 );
211 #endif
212 }
213
214 /************************************************************************
215  * Portable thread implementation
216  ***********************************************************************/
217 struct hb_thread_s
218 {
219     char       * name;
220     int          priority;
221     void      (* function) ( void * );
222     void       * arg;
223
224     hb_lock_t  * lock;
225     int          exited;
226
227 #if defined( SYS_BEOS )
228     thread_id    thread;
229 #elif defined( SYS_DARWIN ) || defined( SYS_LINUX ) || defined( SYS_FREEBSD )
230     pthread_t    thread;
231 #elif defined( SYS_CYGWIN )
232     HANDLE       thread;
233 #endif
234 };
235
236 /************************************************************************
237  * hb_thread_func()
238  ************************************************************************
239  * We use it as the root routine for any thread, for two reasons:
240  *  + To set the thread priority on OS X (pthread_setschedparam() could
241  *    be called from hb_thread_init(), but it's nicer to do it as we
242  *    are sure it is done before the real routine starts)
243  *  + Get informed when the thread exits, so we know whether
244  *    hb_thread_close() will block or not.
245  ***********************************************************************/
246 static void hb_thread_func( void * _t )
247 {
248     hb_thread_t * t = (hb_thread_t *) _t;
249
250 #if defined( SYS_DARWIN )
251     /* Set the thread priority */
252     struct sched_param param;
253     memset( &param, 0, sizeof( struct sched_param ) );
254     param.sched_priority = t->priority;
255     pthread_setschedparam( pthread_self(), SCHED_OTHER, &param );
256 #endif
257
258 #if defined( SYS_BEOS )
259     signal( SIGINT, SIG_IGN );
260 #endif
261
262     /* Start the actual routine */
263     t->function( t->arg );
264
265     /* Inform that the thread can be joined now */
266     hb_log( "thread %d exited (\"%s\")", t->thread, t->name );
267     hb_lock( t->lock );
268     t->exited = 1;
269     hb_unlock( t->lock );
270 }
271
272 /************************************************************************
273  * hb_thread_init()
274  ************************************************************************
275  * name:     user-friendly name
276  * function: the thread routine
277  * arg:      argument of the routine
278  * priority: HB_LOW_PRIORITY or HB_NORMAL_PRIORITY
279  ***********************************************************************/
280 hb_thread_t * hb_thread_init( char * name, void (* function)(void *),
281                               void * arg, int priority )
282 {
283     hb_thread_t * t = calloc( sizeof( hb_thread_t ), 1 );
284
285     t->name     = strdup( name );
286     t->function = function;
287     t->arg      = arg;
288     t->priority = priority;
289
290     t->lock     = hb_lock_init();
291
292     /* Create and start the thread */
293 #if defined( SYS_BEOS )
294     t->thread = spawn_thread( (thread_func) hb_thread_func,
295                               name, priority, t );
296     resume_thread( t->thread );
297
298 #elif defined( SYS_DARWIN ) || defined( SYS_LINUX ) || defined( SYS_FREEBSD )
299     pthread_create( &t->thread, NULL,
300                     (void * (*)( void * )) hb_thread_func, t );
301
302 #elif defined( SYS_CYGWIN )
303     t->thread = CreateThread( NULL, 0,
304         (LPTHREAD_START_ROUTINE) hb_thread_func, t, 0, NULL );
305
306     /* Maybe use THREAD_PRIORITY_LOWEST instead */
307     if( priority == HB_LOW_PRIORITY )
308         SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL );
309 #endif
310
311     hb_log( "thread %d started (\"%s\")", t->thread, t->name );
312     return t;
313 }
314
315 /************************************************************************
316  * hb_thread_close()
317  ************************************************************************
318  * Joins the thread and frees memory.
319  ***********************************************************************/
320 void hb_thread_close( hb_thread_t ** _t )
321 {
322     hb_thread_t * t = *_t;
323
324     /* Join the thread */
325 #if defined( SYS_BEOS )
326     long exit_value;
327     wait_for_thread( t->thread, &exit_value );
328     
329 #elif defined( SYS_DARWIN ) || defined( SYS_LINUX ) || defined( SYS_FREEBSD )
330     pthread_join( t->thread, NULL );
331
332 #elif defined( SYS_CYGWIN )
333     WaitForSingleObject( t->thread, INFINITE );
334 #endif
335     
336     hb_log( "thread %d joined (\"%s\")",
337             t->thread, t->name );
338
339     hb_lock_close( &t->lock );
340     free( t->name );
341     free( t );
342     *_t = NULL; 
343 }
344
345 /************************************************************************
346  * hb_thread_has_exited()
347  ************************************************************************
348  * Returns 1 if the thread can be joined right away, 0 otherwise.
349  ***********************************************************************/
350 int hb_thread_has_exited( hb_thread_t * t )
351 {
352     int exited;
353
354     hb_lock( t->lock );
355     exited = t->exited;
356     hb_unlock( t->lock );
357
358     return exited;
359 }
360
361 /************************************************************************
362  * Portable mutex implementation
363  ***********************************************************************/
364 struct hb_lock_s
365 {
366 #if defined( SYS_BEOS )
367     sem_id          sem;
368 #elif defined( SYS_DARWIN ) || defined( SYS_LINUX ) || defined( SYS_FREEBSD )
369     pthread_mutex_t mutex;
370 #elif defined( SYS_CYGWIN )
371     HANDLE          mutex;
372 #endif
373 };
374
375 /************************************************************************
376  * hb_lock_init()
377  * hb_lock_close()
378  * hb_lock()
379  * hb_unlock()
380  ************************************************************************
381  * Basic wrappers to OS-specific semaphore or mutex functions.
382  ***********************************************************************/
383 hb_lock_t * hb_lock_init()
384 {
385     hb_lock_t * l = calloc( sizeof( hb_lock_t ), 1 );
386
387 #if defined( SYS_BEOS )
388     l->sem = create_sem( 1, "sem" );
389 #elif defined( SYS_DARWIN ) || defined( SYS_LINUX ) || defined( SYS_FREEBSD )
390     pthread_mutex_init( &l->mutex, NULL );
391 #elif defined( SYS_CYGWIN )
392     l->mutex = CreateMutex( 0, FALSE, 0 );
393 #endif
394
395     return l;
396 }
397
398 void hb_lock_close( hb_lock_t ** _l )
399 {
400     hb_lock_t * l = *_l;
401
402 #if defined( SYS_BEOS )
403     delete_sem( l->sem );
404 #elif defined( SYS_DARWIN ) || defined( SYS_LINUX ) || defined( SYS_FREEBSD )
405     pthread_mutex_destroy( &l->mutex );
406 #elif defined( SYS_CYGWIN )
407     CloseHandle( l->mutex );
408 #endif
409     free( l );
410
411     *_l = NULL;
412 }
413
414 void hb_lock( hb_lock_t * l )
415 {
416 #if defined( SYS_BEOS )
417     acquire_sem( l->sem );
418 #elif defined( SYS_DARWIN ) || defined( SYS_LINUX ) || defined( SYS_FREEBSD )
419     pthread_mutex_lock( &l->mutex );
420 #elif defined( SYS_CYGWIN )
421     WaitForSingleObject( l->mutex, INFINITE );
422 #endif
423 }
424
425 void hb_unlock( hb_lock_t * l )
426 {
427 #if defined( SYS_BEOS )
428     release_sem( l->sem );
429 #elif defined( SYS_DARWIN ) || defined( SYS_LINUX ) || defined( SYS_FREEBSD )
430     pthread_mutex_unlock( &l->mutex );
431 #elif defined( SYS_CYGWIN )
432     ReleaseMutex( l->mutex );
433 #endif
434 }
435
436 /************************************************************************
437  * Portable condition variable implementation
438  ***********************************************************************/
439 struct hb_cond_s
440 {
441 #if defined( SYS_BEOS )
442     int                 thread;
443 #elif defined( SYS_DARWIN ) || defined( SYS_LINUX ) || defined( SYS_FREEBSD )
444     pthread_cond_t      cond;
445 #elif defined( SYS_CYGWIN )
446     HANDLE              event;
447 #endif
448 };
449
450 /************************************************************************
451  * hb_cond_init()
452  * hb_cond_close()
453  * hb_cond_wait()
454  * hb_cond_signal()
455  ************************************************************************
456  * Win9x is not supported by this implementation (SignalObjectAndWait()
457  * only available on Windows 2000/XP).
458  ***********************************************************************/
459 hb_cond_t * hb_cond_init()
460 {
461     hb_cond_t * c = calloc( sizeof( hb_cond_t ), 1 );
462
463 #if defined( SYS_BEOS )
464     c->thread = -1;
465 #elif defined( SYS_DARWIN ) || defined( SYS_LINUX ) || defined( SYS_FREEBSD )
466     pthread_cond_init( &c->cond, NULL );
467 #elif defined( SYS_CYGWIN )
468     c->event = CreateEvent( NULL, FALSE, FALSE, NULL );
469 #endif
470
471     return c;
472 }
473
474 void hb_cond_close( hb_cond_t ** _c )
475 {
476     hb_cond_t * c = *_c;
477
478 #if defined( SYS_BEOS )
479 #elif defined( SYS_DARWIN ) || defined( SYS_LINUX ) || defined( SYS_FREEBSD )
480     pthread_cond_destroy( &c->cond );
481 #elif defined( SYS_CYGWIN )
482     CloseHandle( c->event );
483 #endif
484     free( c );
485
486     *_c = NULL;
487 }
488
489 void hb_cond_wait( hb_cond_t * c, hb_lock_t * lock )
490 {
491 #if defined( SYS_BEOS )
492     c->thread = find_thread( NULL );
493     release_sem( lock->sem );
494     suspend_thread( c->thread );
495     acquire_sem( lock->sem );
496     c->thread = -1;
497 #elif defined( SYS_DARWIN ) || defined( SYS_LINUX ) || defined( SYS_FREEBSD )
498     pthread_cond_wait( &c->cond, &lock->mutex );
499 #elif defined( SYS_CYGWIN )
500     SignalObjectAndWait( lock->mutex, c->event, INFINITE, FALSE );
501     WaitForSingleObject( lock->mutex, INFINITE );
502 #endif
503 }
504
505 void hb_cond_signal( hb_cond_t * c )
506 {
507 #if defined( SYS_BEOS )
508     while( c->thread != -1 )
509     {
510         thread_info info;
511         get_thread_info( c->thread, &info );
512         if( info.state == B_THREAD_SUSPENDED )
513         {
514             resume_thread( c->thread );
515             break;
516         }
517         /* Looks like we have been called between hb_cond_wait's
518            release_sem() and suspend_thread() lines. Wait until the
519            thread is actually suspended before we resume it */
520         snooze( 5000 );
521     }
522 #elif defined( SYS_DARWIN ) || defined( SYS_LINUX ) || defined( SYS_FREEBSD )
523     pthread_cond_signal( &c->cond );
524 #elif defined( SYS_CYGWIN )
525     PulseEvent( c->event );
526 #endif
527 }
528
529 /************************************************************************
530  * Network
531  ***********************************************************************/
532
533 struct hb_net_s
534 {
535     int socket;
536 };
537
538 hb_net_t * hb_net_open( char * address, int port )
539 {
540     hb_net_t * n = calloc( sizeof( hb_net_t ), 1 );
541
542     struct sockaddr_in   sock;
543     struct hostent     * host;
544
545     /* TODO: find out why this doesn't work on Win32 */
546     if( !( host = gethostbyname( address ) ) )
547     {
548         hb_log( "gethostbyname failed (%s)", address );
549         free( n );
550         return NULL;
551     }
552
553     memset( &sock, 0, sizeof( struct sockaddr_in ) );
554     sock.sin_family = host->h_addrtype;
555     sock.sin_port   = htons( port );
556     memcpy( &sock.sin_addr, host->h_addr, host->h_length );
557
558     if( ( n->socket = socket( host->h_addrtype, SOCK_STREAM, 0 ) ) < 0 )
559     {
560         hb_log( "socket failed" );
561         free( n );
562         return NULL;
563     }
564
565     if( connect( n->socket, (struct sockaddr *) &sock,
566                  sizeof( struct sockaddr_in ) ) < 0 )
567     {
568         hb_log( "connect failed" );
569         free( n );
570         return NULL;
571     }
572     
573     return n;
574 }
575
576 int hb_net_send( hb_net_t * n, char * buffer )
577 {
578     return send( n->socket, buffer, strlen( buffer ), 0 );
579 }
580
581 int hb_net_recv( hb_net_t * n, char * buffer, int size )
582 {
583     return recv( n->socket, buffer, size - 1, 0 );
584 }
585
586 void hb_net_close( hb_net_t ** _n )
587 {
588     hb_net_t * n = (hb_net_t *) *_n;
589     close( n->socket );
590     free( n );
591     *_n = NULL;
592 }
593