Mercurial > libavformat.hg
annotate audio.c @ 1960:c0289552590f libavformat
Change the vhook code to send real timestamps to the filters instead of the
current time of day, which is useless, and which the filters could just as
easily query for themselves.
patch by Bobby Bingham, uhmmmm gmail com
author | diego |
---|---|
date | Thu, 29 Mar 2007 05:24:35 +0000 |
parents | 62792a60f740 |
children | 69ff78484350 |
rev | line source |
---|---|
0 | 1 /* |
2 * Linux audio play and grab interface | |
3 * Copyright (c) 2000, 2001 Fabrice Bellard. | |
4 * | |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1169
diff
changeset
|
5 * This file is part of FFmpeg. |
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1169
diff
changeset
|
6 * |
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1169
diff
changeset
|
7 * FFmpeg is free software; you can redistribute it and/or |
0 | 8 * modify it under the terms of the GNU Lesser General Public |
9 * License as published by the Free Software Foundation; either | |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1169
diff
changeset
|
10 * version 2.1 of the License, or (at your option) any later version. |
0 | 11 * |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1169
diff
changeset
|
12 * FFmpeg is distributed in the hope that it will be useful, |
0 | 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 | |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1169
diff
changeset
|
18 * License along with FFmpeg; if not, write to the Free Software |
896
edbe5c3717f9
Update licensing information: The FSF changed postal address.
diego
parents:
887
diff
changeset
|
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
0 | 20 */ |
21 #include "avformat.h" | |
22 | |
23 #include <stdlib.h> | |
24 #include <stdio.h> | |
25 #include <string.h> | |
1777
2f59a73884af
#include detected soundcard.h instead of testing for OpenBSD
mru
parents:
1358
diff
changeset
|
26 #ifdef HAVE_SOUNDCARD_H |
754
aa52767bb802
OpenBSD support patch by (Jacob Meuser // jakemsr jakemsr com)
michael
parents:
482
diff
changeset
|
27 #include <soundcard.h> |
aa52767bb802
OpenBSD support patch by (Jacob Meuser // jakemsr jakemsr com)
michael
parents:
482
diff
changeset
|
28 #else |
0 | 29 #include <sys/soundcard.h> |
754
aa52767bb802
OpenBSD support patch by (Jacob Meuser // jakemsr jakemsr com)
michael
parents:
482
diff
changeset
|
30 #endif |
0 | 31 #include <unistd.h> |
32 #include <fcntl.h> | |
33 #include <sys/ioctl.h> | |
34 #include <sys/mman.h> | |
35 #include <sys/time.h> | |
36 | |
37 #define AUDIO_BLOCK_SIZE 4096 | |
38 | |
39 typedef struct { | |
40 int fd; | |
41 int sample_rate; | |
42 int channels; | |
43 int frame_size; /* in bytes ! */ | |
44 int codec_id; | |
45 int flip_left : 1; | |
65 | 46 uint8_t buffer[AUDIO_BLOCK_SIZE]; |
0 | 47 int buffer_ptr; |
48 } AudioData; | |
49 | |
30
90fd30dd68b3
grab device is in AVFormatParameter (at least better than global variable)
bellard
parents:
0
diff
changeset
|
50 static int audio_open(AudioData *s, int is_output, const char *audio_device) |
0 | 51 { |
52 int audio_fd; | |
53 int tmp, err; | |
54 char *flip = getenv("AUDIO_FLIP_LEFT"); | |
55 | |
56 if (is_output) | |
57 audio_fd = open(audio_device, O_WRONLY); | |
58 else | |
59 audio_fd = open(audio_device, O_RDONLY); | |
60 if (audio_fd < 0) { | |
61 perror(audio_device); | |
482 | 62 return AVERROR_IO; |
0 | 63 } |
64 | |
65 if (flip && *flip == '1') { | |
66 s->flip_left = 1; | |
67 } | |
68 | |
69 /* non blocking mode */ | |
70 if (!is_output) | |
71 fcntl(audio_fd, F_SETFL, O_NONBLOCK); | |
72 | |
73 s->frame_size = AUDIO_BLOCK_SIZE; | |
74 #if 0 | |
75 tmp = (NB_FRAGMENTS << 16) | FRAGMENT_BITS; | |
76 err = ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &tmp); | |
77 if (err < 0) { | |
78 perror("SNDCTL_DSP_SETFRAGMENT"); | |
79 } | |
80 #endif | |
81 | |
82 /* select format : favour native format */ | |
83 err = ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &tmp); | |
885 | 84 |
0 | 85 #ifdef WORDS_BIGENDIAN |
86 if (tmp & AFMT_S16_BE) { | |
87 tmp = AFMT_S16_BE; | |
88 } else if (tmp & AFMT_S16_LE) { | |
89 tmp = AFMT_S16_LE; | |
90 } else { | |
91 tmp = 0; | |
92 } | |
93 #else | |
94 if (tmp & AFMT_S16_LE) { | |
95 tmp = AFMT_S16_LE; | |
96 } else if (tmp & AFMT_S16_BE) { | |
97 tmp = AFMT_S16_BE; | |
98 } else { | |
99 tmp = 0; | |
100 } | |
101 #endif | |
102 | |
103 switch(tmp) { | |
104 case AFMT_S16_LE: | |
105 s->codec_id = CODEC_ID_PCM_S16LE; | |
106 break; | |
107 case AFMT_S16_BE: | |
108 s->codec_id = CODEC_ID_PCM_S16BE; | |
109 break; | |
110 default: | |
370
845f9de2c883
av_log() patch by (Michel Bardiaux <mbardiaux at peaktime dot be>)
michael
parents:
241
diff
changeset
|
111 av_log(NULL, AV_LOG_ERROR, "Soundcard does not support 16 bit sample format\n"); |
0 | 112 close(audio_fd); |
482 | 113 return AVERROR_IO; |
0 | 114 } |
115 err=ioctl(audio_fd, SNDCTL_DSP_SETFMT, &tmp); | |
116 if (err < 0) { | |
117 perror("SNDCTL_DSP_SETFMT"); | |
118 goto fail; | |
119 } | |
885 | 120 |
0 | 121 tmp = (s->channels == 2); |
122 err = ioctl(audio_fd, SNDCTL_DSP_STEREO, &tmp); | |
123 if (err < 0) { | |
124 perror("SNDCTL_DSP_STEREO"); | |
125 goto fail; | |
126 } | |
127 if (tmp) | |
128 s->channels = 2; | |
885 | 129 |
0 | 130 tmp = s->sample_rate; |
131 err = ioctl(audio_fd, SNDCTL_DSP_SPEED, &tmp); | |
132 if (err < 0) { | |
133 perror("SNDCTL_DSP_SPEED"); | |
134 goto fail; | |
135 } | |
136 s->sample_rate = tmp; /* store real sample rate */ | |
137 s->fd = audio_fd; | |
138 | |
139 return 0; | |
140 fail: | |
141 close(audio_fd); | |
482 | 142 return AVERROR_IO; |
0 | 143 } |
144 | |
145 static int audio_close(AudioData *s) | |
146 { | |
147 close(s->fd); | |
148 return 0; | |
149 } | |
150 | |
151 /* sound output support */ | |
152 static int audio_write_header(AVFormatContext *s1) | |
153 { | |
154 AudioData *s = s1->priv_data; | |
155 AVStream *st; | |
156 int ret; | |
157 | |
158 st = s1->streams[0]; | |
820
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
754
diff
changeset
|
159 s->sample_rate = st->codec->sample_rate; |
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
754
diff
changeset
|
160 s->channels = st->codec->channels; |
30
90fd30dd68b3
grab device is in AVFormatParameter (at least better than global variable)
bellard
parents:
0
diff
changeset
|
161 ret = audio_open(s, 1, NULL); |
0 | 162 if (ret < 0) { |
482 | 163 return AVERROR_IO; |
0 | 164 } else { |
165 return 0; | |
166 } | |
167 } | |
168 | |
468 | 169 static int audio_write_packet(AVFormatContext *s1, AVPacket *pkt) |
0 | 170 { |
171 AudioData *s = s1->priv_data; | |
172 int len, ret; | |
468 | 173 int size= pkt->size; |
174 uint8_t *buf= pkt->data; | |
0 | 175 |
176 while (size > 0) { | |
177 len = AUDIO_BLOCK_SIZE - s->buffer_ptr; | |
178 if (len > size) | |
179 len = size; | |
180 memcpy(s->buffer + s->buffer_ptr, buf, len); | |
181 s->buffer_ptr += len; | |
182 if (s->buffer_ptr >= AUDIO_BLOCK_SIZE) { | |
183 for(;;) { | |
184 ret = write(s->fd, s->buffer, AUDIO_BLOCK_SIZE); | |
185 if (ret > 0) | |
186 break; | |
187 if (ret < 0 && (errno != EAGAIN && errno != EINTR)) | |
482 | 188 return AVERROR_IO; |
0 | 189 } |
190 s->buffer_ptr = 0; | |
191 } | |
192 buf += len; | |
193 size -= len; | |
194 } | |
195 return 0; | |
196 } | |
197 | |
198 static int audio_write_trailer(AVFormatContext *s1) | |
199 { | |
200 AudioData *s = s1->priv_data; | |
201 | |
202 audio_close(s); | |
203 return 0; | |
204 } | |
205 | |
206 /* grab support */ | |
207 | |
208 static int audio_read_header(AVFormatContext *s1, AVFormatParameters *ap) | |
209 { | |
210 AudioData *s = s1->priv_data; | |
211 AVStream *st; | |
212 int ret; | |
213 | |
1003 | 214 if (ap->sample_rate <= 0 || ap->channels <= 0) |
0 | 215 return -1; |
216 | |
217 st = av_new_stream(s1, 0); | |
218 if (!st) { | |
1787
eb16c64144ee
This fixes error handling for BeOS, removing the need for some ifdefs.
mmu_man
parents:
1777
diff
changeset
|
219 return AVERROR(ENOMEM); |
0 | 220 } |
221 s->sample_rate = ap->sample_rate; | |
222 s->channels = ap->channels; | |
223 | |
1795
62792a60f740
implement new grabbing interface, as described here:
gpoirier
parents:
1787
diff
changeset
|
224 ret = audio_open(s, 0, s1->filename); |
0 | 225 if (ret < 0) { |
226 av_free(st); | |
482 | 227 return AVERROR_IO; |
0 | 228 } |
229 | |
230 /* take real parameters */ | |
820
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
754
diff
changeset
|
231 st->codec->codec_type = CODEC_TYPE_AUDIO; |
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
754
diff
changeset
|
232 st->codec->codec_id = s->codec_id; |
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
754
diff
changeset
|
233 st->codec->sample_rate = s->sample_rate; |
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
754
diff
changeset
|
234 st->codec->channels = s->channels; |
0 | 235 |
921 | 236 av_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */ |
0 | 237 return 0; |
238 } | |
239 | |
240 static int audio_read_packet(AVFormatContext *s1, AVPacket *pkt) | |
241 { | |
242 AudioData *s = s1->priv_data; | |
243 int ret, bdelay; | |
244 int64_t cur_time; | |
245 struct audio_buf_info abufi; | |
885 | 246 |
0 | 247 if (av_new_packet(pkt, s->frame_size) < 0) |
482 | 248 return AVERROR_IO; |
0 | 249 for(;;) { |
56
01d48dc59dab
Fix the 'hard cpu loop' problem when capturing audio from /dev/dsp. This
philipjsg
parents:
30
diff
changeset
|
250 struct timeval tv; |
01d48dc59dab
Fix the 'hard cpu loop' problem when capturing audio from /dev/dsp. This
philipjsg
parents:
30
diff
changeset
|
251 fd_set fds; |
01d48dc59dab
Fix the 'hard cpu loop' problem when capturing audio from /dev/dsp. This
philipjsg
parents:
30
diff
changeset
|
252 |
01d48dc59dab
Fix the 'hard cpu loop' problem when capturing audio from /dev/dsp. This
philipjsg
parents:
30
diff
changeset
|
253 tv.tv_sec = 0; |
01d48dc59dab
Fix the 'hard cpu loop' problem when capturing audio from /dev/dsp. This
philipjsg
parents:
30
diff
changeset
|
254 tv.tv_usec = 30 * 1000; /* 30 msecs -- a bit shorter than 1 frame at 30fps */ |
01d48dc59dab
Fix the 'hard cpu loop' problem when capturing audio from /dev/dsp. This
philipjsg
parents:
30
diff
changeset
|
255 |
01d48dc59dab
Fix the 'hard cpu loop' problem when capturing audio from /dev/dsp. This
philipjsg
parents:
30
diff
changeset
|
256 FD_ZERO(&fds); |
01d48dc59dab
Fix the 'hard cpu loop' problem when capturing audio from /dev/dsp. This
philipjsg
parents:
30
diff
changeset
|
257 FD_SET(s->fd, &fds); |
01d48dc59dab
Fix the 'hard cpu loop' problem when capturing audio from /dev/dsp. This
philipjsg
parents:
30
diff
changeset
|
258 |
01d48dc59dab
Fix the 'hard cpu loop' problem when capturing audio from /dev/dsp. This
philipjsg
parents:
30
diff
changeset
|
259 /* This will block until data is available or we get a timeout */ |
01d48dc59dab
Fix the 'hard cpu loop' problem when capturing audio from /dev/dsp. This
philipjsg
parents:
30
diff
changeset
|
260 (void) select(s->fd + 1, &fds, 0, 0, &tv); |
01d48dc59dab
Fix the 'hard cpu loop' problem when capturing audio from /dev/dsp. This
philipjsg
parents:
30
diff
changeset
|
261 |
0 | 262 ret = read(s->fd, pkt->data, pkt->size); |
263 if (ret > 0) | |
264 break; | |
265 if (ret == -1 && (errno == EAGAIN || errno == EINTR)) { | |
266 av_free_packet(pkt); | |
267 pkt->size = 0; | |
921 | 268 pkt->pts = av_gettime(); |
0 | 269 return 0; |
270 } | |
271 if (!(ret == 0 || (ret == -1 && (errno == EAGAIN || errno == EINTR)))) { | |
272 av_free_packet(pkt); | |
482 | 273 return AVERROR_IO; |
0 | 274 } |
275 } | |
276 pkt->size = ret; | |
277 | |
278 /* compute pts of the start of the packet */ | |
279 cur_time = av_gettime(); | |
280 bdelay = ret; | |
281 if (ioctl(s->fd, SNDCTL_DSP_GETISPACE, &abufi) == 0) { | |
282 bdelay += abufi.bytes; | |
283 } | |
284 /* substract time represented by the number of bytes in the audio fifo */ | |
285 cur_time -= (bdelay * 1000000LL) / (s->sample_rate * s->channels); | |
286 | |
287 /* convert to wanted units */ | |
921 | 288 pkt->pts = cur_time; |
0 | 289 |
290 if (s->flip_left && s->channels == 2) { | |
291 int i; | |
292 short *p = (short *) pkt->data; | |
293 | |
294 for (i = 0; i < ret; i += 4) { | |
295 *p = ~*p; | |
296 p += 2; | |
297 } | |
298 } | |
299 return 0; | |
300 } | |
301 | |
302 static int audio_read_close(AVFormatContext *s1) | |
303 { | |
304 AudioData *s = s1->priv_data; | |
305 | |
306 audio_close(s); | |
307 return 0; | |
308 } | |
309 | |
1169 | 310 #ifdef CONFIG_AUDIO_DEMUXER |
311 AVInputFormat audio_demuxer = { | |
0 | 312 "audio_device", |
313 "audio grab and output", | |
314 sizeof(AudioData), | |
315 NULL, | |
316 audio_read_header, | |
317 audio_read_packet, | |
318 audio_read_close, | |
319 .flags = AVFMT_NOFILE, | |
320 }; | |
1169 | 321 #endif |
0 | 322 |
1169 | 323 #ifdef CONFIG_AUDIO_MUXER |
324 AVOutputFormat audio_muxer = { | |
0 | 325 "audio_device", |
326 "audio grab and output", | |
327 "", | |
328 "", | |
329 sizeof(AudioData), | |
330 /* XXX: we make the assumption that the soundcard accepts this format */ | |
331 /* XXX: find better solution with "preinit" method, needed also in | |
332 other formats */ | |
333 #ifdef WORDS_BIGENDIAN | |
334 CODEC_ID_PCM_S16BE, | |
335 #else | |
336 CODEC_ID_PCM_S16LE, | |
337 #endif | |
338 CODEC_ID_NONE, | |
339 audio_write_header, | |
340 audio_write_packet, | |
341 audio_write_trailer, | |
342 .flags = AVFMT_NOFILE, | |
343 }; | |
1169 | 344 #endif |