]> git.sesse.net Git - x264/blob - output/flv.c
Fix bugs in fps/timestamp handling in FLV muxer
[x264] / output / flv.c
1 /*****************************************************************************
2  * flv.c:
3  *****************************************************************************
4  * Copyright (C) 2009 Kieran Kunhya
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111, USA.
19  *****************************************************************************/
20
21 #include "muxers.h"
22 #include "flv_bytestream.h"
23 #define CHECK(x)\
24 do {\
25     if( (x) < 0 )\
26         return -1;\
27 } while( 0 )
28
29 typedef struct
30 {
31     flv_buffer *c;
32
33     uint8_t b_sps;
34     uint8_t b_pps;
35     uint8_t *sei;
36     int sei_len;
37
38     int64_t i_fps_num;
39     int64_t i_fps_den;
40     int64_t i_init_delay;
41     int64_t i_framenum;
42     double d_mspf;
43
44     uint64_t i_duration_pos;
45     uint64_t i_filesize_pos;
46     uint64_t i_bitrate_pos;
47
48     uint8_t b_write_length;
49
50     unsigned start;
51 } flv_hnd_t;
52
53 static int write_header( flv_buffer *c )
54 {
55     put_tag( c, "FLV" ); // Signature
56     put_byte( c, 1 );    // Version
57     put_byte( c, 1 );    // Video Only
58     put_be32( c, 9 );    // DataOffset
59     put_be32( c, 0 );    // PreviousTagSize0
60
61     return flv_flush_data( c );
62 }
63
64 static int open_file( char *psz_filename, hnd_t *p_handle )
65 {
66     flv_hnd_t *p_flv = malloc( sizeof(*p_flv) );
67     *p_handle = NULL;
68     if( !p_flv )
69         return -1;
70     memset( p_flv, 0, sizeof(*p_flv) );
71
72     p_flv->c = flv_create_writer( psz_filename );
73     if( !p_flv->c )
74         return -1;
75
76     CHECK( write_header( p_flv->c ) );
77     *p_handle = p_flv;
78
79     return 0;
80 }
81
82 static int set_param( hnd_t handle, x264_param_t *p_param )
83 {
84     flv_hnd_t *p_flv = handle;
85     flv_buffer *c = p_flv->c;
86
87     put_byte( c, FLV_TAG_TYPE_META ); // Tag Type "script data"
88
89     int start = c->d_cur;
90     put_be24( c, 0 ); // data length
91     put_be24( c, 0 ); // timestamp
92     put_be32( c, 0 ); // reserved
93
94     put_byte( c, AMF_DATA_TYPE_STRING );
95     put_amf_string( c, "onMetaData" );
96
97     put_byte( c, AMF_DATA_TYPE_MIXEDARRAY );
98     put_be32( c, 7 );
99
100     put_amf_string( c, "width" );
101     put_amf_double( c, p_param->i_width );
102
103     put_amf_string( c, "height" );
104     put_amf_double( c, p_param->i_height );
105
106     put_amf_string( c, "framerate" );
107     put_amf_double( c, (double)p_param->i_fps_num / p_param->i_fps_den );
108
109     put_amf_string( c, "videocodecid" );
110     put_amf_double( c, FLV_CODECID_H264 );
111
112     put_amf_string( c, "duration" );
113     p_flv->i_duration_pos = c->d_cur + c->d_total + 1; // + 1 because of the following AMF_DATA_TYPE_NUMBER byte
114     put_amf_double( c, 0 ); // written at end of encoding
115
116     put_amf_string( c, "filesize" );
117     p_flv->i_filesize_pos = c->d_cur + c->d_total + 1;
118     put_amf_double( c, 0 ); // written at end of encoding
119
120     put_amf_string( c, "videodatarate" );
121     p_flv->i_bitrate_pos = c->d_cur + c->d_total + 1;
122     put_amf_double( c, 0 ); // written at end of encoding
123
124     put_amf_string( c, "" );
125     put_byte( c, AMF_END_OF_OBJECT );
126
127     unsigned length = c->d_cur - start;
128     rewrite_amf_be24( c, length - 10, start );
129
130     put_be32( c, length + 1 ); // tag length
131
132     p_flv->i_fps_num = p_param->i_fps_num;
133     p_flv->i_fps_den = p_param->i_fps_den;
134     p_flv->i_init_delay = p_param->i_bframe ? (p_param->i_bframe_pyramid ? 2 : 1) : 0;
135     p_flv->d_mspf = 1000 * (double)p_flv->i_fps_den / p_flv->i_fps_num;
136
137     fprintf( stderr, "flv [info]: initial delay %i frames\n",
138              (int)p_flv->i_init_delay );
139
140     return 0;
141 }
142
143 static int write_nalu( hnd_t handle, uint8_t *p_nalu, int i_size, x264_picture_t *p_picture )
144 {
145     flv_hnd_t *p_flv = handle;
146     flv_buffer *c = p_flv->c;
147     uint64_t dts = (uint64_t)p_flv->i_framenum * p_flv->d_mspf;
148     uint64_t pts = (uint64_t)p_picture->i_pts * p_flv->d_mspf / p_flv->i_fps_den;
149     uint64_t offset = p_flv->i_init_delay * p_flv->d_mspf + pts - dts;
150     uint8_t type = p_nalu[4] & 0x1f;
151
152     switch( type )
153     {
154         // sps
155         case 0x07:
156             if( !p_flv->b_sps )
157             {
158                 uint8_t *sps = p_nalu + 4;
159
160                 put_byte( c, FLV_TAG_TYPE_VIDEO );
161                 put_be24( c, 0 ); // rewrite later, pps size unknown
162                 put_be24( c, 0 ); // timestamp
163                 put_byte( c, 0 ); // timestamp extended
164                 put_be24( c, 0 ); // StreamID - Always 0
165                 p_flv->start = c->d_cur; // needed for overwriting length
166
167                 put_byte( c, 7 | FLV_FRAME_KEY ); // Frametype and CodecID
168                 put_byte( c, 0 ); // AVC sequence header
169                 put_be24( c, 0 ); // composition time
170
171                 put_byte( c, 1 );      // version
172                 put_byte( c, sps[1] ); // profile
173                 put_byte( c, sps[2] ); // profile
174                 put_byte( c, sps[3] ); // level
175                 put_byte( c, 0xff );   // 6 bits reserved (111111) + 2 bits nal size length - 1 (11)
176                 put_byte( c, 0xe1 );   // 3 bits reserved (111) + 5 bits number of sps (00001)
177
178                 put_be16( c, i_size - 4 );
179                 flv_append_data( c, sps, i_size - 4 );
180
181                 p_flv->b_sps = 1;
182             }
183             break;
184
185         // pps
186         case 0x08:
187             if( !p_flv->b_pps )
188             {
189                 put_byte( c, 1 ); // number of pps
190                 put_be16( c, i_size - 4 );
191                 flv_append_data( c, p_nalu + 4, i_size - 4 );
192
193                 // rewrite data length info
194                 unsigned length = c->d_cur - p_flv->start;
195                 rewrite_amf_be24( c, length, p_flv->start - 10 );
196                 put_be32( c, length + 11 ); // Last tag size
197
198                 p_flv->b_pps = 1;
199             }
200             break;
201
202         // slice
203         case 0x1:
204         case 0x5:
205             if( !p_flv->b_write_length )
206             {
207                 // A new frame - write packet header
208                 put_byte( c, FLV_TAG_TYPE_VIDEO );
209                 put_be24( c, 0 ); // calculated later
210                 put_be24( c, dts );
211                 put_byte( c, dts >> 24 );
212                 put_be24( c, 0 );
213
214                 p_flv->start = c->d_cur;
215                 put_byte( c, p_picture->i_type == X264_TYPE_IDR ? FLV_FRAME_KEY : FLV_FRAME_INTER );
216                 put_byte( c, 1 ); // AVC NALU
217                 put_be24( c, offset );
218
219                 p_flv->b_write_length = 1;
220             }
221             if( p_flv->sei )
222             {
223                 flv_append_data( c, p_flv->sei, p_flv->sei_len );
224                 free( p_flv->sei );
225                 p_flv->sei = NULL;
226             }
227             flv_append_data( c, p_nalu, i_size );
228             break;
229         // sei
230         case 0x6:
231             /* It is within the spec to write this as-is but for
232              * mplayer/ffmpeg playback this is deferred until before the first frame */
233
234             p_flv->sei = malloc( i_size );
235             if( !p_flv->sei )
236                 return -1;
237             p_flv->sei_len = i_size;
238
239             memcpy( p_flv->sei, p_nalu, i_size );
240             break;
241     }
242     return i_size;
243 }
244
245 static int set_eop( hnd_t handle, x264_picture_t *p_picture )
246 {
247     flv_hnd_t *p_flv = handle;
248     flv_buffer *c = p_flv->c;
249
250     if( p_flv->b_write_length )
251     {
252         unsigned length = c->d_cur - p_flv->start;
253         rewrite_amf_be24( c, length, p_flv->start - 10 );
254         put_be32( c, 11 + length ); // Last tag size
255         CHECK( flv_flush_data( c ) );
256         p_flv->b_write_length = 0;
257     }
258     p_flv->i_framenum++;
259
260     return 0;
261 }
262
263 static void rewrite_amf_double( FILE *fp, uint64_t position, double value )
264 {
265     uint64_t x = endian_fix64( dbl2int( value ) );
266     fseek( fp, position, SEEK_SET );
267     fwrite( &x, 8, 1, fp );
268 }
269
270 static int close_file( hnd_t handle )
271 {
272     flv_hnd_t *p_flv = handle;
273     flv_buffer *c = p_flv->c;
274
275     CHECK( flv_flush_data( c ) );
276
277     if( x264_is_regular_file( c->fp ) )
278     {
279         double duration = p_flv->i_fps_den * p_flv->i_framenum / p_flv->i_fps_num;
280         uint64_t filesize = ftell( c->fp );
281         rewrite_amf_double( c->fp, p_flv->i_duration_pos, duration );
282         rewrite_amf_double( c->fp, p_flv->i_filesize_pos, filesize );
283         rewrite_amf_double( c->fp, p_flv->i_bitrate_pos, filesize * 8 / ( duration * 1000 ) );
284     }
285
286     fclose( c->fp );
287     free( p_flv );
288     free( c );
289
290     return 0;
291 }
292
293 cli_output_t flv_output = { open_file, set_param, write_nalu, set_eop, close_file };