Commit | Line | Data |
---|---|---|
2ba45a60 DM |
1 | /* |
2 | * Linux DV1394 interface | |
3 | * Copyright (c) 2003 Max Krasnyansky <maxk@qualcomm.com> | |
4 | * | |
5 | * This file is part of FFmpeg. | |
6 | * | |
7 | * FFmpeg is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU Lesser General Public | |
9 | * License as published by the Free Software Foundation; either | |
10 | * version 2.1 of the License, or (at your option) any later version. | |
11 | * | |
12 | * FFmpeg is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * Lesser General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU Lesser General Public | |
18 | * License along with FFmpeg; if not, write to the Free Software | |
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
20 | */ | |
21 | ||
22 | #include "config.h" | |
23 | #include <unistd.h> | |
24 | #include <fcntl.h> | |
25 | #include <errno.h> | |
26 | #include <poll.h> | |
27 | #include <sys/ioctl.h> | |
28 | #include <sys/mman.h> | |
29 | ||
30 | #include "libavutil/internal.h" | |
31 | #include "libavutil/log.h" | |
32 | #include "libavutil/opt.h" | |
33 | #include "avdevice.h" | |
34 | #include "libavformat/dv.h" | |
35 | #include "dv1394.h" | |
36 | ||
37 | struct dv1394_data { | |
38 | AVClass *class; | |
39 | int fd; | |
40 | int channel; | |
41 | int format; | |
42 | ||
43 | uint8_t *ring; /* Ring buffer */ | |
44 | int index; /* Current frame index */ | |
45 | int avail; /* Number of frames available for reading */ | |
46 | int done; /* Number of completed frames */ | |
47 | ||
48 | DVDemuxContext* dv_demux; /* Generic DV muxing/demuxing context */ | |
49 | }; | |
50 | ||
51 | /* | |
52 | * The trick here is to kludge around well known problem with kernel Ooopsing | |
53 | * when you try to capture PAL on a device node configure for NTSC. That's | |
54 | * why we have to configure the device node for PAL, and then read only NTSC | |
55 | * amount of data. | |
56 | */ | |
57 | static int dv1394_reset(struct dv1394_data *dv) | |
58 | { | |
59 | struct dv1394_init init; | |
60 | ||
61 | init.channel = dv->channel; | |
62 | init.api_version = DV1394_API_VERSION; | |
63 | init.n_frames = DV1394_RING_FRAMES; | |
64 | init.format = DV1394_PAL; | |
65 | ||
66 | if (ioctl(dv->fd, DV1394_INIT, &init) < 0) | |
67 | return -1; | |
68 | ||
69 | dv->avail = dv->done = 0; | |
70 | return 0; | |
71 | } | |
72 | ||
73 | static int dv1394_start(struct dv1394_data *dv) | |
74 | { | |
75 | /* Tell DV1394 driver to enable receiver */ | |
76 | if (ioctl(dv->fd, DV1394_START_RECEIVE, 0) < 0) { | |
77 | av_log(NULL, AV_LOG_ERROR, "Failed to start receiver: %s\n", strerror(errno)); | |
78 | return -1; | |
79 | } | |
80 | return 0; | |
81 | } | |
82 | ||
83 | static int dv1394_read_header(AVFormatContext * context) | |
84 | { | |
85 | struct dv1394_data *dv = context->priv_data; | |
86 | ||
87 | dv->dv_demux = avpriv_dv_init_demux(context); | |
88 | if (!dv->dv_demux) | |
89 | goto failed; | |
90 | ||
91 | /* Open and initialize DV1394 device */ | |
92 | dv->fd = avpriv_open(context->filename, O_RDONLY); | |
93 | if (dv->fd < 0) { | |
94 | av_log(context, AV_LOG_ERROR, "Failed to open DV interface: %s\n", strerror(errno)); | |
95 | goto failed; | |
96 | } | |
97 | ||
98 | if (dv1394_reset(dv) < 0) { | |
99 | av_log(context, AV_LOG_ERROR, "Failed to initialize DV interface: %s\n", strerror(errno)); | |
100 | goto failed; | |
101 | } | |
102 | ||
103 | dv->ring = mmap(NULL, DV1394_PAL_FRAME_SIZE * DV1394_RING_FRAMES, | |
104 | PROT_READ, MAP_PRIVATE, dv->fd, 0); | |
105 | if (dv->ring == MAP_FAILED) { | |
106 | av_log(context, AV_LOG_ERROR, "Failed to mmap DV ring buffer: %s\n", strerror(errno)); | |
107 | goto failed; | |
108 | } | |
109 | ||
110 | if (dv1394_start(dv) < 0) | |
111 | goto failed; | |
112 | ||
113 | return 0; | |
114 | ||
115 | failed: | |
116 | close(dv->fd); | |
117 | return AVERROR(EIO); | |
118 | } | |
119 | ||
120 | static int dv1394_read_packet(AVFormatContext *context, AVPacket *pkt) | |
121 | { | |
122 | struct dv1394_data *dv = context->priv_data; | |
123 | int size; | |
124 | ||
125 | size = avpriv_dv_get_packet(dv->dv_demux, pkt); | |
126 | if (size > 0) | |
127 | return size; | |
128 | ||
129 | if (!dv->avail) { | |
130 | struct dv1394_status s; | |
131 | struct pollfd p; | |
132 | ||
133 | if (dv->done) { | |
134 | /* Request more frames */ | |
135 | if (ioctl(dv->fd, DV1394_RECEIVE_FRAMES, dv->done) < 0) { | |
136 | /* This usually means that ring buffer overflowed. | |
137 | * We have to reset :(. | |
138 | */ | |
139 | ||
140 | av_log(context, AV_LOG_ERROR, "DV1394: Ring buffer overflow. Reseting ..\n"); | |
141 | ||
142 | dv1394_reset(dv); | |
143 | dv1394_start(dv); | |
144 | } | |
145 | dv->done = 0; | |
146 | } | |
147 | ||
148 | /* Wait until more frames are available */ | |
149 | restart_poll: | |
150 | p.fd = dv->fd; | |
151 | p.events = POLLIN | POLLERR | POLLHUP; | |
152 | if (poll(&p, 1, -1) < 0) { | |
153 | if (errno == EAGAIN || errno == EINTR) | |
154 | goto restart_poll; | |
155 | av_log(context, AV_LOG_ERROR, "Poll failed: %s\n", strerror(errno)); | |
156 | return AVERROR(EIO); | |
157 | } | |
158 | ||
159 | if (ioctl(dv->fd, DV1394_GET_STATUS, &s) < 0) { | |
160 | av_log(context, AV_LOG_ERROR, "Failed to get status: %s\n", strerror(errno)); | |
161 | return AVERROR(EIO); | |
162 | } | |
163 | av_dlog(context, "DV1394: status\n" | |
164 | "\tactive_frame\t%d\n" | |
165 | "\tfirst_clear_frame\t%d\n" | |
166 | "\tn_clear_frames\t%d\n" | |
167 | "\tdropped_frames\t%d\n", | |
168 | s.active_frame, s.first_clear_frame, | |
169 | s.n_clear_frames, s.dropped_frames); | |
170 | ||
171 | dv->avail = s.n_clear_frames; | |
172 | dv->index = s.first_clear_frame; | |
173 | dv->done = 0; | |
174 | ||
175 | if (s.dropped_frames) { | |
176 | av_log(context, AV_LOG_ERROR, "DV1394: Frame drop detected (%d). Reseting ..\n", | |
177 | s.dropped_frames); | |
178 | ||
179 | dv1394_reset(dv); | |
180 | dv1394_start(dv); | |
181 | } | |
182 | } | |
183 | ||
184 | av_dlog(context, "index %d, avail %d, done %d\n", dv->index, dv->avail, | |
185 | dv->done); | |
186 | ||
187 | size = avpriv_dv_produce_packet(dv->dv_demux, pkt, | |
188 | dv->ring + (dv->index * DV1394_PAL_FRAME_SIZE), | |
189 | DV1394_PAL_FRAME_SIZE, -1); | |
190 | dv->index = (dv->index + 1) % DV1394_RING_FRAMES; | |
191 | dv->done++; dv->avail--; | |
192 | ||
193 | return size; | |
194 | } | |
195 | ||
196 | static int dv1394_close(AVFormatContext * context) | |
197 | { | |
198 | struct dv1394_data *dv = context->priv_data; | |
199 | ||
200 | /* Shutdown DV1394 receiver */ | |
201 | if (ioctl(dv->fd, DV1394_SHUTDOWN, 0) < 0) | |
202 | av_log(context, AV_LOG_ERROR, "Failed to shutdown DV1394: %s\n", strerror(errno)); | |
203 | ||
204 | /* Unmap ring buffer */ | |
205 | if (munmap(dv->ring, DV1394_NTSC_FRAME_SIZE * DV1394_RING_FRAMES) < 0) | |
206 | av_log(context, AV_LOG_ERROR, "Failed to munmap DV1394 ring buffer: %s\n", strerror(errno)); | |
207 | ||
208 | close(dv->fd); | |
209 | av_free(dv->dv_demux); | |
210 | ||
211 | return 0; | |
212 | } | |
213 | ||
214 | static const AVOption options[] = { | |
215 | { "standard", "", offsetof(struct dv1394_data, format), AV_OPT_TYPE_INT, {.i64 = DV1394_NTSC}, DV1394_NTSC, DV1394_PAL, AV_OPT_FLAG_DECODING_PARAM, "standard" }, | |
216 | { "PAL", "", 0, AV_OPT_TYPE_CONST, {.i64 = DV1394_PAL}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, "standard" }, | |
217 | { "NTSC", "", 0, AV_OPT_TYPE_CONST, {.i64 = DV1394_NTSC}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, "standard" }, | |
218 | { "channel", "", offsetof(struct dv1394_data, channel), AV_OPT_TYPE_INT, {.i64 = DV1394_DEFAULT_CHANNEL}, 0, INT_MAX, AV_OPT_FLAG_DECODING_PARAM }, | |
219 | { NULL }, | |
220 | }; | |
221 | ||
222 | static const AVClass dv1394_class = { | |
223 | .class_name = "DV1394 indev", | |
224 | .item_name = av_default_item_name, | |
225 | .option = options, | |
226 | .version = LIBAVUTIL_VERSION_INT, | |
227 | .category = AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT, | |
228 | }; | |
229 | ||
230 | AVInputFormat ff_dv1394_demuxer = { | |
231 | .name = "dv1394", | |
232 | .long_name = NULL_IF_CONFIG_SMALL("DV1394 A/V grab"), | |
233 | .priv_data_size = sizeof(struct dv1394_data), | |
234 | .read_header = dv1394_read_header, | |
235 | .read_packet = dv1394_read_packet, | |
236 | .read_close = dv1394_close, | |
237 | .flags = AVFMT_NOFILE, | |
238 | .priv_class = &dv1394_class, | |
239 | }; |