OSDN Git Service

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