OSDN Git Service

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