Dynamic FFMPEG Encoder Button

My goal is to create an "Encode to MP4" button, in JScript if possible. My goal is to handle width/height/duration and frame rate variables in if/else, before deciding the FFMPEG formula to use in order to convert the file to MP4.

I think I'd benefit from just being pointed at how to find/get file properties. I'd also like to know which Type of function I should do this script in as I'm very new. I'm not sure what the difference is between: Standard Function (Opus or external), MS-DOS Batch Function, Script Function (JScript, VBScript), WSL Script Function.

You'll find file properties in the metadata object. For JScript, you need to use Script Function (JScript).

There are a few FFMPEG buttons/scripts on the forum already which may be a good starting point, too.

Ok well, given the information I was able to find. I asked ChatGPT to make one and got what I wanted:

function OnClick(clickData) {
    var cmd = clickData.func.command;
    var selectedItems = clickData.func.sourcetab.selected;
    if (selectedItems.count == 0) {
        DOpus.Output("No video files selected.");
        return;
    }
    var ffprobePath = "ffprobe"; // Assumes ffprobe is in your system's PATH
    var ffmpegPath = "ffmpeg"; // Assumes ffmpeg is in your system's PATH
    for (var e = new Enumerator(selectedItems); !e.atEnd(); e.moveNext()) {
        var item = e.item();
        if (!item.is_dir) {
            var inputFilePath = item.realpath;
            var outputFilePath = item.path + "\\" + item.name_stem + "_LQ.mp4";
            
            // Get video information using ffprobe
            var shell = new ActiveXObject("WScript.Shell");
            var exec = shell.Exec(ffprobePath + ' -v error -select_streams v:0 -show_entries stream=width,height,r_frame_rate,duration,bit_rate -of default=noprint_wrappers=1 "' + inputFilePath + '"');
            var stdout = exec.StdOut.ReadAll();
            var stderr = exec.StdErr.ReadAll();
            if (stderr) {
                DOpus.Output("Error: " + stderr);
                continue;
            }
            
            // Parse the ffprobe output
            var width = stdout.match(/width=([0-9]+)/) ? parseInt(stdout.match(/width=([0-9]+)/)[1], 10) : null;
            var height = stdout.match(/height=([0-9]+)/) ? parseInt(stdout.match(/height=([0-9]+)/)[1], 10) : null;
            var frameRate = stdout.match(/r_frame_rate=([0-9]+\/[0-9]+)/) ? stdout.match(/r_frame_rate=([0-9]+\/[0-9]+)/)[1] : "30000/1001";
            var duration = stdout.match(/duration=([0-9.]+)/) ? parseFloat(stdout.match(/duration=([0-9.]+)/)[1]) : null;
            var bitRate = stdout.match(/bit_rate=([0-9]+)/) ? parseInt(stdout.match(/bit_rate=([0-9]+)/)[1], 10) : null;
            if (!width || !height) {
                DOpus.Output("Could not extract necessary video information for file: " + inputFilePath);
                continue;
            }
            // Calculate new dimensions (halving resolution)
            var newWidth = Math.floor(width / 2);
            var newHeight = Math.floor(height / 2);
            // Determine encoding parameters based on resolution
            var crf, maxRate, bufSize;
            if (newWidth >= 1920 || newHeight >= 1080) {
                crf = 23;
                maxRate = "8M";
                bufSize = "10M";
            } else if (newWidth >= 1280 || newHeight >= 720) {
                crf = 25;
                maxRate = "5M";
                bufSize = "6M";
            } else {
                crf = 28;
                maxRate = "3M";
                bufSize = "4M";
            }
            var ffmpegCommand = ffmpegPath + 
                ' -i "' + inputFilePath + '"' +
                ' -vf "scale=' + newWidth + ':' + newHeight + ',format=yuv420p"' +
                ' -c:v libx264' +
                ' -preset slow' +
                ' -crf ' + crf +
                ' -maxrate ' + maxRate +
                ' -bufsize ' + bufSize +
                ' -profile:v baseline' +  // Change profile to baseline
                ' -level 3.1' +  // Lower level to 3.1
                ' -c:a aac' +
                ' -b:a 128k' +
                ' -movflags +faststart' +
                ' "' + outputFilePath + '"';
            DOpus.Output("Running encoding command: " + ffmpegCommand);
            
            // Run the FFMPEG command
            cmd.RunCommand('cmd /c ' + ffmpegCommand);
            
            DOpus.Output("Encoding completed. Output file: " + outputFilePath);
        }
    }
}

That being said, can I actually save the code in the buttons as editable text? i'd like to put the scripts I've been accumulating into a Git repo so that I have version control for when I update/change them.

At the moment, I'm just making copies of the flies and registering them in Git.

1 Like

Toolbars are already in a text (XML) format on disk.

Oh, it just occurred to me that I can drag the entire DO folder from the C:\ into VS code and put that in a repo instead. I'll try to figure out how to keep stuff I want to track registered, or at least this way, I have a better starting point than just guessing where to look for something.

Thanks, I see all my stuff in Menu.dop