Log in

View Full Version : Avisynth+


Pages : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 [88] 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112

LigH
23rd December 2018, 12:36
IIRC, avs2pipemod has a switch to deliver the audio part instead of the video part of the AviSynth output, to feed audio encoders (e.g. QAAC) instead of video encoders.

Even several:

>avs2pipemod64.exe
avs2pipemod ver 1.1.1
built on Aug 15 2016 00:32:12

Usage: avs2pipemod [option] input.avs
e.g. avs2pipemod -wav=24bit input.avs > output.wav
avs2pipemod -y4mt=10:11 input.avs | x264 - --demuxer y4m -o tff.mkv
avs2pipemod -rawvideo -trim=1000,0 input.avs > output.yuv

-wav[=8bit|16bit|24bit|32bit|float default unset]
output wav format audio(WAVEFORMATEX) to stdout.
if optional arg is set, audio sample type of input will be converted
to specified value.

-extwav[=8bit|16bit|24bit|32bit|float default unset]
output wav extensible format audio(WAVEFORMATEXTENSIBLE) containing
channel-mask to stdout.
if optional arg is set, audio sample type of input will be converted
to specified value.

-rawaudio[=8bit|16bit|24bit|32bit|float default unset]
output raw pcm audio(without any header) to stdout.
if optional arg is set, audio sample type of input will be converted
to specified value.
...

tebasuna51
23rd December 2018, 13:49
@Dogway
If you need some avs edits/filtering than can't be done with BatchEncoder or similar, and use avs+ 64 bits you can use avs2pipemod64 (like LigH say).

Also MeGUI (if you want a GUI instead command line) and ffmpeg (recommended to encode to AC3 directly) 64 bits can accept .avs inputs.

Dogway
23rd December 2018, 14:21
Yes, I was already investigating that. I was getting CoreAudioToolBox errors for qaac so I had to do that crazy setup (https://forum.doom9.org/showthread.php?p=1831213#post1831213) with the makeportable.cmd, now it complains about invalid input format so it must be a problem with my avs2pipemod64 line.
avs2pipemod[info]: writing 48915.400 seconds of 44100 Hz, 2 channel audio.
ERROR: Not available input file format

"%PIPER%" -rawaudio "%INPUT%"| "%ENCODER%" --tvbr %QUALITY% --ignorelength --no-optimize - -o "%OUTPUT%"


edit: worked if I added --raw and removed --ignorelength
"%PIPER%" -rawaudio "%INPUT%"| "%ENCODER%" --raw --tvbr %QUALITY% --no-optimize - -o "%OUTPUT%"

wonkey_monkey
23rd December 2018, 18:24
converttoy8 is broken when converting from bit depths other than 8:

version.convertbits(16).converttoy8
version.converttoyv12.convertbits(12).converttoy8


https://i.imgur.com/nZrFmoH.png

pinterf
23rd December 2018, 19:20
Thanks. Seems that it's not guarded by an error message to allow only 8 bit sources. Based on the upside down result, it simply runs on the 8 bit packed rgb case.

wonkey_monkey
23rd December 2018, 23:14
Me again...

colorbars returns a clip with alpha set to 255 with pixel_type="RGBAP8", but with pixel_type="RGB32", alpha is set to 0.

tebasuna51
24th December 2018, 00:57
@Dogway

Try:

"%PIPER%" -extwav=24bit "%INPUT%"| "%ENCODER%" --tvbr %QUALITY% --ignorelength --no-optimize -o "%OUTPUT%" -

All encoders need wav header to know samplerate, bit depth, number of channels and mask

nu774
24th December 2018, 11:58
qaac supports avisynth directly, so you don't have to pipe from avs2pipemod (use qaac64.exe for 64bit Avisynth+).

LigH
25th December 2018, 11:27
It was just an example of an encoder that always worked, even before it supported AviSynth natively.

tebasuna51
25th December 2018, 12:05
qaac supports avisynth directly...

Yep, seems it work ok.

But I can see nothing in qaac docs. Only a reference to Apple AudioFile services (https://github.com/nu774/qaac/wiki/About-input-format)

wonkey_monkey
29th December 2018, 23:53
Is there any in-depth documentation for env->AddFunction anywhere? I seem to remember there are some rules on using + to allow a variable-sized list of parameters but I can't remember what they are, and no matter what I try I either get an "Invalid parameters" error or my extra parameter gets assigned to the first unspecified named parameter.

StainlessS
30th December 2018, 00:25
Post what you are trying.
I had one helluva time trying to get Prune() to work (got coerced into retrying and it eventually all worked ok, still no idea what it was I was doing wrong, starting again from scratch and everything worked perfectly).

Pretty much everything known is below [NOTE, we used i*, ie zero or more ints, if using i+ then requires at least 1 arg in array else error]

// The following function is the function that actually registers the filter in AviSynth
// It is called automatically, when the plugin is loaded to see which functions this filter contains.
extern "C" __declspec(dllexport) const char* __stdcall AvisynthPluginInit2(IScriptEnvironment* env) {
env->AddFunction("FrameSel", "ci*[SCmd]s[Cmd]s[Show]b[Ver]b[Reject]b[Ordered]b[Debug]b[Extract]i", Create_FrameSel, 0);

// The AddFunction has the following paramters:
// AddFunction(Filtername , Arguments, Function to call,0);

// Arguments is a string that defines the types and optional nicknames of the arguments for you filter.
// c - Video Clip
// i - Integer number
// f - Float number
// s - String
// b - boolean
// . - Any type (dot)
// Array Specifiers
// i* - Integer Array, zero or more
// i+ - Integer Array, one or more
// .* - Any type Array, zero or more
// .+ - Any type Array, one or more
// Etc

return "`FrameSel' FrameSel plugin";
// A freeform name of the plugin.
}


Some stuff ripped from various FRAMESEL routines

// from creator function
AVSValue Frames = args[1]; // Frames, Array of frame numbers as filter arguments


// from Frames, CMD, SCMd parser
bool ProcFrames = (Frames.ArraySize()!=0);

if(ProcFrames) {
int nFrms = Frames.ArraySize();
if(Pass==0) {
OutFrameCount += nFrms;
} else {
int i;
for(i=0;i<nFrms; ++i) {
int frm=Frames[i].AsInt();
if(frm < 0 || frm >= NumFrames) {
if(fp) {fclose(fp); fp=NULL;}
if(FrameDat) {delete[] FrameDat; FrameDat = NULL;}
env->ThrowError("%s*ERROR* filter arg frames[%d]=%d, out of clip.\n",myName,i+1,frm);
}
if(RunOff < OutFrameCount) {
FrameDat[RunOff]=frm;
}
++RunOff;
}
}
} // End, ProcFrames



EDIT:
I seem to remember there are some rules on using +
Yep, you need use eg i* rather than i+, probably.
EDIT: Further args immediately following eg 'i*' must NOT be of type int (will be swallowed by the i* Array, I think,
unless using named arg, eg nextInt=NextInt where "i*[nextint]i").
If using ".*[nextint]i" (zero or more variables of any type), then MUST (I think) use named arg ie nextInt=NextInt.
I have to use eg Append=True/False in eg RT_WriteFile as all args before the Optional Append Arg are of variable type and number.

EDIT:

env->AddFunction("RT_WriteFile", "ss.*[Append]b",RT_WriteFile, 0);



AVSValue __cdecl RT_WriteFile(AVSValue args, void* user_data, IScriptEnvironment* env) {
char *myName="RT_WriteFile: ";
const char *ofn = args[0].AsString();
const char *fmt = args[1].AsString();
AVSValue datn = args[2]; // data
const bool append = args[3].AsBool(false);

int arrsz = datn.ArraySize();

enum {
CHICKEN=64
};

// what size buffer we need ?
int i,mem=int(strlen(fmt) + 1 + CHICKEN);
for(i=0;i<arrsz;++i) {
if(datn[i].IsString()) {
const char *st=datn[i].AsString();
mem += int(strlen(st) + 1 + CHICKEN);
} else {
mem += 8 + CHICKEN; // no particular reason why so big, just chicken factor.
}
}

char *pbuf = new char[(mem+1)*2];
if(pbuf==NULL)
env->ThrowError("%sCannot allocate memory",myName);

char *ptem=pbuf+(mem+1); // temp buffer

const unsigned char* r= (const unsigned char*)fmt;
char *p=pbuf;
int c,ix=0;
int t=0;

// Parse text and insert variables
while(c=*r) {
if(c=='%') {
++r;
if(*r=='\0') {
*p++ ='%';
} else if(*r=='%') {
*p++=*r++; // replace escaped double % with single
} else {
if(ix>=arrsz) {
delete [] pbuf;
env->ThrowError("%sExpecting data arg (%d)",myName,ix+1);
}
char *tp=ptem;
*tp++='%';
if(*r=='-' || *r=='+' || *r=='0' || *r==' ' || *r=='#') // flags
*tp++=*r++;
if(*r=='*') { // int holds length
t=datn[ix].IsBool() ?1: \
datn[ix].IsString() ?2: \
datn[ix].IsInt() ?3: \
datn[ix].IsFloat() ?4: \
0;
if(t!=3) {
delete [] pbuf;
env->ThrowError("%sUnsupported data type, Expecting Width as Int (%d)",myName,ix+1);
}
tp+=sprintf(tp,"%d",datn[ix].AsInt());
++r; // skip '*'
++ix; // next data
} else {
while(*r>='0' && *r<='9') {
*tp++ = *r++;
}
}
if(*r=='.') {
*tp++ = *r++; // precision prefix
if(*r=='*') { // int holds length
t=datn[ix].IsBool() ?1: \
datn[ix].IsString() ?2: \
datn[ix].IsInt() ?3: \
datn[ix].IsFloat() ?4: \
0;
if(t!=3) {
delete [] pbuf;
env->ThrowError("%sUnsupported data type, Expecting Precision as Int (%d)",myName,ix+1);
}
tp+=sprintf(tp,"%d",datn[ix].AsInt());
++r; // skip '*'
++ix; // next data
} else {
while(*r>='0' && *r<='9') {
*tp++ = *r++;
}
}
}
t=datn[ix].IsBool() ?1: \
datn[ix].IsString() ?2: \
datn[ix].IsInt() ?3: \
datn[ix].IsFloat() ?4: \
0;
// type
if( (*r=='c' ) || (*r=='C' ) || // char as int
(*r=='d' || *r=='i') || // int
(*r=='o' || *r=='u' || *r=='x' || *r=='X')) { // unsigned int
if(t!=3) {
int tmpc=*r;
delete [] pbuf;
env->ThrowError("%sType='%c', Expecting Int data (%d)",myName,tmpc,ix+1);
}
*tp++=*r++;
*tp='\0';
p+=sprintf(p,ptem,datn[ix].AsInt());
++ix; // next data
} else if(*r=='e' || *r=='E' || *r=='f' || *r=='g' || *r=='G') { // double
if(t!=4&&t!=3) {
int tmpc=*r;
delete [] pbuf;
env->ThrowError("%sType='%c', Expecting Float (%d)",myName,tmpc,ix+1);
}
*tp++=*r++;
*tp='\0';
p+=sprintf(p,ptem,datn[ix].AsFloat());
++ix; // next data
} else if((*r=='s')||(*r=='S')) { // string
if(t!=2&&t!=1) {
delete [] pbuf;
env->ThrowError("%sType='s', Expecting String (%d)",myName,ix+1);
}
*tp++=*r++;
*tp='\0';
if(t==1) { // Bool
p+=sprintf(p,ptem,datn[ix].AsBool()?"True":"False");
} else { // String
p+=sprintf(p,ptem,datn[ix].AsString());
}
++ix; // next data
} else {
int tmpc=*r;
delete [] pbuf;
env->ThrowError("%sUnknown format type '%c' (%d)",myName,tmpc,ix+1);
}
}
} else if(c == '\\') {
++r;
c=*r;
// abfnrtv
switch (c) {
case '\0' : *p++='\\'; break; // copy single backslash at end of string
case '\\' : *p++=*r++; break; // replace double backslash with single backslash
case 'n' : ++r; *p++='\n'; break;
case 'r' : ++r; *p++='\r'; break;
case 't' : ++r; *p++='\t'; break;
case 'v' : ++r; *p++='\v'; break;
case 'f' : ++r; *p++='\f'; break;
case 'b' : ++r; *p++='\b'; break;
case 'a' : ++r; *p++='\a'; break;
default : *p++='\\'; *p++=*r++; break; // anything else we copy backslash and whatever follows
}
} else {
*p++=*r++;
}
}
*p=0; // nul term

if(ix<arrsz) {
delete [] pbuf;
env->ThrowError("%sUnexpected data arg (%d)",myName,ix+1);
}

char *omode=(append)?"a+t":"wt";
FILE * fp;
// we use write in text mode, let C insert '\r'.
if((fp=fopen(ofn, omode ))==NULL) { // Cannot output file
delete [] pbuf;
return -1;
}
int lines = 0;
char *s,*is;
s=is=pbuf;;
do {
c=*s;
if(c=='\n' || c=='\r' || c == '\0') {
if(is<s) {
if(fwrite(is,s-is,1,fp)!=1) {
delete [] pbuf;
fclose(fp);
return -1; // write file error
}
}
if(c=='\n') {
++s;
if(*s=='\r')
++s;
} else if(c=='\r') {
++s;
if(*s=='\n')
++s;
}
if(is<s) {
if (fputc('\n',fp)==EOF) {
delete [] pbuf;
fclose(fp);
return -1; // write file error
}
++lines;
}
is=s;
} else {
++s;
}
} while (*is); // !!! Exit when 1st char in string is end
delete [] pbuf;
fclose(fp);
return lines;
}

wonkey_monkey
30th December 2018, 22:44
I think I figured it out. f* has to go before any named parameters, otherwise if you try to include the array after the use of a named parameter, it tries to assign those numbers to other, unused named parameters. Or something like that.

gaak
31st December 2018, 13:13
I'm looking for a 64 bit version of tritical's TBilateral. Is there a thread for this? Or to make a request for one?

wonkey_monkey
31st December 2018, 13:28
The source code for TBilateral includes inline assembly which isn't supported for x64 (in Visual Studio, anyway), so you might be out of luck unless someone wants to rewrite it.

StainlessS
31st December 2018, 13:28
I think I figured it out. f* has to go before any named parameters, otherwise if you try to include the array after the use of a named parameter, it tries to assign those numbers to other, unused named parameters. Or something like that.

Just as with avs script Functions, optional named args follow after compulsory un-named args[EDIT: un-named in plugin, obviously cannot have un-named args in script funcs], and once you have a single optional arg, then all following ones must also be optional. (otherwise weird things could happen in plugin, script function would complain about it, I think)

EDIT: David, me just got back from shop (Lidl) and trying out the Tio Nico sherry (for my damn cough), its quite lovely and unexpectedly flavoured with raisins and treacle, very dark flavour, never tasted a sherry like it I think. Less than six quid, and easily worth double that. [EDIT: In Waitrose, it is double that]

Groucho2004
1st January 2019, 02:37
I'm looking for a 64 bit version of tritical's TBilateral.Added to my plugin collection (https://forum.doom9.org/showthread.php?t=173259)

wonkey_monkey
2nd January 2019, 01:06
Just curious, but what is it about info() that seems to make it really slow? Showframenumber seems similarly slow, but subtitle isn't. Is that because subtitle renders the text once and only has to composite it onto each frame? Is text rendering really that slow?

Info's speed also seems to depend greatly on video size. Is it possibly missing some optimisations to do with compositing extent?

StainlessS
2nd January 2019, 02:20
what is it about info() that seems to make it really slow? Showframenumber seems similarly slow, but subtitle isn't. Is that because subtitle renders the text once and only has to composite it onto each frame? Is text rendering really that slow?

Info's speed also seems to depend greatly on video size. Is it possibly missing some optimisations to do with compositing extent?

Subtitle fixed text, requires prepping one time only (prior to frame serving, ie in constructor), ShowFrameNumber() or Info() (frame number and time) require prepping at each GetFrame [EDIT: Calling Subtitle Constructor in each and every frame, with big overhead].
Prepp'ing, calls some system function (probably via ApplyMessage) to find size of Subtitle for font etc, (together with eg kerning of each character), and that part is slow. Also, depending upon size of subtitle string, and size of clip, so subtitle may also have to be resized to fit clip (for eg alert error box).

For any kind of plugin metrics output, Subtitle is a slow option and best avoided, see Info.h, or perhaps even DDigit, although neither of them will work in non 8 bit colorspaces.

EDIT: Current Info.h was refactored by IanB most recently about May 2013, (may require a couple of simple warnings fixes for x64 compile).
Info.h available in ClipClop source[with any required x64 warning fixed], if you cannot find it elsewhere. [pre IanB refactored versions have several bugs]

EDIT: More bout it here:- https://forum.doom9.org/showthread.php?t=175443

Info.h and DDigit are lots faster than Subtitle [Fixed monospace font, 10x20 pixels, DDigit also uses Info.h font].
EDIT: IanB refactored Info.h is both font and code, DDigit uses Info.h font only[renamed], the code part being removed.

wonkey_monkey
5th January 2019, 03:04
Another development question:

Is setting the following:

vi.audio_samples_per_second
vi.nchannels
vi.sample_type
vi.num_audio_samples

sufficient and complete for setting a clip's audio properties?

Groucho2004
5th January 2019, 03:15
Another development question:

Is setting the following:

vi.audio_samples_per_second
vi.nchannels
vi.sample_type
vi.num_audio_samples

sufficient and complete for setting a clip's audio properties?Yes. I also use these in AVSMeter.

wonkey_monkey
5th January 2019, 03:17
Thanks Groucho.

tebasuna51
5th January 2019, 03:29
Better than nchannels is maskchannels to define a audio clip.

StainlessS
5th January 2019, 04:21
From Avisynth.h [version 6]

int audio_samples_per_second; // 0 means no audio
int sample_type; // as of 2.5
__int64 num_audio_samples; // changed as of 2.5
int nchannels; // as of 2.5


For some things, is handy to have access to v2.58 avs header (AVISYNTH HEADER = 3) for the BAKED CODE rather than from function call.
(The v2.60 FINAL Compressed Help [*.chm] file available from my MediaFire Account DATA Folder, has both Avisynth v2.60 final and v2.58 baked code
headers available from the HTML table of files).
https://i.postimg.cc/k2mHvBWt/chm.png (https://postimg.cc/k2mHvBWt)

EDIT: From BAKED CODE in V2.58 header (Source Not available in Version 6 header)

// useful functions of the above
bool HasVideo() const { return (width!=0); }
bool HasAudio() const { return (audio_samples_per_second!=0); }



EDIT:
Internal functions, Global Options:- http://avisynth.nl/index.php/Internal_functions#Global_Options
OPT_dwChannelMask

global OPT_dwChannelMask(int v) v2.60
This option enables you to set ChannelMask. It overrides WAVEFORMATEXTENSIBLE.dwChannelMask[[2] which is set according to this table

0x00004, // 1 -- -- Cf
0x00003, // 2 Lf Rf
0x00007, // 3 Lf Rf Cf
0x00033, // 4 Lf Rf -- -- Lr Rr
0x00037, // 5 Lf Rf Cf -- Lr Rr
0x0003F, // 5.1 Lf Rf Cf Sw Lr Rr
0x0013F, // 6.1 Lf Rf Cf Sw Lr Rr -- -- Cr
0x0063F, // 7.1 Lf Rf Cf Sw Lr Rr -- -- -- Ls Rs

tebasuna51
5th January 2019, 10:59
global OPT_dwChannelMask(int v) v2.60

Is a usseless option.

Who know the ChannelMask of a audio are the decoders, do you know any decoder (ffms2.dll, LSMASHSource.dll, NicAudio.dll, ...) than set ChannelMask to the appropiate value?

There are any audio encoder/player, than accept avs input, than use that global variable if defined?

Also, if there are two, or more, audios processed at same time, how we can distinguise both?

The ChannelMask must be a property of each audio clip.

StainlessS
5th January 2019, 11:30
OPT_AllowFloatAudio
OPT_UseWaveExtensible
OPT_dwChannelMask

Are optionally set to signal info to eg MPC-HC and VDub2. [Not sure if VD2 supports FloatAudio, old VDub did not, but MPC-HC does]

Is a usseless option.

Makes one wonder why they were implemented then.

Also, if there are two, or more, audios processed at same time, how we can distinguise both?
Dont think AVI (and therefore AVS) generally support more than 1 audio stream, so the problem does not often arise.
[VDub does have some code connected to multiple audio streams, but I aint ever seen more than 1 used, also dont know if fully implemented in VDub].

Groucho2004
5th January 2019, 13:12
Another development question:

Is setting the following:

vi.audio_samples_per_second
vi.nchannels
vi.sample_type
vi.num_audio_samples

sufficient and complete for setting a clip's audio properties?
I just noticed that you wrote "setting a clip's audio properties" (as opposed to getting). The answer is still yes. "KillAudio()" for example sets all 4 to 0, effectively removing the audio from a clip.

FranceBB
5th January 2019, 13:34
Don't think AVI (and therefore AVS) generally support more than 1 audio stream, so the problem does not often arise.

Yep, you're right, Avisynth always outputs a single audio stream of x channels, which is why whenever I have two languages (like CH.1-2 Stereo Full Mix German - CH.3-4 Stereo Full Mix English) I index them both, then use MergeChannels to make a single audio stream with 4 channels and then I specify how to divide them and encode them separately to the encoder.

wonkey_monkey
5th January 2019, 13:54
Before I go ahead and do this, can anyone raise any objections to the idea of using an audio channel to pass metadata? My filter passes data through the video frame, but it also needs to send a few bytes of metadata with it, so my plan is to override GetAudio and just paste those bytes into the buffer. The other filter in the partnership will then call GetAudio to get the metadata.

Good idea? Bad idea?

DJATOM
5th January 2019, 14:20
Indeed it's a bad practice. In Vapoursynth we can pass external metadata with frame properties, but avisynth lacks that functionality. As workaround you probably can add external metadata as hints, like it was implemented in the TIVTC filters.

wonkey_monkey
5th January 2019, 14:50
In what sense is it bad practice? I mean, I'm already "abusing" the video frame by passing non-video data (although it is pixel-to-pixel related, more or less). I don't think that there being a more formal alternative which Avisynth+ doesn't have is really an objection, per se.

What are hints, and how are they implemented?

pinterf
5th January 2019, 14:52
Nekopanda fork (Avisynth Neo a.k.a Avs CUDA) implemented frame properties.

StainlessS
6th January 2019, 00:19
What are hints, and how are they implemented?

Dont know much about this (I'm sure someone will correct if wrong), but think that the hints are 64 bits encoded in LSB (Least Significant Bit) of the top LHS row of 64 pixels. [what they represent, I dont know, I guess is implementation defined (maybe in luma channel only, dont know)].

EDIT: Methinks that DGIndex embeds some hint stuff, maybe see source. (also TFM I think).

EDIT: Here from DGindex source (looks like only storing 32 bits of colorimetry data there [with additional 32 bits of magic number to signify valid hint]).

Utilities.h

bool PutHintingData(unsigned char *video, unsigned int hint);
bool GetHintingData(unsigned char *video, unsigned int *hint);

#define HINT_INVALID 0x80000000
#define PROGRESSIVE 0x00000001
#define IN_PATTERN 0x00000002
#define COLORIMETRY 0x0000001C
#define COLORIMETRY_SHIFT 2


Utilities.cpp


#include <windows.h>

#define MAGIC_NUMBER (0xdeadbeef)

bool PutHintingData(unsigned char *video, unsigned int hint)
{
unsigned char *p;
unsigned int i, magic_number = MAGIC_NUMBER;
bool error = false;

p = video;
for (i = 0; i < 32; i++)
{
*p &= ~1;
*p++ |= ((magic_number & (1 << i)) >> i); // 1st 32 bits of Magic number validity flag
}
for (i = 0; i < 32; i++)
{
*p &= ~1;
*p++ |= ((hint & (1 << i)) >> i); // 2nd 32 bits of colorimetry data
}
return error;
}

bool GetHintingData(unsigned char *video, unsigned int *hint)
{
unsigned char *p;
unsigned int i, magic_number = 0;
bool error = false;

p = video;
for (i = 0; i < 32; i++)
{
magic_number |= ((*p++ & 1) << i);
}
if (magic_number != MAGIC_NUMBER)
{
error = true;
}
else
{
*hint = 0;
for (i = 0; i < 32; i++)
{
*hint |= ((*p++ & 1) << i);
}
}
return error;
}


AvisynthAPI.cpp

PVideoFrame __stdcall MPEG2Source::GetFrame(int n, IScriptEnvironment* env)
{
int gop, pct;
char Matrix_s[40];
unsigned int raw;
unsigned int hint;

...

else if (m_decoder.info == 3)
{
hint = 0;
if (m_decoder.FrameList[raw].pf == 1) hint |= PROGRESSIVE;
hint |= ((m_decoder.GOPList[gop]->matrix & 7) << COLORIMETRY_SHIFT);
PutHintingData(frame->GetWritePtr(PLANAR_Y), hint);
}
}


EDIT: The hint encoder/decoder would be in the duplicated DGDecode.dll source.
EDIT: GetHintingData() seems not to be used in DGIndex source code, (probably some duplication in DGDecode::Mpeg2Source).

wonkey_monkey
6th January 2019, 03:07
Ah, then not an option in this case as changing any bits would break it. I could add another row, but that seems wrong somehow, since the video (more or less) represents pixel data. I went with the GetAudio route and it works well.

TheFluff
7th January 2019, 17:26
Is a usseless option.

Who know the ChannelMask of a audio are the decoders, do you know any decoder (ffms2.dll, LSMASHSource.dll, NicAudio.dll, ...) than set ChannelMask to the appropiate value?

There are any audio encoder/player, than accept avs input, than use that global variable if defined?

Also, if there are two, or more, audios processed at same time, how we can distinguise both?

The ChannelMask must be a property of each audio clip.
FFMS sets the script variable FFCHANNEL_LAYOUT which contains the dwChannelMask. You can get one variable per clip using the varprefix option if you like.

Before I go ahead and do this, can anyone raise any objections to the idea of using an audio channel to pass metadata? My filter passes data through the video frame, but it also needs to send a few bytes of metadata with it, so my plan is to override GetAudio and just paste those bytes into the buffer. The other filter in the partnership will then call GetAudio to get the metadata.

Good idea? Bad idea?

num_audio_samples is a 64-bit integer. It's like it was made to use as an arbitrary pointer! Distinguishing a valid pointer from any other arbitrary integer is left as an exercise for the reader.

Seriously though, putting arbitrary data in the audio stream is dumb but about par for the course by Avisynth plugin coding standards. I'm pretty sure it's been done before by other plugins. You could serialize the data and put it in a script variable, but it's not really worth the effort.

Stereodude
7th January 2019, 17:51
This script crashes for me using AVSynth+ when loading it in VD2 x64 once LEN is somewhere between 15900-16000. It will crash loading it in AVSmeter (x64) as well when LEN is a slightly lower frame number. I think there's some sort of internal overflow. I was using r2700, but I've since upgraded to r2772. Both do the same thing. There's no popup or error message. VD2x64 just disappears. AVSmeter (x64) just kicks back to the command prompt after getting to the "prescanning script..." message very briefly.

Using the x86 version of AVIsynth+ allows LEN to be larger than the x64 version, but fails by 19000.
LEN2=103848
LEN=15900
A=BlankClip(Length=LEN2, height=786, width=1920, Pixel_type="YV12",COLOR=$FF0000).ShowFrameNumber
B=BlankClip(Length=LEN2, height=786, width=1920, Pixel_type="YV12",COLOR=$00FF00).ShowFrameNumber

Z = A.BlankClip(Length=0)
frame=0

while( frame < LEN) {
for(n=2, 958, 2) {
Z = Z ++ stackhorizontal(stackhorizontal(A.crop(0,0,n,-0),B.crop(n,0,960,-0)),A.crop(960+n,0,-0,-0)).trim(frame,end=frame)
frame = frame + 1
if ( frame == LEN) { Return Z }
}

for(n=958, 2, -2) {
Z = Z ++ stackhorizontal(stackhorizontal(A.crop(0,0,n,-0),B.crop(n,0,960,-0)),A.crop(960+n,0,-0,-0)).trim(frame,end=frame)
frame = frame + 1
if ( frame == LEN) { Return Z }
}
}

Return Z
My computer is running Windows 10 Pro and has 32GB of RAM.

pinterf
7th January 2019, 19:56
This script crashes for me using AVSynth+ when loading it in VD2 x64 once LEN is somewhere between 15900-16000. It will crash loading it in AVSmeter (x64) as well when LEN is a slightly lower frame number. I think there's some sort of internal overflow. I was using r2700, but I've since upgraded to r2772. Both do the same thing. There's no popup or error message. VD2x64 just disappears. AVSmeter (x64) just kicks back to the command prompt after getting to the "prescanning script..." message very briefly.

Using the x86 version of AVIsynth+ allows LEN to be larger than the x64 version, but fails by 19000.
LEN2=103848
LEN=15900
A=BlankClip(Length=LEN2, height=786, width=1920, Pixel_type="YV12",COLOR=$FF0000).ShowFrameNumber
B=BlankClip(Length=LEN2, height=786, width=1920, Pixel_type="YV12",COLOR=$00FF00).ShowFrameNumber

Z = A.BlankClip(Length=0)
frame=0

while( frame < LEN) {
for(n=2, 958, 2) {
Z = Z ++ stackhorizontal(stackhorizontal(A.crop(0,0,n,-0),B.crop(n,0,960,-0)),A.crop(960+n,0,-0,-0)).trim(frame,end=frame)
frame = frame + 1
if ( frame == LEN) { Return Z }
}

for(n=958, 2, -2) {
Z = Z ++ stackhorizontal(stackhorizontal(A.crop(0,0,n,-0),B.crop(n,0,960,-0)),A.crop(960+n,0,-0,-0)).trim(frame,end=frame)
frame = frame + 1
if ( frame == LEN) { Return Z }
}
}

Return Z
My computer is running Windows 10 Pro and has 32GB of RAM.
Finally it fails in Splice::GetFrame.
0xC0000005: Access violation writing location 0x0000000001200000.
and
0xC00000FD: Stack overflow (parameters: 0x0000000000000001, 0x0000000001203FF0).

Loops in Avisynth are much like unrolled loops.

The filter chain of this huge while loop is looking like Splice calling previous Splice calling previous Splice calling...
Even the debugger is giving up showing the stack frame:
"Maximum number of stack frames supported by Visual Studio has been exceeded"

So I think the loops can help only when they are relatively short.

TheFluff
7th January 2019, 20:10
This script crashes for me using AVSynth+ when loading it in VD2 x64 once LEN is somewhere between 15900-16000. It will crash loading it in AVSmeter (x64) as well when LEN is a slightly lower frame number. I think there's some sort of internal overflow. I was using r2700, but I've since upgraded to r2772. Both do the same thing. There's no popup or error message. VD2x64 just disappears. AVSmeter (x64) just kicks back to the command prompt after getting to the "prescanning script..." message very briefly.

Using the x86 version of AVIsynth+ allows LEN to be larger than the x64 version, but fails by 19000.
LEN2=103848
LEN=15900
A=BlankClip(Length=LEN2, height=786, width=1920, Pixel_type="YV12",COLOR=$FF0000).ShowFrameNumber
B=BlankClip(Length=LEN2, height=786, width=1920, Pixel_type="YV12",COLOR=$00FF00).ShowFrameNumber

Z = A.BlankClip(Length=0)
frame=0

while( frame < LEN) {
for(n=2, 958, 2) {
Z = Z ++ stackhorizontal(stackhorizontal(A.crop(0,0,n,-0),B.crop(n,0,960,-0)),A.crop(960+n,0,-0,-0)).trim(frame,end=frame)
frame = frame + 1
if ( frame == LEN) { Return Z }
}

for(n=958, 2, -2) {
Z = Z ++ stackhorizontal(stackhorizontal(A.crop(0,0,n,-0),B.crop(n,0,960,-0)),A.crop(960+n,0,-0,-0)).trim(frame,end=frame)
frame = frame + 1
if ( frame == LEN) { Return Z }
}
}

Return Z
My computer is running Windows 10 Pro and has 32GB of RAM.

Don't try to write procedural code in a functional language.

Stereodude
7th January 2019, 21:02
Don't try to write procedural code in a functional language.
Well, I'm not sure how to do what I want written in a functional language using the AVIsynth functions and plugins that are available. I guess I will have to play around with using ConditionalReader to replace the inner two for loops so that there aren't 10's of thousands of splices.

wonkey_monkey
7th January 2019, 21:07
I'd recommend rgba_rpn (https://forum.doom9.org/showthread.php?t=172601) for this kind of thing, but the learning curve is somewhat precipitous and I've pretty much rewritten the entire thing since then so even I may not be of much help...

Actually masktools or even just Avisynth+'s expr might be better.

Stereodude
7th January 2019, 21:21
Actually masktools or even just Avisynth+'s expr might be better.
I took a brief look at masktools the other day at it and didn't seem like I could do this sort of effect using it without having a video that's the dynamic moving mask.

I'm not familiar with expr. I'll have to look into that.

wonkey_monkey
7th January 2019, 21:38
You could start with a half-white, half-black clip and use animate and pointresize to shift it left and right. I think it'll still be invoking a lot of filter instances though, so expr makes a bit more sense (although it's not as efficient as it could be in this case).

In fact, consider using expr to create a 1-pixel high sliding bar clip and then pointresize it up to full height.

Stereodude
7th January 2019, 23:34
In fact, consider using expr to create a 1-pixel high sliding bar clip and then pointresize it up to full height.
I'll admit I've never used expr and I haven't the foggiest idea how to create that 1-pixel high sliding bar clip with it.

My original idea of replacing the for loops didn't work. Well, I should clarify that... I was able to replace the two for loops with ScriptClip + ConditionalReader (the core piece), but it seems that the use of ScriptClip + ConditionalReader multiple times in a script with the same variable names doesn't work as expected so a loop of multiple instance fails. That would only have ~109 splices instead of 103848 (presumably not crashing).

For example:
LEN=103848
mini_length=956

Asrc=BlankClip(Length=LEN, height=786, width=1920, Pixel_type="YV12",COLOR=$FF0000).ShowFrameNumber
Bsrc=BlankClip(Length=LEN, height=786, width=1920, Pixel_type="YV12",COLOR=$00FF00).ShowFrameNumber

Loop_cnt=0
A=Asrc.trim(Loop_cnt*mini_length, ((Loop_cnt+1)*mini_length-1))
B=Bsrc.trim(Loop_cnt*mini_length, ((Loop_cnt+1)*mini_length-1))
ScriptClip(A, """
stackhorizontal(stackhorizontal(A.crop(0,0,n,-0),B.crop(n,0,960,-0)),A.crop(960+n,0,-0,-0))
""")
ConditionalReader("slide.txt", "n", false)
Y = last

Loop_cnt = Loop_cnt + 1
A=Asrc.trim(Loop_cnt*mini_length, ((Loop_cnt+1)*mini_length-1))
B=Bsrc.trim(Loop_cnt*mini_length, ((Loop_cnt+1)*mini_length-1))
ScriptClip(A, """
stackhorizontal(stackhorizontal(A.crop(0,0,n,-0),B.crop(n,0,960,-0)),A.crop(960+n,0,-0,-0))
""")
ConditionalReader("slide.txt", "n", false)
Z = last

return Y
#return Z
I don't understand why Y and Z are identical. If either of the two code blocks are commented out Y/Z are what is expected, or if the variable names in each block are unique (like A0, B0 in the first and A1, B1 in the second) Y & Z are what is expected. But with limitation I can't use a for or while loop to do this 109 times or even do a manual unroll with copy and paste without making every iteration unique.

slide.txt:
Type int

0 2
1 4
2 6
3 8
4 10
5 12
6 14
7 16
8 18
9 20
10 22
11 24
12 26
13 28
14 30
15 32
16 34
17 36
18 38
19 40
20 42
21 44
22 46
23 48
24 50
25 52
26 54
27 56
28 58
29 60
30 62
31 64
32 66
33 68
34 70
35 72
36 74
37 76
38 78
39 80
40 82
41 84
42 86
43 88
44 90
45 92
46 94
47 96
48 98
49 100
50 102
51 104
52 106
53 108
54 110
55 112
56 114
57 116
58 118
59 120
60 122
61 124
62 126
63 128
64 130
65 132
66 134
67 136
68 138
69 140
70 142
71 144
72 146
73 148
74 150
75 152
76 154
77 156
78 158
79 160
80 162
81 164
82 166
83 168
84 170
85 172
86 174
87 176
88 178
89 180
90 182
91 184
92 186
93 188
94 190
95 192
96 194
97 196
98 198
99 200
100 202
101 204
102 206
103 208
104 210
105 212
106 214
107 216
108 218
109 220
110 222
111 224
112 226
113 228
114 230
115 232
116 234
117 236
118 238
119 240
120 242
121 244
122 246
123 248
124 250
125 252
126 254
127 256
128 258
129 260
130 262
131 264
132 266
133 268
134 270
135 272
136 274
137 276
138 278
139 280
140 282
141 284
142 286
143 288
144 290
145 292
146 294
147 296
148 298
149 300
150 302
151 304
152 306
153 308
154 310
155 312
156 314
157 316
158 318
159 320
160 322
161 324
162 326
163 328
164 330
165 332
166 334
167 336
168 338
169 340
170 342
171 344
172 346
173 348
174 350
175 352
176 354
177 356
178 358
179 360
180 362
181 364
182 366
183 368
184 370
185 372
186 374
187 376
188 378
189 380
190 382
191 384
192 386
193 388
194 390
195 392
196 394
197 396
198 398
199 400
200 402
201 404
202 406
203 408
204 410
205 412
206 414
207 416
208 418
209 420
210 422
211 424
212 426
213 428
214 430
215 432
216 434
217 436
218 438
219 440
220 442
221 444
222 446
223 448
224 450
225 452
226 454
227 456
228 458
229 460
230 462
231 464
232 466
233 468
234 470
235 472
236 474
237 476
238 478
239 480
240 482
241 484
242 486
243 488
244 490
245 492
246 494
247 496
248 498
249 500
250 502
251 504
252 506
253 508
254 510
255 512
256 514
257 516
258 518
259 520
260 522
261 524
262 526
263 528
264 530
265 532
266 534
267 536
268 538
269 540
270 542
271 544
272 546
273 548
274 550
275 552
276 554
277 556
278 558
279 560
280 562
281 564
282 566
283 568
284 570
285 572
286 574
287 576
288 578
289 580
290 582
291 584
292 586
293 588
294 590
295 592
296 594
297 596
298 598
299 600
300 602
301 604
302 606
303 608
304 610
305 612
306 614
307 616
308 618
309 620
310 622
311 624
312 626
313 628
314 630
315 632
316 634
317 636
318 638
319 640
320 642
321 644
322 646
323 648
324 650
325 652
326 654
327 656
328 658
329 660
330 662
331 664
332 666
333 668
334 670
335 672
336 674
337 676
338 678
339 680
340 682
341 684
342 686
343 688
344 690
345 692
346 694
347 696
348 698
349 700
350 702
351 704
352 706
353 708
354 710
355 712
356 714
357 716
358 718
359 720
360 722
361 724
362 726
363 728
364 730
365 732
366 734
367 736
368 738
369 740
370 742
371 744
372 746
373 748
374 750
375 752
376 754
377 756
378 758
379 760
380 762
381 764
382 766
383 768
384 770
385 772
386 774
387 776
388 778
389 780
390 782
391 784
392 786
393 788
394 790
395 792
396 794
397 796
398 798
399 800
400 802
401 804
402 806
403 808
404 810
405 812
406 814
407 816
408 818
409 820
410 822
411 824
412 826
413 828
414 830
415 832
416 834
417 836
418 838
419 840
420 842
421 844
422 846
423 848
424 850
425 852
426 854
427 856
428 858
429 860
430 862
431 864
432 866
433 868
434 870
435 872
436 874
437 876
438 878
439 880
440 882
441 884
442 886
443 888
444 890
445 892
446 894
447 896
448 898
449 900
450 902
451 904
452 906
453 908
454 910
455 912
456 914
457 916
458 918
459 920
460 922
461 924
462 926
463 928
464 930
465 932
466 934
467 936
468 938
469 940
470 942
471 944
472 946
473 948
474 950
475 952
476 954
477 956
478 958
479 956
480 954
481 952
482 950
483 948
484 946
485 944
486 942
487 940
488 938
489 936
490 934
491 932
492 930
493 928
494 926
495 924
496 922
497 920
498 918
499 916
500 914
501 912
502 910
503 908
504 906
505 904
506 902
507 900
508 898
509 896
510 894
511 892
512 890
513 888
514 886
515 884
516 882
517 880
518 878
519 876
520 874
521 872
522 870
523 868
524 866
525 864
526 862
527 860
528 858
529 856
530 854
531 852
532 850
533 848
534 846
535 844
536 842
537 840
538 838
539 836
540 834
541 832
542 830
543 828
544 826
545 824
546 822
547 820
548 818
549 816
550 814
551 812
552 810
553 808
554 806
555 804
556 802
557 800
558 798
559 796
560 794
561 792
562 790
563 788
564 786
565 784
566 782
567 780
568 778
569 776
570 774
571 772
572 770
573 768
574 766
575 764
576 762
577 760
578 758
579 756
580 754
581 752
582 750
583 748
584 746
585 744
586 742
587 740
588 738
589 736
590 734
591 732
592 730
593 728
594 726
595 724
596 722
597 720
598 718
599 716
600 714
601 712
602 710
603 708
604 706
605 704
606 702
607 700
608 698
609 696
610 694
611 692
612 690
613 688
614 686
615 684
616 682
617 680
618 678
619 676
620 674
621 672
622 670
623 668
624 666
625 664
626 662
627 660
628 658
629 656
630 654
631 652
632 650
633 648
634 646
635 644
636 642
637 640
638 638
639 636
640 634
641 632
642 630
643 628
644 626
645 624
646 622
647 620
648 618
649 616
650 614
651 612
652 610
653 608
654 606
655 604
656 602
657 600
658 598
659 596
660 594
661 592
662 590
663 588
664 586
665 584
666 582
667 580
668 578
669 576
670 574
671 572
672 570
673 568
674 566
675 564
676 562
677 560
678 558
679 556
680 554
681 552
682 550
683 548
684 546
685 544
686 542
687 540
688 538
689 536
690 534
691 532
692 530
693 528
694 526
695 524
696 522
697 520
698 518
699 516
700 514
701 512
702 510
703 508
704 506
705 504
706 502
707 500
708 498
709 496
710 494
711 492
712 490
713 488
714 486
715 484
716 482
717 480
718 478
719 476
720 474
721 472
722 470
723 468
724 466
725 464
726 462
727 460
728 458
729 456
730 454
731 452
732 450
733 448
734 446
735 444
736 442
737 440
738 438
739 436
740 434
741 432
742 430
743 428
744 426
745 424
746 422
747 420
748 418
749 416
750 414
751 412
752 410
753 408
754 406
755 404
756 402
757 400
758 398
759 396
760 394
761 392
762 390
763 388
764 386
765 384
766 382
767 380
768 378
769 376
770 374
771 372
772 370
773 368
774 366
775 364
776 362
777 360
778 358
779 356
780 354
781 352
782 350
783 348
784 346
785 344
786 342
787 340
788 338
789 336
790 334
791 332
792 330
793 328
794 326
795 324
796 322
797 320
798 318
799 316
800 314
801 312
802 310
803 308
804 306
805 304
806 302
807 300
808 298
809 296
810 294
811 292
812 290
813 288
814 286
815 284
816 282
817 280
818 278
819 276
820 274
821 272
822 270
823 268
824 266
825 264
826 262
827 260
828 258
829 256
830 254
831 252
832 250
833 248
834 246
835 244
836 242
837 240
838 238
839 236
840 234
841 232
842 230
843 228
844 226
845 224
846 222
847 220
848 218
849 216
850 214
851 212
852 210
853 208
854 206
855 204
856 202
857 200
858 198
859 196
860 194
861 192
862 190
863 188
864 186
865 184
866 182
867 180
868 178
869 176
870 174
871 172
872 170
873 168
874 166
875 164
876 162
877 160
878 158
879 156
880 154
881 152
882 150
883 148
884 146
885 144
886 142
887 140
888 138
889 136
890 134
891 132
892 130
893 128
894 126
895 124
896 122
897 120
898 118
899 116
900 114
901 112
902 110
903 108
904 106
905 104
906 102
907 100
908 98
909 96
910 94
911 92
912 90
913 88
914 86
915 84
916 82
917 80
918 78
919 76
920 74
921 72
922 70
923 68
924 66
925 64
926 62
927 60
928 58
929 56
930 54
931 52
932 50
933 48
934 46
935 44
936 42
937 40
938 38
939 36
940 34
941 32
942 30
943 28
944 26
945 24
946 22
947 20
948 18
949 16
950 14
951 12
952 10
953 8
954 6
955 4

wonkey_monkey
8th January 2019, 00:55
X=480
blankclip(width=960,height=1080,length=X)
stackhorizontal(last,last.invert,last)
animate(last,0,X-1,"crop",0,0,1920,0,960,0,1920,0)
mask=(last+last.reverse).loop(100)

a=colorbars(width=1920,height=1080)
b=version.pointresize(1920,1080)

overlay(a,b,mask=mask)

Stereodude
8th January 2019, 05:08
X=480
blankclip(width=960,height=1080,length=X)
stackhorizontal(last,last.invert,last)
animate(last,0,X-1,"crop",0,0,1920,0,960,0,1920,0)
mask=(last+last.reverse).loop(100)

a=colorbars(width=1920,height=1080)
b=version.pointresize(1920,1080)

overlay(a,b,mask=mask)
There's a few minor "mistakes" in there with the motion of the mask (I had a similar mistake in my example also) and I wanted to start the mask on the other side, but I certainly wouldn't have been able to put together that combo of filters myself. Big :thanks: !

I think this is corrected
X=480
blankclip(width=960,height=1080,length=X+1)
clip1=stackhorizontal(last,last.invert,last)
clip2=clip1.trim(0,X-2)
mask=(animate(clip1,0,X,"crop",960,0,1920,0,0,0,1920,0)+animate(clip2,0,X-1,"crop",2,0,1920,0,960,0,1920,0)).loop(100)

a=colorbars(width=1920,height=1080)
b=version.pointresize(1920,1080)

overlay(a,b,mask=mask)

wonkey_monkey
19th January 2019, 23:30
Another stupid question, mostly out of curiosity...

I'm writing another filter which abuses GetAudio (I have my reasons!). If I callchild->GetAudio(buffer, start, 1, env)on a clip created by filter, I get the debug output I expect (which proves that GetAudio has been called). However, if I callchild->GetAudio(buffer, start, 0, env)my GetAudio is seemingly not called.

I'm not 100% with the fine details of classes and overloading. What is it that stops Avisynth from calling my GetAudio when count=0?

StainlessS
20th January 2019, 00:18
Perhaps Audio Cache swallows the call, and does not call your upstream filter but returns immediately (no idea really).

EDIT: You got some [additional] source at all ?

wonkey_monkey
20th January 2019, 00:29
This is my GetAudio:

void __stdcall tracker::GetAudio(void* buffer, __int64 start, __int64 count, IScriptEnvironment* env) {
debug("GetAudio: %d,%d", start, count);
if (start == -0x5452414b) {
switch (count) {
case 0: {
*((int*)buffer) = 0x5452414b;
} break;
}
} else {
child->GetAudio(buffer, start, count, env);
}
}


and this is my call to GetAudio, in the constructor of another filter:

int check = 0;
child->GetAudio(&check, 0x5452414b, 0, env);
debug("%d", check);


Edit: so does this mean there's something between calling child->GetAudio and my function actually being called, which is rejecting out-of-range values? Hmm... some thinking is required.

StainlessS
20th January 2019, 01:29
debug("GetAudio: %d,%d", start, count);

Dont use %d for __int64, use %I64d, or results will be wrong:- https://docs.microsoft.com/en-us/cpp/c-runtime-library/format-specification-syntax-printf-and-wprintf-functions?view=vs-2017

does this mean there's something between calling child->GetAudio
Well there is some stuff in source about audio cache, but no idea how it works.

enum {
CACHE_NOTHING=0,
CACHE_RANGE=1,
CACHE_ALL=2,
CACHE_AUDIO=3,
CACHE_AUDIO_NONE=4,
CACHE_AUDIO_AUTO=5
};


EDIT: Oops yep, %I64d or eg %I64X.

wonkey_monkey
20th January 2019, 01:40
Dont use %d for __int64, use %I64, or results will be wrong:- https://docs.microsoft.com/en-us/cpp/c-runtime-library/format-specification-syntax-printf-and-wprintf-functions?view=vs-2017

%I64d - %I64 is a prefix. But it's only for debugging so truncation doesn't matter.

If I only put %I64 it crashes VirtualDub2 completely. You'd think things like (vs)printf(_s) would be a little more robust...