OSDN Git Service

If we always require a buffer to be available on every fifo we'll eventually deadlock...
[handbrake-jp/handbrake-jp-git.git] / libhb / muxcommon.c
1 /* $Id: muxcommon.c,v 1.23 2005/03/30 17:27:19 titer Exp $
2
3    This file is part of the HandBrake source code.
4    Homepage: <http://handbrake.fr/>.
5    It may be used under the terms of the GNU General Public License. */
6
7 #include "hb.h"
8
9 struct hb_mux_object_s
10 {
11     HB_MUX_COMMON;
12 };
13
14 typedef struct
15 {
16     hb_job_t * job;
17     uint64_t   pts;
18
19 } hb_mux_t;
20
21 typedef struct
22 {
23     hb_fifo_t     * fifo;
24     hb_mux_data_t * mux_data;
25     uint64_t        frames;
26     uint64_t        bytes;
27
28 } hb_track_t;
29
30 static hb_track_t * GetTrack( hb_list_t * list )
31 {
32     hb_buffer_t * buf;
33     hb_track_t  * track = NULL, * track2;
34     int64_t       pts = 0;
35     int           i;
36
37     for( i = 0; i < hb_list_count( list ); i++ )
38     {
39         track2 = hb_list_item( list, i );
40         buf    = hb_fifo_see( track2->fifo );
41         if( !buf )
42         {
43             // To make sure we don't camp on one fifo & prevent the others
44             // from making progress we take the earliest data of all the
45             // data that's currently available but we don't care if some
46             // fifos don't have data.
47             continue;
48         }
49         if( !track || buf->start < pts )
50         {
51             track = track2;
52             pts   = buf->start;
53         }
54     }
55     return track;
56 }
57
58 static void MuxerFunc( void * _mux )
59 {
60     hb_mux_t    * mux = _mux;
61     hb_job_t    * job = mux->job;
62     hb_title_t  * title = job->title;
63     hb_audio_t  * audio;
64     hb_list_t   * list;
65     hb_buffer_t * buf;
66     hb_track_t  * track;
67     int           i;
68
69     hb_mux_object_t * m = NULL;
70
71     /* Get a real muxer */
72     if( job->pass == 0 || job->pass == 2)
73     {
74         switch( job->mux )
75         {
76             case HB_MUX_MP4:
77             case HB_MUX_PSP:
78                         case HB_MUX_IPOD:
79                 m = hb_mux_mp4_init( job );
80                 break;
81             case HB_MUX_AVI:
82                 m = hb_mux_avi_init( job );
83                 break;
84             case HB_MUX_OGM:
85                 m = hb_mux_ogm_init( job );
86                 break;
87             case HB_MUX_MKV:
88                 m = hb_mux_mkv_init( job );
89         }
90     }
91
92     /* Wait for one buffer for each track */
93     while( !*job->die && !job->done )
94     {
95         int ready;
96
97         ready = 1;
98         if( !hb_fifo_size( job->fifo_mpeg4 ) )
99         {
100             ready = 0;
101         }
102         for( i = 0; i < hb_list_count( title->list_audio ); i++ )
103         {
104             audio = hb_list_item( title->list_audio, i );
105             if( !hb_fifo_size( audio->priv.fifo_out ) )
106             {
107                 ready = 0;
108                 break;
109             }
110         }
111
112         if( ready )
113         {
114             break;
115         }
116
117         hb_snooze( 50 );
118     }
119
120     /* Create file, write headers */
121     if( job->pass == 0 || job->pass == 2 )
122     {
123         m->init( m );
124     }
125
126     /* Build list of fifos we're interested in */
127     list = hb_list_init();
128
129     track           = calloc( sizeof( hb_track_t ), 1 );
130     track->fifo     = job->fifo_mpeg4;
131     track->mux_data = job->mux_data;
132     hb_list_add( list, track );
133
134     for( i = 0; i < hb_list_count( title->list_audio ); i++ )
135     {
136         audio           = hb_list_item( title->list_audio, i );
137         track           = calloc( sizeof( hb_track_t ), 1 );
138         track->fifo     = audio->priv.fifo_out;
139         track->mux_data = audio->priv.mux_data;
140         hb_list_add( list, track );
141     }
142
143         int thread_sleep_interval = 50;
144         while( !*job->die && !job->done )
145     {
146         if( !( track = GetTrack( list ) ) )
147         {
148             hb_snooze( thread_sleep_interval );
149             continue;
150         }
151
152         buf = hb_fifo_get( track->fifo );
153         if( job->pass == 0 || job->pass == 2 )
154         {
155             m->mux( m, track->mux_data, buf );
156             track->frames += 1;
157             track->bytes  += buf->size;
158             mux->pts = buf->stop;
159         }
160         hb_buffer_close( &buf );
161     }
162
163     if( job->pass == 0 || job->pass == 2 )
164     {
165         struct stat sb;
166         uint64_t bytes_total, frames_total;
167
168 #define p state.param.muxing
169         /* Update the UI */
170         hb_state_t state;
171         state.state   = HB_STATE_MUXING;
172                 p.progress = 0;
173         hb_set_state( job->h, &state );
174 #undef p
175         m->end( m );
176
177         if( !stat( job->file, &sb ) )
178         {
179             hb_log( "mux: file size, %lld bytes", (uint64_t) sb.st_size );
180
181             bytes_total  = 0;
182             frames_total = 0;
183             for( i = 0; i < hb_list_count( list ); i++ )
184             {
185                 track = hb_list_item( list, i );
186                 hb_log( "mux: track %d, %lld bytes, %.2f kbps",
187                         i, track->bytes,
188                         90000.0 * track->bytes / mux->pts / 125 );
189                 if( !i && ( job->vquality < 0.0 || job->vquality > 1.0 ) )
190                 {
191                     /* Video */
192                     hb_log( "mux: video bitrate error, %+lld bytes",
193                             track->bytes - mux->pts * job->vbitrate *
194                             125 / 90000 );
195                 }
196                 bytes_total  += track->bytes;
197                 frames_total += track->frames;
198             }
199
200             if( bytes_total && frames_total )
201             {
202                 hb_log( "mux: overhead, %.2f bytes per frame",
203                         (float) ( sb.st_size - bytes_total ) /
204                         frames_total );
205             }
206         }
207     }
208
209     free( m );
210
211     for( i = 0; i < hb_list_count( list ); i++ )
212     {
213         track = hb_list_item( list, i );
214         if( track->mux_data )
215         {
216             free( track->mux_data );
217         }
218         free( track );
219     }
220     hb_list_close( &list );
221
222     free( mux );
223 }
224
225 hb_thread_t * hb_muxer_init( hb_job_t * job )
226 {
227     hb_mux_t * mux = calloc( sizeof( hb_mux_t ), 1 );
228     mux->job = job;
229     return hb_thread_init( "muxer", MuxerFunc, mux,
230                            HB_NORMAL_PRIORITY );
231 }