I wrote a really simple DV capture program myself (see below), and it
works just fine with the Debian packaged kernel
(linux-image-2.6.32-trunk-amd64 2.6.32-3).  dvgrab continues to fail.  I
conclude that dvgrab is at fault, not the kernel.

Note that this program writes DV to stdout; you had better redirect it!

Ben.

/* BEGIN */
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <libraw1394/raw1394.h>

static unsigned long long total_len;
static unsigned int dropped_packets;
static unsigned int dropped_frames;
static unsigned int complete_frames;

static unsigned int seq_count;
static unsigned int next_seq_num;
static unsigned int next_block_num;
static unsigned char frame_buf[144000];

static enum raw1394_iso_disposition
receive(raw1394handle_t handle,
        unsigned char * data,
        unsigned int len,
        unsigned char channel,
        unsigned char tag,
        unsigned char sy,
        unsigned int cycle,
        unsigned int dropped)
{
    total_len += len;
    dropped_packets += dropped;

    if (len == 488)
    {
        unsigned int seq_num, typed_block_num, block_num;

        // Skip firewire header
        data += 8;

        // Find position of these blocks in the sequence
        seq_num = data[1] >> 4;
        typed_block_num = data[2];
        block_num = -1;
        switch (data[0] >> 5)
        {
        case 0:
            // Header: position 0
            if (typed_block_num == 0)
                block_num = 0;
            break;
        case 3:
            // Audio: position 6 or 102
            if (typed_block_num < 9)
                block_num = 6 + typed_block_num * 16;
            break;
        case 4:
            // Video: any other position divisible by 6
            if (typed_block_num < 135)
                block_num = 7 + typed_block_num + typed_block_num / 15;
            break;
        }

        // Are these the blocks we're expecting?
        if (seq_num == next_seq_num && block_num == next_block_num)
        {
            // Set sequence count from the first block of the frame
            if (seq_num == 0 && block_num == 0)
                seq_count = (data[3] & 0x80) ? 12 : 10;

            // Append blocks to frame
            memcpy(frame_buf + (seq_num * 150 + block_num) * 80, data, 480);

            // Advance position in sequence
            next_block_num = block_num + 6;
            if (next_block_num == 150)
            {
                // Advance to next sequence
                next_block_num = 0;
                ++next_seq_num;
                if (next_seq_num == seq_count)
                {
                    // Finish frame
                    write(1, frame_buf, seq_count * 150 * 80);
                    ++complete_frames;
                    next_seq_num = 0;
                }
            }
        }
        else if (next_seq_num != 0 || next_block_num != 0)
        {
            ++dropped_frames;
            next_seq_num = 0;
            next_block_num = 0;
        }
    }
        
    return RAW1394_ISO_OK;
}

int main(void)
{
    raw1394handle_t handle;
    int n_ports, n_ports_again, i;
    struct raw1394_portinfo * ports;

    handle = raw1394_new_handle();
    if (!handle)
    {
        perror("raw1394_new_handle");
        return 1;
    }
    n_ports = raw1394_get_port_info(handle, NULL, 0);
    assert(n_ports >= 0);
    ports = calloc(n_ports, sizeof(*ports));
    if (!ports)
    {
        perror("calloc");
        return 1;
    }
    n_ports_again = raw1394_get_port_info(handle, ports, n_ports);
    if (n_ports > n_ports_again)
        n_ports = n_ports_again;
    if (n_ports == 0)
    {
        fprintf(stderr, "no remote ports found\n");
        return 1;
    }

    for (i = 0; i < n_ports; i++)
        fprintf(stderr, "node %d name \"%s\"\n", ports[i].nodes, ports[i].name);
    fprintf(stderr, "selected node %d\n", ports[0].nodes);

    if (raw1394_set_port(handle, 0))
    {
        perror("raw1394_set_port");
        return 1;
    }

    if (raw1394_iso_recv_init(handle, receive, /*buf_packets=*/ 600,
                              /*max_packet_size=*/ 496, /*channel=*/ 63,
                              /*mode=*/ RAW1394_DMA_DEFAULT,
                              /*irq_interval=*/ 100))
    {
        perror("raw1394_iso_recv_init");
        return 1;
    }

    if (raw1394_iso_recv_start(handle, -1, -1, -1))
    {
        perror("raw1394_iso_recv_start");
        return 1;
    }

    fprintf(stderr, "Press any key to exit\n");

    for (;;)
    {
        int fw_fd = raw1394_get_fd(handle);
        fd_set rfds, xfds;

        FD_ZERO(&rfds);
        FD_ZERO(&xfds);
        FD_SET(0, &rfds);
        FD_SET(fw_fd, &rfds);
        FD_SET(fw_fd, &xfds);
        if (select(fw_fd + 1, &rfds, NULL, &xfds, NULL) <= 0 ||
            FD_ISSET(0, &rfds) || FD_ISSET(fw_fd, &xfds) ||
            raw1394_loop_iterate(handle) < 0)
            break;
    }

    raw1394_iso_stop(handle);
    raw1394_iso_shutdown(handle);

    fprintf(stderr, "Total length received: %llu\n", total_len);
    fprintf(stderr, "Dropped packets: %u\n", dropped_packets);
    fprintf(stderr, "Dropped frames: %u\n", dropped_frames);
    fprintf(stderr, "Complete frames: %u\n", complete_frames);

    return 0;
}
/* END */

-- 
Ben Hutchings
Horngren's Observation:
                   Among economists, the real world is often a special case.

Attachment: signature.asc
Description: This is a digitally signed message part

Reply via email to