Originally committed as revision 1493 to svn://svn.ffmpeg.org/ffmpeg/trunktags/v0.5
| @@ -53,6 +53,7 @@ gprof="no" | |||
| v4l="yes" | |||
| audio_oss="yes" | |||
| audio_beos="no" | |||
| dv1394="yes" | |||
| network="yes" | |||
| zlib="yes" | |||
| mp3lame="no" | |||
| @@ -103,6 +104,7 @@ SHFLAGS=-nostart | |||
| # disable linux things | |||
| audio_oss="no" | |||
| v4l="no" | |||
| dv1394="no" | |||
| # enable beos things | |||
| audio_beos="yes" | |||
| # no need for libm, but the inet stuff | |||
| @@ -117,6 +119,7 @@ fi ;; | |||
| SunOS) | |||
| v4l="no" | |||
| audio_oss="no" | |||
| dv1394="no" | |||
| make="gmake" | |||
| LDFLAGS="" | |||
| FFSLDFLAGS="" | |||
| @@ -126,12 +129,14 @@ extralibs="$extralibs -lsocket -lnsl" | |||
| FreeBSD) | |||
| v4l="no" | |||
| audio_oss="yes" | |||
| dv1394="no" | |||
| make="gmake" | |||
| LDFLAGS="$LDFLAGS -export-dynamic" | |||
| ;; | |||
| BSD/OS) | |||
| v4l="no" | |||
| audio_oss="yes" | |||
| dv1394="no" | |||
| extralibs="-lpoll -lgnugetopt -lm" | |||
| make="gmake" | |||
| ;; | |||
| @@ -139,6 +144,7 @@ Darwin) | |||
| cc="cc" | |||
| v4l="no" | |||
| audio_oss="no" | |||
| dv1394="no" | |||
| SHFLAGS="-dynamiclib" | |||
| extralibs="" | |||
| darwin="yes" | |||
| @@ -158,6 +164,7 @@ esac | |||
| MINGW32*) | |||
| v4l="no" | |||
| audio_oss="no" | |||
| dv1394="no" | |||
| ffserver="no" | |||
| network="no" | |||
| mingw32="yes" | |||
| @@ -165,6 +172,7 @@ mingw32="yes" | |||
| CYGWIN*) | |||
| v4l="no" | |||
| audio_oss="yes" | |||
| dv1394="no" | |||
| extralibs="" | |||
| cygwin="yes" | |||
| test -f /usr/include/inttypes.h || \ | |||
| @@ -190,6 +198,7 @@ SLIBSUF=".dll" | |||
| extralibs="" | |||
| v4l="no" | |||
| audio_oss="no" | |||
| dv1394="no" | |||
| network="no" | |||
| ffserver="no" | |||
| os2="yes" | |||
| @@ -287,6 +296,8 @@ for opt do | |||
| ;; | |||
| --disable-audio-beos) audio_beos="no" | |||
| ;; | |||
| --disable-dv1394) dv1394="no" | |||
| ;; | |||
| --disable-network) network="no" | |||
| ;; | |||
| --disable-zlib) zlib="no" | |||
| @@ -375,6 +386,7 @@ if test "$win32" = "yes" ; then | |||
| cross_prefix="i386-mingw32msvc-" | |||
| v4l="no" | |||
| audio_oss="no" | |||
| dv1394="no" | |||
| network="no" | |||
| fi | |||
| @@ -382,6 +394,7 @@ if test "$mingw32" = "yes" ; then | |||
| cross_prefix="" | |||
| v4l="no" | |||
| audio_oss="no" | |||
| dv1394="no" | |||
| network="no" | |||
| fi | |||
| @@ -543,6 +556,7 @@ echo " --disable-altivec disable AltiVec usage" | |||
| echo " --disable-audio-oss disable OSS audio support [default=no]" | |||
| echo " --disable-audio-beos disable BeOS audio support [default=no]" | |||
| echo " --disable-v4l disable video4linux grabbing [default=no]" | |||
| echo " --disable-dv1394 disable DV1394 grabbing [default=no]" | |||
| echo " --disable-network disable network support [default=no]" | |||
| echo " --disable-zlib disable zlib [default=no]" | |||
| echo " --disable-simple_idct disable simple IDCT routines [default=no]" | |||
| @@ -705,6 +719,11 @@ if test "$v4l" = "yes" ; then | |||
| echo "CONFIG_VIDEO4LINUX=yes" >> config.mak | |||
| fi | |||
| if test "$dv1394" = "yes" ; then | |||
| echo "#define CONFIG_DV1394 1" >> $TMPH | |||
| echo "CONFIG_DV1394=yes" >> config.mak | |||
| fi | |||
| if test "$dlopen" = "yes" ; then | |||
| echo "#define CONFIG_HAVE_DLOPEN 1" >> $TMPH | |||
| fi | |||
| @@ -158,14 +158,14 @@ static char *pass_logfilename = NULL; | |||
| static int audio_stream_copy = 0; | |||
| static int video_stream_copy = 0; | |||
| static char *video_grab_format = "video4linux"; | |||
| static char *audio_grab_format = "audio_device"; | |||
| #define DEFAULT_PASS_LOGFILENAME "ffmpeg2pass" | |||
| #if !defined(CONFIG_AUDIO_OSS) && !defined(CONFIG_AUDIO_BEOS) | |||
| const char *audio_device = "none"; | |||
| #endif | |||
| #ifndef CONFIG_VIDEO4LINUX | |||
| const char *v4l_device = "none"; | |||
| #endif | |||
| typedef struct AVOutputStream { | |||
| int file_index; /* file index */ | |||
| @@ -1870,7 +1870,7 @@ void opt_audio_channels(const char *arg) | |||
| void opt_video_device(const char *arg) | |||
| { | |||
| v4l_device = strdup(arg); | |||
| video_device = strdup(arg); | |||
| } | |||
| void opt_audio_device(const char *arg) | |||
| @@ -1878,6 +1878,12 @@ void opt_audio_device(const char *arg) | |||
| audio_device = strdup(arg); | |||
| } | |||
| void opt_dv1394(const char *arg) | |||
| { | |||
| video_grab_format = "dv1394"; | |||
| audio_grab_format = "none"; | |||
| } | |||
| void opt_audio_codec(const char *arg) | |||
| { | |||
| AVCodec *p; | |||
| @@ -2455,7 +2461,7 @@ void prepare_grab(void) | |||
| if (has_video) { | |||
| AVInputFormat *fmt1; | |||
| fmt1 = av_find_input_format("video_grab_device"); | |||
| fmt1 = av_find_input_format(video_grab_format); | |||
| if (av_open_input_file(&ic, "", fmt1, 0, ap) < 0) { | |||
| fprintf(stderr, "Could not find video grab device\n"); | |||
| exit(1); | |||
| @@ -2463,12 +2469,12 @@ void prepare_grab(void) | |||
| /* by now video grab has one stream */ | |||
| ic->streams[0]->r_frame_rate = ap->frame_rate; | |||
| input_files[nb_input_files] = ic; | |||
| dump_format(ic, nb_input_files, v4l_device, 0); | |||
| dump_format(ic, nb_input_files, video_device, 0); | |||
| nb_input_files++; | |||
| } | |||
| if (has_audio) { | |||
| AVInputFormat *fmt1; | |||
| fmt1 = av_find_input_format("audio_device"); | |||
| fmt1 = av_find_input_format(audio_grab_format); | |||
| if (av_open_input_file(&ic, "", fmt1, 0, ap) < 0) { | |||
| fprintf(stderr, "Could not find audio grab device\n"); | |||
| exit(1); | |||
| @@ -2692,6 +2698,7 @@ const OptionDef options[] = { | |||
| { "minrate", HAS_ARG, {(void*)opt_video_bitrate_min}, "set min video bitrate tolerance (in kbit/s)", "bitrate" }, | |||
| { "bufsize", HAS_ARG, {(void*)opt_video_buffer_size}, "set ratecontrol buffere size (in kbit)", "size" }, | |||
| { "vd", HAS_ARG | OPT_EXPERT, {(void*)opt_video_device}, "set video grab device", "device" }, | |||
| { "dv1394", OPT_EXPERT, {(void*)opt_dv1394}, "set DV1394 options", "[channel]" }, | |||
| { "vcodec", HAS_ARG | OPT_EXPERT, {(void*)opt_video_codec}, "force video codec ('copy' to copy stream)", "codec" }, | |||
| { "me", HAS_ARG | OPT_EXPERT, {(void*)opt_motion_estimation}, "set motion estimation method", | |||
| "method" }, | |||
| @@ -28,6 +28,10 @@ ifeq ($(CONFIG_VIDEO4LINUX),yes) | |||
| OBJS+= grab.o | |||
| endif | |||
| ifeq ($(CONFIG_DV1394),yes) | |||
| OBJS+= dv1394.o | |||
| endif | |||
| ifeq ($(CONFIG_AUDIO_OSS),yes) | |||
| OBJS+= audio.o | |||
| endif | |||
| @@ -21,6 +21,8 @@ | |||
| /* If you do not call this function, then you can select exactly which | |||
| formats you want to support */ | |||
| char *video_device = "none"; | |||
| /** | |||
| * Initialize libavcodec and register all the codecs and formats. | |||
| */ | |||
| @@ -62,6 +64,10 @@ void av_register_all(void) | |||
| audio_init(); | |||
| #endif | |||
| #ifdef CONFIG_DV1394 | |||
| dv1394_init(); | |||
| #endif | |||
| /* image formats */ | |||
| av_register_image_format(&pnm_image_format); | |||
| av_register_image_format(&pbm_image_format); | |||
| @@ -0,0 +1,249 @@ | |||
| /* | |||
| * Linux DV1394 interface | |||
| * Copyright (c) 2003 Max Krasnyansky <maxk@qualcomm.com> | |||
| * | |||
| * This library is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU Lesser General Public | |||
| * License as published by the Free Software Foundation; either | |||
| * version 2 of the License, or (at your option) any later version. | |||
| * | |||
| * This library 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 | |||
| * Lesser General Public License for more details. | |||
| * | |||
| * You should have received a copy of the GNU Lesser General Public | |||
| * License along with this library; if not, write to the Free Software | |||
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| */ | |||
| #include <unistd.h> | |||
| #include <fcntl.h> | |||
| #include <sys/ioctl.h> | |||
| #include <sys/mman.h> | |||
| #include <sys/poll.h> | |||
| #include <sys/time.h> | |||
| #include <time.h> | |||
| #include "avformat.h" | |||
| #undef DV1394_DEBUG | |||
| #include "dv1394.h" | |||
| int dv1394_channel = DV1394_DEFAULT_CHANNEL; | |||
| struct dv1394_data { | |||
| int fd; | |||
| int channel; | |||
| int width, height; | |||
| int frame_rate; | |||
| int frame_size; | |||
| void *ring; /* Ring buffer */ | |||
| int index; /* Current frame index */ | |||
| int avail; /* Number of frames available for reading */ | |||
| int done; /* Number of completed frames */ | |||
| }; | |||
| static int dv1394_reset(struct dv1394_data *dv) | |||
| { | |||
| struct dv1394_init init; | |||
| init.channel = dv->channel; | |||
| init.api_version = DV1394_API_VERSION; | |||
| init.n_frames = DV1394_RING_FRAMES; | |||
| init.format = DV1394_NTSC; | |||
| if (ioctl(dv->fd, DV1394_INIT, &init) < 0) | |||
| return -1; | |||
| dv->avail = 0; | |||
| return 0; | |||
| } | |||
| static int dv1394_start(struct dv1394_data *dv) | |||
| { | |||
| /* Tell DV1394 driver to enable receiver */ | |||
| if (ioctl(dv->fd, DV1394_START_RECEIVE, 0) < 0) { | |||
| perror("Failed to start receiver"); | |||
| return -1; | |||
| } | |||
| return 0; | |||
| } | |||
| static int dv1394_read_header(AVFormatContext * context, AVFormatParameters * ap) | |||
| { | |||
| struct dv1394_data *dv = context->priv_data; | |||
| AVStream *st; | |||
| st = av_new_stream(context, 0); | |||
| if (!st) | |||
| return -ENOMEM; | |||
| dv->width = DV1394_WIDTH; | |||
| dv->height = DV1394_HEIGHT; | |||
| dv->channel = dv1394_channel; | |||
| dv->frame_rate = 30; | |||
| dv->frame_size = DV1394_NTSC_FRAME_SIZE; | |||
| /* Open and initialize DV1394 device */ | |||
| dv->fd = open(video_device, O_RDONLY); | |||
| if (dv->fd < 0) { | |||
| perror("Failed to open DV interface"); | |||
| goto failed; | |||
| } | |||
| if (dv1394_reset(dv) < 0) { | |||
| perror("Failed to initialize DV interface"); | |||
| goto failed; | |||
| } | |||
| dv->ring = mmap(NULL, DV1394_NTSC_FRAME_SIZE * DV1394_RING_FRAMES, | |||
| PROT_READ, MAP_PRIVATE, dv->fd, 0); | |||
| if (!dv->ring) { | |||
| perror("Failed to mmap DV ring buffer"); | |||
| goto failed; | |||
| } | |||
| st->codec.codec_type = CODEC_TYPE_VIDEO; | |||
| st->codec.codec_id = CODEC_ID_DVVIDEO; | |||
| st->codec.width = dv->width; | |||
| st->codec.height = dv->height; | |||
| st->codec.frame_rate = dv->frame_rate * FRAME_RATE_BASE; | |||
| st->codec.bit_rate = 25000000; /* Consumer DV is 25Mbps */ | |||
| av_set_pts_info(context, 48, 1, 1000000); | |||
| if (dv1394_start(dv) < 0) | |||
| goto failed; | |||
| return 0; | |||
| failed: | |||
| close(dv->fd); | |||
| av_free(st); | |||
| return -EIO; | |||
| } | |||
| static inline int __copy_frame(struct dv1394_data *dv, void *buf) | |||
| { | |||
| char *ptr = dv->ring + (dv->index * dv->frame_size); | |||
| memcpy(buf, ptr, dv->frame_size); | |||
| dv->index = (dv->index + 1) % DV1394_RING_FRAMES; | |||
| dv->avail--; | |||
| dv->done++; | |||
| return dv->frame_size; | |||
| } | |||
| static int dv1394_read_packet(AVFormatContext * context, AVPacket * pkt) | |||
| { | |||
| struct dv1394_data *dv = context->priv_data; | |||
| int len; | |||
| if (!dv->avail) { | |||
| struct dv1394_status s; | |||
| struct pollfd p; | |||
| p.fd = dv->fd; | |||
| p.events = POLLIN | POLLERR | POLLHUP; | |||
| /* Wait until more frames are available */ | |||
| if (poll(&p, 1, -1) < 0) { | |||
| perror("Poll failed"); | |||
| return -EIO; | |||
| } | |||
| if (ioctl(dv->fd, DV1394_GET_STATUS, &s) < 0) { | |||
| perror("Failed to get status"); | |||
| return -EIO; | |||
| } | |||
| #ifdef DV1394_DEBUG | |||
| fprintf(stderr, "DV1394: status\n" | |||
| "\tactive_frame\t%d\n" | |||
| "\tfirst_clear_frame\t%d\n" | |||
| "\tn_clear_frames\t%d\n" | |||
| "\tdropped_frames\t%d\n", | |||
| s.active_frame, s.first_clear_frame, | |||
| s.n_clear_frames, s.dropped_frames); | |||
| #endif | |||
| dv->avail = s.n_clear_frames; | |||
| dv->index = s.first_clear_frame; | |||
| dv->done = 0; | |||
| if (s.dropped_frames) { | |||
| fprintf(stderr, "DV1394: Frame drop detected (%d). Reseting ..\n", | |||
| s.dropped_frames); | |||
| dv1394_reset(dv); | |||
| dv1394_start(dv); | |||
| } | |||
| } | |||
| if (av_new_packet(pkt, dv->frame_size) < 0) | |||
| return -EIO; | |||
| #ifdef DV1394_DEBUG | |||
| fprintf(stderr, "index %d, avail %d, done %d\n", dv->index, dv->avail, | |||
| dv->done); | |||
| #endif | |||
| len = __copy_frame(dv, pkt->data); | |||
| pkt->pts = av_gettime() & ((1LL << 48) - 1); | |||
| if (!dv->avail && dv->done) { | |||
| /* Request more frames */ | |||
| if (ioctl(dv->fd, DV1394_RECEIVE_FRAMES, dv->done) < 0) { | |||
| /* This usually means that ring buffer overflowed. | |||
| * We have to reset :(. | |||
| */ | |||
| fprintf(stderr, "DV1394: Ring buffer overflow. Reseting ..\n"); | |||
| dv1394_reset(dv); | |||
| dv1394_start(dv); | |||
| } | |||
| } | |||
| return len; | |||
| } | |||
| static int dv1394_close(AVFormatContext * context) | |||
| { | |||
| struct dv1394_data *dv = context->priv_data; | |||
| /* Shutdown DV1394 receiver */ | |||
| if (ioctl(dv->fd, DV1394_SHUTDOWN, 0) < 0) | |||
| perror("Failed to shutdown DV1394"); | |||
| /* Unmap ring buffer */ | |||
| if (munmap(dv->ring, DV1394_NTSC_FRAME_SIZE * DV1394_RING_FRAMES) < 0) | |||
| perror("Failed to munmap DV1394 ring buffer"); | |||
| close(dv->fd); | |||
| return 0; | |||
| } | |||
| static AVInputFormat dv1394_format = { | |||
| .name = "dv1394", | |||
| .long_name = "dv1394 A/V grab", | |||
| .priv_data_size = sizeof(struct dv1394_data), | |||
| .read_header = dv1394_read_header, | |||
| .read_packet = dv1394_read_packet, | |||
| .read_close = dv1394_close, | |||
| .flags = AVFMT_NOFILE | |||
| }; | |||
| int dv1394_init(void) | |||
| { | |||
| av_register_input_format(&dv1394_format); | |||
| return 0; | |||
| } | |||
| @@ -0,0 +1,353 @@ | |||
| /* | |||
| * dv1394.h - DV input/output over IEEE 1394 on OHCI chips | |||
| * Copyright (C)2001 Daniel Maas <dmaas@dcine.com> | |||
| * receive, proc_fs 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 | |||
| #define DV1394_DEFAULT_CHANNEL 0x63 | |||
| #define DV1394_DEFAULT_CARD 0 | |||
| #define DV1394_RING_FRAMES 20 | |||
| #define DV1394_WIDTH 720 | |||
| #define DV1394_HEIGHT 480 | |||
| /* 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 */ | |||
| enum { | |||
| /* I don't like using 0 as a valid ioctl() */ | |||
| DV1394_INVALID = 0, | |||
| /* get the driver ready to transmit video. | |||
| pass a struct dv1394_init* as the parameter (see below), | |||
| or NULL to get default parameters */ | |||
| DV1394_INIT, | |||
| /* stop transmitting video and free the ringbuffer */ | |||
| DV1394_SHUTDOWN, | |||
| /* submit N new frames to be transmitted, where | |||
| the index of the first new frame is first_clear_buffer, | |||
| and the index of the last new frame is | |||
| (first_clear_buffer + N) % n_frames */ | |||
| DV1394_SUBMIT_FRAMES, | |||
| /* block until N buffers are clear (pass N as the parameter) | |||
| Because we re-transmit the last frame on underrun, there | |||
| will at most be n_frames - 1 clear frames at any time */ | |||
| DV1394_WAIT_FRAMES, | |||
| /* capture new frames that have been received, where | |||
| the index of the first new frame is first_clear_buffer, | |||
| and the index of the last new frame is | |||
| (first_clear_buffer + N) % n_frames */ | |||
| DV1394_RECEIVE_FRAMES, | |||
| DV1394_START_RECEIVE, | |||
| /* pass a struct dv1394_status* as the parameter (see below) */ | |||
| DV1394_GET_STATUS, | |||
| }; | |||
| 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 */ | |||
| @@ -53,8 +53,6 @@ static int aiw_init(VideoData *s); | |||
| static int aiw_read_picture(VideoData *s, uint8_t *data); | |||
| static int aiw_close(VideoData *s); | |||
| const char *v4l_device = "/dev/video"; | |||
| static int grab_read_header(AVFormatContext *s1, AVFormatParameters *ap) | |||
| { | |||
| VideoData *s = s1->priv_data; | |||
| @@ -80,9 +78,9 @@ static int grab_read_header(AVFormatContext *s1, AVFormatParameters *ap) | |||
| s->height = height; | |||
| s->frame_rate = frame_rate; | |||
| video_fd = open(v4l_device, O_RDWR); | |||
| video_fd = open(video_device, O_RDWR); | |||
| if (video_fd < 0) { | |||
| perror(v4l_device); | |||
| perror(video_device); | |||
| goto fail; | |||
| } | |||
| @@ -339,7 +337,7 @@ static int grab_read_close(AVFormatContext *s1) | |||
| } | |||
| static AVInputFormat video_grab_device_format = { | |||
| "video_grab_device", | |||
| "video4linux", | |||
| "video grab", | |||
| sizeof(VideoData), | |||
| NULL, | |||