added PPM read/write support - added pgmyuvpipe format - added PPM pipe read/write...
[libav.git] / libav / utils.c
1 /*
2 * Various utilities for ffmpeg system
3 * Copyright (c) 2000,2001 Gerard Lantau
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program 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
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <unistd.h>
23 #include <fcntl.h>
24 #include <errno.h>
25 #include <sys/time.h>
26 #include <time.h>
27
28 #include "avformat.h"
29
30 AVFormat *first_format;
31
32 void register_avformat(AVFormat *format)
33 {
34 AVFormat **p;
35 p = &first_format;
36 while (*p != NULL) p = &(*p)->next;
37 *p = format;
38 format->next = NULL;
39 }
40
41 int match_ext(const char *filename, const char *extensions)
42 {
43 const char *ext, *p;
44 char ext1[32], *q;
45
46 ext = strrchr(filename, '.');
47 if (ext) {
48 ext++;
49 p = extensions;
50 for(;;) {
51 q = ext1;
52 while (*p != '\0' && *p != ',')
53 *q++ = *p++;
54 *q = '\0';
55 if (!strcasecmp(ext1, ext))
56 return 1;
57 if (*p == '\0')
58 break;
59 p++;
60 }
61 }
62 return 0;
63 }
64
65 AVFormat *guess_format(const char *short_name, const char *filename, const char *mime_type)
66 {
67 AVFormat *fmt, *fmt_found;
68 int score_max, score;
69
70 /* find the proper file type */
71 fmt_found = NULL;
72 score_max = 0;
73 fmt = first_format;
74 while (fmt != NULL) {
75 score = 0;
76 if (fmt->name && short_name && !strcmp(fmt->name, short_name))
77 score += 100;
78 if (fmt->mime_type && mime_type && !strcmp(fmt->mime_type, mime_type))
79 score += 10;
80 if (filename && fmt->extensions &&
81 match_ext(filename, fmt->extensions)) {
82 score += 5;
83 }
84 if (score > score_max) {
85 score_max = score;
86 fmt_found = fmt;
87 }
88 fmt = fmt->next;
89 }
90 return fmt_found;
91 }
92
93 /* return TRUE if val is a prefix of str. If it returns TRUE, ptr is
94 set to the next character in 'str' after the prefix */
95 int strstart(const char *str, const char *val, const char **ptr)
96 {
97 const char *p, *q;
98 p = str;
99 q = val;
100 while (*q != '\0') {
101 if (*p != *q)
102 return 0;
103 p++;
104 q++;
105 }
106 if (ptr)
107 *ptr = p;
108 return 1;
109 }
110
111 void nstrcpy(char *buf, int buf_size, const char *str)
112 {
113 int c;
114 char *q = buf;
115
116 for(;;) {
117 c = *str++;
118 if (c == 0 || q >= buf + buf_size - 1)
119 break;
120 *q++ = c;
121 }
122 *q = '\0';
123 }
124
125 void register_all(void)
126 {
127 avcodec_init();
128 avcodec_register_all();
129
130 register_avformat(&mp2_format);
131 register_avformat(&ac3_format);
132 register_avformat(&mpeg_mux_format);
133 register_avformat(&mpeg1video_format);
134 register_avformat(&h263_format);
135 register_avformat(&rm_format);
136 register_avformat(&asf_format);
137 register_avformat(&avi_format);
138 register_avformat(&mpjpeg_format);
139 register_avformat(&jpeg_format);
140 register_avformat(&swf_format);
141 register_avformat(&wav_format);
142 register_avformat(&pcm_format);
143 register_avformat(&rawvideo_format);
144 register_avformat(&ffm_format);
145 register_avformat(&pgm_format);
146 register_avformat(&ppm_format);
147 register_avformat(&pgmyuv_format);
148 register_avformat(&imgyuv_format);
149 register_avformat(&pgmpipe_format);
150 register_avformat(&pgmyuvpipe_format);
151 register_avformat(&ppmpipe_format);
152
153 register_protocol(&file_protocol);
154 register_protocol(&pipe_protocol);
155 register_protocol(&audio_protocol);
156 register_protocol(&video_protocol);
157 register_protocol(&udp_protocol);
158 register_protocol(&http_protocol);
159 }
160
161 /* memory handling */
162
163 int av_new_packet(AVPacket *pkt, int size)
164 {
165 pkt->data = malloc(size);
166 if (!pkt->data)
167 return -ENOMEM;
168 pkt->size = size;
169 /* sane state */
170 pkt->pts = 0;
171 pkt->stream_index = 0;
172 pkt->flags = 0;
173 return 0;
174 }
175
176 void av_free_packet(AVPacket *pkt)
177 {
178 free(pkt->data);
179 /* fail safe */
180 pkt->data = NULL;
181 pkt->size = 0;
182 }
183
184 /* fifo handling */
185
186 int fifo_init(FifoBuffer *f, int size)
187 {
188 f->buffer = malloc(size);
189 if (!f->buffer)
190 return -1;
191 f->end = f->buffer + size;
192 f->wptr = f->rptr = f->buffer;
193 return 0;
194 }
195
196 void fifo_free(FifoBuffer *f)
197 {
198 free(f->buffer);
199 }
200
201 int fifo_size(FifoBuffer *f, UINT8 *rptr)
202 {
203 int size;
204
205 if (f->wptr >= rptr) {
206 size = f->wptr - rptr;
207 } else {
208 size = (f->end - rptr) + (f->wptr - f->buffer);
209 }
210 return size;
211 }
212
213 /* get data from the fifo (return -1 if not enough data) */
214 int fifo_read(FifoBuffer *f, UINT8 *buf, int buf_size, UINT8 **rptr_ptr)
215 {
216 UINT8 *rptr = *rptr_ptr;
217 int size, len;
218
219 if (f->wptr >= rptr) {
220 size = f->wptr - rptr;
221 } else {
222 size = (f->end - rptr) + (f->wptr - f->buffer);
223 }
224
225 if (size < buf_size)
226 return -1;
227 while (buf_size > 0) {
228 len = f->end - rptr;
229 if (len > buf_size)
230 len = buf_size;
231 memcpy(buf, rptr, len);
232 buf += len;
233 rptr += len;
234 if (rptr >= f->end)
235 rptr = f->buffer;
236 buf_size -= len;
237 }
238 *rptr_ptr = rptr;
239 return 0;
240 }
241
242 void fifo_write(FifoBuffer *f, UINT8 *buf, int size, UINT8 **wptr_ptr)
243 {
244 int len;
245 UINT8 *wptr;
246 wptr = *wptr_ptr;
247 while (size > 0) {
248 len = f->end - wptr;
249 if (len > size)
250 len = size;
251 memcpy(wptr, buf, len);
252 wptr += len;
253 if (wptr >= f->end)
254 wptr = f->buffer;
255 buf += len;
256 size -= len;
257 }
258 *wptr_ptr = wptr;
259 }
260
261 /* media file handling */
262
263 AVFormatContext *av_open_input_file(const char *filename, int buf_size)
264 {
265 AVFormatParameters params, *ap;
266 AVFormat *fmt;
267 AVFormatContext *ic = NULL;
268 URLFormat url_format;
269 int err;
270
271 ic = av_mallocz(sizeof(AVFormatContext));
272 if (!ic)
273 goto fail;
274 if (url_fopen(&ic->pb, filename, URL_RDONLY) < 0)
275 goto fail;
276
277 if (buf_size > 0) {
278 url_setbufsize(&ic->pb, buf_size);
279 }
280
281 /* find format */
282 err = url_getformat(url_fileno(&ic->pb), &url_format);
283 if (err >= 0) {
284 fmt = guess_format(url_format.format_name, NULL, NULL);
285 ap = &params;
286 ap->sample_rate = url_format.sample_rate;
287 ap->frame_rate = url_format.frame_rate;
288 ap->channels = url_format.channels;
289 ap->width = url_format.width;
290 ap->height = url_format.height;
291 ap->pix_fmt = url_format.pix_fmt;
292 } else {
293 fmt = guess_format(NULL, filename, NULL);
294 ap = NULL;
295 }
296 if (!fmt || !fmt->read_header) {
297 return NULL;
298 }
299 ic->format = fmt;
300
301 err = ic->format->read_header(ic, ap);
302 if (err < 0) {
303 url_fclose(&ic->pb);
304 goto fail;
305 }
306
307 return ic;
308
309 fail:
310 if (ic)
311 free(ic);
312 return NULL;
313 }
314
315 int av_read_packet(AVFormatContext *s, AVPacket *pkt)
316 {
317 AVPacketList *pktl;
318
319 pktl = s->packet_buffer;
320 if (pktl) {
321 /* read packet from packet buffer, if there is data */
322 *pkt = pktl->pkt;
323 s->packet_buffer = pktl->next;
324 free(pktl);
325 return 0;
326 } else {
327 return s->format->read_packet(s, pkt);
328 }
329 }
330
331 void av_close_input_file(AVFormatContext *s)
332 {
333 int i;
334
335 if (s->format->read_close)
336 s->format->read_close(s);
337 for(i=0;i<s->nb_streams;i++) {
338 free(s->streams[i]);
339 }
340 if (s->packet_buffer) {
341 AVPacketList *p, *p1;
342 p = s->packet_buffer;
343 while (p != NULL) {
344 p1 = p->next;
345 av_free_packet(&p->pkt);
346 free(p);
347 p = p1;
348 }
349 s->packet_buffer = NULL;
350 }
351 url_fclose(&s->pb);
352 free(s);
353 }
354
355
356 int av_write_packet(AVFormatContext *s, AVPacket *pkt)
357 {
358 /* XXX: currently, an emulation because internal API must change */
359 return s->format->write_packet(s, pkt->stream_index, pkt->data, pkt->size);
360 }
361
362 /* "user interface" functions */
363
364 void dump_format(AVFormatContext *ic,
365 int index,
366 const char *url,
367 int is_output)
368 {
369 int i;
370 char buf[256];
371
372 fprintf(stderr, "%s #%d, %s, %s '%s':\n",
373 is_output ? "Output" : "Input",
374 index, ic->format->name,
375 is_output ? "to" : "from", url);
376 for(i=0;i<ic->nb_streams;i++) {
377 AVStream *st = ic->streams[i];
378 avcodec_string(buf, sizeof(buf), &st->codec, is_output);
379 fprintf(stderr, " Stream #%d.%d: %s\n", index, i, buf);
380 }
381 }
382
383 typedef struct {
384 const char *str;
385 int width, height;
386 } SizeEntry;
387
388 static SizeEntry sizes[] = {
389 { "sqcif", 128, 96 },
390 { "qcif", 176, 144 },
391 { "cif", 352, 288 },
392 { "4cif", 704, 576 },
393 };
394
395 int parse_image_size(int *width_ptr, int *height_ptr, const char *str)
396 {
397 int i;
398 int n = sizeof(sizes) / sizeof(SizeEntry);
399 const char *p;
400 int frame_width = 0, frame_height = 0;
401
402 for(i=0;i<n;i++) {
403 if (!strcmp(sizes[i].str, str)) {
404 frame_width = sizes[i].width;
405 frame_height = sizes[i].height;
406 break;
407 }
408 }
409 if (i == n) {
410 p = str;
411 frame_width = strtol(p, (char **)&p, 10);
412 if (*p)
413 p++;
414 frame_height = strtol(p, (char **)&p, 10);
415 }
416 if (frame_width <= 0 || frame_height <= 0)
417 return -1;
418 *width_ptr = frame_width;
419 *height_ptr = frame_height;
420 return 0;
421 }
422
423 INT64 gettime(void)
424 {
425 struct timeval tv;
426 gettimeofday(&tv,NULL);
427 return (INT64)tv.tv_sec * 1000000 + tv.tv_usec;
428 }
429
430 /* syntax: [YYYY-MM-DD ][[HH:]MM:]SS[.m...] . Return the date in micro seconds since 1970 */
431 INT64 parse_date(const char *datestr, int duration)
432 {
433 const char *p;
434 INT64 t;
435 int sec;
436
437 p = datestr;
438 if (!duration) {
439 static const UINT8 months[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
440 int year, month, day, i;
441
442 if (strlen(p) >= 5 && p[4] == '-') {
443
444 year = strtol(p, (char **)&p, 10);
445 if (*p)
446 p++;
447 month = strtol(p, (char **)&p, 10) - 1;
448 if (*p)
449 p++;
450 day = strtol(p, (char **)&p, 10) - 1;
451 if (*p)
452 p++;
453 day += (year - 1970) * 365;
454 /* if >= March, take February of current year into account too */
455 if (month >= 2)
456 year++;
457 for(i=1970;i<year;i++) {
458 if ((i % 100) == 0) {
459 if ((i % 400) == 0) day++;
460 } else if ((i % 4) == 0) {
461 day++;
462 }
463 }
464 for(i=0;i<month;i++)
465 day += months[i];
466 } else {
467 day = (time(NULL) / (3600 * 24));
468 }
469 t = day * (3600 * 24);
470 } else {
471 t = 0;
472 }
473
474 sec = 0;
475 for(;;) {
476 int val;
477 val = strtol(p, (char **)&p, 10);
478 sec = sec * 60 + val;
479 if (*p != ':')
480 break;
481 p++;
482 }
483 t = (t + sec) * 1000000;
484 if (*p == '.') {
485 int val, n;
486 p++;
487 n = strlen(p);
488 if (n > 6)
489 n = 6;
490 val = strtol(p, NULL, 10);
491 while (n < 6) {
492 val = val * 10;
493 n++;
494 }
495 t += val;
496 }
497 return t;
498 }
499
500 /* syntax: '?tag1=val1&tag2=val2...'. No URL decoding is done. Return
501 1 if found */
502 int find_info_tag(char *arg, int arg_size, const char *tag1, const char *info)
503 {
504 const char *p;
505 char tag[128], *q;
506
507 p = info;
508 if (*p == '?')
509 p++;
510 for(;;) {
511 q = tag;
512 while (*p != '\0' && *p != '=' && *p != '&') {
513 if ((q - tag) < sizeof(tag) - 1)
514 *q++ = *p;
515 p++;
516 }
517 *q = '\0';
518 q = arg;
519 if (*p == '=') {
520 p++;
521 while (*p != '&' && *p != '\0') {
522 if ((q - arg) < arg_size - 1)
523 *q++ = *p;
524 p++;
525 }
526 *q = '\0';
527 }
528 if (!strcmp(tag, tag1))
529 return 1;
530 if (*p != '&')
531 break;
532 }
533 return 0;
534 }
535