Skip to content

Instantly share code, notes, and snippets.

@danilogr
Last active July 27, 2016 17:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save danilogr/ab4976ff4e0831ab274b to your computer and use it in GitHub Desktop.
Save danilogr/ab4976ff4e0831ab274b to your computer and use it in GitHub Desktop.
x264 encoding times
/*
* This gist is based on the original example.c provided by libx264's source
* code. It's slightly modified so that it can use some of c++11 latest features
* (e.g.: chronos lib, std::bind and std::function).
* It also encodes the last frame as many times as there are frames in the input
* file so that it can compare the avg encoding time for these two different situations
* (video with movements vs static image repeated many times)
*
* # Requirements:
* (Tested with) libx264 0.148.2597M e86f3a1
* c++11 compatible compiler (Used g++ 4.8.1)
*
* # Compiling (using libx264 static)
* g++ -std=c++11 -ffast-math -m64 -DHAVE_SSE3 -fPIC -fomit-frame-pointer -c -o encoder_test.o encoder_test.cpp
* g++ -o encoder_test encoder_test.o lib/libx264.a -m64 -lm -pthread -ldl
*
* # Usage:
* ./encoder_test (width)x(height) <input.yuv >output.h264
*
* There is a .h264 file attached to this gist that can be converted to a .yuv
* file and used as an input source.
*
* You'll need ffmpeg in order to convert it:
* ffmpeg -i jake_test.h264 -c:v rawvideo -vframes 430 -pix_fmt yuv420p jake_test.yuv
*
* After obtaining jake_test.yuv, you can use it with encoder_test like this:
* ./encoder_test 1280x720 <jake_test.yuv >jake_new.h264
*
* Encoder parameters will be the following:
*
* 1280x720 fps=25/1 timebase=0/0 bitdepth=8 cabac=0 ref=1 deblock=1:0:0 analyse=0x3:0x113
* me=hex subme=2 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1
* 8x8dct=0 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=0 threads=1 lookahead_threads=0
* sliced_threads=0 slice_max_size=1190 nr=60 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0
* bframes=0 weightp=0 keyint=1200 keyint_min=120 scenecut=40 intra_refresh=0 rc_lookahead=0 rc=crf
* mbtree=0 crf=24.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 vbv_maxrate=1024 vbv_bufsize=350
* crf_max=35.0 nal_hrd=none filler=0 ip_ratio=1.40 aq=1:1.00
*
*****************************************************************************
* example.c: libx264 API usage example
*****************************************************************************
* Copyright (C) 2014-2015 x264 project
*
* Authors: Anton Mitrofanov <BugMaster@narod.ru>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at licensing@x264.com.
******************************************************************************/
#include <iostream>
#include <cstdio>
#include <functional>
#include <memory>
#include <stdint.h>
#include <limits>
#include <chrono>
#include "include/x264.h"
using namespace std;
extern "C" char *x264_param2string(x264_param_t* params);
extern "C" char *x264_free(void* params);
#define FAIL_IF_ERROR( cond, ... )\
do\
{\
if( cond )\
{\
fprintf( stderr, __VA_ARGS__ );\
return -1;\
}\
} while( 0 )
template <typename Callback>
class ScopedMethod
{
public:
ScopedMethod(Callback callback) : c (callback){}
~ScopedMethod() { c(); }
private:
Callback c;
};
int main( int argc, char **argv )
{
int width, height;
x264_param_t param;
x264_picture_t pic;
x264_picture_t pic_out;
x264_t *h;
int i_frame = 0;
int i_frame_size;
x264_nal_t *nal;
int i_nal;
FAIL_IF_ERROR( !(argc > 1), "Example usage: example 352x288 <input.yuv >output.h264\n" );
FAIL_IF_ERROR( 2 != sscanf( argv[1], "%dx%d", &width, &height ), "resolution not specified or incorrect\n" );
/* Get default params for preset/tuning */
// if( x264_param_default_preset( &param, "medium", NULL ) < 0 )
// return -1;
x264_param_default(&param);
/* Configure non-default params */
param.i_log_level = X264_LOG_INFO;
param.analyse.b_transform_8x8 = false;
param.i_csp = X264_CSP_I420;
param.i_width = width;
param.i_height = height;
param.b_repeat_headers = 1;
param.b_annexb = 1;
param.b_cabac = 0;
param.i_slice_max_size = 1190;
param.i_bframe = 0;
// Removing these 3 parameters below won't impact frame encoding avg time
x264_param_parse(&param, "crf","24");
param.rc.i_rc_method = X264_RC_CRF;
param.rc.f_rf_constant_max = 35;
param.analyse.i_weighted_pred = 0;
x264_param_parse(&param, "sync-lookahead", "0");
x264_param_parse(&param, "nr","60");
x264_param_parse(&param, "me","hex");
x264_param_parse(&param, "force-cfr", NULL);
x264_param_parse(&param, "no-mbtree", NULL);
x264_param_parse(&param, "sps-id", "5");
x264_param_parse(&param, "ref", "1");
x264_param_parse(&param, "b-adapt", "1");
x264_param_parse(&param, "tune", "zerolatency");
param.b_sliced_threads = 0;
param.i_threads = 1;
param.rc.i_vbv_max_bitrate = 1024;
param.rc.i_vbv_buffer_size = 350;
param.i_keyint_min = 120;
param.i_keyint_max = 1200;
x264_param_parse(&param,"rc-lookahead", "0");
x264_param_parse(&param,"subme","2");
x264_param_parse(&param,"trellis","1");
x264_param_parse(&param,"cqm","flat");
/* Apply profile restrictions. */
// if( x264_param_apply_profile( &param, "baseline") < 0 )
// return -1;
x264_param_parse(&param, "profile", "baseline");
if( x264_picture_alloc( &pic, param.i_csp, param.i_width, param.i_height ) < 0 )
return -1;
char* parameterString = x264_param2string(&param);
cerr << "Parameter string: " << parameterString << endl;
x264_free(parameterString);
ScopedMethod<function<void()>> picture_clean(bind(x264_picture_clean, &pic));
h = x264_encoder_open( &param );
if( !h )
return -1;
ScopedMethod<function<void()>> encoder_close(bind(x264_encoder_close, h));
int luma_size = width * height;
int chroma_size = luma_size / 4;
/* variables used for tracking amount of time used */
double highest = numeric_limits<double>::min(), avg=0, lowest = numeric_limits<double>::max();
/* Encode frames */
for( ;; i_frame++ )
{
/* Read input frame */
if( fread( pic.img.plane[0], 1, luma_size, stdin ) != luma_size )
break;
if( fread( pic.img.plane[1], 1, chroma_size, stdin ) != chroma_size )
break;
if( fread( pic.img.plane[2], 1, chroma_size, stdin ) != chroma_size )
break;
pic.i_pts = i_frame;
auto start = chrono::steady_clock::now();
i_frame_size = x264_encoder_encode( h, &nal, &i_nal, &pic, &pic_out );
auto end = chrono::steady_clock::now();
chrono::duration<double> diff = end - start;
double diffb = diff.count();
if (diffb > highest)
highest = diffb;
if (diffb < lowest)
lowest = diffb;
avg += diffb;
if( i_frame_size < 0 )
return -1;
else if( i_frame_size )
{
if( !fwrite( nal->p_payload, i_frame_size, 1, stdout ) )
return -1;
}
}
int count = i_frame;
cerr << "Encoded " << count << " frames (Moving) \t"
<< "Highest: " << highest << " Avg: " << avg/i_frame << " Lowest:" << lowest << endl;
/* Encoded the same frame once again */
highest = numeric_limits<double>::min();
avg = 0;
lowest = numeric_limits<double>::max();
while( i_frame-- > 0 )
{
auto start = chrono::steady_clock::now();
i_frame_size = x264_encoder_encode( h, &nal, &i_nal, &pic, &pic_out );
auto end = chrono::steady_clock::now();
chrono::duration<double> diff = end - start;
double diffb = diff.count();
if (diffb > highest)
highest = diffb;
if (diffb < lowest)
lowest = diffb;
avg += diffb;
if( i_frame_size < 0 )
return -1;
else if( i_frame_size )
{
if( !fwrite( nal->p_payload, i_frame_size, 1, stdout ) )
return -1;
}
}
cerr << "Encoded " << count << " frames (Static) \t"
<< "Highest: " << highest << " Avg: " << avg/count << " Lowest:" << lowest << endl << endl;
return 0;
}
This file has been truncated, but you can view the full file.
View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

@danilogr
Copy link
Author

This code belongs to this post on the x264's mailing list: https://mailman.videolan.org/pipermail/x264-devel/2015-September/011389.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment