OSDN Git Service

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