1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2009 Kieran Kunhya <kieran@kunhya.com>
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.
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.
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 *****************************************************************************/
22 #include "flv_bytestream.h"
41 uint64_t i_framerate_pos;
42 uint64_t i_duration_pos;
43 uint64_t i_filesize_pos;
44 uint64_t i_bitrate_pos;
46 uint8_t b_write_length;
50 uint32_t i_timebase_num;
51 uint32_t i_timebase_den;
57 static int write_header( flv_buffer *c )
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
65 return flv_flush_data( c );
68 static int open_file( char *psz_filename, hnd_t *p_handle )
70 flv_hnd_t *p_flv = malloc( sizeof(*p_flv) );
74 memset( p_flv, 0, sizeof(*p_flv) );
76 p_flv->c = flv_create_writer( psz_filename );
80 CHECK( write_header( p_flv->c ) );
86 static int set_param( hnd_t handle, x264_param_t *p_param )
88 flv_hnd_t *p_flv = handle;
89 flv_buffer *c = p_flv->c;
91 x264_put_byte( c, FLV_TAG_TYPE_META ); // Tag Type "script data"
94 x264_put_be24( c, 0 ); // data length
95 x264_put_be24( c, 0 ); // timestamp
96 x264_put_be32( c, 0 ); // reserved
98 x264_put_byte( c, AMF_DATA_TYPE_STRING );
99 x264_put_amf_string( c, "onMetaData" );
101 x264_put_byte( c, AMF_DATA_TYPE_MIXEDARRAY );
102 x264_put_be32( c, 7 );
104 x264_put_amf_string( c, "width" );
105 x264_put_amf_double( c, p_param->i_width );
107 x264_put_amf_string( c, "height" );
108 x264_put_amf_double( c, p_param->i_height );
110 x264_put_amf_string( c, "framerate" );
112 if( !p_param->b_vfr_input )
113 x264_put_amf_double( c, (double)p_param->i_fps_num / p_param->i_fps_den );
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
120 x264_put_amf_string( c, "videocodecid" );
121 x264_put_amf_double( c, FLV_CODECID_H264 );
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
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
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
135 x264_put_amf_string( c, "" );
136 x264_put_byte( c, AMF_END_OF_OBJECT );
138 unsigned length = c->d_cur - start;
139 rewrite_amf_be24( c, length - 10, start );
141 x264_put_be32( c, length + 1 ); // tag length
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;
152 static int write_headers( hnd_t handle, x264_nal_t *p_nal )
154 flv_hnd_t *p_flv = handle;
155 flv_buffer *c = p_flv->c;
157 int sps_size = p_nal[0].i_payload;
158 int pps_size = p_nal[1].i_payload;
159 int sei_size = p_nal[2].i_payload;
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 */
165 p_flv->sei = malloc( sei_size );
168 p_flv->sei_len = sei_size;
170 memcpy( p_flv->sei, p_nal[2].p_payload, sei_size );
173 uint8_t *sps = p_nal[0].p_payload + 4;
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
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
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)
193 x264_put_be16( c, sps_size - 4 );
194 flv_append_data( c, sps, sps_size - 4 );
197 x264_put_byte( c, 1 ); // number of pps
198 x264_put_be16( c, pps_size - 4 );
199 flv_append_data( c, p_nal[1].p_payload + 4, pps_size - 4 );
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 ) );
207 return sei_size + sps_size + pps_size;
210 static int write_frame( hnd_t handle, uint8_t *p_nalu, int i_size, x264_picture_t *p_picture )
212 flv_hnd_t *p_flv = handle;
213 flv_buffer *c = p_flv->c;
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;
219 if( p_flv->i_framenum )
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 )
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 );
229 if( prev_cts == cts )
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" generated by rounding\n"
233 " current internal composition framerate: %.6f fps\n", cts, fps );
236 p_flv->i_prev_dts = p_picture->i_dts;
237 p_flv->i_prev_pts = p_picture->i_pts;
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 );
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 );
253 flv_append_data( c, p_flv->sei, p_flv->sei_len );
257 flv_append_data( c, p_nalu, i_size );
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 ) );
269 static void rewrite_amf_double( FILE *fp, uint64_t position, double value )
271 uint64_t x = endian_fix64( dbl2int( value ) );
272 fseek( fp, position, SEEK_SET );
273 fwrite( &x, 8, 1, fp );
276 static int close_file( hnd_t handle, int64_t largest_pts, int64_t second_largest_pts )
278 flv_hnd_t *p_flv = handle;
279 flv_buffer *c = p_flv->c;
281 CHECK( flv_flush_data( c ) );
283 double total_duration = (double)(2 * largest_pts - second_largest_pts) * p_flv->i_timebase_num / p_flv->i_timebase_den;
285 if( x264_is_regular_file( c->fp ) )
288 uint64_t filesize = ftell( c->fp );
290 if( p_flv->i_framerate_pos )
292 framerate = (double)p_flv->i_framenum / total_duration;
293 rewrite_amf_double( c->fp, p_flv->i_framerate_pos, framerate );
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 ) );
308 const cli_output_t flv_output = { open_file, set_param, write_headers, write_frame, close_file };