aboutsummaryrefslogtreecommitdiffstats
path: root/libav
diff options
context:
space:
mode:
authorFabrice Bellard <fabrice@bellard.org>2001-07-22 14:18:56 +0000
committerFabrice Bellard <fabrice@bellard.org>2001-07-22 14:18:56 +0000
commitde6d9b6404bfd1c589799142da5a95428f146edd (patch)
tree75ae0cbb74bdfafb6f1a40922db111a103db3bcf /libav
parent1b58d58ddaf8a8c766a0353885ff504babed0453 (diff)
downloadffmpeg-de6d9b6404bfd1c589799142da5a95428f146edd.tar.gz
Initial revision
Originally committed as revision 5 to svn://svn.ffmpeg.org/ffmpeg/trunk
Diffstat (limited to 'libav')
-rw-r--r--libav/asf.c956
-rw-r--r--libav/audio.c179
-rw-r--r--libav/avformat.h192
-rw-r--r--libav/avi.h29
-rw-r--r--libav/avidec.c257
-rw-r--r--libav/avienc.c366
-rw-r--r--libav/avio.c146
-rw-r--r--libav/avio.h151
-rw-r--r--libav/aviobuf.c426
-rw-r--r--libav/ffm.c599
-rw-r--r--libav/file.c121
-rw-r--r--libav/grab.c321
-rw-r--r--libav/http.c318
-rw-r--r--libav/img.c578
-rw-r--r--libav/jpegenc.c102
-rw-r--r--libav/mpeg.c663
-rw-r--r--libav/raw.c288
-rw-r--r--libav/rm.c710
-rw-r--r--libav/swf.c552
-rw-r--r--libav/udp.c148
-rw-r--r--libav/utils.c533
-rw-r--r--libav/wav.c211
22 files changed, 7846 insertions, 0 deletions
diff --git a/libav/asf.c b/libav/asf.c
new file mode 100644
index 0000000000..0306ed37c9
--- /dev/null
+++ b/libav/asf.c
@@ -0,0 +1,956 @@
+/*
+ * ASF compatible encoder and decoder.
+ * Copyright (c) 2000, 2001 Gerard Lantau.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include "avformat.h"
+#include "avi.h"
+
+#define PACKET_SIZE 3200
+#define PACKET_HEADER_SIZE 12
+#define FRAME_HEADER_SIZE 17
+
+typedef struct {
+ int num;
+ int seq;
+ /* use for reading */
+ AVPacket pkt;
+ int frag_offset;
+} ASFStream;
+
+typedef struct {
+ int seqno;
+ int packet_size;
+
+ ASFStream streams[2];
+ /* non streamed additonnal info */
+ int data_offset;
+ INT64 nb_packets;
+ INT64 duration; /* in 100ns units */
+ /* packet filling */
+ int packet_size_left;
+ int packet_timestamp_start;
+ int packet_timestamp_end;
+ int packet_nb_frames;
+ UINT8 packet_buf[PACKET_SIZE];
+ ByteIOContext pb;
+ /* only for reading */
+ int packet_padsize;
+} ASFContext;
+
+typedef struct {
+ UINT32 v1;
+ UINT16 v2;
+ UINT16 v3;
+ UINT8 v4[8];
+} GUID;
+
+static const GUID asf_header = {
+ 0x75B22630, 0x668E, 0x11CF, { 0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C },
+};
+
+static const GUID file_header = {
+ 0x8CABDCA1, 0xA947, 0x11CF, { 0x8E, 0xE4, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 },
+};
+
+static const GUID stream_header = {
+ 0xB7DC0791, 0xA9B7, 0x11CF, { 0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 },
+};
+
+static const GUID audio_stream = {
+ 0xF8699E40, 0x5B4D, 0x11CF, { 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B },
+};
+
+static const GUID audio_conceal_none = {
+ 0x49f1a440, 0x4ece, 0x11d0, { 0xa3, 0xac, 0x00, 0xa0, 0xc9, 0x03, 0x48, 0xf6 },
+};
+
+static const GUID video_stream = {
+ 0xBC19EFC0, 0x5B4D, 0x11CF, { 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B },
+};
+
+static const GUID video_conceal_none = {
+ 0x20FB5700, 0x5B55, 0x11CF, { 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B },
+};
+
+
+static const GUID comment_header = {
+ 0x75b22633, 0x668e, 0x11cf, { 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c },
+};
+
+static const GUID codec_comment_header = {
+ 0x86D15240, 0x311D, 0x11D0, { 0xA3, 0xA4, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6 },
+};
+static const GUID codec_comment1_header = {
+ 0x86d15241, 0x311d, 0x11d0, { 0xa3, 0xa4, 0x00, 0xa0, 0xc9, 0x03, 0x48, 0xf6 },
+};
+
+static const GUID data_header = {
+ 0x75b22636, 0x668e, 0x11cf, { 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c },
+};
+
+static const GUID index_guid = {
+ 0x33000890, 0xe5b1, 0x11cf, { 0x89, 0xf4, 0x00, 0xa0, 0xc9, 0x03, 0x49, 0xcb },
+};
+
+static const GUID head1_guid = {
+ 0x5fbf03b5, 0xa92e, 0x11cf, { 0x8e, 0xe3, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65 },
+};
+
+static const GUID head2_guid = {
+ 0xabd3d211, 0xa9ba, 0x11cf, { 0x8e, 0xe6, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65 },
+};
+
+/* I am not a number !!! This GUID is the one found on the PC used to
+ generate the stream */
+static const GUID my_guid = {
+ 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 },
+};
+
+static void put_guid(ByteIOContext *s, const GUID *g)
+{
+ int i;
+
+ put_le32(s, g->v1);
+ put_le16(s, g->v2);
+ put_le16(s, g->v3);
+ for(i=0;i<8;i++)
+ put_byte(s, g->v4[i]);
+}
+
+static void put_str16(ByteIOContext *s, const char *tag)
+{
+ int c;
+
+ put_le16(s,strlen(tag) + 1);
+ for(;;) {
+ c = (UINT8)*tag++;
+ put_le16(s, c);
+ if (c == '\0')
+ break;
+ }
+}
+
+static void put_str16_nolen(ByteIOContext *s, const char *tag)
+{
+ int c;
+
+ for(;;) {
+ c = (UINT8)*tag++;
+ put_le16(s, c);
+ if (c == '\0')
+ break;
+ }
+}
+
+static INT64 put_header(ByteIOContext *pb, const GUID *g)
+{
+ INT64 pos;
+
+ pos = url_ftell(pb);
+ put_guid(pb, g);
+ put_le64(pb, 24);
+ return pos;
+}
+
+/* update header size */
+static void end_header(ByteIOContext *pb, INT64 pos)
+{
+ INT64 pos1;
+
+ pos1 = url_ftell(pb);
+ url_fseek(pb, pos + 16, SEEK_SET);
+ put_le64(pb, pos1 - pos);
+ url_fseek(pb, pos1, SEEK_SET);
+}
+
+/* write an asf chunk (only used in streaming case) */
+static void put_chunk(AVFormatContext *s, int type, int payload_length)
+{
+ ASFContext *asf = s->priv_data;
+ ByteIOContext *pb = &s->pb;
+ int length;
+
+ length = payload_length + 8;
+ put_le16(pb, type);
+ put_le16(pb, length);
+ put_le32(pb, asf->seqno);
+ put_le16(pb, 0); /* unknown bytes */
+ put_le16(pb, length);
+ asf->seqno++;
+}
+
+/* convert from unix to windows time */
+static INT64 unix_to_file_time(int ti)
+{
+ INT64 t;
+
+ t = ti * 10000000LL;
+ t += 116444736000000000LL;
+ return t;
+}
+
+/* write the header (used two times if non streamed) */
+static int asf_write_header1(AVFormatContext *s, INT64 file_size, INT64 data_chunk_size)
+{
+ ASFContext *asf = s->priv_data;
+ ByteIOContext *pb = &s->pb;
+ int header_size, n, extra_size, extra_size2, wav_extra_size, file_time;
+ int has_title;
+ AVCodecContext *enc;
+ INT64 header_offset, cur_pos, hpos;
+
+ has_title = (s->title[0] != '\0');
+
+ if (!url_is_streamed(&s->pb)) {
+ put_guid(pb, &asf_header);
+ put_le64(pb, 0); /* header length, will be patched after */
+ put_le32(pb, 3 + has_title + s->nb_streams); /* number of chunks in header */
+ put_byte(pb, 1); /* ??? */
+ put_byte(pb, 2); /* ??? */
+ } else {
+ put_chunk(s, 0x4824, 0); /* start of stream (length will be patched later) */
+ }
+
+ /* file header */
+ header_offset = url_ftell(pb);
+ hpos = put_header(pb, &file_header);
+ put_guid(pb, &my_guid);
+ put_le64(pb, file_size);
+ file_time = 0;
+ put_le64(pb, unix_to_file_time(file_time));
+ put_le64(pb, asf->nb_packets); /* number of packets */
+ put_le64(pb, asf->duration); /* end time stamp (in 100ns units) */
+ put_le64(pb, asf->duration); /* duration (in 100ns units) */
+ put_le32(pb, 0); /* start time stamp */
+ put_le32(pb, 0); /* ??? */
+ put_le32(pb, 0); /* ??? */
+ put_le32(pb, asf->packet_size); /* packet size */
+ put_le32(pb, asf->packet_size); /* packet size */
+ put_le32(pb, 80 * asf->packet_size); /* frame_size ??? */
+ end_header(pb, hpos);
+
+ /* unknown headers */
+ hpos = put_header(pb, &head1_guid);
+ put_guid(pb, &head2_guid);
+ put_le32(pb, 6);
+ put_le16(pb, 0);
+ end_header(pb, hpos);
+
+ /* title and other infos */
+ if (has_title) {
+ hpos = put_header(pb, &comment_header);
+ put_le16(pb, 2 * (strlen(s->title) + 1));
+ put_le16(pb, 2 * (strlen(s->author) + 1));
+ put_le16(pb, 2 * (strlen(s->copyright) + 1));
+ put_le16(pb, 2 * (strlen(s->comment) + 1));
+ put_le16(pb, 0);
+ put_str16_nolen(pb, s->title);
+ put_str16_nolen(pb, s->author);
+ put_str16_nolen(pb, s->copyright);
+ put_str16_nolen(pb, s->comment);
+ end_header(pb, hpos);
+ }
+
+ /* stream headers */
+ for(n=0;n<s->nb_streams;n++) {
+ enc = &s->streams[n]->codec;
+ asf->streams[n].num = n + 1;
+ asf->streams[n].seq = 0;
+
+ switch(enc->codec_type) {
+ case CODEC_TYPE_AUDIO:
+ wav_extra_size = 0;
+ extra_size = 18 + wav_extra_size;
+ extra_size2 = 0;
+ break;
+ default:
+ case CODEC_TYPE_VIDEO:
+ wav_extra_size = 0;
+ extra_size = 0x33;
+ extra_size2 = 0;
+ break;
+ }
+
+ hpos = put_header(pb, &stream_header);
+ if (enc->codec_type == CODEC_TYPE_AUDIO) {
+ put_guid(pb, &audio_stream);
+ put_guid(pb, &audio_conceal_none);
+ } else {
+ put_guid(pb, &video_stream);
+ put_guid(pb, &video_conceal_none);
+ }
+ put_le64(pb, 0); /* ??? */
+ put_le32(pb, extra_size); /* wav header len */
+ put_le32(pb, extra_size2); /* additional data len */
+ put_le16(pb, n + 1); /* stream number */
+ put_le32(pb, 0); /* ??? */
+
+ if (enc->codec_type == CODEC_TYPE_AUDIO) {
+ /* WAVEFORMATEX header */
+ put_wav_header(pb, enc);
+ } else {
+ put_le32(pb, enc->width);
+ put_le32(pb, enc->height);
+ put_byte(pb, 2); /* ??? */
+ put_le16(pb, 40); /* size */
+
+ /* BITMAPINFOHEADER header */
+ put_bmp_header(pb, enc);
+ }
+ end_header(pb, hpos);
+ }
+
+ /* media comments */
+
+ hpos = put_header(pb, &codec_comment_header);
+ put_guid(pb, &codec_comment1_header);
+ put_le32(pb, s->nb_streams);
+ for(n=0;n<s->nb_streams;n++) {
+ enc = &s->streams[n]->codec;
+
+ put_le16(pb, asf->streams[n].num);
+ put_str16(pb, enc->codec_name);
+ put_le16(pb, 0); /* no parameters */
+ /* id */
+ if (enc->codec_type == CODEC_TYPE_AUDIO) {
+ put_le16(pb, 2);
+ put_le16(pb, codec_get_tag(codec_wav_tags, enc->codec_id));
+ } else {
+ put_le16(pb, 4);
+ put_le32(pb, codec_get_tag(codec_bmp_tags, enc->codec_id));
+ }
+ }
+ end_header(pb, hpos);
+
+ /* patch the header size fields */
+
+ cur_pos = url_ftell(pb);
+ header_size = cur_pos - header_offset;
+ if (!url_is_streamed(&s->pb)) {
+ header_size += 24 + 6;
+ url_fseek(pb, header_offset - 14, SEEK_SET);
+ put_le64(pb, header_size);
+ } else {
+ header_size += 8 + 50;
+ url_fseek(pb, header_offset - 10, SEEK_SET);
+ put_le16(pb, header_size);
+ url_fseek(pb, header_offset - 2, SEEK_SET);
+ put_le16(pb, header_size);
+ }
+ url_fseek(pb, cur_pos, SEEK_SET);
+
+ /* movie chunk, followed by packets of packet_size */
+ asf->data_offset = cur_pos;
+ put_guid(pb, &data_header);
+ put_le64(pb, data_chunk_size);
+ put_guid(pb, &my_guid);
+ put_le64(pb, asf->nb_packets); /* nb packets */
+ put_byte(pb, 1); /* ??? */
+ put_byte(pb, 1); /* ??? */
+ return 0;
+}
+
+static int asf_write_header(AVFormatContext *s)
+{
+ ASFContext *asf;
+
+ asf = av_mallocz(sizeof(ASFContext));
+ if (!asf)
+ return -1;
+ s->priv_data = asf;
+
+ asf->packet_size = PACKET_SIZE;
+ asf->nb_packets = 0;
+
+ asf_write_header1(s, 0, 24);
+
+ put_flush_packet(&s->pb);
+
+ asf->packet_nb_frames = 0;
+ asf->packet_timestamp_start = -1;
+ asf->packet_timestamp_end = -1;
+ asf->packet_size_left = asf->packet_size - PACKET_HEADER_SIZE;
+ init_put_byte(&asf->pb, asf->packet_buf, asf->packet_size, 1,
+ NULL, NULL, NULL, NULL);
+
+ return 0;
+}
+
+/* write a fixed size packet */
+static void put_packet(AVFormatContext *s,
+ unsigned int timestamp, unsigned int duration,
+ int nb_frames, int padsize)
+{
+ ASFContext *asf = s->priv_data;
+ ByteIOContext *pb = &s->pb;
+ int flags;
+
+ if (url_is_streamed(&s->pb)) {
+ put_chunk(s, 0x4424, asf->packet_size);
+ }
+
+ put_byte(pb, 0x82);
+ put_le16(pb, 0);
+
+ flags = 0x01; /* nb segments present */
+ if (padsize > 0) {
+ if (padsize < 256)
+ flags |= 0x08;
+ else
+ flags |= 0x10;
+ }
+ put_byte(pb, flags); /* flags */
+ put_byte(pb, 0x5d);
+ if (flags & 0x10)
+ put_le16(pb, padsize);
+ if (flags & 0x08)
+ put_byte(pb, padsize);
+ put_le32(pb, timestamp);
+ put_le16(pb, duration);
+ put_byte(pb, nb_frames | 0x80);
+}
+
+static void flush_packet(AVFormatContext *s)
+{
+ ASFContext *asf = s->priv_data;
+ int hdr_size, ptr;
+
+ put_packet(s, asf->packet_timestamp_start,
+ asf->packet_timestamp_end - asf->packet_timestamp_start,
+ asf->packet_nb_frames, asf->packet_size_left);
+
+ /* compute padding */
+ hdr_size = PACKET_HEADER_SIZE;
+ if (asf->packet_size_left > 0) {
+ /* if padding needed, don't forget to count the
+ padding byte in the header size */
+ hdr_size++;
+ asf->packet_size_left--;
+ /* XXX: I do not test again exact limit to avoid boundary problems */
+ if (asf->packet_size_left > 200) {
+ hdr_size++;
+ asf->packet_size_left--;
+ }
+ }
+ ptr = asf->packet_size - PACKET_HEADER_SIZE - asf->packet_size_left;
+ memset(asf->packet_buf + ptr, 0, asf->packet_size_left);
+
+ put_buffer(&s->pb, asf->packet_buf, asf->packet_size - hdr_size);
+
+ put_flush_packet(&s->pb);
+ asf->nb_packets++;
+ asf->packet_nb_frames = 0;
+ asf->packet_timestamp_start = -1;
+ asf->packet_timestamp_end = -1;
+ asf->packet_size_left = asf->packet_size - PACKET_HEADER_SIZE;
+ init_put_byte(&asf->pb, asf->packet_buf, asf->packet_size, 1,
+ NULL, NULL, NULL, NULL);
+}
+
+static void put_frame_header(AVFormatContext *s, ASFStream *stream, int timestamp,
+ int payload_size, int frag_offset, int frag_len)
+{
+ ASFContext *asf = s->priv_data;
+ ByteIOContext *pb = &asf->pb;
+ int val;
+
+ val = stream->num;
+ if (s->streams[val - 1]->codec.key_frame)
+ val |= 0x80;
+ put_byte(pb, val);
+ put_byte(pb, stream->seq);
+ put_le32(pb, frag_offset); /* fragment offset */
+ put_byte(pb, 0x08); /* flags */
+ put_le32(pb, payload_size);
+ put_le32(pb, timestamp);
+ put_le16(pb, frag_len);
+}
+
+
+/* Output a frame. We suppose that payload_size <= PACKET_SIZE.
+
+ It is there that you understand that the ASF format is really
+ crap. They have misread the MPEG Systems spec !
+ */
+static void put_frame(AVFormatContext *s, ASFStream *stream, int timestamp,
+ UINT8 *buf, int payload_size)
+{
+ ASFContext *asf = s->priv_data;
+ int frag_pos, frag_len, frag_len1;
+
+ frag_pos = 0;
+ while (frag_pos < payload_size) {
+ frag_len = payload_size - frag_pos;
+ frag_len1 = asf->packet_size_left - FRAME_HEADER_SIZE;
+ if (frag_len1 > 0) {
+ if (frag_len > frag_len1)
+ frag_len = frag_len1;
+ put_frame_header(s, stream, timestamp, payload_size, frag_pos, frag_len);
+ put_buffer(&asf->pb, buf, frag_len);
+ asf->packet_size_left -= (frag_len + FRAME_HEADER_SIZE);
+ asf->packet_timestamp_end = timestamp;
+ if (asf->packet_timestamp_start == -1)
+ asf->packet_timestamp_start = timestamp;
+ asf->packet_nb_frames++;
+ } else {
+ frag_len = 0;
+ }
+ frag_pos += frag_len;
+ buf += frag_len;
+ /* output the frame if filled */
+ if (asf->packet_size_left <= FRAME_HEADER_SIZE)
+ flush_packet(s);
+ }
+ stream->seq++;
+}
+
+
+static int asf_write_packet(AVFormatContext *s, int stream_index,
+ UINT8 *buf, int size)
+{
+ ASFContext *asf = s->priv_data;
+ int timestamp;
+ INT64 duration;
+ AVCodecContext *codec;
+
+ codec = &s->streams[stream_index]->codec;
+ if (codec->codec_type == CODEC_TYPE_AUDIO) {
+ timestamp = (int)((float)codec->frame_number * codec->frame_size * 1000.0 /
+ codec->sample_rate);
+ duration = (codec->frame_number * codec->frame_size * 10000000LL) /
+ codec->sample_rate;
+ } else {
+ timestamp = (int)((float)codec->frame_number * 1000.0 * FRAME_RATE_BASE /
+ codec->frame_rate);
+ duration = codec->frame_number *
+ ((10000000LL * FRAME_RATE_BASE) / codec->frame_rate);
+ }
+ if (duration > asf->duration)
+ asf->duration = duration;
+
+ put_frame(s, &asf->streams[stream_index], (int)timestamp, buf, size);
+ return 0;
+}
+
+static int asf_write_trailer(AVFormatContext *s)
+{
+ ASFContext *asf = s->priv_data;
+ long long file_size;
+
+ /* flush the current packet */
+ if (asf->pb.buf_ptr > asf->pb.buffer)
+ flush_packet(s);
+
+ if (url_is_streamed(&s->pb)) {
+ put_chunk(s, 0x4524, 0); /* end of stream */
+ } else {
+ /* rewrite an updated header */
+ file_size = url_ftell(&s->pb);
+ url_fseek(&s->pb, 0, SEEK_SET);
+ asf_write_header1(s, file_size, file_size - asf->data_offset);
+ }
+
+ put_flush_packet(&s->pb);
+
+ free(asf);
+ return 0;
+}
+
+/**********************************/
+/* decoding */
+
+//#define DEBUG
+
+#ifdef DEBUG
+static void print_guid(const GUID *g)
+{
+ int i;
+ printf("0x%08x, 0x%04x, 0x%04x, {", g->v1, g->v2, g->v3);
+ for(i=0;i<8;i++)
+ printf(" 0x%02x,", g->v4[i]);
+ printf("}\n");
+}
+#endif
+
+static void get_guid(ByteIOContext *s, GUID *g)
+{
+ int i;
+
+ g->v1 = get_le32(s);
+ g->v2 = get_le16(s);
+ g->v3 = get_le16(s);
+ for(i=0;i<8;i++)
+ g->v4[i] = get_byte(s);
+}
+
+#if 0
+static void get_str16(ByteIOContext *pb, char *buf, int buf_size)
+{
+ int len, c;
+ char *q;
+
+ len = get_le16(pb);
+ q = buf;
+ while (len > 0) {
+ c = get_le16(pb);
+ if ((q - buf) < buf_size - 1)
+ *q++ = c;
+ len--;
+ }
+ *q = '\0';
+}
+#endif
+
+static void get_str16_nolen(ByteIOContext *pb, int len, char *buf, int buf_size)
+{
+ int c;
+ char *q;
+
+ q = buf;
+ while (len > 0) {
+ c = get_le16(pb);
+ if ((q - buf) < buf_size - 1)
+ *q++ = c;
+ len-=2;
+ }
+ *q = '\0';
+}
+
+static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap)
+{
+ ASFContext *asf;
+ GUID g;
+ ByteIOContext *pb = &s->pb;
+ AVStream *st;
+ ASFStream *asf_st;
+ int size, i;
+ INT64 gsize;
+
+ asf = av_mallocz(sizeof(ASFContext));
+ if (!asf)
+ return -1;
+ s->priv_data = asf;
+
+ get_guid(pb, &g);
+ if (memcmp(&g, &asf_header, sizeof(GUID)))
+ goto fail;
+ get_le64(pb);
+ get_le32(pb);
+ get_byte(pb);
+ get_byte(pb);
+
+ for(;;) {
+ get_guid(pb, &g);
+ gsize = get_le64(pb);
+#ifdef DEBUG
+ printf("%08Lx: ", url_ftell(pb) - 24);
+ print_guid(&g);
+ printf(" size=0x%Lx\n", gsize);
+#endif
+ if (gsize < 24)
+ goto fail;
+ if (!memcmp(&g, &file_header, sizeof(GUID))) {
+ get_guid(pb, &g);
+ get_le64(pb); /* file size */
+ get_le64(pb); /* file time */
+ get_le64(pb); /* nb_packets */
+ get_le64(pb); /* length 0 in us */
+ get_le64(pb); /* length 1 in us */
+ get_le32(pb);
+ get_le32(pb);
+ get_le32(pb);
+ asf->packet_size = get_le32(pb);
+ get_le32(pb);
+ get_le32(pb);
+ } else if (!memcmp(&g, &stream_header, sizeof(GUID))) {
+ int type, id, total_size;
+ unsigned int tag1;
+ INT64 pos1, pos2;
+
+ pos1 = url_ftell(pb);
+
+ st = av_mallocz(sizeof(AVStream));
+ if (!st)
+ goto fail;
+ s->streams[s->nb_streams++] = st;
+ asf_st = av_mallocz(sizeof(ASFStream));
+ if (!asf_st)
+ goto fail;
+ st->priv_data = asf_st;
+
+ get_guid(pb, &g);
+ if (!memcmp(&g, &audio_stream, sizeof(GUID))) {
+ type = CODEC_TYPE_AUDIO;
+ } else if (!memcmp(&g, &video_stream, sizeof(GUID))) {
+ type = CODEC_TYPE_VIDEO;
+ } else {
+ goto fail;
+ }
+ get_guid(pb, &g);
+ total_size = get_le64(pb);
+ get_le32(pb);
+ get_le32(pb);
+ st->id = get_le16(pb); /* stream id */
+ get_le32(pb);
+ st->codec.codec_type = type;
+ if (type == CODEC_TYPE_AUDIO) {
+ id = get_le16(pb);
+ st->codec.codec_tag = id;
+ st->codec.codec_id = codec_get_id(codec_wav_tags, id);
+ st->codec.channels = get_le16(pb);
+ st->codec.sample_rate = get_le32(pb);
+ st->codec.bit_rate = get_le32(pb) * 8;
+ get_le16(pb); /* block align */
+ get_le16(pb); /* bits per sample */
+ size = get_le16(pb);
+ url_fskip(pb, size);
+ } else {
+ get_le32(pb);
+ get_le32(pb);
+ get_byte(pb);
+ size = get_le16(pb); /* size */
+ get_le32(pb); /* size */
+ st->codec.width = get_le32(pb);
+ st->codec.height = get_le32(pb);
+ st->codec.frame_rate = 25 * FRAME_RATE_BASE; /* XXX: find it */
+ get_le16(pb); /* panes */
+ get_le16(pb); /* depth */
+ tag1 = get_le32(pb);
+ st->codec.codec_tag = tag1;
+ st->codec.codec_id = codec_get_id(codec_bmp_tags, tag1);
+ url_fskip(pb, size - 5 * 4);
+ }
+ pos2 = url_ftell(pb);
+ url_fskip(pb, gsize - (pos2 - pos1 + 24));
+ } else if (!memcmp(&g, &data_header, sizeof(GUID))) {
+ break;
+ } else if (!memcmp(&g, &comment_header, sizeof(GUID))) {
+ int len1, len2, len3, len4, len5;
+
+ len1 = get_le16(pb);
+ len2 = get_le16(pb);
+ len3 = get_le16(pb);
+ len4 = get_le16(pb);
+ len5 = get_le16(pb);
+ get_str16_nolen(pb, len1, s->title, sizeof(s->title));
+ get_str16_nolen(pb, len2, s->author, sizeof(s->author));
+ get_str16_nolen(pb, len3, s->copyright, sizeof(s->copyright));
+ get_str16_nolen(pb, len4, s->comment, sizeof(s->comment));
+ url_fskip(pb, len5);
+#if 0
+ } else if (!memcmp(&g, &head1_guid, sizeof(GUID))) {
+ int v1, v2;
+ get_guid(pb, &g);
+ v1 = get_le32(pb);
+ v2 = get_le16(pb);
+ } else if (!memcmp(&g, &codec_comment_header, sizeof(GUID))) {
+ int len, v1, n, num;
+ char str[256], *q;
+ char tag[16];
+
+ get_guid(pb, &g);
+ print_guid(&g);
+
+ n = get_le32(pb);
+ for(i=0;i<n;i++) {
+ num = get_le16(pb); /* stream number */
+ get_str16(pb, str, sizeof(str));
+ get_str16(pb, str, sizeof(str));
+ len = get_le16(pb);
+ q = tag;
+ while (len > 0) {
+ v1 = get_byte(pb);
+ if ((q - tag) < sizeof(tag) - 1)
+ *q++ = v1;
+ len--;
+ }
+ *q = '\0';
+ }
+#endif
+ } else if (url_feof(pb)) {
+ goto fail;
+ } else {
+ url_fseek(pb, gsize - 24, SEEK_CUR);
+ }
+ }
+ get_guid(pb, &g);
+ get_le64(pb);
+ get_byte(pb);
+ get_byte(pb);
+
+ asf->packet_size_left = 0;
+
+ return 0;
+
+ fail:
+ for(i=0;i<s->nb_streams;i++) {
+ AVStream *st = s->streams[i];
+ if (st)
+ free(st->priv_data);
+ free(st);
+ }
+ free(asf);
+ return -1;
+}
+
+static int asf_get_packet(AVFormatContext *s)
+{
+ ASFContext *asf = s->priv_data;
+ ByteIOContext *pb = &s->pb;
+ int c, flags, timestamp, hdr_size;
+
+ hdr_size = 12;
+ c = get_byte(pb);
+ if (c != 0x82)
+ return -EIO;
+ get_le16(pb);
+ flags = get_byte(pb);
+ get_byte(pb);
+ asf->packet_padsize = 0;
+ if (flags & 0x10) {
+ asf->packet_padsize = get_le16(pb);
+ hdr_size += 2;
+ } else if (flags & 0x08) {
+ asf->packet_padsize = get_byte(pb);
+ hdr_size++;
+ }
+ timestamp = get_le32(pb);
+ get_le16(pb); /* duration */
+ get_byte(pb); /* nb_frames */
+#ifdef DEBUG
+ printf("packet: size=%d padsize=%d\n", asf->packet_size, asf->packet_padsize);
+#endif
+ asf->packet_size_left = asf->packet_size - hdr_size;
+ return 0;
+}
+
+static int asf_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ ASFContext *asf = s->priv_data;
+ AVStream *st;
+ ASFStream *asf_st;
+ ByteIOContext *pb = &s->pb;
+ int ret, num, seq, frag_offset, payload_size, frag_len;
+ int timestamp, i;
+
+ for(;;) {
+ if (asf->packet_size_left < FRAME_HEADER_SIZE ||
+ asf->packet_size_left <= asf->packet_padsize) {
+ /* fail safe */
+ if (asf->packet_size_left)
+ url_fskip(pb, asf->packet_size_left);
+ ret = asf_get_packet(s);
+ if (ret < 0)
+ return -EIO;
+ }
+ /* read frame header */
+ num = get_byte(pb) & 0x7f;
+ seq = get_byte(pb);
+ frag_offset = get_le32(pb);
+ get_byte(pb); /* flags */
+ payload_size = get_le32(pb);
+ timestamp = get_le32(pb);
+ frag_len = get_le16(pb);
+#ifdef DEBUG
+ printf("num=%d seq=%d totsize=%d frag_off=%d frag_size=%d\n",
+ num, seq, payload_size, frag_offset, frag_len);
+#endif
+ st = NULL;
+ for(i=0;i<s->nb_streams;i++) {
+ st = s->streams[i];
+ if (st->id == num)
+ break;
+ }
+ asf->packet_size_left -= FRAME_HEADER_SIZE + frag_len;
+ if (i == s->nb_streams) {
+ /* unhandled packet (should not happen) */
+ url_fskip(pb, frag_len);
+ } else {
+ asf_st = st->priv_data;
+ if (asf_st->frag_offset == 0) {
+ /* new packet */
+ av_new_packet(&asf_st->pkt, payload_size);
+ asf_st->seq = seq;
+ } else {
+ if (seq == asf_st->seq &&
+ frag_offset == asf_st->frag_offset) {
+ /* continuing packet */
+ } else {
+ /* cannot continue current packet: free it */
+ av_free_packet(&asf_st->pkt);
+ asf_st->frag_offset = 0;
+ if (frag_offset != 0) {
+ /* cannot create new packet */
+ url_fskip(pb, frag_len);
+ goto next_frame;
+ } else {
+ /* create new packet */
+ av_new_packet(&asf_st->pkt, payload_size);
+ asf_st->seq = seq;
+ }
+ }
+ }
+ /* read data */
+ get_buffer(pb, asf_st->pkt.data + frag_offset, frag_len);
+ asf_st->frag_offset += frag_len;
+ /* test if whole packet read */
+ if (asf_st->frag_offset == asf_st->pkt.size) {
+ /* return packet */
+ asf_st->pkt.stream_index = i;
+ asf_st->frag_offset = 0;
+ memcpy(pkt, &asf_st->pkt, sizeof(AVPacket));
+ break;
+ }
+ }
+ next_frame:
+ }
+
+ return 0;
+}
+
+static int asf_read_close(AVFormatContext *s)
+{
+ ASFContext *asf = s->priv_data;
+ int i;
+
+ for(i=0;i<s->nb_streams;i++) {
+ AVStream *st = s->streams[i];
+ free(st->priv_data);
+ }
+ free(asf);
+ return 0;
+}
+
+AVFormat asf_format = {
+ "asf",
+ "asf format",
+ "application/octet-stream",
+ "asf",
+ CODEC_ID_MP2,
+ CODEC_ID_MSMPEG4,
+ asf_write_header,
+ asf_write_packet,
+ asf_write_trailer,
+
+ asf_read_header,
+ asf_read_packet,
+ asf_read_close,
+};
diff --git a/libav/audio.c b/libav/audio.c
new file mode 100644
index 0000000000..df5d88eaf6
--- /dev/null
+++ b/libav/audio.c
@@ -0,0 +1,179 @@
+/*
+ * Linux audio play and grab interface
+ * Copyright (c) 2000, 2001 Gerard Lantau.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <linux/soundcard.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <sys/time.h>
+
+#include "avformat.h"
+
+const char *audio_device = "/dev/dsp";
+
+typedef struct {
+ int fd;
+ int rate;
+ int channels;
+} AudioData;
+
+#define AUDIO_BLOCK_SIZE 4096
+
+/* audio read support */
+
+static int audio_read(URLContext *h, UINT8 *buf, int size)
+{
+ AudioData *s = h->priv_data;
+ int ret;
+
+ ret = read(s->fd, buf, size);
+ if (ret < 0)
+ return -errno;
+ else
+ return ret;
+}
+
+static int audio_write(URLContext *h, UINT8 *buf, int size)
+{
+ AudioData *s = h->priv_data;
+ int ret;
+
+ ret = write(s->fd, buf, size);
+ if (ret < 0)
+ return -errno;
+ else
+ return ret;
+}
+
+static int audio_get_format(URLContext *h, URLFormat *f)
+{
+ AudioData *s = h->priv_data;
+
+ strcpy(f->format_name, "pcm");
+ f->sample_rate = s->rate;
+ f->channels = s->channels;
+ return 0;
+}
+
+/* URI syntax: 'audio:[rate[,channels]]'
+ default: rate=44100, channels=2
+ */
+static int audio_open(URLContext *h, const char *uri, int flags)
+{
+ AudioData *s;
+ const char *p;
+ int freq, channels, audio_fd;
+ int tmp, err;
+
+ h->is_streamed = 1;
+ h->packet_size = AUDIO_BLOCK_SIZE;
+
+ s = malloc(sizeof(AudioData));
+ if (!s)
+ return -ENOMEM;
+ h->priv_data = s;
+
+ /* extract parameters */
+ p = uri;
+ strstart(p, "audio:", &p);
+ freq = strtol(p, (char **)&p, 0);
+ if (freq <= 0)
+ freq = 44100;
+ if (*p == ',')
+ p++;
+ channels = strtol(p, (char **)&p, 0);
+ if (channels <= 0)
+ channels = 2;
+ s->rate = freq;
+ s->channels = channels;
+
+ /* open linux audio device */
+ if (flags & URL_WRONLY)
+ audio_fd = open(audio_device,O_WRONLY);
+ else
+ audio_fd = open(audio_device,O_RDONLY);
+ if (audio_fd < 0) {
+ perror(audio_device);
+ return -EIO;
+ }
+
+ /* non blocking mode */
+ fcntl(audio_fd, F_SETFL, O_NONBLOCK);
+
+#if 0
+ tmp=(NB_FRAGMENTS << 16) | FRAGMENT_BITS;
+ err=ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &tmp);
+ if (err < 0) {
+ perror("SNDCTL_DSP_SETFRAGMENT");
+ }
+#endif
+
+ tmp=AFMT_S16_LE;
+ err=ioctl(audio_fd,SNDCTL_DSP_SETFMT,&tmp);
+ if (err < 0) {
+ perror("SNDCTL_DSP_SETFMT");
+ goto fail;
+ }
+
+ tmp= (channels == 2);
+ err=ioctl(audio_fd,SNDCTL_DSP_STEREO,&tmp);
+ if (err < 0) {
+ perror("SNDCTL_DSP_STEREO");
+ goto fail;
+ }
+
+ tmp = freq;
+ err=ioctl(audio_fd, SNDCTL_DSP_SPEED, &tmp);
+ if (err < 0) {
+ perror("SNDCTL_DSP_SPEED");
+ goto fail;
+ }
+
+ s->rate = tmp;
+ s->fd = audio_fd;
+
+ return 0;
+ fail:
+ close(audio_fd);
+ free(s);
+ return -EIO;
+}
+
+static int audio_close(URLContext *h)
+{
+ AudioData *s = h->priv_data;
+
+ close(s->fd);
+ free(s);
+ return 0;
+}
+
+URLProtocol audio_protocol = {
+ "audio",
+ audio_open,
+ audio_read,
+ audio_write,
+ NULL, /* seek */
+ audio_close,
+ audio_get_format,
+};
diff --git a/libav/avformat.h b/libav/avformat.h
new file mode 100644
index 0000000000..44e9da2a55
--- /dev/null
+++ b/libav/avformat.h
@@ -0,0 +1,192 @@
+
+#include "avcodec.h"
+
+#define FFMPEG_VERSION "0.4.5"
+
+#include "avio.h"
+
+/* packet functions */
+
+typedef struct AVPacket {
+ INT64 pts;
+ UINT8 *data;
+ int size;
+ int stream_index;
+ int flags;
+#define PKT_FLAG_KEY 0x0001
+} AVPacket;
+
+int av_new_packet(AVPacket *pkt, int size);
+void av_free_packet(AVPacket *pkt);
+
+/*************************************************/
+/* output formats */
+
+struct AVFormatContext;
+struct AVFormatInputContext;
+
+typedef struct AVFormatParameters {
+ int frame_rate;
+ int sample_rate;
+ int channels;
+ int width;
+ int height;
+ int pix_fmt;
+} AVFormatParameters;
+
+typedef struct AVFormat {
+ const char *name;
+ const char *long_name;
+ const char *mime_type;
+ const char *extensions; /* comma separated extensions */
+
+ /* output support */
+ enum CodecID audio_codec; /* default audio codec */
+ enum CodecID video_codec; /* default video codec */
+ int (*write_header)(struct AVFormatContext *);
+ int (*write_packet)(struct AVFormatContext *,
+ int stream_index,
+ unsigned char *buf, int size);
+ int (*write_trailer)(struct AVFormatContext *);
+
+ /* optional input support */
+ /* read the format header and initialize the AVFormatInputContext
+ structure. Return 0 if OK. 'ap' if non NULL contains
+ additionnal paramters. Only used in raw format right now */
+ int (*read_header)(struct AVFormatContext *,
+ AVFormatParameters *ap);
+ /* read one packet and put it in 'pkt'. pts and flags are also set */
+ 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);
+ int flags;
+#define AVFMT_NOFILE 0x0001 /* no file should be opened */
+ struct AVFormat *next;
+} AVFormat;
+
+typedef struct AVStream {
+ int id; /* internal stream id */
+ AVCodecContext codec; /* codec context */
+ void *priv_data;
+} AVStream;
+
+#define MAX_STREAMS 20
+
+/* format I/O context */
+typedef struct AVFormatContext {
+ struct AVFormat *format;
+ 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];
+ /* 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 AVFormat *first_format;
+
+/* rv10enc.c */
+extern AVFormat rm_format;
+
+/* mpegmux.c */
+extern AVFormat mpeg_mux_format;
+
+/* asfenc.c */
+extern AVFormat asf_format;
+
+/* avienc.c */
+extern AVFormat avi_format;
+
+/* jpegenc.c */
+extern AVFormat mpjpeg_format;
+extern AVFormat jpeg_format;
+
+/* swfenc.c */
+extern AVFormat swf_format;
+
+/* wav.c */
+extern AVFormat wav_format;
+
+/* img.c */
+extern AVFormat pgm_format;
+extern AVFormat pgmyuv_format;
+extern AVFormat imgyuv_format;
+extern AVFormat pgmpipe_format;
+
+/* raw.c */
+extern AVFormat mp2_format;
+extern AVFormat ac3_format;
+extern AVFormat h263_format;
+extern AVFormat mpeg1video_format;
+extern AVFormat pcm_format;
+extern AVFormat rawvideo_format;
+
+/* ffm.c */
+extern AVFormat ffm_format;
+
+/* formats.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 register_avformat(AVFormat *format);
+AVFormat *guess_format(const char *short_name, const char *filename, const char *mime_type);
+
+int strstart(const char *str, const char *val, const char **ptr);
+void nstrcpy(char *buf, int buf_size, const char *str);
+int match_ext(const char *filename, const char *extensions);
+
+void register_all(void);
+
+INT64 gettime(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);
+
+AVFormatContext *av_open_input_file(const char *filename, int buf_size);
+int av_read_packet(AVFormatContext *s, AVPacket *pkt);
+void av_close_input_file(AVFormatContext *s);
+
+int av_write_packet(AVFormatContext *s, AVPacket *pkt);
+
+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 gettime(void);
+INT64 parse_date(const char *datestr, int duration);
+
+/* 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);
+
diff --git a/libav/avi.h b/libav/avi.h
new file mode 100644
index 0000000000..06834cfcbf
--- /dev/null
+++ b/libav/avi.h
@@ -0,0 +1,29 @@
+
+#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, char *tag);
+void end_tag(ByteIOContext *pb, offset_t start);
+
+void put_bmp_header(ByteIOContext *pb, AVCodecContext *enc);
+void put_wav_header(ByteIOContext *pb, AVCodecContext *enc);
+
+typedef struct CodecTag {
+ int id;
+ unsigned int tag;
+} CodecTag;
+
+extern CodecTag codec_bmp_tags[];
+extern CodecTag codec_wav_tags[];
+
+unsigned int codec_get_tag(CodecTag *tags, int id);
+int codec_get_id(CodecTag *tags, unsigned int tag);
+
+/* avidec.c */
+int avi_read_header(AVFormatContext *s, AVFormatParameters *ap);
+int avi_read_packet(AVFormatContext *s, AVPacket *pkt);
+int avi_read_close(AVFormatContext *s);
diff --git a/libav/avidec.c b/libav/avidec.c
new file mode 100644
index 0000000000..ec90565feb
--- /dev/null
+++ b/libav/avidec.c
@@ -0,0 +1,257 @@
+/*
+ * AVI decoder.
+ * Copyright (c) 2001 Gerard Lantau.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <errno.h>
+
+#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
+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
+
+int avi_read_header(AVFormatContext *s, AVFormatParameters *ap)
+{
+ AVIContext *avi;
+ ByteIOContext *pb = &s->pb;
+ UINT32 tag, tag1;
+ int codec_type, stream_index, size, frame_period, bit_rate;
+ int i;
+ AVStream *st;
+
+ avi = malloc(sizeof(AVIContext));
+ if (!avi)
+ return -1;
+ memset(avi, 0, sizeof(AVIContext));
+ s->priv_data = avi;
+
+ /* 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 */
+ 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;
+ st = malloc(sizeof(AVStream));
+ if (!st)
+ goto fail;
+ memset(st, 0, sizeof(AVStream));
+ 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 */
+ url_fskip(pb, size - 7 * 4);
+ break;
+ case MKTAG('a', 'u', 'd', 's'):
+ codec_type = CODEC_TYPE_AUDIO;
+ /* nothing really useful */
+ url_fskip(pb, size - 4);
+ break;
+ default:
+ goto fail;
+ }
+ 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 = (1000000LL * 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:
+ tag1 = get_le16(pb);
+ st->codec.codec_type = CODEC_TYPE_AUDIO;
+ st->codec.codec_tag = tag1;
+ st->codec.codec_id = codec_get_id(codec_wav_tags, tag1);
+#ifdef DEBUG
+ printf("audio: 0x%x\n", tag1);
+#endif
+ st->codec.channels = get_le16(pb);
+ st->codec.sample_rate = get_le32(pb);
+ st->codec.bit_rate = get_le32(pb) * 8;
+ url_fskip(pb, size - 3 * 4);
+ 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++) {
+ if (s->streams[i])
+ free(s->streams[i]);
+ }
+ return -1;
+ }
+
+ return 0;
+}
+
+int avi_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ AVIContext *avi = s->priv_data;
+ ByteIOContext *pb = &s->pb;
+ int n, d1, d2, size;
+
+ find_next:
+ if (url_feof(pb) || url_ftell(pb) >= avi->movi_end)
+ return -1;
+ d1 = get_byte(pb);
+ if (d1 < '0' || d1 > '9')
+ goto find_next;
+ d2 = get_byte(pb);
+ if (d2 < '0' || d2 > '9')
+ goto find_next;
+ n = (d1 - '0') * 10 + (d2 - '0');
+
+ if (n < 0 || n >= s->nb_streams)
+ goto find_next;
+
+ d1 = get_byte(pb);
+ d2 = get_byte(pb);
+ if ((d1 != 'd' && d2 != 'c') &&
+ (d1 != 'w' && d2 != 'b'))
+ goto find_next;
+
+ 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;
+}
+
+int avi_read_close(AVFormatContext *s)
+{
+ AVIContext *avi = s->priv_data;
+ free(avi);
+ return 0;
+}
diff --git a/libav/avienc.c b/libav/avienc.c
new file mode 100644
index 0000000000..cef541d7ba
--- /dev/null
+++ b/libav/avienc.c
@@ -0,0 +1,366 @@
+/*
+ * AVI encoder.
+ * Copyright (c) 2000 Gerard Lantau.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <netinet/in.h>
+#include <string.h>
+
+#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;
+ AVIIndex *first, *last;
+} AVIContext;
+
+offset_t start_tag(ByteIOContext *pb, 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, 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. */
+CodecTag codec_bmp_tags[] = {
+ { CODEC_ID_H263, MKTAG('U', '2', '6', '3') },
+ { CODEC_ID_H263I, MKTAG('I', '2', '6', '3') }, /* intel h263 */
+ { CODEC_ID_MJPEG, MKTAG('M', 'J', 'P', 'G') },
+ { CODEC_ID_OPENDIVX, MKTAG('D', 'I', 'V', 'X') },
+ { CODEC_ID_OPENDIVX, MKTAG('d', 'i', 'v', 'x') },
+ { CODEC_ID_OPENDIVX, MKTAG(0x04, 0, 0, 0) }, /* some broken avi use this */
+ { CODEC_ID_MSMPEG4, MKTAG('D', 'I', 'V', '3') }, /* default signature when using MSMPEG4 */
+ { CODEC_ID_MSMPEG4, MKTAG('M', 'P', '4', '3') },
+ { 0, 0 },
+};
+
+CodecTag codec_wav_tags[] = {
+ { CODEC_ID_MP2, 0x55 },
+ { CODEC_ID_MP2, 0x50 },
+ { CODEC_ID_AC3, 0x2000 },
+ { CODEC_ID_PCM, 0x01 },
+ { 0, 0 },
+};
+
+
+unsigned int codec_get_tag(CodecTag *tags, int id)
+{
+ while (tags->id != 0) {
+ if (tags->id == id)
+ return tags->tag;
+ tags++;
+ }
+ return 0;
+}
+
+int codec_get_id(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)
+{
+ 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, codec_get_bmp_tag(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);
+}
+
+/* WAVEFORMATEX header */
+void put_wav_header(ByteIOContext *pb, AVCodecContext *enc)
+{
+ int tag;
+
+ tag = codec_get_tag(codec_wav_tags, enc->codec_id);
+
+ put_le16(pb, tag);
+ put_le16(pb, enc->channels);
+ put_le32(pb, enc->sample_rate);
+ put_le32(pb, enc->bit_rate / 8);
+ put_le16(pb, 1); /* block align */
+ put_le16(pb, 16); /* bits per sample */
+ put_le16(pb, 0); /* wav_extra_size */
+}
+
+static int avi_write_header(AVFormatContext *s)
+{
+ AVIContext *avi;
+ ByteIOContext *pb = &s->pb;
+ int bitrate, n, i, nb_frames;
+ AVCodecContext *stream, *video_enc;
+ offset_t list1, list2, strh, strf;
+
+ avi = malloc(sizeof(AVIContext));
+ if (!avi)
+ return -1;
+ memset(avi, 0, sizeof(AVIContext));
+ s->priv_data = avi;
+
+ 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) {
+ free(avi);
+ return -1;
+ }
+ nb_frames = 0;
+
+ put_le32(pb, 1000000LL * 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 */
+ 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 */
+ put_le32(pb, nb_frames); /* length, XXX: fill later */
+ put_le32(pb, 1024 * 1024); /* suggested buffer size */
+ put_le32(pb, 10000); /* 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, 0);
+ put_le32(pb, 0); /* flags */
+ put_le16(pb, 0); /* priority */
+ put_le16(pb, 0); /* language */
+ put_le32(pb, 0); /* initial frame */
+ put_le32(pb, 1); /* scale */
+ put_le32(pb, stream->bit_rate / 8); /* rate */
+ put_le32(pb, 0); /* start */
+ put_le32(pb, 0); /* length, XXX: filled later */
+ put_le32(pb, 12 * 1024); /* suggested buffer size */
+ put_le32(pb, -1); /* quality */
+ put_le32(pb, 1); /* sample size */
+ put_le32(pb, 0);
+ put_le32(pb, 0);
+ break;
+ }
+ end_tag(pb, strh);
+
+ strf = start_tag(pb, "strf");
+ switch(stream->codec_type) {
+ case CODEC_TYPE_VIDEO:
+ put_bmp_header(pb, stream);
+ break;
+ case CODEC_TYPE_AUDIO:
+ put_wav_header(pb, stream);
+ break;
+ }
+ 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)
+{
+ 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 (!url_is_streamed(&s->pb)) {
+ idx = 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;
+ 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, file_size);
+ url_fseek(pb, file_size, SEEK_SET);
+ }
+ put_flush_packet(pb);
+
+ free(avi);
+ return 0;
+}
+
+AVFormat avi_format = {
+ "avi",
+ "avi format",
+ "video/x-msvideo",
+ "avi",
+ CODEC_ID_MP2,
+ CODEC_ID_MSMPEG4,
+ avi_write_header,
+ avi_write_packet,
+ avi_write_trailer,
+
+ avi_read_header,
+ avi_read_packet,
+ avi_read_close,
+};
diff --git a/libav/avio.c b/libav/avio.c
new file mode 100644
index 0000000000..243f76f379
--- /dev/null
+++ b/libav/avio.c
@@ -0,0 +1,146 @@
+/*
+ * Unbuffered io for ffmpeg system
+ * Copyright (c) 2001 Gerard Lantau
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#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 (*p == '\0') {
+ strcpy(proto_str, "file");
+ } else {
+ *q = '\0';
+ }
+
+ up = first_protocol;
+ while (up != NULL) {
+ if (!strcmp(proto_str, up->name))
+ goto found;
+ up = up->next;
+ }
+ return -ENOENT;
+ found:
+ uc = malloc(sizeof(URLContext));
+ if (!uc)
+ return -ENOMEM;
+ uc->prot = up;
+ uc->flags = flags;
+ uc->is_streamed = 0; /* default = not streamed */
+ uc->packet_size = 1; /* default packet size */
+ err = up->url_open(uc, filename, flags);
+ if (err < 0) {
+ free(uc);
+ *puc = NULL;
+ return err;
+ }
+ *puc = uc;
+ return 0;
+}
+
+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))
+ 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_getformat(URLContext *h, URLFormat *f)
+{
+ memset(f, 0, sizeof(*f));
+ if (!h->prot->url_getformat)
+ return -ENODATA;
+ return h->prot->url_getformat(h, f);
+}
+
+int url_close(URLContext *h)
+{
+ int ret;
+
+ ret = h->prot->url_close(h);
+ 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;
+}
diff --git a/libav/avio.h b/libav/avio.h
new file mode 100644
index 0000000000..a3e11b61aa
--- /dev/null
+++ b/libav/avio.h
@@ -0,0 +1,151 @@
+/* output byte stream handling */
+
+typedef long long offset_t;
+
+/* unbuffered I/O */
+
+struct URLContext {
+ struct URLProtocol *prot;
+ int flags;
+ int is_streamed; /* true if streamed (no seek possible), default = false */
+ int packet_size;
+ void *priv_data;
+};
+
+typedef struct URLFormat {
+ char format_name[32];
+ int sample_rate;
+ int frame_rate;
+ int channels;
+ int height;
+ int width;
+ int pix_fmt;
+} URLFormat;
+
+typedef struct URLContext URLContext;
+
+typedef struct URLPollEntry {
+ URLContext *handle;
+ int events;
+ int revents;
+} URLPollEntry;
+
+#define URL_RDONLY 0
+#define URL_WRONLY 1
+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_getformat(URLContext *h, URLFormat *f);
+int url_close(URLContext *h);
+int url_exist(const char *filename);
+offset_t url_filesize(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);
+ /* get precise information about the format, if available. return
+ -ENODATA if not available */
+ int (*url_getformat)(URLContext *h, URLFormat *f);
+ 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 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, unsigned char *buf, int size);
+void put_le64(ByteIOContext *s, unsigned long long val);
+void put_be64(ByteIOContext *s, unsigned long long 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, char *tag);
+
+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);
+
+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);
+unsigned long long get_le64(ByteIOContext *s);
+unsigned int get_le16(ByteIOContext *s);
+
+unsigned int get_be16(ByteIOContext *s);
+unsigned int get_be32(ByteIOContext *s);
+unsigned long long get_be64(ByteIOContext *s);
+
+extern inline int url_is_streamed(ByteIOContext *s)
+{
+ return s->is_streamed;
+}
+/* get the prefered packet size of the device. All I/Os should be done
+ by multiple of this size */
+extern inline int url_get_packet_size(ByteIOContext *s)
+{
+ return s->packet_size;
+}
+
+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_open_buf(ByteIOContext *s, UINT8 *buf, int buf_size, int flags);
+int url_close_buf(ByteIOContext *s);
+
+/* file.c */
+extern URLProtocol file_protocol;
+extern URLProtocol pipe_protocol;
+
+/* udp.c */
+extern URLProtocol udp_protocol;
+
+/* http.c */
+extern URLProtocol http_protocol;
+
+/* audio.c */
+extern const char *audio_device;
+extern URLProtocol audio_protocol;
+
+/* grab.c */
+extern const char *v4l_device;
+extern URLProtocol video_protocol;
diff --git a/libav/aviobuf.c b/libav/aviobuf.c
new file mode 100644
index 0000000000..c50629e067
--- /dev/null
+++ b/libav/aviobuf.c
@@ -0,0 +1,426 @@
+/*
+ * Buffered I/O for ffmpeg system
+ * Copyright (c) 2000,2001 Gerard Lantau
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <getopt.h>
+#include <string.h>
+
+#include "avformat.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->packet_size = 1;
+ 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, 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->eof_reached = 0;
+ s->seek(s->opaque, offset, SEEK_SET);
+ s->pos = offset;
+ }
+ }
+ 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);
+}
+
+void put_le64(ByteIOContext *s, unsigned long long val)
+{
+ put_le32(s, val & 0xffffffff);
+ put_le32(s, val >> 32);
+}
+
+void put_be64(ByteIOContext *s, unsigned long long val)
+{
+ put_be32(s, val >> 32);
+ put_be32(s, 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, char *tag)
+{
+ while (*tag) {
+ put_byte(s, *tag++);
+ }
+}
+
+/* Input stream */
+
+static void fill_buffer(ByteIOContext *s)
+{
+ int len;
+
+ len = s->read_packet(s->opaque, s->buffer, s->buffer_size);
+ s->pos += len;
+ s->buf_ptr = s->buffer;
+ s->buf_end = s->buffer + len;
+ if (len == 0) {
+ s->eof_reached = 1;
+ }
+}
+
+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;
+ }
+}
+
+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;
+}
+
+unsigned long long 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;
+}
+
+unsigned long long 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, long long 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;
+
+ buffer_size = (IO_BUFFER_SIZE / h->packet_size) * h->packet_size;
+ buffer = 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) {
+ free(buffer);
+ return -EIO;
+ }
+ s->is_streamed = h->is_streamed;
+ s->packet_size = h->packet_size;
+ return 0;
+}
+
+/* XXX: must be called before any I/O */
+int url_setbufsize(ByteIOContext *s, int buf_size)
+{
+ UINT8 *buffer;
+ buffer = malloc(buf_size);
+ if (!buffer)
+ return -ENOMEM;
+
+ 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;
+}
+
+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;
+
+ free(s->buffer);
+ memset(s, 0, sizeof(ByteIOContext));
+ return url_close(h);
+}
+
+URLContext *url_fileno(ByteIOContext *s)
+{
+ return s->opaque;
+}
+
+/* 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)
+{
+ return s->buf_ptr - s->buffer;
+}
diff --git a/libav/ffm.c b/libav/ffm.c
new file mode 100644
index 0000000000..76e7613286
--- /dev/null
+++ b/libav/ffm.c
@@ -0,0 +1,599 @@
+/*
+ * FFM (ffserver live feed) encoder and decoder
+ * Copyright (c) 2001 Gerard Lantau.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "avformat.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 5
+#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[1]; /* must be last */
+} FFMContext;
+
+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)
+{
+ AVStream *st;
+ FFMStream *fst;
+ FFMContext *ffm;
+ ByteIOContext *pb = &s->pb;
+ AVCodecContext *codec;
+ int bit_rate, i;
+
+ ffm = av_mallocz(sizeof(FFMContext) + FFM_PACKET_SIZE);
+ if (!ffm)
+ return -1;
+
+ s->priv_data = ffm;
+ 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) + ffm->packet_size);
+ 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);
+ /* 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);
+ break;
+ case CODEC_TYPE_AUDIO:
+ put_be32(pb, codec->sample_rate);
+ put_le16(pb, codec->channels);
+ break;
+ }
+ /* hack to have real time */
+ fst->pts = 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];
+ fst = st->priv_data;
+ if (fst)
+ free(fst);
+ }
+ free(ffm);
+ return -1;
+}
+
+static int ffm_write_packet(AVFormatContext *s, int stream_index,
+ UINT8 *buf, int size)
+{
+ AVStream *st = s->streams[stream_index];
+ FFMStream *fst = st->priv_data;
+ INT64 pts;
+ UINT8 header[FRAME_HEADER_SIZE];
+
+ 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;
+ ffm_write_data(s, header, FRAME_HEADER_SIZE, pts, 1);
+ ffm_write_data(s, buf, size, pts, 0);
+
+ if (st->codec.codec_type == CODEC_TYPE_AUDIO) {
+ fst->pts += (INT64)((float)st->codec.frame_size / st->codec.sample_rate * 1000000.0);
+ } else {
+ fst->pts += (INT64)(1000000.0 * FRAME_RATE_BASE / (float)st->codec.frame_rate);
+ }
+ 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);
+
+ for(i=0;i<s->nb_streams;i++)
+ free(s->streams[i]->priv_data);
+ free(ffm);
+ 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 (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);
+ 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)) {
+ ffm->first_packet = 0;
+ 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)
+{
+ AVStream *st;
+ FFMStream *fst;
+ FFMContext *ffm;
+ ByteIOContext *pb = &s->pb;
+ AVCodecContext *codec;
+ int i;
+ UINT32 tag;
+
+ ffm = av_mallocz(sizeof(FFMContext) + FFM_PACKET_SIZE);
+ if (!ffm)
+ return -1;
+
+ s->priv_data = ffm;
+
+ /* 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 = (1ULL << 63) - 1;
+ }
+
+ s->nb_streams = get_be32(pb);
+ get_be32(pb); /* total bitrate */
+ /* read each stream */
+ for(i=0;i<s->nb_streams;i++) {
+ st = av_mallocz(sizeof(AVStream));
+ if (!st)
+ goto fail;
+ s->streams[i] = st;
+ fst = av_mallocz(sizeof(FFMStream) + ffm->packet_size);
+ 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);
+ /* 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);
+ break;
+ case CODEC_TYPE_AUDIO:
+ codec->sample_rate = get_be32(pb);
+ codec->channels = get_le16(pb);
+ break;
+ }
+
+ }
+
+ /* 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) {
+ fst = st->priv_data;
+ if (fst)
+ free(fst);
+ free(st);
+ }
+ }
+ if (ffm)
+ free(ffm);
+ return -1;
+}
+
+/* return < 0 if eof */
+static int ffm_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ int size;
+ FFMContext *ffm = s->priv_data;
+
+ 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;
+ }
+
+ 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;
+ }
+ 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];
+ free(st->priv_data);
+ }
+ free(s->priv_data);
+ return 0;
+}
+
+AVFormat ffm_format = {
+ "ffm",
+ "ffm format",
+ "",
+ "ffm",
+ /* not really used */
+ CODEC_ID_MP2,
+ CODEC_ID_MPEG1VIDEO,
+ ffm_write_header,
+ ffm_write_packet,
+ ffm_write_trailer,
+ ffm_read_header,
+ ffm_read_packet,
+ ffm_read_close,
+ ffm_seek,
+};
diff --git a/libav/file.c b/libav/file.c
new file mode 100644
index 0000000000..0b255341c8
--- /dev/null
+++ b/libav/file.c
@@ -0,0 +1,121 @@
+/*
+ * Buffered file io for ffmpeg system
+ * Copyright (c) 2001 Gerard Lantau
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <sys/time.h>
+
+#include "avformat.h"
+
+/* 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;
+ }
+ 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;
+ return lseek(fd, pos, whence);
+}
+
+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,
+};
diff --git a/libav/grab.c b/libav/grab.c
new file mode 100644
index 0000000000..f92cc397e6
--- /dev/null
+++ b/libav/grab.c
@@ -0,0 +1,321 @@
+/*
+ * Linux video grab interface
+ * Copyright (c) 2000,2001 Gerard Lantau.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <linux/videodev.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <sys/time.h>
+
+#include "avformat.h"
+
+typedef struct {
+ int fd;
+ int frame_format; /* see VIDEO_PALETTE_xxx */
+ int use_mmap;
+ int width, height;
+ float rate;
+ INT64 time_frame;
+} VideoData;
+
+const char *v4l_device = "/dev/video";
+
+/* XXX: move all that to the context */
+
+static struct video_capability video_cap;
+static UINT8 *video_buf;
+static struct video_mbuf gb_buffers;
+static struct video_mmap gb_buf;
+static struct video_audio audio;
+static int gb_frame = 0;
+
+static int v4l_init(URLContext *h)
+{
+ VideoData *s = h->priv_data;
+ int width, height;
+ int ret;
+ int video_fd, frame_size;
+
+ width = s->width;
+ height = s->height;
+
+ video_fd = open(v4l_device, O_RDWR);
+ if (video_fd < 0) {
+ perror(v4l_device);
+ return -EIO;
+ }
+
+ if (ioctl(video_fd,VIDIOCGCAP,&video_cap) < 0) {
+ perror("VIDIOCGCAP");
+ goto fail;
+ }
+
+ if (!(video_cap.type & VID_TYPE_CAPTURE)) {
+ fprintf(stderr, "Fatal: grab device does not handle capture\n");
+ goto fail;
+ }
+
+ /* unmute audio */
+ ioctl(video_fd, VIDIOCGAUDIO, &audio);
+ audio.flags &= ~VIDEO_AUDIO_MUTE;
+ ioctl(video_fd, VIDIOCSAUDIO, &audio);
+
+ ret = ioctl(video_fd,VIDIOCGMBUF,&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=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 = gettime();
+ s->use_mmap = 0;
+ } else {
+ video_buf = mmap(0,gb_buffers.size,PROT_READ|PROT_WRITE,MAP_SHARED,video_fd,0);
+ if ((unsigned char*)-1 == video_buf) {
+ perror("mmap");
+ goto fail;
+ }
+ gb_frame = 0;
+ s->time_frame = gettime();
+
+ /* start to grab the first frame */
+ gb_buf.frame = 1 - gb_frame;
+ gb_buf.height = height;
+ gb_buf.width = width;
+ gb_buf.format = VIDEO_PALETTE_YUV420P;
+
+ ret = ioctl(video_fd, VIDIOCMCAPTURE, &gb_buf);
+ if (ret < 0 && errno != EAGAIN) {
+ /* try YUV422 */
+ gb_buf.format = VIDEO_PALETTE_YUV422;
+
+ ret = ioctl(video_fd, VIDIOCMCAPTURE, &gb_buf);
+ if (ret < 0 && errno != EAGAIN) {
+ /* try RGB24 */
+ gb_buf.format = VIDEO_PALETTE_RGB24;
+ ret = ioctl(video_fd, VIDIOCMCAPTURE, &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 = gb_buf.format;
+ s->use_mmap = 1;
+ }
+
+ switch(s->frame_format) {
+ case VIDEO_PALETTE_YUV420P:
+ frame_size = (width * height * 3) / 2;
+ break;
+ case VIDEO_PALETTE_YUV422:
+ frame_size = width * height * 2;
+ break;
+ case VIDEO_PALETTE_RGB24:
+ frame_size = width * height * 3;
+ break;
+ default:
+ goto fail;
+ }
+ s->fd = video_fd;
+ h->packet_size = frame_size;
+ return 0;
+ fail:
+ close(video_fd);
+ return -EIO;
+}
+
+static int v4l_mm_read_picture(URLContext *h, UINT8 *buf)
+{
+ VideoData *s = h->priv_data;
+ UINT8 *ptr;
+
+ gb_buf.frame = gb_frame;
+ if (ioctl(s->fd, VIDIOCMCAPTURE, &gb_buf) < 0) {
+ if (errno == EAGAIN)
+ fprintf(stderr,"Cannot Sync\n");
+ else
+ perror("VIDIOCMCAPTURE");
+ return -EIO;
+ }
+ gb_frame = 1 - gb_frame;
+
+ while (ioctl(s->fd, VIDIOCSYNC, &gb_frame) < 0 &&
+ (errno == EAGAIN || errno == EINTR));
+
+ ptr = video_buf + gb_buffers.offsets[gb_frame];
+ memcpy(buf, ptr, h->packet_size);
+ return h->packet_size;
+}
+
+/* note: we support only one picture read at a time */
+static int video_read(URLContext *h, UINT8 *buf, int size)
+{
+ VideoData *s = h->priv_data;
+ INT64 curtime;
+
+ if (size != h->packet_size)
+ return -EINVAL;
+
+ /* wait based on the frame rate */
+ s->time_frame += (int)(1000000 / s->rate);
+ do {
+ curtime = gettime();
+ } while (curtime < s->time_frame);
+
+ /* read one frame */
+ if (s->use_mmap) {
+ return v4l_mm_read_picture(h, buf);
+ } else {
+ if (read(s->fd, buf, size) != size)
+ return -EIO;
+ return h->packet_size;
+ }
+}
+
+static int video_get_format(URLContext *h, URLFormat *f)
+{
+ VideoData *s = h->priv_data;
+
+ f->width = s->width;
+ f->height = s->height;
+ f->frame_rate = (int)(s->rate * FRAME_RATE_BASE);
+ strcpy(f->format_name, "rawvideo");
+
+ switch(s->frame_format) {
+ case VIDEO_PALETTE_YUV420P:
+ f->pix_fmt = PIX_FMT_YUV420P;
+ break;
+ case VIDEO_PALETTE_YUV422:
+ f->pix_fmt = PIX_FMT_YUV422;
+ break;
+ case VIDEO_PALETTE_RGB24:
+ f->pix_fmt = PIX_FMT_BGR24; /* NOTE: v4l uses BGR24, not RGB24 ! */
+ break;
+ default:
+ abort();
+ }
+ return 0;
+}
+
+/* URI syntax: 'video:width,height,rate'
+ */
+static int video_open(URLContext *h, const char *uri, int flags)
+{
+ VideoData *s;
+ const char *p;
+ int width, height;
+ int ret;
+ float rate;
+
+ /* extract parameters */
+ p = uri;
+ strstart(p, "video:", &p);
+ width = strtol(p, (char **)&p, 0);
+ if (width <= 0)
+ return -EINVAL;
+ if (*p == ',')
+ p++;
+ height = strtol(p, (char **)&p, 0);
+ if (height <= 0)
+ return -EINVAL;
+ if (*p == ',')
+ p++;
+ rate = strtod(p, (char **)&p);
+ if (rate <= 0)
+ return -EINVAL;
+
+ s = malloc(sizeof(VideoData));
+ if (!s)
+ return -ENOMEM;
+ h->priv_data = s;
+ h->is_streamed = 1;
+ s->width = width;
+ s->height = height;
+ s->rate = rate;
+ ret = v4l_init(h);
+ if (ret)
+ free(s);
+ return ret;
+}
+
+static int video_close(URLContext *h)
+{
+ VideoData *s = h->priv_data;
+
+ close(s->fd);
+ free(s);
+ return 0;
+}
+
+URLProtocol video_protocol = {
+ "video",
+ video_open,
+ video_read,
+ NULL,
+ NULL, /* seek */
+ video_close,
+ video_get_format,
+};
diff --git a/libav/http.c b/libav/http.c
new file mode 100644
index 0000000000..824f98b9e3
--- /dev/null
+++ b/libav/http.c
@@ -0,0 +1,318 @@
+/*
+ * HTTP protocol for ffmpeg client
+ * Copyright (c) 2000, 2001 Gerard Lantau.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include "avformat.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 {
+ int fd;
+ 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);
+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)
+{
+ struct sockaddr_in dest_addr;
+ const char *p, *path, *proxy_path;
+ char hostname[1024], *q;
+ int port, fd = -1, use_proxy;
+ struct hostent *hp;
+ HTTPContext *s;
+
+ h->is_streamed = 1;
+
+ s = malloc(sizeof(HTTPContext));
+ if (!s) {
+ return -ENOMEM;
+ }
+ h->priv_data = s;
+
+ proxy_path = getenv("http_proxy");
+ use_proxy = (proxy_path != NULL) && !getenv("no_proxy");
+
+ /* fill the dest addr */
+ redo:
+ if (use_proxy) {
+ p = proxy_path;
+ } else {
+ p = uri;
+ }
+ if (!strstart(p, "http://", &p))
+ goto fail;
+ q = hostname;
+ while (*p != ':' && *p != '/' && *p != '\0') {
+ if ((q - hostname) < sizeof(hostname) - 1)
+ *q++ = *p;
+ p++;
+ }
+ *q = '\0';
+ port = 80;
+ if (*p == ':') {
+ p++;
+ port = strtoul(p, (char **)&p, 10);
+ }
+ if (port <= 0)
+ goto fail;
+ if (use_proxy) {
+ path = uri;
+ } else {
+ if (*p == '\0')
+ path = "/";
+ else
+ path = p;
+ }
+
+ dest_addr.sin_family = AF_INET;
+ dest_addr.sin_port = htons(port);
+ if ((inet_aton(hostname, &dest_addr.sin_addr)) == 0) {
+ hp = gethostbyname(hostname);
+ if (!hp)
+ goto fail;
+ memcpy (&dest_addr.sin_addr, hp->h_addr, sizeof(dest_addr.sin_addr));
+ }
+
+ 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;
+ if (http_connect(h, path) < 0)
+ goto fail;
+ if (s->http_code == 303 && s->location[0] != '\0') {
+ /* url moved, get next */
+ uri = s->location;
+ goto redo;
+ }
+
+ return 0;
+ fail:
+ if (fd >= 0)
+ close(fd);
+ free(s);
+ return -EIO;
+}
+
+static int http_getc(HTTPContext *s)
+{
+ int len;
+ if (s->buf_ptr >= s->buf_end) {
+ redo:
+ len = read(s->fd, s->buffer, BUFFER_SIZE);
+ if (len < 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ goto redo;
+ 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)
+{
+ 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"
+ "\n",
+ post ? "POST" : "GET",
+ path,
+ FFMPEG_VERSION
+ );
+
+ 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)
+ 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 = read (s->fd, buf, size);
+ if (len < 0) {
+ if (errno != EINTR && errno != EAGAIN)
+ return -errno;
+ else
+ continue;
+ } 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;
+ int ret, size1;
+
+ size1 = size;
+ while (size > 0) {
+ ret = write (s->fd, buf, size);
+ if (ret < 0 && errno != EINTR && errno != EAGAIN)
+ return -errno;
+ size -= ret;
+ buf += ret;
+ }
+ return size1 - size;
+}
+
+static int http_close(URLContext *h)
+{
+ HTTPContext *s = h->priv_data;
+ close(s->fd);
+ return 0;
+}
+
+URLProtocol http_protocol = {
+ "http",
+ http_open,
+ http_read,
+ http_write,
+ NULL, /* seek */
+ http_close,
+};
diff --git a/libav/img.c b/libav/img.c
new file mode 100644
index 0000000000..db2d933ac0
--- /dev/null
+++ b/libav/img.c
@@ -0,0 +1,578 @@
+/*
+ * Image format
+ * Copyright (c) 2000, 2001 Gerard Lantau.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <math.h>
+
+#include "avformat.h"
+
+#define IMGFMT_YUV 1
+#define IMGFMT_PGMYUV 2
+#define IMGFMT_PGM 3
+
+typedef struct {
+ int width;
+ int height;
+ int img_number;
+ int img_size;
+ int img_fmt;
+ int is_pipe;
+ 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 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;
+}
+
+int img_read_packet(AVFormatContext *s1, AVPacket *pkt)
+{
+ VideoData *s = s1->priv_data;
+ char filename[1024];
+ int ret;
+ ByteIOContext f1, *f;
+
+ snprintf(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;
+ default:
+ return -EIO;
+ }
+
+ if (!s->is_pipe) {
+ url_fclose(f);
+ }
+
+ if (ret < 0) {
+ av_free_packet(pkt);
+ return -EIO; /* signal EOF */
+ } else {
+ 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 },
+};
+
+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;
+ int i, h;
+ char buf[1024];
+ char buf1[32];
+ ByteIOContext pb1, *f = &pb1;
+ AVStream *st;
+
+ s = malloc(sizeof(VideoData));
+ if (!s)
+ return -ENOMEM;
+
+ s1->priv_data = s;
+
+ s1->nb_streams = 1;
+ st = av_mallocz(sizeof(AVStream));
+ if (!st) {
+ free(s);
+ return -ENOMEM;
+ }
+ s1->streams[0] = st;
+
+ strcpy(s->path, s1->filename);
+ s->img_number = 0;
+
+ /* find format */
+ if (s1->format->flags & AVFMT_NOFILE)
+ s->is_pipe = 0;
+ else
+ s->is_pipe = 1;
+
+ if (s1->format == &pgmpipe_format ||
+ s1->format == &pgmyuv_format)
+ s->img_fmt = IMGFMT_PGMYUV;
+ else if (s1->format == &pgm_format)
+ s->img_fmt = IMGFMT_PGM;
+ else if (s1->format == &imgyuv_format)
+ s->img_fmt = IMGFMT_YUV;
+ else
+ goto fail;
+
+ if (!s->is_pipe) {
+ /* try to find the first image */
+ for(i=0;i<5;i++) {
+ snprintf(buf, sizeof(buf), s->path, s->img_number);
+ 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:
+ 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 = lseek((int)h->priv_data, 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);
+ }
+
+ s->img_size = (s->width * s->height * 3) / 2;
+
+ st->codec.codec_type = CODEC_TYPE_VIDEO;
+ st->codec.codec_id = CODEC_ID_RAWVIDEO;
+ st->codec.width = s->width;
+ st->codec.height = s->height;
+ st->codec.pix_fmt = PIX_FMT_YUV420P;
+ 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:
+ free(s);
+ return -EIO;
+}
+
+static int img_read_close(AVFormatContext *s1)
+{
+ VideoData *s = s1->priv_data;
+ free(s);
+ return 0;
+}
+
+/******************************************************/
+/* image output */
+
+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 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 img_write_header(AVFormatContext *s)
+{
+ VideoData *img;
+
+ img = av_mallocz(sizeof(VideoData));
+ if (!img)
+ return -1;
+ s->priv_data = img;
+ img->img_number = 1;
+ strcpy(img->path, s->filename);
+
+ /* find format */
+ if (s->format->flags & AVFMT_NOFILE)
+ img->is_pipe = 0;
+ else
+ img->is_pipe = 1;
+
+ if (s->format == &pgmpipe_format ||
+ s->format == &pgmyuv_format)
+ img->img_fmt = IMGFMT_PGMYUV;
+ else if (s->format == &pgm_format)
+ img->img_fmt = IMGFMT_PGM;
+ else if (s->format == &imgyuv_format)
+ img->img_fmt = IMGFMT_YUV;
+ else
+ goto fail;
+ return 0;
+ fail:
+ free(img);
+ return -EIO;
+}
+
+static int img_write_packet(AVFormatContext *s, int stream_index,
+ UINT8 *buf, int size)
+{
+ VideoData *img = s->priv_data;
+ AVStream *st = s->streams[stream_index];
+ ByteIOContext pb1, *pb;
+ AVPicture picture;
+ int width, height, ret, size1;
+ char filename[1024];
+
+ width = st->codec.width;
+ height = st->codec.height;
+ 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;
+ snprintf(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;
+ }
+ if (!img->is_pipe) {
+ url_fclose(pb);
+ }
+
+ img->img_number++;
+ return 0;
+}
+
+static int img_write_trailer(AVFormatContext *s)
+{
+ VideoData *img = s->priv_data;
+ free(img);
+ return 0;
+}
+
+AVFormat pgm_format = {
+ "pgm",
+ "pgm image format",
+ "",
+ "pgm",
+ CODEC_ID_NONE,
+ CODEC_ID_RAWVIDEO,
+ img_write_header,
+ img_write_packet,
+ img_write_trailer,
+
+ img_read_header,
+ img_read_packet,
+ img_read_close,
+ NULL,
+ AVFMT_NOFILE,
+};
+
+AVFormat pgmyuv_format = {
+ "pgmyuv",
+ "pgm with YUV content image format",
+ "",
+ "pgm",
+ CODEC_ID_NONE,
+ CODEC_ID_RAWVIDEO,
+ img_write_header,
+ img_write_packet,
+ img_write_trailer,
+
+ img_read_header,
+ img_read_packet,
+ img_read_close,
+ NULL,
+ AVFMT_NOFILE,
+};
+
+AVFormat imgyuv_format = {
+ ".Y.U.V",
+ ".Y.U.V format",
+ "",
+ "Y",
+ CODEC_ID_NONE,
+ CODEC_ID_RAWVIDEO,
+ img_write_header,
+ img_write_packet,
+ img_write_trailer,
+
+ img_read_header,
+ img_read_packet,
+ img_read_close,
+ NULL,
+ AVFMT_NOFILE,
+};
+
+AVFormat pgmpipe_format = {
+ "pgmpipe",
+ "PGM pipe format",
+ "",
+ "pgm",
+ CODEC_ID_NONE,
+ CODEC_ID_RAWVIDEO,
+ img_write_header,
+ img_write_packet,
+ img_write_trailer,
+
+ img_read_header,
+ img_read_packet,
+ img_read_close,
+ NULL,
+};
diff --git a/libav/jpegenc.c b/libav/jpegenc.c
new file mode 100644
index 0000000000..d02332cd79
--- /dev/null
+++ b/libav/jpegenc.c
@@ -0,0 +1,102 @@
+/*
+ * Miscellaneous MJPEG based formats
+ * Copyright (c) 2000 Gerard Lantau.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <netinet/in.h>
+#include <string.h>
+#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)
+{
+ 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;
+}
+
+AVFormat mpjpeg_format = {
+ "mpjpeg",
+ "Mime multipart JPEG format",
+ "multipart/x-mixed-replace;boundary=" BOUNDARY_TAG,
+ "mjpg",
+ CODEC_ID_NONE,
+ CODEC_ID_MJPEG,
+ mpjpeg_write_header,
+ mpjpeg_write_packet,
+ mpjpeg_write_trailer,
+};
+
+
+/* single frame JPEG */
+
+static int jpeg_write_header(AVFormatContext *s)
+{
+ return 0;
+}
+
+static int jpeg_write_packet(AVFormatContext *s, int stream_index,
+ UINT8 *buf, int size)
+{
+ put_buffer(&s->pb, buf, size);
+ put_flush_packet(&s->pb);
+ return 1; /* no more data can be sent */
+}
+
+static int jpeg_write_trailer(AVFormatContext *s)
+{
+ return 0;
+}
+
+AVFormat jpeg_format = {
+ "jpeg",
+ "JPEG image",
+ "image/jpeg",
+ "jpg,jpeg",
+ CODEC_ID_NONE,
+ CODEC_ID_MJPEG,
+ jpeg_write_header,
+ jpeg_write_packet,
+ jpeg_write_trailer,
+};
diff --git a/libav/mpeg.c b/libav/mpeg.c
new file mode 100644
index 0000000000..86e3af6184
--- /dev/null
+++ b/libav/mpeg.c
@@ -0,0 +1,663 @@
+/*
+ * Output a MPEG1 multiplexed video/audio stream
+ * Copyright (c) 2000 Gerard Lantau.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/time.h>
+
+#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;
+ float pts;
+ 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;
+} MpegMuxContext;
+
+#define PACK_START_CODE ((unsigned int)0x000001ba)
+#define SYSTEM_HEADER_START_CODE ((unsigned int)0x000001bb)
+#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
+
+static int put_pack_header(AVFormatContext *ctx,
+ UINT8 *buf, long long timestamp)
+{
+ MpegMuxContext *s = ctx->priv_data;
+ PutBitContext pb;
+
+ init_put_bits(&pb, buf, 128, NULL, NULL);
+
+ put_bits(&pb, 32, PACK_START_CODE);
+ put_bits(&pb, 4, 0x2);
+ put_bits(&pb, 3, (timestamp >> 30) & 0x07);
+ put_bits(&pb, 1, 1);
+ put_bits(&pb, 15, (timestamp >> 15) & 0x7fff);
+ put_bits(&pb, 1, 1);
+ put_bits(&pb, 15, (timestamp) & 0x7fff);
+ put_bits(&pb, 1, 1);
+ put_bits(&pb, 1, 1);
+ put_bits(&pb, 22, s->mux_rate);
+ put_bits(&pb, 1, 1);
+
+ flush_put_bits(&pb);
+ return pb.buf_ptr - 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 = pb.buf_ptr - 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;
+ int bitrate, i, mpa_id, mpv_id, ac3_id;
+ AVStream *st;
+ StreamInfo *stream;
+
+ s = malloc(sizeof(MpegMuxContext));
+ if (!s)
+ return -1;
+ memset(s, 0, sizeof(MpegMuxContext));
+ ctx->priv_data = s;
+ s->packet_number = 0;
+
+ /* XXX: hardcoded */
+ 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;
+ }
+ }
+
+ /* 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);
+ /* every 2 seconds */
+ s->pack_header_freq = 2 * bitrate / s->packet_size / 8;
+ /* every 10 seconds */
+ 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->pts = 0;
+ stream->start_pts = -1;
+ }
+ return 0;
+ fail:
+ for(i=0;i<ctx->nb_streams;i++) {
+ free(ctx->streams[i]->priv_data);
+ }
+ free(s);
+ return -ENOMEM;
+}
+
+/* flush the packet on stream stream_index */
+static void flush_packet(AVFormatContext *ctx, int stream_index)
+{
+ 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;
+ INT64 timestamp;
+ UINT8 buffer[128];
+
+ 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 */
+ payload_size = s->packet_size - (size + 6 + 5);
+ 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 + 5);
+ /* stuffing */
+ for(i=0;i<stuffing_size;i++)
+ put_byte(&ctx->pb, 0xff);
+
+ /* presentation time stamp */
+ put_byte(&ctx->pb,
+ (0x02 << 4) |
+ (((timestamp >> 30) & 0x07) << 1) |
+ 1);
+ put_be16(&ctx->pb, (((timestamp >> 15) & 0x7fff) << 1) | 1);
+ put_be16(&ctx->pb, (((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);
+ }
+ }
+
+ /* 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)
+{
+ 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 = stream->pts * 90000.0;
+ 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 = stream->pts * 90000.0;
+ flush_packet(ctx, stream_index);
+ }
+ }
+
+ if (st->codec.codec_type == CODEC_TYPE_AUDIO) {
+ stream->pts += (float)st->codec.frame_size / st->codec.sample_rate;
+ } else {
+ stream->pts += FRAME_RATE_BASE / (float)st->codec.frame_rate;
+ }
+ 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)
+ flush_packet(ctx, i);
+ }
+
+ /* 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
+
+typedef struct MpegDemuxContext {
+ int header_state;
+ int mux_rate; /* 50 byte/s unit */
+} 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 mpeg_mux_read_header(AVFormatContext *s,
+ AVFormatParameters *ap)
+{
+ MpegDemuxContext *m;
+ int size, startcode, c, rate_bound, audio_bound, video_bound, mux_rate, val;
+ int codec_id, n, i, type;
+ AVStream *st;
+
+ m = av_mallocz(sizeof(MpegDemuxContext));
+ if (!m)
+ return -ENOMEM;
+ s->priv_data = m;
+
+ /* search first pack header */
+ m->header_state = 0xff;
+ size = MAX_SYNC_SIZE;
+ for(;;) {
+ while (size > 0) {
+ startcode = find_start_code(&s->pb, &size, &m->header_state);
+ if (startcode == PACK_START_CODE)
+ goto found;
+ }
+ return -ENODATA;
+ found:
+ /* search system header just after pack header */
+ /* parse pack header */
+ get_byte(&s->pb); /* ts1 */
+ get_be16(&s->pb); /* ts2 */
+ get_be16(&s->pb); /* ts3 */
+
+ mux_rate = get_byte(&s->pb) << 16;
+ mux_rate |= get_byte(&s->pb) << 8;
+ mux_rate |= get_byte(&s->pb);
+ mux_rate &= (1 << 22) - 1;
+ m->mux_rate = mux_rate;
+
+ startcode = find_start_code(&s->pb, &size, &m->header_state);
+ if (startcode == SYSTEM_HEADER_START_CODE)
+ break;
+ }
+ size = get_be16(&s->pb);
+ rate_bound = get_byte(&s->pb) << 16;
+ rate_bound |= get_byte(&s->pb) << 8;
+ rate_bound |= get_byte(&s->pb);
+ rate_bound = (rate_bound >> 1) & ((1 << 22) - 1);
+ audio_bound = get_byte(&s->pb) >> 2;
+ video_bound = get_byte(&s->pb) & 0x1f;
+ get_byte(&s->pb); /* reserved byte */
+#if 0
+ printf("mux_rate=%d kbit/s\n", (m->mux_rate * 50 * 8) / 1000);
+ printf("rate_bound=%d\n", rate_bound);
+ printf("audio_bound=%d\n", audio_bound);
+ printf("video_bound=%d\n", video_bound);
+#endif
+ size -= 6;
+ s->nb_streams = 0;
+ while (size > 0) {
+ c = get_byte(&s->pb);
+ size--;
+ if ((c & 0x80) == 0)
+ break;
+ val = get_be16(&s->pb);
+ size -= 2;
+ if (c >= 0xc0 && c <= 0xdf) {
+ /* mpeg audio stream */
+ type = CODEC_TYPE_AUDIO;
+ codec_id = CODEC_ID_MP2;
+ n = 1;
+ c = c | 0x100;
+ } else if (c >= 0xe0 && c <= 0xef) {
+ type = CODEC_TYPE_VIDEO;
+ codec_id = CODEC_ID_MPEG1VIDEO;
+ n = 1;
+ c = c | 0x100;
+ } else if (c == 0xb8) {
+ /* all audio streams */
+ /* XXX: hack for DVD: we force AC3, although we do not
+ know that this codec will be used */
+ type = CODEC_TYPE_AUDIO;
+ codec_id = CODEC_ID_AC3;
+ n = audio_bound;
+ c = 0x80;
+ /* c = 0x1c0; */
+ } else if (c == 0xb9) {
+ /* all video streams */
+ type = CODEC_TYPE_VIDEO;
+ codec_id = CODEC_ID_MPEG1VIDEO;
+ n = video_bound;
+ c = 0x1e0;
+ } else {
+ type = 0;
+ codec_id = 0;
+ n = 0;
+ }
+
+ for(i=0;i<n;i++) {
+ st = av_mallocz(sizeof(AVStream));
+ if (!st)
+ return -ENOMEM;
+ s->streams[s->nb_streams++] = st;
+ st->id = c + i;
+ st->codec.codec_type = type;
+ st->codec.codec_id = codec_id;
+ }
+ }
+
+ 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 mpeg_mux_read_packet(AVFormatContext *s,
+ AVPacket *pkt)
+{
+ MpegDemuxContext *m = s->priv_data;
+ AVStream *st;
+ int len, size, startcode, i, c, flags, header_len;
+ 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 = 0;
+ dts = 0;
+ /* 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;
+ dts = pts;
+ } 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) == 0x40) {
+ pts = get_pts(&s->pb, -1);
+ dts = pts;
+ 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;
+ }
+ /* skip packet */
+ url_fskip(&s->pb, len);
+ goto redo;
+ found:
+ av_new_packet(pkt, len);
+ get_buffer(&s->pb, pkt->data, pkt->size);
+ pkt->pts = pts;
+ pkt->stream_index = i;
+ return 0;
+}
+
+static int mpeg_mux_read_close(AVFormatContext *s)
+{
+ MpegDemuxContext *m = s->priv_data;
+ free(m);
+ return 0;
+}
+
+AVFormat mpeg_mux_format = {
+ "mpeg",
+ "MPEG multiplex format",
+ "video/x-mpeg",
+ "mpg,mpeg,vob",
+ CODEC_ID_MP2,
+ CODEC_ID_MPEG1VIDEO,
+ mpeg_mux_init,
+ mpeg_mux_write_packet,
+ mpeg_mux_end,
+
+ mpeg_mux_read_header,
+ mpeg_mux_read_packet,
+ mpeg_mux_read_close,
+};
diff --git a/libav/raw.c b/libav/raw.c
new file mode 100644
index 0000000000..47dfa3b0fe
--- /dev/null
+++ b/libav/raw.c
@@ -0,0 +1,288 @@
+/*
+ * RAW encoder and decoder
+ * Copyright (c) 2001 Gerard Lantau.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <errno.h>
+#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)
+{
+ 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;
+
+ st = malloc(sizeof(AVStream));
+ if (!st)
+ return -1;
+ s->nb_streams = 1;
+ s->streams[0] = st;
+
+ st->id = 0;
+
+ if (ap) {
+ if (s->format->audio_codec != CODEC_ID_NONE) {
+ st->codec.codec_type = CODEC_TYPE_AUDIO;
+ st->codec.codec_id = s->format->audio_codec;
+ } else if (s->format->video_codec != CODEC_ID_NONE) {
+ st->codec.codec_type = CODEC_TYPE_VIDEO;
+ st->codec.codec_id = s->format->video_codec;
+ } else {
+ free(st);
+ return -1;
+ }
+
+ switch(st->codec.codec_type) {
+ case CODEC_TYPE_AUDIO:
+ st->codec.sample_rate = ap->sample_rate;
+ st->codec.channels = ap->channels;
+ /* XXX: endianness */
+ break;
+ case CODEC_TYPE_VIDEO:
+ st->codec.frame_rate = ap->frame_rate;
+ st->codec.width = ap->width;
+ st->codec.height = ap->height;
+ break;
+ default:
+ abort();
+ break;
+ }
+ } else {
+ abort();
+ }
+ return 0;
+}
+
+#define MIN_SIZE 1024
+
+int raw_read_packet(AVFormatContext *s,
+ AVPacket *pkt)
+{
+ int packet_size, n, ret;
+
+ if (url_feof(&s->pb))
+ return -EIO;
+
+ packet_size = url_get_packet_size(&s->pb);
+ n = MIN_SIZE / packet_size;
+ if (n <= 0)
+ n = 1;
+ if (av_new_packet(pkt, n * packet_size) < 0)
+ return -EIO;
+
+ pkt->stream_index = 0;
+ ret = get_buffer(&s->pb, pkt->data, pkt->size);
+ if (ret < 0)
+ av_free_packet(pkt);
+ return ret;
+}
+
+int raw_read_close(AVFormatContext *s)
+{
+ return 0;
+}
+
+/* mp3 read */
+static int mp3_read_header(AVFormatContext *s,
+ AVFormatParameters *ap)
+{
+ AVStream *st;
+
+ st = 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_id = CODEC_ID_MP2;
+ /* XXX: read the first frame and extract rate and channels */
+ st->codec.sample_rate = 44100;
+ st->codec.channels = 2;
+ return 0;
+}
+
+/* mpeg1/h263 input */
+static int video_read_header(AVFormatContext *s,
+ AVFormatParameters *ap)
+{
+ AVStream *st;
+
+ st = av_mallocz(sizeof(AVStream));
+ if (!st)
+ return -1;
+ s->nb_streams = 1;
+ s->streams[0] = st;
+
+ st->codec.codec_type = CODEC_TYPE_VIDEO;
+ st->codec.codec_id = s->format->video_codec;
+ return 0;
+}
+
+AVFormat mp2_format = {
+ "mp2",
+ "MPEG audio",
+ "audio/x-mpeg",
+ "mp2,mp3",
+ CODEC_ID_MP2,
+ 0,
+ raw_write_header,
+ raw_write_packet,
+ raw_write_trailer,
+
+ mp3_read_header,
+ raw_read_packet,
+ raw_read_close,
+};
+
+AVFormat ac3_format = {
+ "ac3",
+ "raw ac3",
+ "audio/x-ac3",
+ "ac3",
+ CODEC_ID_AC3,
+ 0,
+ raw_write_header,
+ raw_write_packet,
+ raw_write_trailer,
+};
+
+AVFormat h263_format = {
+ "h263",
+ "raw h263",
+ "video/x-h263",
+ "h263",
+ 0,
+ CODEC_ID_H263,
+ raw_write_header,
+ raw_write_packet,
+ raw_write_trailer,
+ video_read_header,
+ raw_read_packet,
+ raw_read_close,
+};
+
+AVFormat mpeg1video_format = {
+ "mpegvideo",
+ "MPEG video",
+ "video/x-mpeg",
+ "mpg,mpeg",
+ 0,
+ CODEC_ID_MPEG1VIDEO,
+ raw_write_header,
+ raw_write_packet,
+ raw_write_trailer,
+ video_read_header,
+ raw_read_packet,
+ raw_read_close,
+};
+
+AVFormat pcm_format = {
+ "pcm",
+ "pcm raw format",
+ NULL,
+ "sw",
+ CODEC_ID_PCM,
+ 0,
+ raw_write_header,
+ raw_write_packet,
+ raw_write_trailer,
+
+ raw_read_header,
+ raw_read_packet,
+ raw_read_close,
+};
+
+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:
+ abort();
+ break;
+ }
+
+ if (av_new_packet(pkt, packet_size) < 0)
+ return -EIO;
+
+ pkt->stream_index = 0;
+ /* bypass buffered I/O */
+ ret = url_read(url_fileno(&s->pb), pkt->data, pkt->size);
+ if (ret != pkt->size) {
+ av_free_packet(pkt);
+ return -EIO;
+ } else {
+ return 0;
+ }
+}
+
+AVFormat rawvideo_format = {
+ "rawvideo",
+ "raw video format",
+ NULL,
+ "yuv",
+ CODEC_ID_NONE,
+ CODEC_ID_RAWVIDEO,
+ raw_write_header,
+ raw_write_packet,
+ raw_write_trailer,
+
+ raw_read_header,
+ rawvideo_read_packet,
+ raw_read_close,
+};
diff --git a/libav/rm.c b/libav/rm.c
new file mode 100644
index 0000000000..8c850400e4
--- /dev/null
+++ b/libav/rm.c
@@ -0,0 +1,710 @@
+/*
+ * "Real" compatible mux and demux.
+ * Copyright (c) 2000, 2001 Gerard Lantau.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+#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 */
+ 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, 24); /* frames per seconds ? */
+ put_be32(s,0); /* unknown meaning */
+ put_be16(s, 12); /* 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)
+{
+ StreamInfo *stream;
+ RMContext *rm;
+ int n;
+ AVCodecContext *codec;
+
+ rm = malloc(sizeof(RMContext));
+ if (!rm)
+ return -1;
+ memset(rm, 0, sizeof(RMContext));
+ s->priv_data = rm;
+
+ 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;
+ }
+ }
+
+ 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[size];
+ RMContext *rm = s->priv_data;
+ ByteIOContext *pb = &s->pb;
+ StreamInfo *stream = rm->audio_stream;
+ int i;
+
+ 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++;
+ 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)
+{
+ 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);
+
+ free(rm);
+ 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;
+ 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];
+
+ if (get_le32(pb) != MKTAG('.', 'R', 'M', 'F'))
+ return -EIO;
+ rm = av_mallocz(sizeof(RMContext));
+ if (!rm)
+ return -ENOMEM;
+ s->priv_data = rm;
+
+ 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 */
+ 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;
+ nstrcpy(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:
+ st->codec.sub_id = 0;
+ st->codec.codec_id = CODEC_ID_RV10;
+ break;
+ case 0x10003000:
+ case 0x10003001:
+ st->codec.sub_id = 3;
+ 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 */
+ get_be32(pb); /* next data header */
+ return 0;
+
+ fail:
+ for(i=0;i<s->nb_streams;i++) {
+ free(s->streams[i]);
+ }
+ return -EIO;
+}
+
+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;
+
+ 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 */
+ 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;
+ }
+
+ 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)
+{
+ RMContext *rm = s->priv_data;
+ free(rm);
+ return 0;
+}
+
+AVFormat rm_format = {
+ "rm",
+ "rm format",
+ "audio/x-pn-realaudio",
+ "rm,ra",
+ CODEC_ID_AC3,
+ CODEC_ID_RV10,
+ rm_write_header,
+ rm_write_packet,
+ rm_write_trailer,
+
+ rm_read_header,
+ rm_read_packet,
+ rm_read_close,
+};
diff --git a/libav/swf.c b/libav/swf.c
new file mode 100644
index 0000000000..a93c4f7097
--- /dev/null
+++ b/libav/swf.c
@@ -0,0 +1,552 @@
+/*
+ * Flash Compatible Streaming Format
+ * Copyright (c) 2000 Gerard Lantau.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "avformat.h"
+
+#include <assert.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 {
+ long long duration_pos;
+ long long 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;
+ long long 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, p.buf_ptr - 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, p.buf_ptr - 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 = 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, 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, p.buf_ptr - 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 */
+ 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)
+{
+ 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);
+ }
+ free(swf);
+ 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_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:
+ 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;
+}
+
+AVFormat swf_format = {
+ "swf",
+ "Flash format",
+ "application/x-shockwave-flash",
+ "swf",
+ CODEC_ID_MP2,
+ CODEC_ID_MJPEG,
+ swf_write_header,
+ swf_write_packet,
+ swf_write_trailer,
+
+ swf_read_header,
+ swf_read_packet,
+ swf_read_close,
+};
diff --git a/libav/udp.c b/libav/udp.c
new file mode 100644
index 0000000000..329653bf18
--- /dev/null
+++ b/libav/udp.c
@@ -0,0 +1,148 @@
+/*
+ * UDP prototype streaming system
+ * Copyright (c) 2000 Gerard Lantau.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include "avformat.h"
+
+typedef struct {
+ int udp_socket;
+ int max_payload_size; /* in bytes */
+} UDPContext;
+
+#define UDP_TX_BUF_SIZE 32768
+
+/* put it in UDP context */
+static struct sockaddr_in dest_addr;
+
+/* return non zero if error */
+static int udp_open(URLContext *h, const char *uri, int flags)
+{
+ int local_port = 0;
+ struct sockaddr_in my_addr;
+ const char *p, *q;
+ char hostname[1024];
+ int port, udp_socket, tmp;
+ struct hostent *hp;
+ UDPContext *s;
+
+ h->is_streamed = 1;
+
+ if (!(flags & URL_WRONLY))
+ return -EIO;
+
+ /* fill the dest addr */
+ p = uri;
+ if (!strstart(p, "udp:", &p))
+ return -1;
+ q = strchr(p, ':');
+ if (!q)
+ return -1;
+ memcpy(hostname, p, q - p);
+ hostname[q - p] = '\0';
+ port = strtol(q+1, NULL, 10);
+ if (port <= 0)
+ return -1;
+
+ dest_addr.sin_family = AF_INET;
+ dest_addr.sin_port = htons(port);
+ if ((inet_aton(hostname, &dest_addr.sin_addr)) == 0) {
+ hp = gethostbyname(hostname);
+ if (!hp)
+ return -1;
+ memcpy ((char *) &dest_addr.sin_addr, hp->h_addr, hp->h_length);
+ }
+
+ udp_socket = socket(PF_INET, SOCK_DGRAM, 0);
+ if (udp_socket < 0)
+ return -1;
+
+ my_addr.sin_family = AF_INET;
+ my_addr.sin_port = htons(local_port);
+ my_addr.sin_addr.s_addr = htonl (INADDR_ANY);
+
+ /* the bind is needed to give a port to the socket now */
+ if (bind(udp_socket,(struct sockaddr *)&my_addr, sizeof(my_addr)) < 0)
+ goto fail;
+
+ /* limit the tx buf size to limit latency */
+
+ tmp = UDP_TX_BUF_SIZE;
+ if (setsockopt(udp_socket, SOL_SOCKET, SO_SNDBUF, &tmp, sizeof(tmp)) < 0) {
+ perror("setsockopt sndbuf");
+ goto fail;
+ }
+
+ s = malloc(sizeof(UDPContext));
+ if (!s)
+ return -ENOMEM;
+ h->priv_data = s;
+ s->udp_socket = udp_socket;
+ h->packet_size = 1500;
+ return 0;
+ fail:
+ return -EIO;
+}
+
+int udp_close(URLContext *h)
+{
+ UDPContext *s = h->priv_data;
+ close(s->udp_socket);
+ return 0;
+}
+
+int udp_write(URLContext *h, UINT8 *buf, int size)
+{
+ UDPContext *s = h->priv_data;
+ int ret, len, size1;
+
+ /* primitive way to avoid big packets */
+ size1 = size;
+ while (size > 0) {
+ len = size;
+ if (len > h->packet_size)
+ len = h->packet_size;
+
+ ret = sendto (s->udp_socket, buf, len, 0,
+ (struct sockaddr *) &dest_addr,
+ sizeof (dest_addr));
+ if (ret < 0)
+ perror("sendto");
+ buf += len;
+ size -= len;
+ }
+ return size1 - size;
+}
+
+URLProtocol udp_protocol = {
+ "udp",
+ udp_open,
+ NULL, /* read */
+ udp_write,
+ NULL, /* seek */
+ udp_close,
+};
diff --git a/libav/utils.c b/libav/utils.c
new file mode 100644
index 0000000000..9018d0fb8d
--- /dev/null
+++ b/libav/utils.c
@@ -0,0 +1,533 @@
+/*
+ * Various utilities for ffmpeg system
+ * Copyright (c) 2000,2001 Gerard Lantau
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include "avformat.h"
+
+AVFormat *first_format;
+
+void register_avformat(AVFormat *format)
+{
+ AVFormat **p;
+ p = &first_format;
+ while (*p != NULL) p = &(*p)->next;
+ *p = format;
+ format->next = NULL;
+}
+
+int match_ext(const char *filename, const char *extensions)
+{
+ const char *ext, *p;
+ char ext1[32], *q;
+
+ ext = strrchr(filename, '.');
+ if (ext) {
+ ext++;
+ p = extensions;
+ for(;;) {
+ q = ext1;
+ while (*p != '\0' && *p != ',')
+ *q++ = *p++;
+ *q = '\0';
+ if (!strcasecmp(ext1, ext))
+ return 1;
+ if (*p == '\0')
+ break;
+ p++;
+ }
+ }
+ return 0;
+}
+
+AVFormat *guess_format(const char *short_name, const char *filename, const char *mime_type)
+{
+ AVFormat *fmt, *fmt_found;
+ int score_max, score;
+
+ /* find the proper file type */
+ fmt_found = NULL;
+ score_max = 0;
+ fmt = first_format;
+ while (fmt != NULL) {
+ score = 0;
+ if (fmt->name && short_name && !strcmp(fmt->name, short_name))
+ score += 100;
+ if (fmt->mime_type && mime_type && !strcmp(fmt->mime_type, mime_type))
+ score += 10;
+ if (filename && fmt->extensions &&
+ match_ext(filename, fmt->extensions)) {
+ score += 5;
+ }
+ if (score > score_max) {
+ score_max = score;
+ fmt_found = fmt;
+ }
+ fmt = fmt->next;
+ }
+ return fmt_found;
+}
+
+/* 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 */
+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;
+}
+
+void nstrcpy(char *buf, int buf_size, const char *str)
+{
+ int c;
+ char *q = buf;
+
+ for(;;) {
+ c = *str++;
+ if (c == 0 || q >= buf + buf_size - 1)
+ break;
+ *q++ = c;
+ }
+ *q = '\0';
+}
+
+void register_all(void)
+{
+ avcodec_init();
+ avcodec_register_all();
+ avcodec_register_more();
+
+ register_avformat(&mp2_format);
+ register_avformat(&ac3_format);
+ register_avformat(&mpeg_mux_format);
+ register_avformat(&mpeg1video_format);
+ register_avformat(&h263_format);
+ register_avformat(&rm_format);
+ register_avformat(&asf_format);
+ register_avformat(&avi_format);
+ register_avformat(&mpjpeg_format);
+ register_avformat(&jpeg_format);
+ register_avformat(&swf_format);
+ register_avformat(&wav_format);
+ register_avformat(&pcm_format);
+ register_avformat(&rawvideo_format);
+ register_avformat(&ffm_format);
+ register_avformat(&pgm_format);
+ register_avformat(&pgmyuv_format);
+ register_avformat(&imgyuv_format);
+ register_avformat(&pgmpipe_format);
+
+ register_protocol(&file_protocol);
+ register_protocol(&pipe_protocol);
+ register_protocol(&audio_protocol);
+ register_protocol(&video_protocol);
+ register_protocol(&udp_protocol);
+ register_protocol(&http_protocol);
+}
+
+/* memory handling */
+
+int av_new_packet(AVPacket *pkt, int size)
+{
+ pkt->data = malloc(size);
+ if (!pkt->data)
+ return -ENOMEM;
+ pkt->size = size;
+ /* sane state */
+ pkt->pts = 0;
+ pkt->stream_index = 0;
+ pkt->flags = 0;
+ return 0;
+}
+
+void av_free_packet(AVPacket *pkt)
+{
+ free(pkt->data);
+ /* fail safe */
+ pkt->data = NULL;
+ pkt->size = 0;
+}
+
+/* fifo handling */
+
+int fifo_init(FifoBuffer *f, int size)
+{
+ f->buffer = malloc(size);
+ if (!f->buffer)
+ return -1;
+ f->end = f->buffer + size;
+ f->wptr = f->rptr = f->buffer;
+ return 0;
+}
+
+void fifo_free(FifoBuffer *f)
+{
+ free(f->buffer);
+}
+
+int fifo_size(FifoBuffer *f, UINT8 *rptr)
+{
+ int size;
+
+ if (f->wptr >= rptr) {
+ size = f->wptr - rptr;
+ } else {
+ size = (f->end - rptr) + (f->wptr - f->buffer);
+ }
+ return size;
+}
+
+/* get data from the fifo (return -1 if not enough data) */
+int fifo_read(FifoBuffer *f, UINT8 *buf, int buf_size, UINT8 **rptr_ptr)
+{
+ UINT8 *rptr = *rptr_ptr;
+ int size, len;
+
+ if (f->wptr >= rptr) {
+ size = f->wptr - rptr;
+ } else {
+ size = (f->end - rptr) + (f->wptr - f->buffer);
+ }
+
+ if (size < buf_size)
+ return -1;
+ while (buf_size > 0) {
+ len = f->end - rptr;
+ if (len > buf_size)
+ len = buf_size;
+ memcpy(buf, rptr, len);
+ buf += len;
+ rptr += len;
+ if (rptr >= f->end)
+ rptr = f->buffer;
+ buf_size -= len;
+ }
+ *rptr_ptr = rptr;
+ return 0;
+}
+
+void fifo_write(FifoBuffer *f, UINT8 *buf, int size, UINT8 **wptr_ptr)
+{
+ int len;
+ UINT8 *wptr;
+ wptr = *wptr_ptr;
+ while (size > 0) {
+ len = f->end - wptr;
+ if (len > size)
+ len = size;
+ memcpy(wptr, buf, len);
+ wptr += len;
+ if (wptr >= f->end)
+ wptr = f->buffer;
+ buf += len;
+ size -= len;
+ }
+ *wptr_ptr = wptr;
+}
+
+/* media file handling */
+
+AVFormatContext *av_open_input_file(const char *filename, int buf_size)
+{
+ AVFormatParameters params, *ap;
+ AVFormat *fmt;
+ AVFormatContext *ic = NULL;
+ URLFormat url_format;
+ int err;
+
+ ic = av_mallocz(sizeof(AVFormatContext));
+ if (!ic)
+ goto fail;
+ if (url_fopen(&ic->pb, filename, URL_RDONLY) < 0)
+ goto fail;
+
+ if (buf_size > 0) {
+ url_setbufsize(&ic->pb, buf_size);
+ }
+
+ /* find format */
+ err = url_getformat(url_fileno(&ic->pb), &url_format);
+ if (err >= 0) {
+ fmt = guess_format(url_format.format_name, NULL, NULL);
+ ap = &params;
+ ap->sample_rate = url_format.sample_rate;
+ ap->frame_rate = url_format.frame_rate;
+ ap->channels = url_format.channels;
+ ap->width = url_format.width;
+ ap->height = url_format.height;
+ ap->pix_fmt = url_format.pix_fmt;
+ } else {
+ fmt = guess_format(NULL, filename, NULL);
+ ap = NULL;
+ }
+ if (!fmt || !fmt->read_header) {
+ return NULL;
+ }
+ ic->format = fmt;
+
+ err = ic->format->read_header(ic, ap);
+ if (err < 0) {
+ url_fclose(&ic->pb);
+ goto fail;
+ }
+
+ return ic;
+
+ fail:
+ if (ic)
+ free(ic);
+ return NULL;
+}
+
+int av_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ AVPacketList *pktl;
+
+ pktl = s->packet_buffer;
+ if (pktl) {
+ /* read packet from packet buffer, if there is data */
+ *pkt = pktl->pkt;
+ s->packet_buffer = pktl->next;
+ free(pktl);
+ return 0;
+ } else {
+ return s->format->read_packet(s, pkt);
+ }
+}
+
+void av_close_input_file(AVFormatContext *s)
+{
+ int i;
+
+ if (s->format->read_close)
+ s->format->read_close(s);
+ for(i=0;i<s->nb_streams;i++) {
+ free(s->streams[i]);
+ }
+ if (s->packet_buffer) {
+ AVPacketList *p, *p1;
+ p = s->packet_buffer;
+ while (p != NULL) {
+ p1 = p->next;
+ av_free_packet(&p->pkt);
+ free(p);
+ p = p1;
+ }
+ s->packet_buffer = NULL;
+ }
+ url_fclose(&s->pb);
+ free(s);
+}
+
+
+int av_write_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ /* XXX: currently, an emulation because internal API must change */
+ return s->format->write_packet(s, pkt->stream_index, pkt->data, pkt->size);
+}
+
+/* "user interface" functions */
+
+void dump_format(AVFormatContext *ic,
+ int index,
+ const char *url,
+ int is_output)
+{
+ int i;
+ char buf[256];
+
+ fprintf(stderr, "%s #%d, %s, %s '%s':\n",
+ is_output ? "Output" : "Input",
+ index, ic->format->name,
+ is_output ? "to" : "from", url);
+ for(i=0;i<ic->nb_streams;i++) {
+ AVStream *st = ic->streams[i];
+ avcodec_string(buf, sizeof(buf), &st->codec, is_output);
+ fprintf(stderr, " Stream #%d.%d: %s\n", index, i, buf);
+ }
+}
+
+typedef struct {
+ const char *str;
+ int width, height;
+} SizeEntry;
+
+static SizeEntry sizes[] = {
+ { "sqcif", 128, 96 },
+ { "qcif", 176, 144 },
+ { "cif", 352, 288 },
+ { "4cif", 704, 576 },
+};
+
+int parse_image_size(int *width_ptr, int *height_ptr, const char *str)
+{
+ int i;
+ int n = sizeof(sizes) / sizeof(SizeEntry);
+ const char *p;
+ int frame_width = 0, frame_height = 0;
+
+ for(i=0;i<n;i++) {
+ if (!strcmp(sizes[i].str, str)) {
+ frame_width = sizes[i].width;
+ frame_height = sizes[i].height;
+ break;
+ }
+ }
+ if (i == n) {
+ p = str;
+ frame_width = strtol(p, (char **)&p, 10);
+ if (*p)
+ p++;
+ frame_height = strtol(p, (char **)&p, 10);
+ }
+ if (frame_width <= 0 || frame_height <= 0)
+ return -1;
+ *width_ptr = frame_width;
+ *height_ptr = frame_height;
+ return 0;
+}
+
+INT64 gettime(void)
+{
+ struct timeval tv;
+ gettimeofday(&tv,NULL);
+ return (INT64)tv.tv_sec * 1000000 + tv.tv_usec;
+}
+
+/* syntax: [YYYY-MM-DD ][[HH:]MM:]SS[.m...] . Return the date in micro seconds since 1970 */
+INT64 parse_date(const char *datestr, int duration)
+{
+ const char *p;
+ INT64 t;
+ int sec;
+
+ p = datestr;
+ if (!duration) {
+ static const UINT8 months[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+ int year, month, day, i;
+
+ if (strlen(p) >= 5 && p[4] == '-') {
+
+ year = strtol(p, (char **)&p, 10);
+ if (*p)
+ p++;
+ month = strtol(p, (char **)&p, 10) - 1;
+ if (*p)
+ p++;
+ day = strtol(p, (char **)&p, 10) - 1;
+ if (*p)
+ p++;
+ day += (year - 1970) * 365;
+ /* if >= March, take February of current year into account too */
+ if (month >= 2)
+ year++;
+ for(i=1970;i<year;i++) {
+ if ((i % 100) == 0) {
+ if ((i % 400) == 0) day++;
+ } else if ((i % 4) == 0) {
+ day++;
+ }
+ }
+ for(i=0;i<month;i++)
+ day += months[i];
+ } else {
+ day = (time(NULL) / (3600 * 24));
+ }
+ t = day * (3600 * 24);
+ } else {
+ t = 0;
+ }
+
+ sec = 0;
+ for(;;) {
+ int val;
+ val = strtol(p, (char **)&p, 10);
+ sec = sec * 60 + val;
+ if (*p != ':')
+ break;
+ p++;
+ }
+ t = (t + sec) * 1000000;
+ if (*p == '.') {
+ int val, n;
+ p++;
+ n = strlen(p);
+ if (n > 6)
+ n = 6;
+ val = strtol(p, NULL, 10);
+ while (n < 6) {
+ val = val * 10;
+ n++;
+ }
+ t += val;
+ }
+ return t;
+}
+
+/* syntax: '?tag1=val1&tag2=val2...'. No URL decoding is done. Return
+ 1 if found */
+int find_info_tag(char *arg, int arg_size, const char *tag1, const char *info)
+{
+ const char *p;
+ char tag[128], *q;
+
+ p = info;
+ if (*p == '?')
+ p++;
+ for(;;) {
+ q = tag;
+ while (*p != '\0' && *p != '=' && *p != '&') {
+ if ((q - tag) < sizeof(tag) - 1)
+ *q++ = *p;
+ p++;
+ }
+ *q = '\0';
+ q = arg;
+ if (*p == '=') {
+ p++;
+ while (*p != '&' && *p != '\0') {
+ if ((q - arg) < arg_size - 1)
+ *q++ = *p;
+ p++;
+ }
+ *q = '\0';
+ }
+ if (!strcmp(tag, tag1))
+ return 1;
+ if (*p != '&')
+ break;
+ }
+ return 0;
+}
+
diff --git a/libav/wav.c b/libav/wav.c
new file mode 100644
index 0000000000..9f430bb2f6
--- /dev/null
+++ b/libav/wav.c
@@ -0,0 +1,211 @@
+/*
+ * WAV encoder and decoder
+ * Copyright (c) 2001 Gerard Lantau.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <errno.h>
+#include "avformat.h"
+#include "avi.h"
+
+typedef struct {
+ offset_t data;
+} WAVContext;
+
+static int wav_write_header(AVFormatContext *s)
+{
+ WAVContext *wav;
+ ByteIOContext *pb = &s->pb;
+ offset_t fmt;
+
+ wav = malloc(sizeof(WAVContext));
+ if (!wav)
+ return -1;
+ memset(wav, 0, sizeof(WAVContext));
+ s->priv_data = wav;
+
+ put_tag(pb, "RIFF");
+ put_le32(pb, 0); /* file length */
+ put_tag(pb, "WAVE");
+
+ /* format header */
+ fmt = start_tag(pb, "fmt ");
+ put_wav_header(pb, &s->streams[0]->codec);
+ 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)
+{
+ 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, file_size);
+ url_fseek(pb, file_size, SEEK_SET);
+
+ put_flush_packet(pb);
+ }
+
+ free(wav);
+ return 0;
+}
+
+/* return the size of the found tag */
+/* XXX: > 2GB ? */
+static int find_tag(ByteIOContext *pb, int 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;
+}
+
+/* wav input */
+static int wav_read_header(AVFormatContext *s,
+ AVFormatParameters *ap)
+{
+ int size;
+ unsigned int tag;
+ ByteIOContext *pb = &s->pb;
+ unsigned int id, channels, rate, bit_rate, extra_size;
+ 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;
+ id = get_le16(pb);
+ channels = get_le16(pb);
+ rate = get_le32(pb);
+ bit_rate = get_le32(pb) * 8;
+ get_le16(pb); /* block align */
+ get_le16(pb); /* bits per sample */
+ if (size >= 18) {
+ /* wav_extra_size */
+ extra_size = get_le16(pb);
+ /* skip unused data */
+ url_fseek(pb, size - 18, SEEK_CUR);
+ }
+
+ size = find_tag(pb, MKTAG('d', 'a', 't', 'a'));
+ if (size < 0)
+ return -1;
+
+ /* now we are ready: build format streams */
+ st = 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_get_id(codec_wav_tags, id);
+ st->codec.channels = channels;
+ st->codec.sample_rate = rate;
+ return 0;
+}
+
+#define MAX_SIZE 4096
+
+static int wav_read_packet(AVFormatContext *s,
+ AVPacket *pkt)
+{
+ int packet_size, n, ret;
+
+ if (url_feof(&s->pb))
+ return -EIO;
+ packet_size = url_get_packet_size(&s->pb);
+ n = MAX_SIZE / packet_size;
+ if (n <= 0)
+ return n = 1;
+ if (av_new_packet(pkt, n * packet_size))
+ return -EIO;
+ pkt->stream_index = 0;
+
+ ret = get_buffer(&s->pb, pkt->data, pkt->size);
+ if (ret < 0)
+ av_free_packet(pkt);
+ return ret;
+}
+
+static int wav_read_close(AVFormatContext *s)
+{
+ return 0;
+}
+
+AVFormat wav_format = {
+ "wav",
+ "wav format",
+ "audio/x-wav",
+ "wav",
+ CODEC_ID_PCM,
+ CODEC_ID_NONE,
+ wav_write_header,
+ wav_write_packet,
+ wav_write_trailer,
+
+ wav_read_header,
+ wav_read_packet,
+ wav_read_close,
+};