View Full Version : request: add channel mask property in AviSynth
tebasuna51
21st May 2008, 17:38
Maybe we can hope a ChannelMask audio property in AviSynth v2.5.8?
... ChannelMask audio property ...Are you refering to OPT_UseWaveExtensible with the setting of the WAVEFORMATEXTENSIBLE.dwChannelMask field and the SPEAKER_ALL value discussion?
Or something else?
edit mod: removed comment (see 2.5.8a2 thread).
tebasuna51
22nd May 2008, 00:31
Are you refering to OPT_UseWaveExtensible with the setting of the WAVEFORMATEXTENSIBLE.dwChannelMask field and the SPEAKER_ALL value discussion?
Or something else?
Something like:
struct VideoInfo {
...
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
int channel_mask; // new in 2.8
...
}
in avisynth.h
@tebasuna51,
Perhaps you had better explain what you want channel_mask to do.
GetChannels(clip, int ch1[, int ch2, ...]) and MergeChannels(clip1, clip2[, clip3, ...]) are the prefered method for extracting and shuffling audio channels within a clip.
If it is a new feature then you probably want to open a new developer thread to discuss this feature rather than hide it here among the 2.5.8alpha2 bugs.
tebasuna51
22nd May 2008, 11:24
@tebasuna51,
Perhaps you had better explain what you want channel_mask to do.
Channel_mask is a property of an audioclip like samplerate or bitdepth and complementary to numchannels.
For instance if you load a 3/2.1 ac3 you can assign a value (based in acmod/lfeon bsi ac3 values) of 0x3F to their channel_mask and:
a = NicAc3Source("input5.1.ac3" # channel_mask(a) = 0x3F
b = GetChannels(a, 1, 2) # channel_mask(b) = 0x03 (FL,FR)
c = GetChannels(a, 5, 6) # channel_mask(c) = 0x30 (BL,BR)
d = MergeChannels(b, c) # channel_mask(d) = 0x33 (FL,FR,BL,BR)
Now can assign a correct channel_mask if we output clip d.
If it is a new feature then you probably want to open a new developer thread to discuss this feature rather than hide it here among the 2.5.8alpha2 bugs.
Sorry, if this thread is only for bugs, where is the correct place?
Wilbert
22nd May 2008, 12:28
@tebasuna51, i removed the discussion to this thread. A question of my own about this. If i understand it correctly, the channel_mask property specifies which channels in WAVE-FORMAT-EXTENSIBLE (http://www.cs.bath.ac.uk/~jpff/NOS-DREAM/researchdev/wave-ex/wave_ex.html) are used. Thus, for example:
d = MergeChannels(b, c) # channel_mask(d) = 0x33 (FL,FR,BL,BR)
since (FL,FR,BL,BR) -> 2^5+2^4+2^1+2^0 = 0x33.
However in this post: http://forum.doom9.org/showthread.php?p=1136976#post1136976 i see for example:
# MLP Channel Assignments Mask and MS channels order Detect-MaskCh eac3to libav remap Samples
-- ------------------------ -------------------------- -------------------- ----------- ----------
2 Lf Rf (S) 0x0103 FL FR BC 3.0 0x0007 (1) not needed 02_210.mlp
shouldn't that be 0x0203 since FL FR BC -> 2^9+2^1+2^0 = 0x203. (I didn't check the other values.)
----------
I guess we also need a AssumeChannelMask function?
tebasuna51
22nd May 2008, 16:29
@tebasuna51, i removed the discussion to this thread.
Thanks.
A question of my own about this. If i understand it correctly, the channel_mask property specifies which channels in WAVE-FORMAT-EXTENSIBLE (http://www.cs.bath.ac.uk/~jpff/NOS-DREAM/researchdev/wave-ex/wave_ex.html) are used. Thus, for example:
since (FL,FR,BL,BR) -> 2^5+2^4+2^1+2^0 = 0x33.
...
shouldn't that be 0x0203 since FL FR BC -> 2^9+2^1+2^0 = 0x203. (I didn't check the other values.)
For waht 2^9 for BC?
The values are coded in multichaud doc (http://www.microsoft.com/whdc/device/audio/multichaud.mspx):
00 0x00001 Front Left - FL
01 0x00002 Front Right - FR
02 0x00004 Front Center - FC
03 0x00008 Low Frequency - LF
04 0x00010 Back Left - BL
05 0x00020 Back Right - BR
06 0x00040 Front Left of Center - FLC
07 0x00080 Front Right of Center - FRC
08 0x00100 Back Center - BC
09 0x00200 Side Left - SL
10 0x00400 Side Right - SR
11 0x00800 Top Center - TC
12 0x01000 Top Front Left - TFL
13 0x02000 Top Front Center - TFC
14 0x04000 Top Front Right - TFR
15 0x08000 Top Back Left - TBL
16 0x10000 Top Back Center - TBC
17 0x20000 Top Back Right - TBR
I guess we also need a AssumeChannelMask function?
Yes, I think so.
And
MixAudio (clip1, clip2, float "clip1_factor", float "clip2_factor")
must preserve the channelmask from clip1
And
ConvertToMono
assign 0x04 (Front Center)
Wilbert
22nd May 2008, 17:02
For waht 2^9 for BC?
The values are coded in multichaud doc:
You are right. Counting can be difficult sometimes :)
tebasuna51
22nd May 2008, 18:04
When source ChannelMask is ignored (standard WAV, OGG, FLAC) we need assign a default based in nchannels, for instance:
Chan. Mask MS channels
----- ------ -----------------------
1 0x0004 FC
2 0x0003 FL FR
3 0x0007 FL FR FC
4 0x0033 FL FR BL BR
5 0x0037 FL FR FC BL BR
6 0x003F FL FR FC LF BL BR
7 0x013F FL FR FC LF BL BR BC
8 0x063F FL FR FC LF BL BR SL SR
This match with the Channel assignment (http://flac.sourceforge.net/format.html) (until 6 chan.) in Flac format.
I suggest something similar to Shodan for SoundOut (http://forum.doom9.org/showthread.php?p=951530#post951530), when output WAVE_FORMAT_EXTENSIBLE.
Multichannel formats like AC3, DTS, MLP/TrueHD have parameters to calculate the correct (or more equivalent) channel mask.
I don't know if WMA, AAC have something similar.
@tebasuna51, What do you propose if someone does this :-a = NicAc3Source("input5.1.ac3" # channel_mask(a) = 0x3F
b = GetChannels(a, 1, 2) # channel_mask(b) = 0x03 (FL,FR)
c = GetChannels(a, 5, 6) # channel_mask(c) = 0x30 (BL,BR)
d = MergeChannels(c, b) # channel_mask(d) = ???? (BL,BR,FL,FR)
tebasuna51
23rd May 2008, 15:39
@tebasuna51, What do you propose if someone does this :-a = NicAc3Source("input5.1.ac3" # channel_mask(a) = 0x3F
b = GetChannels(a, 1, 2) # channel_mask(b) = 0x03 (FL,FR)
c = GetChannels(a, 5, 6) # channel_mask(c) = 0x30 (BL,BR)
d = MergeChannels(c, b) # channel_mask(d) = ???? (BL,BR,FL,FR)
If we want be strict this is a Error. The order BL,BR,FL,FR is not possible (if we want output WAVE_FORMAT_EXTENSIBLE).
Also we can ignore the (c,b) order and see only the ChannelMask
a = NicAc3Source("input5.1.ac3" # channel_mask(a) = 0x3F
b = GetChannels(a, 1, 5) # channel_mask(b) = 0x11 (FL,BL)
c = GetChannels(a, 2, 6) # channel_mask(c) = 0x22 (FR,BR)
d = MergeChannels(c, b) # or (b,c), channel_mask(d) = 0x33 (FL,FR,BL,BR)
Maybe we want process the left/right channels in different form and after merge.
When a problem occurs (the same channel present in more than one clip) we can assign the default mask for the output clip.
IanB
18th November 2010, 21:55
@IanB, without a new audio property (ChannelMask) we can't manage properly multichannel audio inside AviSynth.I think you mean :-
... can't manage properly multichannel audio outside AviSynth.
Within a script the channels are as the input filter delivers them (okay some form of input hint could be handy), then as the script author arranges them.
For output when using the "OPT_UseWaveExtensible" hack WAVEFORMATEXTENSIBLE.dwChannelMask 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 CrFor greater than 7 channels we just roll 1 bits in from the right up to 18 channels, above that we just set SPEAKER_ALL.vi->AudioChannels() <=18 ? DWORD(-1) >> (32-vi->AudioChannels()) : SPEAKER_ALL;In the latest CVS you can override this by setting OPT_dwChannelMask as required.
For other output services it is up to the output provider to assign the channel order.
As an aside the dwChannelMask concept is incomplete, you cannot specify channel order, assignment is done from the bit mask right to left. Thus channel 1 is assigned the lowest (right most) set bit, i.e. Centre front for Mono, Left front for others. The Subwoofer mask bit is 0x8 so it can never be assigned greater then channel 4.
tebasuna51
20th November 2010, 14:32
To explain the problem first we need follow the channel syntax of WAVE_FORMAT_EXTENSIBLE.
If Lr mean Left-rear let me say than don't exist, can be Back-Left or Side-Left.
Then your table must be rewritten to:
0x00004, // 1 - - FC
0x00003, // 2 FL FR
0x00007, // 3 FL FR FC
0x00033, // 4 FL FR - - BL BR
0x00037, // 5 FL FR FC - BL BR
0x0003F, // 5.1 FL FR FC LF BL BR
0x0013F, // 6.1 FL FR FC LF BL BR - - BC
Space between BR and BC reserved for not common channels:
FRONT_LEFT_OF_CENTER 0x40
FRONT_RIGHT_OF_CENTER 0x80
I agree with the defaults and we can add safely also the standard 7.1 config:
0x0063F, // 7.1 FL FR FC LF BL BR - - - SL SR
But many soft, after XP SP2, can prefer map the Surround channels to Side channels, instead Back channels, and there are other valid ChannelMask:
0x00603, // 4 FL FR - - - - - - - SL SR
0x00607, // 5 FL FR FC - - - - - - SL SR
0x0060F, // 5.1 FL FR FC LF - - - - - SL SR
0x0070F, // 6.1 FL FR FC LF - - - - BC SL SR
No problem with 4, 5 and 5.1 config because the order is equivalent, but we have a problem with 6.1
0x0013F, // 6.1 FL FR FC LF BL BR - - BC
0x0070F, // 6.1 FL FR FC LF - - - - BC SL SR
How we know if the BC is Getchannel(7) or Getchannel(5) without know the ChannelMask?
Then there are problems outside and inside AviSynth:
How can downmix a 6.1 to 5.1 or 2.0 without know the ChannelMask?
How can manage other ac3 typical channel layout, like L,R,C,S?
(For the future) How can set OPT_dwChannelMask inside NicAudio?, in order to use something like:
NicAc3Source("input.ac3")
OPT_dwChannelMask = 0x00033 ? mixLRSlSr_2(last): last
OPT_dwChannelMask = 0x00107 ? mixLRCS_2(last): last
...
IanB
20th November 2010, 22:32
If Lr mean Left-rear let me say than don't exist, can be Back-Left or Side-Left.
I cut and paste that table from some Microsoft document long ago when I wrote the code. Yes Left-rear is a reasonable interpretation, it is as I understood it at the time.
The syntax I posted from the Avisynth source comments apparently is [Left, Right, Centre, Sub][front, rear, woofer]. Rear and Back are synonyms. You appear to prefer a syntax [Front, Back, Side, Low][Left, Right, Centre, Freq.]. It seems a fairly common syntax in use.
I agree with the defaults and we can add safely also the standard 7.1 config:
0x0063F, // 7.1 FL FR FC LF BL BR - - - SL SR
Yes I will change the default from 0x000FF to 0x0063F for 8 channels
but we have a problem with 6.10x0013F, // 6.1 FL FR FC LF BL BR - - BC
0x0070F, // 6.1 FL FR FC LF - - - - BC SL SRHow we know if the BC is Getchannel(7) or Getchannel(5) without know the ChannelMask?
Then there are problems outside and inside AviSynth:
How can downmix a 6.1 to 5.1 or 2.0 without know the ChannelMask?
How can manage other ac3 typical channel layout, like L,R,C,S?
Yes, you need an input hint from the source filter.
(For the future) How can set OPT_dwChannelMask inside NicAudio?, in order to use something like:
NicAc3Source("input.ac3")
OPT_dwChannelMask = 0x00033 ? mixLRSlSr_2(last): last
OPT_dwChannelMask = 0x00107 ? mixLRCS_2(last): last
...
No! OPT_dwChannelMask controls the contents of the WAVEFORMATEXTENSIBLE.dwChannelMask field in the output AVIFile emulation.
What is needed is a separate hint from the source filter, remember 2 sources in the 1 script may have different masks. Ideally extending VideoInfo to include the meta-data would be best, but that is not possible.
So you probably want something along these lines of :-NicAc3Source("input.ac3", hint="NicChannelMask") # Does env->SetGlobalVar(hint, (int)wfext.dwChannelMask)
NicChannelMask == 0x00033 ? mixLRSlSr_2(last): last
NicChannelMask == 0x00107 ? mixLRCS_2(last): last
...
global OPT_dwChannelMask = NicChannelMask
...Perhaps the the hint gvar might be more useful as a string with more meta-data included. Perhaps a set of meta-data gvar's. Thoughts?
tebasuna51
21st November 2010, 05:03
**The 3 previous post was moved from another thread.**
Thanks IanB.
You know NicAudio source code.
What I need add in NicAudio to set the gvar?
Only: ?
env->SetGlobalVar(hint, 0x00107)
for instance, or
env->SetGlobalVar(hint, "0x00107")
IanB
21st November 2010, 08:14
FFMpegSource() sets some vars as it goes about it's business, problem is they have fixed names, so when you have multiple instances you get conflict. This is not the only case of conflict, inside ColorYUV(), Overlay(), etc there is the option to control the behaviour with conditional processing by vars, again all fixed var names.
Hence my suggestion that if you want to set some global vars to pass extra meta-data into the script from a source, then let the user specify the vars name on the call. Then if one codes multiple instances then there can be multiple uniquely named vars.
So step 1 add an optional named string argument to NIC functions. "Hint" would be a particularly lame name. "dwChannelMaskGlobalVarName" although very descriptive is ludicrously long.
Also what other information from an audio source file might be useful to pass into a script. Well obviously one is dwChannelMask. Others??
How best to present said information, e.g. a single text gvar with all the info pack in is easily extensible, but parsing text strings in Avisynth scripts is not the nicest. May be we could use the hint name as a prefix for the set of gvar names, i.e. name_dwChannelMask, name_FangDangle, name_DoodleBug, etc
class IScriptEnvironment {
public:
...
virtual bool __stdcall SetGlobalVar(const char* name, const AVSValue& val)
...As for setting the gvars, just call env->SetGlobalVar(Name, Value); in the constructor of the source filter. Name being a char* with the gvar's name. And Value be an AVSValue holding the meta-data. There are defined conversions from int, float, char* and PClip to AVSValue so no special casting is required.
More Thoughts??
TheFluff
21st November 2010, 10:23
FFMpegSource() sets some vars as it goes about it's business, problem is they have fixed names, so when you have multiple instances you get conflict. This is not the only case of conflict, inside ColorYUV(), Overlay(), etc there is the option to control the behaviour with conditional processing by vars, again all fixed var names.
Hence my suggestion that if you want to set some global vars to pass extra meta-data into the script from a source, then let the user specify the vars name on the call. Then if one codes multiple instances then there can be multiple uniquely named vars.
I guess I should implement this in FFMS2.
It would be nice if we could agree on a standard naming convention as well as a format for some common properties though, like color range and color matrices and maybe crop values.
TheFluff
23rd January 2012, 08:37
Bumping a year and a half old thread to say FFAudioSource now (from 2.17) sets the variable FFCHANNEL_LAYOUT, which contains a dwChannelMask-compatible integer that describes the channel layout of the stream. Also, you can now set a variable name prefix to prevent different calls in the same script from overwriting each other's variables.
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.