Commits

Justin Lloyd committed c028a83

First checkin of FFMPEGWrapper library and harness to test the library.

  • Participants

Comments (0)

Files changed (15)

+syntax: glob
+*.suo
+*.pdb
+*.log
+*.bak
+
+*/.svn
+obj\*
+
+bin/*

File FFMPEGHarness/FFMPEGHarness.csproj

+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+    <ProductVersion>8.0.30703</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{B532CBEF-743C-493D-B6B3-91DC61DDE4CE}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>FFMPEGHarness</RootNamespace>
+    <AssemblyName>FFMPEGHarness</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <TargetFrameworkProfile>
+    </TargetFrameworkProfile>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <PlatformTarget>x86</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <PlatformTarget>x86</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <CodeAnalysisLogFile>bin\Debug\FFMPEGHarness.exe.CodeAnalysisLog.xml</CodeAnalysisLogFile>
+    <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
+    <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+    <CodeAnalysisRuleSetDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories>
+    <CodeAnalysisIgnoreBuiltInRuleSets>true</CodeAnalysisIgnoreBuiltInRuleSets>
+    <CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
+    <CodeAnalysisIgnoreBuiltInRules>true</CodeAnalysisIgnoreBuiltInRules>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'">
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <CodeAnalysisLogFile>bin\Release\FFMPEGHarness.exe.CodeAnalysisLog.xml</CodeAnalysisLogFile>
+    <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
+    <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+    <CodeAnalysisRuleSetDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories>
+    <CodeAnalysisIgnoreBuiltInRuleSets>true</CodeAnalysisIgnoreBuiltInRuleSets>
+    <CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
+    <CodeAnalysisIgnoreBuiltInRules>true</CodeAnalysisIgnoreBuiltInRules>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Configuration" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Program.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\FFMPEGWrapper\FFMPEGWrapper.csproj">
+      <Project>{928BE5C5-A781-4186-9629-5CFBFFE472A9}</Project>
+      <Name>FFMPEGWrapper</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="app.config">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="hamster.flv">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="watermark.png">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>

File FFMPEGHarness/Program.cs

+using System;
+using System.Linq;
+using System.Drawing;
+using System.IO;
+using FFMPEGWrapper;
+
+namespace FFMPEGHarness
+{
+    class Program
+    {
+        private static readonly string m_outputFilePath;
+        private static readonly string m_inputFilePath;
+
+        static Program()
+        {
+            m_inputFilePath = Directory.GetFiles(".", "*.flv").First();
+            m_outputFilePath = Path.Combine(Path.GetDirectoryName(m_inputFilePath), Path.ChangeExtension(String.Format("{0}_modified", Path.GetFileNameWithoutExtension(m_inputFilePath)), Path.GetExtension(m_inputFilePath)));
+        }
+
+        public static void VideoInfo()
+        {
+            string output = FFMPEG.Execute(m_inputFilePath);
+
+            Console.WriteLine("Duration = " + InfoProcessor.GetDuration(output));
+            Console.WriteLine("Audio Rate = " + InfoProcessor.GetAudioBitRate(output));
+            Console.WriteLine("Audio Format = " + InfoProcessor.GetAudioFormat(output));
+            Console.WriteLine("Video Format = " + InfoProcessor.GetVideoFormat(output));
+            Console.WriteLine("Video Dimensions = " + InfoProcessor.GetVideoDimensions(output));
+        }
+
+        private static void ResizeVideo()
+        {
+            FFMPEGParameters parameters = new FFMPEGParameters()
+            {
+                InputFilePath = m_inputFilePath,
+                OutputFilePath = m_outputFilePath,
+                VideoCodec = "libx264",
+                AudioCodec = "libvo_aacenc",
+                Format = "flv",
+                BufferSize = 50000,
+                Size = new Size(320,240),
+                MaximumRate = 400,
+                Overwrite=true,
+                OutputOptions = "-ar 22050 -ab 128k -ac 1",
+            };
+
+            string output = FFMPEG.Execute(parameters);
+        }
+
+        private static void WatermarkVideo()
+        {
+            string watermarkFilePath = Directory.GetFiles(".", "*.png").First();
+            FFMPEGParameters parameters = new FFMPEGParameters { InputFilePath = m_inputFilePath, OutputFilePath = m_outputFilePath, SameQ = true, Overwrite = true, VideoFilter = String.Format("\"movie=\\'{0}\\' [logo]; [in][logo] overlay=main_w-overlay_w-{1}:main_h-overlay_h-{2} [out]\"", watermarkFilePath.Replace("\\", "\\\\"), 32, 15) };
+            string output = FFMPEG.Execute(parameters);
+        }
+
+        static void Main(string[] args)
+        {
+            VideoInfo();
+            ResizeVideo();
+            WatermarkVideo();
+        }
+
+
+    }
+}

File FFMPEGHarness/Properties/AssemblyInfo.cs

+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("FFMPEGHarness")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("FFMPEGHarness")]
+[assembly: AssemblyCopyright("Copyright ©  2012")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("437da3d5-f974-440c-ba3d-3f9c9ee550e4")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

File FFMPEGHarness/app.config

+<?xml version="1.0"?>
+<configuration>
+  <startup>
+    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
+  </startup>
+  <appSettings>
+    <add key="FFMPEGExecutableFilePath" value=".\ffmpeg.exe" />
+  </appSettings>
+</configuration>

File FFMPEGHarness/hamster.flv

Binary file added.

File FFMPEGHarness/watermark.png

Added
New image

File FFMPEGWrapper.sln

+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FFMPEGWrapper", "FFMPEGWrapper\FFMPEGWrapper.csproj", "{928BE5C5-A781-4186-9629-5CFBFFE472A9}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FFMPEGHarness", "FFMPEGHarness\FFMPEGHarness.csproj", "{B532CBEF-743C-493D-B6B3-91DC61DDE4CE}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Debug|Mixed Platforms = Debug|Mixed Platforms
+		Debug|x86 = Debug|x86
+		Release|Any CPU = Release|Any CPU
+		Release|Mixed Platforms = Release|Mixed Platforms
+		Release|x86 = Release|x86
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{928BE5C5-A781-4186-9629-5CFBFFE472A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{928BE5C5-A781-4186-9629-5CFBFFE472A9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{928BE5C5-A781-4186-9629-5CFBFFE472A9}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{928BE5C5-A781-4186-9629-5CFBFFE472A9}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{928BE5C5-A781-4186-9629-5CFBFFE472A9}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{928BE5C5-A781-4186-9629-5CFBFFE472A9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{928BE5C5-A781-4186-9629-5CFBFFE472A9}.Release|Any CPU.Build.0 = Release|Any CPU
+		{928BE5C5-A781-4186-9629-5CFBFFE472A9}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{928BE5C5-A781-4186-9629-5CFBFFE472A9}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{928BE5C5-A781-4186-9629-5CFBFFE472A9}.Release|x86.ActiveCfg = Release|Any CPU
+		{B532CBEF-743C-493D-B6B3-91DC61DDE4CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B532CBEF-743C-493D-B6B3-91DC61DDE4CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B532CBEF-743C-493D-B6B3-91DC61DDE4CE}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
+		{B532CBEF-743C-493D-B6B3-91DC61DDE4CE}.Debug|Mixed Platforms.Build.0 = Debug|x86
+		{B532CBEF-743C-493D-B6B3-91DC61DDE4CE}.Debug|x86.ActiveCfg = Debug|x86
+		{B532CBEF-743C-493D-B6B3-91DC61DDE4CE}.Debug|x86.Build.0 = Debug|x86
+		{B532CBEF-743C-493D-B6B3-91DC61DDE4CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B532CBEF-743C-493D-B6B3-91DC61DDE4CE}.Release|Any CPU.Build.0 = Release|Any CPU
+		{B532CBEF-743C-493D-B6B3-91DC61DDE4CE}.Release|Mixed Platforms.ActiveCfg = Release|x86
+		{B532CBEF-743C-493D-B6B3-91DC61DDE4CE}.Release|Mixed Platforms.Build.0 = Release|x86
+		{B532CBEF-743C-493D-B6B3-91DC61DDE4CE}.Release|x86.ActiveCfg = Release|x86
+		{B532CBEF-743C-493D-B6B3-91DC61DDE4CE}.Release|x86.Build.0 = Release|x86
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal

File FFMPEGWrapper/FFMPEG.cs

+using System;
+using System.IO;
+using System.Diagnostics;
+using System.Collections.Generic;
+using System.Configuration;
+
+namespace FFMPEGWrapper
+{
+    public static class FFMPEG
+    {
+        public static string FFMPEGExecutableFilePath;
+
+        private const int MaximumBuffers = 25;
+
+        public static Queue<string> PreviousBuffers = new Queue<string>();
+
+        static FFMPEG()
+        {
+            FFMPEGExecutableFilePath = ConfigurationManager.AppSettings["FFMPEGExecutableFilePath"];
+        }
+
+        public static string Execute(string inputFilePath)
+        {
+            if (String.IsNullOrWhiteSpace(inputFilePath))
+            {
+                throw new ArgumentNullException("Input file path cannot be null");
+            }
+
+            FFMPEGParameters parameters = new FFMPEGParameters()
+            {
+                InputFilePath = inputFilePath
+            };
+
+            return Execute(parameters);
+        }
+
+        public static string Execute(string inputFilePath, string outputOptions, string outputFilePath)
+        {
+            if (String.IsNullOrWhiteSpace(inputFilePath))
+            {
+                throw new ArgumentNullException("Input file path cannot be null");
+            }
+
+            if (String.IsNullOrWhiteSpace(inputFilePath))
+            {
+                throw new ArgumentNullException("Output file path cannot be null");
+            }
+
+            FFMPEGParameters parameters = new FFMPEGParameters()
+            {
+                InputFilePath = inputFilePath,
+                OutputOptions = outputOptions,
+                OutputFilePath = outputFilePath,
+            };
+
+            return Execute(parameters);
+
+        }
+
+        public static string Execute(string inputFilePath, string outputOptions)
+        {
+            if (String.IsNullOrWhiteSpace(inputFilePath))
+            {
+                throw new ArgumentNullException("Input file path cannot be null");
+            }
+
+            FFMPEGParameters parameters = new FFMPEGParameters()
+            {
+                InputFilePath = inputFilePath,
+                OutputOptions = outputOptions
+            };
+
+            return Execute(parameters);
+        }
+
+        public static string Execute(FFMPEGParameters parameters)
+        {
+            if (String.IsNullOrWhiteSpace(FFMPEGExecutableFilePath))
+            {
+                throw new ArgumentNullException("Path to FFMPEG executable cannot be null");
+            }
+
+            if (parameters == null)
+            {
+                throw new ArgumentNullException("FFMPEG parameters cannot be completely null");
+            }
+
+            using (Process ffmpegProcess = new Process())
+            {
+                ProcessStartInfo info = new ProcessStartInfo(FFMPEGExecutableFilePath)
+                {
+                    Arguments = parameters.ToString(),
+                    WorkingDirectory = Path.GetDirectoryName(FFMPEGExecutableFilePath),
+                    UseShellExecute = false,
+                    CreateNoWindow = true,
+                    RedirectStandardOutput = true,
+                    RedirectStandardError = true
+                };
+
+                ffmpegProcess.StartInfo = info;
+                ffmpegProcess.Start();
+                string processOutput = ffmpegProcess.StandardError.ReadToEnd();
+                ffmpegProcess.WaitForExit();
+                PreviousBuffers.Enqueue(processOutput);
+                lock (PreviousBuffers)
+                {
+                    while (PreviousBuffers.Count > MaximumBuffers)
+                    {
+                        PreviousBuffers.Dequeue();
+                    }
+
+                }
+
+                return processOutput;
+            }
+
+        }
+
+    }
+
+}

File FFMPEGWrapper/FFMPEGParameters.cs

+using System;
+using System.Text;
+using System.Drawing;
+
+namespace FFMPEGWrapper
+{
+    public class FFMPEGParameters
+    {
+        public string OutputFilePath;
+        public string InputFilePath;
+        public string Options;
+        public string InputOptions;
+        public string OutputOptions;
+        public string VideoCodec;
+        public string AudioCodec;
+        public string Format;
+        public Size Size = Size.Empty;
+        public bool Overwrite;
+
+        public string VideoFilter;
+
+        private int m_bufferSize;
+        private bool m_isBufferSizeSet;
+
+        private int m_maximumRate;
+        private bool m_isMaximumRateSet;
+        private StringBuilder m_assembledOptions;
+
+        public FFMPEGParameters()
+        {
+            m_assembledOptions = new StringBuilder();
+        }
+
+        public int BufferSize
+        {
+            get
+            {
+                return m_bufferSize;
+            }
+
+            set
+            {
+                m_bufferSize = value;
+                m_isBufferSizeSet = true;
+            }
+
+        }
+
+        public int MaximumRate
+        {
+            get
+            {
+                return m_maximumRate;
+            }
+
+            set
+            {
+                m_maximumRate = value;
+                m_isMaximumRateSet = true;
+            }
+
+        }
+
+        public bool SameQ
+        {
+            get;
+            set;
+        }
+
+        protected void AddOption(string option)
+        {
+            if ((m_assembledOptions.Length > 0) && (m_assembledOptions.ToString().EndsWith(" ") == false))
+            {
+                m_assembledOptions.Append(" ");
+            }
+
+            m_assembledOptions.Append("-");
+            m_assembledOptions.Append(option);
+        }
+
+        protected void AddParameter(string parameter)
+        {
+            m_assembledOptions.Append(parameter);
+        }
+
+        protected void AddOption(string option, string parameter)
+        {
+            AddOption(option);
+            m_assembledOptions.Append(" ");
+            AddParameter(parameter);
+        }
+
+        protected void AddOption(string option, string parameter1, string separator, string parameter2)
+        {
+            AddOption(option);
+            m_assembledOptions.Append(" ");
+            AddParameter(parameter1);
+            m_assembledOptions.Append(separator);
+            AddParameter(parameter2);
+        }
+
+        protected void AddSeparator(string separator)
+        {
+            m_assembledOptions.Append(separator);
+        }
+        
+        protected void AddRawOptions(string rawOptions)
+        {
+            m_assembledOptions.Append(rawOptions);
+        }
+
+        protected void AssembleGeneralOptions()
+        {
+            if (SameQ)
+            {
+                AddOption("sameq");
+            }
+
+            if (Overwrite)
+            {
+                AddOption("y");
+            }
+
+            if (!String.IsNullOrWhiteSpace(Options))
+            {
+                AddSeparator(" ");
+                AddRawOptions(Options);
+            }
+
+        }
+
+        protected void AssembleInputOptions()
+        {
+            if (!String.IsNullOrWhiteSpace(InputOptions))
+            {
+                AddSeparator(" ");
+                AddRawOptions(OutputOptions);
+            }
+
+        }
+
+        protected void AssembleOutputOptions()
+        {
+            if (!String.IsNullOrWhiteSpace(VideoCodec))
+            {
+                AddOption("vcodec", VideoCodec);
+            }
+
+            if (!String.IsNullOrWhiteSpace(AudioCodec))
+            {
+                AddOption("acodec", AudioCodec);
+            }
+
+            if (!String.IsNullOrWhiteSpace(Format))
+            {
+                AddOption("f", Format);
+            }
+
+            if (m_isBufferSizeSet)
+            {
+                AddOption("bufsize", String.Format("{0}KB", BufferSize));
+            }
+
+            if (m_isMaximumRateSet)
+            {
+                AddOption("maxrate", String.Format("{0}KB", MaximumRate));
+            }
+
+            if (!Size.IsEmpty)
+            {
+                AddOption("s", Size.Width.ToString(), "x", Size.Height.ToString());
+            }
+
+            if (!String.IsNullOrWhiteSpace(VideoFilter))
+            {
+                AddOption("vf", VideoFilter);
+            }
+
+            if (!String.IsNullOrWhiteSpace(OutputOptions))
+            {
+                AddSeparator(" ");
+                AddRawOptions(OutputOptions);
+            }
+
+        }
+
+        public override string ToString()
+        {
+            m_assembledOptions.Clear();
+            AssembleGeneralOptions();
+            AssembleInputOptions();
+            if (!String.IsNullOrWhiteSpace(InputFilePath))
+            {
+                AddOption("i", String.Format("\"{0}\"", InputFilePath));
+            }
+
+            AssembleOutputOptions();
+
+            if (!String.IsNullOrWhiteSpace(OutputFilePath))
+            {
+                AddSeparator(" ");
+                AddParameter(String.Format("\"{0}\"", OutputFilePath));
+            }
+
+            return m_assembledOptions.ToString();
+        }
+    }
+
+}

File FFMPEGWrapper/FFMPEGWrapper.csproj

+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>8.0.30703</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{928BE5C5-A781-4186-9629-5CFBFFE472A9}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>FFMPEGWrapper</RootNamespace>
+    <AssemblyName>FFMPEGWrapper</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Configuration" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="FFMPEG.cs" />
+    <Compile Include="FFMPEGParameters.cs" />
+    <Compile Include="InfoProcessor.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="ffmpeg.exe">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>

File FFMPEGWrapper/InfoProcessor.cs

+using System;
+using System.Text.RegularExpressions;
+using System.Drawing;
+
+namespace FFMPEGWrapper
+{
+    public class InfoProcessor
+    {
+        public static TimeSpan GetDuration(string outputCapture)
+        {
+            Match m = Regex.Match(outputCapture, @"[D|d]uration:.((\d|:|\.)*)");
+            if (m.Success == false)
+            {
+                return TimeSpan.Zero;
+            }
+
+            string duration = m.Groups[1].Value;
+            string[] timepieces = duration.Split(new char[] { ':', '.' });
+            if (timepieces.Length == 4)
+            {
+                return new TimeSpan(0, Convert.ToInt16(timepieces[0]), Convert.ToInt16(timepieces[1]), Convert.ToInt16(timepieces[2]), Convert.ToInt16(timepieces[3]));
+            }
+
+            return TimeSpan.Zero;
+        }
+
+        public static double GetAudioBitRate(string outputCapture)
+        {
+            Match m = Regex.Match(outputCapture, @"[B|b]itrate:.((\d|:)*)");
+            if (m.Success == false)
+            {
+                return 0.0;
+            }
+
+            double kb = 0.0;
+            Double.TryParse(m.Groups[1].Value, out kb);
+
+            return kb;
+        }
+
+        public static string GetAudioFormat(string outputCapture)
+        {
+            Match m = Regex.Match(outputCapture, @"[A|a]udio:(.*)");
+            if (m.Success == false)
+            {
+                return String.Empty;
+            }
+
+            return m.Captures[0].Value;
+        }
+
+        public static string GetVideoFormat(string outputCapture)
+        {
+            Match m = Regex.Match(outputCapture, @"[V|v]ideo:(.*)");
+            if (m.Success == false)
+            {
+                return string.Empty;
+            }
+
+            return m.Captures[0].Value;
+        }
+
+        public static Size GetVideoDimensions(string outputCapture)
+        {
+            Match m = Regex.Match(outputCapture, @"(\d{2,4})x(\d{2,4})");
+            if (m.Success == false)
+            {
+                return Size.Empty;
+            }
+
+            int w;
+            int h;
+
+            int.TryParse(m.Groups[1].Value, out w);
+            int.TryParse(m.Groups[2].Value, out h);
+
+            return new Size(w, h);
+        }
+
+    }
+
+}

File FFMPEGWrapper/Properties/AssemblyInfo.cs

+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("FFMPEGWrapper")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("FFMPEGWrapper")]
+[assembly: AssemblyCopyright("Copyright ©  2012")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("47d55b20-5a1b-4cde-a422-32232ded6e50")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

File FFMPEGWrapper/VideoFile.cs

+using System;
+using System.IO;
+using System.Text.RegularExpressions;
+using System.Drawing;
+using StandardLogging;
+
+namespace FFMPEG
+{
+    public class VideoFile
+    {
+        private const int WatermarkXOffsetMinimum = 4;
+        private const int WatermarkXOffsetMaximum = 24;
+        private const int WatermarkYOffsetMinimum = 11;
+        private const int WatermarkYOffsetMaximum = 31;
+        protected static Random m_random = new Random();
+
+        public TimeSpan Duration
+        {
+            get;
+            private set;
+        }
+
+        public double AudioBitRate
+        {
+            get;
+            private set;
+        }
+
+        public string AudioFormat
+        {
+            get;
+            private set;
+        }
+
+        public string VideoFormat
+        {
+            get;
+            private set;
+        }
+
+        public Size Dimensions
+        {
+            get;
+            private set;
+        }
+
+        public string FilePath
+        {
+            get;
+            private set;
+        }
+
+        public VideoFile(string filePath)
+        {
+            FilePath = filePath;
+            //first make sure we have a value for the video file setting
+            if (string.IsNullOrEmpty(FilePath))
+            {
+                throw new Exception("Could not find the location of the video file");
+            }
+
+            //Now see if the video file exists
+            if (!File.Exists(FilePath))
+            {
+                throw new Exception(String.Format("The video file {0} does not exist.", FilePath));
+            }
+
+            GetVideoInfo();
+        }
+
+
+
+        public void Watermark(string watermarkFilePath)
+        {
+            // ###### FIRST ATTEMPT ######
+            // ffmpeg -y -sameq -i 9624fa724793e39a2742fc9f752e1542_robot.flv -vf "movie=pwnie-espress.png [logo]; [in][logo] overlay=main_w-overlay_w:main_h-overlay_h [out]" test.flv
+
+            // string parameters = String.Format("-y -sameq -i {0} -vf  \"movie={1} [logo]; [in][logo] overlay=main_w-overlay_w:main_h-overlay_h [out]\" {2}", inputFilePath, watermarkFilePath, outputFilePath);
+            // dimensions of the watermark image need to be the same size as the target website's video dimensions
+
+            // ###### SECOND ATTEMPT ######
+            // dimensions of the watermark can be any size
+            // ffmpeg -y -sameq -i 9624fa724793e39a2742fc9f752e1542_robot.flv -vf "movie=pwnie-espress.png [logo]; [in][logo] overlay=main_w-overlay_w-14:main_h-overlay_h-21 [out]" test.flv
+
+            string outputFilePath = Path.Combine(SuiteConfiguration.TemporaryPath, Path.ChangeExtension(Guid.NewGuid().ToString("D"), "flv"));
+            //string outputFilePath = Path.ChangeExtension(Path.GetTempFileName(), "flv");
+            //Random random = new Random();
+            int xOffset = m_random.Next(WatermarkXOffsetMinimum, WatermarkXOffsetMaximum);
+            int yOffset = m_random.Next(WatermarkYOffsetMinimum, WatermarkYOffsetMaximum);
+            //watermarkFilePath = watermarkFilePath.Replace("\\", "\\\\");
+            //string ffmpegParameters = string.Format("-sameq -vf \"movie=\\'{0}\\' [logo]; [in][logo] overlay=main_w-overlay_w-{1}:main_h-overlay_h-{2} [out]\" {3}", watermarkFilePath, xOffset, yOffset, outputFilePath);
+            FFMPEGParameters parameters = new FFMPEGParameters();
+            parameters.InputFilePath = FilePath;
+            parameters.OutputFilePath = outputFilePath;
+            parameters.SameQ = true;
+            parameters.VideoFilter = String.Format("\"movie=\\'{0}\\' [logo]; [in][logo] overlay=main_w-overlay_w-{1}:main_h-overlay_h-{2} [out]\"", watermarkFilePath.Replace("\\", "\\\\"), xOffset, yOffset);
+
+            string output = FFMPEG.Execute(parameters);
+            if (File.Exists(outputFilePath) == false)
+            {
+                throw new ApplicationException(String.Format("Failed to watermark video {0}" + Environment.NewLine + "{1}", FilePath, output));
+            }
+
+            FileInfo watermarkedVideoFileInfo = new FileInfo(outputFilePath);
+            if (watermarkedVideoFileInfo.Length == 0)
+            {
+                throw new ApplicationException(String.Format("Failed to watermark video {0}" + Environment.NewLine + "{1}", FilePath, output));
+            }
+
+            File.Delete(FilePath);
+            File.Move(outputFilePath, FilePath);
+        }
+
+        public void Resize(Size newDimensions, int videoBitrate)
+        {
+            long originalFileLength = new FileInfo(FilePath).Length;
+            string outputFilePath = Path.Combine(SuiteConfiguration.TemporaryPath, Path.ChangeExtension(Guid.NewGuid().ToString("D"), "flv"));
+            //string outputFilePath = Path.Combine(Path.GetDirectoryName(FilePath), outputFilename);
+            FFMPEGParameters parameters = new FFMPEGParameters()
+            {
+                InputFilePath = FilePath,
+                OutputFilePath = outputFilePath,
+                VideoCodec = "libx264",
+                AudioCodec = "libvo_aacenc",
+                Format = "flv",
+                BufferSize = 50000,
+                Size = newDimensions,
+                MaximumRate = 400,
+                // TODO audio channels
+                // TODO audio bitrate
+                // TODO audio buffer
+                // TODO add assert that output from FFMPEGparameters equals the string ffmpegParameters
+                OutputOptions = string.Format("-ar 22050 -ab 128k -ac 1"),
+            };
+
+            string ffmpegParameters = string.Format("-vcodec libx264 -acodec libvo_aacenc -s {0}x{1} -f flv -ar 22050 -ab 128k -ac 1 -maxrate 400KB -bufsize 50000KB {2}", newDimensions.Width, newDimensions.Height, outputFilePath);
+            string output = FFMPEG.Execute(parameters);
+            if (File.Exists(outputFilePath) == false)
+            {
+                throw new ApplicationException(String.Format("Failed to resize video {0}" + Environment.NewLine + "{1}", FilePath, output));
+            }
+
+            FileInfo resizedVideoFileInfo = new FileInfo(outputFilePath);
+            if (resizedVideoFileInfo.Length == 0)
+            {
+                throw new ApplicationException(String.Format("Failed to resize video {0}" + Environment.NewLine + "{1}", FilePath, output));
+            }
+
+            File.Delete(FilePath);
+            File.Move(outputFilePath, FilePath);
+            Log.Status(String.Format("Resized to {0}x{1}. Original length: {2:N0}  New length: {3:N0}", newDimensions.Width, newDimensions.Height, originalFileLength, resizedVideoFileInfo.Length));
+        }
+
+        public void GetVideoInfo()
+        {
+            //string ffmpegParameters = string.Format("-i {0}", FilePath);
+            string output = FFMPEG.Execute(FilePath);
+
+            //get duration
+            Duration = InfoProcessor.GetDuration(output);
+
+            //get audio bit rate
+            //AudioBitRate = FFMPEG.LastAudioBitRate;
+            AudioBitRate = InfoProcessor.GetAudioBitRate(output);
+
+            //get the audio format
+            AudioFormat = InfoProcessor.GetAudioFormat(output);
+
+            //get the video format
+            VideoFormat = InfoProcessor.GetVideoFormat(output);
+
+            //get the video dimensions
+            Dimensions = InfoProcessor.GetVideoDimensions(output);
+        }
+
+        private static Image LoadImageFromFile(string filePath)
+        {
+            Image loadedImage = null;
+            using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
+            {
+                byte[] img;
+                img = new byte[fileStream.Length];
+                fileStream.Read(img, 0, img.Length);
+                fileStream.Close();
+                loadedImage = Image.FromStream(new MemoryStream(img));
+                img = null;
+            }
+
+            GC.Collect();
+
+            return loadedImage;
+        }
+
+        private static Image ExtractSingleFrame(string filePath, int positionToExtract)
+        {
+            string tempFile = Path.ChangeExtension(Path.GetTempFileName(), "jpg");
+            string ffmpegParameters = string.Format("-f image2 -ss {1} -vframes 1 -an {0}", tempFile, positionToExtract);
+            string output = FFMPEG.Execute(filePath, ffmpegParameters);
+
+            if (File.Exists(tempFile))
+            {
+                Image previewImage = LoadImageFromFile(tempFile);
+
+                try
+                {
+                    File.Delete(tempFile);
+                }
+
+                catch (Exception ex)
+                {
+                    Log.Debug("Failed to delete temporary file used for thumbnail.");
+                    Log.Debug(ex.Message);
+                }
+
+                return previewImage;
+            }
+
+            return null;
+        }
+
+        public Image Thumbnail()
+        {
+            int positionToExtract = (int)Math.Round(TimeSpan.FromTicks(Duration.Ticks / 3).TotalSeconds, 0);
+
+            ////divide the duration in 3 to get a preview image in the middle of the clip
+            ////instead of a black image from the beginning.
+
+            Image img = ExtractSingleFrame(FilePath, positionToExtract);
+            if (img == null)
+            {
+                img = ExtractSingleFrame(FilePath, 1);
+            }
+
+            return img;
+        }
+
+    }
+
+}

File FFMPEGWrapper/ffmpeg.exe

Binary file added.