OSDN Git Service

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