OSDN Git Service

Allow multiple output audio tracks from a single DVD audio track.
[handbrake-jp/handbrake-jp-git.git] / libhb / reader.c
1 /* $Id: reader.c,v 1.21 2005/11/25 15:05:25 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_job_t     * job;
12     hb_title_t   * title;
13     volatile int * die;
14
15     hb_dvd_t     * dvd;
16     hb_buffer_t  * ps;
17     hb_stream_t  * stream;
18     
19     uint           sequence;
20
21 } hb_reader_t;
22
23 /***********************************************************************
24  * Local prototypes
25  **********************************************************************/
26 static void        ReaderFunc( void * );
27 static hb_fifo_t ** GetFifoForId( hb_job_t * job, int id );
28
29 /***********************************************************************
30  * hb_reader_init
31  ***********************************************************************
32  *
33  **********************************************************************/
34 hb_thread_t * hb_reader_init( hb_job_t * job )
35 {
36     hb_reader_t * r;
37
38     r = calloc( sizeof( hb_reader_t ), 1 );
39
40     r->job   = job;
41     r->title = job->title;
42     r->die   = job->die;
43     r->sequence = 0;
44     
45     return hb_thread_init( "reader", ReaderFunc, r,
46                            HB_NORMAL_PRIORITY );
47 }
48
49 /***********************************************************************
50  * ReaderFunc
51  ***********************************************************************
52  *
53  **********************************************************************/
54 static void ReaderFunc( void * _r )
55 {
56     hb_reader_t  * r = _r;
57     hb_fifo_t   ** fifos;
58     hb_buffer_t  * buf;
59     hb_buffer_t  * buf_old;
60     hb_list_t    * list;
61     int            n;
62     int            chapter = -1;
63     int            chapter_end = r->job->chapter_end;
64
65     if( !( r->dvd = hb_dvd_init( r->title->dvd ) ) )
66     {
67         if ( !(r->stream = hb_stream_open(r->title->dvd) ) )
68         {
69           return;
70         }
71     }
72
73     if (r->dvd)
74     {
75       /*
76        * XXX this code is a temporary hack that should go away if/when
77        *     chapter merging goes away in libhb/dvd.c
78        * map the start and end chapter numbers to on-media chapter
79        * numbers since chapter merging could cause the handbrake numbers
80        * to diverge from the media numbers and, if our chapter_end is after
81        * a media chapter that got merged, we'll stop ripping too early.
82        */
83       int start = r->job->chapter_start;
84       hb_chapter_t * chap = hb_list_item( r->title->list_chapter, chapter_end - 1 );
85
86       chapter_end = chap->index;
87       if (start > 1)
88       {
89          chap = hb_list_item( r->title->list_chapter, start - 1 );
90          start = chap->index;
91       }
92       /* end chapter mapping XXX */
93
94       if( !hb_dvd_start( r->dvd, r->title->index, start ) )
95       {
96           hb_dvd_close( &r->dvd );
97           return;
98       }
99     }
100     
101     list  = hb_list_init();
102     r->ps = hb_buffer_init( HB_DVD_READ_BUFFER_SIZE );
103
104     while( !*r->die && !r->job->done )
105     {
106         if (r->dvd)
107           chapter = hb_dvd_chapter( r->dvd );
108         else if (r->stream)
109           chapter = 1;
110           
111         if( chapter < 0 )
112         {
113             hb_log( "reader: end of the title reached" );
114             break;
115         }
116         if( chapter > chapter_end )
117         {
118             hb_log( "reader: end of chapter %d (media %d) reached at media chapter %d",
119                     r->job->chapter_end, chapter_end, chapter );
120             break;
121         }
122
123         if (r->dvd)
124         {
125           if( !hb_dvd_read( r->dvd, r->ps ) )
126           {
127               break;
128           }
129         }
130         else if (r->stream)
131         {
132           if ( !hb_stream_read( r->stream, r->ps ) )
133           {
134             break;
135           }
136         }
137
138         if( r->job->indepth_scan )
139         {
140             /*
141              * Need to update the progress during a subtitle scan
142              */
143             hb_state_t state;
144
145 #define p state.param.working
146
147             state.state = HB_STATE_WORKING;
148             p.progress = (float)chapter / (float)r->job->chapter_end;
149             if( p.progress > 1.0 )
150             {
151                 p.progress = 1.0;
152             } 
153             p.rate_avg = 0.0;
154             p.hours    = -1;
155             p.minutes  = -1;
156             p.seconds  = -1;
157             hb_set_state( r->job->h, &state );
158         }
159
160         hb_demux_ps( r->ps, list );
161
162         while( ( buf = hb_list_item( list, 0 ) ) )
163         {
164             hb_list_rem( list, buf );
165             fifos = GetFifoForId( r->job, buf->id );
166             if( fifos )
167             {  
168                 buf->sequence = r->sequence++;
169                 for( n = 0; fifos[n] != NULL; n++) 
170                 {
171                     if( n != 0 )
172                     {
173                         /*
174                          * Replace the buffer with a new copy of itself for when
175                          * it is being sent down multiple fifos.
176                          */
177                         buf_old = buf;
178                         buf = hb_buffer_init(buf_old->size);
179                         memcpy( buf->data, buf_old->data, buf->size );
180                         hb_buffer_copy_settings( buf, buf_old );
181                     }
182
183                     while( !*r->die && !r->job->done &&
184                            hb_fifo_is_full( fifos[n] ) )
185                     {
186                         /*
187                          * Loop until the incoming fifo is reaqdy to receive 
188                          * this buffer.
189                          */
190                         hb_snooze( 50 );
191                     }
192
193                     hb_fifo_push( fifos[n], buf );
194                 }
195             }
196             else
197             {
198                 hb_buffer_close( &buf );
199             }
200         }
201     }
202
203     hb_list_empty( &list );
204     hb_buffer_close( &r->ps );
205     if (r->dvd)
206     {
207       hb_dvd_stop( r->dvd );
208       hb_dvd_close( &r->dvd );
209     }
210     else if (r->stream)
211     {
212       hb_stream_close(&r->stream);
213     }
214     
215     free( r );
216     _r = NULL;
217
218     hb_log( "reader: done" );
219 }
220
221 /***********************************************************************
222  * GetFifoForId
223  ***********************************************************************
224  *
225  **********************************************************************/
226 static hb_fifo_t ** GetFifoForId( hb_job_t * job, int id )
227 {
228     hb_title_t    * title = job->title;
229     hb_audio_t    * audio;
230     hb_subtitle_t * subtitle;
231     int             i, n;
232     static hb_fifo_t * fifos[8];
233
234     memset(fifos, 0, sizeof(fifos));
235
236     if( id == 0xE0 )
237     {
238         if( job->indepth_scan ) 
239         {
240             /*
241              * Ditch the video here during the indepth scan until
242              * we can improve the MPEG2 decode performance.
243              */
244             return NULL;
245         } 
246         else 
247         {
248             fifos[0] = job->fifo_mpeg2;
249             return fifos;
250         }
251     }
252
253     if( job->indepth_scan ) {
254         /*
255          * Count the occurances of the subtitles, don't actually
256          * return any to encode unless we are looking fro forced
257          * subtitles in which case we need to look in the sub picture
258          * to see if it has the forced flag enabled.
259          */
260         for (i=0; i < hb_list_count(title->list_subtitle); i++) {
261             subtitle =  hb_list_item( title->list_subtitle, i);
262             if (id == subtitle->id) {
263                 /*
264                  * A hit, count it.
265                  */
266                 subtitle->hits++;
267                 if( job->subtitle_force )
268                 {
269                     
270                     fifos[0] = subtitle->fifo_in;
271                     return fifos;
272                 }
273                 break;
274             }
275         }
276     } else {
277         if( ( subtitle = hb_list_item( title->list_subtitle, 0 ) ) &&
278             id == subtitle->id )
279         {
280             fifos[0] = subtitle->fifo_in;
281             return fifos;
282         }
283     }
284     if( !job->indepth_scan ) 
285     {
286         n = 0;
287         for( i = 0; i < hb_list_count( title->list_audio ); i++ )
288         {
289             audio = hb_list_item( title->list_audio, i );
290             if( id == audio->id )
291             {
292                 fifos[n++] = audio->fifo_in;
293             }
294         }
295
296         if( n != 0 )
297         {
298             return fifos;
299         }
300     }
301
302     return NULL;
303 }
304