Showing posts with label msvc. Show all posts
Showing posts with label msvc. Show all posts

Sunday, 11 May 2014

MSVC C99 math.h header.

These days with Visual Studio 2013 (msvc12) being out, Microsoft has a proper C99 compliant math.h C header file. For anyone using any C99 math function I would first recommend you do so using msvc12. However recently I was working on a project that wanted to support older versions of msvc so I wrote up some compatibility code that added the additional missing functions that were added to math.h in C99. Since older msvc versions are C89 compliant they are missing many functions that were added in C99. However some of these functions aren't actually missing they were just added to the header using a different name (often with an '_' prefix). So if you know where these functions are you can make them usable in a C99 way.

So here is some code that can be added under a normal math.h include to add missing C99 functions. Not all of them are here and those that are missing are identified with a simple comment. But many of the commonly used ones are provided so hopefully this may be useful for someone.

#if _MSC_VER > 1800
// MSVC 11 or earlier does not define a C99 compliant math.h header.
// Missing functions are included here for compatibility.
#include 
static __inline double acosh(double x){
    return log(x + sqrt((x * x) - 1.0));
}
static __inline float acoshf(float x){
    return logf(x + sqrtf((x * x) - 1.0f));
}
#   define acoshl(x) acosh(x)
static __inline double asinh(double x){
    return log(x + sqrt((x * x) + 1.0));
}
static __inline float asinhf(float x){
    return logf(x + sqrtf((x * x) + 1.0f));
}
#   define asinhl(x) asinh(x)
static __inline double atanh(double x){
    return (log(1.0 + x) - log(1.0 - x)) / 2;
}
static __inline float atanhf(float x){
    return (logf(1.0f + x) - logf(1.0f - x)) / 2.0f;
}
#define atanhl(x) atanh(x)
static __inline double cbrt(double x){
    return (x > 0.0) ? pow(x, 1.0 / 3.0) : -pow(-x, 1.0 / 3.0);
}
static __inline float cbrtf(float x){
    return (x > 0.0f) ? powf(x, 1.0f / 3.0f) : -powf(-x, 1.0f / 3.0f);
}
#define cbrtl(x) cbrt(x)
#define copysign(x,s) _copysign(x,s)
#define copysignf(x,s) _copysign(x,s)
#define copysignl(x,s) _copysignl(x,s)
static __inline double erf(double x){
    double a1 = 0.254829592, a2 = -0.284496736, a3 = 1.421413741;
    double a4 = -1.453152027, a5 = 1.061405429, p = 0.3275911;
    double t, y;
    int sign = (x >= 0) ? 1 : -1;
    x = fabs(x);
    t = 1.0 / (1.0 + p*x);
    y = 1.0 - (((((a5 * t + a4 ) * t) + a3) * t + a2) * t + a1) * t * exp(-x * x);
    return sign*y;
}
static __inline float erff(float x){
    return erf((float)x);
}
#define erfl(x) erf(x)
// erfc
static __inline double exp2(double x){
    return pow(2.0, x);
}
static __inline float exp2f(float x){
    return powf(2.0f, x);
}
#define exp2l(x) exp2(x)
static __inline double expm1(double x){
    if(fabs(x) < 1e-5)
        return x + 0.5 * x * x;
    else
        return exp(x) - 1.0;
}
static __inline float expm1f(float x){
    if(fabsf(x) < 1e-5f)
        return x + 0.5f * x * x;
    else
        return expf(x) - 1.0f;
}
#define expm1l(x) expm1(x)
static __inline double fdim(double x, double y){
    return (x > y) ? x - y : 0.0;
}
static __inline float fdimf(float x, float y){
    return (x > y) ? x - y : 0.0f;
}
#define fdiml(x,y) fdim(x,y)
static __inline double fma(double x, double y, double z){
    return ((x * y) + z);
}
static __inline float fmaf(float x, float y, float z){
    return ((x * y) + z);
}
#define fmal(x,y,z) fma(x,y,z)
static __inline double fmax(double x, double y){
    return (x > y) ? x : y;
}
static __inline float fmaxf(float x, float y){
    return (x > y) ? x : y;
}
#define fmaxl(x,y) fmax(x,y)
static __inline double fmin(double x, double y){
    return (x < y) ? x : y;
}
static __inline float fminf(float x, float y){
    return (x < y) ? x : y;
}
#define fminl(x,y) fmin(x,y)
#ifndef _HUGE_ENUF
#    define _HUGE_ENUF 1e+300
#endif   
#define INFINITY   ((float)(_HUGE_ENUF * _HUGE_ENUF))  /* causes warning C4756: overflow in constant arithmetic (by design) */
#define NAN        ((float)(INFINITY * 0.0F))
#define FP_INFINITE  1
#define FP_NAN       2
#define FP_NORMAL    (-1)
#define FP_SUBNORMAL (-2)
#define FP_ZERO      0
#define fpclassify(x) ((_fpclass(x)==_FPCLASS_SNAN)?FP_NAN:((_fpclass(x)==_FPCLASS_QNAN)?FP_NAN:((_fpclass(x)==_FPCLASS_QNAN)?FP_NAN: \
 ((_fpclass(x)==_FPCLASS_NINF)?FP_INFINITE:((_fpclass(x)==_FPCLASS_PINF)?FP_INFINITE: \
 ((_fpclass(x)==_FPCLASS_NN)?FP_NORMAL:((_fpclass(x)==_FPCLASS_PN)?FP_NORMAL: \
 ((_fpclass(x)==_FPCLASS_ND)?FP_SUBNORMAL:((_fpclass(x)==_FPCLASS_PD)?FP_SUBNORMAL: \
 FP_ZERO)))))))))
#define hypot(x,y) _hypot(x,y)
#define hypotf(x,y) _hypotf(x,y)
 // ilogb
#define isfinite(x) _finite(x)
#define isnan(x) (!!_isnan(x))
#define isinf(x) (!_finite(x) && !_isnan(x))
#define isnormal(x) ((_fpclass(x) == _FPCLASS_NN) || (_fpclass(x) == _FPCLASS_PN))
#define isgreater(x,y)      ((x) > (y))
#define isgreaterequal(x,y) ((x) >= (y))
#define isless(x,y)         ((x) < (y))
#define islessequal(x,y)    ((x) <= (y))
#define islessgreater(x,y)  (((x) < (y)) || ((x) > (y)))
#define isunordered(x,y)    (_isnan(x) || _isnan(y))
#define j0(x) _j0(x)
#define j1(x) _j1(x)
#define jn(x,y) _jn(x,y)
// lgamma
static __inline double log1p(double x){
    if(fabs(x) > 1e-4){
        return log(1.0 + x);
    }
    return (-0.5 * x + 1.0) * x;
}
static __inline float log1pf(float x){
    if(fabsf(x) > 1e-4f){
        return logf(1.0f + x);
    }
    return (-0.5f * x + 1.0f) * x;
}
#define log1pl(x) log1p(x)
static __inline double log2(double x) {
    return log(x) * M_LOG2E;
}
static __inline float log2f(float x) {
    return logf(x) * (float)M_LOG2E;
}
#define log2l(x) log2(x)
#define logb(x) _logb(x)
#define logbf(x) _logb(x)
#define logbl(x) _logb(x)
// nearbyint
#define nextafter(x,y) _nextafter(x,y)
#define nextafterf(x,y) _nextafter(x,y)
// nexttoward
static __inline double rint(double x){
    const double two_to_52 = 4.5035996273704960e+15;
    double fa = fabs(x);
    if(fa >= two_to_52){
        return x;
    } else{
        return copysign(two_to_52 + fa - two_to_52, x);
    }
}
static __inline float rintf(float x){
    const double two_to_52 = 4.5035996273704960e+15f;
    double fa = fabsf(x);
    if(fa >= two_to_52){
        return x;
    } else{
        return copysignf(two_to_52 + fa - two_to_52, x);
    }
}
#define rintl(x) rint(x)
static __inline double remainder(double x, double y){
    return (x - ( rint(x / y) * y ));
}
static __inline float remainderf(float x, float y){
    return (x - ( rintf(x / y) * y ));
}

#define remainderl(x) remainder(x)
static __inline double remquo(double x, double y, int* q){
    double d = rint(x / y);
    q = (int)d;
    return (x - (d * y));
}
static __inline float remquof(float x, float y, int* q){
    float f = rintf(x / y);
    q = (int)f;
    return (x - (f * y));
}
#define remquo(x) remquo(x)
static __inline double round(double x){ return ((x > 0.0) ? floor(x + 0.5) : ceil(x - 0.5)); } static __inline float roundf(float x){ return ((x > 0.0f) ? floorf(x + 0.5f) : ceilf(x - 0.5f)); } #define roundl(x) round(x) // scalbn #define signbit(x) (_copysign(1.0, x) < 0) // tgamma static __inline double trunc(double x){ return (x > 0.0) ? floor(x) : ceil(x); } static __inline float truncf(float x){ return (x > 0.0f) ? floorf(x) : ceilf(x); } #define truncl(x) trunc(x) #define y0(x) _y0(x) #define y1(x) _y1(x) #define yn(x,y) _yn(x,y) static __inline long lrint(double x){ return (long)rint(x); } static __inline long lrintf(float x){ return (long)rintf(x); } define lrintl(x) lrint(x) static __inline long lround(double x){ return (long)round(x); } static __inline long lroundf(float x){ return (long)roundf(x); } #define lroundl(x) lround(x) static __inline long long llrint(double x){ return (long long)rint(x); } static __inline long long llrintf(float x){ return (long long)rintf(x); } #define llrintl(x) llrint(x) static __inline long long llround(double x){ return (long long)round(x); } static __inline long long llroundf(float x){ return (long long)roundf(x); } #define llroundl(x) llround(x) #endif

Thursday, 13 March 2014

Building x264 on Windows with Visual Studio

For anyone who has ever done any video encoding (or just watching for that matter) will probably have heard of x264. And if you havnt then you should have at least have heard of h264 (and if you still havnt then this post is probably not for you) which is the standard name for the video codec that the x264 encoder implements. So in the world of h264 video encoding x264 is probably one of, if not the best. And it is completely free and open source. So anyone who wants to get their hands on it can do so easily.

One downside of the x264 project (much like most open source projects) is that the default build tool is a gnu make style build chain. These don't run natively on Windows and generally requires an emulated shell such as MSYS or Cygwin. And even from within these shells they only support gcc (MinGW on Windows) based compilers.

But for those wanting to compile x264 natively on Windows using the native Windows build chain (i.e. Visual Studio) then that can actually be done rather simply. For those with Visual Studio 2013 then compiling many similar open source projects becomes a lot easier due to the addition of partial C99 support. C99 is something Microsoft have been neglecting for many years but with the 2013 updates it is a lot closer. x264 however still requires some manipulation in order to get it compile under MSVC's mostly C89 world.
Luckily changing x264 for be MSVC compatiblilty is rather straightforward. Most of the issues are a result of C89 requiring all variable declarations to be altogether and the start of each logical block of code. Straight of the bat most of the errors that Visual Studio will spit out about the x264 code will be a result of this issue (although the error codes don't do you any favours in realising this). So most errors will be due to code such as the following:

int padv = PADV >> v_shift;
// buffer: 2 chroma, 3 luma (rounded to 4) because deblocking goes beyond the top of the mb
if( b_end && !b_start )
    height += 4 >> (v_shift + SLICE_MBAFF);
pixel *pix;
int starty = 16*mb_y - 4*!b_start;

This will generate an error on the variable 'pix' because it is declared mid way through a block of code. Luckily the specifications say 'block' of code, which does not mean function or something similar. Instead it essential means anything between a set of '{' or '}'s (There iss actually a bit more to it than that but for our purposes - as you'll see later - it is good enough). In the above example we can see that the declaration of 'pix' occurs after an if statement. So if all we need to separate blocks are some '{}'s then modifying the code to the following will actually work:

int padv = PADV >> v_shift;
// buffer: 2 chroma, 3 luma (rounded to 4) because deblocking goes beyond the top of the mb
if( b_end && !b_start )
{
    height += 4 >> (v_shift + SLICE_MBAFF);
}
pixel *pix;
int starty = 16*mb_y - 4*!b_start;

All we did here was add the '{' and the '}' to the if statement. This makes that statement a block and so the line following it becomes a new block which makes everything work. This is surprisingly simple fix and will work for all of the cases found in libx264. In fact a complete working libx264 can be achieved by just performing the above operation at 10 different location in code. Or if you couldn't be bothered doing it yourself you can just apply the following patch that I have already made up for you.

Download patch file:
https://github.com/ShiftMediaProject/x264/commit/d9004ba604283fb70a3b67d444f67576c00a0e2e.diff

Now for those who don't just want the lib for x264 but actually want to compile the command line x264.exe then you'll have to perform the same operation a few more times. However there are 2 additional things youll need to do.
First is related to an issue with the use of unions. Specifically the following piece of code:

return (union {double f; uint64_t i;}){value}.i;

The above is too much for MSVC to handle. But with a bit of massaging it can be made to work. Massaging such as this:

union { double f; uint64_t i; } ulld = { value };
return ulld.i

The second issue is due to initialization lists being used on an array of structs. MSVC defaults to thinking that each element in the initializer list is actually an input for each component for the actual struct. So in the following piece of code MSVC treats the initializer list as actually an initializer list for the first 'AVS_Value' in the array.

AVS_Value arg_arr[] = { res, avs_new_value_bool( info->interlaced ), avs_new_value_string( matrix ) };

This will cause some nonsensical errors such as how a type of AVS_Value can not be converted to type short (short here being the type of the first member of AVS_Value). There is pretty much no combination of additional '('s and '{' that will fix this problem. So we have to fallback to the slightly less convenient way of just specifying each array element individually.

AVS_Value arg_arr[3];
arg_arr[0] = res;
arg_arr[1] = avs_new_value_bool( info->interlaced );
arg_arr[2] = avs_new_value_string( matrix );

This is not as nice to look at but it works. Putting all these pieces together and x264cli will compile under Visual Studio without any further problems. Again for those who dont want to do all this themselves then the appropriate patch can be acquired from below.

Download patch file:
https://github.com/ShiftMediaProject/x264/commit/4c51a4fc51737d932eddb4060bcd03d861dfec7d.diff

Of course if you don't want to worry about any of the above then you can check out my git repository that has all the necessary changes already applied and even comes with a pre-built Visual Studio project file. My repo is up to date with the current upstream master and with x264 development slowing down due to the upcoming x265 then its unlikely my repo will fall behind the upstream master so can be treated as up to date.

git repository:
https://github.com/ShiftMediaProject/x264

So with all of those above fixes it should be reasonable trivial to get x264 building natively in Windows. As to whether this is worth it is a debate for another time. For those who aren't familiar with MSYS/Cygwin but are familiar with Visual Studio then this should be a big win. What will be interesting is to test the performance of the compiled binaries between the different compilers. Perhaps ill have more on that soon.....

Saturday, 25 January 2014

Building FFmpeg in Visual Studio

The default build chain for the FFmpeg project uses the standard (well standard for gnu open source projects) gnu autotools. The use of configure and make may be rather familiar to those who compile often on linux but for many Windows developers these can seem like somewhat alien tools. This is compounded by the fact that to use these tools on Windows requires setting up a MSYS/Cygwin environment which can often be easier said than done. Even after that most build chains using this environment require a gcc based compiler which on Windows is MinGW. Gcc is a good compiler but MinGW can have some issues (which in its defence is generally always around Windows specific things) which can make it less than ideal.

FFmpegs default build tools do currently support compiling natively in msvc (Microsoft's C compiler) and will even convert the C99 FFmpeg code to msvc compliant C89 code. But this still requires setting up a MSYS shell and any additional FFmpeg dependencies don't offer msvc support from within the same build tools.

So as powerful as the configure/make build chains can be and say what you like about the msvc compiler (I agree its standards compliance is abysmal) but for those wanting to develop natively on Windows having Visual Studio support is the simplest and most robust. Since FFmpeg wont maintain a native Visual Studio build chain (and I cant blame them for not wanting to), I got a little bored and decided to take it upon myself to provide an alternative.

The result of some holiday free time is that I wrote up a FFmpeg Visual Studio project generator. This is a simple piece of software that will scan in the existing FFmpeg configure/make files and then use those to dynamically generate a visual studio project file that can be used to natively compile FFmpeg. This program not only builds the project files but will also generate the config files dynamically based on a combination of rules found in the original configure script and any passed in arguments. In fact the generator excepts many of the same configuration arguments as the configure script allowing fine-tuned control of what gets enabled/disabled.
Example command line options:

ffmpeg_generator.exe --enable-gpl --enable-bzlib --enable-iconv 
   --enable-zlib --disable-encoders --enable-encoder=vorbis

The program doesn't support all the options of the configure script but it supports many of them and in some cases actually exposes more than the original. Any option that shows up in the config.h file can be manually enabled/disabled through the command line. And even if an invalid option is set the generator uses all the inbuilt configuration checks found in the original build script to automatically validate each setting. Options such as 32/64bit are some of the options that are not supported, mainly because they are not relevant as the generated config.h file can be used for both 32/64 bit and even detects and enables inline asm if the Intel compiler is made available.

#define ARCH_X86 1
#if defined( __x86_64 ) || defined( _M_X64 )
#   define ARCH_X86_32 0
#else
#   define ARCH_X86_32 1
#endif

All of this happens dynamically so for those building from git master, once any commits are and added to your repo you just have to rerun the generator program and it will automatically detect any changes (new/deleted files, configuration changes, new/deleted options etc.) and generate a new project accordingly.

Now I should point out that this generator was rather quickly (and half-assed) thrown together so its not exactly very brilliant code. But for something quick and dirty it gets the job done. It supports all current additional dependencies but not all have been checked and it takes certain liberties with respect to library naming. This is because many dependency libraries don't have consistent naming conventions so the link include the generated project uses may not be exactly the same as the actually file you are linking against. Should this happen then you'll just have to manually tweak the file-name in the include option as without any kind of naming consistency there's not much that can be done about it.

The generator also by default generates a project with default Intel compiler settings. Those without Intel compiler may have to change a few settings in the project properties if they want to set it back to the standard msvc. Intel is chosen as default as Visual Studio 2012 doesn't support enough C99 features to be able to compile FFmpeg so only the Intel compiler can be used with 2012 to build the project. For those with Visual Studio 2013 the default compiler adds enough C99 to be able to get it to work but for the moment the generator is built to default to 2012. The same project can be loaded in both 2012/2013 and all that needs to be changed is the compiler being used. If there is enough interest I may add an option to the generator to allow for people to specify whether they want Intel support or not at generation time but in the meantime you'll just have to change the build tool in the project properties.

Update: The current version of the generator allows for specifying the compiler that will be used as default in the output project file. Of course this can also be changed directly in the project after it is generated but for convenience the "toolchain" option is now processed by the generator. With newer patches to FFmpeg Visual Studio 2013 can compile it without problems. The toolchian parameter accepts either "msvc" for default Microsoft compiler or "icl" for the Intel compiler which also supports inline assembly.

ffmpeg_generator.exe --toolchain=msvc

The project generator can be found in my git repo below. Also in the repo is a pre-built project that is built using the following command options:

ffmpeg_generator.exe --enable-gpl --enable-version3 --enable-avisynth
   --enable-nonfree --enable-bzlib --enable-iconv --enable-zlib
   --enable-libmp3lame --enable-libvorbis --enable-libspeex
   --enable-libopus --enable-libfdk-aac --enable-libtheora
   --enable-libx264 --enable-libxvid --enable-libvpx --enable-libmodplug
   --enable-libsoxr --enable-libfreetype --enable-fontconfig 
   --enable-libass --enable-openssl --enable-librtmp --enable-libssh

Update: The default projects now include libcdio, libbluray, opengl, opencl and sdl enabled. More will be enabled as they are tested. All of these dependencies have working Visual Studio projects found in the SMP directories in each of their repos found at the parent ShiftMediaProject repository.

Your free to use this project directly as I keep it up to date and all the necessary dependency projects can also be found in my github.

git repository:
https://github.com/ShiftMediaProject/FFmpeg