Wednesday, June 16, 2010

Softlogic 6010 4/8/16 Channel MPEG-4 Codec Card Driver Released

As I've talked about before, the company I work for has been dedicated to producing stable video surveillance products based on Linux.

Bluecherry's primary device for their video surveillance applications is the Softlogic based MPEG-4 codec card, which is available in 4, 8 and 16 channel models. The original driver for this card, although available as Open Source, was pretty pathetic to say the least. Most of it was just a kludge of the Windows driver, exposing all of the functionality, but with little effort to make it Linux savvy.

That's where I came in. I've since rewritten the driver so that it makes use of Linux's Video4Linux2 and Alsa driver API's. It's currently 90% functional, and many times more efficient than the original OEM driver.

Here is a quick run-down of some of the features and plus-ones against the original driver:

  • Video4Linux2 interface allows easy use of existing capture software
  • Alsa interface allows for easy audio capture (however, see G.723 caveats from my previous posts)
  • Zero-copy in the driver. The original driver DMA'd and then copied the MPEG frames to userspace. The new driver makes use of v4l2 buffers and can DMA directly to an MMAP buffer for userspace.
  • Simultaneous MPEG/MJPEG feed per channel, selectable via v4l2 format
  • Standard v4l2 uncompressed video YUV display with multi-channel display format (4-up)

Now that the driver is nearing completion, it's about time to release it. I've done so via Launchpad.


If you are on an Ubuntu system, you can install the DKMS package from the PPA archive using these commands:

sudo add-apt-repository ppa:ben-collins/solo6x10
sudo apt-get update
sudo apt-get install solo6010-dkms

Note, I've only supplied this for Lucid right now, but if you download the .deb or the .tar.gz you should be able to install it on any recent kernel.

Friday, June 11, 2010

Feedburner: Adding Flattr to your FeedFlare (Part: 2)

This is a follow up to my previous post: Feedburner: Adding Flattr to your FeedFlare.

I've been wrestling around with FeedBurner's FeedFlare API for a few nights now. Most notably I've had trouble getting some of the documented xPath functions to work, and dealing with what appears to be delays in updating the flare after you add it.

My goal was to add categories to the DynamicFlare href so you could pass those along to Flattr. The problem is that if you add something like ${a:category[1]/@term} to the href, and a:category[1] doesn't exist in your feed, it will not add the flare to your feed (sort of like a filter if the attribute proves false()).

In a final decision of anger, I decided to drop any passing of information from the DynamicFlare href other than the feedUrl. This in itself proved difficult, since ${feedUrl} doesn't work as advertised. I instead opted to pass ${a:link[@rel="self"]/@href} which appears to work on my feed. YMMV.

I've gotten rid of the files I linked to in my last post so people don't use them. For the quick and dirty, here's the URL to use for Personal FeedFlare now:

http://www.swissdisk.com/~bcollins/feedflare/flattr-me-dynamic-v2.php

There are two options you can pass to this script:

  • uid: Your Flattr UID (required)
  • lng: Your preferred language (defaults to en_GB, aka English)

I used this for mine:

http://www.swissdisk.com/~bcollins/feedflare/flattr-me-dynamic-v2.php?uid=17833&lng=en_GB

That's it! The new script will parse the feed in the second script and pass up to 980 characters as the desc, up to 80 characters of the title and all of the categories as tags.

You can also check here for all the PHP-Source files so you can modify to your liking.

Tuesday, June 8, 2010

Feedburner: Adding Flattr to your FeedFlare

Update 2010-06-11: This article and information with-in are superseded by Feedburner: Adding Flattr to your FeedFlare (Part: 2)

I've added Flattr to my blog and also wanted to add it to my feedburner FeedFlare, but alas, no one has yet to create one. So I've gone through the trouble of doing it for you :)

First, I went to the Feedburner FeedFlare API documentation. I wont go into the details of writing your own flare, but I opted for the dynamic type, since it would allow me to show how many times one of my blog posts had been flattered.

Second, I dove into the Flattr JavaScript API. I don't think they recommend this, but it's the only way I could get to the button information contained in their default IFrame.

Third, I downloaded the PHP Simple HTML DOM Parser. There's probably a simpler way to parse the IFrame sent back from Flattr, but I opted for this method since it was pretty straight forward.

For the lazy, you can use my existing FeedFlare URLs as your own. You will need to go to your feedburner page, login, select the feed you want to add this to, click on "Optimize" and then "FeedFlare". Below the stock list you will see a place to enter a URL. Enter the URL below and BE SURE to replace "your_uid" with your Flattr UID, else you wont get the money.

http://www.swissdisk.com/~bcollins/flattr-me-dynamic.php?uid=your_uid

For the interested, here are the two files I've created. First is the dynamic PHP FeedFlare file:

<FeedFlareUnit>
  <Catalog>
    <Title>Flattr Me</Title>
    <Description>
      Adds a Flattr link including flattr count for each feed unit.
    </Description>
    <Link href="http://www.swissdisk.com/~bcollins/flattr-me-dynamic.php?uid=flattr_uid"/>
    <Author email="benmcollins13@gmail.com">Ben Collins
  </Catalog>
  <DynamicFlare href="http://www.swissdisk.com/~bcollins/flattr-me-static.php?uid=<?
        print $_GET['uid']; ?>&title=${title}&link=${link}"/>
  <Sample>Flattr (11)</Sample>
</FeedFlareUnit>

Note that the <Link> element references another PHP script, and that this is in fact PHP. This allows us to pass along the Flattr UID to the second script, which is the one that actually produces the FeedFlare (feedburner periodically checks the second URL it gets from this file for updates to the FeedFlare).

Now, the second script is the one that uses the simple_html_dom.php library I spoke of. You will see it referenced in the file below. Basically I pack the data just like the original Flattr load.js script does, and request the Flattr button, and then rip a few bits of information from it:

<?
include_once("simple_html_dom.php");

$btn_url = "http://api.flattr.com/button/view/";

$data = "button=compact&uid=" . $_GET['uid'] .
        "&url=" . $_GET['link'] . "&lng=en_US&hide=0&title=" .
        $_GET['title'] . "&cat=text&tag=&desc=";

$html = file_get_html($btn_url . bin2hex($data));

$els = $html->find("span.flattr-count");
$count = $els[0]->innertext;

$els = $html->find("a.flattr-pop");
$link = $els[0]->href;

$els = $html->find("span.flattr-link");
$txt = $els[0]->innertext;

?>
<FeedFlare>
  <Text><? print "$txt ($count)"; ?></Text>
  <Link href="<? print $link; ?>"/>
</FeedFlare>

Those familiar with Flattr will note that I did not pass in the description, which could probably be added in the first script (or at least a shortened version of it) and then passed to the button. Usually the description is the first few hundred characters of the post in this case.

Hope all works well. Please post back if you take the time to add the description to this!

Friday, June 4, 2010

PHP: Sending Motion-JPEG

As you may know from past posts, I was trying to send Motion-JPEG from a PHP script. This proved (for many reason) not so easy. After I conquered writing php extension modules, I was still left with nuances in PHP that made it difficult to send MJPEG from my script.

Here's the basic run-down of difficulties:
  • PHP buffers output to the client and this keeps you from doing continuous streams of data easily
  • PHP doesn't allow you to send headers after it thinks the headers have already been sent
  • Apache has some other handlers that also cause buffering
  • Apache does some client negotiation that conflicts with MJPEG (mod_gzip)

Searching the Eentarnets did not produce good results on how to handle this. At least, not in a single place and easily findable. So here's my solution for others to use:

<?
# Used to separate multipart
$boundary = "my_mjpeg";

# We start with the standard headers. PHP allows us this much
header("Cache-Control: no-cache");
header("Cache-Control: private");
header("Pragma: no-cache");
header("Content-type: multipart/x-mixed-replace; boundary=$boundary");

# From here out, we no longer expect to be able to use the header() function
print "--$boundary\n";

# Set this so PHP doesn't timeout during a long stream
set_time_limit(0);

# Disable Apache and PHP's compression of output to the client
@apache_setenv('no-gzip', 1);
@ini_set('zlib.output_compression', 0);

# Set implicit flush, and flush all current buffers
@ini_set('implicit_flush', 1);
for ($i = 0; $i < ob_get_level(); $i++)
    ob_end_flush();
ob_implicit_flush(1);

# The loop, producing one jpeg frame per iteration
while (true) {
    # Per-image header, note the two new-lines
    print "Content-type: image/jpeg\n\n";

    # Your function to get one jpeg image
    print get_one_jpeg();

    # The separator
    print "--$boundary\n";
}
?>

That's it in a nutshell. Make sure that your PHP script does not contain any newlines or data before or after the PHP enclosures (<? ... ?>).

The joy of writing a php5 module

As a follow up to my last post, I wanted to give a quick update.

As it turns out, I ended up writing a php5 Zend module to wrap up some functions I use to access v4l2 devices. I have to say that writing a php5 module was pretty straight forward. Big thanks to the Extension Writing tutorial I found, which was well written, and did not leave me with any questions.

I was able to get the module ready in a few hours, and spent the rest of this morning cleaning it up and tweaking it a bit.

Now I'm completely able to read my v4l2 devices and mjpeg stream them from my PHP script :)