I am looking to display histogram levels when playing mp4/x264 videos to analyse the RGB range used (Limited 16-235 or Full).
I seem to remember ffdshow could do something like this, but ideally I am looking for more current tools.
This thread based on Avisynth was helpful, but maybe other simpler tools could be used for this ?
https://forum.videohelp.com/threads/385078-Adjusting-H-264-Levels-from-mp4
I am struggling a bit with Avisynth+/AvsPmod to get what I want.
This seems to works OK:
Video + sRGB histograms (bt709 colormatrix, no range expansion)
Code:LoadPlugin("b:\AviSynth plugins\lsmash\LSMASHSource.dll") fname = "b:\Videos\monster-1_ed.mp4" vid=LWLibavVideoSource(fname, cachefile="C:\Temp\tmp.mp4.lwi") Import("b:\Downloads\web\avs\Histograms_in_RGB_&_CMY.avsi") ConvertToRGB(vid, matrix="rec709") HistogramRGBLevels()
I would like to display Luma only histogram below the video with levels,
not parade as in following function:
ColorYUV(analyze=true): how to shift the overlay to the corner rather than the top/middle of the screen ?Code:function HistogramOnBottom(clip vid){ top = vid TurnRight(vid).Histogram().TurnLeft() bot = Crop(0, 0, width, 256) StackVertical(top, bot) }
Is it possible to get a File Open dialog to select the video with AvsPmod ?
+ Reply to Thread
Results 1 to 30 of 45
-
Last edited by butterw; 3rd Aug 2020 at 16:00.
-
[QUOTE=butterw;2591117]
This seems to works OK:
Video + sRGB histograms (bt709 colormatrix, no range expansion)
Code:LoadPlugin("b:\AviSynth plugins\lsmash\LSMASHSource.dll") fname = "b:\Videos\monster-1_ed.mp4" vid=LWLibavVideoSource(fname, cachefile="C:\Temp\tmp.mp4.lwi") Import("b:\Downloads\web\avs\Histograms_in_RGB_&_CMY.avsi") ConvertToRGB(vid, matrix="rec709") HistogramRGBLevels()
You can use ConvertToYUY2().VideoScope("bottom"). Or:
Code:function LumaHistogramOnBottom(clip v) { Histogram(v, "levels") Crop(width-256,0,256,64) AddBorders(0, 0, v.width-256, 0) Stackvertical(v,last) }
-
Thanks jagabo.
Am I the only one to think Avisynth could do with having an Easy Mode, for the noobs ?!
For debug, is it only possible to output to the screen (no print to console) ?
with info(), if the video is small, the output is unreadable. Maybe I could return a blank clip with my variable values overlayed ?
After some testing with LumaHistogram, in 16/9 fullscreen the following works best:
- on the side for Aspect Ratio=4/3.
- at the bottom or top for AR>1.85
- for 16/9, It's best to use CropBottom on the video.
Code:function LumaHistogram(clip v){ Histogram(v, "levels") ## the Luma histogram is displayed on the right by default and has dimensions (256, 64). Crop(width-256, 0, 256, 64) ## get rid of clip and U/V histograms # AddBorders(0, 0, 0, v.height-64) ##side luma histogram: best for movies with AR 4/3 in fullscreen # StackHorizontal(v, last) # return last # AddBorders(0, 0, v.width-256, 0) # StackVertical(v, last) ## bottom histogram, best for movies with AR >1.85 in fullscreen ## StackVertical(last, v) ## top histogram }
Displaying an horizontal RGB histogram (rewrite HistogramRGBLevels) + LumaHistogram would make sense.
The lag at indexing when opening a movie probably can't be avoided, but I should probably use multithreading to improve overall performance.
Code:# vid = LSmashVideoSource(fname, prefer_hw=2) ## doesn't require index, only works for mp4 ? vid = LWLibavVideoSource(fname, prefer_hw=2, cachefile="C:\Temp\tmp.mp4.lwi") ## works for mkv ##
Edit: works with conversion to 8bit.
Code:## Decoding 10bit, YUV 4:2:0 source and converting to 8-bit. LWLibavVideoSource(<path>, format="YUV420P10") ConvertBits(8, dither=0) ## '0' means on, '-1' means off
Histogram(vid, "Levels") # bits=10, keepsource=false
# if vid is RGB, histogram displays R, G, B histograms. However the out of (16, 235) range isn't highlighted, so I don't think this can be used.Last edited by butterw; 4th Aug 2020 at 14:39. Reason: I Read the docs
-
I don't know if the output of Info() can be sent to a file. But you can use WriteFile() to send output to a file.
http://avisynth.nl/index.php/WriteFile
For example:
Code:WriteFile("output.txt", """string(width)+" x "+string(height)""")
http://avisynth.nl/index.php/Clip_properties -
Edit: MessageClip("H=" + string(Height)) works if you only want to print one set of variables. Combine that with return statements and you can debug.
subtitle(String(height), align=5) can be used otherwise.
Print to screen (simpler or not):
Code:/* Subtitle position (numpad numbering !) 7 8 9 4 5 6 1 2 3 */ b=blankclip() i=1 blankclip() b = subtitle(b, "H=" + string(Height) + ", W=" + string(Width), align=i) i=i+1 b = subtitle(b, "pix=" + string(PixelType), align=i) i=i+1 b = subtitle(b, "i=" + string(i), align=i) i=i+1 return b
Last edited by butterw; 8th Aug 2020 at 14:32. Reason: Avisynth syntax !!!
-
Another option you can look at is info2() , which has font/size options
http://avisynth.nl/index.php/Info2
The lag at indexing when opening a movie probably can't be avoided, but I should probably use multithreading to improve overall performance.
You can use other non indexing source filters if you don't need frame accuracy . If you're just "playing" this back in a media player, it's probably not important.
eg. DirectShowSource, DSS2 (this is slightly better for seeking, frame accuracy than directshowsource, but it can cut off frames at the end). They can utilize HW acceleration if you setup lav filters correctly
You can look at other non avisynth options too, like ffplay or mpv with -vf histogram and waveform . Maybe overlay (partial transparency) or stack the graphic
# if vid is RGB, histogram displays R, G, B histograms. However the out of (16, 235) range isn't highlighted, so I don't think this can be used. -
I like info2 much better than info().
DSS2mod ? DirectShowSource doesn't load my files.
LSmashVideoSource / LWLibavVideoSource seem pretty decent.
Indexing is an issue for long/large files, yes (a few seconds wait on SSD), but less so for clips. The main problem is the time/hassle it takes to change the filepath in the .avs file.
Certainly I will look into mpv.net if it has a built-in histogram feature.
Benefits of using avisynth is that there are a lot of good libraries available, it can be opened on my preferred player (mpc-hc) and I can apply pixel shaders to it.
I'm looking at realtime correction/effects to be applied on a wide variety of videos sources (not just bluray encodes) with Gpu Pixel shaders, which use rgb natively. I don't think I could read Histogram levels without any range graduation.
As an example here's one such expansion correction formula used in existing code. I haven't looked into whether it is accurate or not, but it is fast.
/* 16-235 to 0-255.hlsl,
1 texture, 2 arithmetic) operations */
#define const_1 ( 16.0 / 255.0)
#define const_2 (255.0 / 219.0)
float4 c0 = tex2D(s0, tex); // c0: original RGB pixel [0, 1]
return ((c0 - const_1) * const_2);Last edited by butterw; 4th Aug 2020 at 14:35.
-
About multithreading in Avisynth+: can it only be used for external plugin (dlls), not built-ins ?
vid.ColorYUV(analyze=true) ## stats overlay struggles with 1080p input.
http://avisynth.nl/images/ColorYUV_analyze_Ex1.jpg
I am seeing quite a few videos where the Min/Max of Luma is 0-255
While the Loose Min/Loose Max, which ignore the brightest and darkest 0.4%, are in the limited Range.
Also videos where the main levels are well inside limited range, but there is also sometimes a spike outside of range.
How should such videos be viewed on a full range monitor ? Clamp, then limited range to full range transformation ?Last edited by butterw; 5th Aug 2020 at 08:32.
-
DirectShowSource / DSSmod should be able to open almost anything. You need a directshow decoder and splitter installed. The most common is lav video decoder / splitter
LSmashVideoSource / LWLibavVideoSource seem pretty decent.
Certainly I will look into mpv.net if it has a built-in histogram feature.
I'm looking at realtime correction/effects to be applied on a wide variety of videos sources (not just bluray encodes) with Gpu Pixel shaders, which use rgb natively. I don't think I could read Histogram levels without any range graduation.
One issue is "where/when" are you measuring? Pre or post shader/effect . Pre or post RGB conversion etc... If you run it in the script you can control where a filter is applied or where something is measured for a histogram/waveform/scope ... say before shader1, or after shader3, etc..
But if you feed an avs or vpy script, the player only "sees" the output node of the script. eg. If you're using a script for a scope measurement, it's not measuring the effect of the shader(s), only the 1st input. If you could only measure 1 place, it should be at the very end, so you can adjust filters/shaders.
As an example here's one such expansion correction formula used in existing code.
Range expansion is not a great example in this case - if you start with a YUV video - you're converting to RGB in the avs script in order to use the histogram; It would be faster/higher quality to convert to RGB correctly in the first place, instead of converting incorrectly, then applying a shader to "fix" it later. (Unless the video was screwed up to begin with) .
It would be more ideal to have the scopes in the player, measuring at the end, or where you specify
In general it works for everything; but certain functions/plugins can become bottlenecks. Some might not be optimized, lack SIMD.
And very few are GPU accelerated - it's difficult to mix/match memory , GPU memory, often the transfer up/down can make things actually much slower . If everything is run on the GPU that makes things easier, but not everything can be run on GPU
And btw for measuring RGB, avisynth has similar function to ColorYUV(analyze=true) ; RGBAdjust(analyze=true)
I am seeing quite a few videos where the Min/Max of Luma is 0-255
While the Loose Min/Loose Max, which ignore the brightest and darkest 0.4%, are in the limited Range.
Also videos where the main levels are well inside limited range, but there is also sometimes a spike outside of range.
How should such videos be viewed on a full range monitor ? Clamp, then limited range to full range transformation ?
Numbers are less useful unless you can correlate what they mean with the actual picture
You need to assess the reference black and white level. Correlate parts of the main picture (what you "see") to what the black and white should be. "black" is easy if you have letterbox bars - they should be Y=16 (and assuming they were part of the original image, not put on at some later date - because multigenerational issues can occur - the bars might not correspond to the same "black" as in the original image) . If you had colorbars on the video, that would be nice too, but unlikely
Black level at Y=16, White at Y=235 should take care of everything, regardless of display . Transients are usually ignored, unless they have useful information
eg. Sometimes "overbrights" contain real information; maybe a bright scene with clouds. You might want bring them down selectively, increase the contrast in the highlight area. It's not as easy to do full manipulations with a shader in a player. If you're doing anything more than "simple", I would consider doing that in another program like resolve or similarLast edited by poisondeathray; 5th Aug 2020 at 20:01.
-
In general it works for everything; but certain functions/plugins can become bottlenecks. Some might not be optimized, lack SIMD.
[quote]
Do I need to do anything in particular to get multithreading on the built-in functions ?
for the external functions I'm doing:
SetFilterMTMode("LSMASHVideoSource", MT_SERIALIZED) at the beginning of the script (can also be done via import of MTmodes.avs).
and Prefetch(last, 3) at the end of the script (to activate MT and get 3 threads).
Black level at Y=16, White at Y=235 should take care of everything, regardless of display . Transients are usually ignored, unless they have useful information
eg. Sometimes "overbrights" contain real information; maybe a bright scene with clouds. You might want bring them down selectively, increase the contrast in the highlight area. It's not as easy to do full manipulations with a shader in a player. If you're doing anything more than "simple", I would consider doing that in another program like resolve or similar
One of the issues when you play a video file on PC, is you don't know if the range is limited or not. From what I've seen, there is a good chance that any file tagging for Limited Range is incorrect.
Min/Max of Luma, 99.6% range looks like it could be used as a first order algorithm to determine whether a video should in fact be treated as limited range.
Lighting changes at scene change could theoretically cause the result to change over the duration of course. -
HistogramRGBLevels is Fine. My comment was about the built-in histogram(rgb_vid, "levels"), which for some reason doesn't highlight.
You can actually get output in the player chain via png screenshots which can then be analysed via my avs script.
Histogram visualization would be nice to have in a video player, but it likely would not see widespread use as it's more of a video/photo editing feature. Devs typically don't want to have to support anything non-essential.Last edited by butterw; 5th Aug 2020 at 15:21.
-
Do you have an example using these filters ? I have LAV Filters installed but as part of Mpc-hc, not as standalone.
It looks like you can specify a path with dss2. But the only avss_x64.dll version I have found dates way back (11/2014).
DirectShowSource doesn't want to open anything.
I remember using DirectShowSource back in the day: you had to specify framerate and it didn't work great for encoding.
- Are LSmashVideoSource / LWLibavVideoSource frame accurate ? -
That looks ok; it's just that coloryuv(analyze=true) is a bottleneck , doesn't thread well
You can use avsmeter to analyze and optimize scripts, cpu/gpu %, threads
One of the issues when you play a video file on PC, is you don't know if the range is limited or not. From what I've seen, there is a good chance that any file tagging for Limited Range is incorrect.
There are some exceptions, but the vast majority are limited range if flagged limited or unflagged. But if something is flagged full, then it's usually full
Min/Max of Luma, 99.6% range looks like it could be used as a first order algorithm to determine whether a video should in fact be treated as limited range.
Lighting changes at scene change could theoretically cause the result to change over the duration of course.
Also, limited vs. full isn't the "complete picture", or all the information; what if it's limited, but levels or contrast are off ? What if black level is slightly elevated ? etc....
That defeats the purpose of a player scenario, real time playback etc...
Histogram visualization would be nice to have in a video player, but it likely would not see widespread use as it's more of a video/photo editing feature. Devs typically don't want to have to support anything non-essential.
There is a scopes.lua partial script that richardpl wrote, but it's not complete
https://gist.github.com/richardpl/02a283eefd9636a15435b1c5596dedeb
It's the same as any filter
DirectShowSource("PATH\video.ext")
or
DSS2("PATH\video.ext")
What error message are you getting ?
I think the ones listed on the dss2mod page are the newest
http://avisynth.nl/index.php/DSS2mod
I remember using DirectShowSource back in the day: you had to specify framerate and it didn't work great for encoding.
- Are LSmashVideoSource / LWLibavVideoSource frame accurate ?
Directshowsource is used as a last resort, because it's not necessarily frame accurate (linear play is generally ok), and temporal filters can mix up frames. But it's generally ok for a media player. If you're using temporal filters in a script , and feed that into a media player, you're going to want to avoid it
But DSS2 is frame accurate with seeks, the problem is it consistently drops 1 or 2 of the last frames
Both can use GPU acceleration through LAV
LSmash can be considered frame accurate (but there are some exceptions) -
Note that DirectShowSource() or DSS2() don't read "everything". They require DirectShow installed readers, splitters, and codecs for the file(s) in question. Generally, if Windows Media Player can play the video those source filters will work. If WMP doesn't play the video those source filters will not work.
-
WMP does play a basic mp4 file on my system. But built-in DirectShowSource doesn't load it.
The error msg goes: DirectShowSource couldn't open as audio or video. can't open file. can't play file. the format is not supported.
With DSS2, I tried specifying a path to Lav Filters folder in lavf_path. But it fails to connect the graph.
I don't have any VSFilter.dll.
string lavf_path = "LAVFilters"
string dvs_path = ""
you can specify a path (relative or absolute) to LAVFilters .ax files and to VSFilter.dll accordingly. By default, LAVFilters will be loaded from \LAVFilters subfolder in the same folder where avss.dll is placed (and was loaded from); VSFilter.dll by default will be loaded from the same folder where avss.dll is placed. If .ax or .dll should be loaded, but wasn't found, you will get an error message. -
Not sure, it sounds like a path issue
Or try placing a LAVFilters subfolder in the appropiate avisynth plugins folder , and copying the .ax files there . Keep x64 / x86 together (use x64 lav for x64 avisynth)
If that does not work, or specifying the direct path does not work, it probably needs to be installed -
I'm x64 for Avisynth/Lav and I believe Wmp is also x64 on Win10.
and I've never been a fan of DirectShowSource or codec packs.
Edit: WMP was 32bit on my Win10 64bit (as indicated in Task Manager)
Installing system wide LAVFilters x64 did get DirectShowSource/DSS2 to work.Last edited by butterw; 6th Aug 2020 at 05:20.
-
-
Here is pass-through code with multi-threading in Avisynth+ (x64). Tested with mp4/mkv files (x264/x265 8bit) in mpc-be video player.
Please point out any mistakes.
Code:## Setup Multi-Threading mode for external dlls SetFilterMTMode("LSMASHVideoSource", MT_SERIALIZED) SetFilterMTMode("LWLibavVideoSource", MT_SERIALIZED) SetFilterMTMode("DSS2", MT_SERIALIZED) ## DSS2mod avss_x64.dll v2.0.0.13 (2014/11/10) SetFilterMTMode("DirectShowSource", MT_SERIALIZED) ## Is this required for DirectShowSource ? ## Input file (yuv420p) mp4/mkv fname = "b:\Videos\monster-1.mp4" ## DirectShowSource/DSS2: must install DS filter system-wide (LAVfilters) + set gpu hw acceleration in lav video decoder vid = DirectShowSource(fname, audio=true) ## Artefacts at start and with seeking (+ cpu spike, frame pacing) !!! loads audio by default. # vid = DSS2(fname, pixel_type="YV12") ## does work. video only. # vid = LSmashVideoSource(fname, prefer_hw=2) ## for mp4 video only !!! prefer_hw=2 (intel igpu hw decoding) # vid = LWLibavVideoSource(fname, prefer_hw=2, cachefile="C:\Temp\tmp_mkv.idv") ## requires initial indexing !!! # vid = vid.subtitle(String(vid.Pixeltype), align=9) Prefetch(vid, 2) ##Enable multithreading with 2 threads return vid
As expected Cpu usage is higher than if you played the file directly.
for video only playback, my choice would be LSMASHVideoSource for mp4.
for mkv, if you can get past the old DS filter install issues, DSS2 does seem to work (without requiring initial indexing like LWLibavVideoSource)
## default pixeltype with DirectShowSource/DSS2 is YUV2 with on my system ??? in DirectShowSource: no video if changed to YV12 !!!
What source filter would you recommend to play video + audio (aac, ac3) ?
I would not consider the video result obtained with DirectShowSource acceptable (better to wait for indexing).Last edited by butterw; 6th Aug 2020 at 06:31. Reason: formatting
-
You can use LSmash too, or FFMS2 (For video and audio)
Code:aud = LWLibavAudioSource("blah.ext") vid = LWLibavVideoSource("blah.ext") AudioDub(vid,aud)
Code:aud = FFAudioSource("blah.ext") vid = FFVideoSource("blah.ext") AudioDub(vid,aud)
-
Avisynth has no If statement only conditional expressions ?!
Code:doAudio = true ## User Setting function loadAudio(clip v, string fname){ audio = LSMASHAudioSource(fname) return AudioDub(v, audio) } vid = doAudio ? vid.loadAudio(fname): vid vid.Prefetch(3) return vid
Edit As pointed out in the following msg, in Avisynth+:
Code:vid = doAudio ? vid.loadAudio(fname): vid
Code:if (doAudio) { vid = vid.loadAudio(fname) }
My LumaHistogram.avs code is available at https://github.com/butterw/bShaders/tree/master/test_LimitedRange
Also available bHighL.hlsl gpu pixel Shader that highlights pixels outside of defined Luma Range (in solid colors)Last edited by butterw; 7th Aug 2020 at 12:03. Reason: code uploaded
-
"Cannot render the file" error msg with Avisynth+
I might be missing something basic here, but I'm getting this error a lot:
- try loading a plugin that isn't at defined path
- use a variable that hasn't been defined (was commented out)
- use LWLibavVideoSource with cache=true + cachefile="c:\Temp\temp.lwi"
- syntax error on if statement: if doAudio vs if (doAudio)
Does Avisynth+ provide useful error messages somewhere ?
I modify my code, launch the avs, and then see this message on the Output, and each time have to debug with return statements. -
That message is probably coming from the editor/encoder you're using. AviSynth usually gives a line and column number of the error in the video it outputs. I usually use VirtualDub2 to check my scripts. It passes those messages along:
[Attachment 54417 - Click to enlarge] -
Originally Posted by butterw
With AvsPmod, I do get more info about the actual error if I launch in the integrated video player (Shift-F5) rather than the external video player (F6).
This does suggest however that editing an Avisynth+ script with a standard text editor isn't practical and that the end-user should install AvsPmod (or equivalent) to be able to configure the script.
Is there a way in Avisynth+, to get the error output by launching the script from commandline ? I'm getting no text output by simply calling the script name.
Can the following feature be used: http://avisynth.nl/index.php/AviSynth+#Logging_Facility ? -
Nonsense. You can use Notepad to edit the script, VirtualDub to check/preview it. If you need to edit script to fix and error VirtualDub you reload reload the script by pressing F2. VirtualDub2 even has a editor for AVS scripts built in (Tools -> Script Editor. It's automatically invoked on errors). You can reload the script by pressing F5 from there.
Just run an editor that loads files from the command line:
Code:X:\path\to\VirtualDub script.avs
-
I will recommend new users of Avisynth+ to download/use AvsPmod (or Virtualdub2) to edit their .avs scripts.
As a user of Notepad++:
1) .avs only has flaky syntaxic coloring through a User Defined Language file.
2) Syntax errors happen in Avisynth: you then need to launch with Virtualdub command line to get a meaningful error msg. (ex: path\VDub64.exe LumaHistogram.avs). Also, the documentation fails to mention this.
The Avisynth+ logfile feature, which I linked to, works, but doesn't seem very practical.Last edited by butterw; 8th Aug 2020 at 08:53.
-
Put a shortcut to VirtualDub in your SendTo folder and you can right click on any AVS script and select Send To -> VirtualDub.
-
btw. error text message could be caught into text file. I used to catch it like this:
https://forum.videohelp.com/threads/377677-Video-batch-files#post2471571
it starts with line:
REM checking script for errors
But reading this, would not be really comfortable (no indexing, any file, extensions associated with player) to use mpv player and also get histogram on screen? Never tried this, but it looks easy to implement it.
Similar Threads
-
Blank stripe display on playback - Sony TRV 460E
By Sathwik in forum Camcorders (DV/HDV/AVCHD/HD)Replies: 6Last Post: 30th Jun 2020, 10:16 -
Red and Blue Climbing Histogram Walls
By koberulz in forum RestorationReplies: 11Last Post: 2nd Jul 2019, 09:48 -
Avisynth Virtual File System doesn't display video true colors
By TeNSoR in forum Newbie / General discussionsReplies: 6Last Post: 11th Feb 2019, 17:05 -
AviSynth 'Histogram' is Suspicious
By WinUser in forum Video ConversionReplies: 13Last Post: 23rd Feb 2017, 08:49 -
Ffmpeg/Ffplay: simultaneous playback of two videos, or video+histogram?
By zopiro in forum EditingReplies: 4Last Post: 19th Dec 2015, 10:44