renamed libav to libavformat

Originally committed as revision 1276 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
Fabrice Bellard
2002-11-25 19:07:40 +00:00
parent 57fc257642
commit abac617591
49 changed files with 10 additions and 10 deletions

6
libavformat/.cvsignore Normal file
View File

@@ -0,0 +1,6 @@
config.h
config.mak
*ffmpeg
ffserver
Makefile.*
.depend

72
libavformat/Makefile Normal file
View File

@@ -0,0 +1,72 @@
#
# libavformat Makefile
# (c) 2000, 2001, 2002 Fabrice Bellard
#
include ../config.mak
VPATH=$(SRC_PATH)/libav
CFLAGS= $(OPTFLAGS) -Wall -g -I.. -I$(SRC_PATH) -I$(SRC_PATH)/libavcodec -DHAVE_AV_CONFIG_H -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_GNU_SOURCE
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
# file I/O
OBJS+= avio.o aviobuf.o file.o
ifeq ($(BUILD_STRPTIME),yes)
OBJS+= strptime.o
endif
ifeq ($(CONFIG_VIDEO4LINUX),yes)
OBJS+= grab.o
endif
ifeq ($(CONFIG_AUDIO_OSS),yes)
OBJS+= audio.o
endif
ifeq ($(CONFIG_AUDIO_BEOS),yes)
OBJS+= beosaudio.o
endif
ifeq ($(CONFIG_NETWORK),yes)
OBJS+= udp.o tcp.o http.o rtsp.o rtp.o rtpproto.o
# BeOS network stuff
ifeq ($(CONFIG_BEOS_NETSERVER),yes)
OBJS+= barpainet.o
endif
endif
ifeq ($(CONFIG_VORBIS),yes)
OBJS+= ogg.o
endif
LIB= libavformat.a
all: $(LIB)
$(LIB): $(OBJS)
rm -f $@
$(AR) rc $@ $(OBJS)
$(RANLIB) $@
installlib: all
install -m 644 $(LIB) $(prefix)/lib
mkdir -p $(prefix)/include/ffmpeg
install -m 644 $(SRC_PATH)/libav/avformat.h $(SRC_PATH)/libav/avio.h \
$(SRC_PATH)/libav/rtp.h $(SRC_PATH)/libav/rtsp.h \
$(SRC_PATH)/libav/rtspcodes.h \
$(prefix)/include/ffmpeg
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
# BeOS: remove -Wall to get rid of all the "multibyte constant" warnings
%.o: %.cpp
g++ $(subst -Wall,,$(CFLAGS)) -c -o $@ $<
clean:
rm -f *.o *~ *.a

74
libavformat/allformats.c Normal file
View File

@@ -0,0 +1,74 @@
/*
* Register all the formats and protocols
* Copyright (c) 2000, 2001, 2002 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"
/* If you do not call this function, then you can select exactly which
formats you want to support */
/**
* Initialize libavcodec and register all the codecs and formats.
*/
void av_register_all(void)
{
avcodec_init();
avcodec_register_all();
mpegps_init();
mpegts_init();
crc_init();
img_init();
raw_init();
rm_init();
asf_init();
avienc_init();
avidec_init();
wav_init();
swf_init();
au_init();
gif_init();
mov_init();
jpeg_init();
dv_init();
#ifdef CONFIG_VORBIS
ogg_init();
#endif
#ifndef CONFIG_WIN32
ffm_init();
#endif
#ifdef CONFIG_VIDEO4LINUX
video_grab_init();
#endif
#if defined(CONFIG_AUDIO_OSS) || defined(CONFIG_AUDIO_BEOS)
audio_init();
#endif
/* file protocols */
register_protocol(&file_protocol);
register_protocol(&pipe_protocol);
#ifdef CONFIG_NETWORK
rtsp_init();
rtp_init();
register_protocol(&udp_protocol);
register_protocol(&rtp_protocol);
register_protocol(&tcp_protocol);
register_protocol(&http_protocol);
#endif
}

1256
libavformat/asf.c Normal file

File diff suppressed because it is too large Load Diff

214
libavformat/au.c Normal file
View File

@@ -0,0 +1,214 @@
/*
* AU encoder and decoder
* Copyright (c) 2001 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
*/
/*
* First version by Francois Revol revol@free.fr
*
* Reference documents:
* http://www.opengroup.org/public/pubs/external/auformat.html
* http://www.goice.co.jp/member/mo/formats/au.html
*/
#include "avformat.h"
#include "avi.h"
/* if we don't know the size in advance */
#define AU_UNKOWN_SIZE ((UINT32)(~0))
/* The ffmpeg codecs we support, and the IDs they have in the file */
static const CodecTag codec_au_tags[] = {
{ CODEC_ID_PCM_MULAW, 1 },
{ CODEC_ID_PCM_S16BE, 3 },
{ CODEC_ID_PCM_ALAW, 27 },
{ 0, 0 },
};
/* AUDIO_FILE header */
static int put_au_header(ByteIOContext *pb, AVCodecContext *enc)
{
int tag;
tag = codec_get_tag(codec_au_tags, enc->codec_id);
if (tag == 0)
return -1;
put_tag(pb, ".snd"); /* magic number */
put_be32(pb, 24); /* header size */
put_be32(pb, AU_UNKOWN_SIZE); /* data size */
put_be32(pb, (UINT32)tag); /* codec ID */
put_be32(pb, enc->sample_rate);
put_be32(pb, (UINT32)enc->channels);
return 0;
}
static int au_write_header(AVFormatContext *s)
{
ByteIOContext *pb = &s->pb;
s->priv_data = NULL;
/* format header */
if (put_au_header(pb, &s->streams[0]->codec) < 0) {
return -1;
}
put_flush_packet(pb);
return 0;
}
static int au_write_packet(AVFormatContext *s, int stream_index_ptr,
UINT8 *buf, int size, int force_pts)
{
ByteIOContext *pb = &s->pb;
put_buffer(pb, buf, size);
return 0;
}
static int au_write_trailer(AVFormatContext *s)
{
ByteIOContext *pb = &s->pb;
offset_t file_size;
if (!url_is_streamed(&s->pb)) {
/* update file size */
file_size = url_ftell(pb);
url_fseek(pb, 8, SEEK_SET);
put_be32(pb, (UINT32)(file_size - 24));
url_fseek(pb, file_size, SEEK_SET);
put_flush_packet(pb);
}
return 0;
}
static int au_probe(AVProbeData *p)
{
/* check file header */
if (p->buf_size <= 24)
return 0;
if (p->buf[0] == '.' && p->buf[1] == 's' &&
p->buf[2] == 'n' && p->buf[3] == 'd')
return AVPROBE_SCORE_MAX;
else
return 0;
}
/* au input */
static int au_read_header(AVFormatContext *s,
AVFormatParameters *ap)
{
int size;
unsigned int tag;
ByteIOContext *pb = &s->pb;
unsigned int id, codec, channels, rate;
AVStream *st;
/* check ".snd" header */
tag = get_le32(pb);
if (tag != MKTAG('.', 's', 'n', 'd'))
return -1;
size = get_be32(pb); /* header size */
get_be32(pb); /* data size */
id = get_be32(pb);
rate = get_be32(pb);
channels = get_be32(pb);
codec = codec_get_id(codec_au_tags, id);
if (size >= 24) {
/* skip unused data */
url_fseek(pb, size - 24, SEEK_CUR);
}
/* now we are ready: build format streams */
st = av_malloc(sizeof(AVStream));
if (!st)
return -1;
s->nb_streams = 1;
s->streams[0] = st;
st->id = 0;
st->codec.codec_type = CODEC_TYPE_AUDIO;
st->codec.codec_tag = id;
st->codec.codec_id = codec;
st->codec.channels = channels;
st->codec.sample_rate = rate;
return 0;
}
#define MAX_SIZE 4096
static int au_read_packet(AVFormatContext *s,
AVPacket *pkt)
{
int ret;
if (url_feof(&s->pb))
return -EIO;
if (av_new_packet(pkt, MAX_SIZE))
return -EIO;
pkt->stream_index = 0;
ret = get_buffer(&s->pb, pkt->data, pkt->size);
if (ret < 0)
av_free_packet(pkt);
/* note: we need to modify the packet size here to handle the last
packet */
pkt->size = ret;
return 0;
}
static int au_read_close(AVFormatContext *s)
{
return 0;
}
static AVInputFormat au_iformat = {
"au",
"SUN AU Format",
0,
au_probe,
au_read_header,
au_read_packet,
au_read_close,
};
static AVOutputFormat au_oformat = {
"au",
"SUN AU Format",
"audio/basic",
"au",
0,
CODEC_ID_PCM_S16BE,
CODEC_ID_NONE,
au_write_header,
au_write_packet,
au_write_trailer,
};
int au_init(void)
{
av_register_input_format(&au_iformat);
av_register_output_format(&au_oformat);
return 0;
}

330
libavformat/audio.c Normal file
View File

@@ -0,0 +1,330 @@
/*
* Linux audio play and grab interface
* Copyright (c) 2000, 2001 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"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/soundcard.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/time.h>
const char *audio_device = "/dev/dsp";
#define AUDIO_BLOCK_SIZE 4096
typedef struct {
int fd;
int sample_rate;
int channels;
int frame_size; /* in bytes ! */
int codec_id;
int flip_left : 1;
UINT8 buffer[AUDIO_BLOCK_SIZE];
int buffer_ptr;
} AudioData;
static int audio_open(AudioData *s, int is_output)
{
int audio_fd;
int tmp, err;
char *flip = getenv("AUDIO_FLIP_LEFT");
/* open linux audio device */
if (is_output)
audio_fd = open(audio_device, O_WRONLY);
else
audio_fd = open(audio_device, O_RDONLY);
if (audio_fd < 0) {
perror(audio_device);
return -EIO;
}
if (flip && *flip == '1') {
s->flip_left = 1;
}
/* non blocking mode */
if (!is_output)
fcntl(audio_fd, F_SETFL, O_NONBLOCK);
s->frame_size = AUDIO_BLOCK_SIZE;
#if 0
tmp = (NB_FRAGMENTS << 16) | FRAGMENT_BITS;
err = ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &tmp);
if (err < 0) {
perror("SNDCTL_DSP_SETFRAGMENT");
}
#endif
/* select format : favour native format */
err = ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &tmp);
#ifdef WORDS_BIGENDIAN
if (tmp & AFMT_S16_BE) {
tmp = AFMT_S16_BE;
} else if (tmp & AFMT_S16_LE) {
tmp = AFMT_S16_LE;
} else {
tmp = 0;
}
#else
if (tmp & AFMT_S16_LE) {
tmp = AFMT_S16_LE;
} else if (tmp & AFMT_S16_BE) {
tmp = AFMT_S16_BE;
} else {
tmp = 0;
}
#endif
switch(tmp) {
case AFMT_S16_LE:
s->codec_id = CODEC_ID_PCM_S16LE;
break;
case AFMT_S16_BE:
s->codec_id = CODEC_ID_PCM_S16BE;
break;
default:
fprintf(stderr, "Soundcard does not support 16 bit sample format\n");
close(audio_fd);
return -EIO;
}
err=ioctl(audio_fd, SNDCTL_DSP_SETFMT, &tmp);
if (err < 0) {
perror("SNDCTL_DSP_SETFMT");
goto fail;
}
tmp = (s->channels == 2);
err = ioctl(audio_fd, SNDCTL_DSP_STEREO, &tmp);
if (err < 0) {
perror("SNDCTL_DSP_STEREO");
goto fail;
}
if (tmp)
s->channels = 2;
tmp = s->sample_rate;
err = ioctl(audio_fd, SNDCTL_DSP_SPEED, &tmp);
if (err < 0) {
perror("SNDCTL_DSP_SPEED");
goto fail;
}
s->sample_rate = tmp; /* store real sample rate */
s->fd = audio_fd;
return 0;
fail:
close(audio_fd);
return -EIO;
}
static int audio_close(AudioData *s)
{
close(s->fd);
return 0;
}
/* sound output support */
static int audio_write_header(AVFormatContext *s1)
{
AudioData *s = s1->priv_data;
AVStream *st;
int ret;
st = s1->streams[0];
s->sample_rate = st->codec.sample_rate;
s->channels = st->codec.channels;
ret = audio_open(s, 1);
if (ret < 0) {
return -EIO;
} else {
return 0;
}
}
static int audio_write_packet(AVFormatContext *s1, int stream_index,
UINT8 *buf, int size, int force_pts)
{
AudioData *s = s1->priv_data;
int len, ret;
while (size > 0) {
len = AUDIO_BLOCK_SIZE - s->buffer_ptr;
if (len > size)
len = size;
memcpy(s->buffer + s->buffer_ptr, buf, len);
s->buffer_ptr += len;
if (s->buffer_ptr >= AUDIO_BLOCK_SIZE) {
for(;;) {
ret = write(s->fd, s->buffer, AUDIO_BLOCK_SIZE);
if (ret > 0)
break;
if (ret < 0 && (errno != EAGAIN && errno != EINTR))
return -EIO;
}
s->buffer_ptr = 0;
}
buf += len;
size -= len;
}
return 0;
}
static int audio_write_trailer(AVFormatContext *s1)
{
AudioData *s = s1->priv_data;
audio_close(s);
return 0;
}
/* grab support */
static int audio_read_header(AVFormatContext *s1, AVFormatParameters *ap)
{
AudioData *s = s1->priv_data;
AVStream *st;
int ret;
if (!ap || ap->sample_rate <= 0 || ap->channels <= 0)
return -1;
st = av_new_stream(s1, 0);
if (!st) {
return -ENOMEM;
}
s->sample_rate = ap->sample_rate;
s->channels = ap->channels;
ret = audio_open(s, 0);
if (ret < 0) {
av_free(st);
return -EIO;
}
/* take real parameters */
st->codec.codec_type = CODEC_TYPE_AUDIO;
st->codec.codec_id = s->codec_id;
st->codec.sample_rate = s->sample_rate;
st->codec.channels = s->channels;
av_set_pts_info(s1, 48, 1, 1000000); /* 48 bits pts in us */
return 0;
}
static int audio_read_packet(AVFormatContext *s1, AVPacket *pkt)
{
AudioData *s = s1->priv_data;
int ret, bdelay;
int64_t cur_time;
struct audio_buf_info abufi;
if (av_new_packet(pkt, s->frame_size) < 0)
return -EIO;
for(;;) {
ret = read(s->fd, pkt->data, pkt->size);
if (ret > 0)
break;
if (ret == -1 && (errno == EAGAIN || errno == EINTR)) {
av_free_packet(pkt);
pkt->size = 0;
return 0;
}
if (!(ret == 0 || (ret == -1 && (errno == EAGAIN || errno == EINTR)))) {
av_free_packet(pkt);
return -EIO;
}
}
pkt->size = ret;
/* compute pts of the start of the packet */
cur_time = av_gettime();
bdelay = ret;
if (ioctl(s->fd, SNDCTL_DSP_GETISPACE, &abufi) == 0) {
bdelay += abufi.bytes;
}
/* substract time represented by the number of bytes in the audio fifo */
cur_time -= (bdelay * 1000000LL) / (s->sample_rate * s->channels);
/* convert to wanted units */
pkt->pts = cur_time & ((1LL << 48) - 1);
if (s->flip_left && s->channels == 2) {
int i;
short *p = (short *) pkt->data;
for (i = 0; i < ret; i += 4) {
*p = ~*p;
p += 2;
}
}
return 0;
}
static int audio_read_close(AVFormatContext *s1)
{
AudioData *s = s1->priv_data;
audio_close(s);
return 0;
}
static AVInputFormat audio_in_format = {
"audio_device",
"audio grab and output",
sizeof(AudioData),
NULL,
audio_read_header,
audio_read_packet,
audio_read_close,
.flags = AVFMT_NOFILE,
};
static AVOutputFormat audio_out_format = {
"audio_device",
"audio grab and output",
"",
"",
sizeof(AudioData),
/* XXX: we make the assumption that the soundcard accepts this format */
/* XXX: find better solution with "preinit" method, needed also in
other formats */
#ifdef WORDS_BIGENDIAN
CODEC_ID_PCM_S16BE,
#else
CODEC_ID_PCM_S16LE,
#endif
CODEC_ID_NONE,
audio_write_header,
audio_write_packet,
audio_write_trailer,
.flags = AVFMT_NOFILE,
};
int audio_init(void)
{
av_register_input_format(&audio_in_format);
av_register_output_format(&audio_out_format);
return 0;
}

351
libavformat/avformat.h Normal file
View File

@@ -0,0 +1,351 @@
#ifndef AVFORMAT_H
#define AVFORMAT_H
#define LIBAVFORMAT_VERSION_INT 0x000406
#define LIBAVFORMAT_VERSION "0.4.6"
#define LIBAVFORMAT_BUILD 4602
#include "avcodec.h"
#include "avio.h"
/* packet functions */
#define AV_NOPTS_VALUE 0
typedef struct AVPacket {
INT64 pts; /* presentation time stamp in stream units (set av_set_pts_info) */
UINT8 *data;
int size;
int stream_index;
int flags;
int duration;
#define PKT_FLAG_KEY 0x0001
} AVPacket;
int av_new_packet(AVPacket *pkt, int size);
void av_free_packet(AVPacket *pkt);
/*************************************************/
/* fractional numbers for exact pts handling */
/* the exact value of the fractional number is: 'val + num / den'. num
is assumed to be such as 0 <= num < den */
typedef struct AVFrac {
INT64 val, num, den;
} AVFrac;
void av_frac_init(AVFrac *f, INT64 val, INT64 num, INT64 den);
void av_frac_add(AVFrac *f, INT64 incr);
void av_frac_set(AVFrac *f, INT64 val);
/*************************************************/
/* input/output formats */
struct AVFormatContext;
/* this structure contains the data a format has to probe a file */
typedef struct AVProbeData {
char *filename;
unsigned char *buf;
int buf_size;
} AVProbeData;
#define AVPROBE_SCORE_MAX 100
typedef struct AVFormatParameters {
int frame_rate;
int sample_rate;
int channels;
int width;
int height;
enum PixelFormat pix_fmt;
} AVFormatParameters;
#define AVFMT_NOFILE 0x0001 /* no file should be opened */
#define AVFMT_NEEDNUMBER 0x0002 /* needs '%d' in filename */
#define AVFMT_NOHEADER 0x0004 /* signal that no header is present
(streams are added dynamically) */
#define AVFMT_SHOW_IDS 0x0008 /* show format stream IDs numbers */
#define AVFMT_RGB24 0x0010 /* force RGB24 output for ppm (hack
- need better api) */
#define AVFMT_RAWPICTURE 0x0020 /* format wants AVPicture structure for
raw picture data */
typedef struct AVOutputFormat {
const char *name;
const char *long_name;
const char *mime_type;
const char *extensions; /* comma separated extensions */
/* size of private data so that it can be allocated in the wrapper */
int priv_data_size;
/* output support */
enum CodecID audio_codec; /* default audio codec */
enum CodecID video_codec; /* default video codec */
int (*write_header)(struct AVFormatContext *);
/* XXX: change prototype for 64 bit pts */
int (*write_packet)(struct AVFormatContext *,
int stream_index,
unsigned char *buf, int size, int force_pts);
int (*write_trailer)(struct AVFormatContext *);
/* can use flags: AVFMT_NOFILE, AVFMT_NEEDNUMBER */
int flags;
/* private fields */
struct AVOutputFormat *next;
} AVOutputFormat;
typedef struct AVInputFormat {
const char *name;
const char *long_name;
/* size of private data so that it can be allocated in the wrapper */
int priv_data_size;
/* tell if a given file has a chance of being parsing by this format */
int (*read_probe)(AVProbeData *);
/* read the format header and initialize the AVFormatContext
structure. Return 0 if OK. 'ap' if non NULL contains
additionnal paramters. Only used in raw format right
now. 'av_new_stream' should be called to create new streams. */
int (*read_header)(struct AVFormatContext *,
AVFormatParameters *ap);
/* read one packet and put it in 'pkt'. pts and flags are also
set. 'av_new_stream' can be called only if the flag
AVFMT_NOHEADER is used. */
int (*read_packet)(struct AVFormatContext *, AVPacket *pkt);
/* close the stream. The AVFormatContext and AVStreams are not
freed by this function */
int (*read_close)(struct AVFormatContext *);
/* seek at or before a given pts (given in microsecond). The pts
origin is defined by the stream */
int (*read_seek)(struct AVFormatContext *, INT64 pts);
/* can use flags: AVFMT_NOFILE, AVFMT_NEEDNUMBER, AVFMT_NOHEADER */
int flags;
/* if extensions are defined, then no probe is done. You should
usually not use extension format guessing because it is not
reliable enough */
const char *extensions;
/* general purpose read only value that the format can use */
int value;
/* private fields */
struct AVInputFormat *next;
} AVInputFormat;
typedef struct AVStream {
int index; /* stream index in AVFormatContext */
int id; /* format specific stream id */
AVCodecContext codec; /* codec context */
int r_frame_rate; /* real frame rate of the stream */
uint64_t time_length; /* real length of the stream in miliseconds */
void *priv_data;
/* internal data used in av_find_stream_info() */
int codec_info_state;
int codec_info_nb_repeat_frames;
int codec_info_nb_real_frames;
/* PTS generation when outputing stream */
AVFrac pts;
/* ffmpeg.c private use */
int stream_copy; /* if TRUE, just copy stream */
} AVStream;
#define MAX_STREAMS 20
/* format I/O context */
typedef struct AVFormatContext {
/* can only be iformat or oformat, not both at the same time */
struct AVInputFormat *iformat;
struct AVOutputFormat *oformat;
void *priv_data;
ByteIOContext pb;
int nb_streams;
AVStream *streams[MAX_STREAMS];
char filename[1024]; /* input or output filename */
/* stream info */
char title[512];
char author[512];
char copyright[512];
char comment[512];
int flags; /* format specific flags */
/* private data for pts handling (do not modify directly) */
int pts_wrap_bits; /* number of bits in pts (used for wrapping control) */
int pts_num, pts_den; /* value to convert to seconds */
/* This buffer is only needed when packets were already buffered but
not decoded, for example to get the codec parameters in mpeg
streams */
struct AVPacketList *packet_buffer;
} AVFormatContext;
typedef struct AVPacketList {
AVPacket pkt;
struct AVPacketList *next;
} AVPacketList;
extern AVInputFormat *first_iformat;
extern AVOutputFormat *first_oformat;
/* XXX: use automatic init with either ELF sections or C file parser */
/* modules */
/* mpeg.c */
int mpegps_init(void);
/* mpegts.c */
extern AVInputFormat mpegts_demux;
int mpegts_init(void);
/* rm.c */
int rm_init(void);
/* crc.c */
int crc_init(void);
/* img.c */
int img_init(void);
/* asf.c */
int asf_init(void);
/* avienc.c */
int avienc_init(void);
/* avidec.c */
int avidec_init(void);
/* swf.c */
int swf_init(void);
/* mov.c */
int mov_init(void);
/* jpeg.c */
int jpeg_init(void);
/* gif.c */
int gif_init(void);
/* au.c */
int au_init(void);
/* wav.c */
int wav_init(void);
/* raw.c */
int raw_init(void);
/* ogg.c */
int ogg_init(void);
/* dv.c */
int dv_init(void);
/* ffm.c */
int ffm_init(void);
/* rtsp.c */
extern AVInputFormat redir_demux;
int redir_open(AVFormatContext **ic_ptr, ByteIOContext *f);
#include "rtp.h"
#include "rtsp.h"
/* utils.c */
#define MKTAG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24))
#define MKBETAG(a,b,c,d) (d | (c << 8) | (b << 16) | (a << 24))
void av_register_input_format(AVInputFormat *format);
void av_register_output_format(AVOutputFormat *format);
AVOutputFormat *guess_stream_format(const char *short_name,
const char *filename, const char *mime_type);
AVOutputFormat *guess_format(const char *short_name,
const char *filename, const char *mime_type);
void av_hex_dump(UINT8 *buf, int size);
void av_register_all(void);
typedef struct FifoBuffer {
UINT8 *buffer;
UINT8 *rptr, *wptr, *end;
} FifoBuffer;
int fifo_init(FifoBuffer *f, int size);
void fifo_free(FifoBuffer *f);
int fifo_size(FifoBuffer *f, UINT8 *rptr);
int fifo_read(FifoBuffer *f, UINT8 *buf, int buf_size, UINT8 **rptr_ptr);
void fifo_write(FifoBuffer *f, UINT8 *buf, int size, UINT8 **wptr_ptr);
/* media file input */
AVInputFormat *av_find_input_format(const char *short_name);
AVInputFormat *av_probe_input_format(AVProbeData *pd, int is_opened);
int av_open_input_file(AVFormatContext **ic_ptr, const char *filename,
AVInputFormat *fmt,
int buf_size,
AVFormatParameters *ap);
#define AVERROR_UNKNOWN (-1) /* unknown error */
#define AVERROR_IO (-2) /* i/o error */
#define AVERROR_NUMEXPECTED (-3) /* number syntax expected in filename */
#define AVERROR_INVALIDDATA (-4) /* invalid data found */
#define AVERROR_NOMEM (-5) /* not enough memory */
#define AVERROR_NOFMT (-6) /* unknown format */
int av_find_stream_info(AVFormatContext *ic);
int av_read_packet(AVFormatContext *s, AVPacket *pkt);
void av_close_input_file(AVFormatContext *s);
AVStream *av_new_stream(AVFormatContext *s, int id);
void av_set_pts_info(AVFormatContext *s, int pts_wrap_bits,
int pts_num, int pts_den);
/* media file output */
int av_write_header(AVFormatContext *s);
int av_write_frame(AVFormatContext *s, int stream_index, const uint8_t *buf,
int size);
int av_write_trailer(AVFormatContext *s);
void dump_format(AVFormatContext *ic,
int index,
const char *url,
int is_output);
int parse_image_size(int *width_ptr, int *height_ptr, const char *str);
INT64 parse_date(const char *datestr, int duration);
INT64 av_gettime(void);
/* ffm specific for ffserver */
#define FFM_PACKET_SIZE 4096
offset_t ffm_read_write_index(int fd);
void ffm_write_write_index(int fd, offset_t pos);
void ffm_set_write_index(AVFormatContext *s, offset_t pos, offset_t file_size);
int find_info_tag(char *arg, int arg_size, const char *tag1, const char *info);
int get_frame_filename(char *buf, int buf_size,
const char *path, int number);
int filename_number_test(const char *filename);
/* grab specific */
int video_grab_init(void);
int audio_init(void);
extern const char *v4l_device;
extern const char *audio_device;
#ifdef HAVE_AV_CONFIG_H
int strstart(const char *str, const char *val, const char **ptr);
int stristart(const char *str, const char *val, const char **ptr);
void pstrcpy(char *buf, int buf_size, const char *str);
char *pstrcat(char *buf, int buf_size, const char *s);
struct in_addr;
int resolve_host(struct in_addr *sin_addr, const char *hostname);
void url_split(char *proto, int proto_size,
char *hostname, int hostname_size,
int *port_ptr,
char *path, int path_size,
const char *url);
int match_ext(const char *filename, const char *extensions);
#endif /* HAVE_AV_CONFIG_H */
#endif /* AVFORMAT_H */

28
libavformat/avi.h Normal file
View File

@@ -0,0 +1,28 @@
#define AVIF_HASINDEX 0x00000010 // Index at end of file?
#define AVIF_MUSTUSEINDEX 0x00000020
#define AVIF_ISINTERLEAVED 0x00000100
#define AVIF_TRUSTCKTYPE 0x00000800 // Use CKType to find key frames?
#define AVIF_WASCAPTUREFILE 0x00010000
#define AVIF_COPYRIGHTED 0x00020000
offset_t start_tag(ByteIOContext *pb, const char *tag);
void end_tag(ByteIOContext *pb, offset_t start);
typedef struct CodecTag {
int id;
unsigned int tag;
unsigned int invalid_asf : 1;
} CodecTag;
void put_bmp_header(ByteIOContext *pb, AVCodecContext *enc, const CodecTag *tags, int for_asf);
int put_wav_header(ByteIOContext *pb, AVCodecContext *enc);
int wav_codec_get_id(unsigned int tag, int bps);
void get_wav_header(ByteIOContext *pb, AVCodecContext *codec,
int has_extra_data);
extern const CodecTag codec_bmp_tags[];
extern const CodecTag codec_wav_tags[];
unsigned int codec_get_tag(const CodecTag *tags, int id);
int codec_get_id(const CodecTag *tags, unsigned int tag);

256
libavformat/avidec.c Normal file
View File

@@ -0,0 +1,256 @@
/*
* AVI decoder.
* Copyright (c) 2001 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"
#include "avi.h"
//#define DEBUG
typedef struct AVIIndex {
unsigned char tag[4];
unsigned int flags, pos, len;
struct AVIIndex *next;
} AVIIndex;
typedef struct {
INT64 movi_end;
offset_t movi_list;
AVIIndex *first, *last;
} AVIContext;
#ifdef DEBUG
static void print_tag(const char *str, unsigned int tag, int size)
{
printf("%s: tag=%c%c%c%c size=0x%x\n",
str, tag & 0xff,
(tag >> 8) & 0xff,
(tag >> 16) & 0xff,
(tag >> 24) & 0xff,
size);
}
#endif
static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap)
{
AVIContext *avi = s->priv_data;
ByteIOContext *pb = &s->pb;
UINT32 tag, tag1;
int codec_type, stream_index, size, frame_period, bit_rate;
int i;
AVStream *st;
/* check RIFF header */
tag = get_le32(pb);
if (tag != MKTAG('R', 'I', 'F', 'F'))
return -1;
get_le32(pb); /* file size */
tag = get_le32(pb);
if (tag != MKTAG('A', 'V', 'I', ' '))
return -1;
/* first list tag */
stream_index = -1;
codec_type = -1;
frame_period = 0;
for(;;) {
if (url_feof(pb))
goto fail;
tag = get_le32(pb);
size = get_le32(pb);
#ifdef DEBUG
print_tag("tag", tag, size);
#endif
switch(tag) {
case MKTAG('L', 'I', 'S', 'T'):
/* ignored, except when start of video packets */
tag1 = get_le32(pb);
#ifdef DEBUG
print_tag("list", tag1, 0);
#endif
if (tag1 == MKTAG('m', 'o', 'v', 'i')) {
avi->movi_end = url_ftell(pb) + size - 4;
#ifdef DEBUG
printf("movi end=%Lx\n", avi->movi_end);
#endif
goto end_of_header;
}
break;
case MKTAG('a', 'v', 'i', 'h'):
/* avi header */
/* using frame_period is bad idea */
frame_period = get_le32(pb);
bit_rate = get_le32(pb) * 8;
url_fskip(pb, 4 * 4);
s->nb_streams = get_le32(pb);
for(i=0;i<s->nb_streams;i++) {
AVStream *st = av_mallocz(sizeof(AVStream));
if (!st)
goto fail;
s->streams[i] = st;
}
url_fskip(pb, size - 7 * 4);
break;
case MKTAG('s', 't', 'r', 'h'):
/* stream header */
stream_index++;
tag1 = get_le32(pb);
switch(tag1) {
case MKTAG('v', 'i', 'd', 's'):
codec_type = CODEC_TYPE_VIDEO;
get_le32(pb); /* codec tag */
get_le32(pb); /* flags */
get_le16(pb); /* priority */
get_le16(pb); /* language */
get_le32(pb); /* XXX: initial frame ? */
get_le32(pb); /* scale */
get_le32(pb); /* rate */
size -= 6 * 4;
break;
case MKTAG('a', 'u', 'd', 's'):
codec_type = CODEC_TYPE_AUDIO;
/* nothing really useful */
}
url_fskip(pb, size - 4);
break;
case MKTAG('s', 't', 'r', 'f'):
/* stream header */
if (stream_index >= s->nb_streams) {
url_fskip(pb, size);
} else {
st = s->streams[stream_index];
switch(codec_type) {
case CODEC_TYPE_VIDEO:
get_le32(pb); /* size */
st->codec.width = get_le32(pb);
st->codec.height = get_le32(pb);
if (frame_period)
st->codec.frame_rate = (INT64_C(1000000) * FRAME_RATE_BASE) / frame_period;
else
st->codec.frame_rate = 25 * FRAME_RATE_BASE;
get_le16(pb); /* panes */
get_le16(pb); /* depth */
tag1 = get_le32(pb);
#ifdef DEBUG
print_tag("video", tag1, 0);
#endif
st->codec.codec_type = CODEC_TYPE_VIDEO;
st->codec.codec_tag = tag1;
st->codec.codec_id = codec_get_id(codec_bmp_tags, tag1);
url_fskip(pb, size - 5 * 4);
break;
case CODEC_TYPE_AUDIO:
get_wav_header(pb, &st->codec, (size >= 18));
break;
default:
url_fskip(pb, size);
break;
}
}
break;
default:
/* skip tag */
size += (size & 1);
url_fskip(pb, size);
break;
}
}
end_of_header:
/* check stream number */
if (stream_index != s->nb_streams - 1) {
fail:
for(i=0;i<s->nb_streams;i++) {
av_freep(&s->streams[i]);
}
return -1;
}
return 0;
}
static int avi_read_packet(AVFormatContext *s, AVPacket *pkt)
{
AVIContext *avi = s->priv_data;
ByteIOContext *pb = &s->pb;
int n, d1, d2, size;
for(;;) {
if (url_feof(pb) || url_ftell(pb) >= avi->movi_end)
return -1;
d1 = get_byte(pb) - '0';
d2 = get_byte(pb) - '0';
if (d1 < 0 || d1 > 9 || d2 < 0 || d2 > 9)
continue;
n = d1 * 10 + d2;
if (n < 0 || n >= s->nb_streams)
continue;
d1 = get_byte(pb);
d2 = get_byte(pb);
if ((d1 == 'd' && d2 == 'c')
|| (d1 == 'w' && d2 == 'b'))
break;
}
size = get_le32(pb);
av_new_packet(pkt, size);
pkt->stream_index = n;
get_buffer(pb, pkt->data, pkt->size);
if (size & 1)
get_byte(pb);
return 0;
}
static int avi_read_close(AVFormatContext *s)
{
return 0;
}
static int avi_probe(AVProbeData *p)
{
/* check file header */
if (p->buf_size <= 32)
return 0;
if (p->buf[0] == 'R' && p->buf[1] == 'I' &&
p->buf[2] == 'F' && p->buf[3] == 'F' &&
p->buf[8] == 'A' && p->buf[9] == 'V' &&
p->buf[10] == 'I' && p->buf[11] == ' ')
return AVPROBE_SCORE_MAX;
else
return 0;
}
static AVInputFormat avi_iformat = {
"avi",
"avi format",
sizeof(AVIContext),
avi_probe,
avi_read_header,
avi_read_packet,
avi_read_close,
};
int avidec_init(void)
{
av_register_input_format(&avi_iformat);
return 0;
}

432
libavformat/avienc.c Normal file
View File

@@ -0,0 +1,432 @@
/*
* AVI encoder.
* Copyright (c) 2000 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"
#include "avi.h"
/*
* TODO:
* - fill all fields if non streamed (nb_frames for example)
*/
typedef struct AVIIndex {
unsigned char tag[4];
unsigned int flags, pos, len;
struct AVIIndex *next;
} AVIIndex;
typedef struct {
offset_t movi_list, frames_hdr_all, frames_hdr_strm[MAX_STREAMS];
int audio_strm_length[MAX_STREAMS];
AVIIndex *first, *last;
} AVIContext;
offset_t start_tag(ByteIOContext *pb, const char *tag)
{
put_tag(pb, tag);
put_le32(pb, 0);
return url_ftell(pb);
}
void end_tag(ByteIOContext *pb, offset_t start)
{
offset_t pos;
pos = url_ftell(pb);
url_fseek(pb, start - 4, SEEK_SET);
put_le32(pb, (UINT32)(pos - start));
url_fseek(pb, pos, SEEK_SET);
}
/* Note: when encoding, the first matching tag is used, so order is
important if multiple tags possible for a given codec. */
const CodecTag codec_bmp_tags[] = {
{ CODEC_ID_H263, MKTAG('H', '2', '6', '3') },
{ CODEC_ID_H263P, MKTAG('H', '2', '6', '3') },
{ CODEC_ID_H263I, MKTAG('I', '2', '6', '3') }, /* intel h263 */
{ CODEC_ID_MJPEG, MKTAG('M', 'J', 'P', 'G') },
{ CODEC_ID_MPEG4, MKTAG('D', 'I', 'V', 'X'), .invalid_asf = 1 },
{ CODEC_ID_MPEG4, MKTAG('d', 'i', 'v', 'x'), .invalid_asf = 1 },
{ CODEC_ID_MPEG4, MKTAG('D', 'X', '5', '0'), .invalid_asf = 1 },
{ CODEC_ID_MPEG4, MKTAG('X', 'V', 'I', 'D'), .invalid_asf = 1 },
{ CODEC_ID_MPEG4, MKTAG('x', 'v', 'i', 'd'), .invalid_asf = 1 },
{ CODEC_ID_MPEG4, MKTAG('m', 'p', '4', 's'), .invalid_asf = 1 },
{ CODEC_ID_MPEG4, MKTAG('M', 'P', '4', 'S') },
{ CODEC_ID_MPEG4, MKTAG('M', '4', 'S', '2') },
{ CODEC_ID_MPEG4, MKTAG('m', '4', 's', '2') },
{ CODEC_ID_MPEG4, MKTAG(0x04, 0, 0, 0) }, /* some broken avi use this */
{ CODEC_ID_MSMPEG4V3, MKTAG('D', 'I', 'V', '3'), .invalid_asf = 1 }, /* default signature when using MSMPEG4 */
{ CODEC_ID_MSMPEG4V3, MKTAG('d', 'i', 'v', '3'), .invalid_asf = 1 },
{ CODEC_ID_MSMPEG4V3, MKTAG('M', 'P', '4', '3') },
{ CODEC_ID_MSMPEG4V2, MKTAG('M', 'P', '4', '2') },
{ CODEC_ID_MSMPEG4V1, MKTAG('M', 'P', 'G', '4') },
{ CODEC_ID_WMV1, MKTAG('W', 'M', 'V', '1') },
{ CODEC_ID_DVVIDEO, MKTAG('d', 'v', 's', 'l') },
{ CODEC_ID_DVVIDEO, MKTAG('d', 'v', 's', 'd') },
{ CODEC_ID_DVVIDEO, MKTAG('D', 'V', 'S', 'D') },
{ CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'h', 'd') },
{ CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', 'g', '1') },
{ CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', 'g', '2') },
{ CODEC_ID_MPEG1VIDEO, MKTAG('P', 'I', 'M', '1') },
{ CODEC_ID_MJPEG, MKTAG('M', 'J', 'P', 'G') },
{ 0, 0 },
};
unsigned int codec_get_tag(const CodecTag *tags, int id)
{
while (tags->id != 0) {
if (tags->id == id)
return tags->tag;
tags++;
}
return 0;
}
static unsigned int codec_get_asf_tag(const CodecTag *tags, int id)
{
while (tags->id != 0) {
if (!tags->invalid_asf && tags->id == id)
return tags->tag;
tags++;
}
return 0;
}
int codec_get_id(const CodecTag *tags, unsigned int tag)
{
while (tags->id != 0) {
if (tags->tag == tag)
return tags->id;
tags++;
}
return 0;
}
unsigned int codec_get_bmp_tag(int id)
{
return codec_get_tag(codec_bmp_tags, id);
}
/* BITMAPINFOHEADER header */
void put_bmp_header(ByteIOContext *pb, AVCodecContext *enc, const CodecTag *tags, int for_asf)
{
put_le32(pb, 40); /* size */
put_le32(pb, enc->width);
put_le32(pb, enc->height);
put_le16(pb, 1); /* planes */
put_le16(pb, 24); /* depth */
/* compression type */
put_le32(pb, for_asf ? codec_get_asf_tag(tags, enc->codec_id) : codec_get_tag(tags, enc->codec_id));
put_le32(pb, enc->width * enc->height * 3);
put_le32(pb, 0);
put_le32(pb, 0);
put_le32(pb, 0);
put_le32(pb, 0);
}
static void parse_specific_params(AVCodecContext *stream, int *au_byterate, int *au_ssize, int *au_scale)
{
switch(stream->codec_id) {
case CODEC_ID_PCM_S16LE:
*au_scale = *au_ssize = 2*stream->channels;
*au_byterate = *au_ssize * stream->sample_rate;
break;
case CODEC_ID_PCM_U8:
case CODEC_ID_PCM_ALAW:
case CODEC_ID_PCM_MULAW:
*au_scale = *au_ssize = stream->channels;
*au_byterate = *au_ssize * stream->sample_rate;
break;
case CODEC_ID_MP2:
*au_ssize = 1;
*au_scale = 1;
*au_byterate = stream->bit_rate / 8;
case CODEC_ID_MP3LAME:
*au_ssize = 1;
*au_scale = 1;
*au_byterate = stream->bit_rate / 8;
default:
*au_ssize = 1;
*au_scale = 1;
*au_byterate = stream->bit_rate / 8;
break;
}
}
static int avi_write_header(AVFormatContext *s)
{
AVIContext *avi = s->priv_data;
ByteIOContext *pb = &s->pb;
int bitrate, n, i, nb_frames, au_byterate, au_ssize, au_scale;
AVCodecContext *stream, *video_enc;
offset_t list1, list2, strh, strf;
put_tag(pb, "RIFF");
put_le32(pb, 0); /* file length */
put_tag(pb, "AVI ");
/* header list */
list1 = start_tag(pb, "LIST");
put_tag(pb, "hdrl");
/* avi header */
put_tag(pb, "avih");
put_le32(pb, 14 * 4);
bitrate = 0;
video_enc = NULL;
for(n=0;n<s->nb_streams;n++) {
stream = &s->streams[n]->codec;
bitrate += stream->bit_rate;
if (stream->codec_type == CODEC_TYPE_VIDEO)
video_enc = stream;
}
if (!video_enc) {
av_free(avi);
return -1;
}
nb_frames = 0;
put_le32(pb, (UINT32)(INT64_C(1000000) * FRAME_RATE_BASE / video_enc->frame_rate));
put_le32(pb, bitrate / 8); /* XXX: not quite exact */
put_le32(pb, 0); /* padding */
put_le32(pb, AVIF_TRUSTCKTYPE | AVIF_HASINDEX | AVIF_ISINTERLEAVED); /* flags */
avi->frames_hdr_all = url_ftell(pb); /* remember this offset to fill later */
put_le32(pb, nb_frames); /* nb frames, filled later */
put_le32(pb, 0); /* initial frame */
put_le32(pb, s->nb_streams); /* nb streams */
put_le32(pb, 1024 * 1024); /* suggested buffer size */
put_le32(pb, video_enc->width);
put_le32(pb, video_enc->height);
put_le32(pb, 0); /* reserved */
put_le32(pb, 0); /* reserved */
put_le32(pb, 0); /* reserved */
put_le32(pb, 0); /* reserved */
/* stream list */
for(i=0;i<n;i++) {
list2 = start_tag(pb, "LIST");
put_tag(pb, "strl");
stream = &s->streams[i]->codec;
/* stream generic header */
strh = start_tag(pb, "strh");
switch(stream->codec_type) {
case CODEC_TYPE_VIDEO:
put_tag(pb, "vids");
put_le32(pb, codec_get_bmp_tag(stream->codec_id));
put_le32(pb, 0); /* flags */
put_le16(pb, 0); /* priority */
put_le16(pb, 0); /* language */
put_le32(pb, 0); /* initial frame */
put_le32(pb, 1000); /* scale */
put_le32(pb, (1000 * stream->frame_rate) / FRAME_RATE_BASE); /* rate */
put_le32(pb, 0); /* start */
avi->frames_hdr_strm[i] = url_ftell(pb); /* remember this offset to fill later */
put_le32(pb, nb_frames); /* length, XXX: fill later */
put_le32(pb, 1024 * 1024); /* suggested buffer size */
put_le32(pb, -1); /* quality */
put_le32(pb, stream->width * stream->height * 3); /* sample size */
put_le16(pb, 0);
put_le16(pb, 0);
put_le16(pb, stream->width);
put_le16(pb, stream->height);
break;
case CODEC_TYPE_AUDIO:
put_tag(pb, "auds");
put_le32(pb, 1); /* tag */
put_le32(pb, 0); /* flags */
put_le16(pb, 0); /* priority */
put_le16(pb, 0); /* language */
put_le32(pb, 0); /* initial frame */
parse_specific_params(stream, &au_byterate, &au_ssize, &au_scale);
put_le32(pb, au_scale); /* scale */
put_le32(pb, au_byterate); /* rate */
put_le32(pb, 0); /* start */
avi->frames_hdr_strm[i] = url_ftell(pb); /* remember this offset to fill later */
put_le32(pb, 0); /* length, XXX: filled later */
put_le32(pb, 12 * 1024); /* suggested buffer size */
put_le32(pb, -1); /* quality */
put_le32(pb, au_ssize); /* sample size */
put_le32(pb, 0);
put_le32(pb, 0);
break;
default:
av_abort();
}
end_tag(pb, strh);
strf = start_tag(pb, "strf");
switch(stream->codec_type) {
case CODEC_TYPE_VIDEO:
put_bmp_header(pb, stream, codec_bmp_tags, 0);
break;
case CODEC_TYPE_AUDIO:
if (put_wav_header(pb, stream) < 0) {
av_free(avi);
return -1;
}
break;
default:
av_abort();
}
end_tag(pb, strf);
end_tag(pb, list2);
}
end_tag(pb, list1);
avi->movi_list = start_tag(pb, "LIST");
avi->first = NULL;
avi->last = NULL;
put_tag(pb, "movi");
put_flush_packet(pb);
return 0;
}
static int avi_write_packet(AVFormatContext *s, int stream_index,
UINT8 *buf, int size, int force_pts)
{
AVIContext *avi = s->priv_data;
ByteIOContext *pb = &s->pb;
AVIIndex *idx;
unsigned char tag[5];
unsigned int flags;
AVCodecContext *enc;
enc = &s->streams[stream_index]->codec;
tag[0] = '0';
tag[1] = '0' + stream_index;
if (enc->codec_type == CODEC_TYPE_VIDEO) {
tag[2] = 'd';
tag[3] = 'c';
flags = enc->key_frame ? 0x10 : 0x00;
} else {
tag[2] = 'w';
tag[3] = 'b';
flags = 0x10;
}
if (enc->codec_type == CODEC_TYPE_AUDIO)
avi->audio_strm_length[stream_index] += size;
if (!url_is_streamed(&s->pb)) {
idx = av_malloc(sizeof(AVIIndex));
memcpy(idx->tag, tag, 4);
idx->flags = flags;
idx->pos = url_ftell(pb) - avi->movi_list;
idx->len = size;
idx->next = NULL;
if (!avi->last)
avi->first = idx;
else
avi->last->next = idx;
avi->last = idx;
}
put_buffer(pb, tag, 4);
put_le32(pb, size);
put_buffer(pb, buf, size);
if (size & 1)
put_byte(pb, 0);
put_flush_packet(pb);
return 0;
}
static int avi_write_trailer(AVFormatContext *s)
{
ByteIOContext *pb = &s->pb;
AVIContext *avi = s->priv_data;
offset_t file_size, idx_chunk;
int n, nb_frames, au_byterate, au_ssize, au_scale;
AVCodecContext *stream;
AVIIndex *idx;
if (!url_is_streamed(&s->pb)) {
end_tag(pb, avi->movi_list);
idx_chunk = start_tag(pb, "idx1");
idx = avi->first;
while (idx != NULL) {
put_buffer(pb, idx->tag, 4);
put_le32(pb, idx->flags);
put_le32(pb, idx->pos);
put_le32(pb, idx->len);
idx = idx->next;
}
end_tag(pb, idx_chunk);
/* update file size */
file_size = url_ftell(pb);
url_fseek(pb, 4, SEEK_SET);
put_le32(pb, (UINT32)(file_size - 8));
/* Fill in frame/sample counters */
nb_frames = 0;
for(n=0;n<s->nb_streams;n++) {
if (avi->frames_hdr_strm[n] != 0) {
stream = &s->streams[n]->codec;
url_fseek(pb, avi->frames_hdr_strm[n], SEEK_SET);
if (stream->codec_type == CODEC_TYPE_VIDEO) {
put_le32(pb, stream->frame_number);
if (nb_frames < stream->frame_number)
nb_frames = stream->frame_number;
} else {
if (stream->codec_id == CODEC_ID_MP2 || stream->codec_id == CODEC_ID_MP3LAME) {
put_le32(pb, stream->frame_number);
nb_frames += stream->frame_number;
} else {
parse_specific_params(stream, &au_byterate, &au_ssize, &au_scale);
put_le32(pb, avi->audio_strm_length[n] / au_ssize);
}
}
}
}
if (avi->frames_hdr_all != 0) {
url_fseek(pb, avi->frames_hdr_all, SEEK_SET);
put_le32(pb, nb_frames);
}
url_fseek(pb, file_size, SEEK_SET);
}
put_flush_packet(pb);
return 0;
}
static AVOutputFormat avi_oformat = {
"avi",
"avi format",
"video/x-msvideo",
"avi",
sizeof(AVIContext),
CODEC_ID_MP2,
CODEC_ID_MSMPEG4V3,
avi_write_header,
avi_write_packet,
avi_write_trailer,
};
int avienc_init(void)
{
av_register_output_format(&avi_oformat);
return 0;
}

156
libavformat/avio.c Normal file
View File

@@ -0,0 +1,156 @@
/*
* Unbuffered io for ffmpeg system
* Copyright (c) 2001 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"
URLProtocol *first_protocol = NULL;
int register_protocol(URLProtocol *protocol)
{
URLProtocol **p;
p = &first_protocol;
while (*p != NULL) p = &(*p)->next;
*p = protocol;
protocol->next = NULL;
return 0;
}
int url_open(URLContext **puc, const char *filename, int flags)
{
URLContext *uc;
URLProtocol *up;
const char *p;
char proto_str[128], *q;
int err;
p = filename;
q = proto_str;
while (*p != '\0' && *p != ':') {
if ((q - proto_str) < sizeof(proto_str) - 1)
*q++ = *p;
p++;
}
/* if the protocol has length 1, we consider it is a dos drive */
if (*p == '\0' || (q - proto_str) <= 1) {
strcpy(proto_str, "file");
} else {
*q = '\0';
}
up = first_protocol;
while (up != NULL) {
if (!strcmp(proto_str, up->name))
goto found;
up = up->next;
}
err = -ENOENT;
goto fail;
found:
uc = av_malloc(sizeof(URLContext));
if (!uc) {
err = -ENOMEM;
goto fail;
}
uc->prot = up;
uc->flags = flags;
uc->is_streamed = 0; /* default = not streamed */
uc->max_packet_size = 0; /* default: stream file */
err = up->url_open(uc, filename, flags);
if (err < 0) {
av_free(uc);
*puc = NULL;
return err;
}
*puc = uc;
return 0;
fail:
*puc = NULL;
return err;
}
int url_read(URLContext *h, unsigned char *buf, int size)
{
int ret;
if (h->flags & URL_WRONLY)
return -EIO;
ret = h->prot->url_read(h, buf, size);
return ret;
}
int url_write(URLContext *h, unsigned char *buf, int size)
{
int ret;
if (!(h->flags & (URL_WRONLY | URL_RDWR)))
return -EIO;
/* avoid sending too big packets */
if (h->max_packet_size && size > h->max_packet_size)
return -EIO;
ret = h->prot->url_write(h, buf, size);
return ret;
}
offset_t url_seek(URLContext *h, offset_t pos, int whence)
{
offset_t ret;
if (!h->prot->url_seek)
return -EPIPE;
ret = h->prot->url_seek(h, pos, whence);
return ret;
}
int url_close(URLContext *h)
{
int ret;
ret = h->prot->url_close(h);
av_free(h);
return ret;
}
int url_exist(const char *filename)
{
URLContext *h;
if (url_open(&h, filename, URL_RDONLY) < 0)
return 0;
url_close(h);
return 1;
}
offset_t url_filesize(URLContext *h)
{
offset_t pos, size;
pos = url_seek(h, 0, SEEK_CUR);
size = url_seek(h, 0, SEEK_END);
url_seek(h, pos, SEEK_SET);
return size;
}
/*
* Return the maximum packet size associated to packetized file
* handle. If the file is not packetized (stream like http or file on
* disk), then 0 is returned.
*
* @param h file handle
* @return maximum packet size in bytes
*/
int url_get_max_packet_size(URLContext *h)
{
return h->max_packet_size;
}

153
libavformat/avio.h Normal file
View File

@@ -0,0 +1,153 @@
#ifndef AVIO_H
#define AVIO_H
/* output byte stream handling */
typedef INT64 offset_t;
/* unbuffered I/O */
struct URLContext {
struct URLProtocol *prot;
int flags;
int is_streamed; /* true if streamed (no seek possible), default = false */
int max_packet_size; /* if non zero, the stream is packetized with this max packet size */
void *priv_data;
};
typedef struct URLContext URLContext;
typedef struct URLPollEntry {
URLContext *handle;
int events;
int revents;
} URLPollEntry;
#define URL_RDONLY 0
#define URL_WRONLY 1
#define URL_RDWR 2
int url_open(URLContext **h, const char *filename, int flags);
int url_read(URLContext *h, unsigned char *buf, int size);
int url_write(URLContext *h, unsigned char *buf, int size);
offset_t url_seek(URLContext *h, offset_t pos, int whence);
int url_close(URLContext *h);
int url_exist(const char *filename);
offset_t url_filesize(URLContext *h);
int url_get_max_packet_size(URLContext *h);
/* not implemented */
int url_poll(URLPollEntry *poll_table, int n, int timeout);
typedef struct URLProtocol {
const char *name;
int (*url_open)(URLContext *h, const char *filename, int flags);
int (*url_read)(URLContext *h, unsigned char *buf, int size);
int (*url_write)(URLContext *h, unsigned char *buf, int size);
offset_t (*url_seek)(URLContext *h, offset_t pos, int whence);
int (*url_close)(URLContext *h);
struct URLProtocol *next;
} URLProtocol;
extern URLProtocol *first_protocol;
int register_protocol(URLProtocol *protocol);
typedef struct {
unsigned char *buffer;
int buffer_size;
unsigned char *buf_ptr, *buf_end;
void *opaque;
int (*read_packet)(void *opaque, UINT8 *buf, int buf_size);
void (*write_packet)(void *opaque, UINT8 *buf, int buf_size);
int (*seek)(void *opaque, offset_t offset, int whence);
offset_t pos; /* position in the file of the current buffer */
int must_flush; /* true if the next seek should flush */
int eof_reached; /* true if eof reached */
int write_flag; /* true if open for writing */
int is_streamed;
int max_packet_size;
} ByteIOContext;
int init_put_byte(ByteIOContext *s,
unsigned char *buffer,
int buffer_size,
int write_flag,
void *opaque,
int (*read_packet)(void *opaque, UINT8 *buf, int buf_size),
void (*write_packet)(void *opaque, UINT8 *buf, int buf_size),
int (*seek)(void *opaque, offset_t offset, int whence));
void put_byte(ByteIOContext *s, int b);
void put_buffer(ByteIOContext *s, const unsigned char *buf, int size);
void put_le64(ByteIOContext *s, UINT64 val);
void put_be64(ByteIOContext *s, UINT64 val);
void put_le32(ByteIOContext *s, unsigned int val);
void put_be32(ByteIOContext *s, unsigned int val);
void put_le16(ByteIOContext *s, unsigned int val);
void put_be16(ByteIOContext *s, unsigned int val);
void put_tag(ByteIOContext *s, const char *tag);
void put_be64_double(ByteIOContext *s, double val);
void put_strz(ByteIOContext *s, const char *buf);
offset_t url_fseek(ByteIOContext *s, offset_t offset, int whence);
void url_fskip(ByteIOContext *s, offset_t offset);
offset_t url_ftell(ByteIOContext *s);
int url_feof(ByteIOContext *s);
#define URL_EOF (-1)
int url_fgetc(ByteIOContext *s);
int url_fprintf(ByteIOContext *s, const char *fmt, ...);
char *url_fgets(ByteIOContext *s, char *buf, int buf_size);
void put_flush_packet(ByteIOContext *s);
int get_buffer(ByteIOContext *s, unsigned char *buf, int size);
int get_byte(ByteIOContext *s);
unsigned int get_le32(ByteIOContext *s);
UINT64 get_le64(ByteIOContext *s);
unsigned int get_le16(ByteIOContext *s);
double get_be64_double(ByteIOContext *s);
char *get_strz(ByteIOContext *s, char *buf, int maxlen);
unsigned int get_be16(ByteIOContext *s);
unsigned int get_be32(ByteIOContext *s);
UINT64 get_be64(ByteIOContext *s);
static inline int url_is_streamed(ByteIOContext *s)
{
return s->is_streamed;
}
int url_fdopen(ByteIOContext *s, URLContext *h);
int url_setbufsize(ByteIOContext *s, int buf_size);
int url_fopen(ByteIOContext *s, const char *filename, int flags);
int url_fclose(ByteIOContext *s);
URLContext *url_fileno(ByteIOContext *s);
int url_fget_max_packet_size(ByteIOContext *s);
int url_open_buf(ByteIOContext *s, UINT8 *buf, int buf_size, int flags);
int url_close_buf(ByteIOContext *s);
int url_open_dyn_buf(ByteIOContext *s);
int url_open_dyn_packet_buf(ByteIOContext *s, int max_packet_size);
int url_close_dyn_buf(ByteIOContext *s, UINT8 **pbuffer);
/* file.c */
extern URLProtocol file_protocol;
extern URLProtocol pipe_protocol;
/* udp.c */
extern URLProtocol udp_protocol;
int udp_set_remote_url(URLContext *h, const char *uri);
int udp_get_local_port(URLContext *h);
int udp_get_file_handle(URLContext *h);
/* tcp.c */
extern URLProtocol tcp_protocol;
/* http.c */
extern URLProtocol http_protocol;
#endif

687
libavformat/aviobuf.c Normal file
View File

@@ -0,0 +1,687 @@
/*
* Buffered I/O for ffmpeg system
* Copyright (c) 2000,2001 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"
#include <stdarg.h>
#define IO_BUFFER_SIZE 32768
int init_put_byte(ByteIOContext *s,
unsigned char *buffer,
int buffer_size,
int write_flag,
void *opaque,
int (*read_packet)(void *opaque, UINT8 *buf, int buf_size),
void (*write_packet)(void *opaque, UINT8 *buf, int buf_size),
int (*seek)(void *opaque, offset_t offset, int whence))
{
s->buffer = buffer;
s->buffer_size = buffer_size;
s->buf_ptr = buffer;
s->write_flag = write_flag;
if (!s->write_flag)
s->buf_end = buffer;
else
s->buf_end = buffer + buffer_size;
s->opaque = opaque;
s->write_packet = write_packet;
s->read_packet = read_packet;
s->seek = seek;
s->pos = 0;
s->must_flush = 0;
s->eof_reached = 0;
s->is_streamed = 0;
s->max_packet_size = 0;
return 0;
}
static void flush_buffer(ByteIOContext *s)
{
if (s->buf_ptr > s->buffer) {
if (s->write_packet)
s->write_packet(s->opaque, s->buffer, s->buf_ptr - s->buffer);
s->pos += s->buf_ptr - s->buffer;
}
s->buf_ptr = s->buffer;
}
void put_byte(ByteIOContext *s, int b)
{
*(s->buf_ptr)++ = b;
if (s->buf_ptr >= s->buf_end)
flush_buffer(s);
}
void put_buffer(ByteIOContext *s, const unsigned char *buf, int size)
{
int len;
while (size > 0) {
len = (s->buf_end - s->buf_ptr);
if (len > size)
len = size;
memcpy(s->buf_ptr, buf, len);
s->buf_ptr += len;
if (s->buf_ptr >= s->buf_end)
flush_buffer(s);
buf += len;
size -= len;
}
}
void put_flush_packet(ByteIOContext *s)
{
flush_buffer(s);
s->must_flush = 0;
}
offset_t url_fseek(ByteIOContext *s, offset_t offset, int whence)
{
offset_t offset1;
if (whence != SEEK_CUR && whence != SEEK_SET)
return -EINVAL;
if (s->write_flag) {
if (whence == SEEK_CUR) {
offset1 = s->pos + (s->buf_ptr - s->buffer);
if (offset == 0)
return offset1;
offset += offset1;
}
offset1 = offset - s->pos;
if (!s->must_flush &&
offset1 >= 0 && offset1 < (s->buf_end - s->buffer)) {
/* can do the seek inside the buffer */
s->buf_ptr = s->buffer + offset1;
} else {
if (!s->seek)
return -EPIPE;
flush_buffer(s);
s->must_flush = 1;
s->buf_ptr = s->buffer;
s->seek(s->opaque, offset, SEEK_SET);
s->pos = offset;
}
} else {
if (whence == SEEK_CUR) {
offset1 = s->pos - (s->buf_end - s->buffer) + (s->buf_ptr - s->buffer);
if (offset == 0)
return offset1;
offset += offset1;
}
offset1 = offset - (s->pos - (s->buf_end - s->buffer));
if (offset1 >= 0 && offset1 <= (s->buf_end - s->buffer)) {
/* can do the seek inside the buffer */
s->buf_ptr = s->buffer + offset1;
} else {
if (!s->seek)
return -EPIPE;
s->buf_ptr = s->buffer;
s->buf_end = s->buffer;
s->seek(s->opaque, offset, SEEK_SET);
s->pos = offset;
}
s->eof_reached = 0;
}
return offset;
}
void url_fskip(ByteIOContext *s, offset_t offset)
{
url_fseek(s, offset, SEEK_CUR);
}
offset_t url_ftell(ByteIOContext *s)
{
return url_fseek(s, 0, SEEK_CUR);
}
int url_feof(ByteIOContext *s)
{
return s->eof_reached;
}
void put_le32(ByteIOContext *s, unsigned int val)
{
put_byte(s, val);
put_byte(s, val >> 8);
put_byte(s, val >> 16);
put_byte(s, val >> 24);
}
void put_be32(ByteIOContext *s, unsigned int val)
{
put_byte(s, val >> 24);
put_byte(s, val >> 16);
put_byte(s, val >> 8);
put_byte(s, val);
}
/* IEEE format is assumed */
void put_be64_double(ByteIOContext *s, double val)
{
union {
double d;
UINT64 ull;
} u;
u.d = val;
put_be64(s, u.ull);
}
void put_strz(ByteIOContext *s, const char *str)
{
if (str)
put_buffer(s, (const unsigned char *) str, strlen(str) + 1);
else
put_byte(s, 0);
}
void put_le64(ByteIOContext *s, UINT64 val)
{
put_le32(s, (UINT32)(val & 0xffffffff));
put_le32(s, (UINT32)(val >> 32));
}
void put_be64(ByteIOContext *s, UINT64 val)
{
put_be32(s, (UINT32)(val >> 32));
put_be32(s, (UINT32)(val & 0xffffffff));
}
void put_le16(ByteIOContext *s, unsigned int val)
{
put_byte(s, val);
put_byte(s, val >> 8);
}
void put_be16(ByteIOContext *s, unsigned int val)
{
put_byte(s, val >> 8);
put_byte(s, val);
}
void put_tag(ByteIOContext *s, const char *tag)
{
while (*tag) {
put_byte(s, *tag++);
}
}
/* Input stream */
static void fill_buffer(ByteIOContext *s)
{
int len;
/* no need to do anything if EOF already reached */
if (s->eof_reached)
return;
len = s->read_packet(s->opaque, s->buffer, s->buffer_size);
if (len <= 0) {
/* do not modify buffer if EOF reached so that a seek back can
be done without rereading data */
s->eof_reached = 1;
} else {
s->pos += len;
s->buf_ptr = s->buffer;
s->buf_end = s->buffer + len;
}
}
/* NOTE: return 0 if EOF, so you cannot use it if EOF handling is
necessary */
/* XXX: put an inline version */
int get_byte(ByteIOContext *s)
{
if (s->buf_ptr < s->buf_end) {
return *s->buf_ptr++;
} else {
fill_buffer(s);
if (s->buf_ptr < s->buf_end)
return *s->buf_ptr++;
else
return 0;
}
}
/* NOTE: return URL_EOF (-1) if EOF */
int url_fgetc(ByteIOContext *s)
{
if (s->buf_ptr < s->buf_end) {
return *s->buf_ptr++;
} else {
fill_buffer(s);
if (s->buf_ptr < s->buf_end)
return *s->buf_ptr++;
else
return URL_EOF;
}
}
int get_buffer(ByteIOContext *s, unsigned char *buf, int size)
{
int len, size1;
size1 = size;
while (size > 0) {
len = s->buf_end - s->buf_ptr;
if (len > size)
len = size;
if (len == 0) {
fill_buffer(s);
len = s->buf_end - s->buf_ptr;
if (len == 0)
break;
} else {
memcpy(buf, s->buf_ptr, len);
buf += len;
s->buf_ptr += len;
size -= len;
}
}
return size1 - size;
}
unsigned int get_le16(ByteIOContext *s)
{
unsigned int val;
val = get_byte(s);
val |= get_byte(s) << 8;
return val;
}
unsigned int get_le32(ByteIOContext *s)
{
unsigned int val;
val = get_byte(s);
val |= get_byte(s) << 8;
val |= get_byte(s) << 16;
val |= get_byte(s) << 24;
return val;
}
UINT64 get_le64(ByteIOContext *s)
{
UINT64 val;
val = (UINT64)get_le32(s);
val |= (UINT64)get_le32(s) << 32;
return val;
}
unsigned int get_be16(ByteIOContext *s)
{
unsigned int val;
val = get_byte(s) << 8;
val |= get_byte(s);
return val;
}
unsigned int get_be32(ByteIOContext *s)
{
unsigned int val;
val = get_byte(s) << 24;
val |= get_byte(s) << 16;
val |= get_byte(s) << 8;
val |= get_byte(s);
return val;
}
double get_be64_double(ByteIOContext *s)
{
union {
double d;
UINT64 ull;
} u;
u.ull = get_be64(s);
return u.d;
}
char *get_strz(ByteIOContext *s, char *buf, int maxlen)
{
int i = 0;
char c;
while ((c = get_byte(s))) {
if (i < maxlen-1)
buf[i++] = c;
}
buf[i] = 0; /* Ensure null terminated, but may be truncated */
return buf;
}
UINT64 get_be64(ByteIOContext *s)
{
UINT64 val;
val = (UINT64)get_be32(s) << 32;
val |= (UINT64)get_be32(s);
return val;
}
/* link with avio functions */
void url_write_packet(void *opaque, UINT8 *buf, int buf_size)
{
URLContext *h = opaque;
url_write(h, buf, buf_size);
}
int url_read_packet(void *opaque, UINT8 *buf, int buf_size)
{
URLContext *h = opaque;
return url_read(h, buf, buf_size);
}
int url_seek_packet(void *opaque, INT64 offset, int whence)
{
URLContext *h = opaque;
url_seek(h, offset, whence);
return 0;
}
int url_fdopen(ByteIOContext *s, URLContext *h)
{
UINT8 *buffer;
int buffer_size, max_packet_size;
max_packet_size = url_get_max_packet_size(h);
if (max_packet_size) {
buffer_size = max_packet_size; /* no need to bufferize more than one packet */
} else {
buffer_size = IO_BUFFER_SIZE;
}
buffer = av_malloc(buffer_size);
if (!buffer)
return -ENOMEM;
if (init_put_byte(s, buffer, buffer_size,
(h->flags & URL_WRONLY) != 0, h,
url_read_packet, url_write_packet, url_seek_packet) < 0) {
av_free(buffer);
return -EIO;
}
s->is_streamed = h->is_streamed;
s->max_packet_size = max_packet_size;
return 0;
}
/* XXX: must be called before any I/O */
int url_setbufsize(ByteIOContext *s, int buf_size)
{
UINT8 *buffer;
buffer = av_malloc(buf_size);
if (!buffer)
return -ENOMEM;
av_free(s->buffer);
s->buffer = buffer;
s->buffer_size = buf_size;
s->buf_ptr = buffer;
if (!s->write_flag)
s->buf_end = buffer;
else
s->buf_end = buffer + buf_size;
return 0;
}
/* NOTE: when opened as read/write, the buffers are only used for
reading */
int url_fopen(ByteIOContext *s, const char *filename, int flags)
{
URLContext *h;
int err;
err = url_open(&h, filename, flags);
if (err < 0)
return err;
err = url_fdopen(s, h);
if (err < 0) {
url_close(h);
return err;
}
return 0;
}
int url_fclose(ByteIOContext *s)
{
URLContext *h = s->opaque;
av_free(s->buffer);
memset(s, 0, sizeof(ByteIOContext));
return url_close(h);
}
URLContext *url_fileno(ByteIOContext *s)
{
return s->opaque;
}
/* XXX: currently size is limited */
int url_fprintf(ByteIOContext *s, const char *fmt, ...)
{
va_list ap;
char buf[4096];
int ret;
va_start(ap, fmt);
ret = vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
put_buffer(s, buf, strlen(buf));
return ret;
}
/* note: unlike fgets, the EOL character is not returned and a whole
line is parsed. return NULL if first char read was EOF */
char *url_fgets(ByteIOContext *s, char *buf, int buf_size)
{
int c;
char *q;
c = url_fgetc(s);
if (c == EOF)
return NULL;
q = buf;
for(;;) {
if (c == EOF || c == '\n')
break;
if ((q - buf) < buf_size - 1)
*q++ = c;
c = url_fgetc(s);
}
if (buf_size > 0)
*q = '\0';
return buf;
}
/*
* Return the maximum packet size associated to packetized buffered file
* handle. If the file is not packetized (stream like http or file on
* disk), then 0 is returned.
*
* @param h buffered file handle
* @return maximum packet size in bytes
*/
int url_fget_max_packet_size(ByteIOContext *s)
{
return s->max_packet_size;
}
/* buffer handling */
int url_open_buf(ByteIOContext *s, UINT8 *buf, int buf_size, int flags)
{
return init_put_byte(s, buf, buf_size,
(flags & URL_WRONLY) != 0, NULL, NULL, NULL, NULL);
}
/* return the written or read size */
int url_close_buf(ByteIOContext *s)
{
put_flush_packet(s);
return s->buf_ptr - s->buffer;
}
/* output in a dynamic buffer */
typedef struct DynBuffer {
int pos, size, allocated_size;
UINT8 *buffer;
int io_buffer_size;
UINT8 io_buffer[1];
} DynBuffer;
static void dyn_buf_write(void *opaque, UINT8 *buf, int buf_size)
{
DynBuffer *d = opaque;
int new_size, new_allocated_size;
UINT8 *new_buffer;
/* reallocate buffer if needed */
new_size = d->pos + buf_size;
new_allocated_size = d->allocated_size;
while (new_size > new_allocated_size) {
if (!new_allocated_size)
new_allocated_size = new_size;
else
new_allocated_size = (new_allocated_size * 3) / 2 + 1;
}
if (new_allocated_size > d->allocated_size) {
new_buffer = av_malloc(new_allocated_size);
if (!new_buffer)
return;
memcpy(new_buffer, d->buffer, d->size);
av_free(d->buffer);
d->buffer = new_buffer;
d->allocated_size = new_allocated_size;
}
memcpy(d->buffer + d->pos, buf, buf_size);
d->pos = new_size;
if (d->pos > d->size)
d->size = d->pos;
}
static void dyn_packet_buf_write(void *opaque, UINT8 *buf, int buf_size)
{
unsigned char buf1[4];
/* packetized write: output the header */
buf1[0] = (buf_size >> 24);
buf1[1] = (buf_size >> 16);
buf1[2] = (buf_size >> 8);
buf1[3] = (buf_size);
dyn_buf_write(opaque, buf1, 4);
/* then the data */
dyn_buf_write(opaque, buf, buf_size);
}
static int dyn_buf_seek(void *opaque, offset_t offset, int whence)
{
DynBuffer *d = opaque;
if (whence == SEEK_CUR)
offset += d->pos;
else if (whence == SEEK_END)
offset += d->size;
if (offset < 0 || offset > 0x7fffffffLL)
return -1;
d->pos = offset;
return 0;
}
static int url_open_dyn_buf_internal(ByteIOContext *s, int max_packet_size)
{
DynBuffer *d;
int io_buffer_size, ret;
if (max_packet_size)
io_buffer_size = max_packet_size;
else
io_buffer_size = 1024;
d = av_malloc(sizeof(DynBuffer) + io_buffer_size);
if (!d)
return -1;
d->io_buffer_size = io_buffer_size;
d->buffer = NULL;
d->pos = 0;
d->size = 0;
d->allocated_size = 0;
ret = init_put_byte(s, d->io_buffer, io_buffer_size,
1, d, NULL,
max_packet_size ? dyn_packet_buf_write : dyn_buf_write,
max_packet_size ? NULL : dyn_buf_seek);
if (ret == 0) {
s->max_packet_size = max_packet_size;
}
return ret;
}
/*
* Open a write only memory stream.
*
* @param s new IO context
* @return zero if no error.
*/
int url_open_dyn_buf(ByteIOContext *s)
{
return url_open_dyn_buf_internal(s, 0);
}
/*
* Open a write only packetized memory stream with a maximum packet
* size of 'max_packet_size'. The stream is stored in a memory buffer
* with a big endian 4 byte header giving the packet size in bytes.
*
* @param s new IO context
* @param max_packet_size maximum packet size (must be > 0)
* @return zero if no error.
*/
int url_open_dyn_packet_buf(ByteIOContext *s, int max_packet_size)
{
if (max_packet_size <= 0)
return -1;
return url_open_dyn_buf_internal(s, max_packet_size);
}
/*
* Return the written size and a pointer to the buffer. The buffer
* must be freed with av_free().
* @param s IO context
* @param pointer to a byte buffer
* @return the length of the byte buffer
*/
int url_close_dyn_buf(ByteIOContext *s, UINT8 **pbuffer)
{
DynBuffer *d = s->opaque;
int size;
put_flush_packet(s);
*pbuffer = d->buffer;
size = d->size;
av_free(d);
return size;
}

25
libavformat/barpainet.c Normal file
View File

@@ -0,0 +1,25 @@
#include <stdlib.h>
#include <strings.h>
#include "barpainet.h"
int inet_aton (const char * str, struct in_addr * add) {
const char * pch = str;
unsigned int add1 = 0, add2 = 0, add3 = 0, add4 = 0;
add1 = atoi(pch);
pch = strpbrk(pch,".");
if (pch == 0 || ++pch == 0) goto done;
add2 = atoi(pch);
pch = strpbrk(pch,".");
if (pch == 0 || ++pch == 0) goto done;
add3 = atoi(pch);
pch = strpbrk(pch,".");
if (pch == 0 || ++pch == 0) goto done;
add4 = atoi(pch);
done:
add->s_addr=(add4<<24)+(add3<<16)+(add2<<8)+add1;
return 1;
}

23
libavformat/barpainet.h Normal file
View File

@@ -0,0 +1,23 @@
#ifndef BARPA_INET_H
#define BARPA_INET_H
#include "../config.h"
#ifdef CONFIG_BEOS_NETSERVER
# include <socket.h>
int inet_aton (const char * str, struct in_addr * add);
# define PF_INET AF_INET
# define SO_SNDBUF 0x40000001
/* fake */
struct ip_mreq {
struct in_addr imr_multiaddr; /* IP multicast address of group */
struct in_addr imr_interface; /* local IP address of interface */
};
#else
# include <arpa/inet.h>
#endif
#endif /* BARPA_INET_H */

449
libavformat/beosaudio.cpp Normal file
View File

@@ -0,0 +1,449 @@
/*
* BeOS audio play interface
* Copyright (c) 2000, 2001 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 <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include <Application.h>
#include <SoundPlayer.h>
extern "C" {
#include "avformat.h"
}
/* enable performance checks */
//#define PERF_CHECK
//const char *audio_device = "/dev/dsp";
const char *audio_device = "beosaudio:";
/* Pipes are 4k in BeOS IIRC */
#define AUDIO_BLOCK_SIZE 4096
//#define AUDIO_BLOCK_SIZE 2048
#define AUDIO_BLOCK_COUNT 8
#define AUDIO_BUFFER_SIZE (AUDIO_BLOCK_SIZE*AUDIO_BLOCK_COUNT)
/* pipes suck for realtime */
#define USE_RING_BUFFER 1
typedef struct {
int fd;
int sample_rate;
int channels;
int frame_size; /* in bytes ! */
CodecID codec_id;
int flip_left : 1;
UINT8 buffer[AUDIO_BUFFER_SIZE];
int buffer_ptr;
int pipefd; /* the other end of the pipe */
/* ring buffer */
sem_id input_sem;
int input_index;
sem_id output_sem;
int output_index;
int queued;
BSoundPlayer *player;
int has_quit; /* signal callbacks not to wait */
volatile bigtime_t starve_time;
} AudioData;
static thread_id main_thid;
static thread_id bapp_thid;
static int own_BApp_created = 0;
static int refcount = 0;
/* create the BApplication and Run() it */
static int32 bapp_thread(void *arg)
{
new BApplication("application/x-vnd.ffmpeg");
own_BApp_created = 1;
be_app->Run();
/* kill the process group */
// kill(0, SIGINT);
// kill(main_thid, SIGHUP);
return B_OK;
}
/* create the BApplication only if needed */
static void create_bapp_if_needed(void)
{
if (refcount++ == 0) {
/* needed by libmedia */
if (be_app == NULL) {
bapp_thid = spawn_thread(bapp_thread, "ffmpeg BApplication", B_NORMAL_PRIORITY, NULL);
resume_thread(bapp_thid);
while (!own_BApp_created)
snooze(50000);
}
}
}
static void destroy_bapp_if_needed(void)
{
if (--refcount == 0 && own_BApp_created) {
be_app->Lock();
be_app->Quit();
be_app = NULL;
}
}
/* called back by BSoundPlayer */
static void audioplay_callback(void *cookie, void *buffer, size_t bufferSize, const media_raw_audio_format &format)
{
AudioData *s;
size_t len, amount;
unsigned char *buf = (unsigned char *)buffer;
s = (AudioData *)cookie;
if (s->has_quit)
return;
while (bufferSize > 0) {
#ifdef PERF_CHECK
bigtime_t t;
t = system_time();
#endif
#ifdef USE_RING_BUFFER
len = MIN(AUDIO_BLOCK_SIZE, bufferSize);
if (acquire_sem_etc(s->output_sem, len, B_CAN_INTERRUPT, 0LL) < B_OK) {
s->has_quit = 1;
s->player->SetHasData(false);
return;
}
amount = MIN(len, (AUDIO_BUFFER_SIZE - s->output_index));
memcpy(buf, &s->buffer[s->output_index], amount);
s->output_index += amount;
if (s->output_index >= AUDIO_BUFFER_SIZE) {
s->output_index %= AUDIO_BUFFER_SIZE;
memcpy(buf + amount, &s->buffer[s->output_index], len - amount);
s->output_index += len-amount;
s->output_index %= AUDIO_BUFFER_SIZE;
}
release_sem_etc(s->input_sem, len, 0);
#else
len = read(s->pipefd, buf, bufferSize);
#endif
#ifdef PERF_CHECK
t = system_time() - t;
s->starve_time = MAX(s->starve_time, t);
#endif
#ifndef USE_RING_BUFFER
if (len < B_OK) {
puts("EPIPE");
s->player->SetHasData(false);
snooze(100000);
return;
}
if (len == 0) {
s->player->SetHasData(false);
snooze(100000);
return;
}
#endif
buf += len;
bufferSize -= len;
}
}
static int audio_open(AudioData *s, int is_output)
{
int p[2];
int ret;
media_raw_audio_format format;
if (!is_output)
return -EIO; /* not for now */
#ifdef USE_RING_BUFFER
s->input_sem = create_sem(AUDIO_BUFFER_SIZE, "ffmpeg_ringbuffer_input");
// s->input_sem = create_sem(AUDIO_BLOCK_SIZE, "ffmpeg_ringbuffer_input");
if (s->input_sem < B_OK)
return -EIO;
s->output_sem = create_sem(0, "ffmpeg_ringbuffer_output");
if (s->output_sem < B_OK) {
delete_sem(s->input_sem);
return -EIO;
}
s->input_index = 0;
s->output_index = 0;
s->queued = 0;
#else
ret = pipe(p);
if (ret < 0)
return -EIO;
s->fd = p[is_output?1:0];
s->pipefd = p[is_output?0:1];
if (s->fd < 0) {
perror(is_output?"audio out":"audio in");
return -EIO;
}
#endif
create_bapp_if_needed();
/* non blocking mode */
// fcntl(s->fd, F_SETFL, O_NONBLOCK);
// fcntl(s->pipefd, F_SETFL, O_NONBLOCK);
s->frame_size = AUDIO_BLOCK_SIZE;
format = media_raw_audio_format::wildcard;
format.format = media_raw_audio_format::B_AUDIO_SHORT;
format.byte_order = B_HOST_IS_LENDIAN ? B_MEDIA_LITTLE_ENDIAN : B_MEDIA_BIG_ENDIAN;
format.channel_count = s->channels;
format.buffer_size = s->frame_size;
format.frame_rate = s->sample_rate;
s->player = new BSoundPlayer(&format, "ffmpeg output", audioplay_callback);
if (s->player->InitCheck() != B_OK) {
delete s->player;
s->player = NULL;
#ifdef USE_RING_BUFFER
if (s->input_sem)
delete_sem(s->input_sem);
if (s->output_sem)
delete_sem(s->output_sem);
#else
close(s->fd);
close(s->pipefd);
#endif
return -EIO;
}
s->player->SetCookie(s);
s->player->SetVolume(1.0);
s->player->Start();
s->player->SetHasData(true);
/* bump up the priority (avoid realtime though) */
set_thread_priority(find_thread(NULL), B_DISPLAY_PRIORITY+1);
return 0;
}
static int audio_close(AudioData *s)
{
#ifdef USE_RING_BUFFER
if (s->input_sem)
delete_sem(s->input_sem);
if (s->output_sem)
delete_sem(s->output_sem);
#endif
s->has_quit = 1;
if (s->player) {
s->player->Stop();
}
if (s->player)
delete s->player;
#ifndef USE_RING_BUFFER
close(s->pipefd);
close(s->fd);
#endif
destroy_bapp_if_needed();
return 0;
}
/* sound output support */
static int audio_write_header(AVFormatContext *s1)
{
AudioData *s = (AudioData *)s1->priv_data;
AVStream *st;
int ret;
st = s1->streams[0];
s->sample_rate = st->codec.sample_rate;
s->channels = st->codec.channels;
ret = audio_open(s, 1);
if (ret < 0)
return -EIO;
return 0;
}
static int audio_write_packet(AVFormatContext *s1, int stream_index,
UINT8 *buf, int size, int force_pts)
{
AudioData *s = (AudioData *)s1->priv_data;
int len, ret;
#ifdef PERF_CHECK
bigtime_t t = s->starve_time;
s->starve_time = 0;
printf("starve_time: %lld \n", t);
#endif
#ifdef USE_RING_BUFFER
while (size > 0) {
int amount;
len = MIN(size, AUDIO_BLOCK_SIZE);
if (acquire_sem_etc(s->input_sem, len, B_CAN_INTERRUPT, 0LL) < B_OK)
return -EIO;
amount = MIN(len, (AUDIO_BUFFER_SIZE - s->input_index));
memcpy(&s->buffer[s->input_index], buf, amount);
s->input_index += amount;
if (s->input_index >= AUDIO_BUFFER_SIZE) {
s->input_index %= AUDIO_BUFFER_SIZE;
memcpy(&s->buffer[s->input_index], buf + amount, len - amount);
s->input_index += len - amount;
}
release_sem_etc(s->output_sem, len, 0);
buf += len;
size -= len;
}
#else
while (size > 0) {
len = AUDIO_BLOCK_SIZE - s->buffer_ptr;
if (len > size)
len = size;
memcpy(s->buffer + s->buffer_ptr, buf, len);
s->buffer_ptr += len;
if (s->buffer_ptr >= AUDIO_BLOCK_SIZE) {
for(;;) {
//snooze(1000);
ret = write(s->fd, s->buffer, AUDIO_BLOCK_SIZE);
if (ret != 0)
break;
if (ret < 0 && (errno != EAGAIN && errno != EINTR))
return -EIO;
}
s->buffer_ptr = 0;
}
buf += len;
size -= len;
}
#endif
return 0;
}
static int audio_write_trailer(AVFormatContext *s1)
{
AudioData *s = (AudioData *)s1->priv_data;
audio_close(s);
return 0;
}
/* grab support */
static int audio_read_header(AVFormatContext *s1, AVFormatParameters *ap)
{
AudioData *s = (AudioData *)s1->priv_data;
AVStream *st;
int ret;
if (!ap || ap->sample_rate <= 0 || ap->channels <= 0)
return -1;
st = av_new_stream(s1, 0);
if (!st) {
return -ENOMEM;
}
s->sample_rate = ap->sample_rate;
s->channels = ap->channels;
ret = audio_open(s, 0);
if (ret < 0) {
av_free(st);
return -EIO;
} else {
/* take real parameters */
st->codec.codec_type = CODEC_TYPE_AUDIO;
st->codec.codec_id = s->codec_id;
st->codec.sample_rate = s->sample_rate;
st->codec.channels = s->channels;
return 0;
}
}
static int audio_read_packet(AVFormatContext *s1, AVPacket *pkt)
{
AudioData *s = (AudioData *)s1->priv_data;
int ret;
if (av_new_packet(pkt, s->frame_size) < 0)
return -EIO;
for(;;) {
ret = read(s->fd, pkt->data, pkt->size);
if (ret > 0)
break;
if (ret == -1 && (errno == EAGAIN || errno == EINTR)) {
av_free_packet(pkt);
pkt->size = 0;
return 0;
}
if (!(ret == 0 || (ret == -1 && (errno == EAGAIN || errno == EINTR)))) {
av_free_packet(pkt);
return -EIO;
}
}
pkt->size = ret;
if (s->flip_left && s->channels == 2) {
int i;
short *p = (short *) pkt->data;
for (i = 0; i < ret; i += 4) {
*p = ~*p;
p += 2;
}
}
return 0;
}
static int audio_read_close(AVFormatContext *s1)
{
AudioData *s = (AudioData *)s1->priv_data;
audio_close(s);
return 0;
}
AVInputFormat audio_in_format = {
"audio_device",
"audio grab and output",
sizeof(AudioData),
NULL,
audio_read_header,
audio_read_packet,
audio_read_close,
NULL,
AVFMT_NOFILE,
};
AVOutputFormat audio_out_format = {
"audio_device",
"audio grab and output",
"",
"",
sizeof(AudioData),
#ifdef WORDS_BIGENDIAN
CODEC_ID_PCM_S16BE,
#else
CODEC_ID_PCM_S16LE,
#endif
CODEC_ID_NONE,
audio_write_header,
audio_write_packet,
audio_write_trailer,
AVFMT_NOFILE,
};
extern "C" {
int audio_init(void)
{
main_thid = find_thread(NULL);
av_register_input_format(&audio_in_format);
av_register_output_format(&audio_out_format);
return 0;
}
} // "C"

111
libavformat/crc.c Normal file
View File

@@ -0,0 +1,111 @@
/*
* CRC decoder (for codec/format testing)
* Copyright (c) 2002 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"
/* adler32.c -- compute the Adler-32 checksum of a data stream
* Copyright (C) 1995 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#define BASE 65521L /* largest prime smaller than 65536 */
#define NMAX 5552
/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
#define DO1(buf) {s1 += *buf++; s2 += s1;}
#define DO2(buf) DO1(buf); DO1(buf);
#define DO4(buf) DO2(buf); DO2(buf);
#define DO8(buf) DO4(buf); DO4(buf);
#define DO16(buf) DO8(buf); DO8(buf);
static UINT32 adler32(UINT32 adler, UINT8 *buf, unsigned int len)
{
unsigned long s1 = adler & 0xffff;
unsigned long s2 = (adler >> 16) & 0xffff;
int k;
if (buf == NULL) return 1L;
while (len > 0) {
k = len < NMAX ? len : NMAX;
len -= k;
while (k >= 16) {
DO16(buf);
k -= 16;
}
if (k != 0) do {
DO1(buf);
} while (--k);
s1 %= BASE;
s2 %= BASE;
}
return (s2 << 16) | s1;
}
typedef struct CRCState {
UINT32 crcval;
} CRCState;
static int crc_write_header(struct AVFormatContext *s)
{
CRCState *crc = s->priv_data;
/* init CRC */
crc->crcval = adler32(0, NULL, 0);
return 0;
}
static int crc_write_packet(struct AVFormatContext *s,
int stream_index,
unsigned char *buf, int size, int force_pts)
{
CRCState *crc = s->priv_data;
crc->crcval = adler32(crc->crcval, buf, size);
return 0;
}
static int crc_write_trailer(struct AVFormatContext *s)
{
CRCState *crc = s->priv_data;
char buf[64];
snprintf(buf, sizeof(buf), "CRC=%08x\n", crc->crcval);
put_buffer(&s->pb, buf, strlen(buf));
put_flush_packet(&s->pb);
return 0;
}
static AVOutputFormat crc_format = {
"crc",
"crc testing format",
NULL,
"",
sizeof(CRCState),
CODEC_ID_PCM_S16LE,
CODEC_ID_RAWVIDEO,
crc_write_header,
crc_write_packet,
crc_write_trailer,
};
int crc_init(void)
{
av_register_output_format(&crc_format);
return 0;
}

110
libavformat/cutils.c Normal file
View File

@@ -0,0 +1,110 @@
/*
* Various simple utilities for ffmpeg system
* Copyright (c) 2000, 2001, 2002 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"
#include <ctype.h>
#if !defined(CONFIG_NOCUTILS)
/**
* Return TRUE if val is a prefix of str. If it returns TRUE, ptr is
* set to the next character in 'str' after the prefix.
*
* @param str input string
* @param val prefix to test
* @param ptr updated after the prefix in str in there is a match
* @return TRUE if there is a match
*/
int strstart(const char *str, const char *val, const char **ptr)
{
const char *p, *q;
p = str;
q = val;
while (*q != '\0') {
if (*p != *q)
return 0;
p++;
q++;
}
if (ptr)
*ptr = p;
return 1;
}
/**
* Return TRUE if val is a prefix of str (case independent). If it
* returns TRUE, ptr is set to the next character in 'str' after the
* prefix.
*
* @param str input string
* @param val prefix to test
* @param ptr updated after the prefix in str in there is a match
* @return TRUE if there is a match */
int stristart(const char *str, const char *val, const char **ptr)
{
const char *p, *q;
p = str;
q = val;
while (*q != '\0') {
if (toupper(*(unsigned char *)p) != toupper(*(unsigned char *)q))
return 0;
p++;
q++;
}
if (ptr)
*ptr = p;
return 1;
}
/**
* Copy the string str to buf. If str length is bigger than buf_size -
* 1 then it is clamped to buf_size - 1.
* NOTE: this function does what strncpy should have done to be
* useful. NEVER use strncpy.
*
* @param buf destination buffer
* @param buf_size size of destination buffer
* @param str source string
*/
void pstrcpy(char *buf, int buf_size, const char *str)
{
int c;
char *q = buf;
if (buf_size <= 0)
return;
for(;;) {
c = *str++;
if (c == 0 || q >= buf + buf_size - 1)
break;
*q++ = c;
}
*q = '\0';
}
/* strcat and truncate. */
char *pstrcat(char *buf, int buf_size, const char *s)
{
int len;
len = strlen(buf);
if (len < buf_size)
pstrcpy(buf + len, buf_size - len, s);
return buf;
}
#endif

134
libavformat/dv.c Normal file
View File

@@ -0,0 +1,134 @@
/*
* Raw DV format
* Copyright (c) 2002 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"
#define NTSC_FRAME_SIZE 120000
#define PAL_FRAME_SIZE 144000
typedef struct DVDemuxContext {
int is_audio;
} DVDemuxContext;
/* raw input */
static int dv_read_header(AVFormatContext *s,
AVFormatParameters *ap)
{
AVStream *vst, *ast;
vst = av_new_stream(s, 0);
if (!vst)
return AVERROR_NOMEM;
vst->codec.codec_type = CODEC_TYPE_VIDEO;
vst->codec.codec_id = CODEC_ID_DVVIDEO;
#if 0
ast = av_new_stream(s, 1);
if (!ast)
return AVERROR_NOMEM;
ast->codec.codec_type = CODEC_TYPE_AUDIO;
ast->codec.codec_id = CODEC_ID_DVAUDIO;
#endif
return 0;
}
/* XXX: build fake audio stream when DV audio decoder will be finished */
static int dv_read_packet(AVFormatContext *s, AVPacket *pkt)
{
int ret, size, dsf;
uint8_t buf[4];
ret = get_buffer(&s->pb, buf, 4);
if (ret <= 0)
return -EIO;
dsf = buf[3] & 0x80;
if (!dsf)
size = NTSC_FRAME_SIZE;
else
size = PAL_FRAME_SIZE;
if (av_new_packet(pkt, size) < 0)
return -EIO;
pkt->stream_index = 0;
memcpy(pkt->data, buf, 4);
ret = get_buffer(&s->pb, pkt->data + 4, size - 4);
if (ret <= 0) {
av_free_packet(pkt);
return -EIO;
}
return ret;
}
static int dv_read_close(AVFormatContext *s)
{
return 0;
}
static AVInputFormat dv_iformat = {
"dv",
"DV video format",
sizeof(DVDemuxContext),
NULL,
dv_read_header,
dv_read_packet,
dv_read_close,
.extensions = "dv",
};
#if 0
int dv_write_header(struct AVFormatContext *s)
{
return 0;
}
int dv_write_packet(struct AVFormatContext *s,
int stream_index,
unsigned char *buf, int size, int force_pts)
{
put_buffer(&s->pb, buf, size);
put_flush_packet(&s->pb);
return 0;
}
int dv_write_trailer(struct AVFormatContext *s)
{
return 0;
}
AVOutputFormat dv_oformat = {
"dv",
"DV video format",
NULL,
"dv",
0,
CODEC_ID_DVVIDEO,
CODEC_ID_DVAUDIO,
dv_write_header,
dv_write_packet,
dv_write_trailer,
};
#endif
int dv_init(void)
{
av_register_input_format(&dv_iformat);
// av_register_output_format(&dv_oformat);
return 0;
}

684
libavformat/ffm.c Normal file
View File

@@ -0,0 +1,684 @@
/*
* FFM (ffserver live feed) encoder and decoder
* Copyright (c) 2001 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"
#include <unistd.h>
/* The FFM file is made of blocks of fixed size */
#define FFM_HEADER_SIZE 14
#define PACKET_ID 0x666d
/* each packet contains frames (which can span several packets */
#define FRAME_HEADER_SIZE 8
#define FLAG_KEY_FRAME 0x01
typedef struct FFMStream {
INT64 pts;
} FFMStream;
enum {
READ_HEADER,
READ_DATA,
};
typedef struct FFMContext {
/* only reading mode */
offset_t write_index, file_size;
int read_state;
UINT8 header[FRAME_HEADER_SIZE];
/* read and write */
int first_packet; /* true if first packet, needed to set the discontinuity tag */
int packet_size;
int frame_offset;
INT64 pts;
UINT8 *packet_ptr, *packet_end;
UINT8 packet[FFM_PACKET_SIZE];
} FFMContext;
/* disable pts hack for testing */
int ffm_nopts = 0;
static void flush_packet(AVFormatContext *s)
{
FFMContext *ffm = s->priv_data;
int fill_size, h;
ByteIOContext *pb = &s->pb;
fill_size = ffm->packet_end - ffm->packet_ptr;
memset(ffm->packet_ptr, 0, fill_size);
/* put header */
put_be16(pb, PACKET_ID);
put_be16(pb, fill_size);
put_be64(pb, ffm->pts);
h = ffm->frame_offset;
if (ffm->first_packet)
h |= 0x8000;
put_be16(pb, h);
put_buffer(pb, ffm->packet, ffm->packet_end - ffm->packet);
/* prepare next packet */
ffm->frame_offset = 0; /* no key frame */
ffm->pts = 0; /* no pts */
ffm->packet_ptr = ffm->packet;
ffm->first_packet = 0;
}
/* 'first' is true if first data of a frame */
static void ffm_write_data(AVFormatContext *s,
UINT8 *buf, int size,
INT64 pts, int first)
{
FFMContext *ffm = s->priv_data;
int len;
if (first && ffm->frame_offset == 0)
ffm->frame_offset = ffm->packet_ptr - ffm->packet + FFM_HEADER_SIZE;
if (first && ffm->pts == 0)
ffm->pts = pts;
/* write as many packets as needed */
while (size > 0) {
len = ffm->packet_end - ffm->packet_ptr;
if (len > size)
len = size;
memcpy(ffm->packet_ptr, buf, len);
ffm->packet_ptr += len;
buf += len;
size -= len;
if (ffm->packet_ptr >= ffm->packet_end) {
/* special case : no pts in packet : we leave the current one */
if (ffm->pts == 0)
ffm->pts = pts;
flush_packet(s);
}
}
}
static int ffm_write_header(AVFormatContext *s)
{
FFMContext *ffm = s->priv_data;
AVStream *st;
FFMStream *fst;
ByteIOContext *pb = &s->pb;
AVCodecContext *codec;
int bit_rate, i;
ffm->packet_size = FFM_PACKET_SIZE;
/* header */
put_tag(pb, "FFM1");
put_be32(pb, ffm->packet_size);
/* XXX: store write position in other file ? */
put_be64(pb, ffm->packet_size); /* current write position */
put_be32(pb, s->nb_streams);
bit_rate = 0;
for(i=0;i<s->nb_streams;i++) {
st = s->streams[i];
bit_rate += st->codec.bit_rate;
}
put_be32(pb, bit_rate);
/* list of streams */
for(i=0;i<s->nb_streams;i++) {
st = s->streams[i];
fst = av_mallocz(sizeof(FFMStream));
if (!fst)
goto fail;
st->priv_data = fst;
codec = &st->codec;
/* generic info */
put_be32(pb, codec->codec_id);
put_byte(pb, codec->codec_type);
put_be32(pb, codec->bit_rate);
put_be32(pb, codec->quality);
put_be32(pb, codec->flags);
/* specific info */
switch(codec->codec_type) {
case CODEC_TYPE_VIDEO:
put_be32(pb, (codec->frame_rate * 1000) / FRAME_RATE_BASE);
put_be16(pb, codec->width);
put_be16(pb, codec->height);
put_be16(pb, codec->gop_size);
put_byte(pb, codec->qmin);
put_byte(pb, codec->qmax);
put_byte(pb, codec->max_qdiff);
put_be16(pb, (int) (codec->qcompress * 10000.0));
put_be16(pb, (int) (codec->qblur * 10000.0));
put_be32(pb, codec->bit_rate_tolerance);
put_strz(pb, codec->rc_eq);
put_be32(pb, codec->rc_max_rate);
put_be32(pb, codec->rc_min_rate);
put_be32(pb, codec->rc_buffer_size);
put_be64_double(pb, codec->i_quant_factor);
put_be64_double(pb, codec->b_quant_factor);
put_be64_double(pb, codec->i_quant_offset);
put_be64_double(pb, codec->b_quant_offset);
put_be32(pb, codec->dct_algo);
break;
case CODEC_TYPE_AUDIO:
put_be32(pb, codec->sample_rate);
put_le16(pb, codec->channels);
put_le16(pb, codec->frame_size);
break;
default:
av_abort();
}
/* hack to have real time */
if (ffm_nopts)
fst->pts = 0;
else
fst->pts = av_gettime();
}
/* flush until end of block reached */
while ((url_ftell(pb) % ffm->packet_size) != 0)
put_byte(pb, 0);
put_flush_packet(pb);
/* init packet mux */
ffm->packet_ptr = ffm->packet;
ffm->packet_end = ffm->packet + ffm->packet_size - FFM_HEADER_SIZE;
ffm->frame_offset = 0;
ffm->pts = 0;
ffm->first_packet = 1;
return 0;
fail:
for(i=0;i<s->nb_streams;i++) {
st = s->streams[i];
av_freep(&st->priv_data);
}
return -1;
}
static int ffm_write_packet(AVFormatContext *s, int stream_index,
UINT8 *buf, int size, int force_pts)
{
AVStream *st = s->streams[stream_index];
FFMStream *fst = st->priv_data;
INT64 pts;
UINT8 header[FRAME_HEADER_SIZE];
int duration;
if (st->codec.codec_type == CODEC_TYPE_AUDIO) {
duration = ((float)st->codec.frame_size / st->codec.sample_rate * 1000000.0);
} else {
duration = (1000000.0 * FRAME_RATE_BASE / (float)st->codec.frame_rate);
}
pts = fst->pts;
/* packet size & key_frame */
header[0] = stream_index;
header[1] = 0;
if (st->codec.key_frame)
header[1] |= FLAG_KEY_FRAME;
header[2] = (size >> 16) & 0xff;
header[3] = (size >> 8) & 0xff;
header[4] = size & 0xff;
header[5] = (duration >> 16) & 0xff;
header[6] = (duration >> 8) & 0xff;
header[7] = duration & 0xff;
ffm_write_data(s, header, FRAME_HEADER_SIZE, pts, 1);
ffm_write_data(s, buf, size, pts, 0);
fst->pts += duration;
return 0;
}
static int ffm_write_trailer(AVFormatContext *s)
{
ByteIOContext *pb = &s->pb;
FFMContext *ffm = s->priv_data;
int i;
/* flush packets */
if (ffm->packet_ptr > ffm->packet)
flush_packet(s);
put_flush_packet(pb);
if (!url_is_streamed(pb)) {
INT64 size;
/* update the write offset */
size = url_ftell(pb);
url_fseek(pb, 8, SEEK_SET);
put_be64(pb, size);
put_flush_packet(pb);
}
for(i=0;i<s->nb_streams;i++)
av_freep(&s->streams[i]->priv_data);
return 0;
}
/* ffm demux */
static int ffm_is_avail_data(AVFormatContext *s, int size)
{
FFMContext *ffm = s->priv_data;
offset_t pos, avail_size;
int len;
len = ffm->packet_end - ffm->packet_ptr;
if (!ffm_nopts) {
/* XXX: I don't understand this test, so I disabled it for testing */
if (size <= len)
return 1;
}
pos = url_ftell(&s->pb);
if (pos == ffm->write_index) {
/* exactly at the end of stream */
return 0;
} else if (pos < ffm->write_index) {
avail_size = ffm->write_index - pos;
} else {
avail_size = (ffm->file_size - pos) + (ffm->write_index - FFM_PACKET_SIZE);
}
avail_size = (avail_size / ffm->packet_size) * (ffm->packet_size - FFM_HEADER_SIZE) + len;
if (size <= avail_size)
return 1;
else
return 0;
}
/* first is true if we read the frame header */
static int ffm_read_data(AVFormatContext *s,
UINT8 *buf, int size, int first)
{
FFMContext *ffm = s->priv_data;
ByteIOContext *pb = &s->pb;
int len, fill_size, size1, frame_offset;
size1 = size;
while (size > 0) {
redo:
len = ffm->packet_end - ffm->packet_ptr;
if (len > size)
len = size;
if (len == 0) {
if (url_ftell(pb) == ffm->file_size)
url_fseek(pb, ffm->packet_size, SEEK_SET);
retry_read:
get_be16(pb); /* PACKET_ID */
fill_size = get_be16(pb);
ffm->pts = get_be64(pb);
frame_offset = get_be16(pb);
get_buffer(pb, ffm->packet, ffm->packet_size - FFM_HEADER_SIZE);
ffm->packet_end = ffm->packet + (ffm->packet_size - FFM_HEADER_SIZE - fill_size);
/* if first packet or resynchronization packet, we must
handle it specifically */
if (ffm->first_packet || (frame_offset & 0x8000)) {
if (!frame_offset) {
/* This packet has no frame headers in it */
if (url_ftell(pb) >= ffm->packet_size * 3) {
url_fseek(pb, -ffm->packet_size * 2, SEEK_CUR);
goto retry_read;
}
/* This is bad, we cannot find a valid frame header */
return 0;
}
ffm->first_packet = 0;
if ((frame_offset & 0x7ffff) < FFM_HEADER_SIZE)
av_abort();
ffm->packet_ptr = ffm->packet + (frame_offset & 0x7fff) - FFM_HEADER_SIZE;
if (!first)
break;
} else {
ffm->packet_ptr = ffm->packet;
}
goto redo;
}
memcpy(buf, ffm->packet_ptr, len);
buf += len;
ffm->packet_ptr += len;
size -= len;
first = 0;
}
return size1 - size;
}
static int ffm_read_header(AVFormatContext *s, AVFormatParameters *ap)
{
FFMContext *ffm = s->priv_data;
AVStream *st;
FFMStream *fst;
ByteIOContext *pb = &s->pb;
AVCodecContext *codec;
int i;
UINT32 tag;
/* header */
tag = get_le32(pb);
if (tag != MKTAG('F', 'F', 'M', '1'))
goto fail;
ffm->packet_size = get_be32(pb);
if (ffm->packet_size != FFM_PACKET_SIZE)
goto fail;
ffm->write_index = get_be64(pb);
/* get also filesize */
if (!url_is_streamed(pb)) {
ffm->file_size = url_filesize(url_fileno(pb));
} else {
ffm->file_size = (UINT64_C(1) << 63) - 1;
}
s->nb_streams = get_be32(pb);
get_be32(pb); /* total bitrate */
/* read each stream */
for(i=0;i<s->nb_streams;i++) {
char rc_eq_buf[128];
st = av_mallocz(sizeof(AVStream));
if (!st)
goto fail;
s->streams[i] = st;
fst = av_mallocz(sizeof(FFMStream));
if (!fst)
goto fail;
st->priv_data = fst;
codec = &st->codec;
/* generic info */
st->codec.codec_id = get_be32(pb);
st->codec.codec_type = get_byte(pb); /* codec_type */
codec->bit_rate = get_be32(pb);
codec->quality = get_be32(pb);
codec->flags = get_be32(pb);
/* specific info */
switch(codec->codec_type) {
case CODEC_TYPE_VIDEO:
codec->frame_rate = ((INT64)get_be32(pb) * FRAME_RATE_BASE) / 1000;
codec->width = get_be16(pb);
codec->height = get_be16(pb);
codec->gop_size = get_be16(pb);
codec->qmin = get_byte(pb);
codec->qmax = get_byte(pb);
codec->max_qdiff = get_byte(pb);
codec->qcompress = get_be16(pb) / 10000.0;
codec->qblur = get_be16(pb) / 10000.0;
codec->bit_rate_tolerance = get_be32(pb);
codec->rc_eq = strdup(get_strz(pb, rc_eq_buf, sizeof(rc_eq_buf)));
codec->rc_max_rate = get_be32(pb);
codec->rc_min_rate = get_be32(pb);
codec->rc_buffer_size = get_be32(pb);
codec->i_quant_factor = get_be64_double(pb);
codec->b_quant_factor = get_be64_double(pb);
codec->i_quant_offset = get_be64_double(pb);
codec->b_quant_offset = get_be64_double(pb);
codec->dct_algo = get_be32(pb);
break;
case CODEC_TYPE_AUDIO:
codec->sample_rate = get_be32(pb);
codec->channels = get_le16(pb);
codec->frame_size = get_le16(pb);
break;
default:
goto fail;
}
}
/* get until end of block reached */
while ((url_ftell(pb) % ffm->packet_size) != 0)
get_byte(pb);
/* init packet demux */
ffm->packet_ptr = ffm->packet;
ffm->packet_end = ffm->packet;
ffm->frame_offset = 0;
ffm->pts = 0;
ffm->read_state = READ_HEADER;
ffm->first_packet = 1;
return 0;
fail:
for(i=0;i<s->nb_streams;i++) {
st = s->streams[i];
if (st) {
av_freep(&st->priv_data);
av_free(st);
}
}
return -1;
}
/* return < 0 if eof */
static int ffm_read_packet(AVFormatContext *s, AVPacket *pkt)
{
int size;
FFMContext *ffm = s->priv_data;
int duration;
switch(ffm->read_state) {
case READ_HEADER:
if (!ffm_is_avail_data(s, FRAME_HEADER_SIZE)) {
return -EAGAIN;
}
#if 0
printf("pos=%08Lx spos=%Lx, write_index=%Lx size=%Lx\n",
url_ftell(&s->pb), s->pb.pos, ffm->write_index, ffm->file_size);
#endif
if (ffm_read_data(s, ffm->header, FRAME_HEADER_SIZE, 1) !=
FRAME_HEADER_SIZE)
return -EAGAIN;
#if 0
{
int i;
for(i=0;i<FRAME_HEADER_SIZE;i++)
printf("%02x ", ffm->header[i]);
printf("\n");
}
#endif
ffm->read_state = READ_DATA;
/* fall thru */
case READ_DATA:
size = (ffm->header[2] << 16) | (ffm->header[3] << 8) | ffm->header[4];
if (!ffm_is_avail_data(s, size)) {
return -EAGAIN;
}
duration = (ffm->header[5] << 16) | (ffm->header[6] << 8) | ffm->header[7];
av_new_packet(pkt, size);
pkt->stream_index = ffm->header[0];
if (ffm->header[1] & FLAG_KEY_FRAME)
pkt->flags |= PKT_FLAG_KEY;
ffm->read_state = READ_HEADER;
if (ffm_read_data(s, pkt->data, size, 0) != size) {
/* bad case: desynchronized packet. we cancel all the packet loading */
av_free_packet(pkt);
return -EAGAIN;
}
pkt->pts = ffm->pts;
pkt->duration = duration;
break;
}
return 0;
}
//#define DEBUG_SEEK
/* pos is between 0 and file_size - FFM_PACKET_SIZE. It is translated
by the write position inside this function */
static void ffm_seek1(AVFormatContext *s, offset_t pos1)
{
FFMContext *ffm = s->priv_data;
ByteIOContext *pb = &s->pb;
offset_t pos;
pos = pos1 + ffm->write_index;
if (pos >= ffm->file_size)
pos -= (ffm->file_size - FFM_PACKET_SIZE);
#ifdef DEBUG_SEEK
printf("seek to %Lx -> %Lx\n", pos1, pos);
#endif
url_fseek(pb, pos, SEEK_SET);
}
static INT64 get_pts(AVFormatContext *s, offset_t pos)
{
ByteIOContext *pb = &s->pb;
INT64 pts;
ffm_seek1(s, pos);
url_fskip(pb, 4);
pts = get_be64(pb);
#ifdef DEBUG_SEEK
printf("pts=%0.6f\n", pts / 1000000.0);
#endif
return pts;
}
/* seek to a given time in the file. The file read pointer is
positionned at or before pts. XXX: the following code is quite
approximative */
static int ffm_seek(AVFormatContext *s, INT64 wanted_pts)
{
FFMContext *ffm = s->priv_data;
offset_t pos_min, pos_max, pos;
INT64 pts_min, pts_max, pts;
double pos1;
#ifdef DEBUG_SEEK
printf("wanted_pts=%0.6f\n", wanted_pts / 1000000.0);
#endif
/* find the position using linear interpolation (better than
dichotomy in typical cases) */
pos_min = 0;
pos_max = ffm->file_size - 2 * FFM_PACKET_SIZE;
while (pos_min <= pos_max) {
pts_min = get_pts(s, pos_min);
pts_max = get_pts(s, pos_max);
/* linear interpolation */
pos1 = (double)(pos_max - pos_min) * (double)(wanted_pts - pts_min) /
(double)(pts_max - pts_min);
pos = (((INT64)pos1) / FFM_PACKET_SIZE) * FFM_PACKET_SIZE;
if (pos <= pos_min)
pos = pos_min;
else if (pos >= pos_max)
pos = pos_max;
pts = get_pts(s, pos);
/* check if we are lucky */
if (pts == wanted_pts) {
goto found;
} else if (pts > wanted_pts) {
pos_max = pos - FFM_PACKET_SIZE;
} else {
pos_min = pos + FFM_PACKET_SIZE;
}
}
pos = pos_min;
if (pos > 0)
pos -= FFM_PACKET_SIZE;
found:
ffm_seek1(s, pos);
return 0;
}
offset_t ffm_read_write_index(int fd)
{
UINT8 buf[8];
offset_t pos;
int i;
lseek(fd, 8, SEEK_SET);
read(fd, buf, 8);
pos = 0;
for(i=0;i<8;i++)
pos |= buf[i] << (56 - i * 8);
return pos;
}
void ffm_write_write_index(int fd, offset_t pos)
{
UINT8 buf[8];
int i;
for(i=0;i<8;i++)
buf[i] = (pos >> (56 - i * 8)) & 0xff;
lseek(fd, 8, SEEK_SET);
write(fd, buf, 8);
}
void ffm_set_write_index(AVFormatContext *s, offset_t pos, offset_t file_size)
{
FFMContext *ffm = s->priv_data;
ffm->write_index = pos;
ffm->file_size = file_size;
}
static int ffm_read_close(AVFormatContext *s)
{
AVStream *st;
int i;
for(i=0;i<s->nb_streams;i++) {
st = s->streams[i];
av_freep(&st->priv_data);
}
return 0;
}
static int ffm_probe(AVProbeData *p)
{
if (p->buf_size >= 4 &&
p->buf[0] == 'F' && p->buf[1] == 'F' && p->buf[2] == 'M' &&
p->buf[3] == '1')
return AVPROBE_SCORE_MAX + 1;
return 0;
}
static AVInputFormat ffm_iformat = {
"ffm",
"ffm format",
sizeof(FFMContext),
ffm_probe,
ffm_read_header,
ffm_read_packet,
ffm_read_close,
ffm_seek,
};
static AVOutputFormat ffm_oformat = {
"ffm",
"ffm format",
"",
"ffm",
sizeof(FFMContext),
/* not really used */
CODEC_ID_MP2,
CODEC_ID_MPEG1VIDEO,
ffm_write_header,
ffm_write_packet,
ffm_write_trailer,
};
int ffm_init(void)
{
av_register_input_format(&ffm_iformat);
av_register_output_format(&ffm_oformat);
return 0;
}

130
libavformat/file.c Normal file
View File

@@ -0,0 +1,130 @@
/*
* Buffered file io for ffmpeg system
* Copyright (c) 2001 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"
#include <fcntl.h>
#ifndef CONFIG_WIN32
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#else
#include <io.h>
#define open(fname,oflag,pmode) _open(fname,oflag,pmode)
#endif /* CONFIG_WIN32 */
/* standard file protocol */
static int file_open(URLContext *h, const char *filename, int flags)
{
int access;
int fd;
if (flags & URL_WRONLY) {
access = O_CREAT | O_TRUNC | O_WRONLY;
} else {
access = O_RDONLY;
}
#ifdef CONFIG_WIN32
access |= O_BINARY;
#endif
fd = open(filename, access, 0666);
if (fd < 0)
return -ENOENT;
h->priv_data = (void *)fd;
return 0;
}
static int file_read(URLContext *h, unsigned char *buf, int size)
{
int fd = (int)h->priv_data;
return read(fd, buf, size);
}
static int file_write(URLContext *h, unsigned char *buf, int size)
{
int fd = (int)h->priv_data;
return write(fd, buf, size);
}
/* XXX: use llseek */
static offset_t file_seek(URLContext *h, offset_t pos, int whence)
{
int fd = (int)h->priv_data;
#ifdef CONFIG_WIN32
return _lseeki64(fd, pos, whence);
#else
return lseek(fd, pos, whence);
#endif
}
static int file_close(URLContext *h)
{
int fd = (int)h->priv_data;
return close(fd);
}
URLProtocol file_protocol = {
"file",
file_open,
file_read,
file_write,
file_seek,
file_close,
};
/* pipe protocol */
static int pipe_open(URLContext *h, const char *filename, int flags)
{
int fd;
if (flags & URL_WRONLY) {
fd = 1;
} else {
fd = 0;
}
h->priv_data = (void *)fd;
return 0;
}
static int pipe_read(URLContext *h, unsigned char *buf, int size)
{
int fd = (int)h->priv_data;
return read(fd, buf, size);
}
static int pipe_write(URLContext *h, unsigned char *buf, int size)
{
int fd = (int)h->priv_data;
return write(fd, buf, size);
}
static int pipe_close(URLContext *h)
{
return 0;
}
URLProtocol pipe_protocol = {
"pipe",
pipe_open,
pipe_read,
pipe_write,
NULL,
pipe_close,
};

102
libavformat/framehook.c Normal file
View File

@@ -0,0 +1,102 @@
/*
* Video processing hooks
* Copyright (c) 2000, 2001 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 <errno.h>
#include "config.h"
#include "framehook.h"
#include "avformat.h"
#ifdef HAVE_VHOOK
#include <dlfcn.h>
#endif
typedef struct _FrameHookEntry {
struct _FrameHookEntry *next;
FrameHookConfigureFn Configure;
FrameHookProcessFn Process;
void *ctx;
} FrameHookEntry;
static FrameHookEntry *first_hook;
/* Returns 0 on OK */
int frame_hook_add(int argc, char *argv[])
{
#ifdef HAVE_VHOOK
void *loaded;
FrameHookEntry *fhe, **fhep;
if (argc < 1) {
return ENOENT;
}
loaded = dlopen(argv[0], RTLD_NOW);
if (!loaded) {
fprintf(stderr, "%s\n", dlerror());
return -1;
}
fhe = av_mallocz(sizeof(*fhe));
if (!fhe) {
return errno;
}
fhe->Configure = dlsym(loaded, "Configure");
fhe->Process = dlsym(loaded, "Process");
if (!fhe->Process) {
fprintf(stderr, "Failed to find Process entrypoint in %s\n", argv[0]);
return -1;
}
if (!fhe->Configure && argc > 1) {
fprintf(stderr, "Failed to find Configure entrypoint in %s\n", argv[0]);
return -1;
}
if (argc > 1 || fhe->Configure) {
if (fhe->Configure(&fhe->ctx, argc, argv)) {
fprintf(stderr, "Failed to Configure %s\n", argv[0]);
return -1;
}
}
for (fhep = &first_hook; *fhep; fhep = &((*fhep)->next)) {
}
*fhep = fhe;
return 0;
#else
fprintf(stderr, "Video hooking not compiled into this version\n");
return 1;
#endif
}
void frame_hook_process(AVPicture *pict, enum PixelFormat pix_fmt, int width, int height)
{
if (first_hook) {
FrameHookEntry *fhe;
INT64 pts = av_gettime();
for (fhe = first_hook; fhe; fhe = fhe->next) {
fhe->Process(fhe->ctx, pict, pix_fmt, width, height, pts);
}
}
}

19
libavformat/framehook.h Normal file
View File

@@ -0,0 +1,19 @@
#ifndef _FRAMEHOOK_H
#define _FRAMEHOOK_H
/*
* Prototypes for interface to .so that implement a video processing hook
*/
#include "avcodec.h"
/* Function must be called 'Configure' */
typedef int (*FrameHookConfigureFn)(void **ctxp, int argc, char *argv[]);
/* Function must be called 'Process' */
typedef void (*FrameHookProcessFn)(void *ctx, struct AVPicture *pict, enum PixelFormat pix_fmt, int width, int height, INT64 pts);
extern int frame_hook_add(int argc, char *argv[]);
extern void frame_hook_process(struct AVPicture *pict, enum PixelFormat pix_fmt, int width, int height);
#endif

375
libavformat/gif.c Normal file
View File

@@ -0,0 +1,375 @@
/*
* Animated GIF encoder
* Copyright (c) 2000 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
*/
/*
* First version by Francois Revol revol@free.fr
*
* Features and limitations:
* - currently no compression is performed,
* in fact the size of the data is 9/8 the size of the image in 8bpp
* - uses only a global standard palette
* - tested with IE 5.0, Opera for BeOS, NetPositive (BeOS), and Mozilla (BeOS).
*
* Reference documents:
* http://www.goice.co.jp/member/mo/formats/gif.html
* http://astronomy.swin.edu.au/pbourke/dataformats/gif/
* http://www.dcs.ed.ac.uk/home/mxr/gfx/2d/GIF89a.txt
*
* this url claims to have an LZW algorithm not covered by Unisys patent:
* http://www.msg.net/utility/whirlgif/gifencod.html
* could help reduce the size of the files _a lot_...
* some sites mentions an RLE type compression also.
*/
#include "avformat.h"
/* bitstream minipacket size */
#define GIF_CHUNKS 100
/* slows down the decoding (and some browsers doesn't like it) */
/* #define GIF_ADD_APP_HEADER */
typedef struct {
unsigned char r;
unsigned char g;
unsigned char b;
} rgb_triplet;
/* we use the standard 216 color palette */
/* this script was used to create the palette:
* for r in 00 33 66 99 cc ff; do for g in 00 33 66 99 cc ff; do echo -n " "; for b in 00 33 66 99 cc ff; do
* echo -n "{ 0x$r, 0x$g, 0x$b }, "; done; echo ""; done; done
*/
static const rgb_triplet gif_clut[216] = {
{ 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x33 }, { 0x00, 0x00, 0x66 }, { 0x00, 0x00, 0x99 }, { 0x00, 0x00, 0xcc }, { 0x00, 0x00, 0xff },
{ 0x00, 0x33, 0x00 }, { 0x00, 0x33, 0x33 }, { 0x00, 0x33, 0x66 }, { 0x00, 0x33, 0x99 }, { 0x00, 0x33, 0xcc }, { 0x00, 0x33, 0xff },
{ 0x00, 0x66, 0x00 }, { 0x00, 0x66, 0x33 }, { 0x00, 0x66, 0x66 }, { 0x00, 0x66, 0x99 }, { 0x00, 0x66, 0xcc }, { 0x00, 0x66, 0xff },
{ 0x00, 0x99, 0x00 }, { 0x00, 0x99, 0x33 }, { 0x00, 0x99, 0x66 }, { 0x00, 0x99, 0x99 }, { 0x00, 0x99, 0xcc }, { 0x00, 0x99, 0xff },
{ 0x00, 0xcc, 0x00 }, { 0x00, 0xcc, 0x33 }, { 0x00, 0xcc, 0x66 }, { 0x00, 0xcc, 0x99 }, { 0x00, 0xcc, 0xcc }, { 0x00, 0xcc, 0xff },
{ 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0x33 }, { 0x00, 0xff, 0x66 }, { 0x00, 0xff, 0x99 }, { 0x00, 0xff, 0xcc }, { 0x00, 0xff, 0xff },
{ 0x33, 0x00, 0x00 }, { 0x33, 0x00, 0x33 }, { 0x33, 0x00, 0x66 }, { 0x33, 0x00, 0x99 }, { 0x33, 0x00, 0xcc }, { 0x33, 0x00, 0xff },
{ 0x33, 0x33, 0x00 }, { 0x33, 0x33, 0x33 }, { 0x33, 0x33, 0x66 }, { 0x33, 0x33, 0x99 }, { 0x33, 0x33, 0xcc }, { 0x33, 0x33, 0xff },
{ 0x33, 0x66, 0x00 }, { 0x33, 0x66, 0x33 }, { 0x33, 0x66, 0x66 }, { 0x33, 0x66, 0x99 }, { 0x33, 0x66, 0xcc }, { 0x33, 0x66, 0xff },
{ 0x33, 0x99, 0x00 }, { 0x33, 0x99, 0x33 }, { 0x33, 0x99, 0x66 }, { 0x33, 0x99, 0x99 }, { 0x33, 0x99, 0xcc }, { 0x33, 0x99, 0xff },
{ 0x33, 0xcc, 0x00 }, { 0x33, 0xcc, 0x33 }, { 0x33, 0xcc, 0x66 }, { 0x33, 0xcc, 0x99 }, { 0x33, 0xcc, 0xcc }, { 0x33, 0xcc, 0xff },
{ 0x33, 0xff, 0x00 }, { 0x33, 0xff, 0x33 }, { 0x33, 0xff, 0x66 }, { 0x33, 0xff, 0x99 }, { 0x33, 0xff, 0xcc }, { 0x33, 0xff, 0xff },
{ 0x66, 0x00, 0x00 }, { 0x66, 0x00, 0x33 }, { 0x66, 0x00, 0x66 }, { 0x66, 0x00, 0x99 }, { 0x66, 0x00, 0xcc }, { 0x66, 0x00, 0xff },
{ 0x66, 0x33, 0x00 }, { 0x66, 0x33, 0x33 }, { 0x66, 0x33, 0x66 }, { 0x66, 0x33, 0x99 }, { 0x66, 0x33, 0xcc }, { 0x66, 0x33, 0xff },
{ 0x66, 0x66, 0x00 }, { 0x66, 0x66, 0x33 }, { 0x66, 0x66, 0x66 }, { 0x66, 0x66, 0x99 }, { 0x66, 0x66, 0xcc }, { 0x66, 0x66, 0xff },
{ 0x66, 0x99, 0x00 }, { 0x66, 0x99, 0x33 }, { 0x66, 0x99, 0x66 }, { 0x66, 0x99, 0x99 }, { 0x66, 0x99, 0xcc }, { 0x66, 0x99, 0xff },
{ 0x66, 0xcc, 0x00 }, { 0x66, 0xcc, 0x33 }, { 0x66, 0xcc, 0x66 }, { 0x66, 0xcc, 0x99 }, { 0x66, 0xcc, 0xcc }, { 0x66, 0xcc, 0xff },
{ 0x66, 0xff, 0x00 }, { 0x66, 0xff, 0x33 }, { 0x66, 0xff, 0x66 }, { 0x66, 0xff, 0x99 }, { 0x66, 0xff, 0xcc }, { 0x66, 0xff, 0xff },
{ 0x99, 0x00, 0x00 }, { 0x99, 0x00, 0x33 }, { 0x99, 0x00, 0x66 }, { 0x99, 0x00, 0x99 }, { 0x99, 0x00, 0xcc }, { 0x99, 0x00, 0xff },
{ 0x99, 0x33, 0x00 }, { 0x99, 0x33, 0x33 }, { 0x99, 0x33, 0x66 }, { 0x99, 0x33, 0x99 }, { 0x99, 0x33, 0xcc }, { 0x99, 0x33, 0xff },
{ 0x99, 0x66, 0x00 }, { 0x99, 0x66, 0x33 }, { 0x99, 0x66, 0x66 }, { 0x99, 0x66, 0x99 }, { 0x99, 0x66, 0xcc }, { 0x99, 0x66, 0xff },
{ 0x99, 0x99, 0x00 }, { 0x99, 0x99, 0x33 }, { 0x99, 0x99, 0x66 }, { 0x99, 0x99, 0x99 }, { 0x99, 0x99, 0xcc }, { 0x99, 0x99, 0xff },
{ 0x99, 0xcc, 0x00 }, { 0x99, 0xcc, 0x33 }, { 0x99, 0xcc, 0x66 }, { 0x99, 0xcc, 0x99 }, { 0x99, 0xcc, 0xcc }, { 0x99, 0xcc, 0xff },
{ 0x99, 0xff, 0x00 }, { 0x99, 0xff, 0x33 }, { 0x99, 0xff, 0x66 }, { 0x99, 0xff, 0x99 }, { 0x99, 0xff, 0xcc }, { 0x99, 0xff, 0xff },
{ 0xcc, 0x00, 0x00 }, { 0xcc, 0x00, 0x33 }, { 0xcc, 0x00, 0x66 }, { 0xcc, 0x00, 0x99 }, { 0xcc, 0x00, 0xcc }, { 0xcc, 0x00, 0xff },
{ 0xcc, 0x33, 0x00 }, { 0xcc, 0x33, 0x33 }, { 0xcc, 0x33, 0x66 }, { 0xcc, 0x33, 0x99 }, { 0xcc, 0x33, 0xcc }, { 0xcc, 0x33, 0xff },
{ 0xcc, 0x66, 0x00 }, { 0xcc, 0x66, 0x33 }, { 0xcc, 0x66, 0x66 }, { 0xcc, 0x66, 0x99 }, { 0xcc, 0x66, 0xcc }, { 0xcc, 0x66, 0xff },
{ 0xcc, 0x99, 0x00 }, { 0xcc, 0x99, 0x33 }, { 0xcc, 0x99, 0x66 }, { 0xcc, 0x99, 0x99 }, { 0xcc, 0x99, 0xcc }, { 0xcc, 0x99, 0xff },
{ 0xcc, 0xcc, 0x00 }, { 0xcc, 0xcc, 0x33 }, { 0xcc, 0xcc, 0x66 }, { 0xcc, 0xcc, 0x99 }, { 0xcc, 0xcc, 0xcc }, { 0xcc, 0xcc, 0xff },
{ 0xcc, 0xff, 0x00 }, { 0xcc, 0xff, 0x33 }, { 0xcc, 0xff, 0x66 }, { 0xcc, 0xff, 0x99 }, { 0xcc, 0xff, 0xcc }, { 0xcc, 0xff, 0xff },
{ 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0x33 }, { 0xff, 0x00, 0x66 }, { 0xff, 0x00, 0x99 }, { 0xff, 0x00, 0xcc }, { 0xff, 0x00, 0xff },
{ 0xff, 0x33, 0x00 }, { 0xff, 0x33, 0x33 }, { 0xff, 0x33, 0x66 }, { 0xff, 0x33, 0x99 }, { 0xff, 0x33, 0xcc }, { 0xff, 0x33, 0xff },
{ 0xff, 0x66, 0x00 }, { 0xff, 0x66, 0x33 }, { 0xff, 0x66, 0x66 }, { 0xff, 0x66, 0x99 }, { 0xff, 0x66, 0xcc }, { 0xff, 0x66, 0xff },
{ 0xff, 0x99, 0x00 }, { 0xff, 0x99, 0x33 }, { 0xff, 0x99, 0x66 }, { 0xff, 0x99, 0x99 }, { 0xff, 0x99, 0xcc }, { 0xff, 0x99, 0xff },
{ 0xff, 0xcc, 0x00 }, { 0xff, 0xcc, 0x33 }, { 0xff, 0xcc, 0x66 }, { 0xff, 0xcc, 0x99 }, { 0xff, 0xcc, 0xcc }, { 0xff, 0xcc, 0xff },
{ 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0x33 }, { 0xff, 0xff, 0x66 }, { 0xff, 0xff, 0x99 }, { 0xff, 0xff, 0xcc }, { 0xff, 0xff, 0xff },
};
/* The GIF format uses reversed order for bitstreams... */
/* at least they don't use PDP_ENDIAN :) */
/* so we 'extend' PutBitContext. hmmm, OOP :) */
/* seems this thing changed slightly since I wrote it... */
#ifdef ALT_BITSTREAM_WRITER
# error no ALT_BITSTREAM_WRITER support for now
#endif
static void gif_put_bits_rev(PutBitContext *s, int n, unsigned int value)
{
unsigned int bit_buf;
int bit_cnt;
#ifdef STATS
st_out_bit_counts[st_current_index] += n;
#endif
// printf("put_bits=%d %x\n", n, value);
assert(n == 32 || value < (1U << n));
bit_buf = s->bit_buf;
bit_cnt = 32 - s->bit_left; /* XXX:lazyness... was = s->bit_cnt; */
// printf("n=%d value=%x cnt=%d buf=%x\n", n, value, bit_cnt, bit_buf);
/* XXX: optimize */
if (n < (32-bit_cnt)) {
bit_buf |= value << (bit_cnt);
bit_cnt+=n;
} else {
bit_buf |= value << (bit_cnt);
*s->buf_ptr = bit_buf & 0xff;
s->buf_ptr[1] = (bit_buf >> 8) & 0xff;
s->buf_ptr[2] = (bit_buf >> 16) & 0xff;
s->buf_ptr[3] = (bit_buf >> 24) & 0xff;
//printf("bitbuf = %08x\n", bit_buf);
s->buf_ptr+=4;
if (s->buf_ptr >= s->buf_end)
puts("bit buffer overflow !!"); // should never happen ! who got rid of the callback ???
// flush_buffer_rev(s);
bit_cnt=bit_cnt + n - 32;
if (bit_cnt == 0) {
bit_buf = 0;
} else {
bit_buf = value >> (n - bit_cnt);
}
}
s->bit_buf = bit_buf;
s->bit_left = 32 - bit_cnt;
}
/* pad the end of the output stream with zeros */
static void gif_flush_put_bits_rev(PutBitContext *s)
{
while (s->bit_left < 32) {
/* XXX: should test end of buffer */
*s->buf_ptr++=s->bit_buf & 0xff;
s->bit_buf>>=8;
s->bit_left+=8;
}
// flush_buffer_rev(s);
s->bit_left=32;
s->bit_buf=0;
}
/* !RevPutBitContext */
typedef struct {
UINT8 buffer[100]; /* data chunks */
INT64 time, file_time;
} GIFContext;
static int gif_write_header(AVFormatContext *s)
{
GIFContext *gif = s->priv_data;
ByteIOContext *pb = &s->pb;
AVCodecContext *enc, *video_enc;
int i, width, height, rate;
/* XXX: do we reject audio streams or just ignore them ?
if(s->nb_streams > 1)
return -1;
*/
gif->time = 0;
gif->file_time = 0;
video_enc = NULL;
for(i=0;i<s->nb_streams;i++) {
enc = &s->streams[i]->codec;
if (enc->codec_type != CODEC_TYPE_AUDIO)
video_enc = enc;
}
if (!video_enc) {
av_free(gif);
return -1;
} else {
width = video_enc->width;
height = video_enc->height;
rate = video_enc->frame_rate;
}
/* XXX: is it allowed ? seems to work so far... */
video_enc->pix_fmt = PIX_FMT_RGB24;
/* GIF header */
put_tag(pb, "GIF");
put_tag(pb, "89a");
put_le16(pb, width);
put_le16(pb, height);
put_byte(pb, 0xf7); /* flags: global clut, 256 entries */
put_byte(pb, 0x1f); /* background color index */
put_byte(pb, 0); /* aspect ratio */
/* the global palette */
put_buffer(pb, (unsigned char *)gif_clut, 216*3);
for(i=0;i<((256-216)*3);i++)
put_byte(pb, 0);
/* application extension header */
/* XXX: not really sure what to put in here... */
#ifdef GIF_ADD_APP_HEADER
put_byte(pb, 0x21);
put_byte(pb, 0xff);
put_byte(pb, 0x0b);
put_tag(pb, "NETSCAPE2.0");
put_byte(pb, 0x03);
put_byte(pb, 0x01);
put_byte(pb, 0x00);
put_byte(pb, 0x00);
#endif
put_flush_packet(&s->pb);
return 0;
}
/* this is maybe slow, but allows for extensions */
static inline unsigned char gif_clut_index(rgb_triplet *clut, UINT8 r, UINT8 g, UINT8 b)
{
return ((((r)/47)%6)*6*6+(((g)/47)%6)*6+(((b)/47)%6));
}
/* chunk writer callback */
/* !!! XXX:deprecated
static void gif_put_chunk(void *pbctx, UINT8 *buffer, int count)
{
ByteIOContext *pb = (ByteIOContext *)pbctx;
put_byte(pb, (UINT8)count);
put_buffer(pb, buffer, count);
}
*/
static int gif_write_video(AVFormatContext *s,
AVCodecContext *enc, UINT8 *buf, int size)
{
ByteIOContext *pb = &s->pb;
GIFContext *gif = s->priv_data;
int i, left, jiffies;
INT64 delay;
PutBitContext p;
UINT8 buffer[200]; /* 100 * 9 / 8 = 113 */
/* graphic control extension block */
put_byte(pb, 0x21);
put_byte(pb, 0xf9);
put_byte(pb, 0x04); /* block size */
put_byte(pb, 0x04); /* flags */
/* 1 jiffy is 1/70 s */
/* the delay_time field indicates the number of jiffies - 1 */
delay = gif->file_time - gif->time;
/* XXX: should use delay, in order to be more accurate */
/* instead of using the same rounded value each time */
/* XXX: don't even remember if I really use it for now */
jiffies = (70*FRAME_RATE_BASE/enc->frame_rate) - 1;
put_le16(pb, jiffies);
put_byte(pb, 0x1f); /* transparent color index */
put_byte(pb, 0x00);
/* image block */
put_byte(pb, 0x2c);
put_le16(pb, 0);
put_le16(pb, 0);
put_le16(pb, enc->width);
put_le16(pb, enc->height);
put_byte(pb, 0x00); /* flags */
/* no local clut */
put_byte(pb, 0x08);
left=size/3;
init_put_bits(&p, buffer, 130, NULL, NULL);
/*
* the thing here is the bitstream is written as little packets, with a size byte before
* but it's still the same bitstream between packets (no flush !)
*/
while(left>0) {
gif_put_bits_rev(&p, 9, 0x0100); /* clear code */
for(i=0;i<GIF_CHUNKS;i++) {
gif_put_bits_rev(&p, 9, gif_clut_index(NULL, *buf, buf[1], buf[2]));
buf+=3;
}
if(left<=GIF_CHUNKS) {
gif_put_bits_rev(&p, 9, 0x101); /* end of stream */
gif_flush_put_bits_rev(&p);
}
if(pbBufPtr(&p) - p.buf > 0) {
put_byte(pb, pbBufPtr(&p) - p.buf); /* byte count of the packet */
put_buffer(pb, p.buf, pbBufPtr(&p) - p.buf); /* the actual buffer */
p.data_out_size += pbBufPtr(&p) - p.buf;
p.buf_ptr = p.buf; /* dequeue the bytes off the bitstream */
}
if(left<=GIF_CHUNKS) {
put_byte(pb, 0x00); /* end of image block */
}
left-=GIF_CHUNKS;
}
put_flush_packet(&s->pb);
return 0;
}
static int gif_write_packet(AVFormatContext *s, int stream_index,
UINT8 *buf, int size, int force_pts)
{
AVCodecContext *codec = &s->streams[stream_index]->codec;
if (codec->codec_type == CODEC_TYPE_AUDIO)
return 0; /* just ignore audio */
else
return gif_write_video(s, codec, buf, size);
}
static int gif_write_trailer(AVFormatContext *s)
{
ByteIOContext *pb = &s->pb;
put_byte(pb, 0x3b);
put_flush_packet(&s->pb);
return 0;
}
static AVOutputFormat gif_oformat = {
"gif",
"GIF Animation",
"image/gif",
"gif",
sizeof(GIFContext),
CODEC_ID_NONE,
CODEC_ID_RAWVIDEO,
gif_write_header,
gif_write_packet,
gif_write_trailer,
};
int gif_init(void)
{
av_register_output_format(&gif_oformat);
return 0;
}

829
libavformat/grab.c Normal file
View File

@@ -0,0 +1,829 @@
/*
* Linux video grab interface
* Copyright (c) 2000,2001 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"
#include <linux/videodev.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <time.h>
typedef struct {
int fd;
int frame_format; /* see VIDEO_PALETTE_xxx */
int use_mmap;
int width, height;
int frame_rate;
INT64 time_frame;
int frame_size;
struct video_capability video_cap;
struct video_audio audio_saved;
UINT8 *video_buf;
struct video_mbuf gb_buffers;
struct video_mmap gb_buf;
int gb_frame;
/* ATI All In Wonder specific stuff */
/* XXX: remove and merge in libavcodec/imgconvert.c */
int aiw_enabled;
int deint;
int halfw;
UINT8 *src_mem;
UINT8 *lum_m4_mem;
} VideoData;
static int aiw_init(VideoData *s);
static int aiw_read_picture(VideoData *s, uint8_t *data);
static int aiw_close(VideoData *s);
const char *v4l_device = "/dev/video";
static int grab_read_header(AVFormatContext *s1, AVFormatParameters *ap)
{
VideoData *s = s1->priv_data;
AVStream *st;
int width, height;
int video_fd, frame_size;
int ret, frame_rate;
int desired_palette;
struct video_audio audio;
if (!ap || ap->width <= 0 || ap->height <= 0 || ap->frame_rate <= 0)
return -1;
width = ap->width;
height = ap->height;
frame_rate = ap->frame_rate;
st = av_new_stream(s1, 0);
if (!st)
return -ENOMEM;
s->width = width;
s->height = height;
s->frame_rate = frame_rate;
video_fd = open(v4l_device, O_RDWR);
if (video_fd < 0) {
perror(v4l_device);
goto fail;
}
if (ioctl(video_fd,VIDIOCGCAP, &s->video_cap) < 0) {
perror("VIDIOCGCAP");
goto fail;
}
if (!(s->video_cap.type & VID_TYPE_CAPTURE)) {
fprintf(stderr, "Fatal: grab device does not handle capture\n");
goto fail;
}
desired_palette = -1;
if (st->codec.pix_fmt == PIX_FMT_YUV420P) {
desired_palette = VIDEO_PALETTE_YUV420P;
} else if (st->codec.pix_fmt == PIX_FMT_YUV422) {
desired_palette = VIDEO_PALETTE_YUV422;
} else if (st->codec.pix_fmt == PIX_FMT_BGR24) {
desired_palette = VIDEO_PALETTE_RGB24;
}
/* unmute audio */
audio.audio = 0;
ioctl(video_fd, VIDIOCGAUDIO, &audio);
memcpy(&s->audio_saved, &audio, sizeof(audio));
audio.flags &= ~VIDEO_AUDIO_MUTE;
ioctl(video_fd, VIDIOCSAUDIO, &audio);
ret = ioctl(video_fd,VIDIOCGMBUF,&s->gb_buffers);
if (ret < 0) {
/* try to use read based access */
struct video_window win;
struct video_picture pict;
int val;
win.x = 0;
win.y = 0;
win.width = width;
win.height = height;
win.chromakey = -1;
win.flags = 0;
ioctl(video_fd, VIDIOCSWIN, &win);
ioctl(video_fd, VIDIOCGPICT, &pict);
#if 0
printf("v4l: colour=%d hue=%d brightness=%d constrast=%d whiteness=%d\n",
pict.colour,
pict.hue,
pict.brightness,
pict.contrast,
pict.whiteness);
#endif
/* try to choose a suitable video format */
pict.palette = desired_palette;
if (desired_palette == -1 || (ret = ioctl(video_fd, VIDIOCSPICT, &pict)) < 0) {
pict.palette=VIDEO_PALETTE_YUV420P;
ret = ioctl(video_fd, VIDIOCSPICT, &pict);
if (ret < 0) {
pict.palette=VIDEO_PALETTE_YUV422;
ret = ioctl(video_fd, VIDIOCSPICT, &pict);
if (ret < 0) {
pict.palette=VIDEO_PALETTE_RGB24;
ret = ioctl(video_fd, VIDIOCSPICT, &pict);
if (ret < 0)
goto fail1;
}
}
}
s->frame_format = pict.palette;
val = 1;
ioctl(video_fd, VIDIOCCAPTURE, &val);
s->time_frame = av_gettime();
s->use_mmap = 0;
/* ATI All In Wonder automatic activation */
if (!strcmp(s->video_cap.name, "Km")) {
if (aiw_init(s) < 0)
goto fail;
s->aiw_enabled = 1;
/* force 420P format because convertion from YUV422 to YUV420P
is done in this driver (ugly) */
s->frame_format = VIDEO_PALETTE_YUV420P;
}
} else {
s->video_buf = mmap(0,s->gb_buffers.size,PROT_READ|PROT_WRITE,MAP_SHARED,video_fd,0);
if ((unsigned char*)-1 == s->video_buf) {
perror("mmap");
goto fail;
}
s->gb_frame = 0;
s->time_frame = av_gettime();
/* start to grab the first frame */
s->gb_buf.frame = s->gb_frame % s->gb_buffers.frames;
s->gb_buf.height = height;
s->gb_buf.width = width;
s->gb_buf.format = desired_palette;
if (desired_palette == -1 || (ret = ioctl(video_fd, VIDIOCMCAPTURE, &s->gb_buf)) < 0) {
s->gb_buf.format = VIDEO_PALETTE_YUV420P;
ret = ioctl(video_fd, VIDIOCMCAPTURE, &s->gb_buf);
if (ret < 0 && errno != EAGAIN) {
/* try YUV422 */
s->gb_buf.format = VIDEO_PALETTE_YUV422;
ret = ioctl(video_fd, VIDIOCMCAPTURE, &s->gb_buf);
if (ret < 0 && errno != EAGAIN) {
/* try RGB24 */
s->gb_buf.format = VIDEO_PALETTE_RGB24;
ret = ioctl(video_fd, VIDIOCMCAPTURE, &s->gb_buf);
}
}
}
if (ret < 0) {
if (errno != EAGAIN) {
fail1:
fprintf(stderr, "Fatal: grab device does not support suitable format\n");
} else {
fprintf(stderr,"Fatal: grab device does not receive any video signal\n");
}
goto fail;
}
s->frame_format = s->gb_buf.format;
s->use_mmap = 1;
}
switch(s->frame_format) {
case VIDEO_PALETTE_YUV420P:
frame_size = (width * height * 3) / 2;
st->codec.pix_fmt = PIX_FMT_YUV420P;
break;
case VIDEO_PALETTE_YUV422:
frame_size = width * height * 2;
st->codec.pix_fmt = PIX_FMT_YUV422;
break;
case VIDEO_PALETTE_RGB24:
frame_size = width * height * 3;
st->codec.pix_fmt = PIX_FMT_BGR24; /* NOTE: v4l uses BGR24, not RGB24 ! */
break;
default:
goto fail;
}
s->fd = video_fd;
s->frame_size = frame_size;
st->codec.codec_type = CODEC_TYPE_VIDEO;
st->codec.codec_id = CODEC_ID_RAWVIDEO;
st->codec.width = width;
st->codec.height = height;
st->codec.frame_rate = frame_rate;
av_set_pts_info(s1, 48, 1, 1000000); /* 48 bits pts in us */
return 0;
fail:
if (video_fd >= 0)
close(video_fd);
av_free(st);
return -EIO;
}
static int v4l_mm_read_picture(VideoData *s, UINT8 *buf)
{
UINT8 *ptr;
/* Setup to capture the next frame */
s->gb_buf.frame = (s->gb_frame + 1) % s->gb_buffers.frames;
if (ioctl(s->fd, VIDIOCMCAPTURE, &s->gb_buf) < 0) {
if (errno == EAGAIN)
fprintf(stderr,"Cannot Sync\n");
else
perror("VIDIOCMCAPTURE");
return -EIO;
}
while (ioctl(s->fd, VIDIOCSYNC, &s->gb_frame) < 0 &&
(errno == EAGAIN || errno == EINTR));
ptr = s->video_buf + s->gb_buffers.offsets[s->gb_frame];
memcpy(buf, ptr, s->frame_size);
/* This is now the grabbing frame */
s->gb_frame = s->gb_buf.frame;
return s->frame_size;
}
static int grab_read_packet(AVFormatContext *s1, AVPacket *pkt)
{
VideoData *s = s1->priv_data;
INT64 curtime, delay;
struct timespec ts;
INT64 per_frame = (INT64_C(1000000) * FRAME_RATE_BASE) / s->frame_rate;
/* Calculate the time of the next frame */
s->time_frame += per_frame;
/* wait based on the frame rate */
for(;;) {
curtime = av_gettime();
delay = s->time_frame - curtime;
if (delay <= 0) {
if (delay < -per_frame) {
/* printf("grabbing is %d frames late (dropping)\n", (int) -(delay / 16666)); */
s->time_frame += per_frame;
}
break;
}
ts.tv_sec = delay / 1000000;
ts.tv_nsec = (delay % 1000000) * 1000;
nanosleep(&ts, NULL);
}
if (av_new_packet(pkt, s->frame_size) < 0)
return -EIO;
pkt->pts = curtime & ((1LL << 48) - 1);
/* read one frame */
if (s->aiw_enabled) {
return aiw_read_picture(s, pkt->data);
} else if (s->use_mmap) {
return v4l_mm_read_picture(s, pkt->data);
} else {
if (read(s->fd, pkt->data, pkt->size) != pkt->size)
return -EIO;
return s->frame_size;
}
}
static int grab_read_close(AVFormatContext *s1)
{
VideoData *s = s1->priv_data;
if (s->aiw_enabled)
aiw_close(s);
if (s->use_mmap)
munmap(s->video_buf, s->gb_buffers.size);
/* mute audio. we must force it because the BTTV driver does not
return its state correctly */
s->audio_saved.flags |= VIDEO_AUDIO_MUTE;
ioctl(s->fd, VIDIOCSAUDIO, &s->audio_saved);
close(s->fd);
return 0;
}
static AVInputFormat video_grab_device_format = {
"video_grab_device",
"video grab",
sizeof(VideoData),
NULL,
grab_read_header,
grab_read_packet,
grab_read_close,
.flags = AVFMT_NOFILE,
};
/* All in Wonder specific stuff */
/* XXX: remove and merge in libavcodec/imgconvert.c */
static int aiw_init(VideoData *s)
{
int width, height;
width = s->width;
height = s->height;
if ((width == s->video_cap.maxwidth && height == s->video_cap.maxheight) ||
(width == s->video_cap.maxwidth && height == s->video_cap.maxheight*2) ||
(width == s->video_cap.maxwidth/2 && height == s->video_cap.maxheight)) {
s->deint=0;
s->halfw=0;
if (height == s->video_cap.maxheight*2) s->deint=1;
if (width == s->video_cap.maxwidth/2) s->halfw=1;
} else {
fprintf(stderr,"\nIncorrect Grab Size Supplied - Supported Sizes Are:\n");
fprintf(stderr," %dx%d %dx%d %dx%d\n\n",
s->video_cap.maxwidth,s->video_cap.maxheight,
s->video_cap.maxwidth,s->video_cap.maxheight*2,
s->video_cap.maxwidth/2,s->video_cap.maxheight);
goto fail;
}
if (s->halfw == 0) {
s->src_mem = av_malloc(s->width*2);
} else {
s->src_mem = av_malloc(s->width*4);
}
if (!s->src_mem) goto fail;
s->lum_m4_mem = av_malloc(s->width);
if (!s->lum_m4_mem)
goto fail;
return 0;
fail:
av_freep(&s->src_mem);
av_freep(&s->lum_m4_mem);
return -1;
}
#ifdef HAVE_MMX
#include "../libavcodec/i386/mmx.h"
#define LINE_WITH_UV \
movq_m2r(ptr[0],mm0); \
movq_m2r(ptr[8],mm1); \
movq_r2r(mm0, mm4); \
punpcklbw_r2r(mm1,mm0); \
punpckhbw_r2r(mm1,mm4); \
movq_r2r(mm0,mm5); \
punpcklbw_r2r(mm4,mm0); \
punpckhbw_r2r(mm4,mm5); \
movq_r2r(mm0,mm1); \
punpcklbw_r2r(mm5,mm1); \
movq_r2m(mm1,lum[0]); \
movq_m2r(ptr[16],mm2); \
movq_m2r(ptr[24],mm1); \
movq_r2r(mm2,mm4); \
punpcklbw_r2r(mm1,mm2); \
punpckhbw_r2r(mm1,mm4); \
movq_r2r(mm2,mm3); \
punpcklbw_r2r(mm4,mm2); \
punpckhbw_r2r(mm4,mm3); \
movq_r2r(mm2,mm1); \
punpcklbw_r2r(mm3,mm1); \
movq_r2m(mm1,lum[8]); \
punpckhdq_r2r(mm2,mm0); \
punpckhdq_r2r(mm3,mm5); \
movq_r2m(mm0,cb[0]); \
movq_r2m(mm5,cr[0]);
#define LINE_NO_UV \
movq_m2r(ptr[0],mm0);\
movq_m2r(ptr[8],mm1);\
movq_r2r(mm0, mm4);\
punpcklbw_r2r(mm1,mm0); \
punpckhbw_r2r(mm1,mm4);\
movq_r2r(mm0,mm5);\
punpcklbw_r2r(mm4,mm0);\
punpckhbw_r2r(mm4,mm5);\
movq_r2r(mm0,mm1);\
punpcklbw_r2r(mm5,mm1);\
movq_r2m(mm1,lum[0]);\
movq_m2r(ptr[16],mm2);\
movq_m2r(ptr[24],mm1);\
movq_r2r(mm2,mm4);\
punpcklbw_r2r(mm1,mm2);\
punpckhbw_r2r(mm1,mm4);\
movq_r2r(mm2,mm3);\
punpcklbw_r2r(mm4,mm2);\
punpckhbw_r2r(mm4,mm3);\
movq_r2r(mm2,mm1);\
punpcklbw_r2r(mm3,mm1);\
movq_r2m(mm1,lum[8]);
#define LINE_WITHUV_AVG \
movq_m2r(ptr[0], mm0);\
movq_m2r(ptr[8], mm1);\
movq_r2r(mm0, mm4);\
punpcklbw_r2r(mm1,mm0);\
punpckhbw_r2r(mm1,mm4);\
movq_r2r(mm0,mm5);\
punpcklbw_r2r(mm4,mm0);\
punpckhbw_r2r(mm4,mm5);\
movq_r2r(mm0,mm1);\
movq_r2r(mm5,mm2);\
punpcklbw_r2r(mm7,mm1);\
punpcklbw_r2r(mm7,mm2);\
paddw_r2r(mm6,mm1);\
paddw_r2r(mm2,mm1);\
psraw_i2r(1,mm1);\
packuswb_r2r(mm7,mm1);\
movd_r2m(mm1,lum[0]);\
movq_m2r(ptr[16],mm2);\
movq_m2r(ptr[24],mm1);\
movq_r2r(mm2,mm4);\
punpcklbw_r2r(mm1,mm2);\
punpckhbw_r2r(mm1,mm4);\
movq_r2r(mm2,mm3);\
punpcklbw_r2r(mm4,mm2);\
punpckhbw_r2r(mm4,mm3);\
movq_r2r(mm2,mm1);\
movq_r2r(mm3,mm4);\
punpcklbw_r2r(mm7,mm1);\
punpcklbw_r2r(mm7,mm4);\
paddw_r2r(mm6,mm1);\
paddw_r2r(mm4,mm1);\
psraw_i2r(1,mm1);\
packuswb_r2r(mm7,mm1);\
movd_r2m(mm1,lum[4]);\
punpckhbw_r2r(mm7,mm0);\
punpckhbw_r2r(mm7,mm2);\
paddw_r2r(mm6,mm0);\
paddw_r2r(mm2,mm0);\
psraw_i2r(1,mm0);\
packuswb_r2r(mm7,mm0);\
punpckhbw_r2r(mm7,mm5);\
punpckhbw_r2r(mm7,mm3);\
paddw_r2r(mm6,mm5);\
paddw_r2r(mm3,mm5);\
psraw_i2r(1,mm5);\
packuswb_r2r(mm7,mm5);\
movd_r2m(mm0,cb[0]);\
movd_r2m(mm5,cr[0]);
#define LINE_NOUV_AVG \
movq_m2r(ptr[0],mm0);\
movq_m2r(ptr[8],mm1);\
pand_r2r(mm5,mm0);\
pand_r2r(mm5,mm1);\
pmaddwd_r2r(mm6,mm0);\
pmaddwd_r2r(mm6,mm1);\
packssdw_r2r(mm1,mm0);\
paddw_r2r(mm6,mm0);\
psraw_i2r(1,mm0);\
movq_m2r(ptr[16],mm2);\
movq_m2r(ptr[24],mm3);\
pand_r2r(mm5,mm2);\
pand_r2r(mm5,mm3);\
pmaddwd_r2r(mm6,mm2);\
pmaddwd_r2r(mm6,mm3);\
packssdw_r2r(mm3,mm2);\
paddw_r2r(mm6,mm2);\
psraw_i2r(1,mm2);\
packuswb_r2r(mm2,mm0);\
movq_r2m(mm0,lum[0]);
#define DEINT_LINE_LUM(ptroff) \
movd_m2r(lum_m4[(ptroff)],mm0);\
movd_m2r(lum_m3[(ptroff)],mm1);\
movd_m2r(lum_m2[(ptroff)],mm2);\
movd_m2r(lum_m1[(ptroff)],mm3);\
movd_m2r(lum[(ptroff)],mm4);\
punpcklbw_r2r(mm7,mm0);\
movd_r2m(mm2,lum_m4[(ptroff)]);\
punpcklbw_r2r(mm7,mm1);\
punpcklbw_r2r(mm7,mm2);\
punpcklbw_r2r(mm7,mm3);\
punpcklbw_r2r(mm7,mm4);\
psllw_i2r(2,mm1);\
psllw_i2r(1,mm2);\
paddw_r2r(mm6,mm1);\
psllw_i2r(2,mm3);\
paddw_r2r(mm2,mm1);\
paddw_r2r(mm4,mm0);\
paddw_r2r(mm3,mm1);\
psubusw_r2r(mm0,mm1);\
psrlw_i2r(3,mm1);\
packuswb_r2r(mm7,mm1);\
movd_r2m(mm1,lum_m2[(ptroff)]);
#else
#include "../libavcodec/dsputil.h"
#define LINE_WITH_UV \
lum[0]=ptr[0];lum[1]=ptr[2];lum[2]=ptr[4];lum[3]=ptr[6];\
cb[0]=ptr[1];cb[1]=ptr[5];\
cr[0]=ptr[3];cr[1]=ptr[7];\
lum[4]=ptr[8];lum[5]=ptr[10];lum[6]=ptr[12];lum[7]=ptr[14];\
cb[2]=ptr[9];cb[3]=ptr[13];\
cr[2]=ptr[11];cr[3]=ptr[15];\
lum[8]=ptr[16];lum[9]=ptr[18];lum[10]=ptr[20];lum[11]=ptr[22];\
cb[4]=ptr[17];cb[5]=ptr[21];\
cr[4]=ptr[19];cr[5]=ptr[23];\
lum[12]=ptr[24];lum[13]=ptr[26];lum[14]=ptr[28];lum[15]=ptr[30];\
cb[6]=ptr[25];cb[7]=ptr[29];\
cr[6]=ptr[27];cr[7]=ptr[31];
#define LINE_NO_UV \
lum[0]=ptr[0];lum[1]=ptr[2];lum[2]=ptr[4];lum[3]=ptr[6];\
lum[4]=ptr[8];lum[5]=ptr[10];lum[6]=ptr[12];lum[7]=ptr[14];\
lum[8]=ptr[16];lum[9]=ptr[18];lum[10]=ptr[20];lum[11]=ptr[22];\
lum[12]=ptr[24];lum[13]=ptr[26];lum[14]=ptr[28];lum[15]=ptr[30];
#define LINE_WITHUV_AVG \
sum=(ptr[0]+ptr[2]+1) >> 1;lum[0]=sum; \
sum=(ptr[4]+ptr[6]+1) >> 1;lum[1]=sum; \
sum=(ptr[1]+ptr[5]+1) >> 1;cb[0]=sum; \
sum=(ptr[3]+ptr[7]+1) >> 1;cr[0]=sum; \
sum=(ptr[8]+ptr[10]+1) >> 1;lum[2]=sum; \
sum=(ptr[12]+ptr[14]+1) >> 1;lum[3]=sum; \
sum=(ptr[9]+ptr[13]+1) >> 1;cb[1]=sum; \
sum=(ptr[11]+ptr[15]+1) >> 1;cr[1]=sum; \
sum=(ptr[16]+ptr[18]+1) >> 1;lum[4]=sum; \
sum=(ptr[20]+ptr[22]+1) >> 1;lum[5]=sum; \
sum=(ptr[17]+ptr[21]+1) >> 1;cb[2]=sum; \
sum=(ptr[19]+ptr[23]+1) >> 1;cr[2]=sum; \
sum=(ptr[24]+ptr[26]+1) >> 1;lum[6]=sum; \
sum=(ptr[28]+ptr[30]+1) >> 1;lum[7]=sum; \
sum=(ptr[25]+ptr[29]+1) >> 1;cb[3]=sum; \
sum=(ptr[27]+ptr[31]+1) >> 1;cr[3]=sum;
#define LINE_NOUV_AVG \
sum=(ptr[0]+ptr[2]+1) >> 1;lum[0]=sum; \
sum=(ptr[4]+ptr[6]+1) >> 1;lum[1]=sum; \
sum=(ptr[8]+ptr[10]+1) >> 1;lum[2]=sum; \
sum=(ptr[12]+ptr[14]+1) >> 1;lum[3]=sum; \
sum=(ptr[16]+ptr[18]+1) >> 1;lum[4]=sum; \
sum=(ptr[20]+ptr[22]+1) >> 1;lum[5]=sum; \
sum=(ptr[24]+ptr[26]+1) >> 1;lum[6]=sum; \
sum=(ptr[28]+ptr[30]+1) >> 1;lum[7]=sum;
#define DEINT_LINE_LUM(ptroff) \
sum=(-lum_m4[(ptroff)]+(lum_m3[(ptroff)]<<2)+(lum_m2[(ptroff)]<<1)+(lum_m1[(ptroff)]<<2)-lum[(ptroff)]); \
lum_m4[(ptroff)]=lum_m2[(ptroff)];\
lum_m2[(ptroff)]=cm[(sum+4)>>3];\
sum=(-lum_m4[(ptroff)+1]+(lum_m3[(ptroff)+1]<<2)+(lum_m2[(ptroff)+1]<<1)+(lum_m1[(ptroff)+1]<<2)-lum[(ptroff)+1]); \
lum_m4[(ptroff)+1]=lum_m2[(ptroff)+1];\
lum_m2[(ptroff)+1]=cm[(sum+4)>>3];\
sum=(-lum_m4[(ptroff)+2]+(lum_m3[(ptroff)+2]<<2)+(lum_m2[(ptroff)+2]<<1)+(lum_m1[(ptroff)+2]<<2)-lum[(ptroff)+2]); \
lum_m4[(ptroff)+2]=lum_m2[(ptroff)+2];\
lum_m2[(ptroff)+2]=cm[(sum+4)>>3];\
sum=(-lum_m4[(ptroff)+3]+(lum_m3[(ptroff)+3]<<2)+(lum_m2[(ptroff)+3]<<1)+(lum_m1[(ptroff)+3]<<2)-lum[(ptroff)+3]); \
lum_m4[(ptroff)+3]=lum_m2[(ptroff)+3];\
lum_m2[(ptroff)+3]=cm[(sum+4)>>3];
#endif
/* Read two fields separately. */
static int aiw_read_picture(VideoData *s, uint8_t *data)
{
UINT8 *ptr, *lum, *cb, *cr;
int h;
#ifndef HAVE_MMX
int sum;
#endif
UINT8* src = s->src_mem;
UINT8 *ptrend = &src[s->width*2];
lum=data;
cb=&lum[s->width*s->height];
cr=&cb[(s->width*s->height)/4];
if (s->deint == 0 && s->halfw == 0) {
while (read(s->fd,src,s->width*2) < 0) {
usleep(100);
}
for (h = 0; h < s->height-2; h+=2) {
for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=16, cb+=8, cr+=8) {
LINE_WITH_UV
}
read(s->fd,src,s->width*2);
for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=16) {
LINE_NO_UV
}
read(s->fd,src,s->width*2);
}
/*
* Do last two lines
*/
for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=16, cb+=8, cr+=8) {
LINE_WITH_UV
}
read(s->fd,src,s->width*2);
for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=16) {
LINE_NO_UV
}
/* drop second field */
while (read(s->fd,src,s->width*2) < 0) {
usleep(100);
}
for (h = 0; h < s->height - 1; h++) {
read(s->fd,src,s->width*2);
}
} else if (s->halfw == 1) {
#ifdef HAVE_MMX
mmx_t rounder;
mmx_t masker;
rounder.uw[0]=1;
rounder.uw[1]=1;
rounder.uw[2]=1;
rounder.uw[3]=1;
masker.ub[0]=0xff;
masker.ub[1]=0;
masker.ub[2]=0xff;
masker.ub[3]=0;
masker.ub[4]=0xff;
masker.ub[5]=0;
masker.ub[6]=0xff;
masker.ub[7]=0;
pxor_r2r(mm7,mm7);
movq_m2r(rounder,mm6);
#endif
while (read(s->fd,src,s->width*4) < 0) {
usleep(100);
}
ptrend = &src[s->width*4];
for (h = 0; h < s->height-2; h+=2) {
for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=8, cb+=4, cr+=4) {
LINE_WITHUV_AVG
}
read(s->fd,src,s->width*4);
#ifdef HAVE_MMX
movq_m2r(masker,mm5);
#endif
for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=8) {
LINE_NOUV_AVG
}
read(s->fd,src,s->width*4);
}
/*
* Do last two lines
*/
for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=8, cb+=4, cr+=4) {
LINE_WITHUV_AVG
}
read(s->fd,src,s->width*4);
#ifdef HAVE_MMX
movq_m2r(masker,mm5);
#endif
for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=8) {
LINE_NOUV_AVG
}
/* drop second field */
while (read(s->fd,src,s->width*4) < 0) {
usleep(100);
}
for (h = 0; h < s->height - 1; h++) {
read(s->fd,src,s->width*4);
}
} else {
UINT8 *lum_m1, *lum_m2, *lum_m3, *lum_m4;
#ifdef HAVE_MMX
mmx_t rounder;
rounder.uw[0]=4;
rounder.uw[1]=4;
rounder.uw[2]=4;
rounder.uw[3]=4;
movq_m2r(rounder,mm6);
pxor_r2r(mm7,mm7);
#else
UINT8 *cm = cropTbl + MAX_NEG_CROP;
#endif
/* read two fields and deinterlace them */
while (read(s->fd,src,s->width*2) < 0) {
usleep(100);
}
for (h = 0; h < (s->height/2)-2; h+=2) {
for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=16, cb+=8, cr+=8) {
LINE_WITH_UV
}
read(s->fd,src,s->width*2);
/* skip a luminance line - will be filled in later */
lum += s->width;
for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=16, cb+=8, cr+=8) {
LINE_WITH_UV
}
/* skip a luminance line - will be filled in later */
lum += s->width;
read(s->fd,src,s->width*2);
}
/*
* Do last two lines
*/
for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=16, cb+=8, cr+=8) {
LINE_WITH_UV
}
/* skip a luminance line - will be filled in later */
lum += s->width;
read(s->fd,src,s->width*2);
for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=16, cb+=8, cr+=8) {
LINE_WITH_UV
}
/*
*
* SECOND FIELD
*
*/
lum=&data[s->width];
while (read(s->fd,src,s->width*2) < 0) {
usleep(10);
}
/* First (and last) two lines not interlaced */
for (h = 0; h < 2; h++) {
for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=16) {
LINE_NO_UV
}
read(s->fd,src,s->width*2);
/* skip a luminance line */
lum += s->width;
}
lum_m1=&lum[-s->width];
lum_m2=&lum_m1[-s->width];
lum_m3=&lum_m2[-s->width];
memmove(s->lum_m4_mem,&lum_m3[-s->width],s->width);
for (; h < (s->height/2)-1; h++) {
lum_m4=s->lum_m4_mem;
for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=16,lum_m1+=16,lum_m2+=16,lum_m3+=16,lum_m4+=16) {
LINE_NO_UV
DEINT_LINE_LUM(0)
DEINT_LINE_LUM(4)
DEINT_LINE_LUM(8)
DEINT_LINE_LUM(12)
}
read(s->fd,src,s->width*2);
/* skip a luminance line */
lum += s->width;
lum_m1 += s->width;
lum_m2 += s->width;
lum_m3 += s->width;
// lum_m4 += s->width;
}
/*
* Do last line
*/
lum_m4=s->lum_m4_mem;
for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=16, lum_m1+=16, lum_m2+=16, lum_m3+=16, lum_m4+=16) {
LINE_NO_UV
DEINT_LINE_LUM(0)
DEINT_LINE_LUM(4)
DEINT_LINE_LUM(8)
DEINT_LINE_LUM(12)
}
}
#ifdef HAVE_MMX
emms();
#endif
return s->frame_size;
}
static int aiw_close(VideoData *s)
{
av_freep(&s->lum_m4_mem);
av_freep(&s->src_mem);
return 0;
}
int video_grab_init(void)
{
av_register_input_format(&video_grab_device_format);
return 0;
}

290
libavformat/http.c Normal file
View File

@@ -0,0 +1,290 @@
/*
* HTTP protocol for ffmpeg client
* Copyright (c) 2000, 2001 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"
#include <unistd.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#ifndef __BEOS__
# include <arpa/inet.h>
#else
# include "barpainet.h"
#endif
#include <netdb.h>
/* XXX: POST protocol is not completly implemented because ffmpeg use
only a subset of it */
//#define DEBUG
/* used for protocol handling */
#define BUFFER_SIZE 1024
#define URL_SIZE 4096
typedef struct {
URLContext *hd;
unsigned char buffer[BUFFER_SIZE], *buf_ptr, *buf_end;
int line_count;
int http_code;
char location[URL_SIZE];
} HTTPContext;
static int http_connect(URLContext *h, const char *path, const char *hoststr);
static int http_write(URLContext *h, UINT8 *buf, int size);
/* return non zero if error */
static int http_open(URLContext *h, const char *uri, int flags)
{
const char *path, *proxy_path;
char hostname[1024], hoststr[1024];
char path1[1024];
char buf[1024];
int port, use_proxy, err;
HTTPContext *s;
URLContext *hd = NULL;
h->is_streamed = 1;
s = av_malloc(sizeof(HTTPContext));
if (!s) {
return -ENOMEM;
}
h->priv_data = s;
proxy_path = getenv("http_proxy");
use_proxy = (proxy_path != NULL) && !getenv("no_proxy") &&
strstart(proxy_path, "http://", NULL);
/* fill the dest addr */
redo:
/* needed in any case to build the host string */
url_split(NULL, 0, hostname, sizeof(hostname), &port,
path1, sizeof(path1), uri);
if (port > 0) {
snprintf(hoststr, sizeof(hoststr), "%s:%d", hostname, port);
} else {
pstrcpy(hoststr, sizeof(hoststr), hostname);
}
if (use_proxy) {
url_split(NULL, 0, hostname, sizeof(hostname), &port,
NULL, 0, proxy_path);
path = uri;
} else {
if (path1[0] == '\0')
path = "/";
else
path = path1;
}
if (port < 0)
port = 80;
snprintf(buf, sizeof(buf), "tcp://%s:%d", hostname, port);
err = url_open(&hd, buf, URL_RDWR);
if (err < 0)
goto fail;
s->hd = hd;
if (http_connect(h, path, hoststr) < 0)
goto fail;
if (s->http_code == 303 && s->location[0] != '\0') {
/* url moved, get next */
uri = s->location;
url_close(hd);
goto redo;
}
return 0;
fail:
if (hd)
url_close(hd);
av_free(s);
return -EIO;
}
static int http_getc(HTTPContext *s)
{
int len;
if (s->buf_ptr >= s->buf_end) {
len = url_read(s->hd, s->buffer, BUFFER_SIZE);
if (len < 0) {
return -EIO;
} else if (len == 0) {
return -1;
} else {
s->buf_ptr = s->buffer;
s->buf_end = s->buffer + len;
}
}
return *s->buf_ptr++;
}
static int process_line(HTTPContext *s, char *line, int line_count)
{
char *tag, *p;
/* end of header */
if (line[0] == '\0')
return 0;
p = line;
if (line_count == 0) {
while (!isspace(*p) && *p != '\0')
p++;
while (isspace(*p))
p++;
s->http_code = strtol(p, NULL, 10);
#ifdef DEBUG
printf("http_code=%d\n", s->http_code);
#endif
} else {
while (*p != '\0' && *p != ':')
p++;
if (*p != ':')
return 1;
*p = '\0';
tag = line;
p++;
while (isspace(*p))
p++;
if (!strcmp(tag, "Location")) {
strcpy(s->location, p);
}
}
return 1;
}
static int http_connect(URLContext *h, const char *path, const char *hoststr)
{
HTTPContext *s = h->priv_data;
int post, err, ch;
char line[1024], *q;
/* send http header */
post = h->flags & URL_WRONLY;
snprintf(s->buffer, sizeof(s->buffer),
"%s %s HTTP/1.0\n"
"User-Agent: FFmpeg %s\n"
"Accept: */*\n"
"Host: %s\n"
"\n",
post ? "POST" : "GET",
path,
FFMPEG_VERSION,
hoststr);
if (http_write(h, s->buffer, strlen(s->buffer)) < 0)
return -EIO;
/* init input buffer */
s->buf_ptr = s->buffer;
s->buf_end = s->buffer;
s->line_count = 0;
s->location[0] = '\0';
if (post) {
sleep(1);
return 0;
}
/* wait for header */
q = line;
for(;;) {
ch = http_getc(s);
if (ch < 0)
return -EIO;
if (ch == '\n') {
/* process line */
if (q > line && q[-1] == '\r')
q--;
*q = '\0';
#ifdef DEBUG
printf("header='%s'\n", line);
#endif
err = process_line(s, line, s->line_count);
if (err < 0)
return err;
if (err == 0)
return 0;
s->line_count++;
q = line;
} else {
if ((q - line) < sizeof(line) - 1)
*q++ = ch;
}
}
}
static int http_read(URLContext *h, UINT8 *buf, int size)
{
HTTPContext *s = h->priv_data;
int size1, len;
size1 = size;
while (size > 0) {
/* read bytes from input buffer first */
len = s->buf_end - s->buf_ptr;
if (len > 0) {
if (len > size)
len = size;
memcpy(buf, s->buf_ptr, len);
s->buf_ptr += len;
} else {
len = url_read (s->hd, buf, size);
if (len < 0) {
return len;
} else if (len == 0) {
break;
}
}
size -= len;
buf += len;
}
return size1 - size;
}
/* used only when posting data */
static int http_write(URLContext *h, UINT8 *buf, int size)
{
HTTPContext *s = h->priv_data;
return url_write(s->hd, buf, size);
}
static int http_close(URLContext *h)
{
HTTPContext *s = h->priv_data;
url_close(s->hd);
av_free(s);
return 0;
}
URLProtocol http_protocol = {
"http",
http_open,
http_read,
http_write,
NULL, /* seek */
http_close,
};

945
libavformat/img.c Normal file
View File

@@ -0,0 +1,945 @@
/*
* Image format
* Copyright (c) 2000, 2001, 2002 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"
extern AVInputFormat pgm_iformat;
extern AVOutputFormat pgm_oformat;
extern AVInputFormat pgmyuv_iformat;
extern AVOutputFormat pgmyuv_oformat;
extern AVInputFormat ppm_iformat;
extern AVOutputFormat ppm_oformat;
extern AVInputFormat imgyuv_iformat;
extern AVOutputFormat imgyuv_oformat;
extern AVInputFormat pgmpipe_iformat;
extern AVOutputFormat pgmpipe_oformat;
extern AVInputFormat pgmyuvpipe_iformat;
extern AVOutputFormat pgmyuvpipe_oformat;
extern AVInputFormat ppmpipe_iformat;
extern AVOutputFormat ppmpipe_oformat;
extern AVOutputFormat yuv4mpegpipe_oformat;
#define IMGFMT_YUV 1
#define IMGFMT_PGMYUV 2
#define IMGFMT_PGM 3
#define IMGFMT_PPM 4
#define IMGFMT_YUV4MPEG 5
#define Y4M_MAGIC "YUV4MPEG2"
#define Y4M_FRAME_MAGIC "FRAME"
#define Y4M_LINE_MAX 256
typedef struct {
int width;
int height;
int img_number;
int img_size;
int img_fmt;
int is_pipe;
int header_written;
char path[1024];
} VideoData;
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;
do {
c=get_byte(f);
if (c=='#') {
do {
c=get_byte(f);
} while (c!='\n');
c=get_byte(f);
}
} while (pnm_space(c));
s=str;
do {
if (url_feof(f))
break;
if ((s - str) < buf_size - 1)
*s++=c;
c=get_byte(f);
} while (!pnm_space(c));
*s = '\0';
}
static int pgm_read(VideoData *s, ByteIOContext *f, UINT8 *buf, int size, int is_yuv)
{
int width, height, i;
char buf1[32];
UINT8 *picture[3];
width = s->width;
height = s->height;
pnm_get(f, buf1, sizeof(buf1));
if (strcmp(buf1, "P5")) {
return -EIO;
}
pnm_get(f, buf1, sizeof(buf1));
pnm_get(f, buf1, sizeof(buf1));
pnm_get(f, buf1, sizeof(buf1));
picture[0] = buf;
picture[1] = buf + width * height;
picture[2] = buf + width * height + (width * height / 4);
get_buffer(f, picture[0], width * height);
height>>=1;
width>>=1;
if (is_yuv) {
for(i=0;i<height;i++) {
get_buffer(f, picture[1] + i * width, width);
get_buffer(f, picture[2] + i * width, width);
}
} else {
for(i=0;i<height;i++) {
memset(picture[1] + i * width, 128, width);
memset(picture[2] + i * width, 128, width);
}
}
return 0;
}
static int ppm_read(VideoData *s, ByteIOContext *f, UINT8 *buf, int size)
{
int width, height;
char buf1[32];
UINT8 *picture[3];
width = s->width;
height = s->height;
pnm_get(f, buf1, sizeof(buf1));
if (strcmp(buf1, "P6")) {
return -EIO;
}
pnm_get(f, buf1, sizeof(buf1));
pnm_get(f, buf1, sizeof(buf1));
pnm_get(f, buf1, sizeof(buf1));
picture[0] = buf;
get_buffer(f, picture[0], width * height*3);
return 0;
}
static int yuv_read(VideoData *s, const char *filename, UINT8 *buf, int size1)
{
ByteIOContext pb1, *pb = &pb1;
char fname[1024], *p;
int size;
size = s->width * s->height;
strcpy(fname, filename);
p = strrchr(fname, '.');
if (!p || p[1] != 'Y')
return -EIO;
if (url_fopen(pb, fname, URL_RDONLY) < 0)
return -EIO;
get_buffer(pb, buf, size);
url_fclose(pb);
p[1] = 'U';
if (url_fopen(pb, fname, URL_RDONLY) < 0)
return -EIO;
get_buffer(pb, buf + size, size / 4);
url_fclose(pb);
p[1] = 'V';
if (url_fopen(pb, fname, URL_RDONLY) < 0)
return -EIO;
get_buffer(pb, buf + size + (size / 4), size / 4);
url_fclose(pb);
return 0;
}
static int img_read_packet(AVFormatContext *s1, AVPacket *pkt)
{
VideoData *s = s1->priv_data;
char filename[1024];
int ret;
ByteIOContext f1, *f;
/*
This if-statement destroys pipes - I do not see why it is necessary
if (get_frame_filename(filename, sizeof(filename),
s->path, s->img_number) < 0)
return -EIO;
*/
get_frame_filename(filename, sizeof(filename),
s->path, s->img_number);
if (!s->is_pipe) {
f = &f1;
if (url_fopen(f, filename, URL_RDONLY) < 0)
return -EIO;
} else {
f = &s1->pb;
if (url_feof(f))
return -EIO;
}
av_new_packet(pkt, s->img_size);
pkt->stream_index = 0;
switch(s->img_fmt) {
case IMGFMT_PGMYUV:
ret = pgm_read(s, f, pkt->data, pkt->size, 1);
break;
case IMGFMT_PGM:
ret = pgm_read(s, f, pkt->data, pkt->size, 0);
break;
case IMGFMT_YUV:
ret = yuv_read(s, filename, pkt->data, pkt->size);
break;
case IMGFMT_PPM:
ret = ppm_read(s, f, pkt->data, pkt->size);
break;
default:
return -EIO;
}
if (!s->is_pipe) {
url_fclose(f);
}
if (ret < 0) {
av_free_packet(pkt);
return -EIO; /* signal EOF */
} else {
pkt->pts = ((INT64)s->img_number * s1->pts_den * FRAME_RATE_BASE) / (s1->streams[0]->codec.frame_rate * s1->pts_num);
s->img_number++;
return 0;
}
}
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 img_read_header(AVFormatContext *s1, AVFormatParameters *ap)
{
VideoData *s = s1->priv_data;
int i, h;
char buf[1024];
char buf1[32];
ByteIOContext pb1, *f = &pb1;
AVStream *st;
st = av_new_stream(s1, 0);
if (!st) {
av_free(s);
return -ENOMEM;
}
strcpy(s->path, s1->filename);
s->img_number = 0;
/* find format */
if (s1->iformat->flags & AVFMT_NOFILE)
s->is_pipe = 0;
else
s->is_pipe = 1;
if (s1->iformat == &pgmyuvpipe_iformat ||
s1->iformat == &pgmyuv_iformat)
s->img_fmt = IMGFMT_PGMYUV;
else if (s1->iformat == &pgmpipe_iformat ||
s1->iformat == &pgm_iformat)
s->img_fmt = IMGFMT_PGM;
else if (s1->iformat == &imgyuv_iformat)
s->img_fmt = IMGFMT_YUV;
else if (s1->iformat == &ppmpipe_iformat ||
s1->iformat == &ppm_iformat)
s->img_fmt = IMGFMT_PPM;
else
goto fail;
if (!s->is_pipe) {
/* try to find the first image */
for(i=0;i<5;i++) {
if (get_frame_filename(buf, sizeof(buf), s->path, s->img_number) < 0)
goto fail;
if (url_fopen(f, buf, URL_RDONLY) >= 0)
break;
s->img_number++;
}
if (i == 5)
goto fail;
} else {
f = &s1->pb;
}
/* find the image size */
/* XXX: use generic file format guessing, as mpeg */
switch(s->img_fmt) {
case IMGFMT_PGM:
case IMGFMT_PGMYUV:
case IMGFMT_PPM:
pnm_get(f, buf1, sizeof(buf1));
pnm_get(f, buf1, sizeof(buf1));
s->width = atoi(buf1);
pnm_get(f, buf1, sizeof(buf1));
h = atoi(buf1);
if (s->img_fmt == IMGFMT_PGMYUV)
h = (h * 2) / 3;
s->height = h;
if (s->width <= 0 ||
s->height <= 0 ||
(s->width % 2) != 0 ||
(s->height % 2) != 0) {
goto fail1;
}
break;
case IMGFMT_YUV:
/* infer size by using the file size. */
{
int img_size;
URLContext *h;
/* XXX: hack hack */
h = url_fileno(f);
img_size = url_seek(h, 0, SEEK_END);
if (infer_size(&s->width, &s->height, img_size) < 0) {
goto fail1;
}
}
break;
}
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;
if (s->img_fmt == IMGFMT_PPM) {
st->codec.pix_fmt = PIX_FMT_RGB24;
s->img_size = (s->width * s->height * 3);
} else {
st->codec.pix_fmt = PIX_FMT_YUV420P;
s->img_size = (s->width * s->height * 3) / 2;
}
if (!ap || !ap->frame_rate)
st->codec.frame_rate = 25 * FRAME_RATE_BASE;
else
st->codec.frame_rate = ap->frame_rate;
return 0;
fail1:
if (!s->is_pipe)
url_fclose(f);
fail:
av_free(s);
return -EIO;
}
static int img_read_close(AVFormatContext *s1)
{
return 0;
}
/******************************************************/
/* image output */
static int pgm_save(AVPicture *picture, int width, int height, ByteIOContext *pb, int is_yuv)
{
int i, h;
char buf[100];
UINT8 *ptr, *ptr1, *ptr2;
h = height;
if (is_yuv)
h = (height * 3) / 2;
snprintf(buf, sizeof(buf),
"P5\n%d %d\n%d\n",
width, h, 255);
put_buffer(pb, buf, strlen(buf));
ptr = picture->data[0];
for(i=0;i<height;i++) {
put_buffer(pb, ptr, width);
ptr += picture->linesize[0];
}
if (is_yuv) {
height >>= 1;
width >>= 1;
ptr1 = picture->data[1];
ptr2 = picture->data[2];
for(i=0;i<height;i++) {
put_buffer(pb, ptr1, width);
put_buffer(pb, ptr2, width);
ptr1 += picture->linesize[1];
ptr2 += picture->linesize[2];
}
}
put_flush_packet(pb);
return 0;
}
static int ppm_save(AVPicture *picture, int width, int height, ByteIOContext *pb)
{
int i;
char buf[100];
UINT8 *ptr;
snprintf(buf, sizeof(buf),
"P6\n%d %d\n%d\n",
width, height, 255);
put_buffer(pb, buf, strlen(buf));
ptr = picture->data[0];
for(i=0;i<height;i++) {
put_buffer(pb, ptr, width * 3);
ptr += picture->linesize[0];
}
put_flush_packet(pb);
return 0;
}
static int yuv_save(AVPicture *picture, int width, int height, const char *filename)
{
ByteIOContext pb1, *pb = &pb1;
char fname[1024], *p;
int i, j;
UINT8 *ptr;
static char *ext = "YUV";
strcpy(fname, filename);
p = strrchr(fname, '.');
if (!p || p[1] != 'Y')
return -EIO;
for(i=0;i<3;i++) {
if (i == 1) {
width >>= 1;
height >>= 1;
}
p[1] = ext[i];
if (url_fopen(pb, fname, URL_WRONLY) < 0)
return -EIO;
ptr = picture->data[i];
for(j=0;j<height;j++) {
put_buffer(pb, ptr, width);
ptr += picture->linesize[i];
}
put_flush_packet(pb);
url_fclose(pb);
}
return 0;
}
static int yuv4mpeg_save(AVPicture *picture, int width, int height, ByteIOContext *pb, int need_stream_header,
int is_yuv, int raten, int rated, int aspectn, int aspectd)
{
int i, n, m;
char buf[Y4M_LINE_MAX+1], buf1[20];
UINT8 *ptr, *ptr1, *ptr2;
/* construct stream header, if this is the first frame */
if(need_stream_header) {
n = snprintf(buf, sizeof(buf), "%s W%d H%d F%d:%d I%s A%d:%d\n",
Y4M_MAGIC,
width,
height,
raten, rated,
"p", /* ffmpeg seems to only output progressive video */
aspectn, aspectd);
if (n < 0) {
fprintf(stderr, "Error. YUV4MPEG stream header write failed.\n");
} else {
fprintf(stderr, "YUV4MPEG stream header written. FPS is %d\n", raten);
put_buffer(pb, buf, strlen(buf));
}
}
/* construct frame header */
m = snprintf(buf1, sizeof(buf1), "%s \n", Y4M_FRAME_MAGIC);
if (m < 0) {
fprintf(stderr, "Error. YUV4MPEG frame header write failed.\n");
} else {
/* fprintf(stderr, "YUV4MPEG frame header written.\n"); */
put_buffer(pb, buf1, strlen(buf1));
}
ptr = picture->data[0];
for(i=0;i<height;i++) {
put_buffer(pb, ptr, width);
ptr += picture->linesize[0];
}
if (is_yuv) {
height >>= 1;
width >>= 1;
ptr1 = picture->data[1];
ptr2 = picture->data[2];
for(i=0;i<height;i++) { /* Cb */
put_buffer(pb, ptr1, width);
ptr1 += picture->linesize[1];
}
for(i=0;i<height;i++) { /* Cr */
put_buffer(pb, ptr2, width);
ptr2 += picture->linesize[2];
}
}
put_flush_packet(pb);
return 0;
}
static int img_write_header(AVFormatContext *s)
{
VideoData *img = s->priv_data;
img->img_number = 1;
strcpy(img->path, s->filename);
/* find format */
if (s->oformat->flags & AVFMT_NOFILE)
img->is_pipe = 0;
else
img->is_pipe = 1;
if (s->oformat == &pgmyuvpipe_oformat ||
s->oformat == &pgmyuv_oformat) {
img->img_fmt = IMGFMT_PGMYUV;
} else if (s->oformat == &pgmpipe_oformat ||
s->oformat == &pgm_oformat) {
img->img_fmt = IMGFMT_PGM;
} else if (s->oformat == &imgyuv_oformat) {
img->img_fmt = IMGFMT_YUV;
} else if (s->oformat == &ppmpipe_oformat ||
s->oformat == &ppm_oformat) {
img->img_fmt = IMGFMT_PPM;
} else if (s->oformat == &yuv4mpegpipe_oformat) {
img->img_fmt = IMGFMT_YUV4MPEG;
img->header_written = 0;
} else {
goto fail;
}
return 0;
fail:
av_free(img);
return -EIO;
}
static int img_write_packet(AVFormatContext *s, int stream_index,
UINT8 *buf, int size, int force_pts)
{
VideoData *img = s->priv_data;
AVStream *st = s->streams[stream_index];
ByteIOContext pb1, *pb;
AVPicture picture;
int width, height, need_stream_header, ret, size1, raten, rated, aspectn, aspectd, fps, fps1;
char filename[1024];
width = st->codec.width;
height = st->codec.height;
if (img->img_number == 1) {
need_stream_header = 1;
} else {
need_stream_header = 0;
}
fps = st->codec.frame_rate;
fps1 = (((float)fps / FRAME_RATE_BASE) * 1000);
/* Sorry about this messy code, but mpeg2enc is very picky about
* the framerates it accepts. */
switch(fps1) {
case 23976:
raten = 24000; /* turn the framerate into a ratio */
rated = 1001;
break;
case 29970:
raten = 30000;
rated = 1001;
break;
case 25000:
raten = 25;
rated = 1;
break;
case 30000:
raten = 30;
rated = 1;
break;
case 24000:
raten = 24;
rated = 1;
break;
case 50000:
raten = 50;
rated = 1;
break;
case 59940:
raten = 60000;
rated = 1001;
break;
case 60000:
raten = 60;
rated = 1;
break;
default:
raten = fps1; /* this setting should work, but often doesn't */
rated = 1000;
break;
}
aspectn = 1;
aspectd = 1; /* ffmpeg always uses a 1:1 aspect ratio */
switch(st->codec.pix_fmt) {
case PIX_FMT_YUV420P:
size1 = (width * height * 3) / 2;
if (size != size1)
return -EIO;
picture.data[0] = buf;
picture.data[1] = picture.data[0] + width * height;
picture.data[2] = picture.data[1] + (width * height) / 4;
picture.linesize[0] = width;
picture.linesize[1] = width >> 1;
picture.linesize[2] = width >> 1;
break;
case PIX_FMT_RGB24:
size1 = (width * height * 3);
if (size != size1)
return -EIO;
picture.data[0] = buf;
picture.linesize[0] = width * 3;
break;
default:
return -EIO;
}
/*
This if-statement destroys pipes - I do not see why it is necessary
if (get_frame_filename(filename, sizeof(filename),
img->path, img->img_number) < 0)
return -EIO;
*/
get_frame_filename(filename, sizeof(filename),
img->path, img->img_number);
if (!img->is_pipe) {
pb = &pb1;
if (url_fopen(pb, filename, URL_WRONLY) < 0)
return -EIO;
} else {
pb = &s->pb;
}
switch(img->img_fmt) {
case IMGFMT_PGMYUV:
ret = pgm_save(&picture, width, height, pb, 1);
break;
case IMGFMT_PGM:
ret = pgm_save(&picture, width, height, pb, 0);
break;
case IMGFMT_YUV:
ret = yuv_save(&picture, width, height, filename);
break;
case IMGFMT_PPM:
ret = ppm_save(&picture, width, height, pb);
break;
case IMGFMT_YUV4MPEG:
ret = yuv4mpeg_save(&picture, width, height, pb,
need_stream_header, 1, raten, rated, aspectn, aspectd);
break;
}
if (!img->is_pipe) {
url_fclose(pb);
}
img->img_number++;
return 0;
}
static int img_write_trailer(AVFormatContext *s)
{
return 0;
}
static AVInputFormat pgm_iformat = {
"pgm",
"pgm image format",
sizeof(VideoData),
NULL,
img_read_header,
img_read_packet,
img_read_close,
NULL,
AVFMT_NOFILE | AVFMT_NEEDNUMBER,
.extensions = "pgm",
};
static AVOutputFormat pgm_oformat = {
"pgm",
"pgm image format",
"",
"pgm",
sizeof(VideoData),
CODEC_ID_NONE,
CODEC_ID_RAWVIDEO,
img_write_header,
img_write_packet,
img_write_trailer,
AVFMT_NOFILE | AVFMT_NEEDNUMBER,
};
static AVInputFormat pgmyuv_iformat = {
"pgmyuv",
"pgm with YUV content image format",
sizeof(VideoData),
NULL, /* no probe */
img_read_header,
img_read_packet,
img_read_close,
NULL,
AVFMT_NOFILE | AVFMT_NEEDNUMBER,
};
static AVOutputFormat pgmyuv_oformat = {
"pgmyuv",
"pgm with YUV content image format",
"",
"pgm",
sizeof(VideoData),
CODEC_ID_NONE,
CODEC_ID_RAWVIDEO,
img_write_header,
img_write_packet,
img_write_trailer,
AVFMT_NOFILE | AVFMT_NEEDNUMBER,
};
static AVInputFormat ppm_iformat = {
"ppm",
"ppm image format",
sizeof(VideoData),
NULL,
img_read_header,
img_read_packet,
img_read_close,
NULL,
AVFMT_NOFILE | AVFMT_NEEDNUMBER | AVFMT_RGB24,
.extensions = "ppm",
};
static AVOutputFormat ppm_oformat = {
"ppm",
"ppm image format",
"",
"ppm",
sizeof(VideoData),
CODEC_ID_NONE,
CODEC_ID_RAWVIDEO,
img_write_header,
img_write_packet,
img_write_trailer,
AVFMT_NOFILE | AVFMT_NEEDNUMBER | AVFMT_RGB24,
};
static AVInputFormat imgyuv_iformat = {
".Y.U.V",
".Y.U.V format",
sizeof(VideoData),
NULL,
img_read_header,
img_read_packet,
img_read_close,
NULL,
AVFMT_NOFILE | AVFMT_NEEDNUMBER,
.extensions = "Y",
};
static AVOutputFormat imgyuv_oformat = {
".Y.U.V",
".Y.U.V format",
"",
"Y",
sizeof(VideoData),
CODEC_ID_NONE,
CODEC_ID_RAWVIDEO,
img_write_header,
img_write_packet,
img_write_trailer,
AVFMT_NOFILE | AVFMT_NEEDNUMBER,
};
static AVInputFormat pgmpipe_iformat = {
"pgmpipe",
"PGM pipe format",
sizeof(VideoData),
NULL, /* no probe */
img_read_header,
img_read_packet,
img_read_close,
NULL,
};
static AVOutputFormat pgmpipe_oformat = {
"pgmpipe",
"PGM pipe format",
"",
"pgm",
sizeof(VideoData),
CODEC_ID_NONE,
CODEC_ID_RAWVIDEO,
img_write_header,
img_write_packet,
img_write_trailer,
};
static AVInputFormat pgmyuvpipe_iformat = {
"pgmyuvpipe",
"PGM YUV pipe format",
sizeof(VideoData),
NULL, /* no probe */
img_read_header,
img_read_packet,
img_read_close,
NULL,
};
static AVOutputFormat pgmyuvpipe_oformat = {
"pgmyuvpipe",
"PGM YUV pipe format",
"",
"pgm",
sizeof(VideoData),
CODEC_ID_NONE,
CODEC_ID_RAWVIDEO,
img_write_header,
img_write_packet,
img_write_trailer,
};
static AVInputFormat ppmpipe_iformat = {
"ppmpipe",
"PPM pipe format",
sizeof(VideoData),
NULL, /* no probe */
img_read_header,
img_read_packet,
img_read_close,
NULL,
.flags = AVFMT_RGB24,
};
static AVOutputFormat ppmpipe_oformat = {
"ppmpipe",
"PPM pipe format",
"",
"ppm",
sizeof(VideoData),
CODEC_ID_NONE,
CODEC_ID_RAWVIDEO,
img_write_header,
img_write_packet,
img_write_trailer,
.flags = AVFMT_RGB24,
};
static AVOutputFormat yuv4mpegpipe_oformat = {
"yuv4mpegpipe",
"YUV4MPEG pipe format",
"",
"yuv4mpeg",
sizeof(VideoData),
CODEC_ID_NONE,
CODEC_ID_RAWVIDEO,
img_write_header,
img_write_packet,
img_write_trailer,
};
int img_init(void)
{
av_register_input_format(&pgm_iformat);
av_register_output_format(&pgm_oformat);
av_register_input_format(&pgmyuv_iformat);
av_register_output_format(&pgmyuv_oformat);
av_register_input_format(&ppm_iformat);
av_register_output_format(&ppm_oformat);
av_register_input_format(&imgyuv_iformat);
av_register_output_format(&imgyuv_oformat);
av_register_input_format(&pgmpipe_iformat);
av_register_output_format(&pgmpipe_oformat);
av_register_input_format(&pgmyuvpipe_iformat);
av_register_output_format(&pgmyuvpipe_oformat);
av_register_input_format(&ppmpipe_iformat);
av_register_output_format(&ppmpipe_oformat);
av_register_output_format(&yuv4mpegpipe_oformat);
return 0;
}

266
libavformat/jpeg.c Normal file
View File

@@ -0,0 +1,266 @@
/*
* JPEG based formats
* Copyright (c) 2000, 2001 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"
/* Multipart JPEG */
#define BOUNDARY_TAG "ffserver"
static int mpjpeg_write_header(AVFormatContext *s)
{
UINT8 buf1[256];
snprintf(buf1, sizeof(buf1), "--%s\n", BOUNDARY_TAG);
put_buffer(&s->pb, buf1, strlen(buf1));
put_flush_packet(&s->pb);
return 0;
}
static int mpjpeg_write_packet(AVFormatContext *s, int stream_index,
UINT8 *buf, int size, int force_pts)
{
UINT8 buf1[256];
snprintf(buf1, sizeof(buf1), "Content-type: image/jpeg\n\n");
put_buffer(&s->pb, buf1, strlen(buf1));
put_buffer(&s->pb, buf, size);
snprintf(buf1, sizeof(buf1), "\n--%s\n", BOUNDARY_TAG);
put_buffer(&s->pb, buf1, strlen(buf1));
put_flush_packet(&s->pb);
return 0;
}
static int mpjpeg_write_trailer(AVFormatContext *s)
{
return 0;
}
static AVOutputFormat mpjpeg_format = {
"mpjpeg",
"Mime multipart JPEG format",
"multipart/x-mixed-replace;boundary=" BOUNDARY_TAG,
"mjpg",
0,
CODEC_ID_NONE,
CODEC_ID_MJPEG,
mpjpeg_write_header,
mpjpeg_write_packet,
mpjpeg_write_trailer,
};
/*************************************/
/* single frame JPEG */
static int single_jpeg_write_header(AVFormatContext *s)
{
return 0;
}
static int single_jpeg_write_packet(AVFormatContext *s, int stream_index,
UINT8 *buf, int size, int force_pts)
{
put_buffer(&s->pb, buf, size);
put_flush_packet(&s->pb);
return 1; /* no more data can be sent */
}
static int single_jpeg_write_trailer(AVFormatContext *s)
{
return 0;
}
static AVOutputFormat single_jpeg_format = {
"singlejpeg",
"single JPEG image",
"image/jpeg",
NULL, /* note: no extension to favorize jpeg multiple images match */
0,
CODEC_ID_NONE,
CODEC_ID_MJPEG,
single_jpeg_write_header,
single_jpeg_write_packet,
single_jpeg_write_trailer,
};
/*************************************/
/* multiple jpeg images */
typedef struct JpegContext {
char path[1024];
int img_number;
} JpegContext;
static int jpeg_write_header(AVFormatContext *s1)
{
JpegContext *s;
s = av_mallocz(sizeof(JpegContext));
if (!s)
return -1;
s1->priv_data = s;
pstrcpy(s->path, sizeof(s->path), s1->filename);
s->img_number = 1;
return 0;
}
static int jpeg_write_packet(AVFormatContext *s1, int stream_index,
UINT8 *buf, int size, int force_pts)
{
JpegContext *s = s1->priv_data;
char filename[1024];
ByteIOContext f1, *pb = &f1;
if (get_frame_filename(filename, sizeof(filename),
s->path, s->img_number) < 0)
return -EIO;
if (url_fopen(pb, filename, URL_WRONLY) < 0)
return -EIO;
put_buffer(pb, buf, size);
put_flush_packet(pb);
url_fclose(pb);
s->img_number++;
return 0;
}
static int jpeg_write_trailer(AVFormatContext *s1)
{
return 0;
}
/***/
static int jpeg_read_header(AVFormatContext *s1, AVFormatParameters *ap)
{
JpegContext *s;
int i;
char buf[1024];
ByteIOContext pb1, *f = &pb1;
AVStream *st;
s = av_mallocz(sizeof(JpegContext));
if (!s)
return -1;
s1->priv_data = s;
pstrcpy(s->path, sizeof(s->path), s1->filename);
s1->nb_streams = 1;
st = av_mallocz(sizeof(AVStream));
if (!st) {
av_free(s);
return -ENOMEM;
}
s1->streams[0] = st;
s->img_number = 0;
/* try to find the first image */
for(i=0;i<5;i++) {
if (get_frame_filename(buf, sizeof(buf), s->path, s->img_number) < 0)
goto fail;
if (url_fopen(f, buf, URL_RDONLY) >= 0)
break;
s->img_number++;
}
if (i == 5)
goto fail;
url_fclose(f);
st->codec.codec_type = CODEC_TYPE_VIDEO;
st->codec.codec_id = CODEC_ID_MJPEG;
if (!ap || !ap->frame_rate)
st->codec.frame_rate = 25 * FRAME_RATE_BASE;
else
st->codec.frame_rate = ap->frame_rate;
return 0;
fail:
av_free(s);
return -EIO;
}
static int jpeg_read_packet(AVFormatContext *s1, AVPacket *pkt)
{
JpegContext *s = s1->priv_data;
char filename[1024];
int size;
ByteIOContext f1, *f = &f1;
if (get_frame_filename(filename, sizeof(filename),
s->path, s->img_number) < 0)
return -EIO;
f = &f1;
if (url_fopen(f, filename, URL_RDONLY) < 0)
return -EIO;
size = url_seek(url_fileno(f), 0, SEEK_END);
url_seek(url_fileno(f), 0, SEEK_SET);
av_new_packet(pkt, size);
pkt->stream_index = 0;
get_buffer(f, pkt->data, size);
url_fclose(f);
s->img_number++;
return 0;
}
static int jpeg_read_close(AVFormatContext *s1)
{
return 0;
}
static AVInputFormat jpeg_iformat = {
"jpeg",
"JPEG image",
sizeof(JpegContext),
NULL,
jpeg_read_header,
jpeg_read_packet,
jpeg_read_close,
NULL,
.flags = AVFMT_NOFILE | AVFMT_NEEDNUMBER,
.extensions = "jpg,jpeg",
};
static AVOutputFormat jpeg_oformat = {
"jpeg",
"JPEG image",
"image/jpeg",
"jpg,jpeg",
sizeof(JpegContext),
CODEC_ID_NONE,
CODEC_ID_MJPEG,
jpeg_write_header,
jpeg_write_packet,
jpeg_write_trailer,
.flags = AVFMT_NOFILE | AVFMT_NEEDNUMBER,
};
int jpeg_init(void)
{
av_register_output_format(&mpjpeg_format);
av_register_output_format(&single_jpeg_format);
av_register_input_format(&jpeg_iformat);
av_register_output_format(&jpeg_oformat);
return 0;
}

1347
libavformat/mov.c Normal file

File diff suppressed because it is too large Load Diff

685
libavformat/mpeg.c Normal file
View File

@@ -0,0 +1,685 @@
/*
* MPEG1/2 mux/demux
* Copyright (c) 2000, 2001, 2002 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"
#define MAX_PAYLOAD_SIZE 4096
#define NB_STREAMS 2
typedef struct {
UINT8 buffer[MAX_PAYLOAD_SIZE];
int buffer_ptr;
UINT8 id;
int max_buffer_size; /* in bytes */
int packet_number;
INT64 start_pts;
} StreamInfo;
typedef struct {
int packet_size; /* required packet size */
int packet_data_max_size; /* maximum data size inside a packet */
int packet_number;
int pack_header_freq; /* frequency (in packets^-1) at which we send pack headers */
int system_header_freq;
int mux_rate; /* bitrate in units of 50 bytes/s */
/* stream info */
int audio_bound;
int video_bound;
int is_mpeg2;
int is_vcd;
} MpegMuxContext;
#define PACK_START_CODE ((unsigned int)0x000001ba)
#define SYSTEM_HEADER_START_CODE ((unsigned int)0x000001bb)
#define SEQUENCE_END_CODE ((unsigned int)0x000001b7)
#define PACKET_START_CODE_MASK ((unsigned int)0xffffff00)
#define PACKET_START_CODE_PREFIX ((unsigned int)0x00000100)
#define ISO_11172_END_CODE ((unsigned int)0x000001b9)
/* mpeg2 */
#define PROGRAM_STREAM_MAP 0x1bc
#define PRIVATE_STREAM_1 0x1bd
#define PADDING_STREAM 0x1be
#define PRIVATE_STREAM_2 0x1bf
#define AUDIO_ID 0xc0
#define VIDEO_ID 0xe0
extern AVOutputFormat mpeg1system_mux;
extern AVOutputFormat mpeg1vcd_mux;
extern AVOutputFormat mpeg2vob_mux;
static int put_pack_header(AVFormatContext *ctx,
UINT8 *buf, INT64 timestamp)
{
MpegMuxContext *s = ctx->priv_data;
PutBitContext pb;
init_put_bits(&pb, buf, 128, NULL, NULL);
put_bits(&pb, 32, PACK_START_CODE);
if (s->is_mpeg2) {
put_bits(&pb, 2, 0x2);
} else {
put_bits(&pb, 4, 0x2);
}
put_bits(&pb, 3, (UINT32)((timestamp >> 30) & 0x07));
put_bits(&pb, 1, 1);
put_bits(&pb, 15, (UINT32)((timestamp >> 15) & 0x7fff));
put_bits(&pb, 1, 1);
put_bits(&pb, 15, (UINT32)((timestamp) & 0x7fff));
put_bits(&pb, 1, 1);
if (s->is_mpeg2) {
/* clock extension */
put_bits(&pb, 9, 0);
put_bits(&pb, 1, 1);
}
put_bits(&pb, 1, 1);
put_bits(&pb, 22, s->mux_rate);
put_bits(&pb, 1, 1);
if (s->is_mpeg2) {
put_bits(&pb, 5, 0x1f); /* reserved */
put_bits(&pb, 3, 0); /* stuffing length */
}
flush_put_bits(&pb);
return pbBufPtr(&pb) - pb.buf;
}
static int put_system_header(AVFormatContext *ctx, UINT8 *buf)
{
MpegMuxContext *s = ctx->priv_data;
int size, rate_bound, i, private_stream_coded, id;
PutBitContext pb;
init_put_bits(&pb, buf, 128, NULL, NULL);
put_bits(&pb, 32, SYSTEM_HEADER_START_CODE);
put_bits(&pb, 16, 0);
put_bits(&pb, 1, 1);
rate_bound = s->mux_rate; /* maximum bit rate of the multiplexed stream */
put_bits(&pb, 22, rate_bound);
put_bits(&pb, 1, 1); /* marker */
put_bits(&pb, 6, s->audio_bound);
put_bits(&pb, 1, 1); /* variable bitrate */
put_bits(&pb, 1, 1); /* non constrainted bit stream */
put_bits(&pb, 1, 0); /* audio locked */
put_bits(&pb, 1, 0); /* video locked */
put_bits(&pb, 1, 1); /* marker */
put_bits(&pb, 5, s->video_bound);
put_bits(&pb, 8, 0xff); /* reserved byte */
/* audio stream info */
private_stream_coded = 0;
for(i=0;i<ctx->nb_streams;i++) {
StreamInfo *stream = ctx->streams[i]->priv_data;
id = stream->id;
if (id < 0xc0) {
/* special case for private streams (AC3 use that) */
if (private_stream_coded)
continue;
private_stream_coded = 1;
id = 0xbd;
}
put_bits(&pb, 8, id); /* stream ID */
put_bits(&pb, 2, 3);
if (id < 0xe0) {
/* audio */
put_bits(&pb, 1, 0);
put_bits(&pb, 13, stream->max_buffer_size / 128);
} else {
/* video */
put_bits(&pb, 1, 1);
put_bits(&pb, 13, stream->max_buffer_size / 1024);
}
}
flush_put_bits(&pb);
size = pbBufPtr(&pb) - pb.buf;
/* patch packet size */
buf[4] = (size - 6) >> 8;
buf[5] = (size - 6) & 0xff;
return size;
}
static int mpeg_mux_init(AVFormatContext *ctx)
{
MpegMuxContext *s = ctx->priv_data;
int bitrate, i, mpa_id, mpv_id, ac3_id;
AVStream *st;
StreamInfo *stream;
s->packet_number = 0;
s->is_vcd = (ctx->oformat == &mpeg1vcd_mux);
s->is_mpeg2 = (ctx->oformat == &mpeg2vob_mux);
if (s->is_vcd)
s->packet_size = 2324; /* VCD packet size */
else
s->packet_size = 2048;
/* startcode(4) + length(2) + flags(1) */
s->packet_data_max_size = s->packet_size - 7;
s->audio_bound = 0;
s->video_bound = 0;
mpa_id = AUDIO_ID;
ac3_id = 0x80;
mpv_id = VIDEO_ID;
for(i=0;i<ctx->nb_streams;i++) {
st = ctx->streams[i];
stream = av_mallocz(sizeof(StreamInfo));
if (!stream)
goto fail;
st->priv_data = stream;
switch(st->codec.codec_type) {
case CODEC_TYPE_AUDIO:
if (st->codec.codec_id == CODEC_ID_AC3)
stream->id = ac3_id++;
else
stream->id = mpa_id++;
stream->max_buffer_size = 4 * 1024;
s->audio_bound++;
break;
case CODEC_TYPE_VIDEO:
stream->id = mpv_id++;
stream->max_buffer_size = 46 * 1024;
s->video_bound++;
break;
default:
av_abort();
}
}
/* we increase slightly the bitrate to take into account the
headers. XXX: compute it exactly */
bitrate = 2000;
for(i=0;i<ctx->nb_streams;i++) {
st = ctx->streams[i];
bitrate += st->codec.bit_rate;
}
s->mux_rate = (bitrate + (8 * 50) - 1) / (8 * 50);
if (s->is_vcd || s->is_mpeg2)
/* every packet */
s->pack_header_freq = 1;
else
/* every 2 seconds */
s->pack_header_freq = 2 * bitrate / s->packet_size / 8;
if (s->is_mpeg2)
/* every 200 packets. Need to look at the spec. */
s->system_header_freq = s->pack_header_freq * 40;
else if (s->is_vcd)
/* every 40 packets, this is my invention */
s->system_header_freq = s->pack_header_freq * 40;
else
s->system_header_freq = s->pack_header_freq * 5;
for(i=0;i<ctx->nb_streams;i++) {
stream = ctx->streams[i]->priv_data;
stream->buffer_ptr = 0;
stream->packet_number = 0;
stream->start_pts = -1;
}
return 0;
fail:
for(i=0;i<ctx->nb_streams;i++) {
av_free(ctx->streams[i]->priv_data);
}
return -ENOMEM;
}
/* flush the packet on stream stream_index */
static void flush_packet(AVFormatContext *ctx, int stream_index, int last_pkt)
{
MpegMuxContext *s = ctx->priv_data;
StreamInfo *stream = ctx->streams[stream_index]->priv_data;
UINT8 *buf_ptr;
int size, payload_size, startcode, id, len, stuffing_size, i, header_len;
INT64 timestamp;
UINT8 buffer[128];
int last = last_pkt ? 4 : 0;
id = stream->id;
timestamp = stream->start_pts;
#if 0
printf("packet ID=%2x PTS=%0.3f\n",
id, timestamp / 90000.0);
#endif
buf_ptr = buffer;
if (((s->packet_number % s->pack_header_freq) == 0)) {
/* output pack and systems header if needed */
size = put_pack_header(ctx, buf_ptr, timestamp);
buf_ptr += size;
if ((s->packet_number % s->system_header_freq) == 0) {
size = put_system_header(ctx, buf_ptr);
buf_ptr += size;
}
}
size = buf_ptr - buffer;
put_buffer(&ctx->pb, buffer, size);
/* packet header */
if (s->is_mpeg2) {
header_len = 8;
} else {
header_len = 5;
}
payload_size = s->packet_size - (size + 6 + header_len + last);
if (id < 0xc0) {
startcode = PRIVATE_STREAM_1;
payload_size -= 4;
} else {
startcode = 0x100 + id;
}
stuffing_size = payload_size - stream->buffer_ptr;
if (stuffing_size < 0)
stuffing_size = 0;
put_be32(&ctx->pb, startcode);
put_be16(&ctx->pb, payload_size + header_len);
/* stuffing */
for(i=0;i<stuffing_size;i++)
put_byte(&ctx->pb, 0xff);
if (s->is_mpeg2) {
put_byte(&ctx->pb, 0x80); /* mpeg2 id */
put_byte(&ctx->pb, 0x80); /* flags */
put_byte(&ctx->pb, 0x05); /* header len (only pts is included) */
}
put_byte(&ctx->pb,
(0x02 << 4) |
(((timestamp >> 30) & 0x07) << 1) |
1);
put_be16(&ctx->pb, (UINT16)((((timestamp >> 15) & 0x7fff) << 1) | 1));
put_be16(&ctx->pb, (UINT16)((((timestamp) & 0x7fff) << 1) | 1));
if (startcode == PRIVATE_STREAM_1) {
put_byte(&ctx->pb, id);
if (id >= 0x80 && id <= 0xbf) {
/* XXX: need to check AC3 spec */
put_byte(&ctx->pb, 1);
put_byte(&ctx->pb, 0);
put_byte(&ctx->pb, 2);
}
}
if (last_pkt) {
put_be32(&ctx->pb, ISO_11172_END_CODE);
}
/* output data */
put_buffer(&ctx->pb, stream->buffer, payload_size - stuffing_size);
put_flush_packet(&ctx->pb);
/* preserve remaining data */
len = stream->buffer_ptr - payload_size;
if (len < 0)
len = 0;
memmove(stream->buffer, stream->buffer + stream->buffer_ptr - len, len);
stream->buffer_ptr = len;
s->packet_number++;
stream->packet_number++;
stream->start_pts = -1;
}
static int mpeg_mux_write_packet(AVFormatContext *ctx, int stream_index,
UINT8 *buf, int size, int pts)
{
MpegMuxContext *s = ctx->priv_data;
AVStream *st = ctx->streams[stream_index];
StreamInfo *stream = st->priv_data;
int len;
while (size > 0) {
/* set pts */
if (stream->start_pts == -1) {
stream->start_pts = pts;
}
len = s->packet_data_max_size - stream->buffer_ptr;
if (len > size)
len = size;
memcpy(stream->buffer + stream->buffer_ptr, buf, len);
stream->buffer_ptr += len;
buf += len;
size -= len;
while (stream->buffer_ptr >= s->packet_data_max_size) {
/* output the packet */
if (stream->start_pts == -1)
stream->start_pts = pts;
flush_packet(ctx, stream_index, 0);
}
}
return 0;
}
static int mpeg_mux_end(AVFormatContext *ctx)
{
StreamInfo *stream;
int i;
/* flush each packet */
for(i=0;i<ctx->nb_streams;i++) {
stream = ctx->streams[i]->priv_data;
if (stream->buffer_ptr > 0) {
if (i == (ctx->nb_streams - 1))
flush_packet(ctx, i, 1);
else
flush_packet(ctx, i, 0);
}
}
/* write the end header */
//put_be32(&ctx->pb, ISO_11172_END_CODE);
//put_flush_packet(&ctx->pb);
return 0;
}
/*********************************************/
/* demux code */
#define MAX_SYNC_SIZE 100000
static int mpegps_probe(AVProbeData *p)
{
int code, c, i;
code = 0xff;
/* we search the first start code. If it is a packet start code,
then we decide it is mpeg ps. We do not send highest value to
give a chance to mpegts */
for(i=0;i<p->buf_size;i++) {
c = p->buf[i];
code = (code << 8) | c;
if ((code & 0xffffff00) == 0x100) {
if (code == PACK_START_CODE ||
code == SYSTEM_HEADER_START_CODE ||
(code >= 0x1e0 && code <= 0x1ef) ||
(code >= 0x1c0 && code <= 0x1df) ||
code == PRIVATE_STREAM_2 ||
code == PROGRAM_STREAM_MAP ||
code == PRIVATE_STREAM_1 ||
code == PADDING_STREAM)
return AVPROBE_SCORE_MAX - 1;
else
return 0;
}
}
return 0;
}
typedef struct MpegDemuxContext {
int header_state;
} MpegDemuxContext;
static int find_start_code(ByteIOContext *pb, int *size_ptr,
UINT32 *header_state)
{
unsigned int state, v;
int val, n;
state = *header_state;
n = *size_ptr;
while (n > 0) {
if (url_feof(pb))
break;
v = get_byte(pb);
n--;
if (state == 0x000001) {
state = ((state << 8) | v) & 0xffffff;
val = state;
goto found;
}
state = ((state << 8) | v) & 0xffffff;
}
val = -1;
found:
*header_state = state;
*size_ptr = n;
return val;
}
static int mpegps_read_header(AVFormatContext *s,
AVFormatParameters *ap)
{
MpegDemuxContext *m = s->priv_data;
m->header_state = 0xff;
/* no need to do more */
return 0;
}
static INT64 get_pts(ByteIOContext *pb, int c)
{
INT64 pts;
int val;
if (c < 0)
c = get_byte(pb);
pts = (INT64)((c >> 1) & 0x07) << 30;
val = get_be16(pb);
pts |= (INT64)(val >> 1) << 15;
val = get_be16(pb);
pts |= (INT64)(val >> 1);
return pts;
}
static int mpegps_read_packet(AVFormatContext *s,
AVPacket *pkt)
{
MpegDemuxContext *m = s->priv_data;
AVStream *st;
int len, size, startcode, i, c, flags, header_len, type, codec_id;
INT64 pts, dts;
/* next start code (should be immediately after) */
redo:
m->header_state = 0xff;
size = MAX_SYNC_SIZE;
startcode = find_start_code(&s->pb, &size, &m->header_state);
//printf("startcode=%x pos=0x%Lx\n", startcode, url_ftell(&s->pb));
if (startcode < 0)
return -EIO;
if (startcode == PACK_START_CODE)
goto redo;
if (startcode == SYSTEM_HEADER_START_CODE)
goto redo;
if (startcode == PADDING_STREAM ||
startcode == PRIVATE_STREAM_2) {
/* skip them */
len = get_be16(&s->pb);
url_fskip(&s->pb, len);
goto redo;
}
/* find matching stream */
if (!((startcode >= 0x1c0 && startcode <= 0x1df) ||
(startcode >= 0x1e0 && startcode <= 0x1ef) ||
(startcode == 0x1bd)))
goto redo;
len = get_be16(&s->pb);
pts = AV_NOPTS_VALUE;
dts = AV_NOPTS_VALUE;
/* stuffing */
for(;;) {
c = get_byte(&s->pb);
len--;
/* XXX: for mpeg1, should test only bit 7 */
if (c != 0xff)
break;
}
if ((c & 0xc0) == 0x40) {
/* buffer scale & size */
get_byte(&s->pb);
c = get_byte(&s->pb);
len -= 2;
}
if ((c & 0xf0) == 0x20) {
pts = get_pts(&s->pb, c);
len -= 4;
} else if ((c & 0xf0) == 0x30) {
pts = get_pts(&s->pb, c);
dts = get_pts(&s->pb, -1);
len -= 9;
} else if ((c & 0xc0) == 0x80) {
/* mpeg 2 PES */
if ((c & 0x30) != 0) {
fprintf(stderr, "Encrypted multiplex not handled\n");
return -EIO;
}
flags = get_byte(&s->pb);
header_len = get_byte(&s->pb);
len -= 2;
if (header_len > len)
goto redo;
if ((flags & 0xc0) == 0x80) {
pts = get_pts(&s->pb, -1);
header_len -= 5;
len -= 5;
} if ((flags & 0xc0) == 0xc0) {
pts = get_pts(&s->pb, -1);
dts = get_pts(&s->pb, -1);
header_len -= 10;
len -= 10;
}
len -= header_len;
while (header_len > 0) {
get_byte(&s->pb);
header_len--;
}
}
if (startcode == 0x1bd) {
startcode = get_byte(&s->pb);
len--;
if (startcode >= 0x80 && startcode <= 0xbf) {
/* audio: skip header */
get_byte(&s->pb);
get_byte(&s->pb);
get_byte(&s->pb);
len -= 3;
}
}
/* now find stream */
for(i=0;i<s->nb_streams;i++) {
st = s->streams[i];
if (st->id == startcode)
goto found;
}
if (startcode >= 0x1e0 && startcode <= 0x1ef) {
type = CODEC_TYPE_VIDEO;
codec_id = CODEC_ID_MPEG1VIDEO;
} else if (startcode >= 0x1c0 && startcode <= 0x1df) {
type = CODEC_TYPE_AUDIO;
codec_id = CODEC_ID_MP2;
} else if (startcode >= 0x80 && startcode <= 0x9f) {
type = CODEC_TYPE_AUDIO;
codec_id = CODEC_ID_AC3;
} else {
skip:
/* skip packet */
url_fskip(&s->pb, len);
goto redo;
}
/* no stream found: add a new stream */
st = av_new_stream(s, startcode);
if (!st)
goto skip;
st->codec.codec_type = type;
st->codec.codec_id = codec_id;
found:
av_new_packet(pkt, len);
//printf("\nRead Packet ID: %x PTS: %f Size: %d", startcode,
// (float)pts/90000, len);
get_buffer(&s->pb, pkt->data, pkt->size);
pkt->pts = pts;
pkt->stream_index = st->index;
return 0;
}
static int mpegps_read_close(AVFormatContext *s)
{
return 0;
}
static AVOutputFormat mpeg1system_mux = {
"mpeg",
"MPEG1 System format",
"video/x-mpeg",
"mpg,mpeg",
sizeof(MpegMuxContext),
CODEC_ID_MP2,
CODEC_ID_MPEG1VIDEO,
mpeg_mux_init,
mpeg_mux_write_packet,
mpeg_mux_end,
};
static AVOutputFormat mpeg1vcd_mux = {
"vcd",
"MPEG1 System format (VCD)",
"video/x-mpeg",
NULL,
sizeof(MpegMuxContext),
CODEC_ID_MP2,
CODEC_ID_MPEG1VIDEO,
mpeg_mux_init,
mpeg_mux_write_packet,
mpeg_mux_end,
};
static AVOutputFormat mpeg2vob_mux = {
"vob",
"MPEG2 PS format (VOB)",
"video/x-mpeg",
"vob",
sizeof(MpegMuxContext),
CODEC_ID_MP2,
CODEC_ID_MPEG1VIDEO,
mpeg_mux_init,
mpeg_mux_write_packet,
mpeg_mux_end,
};
static AVInputFormat mpegps_demux = {
"mpeg",
"MPEG PS format",
sizeof(MpegDemuxContext),
mpegps_probe,
mpegps_read_header,
mpegps_read_packet,
mpegps_read_close,
.flags = AVFMT_NOHEADER,
};
int mpegps_init(void)
{
av_register_output_format(&mpeg1system_mux);
av_register_output_format(&mpeg1vcd_mux);
av_register_output_format(&mpeg2vob_mux);
av_register_input_format(&mpegps_demux);
return 0;
}

316
libavformat/mpegts.c Normal file
View File

@@ -0,0 +1,316 @@
/*
* MPEG2 transport stream (aka DVB) demux
* Copyright (c) 2002 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"
#define TS_FEC_PACKET_SIZE 204
#define TS_PACKET_SIZE 188
#define NB_PID_MAX 8192
enum MpegTSState {
MPEGTS_HEADER = 0,
MPEGTS_PESHEADER_FILL,
MPEGTS_PESHEADER_FLAGS,
MPEGTS_PESHEADER_SIZE,
MPEGTS_PESHEADER_READ,
MPEGTS_PAYLOAD,
MPEGTS_SKIP,
};
/* enough for PES header + length */
#define MAX_HEADER_SIZE 6
typedef struct MpegTSStream {
int pid;
enum MpegTSState state;
int last_cc; /* last cc code (-1 if first packet) */
/* used to get the format */
int header_size;
int payload_size;
int pes_header_size;
AVStream *st;
unsigned char header[MAX_HEADER_SIZE];
} MpegTSStream;
typedef struct MpegTSContext {
int raw_packet_size; /* raw packet size, including FEC if present */
MpegTSStream *pids[NB_PID_MAX];
} MpegTSContext;
/* autodetect fec presence. Must have at least 1024 bytes */
static int get_packet_size(const unsigned char *buf, int size)
{
int i;
if (size < (TS_FEC_PACKET_SIZE * 5 + 1))
return -1;
for(i=0;i<5;i++) {
if (buf[i * TS_PACKET_SIZE] != 0x47)
goto try_fec;
}
return TS_PACKET_SIZE;
try_fec:
for(i=0;i<5;i++) {
if (buf[i * TS_FEC_PACKET_SIZE] != 0x47)
return -1;
}
return TS_FEC_PACKET_SIZE;
}
static int mpegts_probe(AVProbeData *p)
{
int size;
size = get_packet_size(p->buf, p->buf_size);
if (size < 0)
return 0;
return AVPROBE_SCORE_MAX;
}
static int mpegts_read_header(AVFormatContext *s,
AVFormatParameters *ap)
{
MpegTSContext *ts = s->priv_data;
ByteIOContext *pb = &s->pb;
unsigned char buf[1024];
int len;
INT64 pos;
/* read the first 1024 bytes to get packet size */
pos = url_ftell(pb);
len = get_buffer(pb, buf, sizeof(buf));
if (len != sizeof(buf))
goto fail;
ts->raw_packet_size = get_packet_size(buf, sizeof(buf));
if (ts->raw_packet_size <= 0)
goto fail;
/* go again to the start */
url_fseek(pb, pos, SEEK_SET);
return 0;
fail:
return -1;
}
/* return non zero if a packet could be constructed */
static int mpegts_push_data(AVFormatContext *s, MpegTSStream *tss,
AVPacket *pkt,
const unsigned char *buf, int buf_size, int is_start)
{
AVStream *st;
const unsigned char *p;
int len, code, codec_type, codec_id;
if (is_start) {
tss->state = MPEGTS_HEADER;
tss->header_size = 0;
}
p = buf;
while (buf_size > 0) {
len = buf_size;
switch(tss->state) {
case MPEGTS_HEADER:
if (len > MAX_HEADER_SIZE - tss->header_size)
len = MAX_HEADER_SIZE - tss->header_size;
memcpy(tss->header, p, len);
tss->header_size += len;
p += len;
buf_size -= len;
if (tss->header_size == MAX_HEADER_SIZE) {
/* we got all the PES or section header. We can now
decide */
#if 0
av_hex_dump(tss->header, tss->header_size);
#endif
if (tss->header[0] == 0x00 && tss->header[1] == 0x00 &&
tss->header[2] == 0x01) {
/* it must be an mpeg2 PES stream */
/* XXX: add AC3 support */
code = tss->header[3] | 0x100;
if (!((code >= 0x1c0 && code <= 0x1df) ||
(code >= 0x1e0 && code <= 0x1ef)))
goto skip;
if (!tss->st) {
/* allocate stream */
if (code >= 0x1c0 && code <= 0x1df) {
codec_type = CODEC_TYPE_AUDIO;
codec_id = CODEC_ID_MP2;
} else {
codec_type = CODEC_TYPE_VIDEO;
codec_id = CODEC_ID_MPEG1VIDEO;
}
st = av_new_stream(s, tss->pid);
if (st) {
st->priv_data = tss;
st->codec.codec_type = codec_type;
st->codec.codec_id = codec_id;
tss->st = st;
}
}
tss->state = MPEGTS_PESHEADER_FILL;
tss->payload_size = (tss->header[4] << 8) | tss->header[5];
if (tss->payload_size == 0)
tss->payload_size = 65536;
} else {
/* otherwise, it should be a table */
/* skip packet */
skip:
tss->state = MPEGTS_SKIP;
continue;
}
}
break;
/**********************************************/
/* PES packing parsing */
case MPEGTS_PESHEADER_FILL:
/* skip filling */
code = *p++;
buf_size--;
tss->payload_size--;
if (code != 0xff) {
if ((code & 0xc0) != 0x80)
goto skip;
tss->state = MPEGTS_PESHEADER_FLAGS;
}
break;
case MPEGTS_PESHEADER_FLAGS:
code = *p++;
buf_size--;
tss->payload_size--;
tss->state = MPEGTS_PESHEADER_SIZE;
break;
case MPEGTS_PESHEADER_SIZE:
tss->pes_header_size = *p++;
buf_size--;
tss->payload_size--;
tss->state = MPEGTS_PESHEADER_READ;
break;
case MPEGTS_PESHEADER_READ:
/* currently we do nothing except skipping */
if (len > tss->pes_header_size)
len = tss->pes_header_size;
p += len;
buf_size -= len;
tss->pes_header_size -= len;
tss->payload_size -= len;
if (tss->pes_header_size == 0)
tss->state = MPEGTS_PAYLOAD;
break;
case MPEGTS_PAYLOAD:
if (len > tss->payload_size)
len = tss->payload_size;
if (len > 0) {
if (tss->st && av_new_packet(pkt, buf_size) == 0) {
memcpy(pkt->data, p, buf_size);
pkt->stream_index = tss->st->index;
return 1;
}
tss->payload_size -= len;
}
buf_size = 0;
break;
case MPEGTS_SKIP:
buf_size = 0;
break;
}
}
return 0;
}
static int mpegts_read_packet(AVFormatContext *s,
AVPacket *pkt)
{
MpegTSContext *ts = s->priv_data;
MpegTSStream *tss;
ByteIOContext *pb = &s->pb;
unsigned char packet[TS_FEC_PACKET_SIZE];
int len, pid, cc, cc_ok, afc;
const unsigned char *p;
for(;;) {
len = get_buffer(pb, packet, ts->raw_packet_size);
if (len != ts->raw_packet_size)
return AVERROR_IO;
/* check paquet sync byte */
/* XXX: accept to resync ? */
if (packet[0] != 0x47)
return AVERROR_INVALIDDATA;
pid = ((packet[1] & 0x1f) << 8) | packet[2];
tss = ts->pids[pid];
if (tss == NULL) {
/* if no pid found, then add a pid context */
tss = av_mallocz(sizeof(MpegTSStream));
if (!tss)
continue;
ts->pids[pid] = tss;
tss->pid = pid;
tss->last_cc = -1;
// printf("new pid=0x%x\n", pid);
}
/* continuity check (currently not used) */
cc = (packet[3] & 0xf);
cc_ok = (tss->last_cc < 0) || ((((tss->last_cc + 1) & 0x0f) == cc));
tss->last_cc = cc;
/* skip adaptation field */
afc = (packet[3] >> 4) & 3;
p = packet + 4;
if (afc == 0) /* reserved value */
continue;
if (afc == 2) /* adaptation field only */
continue;
if (afc == 3) {
/* skip adapation field */
p += p[0] + 1;
}
/* if past the end of packet, ignore */
if (p >= packet + TS_PACKET_SIZE)
continue;
if (mpegts_push_data(s, tss, pkt, p, TS_PACKET_SIZE - (p - packet),
packet[1] & 0x40))
break;
}
return 0;
}
static int mpegts_read_close(AVFormatContext *s)
{
MpegTSContext *ts = s->priv_data;
int i;
for(i=0;i<NB_PID_MAX;i++)
av_free(ts->pids[i]);
return 0;
}
AVInputFormat mpegts_demux = {
"mpegts",
"MPEG2 transport stream format",
sizeof(MpegTSContext),
mpegts_probe,
mpegts_read_header,
mpegts_read_packet,
mpegts_read_close,
.flags = AVFMT_NOHEADER | AVFMT_SHOW_IDS,
};
int mpegts_init(void)
{
av_register_input_format(&mpegts_demux);
return 0;
}

269
libavformat/ogg.c Normal file
View File

@@ -0,0 +1,269 @@
/*
* Ogg bitstream support
* Mark Hills <mark@pogo.org.uk>
*
* Uses libogg, but requires libvorbisenc to construct correct headers
* when containing Vorbis stream -- currently the only format supported
*/
#include <stdio.h>
#include <time.h>
#include <ogg/ogg.h>
#include <vorbis/vorbisenc.h>
#include "avformat.h"
#include "oggvorbis.h"
#define DECODER_BUFFER_SIZE 4096
typedef struct OggContext {
/* output */
ogg_stream_state os ;
int header_handled ;
ogg_int64_t base_packet_no ;
ogg_int64_t base_granule_pos ;
/* input */
ogg_sync_state oy ;
} OggContext ;
static int ogg_write_header(AVFormatContext *avfcontext) {
OggContext *context ;
AVCodecContext *avccontext ;
vorbis_info vi ;
vorbis_dsp_state vd ;
vorbis_comment vc ;
vorbis_block vb ;
ogg_packet header, header_comm, header_code ;
int n ;
if(!(context = malloc(sizeof(OggContext))))
return -1 ;
avfcontext->priv_data = context ;
srand(time(NULL));
ogg_stream_init(&context->os, rand());
for(n = 0 ; n < avfcontext->nb_streams ; n++) {
avccontext = &avfcontext->streams[n]->codec ;
/* begin vorbis specific code */
vorbis_info_init(&vi) ;
/* code copied from libavcodec/oggvorbis.c */
if(oggvorbis_init_encoder(&vi, avccontext) < 0) {
fprintf(stderr, "ogg_write_header: init_encoder failed") ;
return -1 ;
}
vorbis_analysis_init(&vd, &vi) ;
vorbis_block_init(&vd, &vb) ;
vorbis_comment_init(&vc) ;
vorbis_comment_add_tag(&vc, "encoder", "ffmpeg") ;
if(*avfcontext->title)
vorbis_comment_add_tag(&vc, "title", avfcontext->title) ;
vorbis_analysis_headerout(&vd, &vc, &header,
&header_comm, &header_code) ;
ogg_stream_packetin(&context->os, &header) ;
ogg_stream_packetin(&context->os, &header_comm) ;
ogg_stream_packetin(&context->os, &header_code) ;
vorbis_comment_clear(&vc) ;
/* end of vorbis specific code */
context->header_handled = 0 ;
context->base_packet_no = 0 ;
}
return 0 ;
}
static int ogg_write_packet(AVFormatContext *avfcontext,
int stream_index,
unsigned char *buf, int size, int force_pts)
{
OggContext *context = avfcontext->priv_data ;
ogg_packet *op ;
ogg_page og ;
int l = 0 ;
/* flush header packets so audio starts on a new page */
if(!context->header_handled) {
while(ogg_stream_flush(&context->os, &og)) {
put_buffer(&avfcontext->pb, og.header, og.header_len) ;
put_buffer(&avfcontext->pb, og.body, og.body_len) ;
put_flush_packet(&avfcontext->pb);
}
context->header_handled = 1 ;
}
while(l < size) {
op = (ogg_packet*)(buf + l) ;
op->packet = buf + l + sizeof(ogg_packet) ; /* fix data pointer */
if(!context->base_packet_no) { /* this is the first packet */
context->base_packet_no = op->packetno ;
context->base_granule_pos = op->granulepos ;
}
/* correct the fields in the packet -- essential for streaming */
op->packetno -= context->base_packet_no ;
op->granulepos -= context->base_granule_pos ;
ogg_stream_packetin(&context->os, op) ;
l += sizeof(ogg_packet) + op->bytes ;
while(ogg_stream_pageout(&context->os, &og)) {
put_buffer(&avfcontext->pb, og.header, og.header_len) ;
put_buffer(&avfcontext->pb, og.body, og.body_len) ;
put_flush_packet(&avfcontext->pb);
}
}
return 0;
}
static int ogg_write_trailer(AVFormatContext *avfcontext) {
OggContext *context = avfcontext->priv_data ;
ogg_page og ;
while(ogg_stream_flush(&context->os, &og)) {
put_buffer(&avfcontext->pb, og.header, og.header_len) ;
put_buffer(&avfcontext->pb, og.body, og.body_len) ;
put_flush_packet(&avfcontext->pb);
}
ogg_stream_clear(&context->os) ;
return 0 ;
}
static AVOutputFormat ogg_oformat = {
"ogg",
"Ogg Vorbis",
"audio/x-vorbis",
"ogg",
sizeof(OggContext),
CODEC_ID_VORBIS,
0,
ogg_write_header,
ogg_write_packet,
ogg_write_trailer,
} ;
static int next_packet(AVFormatContext *avfcontext, ogg_packet *op) {
OggContext *context = avfcontext->priv_data ;
ogg_page og ;
char *buf ;
while(ogg_stream_packetout(&context->os, op) != 1) {
/* while no pages are available, read in more data to the sync */
while(ogg_sync_pageout(&context->oy, &og) != 1) {
buf = ogg_sync_buffer(&context->oy, DECODER_BUFFER_SIZE) ;
if(get_buffer(&avfcontext->pb, buf, DECODER_BUFFER_SIZE) <= 0)
return 1 ;
ogg_sync_wrote(&context->oy, DECODER_BUFFER_SIZE) ;
}
/* got a page. Feed it into the stream and get the packet */
if(ogg_stream_pagein(&context->os, &og) != 0)
return 1 ;
}
return 0 ;
}
static int ogg_read_header(AVFormatContext *avfcontext, AVFormatParameters *ap)
{
OggContext *context ;
char *buf ;
ogg_page og ;
AVStream *ast ;
if(!(context = malloc(sizeof(OggContext)))) {
perror("malloc") ;
return -1 ;
}
avfcontext->priv_data = context ;
ogg_sync_init(&context->oy) ;
buf = ogg_sync_buffer(&context->oy, DECODER_BUFFER_SIZE) ;
if(get_buffer(&avfcontext->pb, buf, DECODER_BUFFER_SIZE) <= 0)
return -EIO ;
ogg_sync_wrote(&context->oy, DECODER_BUFFER_SIZE) ;
ogg_sync_pageout(&context->oy, &og) ;
ogg_stream_init(&context->os, ogg_page_serialno(&og)) ;
ogg_stream_pagein(&context->os, &og) ;
/* currently only one vorbis stream supported */
ast = av_new_stream(avfcontext, 0) ;
if(!ast)
return AVERROR_NOMEM ;
ast->codec.codec_type = CODEC_TYPE_AUDIO ;
ast->codec.codec_id = CODEC_ID_VORBIS ;
return 0 ;
}
static int ogg_read_packet(AVFormatContext *avfcontext, AVPacket *pkt) {
ogg_packet op ;
if(next_packet(avfcontext, &op))
return -EIO ;
if(av_new_packet(pkt, sizeof(ogg_packet) + op.bytes) < 0)
return -EIO ;
pkt->stream_index = 0 ;
memcpy(pkt->data, &op, sizeof(ogg_packet)) ;
memcpy(pkt->data + sizeof(ogg_packet), op.packet, op.bytes) ;
return sizeof(ogg_packet) + op.bytes ;
}
static int ogg_read_close(AVFormatContext *avfcontext) {
OggContext *context = avfcontext->priv_data ;
ogg_stream_clear(&context->os) ;
ogg_sync_clear(&context->oy) ;
return 0 ;
}
static AVInputFormat ogg_iformat = {
"ogg",
"Ogg Vorbis",
sizeof(OggContext),
NULL,
ogg_read_header,
ogg_read_packet,
ogg_read_close,
.extensions = "ogg",
} ;
int ogg_init(void) {
av_register_output_format(&ogg_oformat) ;
av_register_input_format(&ogg_iformat);
return 0 ;
}

509
libavformat/raw.c Normal file
View File

@@ -0,0 +1,509 @@
/*
* RAW encoder and decoder
* Copyright (c) 2001 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"
/* simple formats */
int raw_write_header(struct AVFormatContext *s)
{
return 0;
}
int raw_write_packet(struct AVFormatContext *s,
int stream_index,
unsigned char *buf, int size, int force_pts)
{
put_buffer(&s->pb, buf, size);
put_flush_packet(&s->pb);
return 0;
}
int raw_write_trailer(struct AVFormatContext *s)
{
return 0;
}
/* raw input */
static int raw_read_header(AVFormatContext *s,
AVFormatParameters *ap)
{
AVStream *st;
int id;
st = av_new_stream(s, 0);
if (!st)
return AVERROR_NOMEM;
if (ap) {
id = s->iformat->value;
if (id == CODEC_ID_RAWVIDEO) {
st->codec.codec_type = CODEC_TYPE_VIDEO;
} else {
st->codec.codec_type = CODEC_TYPE_AUDIO;
}
st->codec.codec_id = id;
switch(st->codec.codec_type) {
case CODEC_TYPE_AUDIO:
st->codec.sample_rate = ap->sample_rate;
st->codec.channels = ap->channels;
break;
case CODEC_TYPE_VIDEO:
st->codec.frame_rate = ap->frame_rate;
st->codec.width = ap->width;
st->codec.height = ap->height;
break;
default:
return -1;
}
} else {
return -1;
}
return 0;
}
#define RAW_PACKET_SIZE 1024
int raw_read_packet(AVFormatContext *s,
AVPacket *pkt)
{
int ret, size;
AVStream *st = s->streams[0];
size= RAW_PACKET_SIZE;
if (av_new_packet(pkt, size) < 0)
return -EIO;
pkt->stream_index = 0;
ret = get_buffer(&s->pb, pkt->data, size);
if (ret <= 0) {
av_free_packet(pkt);
return -EIO;
}
/* note: we need to modify the packet size here to handle the last
packet */
pkt->size = ret;
return ret;
}
int raw_read_close(AVFormatContext *s)
{
return 0;
}
/* mp3 read */
static int mp3_read_header(AVFormatContext *s,
AVFormatParameters *ap)
{
AVStream *st;
st = av_new_stream(s, 0);
if (!st)
return AVERROR_NOMEM;
st->codec.codec_type = CODEC_TYPE_AUDIO;
st->codec.codec_id = CODEC_ID_MP2;
/* the parameters will be extracted from the compressed bitstream */
return 0;
}
/* mpeg1/h263 input */
static int video_read_header(AVFormatContext *s,
AVFormatParameters *ap)
{
AVStream *st;
st = av_new_stream(s, 0);
if (!st)
return AVERROR_NOMEM;
st->codec.codec_type = CODEC_TYPE_VIDEO;
st->codec.codec_id = s->iformat->value;
/* for mjpeg, specify frame rate */
/* for mpeg4 specify it too (most mpeg4 streams dont have the fixed_vop_rate set ...)*/
if (st->codec.codec_id == CODEC_ID_MJPEG || st->codec.codec_id == CODEC_ID_MPEG4) {
if (ap) {
st->codec.frame_rate = ap->frame_rate;
} else {
st->codec.frame_rate = 25 * FRAME_RATE_BASE;
}
}
return 0;
}
#define SEQ_START_CODE 0x000001b3
#define GOP_START_CODE 0x000001b8
#define PICTURE_START_CODE 0x00000100
/* XXX: improve that by looking at several start codes */
static int mpegvideo_probe(AVProbeData *p)
{
int code, c, i;
code = 0xff;
/* we search the first start code. If it is a sequence, gop or
picture start code then we decide it is an mpeg video
stream. We do not send highest value to give a chance to mpegts */
for(i=0;i<p->buf_size;i++) {
c = p->buf[i];
code = (code << 8) | c;
if ((code & 0xffffff00) == 0x100) {
if (code == SEQ_START_CODE ||
code == GOP_START_CODE ||
code == PICTURE_START_CODE)
return 50 - 1;
else
return 0;
}
}
return 0;
}
AVInputFormat mp3_iformat = {
"mp3",
"MPEG audio",
0,
NULL,
mp3_read_header,
raw_read_packet,
raw_read_close,
.extensions = "mp2,mp3", /* XXX: use probe */
};
AVOutputFormat mp2_oformat = {
"mp2",
"MPEG audio layer 2",
"audio/x-mpeg",
"mp2,mp3",
0,
CODEC_ID_MP2,
0,
raw_write_header,
raw_write_packet,
raw_write_trailer,
};
AVInputFormat ac3_iformat = {
"ac3",
"raw ac3",
0,
NULL,
raw_read_header,
raw_read_packet,
raw_read_close,
.extensions = "ac3",
.value = CODEC_ID_AC3,
};
AVOutputFormat ac3_oformat = {
"ac3",
"raw ac3",
"audio/x-ac3",
"ac3",
0,
CODEC_ID_AC3,
0,
raw_write_header,
raw_write_packet,
raw_write_trailer,
};
AVOutputFormat h263_oformat = {
"h263",
"raw h263",
"video/x-h263",
"h263",
0,
0,
CODEC_ID_H263,
raw_write_header,
raw_write_packet,
raw_write_trailer,
};
AVInputFormat m4v_iformat = {
"m4v",
"raw MPEG4 video format",
0,
NULL /*mpegvideo_probe*/,
video_read_header,
raw_read_packet,
raw_read_close,
.extensions = "m4v", //FIXME remove after writing mpeg4_probe
.value = CODEC_ID_MPEG4,
};
AVOutputFormat m4v_oformat = {
"m4v",
"raw MPEG4 video format",
NULL,
"m4v",
0,
CODEC_ID_NONE,
CODEC_ID_MPEG4,
raw_write_header,
raw_write_packet,
raw_write_trailer,
};
AVInputFormat mpegvideo_iformat = {
"mpegvideo",
"MPEG video",
0,
mpegvideo_probe,
video_read_header,
raw_read_packet,
raw_read_close,
.value = CODEC_ID_MPEG1VIDEO,
};
AVOutputFormat mpeg1video_oformat = {
"mpeg1video",
"MPEG video",
"video/x-mpeg",
"mpg,mpeg",
0,
0,
CODEC_ID_MPEG1VIDEO,
raw_write_header,
raw_write_packet,
raw_write_trailer,
};
AVInputFormat mjpeg_iformat = {
"mjpeg",
"MJPEG video",
0,
NULL,
video_read_header,
raw_read_packet,
raw_read_close,
.extensions = "mjpg,mjpeg",
.value = CODEC_ID_MJPEG,
};
AVOutputFormat mjpeg_oformat = {
"mjpeg",
"MJPEG video",
"video/x-mjpeg",
"mjpg,mjpeg",
0,
0,
CODEC_ID_MJPEG,
raw_write_header,
raw_write_packet,
raw_write_trailer,
};
/* pcm formats */
#define PCMDEF(name, long_name, ext, codec) \
AVInputFormat pcm_ ## name ## _iformat = {\
#name,\
long_name,\
0,\
NULL,\
raw_read_header,\
raw_read_packet,\
raw_read_close,\
.extensions = ext,\
.value = codec,\
};\
\
AVOutputFormat pcm_ ## name ## _oformat = {\
#name,\
long_name,\
NULL,\
ext,\
0,\
codec,\
0,\
raw_write_header,\
raw_write_packet,\
raw_write_trailer,\
};
#ifdef WORDS_BIGENDIAN
#define BE_DEF(s) s
#define LE_DEF(s) NULL
#else
#define BE_DEF(s) NULL
#define LE_DEF(s) s
#endif
PCMDEF(s16le, "pcm signed 16 bit little endian format",
LE_DEF("sw"), CODEC_ID_PCM_S16LE)
PCMDEF(s16be, "pcm signed 16 bit big endian format",
BE_DEF("sw"), CODEC_ID_PCM_S16BE)
PCMDEF(u16le, "pcm unsigned 16 bit little endian format",
LE_DEF("uw"), CODEC_ID_PCM_U16LE)
PCMDEF(u16be, "pcm unsigned 16 bit big endian format",
BE_DEF("uw"), CODEC_ID_PCM_U16BE)
PCMDEF(s8, "pcm signed 8 bit format",
"sb", CODEC_ID_PCM_S8)
PCMDEF(u8, "pcm unsigned 8 bit format",
"ub", CODEC_ID_PCM_U8)
PCMDEF(mulaw, "pcm mu law format",
"ul", CODEC_ID_PCM_MULAW)
PCMDEF(alaw, "pcm A law format",
"al", CODEC_ID_PCM_ALAW)
int rawvideo_read_packet(AVFormatContext *s,
AVPacket *pkt)
{
int packet_size, ret, width, height;
AVStream *st = s->streams[0];
width = st->codec.width;
height = st->codec.height;
switch(st->codec.pix_fmt) {
case PIX_FMT_YUV420P:
packet_size = (width * height * 3) / 2;
break;
case PIX_FMT_YUV422:
packet_size = (width * height * 2);
break;
case PIX_FMT_BGR24:
case PIX_FMT_RGB24:
packet_size = (width * height * 3);
break;
default:
av_abort();
break;
}
if (av_new_packet(pkt, packet_size) < 0)
return -EIO;
pkt->stream_index = 0;
#if 0
/* bypass buffered I/O */
ret = url_read(url_fileno(&s->pb), pkt->data, pkt->size);
#else
ret = get_buffer(&s->pb, pkt->data, pkt->size);
#endif
if (ret != pkt->size) {
av_free_packet(pkt);
return -EIO;
} else {
return 0;
}
}
AVInputFormat rawvideo_iformat = {
"rawvideo",
"raw video format",
0,
NULL,
raw_read_header,
rawvideo_read_packet,
raw_read_close,
.extensions = "yuv",
.value = CODEC_ID_RAWVIDEO,
};
AVOutputFormat rawvideo_oformat = {
"rawvideo",
"raw video format",
NULL,
"yuv",
0,
CODEC_ID_NONE,
CODEC_ID_RAWVIDEO,
raw_write_header,
raw_write_packet,
raw_write_trailer,
};
static int null_write_packet(struct AVFormatContext *s,
int stream_index,
unsigned char *buf, int size, int force_pts)
{
return 0;
}
AVOutputFormat null_oformat = {
"null",
"null video format",
NULL,
NULL,
0,
#ifdef WORDS_BIGENDIAN
CODEC_ID_PCM_S16BE,
#else
CODEC_ID_PCM_S16LE,
#endif
CODEC_ID_RAWVIDEO,
raw_write_header,
null_write_packet,
raw_write_trailer,
.flags = AVFMT_NOFILE | AVFMT_RAWPICTURE,
};
int raw_init(void)
{
av_register_input_format(&mp3_iformat);
av_register_output_format(&mp2_oformat);
av_register_input_format(&ac3_iformat);
av_register_output_format(&ac3_oformat);
av_register_output_format(&h263_oformat);
av_register_input_format(&m4v_iformat);
av_register_output_format(&m4v_oformat);
av_register_input_format(&mpegvideo_iformat);
av_register_output_format(&mpeg1video_oformat);
av_register_input_format(&mjpeg_iformat);
av_register_output_format(&mjpeg_oformat);
av_register_input_format(&pcm_s16le_iformat);
av_register_output_format(&pcm_s16le_oformat);
av_register_input_format(&pcm_s16be_iformat);
av_register_output_format(&pcm_s16be_oformat);
av_register_input_format(&pcm_u16le_iformat);
av_register_output_format(&pcm_u16le_oformat);
av_register_input_format(&pcm_u16be_iformat);
av_register_output_format(&pcm_u16be_oformat);
av_register_input_format(&pcm_s8_iformat);
av_register_output_format(&pcm_s8_oformat);
av_register_input_format(&pcm_u8_iformat);
av_register_output_format(&pcm_u8_oformat);
av_register_input_format(&pcm_mulaw_iformat);
av_register_output_format(&pcm_mulaw_oformat);
av_register_input_format(&pcm_alaw_iformat);
av_register_output_format(&pcm_alaw_oformat);
av_register_input_format(&rawvideo_iformat);
av_register_output_format(&rawvideo_oformat);
av_register_output_format(&null_oformat);
return 0;
}

773
libavformat/rm.c Normal file
View File

@@ -0,0 +1,773 @@
/*
* "Real" compatible mux and demux.
* Copyright (c) 2000, 2001 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"
/* in ms */
#define BUFFER_DURATION 0
typedef struct {
int nb_packets;
int packet_total_size;
int packet_max_size;
/* codec related output */
int bit_rate;
float frame_rate;
int nb_frames; /* current frame number */
int total_frames; /* total number of frames */
int num;
AVCodecContext *enc;
} StreamInfo;
typedef struct {
StreamInfo streams[2];
StreamInfo *audio_stream, *video_stream;
int data_pos; /* position of the data after the header */
int nb_packets;
} RMContext;
static void put_str(ByteIOContext *s, const char *tag)
{
put_be16(s,strlen(tag));
while (*tag) {
put_byte(s, *tag++);
}
}
static void put_str8(ByteIOContext *s, const char *tag)
{
put_byte(s, strlen(tag));
while (*tag) {
put_byte(s, *tag++);
}
}
static void rv10_write_header(AVFormatContext *ctx,
int data_size, int index_pos)
{
RMContext *rm = ctx->priv_data;
ByteIOContext *s = &ctx->pb;
StreamInfo *stream;
unsigned char *data_offset_ptr, *start_ptr;
const char *desc, *mimetype;
int nb_packets, packet_total_size, packet_max_size, size, packet_avg_size, i;
int bit_rate, v, duration, flags, data_pos;
start_ptr = s->buf_ptr;
put_tag(s, ".RMF");
put_be32(s,18); /* header size */
put_be16(s,0);
put_be32(s,0);
put_be32(s,4 + ctx->nb_streams); /* num headers */
put_tag(s,"PROP");
put_be32(s, 50);
put_be16(s, 0);
packet_max_size = 0;
packet_total_size = 0;
nb_packets = 0;
bit_rate = 0;
duration = 0;
for(i=0;i<ctx->nb_streams;i++) {
StreamInfo *stream = &rm->streams[i];
bit_rate += stream->bit_rate;
if (stream->packet_max_size > packet_max_size)
packet_max_size = stream->packet_max_size;
nb_packets += stream->nb_packets;
packet_total_size += stream->packet_total_size;
/* select maximum duration */
v = (int) (1000.0 * (float)stream->total_frames / stream->frame_rate);
if (v > duration)
duration = v;
}
put_be32(s, bit_rate); /* max bit rate */
put_be32(s, bit_rate); /* avg bit rate */
put_be32(s, packet_max_size); /* max packet size */
if (nb_packets > 0)
packet_avg_size = packet_total_size / nb_packets;
else
packet_avg_size = 0;
put_be32(s, packet_avg_size); /* avg packet size */
put_be32(s, nb_packets); /* num packets */
put_be32(s, duration); /* duration */
put_be32(s, BUFFER_DURATION); /* preroll */
put_be32(s, index_pos); /* index offset */
/* computation of data the data offset */
data_offset_ptr = s->buf_ptr;
put_be32(s, 0); /* data offset : will be patched after */
put_be16(s, ctx->nb_streams); /* num streams */
flags = 1 | 2; /* save allowed & perfect play */
if (url_is_streamed(s))
flags |= 4; /* live broadcast */
put_be16(s, flags);
/* comments */
put_tag(s,"CONT");
size = strlen(ctx->title) + strlen(ctx->author) + strlen(ctx->copyright) +
strlen(ctx->comment) + 4 * 2 + 10;
put_be32(s,size);
put_be16(s,0);
put_str(s, ctx->title);
put_str(s, ctx->author);
put_str(s, ctx->copyright);
put_str(s, ctx->comment);
for(i=0;i<ctx->nb_streams;i++) {
int codec_data_size;
stream = &rm->streams[i];
if (stream->enc->codec_type == CODEC_TYPE_AUDIO) {
desc = "The Audio Stream";
mimetype = "audio/x-pn-realaudio";
codec_data_size = 73;
} else {
desc = "The Video Stream";
mimetype = "video/x-pn-realvideo";
codec_data_size = 34;
}
put_tag(s,"MDPR");
size = 10 + 9 * 4 + strlen(desc) + strlen(mimetype) + codec_data_size;
put_be32(s, size);
put_be16(s, 0);
put_be16(s, i); /* stream number */
put_be32(s, stream->bit_rate); /* max bit rate */
put_be32(s, stream->bit_rate); /* avg bit rate */
put_be32(s, stream->packet_max_size); /* max packet size */
if (stream->nb_packets > 0)
packet_avg_size = stream->packet_total_size /
stream->nb_packets;
else
packet_avg_size = 0;
put_be32(s, packet_avg_size); /* avg packet size */
put_be32(s, 0); /* start time */
put_be32(s, BUFFER_DURATION); /* preroll */
/* duration */
if (url_is_streamed(s) || !stream->total_frames)
put_be32(s, (int)(3600 * 1000));
else
put_be32(s, (int)(stream->total_frames * 1000 / stream->frame_rate));
put_str8(s, desc);
put_str8(s, mimetype);
put_be32(s, codec_data_size);
if (stream->enc->codec_type == CODEC_TYPE_AUDIO) {
int coded_frame_size, fscode, sample_rate;
sample_rate = stream->enc->sample_rate;
coded_frame_size = (stream->enc->bit_rate *
stream->enc->frame_size) / (8 * sample_rate);
/* audio codec info */
put_tag(s, ".ra");
put_byte(s, 0xfd);
put_be32(s, 0x00040000); /* version */
put_tag(s, ".ra4");
put_be32(s, 0x01b53530); /* stream length */
put_be16(s, 4); /* unknown */
put_be32(s, 0x39); /* header size */
switch(sample_rate) {
case 48000:
case 24000:
case 12000:
fscode = 1;
break;
default:
case 44100:
case 22050:
case 11025:
fscode = 2;
break;
case 32000:
case 16000:
case 8000:
fscode = 3;
}
put_be16(s, fscode); /* codec additional info, for AC3, seems
to be a frequency code */
/* special hack to compensate rounding errors... */
if (coded_frame_size == 557)
coded_frame_size--;
put_be32(s, coded_frame_size); /* frame length */
put_be32(s, 0x51540); /* unknown */
put_be32(s, 0x249f0); /* unknown */
put_be32(s, 0x249f0); /* unknown */
put_be16(s, 0x01);
/* frame length : seems to be very important */
put_be16(s, coded_frame_size);
put_be32(s, 0); /* unknown */
put_be16(s, stream->enc->sample_rate); /* sample rate */
put_be32(s, 0x10); /* unknown */
put_be16(s, stream->enc->channels);
put_str8(s, "Int0"); /* codec name */
put_str8(s, "dnet"); /* codec name */
put_be16(s, 0); /* title length */
put_be16(s, 0); /* author length */
put_be16(s, 0); /* copyright length */
put_byte(s, 0); /* end of header */
} else {
/* video codec info */
put_be32(s,34); /* size */
put_tag(s,"VIDORV10");
put_be16(s, stream->enc->width);
put_be16(s, stream->enc->height);
put_be16(s, (int) stream->frame_rate); /* frames per seconds ? */
put_be32(s,0); /* unknown meaning */
put_be16(s, (int) stream->frame_rate); /* unknown meaning */
put_be32(s,0); /* unknown meaning */
put_be16(s, 8); /* unknown meaning */
/* Seems to be the codec version: only use basic H263. The next
versions seems to add a diffential DC coding as in
MPEG... nothing new under the sun */
put_be32(s,0x10000000);
//put_be32(s,0x10003000);
}
}
/* patch data offset field */
data_pos = s->buf_ptr - start_ptr;
rm->data_pos = data_pos;
data_offset_ptr[0] = data_pos >> 24;
data_offset_ptr[1] = data_pos >> 16;
data_offset_ptr[2] = data_pos >> 8;
data_offset_ptr[3] = data_pos;
/* data stream */
put_tag(s,"DATA");
put_be32(s,data_size + 10 + 8);
put_be16(s,0);
put_be32(s, nb_packets); /* number of packets */
put_be32(s,0); /* next data header */
}
static void write_packet_header(AVFormatContext *ctx, StreamInfo *stream,
int length, int key_frame)
{
int timestamp;
ByteIOContext *s = &ctx->pb;
stream->nb_packets++;
stream->packet_total_size += length;
if (length > stream->packet_max_size)
stream->packet_max_size = length;
put_be16(s,0); /* version */
put_be16(s,length + 12);
put_be16(s, stream->num); /* stream number */
timestamp = (1000 * (float)stream->nb_frames) / stream->frame_rate;
put_be32(s, timestamp); /* timestamp */
put_byte(s, 0); /* reserved */
put_byte(s, key_frame ? 2 : 0); /* flags */
}
static int rm_write_header(AVFormatContext *s)
{
RMContext *rm = s->priv_data;
StreamInfo *stream;
int n;
AVCodecContext *codec;
for(n=0;n<s->nb_streams;n++) {
s->streams[n]->id = n;
codec = &s->streams[n]->codec;
stream = &rm->streams[n];
memset(stream, 0, sizeof(StreamInfo));
stream->num = n;
stream->bit_rate = codec->bit_rate;
stream->enc = codec;
switch(codec->codec_type) {
case CODEC_TYPE_AUDIO:
rm->audio_stream = stream;
stream->frame_rate = (float)codec->sample_rate / (float)codec->frame_size;
/* XXX: dummy values */
stream->packet_max_size = 1024;
stream->nb_packets = 0;
stream->total_frames = stream->nb_packets;
break;
case CODEC_TYPE_VIDEO:
rm->video_stream = stream;
stream->frame_rate = (float)codec->frame_rate / (float)FRAME_RATE_BASE;
/* XXX: dummy values */
stream->packet_max_size = 4096;
stream->nb_packets = 0;
stream->total_frames = stream->nb_packets;
break;
default:
av_abort();
}
}
rv10_write_header(s, 0, 0);
put_flush_packet(&s->pb);
return 0;
}
static int rm_write_audio(AVFormatContext *s, UINT8 *buf, int size)
{
UINT8 *buf1;
RMContext *rm = s->priv_data;
ByteIOContext *pb = &s->pb;
StreamInfo *stream = rm->audio_stream;
int i;
/* XXX: suppress this malloc */
buf1= (UINT8*) av_malloc( size * sizeof(UINT8) );
write_packet_header(s, stream, size, stream->enc->key_frame);
/* for AC3, the words seems to be reversed */
for(i=0;i<size;i+=2) {
buf1[i] = buf[i+1];
buf1[i+1] = buf[i];
}
put_buffer(pb, buf1, size);
put_flush_packet(pb);
stream->nb_frames++;
av_free(buf1);
return 0;
}
static int rm_write_video(AVFormatContext *s, UINT8 *buf, int size)
{
RMContext *rm = s->priv_data;
ByteIOContext *pb = &s->pb;
StreamInfo *stream = rm->video_stream;
int key_frame = stream->enc->key_frame;
/* XXX: this is incorrect: should be a parameter */
/* Well, I spent some time finding the meaning of these bits. I am
not sure I understood everything, but it works !! */
#if 1
write_packet_header(s, stream, size + 7, key_frame);
/* bit 7: '1' if final packet of a frame converted in several packets */
put_byte(pb, 0x81);
/* bit 7: '1' if I frame. bits 6..0 : sequence number in current
frame starting from 1 */
if (key_frame) {
put_byte(pb, 0x81);
} else {
put_byte(pb, 0x01);
}
put_be16(pb, 0x4000 | (size)); /* total frame size */
put_be16(pb, 0x4000 | (size)); /* offset from the start or the end */
#else
/* full frame */
write_packet_header(s, size + 6);
put_byte(pb, 0xc0);
put_be16(pb, 0x4000 | size); /* total frame size */
put_be16(pb, 0x4000 + packet_number * 126); /* position in stream */
#endif
put_byte(pb, stream->nb_frames & 0xff);
put_buffer(pb, buf, size);
put_flush_packet(pb);
stream->nb_frames++;
return 0;
}
static int rm_write_packet(AVFormatContext *s, int stream_index,
UINT8 *buf, int size, int force_pts)
{
if (s->streams[stream_index]->codec.codec_type ==
CODEC_TYPE_AUDIO)
return rm_write_audio(s, buf, size);
else
return rm_write_video(s, buf, size);
}
static int rm_write_trailer(AVFormatContext *s)
{
RMContext *rm = s->priv_data;
int data_size, index_pos, i;
ByteIOContext *pb = &s->pb;
if (!url_is_streamed(&s->pb)) {
/* end of file: finish to write header */
index_pos = url_fseek(pb, 0, SEEK_CUR);
data_size = index_pos - rm->data_pos;
/* index */
put_tag(pb, "INDX");
put_be32(pb, 10 + 10 * s->nb_streams);
put_be16(pb, 0);
for(i=0;i<s->nb_streams;i++) {
put_be32(pb, 0); /* zero indices */
put_be16(pb, i); /* stream number */
put_be32(pb, 0); /* next index */
}
/* undocumented end header */
put_be32(pb, 0);
put_be32(pb, 0);
url_fseek(pb, 0, SEEK_SET);
for(i=0;i<s->nb_streams;i++)
rm->streams[i].total_frames = rm->streams[i].nb_frames;
rv10_write_header(s, data_size, index_pos);
} else {
/* undocumented end header */
put_be32(pb, 0);
put_be32(pb, 0);
}
put_flush_packet(pb);
return 0;
}
/***************************************************/
static void get_str(ByteIOContext *pb, char *buf, int buf_size)
{
int len, i;
char *q;
len = get_be16(pb);
q = buf;
for(i=0;i<len;i++) {
if (i < buf_size - 1)
*q++ = get_byte(pb);
}
*q = '\0';
}
static void get_str8(ByteIOContext *pb, char *buf, int buf_size)
{
int len, i;
char *q;
len = get_byte(pb);
q = buf;
for(i=0;i<len;i++) {
if (i < buf_size - 1)
*q++ = get_byte(pb);
}
*q = '\0';
}
static int rm_read_header(AVFormatContext *s, AVFormatParameters *ap)
{
RMContext *rm = s->priv_data;
AVStream *st;
ByteIOContext *pb = &s->pb;
unsigned int tag, v;
int tag_size, size, codec_data_size, i;
INT64 codec_pos;
unsigned int h263_hack_version;
char buf[128];
int flags = 0;
if (get_le32(pb) != MKTAG('.', 'R', 'M', 'F'))
return -EIO;
get_be32(pb); /* header size */
get_be16(pb);
get_be32(pb);
get_be32(pb); /* number of headers */
for(;;) {
if (url_feof(pb))
goto fail;
tag = get_le32(pb);
tag_size = get_be32(pb);
get_be16(pb);
#if 0
printf("tag=%c%c%c%c (%08x) size=%d\n",
(tag) & 0xff,
(tag >> 8) & 0xff,
(tag >> 16) & 0xff,
(tag >> 24) & 0xff,
tag,
tag_size);
#endif
if (tag_size < 10)
goto fail;
switch(tag) {
case MKTAG('P', 'R', 'O', 'P'):
/* file header */
get_be32(pb); /* max bit rate */
get_be32(pb); /* avg bit rate */
get_be32(pb); /* max packet size */
get_be32(pb); /* avg packet size */
get_be32(pb); /* nb packets */
get_be32(pb); /* duration */
get_be32(pb); /* preroll */
get_be32(pb); /* index offset */
get_be32(pb); /* data offset */
get_be16(pb); /* nb streams */
flags = get_be16(pb); /* flags */
break;
case MKTAG('C', 'O', 'N', 'T'):
get_str(pb, s->title, sizeof(s->title));
get_str(pb, s->author, sizeof(s->author));
get_str(pb, s->copyright, sizeof(s->copyright));
get_str(pb, s->comment, sizeof(s->comment));
break;
case MKTAG('M', 'D', 'P', 'R'):
st = av_mallocz(sizeof(AVStream));
if (!st)
goto fail;
s->streams[s->nb_streams++] = st;
st->id = get_be16(pb);
get_be32(pb); /* max bit rate */
st->codec.bit_rate = get_be32(pb); /* bit rate */
get_be32(pb); /* max packet size */
get_be32(pb); /* avg packet size */
get_be32(pb); /* start time */
get_be32(pb); /* preroll */
get_be32(pb); /* duration */
get_str8(pb, buf, sizeof(buf)); /* desc */
get_str8(pb, buf, sizeof(buf)); /* mimetype */
codec_data_size = get_be32(pb);
codec_pos = url_ftell(pb);
v = get_be32(pb);
if (v == MKTAG(0xfd, 'a', 'r', '.')) {
/* ra type header */
get_be32(pb); /* version */
get_be32(pb); /* .ra4 */
get_be32(pb);
get_be16(pb);
get_be32(pb); /* header size */
get_be16(pb); /* add codec info */
get_be32(pb); /* coded frame size */
get_be32(pb); /* ??? */
get_be32(pb); /* ??? */
get_be32(pb); /* ??? */
get_be16(pb); /* 1 */
get_be16(pb); /* coded frame size */
get_be32(pb);
st->codec.sample_rate = get_be16(pb);
get_be32(pb);
st->codec.channels = get_be16(pb);
get_str8(pb, buf, sizeof(buf)); /* desc */
get_str8(pb, buf, sizeof(buf)); /* desc */
st->codec.codec_type = CODEC_TYPE_AUDIO;
if (!strcmp(buf, "dnet")) {
st->codec.codec_id = CODEC_ID_AC3;
} else {
st->codec.codec_id = CODEC_ID_NONE;
pstrcpy(st->codec.codec_name, sizeof(st->codec.codec_name),
buf);
}
} else {
if (get_le32(pb) != MKTAG('V', 'I', 'D', 'O')) {
fail1:
fprintf(stderr, "Unsupported video codec\n");
goto fail;
}
st->codec.codec_tag = get_le32(pb);
if (st->codec.codec_tag != MKTAG('R', 'V', '1', '0'))
goto fail1;
st->codec.width = get_be16(pb);
st->codec.height = get_be16(pb);
st->codec.frame_rate = get_be16(pb) * FRAME_RATE_BASE;
st->codec.codec_type = CODEC_TYPE_VIDEO;
get_be32(pb);
get_be16(pb);
get_be32(pb);
get_be16(pb);
/* modification of h263 codec version (!) */
h263_hack_version = get_be32(pb);
switch(h263_hack_version) {
case 0x10000000:
case 0x10003000:
case 0x10003001:
st->codec.sub_id = h263_hack_version;
st->codec.codec_id = CODEC_ID_RV10;
break;
default:
/* not handled */
st->codec.codec_id = CODEC_ID_NONE;
break;
}
}
/* skip codec info */
size = url_ftell(pb) - codec_pos;
url_fskip(pb, codec_data_size - size);
break;
case MKTAG('D', 'A', 'T', 'A'):
goto header_end;
default:
/* unknown tag: skip it */
url_fskip(pb, tag_size - 10);
break;
}
}
header_end:
rm->nb_packets = get_be32(pb); /* number of packets */
if (!rm->nb_packets && (flags & 4))
rm->nb_packets = 3600 * 25;
get_be32(pb); /* next data header */
return 0;
fail:
for(i=0;i<s->nb_streams;i++) {
av_free(s->streams[i]);
}
return -EIO;
}
static int get_num(ByteIOContext *pb, int *len)
{
int n, n1;
n = get_be16(pb);
(*len)-=2;
if (n >= 0x4000) {
return n - 0x4000;
} else {
n1 = get_be16(pb);
(*len)-=2;
return (n << 16) | n1;
}
}
static int rm_read_packet(AVFormatContext *s, AVPacket *pkt)
{
RMContext *rm = s->priv_data;
ByteIOContext *pb = &s->pb;
AVStream *st;
int len, num, timestamp, i, tmp, j;
UINT8 *ptr;
int flags;
redo:
if (rm->nb_packets == 0)
return -EIO;
get_be16(pb);
len = get_be16(pb);
if (len < 12)
return -EIO;
num = get_be16(pb);
timestamp = get_be32(pb);
get_byte(pb); /* reserved */
flags = get_byte(pb); /* flags */
rm->nb_packets--;
len -= 12;
st = NULL;
for(i=0;i<s->nb_streams;i++) {
st = s->streams[i];
if (num == st->id)
break;
}
if (i == s->nb_streams) {
/* skip packet if unknown number */
url_fskip(pb, len);
goto redo;
}
if (st->codec.codec_type == CODEC_TYPE_VIDEO) {
int full_frame, h, pic_num;
h= get_byte(pb);
if ((h & 0xc0) == 0xc0) {
int len2, pos;
full_frame = 1;
len2= get_num(pb, &len);
pos = get_num(pb, &len);
//printf("pos:%d\n",len);
len -= 2;
} else {
int seq, frame_size, pos;
full_frame = 0;
seq = get_byte(pb);
frame_size = get_num(pb, &len);
pos = get_num(pb, &len);
//printf("seq:%d, size:%d, pos:%d\n",seq,frame_size,pos);
len -= 3;
}
/* picture number */
pic_num= get_byte(pb);
//XXX/FIXME/HACK, demuxer should be fixed to send complete frames ...
if(st->codec.slice_offset==NULL) st->codec.slice_offset= (int*)malloc(sizeof(int));
st->codec.slice_count= full_frame;
st->codec.slice_offset[0]= 0;
}
av_new_packet(pkt, len);
pkt->stream_index = i;
get_buffer(pb, pkt->data, len);
/* for AC3, needs to swap bytes */
if (st->codec.codec_id == CODEC_ID_AC3) {
ptr = pkt->data;
for(j=0;j<len;j+=2) {
tmp = ptr[0];
ptr[0] = ptr[1];
ptr[1] = tmp;
ptr += 2;
}
}
return 0;
}
static int rm_read_close(AVFormatContext *s)
{
return 0;
}
static int rm_probe(AVProbeData *p)
{
/* check file header */
if (p->buf_size <= 32)
return 0;
if (p->buf[0] == '.' && p->buf[1] == 'R' &&
p->buf[2] == 'M' && p->buf[3] == 'F' &&
p->buf[4] == 0 && p->buf[5] == 0)
return AVPROBE_SCORE_MAX;
else
return 0;
}
static AVInputFormat rm_iformat = {
"rm",
"rm format",
sizeof(RMContext),
rm_probe,
rm_read_header,
rm_read_packet,
rm_read_close,
};
static AVOutputFormat rm_oformat = {
"rm",
"rm format",
"audio/x-pn-realaudio",
"rm,ra",
sizeof(RMContext),
CODEC_ID_AC3,
CODEC_ID_RV10,
rm_write_header,
rm_write_packet,
rm_write_trailer,
};
int rm_init(void)
{
av_register_input_format(&rm_iformat);
av_register_output_format(&rm_oformat);
return 0;
}

687
libavformat/rtp.c Normal file
View File

@@ -0,0 +1,687 @@
/*
* RTP input/output format
* Copyright (c) 2002 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"
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#ifndef __BEOS__
# include <arpa/inet.h>
#else
# include "barpainet.h"
#endif
#include <netdb.h>
//#define DEBUG
/* TODO: - add RTCP statistics reporting (should be optional).
- add support for h263/mpeg4 packetized output : IDEA: send a
buffer to 'rtp_write_packet' contains all the packets for ONE
frame. Each packet should have a four byte header containing
the length in big endian format (same trick as
'url_open_dyn_packet_buf')
*/
#define RTP_VERSION 2
#define RTP_MAX_SDES 256 /* maximum text length for SDES */
/* RTCP paquets use 0.5 % of the bandwidth */
#define RTCP_TX_RATIO_NUM 5
#define RTCP_TX_RATIO_DEN 1000
typedef enum {
RTCP_SR = 200,
RTCP_RR = 201,
RTCP_SDES = 202,
RTCP_BYE = 203,
RTCP_APP = 204
} rtcp_type_t;
typedef enum {
RTCP_SDES_END = 0,
RTCP_SDES_CNAME = 1,
RTCP_SDES_NAME = 2,
RTCP_SDES_EMAIL = 3,
RTCP_SDES_PHONE = 4,
RTCP_SDES_LOC = 5,
RTCP_SDES_TOOL = 6,
RTCP_SDES_NOTE = 7,
RTCP_SDES_PRIV = 8,
RTCP_SDES_IMG = 9,
RTCP_SDES_DOOR = 10,
RTCP_SDES_SOURCE = 11
} rtcp_sdes_type_t;
enum RTPPayloadType {
RTP_PT_ULAW = 0,
RTP_PT_GSM = 3,
RTP_PT_G723 = 4,
RTP_PT_ALAW = 8,
RTP_PT_S16BE_STEREO = 10,
RTP_PT_S16BE_MONO = 11,
RTP_PT_MPEGAUDIO = 14,
RTP_PT_JPEG = 26,
RTP_PT_H261 = 31,
RTP_PT_MPEGVIDEO = 32,
RTP_PT_MPEG2TS = 33,
RTP_PT_H263 = 34, /* old H263 encapsulation */
RTP_PT_PRIVATE = 96,
};
typedef struct RTPContext {
int payload_type;
UINT32 ssrc;
UINT16 seq;
UINT32 timestamp;
UINT32 base_timestamp;
UINT32 cur_timestamp;
int max_payload_size;
/* rtcp sender statistics receive */
INT64 last_rtcp_ntp_time;
UINT32 last_rtcp_timestamp;
/* rtcp sender statistics */
unsigned int packet_count;
unsigned int octet_count;
unsigned int last_octet_count;
int first_packet;
/* buffer for output */
UINT8 buf[RTP_MAX_PACKET_LENGTH];
UINT8 *buf_ptr;
} RTPContext;
int rtp_get_codec_info(AVCodecContext *codec, int payload_type)
{
switch(payload_type) {
case RTP_PT_ULAW:
codec->codec_id = CODEC_ID_PCM_MULAW;
codec->channels = 1;
codec->sample_rate = 8000;
break;
case RTP_PT_ALAW:
codec->codec_id = CODEC_ID_PCM_ALAW;
codec->channels = 1;
codec->sample_rate = 8000;
break;
case RTP_PT_S16BE_STEREO:
codec->codec_id = CODEC_ID_PCM_S16BE;
codec->channels = 2;
codec->sample_rate = 44100;
break;
case RTP_PT_S16BE_MONO:
codec->codec_id = CODEC_ID_PCM_S16BE;
codec->channels = 1;
codec->sample_rate = 44100;
break;
case RTP_PT_MPEGAUDIO:
codec->codec_id = CODEC_ID_MP2;
break;
case RTP_PT_JPEG:
codec->codec_id = CODEC_ID_MJPEG;
break;
case RTP_PT_MPEGVIDEO:
codec->codec_id = CODEC_ID_MPEG1VIDEO;
break;
default:
return -1;
}
return 0;
}
/* return < 0 if unknown payload type */
int rtp_get_payload_type(AVCodecContext *codec)
{
int payload_type;
/* compute the payload type */
payload_type = -1;
switch(codec->codec_id) {
case CODEC_ID_PCM_MULAW:
payload_type = RTP_PT_ULAW;
break;
case CODEC_ID_PCM_ALAW:
payload_type = RTP_PT_ALAW;
break;
case CODEC_ID_PCM_S16BE:
if (codec->channels == 1) {
payload_type = RTP_PT_S16BE_MONO;
} else if (codec->channels == 2) {
payload_type = RTP_PT_S16BE_STEREO;
}
break;
case CODEC_ID_MP2:
case CODEC_ID_MP3LAME:
payload_type = RTP_PT_MPEGAUDIO;
break;
case CODEC_ID_MJPEG:
payload_type = RTP_PT_JPEG;
break;
case CODEC_ID_MPEG1VIDEO:
payload_type = RTP_PT_MPEGVIDEO;
break;
default:
break;
}
return payload_type;
}
static inline UINT32 decode_be32(const UINT8 *p)
{
return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
}
static inline UINT32 decode_be64(const UINT8 *p)
{
return ((UINT64)decode_be32(p) << 32) | decode_be32(p + 4);
}
static int rtcp_parse_packet(AVFormatContext *s1, const unsigned char *buf, int len)
{
RTPContext *s = s1->priv_data;
if (buf[1] != 200)
return -1;
s->last_rtcp_ntp_time = decode_be64(buf + 8);
s->last_rtcp_timestamp = decode_be32(buf + 16);
return 0;
}
/**
* Parse an RTP packet directly sent as raw data. Can only be used if
* 'raw' is given as input file
* @param s1 media file context
* @param pkt returned packet
* @param buf input buffer
* @param len buffer len
* @return zero if no error.
*/
int rtp_parse_packet(AVFormatContext *s1, AVPacket *pkt,
const unsigned char *buf, int len)
{
RTPContext *s = s1->priv_data;
unsigned int ssrc, h;
int payload_type, seq, delta_timestamp;
AVStream *st;
UINT32 timestamp;
if (len < 12)
return -1;
if ((buf[0] & 0xc0) != (RTP_VERSION << 6))
return -1;
if (buf[1] >= 200 && buf[1] <= 204) {
rtcp_parse_packet(s1, buf, len);
return -1;
}
payload_type = buf[1] & 0x7f;
seq = (buf[2] << 8) | buf[3];
timestamp = decode_be32(buf + 4);
ssrc = decode_be32(buf + 8);
if (s->payload_type < 0) {
s->payload_type = payload_type;
if (payload_type == RTP_PT_MPEG2TS) {
/* XXX: special case : not a single codec but a whole stream */
return -1;
} else {
st = av_new_stream(s1, 0);
if (!st)
return -1;
rtp_get_codec_info(&st->codec, payload_type);
}
}
/* NOTE: we can handle only one payload type */
if (s->payload_type != payload_type)
return -1;
#if defined(DEBUG) || 1
if (seq != ((s->seq + 1) & 0xffff)) {
printf("RTP: PT=%02x: bad cseq %04x expected=%04x\n",
payload_type, seq, ((s->seq + 1) & 0xffff));
}
s->seq = seq;
#endif
len -= 12;
buf += 12;
st = s1->streams[0];
switch(st->codec.codec_id) {
case CODEC_ID_MP2:
/* better than nothing: skip mpeg audio RTP header */
if (len <= 4)
return -1;
h = decode_be32(buf);
len -= 4;
buf += 4;
av_new_packet(pkt, len);
memcpy(pkt->data, buf, len);
break;
case CODEC_ID_MPEG1VIDEO:
/* better than nothing: skip mpeg audio RTP header */
if (len <= 4)
return -1;
h = decode_be32(buf);
buf += 4;
len -= 4;
if (h & (1 << 26)) {
/* mpeg2 */
if (len <= 4)
return -1;
buf += 4;
len -= 4;
}
av_new_packet(pkt, len);
memcpy(pkt->data, buf, len);
break;
default:
av_new_packet(pkt, len);
memcpy(pkt->data, buf, len);
break;
}
if (s->last_rtcp_ntp_time != AV_NOPTS_VALUE) {
/* compute pts from timestamp with received ntp_time */
delta_timestamp = timestamp - s->last_rtcp_timestamp;
/* XXX: do conversion, but not needed for mpeg at 90 KhZ */
pkt->pts = s->last_rtcp_ntp_time + delta_timestamp;
}
return 0;
}
static int rtp_read_header(AVFormatContext *s1,
AVFormatParameters *ap)
{
RTPContext *s = s1->priv_data;
s->payload_type = -1;
s->last_rtcp_ntp_time = AV_NOPTS_VALUE;
return 0;
}
static int rtp_read_packet(AVFormatContext *s1, AVPacket *pkt)
{
char buf[RTP_MAX_PACKET_LENGTH];
int ret;
/* XXX: needs a better API for packet handling ? */
for(;;) {
ret = url_read(url_fileno(&s1->pb), buf, sizeof(buf));
if (ret < 0)
return AVERROR_IO;
if (rtp_parse_packet(s1, pkt, buf, ret) == 0)
break;
}
return 0;
}
static int rtp_read_close(AVFormatContext *s1)
{
// RTPContext *s = s1->priv_data;
return 0;
}
static int rtp_probe(AVProbeData *p)
{
if (strstart(p->filename, "rtp://", NULL))
return AVPROBE_SCORE_MAX;
return 0;
}
/* rtp output */
static int rtp_write_header(AVFormatContext *s1)
{
RTPContext *s = s1->priv_data;
int payload_type, max_packet_size;
AVStream *st;
if (s1->nb_streams != 1)
return -1;
st = s1->streams[0];
payload_type = rtp_get_payload_type(&st->codec);
if (payload_type < 0)
payload_type = RTP_PT_PRIVATE; /* private payload type */
s->payload_type = payload_type;
s->base_timestamp = random();
s->timestamp = s->base_timestamp;
s->ssrc = random();
s->first_packet = 1;
max_packet_size = url_fget_max_packet_size(&s1->pb);
if (max_packet_size <= 12)
return AVERROR_IO;
s->max_payload_size = max_packet_size - 12;
switch(st->codec.codec_id) {
case CODEC_ID_MP2:
case CODEC_ID_MP3LAME:
s->buf_ptr = s->buf + 4;
s->cur_timestamp = 0;
break;
case CODEC_ID_MPEG1VIDEO:
s->cur_timestamp = 0;
break;
default:
s->buf_ptr = s->buf;
break;
}
return 0;
}
/* send an rtcp sender report packet */
static void rtcp_send_sr(AVFormatContext *s1, INT64 ntp_time)
{
RTPContext *s = s1->priv_data;
#if defined(DEBUG)
printf("RTCP: %02x %Lx %x\n", s->payload_type, ntp_time, s->timestamp);
#endif
put_byte(&s1->pb, (RTP_VERSION << 6));
put_byte(&s1->pb, 200);
put_be16(&s1->pb, 6); /* length in words - 1 */
put_be32(&s1->pb, s->ssrc);
put_be64(&s1->pb, ntp_time);
put_be32(&s1->pb, s->timestamp);
put_be32(&s1->pb, s->packet_count);
put_be32(&s1->pb, s->octet_count);
put_flush_packet(&s1->pb);
}
/* send an rtp packet. sequence number is incremented, but the caller
must update the timestamp itself */
static void rtp_send_data(AVFormatContext *s1, UINT8 *buf1, int len)
{
RTPContext *s = s1->priv_data;
#ifdef DEBUG
printf("rtp_send_data size=%d\n", len);
#endif
/* build the RTP header */
put_byte(&s1->pb, (RTP_VERSION << 6));
put_byte(&s1->pb, s->payload_type & 0x7f);
put_be16(&s1->pb, s->seq);
put_be32(&s1->pb, s->timestamp);
put_be32(&s1->pb, s->ssrc);
put_buffer(&s1->pb, buf1, len);
put_flush_packet(&s1->pb);
s->seq++;
s->octet_count += len;
s->packet_count++;
}
/* send an integer number of samples and compute time stamp and fill
the rtp send buffer before sending. */
static void rtp_send_samples(AVFormatContext *s1,
UINT8 *buf1, int size, int sample_size)
{
RTPContext *s = s1->priv_data;
int len, max_packet_size, n;
max_packet_size = (s->max_payload_size / sample_size) * sample_size;
/* not needed, but who nows */
if ((size % sample_size) != 0)
av_abort();
while (size > 0) {
len = (max_packet_size - (s->buf_ptr - s->buf));
if (len > size)
len = size;
/* copy data */
memcpy(s->buf_ptr, buf1, len);
s->buf_ptr += len;
buf1 += len;
size -= len;
n = (s->buf_ptr - s->buf);
/* if buffer full, then send it */
if (n >= max_packet_size) {
rtp_send_data(s1, s->buf, n);
s->buf_ptr = s->buf;
/* update timestamp */
s->timestamp += n / sample_size;
}
}
}
/* NOTE: we suppose that exactly one frame is given as argument here */
/* XXX: test it */
static void rtp_send_mpegaudio(AVFormatContext *s1,
UINT8 *buf1, int size)
{
RTPContext *s = s1->priv_data;
AVStream *st = s1->streams[0];
int len, count, max_packet_size;
max_packet_size = s->max_payload_size;
/* test if we must flush because not enough space */
len = (s->buf_ptr - s->buf);
if ((len + size) > max_packet_size) {
if (len > 4) {
rtp_send_data(s1, s->buf, s->buf_ptr - s->buf);
s->buf_ptr = s->buf + 4;
/* 90 KHz time stamp */
s->timestamp = s->base_timestamp +
(s->cur_timestamp * 90000LL) / st->codec.sample_rate;
}
}
/* add the packet */
if (size > max_packet_size) {
/* big packet: fragment */
count = 0;
while (size > 0) {
len = max_packet_size - 4;
if (len > size)
len = size;
/* build fragmented packet */
s->buf[0] = 0;
s->buf[1] = 0;
s->buf[2] = count >> 8;
s->buf[3] = count;
memcpy(s->buf + 4, buf1, len);
rtp_send_data(s1, s->buf, len + 4);
size -= len;
buf1 += len;
count += len;
}
} else {
if (s->buf_ptr == s->buf + 4) {
/* no fragmentation possible */
s->buf[0] = 0;
s->buf[1] = 0;
s->buf[2] = 0;
s->buf[3] = 0;
}
memcpy(s->buf_ptr, buf1, size);
s->buf_ptr += size;
}
s->cur_timestamp += st->codec.frame_size;
}
/* NOTE: a single frame must be passed with sequence header if
needed. XXX: use slices. */
static void rtp_send_mpegvideo(AVFormatContext *s1,
UINT8 *buf1, int size)
{
RTPContext *s = s1->priv_data;
AVStream *st = s1->streams[0];
int len, h, max_packet_size;
UINT8 *q;
max_packet_size = s->max_payload_size;
while (size > 0) {
/* XXX: more correct headers */
h = 0;
if (st->codec.sub_id == 2)
h |= 1 << 26; /* mpeg 2 indicator */
q = s->buf;
*q++ = h >> 24;
*q++ = h >> 16;
*q++ = h >> 8;
*q++ = h;
if (st->codec.sub_id == 2) {
h = 0;
*q++ = h >> 24;
*q++ = h >> 16;
*q++ = h >> 8;
*q++ = h;
}
len = max_packet_size - (q - s->buf);
if (len > size)
len = size;
memcpy(q, buf1, len);
q += len;
/* 90 KHz time stamp */
/* XXX: overflow */
s->timestamp = s->base_timestamp +
(s->cur_timestamp * 90000LL * FRAME_RATE_BASE) / st->codec.frame_rate;
rtp_send_data(s1, s->buf, q - s->buf);
buf1 += len;
size -= len;
}
s->cur_timestamp++;
}
static void rtp_send_raw(AVFormatContext *s1,
UINT8 *buf1, int size)
{
RTPContext *s = s1->priv_data;
AVStream *st = s1->streams[0];
int len, max_packet_size;
max_packet_size = s->max_payload_size;
while (size > 0) {
len = max_packet_size;
if (len > size)
len = size;
/* 90 KHz time stamp */
/* XXX: overflow */
s->timestamp = s->base_timestamp +
(s->cur_timestamp * 90000LL * FRAME_RATE_BASE) / st->codec.frame_rate;
rtp_send_data(s1, buf1, len);
buf1 += len;
size -= len;
}
s->cur_timestamp++;
}
/* write an RTP packet. 'buf1' must contain a single specific frame. */
static int rtp_write_packet(AVFormatContext *s1, int stream_index,
UINT8 *buf1, int size, int force_pts)
{
RTPContext *s = s1->priv_data;
AVStream *st = s1->streams[0];
int rtcp_bytes;
INT64 ntp_time;
#ifdef DEBUG
printf("%d: write len=%d\n", stream_index, size);
#endif
/* XXX: mpeg pts hardcoded. RTCP send every 0.5 seconds */
rtcp_bytes = ((s->octet_count - s->last_octet_count) * RTCP_TX_RATIO_NUM) /
RTCP_TX_RATIO_DEN;
if (s->first_packet || rtcp_bytes >= 28) {
/* compute NTP time */
ntp_time = force_pts; // ((INT64)force_pts << 28) / 5625
rtcp_send_sr(s1, ntp_time);
s->last_octet_count = s->octet_count;
s->first_packet = 0;
}
switch(st->codec.codec_id) {
case CODEC_ID_PCM_MULAW:
case CODEC_ID_PCM_ALAW:
case CODEC_ID_PCM_U8:
case CODEC_ID_PCM_S8:
rtp_send_samples(s1, buf1, size, 1 * st->codec.channels);
break;
case CODEC_ID_PCM_U16BE:
case CODEC_ID_PCM_U16LE:
case CODEC_ID_PCM_S16BE:
case CODEC_ID_PCM_S16LE:
rtp_send_samples(s1, buf1, size, 2 * st->codec.channels);
break;
case CODEC_ID_MP2:
case CODEC_ID_MP3LAME:
rtp_send_mpegaudio(s1, buf1, size);
break;
case CODEC_ID_MPEG1VIDEO:
rtp_send_mpegvideo(s1, buf1, size);
break;
default:
/* better than nothing : send the codec raw data */
rtp_send_raw(s1, buf1, size);
break;
}
return 0;
}
static int rtp_write_trailer(AVFormatContext *s1)
{
// RTPContext *s = s1->priv_data;
return 0;
}
AVInputFormat rtp_demux = {
"rtp",
"RTP input format",
sizeof(RTPContext),
rtp_probe,
rtp_read_header,
rtp_read_packet,
rtp_read_close,
.flags = AVFMT_NOHEADER,
};
AVOutputFormat rtp_mux = {
"rtp",
"RTP output format",
NULL,
NULL,
sizeof(RTPContext),
CODEC_ID_PCM_MULAW,
CODEC_ID_NONE,
rtp_write_header,
rtp_write_packet,
rtp_write_trailer,
};
int rtp_init(void)
{
av_register_output_format(&rtp_mux);
av_register_input_format(&rtp_demux);
return 0;
}

40
libavformat/rtp.h Normal file
View File

@@ -0,0 +1,40 @@
/*
* RTP definitions
* Copyright (c) 2002 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
*/
#ifndef RTP_H
#define RTP_H
#define RTP_MIN_PACKET_LENGTH 12
#define RTP_MAX_PACKET_LENGTH 1500 /* XXX: suppress this define */
int rtp_init(void);
int rtp_get_codec_info(AVCodecContext *codec, int payload_type);
int rtp_get_payload_type(AVCodecContext *codec);
int rtp_parse_packet(AVFormatContext *s1, AVPacket *pkt,
const unsigned char *buf, int len);
extern AVOutputFormat rtp_mux;
extern AVInputFormat rtp_demux;
int rtp_get_local_port(URLContext *h);
int rtp_set_remote_url(URLContext *h, const char *uri);
void rtp_get_file_handles(URLContext *h, int *prtp_fd, int *prtcp_fd);
extern URLProtocol rtp_protocol;
#endif /* RTP_H */

300
libavformat/rtpproto.c Normal file
View File

@@ -0,0 +1,300 @@
/*
* RTP network protocol
* Copyright (c) 2002 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"
#include <unistd.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#ifndef __BEOS__
# include <arpa/inet.h>
#else
# include "barpainet.h"
#endif
#include <netdb.h>
#include <fcntl.h>
#define RTP_TX_BUF_SIZE (64 * 1024)
#define RTP_RX_BUF_SIZE (128 * 1024)
typedef struct RTPContext {
URLContext *rtp_hd, *rtcp_hd;
int rtp_fd, rtcp_fd;
} RTPContext;
/**
* If no filename is given to av_open_input_file because you want to
* get the local port first, then you must call this function to set
* the remote server address.
*
* @param s1 media file context
* @param uri of the remote server
* @return zero if no error.
*/
int rtp_set_remote_url(URLContext *h, const char *uri)
{
RTPContext *s = h->priv_data;
char hostname[256];
int port;
char buf[1024];
char path[1024];
url_split(NULL, 0, hostname, sizeof(hostname), &port,
path, sizeof(path), uri);
snprintf(buf, sizeof(buf), "udp://%s:%d%s", hostname, port, path);
udp_set_remote_url(s->rtp_hd, buf);
snprintf(buf, sizeof(buf), "udp://%s:%d%s", hostname, port + 1, path);
udp_set_remote_url(s->rtcp_hd, buf);
return 0;
}
/* add option to url of the form:
"http://host:port/path?option1=val1&option2=val2... */
void url_add_option(char *buf, int buf_size, const char *fmt, ...)
{
char buf1[1024];
va_list ap;
va_start(ap, fmt);
if (strchr(buf, '?'))
pstrcat(buf, buf_size, "&");
else
pstrcat(buf, buf_size, "?");
vsnprintf(buf1, sizeof(buf1), fmt, ap);
pstrcat(buf, buf_size, buf1);
va_end(ap);
}
void build_udp_url(char *buf, int buf_size,
const char *hostname, int port,
int local_port, int multicast, int ttl)
{
snprintf(buf, buf_size, "udp://%s:%d", hostname, port);
if (local_port >= 0)
url_add_option(buf, buf_size, "localport=%d", local_port);
if (multicast)
url_add_option(buf, buf_size, "multicast=1", multicast);
if (ttl >= 0)
url_add_option(buf, buf_size, "ttl=%d", ttl);
}
/*
* url syntax: rtp://host:port[?option=val...]
* option: 'multicast=1' : enable multicast
* 'ttl=n' : set the ttl value (for multicast only)
* 'localport=n' : set the local port to n
*
*/
static int rtp_open(URLContext *h, const char *uri, int flags)
{
RTPContext *s;
int port, is_output, is_multicast, ttl, local_port;
char hostname[256];
char buf[1024];
char path[1024];
const char *p;
is_output = (flags & URL_WRONLY);
s = av_mallocz(sizeof(RTPContext));
if (!s)
return -ENOMEM;
h->priv_data = s;
url_split(NULL, 0, hostname, sizeof(hostname), &port,
path, sizeof(path), uri);
/* extract parameters */
is_multicast = 0;
ttl = -1;
local_port = -1;
p = strchr(uri, '?');
if (p) {
is_multicast = find_info_tag(buf, sizeof(buf), "multicast", p);
if (find_info_tag(buf, sizeof(buf), "ttl", p)) {
ttl = strtol(buf, NULL, 10);
}
if (find_info_tag(buf, sizeof(buf), "localport", p)) {
local_port = strtol(buf, NULL, 10);
}
}
build_udp_url(buf, sizeof(buf),
hostname, port, local_port, is_multicast, ttl);
if (url_open(&s->rtp_hd, buf, flags) < 0)
goto fail;
local_port = udp_get_local_port(s->rtp_hd);
/* XXX: need to open another connexion if the port is not even */
/* well, should suppress localport in path */
build_udp_url(buf, sizeof(buf),
hostname, port + 1, local_port + 1, is_multicast, ttl);
if (url_open(&s->rtcp_hd, buf, flags) < 0)
goto fail;
/* just to ease handle access. XXX: need to suppress direct handle
access */
s->rtp_fd = udp_get_file_handle(s->rtp_hd);
s->rtcp_fd = udp_get_file_handle(s->rtcp_hd);
h->max_packet_size = url_get_max_packet_size(s->rtp_hd);
h->is_streamed = 1;
return 0;
fail:
if (s->rtp_hd)
url_close(s->rtp_hd);
if (s->rtcp_hd)
url_close(s->rtcp_hd);
av_free(s);
return -EIO;
}
static int rtp_read(URLContext *h, UINT8 *buf, int size)
{
RTPContext *s = h->priv_data;
struct sockaddr_in from;
int from_len, len, fd_max, n;
fd_set rfds;
#if 0
for(;;) {
from_len = sizeof(from);
len = recvfrom (s->rtp_fd, buf, size, 0,
(struct sockaddr *)&from, &from_len);
if (len < 0) {
if (errno == EAGAIN || errno == EINTR)
continue;
return -EIO;
}
break;
}
#else
for(;;) {
/* build fdset to listen to RTP and RTCP packets */
FD_ZERO(&rfds);
fd_max = s->rtp_fd;
FD_SET(s->rtp_fd, &rfds);
if (s->rtcp_fd > fd_max)
fd_max = s->rtcp_fd;
FD_SET(s->rtcp_fd, &rfds);
n = select(fd_max + 1, &rfds, NULL, NULL, NULL);
if (n > 0) {
/* first try RTCP */
if (FD_ISSET(s->rtcp_fd, &rfds)) {
from_len = sizeof(from);
len = recvfrom (s->rtcp_fd, buf, size, 0,
(struct sockaddr *)&from, &from_len);
if (len < 0) {
if (errno == EAGAIN || errno == EINTR)
continue;
return -EIO;
}
break;
}
/* then RTP */
if (FD_ISSET(s->rtp_fd, &rfds)) {
from_len = sizeof(from);
len = recvfrom (s->rtp_fd, buf, size, 0,
(struct sockaddr *)&from, &from_len);
if (len < 0) {
if (errno == EAGAIN || errno == EINTR)
continue;
return -EIO;
}
break;
}
}
}
#endif
return len;
}
static int rtp_write(URLContext *h, UINT8 *buf, int size)
{
RTPContext *s = h->priv_data;
int ret;
URLContext *hd;
if (buf[1] >= 200 && buf[1] <= 204) {
/* RTCP payload type */
hd = s->rtcp_hd;
} else {
/* RTP payload type */
hd = s->rtp_hd;
}
ret = url_write(hd, buf, size);
#if 0
{
struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = 10 * 1000000;
nanosleep(&ts, NULL);
}
#endif
return ret;
}
static int rtp_close(URLContext *h)
{
RTPContext *s = h->priv_data;
url_close(s->rtp_hd);
url_close(s->rtcp_hd);
av_free(s);
return 0;
}
/**
* Return the local port used by the RTP connexion
* @param s1 media file context
* @return the local port number
*/
int rtp_get_local_port(URLContext *h)
{
RTPContext *s = h->priv_data;
return udp_get_local_port(s->rtp_hd);
}
/**
* Return the rtp and rtcp file handles for select() usage to wait for several RTP
* streams at the same time.
* @param h media file context
*/
void rtp_get_file_handles(URLContext *h, int *prtp_fd, int *prtcp_fd)
{
RTPContext *s = h->priv_data;
*prtp_fd = s->rtp_fd;
*prtcp_fd = s->rtcp_fd;
}
URLProtocol rtp_protocol = {
"rtp",
rtp_open,
rtp_read,
rtp_write,
NULL, /* seek */
rtp_close,
};

1163
libavformat/rtsp.c Normal file

File diff suppressed because it is too large Load Diff

86
libavformat/rtsp.h Normal file
View File

@@ -0,0 +1,86 @@
/*
* RTSP definitions
* Copyright (c) 2002 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
*/
#ifndef RTSP_H
#define RTSP_H
/* RTSP handling */
enum RTSPStatusCode {
#define DEF(n, c, s) c = n,
#include "rtspcodes.h"
#undef DEF
};
enum RTSPProtocol {
RTSP_PROTOCOL_RTP_UDP = 0,
RTSP_PROTOCOL_RTP_TCP = 1,
RTSP_PROTOCOL_RTP_UDP_MULTICAST = 2,
};
#define RTSP_DEFAULT_PORT 554
#define RTSP_MAX_TRANSPORTS 8
typedef struct RTSPTransportField {
int interleaved_min, interleaved_max; /* interleave ids, if TCP transport */
int port_min, port_max; /* RTP ports */
int client_port_min, client_port_max; /* RTP ports */
int server_port_min, server_port_max; /* RTP ports */
int ttl; /* ttl value */
UINT32 destination; /* destination IP address */
enum RTSPProtocol protocol;
} RTSPTransportField;
typedef struct RTSPHeader {
int content_length;
enum RTSPStatusCode status_code; /* response code from server */
int nb_transports;
RTSPTransportField transports[RTSP_MAX_TRANSPORTS];
int seq; /* sequence number */
char session_id[512];
} RTSPHeader;
/* the callback can be used to extend the connection setup/teardown step */
enum RTSPCallbackAction {
RTSP_ACTION_SERVER_SETUP,
RTSP_ACTION_SERVER_TEARDOWN,
RTSP_ACTION_CLIENT_SETUP,
RTSP_ACTION_CLIENT_TEARDOWN,
};
typedef struct RTSPActionServerSetup {
UINT32 ipaddr;
char transport_option[512];
} RTSPActionServerSetup;
typedef int FFRTSPCallback(enum RTSPCallbackAction action,
const char *session_id,
char *buf, int buf_size,
void *arg);
void rtsp_set_callback(FFRTSPCallback *rtsp_cb);
int rtsp_init(void);
void rtsp_parse_line(RTSPHeader *reply, const char *buf);
extern int rtsp_abort_req;
extern int rtsp_default_protocols;
extern int rtsp_rtp_port_min;
extern int rtsp_rtp_port_max;
extern FFRTSPCallback *ff_rtsp_callback;
#endif /* RTSP_H */

11
libavformat/rtspcodes.h Normal file
View File

@@ -0,0 +1,11 @@
DEF(200, RTSP_STATUS_OK, "OK")
DEF(405, RTSP_STATUS_METHOD, "Method Not Allowed")
DEF(453, RTSP_STATUS_BANDWIDTH, "Not Enough Bandwidth")
DEF(454, RTSP_STATUS_SESSION, "Session Not Found")
DEF(455, RTSP_STATUS_STATE, "Method Not Valid in This State")
DEF(459, RTSP_STATUS_AGGREGATE, "Aggregate operation not allowed")
DEF(460, RTSP_STATUS_ONLY_AGGREGATE, "Only aggregate operation allowed")
DEF(461, RTSP_STATUS_TRANSPORT, "Unsupported transport")
DEF(500, RTSP_STATUS_INTERNAL, "Internal Server Error")
DEF(503, RTSP_STATUS_SERVICE, "Service Unavailable")
DEF(505, RTSP_STATUS_VERSION, "RTSP Version not supported")

1004
libavformat/strptime.c Normal file

File diff suppressed because it is too large Load Diff

32
libavformat/strptime.h Normal file
View File

@@ -0,0 +1,32 @@
/* strptime.h
*
* $Id$
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __STRPTIME_H__
#define __STRPTIME_H__
/*
* Version of "strptime()", for the benefit of OSes that don't have it.
*/
extern char *strptime(const char *, const char *, struct tm *);
#endif

571
libavformat/swf.c Normal file
View File

@@ -0,0 +1,571 @@
/*
* Flash Compatible Streaming Format
* Copyright (c) 2000 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"
/* should have a generic way to indicate probable size */
#define DUMMY_FILE_SIZE (100 * 1024 * 1024)
#define DUMMY_DURATION 600 /* in seconds */
#define TAG_END 0
#define TAG_SHOWFRAME 1
#define TAG_DEFINESHAPE 2
#define TAG_FREECHARACTER 3
#define TAG_PLACEOBJECT 4
#define TAG_REMOVEOBJECT 5
#define TAG_STREAMHEAD 18
#define TAG_STREAMBLOCK 19
#define TAG_JPEG2 21
#define TAG_LONG 0x100
/* flags for shape definition */
#define FLAG_MOVETO 0x01
#define FLAG_SETFILL0 0x02
#define FLAG_SETFILL1 0x04
/* character id used */
#define BITMAP_ID 0
#define SHAPE_ID 1
typedef struct {
offset_t duration_pos;
offset_t tag_pos;
int tag;
} SWFContext;
static void put_swf_tag(AVFormatContext *s, int tag)
{
SWFContext *swf = s->priv_data;
ByteIOContext *pb = &s->pb;
swf->tag_pos = url_ftell(pb);
swf->tag = tag;
/* reserve some room for the tag */
if (tag & TAG_LONG) {
put_le16(pb, 0);
put_le32(pb, 0);
} else {
put_le16(pb, 0);
}
}
static void put_swf_end_tag(AVFormatContext *s)
{
SWFContext *swf = s->priv_data;
ByteIOContext *pb = &s->pb;
offset_t pos;
int tag_len, tag;
pos = url_ftell(pb);
tag_len = pos - swf->tag_pos - 2;
tag = swf->tag;
url_fseek(pb, swf->tag_pos, SEEK_SET);
if (tag & TAG_LONG) {
tag &= ~TAG_LONG;
put_le16(pb, (tag << 6) | 0x3f);
put_le32(pb, tag_len - 4);
} else {
assert(tag_len < 0x3f);
put_le16(pb, (tag << 6) | tag_len);
}
url_fseek(pb, pos, SEEK_SET);
}
static inline void max_nbits(int *nbits_ptr, int val)
{
int n;
if (val == 0)
return;
val = abs(val);
n = 1;
while (val != 0) {
n++;
val >>= 1;
}
if (n > *nbits_ptr)
*nbits_ptr = n;
}
static void put_swf_rect(ByteIOContext *pb,
int xmin, int xmax, int ymin, int ymax)
{
PutBitContext p;
UINT8 buf[256];
int nbits, mask;
init_put_bits(&p, buf, sizeof(buf), NULL, NULL);
nbits = 0;
max_nbits(&nbits, xmin);
max_nbits(&nbits, xmax);
max_nbits(&nbits, ymin);
max_nbits(&nbits, ymax);
mask = (1 << nbits) - 1;
/* rectangle info */
put_bits(&p, 5, nbits);
put_bits(&p, nbits, xmin & mask);
put_bits(&p, nbits, xmax & mask);
put_bits(&p, nbits, ymin & mask);
put_bits(&p, nbits, ymax & mask);
flush_put_bits(&p);
put_buffer(pb, buf, pbBufPtr(&p) - p.buf);
}
static void put_swf_line_edge(PutBitContext *pb, int dx, int dy)
{
int nbits, mask;
put_bits(pb, 1, 1); /* edge */
put_bits(pb, 1, 1); /* line select */
nbits = 2;
max_nbits(&nbits, dx);
max_nbits(&nbits, dy);
mask = (1 << nbits) - 1;
put_bits(pb, 4, nbits - 2); /* 16 bits precision */
if (dx == 0) {
put_bits(pb, 1, 0);
put_bits(pb, 1, 1);
put_bits(pb, nbits, dy & mask);
} else if (dy == 0) {
put_bits(pb, 1, 0);
put_bits(pb, 1, 0);
put_bits(pb, nbits, dx & mask);
} else {
put_bits(pb, 1, 1);
put_bits(pb, nbits, dx & mask);
put_bits(pb, nbits, dy & mask);
}
}
#define FRAC_BITS 16
/* put matrix (not size optimized */
static void put_swf_matrix(ByteIOContext *pb,
int a, int b, int c, int d, int tx, int ty)
{
PutBitContext p;
UINT8 buf[256];
init_put_bits(&p, buf, sizeof(buf), NULL, NULL);
put_bits(&p, 1, 1); /* a, d present */
put_bits(&p, 5, 20); /* nb bits */
put_bits(&p, 20, a);
put_bits(&p, 20, d);
put_bits(&p, 1, 1); /* b, c present */
put_bits(&p, 5, 20); /* nb bits */
put_bits(&p, 20, c);
put_bits(&p, 20, b);
put_bits(&p, 5, 20); /* nb bits */
put_bits(&p, 20, tx);
put_bits(&p, 20, ty);
flush_put_bits(&p);
put_buffer(pb, buf, pbBufPtr(&p) - p.buf);
}
/* XXX: handle audio only */
static int swf_write_header(AVFormatContext *s)
{
SWFContext *swf;
ByteIOContext *pb = &s->pb;
AVCodecContext *enc, *audio_enc, *video_enc;
PutBitContext p;
UINT8 buf1[256];
int i, width, height, rate;
swf = av_malloc(sizeof(SWFContext));
if (!swf)
return -1;
s->priv_data = swf;
video_enc = NULL;
audio_enc = NULL;
for(i=0;i<s->nb_streams;i++) {
enc = &s->streams[i]->codec;
if (enc->codec_type == CODEC_TYPE_AUDIO)
audio_enc = enc;
else
video_enc = enc;
}
if (!video_enc) {
/* currenty, cannot work correctly if audio only */
width = 320;
height = 200;
rate = 10 * FRAME_RATE_BASE;
} else {
width = video_enc->width;
height = video_enc->height;
rate = video_enc->frame_rate;
}
put_tag(pb, "FWS");
put_byte(pb, 4); /* version (should use 4 for mpeg audio support) */
put_le32(pb, DUMMY_FILE_SIZE); /* dummy size
(will be patched if not streamed) */
put_swf_rect(pb, 0, width, 0, height);
put_le16(pb, (rate * 256) / FRAME_RATE_BASE); /* frame rate */
swf->duration_pos = url_ftell(pb);
put_le16(pb, (UINT16)(DUMMY_DURATION * (INT64)rate / FRAME_RATE_BASE)); /* frame count */
/* define a shape with the jpeg inside */
put_swf_tag(s, TAG_DEFINESHAPE);
put_le16(pb, SHAPE_ID); /* ID of shape */
/* bounding rectangle */
put_swf_rect(pb, 0, width, 0, height);
/* style info */
put_byte(pb, 1); /* one fill style */
put_byte(pb, 0x41); /* clipped bitmap fill */
put_le16(pb, BITMAP_ID); /* bitmap ID */
/* position of the bitmap */
put_swf_matrix(pb, (int)(1.0 * (1 << FRAC_BITS)), 0,
0, (int)(1.0 * (1 << FRAC_BITS)), 0, 0);
put_byte(pb, 0); /* no line style */
/* shape drawing */
init_put_bits(&p, buf1, sizeof(buf1), NULL, NULL);
put_bits(&p, 4, 1); /* one fill bit */
put_bits(&p, 4, 0); /* zero line bit */
put_bits(&p, 1, 0); /* not an edge */
put_bits(&p, 5, FLAG_MOVETO | FLAG_SETFILL0);
put_bits(&p, 5, 1); /* nbits */
put_bits(&p, 1, 0); /* X */
put_bits(&p, 1, 0); /* Y */
put_bits(&p, 1, 1); /* set fill style 1 */
/* draw the rectangle ! */
put_swf_line_edge(&p, width, 0);
put_swf_line_edge(&p, 0, height);
put_swf_line_edge(&p, -width, 0);
put_swf_line_edge(&p, 0, -height);
/* end of shape */
put_bits(&p, 1, 0); /* not an edge */
put_bits(&p, 5, 0);
flush_put_bits(&p);
put_buffer(pb, buf1, pbBufPtr(&p) - p.buf);
put_swf_end_tag(s);
if (audio_enc) {
int v;
/* start sound */
v = 0;
switch(audio_enc->sample_rate) {
case 11025:
v |= 1 << 2;
break;
case 22050:
v |= 2 << 2;
break;
case 44100:
v |= 3 << 2;
break;
default:
/* not supported */
av_free(swf);
return -1;
}
if (audio_enc->channels == 2)
v |= 1;
v |= 0x20; /* mp3 compressed */
v |= 0x02; /* 16 bits */
put_swf_tag(s, TAG_STREAMHEAD);
put_byte(&s->pb, 0);
put_byte(&s->pb, v);
put_le16(&s->pb, (audio_enc->sample_rate * FRAME_RATE_BASE) / rate); /* avg samples per frame */
put_swf_end_tag(s);
}
put_flush_packet(&s->pb);
return 0;
}
static int swf_write_video(AVFormatContext *s,
AVCodecContext *enc, UINT8 *buf, int size)
{
ByteIOContext *pb = &s->pb;
static int tag_id = 0;
if (enc->frame_number > 1) {
/* remove the shape */
put_swf_tag(s, TAG_REMOVEOBJECT);
put_le16(pb, SHAPE_ID); /* shape ID */
put_le16(pb, 1); /* depth */
put_swf_end_tag(s);
/* free the bitmap */
put_swf_tag(s, TAG_FREECHARACTER);
put_le16(pb, BITMAP_ID);
put_swf_end_tag(s);
}
put_swf_tag(s, TAG_JPEG2 | TAG_LONG);
put_le16(pb, tag_id); /* ID of the image */
/* a dummy jpeg header seems to be required */
put_byte(pb, 0xff);
put_byte(pb, 0xd8);
put_byte(pb, 0xff);
put_byte(pb, 0xd9);
/* write the jpeg image */
put_buffer(pb, buf, size);
put_swf_end_tag(s);
/* draw the shape */
put_swf_tag(s, TAG_PLACEOBJECT);
put_le16(pb, SHAPE_ID); /* shape ID */
put_le16(pb, 1); /* depth */
put_swf_matrix(pb, 1 << FRAC_BITS, 0, 0, 1 << FRAC_BITS, 0, 0);
put_swf_end_tag(s);
/* output the frame */
put_swf_tag(s, TAG_SHOWFRAME);
put_swf_end_tag(s);
put_flush_packet(&s->pb);
return 0;
}
static int swf_write_audio(AVFormatContext *s, UINT8 *buf, int size)
{
ByteIOContext *pb = &s->pb;
put_swf_tag(s, TAG_STREAMBLOCK | TAG_LONG);
put_buffer(pb, buf, size);
put_swf_end_tag(s);
put_flush_packet(&s->pb);
return 0;
}
static int swf_write_packet(AVFormatContext *s, int stream_index,
UINT8 *buf, int size, int force_pts)
{
AVCodecContext *codec = &s->streams[stream_index]->codec;
if (codec->codec_type == CODEC_TYPE_AUDIO)
return swf_write_audio(s, buf, size);
else
return swf_write_video(s, codec, buf, size);
}
static int swf_write_trailer(AVFormatContext *s)
{
SWFContext *swf = s->priv_data;
ByteIOContext *pb = &s->pb;
AVCodecContext *enc, *video_enc;
int file_size, i;
video_enc = NULL;
for(i=0;i<s->nb_streams;i++) {
enc = &s->streams[i]->codec;
if (enc->codec_type == CODEC_TYPE_VIDEO)
video_enc = enc;
}
put_swf_tag(s, TAG_END);
put_swf_end_tag(s);
put_flush_packet(&s->pb);
/* patch file size and number of frames if not streamed */
if (!url_is_streamed(&s->pb) && video_enc) {
file_size = url_ftell(pb);
url_fseek(pb, 4, SEEK_SET);
put_le32(pb, file_size);
url_fseek(pb, swf->duration_pos, SEEK_SET);
put_le16(pb, video_enc->frame_number);
}
return 0;
}
/***********************************/
/* just to extract MP3 from swf */
static int get_swf_tag(ByteIOContext *pb, int *len_ptr)
{
int tag, len;
if (url_feof(pb))
return -1;
tag = get_le16(pb);
len = tag & 0x3f;
tag = tag >> 6;
if (len == 0x3f) {
len = get_le32(pb);
}
*len_ptr = len;
return tag;
}
static int swf_probe(AVProbeData *p)
{
/* check file header */
if (p->buf_size <= 16)
return 0;
if (p->buf[0] == 'F' && p->buf[1] == 'W' &&
p->buf[2] == 'S')
return AVPROBE_SCORE_MAX;
else
return 0;
}
static int swf_read_header(AVFormatContext *s, AVFormatParameters *ap)
{
ByteIOContext *pb = &s->pb;
int nbits, len, frame_rate, tag, v;
AVStream *st;
if ((get_be32(pb) & 0xffffff00) != MKBETAG('F', 'W', 'S', 0))
return -EIO;
get_le32(pb);
/* skip rectangle size */
nbits = get_byte(pb) >> 3;
len = (4 * nbits - 3 + 7) / 8;
url_fskip(pb, len);
frame_rate = get_le16(pb);
get_le16(pb); /* frame count */
for(;;) {
tag = get_swf_tag(pb, &len);
if (tag < 0) {
fprintf(stderr, "No streaming found in SWF\n");
return -EIO;
}
if (tag == TAG_STREAMHEAD) {
/* streaming found */
get_byte(pb);
v = get_byte(pb);
get_le16(pb);
/* if mp3 streaming found, OK */
if ((v & 0x20) != 0) {
st = av_mallocz(sizeof(AVStream));
if (!st)
return -ENOMEM;
if (v & 0x01)
st->codec.channels = 2;
else
st->codec.channels = 1;
s->nb_streams = 1;
s->streams[0] = st;
switch((v>> 2) & 0x03) {
case 1:
st->codec.sample_rate = 11025;
break;
case 2:
st->codec.sample_rate = 22050;
break;
case 3:
st->codec.sample_rate = 44100;
break;
default:
av_free(st);
return -EIO;
}
st->codec.codec_type = CODEC_TYPE_AUDIO;
st->codec.codec_id = CODEC_ID_MP2;
break;
}
} else {
url_fskip(pb, len);
}
}
return 0;
}
static int swf_read_packet(AVFormatContext *s, AVPacket *pkt)
{
ByteIOContext *pb = &s->pb;
int tag, len;
for(;;) {
tag = get_swf_tag(pb, &len);
if (tag < 0)
return -EIO;
if (tag == TAG_STREAMBLOCK) {
av_new_packet(pkt, len);
get_buffer(pb, pkt->data, pkt->size);
break;
} else {
url_fskip(pb, len);
}
}
return 0;
}
static int swf_read_close(AVFormatContext *s)
{
return 0;
}
static AVInputFormat swf_iformat = {
"swf",
"Flash format",
0,
swf_probe,
swf_read_header,
swf_read_packet,
swf_read_close,
};
static AVOutputFormat swf_oformat = {
"swf",
"Flash format",
"application/x-shockwave-flash",
"swf",
sizeof(SWFContext),
CODEC_ID_MP2,
CODEC_ID_MJPEG,
swf_write_header,
swf_write_packet,
swf_write_trailer,
};
int swf_init(void)
{
av_register_input_format(&swf_iformat);
av_register_output_format(&swf_oformat);
return 0;
}

176
libavformat/tcp.c Normal file
View File

@@ -0,0 +1,176 @@
/*
* TCP protocol
* Copyright (c) 2002 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"
#include <unistd.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#ifndef __BEOS__
# include <arpa/inet.h>
#else
# include "barpainet.h"
#endif
#include <netdb.h>
typedef struct TCPContext {
int fd;
} TCPContext;
/* resolve host with also IP address parsing */
int resolve_host(struct in_addr *sin_addr, const char *hostname)
{
struct hostent *hp;
if ((inet_aton(hostname, sin_addr)) == 0) {
hp = gethostbyname(hostname);
if (!hp)
return -1;
memcpy (sin_addr, hp->h_addr, sizeof(struct in_addr));
}
return 0;
}
/* return non zero if error */
static int tcp_open(URLContext *h, const char *uri, int flags)
{
struct sockaddr_in dest_addr;
char hostname[1024], *q;
int port, fd = -1;
TCPContext *s;
const char *p;
s = av_malloc(sizeof(TCPContext));
if (!s)
return -ENOMEM;
h->priv_data = s;
p = uri;
if (!strstart(p, "tcp://", &p))
goto fail;
q = hostname;
while (*p != ':' && *p != '/' && *p != '\0') {
if ((q - hostname) < sizeof(hostname) - 1)
*q++ = *p;
p++;
}
*q = '\0';
if (*p != ':')
goto fail;
p++;
port = strtoul(p, (char **)&p, 10);
if (port <= 0 || port >= 65536)
goto fail;
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(port);
if (resolve_host(&dest_addr.sin_addr, hostname) < 0)
goto fail;
fd = socket(PF_INET, SOCK_STREAM, 0);
if (fd < 0)
goto fail;
if (connect(fd, (struct sockaddr *)&dest_addr,
sizeof(dest_addr)) < 0)
goto fail;
s->fd = fd;
return 0;
fail:
if (fd >= 0)
close(fd);
av_free(s);
return -EIO;
}
static int tcp_read(URLContext *h, UINT8 *buf, int size)
{
TCPContext *s = h->priv_data;
int size1, len;
size1 = size;
while (size > 0) {
#ifdef CONFIG_BEOS_NETSERVER
len = recv (s->fd, buf, size, 0);
#else
len = read (s->fd, buf, size);
#endif
if (len < 0) {
if (errno != EINTR && errno != EAGAIN)
#ifdef __BEOS__
return errno;
#else
return -errno;
#endif
else
continue;
} else if (len == 0) {
break;
}
size -= len;
buf += len;
}
return size1 - size;
}
static int tcp_write(URLContext *h, UINT8 *buf, int size)
{
TCPContext *s = h->priv_data;
int ret, size1;
size1 = size;
while (size > 0) {
#ifdef CONFIG_BEOS_NETSERVER
ret = send (s->fd, buf, size, 0);
#else
ret = write (s->fd, buf, size);
#endif
if (ret < 0 && errno != EINTR && errno != EAGAIN)
#ifdef __BEOS__
return errno;
#else
return -errno;
#endif
size -= ret;
buf += ret;
}
return size1 - size;
}
static int tcp_close(URLContext *h)
{
TCPContext *s = h->priv_data;
#ifdef CONFIG_BEOS_NETSERVER
closesocket(s->fd);
#else
close(s->fd);
#endif
av_free(s);
return 0;
}
URLProtocol tcp_protocol = {
"tcp",
tcp_open,
tcp_read,
tcp_write,
NULL, /* seek */
tcp_close,
};

272
libavformat/udp.c Normal file
View File

@@ -0,0 +1,272 @@
/*
* UDP prototype streaming system
* Copyright (c) 2000, 2001, 2002 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"
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#ifndef __BEOS__
# include <arpa/inet.h>
#else
# include "barpainet.h"
#endif
#include <netdb.h>
typedef struct {
int udp_fd;
int ttl;
int is_multicast;
int local_port;
struct ip_mreq mreq;
struct sockaddr_in dest_addr;
} UDPContext;
#define UDP_TX_BUF_SIZE 32768
/**
* If no filename is given to av_open_input_file because you want to
* get the local port first, then you must call this function to set
* the remote server address.
*
* url syntax: udp://host:port[?option=val...]
* option: 'multicast=1' : enable multicast
* 'ttl=n' : set the ttl value (for multicast only)
* 'localport=n' : set the local port
*
* @param s1 media file context
* @param uri of the remote server
* @return zero if no error.
*/
int udp_set_remote_url(URLContext *h, const char *uri)
{
UDPContext *s = h->priv_data;
char hostname[256];
int port;
url_split(NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri);
/* set the destination address */
if (resolve_host(&s->dest_addr.sin_addr, hostname) < 0)
return -EIO;
s->dest_addr.sin_family = AF_INET;
s->dest_addr.sin_port = htons(port);
return 0;
}
/**
* Return the local port used by the UDP connexion
* @param s1 media file context
* @return the local port number
*/
int udp_get_local_port(URLContext *h)
{
UDPContext *s = h->priv_data;
return s->local_port;
}
/**
* Return the udp file handle for select() usage to wait for several RTP
* streams at the same time.
* @param h media file context
*/
int udp_get_file_handle(URLContext *h)
{
UDPContext *s = h->priv_data;
return s->udp_fd;
}
/* put it in UDP context */
/* return non zero if error */
static int udp_open(URLContext *h, const char *uri, int flags)
{
struct sockaddr_in my_addr, my_addr1;
char hostname[1024];
int port, udp_fd = -1, tmp;
UDPContext *s = NULL;
int is_output, len;
const char *p;
char buf[256];
h->is_streamed = 1;
is_output = (flags & URL_WRONLY);
s = av_malloc(sizeof(UDPContext));
if (!s)
return -ENOMEM;
h->priv_data = s;
s->ttl = 16;
s->is_multicast = 0;
p = strchr(uri, '?');
if (p) {
s->is_multicast = find_info_tag(buf, sizeof(buf), "multicast", p);
if (find_info_tag(buf, sizeof(buf), "ttl", p)) {
s->ttl = strtol(buf, NULL, 10);
}
if (find_info_tag(buf, sizeof(buf), "localport", p)) {
s->local_port = strtol(buf, NULL, 10);
}
}
/* fill the dest addr */
url_split(NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri);
/* XXX: fix url_split */
if (hostname[0] == '\0' || hostname[0] == '?') {
/* only accepts null hostname if input */
if (s->is_multicast || (flags & URL_WRONLY))
goto fail;
} else {
udp_set_remote_url(h, uri);
}
udp_fd = socket(PF_INET, SOCK_DGRAM, 0);
if (udp_fd < 0)
goto fail;
my_addr.sin_family = AF_INET;
my_addr.sin_addr.s_addr = htonl (INADDR_ANY);
if (s->is_multicast && !(h->flags & URL_WRONLY)) {
/* special case: the bind must be done on the multicast address port */
my_addr.sin_port = s->dest_addr.sin_port;
} else {
my_addr.sin_port = htons(s->local_port);
}
/* the bind is needed to give a port to the socket now */
if (bind(udp_fd,(struct sockaddr *)&my_addr, sizeof(my_addr)) < 0)
goto fail;
len = sizeof(my_addr1);
getsockname(udp_fd, (struct sockaddr *)&my_addr1, &len);
s->local_port = ntohs(my_addr1.sin_port);
#ifndef CONFIG_BEOS_NETSERVER
if (s->is_multicast) {
if (h->flags & URL_WRONLY) {
/* output */
if (setsockopt(udp_fd, IPPROTO_IP, IP_MULTICAST_TTL,
&s->ttl, sizeof(s->ttl)) < 0) {
perror("IP_MULTICAST_TTL");
goto fail;
}
} else {
/* input */
memset(&s->mreq, 0, sizeof(s->mreq));
s->mreq.imr_multiaddr = s->dest_addr.sin_addr;
s->mreq.imr_interface.s_addr = htonl (INADDR_ANY);
if (setsockopt(udp_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
&s->mreq, sizeof(s->mreq)) < 0) {
perror("rtp: IP_ADD_MEMBERSHIP");
goto fail;
}
}
}
#endif
if (is_output) {
/* limit the tx buf size to limit latency */
tmp = UDP_TX_BUF_SIZE;
if (setsockopt(udp_fd, SOL_SOCKET, SO_SNDBUF, &tmp, sizeof(tmp)) < 0) {
perror("setsockopt sndbuf");
goto fail;
}
}
s->udp_fd = udp_fd;
h->max_packet_size = 1472; /* XXX: probe it ? */
return 0;
fail:
if (udp_fd >= 0)
#ifdef CONFIG_BEOS_NETSERVER
closesocket(udp_fd);
#else
close(udp_fd);
#endif
av_free(s);
return -EIO;
}
static int udp_read(URLContext *h, UINT8 *buf, int size)
{
UDPContext *s = h->priv_data;
struct sockaddr_in from;
int from_len, len;
for(;;) {
from_len = sizeof(from);
len = recvfrom (s->udp_fd, buf, size, 0,
(struct sockaddr *)&from, &from_len);
if (len < 0) {
if (errno != EAGAIN && errno != EINTR)
return -EIO;
} else {
break;
}
}
return len;
}
static int udp_write(URLContext *h, UINT8 *buf, int size)
{
UDPContext *s = h->priv_data;
int ret;
for(;;) {
ret = sendto (s->udp_fd, buf, size, 0,
(struct sockaddr *) &s->dest_addr,
sizeof (s->dest_addr));
if (ret < 0) {
if (errno != EINTR && errno != EAGAIN)
return -EIO;
} else {
break;
}
}
return size;
}
static int udp_close(URLContext *h)
{
UDPContext *s = h->priv_data;
#ifndef CONFIG_BEOS_NETSERVER
if (s->is_multicast && !(h->flags & URL_WRONLY)) {
if (setsockopt(s->udp_fd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
&s->mreq, sizeof(s->mreq)) < 0) {
perror("IP_DROP_MEMBERSHIP");
}
}
close(s->udp_fd);
#else
closesocket(s->udp_fd);
#endif
av_free(s);
return 0;
}
URLProtocol udp_protocol = {
"udp",
udp_open,
udp_read,
udp_write,
NULL, /* seek */
udp_close,
};

1280
libavformat/utils.c Normal file

File diff suppressed because it is too large Load Diff

326
libavformat/wav.c Normal file
View File

@@ -0,0 +1,326 @@
/*
* WAV encoder and decoder
* Copyright (c) 2001, 2002 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"
#include "avi.h"
const CodecTag codec_wav_tags[] = {
{ CODEC_ID_MP2, 0x50 },
{ CODEC_ID_MP3LAME, 0x55 },
{ CODEC_ID_AC3, 0x2000 },
{ CODEC_ID_PCM_S16LE, 0x01 },
{ CODEC_ID_PCM_U8, 0x01 }, /* must come after s16le in this list */
{ CODEC_ID_PCM_ALAW, 0x06 },
{ CODEC_ID_PCM_MULAW, 0x07 },
{ CODEC_ID_ADPCM_MS, 0x02 },
{ CODEC_ID_ADPCM_IMA_WAV, 0x11 },
{ CODEC_ID_WMAV1, 0x160 },
{ CODEC_ID_WMAV2, 0x161 },
{ 0, 0 },
};
/* WAVEFORMATEX header */
/* returns the size or -1 on error */
int put_wav_header(ByteIOContext *pb, AVCodecContext *enc)
{
int tag, bps, blkalign, bytespersec;
int hdrsize = 18;
tag = codec_get_tag(codec_wav_tags, enc->codec_id);
if (tag == 0)
return -1;
put_le16(pb, tag);
put_le16(pb, enc->channels);
put_le32(pb, enc->sample_rate);
if (enc->codec_id == CODEC_ID_PCM_U8 ||
enc->codec_id == CODEC_ID_PCM_ALAW ||
enc->codec_id == CODEC_ID_PCM_MULAW) {
bps = 8;
} else if (enc->codec_id == CODEC_ID_MP2 || enc->codec_id == CODEC_ID_MP3LAME) {
bps = 0;
} else if (enc->codec_id == CODEC_ID_ADPCM_IMA_WAV || enc->codec_id == CODEC_ID_ADPCM_MS) {
bps = 4;
} else {
bps = 16;
}
if (enc->codec_id == CODEC_ID_MP2 || enc->codec_id == CODEC_ID_MP3LAME) {
blkalign = 1;
//blkalign = 144 * enc->bit_rate/enc->sample_rate;
} else if (enc->block_align != 0) { /* specified by the codec */
blkalign = enc->block_align;
} else
blkalign = enc->channels*bps >> 3;
if (enc->codec_id == CODEC_ID_PCM_U8 ||
enc->codec_id == CODEC_ID_PCM_S16LE) {
bytespersec = enc->sample_rate * blkalign;
} else {
bytespersec = enc->bit_rate / 8;
}
put_le32(pb, bytespersec); /* bytes per second */
put_le16(pb, blkalign); /* block align */
put_le16(pb, bps); /* bits per sample */
if (enc->codec_id == CODEC_ID_MP3LAME) {
put_le16(pb, 12); /* wav_extra_size */
hdrsize += 12;
put_le16(pb, 1); /* wID */
put_le32(pb, 2); /* fdwFlags */
put_le16(pb, 1152); /* nBlockSize */
put_le16(pb, 1); /* nFramesPerBlock */
put_le16(pb, 1393); /* nCodecDelay */
} else if (enc->codec_id == CODEC_ID_MP2) {
put_le16(pb, 22); /* wav_extra_size */
hdrsize += 22;
put_le16(pb, 2); /* fwHeadLayer */
put_le32(pb, enc->bit_rate); /* dwHeadBitrate */
put_le16(pb, enc->channels == 2 ? 1 : 8); /* fwHeadMode */
put_le16(pb, 0); /* fwHeadModeExt */
put_le16(pb, 1); /* wHeadEmphasis */
put_le16(pb, 16); /* fwHeadFlags */
put_le32(pb, 0); /* dwPTSLow */
put_le32(pb, 0); /* dwPTSHigh */
} else if (enc->codec_id == CODEC_ID_ADPCM_IMA_WAV) {
put_le16(pb, 2); /* wav_extra_size */
put_le16(pb, ((enc->block_align - 4 * enc->channels) / (4 * enc->channels)) * 8 + 1); /* wSamplesPerBlock */
} else
put_le16(pb, 0); /* wav_extra_size */
return hdrsize;
}
void get_wav_header(ByteIOContext *pb, AVCodecContext *codec,
int has_extra_data)
{
int id;
id = get_le16(pb);
codec->codec_type = CODEC_TYPE_AUDIO;
codec->codec_tag = id;
codec->fourcc = id;
codec->channels = get_le16(pb);
codec->sample_rate = get_le32(pb);
codec->bit_rate = get_le32(pb) * 8;
codec->block_align = get_le16(pb);
codec->frame_bits = get_le16(pb); /* bits per sample */
codec->codec_id = wav_codec_get_id(id, codec->frame_bits);
if (has_extra_data) {
codec->extradata_size = get_le16(pb);
if (codec->extradata_size > 0) {
codec->extradata = av_mallocz(codec->extradata_size);
get_buffer(pb, codec->extradata, codec->extradata_size);
}
}
}
int wav_codec_get_id(unsigned int tag, int bps)
{
int id;
id = codec_get_id(codec_wav_tags, tag);
if (id <= 0)
return id;
/* handle specific u8 codec */
if (id == CODEC_ID_PCM_S16LE && bps == 8)
id = CODEC_ID_PCM_U8;
return id;
}
typedef struct {
offset_t data;
} WAVContext;
static int wav_write_header(AVFormatContext *s)
{
WAVContext *wav = s->priv_data;
ByteIOContext *pb = &s->pb;
offset_t fmt;
put_tag(pb, "RIFF");
put_le32(pb, 0); /* file length */
put_tag(pb, "WAVE");
/* format header */
fmt = start_tag(pb, "fmt ");
if (put_wav_header(pb, &s->streams[0]->codec) < 0) {
av_free(wav);
return -1;
}
end_tag(pb, fmt);
/* data header */
wav->data = start_tag(pb, "data");
put_flush_packet(pb);
return 0;
}
static int wav_write_packet(AVFormatContext *s, int stream_index_ptr,
UINT8 *buf, int size, int force_pts)
{
ByteIOContext *pb = &s->pb;
put_buffer(pb, buf, size);
return 0;
}
static int wav_write_trailer(AVFormatContext *s)
{
ByteIOContext *pb = &s->pb;
WAVContext *wav = s->priv_data;
offset_t file_size;
if (!url_is_streamed(&s->pb)) {
end_tag(pb, wav->data);
/* update file size */
file_size = url_ftell(pb);
url_fseek(pb, 4, SEEK_SET);
put_le32(pb, (UINT32)(file_size - 8));
url_fseek(pb, file_size, SEEK_SET);
put_flush_packet(pb);
}
return 0;
}
/* return the size of the found tag */
/* XXX: > 2GB ? */
static int find_tag(ByteIOContext *pb, UINT32 tag1)
{
unsigned int tag;
int size;
for(;;) {
if (url_feof(pb))
return -1;
tag = get_le32(pb);
size = get_le32(pb);
if (tag == tag1)
break;
url_fseek(pb, size, SEEK_CUR);
}
if (size < 0)
size = 0x7fffffff;
return size;
}
static int wav_probe(AVProbeData *p)
{
/* check file header */
if (p->buf_size <= 32)
return 0;
if (p->buf[0] == 'R' && p->buf[1] == 'I' &&
p->buf[2] == 'F' && p->buf[3] == 'F' &&
p->buf[8] == 'W' && p->buf[9] == 'A' &&
p->buf[10] == 'V' && p->buf[11] == 'E')
return AVPROBE_SCORE_MAX;
else
return 0;
}
/* wav input */
static int wav_read_header(AVFormatContext *s,
AVFormatParameters *ap)
{
int size;
unsigned int tag;
ByteIOContext *pb = &s->pb;
AVStream *st;
/* check RIFF header */
tag = get_le32(pb);
if (tag != MKTAG('R', 'I', 'F', 'F'))
return -1;
get_le32(pb); /* file size */
tag = get_le32(pb);
if (tag != MKTAG('W', 'A', 'V', 'E'))
return -1;
/* parse fmt header */
size = find_tag(pb, MKTAG('f', 'm', 't', ' '));
if (size < 0)
return -1;
st = av_new_stream(s, 0);
if (!st)
return AVERROR_NOMEM;
get_wav_header(pb, &st->codec, (size >= 18));
size = find_tag(pb, MKTAG('d', 'a', 't', 'a'));
if (size < 0)
return -1;
return 0;
}
#define MAX_SIZE 4096
static int wav_read_packet(AVFormatContext *s,
AVPacket *pkt)
{
int ret;
if (url_feof(&s->pb))
return -EIO;
if (av_new_packet(pkt, MAX_SIZE))
return -EIO;
pkt->stream_index = 0;
ret = get_buffer(&s->pb, pkt->data, pkt->size);
if (ret < 0)
av_free_packet(pkt);
/* note: we need to modify the packet size here to handle the last
packet */
pkt->size = ret;
return ret;
}
static int wav_read_close(AVFormatContext *s)
{
return 0;
}
static AVInputFormat wav_iformat = {
"wav",
"wav format",
0,
wav_probe,
wav_read_header,
wav_read_packet,
wav_read_close,
};
static AVOutputFormat wav_oformat = {
"wav",
"wav format",
"audio/x-wav",
"wav",
sizeof(WAVContext),
CODEC_ID_PCM_S16LE,
CODEC_ID_NONE,
wav_write_header,
wav_write_packet,
wav_write_trailer,
};
int wav_init(void)
{
av_register_input_format(&wav_iformat);
av_register_output_format(&wav_oformat);
return 0;
}