Monday, August 09, 2010

Bulk Video / Podcast Encoder for iPod / Mobile Devices

I have been using my BlackBerry and more recently my iPod nano to watch TV shows and several Revision3 podcasts which do not come in QuickTime format (Penn Jillette’s PennPoint). I have been using AKME FFmpeg for a few months to re-encode these videos, however, it is a pain to do only a few at a time manually. So I wrote this batch processor to work with AkmeFFmpeg.

Requirements: AkmeFFmpeg from http://sourceforge.net/projects/akmeffmpeg/
Suggested: SmartSync from http://www.smartsync.com/
Suggested: Juice from http://juicereceiver.sourceforge.net/

Language: C# .NET

What is AkmeFFmpeg?
AkmeFFmpeg is a simple yet powerful tool to re-encode audio-video such as
AVI, Flash FLV, MOV, MP3, MP4, WMV, 3GP. It puts a friendly GUI on the ffmpeg CLI to easily convert for YouTube or download to your BlackBerry, iPhone, iTouch, iPod, PSP, etc.

What is SmartSync?
It is a very simple GUI based application that can be used to sync directories on one or many computers.

What Does This Application Do?
It is an automated mass-converting tool that will allow you to re-encode your video files. Use this application with the task scheduler and your video files will be ready for your device by the time you wake up.

What this program does is it scans a directory and converts all of the videos in that directory to a new, smaller format and places them into another folder ready to be copied to your mobile device ("To Convert", and "Converted").

What I do is schedule this program to run every day at 3am and then I copy lots of video files into the "To Convert" folder. I also setup my podcast downloader (Juice) to download new postcast videos from Revision3 into this directory as well. Then the next day I just add the "Converted" folder to iTunes and download it all to my iPod Nano.

You will notice that the code below converts the videos to QuickTime mov files at a very low quality, that is because that is the only format my old iPod will play. However, you can change this to anything you like. Just download AKME FFmpeg and use the GUI to determine what the arguments for your specific needs should be.

 App.config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="SourceFileTypes" value="*.avi,*.mp4,*.mov" />
    <add key="RecursiveSourceDirectory" value="true" />
    <add key="SourceDirectory" value="C:\To Convert" />
    <add key="DestinationDirectory" value="C:\Converted" />
    <add key="ffmpegLocation" value="C:\Program Files (x86)\AKME\AkmeFFmpeg\ffmpeg.exe" />
  </appSettings>
</configuration>

Program.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Configuration;

using System.IO;

 

namespace VideoConverter

{

    class Program

    {

        //Get the variables from the app.config.

        public static string strSourceFileTypes = ConfigurationSettings.AppSettings["SourceFileTypes"].ToString().TrimStart(',').TrimEnd(',').Trim();

        public static bool bitRecursiveSourceDirectory = Convert.ToBoolean(ConfigurationSettings.AppSettings["RecursiveSourceDirectory"]);

        public static string strSourceDirectory = ConfigurationSettings.AppSettings["SourceDirectory"].ToString().TrimEnd('\\').Trim();

        public static string strDestinationDirectory = ConfigurationSettings.AppSettings["DestinationDirectory"].ToString().TrimEnd('\\').Trim();

        public static string strFfmpegLocation = ConfigurationSettings.AppSettings["ffmpegLocation"].ToString().Trim();

 

        static void Main(string[] args)

        {

            //Create the base directories if needed.

            if (!Directory.Exists(strSourceDirectory))

                Directory.CreateDirectory(strSourceDirectory);

 

            if (!Directory.Exists(strDestinationDirectory))

                Directory.CreateDirectory(strDestinationDirectory);

 

            //Process the root directory.

            processDirectory(strSourceDirectory);

        }

 

        private static void processDirectory(string strDirectory)

        {

            strDirectory = strDirectory.TrimEnd('\\');

 

            DirectoryInfo diRootDirectory = new DirectoryInfo(strDirectory);

 

            //If recursive is turned on and then process each sub-directory.

            if (bitRecursiveSourceDirectory)

            {

                foreach (DirectoryInfo diDirectory in diRootDirectory.GetDirectories())

                {

                    processDirectory(strDirectory + "\\" + diDirectory.Name);

                }

            }

 

            //Process each file matching the criteria.

            foreach (string strFileType in strSourceFileTypes.Split(','))

            {

                if (strFileType.Trim() != "")

                {

                    FileInfo[] fiFiles = diRootDirectory.GetFiles(strFileType);

                    foreach (FileInfo fiFile in fiFiles)

                    {

                        if (!File.Exists(strDestinationDirectory + "\\" + fiFile.Name + ".mov"))

                            processFile(fiFile.FullName, strDestinationDirectory + "\\" + fiFile.Name + ".mov");

                    }

                }

            }

        }

 

        private static void processFile(string strSourceFile, string strDestinationFile)

        {

            //Execute akmeffmpeg for each file using the following arguments.

            string strCommandArguments = "-i \"" + strSourceFile + "\" -f mov -s 240x134 -aspect 16:9 -b 128k -minrate 0k -maxrate 256k -bufsize 8192k -aq 128 -profile aac_low -y \"" + strDestinationFile + "\"";

 

            System.Diagnostics.Process proc = new System.Diagnostics.Process();

            proc.StartInfo.FileName = strFfmpegLocation;

            proc.StartInfo.Arguments = strCommandArguments;

            proc.Start();

 

            //Optional. Be warned that if you remove this, every file will be processed at the same time and your computer will become unusable, not an issue if you schedule this to run in the middle of the night.

            proc.WaitForExit();

        }

    }

} 

Monday, October 22, 2007

Linksys SPA942 Directory Synchronization

I wrote a simple C# .NET console application that can pull contacts from ether a CSV file or outlook installed on the local machine and dump them into the directory of an SPA942.

This code will probably work with other models, but I have only tested it with the SPA942 and Outlook 2003.   I am posting the source here incase anyone is interested. If you would like me to send you the .cs file, feel free to email me (I am sure the forum will mess up the code).

Use this code at your own risk.

I have uploaded the exe and cs file to http://www.abourbih.com/nathan/SPA942-UseAtYourOwn Risk.zip

Sorry about the file name, I don't want anyone blowing up a perfectly good phone if they aren't sure what their doing. It didn't blow up my phone though.

Use this code at your own risk.

using System;

using System.Collections.Generic;

using System.Text;

using System.Data;

using System.Collections;

using System.IO;

using System.Net;

using System.Web;

using Outlook = Microsoft.Office.Interop.Outlook;

 

namespace SPA942DirectorySync

{

    class Program

    {

        private static Hashtable hashIndexes = new Hashtable();

 

        public static CookieContainer cookieJar;

 

        public static string strPostData;

 

 

        static void Main(string[] args)

        {

            BuildVariables();

 

            //WipeDirectory("10.0.3.60");

 

            //AddDirectoryItem(1, "Name1", 111, 1);

            //OR

            //ReadFromCSV(@"c:\file.txt");

            //OR

            ReadFromOutlook();

 

            SaveDirectoryItems("10.0.3.60");

 

        }

 

        public static void WipeDirectory(string strIPAddress)

        {

            Console.WriteLine("Clearing directory items on SPA at " + strIPAddress + ".");

 

            string strWipeData = "";

 

            for (int i = 1; i <= 100; i++)

            {

                if (strWipeData.Length > 0)

                    strWipeData += "&";

 

                strWipeData += hashIndexes[i.ToString()].ToString() + "=";

            }

 

            Console.WriteLine(strWipeData);

            HTTPPost(cookieJar, strWipeData, "http://" + strIPAddress.Trim() + "/pdir.spa");

 

        }

 

        public static void ReadFromOutlook()

        {

            Console.WriteLine("Attempting to read outlook contacts.");

 

            Outlook._Application outlookObj = new Outlook.Application();

 

            Outlook.MAPIFolder fldContacts = (Outlook.MAPIFolder)outlookObj.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderContacts);

 

            int i = 1;

 

            foreach (Microsoft.Office.Interop.Outlook._ContactItem contactItem in fldContacts.Items)

            {

                bool bitGetContact = true;

 

                string strFullName = "";

 

                string strFirstName = "";

                try

                {

                    strFirstName = contactItem.FirstName.ToString();

                }

                catch

                {

                }

                string strLastName = "";

                try

                {

                    strLastName = contactItem.LastName.ToString();

                }

                catch

                {

                }

                string strCompanyName = "";

                try

                {

                    strCompanyName = contactItem.CompanyName.ToString();

                }

                catch

                {

                }

 

                if (strFirstName.Length > 2 && strLastName.Length > 2)

                    strFullName = strFirstName + " " + strLastName;

                else if (strCompanyName.Length > 2)

                    strFullName = strCompanyName;

                else

                    bitGetContact = false;

 

                if (bitGetContact && i <= 100)

                {

                    string strHomeTelephone = "";

                    try

                    {

                        strHomeTelephone = contactItem.HomeTelephoneNumber.ToString().Replace("(", "").Replace(")", "").Replace("-", "").Replace(" ", "").Trim();

                    }

                    catch

                    {

                    }

 

                    string strWorkTelephone = "";

                    try

                    {

                        strWorkTelephone = contactItem.BusinessTelephoneNumber.ToString().Replace("(", "").Replace(")", "").Replace("-", "").Replace(" ", "").Trim();

                    }

                    catch

                    {

                    }

 

 

                    string strMobileTelephone = "";

                    try

                    {

                        strMobileTelephone = contactItem.MobileTelephoneNumber.ToString().Replace("(", "").Replace(")", "").Replace("-", "").Replace(" ", "").Trim();

                    }

                    catch

                    {

                    }

 

                    string strPagerTelephone = "";

                    try

                    {

                        strPagerTelephone = contactItem.PagerNumber.ToString().Replace("(", "").Replace(")", "").Replace("-", "").Replace(" ", "").Trim();

                    }

                    catch

                    {

                    }

 

                    if (strFullName.Length > 35)

                        strFullName = strFullName.Substring(1, 35);

                   

                    if (strHomeTelephone.Length > 0)

                    {

                        AddDirectoryItem(i, strFullName + " (H)", Convert.ToDouble(strHomeTelephone), 1);

                        Console.WriteLine(strFullName + " (H)");

                        i++;

                    }

 

                    if (strWorkTelephone.Length > 0)

                    {

                        AddDirectoryItem(i, strFullName + " (W)", Convert.ToDouble(strWorkTelephone), 1);

                        Console.WriteLine(strFullName + " (W)");

                        i++;

                    }

 

                    if (strMobileTelephone.Length > 0)

                    {

                        AddDirectoryItem(i, strFullName + " (M)", Convert.ToDouble(strMobileTelephone), 1);

                        Console.WriteLine(strFullName + " (M)");

                        i++;

                    }

 

                    if (strPagerTelephone.Length > 0)

                    {

                        AddDirectoryItem(i, strFullName + " (P)", Convert.ToDouble(strPagerTelephone), 1);

                        Console.WriteLine(strFullName + " (P)");

                        i++;

                    }

 

                }

            }

 

        }

 

        static void ReadFromCSV(string strFilePath)

        {

            Console.WriteLine("Attempting to read CSV file " + strFilePath + ".");

 

            try

            {

                StreamReader srReader = new FileInfo(strFilePath).OpenText();

                string strLine = srReader.ReadLine();

                int i = 1;

                while (strLine != null)

                {

                    string[] strLineData;

 

                    strLineData = strLine.Split(Convert.ToChar(","));

 

                    Console.WriteLine("Name: " + strLineData[0] + " Phone: " + Convert.ToString(strLineData[1]).Replace("(", "").Replace(")", "").Replace("-", "").Replace(" ", "").Trim() + " Ringer: " + strLineData[2]);

 

                    AddDirectoryItem(i, strLineData[0], Convert.ToDouble(Convert.ToString(strLineData[1]).Replace("(", "").Replace(")", "").Replace("-", "").Replace(" ", "").Trim()), Convert.ToInt32(strLineData[2]));

 

                    strLine = srReader.ReadLine();

                    i++;

                }

                srReader.Close();

            }

            catch (Exception e)

            {

                Console.WriteLine("Error reading file " + strFilePath + ". " + e.Message);

 

                strPostData = "";

            }

        }

 

        static void BuildVariables()

        {

            Console.WriteLine("Building variables.");

 

            strPostData = "";

 

            hashIndexes.Add("1", "28398");

            hashIndexes.Add("2", "28334");

            hashIndexes.Add("3", "28526");

            hashIndexes.Add("4", "28462");

            hashIndexes.Add("5", "28654");

            hashIndexes.Add("6", "28590");

            hashIndexes.Add("7", "27758");

            hashIndexes.Add("8", "27694");

            hashIndexes.Add("9", "27886");

            hashIndexes.Add("10", "27822");

            hashIndexes.Add("11", "28014");

            hashIndexes.Add("12", "27950");

            hashIndexes.Add("13", "28142");

            hashIndexes.Add("14", "28078");

            hashIndexes.Add("15", "21102");

            hashIndexes.Add("16", "21038");

            hashIndexes.Add("17", "21230");

            hashIndexes.Add("18", "21166");

            hashIndexes.Add("19", "21358");

            hashIndexes.Add("20", "21294");

            hashIndexes.Add("21", "21486");

            hashIndexes.Add("22", "21422");

            hashIndexes.Add("23", "20590");

            hashIndexes.Add("24", "20526");

            hashIndexes.Add("25", "20718");

            hashIndexes.Add("26", "20654");

            hashIndexes.Add("27", "20846");

            hashIndexes.Add("28", "20782");

            hashIndexes.Add("29", "20974");

            hashIndexes.Add("30", "20910");

            hashIndexes.Add("31", "22126");

            hashIndexes.Add("32", "22062");

            hashIndexes.Add("33", "22254");

            hashIndexes.Add("34", "22190");

            hashIndexes.Add("35", "22382");

            hashIndexes.Add("36", "22318");

            hashIndexes.Add("37", "22510");

            hashIndexes.Add("38", "22446");

            hashIndexes.Add("39", "21614");

            hashIndexes.Add("40", "21550");

            hashIndexes.Add("41", "21742");

            hashIndexes.Add("42", "21678");

            hashIndexes.Add("43", "21870");

            hashIndexes.Add("44", "21806");

            hashIndexes.Add("45", "21998");

            hashIndexes.Add("46", "21934");

            hashIndexes.Add("47", "23150");

            hashIndexes.Add("48", "23086");

            hashIndexes.Add("49", "23278");

            hashIndexes.Add("50", "23214");

            hashIndexes.Add("51", "23406");

            hashIndexes.Add("52", "23342");

            hashIndexes.Add("53", "23534");

            hashIndexes.Add("54", "23470");

            hashIndexes.Add("55", "22638");

            hashIndexes.Add("56", "22574");

            hashIndexes.Add("57", "22766");

            hashIndexes.Add("58", "22702");

            hashIndexes.Add("59", "22894");

            hashIndexes.Add("60", "22830");

            hashIndexes.Add("61", "23022");

            hashIndexes.Add("62", "22958");

            hashIndexes.Add("63", "24174");

            hashIndexes.Add("64", "24110");

            hashIndexes.Add("65", "24302");

            hashIndexes.Add("66", "24238");

            hashIndexes.Add("67", "24430");

            hashIndexes.Add("68", "24366");

            hashIndexes.Add("69", "24558");

            hashIndexes.Add("70", "24494");

            hashIndexes.Add("71", "23662");

            hashIndexes.Add("72", "23598");

            hashIndexes.Add("73", "23790");

            hashIndexes.Add("74", "23726");

            hashIndexes.Add("75", "23918");

            hashIndexes.Add("76", "23854");

            hashIndexes.Add("77", "24046");

            hashIndexes.Add("78", "23982");

            hashIndexes.Add("79", "17006");

            hashIndexes.Add("80", "16942");

            hashIndexes.Add("81", "17134");

            hashIndexes.Add("82", "17070");

            hashIndexes.Add("83", "17262");

            hashIndexes.Add("84", "17198");

            hashIndexes.Add("85", "17390");

            hashIndexes.Add("86", "17326");

            hashIndexes.Add("87", "16494");

            hashIndexes.Add("88", "16430");

            hashIndexes.Add("89", "16622");

            hashIndexes.Add("90", "16558");

            hashIndexes.Add("91", "16750");

            hashIndexes.Add("92", "16686");

            hashIndexes.Add("93", "16878");

            hashIndexes.Add("94", "16814");

            hashIndexes.Add("95", "18030");

            hashIndexes.Add("96", "17966");

            hashIndexes.Add("97", "18158");

            hashIndexes.Add("98", "18094");

            hashIndexes.Add("99", "18286");

            hashIndexes.Add("100", "18222");

        }

 

        static void AddDirectoryItem(int intLocation, string strName, Double douPhone, int intRing)

        {

            Console.WriteLine("Adding directory name " + strName + ".");

 

            if (strPostData.Length > 0)

                strPostData += "&";

 

            strPostData += hashIndexes[intLocation.ToString()].ToString() + "=n%3d" + HtmlEncode(strName).Trim() + ";p%3d" + douPhone.ToString() + ";r%3d" + intRing.ToString();

 

        }

 

        static void SaveDirectoryItems(string strIPAddress)

        {

            Console.WriteLine("Saving directory items to SPA at " + strIPAddress + ".");

 

            HTTPPost(cookieJar, strPostData, "http://" + strIPAddress.Trim() + "/pdir.spa");

        }

        public static string HtmlEncode(string strString)

        {

            strString = strString.Replace("(","%28");

            strString = strString.Replace(")", "%29");

            strString = strString.Replace(" ", "%20");

            strString = strString.Replace("&", "%26");

 

            return strString;

        }

        private static string HTTPPost(CookieContainer cookieJar, string strPOST, string strURL)

        {

            Console.WriteLine("Posting HTTP data.");

 

            string strResponse = "";

 

            //Our postvars

            byte[] buffer = Encoding.ASCII.GetBytes(strPOST);

 

            //Initialisation, we use localhost, change if appliable

            HttpWebRequest WebReq = (HttpWebRequest)WebRequest.Create(strURL);

 

            WebReq.CookieContainer = cookieJar;

 

            //Our method is post, otherwise the buffer (postvars) would be useless

            WebReq.Method = "POST";

 

            //We use form contentType, for the postvars.

            WebReq.ContentType = "application/x-www-form-urlencoded";

 

            //The length of the buffer (postvars) is used as contentlength.

            WebReq.ContentLength = buffer.Length;

 

            //We open a stream for writing the postvars

            Stream PostData = WebReq.GetRequestStream();

 

            //Now we write, and afterwards, we close. Closing is always important!

            PostData.Write(buffer, 0, buffer.Length);

            PostData.Close();

 

            //Get the response handle, we have no true response yet!

            HttpWebResponse WebResp = (HttpWebResponse)WebReq.GetResponse();

 

            //Let's show some information about the response

            Console.WriteLine(WebResp.StatusCode);

            Console.WriteLine(WebResp.Server);

 

            //Now, we read the response (the string), and output it.

            Stream Answer = WebResp.GetResponseStream();

            StreamReader _Answer = new StreamReader(Answer);

            strResponse = _Answer.ReadToEnd();

 

            return strResponse;

        }

    }

}

 

 

 

Copyright © Nathan Abourbih