Initial revision
authorFabrice Bellard <fabrice@bellard.org>
Sun, 22 Jul 2001 14:18:56 +0000 (14:18 +0000)
committerFabrice Bellard <fabrice@bellard.org>
Sun, 22 Jul 2001 14:18:56 +0000 (14:18 +0000)
Originally committed as revision 5 to svn://svn.ffmpeg.org/ffmpeg/trunk

80 files changed:
Changelog [new file with mode: 0644]
INSTALL [new file with mode: 0644]
configure [new file with mode: 0755]
doc/README.dev [new file with mode: 0644]
doc/bench.txt [new file with mode: 0644]
doc/ffserver.txt [new file with mode: 0644]
libav/asf.c [new file with mode: 0644]
libav/audio.c [new file with mode: 0644]
libav/avformat.h [new file with mode: 0644]
libav/avi.h [new file with mode: 0644]
libav/avidec.c [new file with mode: 0644]
libav/avienc.c [new file with mode: 0644]
libav/avio.c [new file with mode: 0644]
libav/avio.h [new file with mode: 0644]
libav/aviobuf.c [new file with mode: 0644]
libav/ffm.c [new file with mode: 0644]
libav/file.c [new file with mode: 0644]
libav/grab.c [new file with mode: 0644]
libav/http.c [new file with mode: 0644]
libav/img.c [new file with mode: 0644]
libav/jpegenc.c [new file with mode: 0644]
libav/mpeg.c [new file with mode: 0644]
libav/raw.c [new file with mode: 0644]
libav/rm.c [new file with mode: 0644]
libav/swf.c [new file with mode: 0644]
libav/udp.c [new file with mode: 0644]
libav/utils.c [new file with mode: 0644]
libav/wav.c [new file with mode: 0644]
libavcodec/Makefile [new file with mode: 0644]
libavcodec/ac3dec.c [new file with mode: 0644]
libavcodec/ac3enc.c [new file with mode: 0644]
libavcodec/ac3enc.h [new file with mode: 0644]
libavcodec/ac3tab.h [new file with mode: 0644]
libavcodec/apiexample.c [new file with mode: 0644]
libavcodec/avcodec.h [new file with mode: 0644]
libavcodec/common.c [new file with mode: 0644]
libavcodec/common.h [new file with mode: 0644]
libavcodec/dct-test.c [new file with mode: 0644]
libavcodec/dsputil.c [new file with mode: 0644]
libavcodec/dsputil.h [new file with mode: 0644]
libavcodec/fdctref.c [new file with mode: 0644]
libavcodec/h263.c [new file with mode: 0644]
libavcodec/h263data.h [new file with mode: 0644]
libavcodec/h263dec.c [new file with mode: 0644]
libavcodec/i386/cputest.c [new file with mode: 0644]
libavcodec/i386/dsputil_mmx.c [new file with mode: 0644]
libavcodec/i386/dsputil_mmx_avg.h [new file with mode: 0644]
libavcodec/i386/fdct_mmx.s [new file with mode: 0644]
libavcodec/i386/fdctdata.c [new file with mode: 0644]
libavcodec/i386/mmx.h [new file with mode: 0644]
libavcodec/i386/sad_mmx.s [new file with mode: 0644]
libavcodec/imgconvert.c [new file with mode: 0644]
libavcodec/imgresample.c [new file with mode: 0644]
libavcodec/jfdctfst.c [new file with mode: 0644]
libavcodec/jrevdct.c [new file with mode: 0644]
libavcodec/libac3/ac3.h [new file with mode: 0644]
libavcodec/libac3/ac3_internal.h [new file with mode: 0644]
libavcodec/libac3/bit_allocate.c [new file with mode: 0644]
libavcodec/libac3/bitstream.c [new file with mode: 0644]
libavcodec/libac3/bitstream.h [new file with mode: 0644]
libavcodec/libac3/downmix.c [new file with mode: 0644]
libavcodec/libac3/imdct.c [new file with mode: 0644]
libavcodec/libac3/parse.c [new file with mode: 0644]
libavcodec/libac3/tables.h [new file with mode: 0644]
libavcodec/mjpegenc.c [new file with mode: 0644]
libavcodec/motion_est.c [new file with mode: 0644]
libavcodec/mpeg12.c [new file with mode: 0644]
libavcodec/mpeg12data.h [new file with mode: 0644]
libavcodec/mpeg4data.h [new file with mode: 0644]
libavcodec/mpegaudio.c [new file with mode: 0644]
libavcodec/mpegaudio.h [new file with mode: 0644]
libavcodec/mpegaudiodec.c [new file with mode: 0644]
libavcodec/mpegaudiotab.h [new file with mode: 0644]
libavcodec/mpegvideo.c [new file with mode: 0644]
libavcodec/mpegvideo.h [new file with mode: 0644]
libavcodec/msmpeg4.c [new file with mode: 0644]
libavcodec/msmpeg4data.h [new file with mode: 0644]
libavcodec/resample.c [new file with mode: 0644]
libavcodec/rv10.c [new file with mode: 0644]
libavcodec/utils.c [new file with mode: 0644]

diff --git a/Changelog b/Changelog
new file mode 100644 (file)
index 0000000..3d14216
--- /dev/null
+++ b/Changelog
@@ -0,0 +1,139 @@
+version 0.4.5:
+
+- some header fixes (Zdenek Kabelac <kabi@informatics.muni.cz>).
+- many MMX optimizations (Nick Kurshev <nickols_k@mail.ru>).
+- added configure system (actually a small shell script).
+- added mpeg audio layer 1/2/3 decoding using LGPL'ed mpglib by
+  Michael Hipp (temporary solution - waiting for integer only
+  decoder).
+- fixed VIDIOCSYNC interrupt.
+- added Intel H263 decoding support ('I263' avi fourCC)
+- added Real Video 1.0 decoding (needs further testing).
+- simplified image formats again. Added PGM format (=grey
+  pgm). Renamed old PGM to PGMYUV.
+- fixed msmpeg4 slice issues (tell me if you still find problems).
+- fixed opendivx bugs with newer versions (added VOL header decoding).
+- added support for mplayer interface.
+
+version 0.4.4:
+
+- fixed some std header definitions (Bjorn Lindgren
+  <bjorn.e.lindgren@telia.com>).
+- added mpeg demux (mpeg 1 and 2 compatible).
+- added ASF demux.
+- added prototype RM demux.
+- added AC3 decoding (done with libac3 by Aaron Holtzman).
+- added decoding codec parameter guessing (.e.g. for mpeg, because the
+  header does not include them).
+- fixed header generation in mpeg1, AVI and ASF mux : wmplayer can now
+  play them (only tested video).
+- fixed h263 white bug.
+- fixed phase rounding in img resample filter.
+- add mmx code for polyphase img resample filter.
+- added CPU autodetect.
+- added generic title/author/copyright/comment string handling (ASF and RM use them).
+- added SWF demux to extract MP3 track (not usable yet because no MP3
+  decoder).
+- added fractional frame rate support.
+- codecs are no longer searched by read_header() (should fix ffserver
+  segfault).
+
+version 0.4.3:
+
+- BGR24 patch (initial patch by Jeroen Vreeken <pe1rxq@amsat.org>).
+- fixed raw yuv output.
+- added motion rounding support in MPEG4.
+- fixed motion bug rounding in MSMPEG4.
+- added B frame handling in video core.
+- added full MPEG1 decoding support.
+- added partial (frame only) MPEG2 support.
+- changed the FOURCC code for H.263 to "U263" to be able to see the
++AVI/H.263 file with the UB Video H.263+ decoder. MPlayer works with
+this +codec ;) (JuanJo).
+- Halfpel motion estimation after mb type selection (JuanJo).
+- added pgm and .Y.U.V output format.
+- suppressed 'img:' protocol. Simply use: /tmp/test%d.[pgm|Y] as input or
+  output.
+- added pgmpipe I/O format (original patch from Martin Aumueller
+  <lists@reserv.at>, but changed completely since we use a format
+  instead of a protocol).
+
+version 0.4.2:
+
+- added H263/MPEG4/MSMPEG4 decoding support. MPEG4 decoding support
+  (for openDIVX) is almost complete: 8x8 MVs and rounding are
+  missing. MSMPEG4 support is complete.
+- added prototype MPEG1 decoder. Only I and P frames handled yet (it
+  can decode ffmpeg mpegs :-)).
+- added libavcodec API documentation (see apiexample.c).
+- fixed image polyphase bug (the bottom of some images could be
+  greenish).
+- added support for non clipped motion vectors (decoding only)
+  and image sizes non multiple of 16.
+- added support for AC prediction (decoding only).
+- added file overwrite confirmation (can be disabled with -y).
+- Added custom size picture to H.263 using H.263+ (Juanjo).
+
+version 0.4.1:
+
+- added MSMPEG4 (aka DIVX) compatible encoder. Changed default codec
+  of avi and asf to DIV3.
+- added -me option to set motion estimation method
+  (default=log). suppressed redundant -hq option.
+- added options -acodec and -vcodec to force a given codec (useful for
+  AVI for example).
+- fixed -an option.
+- improved dct_quantize speed.
+- factorized some motion estimation code.
+
+version 0.4.0:
+
+- removing grab code from ffserver and moved it to ffmpeg. Added multi
+  stream support to ffmpeg.
+- added timeshifting support for live feeds (option ?date=xxx in the
+  URL).
+- added high quality image resize code with polyphase filter (need
+  mmx/see optimisation). Enable multiple image size support in ffserver.
+- added multi live feed support in ffserver.
+- suppressed master feature from ffserver (it should be done with an
+  external program which opens the .ffm url and writes it to another
+  ffserver).
+- added preliminary support for video stream parsing (wav and avi half
+  done). Added proper support for audio/video file convertion in
+  ffmpeg.
+- added preliminary support for video file sending from ffserver.
+- redesigning I/O subsystem : now using URL based input and output
+  (see avio.h).
+- added wav format support.
+- added "tty user interface" to ffmpeg to stop grabbing gracefully.
+- added MMX/SSE optimizations to SAD (Sums of Absolutes Diferences)
+  (Juan J. Sierralta P. a.k.a. "Juanjo" <juanjo@atmlab.utfsm.cl>).
+- added MMX DCT from mpeg2_movie 1.5 (Juanjo).
+- added new motion estimation algorithms, log and phods (Juanjo).
+- changed directories : libav for format handling, libavcodec for
+  codecs.
+
+version 0.3.4:
+
+- added stereo in mpeg audio encoder.
+
+version 0.3.3:
+
+- added 'high quality' mode which use motion vectors. It can be used in
+  real time at low resolution.
+- fixed rounding problems which caused quality problems at high
+  bitrates and large gop size.
+
+version 0.3.2: small fixes
+
+- asf fixes
+- put_seek bug fix
+
+version 0.3.1: added avi/divx support
+
+- added avi support
+- added mpeg4 codec compatible with open divx. It is based on the h263
+  codec.
+- added sound for flash format (not tested)
+
+version 0.3: initial public release
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..aa2f6a3
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,8 @@
+
+1) Type './configure' create the configuration (use './configure
+--help' to have the configure options).
+
+2) Then type 'make' to build ffmpeg.
+
+3) Type 'make install' to install ffmpeg and ffserver in
+/usr/local/bin.
diff --git a/configure b/configure
new file mode 100755 (executable)
index 0000000..f22c837
--- /dev/null
+++ b/configure
@@ -0,0 +1,75 @@
+#!/bin/sh
+
+# default parameters
+prefix="/usr/local"
+cc="gcc"
+ar="ar"
+cpu=`uname -m`
+case "$cpu" in
+  i386|i486|i586|i686)
+    cpu="x86"
+    mmx="yes"
+  ;;
+  *)
+    mmx="no"
+  ;;
+esac
+gprof="no"
+
+if [ "$1" = "-h" -o "$1" = "--help" ] ; then
+cat << EOF
+
+Usage: configure [options]
+Options: [defaults in brackets after descriptions]
+
+  --help                  print this message
+EOF
+echo "  --prefix=PREFIX         install in PREFIX [$prefix]"
+echo "  --cc=CC                 use C compiler CC [$cc]"
+echo "  --cpu=CPU               force cpu to CPU  [$cpu]"
+echo "  --disable-mmx           disable mmx usage"
+echo "  --enable-gprof          enable profiling with gprof [$gprof]"
+exit 1
+fi
+
+for opt do
+  case "$opt" in
+  --prefix=*) prefix=`echo $opt | cut -d '=' -f 2`
+  ;;
+  --cc=*) cc=`echo $opt | cut -d '=' -f 2`
+  ;;
+  --cpu=*) cpu=`echo $opt | cut -d '=' -f 2`
+  ;;
+  --disable-mmx) mmx="no"
+  ;;
+  --enable-gprof) gprof="yes"
+  ;;
+  esac
+done
+
+echo "Install prefix   $prefix"
+echo "C compiler       $cc"
+echo "CPU              $cpu"
+echo "MMX enabled      $mmx"
+echo "gprof enabled    $gprof"
+
+echo "Creating config.mk and config.h"
+
+echo "# Automatically generated by configure - do not modify" > config.mk
+echo "/* Automatically generated by configure - do not modify */" > config.h
+
+echo "PREFIX=$prefix" >> config.mk
+echo "CC=$cc" >> config.mk
+echo "AR=$ar" >> config.mk
+if [ "$cpu" = "x86" ] ; then
+  echo "CONFIG_CPU_X86=y" >> config.mk
+  echo "#define CONFIG_CPU_X86 1" >> config.h
+fi
+if [ "$mmx" = "yes" ] ; then
+  echo "CONFIG_MMX=y" >> config.mk
+  echo "#define CONFIG_MMX 1" >> config.h
+fi
+if [ "$gprof" = "yes" ] ; then
+  echo "CONFIG_GPROF=y" >> config.mk
+  echo "#define CONFIG_GPROF 1" >> config.h
+fi
diff --git a/doc/README.dev b/doc/README.dev
new file mode 100644 (file)
index 0000000..ae28bc0
--- /dev/null
@@ -0,0 +1,20 @@
+1) API
+------
+
+* libavcodec is the library containing the codecs (both encoding and
+  decoding). See libavcodec/apiexample.c to see how to use it.
+
+* libav is the library containing the file formats handling (mux and
+  demux code for several formats). (no example yet, the API is likely
+  to evolve).
+
+2) Coding Rules
+---------------
+
+ffmpeg is programmed in ANSI C language. GCC extension are
+tolerated. TAB size is 4. The identation is the one specified by
+'indent -i4 -kr'.
+
+Main priority in ffmpeg is simplicity and small code size (=less
+bugs).
+
diff --git a/doc/bench.txt b/doc/bench.txt
new file mode 100644 (file)
index 0000000..a60572e
--- /dev/null
@@ -0,0 +1,52 @@
+
+source: MarsAttack, divx, 800 kbit/s
+
+q=10 constant:
+
+* full motion search, fcode=1, half pel:
+  Video: opendivx (hq), 640x352, 25 fps, 200 kb/s
+frame=  500 q=10 size=    1815kB time=20.0 bitrate= 743.6kbits/s
+
+* log motion search:
+  Video: opendivx (hq), 640x352, 25 fps, 200 kb/s
+frame=  500 q=10 size=    1995kB time=20.0 bitrate= 817.2kbits/s
+
+* no motion search:
+  Video: opendivx, 640x352, 25 fps, 200 kb/s
+frame=  500 size=    3197kB time=20.0 fps=25.0 bitrate=1309.6kbits/s q=10
+
+* log motion search:
+  Video: opendivx (hq), 640x352, 25 fps, 200 kb/s
+frame=  500 q=10 size=    1995kB time=20.0 bitrate= 817.2kbits/s
+
+./ffmpeg -me log -t 20 -g 100 -qscale 10 -i img:%d.pgm -an /tmp/b.avi
+  Stream #0.0: Video: msmpeg4, 640x352, 25 fps, 200 kb/s
+frame=  500 q=10 size=    1833kB time=20.0 bitrate= 750.9kbits/s    
+
+./ffmpeg -me full -t 20 -g 100 -qscale 10 -i img:%d.pgm -an /tmp/b.avi
+  Stream #0.0: Video: msmpeg4, 640x352, 25 fps, 200 kb/s
+frame=  500 q=10 size=    1793kB time=20.0 bitrate= 734.8kbits/s    
+
+-------------------------------------------
+
+* with -sameq, -me log
+
+./ffmpeg -g 100 -t 20 -sameq -i MarsAttacks_f800.avi -an /tmp/a.avi
+  Stream #0.0: Video: msmpeg4, 640x352, 25 fps, 200 kb/s
+frame=  500 q= 5 size=    2605kB time=20.0 bitrate=1067.1kbits/s
+
+./ffmpeg -g 100 -t 20 -sameq -i MarsAttacks_f800.avi -f mpeg1video -an /tmp/a.mpg
+  Stream #0.0: Video: mpeg1video, 640x352, 25 fps, 200 kb/s
+frame=  500 q= 5 size=    2655kB time=20.0 bitrate=1087.7kbits/s
+
+./ffmpeg -g 100 -t 20 -sameq -i MarsAttacks_f800.avi -vcodec opendivx -an /tmp/a.avi
+frame=  500 q= 5 size=    2774kB time=20.0 bitrate=1136.2kbits/s
+
+
+the matrix, complete, video only:
+
+source=14147kB
+
+ffmpeg:
+  mpeg1     17154kB (20%)
+  msmpeg4   17229kB
diff --git a/doc/ffserver.txt b/doc/ffserver.txt
new file mode 100644 (file)
index 0000000..7019556
--- /dev/null
@@ -0,0 +1,79 @@
+*************** FFserver live broadcast server *****************
+
+0) Introduction
+
+ffserver is a streaming server for both audio and video. It supports
+several live feeds, streaming from files and time shifting on live
+feeds (you can seek to positions in the past on each live feed,
+provided you specify a big enough feed storage in ffserver.conf).
+
+1) Quick help
+
+- First you must ensure that your grab system is OK. Verify with
+  'xawtv' that your TV card is tuned on a correct video source.
+
+- Try with ffmpeg that you can record correctly. For example:
+
+  ffmpeg /tmp/a.mpg
+
+will record a ten seconds mpeg file from your TV card and audio
+card. Use for example the mpegtv player or MPlayer to view the created
+MPEG file.
+
+- Launch ffserver on your PC with the sample config file:
+
+  ffserver -f doc/ffserver.conf
+
+- Verify with your browser that ffserver is working correctly. For
+  that purpose, explore: http://localhost:8090/stat.html .
+
+- Now launch ffmpeg to do real time encoding :
+
+  ffmpeg http://localhost:8090/feed1.ffm
+
+- Then, use your favorite players to see each generated stream:
+
+  mtvp http://localhost:8090/test1.mpg
+
+  mpg123 http://localhost:8090/test.mp2
+
+  netscape http://localhost:8090/test.swf
+
+  realplayer http://localhost:8090/test.rm
+
+  etc...
+
+  Note that ffserver generate multiple streams in multiple formats AT
+  THE SAME TIME. It should be able to handle hundreds of users at the
+  same time if you internet connection is fast enough.
+
+- Now you can configure ffserver for your real needs. Edit the
+  ffserver.conf file to use only the formats you want. Read the ffmpeg
+  documentation (ffmpeg.txt) to learn more about the codec and format
+  stuff.
+
+- Report any bug you find (and the fix if you have it!).
+
+2) URL Format
+
+  ffserver supports that you seek in some formats. The syntax is to
+  add a '?' option to the URL. Only the 'date' option is supported. 
+
+  The date format is [YYYY-MM-DDT][[HH:]MM:]SS[.m...] (clost to ISO
+  date format). For live streams, the date is absolute and give in
+  GMT. If the day is not specified, the current day is used.
+
+  example: 
+
+     mpg123 http://localhost:8090/test.mp2?date=10:00
+
+  play the stream starting at 10:00 AM GMT today.
+
+     mpg123 http://localhost:8090/test.mp2?date=2001-06-23T23:00
+
+  is also a valid date.
+
+  For file streams, the date is relative to the start of the file. No
+  day can be specified.
+
+
diff --git a/libav/asf.c b/libav/asf.c
new file mode 100644 (file)
index 0000000..0306ed3
--- /dev/null
@@ -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 (file)
index 0000000..df5d88e
--- /dev/null
@@ -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 (file)
index 0000000..44e9da2
--- /dev/null
@@ -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 (file)
index 0000000..06834cf
--- /dev/null
@@ -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 (file)
index 0000000..ec90565
--- /dev/null
@@ -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 (file)
index 0000000..cef541d
--- /dev/null
@@ -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 (file)
index 0000000..243f76f
--- /dev/null
@@ -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 (file)
index 0000000..a3e11b6
--- /dev/null
@@ -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 (file)
index 0000000..c50629e
--- /dev/null
@@ -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 (file)
index 0000000..76e7613
--- /dev/null
@@ -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 (file)
index 0000000..0b25534
--- /dev/null
@@ -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 (file)
index 0000000..f92cc39
--- /dev/null
@@ -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 (file)
index 0000000..824f98b
--- /dev/null
@@ -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 (file)
index 0000000..db2d933
--- /dev/null
@@ -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 (file)
index 0000000..d02332c
--- /dev/null
@@ -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 (file)
index 0000000..86e3af6
--- /dev/null
@@ -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 (file)
index 0000000..47dfa3b
--- /dev/null
@@ -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 (file)
index 0000000..8c85040
--- /dev/null
@@ -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 (file)
index 0000000..a93c4f7
--- /dev/null
@@ -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 (file)
index 0000000..329653b
--- /dev/null
@@ -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 (file)
index 0000000..9018d0f
--- /dev/null
@@ -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 (file)
index 0000000..9f430bb
--- /dev/null
@@ -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,
+};
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
new file mode 100644 (file)
index 0000000..a418516
--- /dev/null
@@ -0,0 +1,59 @@
+include ../config.mk
+CFLAGS= -O2 -Wall -g
+LDFLAGS= -g
+
+OBJS= common.o utils.o mpegvideo.o h263.o jrevdct.o jfdctfst.o \
+      mpegaudio.o ac3enc.o mjpegenc.o resample.o dsputil.o \
+      motion_est.o imgconvert.o imgresample.o msmpeg4.o \
+      mpeg12.o h263dec.o rv10.o
+
+# currently using libac3 for ac3 decoding
+OBJS+= ac3dec.o \
+       libac3/bit_allocate.o libac3/bitstream.o libac3/downmix.o \
+       libac3/imdct.o  libac3/parse.o
+
+# currently using mpglib for mpeg audio decoding
+OBJS+= mpegaudiodec.o \
+       mpglib/layer1.o mpglib/layer2.o mpglib/layer3.o \
+       mpglib/dct64_i386.o mpglib/decode_i386.o  mpglib/tabinit.o
+
+# i386 mmx specific stuff
+ifdef CONFIG_MMX
+OBJS += i386/fdct_mmx.o i386/fdctdata.o i386/sad_mmx.o i386/cputest.o \
+       i386/dsputil_mmx.o
+endif
+
+LIB= libavcodec.a
+TESTS= imgresample-test dct-test
+
+all: $(LIB) apiexample
+
+$(LIB): $(OBJS)
+       rm -f $@
+       $(AR) rcs $@ $(OBJS)
+
+dsputil.o: dsputil.c dsputil.h
+
+%.o: %.c
+       $(CC) $(CFLAGS) -c -o $@ $< 
+
+%.o: %.s
+       nasm -f elf -o $@ $<
+
+clean: 
+       rm -f *.o *~ *.a i386/*.o i386/*~ \
+           libac3/*.o libac3/*~ \
+           mpglib/*.o mpglib/*~ \
+           apiexample $(TESTS)
+
+# api example program
+apiexample: apiexample.c $(LIB)
+       $(CC) $(CFLAGS) -o $@ $< $(LIB) -lm
+
+# testing progs
+
+imgresample-test: imgresample.c
+       $(CC) $(CFLAGS) -DTEST -o $@ $^ 
+
+dct-test: dct-test.o jfdctfst.o i386/fdct_mmx.o i386/fdctdata.o fdctref.o
+       $(CC) -o $@ $^
diff --git a/libavcodec/ac3dec.c b/libavcodec/ac3dec.c
new file mode 100644 (file)
index 0000000..7332a11
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * AC3 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 <string.h>
+#include "avcodec.h"
+
+#include <inttypes.h>
+#include "libac3/ac3.h"
+
+/* currently, I use libac3 which is Copyright (C) Aaron Holtzman and
+   released under the GPL license. I may reimplement it someday... */
+typedef struct AC3DecodeState {
+    UINT8 inbuf[4096]; /* input buffer */
+    UINT8 *inbuf_ptr;
+    int frame_size;
+    int flags;
+    ac3_state_t state;
+} AC3DecodeState;
+
+static int ac3_decode_init(AVCodecContext *avctx)
+{
+    AC3DecodeState *s = avctx->priv_data;
+
+    ac3_init ();
+    s->inbuf_ptr = s->inbuf;
+    s->frame_size = 0;
+    return 0;
+}
+
+stream_samples_t samples;
+
+/**** the following two functions comes from ac3dec */
+static inline int blah (int32_t i)
+{
+    if (i > 0x43c07fff)
+       return 32767;
+    else if (i < 0x43bf8000)
+       return -32768;
+    else
+       return i - 0x43c00000;
+}
+
+static inline void float_to_int (float * _f, INT16 * s16) 
+{
+    int i;
+    int32_t * f = (int32_t *) _f;      // XXX assumes IEEE float format
+
+    for (i = 0; i < 256; i++) {
+       s16[2*i] = blah (f[i]);
+       s16[2*i+1] = blah (f[i+256]);
+    }
+}
+
+static inline void float_to_int_mono (float * _f, INT16 * s16) 
+{
+    int i;
+    int32_t * f = (int32_t *) _f;      // XXX assumes IEEE float format
+
+    for (i = 0; i < 256; i++) {
+       s16[i] = blah (f[i]);
+    }
+}
+
+/**** end */
+
+#define HEADER_SIZE 7
+
+static int ac3_decode_frame(AVCodecContext *avctx, 
+                            void *data, int *data_size,
+                            UINT8 *buf, int buf_size)
+{
+    AC3DecodeState *s = avctx->priv_data;
+    UINT8 *buf_ptr;
+    int flags, i, len;
+    int sample_rate, bit_rate;
+    short *out_samples = data;
+    float level;
+
+    *data_size = 0;
+    buf_ptr = buf;
+    while (buf_size > 0) {
+        len = s->inbuf_ptr - s->inbuf;
+        if (s->frame_size == 0) {
+            /* no header seen : find one. We need at least 7 bytes to parse it */
+            len = HEADER_SIZE - len;
+            if (len > buf_size)
+                len = buf_size;
+            memcpy(s->inbuf_ptr, buf_ptr, len);
+            buf_ptr += len;
+            s->inbuf_ptr += len;
+            buf_size -= len;
+            if ((s->inbuf_ptr - s->inbuf) == HEADER_SIZE) {
+                len = ac3_syncinfo (s->inbuf, &s->flags, &sample_rate, &bit_rate);
+                if (len == 0) {
+                    /* no sync found : move by one byte (inefficient, but simple!) */
+                    memcpy(s->inbuf, s->inbuf + 1, HEADER_SIZE - 1);
+                    s->inbuf_ptr--;
+                } else {
+                    s->frame_size = len;
+                    /* update codec info */
+                    avctx->sample_rate = sample_rate;
+                    if ((s->flags & AC3_CHANNEL_MASK) == AC3_MONO)
+                        avctx->channels = 1;
+                    else
+                        avctx->channels = 2;
+                    avctx->bit_rate = bit_rate;
+                }
+            }
+        } else if (len < s->frame_size) {
+            len = s->frame_size - len;
+            if (len > buf_size)
+                len = buf_size;
+            
+            memcpy(s->inbuf_ptr, buf_ptr, len);
+            buf_ptr += len;
+            s->inbuf_ptr += len;
+            buf_size -= len;
+        } else {
+            if (avctx->channels == 1)
+                flags = AC3_MONO;
+            else
+                flags = AC3_STEREO;
+
+            flags |= AC3_ADJUST_LEVEL;
+            level = 1;
+            if (ac3_frame (&s->state, s->inbuf, &flags, &level, 384)) {
+            fail:
+                s->inbuf_ptr = s->inbuf;
+                s->frame_size = 0;
+                continue;
+            }
+            for (i = 0; i < 6; i++) {
+                if (ac3_block (&s->state))
+                    goto fail;
+                if (avctx->channels == 1)
+                    float_to_int_mono (*samples, out_samples + i * 256);
+                else
+                    float_to_int (*samples, out_samples + i * 512);
+            }
+            s->inbuf_ptr = s->inbuf;
+            s->frame_size = 0;
+            *data_size = 6 * avctx->channels * 256 * sizeof(INT16);
+            break;
+        }
+    }
+    return buf_ptr - buf;
+}
+
+static int ac3_decode_end(AVCodecContext *s)
+{
+    return 0;
+}
+
+AVCodec ac3_decoder = {
+    "ac3",
+    CODEC_TYPE_AUDIO,
+    CODEC_ID_AC3,
+    sizeof(AC3DecodeState),
+    ac3_decode_init,
+    NULL,
+    ac3_decode_end,
+    ac3_decode_frame,
+};
+
+/* register codecs which could clash with mplayer symbols */
+/* XXX: rename all symbols to avoid clashed */
+void avcodec_register_more(void)
+{
+    register_avcodec(&mp3_decoder);
+    register_avcodec(&ac3_decoder);
+}
+
diff --git a/libavcodec/ac3enc.c b/libavcodec/ac3enc.c
new file mode 100644 (file)
index 0000000..2bd4179
--- /dev/null
@@ -0,0 +1,1460 @@
+/*
+ * The simplest AC3 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 <string.h>
+#include <math.h>
+#include "avcodec.h"
+
+#include "ac3enc.h"
+#include "ac3tab.h"
+
+//#define DEBUG
+//#define DEBUG_BITALLOC
+#define NDEBUG
+#include <assert.h>
+
+#define MDCT_NBITS 9
+#define N         (1 << MDCT_NBITS)
+#define NB_BLOCKS 6 /* number of PCM blocks inside an AC3 frame */
+
+/* new exponents are sent if their Norm 1 exceed this number */
+#define EXP_DIFF_THRESHOLD 1000
+
+/* exponent encoding strategy */
+#define EXP_REUSE 0
+#define EXP_NEW   1
+
+#define EXP_D15   1
+#define EXP_D25   2
+#define EXP_D45   3
+
+static void fft_init(int ln);
+static void ac3_crc_init(void);
+
+static inline INT16 fix15(float a)
+{
+    int v;
+    v = (int)(a * (float)(1 << 15));
+    if (v < -32767)
+        v = -32767;
+    else if (v > 32767) 
+        v = 32767;
+    return v;
+}
+
+static inline int calc_lowcomp1(int a, int b0, int b1)
+{
+    if ((b0 + 256) == b1) {
+        a = 384 ;
+    } else if (b0 > b1) { 
+        a = a - 64;
+        if (a < 0) a=0;
+    }
+    return a;
+}
+
+static inline int calc_lowcomp(int a, int b0, int b1, int bin)
+{
+    if (bin < 7) {
+        if ((b0 + 256) == b1) {
+            a = 384 ;
+        } else if (b0 > b1) { 
+            a = a - 64;
+            if (a < 0) a=0;
+        }
+    } else if (bin < 20) {
+        if ((b0 + 256) == b1) {
+            a = 320 ;
+        } else if (b0 > b1) {
+            a= a - 64;
+            if (a < 0) a=0;
+        }
+    } else {
+        a = a - 128;
+        if (a < 0) a=0;
+    }
+    return a;
+}
+
+/* AC3 bit allocation. The algorithm is the one described in the AC3
+   spec with some optimizations because of our simplified encoding
+   assumptions. */
+void parametric_bit_allocation(AC3EncodeContext *s, UINT8 *bap,
+                               INT8 *exp, int start, int end,
+                               int snroffset, int fgain)
+{
+    int bin,i,j,k,end1,v,v1,bndstrt,bndend,lowcomp,begin;
+    int fastleak,slowleak,address,tmp;
+    INT16 psd[256]; /* scaled exponents */
+    INT16 bndpsd[50]; /* interpolated exponents */
+    INT16 excite[50]; /* excitation */
+    INT16 mask[50];   /* masking value */
+
+    /* exponent mapping to PSD */
+    for(bin=start;bin<end;bin++) {
+        psd[bin]=(3072 - (exp[bin] << 7));
+    }
+
+    /* PSD integration */
+    j=start;
+    k=masktab[start];
+    do {
+        v=psd[j];
+        j++;
+        end1=bndtab[k+1];
+        if (end1 > end) end1=end;
+        for(i=j;i<end1;i++) {
+            int c,adr;
+            /* logadd */
+            v1=psd[j];
+            c=v-v1;
+            if (c >= 0) {
+                adr=c >> 1;
+                if (adr > 255) adr=255;
+                v=v + latab[adr];
+            } else {
+                adr=(-c) >> 1;
+                if (adr > 255) adr=255;
+                v=v1 + latab[adr];
+            }
+            j++;
+        }
+        bndpsd[k]=v;
+        k++;
+    } while (end > bndtab[k]);
+
+    /* excitation function */
+    bndstrt = masktab[start];
+    bndend = masktab[end-1] + 1;
+    
+    lowcomp = 0;
+    lowcomp = calc_lowcomp1(lowcomp, bndpsd[0], bndpsd[1]) ;
+    excite[0] = bndpsd[0] - fgain - lowcomp ;
+    lowcomp = calc_lowcomp1(lowcomp, bndpsd[1], bndpsd[2]) ;
+    excite[1] = bndpsd[1] - fgain - lowcomp ;
+    begin = 7 ;
+    for (bin = 2; bin < 7; bin++) {
+        lowcomp = calc_lowcomp1(lowcomp, bndpsd[bin], bndpsd[bin+1]) ;
+        fastleak = bndpsd[bin] - fgain ;
+        slowleak = bndpsd[bin] - s->sgain ;
+        excite[bin] = fastleak - lowcomp ;
+        if (bndpsd[bin] <= bndpsd[bin+1]) {
+            begin = bin + 1 ;
+            break ;
+        }
+    }
+    
+    end1=bndend;
+    if (end1 > 22) end1=22;
+    
+    for (bin = begin; bin < end1; bin++) {
+        lowcomp = calc_lowcomp(lowcomp, bndpsd[bin], bndpsd[bin+1], bin) ;
+        
+        fastleak -= s->fdecay ;
+        v = bndpsd[bin] - fgain;
+        if (fastleak < v) fastleak = v;
+        
+        slowleak -= s->sdecay ;
+        v = bndpsd[bin] - s->sgain;
+        if (slowleak < v) slowleak = v;
+        
+        v=fastleak - lowcomp;
+        if (slowleak > v) v=slowleak;
+        
+        excite[bin] = v;
+    }
+
+    for (bin = 22; bin < bndend; bin++) {
+        fastleak -= s->fdecay ;
+        v = bndpsd[bin] - fgain;
+        if (fastleak < v) fastleak = v;
+        slowleak -= s->sdecay ;
+        v = bndpsd[bin] - s->sgain;
+        if (slowleak < v) slowleak = v;
+
+        v=fastleak;
+        if (slowleak > v) v = slowleak;
+        excite[bin] = v;
+    }
+
+    /* compute masking curve */
+
+    for (bin = bndstrt; bin < bndend; bin++) {
+        v1 = excite[bin];
+        tmp = s->dbknee - bndpsd[bin];
+        if (tmp > 0) {
+            v1 += tmp >> 2;
+        }
+        v=hth[bin >> s->halfratecod][s->fscod];
+        if (v1 > v) v=v1;
+        mask[bin] = v;
+    }
+
+    /* compute bit allocation */
+    
+    i = start ;
+    j = masktab[start] ;
+    do {
+        v=mask[j];
+        v -= snroffset ;
+        v -= s->floor ;
+        if (v < 0) v = 0;
+        v &= 0x1fe0 ;
+        v += s->floor ;
+
+        end1=bndtab[j] + bndsz[j];
+        if (end1 > end) end1=end;
+
+        for (k = i; k < end1; k++) {
+            address = (psd[i] - v) >> 5 ;
+            if (address < 0) address=0;
+            else if (address > 63) address=63;
+            bap[i] = baptab[address];
+            i++;
+        }
+    } while (end > bndtab[j++]) ;
+}
+
+typedef struct IComplex {
+    short re,im;
+} IComplex;
+
+static void fft_init(int ln)
+{
+    int i, j, m, n;
+    float alpha;
+
+    n = 1 << ln;
+
+    for(i=0;i<(n/2);i++) {
+        alpha = 2 * M_PI * (float)i / (float)n;
+        costab[i] = fix15(cos(alpha));
+        sintab[i] = fix15(sin(alpha));
+    }
+
+    for(i=0;i<n;i++) {
+        m=0;
+        for(j=0;j<ln;j++) {
+            m |= ((i >> j) & 1) << (ln-j-1);
+        }
+        fft_rev[i]=m;
+    }
+}
+
+/* butter fly op */
+#define BF(pre, pim, qre, qim, pre1, pim1, qre1, qim1) \
+{\
+  int ax, ay, bx, by;\
+  bx=pre1;\
+  by=pim1;\
+  ax=qre1;\
+  ay=qim1;\
+  pre = (bx + ax) >> 1;\
+  pim = (by + ay) >> 1;\
+  qre = (bx - ax) >> 1;\
+  qim = (by - ay) >> 1;\
+}
+
+#define MUL16(a,b) ((a) * (b))
+
+#define CMUL(pre, pim, are, aim, bre, bim) \
+{\
+   pre = (MUL16(are, bre) - MUL16(aim, bim)) >> 15;\
+   pim = (MUL16(are, bim) + MUL16(bre, aim)) >> 15;\
+}
+
+
+/* do a 2^n point complex fft on 2^ln points. */
+static void fft(IComplex *z, int ln)
+{
+    int        j, l, np, np2;
+    int        nblocks, nloops;
+    register IComplex *p,*q;
+    int tmp_re, tmp_im;
+
+    np = 1 << ln;
+
+    /* reverse */
+    for(j=0;j<np;j++) {
+        int k;
+        IComplex tmp;
+        k = fft_rev[j];
+        if (k < j) {
+            tmp = z[k];
+            z[k] = z[j];
+            z[j] = tmp;
+        }
+    }
+
+    /* pass 0 */
+
+    p=&z[0];
+    j=(np >> 1);
+    do {
+        BF(p[0].re, p[0].im, p[1].re, p[1].im, 
+           p[0].re, p[0].im, p[1].re, p[1].im);
+        p+=2;
+    } while (--j != 0);
+
+    /* pass 1 */
+
+    p=&z[0];
+    j=np >> 2;
+    do {
+        BF(p[0].re, p[0].im, p[2].re, p[2].im, 
+           p[0].re, p[0].im, p[2].re, p[2].im);
+        BF(p[1].re, p[1].im, p[3].re, p[3].im, 
+           p[1].re, p[1].im, p[3].im, -p[3].re);
+        p+=4;
+    } while (--j != 0);
+
+    /* pass 2 .. ln-1 */
+
+    nblocks = np >> 3;
+    nloops = 1 << 2;
+    np2 = np >> 1;
+    do {
+        p = z;
+        q = z + nloops;
+        for (j = 0; j < nblocks; ++j) {
+
+            BF(p->re, p->im, q->re, q->im,
+               p->re, p->im, q->re, q->im);
+            
+            p++;
+            q++;
+            for(l = nblocks; l < np2; l += nblocks) {
+                CMUL(tmp_re, tmp_im, costab[l], -sintab[l], q->re, q->im);
+                BF(p->re, p->im, q->re, q->im,
+                   p->re, p->im, tmp_re, tmp_im);
+                p++;
+                q++;
+            }
+            p += nloops;
+            q += nloops;
+        }
+        nblocks = nblocks >> 1;
+        nloops = nloops << 1;
+    } while (nblocks != 0);
+}
+
+/* do a 512 point mdct */
+static void mdct512(INT32 *out, INT16 *in)
+{
+    int i, re, im, re1, im1;
+    INT16 rot[N]; 
+    IComplex x[N/4];
+
+    /* shift to simplify computations */
+    for(i=0;i<N/4;i++)
+        rot[i] = -in[i + 3*N/4];
+    for(i=N/4;i<N;i++)
+        rot[i] = in[i - N/4];
+        
+    /* pre rotation */
+    for(i=0;i<N/4;i++) {
+        re = ((int)rot[2*i] - (int)rot[N-1-2*i]) >> 1;
+        im = -((int)rot[N/2+2*i] - (int)rot[N/2-1-2*i]) >> 1;
+        CMUL(x[i].re, x[i].im, re, im, -xcos1[i], xsin1[i]);
+    }
+
+    fft(x, MDCT_NBITS - 2);
+  
+    /* post rotation */
+    for(i=0;i<N/4;i++) {
+        re = x[i].re;
+        im = x[i].im;
+        CMUL(re1, im1, re, im, xsin1[i], xcos1[i]);
+        out[2*i] = im1;
+        out[N/2-1-2*i] = re1;
+    }
+}
+
+/* XXX: use another norm ? */
+static int calc_exp_diff(UINT8 *exp1, UINT8 *exp2, int n)
+{
+    int sum, i;
+    sum = 0;
+    for(i=0;i<n;i++) {
+        sum += abs(exp1[i] - exp2[i]);
+    }
+    return sum;
+}
+
+static void compute_exp_strategy(UINT8 exp_strategy[NB_BLOCKS][AC3_MAX_CHANNELS],
+                                 UINT8 exp[NB_BLOCKS][AC3_MAX_CHANNELS][N/2],
+                                 int ch)
+{
+    int i, j;
+    int exp_diff;
+    
+    /* estimate if the exponent variation & decide if they should be
+       reused in the next frame */
+    exp_strategy[0][ch] = EXP_NEW;
+    for(i=1;i<NB_BLOCKS;i++) {
+        exp_diff = calc_exp_diff(exp[i][ch], exp[i-1][ch], N/2);
+#ifdef DEBUG            
+        printf("exp_diff=%d\n", exp_diff);
+#endif
+        if (exp_diff > EXP_DIFF_THRESHOLD)
+            exp_strategy[i][ch] = EXP_NEW;
+        else
+            exp_strategy[i][ch] = EXP_REUSE;
+    }
+    /* now select the encoding strategy type : if exponents are often
+       recoded, we use a coarse encoding */
+    i = 0;
+    while (i < NB_BLOCKS) {
+        j = i + 1;
+        while (j < NB_BLOCKS && exp_strategy[j][ch] == EXP_REUSE)
+            j++;
+        switch(j - i) {
+        case 1:
+            exp_strategy[i][ch] = EXP_D45;
+            break;
+        case 2:
+        case 3:
+            exp_strategy[i][ch] = EXP_D25;
+            break;
+        default:
+            exp_strategy[i][ch] = EXP_D15;
+            break;
+        }
+        i = j;
+    }
+}
+
+/* set exp[i] to min(exp[i], exp1[i]) */
+static void exponent_min(UINT8 exp[N/2], UINT8 exp1[N/2], int n)
+{
+    int i;
+
+    for(i=0;i<n;i++) {
+        if (exp1[i] < exp[i])
+            exp[i] = exp1[i];
+    }
+}
+                                 
+/* update the exponents so that they are the ones the decoder will
+   decode. Return the number of bits used to code the exponents */
+static int encode_exp(UINT8 encoded_exp[N/2], 
+                      UINT8 exp[N/2], 
+                      int nb_exps,
+                      int exp_strategy)
+{
+    int group_size, nb_groups, i, j, k, recurse, exp_min, delta;
+    UINT8 exp1[N/2];
+
+    switch(exp_strategy) {
+    case EXP_D15:
+        group_size = 1;
+        break;
+    case EXP_D25:
+        group_size = 2;
+        break;
+    default:
+    case EXP_D45:
+        group_size = 4;
+        break;
+    }
+    nb_groups = ((nb_exps + (group_size * 3) - 4) / (3 * group_size)) * 3;
+
+    /* for each group, compute the minimum exponent */
+    exp1[0] = exp[0]; /* DC exponent is handled separately */
+    k = 1;
+    for(i=1;i<=nb_groups;i++) {
+        exp_min = exp[k];
+        assert(exp_min >= 0 && exp_min <= 24);
+        for(j=1;j<group_size;j++) {
+            if (exp[k+j] < exp_min)
+                exp_min = exp[k+j];
+        }
+        exp1[i] = exp_min;
+        k += group_size;
+    }
+
+    /* constraint for DC exponent */
+    if (exp1[0] > 15)
+        exp1[0] = 15;
+
+    /* Iterate until the delta constraints between each groups are
+       satisfyed. I'm sure it is possible to find a better algorithm,
+       but I am lazy */
+    do {
+        recurse = 0;
+        for(i=1;i<=nb_groups;i++) {
+            delta = exp1[i] - exp1[i-1];
+            if (delta > 2) {
+                /* if delta too big, we encode a smaller exponent */
+                exp1[i] = exp1[i-1] + 2;
+            } else if (delta < -2) {
+                /* if delta is too small, we must decrease the previous
+               exponent, which means we must recurse */
+                recurse = 1;
+                exp1[i-1] = exp1[i] + 2;
+            }
+        }
+    } while (recurse);
+    
+    /* now we have the exponent values the decoder will see */
+    encoded_exp[0] = exp1[0];
+    k = 1;
+    for(i=1;i<=nb_groups;i++) {
+        for(j=0;j<group_size;j++) {
+            encoded_exp[k+j] = exp1[i];
+        }
+        k += group_size;
+    }
+    
+#if defined(DEBUG)
+    printf("exponents: strategy=%d\n", exp_strategy);
+    for(i=0;i<=nb_groups * group_size;i++) {
+        printf("%d ", encoded_exp[i]);
+    }
+    printf("\n");
+#endif
+
+    return 4 + (nb_groups / 3) * 7;
+}
+
+/* return the size in bits taken by the mantissa */
+int compute_mantissa_size(AC3EncodeContext *s, UINT8 *m, int nb_coefs)
+{
+    int bits, mant, i;
+
+    bits = 0;
+    for(i=0;i<nb_coefs;i++) {
+        mant = m[i];
+        switch(mant) {
+        case 0:
+            /* nothing */
+            break;
+        case 1:
+            /* 3 mantissa in 5 bits */
+            if (s->mant1_cnt == 0) 
+                bits += 5;
+            if (++s->mant1_cnt == 3)
+                s->mant1_cnt = 0;
+            break;
+        case 2:
+            /* 3 mantissa in 7 bits */
+            if (s->mant2_cnt == 0) 
+                bits += 7;
+            if (++s->mant2_cnt == 3)
+                s->mant2_cnt = 0;
+            break;
+        case 3:
+            bits += 3;
+            break;
+        case 4:
+            /* 2 mantissa in 7 bits */
+            if (s->mant4_cnt == 0)
+                bits += 7;
+            if (++s->mant4_cnt == 2) 
+                s->mant4_cnt = 0;
+            break;
+        case 14:
+            bits += 14;
+            break;
+        case 15:
+            bits += 16;
+            break;
+        default:
+            bits += mant - 1;
+            break;
+        }
+    }
+    return bits;
+}
+
+
+static int bit_alloc(AC3EncodeContext *s,
+                     UINT8 bap[NB_BLOCKS][AC3_MAX_CHANNELS][N/2],
+                     UINT8 encoded_exp[NB_BLOCKS][AC3_MAX_CHANNELS][N/2],
+                     UINT8 exp_strategy[NB_BLOCKS][AC3_MAX_CHANNELS],
+                     int frame_bits, int csnroffst, int fsnroffst)
+{
+    int i, ch;
+
+    /* compute size */
+    for(i=0;i<NB_BLOCKS;i++) {
+        s->mant1_cnt = 0;
+        s->mant2_cnt = 0;
+        s->mant4_cnt = 0;
+        for(ch=0;ch<s->nb_channels;ch++) {
+            parametric_bit_allocation(s, bap[i][ch], encoded_exp[i][ch], 
+                                      0, s->nb_coefs[ch], 
+                                      (((csnroffst-15) << 4) + 
+                                       fsnroffst) << 2, 
+                                      fgaintab[s->fgaincod[ch]]);
+            frame_bits += compute_mantissa_size(s, bap[i][ch], 
+                                                 s->nb_coefs[ch]);
+        }
+    }
+#if 0
+    printf("csnr=%d fsnr=%d frame_bits=%d diff=%d\n", 
+           csnroffst, fsnroffst, frame_bits, 
+           16 * s->frame_size - ((frame_bits + 7) & ~7));
+#endif
+    return 16 * s->frame_size - frame_bits;
+}
+
+#define SNR_INC1 4
+
+static int compute_bit_allocation(AC3EncodeContext *s,
+                                  UINT8 bap[NB_BLOCKS][AC3_MAX_CHANNELS][N/2],
+                                  UINT8 encoded_exp[NB_BLOCKS][AC3_MAX_CHANNELS][N/2],
+                                  UINT8 exp_strategy[NB_BLOCKS][AC3_MAX_CHANNELS],
+                                  int frame_bits)
+{
+    int i, ch;
+    int csnroffst, fsnroffst;
+    UINT8 bap1[NB_BLOCKS][AC3_MAX_CHANNELS][N/2];
+
+    /* init default parameters */
+    s->sdecaycod = 2;
+    s->fdecaycod = 1;
+    s->sgaincod = 1;
+    s->dbkneecod = 2;
+    s->floorcod = 4;
+    for(ch=0;ch<s->nb_channels;ch++) 
+        s->fgaincod[ch] = 4;
+    
+    /* compute real values */
+    s->sdecay = sdecaytab[s->sdecaycod] >> s->halfratecod;
+    s->fdecay = fdecaytab[s->fdecaycod] >> s->halfratecod;
+    s->sgain = sgaintab[s->sgaincod];
+    s->dbknee = dbkneetab[s->dbkneecod];
+    s->floor = floortab[s->floorcod];
+
+    /* header size */
+    frame_bits += 65;
+    if (s->acmod == 2)
+        frame_bits += 2;
+
+    /* audio blocks */
+    for(i=0;i<NB_BLOCKS;i++) {
+        frame_bits += s->nb_channels * 2 + 2;
+        if (s->acmod == 2)
+            frame_bits++;
+        frame_bits += 2 * s->nb_channels;
+        for(ch=0;ch<s->nb_channels;ch++) {
+            if (exp_strategy[i][ch] != EXP_REUSE)
+                frame_bits += 6 + 2;
+        }
+        frame_bits++; /* baie */
+        frame_bits++; /* snr */
+        frame_bits += 2; /* delta / skip */
+    }
+    frame_bits++; /* cplinu for block 0 */
+    /* bit alloc info */
+    frame_bits += 2*4 + 3 + 6 + s->nb_channels * (4 + 3);
+
+    /* CRC */
+    frame_bits += 16;
+
+    /* now the big work begins : do the bit allocation. Modify the snr
+       offset until we can pack everything in the requested frame size */
+
+    csnroffst = s->csnroffst;
+    while (csnroffst >= 0 && 
+           bit_alloc(s, bap, encoded_exp, exp_strategy, frame_bits, csnroffst, 0) < 0)
+        csnroffst -= SNR_INC1;
+    if (csnroffst < 0) {
+        fprintf(stderr, "Error !!!\n");
+        return -1;
+    }
+    while ((csnroffst + SNR_INC1) <= 63 && 
+           bit_alloc(s, bap1, encoded_exp, exp_strategy, frame_bits, 
+                     csnroffst + SNR_INC1, 0) >= 0) {
+        csnroffst += SNR_INC1;
+        memcpy(bap, bap1, sizeof(bap1));
+    }
+    while ((csnroffst + 1) <= 63 && 
+           bit_alloc(s, bap1, encoded_exp, exp_strategy, frame_bits, csnroffst + 1, 0) >= 0) {
+        csnroffst++;
+        memcpy(bap, bap1, sizeof(bap1));
+    }
+
+    fsnroffst = 0;
+    while ((fsnroffst + SNR_INC1) <= 15 && 
+           bit_alloc(s, bap1, encoded_exp, exp_strategy, frame_bits, 
+                     csnroffst, fsnroffst + SNR_INC1) >= 0) {
+        fsnroffst += SNR_INC1;
+        memcpy(bap, bap1, sizeof(bap1));
+    }
+    while ((fsnroffst + 1) <= 15 && 
+           bit_alloc(s, bap1, encoded_exp, exp_strategy, frame_bits, 
+                     csnroffst, fsnroffst + 1) >= 0) {
+        fsnroffst++;
+        memcpy(bap, bap1, sizeof(bap1));
+    }
+    
+    s->csnroffst = csnroffst;
+    for(ch=0;ch<s->nb_channels;ch++)
+        s->fsnroffst[ch] = fsnroffst;
+#if defined(DEBUG_BITALLOC)
+    {
+        int j;
+
+        for(i=0;i<6;i++) {
+            for(ch=0;ch<s->nb_channels;ch++) {
+                printf("Block #%d Ch%d:\n", i, ch);
+                printf("bap=");
+                for(j=0;j<s->nb_coefs[ch];j++) {
+                    printf("%d ",bap[i][ch][j]);
+                }
+                printf("\n");
+            }
+        }
+    }
+#endif
+    return 0;
+}
+
+static int AC3_encode_init(AVCodecContext *avctx)
+{
+    int freq = avctx->sample_rate;
+    int bitrate = avctx->bit_rate;
+    int channels = avctx->channels;
+    AC3EncodeContext *s = avctx->priv_data;
+    int i, j, k, l, ch, v;
+    float alpha;
+    static unsigned short freqs[3] = { 48000, 44100, 32000 };
+
+    avctx->frame_size = AC3_FRAME_SIZE;
+    avctx->key_frame = 1; /* always key frame */
+    
+    /* number of channels */
+    if (channels == 1)
+        s->acmod = 1;
+    else if (channels == 2)
+        s->acmod = 2;
+    else
+        return -1;
+    s->nb_channels = channels;
+
+    /* frequency */
+    for(i=0;i<3;i++) {
+        for(j=0;j<3;j++) 
+            if ((freqs[j] >> i) == freq)
+                goto found;
+    }
+    return -1;
+ found:    
+    s->sample_rate = freq;
+    s->halfratecod = i;
+    s->fscod = j;
+    s->bsid = 8 + s->halfratecod;
+    s->bsmod = 0; /* complete main audio service */
+
+    /* bitrate & frame size */
+    bitrate /= 1000;
+    for(i=0;i<19;i++) {
+        if ((bitratetab[i] >> s->halfratecod) == bitrate)
+            break;
+    }
+    if (i == 19)
+        return -1;
+    s->bit_rate = bitrate;
+    s->frmsizecod = i << 1;
+    s->frame_size_min = (bitrate * 1000 * AC3_FRAME_SIZE) / (freq * 16);
+    /* for now we do not handle fractional sizes */
+    s->frame_size = s->frame_size_min;
+    
+    /* bit allocation init */
+    for(ch=0;ch<s->nb_channels;ch++) {
+        /* bandwidth for each channel */
+        /* XXX: should compute the bandwidth according to the frame
+           size, so that we avoid anoying high freq artefacts */
+        s->chbwcod[ch] = 50; /* sample bandwidth as mpeg audio layer 2 table 0 */
+        s->nb_coefs[ch] = ((s->chbwcod[ch] + 12) * 3) + 37;
+    }
+    /* initial snr offset */
+    s->csnroffst = 40;
+
+    /* compute bndtab and masktab from bandsz */
+    k = 0;
+    l = 0;
+    for(i=0;i<50;i++) {
+        bndtab[i] = l;
+        v = bndsz[i];
+        for(j=0;j<v;j++) masktab[k++]=i;
+        l += v;
+    }
+    bndtab[50] = 0;
+
+    /* mdct init */
+    fft_init(MDCT_NBITS - 2);
+    for(i=0;i<N/4;i++) {
+        alpha = 2 * M_PI * (i + 1.0 / 8.0) / (float)N;
+        xcos1[i] = fix15(-cos(alpha));
+        xsin1[i] = fix15(-sin(alpha));
+    }
+
+    ac3_crc_init();
+
+    return 0;
+}
+
+/* output the AC3 frame header */
+static void output_frame_header(AC3EncodeContext *s, unsigned char *frame)
+{
+    init_put_bits(&s->pb, frame, AC3_MAX_CODED_FRAME_SIZE, NULL, NULL);
+
+    put_bits(&s->pb, 16, 0x0b77); /* frame header */
+    put_bits(&s->pb, 16, 0); /* crc1: will be filled later */
+    put_bits(&s->pb, 2, s->fscod);
+    put_bits(&s->pb, 6, s->frmsizecod + (s->frame_size - s->frame_size_min));
+    put_bits(&s->pb, 5, s->bsid);
+    put_bits(&s->pb, 3, s->bsmod);
+    put_bits(&s->pb, 3, s->acmod);
+    if (s->acmod == 2) {
+        put_bits(&s->pb, 2, 0); /* surround not indicated */
+    }
+    put_bits(&s->pb, 1, 0); /* no LFE */
+    put_bits(&s->pb, 5, 31); /* dialog norm: -31 db */
+    put_bits(&s->pb, 1, 0); /* no compression control word */
+    put_bits(&s->pb, 1, 0); /* no lang code */
+    put_bits(&s->pb, 1, 0); /* no audio production info */
+    put_bits(&s->pb, 1, 0); /* no copyright */
+    put_bits(&s->pb, 1, 1); /* original bitstream */
+    put_bits(&s->pb, 1, 0); /* no time code 1 */
+    put_bits(&s->pb, 1, 0); /* no time code 2 */
+    put_bits(&s->pb, 1, 0); /* no addtional bit stream info */
+}
+
+/* symetric quantization on 'levels' levels */
+static inline int sym_quant(int c, int e, int levels)
+{
+    int v;
+
+    if (c >= 0) {
+        v = (levels * (c << e)) >> 25;
+        v = (levels >> 1) + v;
+    } else {
+        v = (levels * ((-c) << e)) >> 25;
+        v = (levels >> 1) - v;
+    }
+    assert (v >= 0 && v < levels);
+    return v;
+}
+
+/* asymetric quantization on 2^qbits levels */
+static inline int asym_quant(int c, int e, int qbits)
+{
+    int lshift, m, v;
+
+    lshift = e + qbits - 24;
+    if (lshift >= 0)
+        v = c << lshift;
+    else
+        v = c >> (-lshift);
+    /* rounding */
+    v = (v + 1) >> 1;
+    m = (1 << (qbits-1));
+    if (v >= m)
+        v = m - 1;
+    assert(v >= -m);
+    return v & ((1 << qbits)-1);
+}
+
+/* Output one audio block. There are NB_BLOCKS audio blocks in one AC3
+   frame */
+static void output_audio_block(AC3EncodeContext *s,
+                               UINT8 exp_strategy[AC3_MAX_CHANNELS],
+                               UINT8 encoded_exp[AC3_MAX_CHANNELS][N/2],
+                               UINT8 bap[AC3_MAX_CHANNELS][N/2],
+                               INT32 mdct_coefs[AC3_MAX_CHANNELS][N/2],
+                               INT8 global_exp[AC3_MAX_CHANNELS],
+                               int block_num)
+{
+    int ch, nb_groups, group_size, i, baie;
+    UINT8 *p;
+    UINT16 qmant[AC3_MAX_CHANNELS][N/2];
+    int exp0, exp1;
+    int mant1_cnt, mant2_cnt, mant4_cnt;
+    UINT16 *qmant1_ptr, *qmant2_ptr, *qmant4_ptr;
+    int delta0, delta1, delta2;
+
+    for(ch=0;ch<s->nb_channels;ch++) 
+        put_bits(&s->pb, 1, 0); /* 512 point MDCT */
+    for(ch=0;ch<s->nb_channels;ch++) 
+        put_bits(&s->pb, 1, 1); /* no dither */
+    put_bits(&s->pb, 1, 0); /* no dynamic range */
+    if (block_num == 0) {
+        /* for block 0, even if no coupling, we must say it. This is a
+           waste of bit :-) */
+        put_bits(&s->pb, 1, 1); /* coupling strategy present */
+        put_bits(&s->pb, 1, 0); /* no coupling strategy */
+    } else {
+        put_bits(&s->pb, 1, 0); /* no new coupling strategy */
+    }
+
+    if (s->acmod == 2) {
+        put_bits(&s->pb, 1, 0); /* no matrixing (but should be used in the future) */
+    }
+
+#if defined(DEBUG) 
+    {
+        static int count = 0;
+        printf("Block #%d (%d)\n", block_num, count++);
+    }
+#endif
+    /* exponent strategy */
+    for(ch=0;ch<s->nb_channels;ch++) {
+        put_bits(&s->pb, 2, exp_strategy[ch]);
+    }
+    
+    for(ch=0;ch<s->nb_channels;ch++) {
+        if (exp_strategy[ch] != EXP_REUSE)
+            put_bits(&s->pb, 6, s->chbwcod[ch]);
+    }
+    
+    /* exponents */
+    for (ch = 0; ch < s->nb_channels; ch++) {
+        switch(exp_strategy[ch]) {
+        case EXP_REUSE:
+            continue;
+        case EXP_D15:
+            group_size = 1;
+            break;
+        case EXP_D25:
+            group_size = 2;
+            break;
+        default:
+        case EXP_D45:
+            group_size = 4;
+            break;
+        }
+        nb_groups = (s->nb_coefs[ch] + (group_size * 3) - 4) / (3 * group_size);
+        p = encoded_exp[ch];
+
+        /* first exponent */
+        exp1 = *p++;
+        put_bits(&s->pb, 4, exp1);
+
+        /* next ones are delta encoded */
+        for(i=0;i<nb_groups;i++) {
+            /* merge three delta in one code */
+            exp0 = exp1;
+            exp1 = p[0];
+            p += group_size;
+            delta0 = exp1 - exp0 + 2;
+
+            exp0 = exp1;
+            exp1 = p[0];
+            p += group_size;
+            delta1 = exp1 - exp0 + 2;
+
+            exp0 = exp1;
+            exp1 = p[0];
+            p += group_size;
+            delta2 = exp1 - exp0 + 2;
+
+            put_bits(&s->pb, 7, ((delta0 * 5 + delta1) * 5) + delta2);
+        }
+
+        put_bits(&s->pb, 2, 0); /* no gain range info */
+    }
+
+    /* bit allocation info */
+    baie = (block_num == 0);
+    put_bits(&s->pb, 1, baie);
+    if (baie) {
+        put_bits(&s->pb, 2, s->sdecaycod);
+        put_bits(&s->pb, 2, s->fdecaycod);
+        put_bits(&s->pb, 2, s->sgaincod);
+        put_bits(&s->pb, 2, s->dbkneecod);
+        put_bits(&s->pb, 3, s->floorcod);
+    }
+
+    /* snr offset */
+    put_bits(&s->pb, 1, baie); /* always present with bai */
+    if (baie) {
+        put_bits(&s->pb, 6, s->csnroffst);
+        for(ch=0;ch<s->nb_channels;ch++) {
+            put_bits(&s->pb, 4, s->fsnroffst[ch]);
+            put_bits(&s->pb, 3, s->fgaincod[ch]);
+        }
+    }
+    
+    put_bits(&s->pb, 1, 0); /* no delta bit allocation */
+    put_bits(&s->pb, 1, 0); /* no data to skip */
+
+    /* mantissa encoding : we use two passes to handle the grouping. A
+       one pass method may be faster, but it would necessitate to
+       modify the output stream. */
+
+    /* first pass: quantize */
+    mant1_cnt = mant2_cnt = mant4_cnt = 0;
+    qmant1_ptr = qmant2_ptr = qmant4_ptr = NULL;
+
+    for (ch = 0; ch < s->nb_channels; ch++) {
+        int b, c, e, v;
+
+        for(i=0;i<s->nb_coefs[ch];i++) {
+            c = mdct_coefs[ch][i];
+            e = encoded_exp[ch][i] - global_exp[ch];
+            b = bap[ch][i];
+            switch(b) {
+            case 0:
+                v = 0;
+                break;
+            case 1:
+                v = sym_quant(c, e, 3);
+                switch(mant1_cnt) {
+                case 0:
+                    qmant1_ptr = &qmant[ch][i];
+                    v = 9 * v;
+                    mant1_cnt = 1;
+                    break;
+                case 1:
+                    *qmant1_ptr += 3 * v;
+                    mant1_cnt = 2;
+                    v = 128;
+                    break;
+                default:
+                    *qmant1_ptr += v;
+                    mant1_cnt = 0;
+                    v = 128;
+                    break;
+                }
+                break;
+            case 2:
+                v = sym_quant(c, e, 5);
+                switch(mant2_cnt) {
+                case 0:
+                    qmant2_ptr = &qmant[ch][i];
+                    v = 25 * v;
+                    mant2_cnt = 1;
+                    break;
+                case 1:
+                    *qmant2_ptr += 5 * v;
+                    mant2_cnt = 2;
+                    v = 128;
+                    break;
+                default:
+                    *qmant2_ptr += v;
+                    mant2_cnt = 0;
+                    v = 128;
+                    break;
+                }
+                break;
+            case 3:
+                v = sym_quant(c, e, 7);
+                break;
+            case 4:
+                v = sym_quant(c, e, 11);
+                switch(mant4_cnt) {
+                case 0:
+                    qmant4_ptr = &qmant[ch][i];
+                    v = 11 * v;
+                    mant4_cnt = 1;
+                    break;
+                default:
+                    *qmant4_ptr += v;
+                    mant4_cnt = 0;
+                    v = 128;
+                    break;
+                }
+                break;
+            case 5:
+                v = sym_quant(c, e, 15);
+                break;
+            case 14:
+                v = asym_quant(c, e, 14);
+                break;
+            case 15:
+                v = asym_quant(c, e, 16);
+                break;
+            default:
+                v = asym_quant(c, e, b - 1);
+                break;
+            }
+            qmant[ch][i] = v;
+        }
+    }
+
+    /* second pass : output the values */
+    for (ch = 0; ch < s->nb_channels; ch++) {
+        int b, q;
+        
+        for(i=0;i<s->nb_coefs[ch];i++) {
+            q = qmant[ch][i];
+            b = bap[ch][i];
+            switch(b) {
+            case 0:
+                break;
+            case 1:
+                if (q != 128) 
+                    put_bits(&s->pb, 5, q);
+                break;
+            case 2:
+                if (q != 128) 
+                    put_bits(&s->pb, 7, q);
+                break;
+            case 3:
+                put_bits(&s->pb, 3, q);
+                break;
+            case 4:
+                if (q != 128)
+                    put_bits(&s->pb, 7, q);
+                break;
+            case 14:
+                put_bits(&s->pb, 14, q);
+                break;
+            case 15:
+                put_bits(&s->pb, 16, q);
+                break;
+            default:
+                put_bits(&s->pb, b - 1, q);
+                break;
+            }
+        }
+    }
+}
+
+/* compute the ac3 crc */
+
+#define CRC16_POLY ((1 << 0) | (1 << 2) | (1 << 15) | (1 << 16))
+
+static void ac3_crc_init(void)
+{
+    unsigned int c, n, k;
+
+    for(n=0;n<256;n++) {
+        c = n << 8;
+        for (k = 0; k < 8; k++) {
+            if (c & (1 << 15)) 
+                c = ((c << 1) & 0xffff) ^ (CRC16_POLY & 0xffff);
+            else
+                c = c << 1;
+        }
+        crc_table[n] = c;
+    }
+}
+
+static unsigned int ac3_crc(UINT8 *data, int n, unsigned int crc)
+{
+    int i;
+    for(i=0;i<n;i++) {
+        crc = (crc_table[data[i] ^ (crc >> 8)] ^ (crc << 8)) & 0xffff;
+    }
+    return crc;
+}
+
+static unsigned int mul_poly(unsigned int a, unsigned int b, unsigned int poly)
+{
+    unsigned int c;
+
+    c = 0;
+    while (a) {
+        if (a & 1)
+            c ^= b;
+        a = a >> 1;
+        b = b << 1;
+        if (b & (1 << 16))
+            b ^= poly;
+    }
+    return c;
+}
+
+static unsigned int pow_poly(unsigned int a, unsigned int n, unsigned int poly)
+{
+    unsigned int r;
+    r = 1;
+    while (n) {
+        if (n & 1)
+            r = mul_poly(r, a, poly);
+        a = mul_poly(a, a, poly);
+        n >>= 1;
+    }
+    return r;
+}
+
+
+/* compute log2(max(abs(tab[]))) */
+static int log2_tab(INT16 *tab, int n)
+{
+    int i, v;
+
+    v = 0;
+    for(i=0;i<n;i++) {
+        v |= abs(tab[i]);
+    }
+    return log2(v);
+}
+
+static void lshift_tab(INT16 *tab, int n, int lshift)
+{
+    int i;
+
+    if (lshift > 0) {
+        for(i=0;i<n;i++) {
+            tab[i] <<= lshift;
+        }
+    } else if (lshift < 0) {
+        lshift = -lshift;
+        for(i=0;i<n;i++) {
+            tab[i] >>= lshift;
+        }
+    }
+}
+
+/* fill the end of the frame and compute the two crcs */
+static int output_frame_end(AC3EncodeContext *s)
+{
+    int frame_size, frame_size_58, n, crc1, crc2, crc_inv;
+    UINT8 *frame;
+
+    frame_size = s->frame_size; /* frame size in words */
+    /* align to 8 bits */
+    flush_put_bits(&s->pb);
+    /* add zero bytes to reach the frame size */
+    frame = s->pb.buf;
+    n = 2 * s->frame_size - (s->pb.buf_ptr - frame) - 2;
+    assert(n >= 0);
+    memset(s->pb.buf_ptr, 0, n);
+    
+    /* Now we must compute both crcs : this is not so easy for crc1
+       because it is at the beginning of the data... */
+    frame_size_58 = (frame_size >> 1) + (frame_size >> 3);
+    crc1 = ac3_crc(frame + 4, (2 * frame_size_58) - 4, 0);
+    /* XXX: could precompute crc_inv */
+    crc_inv = pow_poly((CRC16_POLY >> 1), (16 * frame_size_58) - 16, CRC16_POLY);
+    crc1 = mul_poly(crc_inv, crc1, CRC16_POLY);
+    frame[2] = crc1 >> 8;
+    frame[3] = crc1;
+    
+    crc2 = ac3_crc(frame + 2 * frame_size_58, (frame_size - frame_size_58) * 2 - 2, 0);
+    frame[2*frame_size - 2] = crc2 >> 8;
+    frame[2*frame_size - 1] = crc2;
+
+    //    printf("n=%d frame_size=%d\n", n, frame_size);
+    return frame_size * 2;
+}
+
+int AC3_encode_frame(AVCodecContext *avctx,
+                     unsigned char *frame, int buf_size, void *data)
+{
+    AC3EncodeContext *s = avctx->priv_data;
+    short *samples = data;
+    int i, j, k, v, ch;
+    INT16 input_samples[N];
+    INT32 mdct_coef[NB_BLOCKS][AC3_MAX_CHANNELS][N/2];
+    UINT8 exp[NB_BLOCKS][AC3_MAX_CHANNELS][N/2];
+    UINT8 exp_strategy[NB_BLOCKS][AC3_MAX_CHANNELS];
+    UINT8 encoded_exp[NB_BLOCKS][AC3_MAX_CHANNELS][N/2];
+    UINT8 bap[NB_BLOCKS][AC3_MAX_CHANNELS][N/2];
+    INT8 exp_samples[NB_BLOCKS][AC3_MAX_CHANNELS];
+    int frame_bits;
+
+    frame_bits = 0;
+    for(ch=0;ch<s->nb_channels;ch++) {
+        /* fixed mdct to the six sub blocks & exponent computation */
+        for(i=0;i<NB_BLOCKS;i++) {
+            INT16 *sptr;
+            int sinc;
+
+            /* compute input samples */
+            memcpy(input_samples, s->last_samples[ch], N/2 * sizeof(INT16));
+            sinc = s->nb_channels;
+            sptr = samples + (sinc * (N/2) * i) + ch;
+            for(j=0;j<N/2;j++) {
+                v = *sptr;
+                input_samples[j + N/2] = v;
+                s->last_samples[ch][j] = v; 
+                sptr += sinc;
+            }
+
+            /* apply the MDCT window */
+            for(j=0;j<N/2;j++) {
+                input_samples[j] = MUL16(input_samples[j], 
+                                         ac3_window[j]) >> 15;
+                input_samples[N-j-1] = MUL16(input_samples[N-j-1], 
+                                             ac3_window[j]) >> 15;
+            }
+        
+            /* Normalize the samples to use the maximum available
+               precision */
+            v = 14 - log2_tab(input_samples, N);
+            if (v < 0)
+                v = 0;
+            exp_samples[i][ch] = v - 8;
+            lshift_tab(input_samples, N, v);
+
+            /* do the MDCT */
+            mdct512(mdct_coef[i][ch], input_samples);
+            
+            /* compute "exponents". We take into account the
+               normalization there */
+            for(j=0;j<N/2;j++) {
+                int e;
+                v = abs(mdct_coef[i][ch][j]);
+                if (v == 0)
+                    e = 24;
+                else {
+                    e = 23 - log2(v) + exp_samples[i][ch];
+                    if (e >= 24) {
+                        e = 24;
+                        mdct_coef[i][ch][j] = 0;
+                    }
+                }
+                exp[i][ch][j] = e;
+            }
+        }
+        
+        compute_exp_strategy(exp_strategy, exp, ch);
+
+        /* compute the exponents as the decoder will see them. The
+           EXP_REUSE case must be handled carefully : we select the
+           min of the exponents */
+        i = 0;
+        while (i < NB_BLOCKS) {
+            j = i + 1;
+            while (j < NB_BLOCKS && exp_strategy[j][ch] == EXP_REUSE) {
+                exponent_min(exp[i][ch], exp[j][ch], s->nb_coefs[ch]);
+                j++;
+            }
+            frame_bits += encode_exp(encoded_exp[i][ch],
+                                     exp[i][ch], s->nb_coefs[ch], 
+                                     exp_strategy[i][ch]);
+            /* copy encoded exponents for reuse case */
+            for(k=i+1;k<j;k++) {
+                memcpy(encoded_exp[k][ch], encoded_exp[i][ch], 
+                       s->nb_coefs[ch] * sizeof(UINT8));
+            }
+            i = j;
+        }
+    }
+
+    compute_bit_allocation(s, bap, encoded_exp, exp_strategy, frame_bits);
+    /* everything is known... let's output the frame */
+    output_frame_header(s, frame);
+        
+    for(i=0;i<NB_BLOCKS;i++) {
+        output_audio_block(s, exp_strategy[i], encoded_exp[i], 
+                           bap[i], mdct_coef[i], exp_samples[i], i);
+    }
+    return output_frame_end(s);
+}
+
+#if 0
+/*************************************************************************/
+/* TEST */
+
+#define FN (N/4)
+
+void fft_test(void)
+{
+    IComplex in[FN], in1[FN];
+    int k, n, i;
+    float sum_re, sum_im, a;
+
+    /* FFT test */
+
+    for(i=0;i<FN;i++) {
+        in[i].re = random() % 65535 - 32767;
+        in[i].im = random() % 65535 - 32767;
+        in1[i] = in[i];
+    }
+    fft(in, 7);
+
+    /* do it by hand */
+    for(k=0;k<FN;k++) {
+        sum_re = 0;
+        sum_im = 0;
+        for(n=0;n<FN;n++) {
+            a = -2 * M_PI * (n * k) / FN;
+            sum_re += in1[n].re * cos(a) - in1[n].im * sin(a);
+            sum_im += in1[n].re * sin(a) + in1[n].im * cos(a);
+        }
+        printf("%3d: %6d,%6d %6.0f,%6.0f\n", 
+               k, in[k].re, in[k].im, sum_re / FN, sum_im / FN); 
+    }
+}
+
+void mdct_test(void)
+{
+    INT16 input[N];
+    INT32 output[N/2];
+    float input1[N];
+    float output1[N/2];
+    float s, a, err, e, emax;
+    int i, k, n;
+
+    for(i=0;i<N;i++) {
+        input[i] = (random() % 65535 - 32767) * 9 / 10;
+        input1[i] = input[i];
+    }
+
+    mdct512(output, input);
+    
+    /* do it by hand */
+    for(k=0;k<N/2;k++) {
+        s = 0;
+        for(n=0;n<N;n++) {
+            a = (2*M_PI*(2*n+1+N/2)*(2*k+1) / (4 * N));
+            s += input1[n] * cos(a);
+        }
+        output1[k] = -2 * s / N;
+    }
+    
+    err = 0;
+    emax = 0;
+    for(i=0;i<N/2;i++) {
+        printf("%3d: %7d %7.0f\n", i, output[i], output1[i]);
+        e = output[i] - output1[i];
+        if (e > emax)
+            emax = e;
+        err += e * e;
+    }
+    printf("err2=%f emax=%f\n", err / (N/2), emax);
+}
+
+void test_ac3(void)
+{
+    AC3EncodeContext ctx;
+    unsigned char frame[AC3_MAX_CODED_FRAME_SIZE];
+    short samples[AC3_FRAME_SIZE];
+    int ret, i;
+    
+    AC3_encode_init(&ctx, 44100, 64000, 1);
+
+    fft_test();
+    mdct_test();
+
+    for(i=0;i<AC3_FRAME_SIZE;i++)
+        samples[i] = (int)(sin(2*M_PI*i*1000.0/44100) * 10000);
+    ret = AC3_encode_frame(&ctx, frame, samples);
+    printf("ret=%d\n", ret);
+}
+#endif
+
+AVCodec ac3_encoder = {
+    "ac3",
+    CODEC_TYPE_AUDIO,
+    CODEC_ID_AC3,
+    sizeof(AC3EncodeContext),
+    AC3_encode_init,
+    AC3_encode_frame,
+    NULL,
+};
diff --git a/libavcodec/ac3enc.h b/libavcodec/ac3enc.h
new file mode 100644 (file)
index 0000000..40cc53a
--- /dev/null
@@ -0,0 +1,32 @@
+
+#define AC3_FRAME_SIZE (6*256)
+#define AC3_MAX_CODED_FRAME_SIZE 3840 /* in bytes */
+#define AC3_MAX_CHANNELS 2 /* we handle at most two channels, although
+                              AC3 allows 6 channels */
+
+typedef struct AC3EncodeContext {
+    PutBitContext pb;
+    int nb_channels;
+    int bit_rate;
+    int sample_rate;
+    int bsid;
+    int frame_size_min; /* minimum frame size in case rounding is necessary */
+    int frame_size; /* current frame size in words */
+    int halfratecod;
+    int frmsizecod;
+    int fscod; /* frequency */
+    int acmod;
+    int bsmod;
+    short last_samples[AC3_MAX_CHANNELS][256];
+    int chbwcod[AC3_MAX_CHANNELS];
+    int nb_coefs[AC3_MAX_CHANNELS];
+    
+    /* bitrate allocation control */
+    int sgaincod, sdecaycod, fdecaycod, dbkneecod, floorcod; 
+    int sgain, sdecay, fdecay, dbknee, floor;
+    int csnroffst;
+    int fgaincod[AC3_MAX_CHANNELS];
+    int fsnroffst[AC3_MAX_CHANNELS];
+    /* mantissa encoding */
+    int mant1_cnt, mant2_cnt, mant4_cnt;
+} AC3EncodeContext;
diff --git a/libavcodec/ac3tab.h b/libavcodec/ac3tab.h
new file mode 100644 (file)
index 0000000..2d379f0
--- /dev/null
@@ -0,0 +1,180 @@
+/* tables taken directly from AC3 spec */
+
+/* possible bitrates */
+static const UINT16 bitratetab[19] = {
+    32, 40, 48, 56, 64, 80, 96, 112, 128, 
+    160, 192, 224, 256, 320, 384, 448, 512, 576, 640 
+};
+
+/* AC3 MDCT window */
+
+/* MDCT window */
+static const INT16 ac3_window[256]= {
+    4,    7,   12,   16,   21,   28,   34,   42,
+   51,   61,   72,   84,   97,  111,  127,  145,
+  164,  184,  207,  231,  257,  285,  315,  347,
+  382,  419,  458,  500,  544,  591,  641,  694,
+  750,  810,  872,  937, 1007, 1079, 1155, 1235,
+ 1318, 1406, 1497, 1593, 1692, 1796, 1903, 2016,
+ 2132, 2253, 2379, 2509, 2644, 2783, 2927, 3076,
+ 3230, 3389, 3552, 3721, 3894, 4072, 4255, 4444,
+ 4637, 4835, 5038, 5246, 5459, 5677, 5899, 6127,
+ 6359, 6596, 6837, 7083, 7334, 7589, 7848, 8112,
+ 8380, 8652, 8927, 9207, 9491, 9778,10069,10363,
+10660,10960,11264,11570,11879,12190,12504,12820,
+13138,13458,13780,14103,14427,14753,15079,15407,
+15735,16063,16392,16720,17049,17377,17705,18032,
+18358,18683,19007,19330,19651,19970,20287,20602,
+20914,21225,21532,21837,22139,22438,22733,23025,
+23314,23599,23880,24157,24430,24699,24964,25225,
+25481,25732,25979,26221,26459,26691,26919,27142,
+27359,27572,27780,27983,28180,28373,28560,28742,
+28919,29091,29258,29420,29577,29729,29876,30018,
+30155,30288,30415,30538,30657,30771,30880,30985,
+31086,31182,31274,31363,31447,31528,31605,31678,
+31747,31814,31877,31936,31993,32046,32097,32145,
+32190,32232,32272,32310,32345,32378,32409,32438,
+32465,32490,32513,32535,32556,32574,32592,32608,
+32623,32636,32649,32661,32671,32681,32690,32698,
+32705,32712,32718,32724,32729,32733,32737,32741,
+32744,32747,32750,32752,32754,32756,32757,32759,
+32760,32761,32762,32763,32764,32764,32765,32765,
+32766,32766,32766,32766,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,  
+};
+
+static UINT8 masktab[253];
+
+static const UINT8 latab[260]= {
+0x0040,0x003f,0x003e,0x003d,0x003c,0x003b,0x003a,0x0039,0x0038,0x0037,
+0x0036,0x0035,0x0034,0x0034,0x0033,0x0032,0x0031,0x0030,0x002f,0x002f,
+0x002e,0x002d,0x002c,0x002c,0x002b,0x002a,0x0029,0x0029,0x0028,0x0027,
+0x0026,0x0026,0x0025,0x0024,0x0024,0x0023,0x0023,0x0022,0x0021,0x0021,
+0x0020,0x0020,0x001f,0x001e,0x001e,0x001d,0x001d,0x001c,0x001c,0x001b,
+0x001b,0x001a,0x001a,0x0019,0x0019,0x0018,0x0018,0x0017,0x0017,0x0016,
+0x0016,0x0015,0x0015,0x0015,0x0014,0x0014,0x0013,0x0013,0x0013,0x0012,
+0x0012,0x0012,0x0011,0x0011,0x0011,0x0010,0x0010,0x0010,0x000f,0x000f,
+0x000f,0x000e,0x000e,0x000e,0x000d,0x000d,0x000d,0x000d,0x000c,0x000c,
+0x000c,0x000c,0x000b,0x000b,0x000b,0x000b,0x000a,0x000a,0x000a,0x000a,
+0x000a,0x0009,0x0009,0x0009,0x0009,0x0009,0x0008,0x0008,0x0008,0x0008,
+0x0008,0x0008,0x0007,0x0007,0x0007,0x0007,0x0007,0x0007,0x0006,0x0006,
+0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0005,0x0005,0x0005,0x0005,
+0x0005,0x0005,0x0005,0x0005,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,
+0x0004,0x0004,0x0004,0x0004,0x0004,0x0003,0x0003,0x0003,0x0003,0x0003,
+0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0002,
+0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,
+0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0001,0x0001,
+0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,
+0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,
+0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,
+0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+};
+
+static const UINT16 hth[50][3]= {
+{ 0x04d0,0x04f0,0x0580 },
+{ 0x04d0,0x04f0,0x0580 },
+{ 0x0440,0x0460,0x04b0 },
+{ 0x0400,0x0410,0x0450 },
+{ 0x03e0,0x03e0,0x0420 },
+{ 0x03c0,0x03d0,0x03f0 },
+{ 0x03b0,0x03c0,0x03e0 },
+{ 0x03b0,0x03b0,0x03d0 },
+{ 0x03a0,0x03b0,0x03c0 },
+{ 0x03a0,0x03a0,0x03b0 },
+{ 0x03a0,0x03a0,0x03b0 },
+{ 0x03a0,0x03a0,0x03b0 },
+{ 0x03a0,0x03a0,0x03a0 },
+{ 0x0390,0x03a0,0x03a0 },
+{ 0x0390,0x0390,0x03a0 },
+{ 0x0390,0x0390,0x03a0 },
+{ 0x0380,0x0390,0x03a0 },
+{ 0x0380,0x0380,0x03a0 },
+{ 0x0370,0x0380,0x03a0 },
+{ 0x0370,0x0380,0x03a0 },
+{ 0x0360,0x0370,0x0390 },
+{ 0x0360,0x0370,0x0390 },
+{ 0x0350,0x0360,0x0390 },
+{ 0x0350,0x0360,0x0390 },
+{ 0x0340,0x0350,0x0380 },
+{ 0x0340,0x0350,0x0380 },
+{ 0x0330,0x0340,0x0380 },
+{ 0x0320,0x0340,0x0370 },
+{ 0x0310,0x0320,0x0360 },
+{ 0x0300,0x0310,0x0350 },
+{ 0x02f0,0x0300,0x0340 },
+{ 0x02f0,0x02f0,0x0330 },
+{ 0x02f0,0x02f0,0x0320 },
+{ 0x02f0,0x02f0,0x0310 },
+{ 0x0300,0x02f0,0x0300 },
+{ 0x0310,0x0300,0x02f0 },
+{ 0x0340,0x0320,0x02f0 },
+{ 0x0390,0x0350,0x02f0 },
+{ 0x03e0,0x0390,0x0300 },
+{ 0x0420,0x03e0,0x0310 },
+{ 0x0460,0x0420,0x0330 },
+{ 0x0490,0x0450,0x0350 },
+{ 0x04a0,0x04a0,0x03c0 },
+{ 0x0460,0x0490,0x0410 },
+{ 0x0440,0x0460,0x0470 },
+{ 0x0440,0x0440,0x04a0 },
+{ 0x0520,0x0480,0x0460 },
+{ 0x0800,0x0630,0x0440 },
+{ 0x0840,0x0840,0x0450 },
+{ 0x0840,0x0840,0x04e0 },
+};
+
+static const UINT8 baptab[64]= {
+    0, 1, 1, 1, 1, 1, 2, 2, 3, 3, 
+    3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 
+    7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 
+    9, 10, 10, 10, 10, 11, 11, 11, 11, 12, 
+    12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 
+    14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 
+    15, 15, 15, 15,
+};
+
+static const UINT8 sdecaytab[4]={ 
+    0x0f, 0x11, 0x13, 0x15,
+};
+
+static const UINT8 fdecaytab[4]={ 
+    0x3f, 0x53, 0x67, 0x7b, 
+};
+
+static const UINT16 sgaintab[4]= { 
+    0x540, 0x4d8, 0x478, 0x410,
+};
+
+static const UINT16 dbkneetab[4]= { 
+    0x000, 0x700, 0x900, 0xb00,
+};
+
+static const UINT16 floortab[8]= { 
+    0x2f0, 0x2b0, 0x270, 0x230, 0x1f0, 0x170, 0x0f0, 0xf800,
+};
+
+static const UINT16 fgaintab[8]= {
+    0x080, 0x100, 0x180, 0x200, 0x280, 0x300, 0x380, 0x400,
+};
+
+static const UINT8 bndsz[50]={
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 
+    3, 6, 6, 6, 6, 6, 6, 12, 12, 12, 12, 24, 24, 24, 24, 24 
+};
+
+static UINT8 bndtab[51]; 
+
+/* fft & mdct sin cos tables */
+static INT16 costab[64];
+static INT16 sintab[64];
+static INT16 fft_rev[512];
+static INT16 xcos1[128];
+static INT16 xsin1[128];
+
+static UINT16 crc_table[256];
diff --git a/libavcodec/apiexample.c b/libavcodec/apiexample.c
new file mode 100644 (file)
index 0000000..e7ae6e8
--- /dev/null
@@ -0,0 +1,407 @@
+/* avcodec API use example.
+ *
+ * Note that this library only handles codecs (mpeg, mpeg4, etc...),
+ * not file formats (avi, vob, etc...). See library 'libav' for the
+ * format handling 
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+#include "avcodec.h"
+
+#define INBUF_SIZE 4096
+
+/*
+ * Audio encoding example 
+ */
+void audio_encode_example(const char *filename)
+{
+    AVCodec *codec;
+    AVCodecContext codec_context, *c = &codec_context;
+    int frame_size, i, j, out_size, outbuf_size;
+    FILE *f;
+    short *samples;
+    float t, tincr;
+    UINT8 *outbuf;
+
+    printf("Audio encoding\n");
+
+    /* find the MP2 encoder */
+    codec = avcodec_find_encoder(CODEC_ID_MP2);
+    if (!codec) {
+        fprintf(stderr, "codec not found\n");
+        exit(1);
+    }
+
+    /* put default values */
+    memset(c, 0, sizeof(*c));
+
+    /* put sample parameters */
+    c->bit_rate = 64000;
+    c->sample_rate = 44100;
+    c->channels = 2;
+
+    /* open it */
+    if (avcodec_open(c, codec) < 0) {
+        fprintf(stderr, "could not open codec\n");
+        exit(1);
+    }
+    
+    /* the codec gives us the frame size, in samples */
+    frame_size = c->frame_size;
+    samples = malloc(frame_size * 2 * c->channels);
+    outbuf_size = 10000;
+    outbuf = malloc(outbuf_size);
+
+    f = fopen(filename, "w");
+    if (!f) {
+        fprintf(stderr, "could not open %s\n", filename);
+        exit(1);
+    }
+        
+    /* encode a single tone sound */
+    t = 0;
+    tincr = 2 * M_PI * 440.0 / c->sample_rate;
+    for(i=0;i<200;i++) {
+        for(j=0;j<frame_size;j++) {
+            samples[2*j] = (int)(sin(t) * 10000);
+            samples[2*j+1] = samples[2*j];
+            t += tincr;
+        }
+        /* encode the samples */
+        out_size = avcodec_encode_audio(c, outbuf, outbuf_size, samples);
+        fwrite(outbuf, 1, out_size, f);
+    }
+    fclose(f);
+    free(outbuf);
+    free(samples);
+
+    avcodec_close(c);
+}
+
+/*
+ * Audio decoding. 
+ */
+void audio_decode_example(const char *outfilename, const char *filename)
+{
+    AVCodec *codec;
+    AVCodecContext codec_context, *c = &codec_context;
+    int out_size, size, len;
+    FILE *f, *outfile;
+    UINT8 *outbuf;
+    UINT8 inbuf[INBUF_SIZE], *inbuf_ptr;
+
+    printf("Audio decoding\n");
+
+    /* find the mpeg audio decoder */
+    codec = avcodec_find_decoder(CODEC_ID_MP2);
+    if (!codec) {
+        fprintf(stderr, "codec not found\n");
+        exit(1);
+    }
+
+    /* put default values */
+    memset(c, 0, sizeof(*c));
+
+    /* open it */
+    if (avcodec_open(c, codec) < 0) {
+        fprintf(stderr, "could not open codec\n");
+        exit(1);
+    }
+    
+    outbuf = malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
+
+    f = fopen(filename, "r");
+    if (!f) {
+        fprintf(stderr, "could not open %s\n", filename);
+        exit(1);
+    }
+    outfile = fopen(outfilename, "w");
+    if (!outfile) {
+        fprintf(stderr, "could not open %s\n", outfilename);
+        exit(1);
+    }
+        
+    /* decode until eof */
+    inbuf_ptr = inbuf;
+    for(;;) {
+        size = fread(inbuf, 1, INBUF_SIZE, f);
+        if (size == 0)
+            break;
+
+        inbuf_ptr = inbuf;
+        while (size > 0) {
+            len = avcodec_decode_audio(c, (short *)outbuf, &out_size, 
+                                       inbuf_ptr, size);
+            if (len < 0) {
+                fprintf(stderr, "Error while decoding\n");
+                exit(1);
+            }
+            if (out_size > 0) {
+                /* if a frame has been decoded, output it */
+                fwrite(outbuf, 1, out_size, outfile);
+            }
+          &nb