Wednesday, June 2, 2010

Request-for-help: PHP and Video4Linux

As it turns out, I do not like writing web applications. Give me registers and DMA, keep the CSS and JS...thanks.

Anyway, I have to find a way to feed an MJPEG output from a PHP script. WAIT! I know this sounds easy, and if not for all the caveats of what I have to adhere to, it would be very simple...maybe.

It seems that PHP doesn't have a way to use ioctl()'s. I can open() a v4l2 device just fine, and read() from it with ease, but your SOL if you want to do something cool with that file handle in PHP.

I need to be able to do ioctl()'s because my v4l2 device requires at least one so I can put it into MJPEG format (as opposed to the default MPEG format). I can serve up these JPEG/MJPEG's through apache perfectly using a C program I've written.

However, I have to use PHP because the rest of the web application is written in PHP and there is already authentication mechanisms storing credentials in PHP sessions. I don't want to have to parse PHP sessions in a C program.

The normal method I found for doing JPEG from a PHP script worked like this:

<?
header("Content-Type: application/jpeg");
passthru("/usr/bin/grabjpeg");
?>

This works perfectly. Except I want to be able to do a MJPEG feed which requires sending one image after the next with headers in between. PHP doesn't like this much, nor does it like the fact that I want all of these headers to come directly from my C program and not from the PHP script. I also do not want to call grabjpeg for each frame, since that's too much overhead in between frames.

What ends up happening is that my headers from the C program are sent as part of the content that the client thinks is the JPEG file.

Right now, I can only see one way to handle this, and that's to write a PHP module to expose libv4l, but I'm open to suggestions on being able to call an ioctl() from within a PHP script.

4 comments:

  1. Why not just send the first header with php, then the rest with your C program? Technically, an HTTP request can only have one header block followed by an empty line and the optional message body, so PHP not liking you trying to send multiple header blocks isn't really a problem with PHP per-se.
    Also, it looks like you're using the wrong mime type.
    Have a look at:
    http://en.wikipedia.org/wiki/Motion_JPEG#M-JPEG_over_HTTP

    ReplyDelete
  2. Have you considered passthrough to vlc/vls?

    ReplyDelete
  3. @David, yes, the example I gave was for a single jpeg image. I'm toying around with the idea you suggested for starting the feed with PHP and having the C program do the rest. I'll keep you posted on that front.

    @abas, Using vlc/vls with PHP passthru() would probably end up with the same thing I am getting now. But thanks for the idea.

    ReplyDelete
  4. Look at ffserver - it can convert any ffmpeg-playable source into exactly what you want.

    ReplyDelete