]> git.sesse.net Git - x264/blob - output/flv.c
Improve DTS generation, move DTS compression into libx264
[x264] / output / flv.c
1 /*****************************************************************************
2  * flv.c:
3  *****************************************************************************
4  * Copyright (C) 2009 Kieran Kunhya <kieran@kunhya.com>
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
24 #define CHECK(x)\
25 do {\
26     if( (x) < 0 )\
27         return -1;\
28 } while( 0 )
29
30 typedef struct
31 {
32     flv_buffer *c;
33
34     uint8_t *sei;
35     int sei_len;
36
37     int64_t i_fps_num;
38     int64_t i_fps_den;
39     int64_t i_framenum;
40
41     uint64_t i_framerate_pos;
42     uint64_t i_duration_pos;
43     uint64_t i_filesize_pos;
44     uint64_t i_bitrate_pos;
45
46     uint8_t b_write_length;
47     int64_t i_prev_dts;
48     int64_t i_prev_pts;
49
50     int i_timebase_num;
51     int i_timebase_den;
52     int b_vfr_input;
53
54     unsigned start;
55 } flv_hnd_t;
56
57 static int write_header( flv_buffer *c )
58 {
59     x264_put_tag( c, "FLV" ); // Signature
60     x264_put_byte( c, 1 );    // Version
61     x264_put_byte( c, 1 );    // Video Only
62     x264_put_be32( c, 9 );    // DataOffset
63     x264_put_be32( c, 0 );    // PreviousTagSize0
64
65     return flv_flush_data( c );
66 }
67
68 static int open_file( char *psz_filename, hnd_t *p_handle )
69 {
70     flv_hnd_t *p_flv = malloc( sizeof(*p_flv) );
71     *p_handle = NULL;
72     if( !p_flv )
73         return -1;
74     memset( p_flv, 0, sizeof(*p_flv) );
75
76     p_flv->c = flv_create_writer( psz_filename );
77     if( !p_flv->c )
78         return -1;
79
80     CHECK( write_header( p_flv->c ) );
81     *p_handle = p_flv;
82
83     return 0;
84 }
85
86 static int set_param( hnd_t handle, x264_param_t *p_param )
87 {
88     flv_hnd_t *p_flv = handle;
89     flv_buffer *c = p_flv->c;
90
91     x264_put_byte( c, FLV_TAG_TYPE_META ); // Tag Type "script data"
92
93     int start = c->d_cur;
94     x264_put_be24( c, 0 ); // data length
95     x264_put_be24( c, 0 ); // timestamp
96     x264_put_be32( c, 0 ); // reserved
97
98     x264_put_byte( c, AMF_DATA_TYPE_STRING );
99     x264_put_amf_string( c, "onMetaData" );
100
101     x264_put_byte( c, AMF_DATA_TYPE_MIXEDARRAY );
102     x264_put_be32( c, 7 );
103
104     x264_put_amf_string( c, "width" );
105     x264_put_amf_double( c, p_param->i_width );
106
107     x264_put_amf_string( c, "height" );
108     x264_put_amf_double( c, p_param->i_height );
109
110     x264_put_amf_string( c, "framerate" );
111
112     if( !p_param->b_vfr_input )
113         x264_put_amf_double( c, (double)p_param->i_fps_num / p_param->i_fps_den );
114     else
115     {
116         p_flv->i_framerate_pos = c->d_cur + c->d_total + 1;
117         x264_put_amf_double( c, 0 ); // written at end of encoding
118     }
119
120     x264_put_amf_string( c, "videocodecid" );
121     x264_put_amf_double( c, FLV_CODECID_H264 );
122
123     x264_put_amf_string( c, "duration" );
124     p_flv->i_duration_pos = c->d_cur + c->d_total + 1;
125     x264_put_amf_double( c, 0 ); // written at end of encoding
126
127     x264_put_amf_string( c, "filesize" );
128     p_flv->i_filesize_pos = c->d_cur + c->d_total + 1;
129     x264_put_amf_double( c, 0 ); // written at end of encoding
130
131     x264_put_amf_string( c, "videodatarate" );
132     p_flv->i_bitrate_pos = c->d_cur + c->d_total + 1;
133     x264_put_amf_double( c, 0 ); // written at end of encoding
134
135     x264_put_amf_string( c, "" );
136     x264_put_byte( c, AMF_END_OF_OBJECT );
137
138     unsigned length = c->d_cur - start;
139     rewrite_amf_be24( c, length - 10, start );
140
141     x264_put_be32( c, length + 1 ); // tag length
142
143     p_flv->i_fps_num = p_param->i_fps_num;
144     p_flv->i_fps_den = p_param->i_fps_den;
145     p_flv->i_timebase_num = p_param->i_timebase_num;
146     p_flv->i_timebase_den = p_param->i_timebase_den;
147     p_flv->b_vfr_input = p_param->b_vfr_input;
148
149     return 0;
150 }
151
152 static int write_headers( hnd_t handle, x264_nal_t *p_nal )
153 {
154     flv_hnd_t *p_flv = handle;
155     flv_buffer *c = p_flv->c;
156
157     int sei_size = p_nal[0].i_payload;
158     int sps_size = p_nal[1].i_payload;
159     int pps_size = p_nal[2].i_payload;
160
161     // SEI
162     /* It is within the spec to write this as-is but for
163      * mplayer/ffmpeg playback this is deferred until before the first frame */
164
165     p_flv->sei = malloc( sei_size );
166     if( !p_flv->sei )
167         return -1;
168     p_flv->sei_len = sei_size;
169
170     memcpy( p_flv->sei, p_nal[0].p_payload, sei_size );
171
172     // SPS
173     uint8_t *sps = p_nal[1].p_payload + 4;
174
175     x264_put_byte( c, FLV_TAG_TYPE_VIDEO );
176     x264_put_be24( c, 0 ); // rewrite later
177     x264_put_be24( c, 0 ); // timestamp
178     x264_put_byte( c, 0 ); // timestamp extended
179     x264_put_be24( c, 0 ); // StreamID - Always 0
180     p_flv->start = c->d_cur; // needed for overwriting length
181
182     x264_put_byte( c, 7 | FLV_FRAME_KEY ); // Frametype and CodecID
183     x264_put_byte( c, 0 ); // AVC sequence header
184     x264_put_be24( c, 0 ); // composition time
185
186     x264_put_byte( c, 1 );      // version
187     x264_put_byte( c, sps[1] ); // profile
188     x264_put_byte( c, sps[2] ); // profile
189     x264_put_byte( c, sps[3] ); // level
190     x264_put_byte( c, 0xff );   // 6 bits reserved (111111) + 2 bits nal size length - 1 (11)
191     x264_put_byte( c, 0xe1 );   // 3 bits reserved (111) + 5 bits number of sps (00001)
192
193     x264_put_be16( c, sps_size - 4 );
194     flv_append_data( c, sps, sps_size - 4 );
195
196     // PPS
197     x264_put_byte( c, 1 ); // number of pps
198     x264_put_be16( c, pps_size - 4 );
199     flv_append_data( c, p_nal[2].p_payload + 4, pps_size - 4 );
200
201     // rewrite data length info
202     unsigned length = c->d_cur - p_flv->start;
203     rewrite_amf_be24( c, length, p_flv->start - 10 );
204     x264_put_be32( c, length + 11 ); // Last tag size
205     CHECK( flv_flush_data( c ) );
206
207     return sei_size + sps_size + pps_size;
208 }
209
210 static int write_frame( hnd_t handle, uint8_t *p_nalu, int i_size, x264_picture_t *p_picture )
211 {
212     flv_hnd_t *p_flv = handle;
213     flv_buffer *c = p_flv->c;
214
215     int64_t dts = (int64_t)( (p_picture->i_dts * 1000 * ((double)p_flv->i_timebase_num / p_flv->i_timebase_den)) + 0.5 );
216     int64_t cts = (int64_t)( (p_picture->i_pts * 1000 * ((double)p_flv->i_timebase_num / p_flv->i_timebase_den)) + 0.5 );
217     int64_t offset = cts - dts;
218
219     if( p_flv->i_framenum )
220     {
221         int64_t prev_dts = (int64_t)( (p_flv->i_prev_dts * 1000 * ((double)p_flv->i_timebase_num / p_flv->i_timebase_den)) + 0.5 );
222         int64_t prev_cts = (int64_t)( (p_flv->i_prev_pts * 1000 * ((double)p_flv->i_timebase_num / p_flv->i_timebase_den)) + 0.5 );
223         if( prev_dts == dts )
224         {
225             double fps = ((double)p_flv->i_timebase_den / p_flv->i_timebase_num) / (p_picture->i_dts - p_flv->i_prev_dts);
226             fprintf( stderr, "flv [warning]: duplicate DTS %"PRId64" generated by rounding\n"
227                              "               current internal decoding framerate: %.6f fps\n", dts, fps );
228         }
229         if( prev_cts == cts )
230         {
231             double fps = ((double)p_flv->i_timebase_den / p_flv->i_timebase_num) / (p_picture->i_pts - p_flv->i_prev_pts);
232             fprintf( stderr, "flv [warning]: duplicate CTS %"PRId64" is generated by rounding\n"
233                              "               current internal composition framerate: %.6f fps\n", cts, fps );
234         }
235     }
236     p_flv->i_prev_dts = p_picture->i_dts;
237     p_flv->i_prev_pts = p_picture->i_pts;
238
239     // A new frame - write packet header
240     x264_put_byte( c, FLV_TAG_TYPE_VIDEO );
241     x264_put_be24( c, 0 ); // calculated later
242     x264_put_be24( c, dts );
243     x264_put_byte( c, dts >> 24 );
244     x264_put_be24( c, 0 );
245
246     p_flv->start = c->d_cur;
247     x264_put_byte( c, p_picture->b_keyframe ? FLV_FRAME_KEY : FLV_FRAME_INTER );
248     x264_put_byte( c, 1 ); // AVC NALU
249     x264_put_be24( c, offset );
250
251     if( p_flv->sei )
252     {
253         flv_append_data( c, p_flv->sei, p_flv->sei_len );
254         free( p_flv->sei );
255         p_flv->sei = NULL;
256     }
257     flv_append_data( c, p_nalu, i_size );
258
259     unsigned length = c->d_cur - p_flv->start;
260     rewrite_amf_be24( c, length, p_flv->start - 10 );
261     x264_put_be32( c, 11 + length ); // Last tag size
262     CHECK( flv_flush_data( c ) );
263
264     p_flv->i_framenum++;
265
266     return i_size;
267 }
268
269 static void rewrite_amf_double( FILE *fp, uint64_t position, double value )
270 {
271     uint64_t x = endian_fix64( dbl2int( value ) );
272     fseek( fp, position, SEEK_SET );
273     fwrite( &x, 8, 1, fp );
274 }
275
276 static int close_file( hnd_t handle, int64_t largest_pts, int64_t second_largest_pts )
277 {
278     flv_hnd_t *p_flv = handle;
279     flv_buffer *c = p_flv->c;
280
281     CHECK( flv_flush_data( c ) );
282
283     double total_duration = (double)(2 * largest_pts - second_largest_pts) * p_flv->i_timebase_num / p_flv->i_timebase_den;
284
285     if( x264_is_regular_file( c->fp ) )
286     {
287         double framerate;
288         uint64_t filesize = ftell( c->fp );
289
290         if( p_flv->i_framerate_pos )
291         {
292             framerate = (double)p_flv->i_framenum / total_duration;
293             rewrite_amf_double( c->fp, p_flv->i_framerate_pos, framerate );
294         }
295
296         rewrite_amf_double( c->fp, p_flv->i_duration_pos, total_duration );
297         rewrite_amf_double( c->fp, p_flv->i_filesize_pos, filesize );
298         rewrite_amf_double( c->fp, p_flv->i_bitrate_pos, filesize * 8 / ( total_duration * 1000 ) );
299     }
300
301     fclose( c->fp );
302     free( p_flv );
303     free( c );
304
305     return 0;
306 }
307
308 cli_output_t flv_output = { open_file, set_param, write_headers, write_frame, close_file };