EE Logo Twitter Logo Facebook Logo Linked In Logo

June 21, 2011

Getting Started With Video Streaming


File Formats

When streaming videos over the Internet you must decide to encode your videos in either MP4 or FLV formats. Most servers and players support both file formats. I personally recommend using MP4 because you get DVD quality videos at a much smaller file size. It also uses less CPU on client machines and it works on mobile phones. The downside to MP4 is that the videos will take longer to load than an FLV video.

FFMPEG is a great free and very powerful encoder, but can be somewhat difficult to learn. It supports many popular video formats and has many options to configure. Bitrate is probably the most important factor in determining the quality and file size of your video. If your video contains lots of action and motion it will need to have a higher bitrate. Youtube encodes their normal videos at a bitrate of 200kbps and their high quality videos at 900kbps. Be wise in picking a bitrate because the higher it is the more likely users will experience streaming problems.

Streaming and Servers

There are three different types of streaming. These types are progressive download, pseudo streaming, and RTMP. Progressive download is just like downloading any file off the Internet expect that the user can begin watching the part that has downloaded. The downside to this is that it is very load and bandwidth intensive and the user can not skip to parts of the video that have not been downloaded yet.

Pseudo streaming is just like progressive streaming except that it allows the user to skip around in the video even to parts that have not been downloaded yet. Youtube is a greate example of pseudo streaming. Pseudo streaming is usually enabled through the use of mods or plugins on HTTP servers such as Apache, Lighthttpd, or Nginx. Pseudo streaming is also a lot less load intensive and provides ways to throttle bandwidth.

RTMP streaming was created by Adobe Flash and provides ways to stream secure copyrighed content. Unlike progressive download and pseudo streaming, RTMP does not download to the clients computer or browser’s cache but only buffers a small bit into the flash players memory. Some popular servers that support this type of streaming are Red5, Wowza, and Flash Media Server.

Players

Many different players can be found across the Internet but there seems to be two feature rich players that dominate the market. Both Flowplayer and JW Player provide features like plugins, JavaScript API, and skins. Both are great players having slight differences and offerings making it a matter of user preference on which to use.

April 11, 2011

SEO Friendly URLS in CodeIgniter 2.0 + HMVC


Many of you SEO fanatics may have realized that CodeIgniter is not very SEO-friendly out of the box. It auto generates URLs based on routes which are made up of a controller name and method name. For URLs to be considered SEO-friendly and be universally recognized by search engines, keywords must be separated by a dash. Many of you are thinking you will just go rename your controllers and methods with dashes. That would be nice and easy, but this is not a legal syntax and PHP will throw errors. There is the option to manually enter each route in your routes.php file, but this could be a serious beat down and come back to haunt you later on down the road.

Here is a quick guide to get your CodeIgniter 2.0 + HMVC (Modular Extensions) setup supporting SEO friendly URLs:

Because of the way CodeIgniter functions, you will not have to make any changes to your CodeIgniter or HMVC core files. When you installed HMVC you should have added a MY_Router.php file to the /application/core/ directory. By replacing that file with the following code you should now be able to reference controllers and methods with dashes. For example a controller with the name my_controller can can now be referenced as my-controller in your URL.

<?php (defined('BASEPATH')) OR exit('No direct script access allowed');
// load the MX_Router class
require APPPATH."third_party/MX/Router.php";                                                                             

class MY_Router extends MX_Router {                                                                                      

    private $module;                                                                                                     

    public function fetch_module() {
        return $this->module;
    }                                                                                                           

    public function _validate_request($segments) {                                                                       

        /* locate module controller */
        if ($located = $this->locate($segments)) return $located;                                                        

        /* use a default 404 controller */
        if (isset($this->routes['404']) AND $segments = explode('/', $this->routes['404'])) {
            if ($located = $this->locate($segments)) return $located;
        }                                                                                                                

        /* use a default 404_override controller CI 2.0 */
        if (isset($this->routes['404_override']) AND $segments = explode('/', $this->routes['404_override'])) {
            if ($located = $this->locate($segments)) return $located;
        }                                                                                                                

        /* no controller found */
        show_404();
    }                                                                                                                    

    /** Locate the controller **/
    public function locate($segments) {                                                                                  

        $this->module = '';
        $this->directory = '';
        $ext = $this->config->item('controller_suffix').EXT;                                                             

        /* use module route if available */
        if (isset($segments[0]) AND $routes = Modules::parse_routes($segments[0], implode('/', $segments)) {
            $segments = $routes;
        }                                                                                                                

        /* get the segments array elements */
        list($module, $directory, $controller) = array_pad($segments, 3, NULL);                                          

        $module = str_replace('-', '_', $module);                                                                                                                                                                                

        $controller = str_replace('-', '_', $controller);                                                                                                    

        $directory = str_replace('-', '_', $directory);                                                                  

        foreach (Modules::$locations as $location => $offset) {                                                          

            /* module exists? */
            if (is_dir($source = $location.$module.'/controllers/')) {                                                   

                $this->module = $module;
                $this->directory = $offset.$module.'/controllers/';                                                      

                /* module sub-controller exists? */
                if($directory AND is_file($source.$directory.$ext)) {
                    return array_slice($segments, 1);
                }                                                                                                        

                /* module sub-directory exists? */
                if($directory AND is_dir($module_subdir = $source.$directory.'/')) {                                     

                    $this->directory .= $directory.'/';                                                                  

                    /* module sub-directory controller exists? */
                    if(is_file($module_subdir.$directory.$ext)) {
                        return array_slice($segments, 1);
                    }                                                                                                    

                    /* module sub-directory sub-controller exists? */
                    if($controller AND is_file($module_subdir.$controller.$ext))    {
                        return array_slice($segments, 2);
                    }
                }                                                                                                        

                /* module controller exists? */
                if(is_file($source.$module.$ext)) {
                    return $segments;
                }
            }
        }                                                                                                                

        /* application controller exists? */
        if(is_file(APPPATH.'controllers/'.$module.$ext)) {
            return $segments;
        }                                                                                                                

        /* application sub-directory controller exists? */
        if(is_file(APPPATH.'controllers/'.$module.'/'.$directory.$ext)) {
            $this->directory = $module.'/';
            return array_slice($segments, 1);
        }                                                                                                                

        /* application sub-directory default controller exists? */
        if(is_file(APPPATH.'controllers/'.$module.'/'.$this->default_controller.$ext)) {
            $this->directory = $module.'/';
            return array($this->default_controller);
        }
    }                                                                                                                 

    public function set_class($class)
    {
        $this->class = str_replace('-', '_', $this->class).$this->config->item('controller_suffix');
    }                                                                                                                 

    public function set_method($method)
    {
        $this->method = str_replace('-', '_', $this->method);
    }
}

November 19, 2010

My Head’s in the Cloud


If you happen to follow the Einstein’s Eyes twitter (www.twitter.com/einsteinseyes) or are a fan of our Facebook page (www.facebook.com/einsteinseyes), then you may have seen a few recent articles posted that discuss cloud computing. This is an area that fascinates me – I am personally convinced that cloud computing is the current “next big thing” in our industry.

Before my time, companies used a mainframe and terminal setup – employees had access to terminals that they could log into and use the mainframe’s resources to run their programs or look up their information. More recently, scientists have been uploading their programs to supercomputers and reserving time slots for them to actually run their programs. For both of these situations, the involved tasks are hugely complex (for the time period) and thus running them on a personal computer would either be too expensive or take far too long. The ability to utilize one extremely powerful machine for these problems was a great solution – and cloud computing is the new development in this area.

Essentially, a cloud is a large set of computers working together as one. Traditionally, we think of computers as individual entities – you have a CPU, memory, hard disk, various inputs and outputs, and it all works inside the bounds of an operating system, but clouds rethink this age-old idea. Instead, think of a computer as a set of CPUs, each with their own memory, their own hard disk, their own I/Os, and yet just one distributed operating system between them all.

There is no one “master” computer involved; every computer in a cloud has the potential to begin its own process and allocate resources to other computers. Additionally, a cloud of X total computers can recover gracefully from the failing of up to X computers in their cloud; basically, the only way to take down a cloud is to take down every single computer in the cloud. Also, clouds allow for new computers to be added to the cloud at any time, and can even rejoin computers that failed unexpectedly and get them caught back up to where they were.

Clouds are the future of the supercomputer. The notion of a supercomputer has grown to mean a ginormous space heater with many hundreds or thousands of processors chugging along on some distributed memory and hard disk space. Clouds can redefine this. I’m sure that the most powerful supercomputers of tomorrow will actually just be clouds. No longer will you need an entire floor for the next best computer (though, of course you could), you’ll instead be able to distribute the computers all around the world!

In a way, clouds will be a return to the idea of the mainframe and terminal. You’ll be able to purchase a very inexpensive PC that, with a good internet connection, will be more powerful than any $5,000 machine you could build yourself. Basically, your computer will only need to be capable of streaming inputs and outputs to and from the cloud – something any computer made in the last 10 years should be able to handle. Your computer just handles the display and relaying of I/Os and the cloud handles all of the actual “thinking” for you.

There are already some companies that are utilizing clouds. Google is one example. Another is OnLive, a subscription service for computer games. You pay a subscription fee, which gives you access to the OnLive cloud. They claim that when they go live in 2011 that subscribers will be able to game at 60 frames per second in up to 1080p – the home computer and internet connection will only need to be able to handle a video stream of their desired speed and quality.

Cloud computing is not without its faults (openness of the cloud, potential for sensitive information to be captured by others in the cloud, etc), but despite these issues, I’m sure that clouds will become quite a norm in the near future.

September 21, 2010

Before Search Engine Optimization Can Start


There is a lot of talk about Search Engine Optimization (SEO) and there is an expectation that every website will be searchable by Google right away. I have heard SEO described as mysterious or voodoo-like. The simple truth is that before an SEO project can start, your web site has to be developed in a manner that is Search Engine Friendly (ready for SEO). There is no mystery or voodoo involved – as a matter of fact, Google tells you exactly what is needed for a Search Engine Friendly site and it is a good standard coding practice.

From Google’s Search Engine Optimization Starter Guide, here are the six most important items that are required for your website to be built as Search Engine Friendly:

Read more…

August 27, 2010

How about them DOCTYPES


Document Type Definitions (DTD), also known as DOCTYPES, are markup declarations of web standards designed to increase cross-browser compatibility. Unfortunately, there are many options to choose from and very few details on the web of what exactly they do and how they differ. As you may have noticed, most DTDs reference the website w3.org (W3Schools). This is because W3Schools is backed by a large community and is considered to lead the web development industry and define its standards.

When utilizing a DTD, your browser will render in standards mode instead of the default backwards-compatible quirks mode. Quirks mode should only be used on websites written for older browsers. One of the biggest differences between quirks mode and standards mode is the quirks’ rendering of CSS in Internet Explorer as compared to other browsers. The Internet Explorer rendering, known as the Internet Explorer box model bug, differs from the W3C standards being that the content, padding and borders are within a specified width or height. W3C standards, on the other hand, define padding and borders as an addition to the specified width or height of the content. This issue has been resolved in the standards mode of Internet Explorer 6 and greater. Other notable quirks include browser differences in the vertical alignment of images and the ability of tables to inherit the CSS default font styles.

Your DTD should be the very first thing on the HTML page preceding the <html> tag without any leading white space. When picking a declaration you must choose between using an HTML or XHTML declaration. XHTML is very similar to HTML and is to help the transition to a new generation of mark-up languages. XHTML looks just like HTML except that it enforces syntax rules such as case sensitivity and that elements are properly closed. There is not much benefit of using XHTML markup over HTML other than that it is XSL ready, easier to maintain, and is ready for the future.

Generally, all new sites should aim to use a Strict DOCTYPE. A Strict DOCTYPE encourages and helps enforce the separation of structure and presentation as it excludes presentation attributes and elements. Also, using a Strict DOCTYPE ensures that browsers use their strictest, most standards complaint rendering modes. A Transitional DOCTYPE, however, is designed for older sites to make the transition to modern ways. The Transitional DOCTYPE permits the use of deprecated legacy markup such as <font>, <iframe>, and <u>. A full list of supported markup elements for the different DOCTYPES can be found here.

For a great list of available DOCTYPE declarations you can visit the W3School’s HTML <!DOCTYPE> Declaration page. When picking a declaration, be sure that it contains a full URL and that the URL actually works. There are many websites that post declarations that use relative paths or have a .dtd URL that longer works. You can test this by visiting to the URL address in your browser.

August 5, 2010

Search Engine Truths


Frequently people will ask us how they can improve their website rankings in search engines. Over the past four years, we have developed the following list of suggestions.

  • Use unique and meaningful title information on every page. When title information is repetitive, the search engine assumes that the pages are too. The same is true for meta description.
  • Include your listing on relevant online directories such as Yellow Pages, Yahoo, Yelp, local service directories or professional groups.
  • Remove technology like frames and excessive graphics, especially if they include text. Text should stand on its own as HTML. Otherwise, it is guaranteed not be seen by search engines.
  • Keep a good balance between text and graphics. Search engines will ignore your graphics and focus on your text, but actual visitors will respond to both.
  • Keep your message accurate and current. More frequently updated sites tend to be indexed more. More usable updates satisfy visitors. Look at ways to add to your content. Blogs or regular site updates can be helpful.
  • Look for online communities to participate in. Freely exchanging information and providing expertise about your field will always increase success.
  • Monitor visitor activity and trends. Review activity and change your website to produce the desired results.

May 24, 2010

It’s just a Report


When developing applications, there is always a requirement to develop reports. And it seems that once everything is gathered and documented to develop the application itself, sometimes the report requirements are left until the end. After all, it’s just a report, right? How hard can it be? But when it comes to reports, the devil is in the details. Here is the approach we use to make sure the client has everything they need: Read more…

April 30, 2010

Facing Your Fonts


Let’s face it

For some time now web developers have relied on a hand full of “web-safe” fonts for dealing with text on their sites before giving up and using an image to satisfy a design requirement. Recently however I’ve been hearing more and more about using the css attribute font-face to help break down some of these barriers.

The idea behind the font-face attribute is to load the font definition into the browser at run time to allow the developer access to a font family they have created themselves or one that is available to them via the web. Let’s see how it looks in practice shall we?

Read more…

April 2, 2010

The Cost of Spam


The effects and cost of Spam are never easy to encapsulate, but Spam can be a huge problem for a small business. Spam is more then a nuisance – it affects our most critical business communication tool and also costs the following:

Loss of Productivity: The first indicator of a Spam problem is loss of productivity. If returning to work after a long weekend causes a lot of pain because of the emails you have to sort through, chances are you have a Spam problem. The average employee can spend the better part of a full day per month sorting through Spam on an unfiltered system – and possibly losing legitimate emails, which wastes even more time. Read more…

March 26, 2010

Adventures in Speed


App Speed

The Most Important Metric

Speed. The metric by which all websites are eventually judged. You may have the most beautiful design, the best content, the latest markup and coolest JavaScript libraries but in the end it doesn’t mean squat if your pages take forever to load. Do we really know what we need to do to improve performance or do we merely think we do?

Saving Cycles

The classic approach to improving application performance is to look everywhere to save processor cycles. How many of us have spent countless days tracking down inefficient database queries or  errant loops just trying to save a line here or a line there in our application? Sometimes it seems as if we do nothing but try to think of ways to re-factor our code to save lines. It feels as if we can save just one more line of code it will run faster and we trim and tweak and pour over the code looking for every place we can cut back and shave.

At the end of the day, however, how much have we really saved? Is it even noticeable to the end-user? Read more…

Older Posts »

© 2012 Einstein's Eyes