/*****************************************************************************
* flv.c: flv muxer
*****************************************************************************
- * Copyright (C) 2009-2011 x264 project
+ * Copyright (C) 2009-2015 x264 project
*
* Authors: Kieran Kunhya <kieran@kunhya.com>
*
static int write_header( flv_buffer *c )
{
- x264_put_tag( c, "FLV" ); // Signature
- x264_put_byte( c, 1 ); // Version
- x264_put_byte( c, 1 ); // Video Only
- x264_put_be32( c, 9 ); // DataOffset
- x264_put_be32( c, 0 ); // PreviousTagSize0
+ flv_put_tag( c, "FLV" ); // Signature
+ flv_put_byte( c, 1 ); // Version
+ flv_put_byte( c, 1 ); // Video Only
+ flv_put_be32( c, 9 ); // DataOffset
+ flv_put_be32( c, 0 ); // PreviousTagSize0
return flv_flush_data( c );
}
static int open_file( char *psz_filename, hnd_t *p_handle, cli_output_opt_t *opt )
{
- flv_hnd_t *p_flv = malloc( sizeof(*p_flv) );
- *p_handle = NULL;
- if( !p_flv )
- return -1;
- memset( p_flv, 0, sizeof(*p_flv) );
-
- p_flv->b_dts_compress = opt->use_dts_compress;
-
- p_flv->c = flv_create_writer( psz_filename );
- if( !p_flv->c )
- return -1;
-
- CHECK( write_header( p_flv->c ) );
- *p_handle = p_flv;
+ flv_hnd_t *p_flv = calloc( 1, sizeof(flv_hnd_t) );
+ if( p_flv )
+ {
+ flv_buffer *c = flv_create_writer( psz_filename );
+ if( c )
+ {
+ if( !write_header( c ) )
+ {
+ p_flv->c = c;
+ p_flv->b_dts_compress = opt->use_dts_compress;
+ *p_handle = p_flv;
+ return 0;
+ }
+
+ fclose( c->fp );
+ free( c->data );
+ free( c );
+ }
+ free( p_flv );
+ }
- return 0;
+ *p_handle = NULL;
+ return -1;
}
static int set_param( hnd_t handle, x264_param_t *p_param )
flv_hnd_t *p_flv = handle;
flv_buffer *c = p_flv->c;
- x264_put_byte( c, FLV_TAG_TYPE_META ); // Tag Type "script data"
+ flv_put_byte( c, FLV_TAG_TYPE_META ); // Tag Type "script data"
int start = c->d_cur;
- x264_put_be24( c, 0 ); // data length
- x264_put_be24( c, 0 ); // timestamp
- x264_put_be32( c, 0 ); // reserved
+ flv_put_be24( c, 0 ); // data length
+ flv_put_be24( c, 0 ); // timestamp
+ flv_put_be32( c, 0 ); // reserved
- x264_put_byte( c, AMF_DATA_TYPE_STRING );
- x264_put_amf_string( c, "onMetaData" );
+ flv_put_byte( c, AMF_DATA_TYPE_STRING );
+ flv_put_amf_string( c, "onMetaData" );
- x264_put_byte( c, AMF_DATA_TYPE_MIXEDARRAY );
- x264_put_be32( c, 7 );
+ flv_put_byte( c, AMF_DATA_TYPE_MIXEDARRAY );
+ flv_put_be32( c, 7 );
- x264_put_amf_string( c, "width" );
- x264_put_amf_double( c, p_param->i_width );
+ flv_put_amf_string( c, "width" );
+ flv_put_amf_double( c, p_param->i_width );
- x264_put_amf_string( c, "height" );
- x264_put_amf_double( c, p_param->i_height );
+ flv_put_amf_string( c, "height" );
+ flv_put_amf_double( c, p_param->i_height );
- x264_put_amf_string( c, "framerate" );
+ flv_put_amf_string( c, "framerate" );
if( !p_param->b_vfr_input )
- x264_put_amf_double( c, (double)p_param->i_fps_num / p_param->i_fps_den );
+ flv_put_amf_double( c, (double)p_param->i_fps_num / p_param->i_fps_den );
else
{
p_flv->i_framerate_pos = c->d_cur + c->d_total + 1;
- x264_put_amf_double( c, 0 ); // written at end of encoding
+ flv_put_amf_double( c, 0 ); // written at end of encoding
}
- x264_put_amf_string( c, "videocodecid" );
- x264_put_amf_double( c, FLV_CODECID_H264 );
+ flv_put_amf_string( c, "videocodecid" );
+ flv_put_amf_double( c, FLV_CODECID_H264 );
- x264_put_amf_string( c, "duration" );
+ flv_put_amf_string( c, "duration" );
p_flv->i_duration_pos = c->d_cur + c->d_total + 1;
- x264_put_amf_double( c, 0 ); // written at end of encoding
+ flv_put_amf_double( c, 0 ); // written at end of encoding
- x264_put_amf_string( c, "filesize" );
+ flv_put_amf_string( c, "filesize" );
p_flv->i_filesize_pos = c->d_cur + c->d_total + 1;
- x264_put_amf_double( c, 0 ); // written at end of encoding
+ flv_put_amf_double( c, 0 ); // written at end of encoding
- x264_put_amf_string( c, "videodatarate" );
+ flv_put_amf_string( c, "videodatarate" );
p_flv->i_bitrate_pos = c->d_cur + c->d_total + 1;
- x264_put_amf_double( c, 0 ); // written at end of encoding
+ flv_put_amf_double( c, 0 ); // written at end of encoding
- x264_put_amf_string( c, "" );
- x264_put_byte( c, AMF_END_OF_OBJECT );
+ flv_put_amf_string( c, "" );
+ flv_put_byte( c, AMF_END_OF_OBJECT );
unsigned length = c->d_cur - start;
- rewrite_amf_be24( c, length - 10, start );
+ flv_rewrite_amf_be24( c, length - 10, start );
- x264_put_be32( c, length + 1 ); // tag length
+ flv_put_be32( c, length + 1 ); // tag length
p_flv->i_fps_num = p_param->i_fps_num;
p_flv->i_fps_den = p_param->i_fps_den;
// SPS
uint8_t *sps = p_nal[0].p_payload + 4;
- x264_put_byte( c, FLV_TAG_TYPE_VIDEO );
- x264_put_be24( c, 0 ); // rewrite later
- x264_put_be24( c, 0 ); // timestamp
- x264_put_byte( c, 0 ); // timestamp extended
- x264_put_be24( c, 0 ); // StreamID - Always 0
+ flv_put_byte( c, FLV_TAG_TYPE_VIDEO );
+ flv_put_be24( c, 0 ); // rewrite later
+ flv_put_be24( c, 0 ); // timestamp
+ flv_put_byte( c, 0 ); // timestamp extended
+ flv_put_be24( c, 0 ); // StreamID - Always 0
p_flv->start = c->d_cur; // needed for overwriting length
- x264_put_byte( c, 7 | FLV_FRAME_KEY ); // Frametype and CodecID
- x264_put_byte( c, 0 ); // AVC sequence header
- x264_put_be24( c, 0 ); // composition time
+ flv_put_byte( c, 7 | FLV_FRAME_KEY ); // Frametype and CodecID
+ flv_put_byte( c, 0 ); // AVC sequence header
+ flv_put_be24( c, 0 ); // composition time
- x264_put_byte( c, 1 ); // version
- x264_put_byte( c, sps[1] ); // profile
- x264_put_byte( c, sps[2] ); // profile
- x264_put_byte( c, sps[3] ); // level
- x264_put_byte( c, 0xff ); // 6 bits reserved (111111) + 2 bits nal size length - 1 (11)
- x264_put_byte( c, 0xe1 ); // 3 bits reserved (111) + 5 bits number of sps (00001)
+ flv_put_byte( c, 1 ); // version
+ flv_put_byte( c, sps[1] ); // profile
+ flv_put_byte( c, sps[2] ); // profile
+ flv_put_byte( c, sps[3] ); // level
+ flv_put_byte( c, 0xff ); // 6 bits reserved (111111) + 2 bits nal size length - 1 (11)
+ flv_put_byte( c, 0xe1 ); // 3 bits reserved (111) + 5 bits number of sps (00001)
- x264_put_be16( c, sps_size - 4 );
+ flv_put_be16( c, sps_size - 4 );
flv_append_data( c, sps, sps_size - 4 );
// PPS
- x264_put_byte( c, 1 ); // number of pps
- x264_put_be16( c, pps_size - 4 );
+ flv_put_byte( c, 1 ); // number of pps
+ flv_put_be16( c, pps_size - 4 );
flv_append_data( c, p_nal[1].p_payload + 4, pps_size - 4 );
// rewrite data length info
unsigned length = c->d_cur - p_flv->start;
- rewrite_amf_be24( c, length, p_flv->start - 10 );
- x264_put_be32( c, length + 11 ); // Last tag size
+ flv_rewrite_amf_be24( c, length, p_flv->start - 10 );
+ flv_put_be32( c, length + 11 ); // Last tag size
CHECK( flv_flush_data( c ) );
return sei_size + sps_size + pps_size;
p_flv->i_prev_cts = cts;
// A new frame - write packet header
- x264_put_byte( c, FLV_TAG_TYPE_VIDEO );
- x264_put_be24( c, 0 ); // calculated later
- x264_put_be24( c, dts );
- x264_put_byte( c, dts >> 24 );
- x264_put_be24( c, 0 );
+ flv_put_byte( c, FLV_TAG_TYPE_VIDEO );
+ flv_put_be24( c, 0 ); // calculated later
+ flv_put_be24( c, dts );
+ flv_put_byte( c, dts >> 24 );
+ flv_put_be24( c, 0 );
p_flv->start = c->d_cur;
- x264_put_byte( c, p_picture->b_keyframe ? FLV_FRAME_KEY : FLV_FRAME_INTER );
- x264_put_byte( c, 1 ); // AVC NALU
- x264_put_be24( c, offset );
+ flv_put_byte( c, p_picture->b_keyframe ? FLV_FRAME_KEY : FLV_FRAME_INTER );
+ flv_put_byte( c, 1 ); // AVC NALU
+ flv_put_be24( c, offset );
if( p_flv->sei )
{
flv_append_data( c, p_nalu, i_size );
unsigned length = c->d_cur - p_flv->start;
- rewrite_amf_be24( c, length, p_flv->start - 10 );
- x264_put_be32( c, 11 + length ); // Last tag size
+ flv_rewrite_amf_be24( c, length, p_flv->start - 10 );
+ flv_put_be32( c, 11 + length ); // Last tag size
CHECK( flv_flush_data( c ) );
p_flv->i_framenum++;
return i_size;
}
-static void rewrite_amf_double( FILE *fp, uint64_t position, double value )
+static int rewrite_amf_double( FILE *fp, uint64_t position, double value )
{
- uint64_t x = endian_fix64( dbl2int( value ) );
- fseek( fp, position, SEEK_SET );
- fwrite( &x, 8, 1, fp );
+ uint64_t x = endian_fix64( flv_dbl2int( value ) );
+ return !fseek( fp, position, SEEK_SET ) && fwrite( &x, 8, 1, fp ) == 1 ? 0 : -1;
}
+#undef CHECK
+#define CHECK(x)\
+do {\
+ if( (x) < 0 )\
+ goto error;\
+} while( 0 )
+
static int close_file( hnd_t handle, int64_t largest_pts, int64_t second_largest_pts )
{
+ int ret = -1;
flv_hnd_t *p_flv = handle;
flv_buffer *c = p_flv->c;
if( p_flv->i_framerate_pos )
{
framerate = (double)p_flv->i_framenum / total_duration;
- rewrite_amf_double( c->fp, p_flv->i_framerate_pos, framerate );
+ CHECK( rewrite_amf_double( c->fp, p_flv->i_framerate_pos, framerate ) );
}
- rewrite_amf_double( c->fp, p_flv->i_duration_pos, total_duration );
- rewrite_amf_double( c->fp, p_flv->i_filesize_pos, filesize );
- rewrite_amf_double( c->fp, p_flv->i_bitrate_pos, filesize * 8 / ( total_duration * 1000 ) );
+ CHECK( rewrite_amf_double( c->fp, p_flv->i_duration_pos, total_duration ) );
+ CHECK( rewrite_amf_double( c->fp, p_flv->i_filesize_pos, filesize ) );
+ CHECK( rewrite_amf_double( c->fp, p_flv->i_bitrate_pos, filesize * 8 / ( total_duration * 1000 ) ) );
}
+ ret = 0;
+error:
fclose( c->fp );
- free( p_flv );
+ free( c->data );
free( c );
+ free( p_flv );
- return 0;
+ return ret;
}
const cli_output_t flv_output = { open_file, set_param, write_headers, write_frame, close_file };