OSDN Git Service

fix some mingw warnings and a mingw build issue
[handbrake-jp/handbrake-jp-git.git] / libhb / hb.c
1 #include "hb.h"
2 #include "hbffmpeg.h"
3
4 #if defined( SYS_MINGW ) && defined( PTW32_STATIC_LIB )
5 #include <pthread.h>
6 #endif
7
8 struct hb_handle_s
9 {
10     int            id;
11     
12     /* The "Check for update" thread */
13     int            build;
14     char           version[32];
15     hb_thread_t  * update_thread;
16
17     /* This thread's only purpose is to check other threads'
18        states */
19     volatile int   die;
20     hb_thread_t  * main_thread;
21     int            pid;
22
23     /* DVD/file scan thread */
24     hb_list_t    * list_title;
25     hb_thread_t  * scan_thread;
26
27     /* The thread which processes the jobs. Others threads are launched
28        from this one (see work.c) */
29     hb_list_t    * jobs;
30     hb_job_t     * current_job;
31     int            job_count;
32     int            job_count_permanent;
33     volatile int   work_die;
34     int            work_error;
35     hb_thread_t  * work_thread;
36
37     int            cpu_count;
38
39     hb_lock_t    * state_lock;
40     hb_state_t     state;
41
42     int            paused;
43     hb_lock_t    * pause_lock;
44     /* For MacGui active queue
45        increments each time the scan thread completes*/
46     int            scanCount;
47     volatile int   scan_die;
48     
49     /* Stash of persistent data between jobs, for stuff
50        like correcting frame count and framerate estimates
51        on multi-pass encodes where frames get dropped.     */
52     hb_interjob_t * interjob;
53
54 };
55
56 hb_lock_t *hb_avcodec_lock;
57 hb_work_object_t * hb_objects = NULL;
58 int hb_instance_counter = 0;
59 int hb_process_initialized = 0;
60
61 static void thread_func( void * );
62
63 void hb_avcodec_init()
64 {
65     hb_avcodec_lock  = hb_lock_init();
66     av_register_all();
67 }
68
69 int hb_avcodec_open(AVCodecContext *avctx, AVCodec *codec)
70 {
71     int ret;
72     hb_lock( hb_avcodec_lock );
73     ret = avcodec_open(avctx, codec);
74     hb_unlock( hb_avcodec_lock );
75     return ret;
76 }
77
78 int hb_avcodec_close(AVCodecContext *avctx)
79 {
80     int ret;
81     hb_lock( hb_avcodec_lock );
82     ret = avcodec_close(avctx);
83     hb_unlock( hb_avcodec_lock );
84     return ret;
85 }
86
87 int hb_ff_layout_xlat(int64_t ff_channel_layout, int channels)
88 {
89     switch (ff_channel_layout)
90     {
91         case CH_LAYOUT_MONO:
92             return HB_INPUT_CH_LAYOUT_MONO;
93         case CH_LAYOUT_STEREO:
94             return HB_INPUT_CH_LAYOUT_STEREO;
95         case CH_LAYOUT_SURROUND:
96             return HB_INPUT_CH_LAYOUT_3F;
97         case CH_LAYOUT_4POINT0:
98             return HB_INPUT_CH_LAYOUT_3F1R;
99         case CH_LAYOUT_2_2:
100             return HB_INPUT_CH_LAYOUT_2F2R;
101         case CH_LAYOUT_QUAD:
102             return HB_INPUT_CH_LAYOUT_2F2R;
103         case CH_LAYOUT_5POINT0:
104             // ffmpeg like to neglect to signal LFE
105             if (channels == 6)
106                 return HB_INPUT_CH_LAYOUT_3F2R|HB_INPUT_CH_LAYOUT_HAS_LFE;
107             return HB_INPUT_CH_LAYOUT_3F2R;
108         case CH_LAYOUT_5POINT1:
109             return HB_INPUT_CH_LAYOUT_3F2R|HB_INPUT_CH_LAYOUT_HAS_LFE;
110         case CH_LAYOUT_5POINT0_BACK:
111             // ffmpeg like to neglect to signal LFE
112             if (channels == 6)
113                 return HB_INPUT_CH_LAYOUT_3F2R|HB_INPUT_CH_LAYOUT_HAS_LFE;
114             return HB_INPUT_CH_LAYOUT_3F2R;
115         case CH_LAYOUT_5POINT1_BACK:
116             return HB_INPUT_CH_LAYOUT_3F2R|HB_INPUT_CH_LAYOUT_HAS_LFE;
117         case CH_LAYOUT_7POINT0:
118             // ffmpeg like to neglect to signal LFE
119             if (channels == 8)
120                 return HB_INPUT_CH_LAYOUT_3F4R|HB_INPUT_CH_LAYOUT_HAS_LFE;
121             return HB_INPUT_CH_LAYOUT_3F4R;
122         case CH_LAYOUT_7POINT1:
123             return HB_INPUT_CH_LAYOUT_3F4R|HB_INPUT_CH_LAYOUT_HAS_LFE;
124         case CH_LAYOUT_STEREO_DOWNMIX:
125             return HB_INPUT_CH_LAYOUT_STEREO;
126         default:
127             return HB_INPUT_CH_LAYOUT_STEREO;
128     }
129     return HB_INPUT_CH_LAYOUT_STEREO;
130 }
131
132 /**
133  * Registers work objects, by adding the work object to a liked list.
134  * @param w Handle to hb_work_object_t to register.
135  */
136 void hb_register( hb_work_object_t * w )
137 {
138     w->next    = hb_objects;
139     hb_objects = w;
140 }
141
142 /**
143  * libhb initialization routine.
144  * @param verbose HB_DEBUG_NONE or HB_DEBUG_ALL.
145  * @param update_check signals libhb to check for updated version from HandBrake website.
146  * @return Handle to hb_handle_t for use on all subsequent calls to libhb.
147  */
148 hb_handle_t * hb_init( int verbose, int update_check )
149 {
150     if (!hb_process_initialized)
151     {
152 #if defined( SYS_MINGW ) && defined( PTW32_STATIC_LIB )
153         pthread_win32_process_attach_np();
154 #endif
155         hb_process_initialized =1;
156     }
157     
158     hb_handle_t * h = calloc( sizeof( hb_handle_t ), 1 );
159     uint64_t      date;
160
161     /* See hb_deep_log() and hb_log() in common.c */
162     global_verbosity_level = verbose;
163     if( verbose )
164         putenv( "HB_DEBUG=1" );
165     
166     h->id = hb_instance_counter++;
167     
168     /* Check for an update on the website if asked to */
169     h->build = -1;
170
171     if( update_check )
172     {
173         hb_log( "hb_init: checking for updates" );
174         date             = hb_get_date();
175         h->update_thread = hb_update_init( &h->build, h->version );
176
177         for( ;; )
178         {
179             if( hb_thread_has_exited( h->update_thread ) )
180             {
181                 /* Immediate success or failure */
182                 hb_thread_close( &h->update_thread );
183                 break;
184             }
185             if( hb_get_date() > date + 1000 )
186             {
187                 /* Still nothing after one second. Connection problem,
188                    let the thread die */
189                 hb_log( "hb_init: connection problem, not waiting for "
190                         "update_thread" );
191                 break;
192             }
193             hb_snooze( 500 );
194         }
195     }
196
197     /*
198      * Initialise buffer pool
199      */
200     hb_buffer_pool_init();
201
202     /* CPU count detection */
203     hb_log( "hb_init: checking cpu count" );
204     h->cpu_count = hb_get_cpu_count();
205
206     h->list_title = hb_list_init();
207     h->jobs       = hb_list_init();
208
209     h->state_lock  = hb_lock_init();
210     h->state.state = HB_STATE_IDLE;
211
212     h->pause_lock = hb_lock_init();
213
214     h->interjob = calloc( sizeof( hb_interjob_t ), 1 );
215
216     /* libavcodec */
217     hb_avcodec_init();
218
219     /* Start library thread */
220     hb_log( "hb_init: starting libhb thread" );
221     h->die         = 0;
222     h->main_thread = hb_thread_init( "libhb", thread_func, h,
223                                      HB_NORMAL_PRIORITY );
224     hb_register( &hb_sync_video );
225     hb_register( &hb_sync_audio );
226         hb_register( &hb_decmpeg2 );
227         hb_register( &hb_decvobsub );
228     hb_register( &hb_encvobsub );
229     hb_register( &hb_deccc608 );
230     hb_register( &hb_decsrtsub );
231         hb_register( &hb_render );
232         hb_register( &hb_encavcodec );
233         hb_register( &hb_encx264 );
234     hb_register( &hb_enctheora );
235         hb_register( &hb_deca52 );
236         hb_register( &hb_decdca );
237         hb_register( &hb_decavcodec );
238         hb_register( &hb_decavcodecv );
239         hb_register( &hb_decavcodecvi );
240         hb_register( &hb_decavcodecai );
241         hb_register( &hb_declpcm );
242         hb_register( &hb_encfaac );
243         hb_register( &hb_enclame );
244         hb_register( &hb_encvorbis );
245         hb_register( &hb_muxer );
246 #ifdef __APPLE__
247         hb_register( &hb_encca_aac );
248 #endif
249     
250     return h;
251 }
252
253 /**
254  * libhb initialization routine.
255  * This version is to use when calling the dylib, the macro hb_init isn't available from a dylib call!
256  * @param verbose HB_DEBUG_NONE or HB_DEBUG_ALL.
257  * @param update_check signals libhb to check for updated version from HandBrake website.
258  * @return Handle to hb_handle_t for use on all subsequent calls to libhb.
259  */
260 hb_handle_t * hb_init_dl( int verbose, int update_check )
261 {
262     hb_handle_t * h = calloc( sizeof( hb_handle_t ), 1 );
263     uint64_t      date;
264
265     /* See hb_log() in common.c */
266     if( verbose > HB_DEBUG_NONE )
267     {
268         putenv( "HB_DEBUG=1" );
269     }
270
271     h->id = hb_instance_counter++;
272
273     /* Check for an update on the website if asked to */
274     h->build = -1;
275
276     if( update_check )
277     {
278         hb_log( "hb_init: checking for updates" );
279         date             = hb_get_date();
280         h->update_thread = hb_update_init( &h->build, h->version );
281
282         for( ;; )
283         {
284             if( hb_thread_has_exited( h->update_thread ) )
285             {
286                 /* Immediate success or failure */
287                 hb_thread_close( &h->update_thread );
288                 break;
289             }
290             if( hb_get_date() > date + 1000 )
291             {
292                 /* Still nothing after one second. Connection problem,
293                    let the thread die */
294                 hb_log( "hb_init: connection problem, not waiting for "
295                         "update_thread" );
296                 break;
297             }
298             hb_snooze( 500 );
299         }
300     }
301
302     /* CPU count detection */
303     hb_log( "hb_init: checking cpu count" );
304     h->cpu_count = hb_get_cpu_count();
305
306     h->list_title = hb_list_init();
307     h->jobs       = hb_list_init();
308     h->current_job = NULL;
309
310     h->state_lock  = hb_lock_init();
311     h->state.state = HB_STATE_IDLE;
312
313     h->pause_lock = hb_lock_init();
314
315     /* libavcodec */
316     avcodec_init();
317     avcodec_register_all();
318
319     /* Start library thread */
320     hb_log( "hb_init: starting libhb thread" );
321     h->die         = 0;
322     h->main_thread = hb_thread_init( "libhb", thread_func, h,
323                                      HB_NORMAL_PRIORITY );
324
325     hb_register( &hb_sync_video );
326     hb_register( &hb_sync_audio );
327         hb_register( &hb_decmpeg2 );
328         hb_register( &hb_decvobsub );
329     hb_register( &hb_encvobsub );
330     hb_register( &hb_deccc608 );
331     hb_register( &hb_decsrtsub );
332         hb_register( &hb_render );
333         hb_register( &hb_encavcodec );
334         hb_register( &hb_encx264 );
335     hb_register( &hb_enctheora );
336         hb_register( &hb_deca52 );
337         hb_register( &hb_decdca );
338         hb_register( &hb_decavcodec );
339         hb_register( &hb_decavcodecv );
340         hb_register( &hb_decavcodecvi );
341         hb_register( &hb_decavcodecai );
342         hb_register( &hb_declpcm );
343         hb_register( &hb_encfaac );
344         hb_register( &hb_enclame );
345         hb_register( &hb_encvorbis );
346         hb_register( &hb_muxer );
347 #ifdef __APPLE__
348         hb_register( &hb_encca_aac );
349 #endif
350
351         return h;
352 }
353
354
355 /**
356  * Returns current version of libhb.
357  * @param h Handle to hb_handle_t.
358  * @return character array of version number.
359  */
360 char * hb_get_version( hb_handle_t * h )
361 {
362     return HB_PROJECT_VERSION;
363 }
364
365 /**
366  * Returns current build of libhb.
367  * @param h Handle to hb_handle_t.
368  * @return character array of build number.
369  */
370 int hb_get_build( hb_handle_t * h )
371 {
372     return HB_PROJECT_BUILD;
373 }
374
375 /**
376  * Checks for needed update.
377  * @param h Handle to hb_handle_t.
378  * @param version Pointer to handle where version will be copied.
379  * @return update indicator.
380  */
381 int hb_check_update( hb_handle_t * h, char ** version )
382 {
383     *version = ( h->build < 0 ) ? NULL : h->version;
384     return h->build;
385 }
386
387 /**
388  * Sets the cpu count to the desired value.
389  * @param h Handle to hb_handle_t
390  * @param cpu_count Number of CPUs to use.
391  */
392 void hb_set_cpu_count( hb_handle_t * h, int cpu_count )
393 {
394     cpu_count    = MAX( 1, cpu_count );
395     cpu_count    = MIN( cpu_count, 8 );
396     h->cpu_count = cpu_count;
397 }
398
399 /**
400  * Deletes current previews associated with titles
401  * @param h Handle to hb_handle_t
402  */
403 void hb_remove_previews( hb_handle_t * h )
404 {
405     char            filename[1024];
406     char            dirname[1024];
407     hb_title_t    * title;
408     int             i, count, len;
409     DIR           * dir;
410     struct dirent * entry;
411
412     memset( dirname, 0, 1024 );
413     hb_get_temporary_directory( dirname );
414     dir = opendir( dirname );
415     if (dir == NULL) return;
416
417     count = hb_list_count( h->list_title );
418     while( ( entry = readdir( dir ) ) )
419     {
420         if( entry->d_name[0] == '.' )
421         {
422             continue;
423         }
424         for( i = 0; i < count; i++ )
425         {
426             title = hb_list_item( h->list_title, i );
427             len = snprintf( filename, 1024, "%d_%d", h->id, title->index );
428             if (strncmp(entry->d_name, filename, len) == 0)
429             {
430                 snprintf( filename, 1024, "%s/%s", dirname, entry->d_name );
431                 unlink( filename );
432                 break;
433             }
434         }
435     }
436     closedir( dir );
437 }
438
439 /**
440  * Initializes a scan of the by calling hb_scan_init
441  * @param h Handle to hb_handle_t
442  * @param path location of VIDEO_TS folder.
443  * @param title_index Desired title to scan.  0 for all titles.
444  * @param preview_count Number of preview images to generate.
445  * @param store_previews Whether or not to write previews to disk.
446  */
447 void hb_scan( hb_handle_t * h, const char * path, int title_index,
448               int preview_count, int store_previews )
449 {
450     hb_title_t * title;
451
452     h->scan_die = 0;
453
454     /* Clean up from previous scan */
455     hb_remove_previews( h );
456     while( ( title = hb_list_item( h->list_title, 0 ) ) )
457     {
458         hb_list_rem( h->list_title, title );
459         hb_title_close( &title );
460     }
461
462     hb_log( "hb_scan: path=%s, title_index=%d", path, title_index );
463     h->scan_thread = hb_scan_init( h, &h->scan_die, path, title_index, 
464                                    h->list_title, preview_count, 
465                                    store_previews );
466 }
467
468 /**
469  * Returns the list of titles found.
470  * @param h Handle to hb_handle_t
471  * @return Handle to hb_list_t of the title list.
472  */
473 hb_list_t * hb_get_titles( hb_handle_t * h )
474 {
475     return h->list_title;
476 }
477
478 /**
479  * Create preview image of desired title a index of picture.
480  * @param h Handle to hb_handle_t.
481  * @param title Handle to hb_title_t of desired title.
482  * @param picture Index in title.
483  * @param buffer Handle to buufer were inage will be drawn.
484  */
485 void hb_get_preview( hb_handle_t * h, hb_title_t * title, int picture,
486                      uint8_t * buffer )
487 {
488     hb_job_t           * job = title->job;
489     char                 filename[1024];
490     FILE               * file;
491     uint8_t            * buf1, * buf2, * buf3, * buf4, * pen;
492     uint32_t             swsflags;
493     AVPicture            pic_in, pic_preview, pic_deint, pic_crop, pic_scale;
494     struct SwsContext  * context;
495     int                  i;
496     int                  rgb_width = ((job->width + 7) >> 3) << 3;
497     int                  preview_size;
498
499     swsflags = SWS_LANCZOS | SWS_ACCURATE_RND;
500
501     buf1 = av_malloc( avpicture_get_size( PIX_FMT_YUV420P, title->width, title->height ) );
502     buf2 = av_malloc( avpicture_get_size( PIX_FMT_YUV420P, title->width, title->height ) );
503     buf3 = av_malloc( avpicture_get_size( PIX_FMT_YUV420P, rgb_width, job->height ) );
504     buf4 = av_malloc( avpicture_get_size( PIX_FMT_RGB32, rgb_width, job->height ) );
505     avpicture_fill( &pic_in, buf1, PIX_FMT_YUV420P,
506                     title->width, title->height );
507     avpicture_fill( &pic_deint, buf2, PIX_FMT_YUV420P,
508                     title->width, title->height );
509     avpicture_fill( &pic_scale, buf3, PIX_FMT_YUV420P,
510                     rgb_width, job->height );
511     avpicture_fill( &pic_preview, buf4, PIX_FMT_RGB32,
512                     rgb_width, job->height );
513
514     // Allocate the AVPicture frames and fill in
515
516     memset( filename, 0, 1024 );
517
518     hb_get_tempory_filename( h, filename, "%d_%d_%d",
519                              h->id, title->index, picture );
520
521     file = fopen( filename, "rb" );
522     if( !file )
523     {
524         hb_log( "hb_get_preview: fopen failed" );
525         return;
526     }
527
528     fread( buf1, avpicture_get_size( PIX_FMT_YUV420P, title->width, title->height), 1, file );
529     fclose( file );
530
531     if( job->deinterlace )
532     {
533         // Deinterlace and crop
534         avpicture_deinterlace( &pic_deint, &pic_in, PIX_FMT_YUV420P, title->width, title->height );
535         av_picture_crop( &pic_crop, &pic_deint, PIX_FMT_YUV420P, job->crop[0], job->crop[2] );
536     }
537     else
538     {
539         // Crop
540         av_picture_crop( &pic_crop, &pic_in, PIX_FMT_YUV420P, job->crop[0], job->crop[2] );
541     }
542
543     // Get scaling context
544     context = sws_getContext(title->width  - (job->crop[2] + job->crop[3]),
545                              title->height - (job->crop[0] + job->crop[1]),
546                              PIX_FMT_YUV420P,
547                              job->width, job->height, PIX_FMT_YUV420P,
548                              swsflags, NULL, NULL, NULL);
549
550     // Scale
551     sws_scale(context,
552               pic_crop.data, pic_crop.linesize,
553               0, title->height - (job->crop[0] + job->crop[1]),
554               pic_scale.data, pic_scale.linesize);
555
556     // Free context
557     sws_freeContext( context );
558
559     // Get preview context
560     context = sws_getContext(rgb_width, job->height, PIX_FMT_YUV420P,
561                               rgb_width, job->height, PIX_FMT_RGB32,
562                               swsflags, NULL, NULL, NULL);
563
564     // Create preview
565     sws_scale(context,
566               pic_scale.data, pic_scale.linesize,
567               0, job->height,
568               pic_preview.data, pic_preview.linesize);
569
570     // Free context
571     sws_freeContext( context );
572
573     preview_size = pic_preview.linesize[0];
574     pen = buffer;
575     for( i = 0; i < job->height; i++ )
576     {
577         memcpy( pen, buf4 + preview_size * i, 4 * job->width );
578         pen += 4 * job->width;
579     }
580
581     // Clean up
582     avpicture_free( &pic_preview );
583     avpicture_free( &pic_scale );
584     avpicture_free( &pic_deint );
585     avpicture_free( &pic_in );
586 }
587
588  /**
589  * Analyzes a frame to detect interlacing artifacts
590  * and returns true if interlacing (combing) is found.
591  *
592  * Code taken from Thomas Oestreich's 32detect filter
593  * in the Transcode project, with minor formatting changes.
594  *
595  * @param buf         An hb_buffer structure holding valid frame data
596  * @param width       The frame's width in pixels
597  * @param height      The frame's height in pixels
598  * @param color_equal Sensitivity for detecting similar colors
599  * @param color_diff  Sensitivity for detecting different colors
600  * @param threshold   Sensitivity for flagging planes as combed
601  * @param prog_equal  Sensitivity for detecting similar colors on progressive frames
602  * @param prog_diff   Sensitivity for detecting different colors on progressive frames
603  * @param prog_threshold Sensitivity for flagging progressive frames as combed
604  */
605 int hb_detect_comb( hb_buffer_t * buf, int width, int height, int color_equal, int color_diff, int threshold, int prog_equal, int prog_diff, int prog_threshold )
606 {
607     int j, k, n, off, cc_1, cc_2, cc[3];
608         // int flag[3] ; // debugging flag
609     uint16_t s1, s2, s3, s4;
610     cc_1 = 0; cc_2 = 0;
611
612     int offset = 0;
613     
614     if ( buf->flags & 16 )
615     {
616         /* Frame is progressive, be more discerning. */
617         color_diff = prog_diff;
618         color_equal = prog_equal;
619         threshold = prog_threshold;
620     }
621
622     /* One pas for Y, one pass for Cb, one pass for Cr */    
623     for( k = 0; k < 3; k++ )
624     {
625         if( k == 1 )
626         {
627             /* Y has already been checked, now offset by Y's dimensions
628                and divide all the other values by 2, since Cr and Cb
629                are half-size compared to Y.                               */
630             offset = width * height;
631             width >>= 1;
632             height >>= 1;
633         }
634         else if ( k == 2 )
635         {
636             /* Y and Cb are done, so the offset needs to be bumped
637                so it's width*height + (width / 2) * (height / 2)  */
638             offset *= 5/4;
639         }
640
641         for( j = 0; j < width; ++j )
642         {
643             off = 0;
644
645             for( n = 0; n < ( height - 4 ); n = n + 2 )
646             {
647                 /* Look at groups of 4 sequential horizontal lines */
648                 s1 = ( ( buf->data + offset )[ off + j             ] & 0xff );
649                 s2 = ( ( buf->data + offset )[ off + j + width     ] & 0xff );
650                 s3 = ( ( buf->data + offset )[ off + j + 2 * width ] & 0xff );
651                 s4 = ( ( buf->data + offset )[ off + j + 3 * width ] & 0xff );
652
653                 /* Note if the 1st and 2nd lines are more different in
654                    color than the 1st and 3rd lines are similar in color.*/
655                 if ( ( abs( s1 - s3 ) < color_equal ) &&
656                      ( abs( s1 - s2 ) > color_diff ) )
657                         ++cc_1;
658
659                 /* Note if the 2nd and 3rd lines are more different in
660                    color than the 2nd and 4th lines are similar in color.*/
661                 if ( ( abs( s2 - s4 ) < color_equal ) &&
662                      ( abs( s2 - s3 ) > color_diff) )
663                         ++cc_2;
664
665                 /* Now move down 2 horizontal lines before starting over.*/
666                 off += 2 * width;
667             }
668         }
669
670         // compare results
671         /*  The final cc score for a plane is the percentage of combed pixels it contains.
672             Because sensitivity goes down to hundreths of a percent, multiply by 1000
673             so it will be easy to compare against the threhold value which is an integer. */
674         cc[k] = (int)( ( cc_1 + cc_2 ) * 1000.0 / ( width * height ) );
675     }
676
677
678     /* HandBrake is all yuv420, so weight the average percentage of all 3 planes accordingly.*/
679     int average_cc = ( 2 * cc[0] + ( cc[1] / 2 ) + ( cc[2] / 2 ) ) / 3;
680     
681     /* Now see if that average percentage of combed pixels surpasses the threshold percentage given by the user.*/
682     if( average_cc > threshold )
683     {
684 #if 0
685             hb_log("Average %i combed (Threshold %i) %i/%i/%i | PTS: %"PRId64" (%fs) %s", average_cc, threshold, cc[0], cc[1], cc[2], buf->start, (float)buf->start / 90000, (buf->flags & 16) ? "Film" : "Video" );
686 #endif
687         return 1;
688     }
689
690 #if 0
691     hb_log("SKIPPED Average %i combed (Threshold %i) %i/%i/%i | PTS: %"PRId64" (%fs) %s", average_cc, threshold, cc[0], cc[1], cc[2], buf->start, (float)buf->start / 90000, (buf->flags & 16) ? "Film" : "Video" );
692 #endif
693
694     /* Reaching this point means no combing detected. */
695     return 0;
696
697 }
698
699 /**
700  * Calculates job width and height for anamorphic content,
701  *
702  * @param job Handle to hb_job_t
703  * @param output_width Pointer to returned storage width
704  * @param output_height Pointer to returned storage height
705  * @param output_par_width Pointer to returned pixel width
706  @ param output_par_height Pointer to returned pixel height
707  */
708 void hb_set_anamorphic_size( hb_job_t * job,
709         int *output_width, int *output_height,
710         int *output_par_width, int *output_par_height )
711 {
712     /* Set up some variables to make the math easier to follow. */
713     hb_title_t * title = job->title;
714     int cropped_width = title->width - job->crop[2] - job->crop[3] ;
715     int cropped_height = title->height - job->crop[0] - job->crop[1] ;
716     double storage_aspect = (double)cropped_width / (double)cropped_height;
717     int mod = job->modulus ? job->modulus : 16;
718     double aspect = title->aspect;
719     
720     int pixel_aspect_width  = job->anamorphic.par_width;
721     int pixel_aspect_height = job->anamorphic.par_height;
722
723     /* If a source was really NTSC or PAL and the user specified ITU PAR
724        values, replace the standard PAR values with the ITU broadcast ones. */
725     if( title->width == 720 && job->anamorphic.itu_par )
726     {
727         // convert aspect to a scaled integer so we can test for 16:9 & 4:3
728         // aspect ratios ignoring insignificant differences in the LSBs of
729         // the floating point representation.
730         int iaspect = aspect * 9.;
731
732         /* Handle ITU PARs */
733         if (title->height == 480)
734         {
735             /* It's NTSC */
736             if (iaspect == 16)
737             {
738                 /* It's widescreen */
739                 pixel_aspect_width = 40;
740                 pixel_aspect_height = 33;
741             }
742             else if (iaspect == 12)
743             {
744                 /* It's 4:3 */
745                 pixel_aspect_width = 10;
746                 pixel_aspect_height = 11;
747             }
748         }
749         else if (title->height == 576)
750         {
751             /* It's PAL */
752             if(iaspect == 16)
753             {
754                 /* It's widescreen */
755                 pixel_aspect_width = 16;
756                 pixel_aspect_height = 11;
757             }
758             else if (iaspect == 12)
759             {
760                 /* It's 4:3 */
761                 pixel_aspect_width = 12;
762                 pixel_aspect_height = 11;
763             }
764         }
765     }
766
767     /* Figure out what width the source would display at. */
768     int source_display_width = cropped_width * (double)pixel_aspect_width /
769                                (double)pixel_aspect_height ;
770
771     /*
772        3 different ways of deciding output dimensions:
773         - 1: Strict anamorphic, preserve source dimensions
774         - 2: Loose anamorphic, round to mod16 and preserve storage aspect ratio
775         - 3: Power user anamorphic, specify everything
776     */
777     int width, height;
778     switch( job->anamorphic.mode )
779     {
780         case 1:
781             /* Strict anamorphic */
782             *output_width = cropped_width;
783             *output_height = cropped_height;
784             *output_par_width = title->pixel_aspect_width;
785             *output_par_height = title->pixel_aspect_height;
786         break;
787
788         case 2:
789             /* "Loose" anamorphic.
790                 - Uses mod16-compliant dimensions,
791                 - Allows users to set the width
792             */
793             width = job->width;
794             // height: Gets set later, ignore user job->height value
795
796             /* Gotta handle bounding dimensions.
797                If the width is too big, just reset it with no rescaling.
798                Instead of using the aspect-scaled job height,
799                we need to see if the job width divided by the storage aspect
800                is bigger than the max. If so, set it to the max (this is sloppy).
801                If not, set job height to job width divided by storage aspect.
802             */
803
804             if ( job->maxWidth && (job->maxWidth < job->width) )
805                 width = job->maxWidth;
806
807             /* Time to get picture width that divide cleanly.*/
808             width  = MULTIPLE_MOD( width, mod);
809
810             /* Verify these new dimensions don't violate max height and width settings */
811             if ( job->maxWidth && (job->maxWidth < job->width) )
812                 width = job->maxWidth;
813
814             height = ((double)width / storage_aspect) + 0.5;
815             
816             if ( job->maxHeight && (job->maxHeight < height) )
817                 height = job->maxHeight;
818
819             /* Time to get picture height that divide cleanly.*/
820             height = MULTIPLE_MOD( height, mod);
821
822             /* Verify these new dimensions don't violate max height and width settings */
823             if ( job->maxHeight && (job->maxHeight < height) )
824                 height = job->maxHeight;
825
826             /* The film AR is the source's display width / cropped source height.
827                The output display width is the output height * film AR.
828                The output PAR is the output display width / output storage width. */
829             pixel_aspect_width = height * source_display_width / cropped_height;
830             pixel_aspect_height = width;
831
832             /* Pass the results back to the caller */
833             *output_width = width;
834             *output_height = height;
835         break;
836             
837         case 3:
838             /* Anamorphic 3: Power User Jamboree
839                - Set everything based on specified values */
840             
841             /* Use specified storage dimensions */
842             width = job->width;
843             height = job->height;
844             
845             /* Bind to max dimensions */
846             if( job->maxWidth && width > job->maxWidth )
847                 width = job->maxWidth;
848             if( job->maxHeight && height > job->maxHeight )
849                 height = job->maxHeight;
850             
851             /* Time to get picture dimensions that divide cleanly.*/
852             width  = MULTIPLE_MOD( width, mod);
853             height = MULTIPLE_MOD( height, mod);
854             
855             /* Verify we're still within max dimensions */
856             if( job->maxWidth && width > job->maxWidth )
857                 width = job->maxWidth - (mod/2);
858             if( job->maxHeight && height > job->maxHeight )
859                 height = job->maxHeight - (mod/2);
860                 
861             /* Re-ensure we have picture dimensions that divide cleanly. */
862             width  = MULTIPLE_MOD( width, mod );
863             height = MULTIPLE_MOD( height, mod );
864             
865             /* That finishes the storage dimensions. On to display. */            
866             if( job->anamorphic.dar_width && job->anamorphic.dar_height )
867             {
868                 /* We need to adjust the PAR to produce this aspect. */
869                 pixel_aspect_width = height * job->anamorphic.dar_width / job->anamorphic.dar_height;
870                 pixel_aspect_height = width;
871             }
872             else
873             {
874                 /* If we're doing ana 3 and not specifying a DAR, care needs to be taken.
875                    This indicates a PAR is potentially being set by the interface. But
876                    this is an output PAR, to correct a source, and it should not be assumed
877                    that it properly creates a display aspect ratio when applied to the source,
878                    which could easily be stored in a different resolution. */
879                 if( job->anamorphic.keep_display_aspect )
880                 {
881                     /* We can ignore the possibility of a PAR change */
882                     pixel_aspect_width = height * ( (double)source_display_width / (double)cropped_height );
883                     pixel_aspect_height = width;
884                 }
885                 else
886                 {
887                     int output_display_width = width * (double)pixel_aspect_width /
888                         (double)pixel_aspect_height;
889                     pixel_aspect_width = output_display_width;
890                     pixel_aspect_height = width;
891                 }
892             }
893             
894             /* Back to caller */
895             *output_width = width;
896             *output_height = height;
897         break;
898     }
899     
900     /* While x264 is smart enough to reduce fractions on its own, libavcodec
901        needs some help with the math, so lose superfluous factors.            */
902     hb_reduce( output_par_width, output_par_height,
903                pixel_aspect_width, pixel_aspect_height );
904 }
905
906 /**
907  * Calculates job width, height, and cropping parameters.
908  * @param job Handle to hb_job_t.
909  * @param aspect Desired aspect ratio. Value of -1 uses title aspect.
910  * @param pixels Maximum desired pixel count.
911  */
912 void hb_set_size( hb_job_t * job, double aspect, int pixels )
913 {
914     hb_title_t * title = job->title;
915
916     int croppedWidth  = title->width - title->crop[2] - title->crop[3];
917     int croppedHeight = title->height - title->crop[0] - title->crop[1];
918     double croppedAspect = title->aspect * title->height * croppedWidth /
919                            croppedHeight / title->width;
920     int addCrop;
921     int i, w, h;
922
923     if( aspect <= 0 )
924     {
925         /* Keep the best possible aspect ratio */
926         aspect = croppedAspect;
927     }
928
929     /* Crop if necessary to obtain the desired ratio */
930     memcpy( job->crop, title->crop, 4 * sizeof( int ) );
931     if( aspect < croppedAspect )
932     {
933         /* Need to crop on the left and right */
934         addCrop = croppedWidth - aspect * croppedHeight * title->width /
935                     title->aspect / title->height;
936         if( addCrop & 3 )
937         {
938             addCrop = ( addCrop + 1 ) / 2;
939             job->crop[2] += addCrop;
940             job->crop[3] += addCrop;
941         }
942         else if( addCrop & 2 )
943         {
944             addCrop /= 2;
945             job->crop[2] += addCrop - 1;
946             job->crop[3] += addCrop + 1;
947         }
948         else
949         {
950             addCrop /= 2;
951             job->crop[2] += addCrop;
952             job->crop[3] += addCrop;
953         }
954     }
955     else if( aspect > croppedAspect )
956     {
957         /* Need to crop on the top and bottom */
958         addCrop = croppedHeight - croppedWidth * title->aspect *
959             title->height / aspect / title->width;
960         if( addCrop & 3 )
961         {
962             addCrop = ( addCrop + 1 ) / 2;
963             job->crop[0] += addCrop;
964             job->crop[1] += addCrop;
965         }
966         else if( addCrop & 2 )
967         {
968             addCrop /= 2;
969             job->crop[0] += addCrop - 1;
970             job->crop[1] += addCrop + 1;
971         }
972         else
973         {
974             addCrop /= 2;
975             job->crop[0] += addCrop;
976             job->crop[1] += addCrop;
977         }
978     }
979
980     /* Compute a resolution from the number of pixels and aspect */
981     for( i = 0;; i++ )
982     {
983         w = 16 * i;
984         h = MULTIPLE_16( (int)( (double)w / aspect ) );
985         if( w * h > pixels )
986         {
987             break;
988         }
989     }
990     i--;
991     job->width  = 16 * i;
992     job->height = MULTIPLE_16( (int)( (double)job->width / aspect ) );
993 }
994
995 /**
996  * Returns the number of jobs in the queue.
997  * @param h Handle to hb_handle_t.
998  * @return Number of jobs.
999  */
1000 int hb_count( hb_handle_t * h )
1001 {
1002     return hb_list_count( h->jobs );
1003 }
1004
1005 /**
1006  * Returns handle to job at index i within the job list.
1007  * @param h Handle to hb_handle_t.
1008  * @param i Index of job.
1009  * @returns Handle to hb_job_t of desired job.
1010  */
1011 hb_job_t * hb_job( hb_handle_t * h, int i )
1012 {
1013     return hb_list_item( h->jobs, i );
1014 }
1015
1016 hb_job_t * hb_current_job( hb_handle_t * h )
1017 {
1018     return( h->current_job );
1019 }
1020
1021 /**
1022  * Adds a job to the job list.
1023  * @param h Handle to hb_handle_t.
1024  * @param job Handle to hb_job_t.
1025  */
1026 void hb_add( hb_handle_t * h, hb_job_t * job )
1027 {
1028     hb_job_t      * job_copy;
1029     hb_title_t    * title,    * title_copy;
1030     hb_chapter_t  * chapter,  * chapter_copy;
1031     hb_audio_t    * audio;
1032     hb_subtitle_t * subtitle, * subtitle_copy;
1033     int             i;
1034     char            audio_lang[4];
1035
1036     /* Copy the title */
1037     title      = job->title;
1038     title_copy = malloc( sizeof( hb_title_t ) );
1039     memcpy( title_copy, title, sizeof( hb_title_t ) );
1040
1041     title_copy->list_chapter = hb_list_init();
1042     for( i = 0; i < hb_list_count( title->list_chapter ); i++ )
1043     {
1044         chapter      = hb_list_item( title->list_chapter, i );
1045         chapter_copy = malloc( sizeof( hb_chapter_t ) );
1046         memcpy( chapter_copy, chapter, sizeof( hb_chapter_t ) );
1047         hb_list_add( title_copy->list_chapter, chapter_copy );
1048     }
1049
1050     /*
1051      * Copy the metadata
1052      */
1053     if( title->metadata )
1054     {
1055         title_copy->metadata = malloc( sizeof( hb_metadata_t ) );
1056         
1057         if( title_copy->metadata ) 
1058         {
1059             memcpy( title_copy->metadata, title->metadata, sizeof( hb_metadata_t ) );
1060
1061             /*
1062              * Need to copy the artwork seperatly (TODO).
1063              */
1064             if( title->metadata->coverart )
1065             {
1066                 title_copy->metadata->coverart = malloc( title->metadata->coverart_size );
1067                 if( title_copy->metadata->coverart )
1068                 {
1069                     memcpy( title_copy->metadata->coverart, title->metadata->coverart,
1070                             title->metadata->coverart_size );
1071                 } else {
1072                     title_copy->metadata->coverart_size = 0; 
1073                 }
1074             }
1075         }
1076     }
1077
1078     /* Copy the audio track(s) we want */
1079     title_copy->list_audio = hb_list_init();
1080
1081     for( i = 0; i < hb_list_count(job->list_audio); i++ )
1082     {
1083         if( ( audio = hb_list_item( job->list_audio, i ) ) )
1084         {
1085             hb_list_add( title_copy->list_audio, hb_audio_copy(audio) );
1086         }
1087     }
1088
1089     title_copy->list_subtitle = hb_list_init();
1090
1091     /*
1092      * The following code is confusing, there are two ways in which
1093      * we select subtitles and it depends on whether this is single or
1094      * two pass mode.
1095      *
1096      * subtitle_scan may be enabled, in which case the first pass
1097      * scans all subtitles of that language. The second pass does not
1098      * select any because they are set at the end of the first pass.
1099      *
1100      * We may have manually selected a subtitle, in which case that is
1101      * selected in the first pass of a single pass, or the second of a
1102      * two pass.
1103      */
1104     memset( audio_lang, 0, sizeof( audio_lang ) );
1105
1106     if ( job->indepth_scan ) {
1107
1108         /*
1109          * Find the first audio language that is being encoded
1110          */
1111         for( i = 0; i < hb_list_count(job->list_audio); i++ )
1112         {
1113             if( ( audio = hb_list_item( job->list_audio, i ) ) )
1114             {
1115                 strncpy(audio_lang, audio->config.lang.iso639_2, sizeof(audio_lang));
1116                 break;
1117             }
1118         }
1119     }
1120
1121     /*
1122      * If doing a subtitle scan then add all the matching subtitles for this
1123      * language.
1124      */
1125     if ( job->indepth_scan )
1126     {
1127         for( i=0; i < hb_list_count( title->list_subtitle ); i++ )
1128         {
1129             subtitle = hb_list_item( title->list_subtitle, i );
1130             if( strcmp( subtitle->iso639_2, audio_lang ) == 0 &&
1131                 subtitle->source == VOBSUB )
1132             {
1133                 /*
1134                  * Matched subtitle language with audio language, so
1135                  * add this to our list to scan.
1136                  *
1137                  * We will update the subtitle list on the second pass
1138                  * later after the first pass has completed.
1139                  */
1140                 subtitle_copy = malloc( sizeof( hb_subtitle_t ) );
1141                 memcpy( subtitle_copy, subtitle, sizeof( hb_subtitle_t ) );
1142                 hb_list_add( title_copy->list_subtitle, subtitle_copy );
1143             }
1144         }
1145     } else {
1146         /*
1147          * Not doing a subtitle scan in this pass, but maybe we are in the
1148          * first pass?
1149          */
1150         if( job->pass != 1 )
1151         {
1152             /*
1153              * Copy all of them from the input job, to the title_copy/job_copy.
1154              */
1155             for(  i = 0; i < hb_list_count(job->list_subtitle); i++ ) {
1156                 if( ( subtitle = hb_list_item( job->list_subtitle, i ) ) )
1157                 {
1158                     subtitle_copy = malloc( sizeof( hb_subtitle_t ) );
1159                     memcpy( subtitle_copy, subtitle, sizeof( hb_subtitle_t ) );
1160                     hb_list_add( title_copy->list_subtitle, subtitle_copy );
1161                 }
1162             }
1163         }
1164     }
1165
1166     /* Copy the job */
1167     job_copy        = calloc( sizeof( hb_job_t ), 1 );
1168     memcpy( job_copy, job, sizeof( hb_job_t ) );
1169     title_copy->job = job_copy;
1170     job_copy->title = title_copy;
1171     job_copy->list_audio = title_copy->list_audio;
1172     job_copy->list_subtitle = title_copy->list_subtitle;   // sharing list between title and job
1173     job_copy->file  = strdup( job->file );
1174     job_copy->h     = h;
1175     job_copy->pause = h->pause_lock;
1176
1177     /* Copy the job filter list */
1178     if( job->filters )
1179     {
1180         int i;
1181         int filter_count = hb_list_count( job->filters );
1182         job_copy->filters = hb_list_init();
1183         for( i = 0; i < filter_count; i++ )
1184         {
1185             /*
1186              * Copy the filters, since the MacGui reuses the global filter objects
1187              * meaning that queued up jobs overwrite the previous filter settings.
1188              * In reality, settings is probably the only field that needs duplicating
1189              * since it's the only value that is ever changed. But name is duplicated
1190              * as well for completeness. Not copying private_data since it gets
1191              * created for each job in renderInit.
1192              */
1193             hb_filter_object_t * filter = hb_list_item( job->filters, i );
1194             hb_filter_object_t * filter_copy = malloc( sizeof( hb_filter_object_t ) );
1195             memcpy( filter_copy, filter, sizeof( hb_filter_object_t ) );
1196             if( filter->name )
1197                 filter_copy->name = strdup( filter->name );
1198             if( filter->settings )
1199                 filter_copy->settings = strdup( filter->settings );
1200             hb_list_add( job_copy->filters, filter_copy );
1201         }
1202     }
1203
1204     /* Add the job to the list */
1205     hb_list_add( h->jobs, job_copy );
1206     h->job_count = hb_count(h);
1207     h->job_count_permanent++;
1208 }
1209
1210 /**
1211  * Removes a job from the job list.
1212  * @param h Handle to hb_handle_t.
1213  * @param job Handle to hb_job_t.
1214  */
1215 void hb_rem( hb_handle_t * h, hb_job_t * job )
1216 {
1217     hb_list_rem( h->jobs, job );
1218
1219     h->job_count = hb_count(h);
1220     if (h->job_count_permanent)
1221         h->job_count_permanent--;
1222
1223     /* XXX free everything XXX */
1224 }
1225
1226 /**
1227  * Starts the conversion process.
1228  * Sets state to HB_STATE_WORKING.
1229  * calls hb_work_init, to launch work thread. Stores handle to work thread.
1230  * @param h Handle to hb_handle_t.
1231  */
1232 void hb_start( hb_handle_t * h )
1233 {
1234     /* XXX Hack */
1235     h->job_count = hb_list_count( h->jobs );
1236     h->job_count_permanent = h->job_count;
1237
1238     hb_lock( h->state_lock );
1239     h->state.state = HB_STATE_WORKING;
1240 #define p h->state.param.working
1241     p.progress  = 0.0;
1242     p.job_cur   = 1;
1243     p.job_count = h->job_count;
1244     p.rate_cur  = 0.0;
1245     p.rate_avg  = 0.0;
1246     p.hours     = -1;
1247     p.minutes   = -1;
1248     p.seconds   = -1;
1249     p.sequence_id = 0;
1250 #undef p
1251     hb_unlock( h->state_lock );
1252
1253     h->paused = 0;
1254
1255     h->work_die    = 0;
1256     h->work_thread = hb_work_init( h->jobs, h->cpu_count,
1257                                    &h->work_die, &h->work_error, &h->current_job );
1258 }
1259
1260 /**
1261  * Pauses the conversion process.
1262  * @param h Handle to hb_handle_t.
1263  */
1264 void hb_pause( hb_handle_t * h )
1265 {
1266     if( !h->paused )
1267     {
1268         hb_lock( h->pause_lock );
1269         h->paused = 1;
1270
1271         hb_current_job( h )->st_pause_date = hb_get_date();
1272
1273         hb_lock( h->state_lock );
1274         h->state.state = HB_STATE_PAUSED;
1275         hb_unlock( h->state_lock );
1276     }
1277 }
1278
1279 /**
1280  * Resumes the conversion process.
1281  * @param h Handle to hb_handle_t.
1282  */
1283 void hb_resume( hb_handle_t * h )
1284 {
1285     if( h->paused )
1286     {
1287 #define job hb_current_job( h )
1288         if( job->st_pause_date != -1 )
1289         {
1290            job->st_paused += hb_get_date() - job->st_pause_date;
1291         }
1292 #undef job
1293
1294         hb_unlock( h->pause_lock );
1295         h->paused = 0;
1296     }
1297 }
1298
1299 /**
1300  * Stops the conversion process.
1301  * @param h Handle to hb_handle_t.
1302  */
1303 void hb_stop( hb_handle_t * h )
1304 {
1305     h->work_die = 1;
1306
1307     h->job_count = hb_count(h);
1308     h->job_count_permanent = 0;
1309
1310     hb_resume( h );
1311 }
1312
1313 /**
1314  * Stops the conversion process.
1315  * @param h Handle to hb_handle_t.
1316  */
1317 void hb_scan_stop( hb_handle_t * h )
1318 {
1319     h->scan_die = 1;
1320
1321     h->job_count = hb_count(h);
1322     h->job_count_permanent = 0;
1323
1324     hb_resume( h );
1325 }
1326
1327 /**
1328  * Returns the state of the conversion process.
1329  * @param h Handle to hb_handle_t.
1330  * @param s Handle to hb_state_t which to copy the state data.
1331  */
1332 void hb_get_state( hb_handle_t * h, hb_state_t * s )
1333 {
1334     hb_lock( h->state_lock );
1335
1336     memcpy( s, &h->state, sizeof( hb_state_t ) );
1337     if ( h->state.state == HB_STATE_SCANDONE || h->state.state == HB_STATE_WORKDONE )
1338         h->state.state = HB_STATE_IDLE;
1339
1340     hb_unlock( h->state_lock );
1341 }
1342
1343 void hb_get_state2( hb_handle_t * h, hb_state_t * s )
1344 {
1345     hb_lock( h->state_lock );
1346
1347     memcpy( s, &h->state, sizeof( hb_state_t ) );
1348
1349     hb_unlock( h->state_lock );
1350 }
1351
1352 /**
1353  * Called in MacGui in UpdateUI to check
1354  *  for a new scan being completed to set a new source
1355  */
1356 int hb_get_scancount( hb_handle_t * h)
1357  {
1358      return h->scanCount;
1359  }
1360
1361 /**
1362  * Closes access to libhb by freeing the hb_handle_t handle ontained in hb_init.
1363  * @param _h Pointer to handle to hb_handle_t.
1364  */
1365 void hb_close( hb_handle_t ** _h )
1366 {
1367     hb_handle_t * h = *_h;
1368     hb_title_t * title;
1369
1370     h->die = 1;
1371     
1372     hb_thread_close( &h->main_thread );
1373
1374     while( ( title = hb_list_item( h->list_title, 0 ) ) )
1375     {
1376         hb_list_rem( h->list_title, title );
1377         if( title->job && title->job->filters )
1378         {
1379             hb_list_close( &title->job->filters );
1380         }
1381         free( title->job );
1382         hb_title_close( &title );
1383     }
1384     hb_list_close( &h->list_title );
1385
1386     hb_list_close( &h->jobs );
1387     hb_lock_close( &h->state_lock );
1388     hb_lock_close( &h->pause_lock );
1389
1390     free( h );
1391     *_h = NULL;
1392 }
1393
1394 /**
1395  * Cleans up libhb at a process level. Call before the app closes. Removes preview directory.
1396  */
1397 void hb_global_close()
1398 {
1399     char dirname[1024];
1400     DIR * dir;
1401     struct dirent * entry;
1402     
1403     /* Find and remove temp folder */
1404     memset( dirname, 0, 1024 );
1405     hb_get_temporary_directory( dirname );
1406
1407     dir = opendir( dirname );
1408     if (dir)
1409     {
1410         while( ( entry = readdir( dir ) ) )
1411         {
1412             char filename[1024];
1413             if( entry->d_name[0] == '.' )
1414             {
1415                 continue;
1416             }
1417             memset( filename, 0, 1024 );
1418             snprintf( filename, 1023, "%s/%s", dirname, entry->d_name );
1419             unlink( filename );
1420         }
1421         closedir( dir );
1422         rmdir( dirname );
1423     }
1424 }
1425
1426 /**
1427  * Monitors the state of the update, scan, and work threads.
1428  * Sets scan done state when scan thread exits.
1429  * Sets work done state when work thread exits.
1430  * @param _h Handle to hb_handle_t
1431  */
1432 static void thread_func( void * _h )
1433 {
1434     hb_handle_t * h = (hb_handle_t *) _h;
1435     char dirname[1024];
1436
1437     h->pid = getpid();
1438
1439     /* Create folder for temporary files */
1440     memset( dirname, 0, 1024 );
1441     hb_get_temporary_directory( dirname );
1442
1443     hb_mkdir( dirname );
1444
1445     while( !h->die )
1446     {
1447         /* In case the check_update thread hangs, it'll die sooner or
1448            later. Then, we join it here */
1449         if( h->update_thread &&
1450             hb_thread_has_exited( h->update_thread ) )
1451         {
1452             hb_thread_close( &h->update_thread );
1453         }
1454
1455         /* Check if the scan thread is done */
1456         if( h->scan_thread &&
1457             hb_thread_has_exited( h->scan_thread ) )
1458         {
1459             hb_thread_close( &h->scan_thread );
1460
1461             if ( h->scan_die )
1462             {
1463                 hb_title_t * title;
1464
1465                 hb_remove_previews( h );
1466                 while( ( title = hb_list_item( h->list_title, 0 ) ) )
1467                 {
1468                     hb_list_rem( h->list_title, title );
1469                     hb_title_close( &title );
1470                 }
1471
1472                 hb_log( "hb_scan: canceled" );
1473             }
1474             else
1475             {
1476                 hb_log( "libhb: scan thread found %d valid title(s)",
1477                         hb_list_count( h->list_title ) );
1478             }
1479             hb_lock( h->state_lock );
1480             h->state.state = HB_STATE_SCANDONE; //originally state.state
1481                         hb_unlock( h->state_lock );
1482                         /*we increment this sessions scan count by one for the MacGui
1483                         to trigger a new source being set */
1484             h->scanCount++;
1485         }
1486
1487         /* Check if the work thread is done */
1488         if( h->work_thread &&
1489             hb_thread_has_exited( h->work_thread ) )
1490         {
1491             hb_thread_close( &h->work_thread );
1492
1493             hb_log( "libhb: work result = %d",
1494                     h->work_error );
1495             hb_lock( h->state_lock );
1496             h->state.state                = HB_STATE_WORKDONE;
1497             h->state.param.workdone.error = h->work_error;
1498
1499             h->job_count = hb_count(h);
1500             if (h->job_count < 1)
1501                 h->job_count_permanent = 0;
1502             hb_unlock( h->state_lock );
1503         }
1504
1505         hb_snooze( 50 );
1506     }
1507
1508     if( h->scan_thread )
1509     {
1510         hb_scan_stop( h );
1511         hb_thread_close( &h->scan_thread );
1512     }
1513     if( h->work_thread )
1514     {
1515         hb_stop( h );
1516         hb_thread_close( &h->work_thread );
1517     }
1518     hb_remove_previews( h );
1519 }
1520
1521 /**
1522  * Returns the PID.
1523  * @param h Handle to hb_handle_t
1524  */
1525 int hb_get_pid( hb_handle_t * h )
1526 {
1527     return h->pid;
1528 }
1529
1530 /**
1531  * Returns the id for the given instance.
1532  * @param h Handle to hb_handle_t
1533  */
1534 int hb_get_instance_id( hb_handle_t * h )
1535 {
1536     return h->id;
1537 }
1538
1539 /**
1540  * Sets the current state.
1541  * @param h Handle to hb_handle_t
1542  * @param s Handle to new hb_state_t
1543  */
1544 void hb_set_state( hb_handle_t * h, hb_state_t * s )
1545 {
1546     hb_lock( h->pause_lock );
1547     hb_lock( h->state_lock );
1548     memcpy( &h->state, s, sizeof( hb_state_t ) );
1549     if( h->state.state == HB_STATE_WORKING ||
1550         h->state.state == HB_STATE_SEARCHING )
1551     {
1552         /* XXX Hack */
1553         if (h->job_count < 1)
1554             h->job_count_permanent = 1;
1555
1556         h->state.param.working.job_cur =
1557             h->job_count_permanent - hb_list_count( h->jobs );
1558         h->state.param.working.job_count = h->job_count_permanent;
1559
1560         // Set which job is being worked on
1561         if (h->current_job)
1562             h->state.param.working.sequence_id = h->current_job->sequence_id;
1563         else
1564             h->state.param.working.sequence_id = 0;
1565     }
1566     hb_unlock( h->state_lock );
1567     hb_unlock( h->pause_lock );
1568 }
1569
1570 /* Passes a pointer to persistent data */
1571 hb_interjob_t * hb_interjob_get( hb_handle_t * h )
1572 {
1573     return h->interjob;
1574 }