OSDN Git Service

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