Due to continual spamming, forum registrations are now by Invitation Only. Hopefully this will be only a temporary measure to combat spammers.

If you want an invitation contact forumapplication @ camstudio . org

Sorry for the inconvenience.

CamStudio_Monitor: Helps prevent exceeding maximum AVI file size while recording.

CamStudio_Monitor watches the two files temporary files CamStudio creates while recording (~temp*.wav and ~temp*.avi) adds up the two files sizes once a second and displays the results on a ProgressBar. It is displayed as a percentage of the maximum files size before CamStudio blows up saving an avi file (2147483647 bytes); starting Green, it turns Yellow when reaching 70%, Red at 85%, and finally turning Black when you've exceeded 100% of the maximum size. I have only tested using CamStudio Lossless Codec v1.5 and PCM @ 22.05kHz, stereo 16-bit; using those settings tests show the estimate is usually about 3.5% on the high side, but that's actually a good thing 'cause it gives you a small safety margin. (But don't push your luck 'cause I have had it blow up while still at about 98%... YMMV.)

Continued...

Comments


  • Create any directory for it (i.e. C:/Program Files/CamStudio/Camstudio_Monitor) and put CamStudio_Monitor.java in there. Also create a file named "CamStudio_Monitor_Configuration.txt" and enter the directories CamStudio uses for its temporary files. For example the contents of my Configuration file are (note it is only monitoring two directories because two are commented out)...
    --- Begin: File Contents ---
    'Comment Lines begin with a "'"
    'Blank lines are ignored
    'A List for Directories to Monitor for CamStudio's Files...

    'C:\Program Files\CamStudio 2.6b\Recordings
    C:\Program Files (x86)\CamStudio 2.6b\Recordings
    'D:\Download_Programs\CamStudio\AVI_Files
    C:\Machinima
    --- End: File Contents ---

    Continued...
  • To compile (assuming you have a Java JDK correctly installed) create a batch file something like...
    --- Begin: File Contents ---
    REM *** Compiling ***
    del *.class
    javac *.java
    Pause

    REM *** Packaging ***
    del *.jar
    jar -cvef CamStudio_Monitor CamStudio_Monitor.jar *.*
    Pause
    --- End: File Contents ---

    To execute just double-click on the jar file, create a short-cut to the jar on your DeskTop, or create another batch file containing...
    --- Begin: File Contents ---
    REM *** Executing (jar) ***
    CamStudio_Monitor.jar
    pause

    REM *** Executing (java) ***
    REM If the above jar file didn't execute on your OS, try uncommenting the following two lines...
    REM java -jar CamStudio_Monitor.jar
    REM pause
    --- End: File Contents ---
    (If the jar files doesn't execute directly on your OS, uncomment the last two lines.)

    Continued...

  • Assuming you've put the correct directories to monitor in the Configuration file, it will watch for growing files and switch to "Triggered" mode after two consecutive seconds of growing files. You can pause CamStudio and continue recording later. After 10 consecutive seconds of no file size changes, CamStudio_Monitor will switch back to "Waiting" mode. It deliberately positions itself at the very bottom of the screen so you can cover it with the application your recording, only leaving a small sliver of space at the bottom to see the color-coded ProgressBar. Enjoy.

    Continued...
  • //package CamStudio_Monitor;
    //***********************************************************************//
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.GridBagConstraints;
    import java.awt.GridBagLayout;
    import java.awt.Toolkit;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.WindowAdapter;
    import java.awt.event.WindowEvent;
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileReader;
    import java.util.Timer;
    import java.util.TimerTask;
    import java.util.Vector;

    import javax.swing.JButton;
    import javax.swing.JEditorPane;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JProgressBar;
    import javax.swing.JScrollPane;
    import javax.swing.ScrollPaneConstants;
    import javax.swing.SwingConstants;
  • //***********************************************************************//
    public class CamStudio_Monitor extends JFrame implements ActionListener {
    private static final String sCONFIGURATION_PATH = "CamStudio_Monitor_Configuration.txt";
    private static final int iSTATUS_MIN_X = 200;
    private static final int iSTATUS_MIN_Y = 120;
    private static final int iSTATUSBAR_HEIGHT = 30;
    private static final long lMAX_VALUE = (long)(Integer.MAX_VALUE);//(long)(Integer.MAX_VALUE*0.01);//Integer.MAX_VALUE;
    private static final long lRED_WARNING_VALUE = (long)(lMAX_VALUE*0.85);
    private static final long lYELLOW_WARNING_VALUE = (long)(lMAX_VALUE*0.70);
    private static final int iPERIOD = 1000;
    private static final int iTRIGGER_CHANGE_COUNT = 3;
    private static final int iUNTRIGGER_NOCHANGE_COUNT = 10;
    private static final String sCAMSTUDIO_TEMP_PREFIX = "~temp-";
    private static final String sCAMSTUDIO_TEMP_AVI_POSTFIX = ".avi";
    private static final String sCAMSTUDIO_TEMP_WAV_POSTFIX = ".wav";
    private static enum MonitorEnum { ENTERING_WAITING, WAITING, ENTERING_TRIGGERED, TRIGGERED }
  • private final JButton jbReload = new JButton("Reload"); //private final JCheckBox jcbBeep = new JCheckBox("Beep"); private final JButton jbExit = new JButton("Exit"); private final JEditorPane jepStatus = new JEditorPane(); private final JProgressBar jpPercent = new JProgressBar(SwingConstants.HORIZONTAL, 0, 100); private final Vector<String> vDirsToMonitor = new Vector<String>(); private final Timer tTimer = new Timer(); private MonitorEnum eMonitorMode = MonitorEnum.ENTERING_WAITING; private int iSecondsSinceTrigger = 0;
  • //***********************************************************************//
    public CamStudio_Monitor() {
    try {
    System.out.println("usage: java "+this.getClass().getSimpleName());
    GridBagLayout gridbag = new GridBagLayout();
    getContentPane().setLayout(gridbag);
    addWindowListener(new WindowAdapter() {
    public void windowClosing(WindowEvent e) {
    dispose();
    System.exit(0x0000);
    }
    });
    setTitle(this.getClass().getSimpleName());

    /* Title (0,0 - 1,0) */
    final JLabel jlTitle = new JLabel(this.getClass().getSimpleName(), JLabel.CENTER);
    //jlTitle.setForeground(Color.RED);
    //jlTitle.setFont(new Font(jlTitle.getFont().getFontName(), jlTitle.getFont().getStyle()|Font.BOLD|Font.ITALIC, jlTitle.getFont().getSize()+2));
    gridbag.setConstraints(jlTitle, buildGridBagConstraints(0, 0, 7, 1, 1, 1));
    getContentPane().add(jlTitle);

    /* Reload, Exit (0,1 - 1,1) */
    jbReload.setEnabled(false);
    jbReload.addActionListener(this);
    gridbag.setConstraints(jbReload, buildGridBagConstraints(0, 1, 1, 1, 1, 1));
    getContentPane().add(jbReload);
    jbExit.addActionListener(this);
    gridbag.setConstraints(jbExit, buildGridBagConstraints(1, 1, 1, 1, 1, 1));
    getContentPane().add(jbExit);
  • /* Status (0,2 - 1,2) */
    //jepStatus.setAutoscrolls(true);
    jepStatus.setEditable(false);
    //jepStatus.setLineWrap(true);
    //jepStatus.setWrapStyleWord(true);
    jepStatus.setBackground(Color.GRAY);
    jepStatus.setMinimumSize(new Dimension(iSTATUS_MIN_X, iSTATUS_MIN_Y));
    jepStatus.setPreferredSize(jepStatus.getMinimumSize());
    JScrollPane jspStatus = new JScrollPane(jepStatus);
    jspStatus.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
    jspStatus.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
    gridbag.setConstraints(jspStatus, buildGridBagConstraints(0, 2, 2, 1, 100, 100, GridBagConstraints.CENTER, GridBagConstraints.BOTH));
    getContentPane().add(jspStatus);

    /* Status (0,2 - 1,2) */
    jpPercent.setMinimumSize(jpPercent.getPreferredSize());
    jpPercent.setMaximumSize(new Dimension(Integer.MAX_VALUE, getPreferredSize().height));
    gridbag.setConstraints(jpPercent, buildGridBagConstraints(0, 3, 2, 1, 100, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH));
    getContentPane().add(jpPercent);

    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    pack();
    setLocation(Toolkit.getDefaultToolkit().getScreenSize().width/2-getWidth()/2, Toolkit.getDefaultToolkit().getScreenSize().height-getHeight()-iSTATUSBAR_HEIGHT);
    setMinimumSize(getPreferredSize());
    setVisible(true);

    Reload();
  • } catch(final Exception ex) {
    System.err.println("FOLDataServer2:"+ex+"\n");
    ex.printStackTrace();
    }
    }
    //***********************************************************************//
    final static GridBagConstraints gbc = new GridBagConstraints();
    private static GridBagConstraints buildGridBagConstraints(final int gx, final int gy, final int gw, final int gh, final int wx, final int wy) {
    return buildGridBagConstraints(gx, gy, gw, gh, wx, wy, GridBagConstraints.CENTER, GridBagConstraints.NONE);
    }
    private static GridBagConstraints buildGridBagConstraints(final int gx, final int gy, final int gw, final int gh, final int wx, final int wy, final int anchor, final int fill) {
    gbc.gridx = gx; gbc.gridy = gy; gbc.gridwidth = gw; gbc.gridheight = gh; gbc.weightx = wx; gbc.weighty = wy; gbc.ipadx = 0; gbc.ipady = 0; gbc.anchor = anchor; gbc.fill = fill;
    //gbc.fill = GridBagConstraints.BOTH; //* * * Helpful to see what's going on * * *//
    return gbc;
    }
  • //***********************************************************************//
    @Override
    public void actionPerformed(final ActionEvent arg0) {
    if(arg0.getSource()==jbExit) {
    tTimer.cancel();
    System.exit(0x0000);
    //} else if(arg0.getSource()==jbReload) {
    //reload();
    }
    }
  • //***********************************************************************//
    private void Reload() {
    eMonitorMode = MonitorEnum.ENTERING_WAITING;
    readConfiguration(sCONFIGURATION_PATH);
    System.out.println("Configuration Paths...");
    for(String s : vDirsToMonitor) {
    System.out.println("\t"+s);
    }
    }
  • //***********************************************************************//
    private void readConfiguration(final String sConfigurationPath) {
    try {
    vDirsToMonitor.clear();
    BufferedReader brConfigFile = new BufferedReader(new FileReader(sConfigurationPath));
    String sLine = brConfigFile.readLine();
    while(sLine!=null) {
    sLine = sLine.trim();
    if(sLine.equals("")==false&&sLine.startsWith("'")==false) {
    vDirsToMonitor.add(sLine);
    }
    sLine = brConfigFile.readLine();
    }
    brConfigFile.close();
    } catch(final Exception ex) {
    System.err.println("readConfiguration:"+ex+"\n");
    ex.printStackTrace();
    }
    }
  • //***********************************************************************// private final Vector<FileMonitor> vFilesToMonitor = new Vector<FileMonitor>(); private int iNoChangeCount = 0; private void Monitor() { try { StringBuilder sb = new StringBuilder(); sb.append("Mode: "+eMonitorMode.name()+"\r\n"); //System.out.println("Monitor()"); switch(eMonitorMode) { case ENTERING_WAITING : iSecondsSinceTrigger = 0; vFilesToMonitor.clear(); jepStatus.setBackground(Color.GRAY); jpPercent.setValue(0); jpPercent.setForeground(Color.GRAY); eMonitorMode = MonitorEnum.WAITING; //break; // Deliberately Falling thru...
  • case WAITING :
    for(String sDirsToMonitor : vDirsToMonitor) {
    File fDir = new File(sDirsToMonitor);
    for(File fFile : fDir.listFiles()) {
    if(fFile.isFile()&&fFile.getName().startsWith(sCAMSTUDIO_TEMP_PREFIX)&&(fFile.getName().endsWith(sCAMSTUDIO_TEMP_AVI_POSTFIX)||fFile.getName().endsWith(sCAMSTUDIO_TEMP_WAV_POSTFIX))) {
    boolean bFound = false;
    for(FileMonitor fm : vFilesToMonitor) {
    if(fFile.getName().equals(fm.getFile().getName())) {
    bFound = true;
    }
    }
    if(bFound==false) {
    vFilesToMonitor.add(new FileMonitor(fFile, fFile.length()));
    sb.append("\tAdded:"+fFile.getName()+"\r\n");
    }
    }
    }
    }
  • for(FileMonitor fm : vFilesToMonitor) { fm.checkForChanges(); if(fm.getChangeCount()>iTRIGGER_CHANGE_COUNT) { sb.append("\tChanged:"+fm.getFile().getName()+"\r\n"); eMonitorMode = MonitorEnum.ENTERING_TRIGGERED; } } break; case ENTERING_TRIGGERED : iSecondsSinceTrigger = 0; final Vector<FileMonitor> vOldFilesToMonitor = new Vector<FileMonitor>(vFilesToMonitor); vFilesToMonitor.clear(); for(FileMonitor fmOld : vOldFilesToMonitor) { if(fmOld.getChangeCount()>=iTRIGGER_CHANGE_COUNT) { vFilesToMonitor.add(fmOld); } } sb.append("\tvFilesToMonitor:"+vFilesToMonitor.toString()+"\r\n"); jepStatus.setBackground(Color.LIGHT_GRAY); eMonitorMode = MonitorEnum.TRIGGERED; break;
  • case TRIGGERED : iSecondsSinceTrigger++; long lTotal = 0; boolean bChanges = false; for(FileMonitor fm : vFilesToMonitor) { bChanges |= fm.checkForChanges(); lTotal += fm.getFile().length(); sb.append(fm.getFile().getName()+"\r\n"); sb.append("\t"+fm.getLength()+"\r\n"); } if(bChanges==true) { iNoChangeCount = 0; } else { iNoChangeCount++; if(iNoChangeCount>iUNTRIGGER_NOCHANGE_COUNT) { eMonitorMode = MonitorEnum.ENTERING_WAITING; } } sb.append("\tlTotal:"+lTotal+"\r\n"); int iPercent = (int)((lTotal*100.0)/lMAX_VALUE); sb.append("\tlPercent:"+iPercent+"%\r\n"); jpPercent.setValue(iPercent); if(lTotal<lYELLOW_WARNING_VALUE) { //jepStatus.setBackground(Color.GREEN); jpPercent.setForeground(Color.GREEN); jpPercent.setBackground(Color.LIGHT_GRAY); } else if(lTotal<lRED_WARNING_VALUE) { //jepStatus.setBackground(Color.YELLOW); if((iSecondsSinceTrigger&0x0001)==0x0001) { jpPercent.setForeground(Color.YELLOW); jpPercent.setBackground(Color.WHITE); } else { jpPercent.setForeground(Color.WHITE); jpPercent.setBackground(Color.YELLOW); }
  • } else if(lTotal<lMAX_VALUE) { //jepStatus.setBackground(Color.RED); //jpPercent.setForeground(Color.RED); if((iSecondsSinceTrigger&0x0001)==0x0001) { jpPercent.setForeground(Color.RED); jpPercent.setBackground(Color.WHITE); } else { jpPercent.setForeground(Color.WHITE); jpPercent.setBackground(Color.RED); } } else { //jepStatus.setBackground(Color.BLACK); //jpPercent.setForeground(Color.BLACK); if((iSecondsSinceTrigger&0x0001)==0x0001) { jpPercent.setForeground(Color.BLACK); jpPercent.setBackground(Color.WHITE); } else { jpPercent.setForeground(Color.WHITE); jpPercent.setBackground(Color.BLACK); } } break; default : throw new Exception("Invalid MonitorEnum "+eMonitorMode.toString()); } jepStatus.setText(sb.toString()); //System.out.println(sb); } catch(final Exception ex) { System.err.println("Monitor:"+ex+"\n"); ex.printStackTrace(); } }
  • //***********************************************************************//
    public static void main(final String[] args) {
    final CamStudio_Monitor csm = new CamStudio_Monitor();
    //try { Thread.sleep(1000); } catch(final Exception _) { ; }
    csm.tTimer.scheduleAtFixedRate(new TimerTask(){ public void run(){ csm.Monitor(); } },0, iPERIOD);
    }
    //***********************************************************************//
    }
    //***********************************************************************//
    class FileMonitor {
    private File f = null;
    private long l = 0;
    private int iChangeCount = 0;
    public FileMonitor(final File f, final long l) { this.f = f; this.l = l; }
    public boolean checkForChanges() { if(f.length()!=l) { l=f.length(); iChangeCount++; return true; } else { return false; } }
    public File getFile() { return this.f; }
    public long getLength() { return this.l; }
    public int getChangeCount() { return this.iChangeCount; }
    @Override
    public String toString() { return "{f:"+f.getName()+", l="+l+", iChangeCount="+iChangeCount+"}"; }
    }
    //***********************************************************************//
  • (Hope I got everything posted correctly.)
  • CamStudio_Monitor Demonstration:

    Note Green Bar at bottom of screen, eventually turning Yellow, then Red.

    2,036,938,240 bytes Final Estimate was
    2,037,984,768 bytes Actual Final Size
    2,147,483,647 bytes Absolute Maximum


  • Almost_There,

    This tool is invaluable for doing tests with more control. Interestingly, I've experienced higher values of the .wav and .avi total than this have still gotten through somehow, when using Xvid in tests. I'll run some more.

    I'm too busy to focus on this right now, but I will compile this soon and run some tests with other codecs. Sorry for the character limit in the new forum - that has bitten me many times now!!!

    Terry
Sign In or Register to comment.