OSDN Git Service

SunOS support fixed with new ffmpeg and x264
[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     int             eof;
28 } hb_track_t;
29
30 static hb_track_t * GetTrack( hb_list_t * list, hb_job_t *job )
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         if ( ! track2->eof )
41         {
42             buf    = hb_fifo_see( track2->fifo );
43             if( !buf )
44             {
45                 // XXX the libmkv muxer will produce unplayable files if the
46                 // audio & video are far out of sync.  To keep them in sync we require
47                 // that *all* fifos have a buffer then we take the oldest.
48                 // Unfortunately this means we can hang in a deadlock with the
49                 // reader process filling the fifos.
50                 if ( job->mux == HB_MUX_MKV )
51                 {
52                     return NULL;
53                 }
54
55                 // To make sure we don't camp on one fifo & prevent the others
56                 // from making progress we take the earliest data of all the
57                 // data that's currently available but we don't care if some
58                 // fifos don't have data.
59                 continue;
60             }
61             if ( buf->size <= 0 )
62             {
63                 // EOF - mark this track as done
64                 buf = hb_fifo_get( track2->fifo );
65                 hb_buffer_close( &buf );
66                 track2->eof = 1;
67                 continue;
68             }
69             if( !track || buf->start < pts )
70             {
71                 track = track2;
72                 pts   = buf->start;
73             }
74         }
75     }
76     return track;
77 }
78
79 static int AllTracksDone( hb_list_t * list )
80 {
81     hb_track_t  * track;
82     int           i;
83
84     for( i = 0; i < hb_list_count( list ); i++ )
85     {
86         track = hb_list_item( list, i );
87         if ( track->eof == 0 )
88         {
89             return 0;
90         }
91     }
92     return 1;
93 }
94
95 static void MuxerFunc( void * _mux )
96 {
97     hb_mux_t    * mux = _mux;
98     hb_job_t    * job = mux->job;
99     hb_title_t  * title = job->title;
100     hb_audio_t  * audio;
101     hb_list_t   * list;
102     hb_buffer_t * buf;
103     hb_track_t  * track;
104     int           i;
105
106     hb_mux_object_t * m = NULL;
107
108     /* Get a real muxer */
109     if( job->pass == 0 || job->pass == 2)
110     {
111         switch( job->mux )
112         {
113             case HB_MUX_MP4:
114             case HB_MUX_PSP:
115                         case HB_MUX_IPOD:
116                 m = hb_mux_mp4_init( job );
117                 break;
118             case HB_MUX_AVI:
119                 m = hb_mux_avi_init( job );
120                 break;
121             case HB_MUX_OGM:
122                 m = hb_mux_ogm_init( job );
123                 break;
124             case HB_MUX_MKV:
125                 m = hb_mux_mkv_init( job );
126         }
127     }
128
129     /* Create file, write headers */
130     if( job->pass == 0 || job->pass == 2 )
131     {
132         m->init( m );
133     }
134
135     /* Build list of fifos we're interested in */
136     list = hb_list_init();
137
138     track           = calloc( sizeof( hb_track_t ), 1 );
139     track->fifo     = job->fifo_mpeg4;
140     track->mux_data = job->mux_data;
141     hb_list_add( list, track );
142
143     for( i = 0; i < hb_list_count( title->list_audio ); i++ )
144     {
145         audio           = hb_list_item( title->list_audio, i );
146         track           = calloc( sizeof( hb_track_t ), 1 );
147         track->fifo     = audio->priv.fifo_out;
148         track->mux_data = audio->priv.mux_data;
149         hb_list_add( list, track );
150     }
151
152         int thread_sleep_interval = 50;
153         while( !*job->die )
154     {
155         if( !( track = GetTrack( list, job ) ) )
156         {
157             if ( AllTracksDone( list )  )
158             {
159                 // all our input fifos have signaled EOF
160                 break;
161             }
162             hb_snooze( thread_sleep_interval );
163             continue;
164         }
165
166         buf = hb_fifo_get( track->fifo );
167         if( job->pass == 0 || job->pass == 2 )
168         {
169             m->mux( m, track->mux_data, buf );
170             track->frames += 1;
171             track->bytes  += buf->size;
172             mux->pts = buf->stop;
173         }
174         hb_buffer_close( &buf );
175     }
176
177     if( job->pass == 0 || job->pass == 2 )
178     {
179         struct stat sb;
180         uint64_t bytes_total, frames_total;
181
182 #define p state.param.muxing
183         /* Update the UI */
184         hb_state_t state;
185         state.state   = HB_STATE_MUXING;
186                 p.progress = 0;
187         hb_set_state( job->h, &state );
188 #undef p
189         m->end( m );
190
191         if( !stat( job->file, &sb ) )
192         {
193             hb_deep_log( 2, "mux: file size, %lld bytes", (uint64_t) sb.st_size );
194
195             bytes_total  = 0;
196             frames_total = 0;
197             for( i = 0; i < hb_list_count( list ); i++ )
198             {
199                 track = hb_list_item( list, i );
200                 hb_deep_log( 2, "mux: track %d, %lld bytes, %.2f kbps",
201                         i, track->bytes,
202                         90000.0 * track->bytes / mux->pts / 125 );
203                 if( !i && ( job->vquality < 0.0 || job->vquality > 1.0 ) )
204                 {
205                     /* Video */
206                     hb_deep_log( 2, "mux: video bitrate error, %+lld bytes",
207                             track->bytes - mux->pts * job->vbitrate *
208                             125 / 90000 );
209                 }
210                 bytes_total  += track->bytes;
211                 frames_total += track->frames;
212             }
213
214             if( bytes_total && frames_total )
215             {
216                 hb_deep_log( 2, "mux: overhead, %.2f bytes per frame",
217                         (float) ( sb.st_size - bytes_total ) /
218                         frames_total );
219             }
220         }
221     }
222
223     free( m );
224
225     for( i = 0; i < hb_list_count( list ); i++ )
226     {
227         track = hb_list_item( list, i );
228         if( track->mux_data )
229         {
230             free( track->mux_data );
231         }
232         free( track );
233     }
234     hb_list_close( &list );
235
236     free( mux );
237 }
238
239 hb_thread_t * hb_muxer_init( hb_job_t * job )
240 {
241     hb_mux_t * mux = calloc( sizeof( hb_mux_t ), 1 );
242     mux->job = job;
243     return hb_thread_init( "muxer", MuxerFunc, mux,
244                            HB_NORMAL_PRIORITY );
245 }