1. video – more than just a tag

    This article is written by Paul Rouget, Mozilla contributor and purveyor of extraordinary Open Web demos.

    Starting with Firefox 3.5, you can embed a video in a web page like an image. This means video is now a part of the document, and finally, a first class citizen of the Open Web. Like all other elements, you can use it with CSS and JavaScript. Let’s see what this all means …

    The Basics

    First, you need a video to play. Firefox supports the Theora codec (see here to know all media formats supported by the audio and video elements).

    Add the video to your document:

    <video id="myVideo" src="myFile.ogv"/>

    You might need to add some “fallback” code if the browser doesn’t support the video tag. Just include some HTML (which could be a warning, or even some Flash) inside the video tag.

    <video id="myVideo" src="myFile.ogv">
    <strong>Your browser is not awesome enough!</strong>
    </video>

    Here’s some more information about the fallback mechanism.

    HTML Attributes

    You can find all the available attributes here.

    Some important attributes:

    • autoplay: The video will be played just after the page loads.
    • autobuffer: By default (without this attribute), the video file is not downloaded unless you click on the play button. Adding this attribute starts downloading the video just after the page loads.
    • controls: by default (without this attribute), the video doesn’t include any controls (play/pause button, volume, etc.). Use this attribute if you want the default controls.
    • height/width: The size of the video

    Example:

    <video id="myVideo" src="myFile.ogv" 
       autobuffer="true" controls="true"/>

    You don’t have to add the “true” value to some of these attributes in HTML5, but it’s neater to do so. If you’re not in an XML document, you can simply write:

    <video id="myVideo" src="myFile.ogv" autobuffer controls/>

    JavaScript API

    Like any other HTML element, you have access to the video element via the Document Object Model (DOM):

    var myVideo = document.getElementById("myVideo");

    Once you obtain a handle to the video element, you can use the JavaScript API for video.

    Here is a short list of some useful methods and properties (and see here for more of the DOM API for audio and video elements):

    • play() / pause(): Play and pause your video.
    • currentTime: The current playback time, in seconds. You can change this to seek.
    • duration: The duration of the video.
    • muted: Is the sound muted?
    • ended: Has the video ended?
    • paused: Is the video paused?
    • volume: To determine the volume, and to change it.

    Example:

    <button onclick="myVideo.play()">Play</button>
    <button onclick="myVideo.volume = 0.5">Set Volume</button>
    <button onclick="alert(myVideo.volume)">Volume?</button>

    Events

    You know how to control a video (play/pause, seek, change the volume, etc.). You have almost everything you need to create your own controls. But you need some feedback from the video, and for that, let’s see the different events you can listen to:

    • canplay: The video is ready to play
    • canplaythrough: The video is ready to play without interruption (if the download rate doesn’t change)
    • load: The video is ready to play without interruption (the video has been downloaded entirely)
    • ended: The video just ended
    • play: The video just started playing
    • pause: The video has been paused
    • seeking: The video is seeking (it can take some seconds)
    • seeked: The seeking process just finished
    • timeupdate: While the video is playing, the currentTime is updated. Every time the currentTime is updated, timeupdate is fired.

    Here’s a full list of events.

    For example, you can follow the percentage of the video that has just been played:

    function init() 
    {
      var video = document.getElementById("myVideo");
      var textbox = document.getElementById("sometext");
      video.addEventListener("timeupdate", function() {
      textbox.value = Math.round(100 * (video.currentTime / video.duration)) + "%"; }
     
    }
    <video id="myVideo" src="myFile.ogv" 
                autoplay="true" onplay="init()"/>
    <input id="sometext"/>

    Showing all this in action, here’s a nice open video player using the Video API.

    Now that you’re familiar with some of the broad concepts behind the Video API, let’s really delve into the video as a part of the Open Web, introducing video to CSS, SVG, and Canvas.

    CSS and SVG

    A video element is an HTML element. That means you can use CSS to style it.

    A simple example: using the CSS Image Border rule (a new CSS 3 feature introduced in Firefox 3.5). You can view how it works on the Mozilla Developer Wiki.

    And obviously, you can use it with the video tag:

     
    <video id="myVideo" src="myFile.ogv" 
    style="-moz-border-image: 
               url(tv-border.jpg) 25 31 37 31 stretch stretch; 
               border-width: 20px;"/>

    One of my demos uses this very trick.

    Since Firefox 3.5 provides some new snazzy new CSS features, you can do some really fantastic things. Take a look at the infamous washing machine demo, in which I subject an esteemed colleague to some rotation.

    It uses some CSS rules:

    And some SVG:

    Because the video element is like any other HTML element, you can add some HTML content over the video itself, like I do in this demo. As you can see, there is a <div> element on top of the video (position: absolute;).

    Time for a Break

    Well, we’ve just seen how far we can go with the video element, both how to control it and how to style it. That’s great, and it’s powerful. I strongly encourage you to read about the new web features available in Firefox 3.5, and to think about what you can do with such features and the video element.

    You can do so much with the power of the Open Web. You can compute the pixels of the video. You can, for example, try to find some shapes in the video, follow the shapes, and draw something as an attachment to these shapes. That’s what I do here! Let’s see how it actually works.

    Canvas & Video

    Another HTML 5 element is canvas. With this element, you can draw bitmap data (see the canvas reference, and I strongly suggest this canvas overview). But something you might not know is that you can copy the content of an <img/> element, a <canvas/> element and a <video/> element.

    That’s a really important point for the video element. It gives you a way to play with the values of the pixels of the video frames.

    You can do a “screenshot” of the current frame of the video in a canvas.

    function screenshot() {
     var video = document.getElementById("myVideo");
     var canvas = document.getElementById("myCanvas");
     var ctx = canvas.getContext("2d");
     
     ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
    }
    <video id="myVideo" src="myFile.ogv" autoplay="true" with="600" height="400"/>
    <canvas id="myCanvas" with="600" height="400"/>
    <button onclick="screenshot()">Copy current frame to canvas</button>

    You can first apply a transformation to your canvas (see the documentation). You can also copy a thumbnail of the video.

    If you draw every frame in a canvas, your canvas will look like a video element. And you can draw what you want in this canvas, after drawing the frame. That’s what I do in this demo.

    Once you have a video frame in your canvas, you can compute the values of the pixels.

    Some things you should know if you want to compute the pixels values of a frame:

    • you can’t use this mechanism with a video from another domain.
    • you can’t use this mechanism with a video from a file:/// URL (which would be useful during the development of your web application). But you can change this behavior for testing: in about:config, change the value of “security.fileuri.strict_origin_policy” to “false”. But be very careful! editing about:config — that’s an expert feature!
    • There are two ways to display the result of your application on the top of the video:
      • use your canvas as a video (if you draw the frame every time), and then draw directly into the canvas
      • use a transparent canvas on the top of the video
    • the canvas element can be “display: none”
    • the video element can be “display: none”

    About JavaScript

    For the image processing, you will need to do a lot of computation. Here are some tricks:

    • copy your frame in a small canvas. If the canvas is three times smaller than the video, it means nine times fewer pixels to compute.
    • avoid recursion. In a recursion, the script engine doesn’t use the JIT optimization.
    • if you want to do a distance between colors, use the L.A.B colorspace.
    • if you want to find the center of an object, compute its centroid. See the “computeFrame” function that I use in this JavaScript snippet for my demo.
    • if the algorithm is really heavy, you can use a Worker thread, but take into account that you will need to send the content of the canvas to the thread. It’s a big array, and objects are automatically JSONified before being sent. It can take a while.

    Conclusion

    As you can see, you can do powerful things with the video element, the canvas element, CSS3, SVG and the new JavaScript engine. You have everything in your hands to create a completely new way to use Video on the web. It’s up to you now — upgrade the web!

    References

  2. slick tables with css 3 selectors

    This article and demo come to us courtesy of Ivan Enderlin, author of the HOA Framework and longtime web developer.

    This is the article that accompanies the demo below, showing the use of CSS3 selectors implemented in Firefox 3.5 for easy and stylish tables.

    CSS3 Selectors for Quick and Pretty Tables

    View the Demo | CSS3 Selectors for Quick and Pretty Tables


    See this demo step by step.

    Basic HTML Table

    First, we start by writing a simple HTML table. Note: we do not have any classes or ids, which is what makes this all so fantastic:

    <table>
      <thead>
        <th>...</th>
        ...
        <th>...</th>
      </thead>
      <tbody>
        <tr>
          <td>...</td>
          ...
          <td>...</td>
        <tr>
        ...
        <tr>
          <td>...</td>
          ...
          <td>...</td>
        <tr>
      </tbody>
    </table>

    And now, let us write some CSS to make the plain old table look a bit more stylish:

    table {
        font: 90%/1.5em "Lucida Grande", Geneva,
                        "DejaVu Sans", "Bitstream Vera Sans", AnjaliOldLipi,
                        "Lucida sans", "Trebuchet MS", Arial, Verdana;
        text-align: center;
        border: 4px black double;
        border-spacing: 0;
        -moz-border-radius: 12px;
        -moz-box-shadow: #6a3d37 5px 5px 6px;
        -webkit-border-radius: 12px;
        -webkit-box-shadow: #6a3d37 5px 5px 6px;
        border-radius: 12px;
        box-shadow: #6a3d37 5px 5px 6px;
        background: #b59d5c
    }

    The use of border-spacing, border-radius and box-shadow properties make for a quick and easy way to inject a little beauty into the table.

    First Selection

    Now, we would like to style all the th tags. This is easy with CSS Selectors:

    th {
        color: #fff;
        font-size: 110%;
        text-shadow: #6a3d37 2px 2px 2px
    }

    Reminder: if we write table th we intend to select all the th elements which are child elements of the the table element, and if we write thead > th, we intend to select all the th elements which are direct children of the thead element. Well, it was just a reminder :-)

    More Nuanced Selection

    The th tag represents a table header. We would like to select the first table header. Hmm… maybe we should use the first-of-type pseudo-class. It represents an element that is the first sibling of its type in the list of children of its parent element. So now we have:

     
    th:first-of-type {
    font-weight: bold;
    font-style: italic
    }

    Even and odd rows

    A recurrent problem with tables is: how to select even and odd rows? The solution is the nth-child() pseudo-class. All these pseudo-classes understand the an+b syntax — to select all the even elements, we use 2n; to select all the odd elements, we use the 2n+1 elements; to select all third elements, we use 3n. In other words, this matches the bth child of an element after all the children have been split into groups of a elements each.

    So, let’s style the even and odd rows:

     
    tr:nth-child(odd) {
        color: #e0d8cb;
        background: #474644
    }
     
    tr:nth-child(even) {
        color: #6a3d37
    }

    Padding on first and last columns

    Now, we want to add a padding to the first and the last column. I remind you again that we do not have any classes or IDs, and that the number of columns is unknown.

    The solution is the first-of-type and the last-of-type pseudo-classes. We select all the first and last th and td like this:

     
    th:first-of-type,
    td:first-of-type {
        padding: 0 0 0 4em
    }
     
    th:last-of-type,
    td:last-of-type {
        padding: 0 4em 0 0
    }

    The two last rows

    Now, we would like to combine many pseudo-classes (and introduce a new one).

    Let’s say we would like to select row number 1, number 4 and number 7. The mathematical expression is not so simple as we hoped. The tips is to split our rows in groups of 3, like this: 3n. But, that will select rows number 3, 6 and 9. Almost there! In these groups, we will select the first element, so 3n+1 (or 3n-2 if you like to complicate things).

    That’s good, but that will select a row in our two last non-opaque rows. Ideally, we should say: “select the first row of each groups of three rows, but not the last row (which will be selected, because the last is the 7th row).” Simple. We are going to use the not pseudo-class, combined with the last-child pseudo-class (or last-of-type, which also works here).

    Thus:

     
    tr:nth-last-child(-n+2) {
        opacity: .75
    }
     
    tr:nth-child(3n+1):not(:last-child) td {
        text-shadow: red 0 0 8px
    }

    The final source is:

    table {
        display: table;
        font: 90%/1.5em "Lucida Grande", Geneva,
                        "DejaVu Sans", "Bitstream Vera Sans", AnjaliOldLipi,
                        "Lucida sans", "Trebuchet MS", Arial, Verdana;
        text-align: center;
        border: 4px black double;
        border-spacing: 0;
        -moz-border-radius: 12px;
        -moz-box-shadow: #6a3d37 5px 5px 6px;
        -webkit-border-radius: 12px;
        -webkit-box-shadow: #6a3d37 5px 5px 6px;
        border-radius: 12px;
        box-shadow: #6a3d37 5px 5px 6px;
        background: #b59d5c
    }
     
    th {
        color: #fff;
        font-size: 110%;
        text-shadow: #6a3d37 2px 2px 2px
    }
     
        th:first-of-type {
            font-weight: bold;
            font-style: italic
        }
     
    tr:nth-child(odd) {
        color: #e0d8cb;
        background: #474644
    }
     
    tr:nth-child(even) {
        color: #6a3d37
    }
     
    th:first-of-type,
    td:first-of-type {
        padding: 0 0 0 4em
    }
     
    th:last-of-type,
    td:last-of-type {
        padding: 0 4em 0 0
    }
     
    tr:nth-last-child(-n+2) {
        opacity: .75
    }
     
    tr:nth-child(3n+1):not(:last-child) td {
        text-shadow: red 0 0 8px
    }


    View this demo step by step
    .