306 lines
		
	
	
	
		
			10 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			306 lines
		
	
	
	
		
			10 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								 * dv1394.h - DV input/output over IEEE 1394 on OHCI chips
							 | 
						||
| 
								 | 
							
								 *   Copyright (C)2001 Daniel Maas <dmaas@dcine.com>
							 | 
						||
| 
								 | 
							
								 *     receive by Dan Dennedy <dan@dennedy.org>
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * based on:
							 | 
						||
| 
								 | 
							
								 *   video1394.h - driver for OHCI 1394 boards
							 | 
						||
| 
								 | 
							
								 *   Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
							 | 
						||
| 
								 | 
							
								 *                          Peter Schlaile <udbz@rz.uni-karlsruhe.de>
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * This program is free software; you can redistribute it and/or modify
							 | 
						||
| 
								 | 
							
								 * it under the terms of the GNU General Public License as published by
							 | 
						||
| 
								 | 
							
								 * the Free Software Foundation; either version 2 of the License, or
							 | 
						||
| 
								 | 
							
								 * (at your option) any later version.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * This program is distributed in the hope that it will be useful,
							 | 
						||
| 
								 | 
							
								 * but WITHOUT ANY WARRANTY; without even the implied warranty of
							 | 
						||
| 
								 | 
							
								 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
							 | 
						||
| 
								 | 
							
								 * GNU General Public License for more details.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * You should have received a copy of the GNU General Public License
							 | 
						||
| 
								 | 
							
								 * along with this program; if not, write to the Free Software Foundation,
							 | 
						||
| 
								 | 
							
								 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifndef _DV_1394_H
							 | 
						||
| 
								 | 
							
								#define _DV_1394_H
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* This is the public user-space interface. Try not to break it. */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define DV1394_API_VERSION 0x20011127
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* ********************
							 | 
						||
| 
								 | 
							
								   **                **
							 | 
						||
| 
								 | 
							
								   **   DV1394 API   **
							 | 
						||
| 
								 | 
							
								   **                **
							 | 
						||
| 
								 | 
							
								   ********************
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   There are two methods of operating the DV1394 DV output device.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   1)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   The simplest is an interface based on write(): simply write
							 | 
						||
| 
								 | 
							
								   full DV frames of data to the device, and they will be transmitted
							 | 
						||
| 
								 | 
							
								   as quickly as possible. The FD may be set for non-blocking I/O,
							 | 
						||
| 
								 | 
							
								   in which case you can use select() or poll() to wait for output
							 | 
						||
| 
								 | 
							
								   buffer space.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   To set the DV output parameters (e.g. whether you want NTSC or PAL
							 | 
						||
| 
								 | 
							
								   video), use the DV1394_INIT ioctl, passing in the parameters you
							 | 
						||
| 
								 | 
							
								   want in a struct dv1394_init.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   Example 1:
							 | 
						||
| 
								 | 
							
								         To play a raw .DV file:   cat foo.DV > /dev/dv1394
							 | 
						||
| 
								 | 
							
									 (cat will use write() internally)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   Example 2:
							 | 
						||
| 
								 | 
							
								           static struct dv1394_init init = {
							 | 
						||
| 
								 | 
							
									      0x63,        (broadcast channel)
							 | 
						||
| 
								 | 
							
								              4,           (four-frame ringbuffer)
							 | 
						||
| 
								 | 
							
									      DV1394_NTSC, (send NTSC video)
							 | 
						||
| 
								 | 
							
									      0, 0         (default empty packet rate)
							 | 
						||
| 
								 | 
							
								           }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									   ioctl(fd, DV1394_INIT, &init);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									   while (1) {
							 | 
						||
| 
								 | 
							
									          read( <a raw DV file>, buf, DV1394_NTSC_FRAME_SIZE );
							 | 
						||
| 
								 | 
							
										  write( <the dv1394 FD>, buf, DV1394_NTSC_FRAME_SIZE );
							 | 
						||
| 
								 | 
							
								           }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   2)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   For more control over buffering, and to avoid unnecessary copies
							 | 
						||
| 
								 | 
							
								   of the DV data, you can use the more sophisticated the mmap() interface.
							 | 
						||
| 
								 | 
							
								   First, call the DV1394_INIT ioctl to specify your parameters,
							 | 
						||
| 
								 | 
							
								   including the number of frames in the ringbuffer. Then, calling mmap()
							 | 
						||
| 
								 | 
							
								   on the dv1394 device will give you direct access to the ringbuffer
							 | 
						||
| 
								 | 
							
								   from which the DV card reads your frame data.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   The ringbuffer is simply one large, contiguous region of memory
							 | 
						||
| 
								 | 
							
								   containing two or more frames of packed DV data. Each frame of DV data
							 | 
						||
| 
								 | 
							
								   is 120000 bytes (NTSC) or 144000 bytes (PAL).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   Fill one or more frames in the ringbuffer, then use the DV1394_SUBMIT_FRAMES
							 | 
						||
| 
								 | 
							
								   ioctl to begin I/O. You can use either the DV1394_WAIT_FRAMES ioctl
							 | 
						||
| 
								 | 
							
								   or select()/poll() to wait until the frames are transmitted. Next, you'll
							 | 
						||
| 
								 | 
							
								   need to call the DV1394_GET_STATUS ioctl to determine which ringbuffer
							 | 
						||
| 
								 | 
							
								   frames are clear (ready to be filled with new DV data). Finally, use
							 | 
						||
| 
								 | 
							
								   DV1394_SUBMIT_FRAMES again to send the new data to the DV output.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   Example: here is what a four-frame ringbuffer might look like
							 | 
						||
| 
								 | 
							
								            during DV transmission:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								         frame 0   frame 1   frame 2   frame 3
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									*--------------------------------------*
							 | 
						||
| 
								 | 
							
								        | CLEAR   | DV data | DV data | CLEAR  |
							 | 
						||
| 
								 | 
							
								        *--------------------------------------*
							 | 
						||
| 
								 | 
							
								                   <ACTIVE>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									transmission goes in this direction --->>>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   The DV hardware is currently transmitting the data in frame 1.
							 | 
						||
| 
								 | 
							
								   Once frame 1 is finished, it will automatically transmit frame 2.
							 | 
						||
| 
								 | 
							
								   (if frame 2 finishes before frame 3 is submitted, the device
							 | 
						||
| 
								 | 
							
								   will continue to transmit frame 2, and will increase the dropped_frames
							 | 
						||
| 
								 | 
							
								   counter each time it repeats the transmission).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   If you called DV1394_GET_STATUS at this instant, you would
							 | 
						||
| 
								 | 
							
								   receive the following values:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                  n_frames          = 4
							 | 
						||
| 
								 | 
							
										  active_frame      = 1
							 | 
						||
| 
								 | 
							
										  first_clear_frame = 3
							 | 
						||
| 
								 | 
							
										  n_clear_frames    = 2
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   At this point, you should write new DV data into frame 3 and optionally
							 | 
						||
| 
								 | 
							
								   frame 0. Then call DV1394_SUBMIT_FRAMES to inform the device that
							 | 
						||
| 
								 | 
							
								   it may transmit the new frames.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   ERROR HANDLING
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   An error (buffer underflow/overflow or a break in the DV stream due
							 | 
						||
| 
								 | 
							
								   to a 1394 bus reset) can be detected by checking the dropped_frames
							 | 
						||
| 
								 | 
							
								   field of struct dv1394_status (obtained through the
							 | 
						||
| 
								 | 
							
								   DV1394_GET_STATUS ioctl).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   The best way to recover from such an error is to re-initialize
							 | 
						||
| 
								 | 
							
								   dv1394, either by using the DV1394_INIT ioctl call, or closing the
							 | 
						||
| 
								 | 
							
								   file descriptor and opening it again. (note that you must unmap all
							 | 
						||
| 
								 | 
							
								   ringbuffer mappings when closing the file descriptor, or else
							 | 
						||
| 
								 | 
							
								   dv1394 will still be considered 'in use').
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   MAIN LOOP
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   For maximum efficiency and robustness against bus errors, you are
							 | 
						||
| 
								 | 
							
								   advised to model the main loop of your application after the
							 | 
						||
| 
								 | 
							
								   following pseudo-code example:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   (checks of system call return values omitted for brevity; always
							 | 
						||
| 
								 | 
							
								   check return values in your code!)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   while ( frames left ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    struct pollfd *pfd = ...;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    pfd->fd = dv1394_fd;
							 | 
						||
| 
								 | 
							
								    pfd->revents = 0;
							 | 
						||
| 
								 | 
							
								    pfd->events = POLLOUT | POLLIN; (OUT for transmit, IN for receive)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    (add other sources of I/O here)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    poll(pfd, 1, -1); (or select(); add a timeout if you want)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (pfd->revents) {
							 | 
						||
| 
								 | 
							
								         struct dv1394_status status;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								         ioctl(dv1394_fd, DV1394_GET_STATUS, &status);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									 if (status.dropped_frames > 0) {
							 | 
						||
| 
								 | 
							
									      reset_dv1394();
							 | 
						||
| 
								 | 
							
								         } else {
							 | 
						||
| 
								 | 
							
								              for (int i = 0; i < status.n_clear_frames; i++) {
							 | 
						||
| 
								 | 
							
									          copy_DV_frame();
							 | 
						||
| 
								 | 
							
								              }
							 | 
						||
| 
								 | 
							
								         }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   where copy_DV_frame() reads or writes on the dv1394 file descriptor
							 | 
						||
| 
								 | 
							
								   (read/write mode) or copies data to/from the mmap ringbuffer and
							 | 
						||
| 
								 | 
							
								   then calls ioctl(DV1394_SUBMIT_FRAMES) to notify dv1394 that new
							 | 
						||
| 
								 | 
							
								   frames are availble (mmap mode).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   reset_dv1394() is called in the event of a buffer
							 | 
						||
| 
								 | 
							
								   underflow/overflow or a halt in the DV stream (e.g. due to a 1394
							 | 
						||
| 
								 | 
							
								   bus reset). To guarantee recovery from the error, this function
							 | 
						||
| 
								 | 
							
								   should close the dv1394 file descriptor (and munmap() all
							 | 
						||
| 
								 | 
							
								   ringbuffer mappings, if you are using them), then re-open the
							 | 
						||
| 
								 | 
							
								   dv1394 device (and re-map the ringbuffer).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* maximum number of frames in the ringbuffer */
							 | 
						||
| 
								 | 
							
								#define DV1394_MAX_FRAMES 32
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* number of *full* isochronous packets per DV frame */
							 | 
						||
| 
								 | 
							
								#define DV1394_NTSC_PACKETS_PER_FRAME 250
							 | 
						||
| 
								 | 
							
								#define DV1394_PAL_PACKETS_PER_FRAME  300
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* size of one frame's worth of DV data, in bytes */
							 | 
						||
| 
								 | 
							
								#define DV1394_NTSC_FRAME_SIZE (480 * DV1394_NTSC_PACKETS_PER_FRAME)
							 | 
						||
| 
								 | 
							
								#define DV1394_PAL_FRAME_SIZE  (480 * DV1394_PAL_PACKETS_PER_FRAME)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* ioctl() commands */
							 | 
						||
| 
								 | 
							
								#include "ieee1394-ioctl.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								enum pal_or_ntsc {
							 | 
						||
| 
								 | 
							
									DV1394_NTSC = 0,
							 | 
						||
| 
								 | 
							
									DV1394_PAL
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* this is the argument to DV1394_INIT */
							 | 
						||
| 
								 | 
							
								struct dv1394_init {
							 | 
						||
| 
								 | 
							
									/* DV1394_API_VERSION */
							 | 
						||
| 
								 | 
							
									unsigned int api_version;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* isochronous transmission channel to use */
							 | 
						||
| 
								 | 
							
									unsigned int channel;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* number of frames in the ringbuffer. Must be at least 2
							 | 
						||
| 
								 | 
							
									   and at most DV1394_MAX_FRAMES. */
							 | 
						||
| 
								 | 
							
									unsigned int n_frames;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* send/receive PAL or NTSC video format */
							 | 
						||
| 
								 | 
							
									enum pal_or_ntsc format;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* the following are used only for transmission */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* set these to zero unless you want a
							 | 
						||
| 
								 | 
							
									   non-default empty packet rate (see below) */
							 | 
						||
| 
								 | 
							
									unsigned long cip_n;
							 | 
						||
| 
								 | 
							
									unsigned long cip_d;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* set this to zero unless you want a
							 | 
						||
| 
								 | 
							
									   non-default SYT cycle offset (default = 3 cycles) */
							 | 
						||
| 
								 | 
							
									unsigned int syt_offset;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* NOTE: you may only allocate the DV frame ringbuffer once each time
							 | 
						||
| 
								 | 
							
								   you open the dv1394 device. DV1394_INIT will fail if you call it a
							 | 
						||
| 
								 | 
							
								   second time with different 'n_frames' or 'format' arguments (which
							 | 
						||
| 
								 | 
							
								   would imply a different size for the ringbuffer). If you need a
							 | 
						||
| 
								 | 
							
								   different buffer size, simply close and re-open the device, then
							 | 
						||
| 
								 | 
							
								   initialize it with your new settings. */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* Q: What are cip_n and cip_d? */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								  A: DV video streams do not utilize 100% of the potential bandwidth offered
							 | 
						||
| 
								 | 
							
								  by IEEE 1394 (FireWire). To achieve the correct rate of data transmission,
							 | 
						||
| 
								 | 
							
								  DV devices must periodically insert empty packets into the 1394 data stream.
							 | 
						||
| 
								 | 
							
								  Typically there is one empty packet per 14-16 data-carrying packets.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  Some DV devices will accept a wide range of empty packet rates, while others
							 | 
						||
| 
								 | 
							
								  require a precise rate. If the dv1394 driver produces empty packets at
							 | 
						||
| 
								 | 
							
								  a rate that your device does not accept, you may see ugly patterns on the
							 | 
						||
| 
								 | 
							
								  DV output, or even no output at all.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  The default empty packet insertion rate seems to work for many people; if
							 | 
						||
| 
								 | 
							
								  your DV output is stable, you can simply ignore this discussion. However,
							 | 
						||
| 
								 | 
							
								  we have exposed the empty packet rate as a parameter to support devices that
							 | 
						||
| 
								 | 
							
								  do not work with the default rate.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  The decision to insert an empty packet is made with a numerator/denominator
							 | 
						||
| 
								 | 
							
								  algorithm. Empty packets are produced at an average rate of CIP_N / CIP_D.
							 | 
						||
| 
								 | 
							
								  You can alter the empty packet rate by passing non-zero values for cip_n
							 | 
						||
| 
								 | 
							
								  and cip_d to the INIT ioctl.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								struct dv1394_status {
							 | 
						||
| 
								 | 
							
									/* this embedded init struct returns the current dv1394
							 | 
						||
| 
								 | 
							
									   parameters in use */
							 | 
						||
| 
								 | 
							
									struct dv1394_init init;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* the ringbuffer frame that is currently being
							 | 
						||
| 
								 | 
							
									   displayed. (-1 if the device is not transmitting anything) */
							 | 
						||
| 
								 | 
							
									int active_frame;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* index of the first buffer (ahead of active_frame) that
							 | 
						||
| 
								 | 
							
									   is ready to be filled with data */
							 | 
						||
| 
								 | 
							
									unsigned int first_clear_frame;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* how many buffers, including first_clear_buffer, are
							 | 
						||
| 
								 | 
							
									   ready to be filled with data */
							 | 
						||
| 
								 | 
							
									unsigned int n_clear_frames;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* how many times the DV stream has underflowed, overflowed,
							 | 
						||
| 
								 | 
							
									   or otherwise encountered an error, since the previous call
							 | 
						||
| 
								 | 
							
									   to DV1394_GET_STATUS */
							 | 
						||
| 
								 | 
							
									unsigned int dropped_frames;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* N.B. The dropped_frames counter is only a lower bound on the actual
							 | 
						||
| 
								 | 
							
									   number of dropped frames, with the special case that if dropped_frames
							 | 
						||
| 
								 | 
							
									   is zero, then it is guaranteed that NO frames have been dropped
							 | 
						||
| 
								 | 
							
									   since the last call to DV1394_GET_STATUS.
							 | 
						||
| 
								 | 
							
									*/
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#endif /* _DV_1394_H */
							 |