static int open_file( char *psz_filename, hnd_t *p_handle, cli_output_opt_t *opt ) { avi_hnd_t *h; AVOutputFormat *mux_fmt; *p_handle = NULL; FILE *fh = fopen( psz_filename, "w" ); if( !fh ) return -1; int b_regular = x264_is_regular_file( fh ); fclose( fh ); if( !b_regular ) { x264vfw_cli_log( opt->p_private, "avi", X264_LOG_ERROR, "AVI output is incompatible with non-regular file `%s'\n", psz_filename ); return -1; } if( !(h = malloc( sizeof(avi_hnd_t) )) ) return -1; memset( h, 0, sizeof(avi_hnd_t) ); memcpy( &h->opt, opt, sizeof(cli_output_opt_t) ); av_register_all(); mux_fmt = av_guess_format( "avi", NULL, NULL ); if( !mux_fmt ) { close_file( h, 0, 0 ); return -1; } h->mux_fc = avformat_alloc_context(); if( !h->mux_fc ) { close_file( h, 0, 0 ); return -1; } h->mux_fc->oformat = mux_fmt; memset( h->mux_fc->filename, 0, sizeof(h->mux_fc->filename) ); snprintf( h->mux_fc->filename, sizeof(h->mux_fc->filename) - 1, "%s", psz_filename ); if( avio_open( &h->mux_fc->pb, psz_filename, AVIO_FLAG_WRITE ) < 0 ) { close_file( h, 0, 0 ); return -1; } *p_handle = h; return 0; }
static int write_frame( hnd_t handle, uint8_t *p_nalu, int i_size, x264_picture_t *p_picture ) { flv_hnd_t *p_flv = handle; flv_buffer *c = p_flv->c; #define convert_timebase_ms( timestamp, timebase ) (int64_t)((timestamp) * (timebase) * 1000 + 0.5) if( !p_flv->i_framenum ) { p_flv->i_delay_time = p_picture->i_dts * -1; if( !p_flv->opt.use_dts_compress && p_flv->i_delay_time ) x264vfw_cli_log( p_flv->opt.p_private, "flv", X264_LOG_WARNING, "initial delay %"PRId64" ms\n", convert_timebase_ms( p_picture->i_pts + p_flv->i_delay_time, p_flv->d_timebase ) ); } int64_t dts; int64_t cts; int64_t offset; if( p_flv->opt.use_dts_compress ) { if( p_flv->i_framenum == 1 ) p_flv->i_init_delta = convert_timebase_ms( p_picture->i_dts + p_flv->i_delay_time, p_flv->d_timebase ); dts = p_flv->i_framenum > p_flv->i_delay_frames ? convert_timebase_ms( p_picture->i_dts, p_flv->d_timebase ) : p_flv->i_framenum * p_flv->i_init_delta / (p_flv->i_delay_frames + 1); cts = convert_timebase_ms( p_picture->i_pts, p_flv->d_timebase ); } else { dts = convert_timebase_ms( p_picture->i_dts + p_flv->i_delay_time, p_flv->d_timebase ); cts = convert_timebase_ms( p_picture->i_pts + p_flv->i_delay_time, p_flv->d_timebase ); } offset = cts - dts; if( p_flv->i_framenum ) { if( p_flv->i_prev_dts == dts ) x264vfw_cli_log( p_flv->opt.p_private, "flv", X264_LOG_WARNING, "duplicate DTS %"PRId64" generated by rounding\n" " decoding framerate cannot exceed 1000fps\n", dts ); if( p_flv->i_prev_cts == cts ) x264vfw_cli_log( p_flv->opt.p_private, "flv", X264_LOG_WARNING, "duplicate CTS %"PRId64" generated by rounding\n" " composition framerate cannot exceed 1000fps\n", cts ); } p_flv->i_prev_dts = dts; p_flv->i_prev_cts = cts; // A new frame - write packet header 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; flv_put_byte( c, (p_picture->b_keyframe ? FLV_FRAME_KEY : FLV_FRAME_INTER) | FLV_CODECID_H264 ); flv_put_byte( c, 1 ); // AVC NALU flv_put_be24( c, offset ); if( p_flv->sei ) { flv_append_data( c, p_flv->sei, p_flv->sei_len ); free( p_flv->sei ); p_flv->sei = NULL; } flv_append_data( c, p_nalu, i_size ); unsigned length = c->d_cur - p_flv->start; 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; }