OSDN Git Service

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