Welcome to the wiki of QMtrim!
(This document is a free adaptation of the original HoHoHo's guide. --KICKAHA)
One of the aims of video compression is to achieve the best quality with minimum size. To this end, different software tools were developed to be used during compression. Some of those are:
AviSynth is a frame server with a powerful scripting language that allows video processing with highly effective logic. AviSynth has also a well developed set of filters enabling many type of image processing.
You can use AviSynth to split the video in different sequences with the trim function, process each sequence with a different filter chain and merge back the sequences just before compressing the video. This type of work-flow let you apply the best possible filter for each sequence.
QMtrim was thought to further enhance this work-flow by applying "rougher" filters (dropping details for best compression) to sequences with more motion (where the eyes don't catch the details) and "lighter" filters to more static sequences (where eyes have a more fine perception). This way you lose detail where is less needed leaving space for images that will be seen more accurately and achieving a higher perceived quality.
To realize this kind of video processing, you need at first to measure motion. There are filters for AviSynth doing this job: one of them is MVAnalyse from Manao & Fizick's MVtools. Comparing each frame with the next and applying a motion-compensation algorithm just link some codecs, it returns the sum of motion of every block of pixels.
As filter system, you could think of an ideal algorithm probing every frame for motion and applying a filter just fit for it, but this means that in a sequence becoming faster and faster you would apply rougher and rougher filters in a very short time and your eyes would see the quality dropping.
Also, motion measurement is not an exact data, a continuous line; values are likely affected by error (like a white noise) and there are motion "peaks" that should be ignored as too short to be noticed by the eyes: it's typical of the scene change case, measured as big motion in a single frame maybe immediately followed by a static sequence.
In using QMtrim you have to think to a discrete set of filters, each a little "rougher" that the previous: the first filter will be used for almost static images, the last for sequence with the most motion. If the number of filters is high enough you will not notice the difference between a filter and the next and you will achieve the same effect an infinite set of filter would have, with each one perfectly fit for each image motion.
Another problem is to split the video in sequences where every image has roughly the same motion to apply the right filter to each one. AviSynth uses the trim function to split video, but as the number of filters grows, the sequences become shorter and too many to be handled manually. And last, you must avoid to use rougher and rougher filters too fast.
QMtrim tries to solve this issues.
First of all you need to measure motion for every frame to feed QMtrim with. With respect to this, QMtrim was thought as independent to the measured quantity and the filter logic; i.e. given a filter that measures image redness, you could use QMtrim to choose the filter to be used to reduce the red component or anything else. Within this guide the motion approach will be discussed: how to apply more or less rough filters depending on the motion of every frame.
What matters to QMtrim is to have an input file to process, with this format:
You need to get MVtools at this address (http://avisynth.org.ru/mvtools/mvtools.html) and install them with other AviSynth libraries so that it can be used within you scripts (in the following examples I'll suppose you installed the DLL in this path: "C:\Programs\AviSynth 2.5\plugins\").
To ease your job a script for AviSynth (QMlib.avsi) is provided: it generates the statfile using MVtools libraries.
To create the statfile you need to write an AviSynth script that decodes the video stream and apply minimum filters to measure motion calling the statfile generator function.
From MVtools website you can read that only progressive stream can be analyzed and those must use YV12/YUY2 color format. Also QMlib.avsi allows only YV12, then the minimum filtering usually is:
At this step is not necessary to apply other filters, unless you really need a more precise motion measurement (and usually you don't).
A script example:
LoadPlugin("DGDecode.dll") LoadPlugin("C:\Programs\AviSynth 2.5\plugins\MVtools.dll") Import("QMlib.avsi") Mpeg2Source("VTS_01.d2v") Spline16Resize(576,432,10,4,-20,-2)
On the script tail you add the call to the functions provided in QMlib.avsi: QMwritesub(), QMstack() e QMwritefile().
The analysis is made with respect to the next frame: for the frame #0 the motion is measured between frame #0 and frame #1.
The functions have this syntax:
The parameters are:
For most videos, the default values for Ysc, thSCD1 e thSCD2 are adequate. Please refer also to MVtools documentation for more information about these parameters.
Our script producing the statfile for QMtrim will become something like:
LoadPlugin("DGDecode.dll") LoadPlugin("C:\Programs\AviSynth 2.5\plugins\MVtools.dll") Import("QMlib.avsi") Mpeg2Source("VTS_01.d2v") Spline16Resize(576,432,10,4,-20,-2) QMwritefile(statfile="StatFile.txt")
To generate the statfile you'll have to allow AviSynth to process the whole video in a single step, starting from the first frame to the last. Then, if you use VirtualDubMod, play the video from the beginning and leave it complete the playback until the end; it's easy to corrupt the statfile by seeking and playing as much as a few frames. When done, close the application and get the statfile.
Now QMtrim has the information needed to generate the trim sequence.
QMtrim was initially written as a command line tool and can still be used as such. Moreover now you can use its GUI. The parameters used when you launch it, will be proposed in the GUI to be used or modified; if you launch QMtrim without parameters, the GUI will have default values.
Below the parameter list:
First of all you have to define how many levels of filtering you want: 3-4 levels manage most videos, AvsOptimizer uses 10 levels, for more precise optimization you can use 32 levels of filtering. QMtrim support up to 250 levels.
The number of levels defined, you decide which type of distribution you want to start with: by quotas or by thresholds.
The distribution by thresholds is a growing sequence of values that correspond directly to those you have in the statfile, that is: motion values. Each frame will be assigned to the corresponding level depending on its motion value. Each level n will have frames with motion between the n-1-th value of the distribution and the n-th value. Specifically the first level will have motion below the first value of the distribution and frames with motion above the last values will be still assigned to the last level. Below is an example:
|Level||Threshold||Frame assigned to this level|
|0||10||Those with motion between 0 and 10 included|
|1||20||Those with motion above 10 and up to 20|
|2||50||Those with motion above 20 and up to 50|
|3||80||Those with motion above 50|
The distribution by quotas requires a set of values indicating which quota of frames will be assigned to each level. It will be QMtrim job to find the right threshold values to use to achieve this result. It does not matter what absolute values you use as quota, just what value is each with respect to the others in the distribution. Below are three examples of equivalent quota:
|Level||Ex. 1||Ex. 2||Ex. 3||Frame assigned to this level|
|0||1||0.125||3||12.5% of frames|
|1||2||0.25||6||25% of frames|
|2||3||0.375||9||37.5% of frames|
|3||2||0.25||6||25% of frames|
Then the distribution on the command line will define motion value thresholds if the flag -t (or --thresholds) is present and quotas otherwise.
The values must be specified in growing level order and must be separated by comma (,) semicolon (;) or space, using the dot (.) as decimal separator.
The default distribution (1,1,1,1,1,1,1,1,1,1) has 10 identical quotas that will assign 10% of frames to each filtering level. It's equally possible to achieve a flat distribution with an arbitrary number of levels with option -f (or --flat-distrib) followed by the number of levels.
Other two parameters are used to refine the analysis: unsaw e cxrest.
The unsaw parameter modifies the statfile sequence of values to cut peaks. QMtrim analyzes a window of unsaw_val frames and define a limit as the maximum value found on the window edges; every values inside this window must be less that this limit, otherwise they will be set to the limit itself. The higher unsaw_val the wider the window that will cut the peaks. A similar algorithm will be applied anyway, also with unsaw_val = 0: every value above both the previous and the next frame will be reduced to their average.
The cxrest parameter, instead, modifies the trim sequence by delaying too fast filter change. Basically cxrest_val define for how many frames the filtering level cannot increase, to avoid the eyes notice an image is becoming more rough. Decreasing the filtering level, instead, will be freely allowed.
The GUI displays every parameter described above and shows more useful information about the distribution and frame assignment, and allow the user to operate a set of functions.
The statfile name is shown, followed by the button used to open another file and to reload the file whether it has been modified (QMtrim avoid to read it every time, and you must explicitly reload it).
The parameters unsaw and cxrest follow with the check box thresholds indicating whether you are providing a set of thresholds or quotas.
The distribution table looks like the one printed by the previous version of QMtrim. You can add/remove levels, setup a flat distribution with a number of levels of your choice (option -f or --flat-distrib) or redistribute quotas with an automatic algorithm(*).
The table shows the following information:
Under the distribution you have the buttons for: copying the table values in a sequence of tab-separated fields, copying in the clipboard the command line to use to setup the current GUI, generating the trim sequence.
The trim sequence follows with fields to save the result: trimfile name, button to choose the trimfile, save button.
The status bar on the bottom will provide information on the execution, missing data needed to proceed and suggestions about how to use the dialog.
(*) The automatic redistribution of quotas let you achieve a better assignment of levels and can be done as follows:
The trim sequence will be something like (usually much longer):
C0.Trim(0,10)+C1.Trim(11,16)+C2.Trim(17,23)\ +C3.Trim(24,29)+C4.Trim(30,32)+C3.Trim(33,33)\ +C4.Trim(34,39)+C5.Trim(40,45)+C6.Trim(46,49)
To use it you should have defined the filter for each level and called the result Cn where n is the level number. The trim sequence can be manually inserted into your script after copying it from the text box or simply by including the trimfile in your script. An example with filter definition followed by the trim sequence is:
# filters C0 = clip.Spline36Resize(XRES,YRES,X0,Y0,X1,Y1) C1 = clip.Spline16Resize(XRES,YRES,X0,Y0,X1,Y1) C2 = clip.GaussResize(XRES,YRES,X0,Y0,X1,Y1,p=80) C3 = clip.GaussResize(XRES,YRES,X0,Y0,X1,Y1,p=70) C4 = clip.GaussResize(XRES,YRES,X0,Y0,X1,Y1,p=60) C5 = clip.GaussResize(XRES,YRES,X0,Y0,X1,Y1,p=50) C6 = clip.GaussResize(XRES,YRES,X0,Y0,X1,Y1,p=40) C7 = clip.GaussResize(XRES,YRES,X0,Y0,X1,Y1,p=30) C8 = clip.GaussResize(XRES,YRES,X0,Y0,X1,Y1,p=20) C9 = clip.GaussResize(XRES,YRES,X0,Y0,X1,Y1,p=10) # trim generated by QMtrim Import("C:\qmtrim\QMtrim\trim.avsi")
On SourceForge you can use:
The aim of the prototype (0.7.7) was to wrap the original tool in a GUI and fix issues without too much care about how the code was developed.
The next version (0.8) will be a real beta to start with.
At the moment I'm rewriting everything to have:
- a standard GUI;
- every function in v0.7.7;
- (possibly) a GNU/Linux release.
In the future (it's not a promise!) some of the following could be added:
- support for processing different range of frames with different distribution (static filter included);
- save/load configuration;
- hints to guide first time users.