Originally committed as revision 7894 to svn://svn.ffmpeg.org/ffmpeg/trunktags/v0.5
| @@ -1,400 +0,0 @@ | |||
| /* | |||
| * Image format | |||
| * Copyright (c) 2000, 2001, 2002 Fabrice Bellard. | |||
| * | |||
| * This file is part of FFmpeg. | |||
| * | |||
| * FFmpeg 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.1 of the License, or (at your option) any later version. | |||
| * | |||
| * FFmpeg 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 FFmpeg; if not, write to the Free Software | |||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
| */ | |||
| #include "avformat.h" | |||
| typedef struct { | |||
| int width; | |||
| int height; | |||
| int img_first; | |||
| int img_last; | |||
| int img_number; | |||
| int img_count; | |||
| int img_size; | |||
| AVImageFormat *img_fmt; | |||
| int pix_fmt; | |||
| int is_pipe; | |||
| char path[1024]; | |||
| /* temporary usage */ | |||
| void *ptr; | |||
| } VideoData; | |||
| /* return -1 if no image found */ | |||
| static int find_image_range(int *pfirst_index, int *plast_index, | |||
| const char *path) | |||
| { | |||
| char buf[1024]; | |||
| int range, last_index, range1, first_index; | |||
| /* find the first image */ | |||
| for(first_index = 0; first_index < 5; first_index++) { | |||
| if (av_get_frame_filename(buf, sizeof(buf), path, first_index) < 0) | |||
| goto fail; | |||
| if (url_exist(buf)) | |||
| break; | |||
| } | |||
| if (first_index == 5) | |||
| goto fail; | |||
| /* find the last image */ | |||
| last_index = first_index; | |||
| for(;;) { | |||
| range = 0; | |||
| for(;;) { | |||
| if (!range) | |||
| range1 = 1; | |||
| else | |||
| range1 = 2 * range; | |||
| if (av_get_frame_filename(buf, sizeof(buf), path, | |||
| last_index + range1) < 0) | |||
| goto fail; | |||
| if (!url_exist(buf)) | |||
| break; | |||
| range = range1; | |||
| /* just in case... */ | |||
| if (range >= (1 << 30)) | |||
| goto fail; | |||
| } | |||
| /* we are sure than image last_index + range exists */ | |||
| if (!range) | |||
| break; | |||
| last_index += range; | |||
| } | |||
| *pfirst_index = first_index; | |||
| *plast_index = last_index; | |||
| return 0; | |||
| fail: | |||
| return -1; | |||
| } | |||
| static int image_probe(AVProbeData *p) | |||
| { | |||
| if (av_filename_number_test(p->filename) && guess_image_format(p->filename)) | |||
| return AVPROBE_SCORE_MAX-1; | |||
| else | |||
| return 0; | |||
| } | |||
| static int read_header_alloc_cb(void *opaque, AVImageInfo *info) | |||
| { | |||
| VideoData *s = opaque; | |||
| s->width = info->width; | |||
| s->height = info->height; | |||
| s->pix_fmt = info->pix_fmt; | |||
| /* stop image reading but no error */ | |||
| return 1; | |||
| } | |||
| static int img_read_header(AVFormatContext *s1, AVFormatParameters *ap) | |||
| { | |||
| VideoData *s = s1->priv_data; | |||
| int ret, first_index, last_index; | |||
| char buf[1024]; | |||
| ByteIOContext pb1, *f = &pb1; | |||
| AVStream *st; | |||
| st = av_new_stream(s1, 0); | |||
| if (!st) { | |||
| return -ENOMEM; | |||
| } | |||
| if (ap->image_format) | |||
| s->img_fmt = ap->image_format; | |||
| pstrcpy(s->path, sizeof(s->path), s1->filename); | |||
| s->img_number = 0; | |||
| s->img_count = 0; | |||
| /* find format */ | |||
| if (s1->iformat->flags & AVFMT_NOFILE) | |||
| s->is_pipe = 0; | |||
| else | |||
| s->is_pipe = 1; | |||
| if (!ap->time_base.num) { | |||
| st->codec->time_base= (AVRational){1,25}; | |||
| } else { | |||
| st->codec->time_base= ap->time_base; | |||
| } | |||
| if (!s->is_pipe) { | |||
| if (find_image_range(&first_index, &last_index, s->path) < 0) | |||
| goto fail; | |||
| s->img_first = first_index; | |||
| s->img_last = last_index; | |||
| s->img_number = first_index; | |||
| /* compute duration */ | |||
| st->start_time = 0; | |||
| st->duration = last_index - first_index + 1; | |||
| if (av_get_frame_filename(buf, sizeof(buf), s->path, s->img_number) < 0) | |||
| goto fail; | |||
| if (url_fopen(f, buf, URL_RDONLY) < 0) | |||
| goto fail; | |||
| } else { | |||
| f = &s1->pb; | |||
| } | |||
| ret = av_read_image(f, s1->filename, s->img_fmt, read_header_alloc_cb, s); | |||
| if (ret < 0) | |||
| goto fail1; | |||
| if (!s->is_pipe) { | |||
| url_fclose(f); | |||
| } else { | |||
| url_fseek(f, 0, SEEK_SET); | |||
| } | |||
| st->codec->codec_type = CODEC_TYPE_VIDEO; | |||
| st->codec->codec_id = CODEC_ID_RAWVIDEO; | |||
| st->codec->width = s->width; | |||
| st->codec->height = s->height; | |||
| st->codec->pix_fmt = s->pix_fmt; | |||
| s->img_size = avpicture_get_size(s->pix_fmt, (s->width+15)&(~15), (s->height+15)&(~15)); | |||
| return 0; | |||
| fail1: | |||
| if (!s->is_pipe) | |||
| url_fclose(f); | |||
| fail: | |||
| return AVERROR_IO; | |||
| } | |||
| static int read_packet_alloc_cb(void *opaque, AVImageInfo *info) | |||
| { | |||
| VideoData *s = opaque; | |||
| if (info->width != s->width || | |||
| info->height != s->height) | |||
| return -1; | |||
| avpicture_fill(&info->pict, s->ptr, info->pix_fmt, (info->width+15)&(~15), (info->height+15)&(~15)); | |||
| return 0; | |||
| } | |||
| static int img_read_packet(AVFormatContext *s1, AVPacket *pkt) | |||
| { | |||
| VideoData *s = s1->priv_data; | |||
| char filename[1024]; | |||
| int ret; | |||
| ByteIOContext f1, *f; | |||
| if (!s->is_pipe) { | |||
| /* loop over input */ | |||
| if (s1->loop_input && s->img_number > s->img_last) { | |||
| s->img_number = s->img_first; | |||
| } | |||
| if (av_get_frame_filename(filename, sizeof(filename), | |||
| s->path, s->img_number) < 0) | |||
| return AVERROR_IO; | |||
| f = &f1; | |||
| if (url_fopen(f, filename, URL_RDONLY) < 0) | |||
| return AVERROR_IO; | |||
| } else { | |||
| f = &s1->pb; | |||
| if (url_feof(f)) | |||
| return AVERROR_IO; | |||
| } | |||
| av_new_packet(pkt, s->img_size); | |||
| pkt->stream_index = 0; | |||
| s->ptr = pkt->data; | |||
| ret = av_read_image(f, filename, s->img_fmt, read_packet_alloc_cb, s); | |||
| if (!s->is_pipe) { | |||
| url_fclose(f); | |||
| } | |||
| if (ret < 0) { | |||
| av_free_packet(pkt); | |||
| return AVERROR_IO; /* signal EOF */ | |||
| } else { | |||
| /* XXX: computing this pts is not necessary as it is done in | |||
| the generic code too */ | |||
| pkt->pts = av_rescale((int64_t)s->img_count * s1->streams[0]->codec->time_base.num, s1->streams[0]->time_base.den, s1->streams[0]->codec->time_base.den) / s1->streams[0]->time_base.num; | |||
| s->img_count++; | |||
| s->img_number++; | |||
| return 0; | |||
| } | |||
| } | |||
| static int img_read_close(AVFormatContext *s1) | |||
| { | |||
| return 0; | |||
| } | |||
| /******************************************************/ | |||
| /* image output */ | |||
| static int img_set_parameters(AVFormatContext *s, AVFormatParameters *ap) | |||
| { | |||
| VideoData *img = s->priv_data; | |||
| AVStream *st; | |||
| AVImageFormat *img_fmt; | |||
| int i; | |||
| /* find output image format */ | |||
| if (ap->image_format) { | |||
| img_fmt = ap->image_format; | |||
| } else { | |||
| img_fmt = guess_image_format(s->filename); | |||
| } | |||
| if (!img_fmt) | |||
| return -1; | |||
| if (s->nb_streams != 1) | |||
| return -1; | |||
| st = s->streams[0]; | |||
| /* we select the first matching format */ | |||
| for(i=0;i<PIX_FMT_NB;i++) { | |||
| if (img_fmt->supported_pixel_formats & (1 << i)) | |||
| break; | |||
| } | |||
| if (i >= PIX_FMT_NB) | |||
| return -1; | |||
| img->img_fmt = img_fmt; | |||
| img->pix_fmt = i; | |||
| st->codec->pix_fmt = img->pix_fmt; | |||
| return 0; | |||
| } | |||
| static int img_write_header(AVFormatContext *s) | |||
| { | |||
| VideoData *img = s->priv_data; | |||
| img->img_number = 1; | |||
| pstrcpy(img->path, sizeof(img->path), s->filename); | |||
| /* find format */ | |||
| if (s->oformat->flags & AVFMT_NOFILE) | |||
| img->is_pipe = 0; | |||
| else | |||
| img->is_pipe = 1; | |||
| return 0; | |||
| } | |||
| static int img_write_packet(AVFormatContext *s, AVPacket *pkt) | |||
| { | |||
| VideoData *img = s->priv_data; | |||
| AVStream *st = s->streams[pkt->stream_index]; | |||
| ByteIOContext pb1, *pb; | |||
| AVPicture *picture; | |||
| int width, height, ret; | |||
| char filename[1024]; | |||
| AVImageInfo info; | |||
| width = st->codec->width; | |||
| height = st->codec->height; | |||
| picture = (AVPicture *)pkt->data; | |||
| if (!img->is_pipe) { | |||
| if (av_get_frame_filename(filename, sizeof(filename), | |||
| img->path, img->img_number) < 0) | |||
| return AVERROR_IO; | |||
| pb = &pb1; | |||
| if (url_fopen(pb, filename, URL_WRONLY) < 0) | |||
| return AVERROR_IO; | |||
| } else { | |||
| pb = &s->pb; | |||
| } | |||
| info.width = width; | |||
| info.height = height; | |||
| info.pix_fmt = st->codec->pix_fmt; | |||
| info.interleaved = 0; /* FIXME: there should be a way to set it right */ | |||
| info.pict = *picture; | |||
| ret = av_write_image(pb, img->img_fmt, &info); | |||
| if (!img->is_pipe) { | |||
| url_fclose(pb); | |||
| } | |||
| img->img_number++; | |||
| return 0; | |||
| } | |||
| static int img_write_trailer(AVFormatContext *s) | |||
| { | |||
| return 0; | |||
| } | |||
| /* input */ | |||
| #ifdef CONFIG_IMAGE_DEMUXER | |||
| AVInputFormat image_demuxer = { | |||
| "image", | |||
| "image sequence", | |||
| sizeof(VideoData), | |||
| image_probe, | |||
| img_read_header, | |||
| img_read_packet, | |||
| img_read_close, | |||
| NULL, | |||
| NULL, | |||
| AVFMT_NOFILE | AVFMT_NEEDNUMBER, | |||
| }; | |||
| #endif | |||
| #ifdef CONFIG_IMAGEPIPE_DEMUXER | |||
| AVInputFormat imagepipe_demuxer = { | |||
| "imagepipe", | |||
| "piped image sequence", | |||
| sizeof(VideoData), | |||
| NULL, /* no probe */ | |||
| img_read_header, | |||
| img_read_packet, | |||
| img_read_close, | |||
| NULL, | |||
| }; | |||
| #endif | |||
| /* output */ | |||
| #ifdef CONFIG_IMAGE_MUXER | |||
| AVOutputFormat image_muxer = { | |||
| "image", | |||
| "image sequence", | |||
| "", | |||
| "", | |||
| sizeof(VideoData), | |||
| CODEC_ID_NONE, | |||
| CODEC_ID_RAWVIDEO, | |||
| img_write_header, | |||
| img_write_packet, | |||
| img_write_trailer, | |||
| AVFMT_NOFILE | AVFMT_NEEDNUMBER | AVFMT_RAWPICTURE, | |||
| img_set_parameters, | |||
| }; | |||
| #endif | |||
| #ifdef CONFIG_IMAGEPIPE_MUXER | |||
| AVOutputFormat imagepipe_muxer = { | |||
| "imagepipe", | |||
| "piped image sequence", | |||
| "", | |||
| "", | |||
| sizeof(VideoData), | |||
| CODEC_ID_NONE, | |||
| CODEC_ID_RAWVIDEO, | |||
| img_write_header, | |||
| img_write_packet, | |||
| img_write_trailer, | |||
| AVFMT_RAWPICTURE, | |||
| img_set_parameters, | |||
| }; | |||
| #endif | |||
| @@ -1,240 +0,0 @@ | |||
| /* | |||
| * JPEG image format | |||
| * Copyright (c) 2003 Fabrice Bellard. | |||
| * | |||
| * This file is part of FFmpeg. | |||
| * | |||
| * FFmpeg 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.1 of the License, or (at your option) any later version. | |||
| * | |||
| * FFmpeg 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 FFmpeg; if not, write to the Free Software | |||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
| */ | |||
| #include "avformat.h" | |||
| static int jpeg_probe(AVProbeData *pd) | |||
| { | |||
| if (pd->buf_size >= 64 && | |||
| pd->buf[0] == 0xff && pd->buf[1] == 0xd8 && pd->buf[2] == 0xff) | |||
| return AVPROBE_SCORE_MAX; | |||
| else | |||
| return 0; | |||
| } | |||
| typedef struct JpegOpaque { | |||
| int (*alloc_cb)(void *opaque, AVImageInfo *info); | |||
| void *opaque; | |||
| int ret_code; | |||
| } JpegOpaque; | |||
| /* called by the codec to allocate the image */ | |||
| static int jpeg_get_buffer(AVCodecContext *c, AVFrame *picture) | |||
| { | |||
| JpegOpaque *jctx = c->opaque; | |||
| AVImageInfo info1, *info = &info1; | |||
| int ret, i; | |||
| info->width = c->width; | |||
| info->height = c->height; | |||
| switch(c->pix_fmt) { | |||
| case PIX_FMT_YUV420P: | |||
| info->pix_fmt = PIX_FMT_YUVJ420P; | |||
| break; | |||
| case PIX_FMT_YUV422P: | |||
| info->pix_fmt = PIX_FMT_YUVJ422P; | |||
| break; | |||
| case PIX_FMT_YUV444P: | |||
| info->pix_fmt = PIX_FMT_YUVJ444P; | |||
| break; | |||
| default: | |||
| return -1; | |||
| } | |||
| ret = jctx->alloc_cb(jctx->opaque, info); | |||
| if (ret) { | |||
| jctx->ret_code = ret; | |||
| return -1; | |||
| } else { | |||
| for(i=0;i<3;i++) { | |||
| picture->data[i] = info->pict.data[i]; | |||
| picture->linesize[i] = info->pict.linesize[i]; | |||
| } | |||
| return 0; | |||
| } | |||
| } | |||
| static void jpeg_img_copy(uint8_t *dst, int dst_wrap, | |||
| uint8_t *src, int src_wrap, | |||
| int width, int height) | |||
| { | |||
| for(;height > 0; height--) { | |||
| memcpy(dst, src, width); | |||
| dst += dst_wrap; | |||
| src += src_wrap; | |||
| } | |||
| } | |||
| /* XXX: libavcodec is broken for truncated jpegs! */ | |||
| #define IO_BUF_SIZE (1024*1024) | |||
| static int jpeg_read(ByteIOContext *f, | |||
| int (*alloc_cb)(void *opaque, AVImageInfo *info), void *opaque) | |||
| { | |||
| AVCodecContext *c; | |||
| AVFrame *picture, picture1; | |||
| int len, size, got_picture, i; | |||
| uint8_t *inbuf_ptr, inbuf[IO_BUF_SIZE]; | |||
| JpegOpaque jctx; | |||
| jctx.alloc_cb = alloc_cb; | |||
| jctx.opaque = opaque; | |||
| jctx.ret_code = -1; /* default return code is error */ | |||
| c = avcodec_alloc_context(); | |||
| if (!c) | |||
| return -1; | |||
| picture= avcodec_alloc_frame(); | |||
| if (!picture) { | |||
| av_free(c); | |||
| return -1; | |||
| } | |||
| c->opaque = &jctx; | |||
| c->get_buffer = jpeg_get_buffer; | |||
| c->flags |= CODEC_FLAG_TRUNCATED; /* we dont send complete frames */ | |||
| if (avcodec_open(c, &mjpeg_decoder) < 0) | |||
| goto fail1; | |||
| for(;;) { | |||
| size = get_buffer(f, inbuf, sizeof(inbuf)); | |||
| if (size == 0) | |||
| break; | |||
| inbuf_ptr = inbuf; | |||
| while (size > 0) { | |||
| len = avcodec_decode_video(c, &picture1, &got_picture, | |||
| inbuf_ptr, size); | |||
| if (len < 0) | |||
| goto fail; | |||
| if (got_picture) | |||
| goto the_end; | |||
| size -= len; | |||
| inbuf_ptr += len; | |||
| } | |||
| } | |||
| the_end: | |||
| /* XXX: currently, the mjpeg decoder does not use AVFrame, so we | |||
| must do it by hand */ | |||
| if (jpeg_get_buffer(c, picture) < 0) | |||
| goto fail; | |||
| for(i=0;i<3;i++) { | |||
| int w, h; | |||
| w = c->width; | |||
| h = c->height; | |||
| if (i >= 1) { | |||
| switch(c->pix_fmt) { | |||
| default: | |||
| case PIX_FMT_YUV420P: | |||
| w = (w + 1) >> 1; | |||
| h = (h + 1) >> 1; | |||
| break; | |||
| case PIX_FMT_YUV422P: | |||
| w = (w + 1) >> 1; | |||
| break; | |||
| case PIX_FMT_YUV444P: | |||
| break; | |||
| } | |||
| } | |||
| jpeg_img_copy(picture->data[i], picture->linesize[i], | |||
| picture1.data[i], picture1.linesize[i], | |||
| w, h); | |||
| } | |||
| jctx.ret_code = 0; | |||
| fail: | |||
| avcodec_close(c); | |||
| fail1: | |||
| av_free(picture); | |||
| av_free(c); | |||
| return jctx.ret_code; | |||
| } | |||
| #if defined(CONFIG_MUXERS) && defined(CONFIG_MJPEG_ENCODER) | |||
| static int jpeg_write(ByteIOContext *pb, AVImageInfo *info) | |||
| { | |||
| AVCodecContext *c; | |||
| uint8_t *outbuf = NULL; | |||
| int outbuf_size, ret, size, i; | |||
| AVFrame *picture; | |||
| ret = -1; | |||
| c = avcodec_alloc_context(); | |||
| if (!c) | |||
| return -1; | |||
| picture = avcodec_alloc_frame(); | |||
| if (!picture) | |||
| goto fail2; | |||
| c->width = info->width; | |||
| c->height = info->height; | |||
| /* XXX: currently move that to the codec ? */ | |||
| switch(info->pix_fmt) { | |||
| case PIX_FMT_YUVJ420P: | |||
| c->pix_fmt = PIX_FMT_YUV420P; | |||
| break; | |||
| case PIX_FMT_YUVJ422P: | |||
| c->pix_fmt = PIX_FMT_YUV422P; | |||
| break; | |||
| case PIX_FMT_YUVJ444P: | |||
| c->pix_fmt = PIX_FMT_YUV444P; | |||
| break; | |||
| default: | |||
| goto fail1; | |||
| } | |||
| for(i=0;i<3;i++) { | |||
| picture->data[i] = info->pict.data[i]; | |||
| picture->linesize[i] = info->pict.linesize[i]; | |||
| } | |||
| /* set the quality */ | |||
| picture->quality = 3; /* XXX: a parameter should be used */ | |||
| c->flags |= CODEC_FLAG_QSCALE; | |||
| if (avcodec_open(c, &mjpeg_encoder) < 0) | |||
| goto fail1; | |||
| /* XXX: needs to sort out that size problem */ | |||
| outbuf_size = 1000000; | |||
| outbuf = av_malloc(outbuf_size); | |||
| size = avcodec_encode_video(c, outbuf, outbuf_size, picture); | |||
| if (size < 0) | |||
| goto fail; | |||
| put_buffer(pb, outbuf, size); | |||
| put_flush_packet(pb); | |||
| ret = 0; | |||
| fail: | |||
| avcodec_close(c); | |||
| av_free(outbuf); | |||
| fail1: | |||
| av_free(picture); | |||
| fail2: | |||
| av_free(c); | |||
| return ret; | |||
| } | |||
| #endif //CONFIG_MUXERS | |||
| AVImageFormat jpeg_image_format = { | |||
| "jpeg", | |||
| "jpg,jpeg", | |||
| jpeg_probe, | |||
| jpeg_read, | |||
| (1 << PIX_FMT_YUVJ420P) | (1 << PIX_FMT_YUVJ422P) | (1 << PIX_FMT_YUVJ444P), | |||
| #if defined(CONFIG_MUXERS) && defined(CONFIG_MJPEG_ENCODER) | |||
| jpeg_write, | |||
| #else | |||
| NULL, | |||
| #endif //CONFIG_MUXERS | |||
| }; | |||
| @@ -1,161 +0,0 @@ | |||
| /* | |||
| * .Y.U.V image format | |||
| * Copyright (c) 2003 Fabrice Bellard. | |||
| * | |||
| * This file is part of FFmpeg. | |||
| * | |||
| * FFmpeg 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.1 of the License, or (at your option) any later version. | |||
| * | |||
| * FFmpeg 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 FFmpeg; if not, write to the Free Software | |||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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; | |||
| img_size = url_fsize(f); | |||
| /* XXX: hack hack */ | |||
| h = url_fileno(f); | |||
| url_get_filename(h, fname, sizeof(fname)); | |||
| if (infer_size(&info->width, &info->height, img_size) < 0) { | |||
| return AVERROR_IO; | |||
| } | |||
| 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 AVERROR_IO; | |||
| get_buffer(f, info->pict.data[0], size); | |||
| p[1] = 'U'; | |||
| if (url_fopen(pb, fname, URL_RDONLY) < 0) | |||
| return AVERROR_IO; | |||
| get_buffer(pb, info->pict.data[1], size / 4); | |||
| url_fclose(pb); | |||
| p[1] = 'V'; | |||
| if (url_fopen(pb, fname, URL_RDONLY) < 0) | |||
| return AVERROR_IO; | |||
| 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_t *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 AVERROR_IO; | |||
| 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 AVERROR_IO; | |||
| } 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, | |||
| }; | |||