terça-feira, 29 de janeiro de 2013

Release 0.0.4

Screenshots from release 0.0.4


Grid view with a customized layout showing some dragged and resized cameras:


A singled camera viewed from an iPhone:


The home/configuration page showing all my five configured cameras:


Release notes


  • Fixed the problem with multichannel cards. Reads from multiple cameras connected to the same chip (device - e.g. /dev/video0) are now synchronous.
  • Implemented a simple image change detection routine to trigger event recording.
  • Improvements in the client (browser) to allow grid camera view positioning and resizing, saving these customizations using HTML5 localStorage feature.
  • Events recording for each configured camera.

sexta-feira, 18 de janeiro de 2013

Let's rock the client

The next image shows how the cameras were displayed in the client browser. So annoying, the image of each camera after the previous, all the same size. Without possibility of any sort of customization. Really very annoying!


So, let's start with a little of rock and roll in this project. Let's use tiny drops of jQuery UI to move and resize the camera images the way we want.

For the times they are a-changin. In the next image we can see how the presentation is now. We can freely move and resize each camera image regardless of the other cameras sizes and positions. We may even overlap then.


The coolest thing is that we can do it all with very few new lines of code.

Some relevant parts of the Jade script:

doctype 5
html
  head
    ...
    link(rel='stylesheet', href='http://code.jquery.com/ui/1.10.0/themes/base/jquery-ui.css')
    script(src='/javascripts/jquery.min.js')
    script(src='/javascripts/jquery-ui.custom.min.js')
    ...
    script
      $(function() {
        $(".draggable").draggable();
        $(".resizable").resizable({
          aspectRatio: 320 / 240
        });        
      });
  body
    #grid
      .linha
        #cam01.camera.draggable
          .image
            img#img01.resizable(src='#', width=320, height=240) 
          .info
        ...

The fifth element

Installing the fifth camera for testing, we had problems and this did not work at all.

Searching in Google, I remembered that the GV-800 card is a multichannel card with four Bt8xx chips, each one with four channels, that is, each chip can control up to four cameras.

The problem is that each chip can control only one camera at a time, and we can not read two or more of these four cameras simultaneously. So we must have some synchronization mechanism to control the capture from these cameras connected to the same chip (device).



So, a implemented a function that acquires a exclusive lock on the device file descriptor (/dev/video0, /dev/video1, etc).

void acquire_file_lock(int fd, int retry_ms)
{
  int rc;

  for (;;) {
    rc = flock(fd, LOCK_EX | LOCK_NB); // grab exclusive lock, fail if can't obtain.
    if (rc == -1) {
      // fail - sleep retry_ms (ms) and try again
      xsleep(0, retry_ms);
    } else {
      // success - return
      return;
    }
  }
}

In the main loop that reads the device, we acquire the lock, read the device and release the lock, ensuring the synchronization between the cameras connected to the same device, preventing concurrent accesses.

static void mainloop(void)
{
  ...

  while (1) {
    acquire_file_lock(fd, 10);
    init_device();

    // read the device - capture frame
    ...

    release_file_lock(fd);

    ...
  } // while (1)
}

This way, our fifth camera started to work ok.

Links:

quarta-feira, 9 de janeiro de 2013

Release 0.0.3

In this third release, the project is becoming more functional and stable.

We already have a configuration file with server and cameras configuration options. See the wiki configuration page.

Some screenshots from this release:



See more details in our github page.

terça-feira, 8 de janeiro de 2013

How to make a zebra-striped table with Jade

This is a very simple tutorial on how to make a zebra-striped table, such as the one below, using the Jade template engine.


The jade template looks like this:

  table#cameras
    thead
      tr.head
        th Camera
        th Description
        th Type
        th Device
        th Channel
        th Format
        th Palette
        th Width
        th Height
        th Fps
    tbody
      - var i = -1
      each val, key in cameras
        - ++i
        tr(class=(i % 2 == 0) ? 'odd' : 'even')
          td #{key}
          td #{val.descr}
          td #{val.type}
          td #{val.device}
          td #{val.channel}
          td #{val.format}
          td #{val.palette}
          td #{val.width}
          td #{val.height}
          td #{val.fps}

Note the lines prefixed with a hyphen (-), the first one creates a var and the second increments this var inside the each loop.

In the loop it cycles between 'odd' and 'even' tr class, depending on the i var value.

The stylus template looks like this:

table#cameras tr.odd
  background-color: #444

table#cameras tr.even
  background-color: #888


sexta-feira, 4 de janeiro de 2013

Release 0.0.2

This screenshot shows version 0.0.2 working with two cameras (the second one is defective) connected to a Geovision GV-800 card.


This second release is again a concept proof to test some design and tools options.

No configuration yet, and almost everything is hard coded.

I'm developing this on an Ubuntu 12.04 64 bits server with a GV-800 card with two attached cheap mini-cameras, the second one with malfunction, as we can see above.

See more instructions and comments in our github page.