www.pudn.com > ReadingPeopleTracker-1.28.rar > IEEE1394Adaptor.cc


///////////////////////////////////////////////////////////////////////////////
//                                                                           //
//  IEEE1394Adaptor.cc                                                       //
//                                                                           //
//  This program reads individual DV encoded frames                          //
//  from the 1394 Digital Camera.                                            //
//                                                                           //
//                                                                           //
//  Author    :  Sarah Laval (sl) supervised by Nils T Siebel (nts)          //
//  Created   : Mon Jun 17 17:32:34 BST 2002                                 //
//  Copyright : The University of Reading                                    //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////


#include 
#include   // for exit()

#include "IEEE1394Adaptor.h"

namespace ReadingPeopleTracker
{

// definition and initialisation of static member variables
// all  static variables are initialized to zero before 
// the first object is created.
bool IEEE1394Adaptor::dv_frame_has_started;
DV_encoded_frame_t IEEE1394Adaptor::buffer;


IEEE1394Adaptor::IEEE1394Adaptor()
{
    handle = NULL; 
    port = 0; 
    num_nodes = 0;
  
    channel = 63;

    packet_length = 0;
    dv_frame_has_started = false;
    is_dataflow = false;
}

IEEE1394Adaptor::~IEEE1394Adaptor()
{
    disconnect_1394();
}

void IEEE1394Adaptor::connect_1394()
{
    struct raw1394_portinfo pinf[16];
    int nbport = 0;
    
    assert(handle == NULL);
    handle = raw1394_new_handle(); 
    // Required as initialization. 

    if (handle == NULL)
    {
	cerror << " IEEE1394Adaptor::connect :"
	       << " Error : Could not get handle."
	       << endl;	

	exit(1);	
    }
    else
    {
	nbport = raw1394_get_port_info(handle, pinf, 16);
        // Returns number of available ports.
	// maximum number of port is here 16.
	
	raw1394_get_generation(handle);
	// give handle's value
    }
    
    if (raw1394_set_port(handle, port) < 0)
	// attach handle to port.
    {
	cerror << " IEEE1394Adaptor::connect :"
	       << " Error : Could not set port." 
	       << endl;	
	
	disconnect_1394();
	exit(1);
    }

    // port set.
}


void IEEE1394Adaptor::disconnect_1394()
{
    iso_handler_t result = NULL;
    old_iso_handler = NULL;
    
    if (is_dataflow)
    {
	// ends the dialog with the DV camera.
	stop_dataflow();
    }
    

    // clear iso handler
    raw1394_set_iso_handler(handle, channel, NULL);
    
    // restore old iso handler
    result = raw1394_set_iso_handler(handle, channel, old_iso_handler); 

    if (result != NULL)
    {
	cdebug << " IEEE1394Adaptor::disconnect_1394: "
	       << " Warning: could not restore the old iso handler."
	       << endl;
    }

    // destroy 1394 handle
    raw1394_destroy_handle(handle); 

    // remember that handle is not valid any more
    handle = NULL;


    return;
}


int IEEE1394Adaptor::frame_iso_handler(raw1394handle_t handle, int channel, 
				       size_t packet_length, quadlet_t *data)
{	
    
// The PAL/NTSC DV data has the following format:
//
//      - packets of 496 bytes length
//      - packets of  16 bytes length.
//
// The long packets contain the actual video and audio contents . 
//           
// The actual DV data starts at quadlet 4 of the long packet,
// so we have 480 bytes of DV data per packet.  For PAL, each
// frame is made out of 300 packets and there are 25 frames
// per second.  That is 144000 bytes per frame and 3600000
// bytes per second. 
    

    if (packet_length < 492)  // ignore 16-byte packets 
	return 0;
    
 
    assert (packet_length == 492);

    // we have already retrieve the whole frame
    if (buffer.buffer_size_used >= 144000)
	return 0;
    
    unsigned char *p = (unsigned char*) & data[3];
    int section_type = p[0] >> 5;   // section type is in bits 5 - 7 
    int dif_sequence = p[1] >> 4;   // dif sequence number is in bits 4 - 7 
    int dif_block = p[2];
 
    if ((section_type == 0) && (dif_sequence == 0))
    {	   
	// we are at the beginning of the frame

	// check whether we have started to fill up our buffer
	if (buffer.buffer_size_used > 0) 
	{
	    // re-start reading the frame
	    buffer.buffer_size_used = 0; // no bytes for this frame yet	    
	}

        // we have found the beginning of the frame
	dv_frame_has_started = true;
    }
    
    if (dv_frame_has_started) 
    {
	switch (section_type) 
	{
	    
	case 0:           // 1 Header block
	    memcpy(buffer.current_frame + dif_sequence * 150 * 80, p, 480);
	    break;
	    
	case 1:           // 2 Subcode blocks
	    memcpy(buffer.current_frame + dif_sequence * 150 * 80 + (1 + dif_block) * 80, p, 480);
	    break;
	    
	case 2:           // 3 VAUX blocks
	    memcpy(buffer.current_frame + dif_sequence * 150 * 80 + (3 + dif_block) * 80, p, 480);
	    break;
	    
	case 3:           // 9 Audio blocks interleaved with video
	    memcpy(buffer.current_frame + dif_sequence * 150 * 80 + (6 + dif_block * 16) * 80, p, 480);
	    break;
	    
	case 4:           // 135 Video blocks interleaved with audio
	    memcpy(buffer.current_frame + dif_sequence * 150 * 80 + (7 + (dif_block / 15) + dif_block) * 80, p, 480);
	    break;
	    
	default:           // we cannot handle any other data
	    break;
	}
	
	buffer.buffer_size_used += 480;	
    }
 
    return 0;
}


int IEEE1394Adaptor::frame_reset_handler(raw1394handle_t handle, unsigned int generation)
{
   
    cdebug  << " IEEE1394Adaptor::frame_reset_handler: "
	    << " Reset. "
	    << endl;
 
    return 0;
}   

void IEEE1394Adaptor::find_camera()
{
    int camera = -1;
    
    // get number of nodes on the bus
    num_nodes = raw1394_get_nodecount(handle);
    
    for (unsigned int node = 0; node < num_nodes; node++)
    {  
	if (rom1394_get_directory(handle, node, &rom_dir) < 0)
    	{
    	    cerror << " IEEE1394Adaptor::find_camera : "
		   << " Error : Cannot read config rom directory for node " << node
		   << endl;
	    
            raw1394_destroy_handle(handle);
    	    exit(1);
        }
	
	// Get the type / protocol of a node
	if ((rom1394_get_node_type(&rom_dir) == ROM1394_NODE_TYPE_AVC) && 
	     avc1394_check_subunit_type(handle, node, AVC1394_SUBUNIT_TYPE_VCR))            
	{
	    camera = node + 1;
	}
	else 
	{
 	    // Node #node is not a camera.
	}
    }
    
    if (camera == -1)
    {
	cerror << " IEEE1394Adaptor::find_camera : "
	       << " Error : Could not find AV/C devices on 1394 bus." 
	       << endl;
	
	disconnect_1394();

	exit(0);
    }
    else
    {
	// There are `camera' camera(s) on the bus
	if (camera > 1)
	{
	    cerror << " IEEE1394Adaptor::find_camera : "
		   << " Warning:  There is more than one camera on the bus." 
		   << " Using one of them. " 
		   << endl;
	}
    }
}

void IEEE1394Adaptor::set_iso_handler()
{
    
    iso_handler_t result = NULL;
    old_iso_handler = NULL;
    
    // remember old handler (will be returned with NULL parameter)
    old_iso_handler = raw1394_set_iso_handler(handle, channel, NULL);

    // Set the handler that will be called when an iso packet arrives 
    // we only do isochronous transfert so we define iso_handler here
    result = raw1394_set_iso_handler(handle, channel, &IEEE1394Adaptor::frame_iso_handler); 
 
    if (result != NULL)
    {
	cerror << " IEEE1394Adaptor::set_iso_handler: "
	       << " Error: could not set iso handler."
	       << endl;
	exit(1);
    }

}


void IEEE1394Adaptor::start_dataflow()
{
    int result = 0;

    result = raw1394_start_iso_rcv(handle, channel);
    // Start receiving a certain isochronous channel. 
    
    if(result < 0)
    {
	cerror << " IEEE1394Adaptor::start_dataflow : "
	       << " Error : Could not start receiving isochronous channel." 
	       << endl;
	exit(1);
    }

    is_dataflow = true;
}


void IEEE1394Adaptor::stop_dataflow()
{
    int result = 0;
  
    
    if (handle != NULL)
    {
	result = raw1394_stop_iso_rcv(handle, channel);
    }
    
    if (result < 0)
    {
	cerror << " IEEE1394Adaptor::stop_dataflow : "
	       << " Error : Could not stop receiving isochronous channel." 
	       << endl;
	exit(1);
    }
      
    is_dataflow = false;

    return;
}

DV_encoded_frame_t *IEEE1394Adaptor::capture_frame(int channel)
{
    if (handle == NULL)
    {
	// this is the first capture.
	// open the connection with the device
	// and declare all the arguments needed.
	
	connect_1394();
	find_camera(); 

	set_iso_handler();
    }
	
    // begin communication with the device
    start_dataflow();
    
    // no data read yet.
    buffer.buffer_size_used = 0;
    
    while (buffer.buffer_size_used < 144000)
    {
	raw1394_loop_iterate(handle);
	// retrieve PAL data from the DV camera.
    }

    if (is_dataflow)
    {
	// ends the dialog with the DV camera.
	stop_dataflow();
    }
    
    return &buffer;
}

} // namespace ReadingPeopleTracker