Commit 87a0a681 authored by Fabrice Bellard's avatar Fabrice Bellard

added still image support

Originally committed as revision 1439 to svn://svn.ffmpeg.org/ffmpeg/trunk
parent f746a046
......@@ -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);
......
This diff is collapsed.
/*
* 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);
}
/*
* .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,
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment