Originally committed as revision 1439 to svn://svn.ffmpeg.org/ffmpeg/trunktags/v0.5
| @@ -12,9 +12,13 @@ OBJS= utils.o cutils.o allformats.o | |||
| # mux and demuxes | |||
| OBJS+=mpeg.o mpegts.o ffm.o crc.o img.o raw.o rm.o asf.o \ | |||
| avienc.o avidec.o wav.o swf.o au.o gif.o mov.o jpeg.o dv.o framehook.o | |||
| avienc.o avidec.o wav.o swf.o au.o gif.o mov.o jpeg.o dv.o \ | |||
| yuv4mpeg.o | |||
| # image formats | |||
| OBJS+= pnm.o yuv.o | |||
| # file I/O | |||
| OBJS+= avio.o aviobuf.o file.o | |||
| OBJS+= framehook.o | |||
| ifeq ($(BUILD_STRPTIME),yes) | |||
| OBJS+= strptime.o | |||
| @@ -45,6 +45,8 @@ void av_register_all(void) | |||
| mov_init(); | |||
| jpeg_init(); | |||
| dv_init(); | |||
| av_register_output_format(&yuv4mpegpipe_oformat); | |||
| #ifdef CONFIG_VORBIS | |||
| ogg_init(); | |||
| @@ -60,6 +62,14 @@ void av_register_all(void) | |||
| audio_init(); | |||
| #endif | |||
| /* image formats */ | |||
| av_register_image_format(&pnm_image_format); | |||
| av_register_image_format(&pbm_image_format); | |||
| av_register_image_format(&pgm_image_format); | |||
| av_register_image_format(&ppm_image_format); | |||
| av_register_image_format(&pgmyuv_image_format); | |||
| av_register_image_format(&yuv_image_format); | |||
| /* file protocols */ | |||
| register_protocol(&file_protocol); | |||
| register_protocol(&pipe_protocol); | |||
| @@ -0,0 +1,285 @@ | |||
| /* | |||
| * PNM image format | |||
| * Copyright (c) 2002, 2003 Fabrice Bellard. | |||
| * | |||
| * 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 "avformat.h" | |||
| static inline int pnm_space(int c) | |||
| { | |||
| return (c == ' ' || c == '\n' || c == '\r' || c == '\t'); | |||
| } | |||
| static void pnm_get(ByteIOContext *f, char *str, int buf_size) | |||
| { | |||
| char *s; | |||
| int c; | |||
| /* skip spaces and comments */ | |||
| for(;;) { | |||
| c = url_fgetc(f); | |||
| if (c == '#') { | |||
| do { | |||
| c = url_fgetc(f); | |||
| } while (c != '\n' && c != URL_EOF); | |||
| } else if (!pnm_space(c)) { | |||
| break; | |||
| } | |||
| } | |||
| s = str; | |||
| while (c != URL_EOF && !pnm_space(c)) { | |||
| if ((s - str) < buf_size - 1) | |||
| *s++ = c; | |||
| c = url_fgetc(f); | |||
| } | |||
| *s = '\0'; | |||
| } | |||
| static int pnm_read1(ByteIOContext *f, | |||
| int (*alloc_cb)(void *opaque, AVImageInfo *info), void *opaque, | |||
| int allow_yuv) | |||
| { | |||
| int i, n, linesize, h; | |||
| char buf1[32]; | |||
| unsigned char *ptr; | |||
| AVImageInfo info1, *info = &info1; | |||
| int ret; | |||
| pnm_get(f, buf1, sizeof(buf1)); | |||
| if (!strcmp(buf1, "P4")) { | |||
| info->pix_fmt = PIX_FMT_MONOWHITE; | |||
| } else if (!strcmp(buf1, "P5")) { | |||
| if (allow_yuv) | |||
| info->pix_fmt = PIX_FMT_YUV420P; | |||
| else | |||
| info->pix_fmt = PIX_FMT_GRAY8; | |||
| } else if (!strcmp(buf1, "P6")) { | |||
| info->pix_fmt = PIX_FMT_RGB24; | |||
| } else { | |||
| return AVERROR_INVALIDDATA; | |||
| } | |||
| pnm_get(f, buf1, sizeof(buf1)); | |||
| info->width = atoi(buf1); | |||
| if (info->width <= 0) | |||
| return AVERROR_INVALIDDATA; | |||
| pnm_get(f, buf1, sizeof(buf1)); | |||
| info->height = atoi(buf1); | |||
| if (info->height <= 0) | |||
| return AVERROR_INVALIDDATA; | |||
| if (info->pix_fmt != PIX_FMT_MONOWHITE) { | |||
| pnm_get(f, buf1, sizeof(buf1)); | |||
| } | |||
| /* more check if YUV420 */ | |||
| if (info->pix_fmt == PIX_FMT_YUV420P) { | |||
| if ((info->width & 1) != 0) | |||
| return AVERROR_INVALIDDATA; | |||
| h = (info->height * 2); | |||
| if ((h % 3) != 0) | |||
| return AVERROR_INVALIDDATA; | |||
| h /= 3; | |||
| info->height = h; | |||
| } | |||
| ret = alloc_cb(opaque, info); | |||
| if (ret) | |||
| return ret; | |||
| switch(info->pix_fmt) { | |||
| default: | |||
| return AVERROR_INVALIDDATA; | |||
| case PIX_FMT_RGB24: | |||
| n = info->width * 3; | |||
| goto do_read; | |||
| case PIX_FMT_GRAY8: | |||
| n = info->width; | |||
| goto do_read; | |||
| case PIX_FMT_MONOWHITE: | |||
| n = (info->width + 7) >> 3; | |||
| do_read: | |||
| ptr = info->pict.data[0]; | |||
| linesize = info->pict.linesize[0]; | |||
| for(i = 0; i < info->height; i++) { | |||
| get_buffer(f, ptr, n); | |||
| ptr += linesize; | |||
| } | |||
| break; | |||
| case PIX_FMT_YUV420P: | |||
| { | |||
| unsigned char *ptr1, *ptr2; | |||
| n = info->width; | |||
| ptr = info->pict.data[0]; | |||
| linesize = info->pict.linesize[0]; | |||
| for(i = 0; i < info->height; i++) { | |||
| get_buffer(f, ptr, n); | |||
| ptr += linesize; | |||
| } | |||
| ptr1 = info->pict.data[1]; | |||
| ptr2 = info->pict.data[2]; | |||
| n >>= 1; | |||
| h = info->height >> 1; | |||
| for(i = 0; i < h; i++) { | |||
| get_buffer(f, ptr1, n); | |||
| get_buffer(f, ptr2, n); | |||
| ptr1 += info->pict.linesize[1]; | |||
| ptr2 += info->pict.linesize[2]; | |||
| } | |||
| } | |||
| break; | |||
| } | |||
| return 0; | |||
| } | |||
| static int pnm_read(ByteIOContext *f, | |||
| int (*alloc_cb)(void *opaque, AVImageInfo *info), void *opaque) | |||
| { | |||
| return pnm_read1(f, alloc_cb, opaque, 0); | |||
| } | |||
| static int pgmyuv_read(ByteIOContext *f, | |||
| int (*alloc_cb)(void *opaque, AVImageInfo *info), void *opaque) | |||
| { | |||
| return pnm_read1(f, alloc_cb, opaque, 1); | |||
| } | |||
| static int pnm_write(ByteIOContext *pb, AVImageInfo *info) | |||
| { | |||
| int i, h, h1, c, n, linesize; | |||
| char buf[100]; | |||
| UINT8 *ptr, *ptr1, *ptr2; | |||
| h = info->height; | |||
| h1 = h; | |||
| switch(info->pix_fmt) { | |||
| case PIX_FMT_MONOWHITE: | |||
| c = '4'; | |||
| n = (info->width + 7) >> 3; | |||
| break; | |||
| case PIX_FMT_GRAY8: | |||
| c = '5'; | |||
| n = info->width; | |||
| break; | |||
| case PIX_FMT_RGB24: | |||
| c = '6'; | |||
| n = info->width * 3; | |||
| break; | |||
| case PIX_FMT_YUV420P: | |||
| c = '5'; | |||
| n = info->width; | |||
| h1 = (h * 3) / 2; | |||
| break; | |||
| default: | |||
| return AVERROR_INVALIDDATA; | |||
| } | |||
| snprintf(buf, sizeof(buf), | |||
| "P%c\n%d %d\n", | |||
| c, info->width, h1); | |||
| put_buffer(pb, buf, strlen(buf)); | |||
| if (info->pix_fmt != PIX_FMT_MONOWHITE) { | |||
| snprintf(buf, sizeof(buf), | |||
| "%d\n", 255); | |||
| put_buffer(pb, buf, strlen(buf)); | |||
| } | |||
| ptr = info->pict.data[0]; | |||
| linesize = info->pict.linesize[0]; | |||
| for(i=0;i<h;i++) { | |||
| put_buffer(pb, ptr, n); | |||
| ptr += linesize; | |||
| } | |||
| if (info->pix_fmt == PIX_FMT_YUV420P) { | |||
| h >>= 1; | |||
| n >>= 1; | |||
| ptr1 = info->pict.data[1]; | |||
| ptr2 = info->pict.data[2]; | |||
| for(i=0;i<h;i++) { | |||
| put_buffer(pb, ptr1, n); | |||
| put_buffer(pb, ptr2, n); | |||
| ptr1 += info->pict.linesize[1]; | |||
| ptr2 += info->pict.linesize[2]; | |||
| } | |||
| } | |||
| put_flush_packet(pb); | |||
| return 0; | |||
| } | |||
| static int pnm_probe(AVProbeData *pd) | |||
| { | |||
| const char *p = pd->buf; | |||
| if (pd->buf_size >= 8 && | |||
| p[0] == 'P' && | |||
| p[1] >= '4' && p[1] <= '6' && | |||
| p[2] == '\n') | |||
| return AVPROBE_SCORE_MAX; | |||
| else | |||
| return 0; | |||
| } | |||
| static int pgmyuv_probe(AVProbeData *pd) | |||
| { | |||
| if (match_ext(pd->filename, "pgmyuv")) | |||
| return AVPROBE_SCORE_MAX; | |||
| else | |||
| return 0; | |||
| } | |||
| AVImageFormat pnm_image_format = { | |||
| "pnm", | |||
| NULL, | |||
| pnm_probe, | |||
| pnm_read, | |||
| 0, | |||
| NULL, | |||
| }; | |||
| AVImageFormat pbm_image_format = { | |||
| "pbm", | |||
| "pbm", | |||
| NULL, | |||
| NULL, | |||
| (1 << PIX_FMT_MONOWHITE), | |||
| pnm_write, | |||
| }; | |||
| AVImageFormat pgm_image_format = { | |||
| "pgm", | |||
| "pgm", | |||
| NULL, | |||
| NULL, | |||
| (1 << PIX_FMT_GRAY8), | |||
| pnm_write, | |||
| }; | |||
| AVImageFormat ppm_image_format = { | |||
| "ppm", | |||
| "ppm", | |||
| NULL, | |||
| NULL, | |||
| (1 << PIX_FMT_RGB24), | |||
| pnm_write, | |||
| }; | |||
| AVImageFormat pgmyuv_image_format = { | |||
| "pgmyuv", | |||
| NULL, | |||
| pgmyuv_probe, | |||
| pgmyuv_read, | |||
| (1 << PIX_FMT_YUV420P), | |||
| pnm_write, | |||
| }; | |||
| @@ -35,6 +35,7 @@ | |||
| AVInputFormat *first_iformat; | |||
| AVOutputFormat *first_oformat; | |||
| AVImageFormat *first_image_format; | |||
| void av_register_input_format(AVInputFormat *format) | |||
| { | |||
| @@ -84,6 +85,11 @@ AVOutputFormat *guess_format(const char *short_name, const char *filename, | |||
| AVOutputFormat *fmt, *fmt_found; | |||
| int score_max, score; | |||
| /* specific test for image sequences */ | |||
| if (!short_name && filename && filename_number_test(filename) >= 0) { | |||
| return guess_format("image", NULL, NULL); | |||
| } | |||
| /* find the proper file type */ | |||
| fmt_found = NULL; | |||
| score_max = 0; | |||
| @@ -326,8 +332,8 @@ int av_open_input_file(AVFormatContext **ic_ptr, const char *filename, | |||
| fmt = av_probe_input_format(pd, 0); | |||
| } | |||
| /* if no file needed do not try to open one */ | |||
| if (!fmt || !(fmt->flags & AVFMT_NOFILE)) { | |||
| /* if no file needed do not try to open one */ | |||
| if (url_fopen(&ic->pb, filename, URL_RDONLY) < 0) { | |||
| err = AVERROR_IO; | |||
| goto fail; | |||
| @@ -365,6 +371,14 @@ int av_open_input_file(AVFormatContext **ic_ptr, const char *filename, | |||
| ic->iformat = fmt; | |||
| /* check filename in case of an image number is expected */ | |||
| if (ic->iformat->flags & AVFMT_NEEDNUMBER) { | |||
| if (filename_number_test(ic->filename) < 0) { | |||
| err = AVERROR_NUMEXPECTED; | |||
| goto fail1; | |||
| } | |||
| } | |||
| /* allocate private data */ | |||
| ic->priv_data = av_mallocz(fmt->priv_data_size); | |||
| if (!ic->priv_data) { | |||
| @@ -375,14 +389,6 @@ int av_open_input_file(AVFormatContext **ic_ptr, const char *filename, | |||
| /* default pts settings is MPEG like */ | |||
| av_set_pts_info(ic, 33, 1, 90000); | |||
| /* check filename in case of an image number is expected */ | |||
| if (ic->iformat->flags & AVFMT_NEEDNUMBER) { | |||
| if (filename_number_test(ic->filename) < 0) { | |||
| err = AVERROR_NUMEXPECTED; | |||
| goto fail1; | |||
| } | |||
| } | |||
| err = ic->iformat->read_header(ic, ap); | |||
| if (err < 0) | |||
| goto fail1; | |||
| @@ -707,6 +713,21 @@ AVStream *av_new_stream(AVFormatContext *s, int id) | |||
| /************************************************************/ | |||
| /* output media file */ | |||
| int av_set_parameters(AVFormatContext *s, AVFormatParameters *ap) | |||
| { | |||
| int ret; | |||
| s->priv_data = av_mallocz(s->oformat->priv_data_size); | |||
| if (!s->priv_data) | |||
| return AVERROR_NOMEM; | |||
| if (s->oformat->set_parameters) { | |||
| ret = s->oformat->set_parameters(s, ap); | |||
| if (ret < 0) | |||
| return ret; | |||
| } | |||
| return 0; | |||
| } | |||
| /** | |||
| * allocate the stream private data and write the stream header to an | |||
| * output media file | |||
| @@ -719,9 +740,6 @@ int av_write_header(AVFormatContext *s) | |||
| int ret, i; | |||
| AVStream *st; | |||
| s->priv_data = av_mallocz(s->oformat->priv_data_size); | |||
| if (!s->priv_data) | |||
| return AVERROR_NOMEM; | |||
| /* default pts settings is MPEG like */ | |||
| av_set_pts_info(s, 33, 1, 90000); | |||
| ret = s->oformat->write_header(s); | |||
| @@ -1291,3 +1309,88 @@ void av_frac_add(AVFrac *f, INT64 incr) | |||
| } | |||
| f->num = num; | |||
| } | |||
| /** | |||
| * register a new image format | |||
| * @param img_fmt Image format descriptor | |||
| */ | |||
| void av_register_image_format(AVImageFormat *img_fmt) | |||
| { | |||
| AVImageFormat **p; | |||
| p = &first_image_format; | |||
| while (*p != NULL) p = &(*p)->next; | |||
| *p = img_fmt; | |||
| img_fmt->next = NULL; | |||
| } | |||
| /* guess image format */ | |||
| AVImageFormat *av_probe_image_format(AVProbeData *pd) | |||
| { | |||
| AVImageFormat *fmt1, *fmt; | |||
| int score, score_max; | |||
| fmt = NULL; | |||
| score_max = 0; | |||
| for(fmt1 = first_image_format; fmt1 != NULL; fmt1 = fmt1->next) { | |||
| if (fmt1->img_probe) { | |||
| score = fmt1->img_probe(pd); | |||
| if (score > score_max) { | |||
| score_max = score; | |||
| fmt = fmt1; | |||
| } | |||
| } | |||
| } | |||
| return fmt; | |||
| } | |||
| AVImageFormat *guess_image_format(const char *filename) | |||
| { | |||
| AVImageFormat *fmt1; | |||
| for(fmt1 = first_image_format; fmt1 != NULL; fmt1 = fmt1->next) { | |||
| if (fmt1->extensions && match_ext(filename, fmt1->extensions)) | |||
| return fmt1; | |||
| } | |||
| return NULL; | |||
| } | |||
| /** | |||
| * Read an image from a stream. | |||
| * @param gb byte stream containing the image | |||
| * @param fmt image format, NULL if probing is required | |||
| */ | |||
| int av_read_image(ByteIOContext *pb, const char *filename, | |||
| AVImageFormat *fmt, | |||
| int (*alloc_cb)(void *, AVImageInfo *info), void *opaque) | |||
| { | |||
| char buf[PROBE_BUF_SIZE]; | |||
| AVProbeData probe_data, *pd = &probe_data; | |||
| offset_t pos; | |||
| int ret; | |||
| if (!fmt) { | |||
| pd->filename = (char *)filename; | |||
| pd->buf = buf; | |||
| pos = url_ftell(pb); | |||
| pd->buf_size = get_buffer(pb, buf, PROBE_BUF_SIZE); | |||
| url_fseek(pb, pos, SEEK_SET); | |||
| fmt = av_probe_image_format(pd); | |||
| } | |||
| if (!fmt) | |||
| return AVERROR_NOFMT; | |||
| ret = fmt->img_read(pb, alloc_cb, opaque); | |||
| return ret; | |||
| } | |||
| /** | |||
| * Write an image to a stream. | |||
| * @param pb byte stream for the image output | |||
| * @param fmt image format | |||
| * @param img image data and informations | |||
| */ | |||
| int av_write_image(ByteIOContext *pb, AVImageFormat *fmt, AVImageInfo *img) | |||
| { | |||
| return fmt->img_write(pb, img); | |||
| } | |||
| @@ -0,0 +1,158 @@ | |||
| /* | |||
| * .Y.U.V image format | |||
| * Copyright (c) 2003 Fabrice Bellard. | |||
| * | |||
| * 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 "avformat.h" | |||
| static int sizes[][2] = { | |||
| { 640, 480 }, | |||
| { 720, 480 }, | |||
| { 720, 576 }, | |||
| { 352, 288 }, | |||
| { 352, 240 }, | |||
| { 160, 128 }, | |||
| { 512, 384 }, | |||
| { 640, 352 }, | |||
| { 640, 240 }, | |||
| }; | |||
| static int infer_size(int *width_ptr, int *height_ptr, int size) | |||
| { | |||
| int i; | |||
| for(i=0;i<sizeof(sizes)/sizeof(sizes[0]);i++) { | |||
| if ((sizes[i][0] * sizes[i][1]) == size) { | |||
| *width_ptr = sizes[i][0]; | |||
| *height_ptr = sizes[i][1]; | |||
| return 0; | |||
| } | |||
| } | |||
| return -1; | |||
| } | |||
| static int yuv_read(ByteIOContext *f, | |||
| int (*alloc_cb)(void *opaque, AVImageInfo *info), void *opaque) | |||
| { | |||
| ByteIOContext pb1, *pb = &pb1; | |||
| int img_size, ret; | |||
| char fname[1024], *p; | |||
| int size; | |||
| URLContext *h; | |||
| AVImageInfo info1, *info = &info1; | |||
| /* XXX: hack hack */ | |||
| h = url_fileno(f); | |||
| img_size = url_seek(h, 0, SEEK_END); | |||
| url_get_filename(h, fname, sizeof(fname)); | |||
| if (infer_size(&info->width, &info->height, img_size) < 0) { | |||
| return -EIO; | |||
| } | |||
| info->pix_fmt = PIX_FMT_YUV420P; | |||
| ret = alloc_cb(opaque, info); | |||
| if (ret) | |||
| return ret; | |||
| size = info->width * info->height; | |||
| p = strrchr(fname, '.'); | |||
| if (!p || p[1] != 'Y') | |||
| return -EIO; | |||
| get_buffer(f, info->pict.data[0], size); | |||
| p[1] = 'U'; | |||
| if (url_fopen(pb, fname, URL_RDONLY) < 0) | |||
| return -EIO; | |||
| get_buffer(pb, info->pict.data[1], size / 4); | |||
| url_fclose(pb); | |||
| p[1] = 'V'; | |||
| if (url_fopen(pb, fname, URL_RDONLY) < 0) | |||
| return -EIO; | |||
| get_buffer(pb, info->pict.data[2], size / 4); | |||
| url_fclose(pb); | |||
| return 0; | |||
| } | |||
| static int yuv_write(ByteIOContext *pb2, AVImageInfo *info) | |||
| { | |||
| ByteIOContext pb1, *pb; | |||
| char fname[1024], *p; | |||
| int i, j, width, height; | |||
| UINT8 *ptr; | |||
| URLContext *h; | |||
| static const char *ext = "YUV"; | |||
| /* XXX: hack hack */ | |||
| h = url_fileno(pb2); | |||
| url_get_filename(h, fname, sizeof(fname)); | |||
| p = strrchr(fname, '.'); | |||
| if (!p || p[1] != 'Y') | |||
| return -EIO; | |||
| width = info->width; | |||
| height = info->height; | |||
| for(i=0;i<3;i++) { | |||
| if (i == 1) { | |||
| width >>= 1; | |||
| height >>= 1; | |||
| } | |||
| if (i >= 1) { | |||
| pb = &pb1; | |||
| p[1] = ext[i]; | |||
| if (url_fopen(pb, fname, URL_WRONLY) < 0) | |||
| return -EIO; | |||
| } else { | |||
| pb = pb2; | |||
| } | |||
| ptr = info->pict.data[i]; | |||
| for(j=0;j<height;j++) { | |||
| put_buffer(pb, ptr, width); | |||
| ptr += info->pict.linesize[i]; | |||
| } | |||
| put_flush_packet(pb); | |||
| if (i >= 1) { | |||
| url_fclose(pb); | |||
| } | |||
| } | |||
| return 0; | |||
| } | |||
| static int yuv_probe(AVProbeData *pd) | |||
| { | |||
| if (match_ext(pd->filename, "Y")) | |||
| return AVPROBE_SCORE_MAX; | |||
| else | |||
| return 0; | |||
| } | |||
| AVImageFormat yuv_image_format = { | |||
| "yuv", | |||
| "Y", | |||
| yuv_probe, | |||
| yuv_read, | |||
| (1 << PIX_FMT_YUV420P), | |||
| yuv_write, | |||
| }; | |||