Filter SDK/avs2yuv
(→Line by line breakdown) |
|||
Line 121: | Line 121: | ||
#include <stdio.h> | #include <stdio.h> | ||
− | The header stdio.h contains objects like [http://www.cplusplus.com/reference/cstdio/stderr/ stderr] ( | + | The header stdio.h contains objects like [http://www.cplusplus.com/reference/cstdio/stderr/ stderr] (a pointer to a FILE object) and functions like [http://www.cplusplus.com/reference/cstdio/fprintf/ fprintf] and [http://www.cplusplus.com/reference/cstdio/fopen/ fopen]. Those will be used later on. |
The standard error stream (''stderr'') is the default destination for error messages and other diagnostic warnings. Like stdout, it is usually also directed by default to the text console (generally, on the screen). | The standard error stream (''stderr'') is the default destination for error messages and other diagnostic warnings. Like stdout, it is usually also directed by default to the text console (generally, on the screen). | ||
Line 137: | Line 137: | ||
#define MY_VERSION "Avs2YUV 0.24" | #define MY_VERSION "Avs2YUV 0.24" | ||
− | Defines the version | + | Defines the version number which will be printed (using the "-h" option) later on. |
const AVS_Linkage *AVS_linkage = 0; | const AVS_Linkage *AVS_linkage = 0; | ||
− | + | ||
+ | This declares and initializes the server pointers static storage [[Filter_SDK/AVS_Linkage|AVS_Linkage]]. | ||
+ | |||
int __cdecl main(int argc, const char* argv[]) | int __cdecl main(int argc, const char* argv[]) | ||
+ | |||
+ | argv and argc are how command line arguments are passed to main() in C and C++ (you can name them the way you want to). argc will be the number of strings pointed to by the array argv. This will be one plus the number of arguments, with the first one being the name of the application. Thus when using the command line "avs2yuv.exe in.avs out.raw" we have argv[0]="avs2yuv.exe", argv[1]="in.avs", argv[2]="out.raw" and argc=2. | ||
+ | |||
{ | { | ||
const char* infile = NULL; | const char* infile = NULL; | ||
const char* outfile = NULL; | const char* outfile = NULL; | ||
+ | |||
+ | initialize infile and outfile as null pointers by setting them to [http://www.cplusplus.com/reference/cstddef/NULL/ NULL]. We could have set them to 0 too since that's the same in C/C++. | ||
+ | |||
FILE* out_fh; | FILE* out_fh; | ||
+ | |||
+ | out_fh is declared as a pointer to a [http://www.cplusplus.com/reference/cstdio/FILE/ FILE] object. | ||
if (!strcmp(argv[1], "-h")) { | if (!strcmp(argv[1], "-h")) { | ||
Line 151: | Line 161: | ||
"Usage: avs2yuv.exe in.avs out.raw\n"); | "Usage: avs2yuv.exe in.avs out.raw\n"); | ||
return 2; | return 2; | ||
+ | |||
+ | When using the command line "avs2yuv.exe -h" it will print to the console how the application should be used. The [http://www.cplusplus.com/doc/tutorial/functions/ return] terminates the function main() (and thus the application). returning 0 means that your program executed without errors and returning a different int means it executed with errors. | ||
+ | |||
+ | "Avs2YUV 0.24" (followed by an enter) | ||
+ | "Usage: avs2yuv.exe in.avs out.raw" (followed by an enter) | ||
+ | |||
} else { | } else { | ||
infile = argv[1]; | infile = argv[1]; | ||
outfile = argv[2]; | outfile = argv[2]; | ||
} | } | ||
− | + | ||
+ | When the second argument (argv[1]) is not '-h' it will set infile to the name of the input file (being argv[1]) and outfile to the name of the output file (being argv[2]). | ||
+ | |||
try { | try { | ||
char* colorformat; | char* colorformat; | ||
IScriptEnvironment* (__stdcall *CreateEnv)(int); | IScriptEnvironment* (__stdcall *CreateEnv)(int); | ||
+ | |||
+ | x | ||
+ | |||
HMODULE avsdll = LoadLibrary("avisynth.dll"); | HMODULE avsdll = LoadLibrary("avisynth.dll"); | ||
+ | |||
+ | [http://msdn.microsoft.com/en-us/library/windows/desktop/ms684175%28v=vs.85%29.aspx LoadLibrary] loads the specified module (which is avisynth.dll here) into the address space of the process (the process being avs2yuv.exe here). When successful avsdll will be the handle to the module, else it will be NULL. | ||
+ | |||
if (!avsdll) { | if (!avsdll) { | ||
fprintf(stderr, "failed to load avisynth.dll\n"); | fprintf(stderr, "failed to load avisynth.dll\n"); | ||
Line 165: | Line 189: | ||
} | } | ||
− | CreateEnv = (IScriptEnvironment *(__stdcall *)(int))GetProcAddress(avsdll, "CreateScriptEnvironment"); | + | CreateEnv = (IScriptEnvironment *(__stdcall *)(int))GetProcAddress(avsdll, "CreateScriptEnvironment"); |
+ | |||
+ | When avsdll is NULL (thus 0), !avsdll evaluates to one, and the error "failed to load avisynth.dll" is printed to the console. | ||
+ | |||
if (!CreateEnv) { | if (!CreateEnv) { | ||
fprintf(stderr, "failed to load CreateScriptEnvironment()\n"); | fprintf(stderr, "failed to load CreateScriptEnvironment()\n"); |
Revision as of 17:23, 3 January 2014
avs2yuv reads a script and outputs raw video (YUV or RGB). It's a stripped down version of the famous avs2yuv.
Here's avs2yuv.cpp:
#include <stdio.h> #include <Windows.h> #include "avisynth.h" #define MY_VERSION "Avs2YUV 0.24" const AVS_Linkage *AVS_linkage = 0; int __cdecl main(int argc, const char* argv[]) { const char* infile = NULL; const char* outfile = NULL; FILE* out_fh; if (!strcmp(argv[1], "-h")) { fprintf(stderr, MY_VERSION "\n" "Usage: avs2yuv.exe in.avs out.raw\n"); return 2; } else { infile = argv[1]; outfile = argv[2]; } try { char* colorformat; IScriptEnvironment* (__stdcall *CreateEnv)(int); HMODULE avsdll = LoadLibrary("avisynth.dll"); if (!avsdll) { fprintf(stderr, "failed to load avisynth.dll\n"); return 2; } CreateEnv = (IScriptEnvironment *(__stdcall *)(int))GetProcAddress(avsdll, "CreateScriptEnvironment"); if (!CreateEnv) { fprintf(stderr, "failed to load CreateScriptEnvironment()\n"); return 1; } IScriptEnvironment* env = CreateEnv(AVISYNTH_INTERFACE_VERSION); env->CheckVersion(5); AVS_linkage = env->GetAVSLinkage(); AVSValue arg(infile); AVSValue res = env->Invoke("Import", AVSValue(&arg, 1)); if (!res.IsClip()) { fprintf(stderr, "Error: '%s' didn't return a video clip.\n", infile); return 1; } PClip clip = res.AsClip(); VideoInfo vi = clip->GetVideoInfo(); fprintf(stderr, " %s:\n", infile); fprintf(stderr, " %dx%d,\n", vi.width, vi.height); fprintf(stderr, " %d/%d fps,\n", vi.fps_numerator, vi.fps_denominator); fprintf(stderr, " %d frames,\n", vi.num_frames); if (vi.IsYUV()) { colorformat = "YUV"; } else { colorformat = "RGB"; } fprintf(stderr, " %s color format", colorformat); out_fh = fopen(outfile, "wb"); if (!out_fh) { fprintf(stderr, "fopen(\"%s\") failed", outfile); return 1; } for (int frm = 0; frm < vi.num_frames; ++frm) { PVideoFrame f = clip->GetFrame(frm, env); static const int planes[] = {PLANAR_Y, PLANAR_U, PLANAR_V}; int wrote = 0; for (int p=0; p<3; p++) { // for interleaved formats only the first plane (being the whole frame) is written int w = vi.width >> vi.GetPlaneWidthSubsampling(planes[p]); int h = vi.height >> vi.GetPlaneHeightSubsampling(planes[p]); int pitch = f->GetPitch(planes[p]); const BYTE* data = f->GetReadPtr(planes[p]); for (int y=0; y<h; y++) { wrote += fwrite(data, 1, w, out_fh); data += pitch; } } } env->DeleteScriptEnvironment(); FreeLibrary(avsdll); } catch(AvisynthError err) { fprintf(stderr, "\nAvisynth error:\n%s\n", err.msg); return 1; } AVS_linkage = 0; fclose(out_fh); return 0; }
Compile this file into an EXE named avs2yuv.exe. See compiling instructions. Now open the command line and go to the folder where avs2yuv.exe and your script (called example.avs here) are located. Our script:
ColorBars() ConvertToYV12() Trim(0,4) Showframenumber()
Type the following on the command line (the name of the output clip can be arbitrary in our application):
avs2yuv.exe example.avs output.raw
So the output file will contain five frames of YV12 data (640x480). The raw stream can be played with YUVtoolkit for example. You can also import it in AviSynth using the plugin RawSource.
Line by line breakdown
Here's a line-by-line breakdown of avs2yuv.cpp.
#include <stdio.h>
The header stdio.h contains objects like stderr (a pointer to a FILE object) and functions like fprintf and fopen. Those will be used later on.
The standard error stream (stderr) is the default destination for error messages and other diagnostic warnings. Like stdout, it is usually also directed by default to the text console (generally, on the screen).
fprintf writes formatted data to stream.
fopen opens the file whose name is specified in the parameter filename and associates it with a stream that can be identified in future operations by the FILE pointer returned.
#include <Windows.h>
#include "avisynth.h"
This header declares all the classes and miscellaneous constants that you might need when accessing avisynth.dll.
#define MY_VERSION "Avs2YUV 0.24"
Defines the version number which will be printed (using the "-h" option) later on.
const AVS_Linkage *AVS_linkage = 0;
This declares and initializes the server pointers static storage AVS_Linkage.
int __cdecl main(int argc, const char* argv[])
argv and argc are how command line arguments are passed to main() in C and C++ (you can name them the way you want to). argc will be the number of strings pointed to by the array argv. This will be one plus the number of arguments, with the first one being the name of the application. Thus when using the command line "avs2yuv.exe in.avs out.raw" we have argv[0]="avs2yuv.exe", argv[1]="in.avs", argv[2]="out.raw" and argc=2.
{ const char* infile = NULL; const char* outfile = NULL;
initialize infile and outfile as null pointers by setting them to NULL. We could have set them to 0 too since that's the same in C/C++.
FILE* out_fh;
out_fh is declared as a pointer to a FILE object.
if (!strcmp(argv[1], "-h")) { fprintf(stderr, MY_VERSION "\n" "Usage: avs2yuv.exe in.avs out.raw\n"); return 2;
When using the command line "avs2yuv.exe -h" it will print to the console how the application should be used. The return terminates the function main() (and thus the application). returning 0 means that your program executed without errors and returning a different int means it executed with errors.
"Avs2YUV 0.24" (followed by an enter) "Usage: avs2yuv.exe in.avs out.raw" (followed by an enter)
} else { infile = argv[1]; outfile = argv[2]; }
When the second argument (argv[1]) is not '-h' it will set infile to the name of the input file (being argv[1]) and outfile to the name of the output file (being argv[2]).
try { char* colorformat; IScriptEnvironment* (__stdcall *CreateEnv)(int);
x
HMODULE avsdll = LoadLibrary("avisynth.dll");
LoadLibrary loads the specified module (which is avisynth.dll here) into the address space of the process (the process being avs2yuv.exe here). When successful avsdll will be the handle to the module, else it will be NULL.
if (!avsdll) { fprintf(stderr, "failed to load avisynth.dll\n"); return 2; } CreateEnv = (IScriptEnvironment *(__stdcall *)(int))GetProcAddress(avsdll, "CreateScriptEnvironment");
When avsdll is NULL (thus 0), !avsdll evaluates to one, and the error "failed to load avisynth.dll" is printed to the console.
if (!CreateEnv) { fprintf(stderr, "failed to load CreateScriptEnvironment()\n"); return 1; } IScriptEnvironment* env = CreateEnv(AVISYNTH_INTERFACE_VERSION); env->CheckVersion(5); AVS_linkage = env->GetAVSLinkage(); AVSValue arg(infile); AVSValue res = env->Invoke("Import", AVSValue(&arg, 1)); if (!res.IsClip()) { fprintf(stderr, "Error: '%s' didn't return a video clip.\n", infile); return 1; } PClip clip = res.AsClip(); VideoInfo vi = clip->GetVideoInfo(); fprintf(stderr, " %s:\n", infile); fprintf(stderr, " %dx%d,\n", vi.width, vi.height); fprintf(stderr, " %d/%d fps,\n", vi.fps_numerator, vi.fps_denominator); fprintf(stderr, " %d frames,\n", vi.num_frames); if (vi.IsYUV()) { colorformat = "YUV"; } else { colorformat = "RGB"; } fprintf(stderr, " %s color format", colorformat); out_fh = fopen(outfile, "wb"); if (!out_fh) { fprintf(stderr, "fopen(\"%s\") failed", outfile); return 1; } for (int frm = 0; frm < vi.num_frames; ++frm) { PVideoFrame f = clip->GetFrame(frm, env); static const int planes[] = {PLANAR_Y, PLANAR_U, PLANAR_V}; int wrote = 0; for (int p=0; p<3; p++) { // for interleaved formats only the first plane (being the whole frame) is written int w = vi.width >> vi.GetPlaneWidthSubsampling(planes[p]); int h = vi.height >> vi.GetPlaneHeightSubsampling(planes[p]); int pitch = f->GetPitch(planes[p]); const BYTE* data = f->GetReadPtr(planes[p]); for (int y=0; y<h; y++) { wrote += fwrite(data, 1, w, out_fh); data += pitch; } } } env->DeleteScriptEnvironment(); FreeLibrary(avsdll); } catch(AvisynthError err) { fprintf(stderr, "\nAvisynth error:\n%s\n", err.msg); return 1; } AVS_linkage = 0; fclose(out_fh); return 0; }
todo - static and dynamic linking (see above) - http://msdn.microsoft.com/en-us/library/windows/desktop/ms685090%28v=vs.85%29.aspx