[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#545112: Errors in new firewire stack, DV camera don't work anymore



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 to: