OSDN Git Service

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