Welcome to Doom9's Forum, THE in-place to be for everyone interested in DVD conversion.

Before you start posting please read the forum rules. By posting to this forum you agree to abide by the rules.

 

Go Back   Doom9's Forum > Announcements and Chat > General Discussion

Reply
 
Thread Tools Search this Thread Display Modes
Old 9th October 2017, 18:14   #1  |  Link
FranceBB
Broadcast Encoder
 
FranceBB's Avatar
 
Join Date: Nov 2013
Location: Royal Borough of Kensington & Chelsea, UK
Posts: 2,869
Automatic Video Analyzer (luma values, chroma values etc)

Hi,
I'm looking for an Automatic Video Analyzer, which analyses both video and audio of an encoded file and gives me results: whether luma and chroma are out of range (Tv Range) or not, whether the audio loudness is too high or not (-24LUFS is the broadcast standard), whether there are many dialogues or not (mainly music for instance), and finally if there are many still footages or if it's dynamic.

I've been using Cerify (provided by Tektronix) so far, but it seems it doesn't quite do what I want. (it partially does it).
The main reason why I'm asking this, is not to test encoded files to see whether they are within the standard or not, but to divide them into categories.
For instance, if a movie is shot during the night, for instance, I'm gonna have a very low luma (with lots of black scenes). On the other hand, if a movie is mainly shot outside during the day, luma value is gonna be high. That's what I'm interested in, 'cause it falls into automation and that's what marketing asked me. But... I'm an encoder, so I don't know how to get these values automatically unless I manually spot-check the movie with a videoscope (I obviously can't do that).
Any thoughts? Is there a way to get these values (according to personalized thresholds, perhaps)?

Thank you in advance.

Last edited by FranceBB; 9th October 2017 at 18:17.
FranceBB is offline   Reply With Quote
Old 9th October 2017, 19:59   #2  |  Link
ChaosKing
Registered User
 
Join Date: Dec 2005
Location: Germany
Posts: 1,795
https://www.clarifai.com/demo

See last example

and https://forum.doom9.org/showthread.php?t=174933
__________________
AVSRepoGUI // VSRepoGUI - Package Manager for AviSynth // VapourSynth
VapourSynth Portable FATPACK || VapourSynth Database
ChaosKing is offline   Reply With Quote
Old 10th October 2017, 00:28   #3  |  Link
raffriff42
Retried Guesser
 
raffriff42's Avatar
 
Join Date: Jun 2012
Posts: 1,373
Quote:
Originally Posted by FranceBB View Post
The main reason why I'm asking this, is not to test encoded files to see whether they are within the standard or not, but to divide them into categories.
For instance, if a movie is shot during the night, for instance, I'm gonna have a very low luma (with lots of black scenes). On the other hand, if a movie is mainly shot outside during the day, luma value is gonna be high. That's what I'm interested in, 'cause it falls into automation and that's what marketing asked me.
Creating video fingerprints aka movie barcodes:

...seems like a good way to communicate the general look and feel of a film in a way that marketing guys can understand.
(the multicolored bar grows from left to right as the video plays)

https://forum.doom9.org/showthread.php?t=167769
https://forum.doom9.org/showthread.p...69#post1799769

Code:
##################################
# Trailer Fingerprint: How? Is it even possible? 
# http://forum.doom9.org/showthread.php?t=167769

## http://forum.doom9.org/showthread.php?p=1626707#post1626707
## (note: long load time)
##
function fingerprint_1(clip src, int "fingerprint_height")
{
    fph = Default(fingerprint_height, 32)
    
    w = Width(src)
    v = Crop(src, 8, 8, -8, -8)
    v = BicubicResize(v, 640, 360)
    calc = FrameRate(v) * w / Framecount(v)
    v = ChangeFPS(v, calc, linear = false).Trim(0, -w)
    v = ConvertToRGB32(v).BicubicResize(4, 4).Blur(0.65).BilinearResize(2, 2)
    
    a = Crop(v, 0, 0, -1, -1)
    b = Crop(v, 1, 0, 0, -1)
    c = Crop(v, 0, 1, -1, 0)
    d = Crop(v, 1, 1, 0, 0)
    x = Overlay(a, b, mode="blend", opacity=0.5)
    y = Overlay(c, d, mode="blend", opacity=0.5)
    v = Overlay(x, y, mode="blend", opacity=0.5)
    v = PointResize(v, 1, fph)
    v = WeaveColumns(v, w).Converttoyv12()
    bg = BlankClip(Width=w, Height=fph)
    v = StackVertical(src, v)
    
    Function ovl(clip c1, clip c2, int xx, int yy) { 
    \    Overlay(c1, c2 , xx , yy) 
    \  }

    v = Animate(v, 0, src.framecount+1, "ovl", 
    \  bg, 0, src.Height,   
    \  bg, src.Width, src.Height)
    return v
}
raffriff42 is offline   Reply With Quote
Old 10th October 2017, 00:54   #4  |  Link
FranceBB
Broadcast Encoder
 
FranceBB's Avatar
 
Join Date: Nov 2013
Location: Royal Borough of Kensington & Chelsea, UK
Posts: 2,869
@raffriff42... thanks! Well, it kinda is. I also started implementing something kinda nice that I think they'll use.
It basically gets the average luma value of each frame through avisynth, writes every value to a text file and then a program in C# reads these values, and uses these values to get the average value of the whole movie, then checks whether it's within a certain threshold and outputs a result:

1) "The average value is xxx, this movie develops during the night"
2) "The average value is xxx, this movie has some dark/night scenes"
3) "The average value is xxx, this movie has some bright/morning scenes"
4) "The average value is xxx, this movie develops during the daylight"

Avisynth Script:
Code:
FFVideoSource("test.mxf")

PointResizeMT(704, 396)
ScriptClip(Last, """
    threshold = 55
    luma = AverageLuma ## gives the average luma of the current frame
    #luma = AverageLuma(1) ## gives the average luma of the next frame
    luma < threshold 
    \ ? Levels(0, 1.0+0.5*(threshold-luma)/threshold, 255, 0, 255) 
    \ : last
    Subtitle("luma=" + String(luma), align=2)
    
    filename = "C:\Documents and Settings\l\Desktop\luma.txt"
    
    WriteFile(filename, "luma")
    
""")
C# Program:

Code:
using System;
using System.Collections.Generic;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.Common;
using System.IO;

namespace VideoAnalyzer
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            button1.Click += button1_Click;
            button2.Click += button2_Click;
            button3.Click += button3_Click;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
        }


            public void button1_Click(object sender, EventArgs e)
        {
            string text = File.ReadAllText(@"c:\VideoAnalyzer\NomeFile.ini", Encoding.UTF8);
                
            System.Diagnostics.Process.Start("explorer.exe", @text);
        }

        public void button2_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process.Start("explorer.exe", @"c:\VideoAnalyzer\processer.bat");
        }

        private void button3_Click(object sender, EventArgs e)
        {
            //string text = File.ReadAllText(@"c:\VideoAnalyzer\luma.txt", Encoding.UTF8);
            string[] text = System.IO.File.ReadAllLines(@"c:\VideoAnalyzer\luma.txt", Encoding.UTF8);
            //int[] values = text.Select((l) => int.Parse(l)).ToArray();
            float[] values = text.Select((l) => float.Parse(l)).ToArray();
            double average = values.Average();
            float peak = values.Max();

            string valoremedio = average.ToString();
            
            if (average >= 0 && average <= 37)
            {
                MessageBox.Show("The average value is  " + valoremedio + "\n" + "this movie develops during the night");
            }

            if (average >= 38 && average <= 98)
            {
                MessageBox.Show("The average value is  " + valoremedio + "\n" + "this movie has some dark/night scenes");
            }

            if (average >= 99 && average <= 140)
            {
                MessageBox.Show("The average value is  " + valoremedio + "\n" + "this movie has some bright/morning scenes");
            }

            if (average >= 141 && average <= 255)
            {
                MessageBox.Show("The average value is  " + valoremedio + "\n" + "this movie develops during the daylight");
            }

            //MessageBox.Show(peak);

            /*
            string[] entries = Directory.GetFileSystemEntries(text, "*", SearchOption.AllDirectories);
            foreach (string value in entries)
            {
                string numeroluma = Path.GetFileNameWithoutExtension(value);
                ListViewItem item = new ListViewItem(numeroluma);

            }
            */





        }



        }
    }
FranceBB is offline   Reply With Quote
Old 10th October 2017, 03:42   #5  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
ShowChannels, http://forum.doom9.org/showthread.php?t=163829

Code:
ShowChannels()

(c) 2012 StainlessS

Plugins for Avisynth v2.5 & v2.6

Planar, YUY2 and RGB.

Simple plugin whose only function is to display the average Y,U and V 
values for a YUV frame or R,G, and B for an RGB frame.
Also shows accumulated average for all frames visited so far.

Typical output for a YUV clip:-
---------------------------

347 ] Frames Visited = 348

          This Frame           Accumulated
       Y     U      V        Y     U      V
 Ave  77.00 125.52 125.42   70.91 125.87 125.78
 Min   4     80     95       0     69     83
 Max 255    177    165     255    190    174
~Min  14     95    101      12     92    101
~Max 234    167    148     235    167    151

---------------------------

where
 'AVE' shows average for current frame and accumulated average for all visited frames.

 'MIN' shows minimum value for a channel, this frame and accumulated.

 'MAX' shows maximum value for a channel, this frame and accumulated.

 '~MIN' shows loose minimum value for a channel, this frame and accumulated.

 '~MAX' shows loose maximum value for a channel, this frame and accumulated.

Loose minimum uses the filter arg float MinPerc, a percentage of total pixels to ignore
when finding the loose minimum, allows to ignore extreme stray pixels (noise).

Loose maximum uses the filter arg float MaxPerc, a percentage of total pixels to ignore
when finding the loose maximum, allows to ignore extreme stray pixels (noise).

The "loose" values are made to filter out very bright
or very dark noise creating an artificially low or high minimum / maximum.

The Accumulated Ave is a "Average of Averages", or "Average Mean" or "Mean Average", take your pick but accumulated seemed more appropriate
considering that it was not restricted to describing just the averages. Accumulated Min is the minimum of all minimums so far, etc.
      
Usage:-

ShowChannels(clip c,float "MinPerc"=0.1, float "MaxPerc"=0.1, bool "ver"=false,bool "Setvar"=false,String "Prefix"="SC_", \
         bool "Show"=true,String ="AccFile"="",int "x"=0,int "y"=0,int "w"=0,int "h"=0,bool "Interlaced"=false)

  Where:-
    c is the clip

    MinPerc is percentage of pixels to ignore for loose minimum. (default 0.1%, ie 1/1000 of total pixels)
    ColorYUV (Analyze=true) Loose Minimum ignores 1/256 of the darkest pixels, and ShowChannels 0.1% or 1/1000 by default,
    so a Minperc of 0.4% would be about the same as ColorYUV uses.

    MaxPerc is percentage of pixels to ignore for loose maximum. (default 0.1%, ie 1/1000 of total pixels)
    ColorYUV (Analyze=true) Loose Maximum ignores 1/256 of the lightest pixels, and ShowChannels 0.1% or 1/1000 by default,
    so a Maxperc of 0.4% would be about the same as ColorYUV uses.

    ver display version info, false OFF [default] , true ON

    Setvar if true then sets Global Variables using Prefix string.

    Prefix (default "SC_"), prefix to Global variable names when using SetVar.

    Show, false switches off normal text display, you may want to set false if using SetVar.

    AccFile, default "", name of text file to output final Accumulated values for entire file.

    x,y,w,h, sets coordinates, all default to 0 as for crop, ie full image. NOT colorspace limited, eg can use odd values
      even for YV12 and YUY2.

    Interlaced (default false). Planar formats only, alters interpretation for the chroma, false=Progressive, true=interlaced.

    Default Global variable names when SetVar=true and using Default Prefix = "SC_"

      "SC_Visited"    = Frames visited
    
      Channel 0 (Y or R)
      "SC_Ave_0","SC_Min_0","SC_Max_0","SC_LMn_0","SC_LMx_0","SC_AAve_0","SC_AMin_0","SC_AMax_0","SC_ALMn_0","SC_ALMx_0",
      Channel 1 (U or G, NOT Y8)
      "SC_Ave_1","SC_Min_1","SC_Max_1","SC_LMn_1","SC_LMx_1","SC_AAve_1","SC_AMin_1","SC_AMax_1","SC_ALMn_1","SC_ALMx_1",
      Channel 2 (V or B, NOT Y8)
      "SC_Ave_2","SC_Min_2","SC_Max_2","SC_LMn_2","SC_LMx_2","SC_AAve_2","SC_AMin_2","SC_AMax_2","SC_ALMn_2","SC_ALMx_2",
    
      For Y8, channels 1 and 2 will all be set to -1
--------------------------------------------------------------------------------
Typical Global Variable settings for RGB something like:-

    SC_Ave_0=124.55    SC_Ave_1=126.06    SC_Ave_2=199.77
    SC_Min_0=0         SC_Min_1=0         SC_Min_2=0
    SC_Max_0=255       SC_Max_1=255       SC_Max_2=255
    SC_LMn_0=0         SC_LMn_1=0         SC_LMn_2=0
    SC_LMx_0=255       SC_LMx_1=255       SC_LMx_2=255
    SC_AAve_0=129.24   SC_AAve_1=132.12   SC_AAve_2=126.68
    SC_AMin_0=0        SC_AMin_1=0        SC_AMin_2=0
    SC_AMax_0=255      SC_AMax_1=255      SC_AMax_2=255
    SC_ALMn_0=0        SC_ALMn_1=0        SC_ALMn_2=0
    SC_ALMx_0=255      SC_ALMx_1=255      SC_ALMx_2=255
--------------------------------------------------------------------------------
Contents of AccFile for a small sample clip showing typical output using defaults:

SC_AAve_0=98.971779  SC_AMin_0=0  SC_AMax_0=255 SC_ALMn_0=14  SC_ALMx_0=241 
SC_AAve_1=122.572746 SC_AMin_1=66 SC_AMax_1=200 SC_ALMn_1=99  SC_ALMx_1=160 
SC_AAve_2=137.286911 SC_AMin_2=72 SC_AMax_2=209 SC_ALMn_2=108 SC_ALMx_2=175 
SC_Visited=4000 

--------------------------------------------------------------------------------

Lastly, you may find it better to crop off any borders when ascertaining frame/accumulated values, or set coordinates to suit.

ssS
Any good ?

EDIT: Also ClipBlend(delay=0):- http://forum.doom9.org/showthread.php?t=168048
Code:
ClipBlend(clip,"delay"=0)       # 8 bit Planar, YUY2, RGB
ClipBlend16(clip,"delay"=0)     # 16 bit, Stack16 Planar, YUY2, RGB (see Dither Tools)

Added Delay arg to plugin.

Delay, default = 0, == ALL frames played so far blended.

1  = blend with previous frame ie two frames blended.
10 = blend with 10 previous frames, ie 11 frames blended, etc.

Accumulator resets at frame 0.

To get average of all frames 0 to frame 300
# ------------------------
FRM =300                    # Required frame number
Avisource("D:\avs\test.avi")
ClipBlend()                 # Default delay=0 ie all previous frames
Trim(FRM,-1)                # Get Required frame
return Last
# ------------------------

Or to get a single frame average of all frames in a clip
# ------------------------
Avisource("D:\avs\test.avi")
ClipBlend()
return Trim(FrameCount-1,-1)
# ------------------------


How ClipBlend it works

ClipBlend() uses a single 32 bit accumulator (unsigned int) for each channel of each pixel x,y position in the clip frame.
With a maximum possible value per pixel/channel being 255 ie 8 bits, this leaves 24 bits available for accumulating
the sum of values for that pixel/channel position, ie adding the values for that pixel/channel from every selected frame
in the blended range. The additional 24 bits would allow for up to ~16 Million (2^24) frames to be summed, however we also
need another bit to maintain maximum precision possible for 8 bit result, so reducing maximum possible frame range to
~8 million frames.

Code:

Return Avisource("test.avi").ClipBlend(delay=0).Trim(999,-1)  # 1000 frames, 1000 values per accumulator, ie max 1000*255

Above would sum (each channel/pixel) with maximum possible sum for an accumulator being 1000*255 (about 18 bits, 2^10=1024,2^8=256)
As clipblend scans frames, it adds the channel/pixel values at each x,y position to the accumulators, for all of the
required frames. If delay = 0, it just adds next frame values to the accumulators. If eg delay=10, and current scanned range is already
10, it subtracts the channel/pixel values of the oldest frame (lowest number) and then adds the values for the next frame to the
accumulators. When delivering the result (delay=whatever), it just divides the accumulated sum by the number of sample frames to
get the average, and writes it to the relevant pixel/channel/x/y position, could not be simpler.

Implementation is equivalent to this:

int(accumulator / Float(FramesDone) + 0.5)

The actual implementation and reason for the extra needed bit that was mentioned (ie accumulator*2):

((accumulator*2) + FramesDone) / (FramesDone*2)

The *2 pair and addition of FramesDone is the integer equivalent of division, adding 0.5 and taking Int() whist maintaining max possible
precision at 8 bits result.
All blended frames given equal weight.
__________________
I sometimes post sober.
StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace

"Some infinities are bigger than other infinities", but how many of them are infinitely bigger ???

Last edited by StainlessS; 10th October 2017 at 14:34.
StainlessS is offline   Reply With Quote
Old 10th October 2017, 22:40   #6  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
A Different take, dont know if of any use at all.

SequenceAverage.avs (if separate scripts, need Import)
Code:
/*
    SequenceAverage.avs
    Returns a clip of n sequences, where every frame in each sequence is average color of all frames in source clip sequence.

    Req:-
        GScript, Grunt, (c) Gavino.
        RT_Stats v1.43, ClipBlend, CallCmd(if Auto Delete DB required), (c) StainlessS.

*/

GSCript("""
    ###### DBase Field Numbers
    Global DB_IsVALID   = 0     # Bool, true= Record Valid
    Global DB_START_FLD = 1     # Int, START frame field
    Global DB_END_FLD   = 2     # Int, END frame Field
    Global DB_COLOR_FLD = 3     # Int, Color
    # DBase ID Index, basic clip validation.
    Global DB_IsYUV_ID  = 0     # Int, 0=RGB : 1=YUV
    Global DB_FRMS_ID   = 1     # Int, Framecount of input clip
    Global DB_WIDTH_ID  = 2     # Int, Width of input clip
    Global DB_HEIGHT_ID = 3     # Int, Height of input clip
    Global DB_REC_ID    = 4     # Int, Initialized Record Sequences
    #  User Attributes, Debug On Frame and to Debugview
    Global DB_DBUG_ATTR = 0     # Int, 1 = DEBUG
    # User String Attributes Index
    Global DB_NAME_STR  = 0     # String, Optional clip name for whatever use.
    ######

    Function PrepDBase(clip c,String DB,Int Records,String "ClipName",Bool "Debug",Bool "PreScan") {   # Initialize DBase, Optional PreScan
        myName="PrepDBase: "
        Debug   = Default(Debug,False)
        PreScan = Default(PreScan,False)    # If True, then force Prescan producing Valid DBase on function exit, Function returns PreScan Status.
        Assert(DB!="",RT_String("%sNeed DBase name",myName))
        Frms = c.FrameCount
        Assert(0 < Records <= Frms,RT_String("%s0 < Records(%d) <= c.FrameCount(%d)",myName,Records,Frms))
        (Debug) ? RT_DebugF("Allocating DBase of %d Sequences/Records for %d frame clip",Records,Frms,name=myName) : NOP
        RT_DBaseAlloc(DB,Records,"biii")     # Bool, Int, Int, Int
        MaxFramesPerRecord = Ceil(Float(Frms) / Records)
        (Debug) ? RT_DebugF("MaxFramesPerRecord =%d",MaxFramesPerRecord,name=myName) : NOP
        E=-1
        for(rec=0,Records-1) {
            S = E + 1
            E = Min(S + MaxFramesPerRecord,Frms) - 1
            RT_DBaseSetField(DB,rec,DB_START_FLD,S)
            RT_DBaseSetField(DB,rec,DB_END_FLD,  E)
            (DEBUG) ? RT_DebugF("%d} [%d,%d] (%d Frames)",rec,S,E,E-S+1,Name=myName) : NOP
        }
        RT_DBaseSetID(DB,DB_IsYUV_ID,  c.IsRGB?0:1)
        RT_DBaseSetID(DB,DB_FRMS_ID,   c.FrameCount)
        RT_DBaseSetID(DB,DB_WIDTH_ID,  c.Width)
        RT_DBaseSetID(DB,DB_HEIGHT_ID, c.Height)
        RT_DBaseSetID(DB,DB_REC_ID,    Records)         # Number of records that are properley initialized.
        ClipName=Default(ClipName,"")                   # Optional clip name to store in user strings
        RT_DBaseSetStrAttrib(DB,DB_NAME_STR,ClipName)   # Set Clipname
        RT_DBaseSetAttrib(DB,DB_DBUG_ATTR,Debug?1:0)    # Set DEBUG Status
        if(PreScan) {for(rec=0,Records-1) {DBaseSetSeqColor(c,DB,rec)}}     # PreScan, so the DBase is fully valid before function exit.
        return PreScan                                  # Returns PreScan Status
    }

    Function DB_FindTrim(String DB,Int S_Field,Int E_Field,Int Frame) { # DB_FindTrim Returns clip (or record number) containing movie frame Frame.
        # NOTE, This script function replaced in RT_Stats v2.0, by plugin version RT_DBaseFindSeq().
        result = -1                                                     # Init NOT FOUND
        low     = 0
        high    = RT_DBaseRecords(DB) - 1
            while(low <= high) {
                mid = (low + high) / 2
                if(RT_DBaseGetField(DB,mid,E_Field) < Frame)        { low = mid + 1 }
                Else If (RT_DBaseGetField(DB,mid,S_Field) > Frame)  {high = mid - 1 }
                Else                                                {low = high + 1  Result = mid }
            }
        return result
    }

    Function DBaseClipCheck(clip c, String DB,String "OptNam") { # Basic check c corresponds with DBase clip
        OptNam=Default(OptNam,"")
        myName="DBaseClipCheck:"+(OptNam!=""?":"+OptNam:" ")
        if(RT_DBaseGetID(DB,DB_IsYUV_ID)!=(c.IsRGB?0:1))     {S=RT_String("%sDB_IsYUV_ID Invalid for clip",myName)  RT_DebugF("%s",S)   Assert(false,S)}
        if(RT_DBaseGetID(DB,DB_FRMS_ID)!=c.FrameCount)       {S=RT_String("%sDB_FRMS_ID Invalid for clip",myName)   RT_DebugF("%s",S)   Assert(false,S)}
        if(RT_DBaseGetID(DB,DB_WIDTH_ID)!=c.Width)           {S=RT_String("%sDB_WIDTH_ID Invalid for clip",myName)  RT_DebugF("%s",S)   Assert(false,S)}
        if(RT_DBaseGetID(DB,DB_HEIGHT_ID)!=c.Height)         {S=RT_String("%sDB_HEIGHT_ID Invalid for clip",myName) RT_DebugF("%s",S)   Assert(false,S)}
        if(RT_DBaseGetID(DB,DB_REC_ID)!=RT_DBaseRecords(DB)) {S=RT_String("%sDB_REC_ID Invalid",myName)             RT_DebugF("%s",S)   Assert(false,S)}
        return True
    }

    Function DBaseSetSeqColor(clip c, String DB,Int rec) { # Set Averge color for seqence/record
        myName="DBaseSetSeqColor: "
        Records = RT_DBaseRecords(DB)
        if(!(0 <= rec < Records))           {S=RT_String("%s0 <= rec(%d) < Records(%d)",myName,rec,Records)  RT_DebugF("%s",S)  Assert(false,S)}
        DBaseClipCheck(c,DB,myName)
        IsValid   = RT_DBaseGetField(DB,rec,DB_IsVALID)     # Have we used Clipblend on this range yet ?
        if(!IsValid) {
            Start_Frm = RT_DBaseGetField(DB,rec,DB_START_FLD)
            End_Frm   = RT_DBaseGetField(DB,rec,DB_END_FLD)
            DBUG = (RT_DBaseGetAttrib(DB,DB_DBUG_ATTR) != 0)
            # (DBUG) ? RT_DebugF("%d} [%d,%d] Getting sequence color",rec,Start_Frm,End_Frm,name=myName) : NOP
            nFrames = End_Frm - Start_Frm + 1               # Avoid End_Frm==0 prob.
            Tmp_C = c.Trim(Start_Frm,-nFrames)
            Tmp_C = Tmp_C.ClipBlend(Delay=0).Trim(nFrames-1,-1)   # Average entire range, quick
            nchans = Tmp_C.RT_ChanAve(n=0)                  # Get chan averages as locals (will be integer floats)
            ch0=Int(RCA_Ave_0)  ch1=Int((nchans!=1)?RCA_Ave_1:128)  ch2=Int((nchans!=1)?RCA_Ave_2:128)
            Col=(ch0*256+ch1)*256+ch2
            RT_DBaseSetField(DB,rec,DB_COLOR_FLD,Col)       # Y8 Set as $XX8080
            RT_DBaseSetField(DB,rec,DB_IsVALID,True)        # Now Valid
            (DBUG) ? RT_DebugF("%d} [%d,%d] Setting sequence color=$%0.6X",rec,Start_Frm,End_Frm,Col,name=myName) : NOP
        }
        return True
    }

    Function GetAveColor(clip c, String DB, Int Frm) {      # Find Average Color of Frame, returning Int
        myName="AveColor: "
        rec=DB_FindTrim(DB,DB_START_FLD,DB_END_FLD,Frm)
        if(!(rec>=0)) {S=RT_String("%sDB_FindTrim could not find record for frame %d",myName,Frm)  RT_DebugF("%s",S)  Assert(false,S)}
        IsValid   = RT_DBaseGetField(DB,rec,DB_IsVALID)     # Have we used ClipBlend on this range yet ?
        (!IsValid) ? DBaseSetSeqColor(c,DB,rec) : NOP       # Set Dbase for current sequence/record
        col = RT_DBaseGetField(DB,rec,DB_COLOR_FLD)
        return Col
    }

    Function GetAveColorFrame(clip c, String DB, Int Frm) {  # Return frame, that is Average color of its record/sequence (Same frame type/size as clip c)
        col = GetAveColor(c,DB,Frm)
        (c.IsRGB) ? c.BlankClip(Length=1,color=col) : c.BlankClip(Length=1,color_yuv=col)
        DBUG = (RT_DBaseGetAttrib(DB,DB_DBUG_ATTR) != 0)    # DBUG Status
        (DBUG)
            \ ? RT_Subtitle("%d/%d] Seq=%d/%d Col=$%0.6X\n'%s'",
            \       Frm,c.FrameCount-1,DB_FindTrim(DB,DB_START_FLD,DB_END_FLD,Frm),RT_DBaseRecords(DB)-1,col,RT_DBaseGetStrAttrib(DB,DB_NAME_STR))
            \ : NOP
        return Last
    }

    Function ShortSequenceClip(clip c, String DB,Bool "Debug") {  # Return clip with Single Frame Average for each Sequence (no audio).
        myName="ShortSequenceClip:"
        Debug=Default(Debug,False)                  # Function Specific Debug
        DBaseClipCheck(c,DB,myName)                 # Check DB OK
        Records=RT_DBaseRecords(DB)
        cret=c.BlankClip(Length=0)
        for(rec=0,records-1) {
            (!RT_DBaseGetField(DB,rec,DB_IsVALID)) ? DBaseSetSeqColor(c,DB,rec) : NOP   # Scan if Necessary
            Start_Frm = RT_DBaseGetField(DB,rec,DB_START_FLD)                           # start frame of this sequence
            End_Frm = RT_DBaseGetField(DB,rec,DB_END_FLD)                               # end frame of this sequence
            col = GetAveColor(c,DB,Start_Frm)                                           # Average color of the sequence
            (c.IsRGB) ? c.BlankClip(Length=1,color=col) : c.BlankClip(Length=1,color_yuv=col)
            (DEBUG)
                \ ? RT_Subtitle("ShortSeq:\n%d/%d} S=%d E=%d Len=%d Col=$%0.6X\n'%s'",
                \       rec,Records-1,Start_Frm,End_Frm,End_Frm-Start_Frm+1,col,RT_DBaseGetStrAttrib(DB,DB_NAME_STR))
                \ : NOP
            cret = cret ++ Last                                                           # Add to Clip so far/
        }
        return cret.KillAudio
    }
""")
Client DEMO script
Code:
# Client Script, Several Demo uses rolled into one.
#Import("SequenceAverage.avs")
##### CONFIG #####
FileName  = "D:\TEST.AVI"
DB        = "MyDBase.DB"        # DBase Name
OUTLOG    = "MyLog.Log"         # Demo Log
SEQUENCES = 25                  # Average clip into SEQUENCES number of sequences
DEBUG     = True                # Some Debug Stuff
PRESCAN   = False               # Whether or not to scan and fully prep DBase prior to clip play. (Better if True)
SHORTSEQ  = False               # If True then generate only single frame for each sequences, else use Scriptclip
DEL_DB    = False               # Delete DBase on clip closure, Requires CallCmd if True
### End CONFIG ###

FileName  = (FileName!="") ? RT_GetFullPathName(FileName) : FileName
DB        = (DB!="")       ? RT_GetFullPathName(DB)       : DB        # Make sure is full filename incl Drive and path nodes
OUTLOG    = (OUTLOG!="")   ? RT_GetFullPathName(OUTLOG)   : OUTLOG
Assert(FileName!="","Need FileName")
Assert(DB!="","Need DB")

########################

AVISource(FileName)
Trim(0,-1000)                   # 1000 Frame test clip
#BiCubicResize(640,480)         # Whatever

PrepDBase(DB,SEQUENCES,ClipName=FileName,Debug=DEBUG,PreScan=PRESCAN)   # Prepare DB

GScript("""
    # Demo usage to access Fully PreScanned DBase, for whatever reason
    if(PRESCAN && OUTLOG !="") {
        RT_FileDelete(OUTLOG)   # Del Existing, log file
        RT_WriteFile(OUTLOG,"FileName='%s'",FileName,Append=True)
        RT_WriteFile(OUTLOG,"DB      ='%s'",DB,Append=True)
        RT_WriteFile(OUTLOG,"SEQS    = %d",  SEQUENCES,Append=True)
        RT_WriteFile(OUTLOG,"IsYUV   = %s",  RT_DBaseGetID(DB,DB_IsYUV_ID)!=0,Append=True)      # Bool is printed as a String
        RT_WriteFile(OUTLOG,"FrmCnt  = %d",  RT_DBaseGetID(DB,DB_FRMS_ID),Append=True)
        RT_WriteFile(OUTLOG,"Width   = %d",  RT_DBaseGetID(DB,DB_WIDTH_ID),Append=True)
        RT_WriteFile(OUTLOG,"Height  = %d",  RT_DBaseGetID(DB,DB_HEIGHT_ID),Append=True)
        RT_WriteFile(OUTLOG,"Records = %d",  RT_DBaseRecords(DB),Append=True)                   # Same As SEQUENCES
        RT_WriteFile(OUTLOG,"ClipName='%s'",RT_DBaseGetStrAttrib(DB,DB_NAME_STR),Append=True)  # Internally stored DBase clip name
        RT_WriteFile(OUTLOG,"DEBUG   = %d",  RT_DBaseGetAttrib(DB,DB_DBUG_ATTR),Append=True)    # Internally stored Debug, 0=False, 1=True
        RT_WriteFile(OUTLOG,"\n",Append=True)                                                   # Blank Line
        for(i=0,SEQUENCES-1) {
            RT_WriteFile(OUTLOG,"%d} [%d,%d:Len=%d] Color=$%0.6X",
                \ i,
                \ RT_DBaseGetField(DB,i,DB_START_FLD),
                \ RT_DBaseGetField(DB,i,DB_END_FLD),
                \ RT_DBaseGetField(DB,i,DB_END_FLD)-RT_DBaseGetField(DB,i,DB_START_FLD)+1,
                \ RT_DBaseGetField(DB,i,DB_COLOR_FLD),
                \ Append=True)
        }
    }
""")

SCRIPT = """return GetAveColorFrame(DB,current_frame)"""        # For ScriptClip mode only : Not used for SHORTSEQ

(SHORTSEQ)
    \ ? Last.ShortSequenceClip(DB,DEBUG)
    \ : Last.Scriptclip(SCRIPT,args="DB",Local=True)

(DEL_DB) ? CallCmd(Close="CMD /C del "+DB, Hide=true) : NOP

Return Last
EDIT: A cleverer script might split clip into scenes, and produces data on each scene,
above splits clip into n sequences of same number of frames each (perhaps fewer in last sequence).

NOTE, in Scriptclip mode, will auto scan each new sequence on frame access that has not as yet been sequence scanned,
so may pause at each sequence, or can call PrepDBase(PreScan=true) to prescan complete clip before commence play clip.
__________________
I sometimes post sober.
StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace

"Some infinities are bigger than other infinities", but how many of them are infinitely bigger ???

Last edited by StainlessS; 10th October 2017 at 23:19.
StainlessS is offline   Reply With Quote
Old 10th October 2017, 22:47   #7  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
OutLog.log for above posted script

Show for each sequence, start frame, end frame, len of seq, Average color of sequence.
Code:
FileName='D:\TEST.AVI'
DB      ='D:\MyDBase.DB'
SEQS    = 25
IsYUV   = True
FrmCnt  = 1000
Width   = 1280
Height  = 604
Records = 25            # Same as SEQS (DB Internal)
ClipName='D:\TEST.AVI'  # Same as FileName (DB Internal)
DEBUG   = 1

0} [0,39:Len=40] Color=$2A887B
1} [40,79:Len=40] Color=$308C79
2} [80,119:Len=40] Color=$308C7A
3} [120,159:Len=40] Color=$31897C
4} [160,199:Len=40] Color=$3F8D7A
5} [200,239:Len=40] Color=$368E77
6} [240,279:Len=40] Color=$338C79
7} [280,319:Len=40] Color=$5C9070
8} [320,359:Len=40] Color=$338879
9} [360,399:Len=40] Color=$3A8779
10} [400,439:Len=40] Color=$3B867A
11} [440,479:Len=40] Color=$36867A
12} [480,519:Len=40] Color=$3E8A76
13} [520,559:Len=40] Color=$338978
14} [560,599:Len=40] Color=$40847B
15} [600,639:Len=40] Color=$378B77
16} [640,679:Len=40] Color=$4F8A78
17} [680,719:Len=40] Color=$3A8977
18} [720,759:Len=40] Color=$498976
19} [760,799:Len=40] Color=$398977
20} [800,839:Len=40] Color=$328879
21} [840,879:Len=40] Color=$4A8279
22} [880,919:Len=40] Color=$3F7F7D
23} [920,959:Len=40] Color=$3F7A83
24} [960,999:Len=40] Color=$427D81
__________________
I sometimes post sober.
StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace

"Some infinities are bigger than other infinities", but how many of them are infinitely bigger ???

Last edited by StainlessS; 10th October 2017 at 23:12.
StainlessS is offline   Reply With Quote
Old 11th October 2017, 09:31   #8  |  Link
pandy
Registered User
 
Join Date: Mar 2006
Posts: 1,049
https://www.ffmpeg.org/ffmpeg-filter...#signalstats-1

https://www.ffmpeg.org/ffmpeg-filters.html#loudnorm

https://www.ffmpeg.org/ffmpeg-filters.html#astats-1

https://www.ffmpeg.org/ffmpeg-filters.html#ebur128-1

Last edited by pandy; 11th October 2017 at 09:36.
pandy is offline   Reply With Quote
Reply

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +1. The time now is 04:42.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.