Archive for the ‘Web & Design’ Category

Encoding high quality h.264 / aacPlus v2 media for web streaming with Flash 9, version 2.

Tuesday, January 1st, 2008

Update Notice

This post has been updated with a newer and improved script and instructions, please visit the new one HERE.

It was some months ago when I wrote a tutorial about how to encode good quality h.264 video with aacPlus audio in order to use the great capabilities of the new flash player version 9.0.115 (that in case you missed it, now can play h264 video and aacPlus v2 audio).
Due to some personal convictions for my prior tutorial, i decided to use FFMPEG, and while it does the job pretty well, it has some limitations (specially in the video scaling / resizing area). So in my particular case, I had to use several php / bash scripts in order to feed the encoders with the proper resizing data, etcetera.
Well, let me introduce you to the 2nd version of my h.264 / aacPlus v2 tutorial.

This time I used Mencoder, an amazing tool that comes with the mPlayer package, and i also created what i think is a really nice bash script to make the process almost 100% smooth and simple.

These are the things you will need:

(more…)

Switching servers…

Monday, December 17th, 2007

Hi there all, just a quick note to inform you that i am switching servers in the following days.
I’m going to move this blog to a dedicated server provided by the guys at SolarVPS, why ?
Simply because i have several servers with them already so i know their service quality, also because they have an unbeatable price / features relation, and because their support is just from other world, one of the few big companies where you still can talk (chat) with the CEO eventually.
So, expect some DNS downtime in the following days. :)

Record your favorite radio shows and generate a podcast with the episodes.

Tuesday, October 9th, 2007

Podcast as shown by iTunes 7Ok, this is something that i had in mind since some time ago but i didn’t had the time to actually do it. But now i finished it.
The situation is like this, there is a radio show that i love, but the problem is that this radio show starts at 12 AM and finishes at 2 AM, and usually, I’m doing any other thing at that time in the night.
So, i decided to create some simple script to record the audio in one of my servers (by using the Radio station internet broadcast).

For all this to work, you will need the following things:

  1. PHP 5.1.6 or newer
  2. MPlayer
  3. the GPAC utilitles
  4. the Nero Digital AAC Encoder

The idea for the bash script to record the audio stream is based on a nice tutorial by Phil Salkie, but honestly, i think i improved it a lot, specially because it uses a FIFO as temporary storage, and because it compresses the audio to a more recent audio format like HE-AAC.

Basically, the following bash script will record any audio stream of your choice and will convert it to a HE-AAC file inside an m4a container compatible with any audio player out there AND iTunes / iPod of course ;)

After the audio file is done, the second script will generate a podcast feed (RSS) compatible with iTunes or any podcast client out there, like for example Juice.

Here is the script to capture the radio show and convert it to a M4A file (AAC Plus inside an MP4 container).

#!/bin/bash
TERM="linux"
# RANDOM GUID GENERATION
SUM=`date`
SUM2=`echo $SUM | md5sum | cut -c 1-8`

# INITIALIZATION VARIABLES
DATE=`date +%F`  # Save the date as YYYY-MM-DD
FILE=/home/plusmedia/public_html/media/$DATE---$SUM2.mp4  # WHERE TO SAVE THE STREAM ?
STREAM=mms://200.43.193.143/radio10  # The URL of the stream to save.
FIFO=/tmp/stream.wav  # We create a FIFO as intermediate storage for the encoding.
ARTWORK=/home/plusmedia/public_html/lvst.jpg  # Path to some artwork file for iTunes, can be JPG or PNG.
DURATION=122m # How many minutes should we record ?

# MP4 TAGS
AUTHOR="Some Author"
ALBUM="Some Radio Show"
TITLE="Some Radio Program - $DATE" 

# We use mplayer to capture the stream to a wav file being stored into a FIFO.
mkfifo $FIFO
/usr/bin/mplayer $STREAM -af resample=44100:0:2,volume=0:1,pan=1:0.5:0.5,comp -ao pcm:file="$FIFO" -vo null -vc dummy < /dev/null 2>&1 >/dev/null & pA=$!

# Encoding the fifo to AAC with the Nero Digital Encoder for Linux.
/usr/bin/neroAacEnc -br 24000 -he -if $FIFO -of $FILE & pB=$!

sleep $DURATION  # wait for the show to be over

kill $pA # end the mplayer process
sleep 2s # IMPORTANT! wait a while for the Nero encoder to finish and close the opened files.

echo "CREATING M4A AND APPLYING TAGS..."
/usr/bin/MP4Box -add "$FILE#audio" -itags cover="$ARTWORK":artist="$AUTHOR":comment="$DATE":album_artist="$AUTHOR" -lang english -new "${FILE%.*}.m4a"
sleep 1s
echo "Generating Podcast Item..."
# We have a new episode recorded, so it is time to call the podcast generation script to update the RSS feed.
/home/plusmedia/podcast

echo "Deleting FIFO and temporary files..."
rm $FIFO -f
rm $FILE -f

echo "done!"

And this is the PHP script to generate the “iTunes Compliant” podcast feed:

#!/usr/bin/php
setIndent = true;
    $xmlObject->openMemory();
    $xmlObject->startDocument('1.0','UTF-8');
    $xmlObject->startElement ('rss'); //
    $xmlObject->writeAttribute( 'xmlns:itunes', 'http://www.itunes.com/dtds/podcast-1.0.dtd');
    $xmlObject->writeAttribute( 'version', '2.0');
	$xmlObject->startElement ('channel');
	$xmlObject->writeElement ('title', $title);
	$xmlObject->writeElement ('link', $link);
	$xmlObject->writeElement ('language', $language);
	$xmlObject->writeElement ('copyright', $copyright);
	$xmlObject->writeElement ('itunes:subtitle', $itunesSubtitle);
	$xmlObject->writeElement ('itunes:author', $itunesAuthor);
	$xmlObject->writeElement ('itunes:summary', $itunesSummary);
	$xmlObject->writeElement ('itunes:explicit', $itunesExplicit);
	$xmlObject->writeElement ('description', $description);
		$xmlObject->startElement ('itunes:owner');
		$xmlObject->writeElement ('itunes:name', $ownerName);
		$xmlObject->writeElement ('itunes:email', $ownerEmail);
		$xmlObject->endElement();
	$xmlObject->startElement ('itunes:image');
		$xmlObject->writeAttribute ('href', $baseURL.$image);
	$xmlObject->endElement();
		$xmlObject->startElement ('itunes:category');
		$xmlObject->writeAttribute ('text', $mainCategory);
			$xmlObject->startElement ('itunes:category');
			$xmlObject->writeAttribute ('text', $childCategory);
			$xmlObject->endElement();
		$xmlObject->endElement();
// 	ITEMS
	$files = scandir($mediaDIR);
	$sortedFiles = array();
	foreach ($files as $filePath) {
		$fileItem = array( 	'modified'  => filemtime($mediaDIR.$filePath),
							'path'		=> $filePath
		            	 );
		array_push ($sortedFiles, $fileItem);
	}
	usort($sortedFiles, "cmp");
	foreach ($sortedFiles as $value) {
		$extension = substr($value['path'], strrpos($value['path'], "."));
		if ($extension == $fileExtension) {
			$nameParts = explode("---", parseFileName($value['path']));
			$xmlObject->startElement ('item');
			$dateComponent = strtotime($nameParts[0]);
			$xmlObject->writeElement ('title', $itemTitle.strftime('%A, %B %d, %Y', $dateComponent));
			$xmlObject->writeElement ('itunes:author', $itunesAuthor);
			$xmlObject->writeElement ('itunes:subtitle', $itunesSubtitle);
			$xmlObject->writeElement ('itunes:image', $baseURL.$image);
			$xmlObject->writeElement ('pubDate', date('r', $dateComponent));
			$xmlObject->startElement ('enclosure');
				$xmlObject->writeAttribute( 'url', $baseURL.$mediaURL.$value['path']);
				$xmlObject->writeAttribute( 'length', filesize($mediaDIR.$value['path']));
				$xmlObject->writeAttribute( 'type', 'audio/x-m4a');
			$xmlObject->endElement(); //
			$xmlObject->writeElement ('guid', $baseURL.$mediaURL.$value['path']);
			$xmlObject->endElement(); //
		}
	}
	$xmlObject->endElement(); //
    $xmlObject->endElement(); // 

// 	Write XML data to file...
    writeXmlFile($xmlObject->outputMemory(true), $XML);    

function writeXmlFile($contents, $file) {
	$fh = fopen($file, 'w') or die("can't open file");
	fwrite($fh, $contents);
}

function parseFileName($fileName) {
	$input = explode(".",$fileName);
	$noExt = $input[0];
	return $noExt;
}

// Custom array ordering function for usort
// orders by REVERSE order (Biggest timestamp goes FIRST).
function cmp($a, $b)
{
    return strcmp($b["modified"], $a["modified"]);
}
?>

The PHP script will scan a given directory for files with the extension “m4a” (or any other extension configured in the $fileExtension variable), it will order the files by their created date (in reverse order) and will generate a file called “podcast.xml” that you can access with iTunes on mac or PC, or you could use any other podcast client like Juice.

You should for example call the bash script “recorder” and call the php script “podcast”, then chmod +x both files to make them executables, and then just run the bash script by typing:

./recorder

Obviously, the idea behind all this is that you should create a crontab entry to run the process automatically, in my case, it runs everyday at 12:00 AM and i did set the duration variable to 121 minutes (2 hours and a bit).
All the rest should be smooth and automatic if you configured correctly the initialization variables in both scripts.

More changes to Illacrimo for WordPress

Thursday, October 4th, 2007

As you can see, i did several other changes to the Illacrimo theme for WordPress.
Between several minor fixes, you will notice that there is more space on the post column now, and I removed the original column for the post’s date too. Instead, the date is located now next to the post title.
I also replaced several images with CSS equivalents, so the site loads a little faster now and uses less bandwidth.
You can download the new version by clicking here.

If you have any questions or suggestions, you can leave a comment on this post.

Serverside video resizing script for ffmpeg or Mencoder

Monday, October 1st, 2007

Some days ago, while working on a project that involves the re-encoding of a lot of videos coming from several sources, aspect ratios, resolutions, etc, i found myself in the situation where i needed to “standarize” somehow all the videos to a prefixed size in order to place them on a fixed space in a web page.
While most linux tools like ffmpeg or mencoder include native functions to scale or resize the video, they don’t care about the aspect ratios or about the fact that most video encoders expect mod16 values for the height and width values.
So my situation was like this:

I needed to make all the videos 480 pixels high, and scale the width proportionally.

That being said, i came up with this PHP script that i call from inside a bash script:

#!/usr/bin/php
<?php
$cmdWidth = 'midentify '.$argv[1];
$finalHeight = $argv[2];
exec($cmdWidth, $output);

foreach ($output as $value) {
    if (strstr($value, "ID_VIDEO_WIDTH")) {
		
		$width = parseResult($value);
    }
    if (strstr($value, "ID_VIDEO_HEIGHT")) {
    	$height = parseResult($value);
    }
}
$frameSize = $width / $height;
$finalWidth = $finalHeight * $frameSize;
echo getMod16(round($finalWidth)) . "x" . getMod16(round($finalHeight)) . "\n";
function parseResult($line) {
	$v1 = explode("=",$line);
	$v20 = $v1[1];
	
	//var_dump($v2);
	return $v20;
}
function getMod16($number){
	while (fmod($number, 16) != 0) {
		$number ++;
	}
	return $number;
}
?>

This script assumes that you have the “midentify” utility (wich comes with mplayer) installed in your path, and expects 2 arguments, being argument 1 the movie you want to resize and argument 2 the actual height you want to reach.
That being said, suppose you have a movie that is 848 pixels width and 480 pixels high and you want to re-scale it so it fits inside a 400 pixels high space, you would call the script like this:

./resizer mymovie.avi 400

The script will output this:

720x400

You can use later this value as an input parameter for ffmpeg for example.

Before somebody asks, the reason because i used PHP instead of BASH, is simply because bash does not supports floats.

CSSEdit 2.5, a visual CSS Editor that doesn’t suck.

Thursday, September 27th, 2007

CSSEdit 2.5 screenshotOh my God, some weeks ago I bought a license for this amazing piece of software made by the guys at macrabbit.com. This is not just another CSS Editor, this is **THE** CSS Editor.
Not only you can edit each and every aspect of the css code in a visual manner, but also, every change that you do is reflected in the display window in real time! Yay!
One of the features that i really love about this software is the “X-Ray” function, where you basically click on the different elements of the webpage you are working on, and it tells you all the CSS classes that are affecting it, you also see the full inheritance tree and you can, obviously create new CSS Classes with full inheritance control thanks to the “inspector” window.
(more…)

Illacrimo WordPress theme: validated and fixed.

Wednesday, September 26th, 2007

As you maybe noticed, i am using the excellent Illacrimo theme for wordpress on this blog because, basically, i was lazy to code and design my own theme, but most importantly, because i just loved this one.

In any case, there were some minor problems about this really wonderful theme:

  1. It was not Valid XHTML
  2. It was not Valid CSS
  3. There were some minor discrepancies around different browsers (specially in the search box)

So i just fixed the whole HTML and CSS code to be 100% valid, and i also corrected the minor CSS related problems in regards to the search box.
I also did some other minor modifications regarding the line and letter spacing on the fonts to make it “easier to the eyes”.

Please note that this theme includes MY OWN ADSENSE code on it. In order to remove or replace the adsense block with your own, you MUST edit the files single.php and sidebar.php and replace the adsense block with your own. I added adsense directly inside the template to avoid the use of an extra plugin.

Also, in order to create the “info” box (like this one) or the “quote” box, you need to use a span with “info” or “quote” as the class name:
<span class=\"info\">the text for the info box goes here</span>

If you want, you can download the “fixed” version by clicking here.