OSDN Git Service

HandBrake 0.7.0
[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 struct hb_work_object_s
10 {
11     HB_WORK_COMMON;
12 };
13
14 typedef struct
15 {
16     hb_list_t * jobs;
17     int         cpu_count;
18     int       * error;
19     volatile int * die;
20
21 } hb_work_t;
22
23 static void work_func();
24 static void do_job( hb_job_t *, int cpu_count );
25 static void job_loop( void * );
26
27 hb_thread_t * hb_work_init( hb_list_t * jobs, int cpu_count,
28                             volatile int * die, int * error )
29 {
30     hb_work_t * work = calloc( sizeof( hb_work_t ), 1 );
31
32     work->jobs      = jobs;
33     work->cpu_count = cpu_count;
34     work->die       = die;
35     work->error     = error;
36
37     return hb_thread_init( "work", work_func, work, HB_LOW_PRIORITY );
38 }
39
40 static void work_func( void * _work )
41 {
42     hb_work_t  * work = _work;
43     hb_job_t   * job;
44
45     hb_log( "%d job(s) to process", hb_list_count( work->jobs ) );
46
47     while( !*work->die && ( job = hb_list_item( work->jobs, 0 ) ) )
48     {
49         hb_list_rem( work->jobs, job );
50         job->die = work->die;
51         do_job( job, work->cpu_count );
52     }
53
54     *(work->error) = HB_ERROR_NONE;
55
56     free( work );
57 }
58
59 static void do_job( hb_job_t * job, int cpu_count )
60 {
61     hb_title_t    * title;
62     int             i;
63     hb_thread_t   * threads[8];
64     hb_work_object_t * w;
65     uint64_t time_total;
66     hb_audio_t   * audio;
67     hb_subtitle_t * subtitle;
68
69     title = job->title;
70
71     job->list_work = hb_list_init();
72
73     hb_log( "starting job" );
74     hb_log( " + device %s", title->dvd );
75     hb_log( " + title %d, chapter(s) %d to %d", title->index,
76             job->chapter_start, job->chapter_end );
77     hb_log( " + %dx%d -> %dx%d, crop %d/%d/%d/%d",
78             title->width, title->height, job->width, job->height,
79             job->crop[0], job->crop[1], job->crop[2], job->crop[3] );
80     hb_log( " + deinterlace %s", job->deinterlace ? "on" : "off" );
81     hb_log( " + grayscale %s", job->grayscale ? "on" : "off" );
82     if( job->vquality >= 0.0 && job->vquality <= 1.0 )
83     {
84         hb_log( " + %.3f fps, video quality %.2f", (float) job->vrate /
85                 (float) job->vrate_base, job->vquality );
86     }
87     else
88     {
89         hb_log( " + %.3f fps, video bitrate %d kbps, pass %d",
90                 (float) job->vrate / (float) job->vrate_base,
91                 job->vbitrate, job->pass );
92     }
93
94     job->fifo_mpeg2  = hb_fifo_init( 2048 );
95     job->fifo_raw    = hb_fifo_init( 8 );
96     job->fifo_sync   = hb_fifo_init( 8 );
97     job->fifo_render = hb_fifo_init( 8 );
98     job->fifo_mpeg4  = hb_fifo_init( 8 );
99
100     /* Synchronization */
101     w           = hb_work_sync_init( job );
102     w->fifo_in  = NULL;
103     w->fifo_out = NULL;
104     hb_list_add( job->list_work, w );
105
106     /* Video decoder */
107     w           = hb_work_decmpeg2_init( job );
108     w->fifo_in  = job->fifo_mpeg2;
109     w->fifo_out = job->fifo_raw;
110     hb_list_add( job->list_work, w );
111
112     /* Video renderer */
113     w           = hb_work_render_init( job );
114     w->fifo_in  = job->fifo_sync;
115     w->fifo_out = job->fifo_render;
116     hb_list_add( job->list_work, w );
117
118     /* Video encoder */
119     switch( job->vcodec )
120     {
121         case HB_VCODEC_FFMPEG:
122             hb_log( " + encoder FFmpeg" );
123             w = hb_work_encavcodec_init( job );
124             break;
125         case HB_VCODEC_XVID:
126             hb_log( " + encoder XviD" );
127             w = hb_work_encxvid_init( job );
128             break;
129         case HB_VCODEC_X264:
130             hb_log( " + encoder x264" );
131             w = hb_work_encx264_init( job );
132             break;
133     }
134     w->fifo_in  = job->fifo_render;
135     w->fifo_out = job->fifo_mpeg4;
136     hb_list_add( job->list_work, w );
137
138     subtitle = hb_list_item( title->list_subtitle, 0 );
139     if( subtitle )
140     {
141         hb_log( " + subtitle %x, %s", subtitle->id, subtitle->lang );
142
143         subtitle->fifo_in  = hb_fifo_init( 8 );
144         subtitle->fifo_raw = hb_fifo_init( 8 );
145
146         w           = hb_work_decsub_init( job );
147         w->fifo_in  = subtitle->fifo_in;
148         w->fifo_out = subtitle->fifo_raw;
149         hb_list_add( job->list_work, w );
150     }
151
152     if( job->acodec & HB_ACODEC_AC3 )
153     {
154         hb_log( " + audio AC3 passthrough" );
155     }
156     else
157     {
158         hb_log( " + audio %d kbps, %d Hz", job->abitrate, job->arate );
159         hb_log( " + encoder %s", ( job->acodec & HB_ACODEC_FAAC ) ?
160                 "faac" : ( ( job->acodec & HB_ACODEC_LAME ) ? "lame" :
161                 "vorbis" ) );
162     }
163
164     for( i = 0; i < hb_list_count( title->list_audio ); i++ )
165     {
166         audio = hb_list_item( title->list_audio, i );
167         hb_log( "   + %x, %s", audio->id, audio->lang );
168
169         audio->fifo_in   = hb_fifo_init( 2048 );
170         audio->fifo_raw  = hb_fifo_init( 8 );
171         audio->fifo_sync = hb_fifo_init( 8 );
172         audio->fifo_out  = hb_fifo_init( 8 );
173
174         switch( audio->codec )
175         {
176             case HB_ACODEC_AC3:
177                 w = hb_work_deca52_init( job, audio );
178                 break;
179             case HB_ACODEC_MPGA:
180                 w = hb_work_decavcodec_init( job, audio );
181                 break;
182             case HB_ACODEC_LPCM:
183                 w = hb_work_declpcm_init( job, audio );
184                 break;
185         }
186         w->fifo_in  = audio->fifo_in;
187         w->fifo_out = audio->fifo_raw;
188         hb_list_add( job->list_work, w );
189
190         switch( job->acodec )
191         {
192             case HB_ACODEC_FAAC:
193                 w = hb_work_encfaac_init( job, audio );
194                 break;
195             case HB_ACODEC_LAME:
196                 w = hb_work_enclame_init( job, audio );
197                 break;
198             case HB_ACODEC_VORBIS:
199                 w = hb_work_encvorbis_init( job, audio );
200                 break;
201         }
202         if( job->acodec != HB_ACODEC_AC3 )
203         {
204             w->fifo_in  = audio->fifo_sync;
205             w->fifo_out = audio->fifo_out;
206             hb_list_add( job->list_work, w );
207         }
208     }
209
210     /* Init read & write threads */
211     job->reader = hb_reader_init( job );
212
213     hb_log( " + output: %s", job->file );
214     job->muxer = hb_muxer_init( job );
215
216     for( i = 0; i < hb_list_count( job->list_work ); i++ )
217     {
218         w       = hb_list_item( job->list_work, i );
219         w->lock = hb_lock_init();
220         w->used = 0;
221         w->time = 0;
222     }
223
224     job->done = 0;
225
226     /* Launch processing threads */
227     for( i = 0; i < cpu_count; i++ )
228     {
229         char thread_name[16];
230         if( cpu_count - 1 )
231         {
232             snprintf( thread_name, 16, "cpu killer %d", i + 1 );
233         }
234         else
235         {
236             snprintf( thread_name, 16, "cpu killer" );
237         }
238         threads[i] = hb_thread_init( thread_name, job_loop, job,
239                                      HB_LOW_PRIORITY );
240     }
241
242     while( !*job->die && !job->done )
243     {
244         hb_snooze( 500 );
245     }
246
247     for( i = 0; i < cpu_count; i++ )
248     {
249         hb_thread_close( &threads[i] );
250     }
251
252     /* Stop read & write threads */
253     hb_thread_close( &job->reader );
254     hb_thread_close( &job->muxer );
255
256     /* Stats */
257     time_total = 0;
258     for( i = 0; i < hb_list_count( job->list_work ); i++ )
259     {
260         w = hb_list_item( job->list_work, i );
261         time_total += w->time;
262     }
263     for( i = 0; i < hb_list_count( job->list_work ); i++ )
264     {
265         w = hb_list_item( job->list_work, i );
266         hb_log( "%s: %.2f %%", w->name,
267                 100.0 * (float) w->time / (float) time_total );
268     }
269
270     /* Close work objects */
271     while( ( w = hb_list_item( job->list_work, 0 ) ) )
272     {
273         hb_list_rem( job->list_work, w );
274         hb_lock_close( &w->lock );
275         w->close( &w );
276     }
277
278     /* Close fifos */
279     hb_fifo_close( &job->fifo_mpeg2 );
280     hb_fifo_close( &job->fifo_raw );
281     hb_fifo_close( &job->fifo_sync );
282     hb_fifo_close( &job->fifo_render );
283     hb_fifo_close( &job->fifo_mpeg4 );
284     if( subtitle )
285     {
286         hb_fifo_close( &subtitle->fifo_in );
287         hb_fifo_close( &subtitle->fifo_raw );
288     }
289     for( i = 0; i < hb_list_count( title->list_audio ); i++ )
290     {
291         audio = hb_list_item( title->list_audio, i );
292         hb_fifo_close( &audio->fifo_in );
293         hb_fifo_close( &audio->fifo_raw );
294         hb_fifo_close( &audio->fifo_sync );
295         hb_fifo_close( &audio->fifo_out );
296     }
297 }
298
299 static int lock( hb_work_object_t * w )
300 {
301     hb_lock( w->lock );
302     if( w->used )
303     {
304         hb_unlock( w->lock );
305         return 0;
306     }
307     w->used = 1;
308     hb_unlock( w->lock );
309     return 1;
310 }
311
312 static void unlock( hb_work_object_t * w )
313 {
314     hb_lock( w->lock );
315     w->used = 0;
316     hb_unlock( w->lock );
317 }
318
319 static void job_loop( void * _job )
320 {
321     hb_job_t         * job = _job;
322     hb_buffer_t      * buf_in, * buf_out;
323     hb_work_object_t * w;
324     int                work_count;
325     int                act;
326     int                i;
327     uint64_t           date;
328     int                done;
329
330     work_count = hb_list_count( job->list_work );
331     act        = 0;
332     done       = 0;
333
334     while( !*job->die && !job->done )
335     {
336         /* Handle synchronization, resampling, framerate change,
337            etc */
338         w = hb_list_item( job->list_work, 0 );
339         if( lock( w ) )
340         {
341             date = hb_get_date();
342             if( w->work( w, NULL, NULL ) == HB_WORK_DONE )
343             {
344                 done = 1;
345             }
346             w->time += hb_get_date() - date;
347             unlock( w );
348         }
349
350         for( i = 1; !*job->die && !job->done && i < work_count; i++ )
351         {
352             w = hb_list_item( job->list_work, i );
353             if( !lock( w ) )
354                 continue;
355
356             for( ;; )
357             {
358                 hb_lock( job->pause );
359                 hb_unlock( job->pause );
360
361                 if( hb_fifo_is_full( w->fifo_out ) ||
362                     !( buf_in = hb_fifo_get( w->fifo_in ) ) )
363                 {
364                     break;
365                 }
366
367                 date = hb_get_date();
368                 w->work( w, &buf_in, &buf_out );
369                 w->time += hb_get_date() - date;
370                 if( buf_in )
371                 {
372                     hb_buffer_close( &buf_in );
373                 }
374                 if( buf_out )
375                 {
376                     act = 1;
377                     hb_fifo_push( w->fifo_out, buf_out );
378                 }
379             }
380
381             unlock( w );
382         }
383
384         if( done &&
385             !hb_fifo_size( job->fifo_sync ) &&
386             !hb_fifo_size( job->fifo_render ) &&
387             hb_fifo_size( job->fifo_mpeg4 ) < 2 )
388         {
389             job->done = 1;
390             break;
391         }
392
393         /* If we did nothing, wait a bit before trying again */
394         if( !act )
395         {
396             hb_snooze( 50 );
397         }
398         act = 0;
399     }
400 }