OSDN Git Service

Applied and committed saintdev's patch to fix multi-track audio. Only in the CLI...
[handbrake-jp/handbrake-jp-git.git] / libhb / work.c
1 /* $Id: work.c,v 1.43 2005/03/17 16:38:49 titer Exp $
2
3    This file is part of the HandBrake source code.
4    Homepage: <http://handbrake.m0k.org/>.
5    It may be used under the terms of the GNU General Public License. */
6
7 #include "hb.h"
8
9 typedef struct
10 {
11     hb_list_t * jobs;
12     int         cpu_count;
13     int       * error;
14     volatile int * die;
15
16 } hb_work_t;
17
18 static void work_func();
19 static void do_job( hb_job_t *, int cpu_count );
20 static void work_loop( void * );
21
22 /**
23  * Allocates work object and launches work thread with work_func.
24  * @param jobs Handle to hb_list_t.
25  * @param cpu_count Humber of CPUs found in system.
26  * @param die Handle to user inititated exit indicator.
27  * @param error Handle to error indicator.
28  */
29 hb_thread_t * hb_work_init( hb_list_t * jobs, int cpu_count,
30                             volatile int * die, int * error )
31 {
32     hb_work_t * work = calloc( sizeof( hb_work_t ), 1 );
33
34     work->jobs      = jobs;
35     work->cpu_count = cpu_count;
36     work->die       = die;
37     work->error     = error;
38
39     return hb_thread_init( "work", work_func, work, HB_LOW_PRIORITY );
40 }
41
42 /**
43  * Iterates through job list and calls do_job for each job.
44  * @param _work Handle work object.
45  */
46 static void work_func( void * _work )
47 {
48     hb_work_t  * work = _work;
49     hb_job_t   * job;
50
51     hb_log( "%d job(s) to process", hb_list_count( work->jobs ) );
52
53     while( !*work->die && ( job = hb_list_item( work->jobs, 0 ) ) )
54     {
55         hb_list_rem( work->jobs, job );
56         job->die = work->die;
57         do_job( job, work->cpu_count );
58     }
59
60     *(work->error) = HB_ERROR_NONE;
61
62     free( work );
63 }
64
65 static hb_work_object_t * getWork( int id )
66 {
67     hb_work_object_t * w;
68     for( w = hb_objects; w; w = w->next )
69     {
70         if( w->id == id )
71         {
72             return w;
73         }
74     }
75     return NULL;
76 }
77
78 /**
79  * Job initialization rountine.
80  * Initializes fifos.
81  * Creates work objects for synchronizer, video decoder, video renderer, video decoder, audio decoder, audio encoder, reader, muxer.
82  * Launches thread for each work object with work_loop.
83  * Loops while monitoring status of work threads and fifos.
84  * Exits loop when conversion is done and fifos are empty.
85  * Closes threads and frees fifos.
86  * @param job Handle work hb_job_t.
87  * @param cpu_count number of CPUs found in system.
88  */
89 static void do_job( hb_job_t * job, int cpu_count )
90 {
91     hb_title_t    * title;
92     int             i;
93     hb_work_object_t * w;
94     
95     /* FIXME: This feels really hackish, anything better? */
96     hb_work_object_t * audio_w = NULL;
97
98     hb_audio_t   * audio;
99     hb_subtitle_t * subtitle;
100     int done;
101
102     title = job->title;
103
104     job->list_work = hb_list_init();
105
106     hb_log( "starting job" );
107     hb_log( " + device %s", title->dvd );
108     hb_log( " + title %d, chapter(s) %d to %d", title->index,
109             job->chapter_start, job->chapter_end );
110     if ( job->pixel_ratio == 1 )
111     {
112         /* Correct the geometry of the output movie when using PixelRatio */
113         job->height=title->height-job->crop[0]-job->crop[1];
114         job->width=title->width-job->crop[2]-job->crop[3];
115     }
116
117         /* Keep width and height within these boundaries */
118         if (job->maxHeight && (job->height > job->maxHeight) )
119         {
120                 job->height = job->maxHeight;
121                 hb_fix_aspect( job, HB_KEEP_HEIGHT );
122                 hb_log("Height out of bounds, scaling down to %i", job->maxHeight);
123                 hb_log("New dimensions %i * %i", job->width, job->height);
124         }
125         if (job->maxWidth && (job->width > job->maxWidth) )
126         {
127                 job->width = job->maxWidth;
128                 hb_fix_aspect( job, HB_KEEP_WIDTH );   
129                 hb_log("Width out of bounds, scaling down to %i", job->maxWidth);
130                 hb_log("New dimensions %i * %i", job->width, job->height);
131         }
132
133     hb_log( " + %dx%d -> %dx%d, crop %d/%d/%d/%d",
134             title->width, title->height, job->width, job->height,
135             job->crop[0], job->crop[1], job->crop[2], job->crop[3] );
136     hb_log( " + deinterlace %s", job->deinterlace ? "on" : "off" );
137     hb_log( " + grayscale %s", job->grayscale ? "on" : "off" );
138     if( job->vquality >= 0.0 && job->vquality <= 1.0 )
139     {
140         hb_log( " + %.3f fps, video quality %.2f", (float) job->vrate /
141                 (float) job->vrate_base, job->vquality );
142     }
143     else
144     {
145         hb_log( " + %.3f fps, video bitrate %d kbps, pass %d",
146                 (float) job->vrate / (float) job->vrate_base,
147                 job->vbitrate, job->pass );
148     }
149         hb_log (" + PixelRatio: %d, width:%d, height: %d",job->pixel_ratio,job->width, job->height);
150     job->fifo_mpeg2  = hb_fifo_init( 2048 );
151     job->fifo_raw    = hb_fifo_init( 8 );
152     job->fifo_sync   = hb_fifo_init( 8 );
153     job->fifo_render = hb_fifo_init( 8 );
154     job->fifo_mpeg4  = hb_fifo_init( 8 );
155
156     /* Synchronization */
157     hb_list_add( job->list_work, ( w = getWork( WORK_SYNC ) ) );
158     w->fifo_in  = NULL;
159     w->fifo_out = NULL;
160
161     /* Video decoder */
162     hb_list_add( job->list_work, ( w = getWork( WORK_DECMPEG2 ) ) );
163     w->fifo_in  = job->fifo_mpeg2;
164     w->fifo_out = job->fifo_raw;
165
166     /* Video renderer */
167     hb_list_add( job->list_work, ( w = getWork( WORK_RENDER ) ) );
168     w->fifo_in  = job->fifo_sync;
169     w->fifo_out = job->fifo_render;
170
171     /* Video encoder */
172     switch( job->vcodec )
173     {
174         case HB_VCODEC_FFMPEG:
175             hb_log( " + encoder FFmpeg" );
176             w = getWork( WORK_ENCAVCODEC );
177             break;
178         case HB_VCODEC_XVID:
179             hb_log( " + encoder XviD" );
180             w = getWork( WORK_ENCXVID );
181             break;
182         case HB_VCODEC_X264:
183             hb_log( " + encoder x264" );
184             w = getWork( WORK_ENCX264 );
185             break;
186     }
187     w->fifo_in  = job->fifo_render;
188     w->fifo_out = job->fifo_mpeg4;
189     w->config   = &job->config;
190     hb_list_add( job->list_work, w );
191
192     subtitle = hb_list_item( title->list_subtitle, 0 );
193     if( subtitle )
194     {
195         hb_log( " + subtitle %x, %s", subtitle->id, subtitle->lang );
196
197         subtitle->fifo_in  = hb_fifo_init( 8 );
198         subtitle->fifo_raw = hb_fifo_init( 8 );
199
200         hb_list_add( job->list_work, ( w = getWork( WORK_DECSUB ) ) );
201         w->fifo_in  = subtitle->fifo_in;
202         w->fifo_out = subtitle->fifo_raw;
203     }
204
205     if( job->acodec & HB_ACODEC_AC3 )
206     {
207         hb_log( " + audio AC3 passthrough" );
208     }
209     else
210     {
211         hb_log( " + audio %d kbps, %d Hz", job->abitrate, job->arate );
212         hb_log( " + encoder %s", ( job->acodec & HB_ACODEC_FAAC ) ?
213                 "faac" : ( ( job->acodec & HB_ACODEC_LAME ) ? "lame" :
214                 "vorbis" ) );
215     }
216
217     for( i = 0; i < hb_list_count( title->list_audio ); i++ )
218     {
219         audio = hb_list_item( title->list_audio, i );
220         hb_log( "   + %x, %s", audio->id, audio->lang );
221
222         audio->fifo_in   = hb_fifo_init( 2048 );
223         audio->fifo_raw  = hb_fifo_init( 8 );
224         audio->fifo_sync = hb_fifo_init( 8 );
225         audio->fifo_out  = hb_fifo_init( 8 );
226
227         switch( audio->codec )
228         {
229             case HB_ACODEC_AC3:
230                 w = getWork( WORK_DECA52 );
231                 break;
232             case HB_ACODEC_MPGA:
233                 w = getWork( WORK_DECAVCODEC );
234                 break;
235             case HB_ACODEC_LPCM:
236                 w = getWork( WORK_DECLPCM );
237                 break;
238         }
239         w->fifo_in  = audio->fifo_in;
240         w->fifo_out = audio->fifo_raw;
241         w->config   = &audio->config;
242         
243         /* FIXME: This feels really hackish, anything better? */
244         audio_w = calloc( sizeof( hb_work_object_t ), 1 );
245         audio_w = memcpy( audio_w, w, sizeof( hb_work_object_t ));
246         
247         hb_list_add( job->list_work, audio_w );
248
249         switch( job->acodec )
250         {
251             case HB_ACODEC_FAAC:
252                 w = getWork( WORK_ENCFAAC );
253                 break;
254             case HB_ACODEC_LAME:
255                 w = getWork( WORK_ENCLAME );
256                 break;
257             case HB_ACODEC_VORBIS:
258                 w = getWork( WORK_ENCVORBIS );
259                 break;
260         }
261         if( job->acodec != HB_ACODEC_AC3 )
262         {
263             w->fifo_in  = audio->fifo_sync;
264             w->fifo_out = audio->fifo_out;
265             w->config   = &audio->config;
266             
267             /* FIXME: This feels really hackish, anything better? */
268             audio_w = calloc( sizeof( hb_work_object_t ), 1 );
269             audio_w = memcpy( audio_w, w, sizeof( hb_work_object_t ));
270         
271             hb_list_add( job->list_work, audio_w );
272         }
273                 
274                 /* store this audio's channel counts in the audio struct */
275                 
276                 /* we will only end up with a channelsused value other than 2
277                 if we are encoding to AAC.  All other audio encodings will get
278                 a stereo mix. */
279                 
280                 if (audio->channels == 5 && audio->lfechannels == 1) {
281                         /* we have a 5.1 AC-3 source soundtrack */
282                         if (job->acodec == HB_ACODEC_FAAC && job->surround) {
283                                 /* we're going to be encoding to AAC,
284                                 and have turned on the "preserve 5.1" flag */
285                                 audio->channelsused = 6;
286                         } else {
287                                 /* mix 5.1 down to Dolby Digital (2-channel) for
288                                 non-AAC audio, or for AAC without 5.1 preservation */
289                                 audio->channelsused = 2;
290                         }
291                 } else if (audio->channels == 1 && audio->lfechannels == 0) {
292                         /* we have a 1.0 mono AC-3 source soundtrack */
293                         if (job->acodec == HB_ACODEC_FAAC) {
294                                 /* we're going to be encoding to AAC,
295                                 so mix down to a mono AAC track */
296                                 audio->channelsused = 1;
297                         } else {
298                                 /* mix up the mono track to stereo for non-AAC formats */
299                                 audio->channelsused = 2;
300                         }
301                 } else {
302                         /* mix everything else down to stereo */
303                         /* dolby pro-logic will be preserved in deca52.c if necessary
304                         by referring to the value of audio->config->a52.ac3flags */
305                         audio->channelsused = 2;
306                 }
307                 
308         audio->config.aac.channelsused = audio->config.a52.channelsused = audio->channelsused;
309                 
310     }
311
312     /* Init read & write threads */
313     job->reader = hb_reader_init( job );
314
315     hb_log( " + output: %s", job->file );
316     job->muxer = hb_muxer_init( job );
317
318     job->done = 0;
319
320     /* Launch processing threads */
321     for( i = 1; i < hb_list_count( job->list_work ); i++ )
322     {
323         w = hb_list_item( job->list_work, i );
324         w->done = &job->done;
325                 w->thread_sleep_interval = 10;
326         w->init( w, job );
327         w->thread = hb_thread_init( w->name, work_loop, w,
328                                     HB_LOW_PRIORITY );
329     }
330
331     done = 0;
332     w = hb_list_item( job->list_work, 0 );
333         w->thread_sleep_interval = 50;
334     w->init( w, job );
335     while( !*job->die )
336     {
337         if( w->work( w, NULL, NULL ) == HB_WORK_DONE )
338         {
339             done = 1;
340         }
341         if( done &&
342             !hb_fifo_size( job->fifo_sync ) &&
343             !hb_fifo_size( job->fifo_render ) &&
344             hb_fifo_size( job->fifo_mpeg4 ) < 2 )
345         {
346             break;
347         }
348         hb_snooze( w->thread_sleep_interval );
349     }
350     hb_list_rem( job->list_work, w );
351     w->close( w );
352     job->done = 1;
353
354     /* Close work objects */
355     while( ( w = hb_list_item( job->list_work, 0 ) ) )
356     {
357         hb_list_rem( job->list_work, w );
358         hb_thread_close( &w->thread );
359         w->close( w );
360         
361         /* FIXME: This feels really hackish, anything better? */
362         if ( w->id == WORK_DECA52 ||
363              w->id == WORK_DECLPCM ||
364              w->id == WORK_ENCFAAC ||
365              w->id == WORK_ENCLAME ||
366              w->id == WORK_ENCVORBIS )
367         {
368             free( w );
369             w = NULL;
370         }
371     }
372
373     /* Stop read & write threads */
374     hb_thread_close( &job->reader );
375     hb_thread_close( &job->muxer );
376
377     /* Close fifos */
378     hb_fifo_close( &job->fifo_mpeg2 );
379     hb_fifo_close( &job->fifo_raw );
380     hb_fifo_close( &job->fifo_sync );
381     hb_fifo_close( &job->fifo_render );
382     hb_fifo_close( &job->fifo_mpeg4 );
383     if( subtitle )
384     {
385         hb_fifo_close( &subtitle->fifo_in );
386         hb_fifo_close( &subtitle->fifo_raw );
387     }
388     for( i = 0; i < hb_list_count( title->list_audio ); i++ )
389     {
390         audio = hb_list_item( title->list_audio, i );
391         hb_fifo_close( &audio->fifo_in );
392         hb_fifo_close( &audio->fifo_raw );
393         hb_fifo_close( &audio->fifo_sync );
394         hb_fifo_close( &audio->fifo_out );
395     }
396 }
397
398 /**
399  * Performs the work objects specific work function.
400  * Loops calling work function for associated work object. Sleeps when fifo is full.
401  * Monitors work done indicator.
402  * Exits loop when work indiactor is set.
403  * @param _w Handle to work object.
404  */
405 static void work_loop( void * _w )
406 {
407     hb_work_object_t * w = _w;
408     hb_buffer_t      * buf_in, * buf_out;
409
410     while( !*w->done )
411     {
412 #if 0
413         hb_lock( job->pause );
414         hb_unlock( job->pause );
415 #endif
416         if( hb_fifo_is_full( w->fifo_out ) ||
417 //        if( (hb_fifo_percent_full( w->fifo_out ) > 0.8) ||
418             !( buf_in = hb_fifo_get( w->fifo_in ) ) )
419         {
420             hb_snooze( w->thread_sleep_interval );
421 //                      w->thread_sleep_interval += 1;
422             continue;
423         }
424 //              w->thread_sleep_interval = MAX(1, (w->thread_sleep_interval - 1));
425
426         w->work( w, &buf_in, &buf_out );
427         if( buf_in )
428         {
429             hb_buffer_close( &buf_in );
430         }
431         if( buf_out )
432         {
433             hb_fifo_push( w->fifo_out, buf_out );
434         }
435     }
436 }