Mercurial > libavformat.hg
annotate dv1394.c @ 47:45308962220f libavformat
added jpeg image encoder and decoder (new YUV handling routines and mjpeg codec fixes are necessary to go further)
author | bellard |
---|---|
date | Sun, 02 Feb 2003 19:18:09 +0000 |
parents | cb1eb8829175 |
children | fb671d87824e |
rev | line source |
---|---|
27 | 1 /* |
2 * Linux DV1394 interface | |
3 * Copyright (c) 2003 Max Krasnyansky <maxk@qualcomm.com> | |
4 * | |
5 * This library is free software; you can redistribute it and/or | |
6 * modify it under the terms of the GNU Lesser General Public | |
7 * License as published by the Free Software Foundation; either | |
8 * version 2 of the License, or (at your option) any later version. | |
9 * | |
10 * This library is distributed in the hope that it will be useful, | |
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 * Lesser General Public License for more details. | |
14 * | |
15 * You should have received a copy of the GNU Lesser General Public | |
16 * License along with this library; if not, write to the Free Software | |
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 */ | |
19 | |
20 #include <unistd.h> | |
21 #include <fcntl.h> | |
22 #include <sys/ioctl.h> | |
23 #include <sys/mman.h> | |
24 #include <sys/poll.h> | |
25 #include <sys/time.h> | |
26 #include <time.h> | |
27 | |
28 #include "avformat.h" | |
29 | |
30 #undef DV1394_DEBUG | |
31 | |
32 #include "dv1394.h" | |
33 | |
34 struct dv1394_data { | |
35 int fd; | |
36 int channel; | |
37 int width, height; | |
38 int frame_rate; | |
39 int frame_size; | |
38 | 40 int format; |
27 | 41 |
42 void *ring; /* Ring buffer */ | |
43 int index; /* Current frame index */ | |
44 int avail; /* Number of frames available for reading */ | |
45 int done; /* Number of completed frames */ | |
38 | 46 |
47 int stream; /* Current stream. 0 - video, 1 - audio */ | |
48 INT64 pts; /* Current timestamp */ | |
27 | 49 }; |
50 | |
51 static int dv1394_reset(struct dv1394_data *dv) | |
52 { | |
53 struct dv1394_init init; | |
54 | |
38 | 55 init.channel = dv->channel; |
27 | 56 init.api_version = DV1394_API_VERSION; |
38 | 57 init.n_frames = DV1394_RING_FRAMES; |
58 init.format = dv->format; | |
27 | 59 |
60 if (ioctl(dv->fd, DV1394_INIT, &init) < 0) | |
61 return -1; | |
62 | |
63 dv->avail = 0; | |
64 return 0; | |
65 } | |
66 | |
67 static int dv1394_start(struct dv1394_data *dv) | |
68 { | |
69 /* Tell DV1394 driver to enable receiver */ | |
70 if (ioctl(dv->fd, DV1394_START_RECEIVE, 0) < 0) { | |
71 perror("Failed to start receiver"); | |
72 return -1; | |
73 } | |
74 return 0; | |
75 } | |
76 | |
77 static int dv1394_read_header(AVFormatContext * context, AVFormatParameters * ap) | |
78 { | |
79 struct dv1394_data *dv = context->priv_data; | |
38 | 80 AVStream *vst, *ast; |
30
90fd30dd68b3
grab device is in AVFormatParameter (at least better than global variable)
bellard
parents:
27
diff
changeset
|
81 const char *video_device; |
27 | 82 |
38 | 83 vst = av_new_stream(context, 0); |
84 if (!vst) | |
27 | 85 return -ENOMEM; |
38 | 86 ast = av_new_stream(context, 1); |
87 if (!ast) { | |
88 av_free(vst); | |
89 return -ENOMEM; | |
90 } | |
27 | 91 |
92 dv->width = DV1394_WIDTH; | |
93 dv->height = DV1394_HEIGHT; | |
31
36dd902f98d2
dv1394 channel selection by Max Krasnyansky - modified channel number to be in base 10 by default
bellard
parents:
30
diff
changeset
|
94 |
36dd902f98d2
dv1394 channel selection by Max Krasnyansky - modified channel number to be in base 10 by default
bellard
parents:
30
diff
changeset
|
95 if (ap->channel) |
36dd902f98d2
dv1394 channel selection by Max Krasnyansky - modified channel number to be in base 10 by default
bellard
parents:
30
diff
changeset
|
96 dv->channel = ap->channel; |
36dd902f98d2
dv1394 channel selection by Max Krasnyansky - modified channel number to be in base 10 by default
bellard
parents:
30
diff
changeset
|
97 else |
36dd902f98d2
dv1394 channel selection by Max Krasnyansky - modified channel number to be in base 10 by default
bellard
parents:
30
diff
changeset
|
98 dv->channel = DV1394_DEFAULT_CHANNEL; |
27 | 99 |
38 | 100 /* FIXME: Need a format change parameter */ |
101 dv->format = DV1394_NTSC; | |
27 | 102 |
38 | 103 if (dv->format == DV1394_NTSC) { |
104 dv->frame_size = DV1394_NTSC_FRAME_SIZE; | |
105 dv->frame_rate = 30; | |
106 } else { | |
107 dv->frame_size = DV1394_PAL_FRAME_SIZE; | |
108 dv->frame_rate = 25; | |
109 } | |
27 | 110 |
111 /* Open and initialize DV1394 device */ | |
30
90fd30dd68b3
grab device is in AVFormatParameter (at least better than global variable)
bellard
parents:
27
diff
changeset
|
112 video_device = ap->device; |
90fd30dd68b3
grab device is in AVFormatParameter (at least better than global variable)
bellard
parents:
27
diff
changeset
|
113 if (!video_device) |
90fd30dd68b3
grab device is in AVFormatParameter (at least better than global variable)
bellard
parents:
27
diff
changeset
|
114 video_device = "/dev/dv1394/0"; |
27 | 115 dv->fd = open(video_device, O_RDONLY); |
116 if (dv->fd < 0) { | |
117 perror("Failed to open DV interface"); | |
118 goto failed; | |
119 } | |
120 | |
121 if (dv1394_reset(dv) < 0) { | |
122 perror("Failed to initialize DV interface"); | |
123 goto failed; | |
124 } | |
125 | |
126 dv->ring = mmap(NULL, DV1394_NTSC_FRAME_SIZE * DV1394_RING_FRAMES, | |
127 PROT_READ, MAP_PRIVATE, dv->fd, 0); | |
128 if (!dv->ring) { | |
129 perror("Failed to mmap DV ring buffer"); | |
130 goto failed; | |
131 } | |
132 | |
38 | 133 dv->stream = 0; |
27 | 134 |
38 | 135 vst->codec.codec_type = CODEC_TYPE_VIDEO; |
136 vst->codec.codec_id = CODEC_ID_DVVIDEO; | |
137 vst->codec.width = dv->width; | |
138 vst->codec.height = dv->height; | |
139 vst->codec.frame_rate = dv->frame_rate * FRAME_RATE_BASE; | |
140 vst->codec.bit_rate = 25000000; /* Consumer DV is 25Mbps */ | |
141 | |
142 ast->codec.codec_type = CODEC_TYPE_AUDIO; | |
143 ast->codec.codec_id = CODEC_ID_DVAUDIO; | |
144 ast->codec.channels = 2; | |
145 ast->codec.sample_rate= 48000; | |
27 | 146 |
147 av_set_pts_info(context, 48, 1, 1000000); | |
148 | |
149 if (dv1394_start(dv) < 0) | |
150 goto failed; | |
151 | |
152 return 0; | |
153 | |
154 failed: | |
155 close(dv->fd); | |
38 | 156 av_free(vst); |
157 av_free(ast); | |
27 | 158 return -EIO; |
159 } | |
160 | |
38 | 161 static inline int __copy_frame(struct dv1394_data *dv, AVPacket *pkt) |
27 | 162 { |
163 char *ptr = dv->ring + (dv->index * dv->frame_size); | |
164 | |
38 | 165 if (dv->stream) { |
166 dv->index = (dv->index + 1) % DV1394_RING_FRAMES; | |
167 dv->done++; dv->avail--; | |
168 } else { | |
169 dv->pts = av_gettime() & ((1LL << 48) - 1); | |
170 } | |
27 | 171 |
38 | 172 memcpy(pkt->data, ptr, dv->frame_size); |
173 pkt->stream_index = dv->stream; | |
174 pkt->pts = dv->pts; | |
175 | |
176 dv->stream ^= 1; | |
27 | 177 |
178 return dv->frame_size; | |
179 } | |
180 | |
38 | 181 static int dv1394_read_packet(AVFormatContext *context, AVPacket *pkt) |
27 | 182 { |
183 struct dv1394_data *dv = context->priv_data; | |
184 int len; | |
185 | |
186 if (!dv->avail) { | |
187 struct dv1394_status s; | |
188 struct pollfd p; | |
189 p.fd = dv->fd; | |
190 p.events = POLLIN | POLLERR | POLLHUP; | |
191 | |
192 /* Wait until more frames are available */ | |
193 if (poll(&p, 1, -1) < 0) { | |
194 perror("Poll failed"); | |
195 return -EIO; | |
196 } | |
197 | |
198 if (ioctl(dv->fd, DV1394_GET_STATUS, &s) < 0) { | |
199 perror("Failed to get status"); | |
200 return -EIO; | |
201 } | |
202 #ifdef DV1394_DEBUG | |
203 fprintf(stderr, "DV1394: status\n" | |
204 "\tactive_frame\t%d\n" | |
205 "\tfirst_clear_frame\t%d\n" | |
206 "\tn_clear_frames\t%d\n" | |
207 "\tdropped_frames\t%d\n", | |
208 s.active_frame, s.first_clear_frame, | |
209 s.n_clear_frames, s.dropped_frames); | |
210 #endif | |
211 | |
212 dv->avail = s.n_clear_frames; | |
213 dv->index = s.first_clear_frame; | |
214 dv->done = 0; | |
215 | |
216 if (s.dropped_frames) { | |
217 fprintf(stderr, "DV1394: Frame drop detected (%d). Reseting ..\n", | |
218 s.dropped_frames); | |
219 | |
220 dv1394_reset(dv); | |
221 dv1394_start(dv); | |
222 } | |
223 } | |
224 | |
225 if (av_new_packet(pkt, dv->frame_size) < 0) | |
226 return -EIO; | |
227 | |
228 #ifdef DV1394_DEBUG | |
229 fprintf(stderr, "index %d, avail %d, done %d\n", dv->index, dv->avail, | |
230 dv->done); | |
231 #endif | |
232 | |
38 | 233 len = __copy_frame(dv, pkt); |
27 | 234 |
235 if (!dv->avail && dv->done) { | |
236 /* Request more frames */ | |
237 if (ioctl(dv->fd, DV1394_RECEIVE_FRAMES, dv->done) < 0) { | |
238 /* This usually means that ring buffer overflowed. | |
239 * We have to reset :(. | |
240 */ | |
241 | |
242 fprintf(stderr, "DV1394: Ring buffer overflow. Reseting ..\n"); | |
243 | |
244 dv1394_reset(dv); | |
245 dv1394_start(dv); | |
246 } | |
247 } | |
248 | |
249 return len; | |
250 } | |
251 | |
252 static int dv1394_close(AVFormatContext * context) | |
253 { | |
254 struct dv1394_data *dv = context->priv_data; | |
255 | |
256 /* Shutdown DV1394 receiver */ | |
257 if (ioctl(dv->fd, DV1394_SHUTDOWN, 0) < 0) | |
258 perror("Failed to shutdown DV1394"); | |
259 | |
260 /* Unmap ring buffer */ | |
261 if (munmap(dv->ring, DV1394_NTSC_FRAME_SIZE * DV1394_RING_FRAMES) < 0) | |
262 perror("Failed to munmap DV1394 ring buffer"); | |
263 | |
264 close(dv->fd); | |
265 | |
266 return 0; | |
267 } | |
268 | |
269 static AVInputFormat dv1394_format = { | |
270 .name = "dv1394", | |
271 .long_name = "dv1394 A/V grab", | |
272 .priv_data_size = sizeof(struct dv1394_data), | |
273 .read_header = dv1394_read_header, | |
274 .read_packet = dv1394_read_packet, | |
275 .read_close = dv1394_close, | |
276 .flags = AVFMT_NOFILE | |
277 }; | |
278 | |
279 int dv1394_init(void) | |
280 { | |
281 av_register_input_format(&dv1394_format); | |
282 return 0; | |
283 } |