please see => Newer Approach
I have a Panasonic DMC-ZS5 (dpreview, Panasonic) which creates .MOV files that contain the Motion JPEG (M-JPEG) “format” (for want of a more technical term).
In order to stream those videos from my IIS/PHP based photo gallery (zenPhoto.org), they must be converted to a more “web compatible” format like MPEG-4. I haven’t found a more straightforward approach than direct batch conversion to another format… you can readily automate the conversion of say all the videos in a folder so it’s pretty much turnkey and ignore.
Update 2015-01-05: This is my current go-to:
for %v in (*.mov) do ffmpeg -i "%v" -vcodec h264 -acodec aac -strict -2 "%~nv.mp4"
Notes:
- make sure to double up all the %%v if you put in .cmd batch file
- ffmpeg is a very popular 3rd party command line util. I get mine from here.
Update 2015-07-18: cropping 3D movies down to single image
ffmpeg -i "in_movie_file.ext" -vf "crop=960:800:0:0,setdar=4:2" -vcodec h264 -acodec aac -strict -2 "out_movie_file.mp4"
- obviously check the real resolution before setting the crop… just divide it by 2
- “setdar” is the aspect ratio… i found it was necessary… one way to find it is with VLC CTRL-J on the original video
VLC will do this via a command line like so:
"c:Program Files (x86)VLCvlc.exe" -vvv %1 --sout=#transcode{acodec=mpga,vcodec=h264,venc=x264,deinterlace,vfilter="rotate{angle=270}"}:standard{mux=mp4,dst="%~n1.mp4"}, vlc://quit
Notes:
- I’ve had to remove the acodec=mpga for my iPhone MOV’s or else I get garbled audio.
- I included the vfilter=”rotate…” for rotation syntax since it was so hard for me to find but only include if you want rotation.
However, I noticed that VLC chops off the last 2 seconds no matter what I do… it seemed a little better choosing a different vcodec but h264 is too rocking to use anything else.
So I wound up going with QuickTime as my go-to transcoder for now. It doesn’t truncate any video and creates a slightly smaller output file than VLC. The compression is dramatic and h264 does an awesome job with preserving quality… even while maintaining 1280 x 720 HD, a 100MB MJPG will go down to a 5MB h264/MPEG file.
Following code stolen from here and tweaked a little, automates the QuickTime COM API to convert a directory full of MJPG’s (see sample code for Chapter.8 > “BatchExport.js”).
There’s no reason why this shouldn’t be in PowerShell… it’d be interesting to see if it was any more readable.
//----------------------------------------------------------------------------------
//
// Written by : John Cromie
// Copyright : ? 2006 Skylark Associates Ltd.
//
// Purchasers of the book "QuickTime for .NET and COM Developers" are entitled
// to use this source code for commercial and non-commercial purposes.
// This file may not be redistributed without the written consent of the author.
// This file is provided "as is" with no expressed or implied warranty.
//
//----------------------------------------------------------------------------------
function unquote(str) { return str.charAt(0) == '"' && str.charAt(str.length - 1) == '"' ? str.substring(1, str.length - 1) : str; }
// Run from command line as follows:
//
// cscript BatchExport.js , , , , ,
var sourcePath, destPath, configXMLFilePath, convertFileExtension, exporterType, exportFileExtension;
// Get script arguments
if (WScript.Arguments.Length >= 4)
{
sourcePath = unquote(WScript.Arguments(0));
destPath = unquote(WScript.Arguments(1));
configXMLFilePath = unquote(WScript.Arguments(2));
convertFileExtension = unquote(WScript.Arguments(3));
exporterType = WScript.Arguments(4);
exportFileExtension = WScript.Arguments(5);
}
//sourcePath = "D:QuickTimeMoviesBirdsKittiwake";
//destPath = "D:QuickTimeMoviesExportDest";
//exporterType = "BMP";
//exportFileExtension = "bmp";
// Sanity check arguments
var fso = WScript.CreateObject("Scripting.FileSystemObject");
var e = "";
if (!fso.FolderExists(sourcePath))
e += "Source path does not exist : " + "[" + sourcePath + "]n";
if (!fso.FolderExists(destPath))
e += "Destination path does not exist : " + "[" + destPath + "]n";
if (!fso.FolderExists(configXMLFilePath))
e += "Config XML file path does not exist : " + "[" + configXMLFilePath + "]n";
if (convertFileExtension == undefined)
e += "No convert file extension supplied!n";
if (exporterType == undefined)
e += "No exporter type supplied!n";
if (exportFileExtension == undefined)
e += "No exporter file extension supplied!n";
if (e != "")
{
WScript.Echo(e);
WScript.Echo("Usage:");
WScript.Echo("cscript BatchExport.js , , , , , ");
WScript.Quit();
}
// Launch QuickTime Player
var qtPlayerApp = WScript.CreateObject("QuickTimePlayerLib.QuickTimePlayerApp");
if (qtPlayerApp == null)
{
WScript.Echo("Unable to launch QuickTime Player!");
WScript.Quit();
}
var qtPlayerSrc = qtPlayerApp.Players(1);
if (qtPlayerSrc == null)
{
WScript.Echo("Unable to retrieve QuickTime Player instance!");
WScript.Quit();
}
// Set up the exporter and have it configured
var qt = qtPlayerSrc.QTControl.QuickTime;
qt.Exporters.Add();
var exp = qt.Exporters(1);
exp.TypeName = exporterType;
// settings file...
var FileSystemObject = WScript.CreateObject("Scripting.FileSystemObject");
var configXMLFileInfo;
if ( FileSystemObject.FileExists(configXMLFilePath) )
configXMLFileInfo = FileSystemObject.OpenTextFile( configXMLFilePath );
// if settings files exists, load it and assign it to the exporter
if ( configXMLFileInfo ) {
var configXMLString = configXMLFileInfo.ReadAll();
// cause the exporter to be reconfigured
// https://developer.apple.com/technotes/tn2006/tn2120.html
var tempSettings = exp.Settings;
tempSettings.XML = configXMLString;
exp.Settings = tempSettings;
} else {
//otherwise, get the settings from the user dialog and save them to xml file for subsequent runs
exp.ShowSettingsDialog();
var configXMLString = exp.Settings.XML;
configXMLFileInfo = FileSystemObject.CreateTextFile( configXMLFilePath );
if ( configXMLFileInfo ) {
configXMLFileInfo.WriteLine(configXMLString);
configXMLFileInfo.Close();
} else {
WScript.Echo("Unable to create config XML file : " + "[" + configXMLFilePath + "]");
WScript.Quit();
}
}
var fldr = fso.GetFolder(sourcePath);
// Regular expression to match file extension
var re = new RegExp("."+convertFileExtension+"$", "i");
// Iterate over the source files
var fc = new Enumerator(fldr.Files);
for (; !fc.atEnd(); fc.moveNext())
{
var f = fc.item().Name;
// Filter by file extension
if (!re.test(f))
continue;
try
{
// Open the movie and export it
qtPlayerSrc.OpenURL(fc.item());
var mov = qtPlayerSrc.QTControl.Movie;
if (mov)
{
exp.SetDataSource(mov);
// Strip file extension and compose new file name
f = f.replace(/.[^.]*$/, "");
var fDest = destPath + "" + f + "." + exportFileExtension;
exp.DestinationFileName = fDest;
exp.BeginExport();
WScript.Echo("Exported: " + fDest);
}
}
catch (err)
{
WScript.Echo("Error Exporting: " + fc.item());
}
}
// Tidy up
qtPlayerSrc.Close();