OSDN Git Service

Merge the 5.1 branch into the trunk.
[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     hb_audio_t   * audio;
95     hb_subtitle_t * subtitle;
96     int done;
97
98     title = job->title;
99
100     job->list_work = hb_list_init();
101
102     hb_log( "starting job" );
103     hb_log( " + device %s", title->dvd );
104     hb_log( " + title %d, chapter(s) %d to %d", title->index,
105             job->chapter_start, job->chapter_end );
106     if ( job->pixel_ratio == 1 )
107     {
108         /* Correct the geometry of the output movie when using PixelRatio */
109         job->height=title->height-job->crop[0]-job->crop[1];
110         job->width=title->width-job->crop[2]-job->crop[3];
111     }
112
113         /* Keep width and height within these boundaries */
114         if (job->maxHeight && (job->height > job->maxHeight) )
115         {
116                 job->height = job->maxHeight;
117                 hb_fix_aspect( job, HB_KEEP_HEIGHT );
118                 hb_log("Height out of bounds, scaling down to %i", job->maxHeight);
119                 hb_log("New dimensions %i * %i", job->width, job->height);
120         }
121         if (job->maxWidth && (job->width > job->maxWidth) )
122         {
123                 job->width = job->maxWidth;
124                 hb_fix_aspect( job, HB_KEEP_WIDTH );   
125                 hb_log("Width out of bounds, scaling down to %i", job->maxWidth);
126                 hb_log("New dimensions %i * %i", job->width, job->height);
127         }
128
129     hb_log( " + %dx%d -> %dx%d, crop %d/%d/%d/%d",
130             title->width, title->height, job->width, job->height,
131             job->crop[0], job->crop[1], job->crop[2], job->crop[3] );
132     hb_log( " + deinterlace %s", job->deinterlace ? "on" : "off" );
133     hb_log( " + grayscale %s", job->grayscale ? "on" : "off" );
134     if( job->vquality >= 0.0 && job->vquality <= 1.0 )
135     {
136         hb_log( " + %.3f fps, video quality %.2f", (float) job->vrate /
137                 (float) job->vrate_base, job->vquality );
138     }
139     else
140     {
141         hb_log( " + %.3f fps, video bitrate %d kbps, pass %d",
142                 (float) job->vrate / (float) job->vrate_base,
143                 job->vbitrate, job->pass );
144     }
145         hb_log (" + PixelRatio: %d, width:%d, height: %d",job->pixel_ratio,job->width, job->height);
146     job->fifo_mpeg2  = hb_fifo_init( 2048 );
147     job->fifo_raw    = hb_fifo_init( 8 );
148     job->fifo_sync   = hb_fifo_init( 8 );
149     job->fifo_render = hb_fifo_init( 8 );
150     job->fifo_mpeg4  = hb_fifo_init( 8 );
151
152     /* Synchronization */
153     hb_list_add( job->list_work, ( w = getWork( WORK_SYNC ) ) );
154     w->fifo_in  = NULL;
155     w->fifo_out = NULL;
156
157     /* Video decoder */
158     hb_list_add( job->list_work, ( w = getWork( WORK_DECMPEG2 ) ) );
159     w->fifo_in  = job->fifo_mpeg2;
160     w->fifo_out = job->fifo_raw;
161
162     /* Video renderer */
163     hb_list_add( job->list_work, ( w = getWork( WORK_RENDER ) ) );
164     w->fifo_in  = job->fifo_sync;
165     w->fifo_out = job->fifo_render;
166
167     /* Video encoder */
168     switch( job->vcodec )
169     {
170         case HB_VCODEC_FFMPEG:
171             hb_log( " + encoder FFmpeg" );
172             w = getWork( WORK_ENCAVCODEC );
173             break;
174         case HB_VCODEC_XVID:
175             hb_log( " + encoder XviD" );
176             w = getWork( WORK_ENCXVID );
177             break;
178         case HB_VCODEC_X264:
179             hb_log( " + encoder x264" );
180             w = getWork( WORK_ENCX264 );
181             break;
182     }
183     w->fifo_in  = job->fifo_render;
184     w->fifo_out = job->fifo_mpeg4;
185     w->config   = &job->config;
186     hb_list_add( job->list_work, w );
187
188     subtitle = hb_list_item( title->list_subtitle, 0 );
189     if( subtitle )
190     {
191         hb_log( " + subtitle %x, %s", subtitle->id, subtitle->lang );
192
193         subtitle->fifo_in  = hb_fifo_init( 8 );
194         subtitle->fifo_raw = hb_fifo_init( 8 );
195
196         hb_list_add( job->list_work, ( w = getWork( WORK_DECSUB ) ) );
197         w->fifo_in  = subtitle->fifo_in;
198         w->fifo_out = subtitle->fifo_raw;
199     }
200
201     if( job->acodec & HB_ACODEC_AC3 )
202     {
203         hb_log( " + audio AC3 passthrough" );
204     }
205     else
206     {
207         hb_log( " + audio %d kbps, %d Hz", job->abitrate, job->arate );
208         hb_log( " + encoder %s", ( job->acodec & HB_ACODEC_FAAC ) ?
209                 "faac" : ( ( job->acodec & HB_ACODEC_LAME ) ? "lame" :
210                 "vorbis" ) );
211     }
212
213     for( i = 0; i < hb_list_count( title->list_audio ); i++ )
214     {
215         audio = hb_list_item( title->list_audio, i );
216         hb_log( "   + %x, %s", audio->id, audio->lang );
217
218         audio->fifo_in   = hb_fifo_init( 2048 );
219         audio->fifo_raw  = hb_fifo_init( 8 );
220         audio->fifo_sync = hb_fifo_init( 8 );
221         audio->fifo_out  = hb_fifo_init( 8 );
222
223         switch( audio->codec )
224         {
225             case HB_ACODEC_AC3:
226                 w = getWork( WORK_DECA52 );
227                 break;
228             case HB_ACODEC_MPGA:
229                 w = getWork( WORK_DECAVCODEC );
230                 break;
231             case HB_ACODEC_LPCM:
232                 w = getWork( WORK_DECLPCM );
233                 break;
234         }
235         w->fifo_in  = audio->fifo_in;
236         w->fifo_out = audio->fifo_raw;
237         hb_list_add( job->list_work, w );
238
239         switch( job->acodec )
240         {
241             case HB_ACODEC_FAAC:
242                 w = getWork( WORK_ENCFAAC );
243                 break;
244             case HB_ACODEC_LAME:
245                 w = getWork( WORK_ENCLAME );
246                 break;
247             case HB_ACODEC_VORBIS:
248                 w = getWork( WORK_ENCVORBIS );
249                 break;
250         }
251         if( job->acodec != HB_ACODEC_AC3 )
252         {
253             w->fifo_in  = audio->fifo_sync;
254             w->fifo_out = audio->fifo_out;
255             w->config   = &audio->config;
256             hb_list_add( job->list_work, w );
257         }
258                 
259                 /* store this audio's channel counts with the job */
260                 /* this should be an array -
261                 we just use the last channel count for now */
262                 
263                 /* we will only end up with a channelsused value other than 2
264                 if we are encoding to AAC.  All other audio encodings will get
265                 a stereo mix. */
266                 
267                 if (audio->channels == 5 && audio->lfechannels == 1) {
268                         /* we have a 5.1 AC-3 source soundtrack */
269                         if (job->acodec == HB_ACODEC_FAAC && job->surround) {
270                                 /* we're going to be encoding to AAC,
271                                 and have turned on the "preserve 5.1" flag */
272                                 job->channelsused = 6;
273                         } else {
274                                 /* mix 5.1 down to Dolby Digital (2-channel) for
275                                 non-AAC audio, or for AAC without 5.1 preservation */
276                                 job->channelsused = 2;
277                         }
278                 } else if (audio->channels == 1 && audio->lfechannels == 0) {
279                         /* we have a 1.0 mono AC-3 source soundtrack */
280                         if (job->acodec == HB_ACODEC_FAAC) {
281                                 /* we're going to be encoding to AAC,
282                                 so mix down to a mono AAC track */
283                                 job->channelsused = 1;
284                         } else {
285                                 /* mix up the mono track to stereo for non-AAC formats */
286                                 job->channelsused = 2;
287                         }
288                 } else {
289                         /* mix everything else down to stereo */
290                         /* dolby pro-logic will be preserved in deca52.c if necessary
291                         by referring to the value of job->ac3flags stored below */
292                         job->channelsused = 2;
293                 }
294                 
295                 /* remember the actual number of channels and lfe channels */
296                 /* again, we are using the last channel's count for now */
297                 job->channels = audio->channels;
298                 job->lfechannels = audio->lfechannels;
299                 
300                 /* remember the AC3 flags for future reference */
301                 /* again, we are using the last channel's flags for now */
302                 job->ac3flags = audio->ac3flags;
303                 
304     }
305
306     /* Init read & write threads */
307     job->reader = hb_reader_init( job );
308
309     hb_log( " + output: %s", job->file );
310     job->muxer = hb_muxer_init( job );
311
312     job->done = 0;
313
314     /* Launch processing threads */
315     for( i = 1; i < hb_list_count( job->list_work ); i++ )
316     {
317         w = hb_list_item( job->list_work, i );
318         w->done = &job->done;
319                 w->thread_sleep_interval = 10;
320         w->init( w, job );
321         w->thread = hb_thread_init( w->name, work_loop, w,
322                                     HB_LOW_PRIORITY );
323     }
324
325     done = 0;
326     w = hb_list_item( job->list_work, 0 );
327         w->thread_sleep_interval = 50;
328     w->init( w, job );
329     while( !*job->die )
330     {
331         if( w->work( w, NULL, NULL ) == HB_WORK_DONE )
332         {
333             done = 1;
334         }
335         if( done &&
336             !hb_fifo_size( job->fifo_sync ) &&
337             !hb_fifo_size( job->fifo_render ) &&
338             hb_fifo_size( job->fifo_mpeg4 ) < 2 )
339         {
340             break;
341         }
342         hb_snooze( w->thread_sleep_interval );
343     }
344     hb_list_rem( job->list_work, w );
345     w->close( w );
346     job->done = 1;
347
348     /* Close work objects */
349     while( ( w = hb_list_item( job->list_work, 0 ) ) )
350     {
351         hb_list_rem( job->list_work, w );
352         hb_thread_close( &w->thread );
353         w->close( w );
354     }
355
356     /* Stop read & write threads */
357     hb_thread_close( &job->reader );
358     hb_thread_close( &job->muxer );
359
360     /* Close fifos */
361     hb_fifo_close( &job->fifo_mpeg2 );
362     hb_fifo_close( &job->fifo_raw );
363     hb_fifo_close( &job->fifo_sync );
364     hb_fifo_close( &job->fifo_render );
365     hb_fifo_close( &job->fifo_mpeg4 );
366     if( subtitle )
367     {
368         hb_fifo_close( &subtitle->fifo_in );
369         hb_fifo_close( &subtitle->fifo_raw );
370     }
371     for( i = 0; i < hb_list_count( title->list_audio ); i++ )
372     {
373         audio = hb_list_item( title->list_audio, i );
374         hb_fifo_close( &audio->fifo_in );
375         hb_fifo_close( &audio->fifo_raw );
376         hb_fifo_close( &audio->fifo_sync );
377         hb_fifo_close( &audio->fifo_out );
378     }
379 }
380
381 /**
382  * Performs the work objects specific work function.
383  * Loops calling work function for associated work object. Sleeps when fifo is full.
384  * Monitors work done indicator.
385  * Exits loop when work indiactor is set.
386  * @param _w Handle to work object.
387  */
388 static void work_loop( void * _w )
389 {
390     hb_work_object_t * w = _w;
391     hb_buffer_t      * buf_in, * buf_out;
392
393     while( !*w->done )
394     {
395 #if 0
396         hb_lock( job->pause );
397         hb_unlock( job->pause );
398 #endif
399         if( hb_fifo_is_full( w->fifo_out ) ||
400 //        if( (hb_fifo_percent_full( w->fifo_out ) > 0.8) ||
401             !( buf_in = hb_fifo_get( w->fifo_in ) ) )
402         {
403             hb_snooze( w->thread_sleep_interval );
404 //                      w->thread_sleep_interval += 1;
405             continue;
406         }
407 //              w->thread_sleep_interval = MAX(1, (w->thread_sleep_interval - 1));
408
409         w->work( w, &buf_in, &buf_out );
410         if( buf_in )
411         {
412             hb_buffer_close( &buf_in );
413         }
414         if( buf_out )
415         {
416             hb_fifo_push( w->fifo_out, buf_out );
417         }
418     }
419 }