It has not been properly maintained for years and there is little hope of that changing in the future. It appears simpler to write a new replacement from scratch than unbreaking it.tags/n2.3
| @@ -24,7 +24,6 @@ | |||
| /avconv | |||
| /avplay | |||
| /avprobe | |||
| /avserver | |||
| /config.* | |||
| /coverage.info | |||
| /version.h | |||
| @@ -27,6 +27,7 @@ version <next>: | |||
| - libbs2b-based stereo-to-binaural audio filter | |||
| - native Opus decoder | |||
| - display matrix export and rotation api | |||
| - drop avserver, it was unmaintained for years and largely broken | |||
| version 10: | |||
| @@ -63,12 +63,11 @@ COMPILE_HOSTC = $(call COMPILE,HOSTCC) | |||
| AVPROGS-$(CONFIG_AVCONV) += avconv | |||
| AVPROGS-$(CONFIG_AVPLAY) += avplay | |||
| AVPROGS-$(CONFIG_AVPROBE) += avprobe | |||
| AVPROGS-$(CONFIG_AVSERVER) += avserver | |||
| AVPROGS := $(AVPROGS-yes:%=%$(EXESUF)) | |||
| PROGS += $(AVPROGS) | |||
| AVBASENAMES = avconv avplay avprobe avserver | |||
| AVBASENAMES = avconv avplay avprobe | |||
| ALLAVPROGS = $(AVBASENAMES:%=%$(EXESUF)) | |||
| $(foreach prog,$(AVBASENAMES),$(eval OBJS-$(prog) += cmdutils.o)) | |||
| @@ -108,7 +108,7 @@ Program options: | |||
| --disable-avconv disable avconv build | |||
| --disable-avplay disable avplay build | |||
| --disable-avprobe disable avprobe build | |||
| --disable-avserver disable avserver build | |||
| --disable-avserver deprecated, does nothing | |||
| Component options: | |||
| --disable-doc do not build documentation | |||
| @@ -1209,7 +1209,6 @@ PROGRAM_LIST=" | |||
| avconv | |||
| avplay | |||
| avprobe | |||
| avserver | |||
| " | |||
| SUBSYSTEM_LIST=" | |||
| @@ -2142,8 +2141,6 @@ avplay_deps="avcodec avformat avresample swscale sdl" | |||
| avplay_libs='$sdl_libs' | |||
| avplay_select="rdft" | |||
| avprobe_deps="avcodec avformat" | |||
| avserver_deps="avformat fork !shared" | |||
| avserver_select="ffm_muxer rtp_protocol rtsp_demuxer" | |||
| # documentation | |||
| pod2man_deps="doc" | |||
| @@ -2380,6 +2377,10 @@ for opt do | |||
| name=$(echo "${optval}" | sed "s/,/_${thing}|/g")_${thing} | |||
| $action $(filter "$name" $list) | |||
| ;; | |||
| --enable-avserver|--disable-avserver*) | |||
| warn "avserver has been removed, the ${opt} option is only"\ | |||
| "provided for compatibility and will be removed in the future" | |||
| ;; | |||
| --enable-?*|--disable-?*) | |||
| eval $(echo "$opt" | sed 's/--/action=/;s/-/ option=/;s/-/_/g') | |||
| if is_in $option $COMPONENT_LIST; then | |||
| @@ -3539,7 +3540,6 @@ case $target_os in | |||
| add_compat strtod.o strtod=avpriv_strtod | |||
| network_extralibs='-lbsd' | |||
| exeobjs=compat/plan9/main.o | |||
| disable avserver | |||
| cp_f='cp' | |||
| ;; | |||
| none) | |||
| @@ -1,372 +0,0 @@ | |||
| # Port on which the server is listening. You must select a different | |||
| # port from your standard HTTP web server if it is running on the same | |||
| # computer. | |||
| Port 8090 | |||
| # Address on which the server is bound. Only useful if you have | |||
| # several network interfaces. | |||
| BindAddress 0.0.0.0 | |||
| # Number of simultaneous HTTP connections that can be handled. It has | |||
| # to be defined *before* the MaxClients parameter, since it defines the | |||
| # MaxClients maximum limit. | |||
| MaxHTTPConnections 2000 | |||
| # Number of simultaneous requests that can be handled. Since AVServer | |||
| # is very fast, it is more likely that you will want to leave this high | |||
| # and use MaxBandwidth, below. | |||
| MaxClients 1000 | |||
| # This the maximum amount of kbit/sec that you are prepared to | |||
| # consume when streaming to clients. | |||
| MaxBandwidth 1000 | |||
| # Access log file (uses standard Apache log file format) | |||
| # '-' is the standard output. | |||
| CustomLog - | |||
| ################################################################## | |||
| # Definition of the live feeds. Each live feed contains one video | |||
| # and/or audio sequence coming from an avconv encoder or another | |||
| # avserver. This sequence may be encoded simultaneously with several | |||
| # codecs at several resolutions. | |||
| <Feed feed1.ffm> | |||
| # You must use 'avconv' to send a live feed to avserver. In this | |||
| # example, you can type: | |||
| # | |||
| # avconv http://localhost:8090/feed1.ffm | |||
| # avserver can also do time shifting. It means that it can stream any | |||
| # previously recorded live stream. The request should contain: | |||
| # "http://xxxx?date=[YYYY-MM-DDT][[HH:]MM:]SS[.m...]".You must specify | |||
| # a path where the feed is stored on disk. You also specify the | |||
| # maximum size of the feed, where zero means unlimited. Default: | |||
| # File=/tmp/feed_name.ffm FileMaxSize=5M | |||
| File /tmp/feed1.ffm | |||
| FileMaxSize 200K | |||
| # You could specify | |||
| # ReadOnlyFile /saved/specialvideo.ffm | |||
| # This marks the file as readonly and it will not be deleted or updated. | |||
| # Specify launch in order to start avconv automatically. | |||
| # First avconv must be defined with an appropriate path if needed, | |||
| # after that options can follow, but avoid adding the http:// field | |||
| #Launch avconv | |||
| # Only allow connections from localhost to the feed. | |||
| ACL allow 127.0.0.1 | |||
| </Feed> | |||
| ################################################################## | |||
| # Now you can define each stream which will be generated from the | |||
| # original audio and video stream. Each format has a filename (here | |||
| # 'test1.mpg'). AVServer will send this stream when answering a | |||
| # request containing this filename. | |||
| <Stream test1.mpg> | |||
| # coming from live feed 'feed1' | |||
| Feed feed1.ffm | |||
| # Format of the stream : you can choose among: | |||
| # mpeg : MPEG-1 multiplexed video and audio | |||
| # mpegvideo : only MPEG-1 video | |||
| # mp2 : MPEG-2 audio (use AudioCodec to select layer 2 and 3 codec) | |||
| # ogg : Ogg format (Vorbis audio codec) | |||
| # rm : RealNetworks-compatible stream. Multiplexed audio and video. | |||
| # ra : RealNetworks-compatible stream. Audio only. | |||
| # mpjpeg : Multipart JPEG (works with Netscape without any plugin) | |||
| # jpeg : Generate a single JPEG image. | |||
| # asf : ASF compatible streaming (Windows Media Player format). | |||
| # swf : Macromedia Flash compatible stream | |||
| # avi : AVI format (MPEG-4 video, MPEG audio sound) | |||
| Format mpeg | |||
| # Bitrate for the audio stream. Codecs usually support only a few | |||
| # different bitrates. | |||
| AudioBitRate 32 | |||
| # Number of audio channels: 1 = mono, 2 = stereo | |||
| AudioChannels 1 | |||
| # Sampling frequency for audio. When using low bitrates, you should | |||
| # lower this frequency to 22050 or 11025. The supported frequencies | |||
| # depend on the selected audio codec. | |||
| AudioSampleRate 44100 | |||
| # Bitrate for the video stream | |||
| VideoBitRate 64 | |||
| # Ratecontrol buffer size | |||
| VideoBufferSize 40 | |||
| # Number of frames per second | |||
| VideoFrameRate 3 | |||
| # Size of the video frame: WxH (default: 160x128) | |||
| # The following abbreviations are defined: sqcif, qcif, cif, 4cif, qqvga, | |||
| # qvga, vga, svga, xga, uxga, qxga, sxga, qsxga, hsxga, wvga, wxga, wsxga, | |||
| # wuxga, woxga, wqsxga, wquxga, whsxga, whuxga, cga, ega, hd480, hd720, | |||
| # hd1080 | |||
| VideoSize 160x128 | |||
| # Transmit only intra frames (useful for low bitrates, but kills frame rate). | |||
| #VideoIntraOnly | |||
| # If non-intra only, an intra frame is transmitted every VideoGopSize | |||
| # frames. Video synchronization can only begin at an intra frame. | |||
| VideoGopSize 12 | |||
| # More MPEG-4 parameters | |||
| # VideoHighQuality | |||
| # Video4MotionVector | |||
| # Choose your codecs: | |||
| #AudioCodec mp2 | |||
| #VideoCodec mpeg1video | |||
| # Suppress audio | |||
| #NoAudio | |||
| # Suppress video | |||
| #NoVideo | |||
| #VideoQMin 3 | |||
| #VideoQMax 31 | |||
| # Set this to the number of seconds backwards in time to start. Note that | |||
| # most players will buffer 5-10 seconds of video, and also you need to allow | |||
| # for a keyframe to appear in the data stream. | |||
| #Preroll 15 | |||
| # ACL: | |||
| # You can allow ranges of addresses (or single addresses) | |||
| #ACL ALLOW <first address> <last address> | |||
| # You can deny ranges of addresses (or single addresses) | |||
| #ACL DENY <first address> <last address> | |||
| # You can repeat the ACL allow/deny as often as you like. It is on a per | |||
| # stream basis. The first match defines the action. If there are no matches, | |||
| # then the default is the inverse of the last ACL statement. | |||
| # | |||
| # Thus 'ACL allow localhost' only allows access from localhost. | |||
| # 'ACL deny 1.0.0.0 1.255.255.255' would deny the whole of network 1 and | |||
| # allow everybody else. | |||
| </Stream> | |||
| ################################################################## | |||
| # Example streams | |||
| # Multipart JPEG | |||
| #<Stream test.mjpg> | |||
| #Feed feed1.ffm | |||
| #Format mpjpeg | |||
| #VideoFrameRate 2 | |||
| #VideoIntraOnly | |||
| #NoAudio | |||
| #Strict -1 | |||
| #</Stream> | |||
| # Single JPEG | |||
| #<Stream test.jpg> | |||
| #Feed feed1.ffm | |||
| #Format jpeg | |||
| #VideoFrameRate 2 | |||
| #VideoIntraOnly | |||
| ##VideoSize 352x240 | |||
| #NoAudio | |||
| #Strict -1 | |||
| #</Stream> | |||
| # Flash | |||
| #<Stream test.swf> | |||
| #Feed feed1.ffm | |||
| #Format swf | |||
| #VideoFrameRate 2 | |||
| #VideoIntraOnly | |||
| #NoAudio | |||
| #</Stream> | |||
| # ASF compatible | |||
| <Stream test.asf> | |||
| Feed feed1.ffm | |||
| Format asf | |||
| VideoFrameRate 15 | |||
| VideoSize 352x240 | |||
| VideoBitRate 256 | |||
| VideoBufferSize 40 | |||
| VideoGopSize 30 | |||
| AudioBitRate 64 | |||
| StartSendOnKey | |||
| </Stream> | |||
| # MP3 audio | |||
| #<Stream test.mp3> | |||
| #Feed feed1.ffm | |||
| #Format mp2 | |||
| #AudioCodec mp3 | |||
| #AudioBitRate 64 | |||
| #AudioChannels 1 | |||
| #AudioSampleRate 44100 | |||
| #NoVideo | |||
| #</Stream> | |||
| # Ogg Vorbis audio | |||
| #<Stream test.ogg> | |||
| #Feed feed1.ffm | |||
| #Title "Stream title" | |||
| #AudioBitRate 64 | |||
| #AudioChannels 2 | |||
| #AudioSampleRate 44100 | |||
| #NoVideo | |||
| #</Stream> | |||
| # Real with audio only at 32 kbits | |||
| #<Stream test.ra> | |||
| #Feed feed1.ffm | |||
| #Format rm | |||
| #AudioBitRate 32 | |||
| #NoVideo | |||
| #NoAudio | |||
| #</Stream> | |||
| # Real with audio and video at 64 kbits | |||
| #<Stream test.rm> | |||
| #Feed feed1.ffm | |||
| #Format rm | |||
| #AudioBitRate 32 | |||
| #VideoBitRate 128 | |||
| #VideoFrameRate 25 | |||
| #VideoGopSize 25 | |||
| #NoAudio | |||
| #</Stream> | |||
| ################################################################## | |||
| # A stream coming from a file: you only need to set the input | |||
| # filename and optionally a new format. Supported conversions: | |||
| # AVI -> ASF | |||
| #<Stream file.rm> | |||
| #File "/usr/local/httpd/htdocs/tlive.rm" | |||
| #NoAudio | |||
| #</Stream> | |||
| #<Stream file.asf> | |||
| #File "/usr/local/httpd/htdocs/test.asf" | |||
| #NoAudio | |||
| #Author "Me" | |||
| #Copyright "Super MegaCorp" | |||
| #Title "Test stream from disk" | |||
| #Comment "Test comment" | |||
| #</Stream> | |||
| ################################################################## | |||
| # RTSP examples | |||
| # | |||
| # You can access this stream with the RTSP URL: | |||
| # rtsp://localhost:5454/test1-rtsp.mpg | |||
| # | |||
| # A non-standard RTSP redirector is also created. Its URL is: | |||
| # http://localhost:8090/test1-rtsp.rtsp | |||
| #<Stream test1-rtsp.mpg> | |||
| #Format rtp | |||
| #File "/usr/local/httpd/htdocs/test1.mpg" | |||
| #</Stream> | |||
| # Transcode an incoming live feed to another live feed, | |||
| # using libx264 and video presets | |||
| #<Stream live.h264> | |||
| #Format rtp | |||
| #Feed feed1.ffm | |||
| #VideoCodec libx264 | |||
| #VideoFrameRate 24 | |||
| #VideoBitRate 100 | |||
| #VideoSize 480x272 | |||
| #AVPresetVideo default | |||
| #AVPresetVideo baseline | |||
| #AVOptionVideo flags +global_header | |||
| # | |||
| #AudioCodec libfaac | |||
| #AudioBitRate 32 | |||
| #AudioChannels 2 | |||
| #AudioSampleRate 22050 | |||
| #AVOptionAudio flags +global_header | |||
| #</Stream> | |||
| ################################################################## | |||
| # SDP/multicast examples | |||
| # | |||
| # If you want to send your stream in multicast, you must set the | |||
| # multicast address with MulticastAddress. The port and the TTL can | |||
| # also be set. | |||
| # | |||
| # An SDP file is automatically generated by avserver by adding the | |||
| # 'sdp' extension to the stream name (here | |||
| # http://localhost:8090/test1-sdp.sdp). You should usually give this | |||
| # file to your player to play the stream. | |||
| # | |||
| # The 'NoLoop' option can be used to avoid looping when the stream is | |||
| # terminated. | |||
| #<Stream test1-sdp.mpg> | |||
| #Format rtp | |||
| #File "/usr/local/httpd/htdocs/test1.mpg" | |||
| #MulticastAddress 224.124.0.1 | |||
| #MulticastPort 5000 | |||
| #MulticastTTL 16 | |||
| #NoLoop | |||
| #</Stream> | |||
| ################################################################## | |||
| # Special streams | |||
| # Server status | |||
| <Stream stat.html> | |||
| Format status | |||
| # Only allow local people to get the status | |||
| ACL allow localhost | |||
| ACL allow 192.168.0.0 192.168.255.255 | |||
| #FaviconURL http://pond1.gladstonefamily.net:8080/favicon.ico | |||
| </Stream> | |||
| # Redirect index.html to the appropriate site | |||
| <Redirect index.html> | |||
| URL http://www.libav.org/ | |||
| </Redirect> | |||
| @@ -1,276 +0,0 @@ | |||
| \input texinfo @c -*- texinfo -*- | |||
| @settitle avserver Documentation | |||
| @titlepage | |||
| @center @titlefont{avserver Documentation} | |||
| @end titlepage | |||
| @top | |||
| @contents | |||
| @chapter Synopsys | |||
| The generic syntax is: | |||
| @example | |||
| @c man begin SYNOPSIS | |||
| avserver [options] | |||
| @c man end | |||
| @end example | |||
| @chapter Description | |||
| @c man begin DESCRIPTION | |||
| WARNING: avserver is unmaintained, largely broken and in need of a | |||
| complete rewrite. It probably won't work for you. Use at your own | |||
| risk. | |||
| avserver 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 avserver.conf). | |||
| This documentation covers only the streaming aspects of avserver / | |||
| avconv. All questions about parameters for avconv, codec questions, | |||
| etc. are not covered here. Read @file{avconv.html} for more | |||
| information. | |||
| @section How does it work? | |||
| avserver receives prerecorded files or FFM streams from some avconv | |||
| instance as input, then streams them over RTP/RTSP/HTTP. | |||
| An avserver instance will listen on some port as specified in the | |||
| configuration file. You can launch one or more instances of avconv and | |||
| send one or more FFM streams to the port where avserver is expecting | |||
| to receive them. Alternately, you can make avserver launch such avconv | |||
| instances at startup. | |||
| Input streams are called feeds, and each one is specified by a <Feed> | |||
| section in the configuration file. | |||
| For each feed you can have different output streams in various | |||
| formats, each one specified by a <Stream> section in the configuration | |||
| file. | |||
| @section Status stream | |||
| avserver supports an HTTP interface which exposes the current status | |||
| of the server. | |||
| Simply point your browser to the address of the special status stream | |||
| specified in the configuration file. | |||
| For example if you have: | |||
| @example | |||
| <Stream status.html> | |||
| Format status | |||
| # Only allow local people to get the status | |||
| ACL allow localhost | |||
| ACL allow 192.168.0.0 192.168.255.255 | |||
| </Stream> | |||
| @end example | |||
| then the server will post a page with the status information when | |||
| the special stream @file{status.html} is requested. | |||
| @section What can this do? | |||
| When properly configured and running, you can capture video and audio in real | |||
| time from a suitable capture card, and stream it out over the Internet to | |||
| either Windows Media Player or RealAudio player (with some restrictions). | |||
| It can also stream from files, though that is currently broken. Very often, a | |||
| web server can be used to serve up the files just as well. | |||
| It can stream prerecorded video from .ffm files, though it is somewhat tricky | |||
| to make it work correctly. | |||
| @section What do I need? | |||
| I use Linux on a 900 MHz Duron with a cheapo Bt848 based TV capture card. I'm | |||
| using stock Linux 2.4.17 with the stock drivers. [Actually that isn't true, | |||
| I needed some special drivers for my motherboard-based sound card.] | |||
| I understand that FreeBSD systems work just fine as well. | |||
| @section How do I make it work? | |||
| First, build the kit. It *really* helps to have installed LAME first. Then when | |||
| you run the avserver ./configure, make sure that you have the | |||
| @code{--enable-libmp3lame} flag turned on. | |||
| LAME is important as it allows for streaming audio to Windows Media Player. | |||
| Don't ask why the other audio types do not work. | |||
| As a simple test, just run the following two command lines where INPUTFILE | |||
| is some file which you can decode with avconv: | |||
| @example | |||
| ./avserver -f doc/avserver.conf & | |||
| ./avconv -i INPUTFILE http://localhost:8090/feed1.ffm | |||
| @end example | |||
| At this point you should be able to go to your Windows machine and fire up | |||
| Windows Media Player (WMP). Go to Open URL and enter | |||
| @example | |||
| http://<linuxbox>:8090/test.asf | |||
| @end example | |||
| You should (after a short delay) see video and hear audio. | |||
| WARNING: trying to stream test1.mpg doesn't work with WMP as it tries to | |||
| transfer the entire file before starting to play. | |||
| The same is true of AVI files. | |||
| @section What happens next? | |||
| You should edit the avserver.conf file to suit your needs (in terms of | |||
| frame rates etc). Then install avserver and avconv, write a script to start | |||
| them up, and off you go. | |||
| @section Troubleshooting | |||
| @subsection I don't hear any audio, but video is fine. | |||
| Maybe you didn't install LAME, or got your ./configure statement wrong. Check | |||
| the avconv output to see if a line referring to MP3 is present. If not, then | |||
| your configuration was incorrect. If it is, then maybe your wiring is not | |||
| set up correctly. Maybe the sound card is not getting data from the right | |||
| input source. Maybe you have a really awful audio interface (like I do) | |||
| that only captures in stereo and also requires that one channel be flipped. | |||
| If you are one of these people, then export 'AUDIO_FLIP_LEFT=1' before | |||
| starting avconv. | |||
| @subsection The audio and video lose sync after a while. | |||
| Yes, they do. | |||
| @subsection After a long while, the video update rate goes way down in WMP. | |||
| Yes, it does. Who knows why? | |||
| @subsection WMP 6.4 behaves differently to WMP 7. | |||
| Yes, it does. Any thoughts on this would be gratefully received. These | |||
| differences extend to embedding WMP into a web page. [There are two | |||
| object IDs that you can use: The old one, which does not play well, and | |||
| the new one, which does (both tested on the same system). However, | |||
| I suspect that the new one is not available unless you have installed WMP 7]. | |||
| @section What else can it do? | |||
| You can replay video from .ffm files that was recorded earlier. | |||
| However, there are a number of caveats, including the fact that the | |||
| avserver parameters must match the original parameters used to record the | |||
| file. If they do not, then avserver deletes the file before recording into it. | |||
| (Now that I write this, it seems broken). | |||
| You can fiddle with many of the codec choices and encoding parameters, and | |||
| there are a bunch more parameters that you cannot control. Post a message | |||
| to the mailing list if there are some 'must have' parameters. Look in | |||
| avserver.conf for a list of the currently available controls. | |||
| It will automatically generate the ASX or RAM files that are often used | |||
| in browsers. These files are actually redirections to the underlying ASF | |||
| or RM file. The reason for this is that the browser often fetches the | |||
| entire file before starting up the external viewer. The redirection files | |||
| are very small and can be transferred quickly. [The stream itself is | |||
| often 'infinite' and thus the browser tries to download it and never | |||
| finishes.] | |||
| @section Tips | |||
| * When you connect to a live stream, most players (WMP, RA, etc) want to | |||
| buffer a certain number of seconds of material so that they can display the | |||
| signal continuously. However, avserver (by default) starts sending data | |||
| in realtime. This means that there is a pause of a few seconds while the | |||
| buffering is being done by the player. The good news is that this can be | |||
| cured by adding a '?buffer=5' to the end of the URL. This means that the | |||
| stream should start 5 seconds in the past -- and so the first 5 seconds | |||
| of the stream are sent as fast as the network will allow. It will then | |||
| slow down to real time. This noticeably improves the startup experience. | |||
| You can also add a 'Preroll 15' statement into the avserver.conf that will | |||
| add the 15 second prebuffering on all requests that do not otherwise | |||
| specify a time. In addition, avserver will skip frames until a key_frame | |||
| is found. This further reduces the startup delay by not transferring data | |||
| that will be discarded. | |||
| * You may want to adjust the MaxBandwidth in the avserver.conf to limit | |||
| the amount of bandwidth consumed by live streams. | |||
| @section Why does the ?buffer / Preroll stop working after a time? | |||
| It turns out that (on my machine at least) the number of frames successfully | |||
| grabbed is marginally less than the number that ought to be grabbed. This | |||
| means that the timestamp in the encoded data stream gets behind realtime. | |||
| This means that if you say 'Preroll 10', then when the stream gets 10 | |||
| or more seconds behind, there is no Preroll left. | |||
| Fixing this requires a change in the internals of how timestamps are | |||
| handled. | |||
| @section Does the @code{?date=} stuff work. | |||
| Yes (subject to the limitation outlined above). Also note that whenever you | |||
| start avserver, it deletes the ffm file (if any parameters have changed), | |||
| thus wiping out what you had recorded before. | |||
| The format of the @code{?date=xxxxxx} is fairly flexible. You should use one | |||
| of the following formats (the 'T' is literal): | |||
| @example | |||
| * YYYY-MM-DDTHH:MM:SS (localtime) | |||
| * YYYY-MM-DDTHH:MM:SSZ (UTC) | |||
| @end example | |||
| You can omit the YYYY-MM-DD, and then it refers to the current day. However | |||
| note that @samp{?date=16:00:00} refers to 16:00 on the current day -- this | |||
| may be in the future and so is unlikely to be useful. | |||
| You use this by adding the ?date= to the end of the URL for the stream. | |||
| For example: @samp{http://localhost:8080/test.asf?date=2002-07-26T23:05:00}. | |||
| @c man end | |||
| @chapter Options | |||
| @c man begin OPTIONS | |||
| @include avtools-common-opts.texi | |||
| @section Main options | |||
| @table @option | |||
| @item -f @var{configfile} | |||
| Use @file{configfile} instead of @file{/etc/avserver.conf}. | |||
| @item -n | |||
| Enable no-launch mode. This option disables all the Launch directives | |||
| within the various <Stream> sections. Since avserver will not launch | |||
| any avconv instances, you will have to launch them manually. | |||
| @item -d | |||
| Enable debug mode. This option increases log verbosity, directs log | |||
| messages to stdout. | |||
| @end table | |||
| @c man end | |||
| @ignore | |||
| @setfilename avserver | |||
| @settitle avserver video server | |||
| @c man begin SEEALSO | |||
| avconv(1), avplay(1), avprobe(1), the @file{avserver.conf} | |||
| example and the Libav HTML documentation | |||
| @c man end | |||
| @c man begin AUTHORS | |||
| The Libav developers | |||
| @c man end | |||
| @end ignore | |||
| @bye | |||
| @@ -235,7 +235,6 @@ library: | |||
| @item Electronic Arts cdata @tab @tab X | |||
| @item Electronic Arts Multimedia @tab @tab X | |||
| @tab Used in various EA games; files have extensions like WVE and UV2. | |||
| @item FFM (AVserver live feed) @tab X @tab X | |||
| @item Flash (SWF) @tab X @tab X | |||
| @item Flash 9 (AVM2) @tab X @tab X | |||
| @tab Only embedded audio is decoded. | |||
| @@ -107,8 +107,6 @@ OBJS-$(CONFIG_EA_CDATA_DEMUXER) += eacdata.o | |||
| OBJS-$(CONFIG_EA_DEMUXER) += electronicarts.o | |||
| OBJS-$(CONFIG_EAC3_DEMUXER) += ac3dec.o rawdec.o | |||
| OBJS-$(CONFIG_EAC3_MUXER) += rawenc.o | |||
| OBJS-$(CONFIG_FFM_DEMUXER) += ffmdec.o | |||
| OBJS-$(CONFIG_FFM_MUXER) += ffmenc.o | |||
| OBJS-$(CONFIG_FFMETADATA_DEMUXER) += ffmetadec.o | |||
| OBJS-$(CONFIG_FFMETADATA_MUXER) += ffmetaenc.o | |||
| OBJS-$(CONFIG_FILMSTRIP_DEMUXER) += filmstripdec.o | |||
| @@ -100,7 +100,6 @@ void av_register_all(void) | |||
| REGISTER_DEMUXER (EA_CDATA, ea_cdata); | |||
| REGISTER_MUXDEMUX(EAC3, eac3); | |||
| REGISTER_MUXER (F4V, f4v); | |||
| REGISTER_MUXDEMUX(FFM, ffm); | |||
| REGISTER_MUXDEMUX(FFMETADATA, ffmetadata); | |||
| REGISTER_MUXDEMUX(FILMSTRIP, filmstrip); | |||
| REGISTER_MUXDEMUX(FLAC, flac); | |||
| @@ -1,59 +0,0 @@ | |||
| /* | |||
| * FFM (avserver live feed) common header | |||
| * Copyright (c) 2001 Fabrice Bellard | |||
| * | |||
| * This file is part of Libav. | |||
| * | |||
| * Libav is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU Lesser General Public | |||
| * License as published by the Free Software Foundation; either | |||
| * version 2.1 of the License, or (at your option) any later version. | |||
| * | |||
| * Libav is distributed in the hope that it will be useful, | |||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
| * Lesser General Public License for more details. | |||
| * | |||
| * You should have received a copy of the GNU Lesser General Public | |||
| * License along with Libav; if not, write to the Free Software | |||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
| */ | |||
| #ifndef AVFORMAT_FFM_H | |||
| #define AVFORMAT_FFM_H | |||
| #include <stdint.h> | |||
| #include "avformat.h" | |||
| #include "avio.h" | |||
| /* The FFM file is made of blocks of fixed size */ | |||
| #define FFM_HEADER_SIZE 14 | |||
| #define FFM_PACKET_SIZE 4096 | |||
| #define PACKET_ID 0x666d | |||
| /* each packet contains frames (which can span several packets */ | |||
| #define FRAME_HEADER_SIZE 16 | |||
| #define FLAG_KEY_FRAME 0x01 | |||
| #define FLAG_DTS 0x02 | |||
| enum { | |||
| READ_HEADER, | |||
| READ_DATA, | |||
| }; | |||
| typedef struct FFMContext { | |||
| /* only reading mode */ | |||
| int64_t write_index, file_size; | |||
| int read_state; | |||
| uint8_t header[FRAME_HEADER_SIZE+4]; | |||
| /* read and write */ | |||
| int first_packet; /* true if first packet, needed to set the discontinuity tag */ | |||
| int packet_size; | |||
| int frame_offset; | |||
| int64_t dts; | |||
| uint8_t *packet_ptr, *packet_end; | |||
| uint8_t packet[FFM_PACKET_SIZE]; | |||
| } FFMContext; | |||
| #endif /* AVFORMAT_FFM_H */ | |||
| @@ -1,483 +0,0 @@ | |||
| /* | |||
| * FFM (avserver live feed) demuxer | |||
| * Copyright (c) 2001 Fabrice Bellard | |||
| * | |||
| * This file is part of Libav. | |||
| * | |||
| * Libav is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU Lesser General Public | |||
| * License as published by the Free Software Foundation; either | |||
| * version 2.1 of the License, or (at your option) any later version. | |||
| * | |||
| * Libav is distributed in the hope that it will be useful, | |||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
| * Lesser General Public License for more details. | |||
| * | |||
| * You should have received a copy of the GNU Lesser General Public | |||
| * License along with Libav; if not, write to the Free Software | |||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
| */ | |||
| #include <stdint.h> | |||
| #include "libavutil/intreadwrite.h" | |||
| #include "libavutil/intfloat.h" | |||
| #include "avformat.h" | |||
| #include "internal.h" | |||
| #include "ffm.h" | |||
| static int ffm_is_avail_data(AVFormatContext *s, int size) | |||
| { | |||
| FFMContext *ffm = s->priv_data; | |||
| int64_t pos, avail_size; | |||
| int len; | |||
| len = ffm->packet_end - ffm->packet_ptr; | |||
| if (size <= len) | |||
| return 1; | |||
| pos = avio_tell(s->pb); | |||
| if (!ffm->write_index) { | |||
| if (pos == ffm->file_size) | |||
| return AVERROR_EOF; | |||
| avail_size = ffm->file_size - pos; | |||
| } else { | |||
| if (pos == ffm->write_index) { | |||
| /* exactly at the end of stream */ | |||
| return AVERROR(EAGAIN); | |||
| } 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 AVERROR(EAGAIN); | |||
| } | |||
| static int ffm_resync(AVFormatContext *s, int state) | |||
| { | |||
| av_log(s, AV_LOG_ERROR, "resyncing\n"); | |||
| while (state != PACKET_ID) { | |||
| if (s->pb->eof_reached) { | |||
| av_log(s, AV_LOG_ERROR, "cannot find FFM syncword\n"); | |||
| return -1; | |||
| } | |||
| state = (state << 8) | avio_r8(s->pb); | |||
| } | |||
| return 0; | |||
| } | |||
| /* first is true if we read the frame header */ | |||
| static int ffm_read_data(AVFormatContext *s, | |||
| uint8_t *buf, int size, int header) | |||
| { | |||
| FFMContext *ffm = s->priv_data; | |||
| AVIOContext *pb = s->pb; | |||
| int len, fill_size, size1, frame_offset, id; | |||
| size1 = size; | |||
| while (size > 0) { | |||
| redo: | |||
| len = ffm->packet_end - ffm->packet_ptr; | |||
| if (len < 0) | |||
| return -1; | |||
| if (len > size) | |||
| len = size; | |||
| if (len == 0) { | |||
| if (avio_tell(pb) == ffm->file_size) | |||
| avio_seek(pb, ffm->packet_size, SEEK_SET); | |||
| retry_read: | |||
| id = avio_rb16(pb); /* PACKET_ID */ | |||
| if (id != PACKET_ID) | |||
| if (ffm_resync(s, id) < 0) | |||
| return -1; | |||
| fill_size = avio_rb16(pb); | |||
| ffm->dts = avio_rb64(pb); | |||
| frame_offset = avio_rb16(pb); | |||
| avio_read(pb, ffm->packet, ffm->packet_size - FFM_HEADER_SIZE); | |||
| ffm->packet_end = ffm->packet + (ffm->packet_size - FFM_HEADER_SIZE - fill_size); | |||
| if (ffm->packet_end < ffm->packet || frame_offset < 0) | |||
| return -1; | |||
| /* if first packet or resynchronization packet, we must | |||
| handle it specifically */ | |||
| if (ffm->first_packet || (frame_offset & 0x8000)) { | |||
| if (!frame_offset) { | |||
| /* This packet has no frame headers in it */ | |||
| if (avio_tell(pb) >= ffm->packet_size * 3) { | |||
| avio_seek(pb, -ffm->packet_size * 2, SEEK_CUR); | |||
| goto retry_read; | |||
| } | |||
| /* This is bad, we cannot find a valid frame header */ | |||
| return 0; | |||
| } | |||
| ffm->first_packet = 0; | |||
| if ((frame_offset & 0x7fff) < FFM_HEADER_SIZE) | |||
| return -1; | |||
| ffm->packet_ptr = ffm->packet + (frame_offset & 0x7fff) - FFM_HEADER_SIZE; | |||
| if (!header) | |||
| break; | |||
| } else { | |||
| ffm->packet_ptr = ffm->packet; | |||
| } | |||
| goto redo; | |||
| } | |||
| memcpy(buf, ffm->packet_ptr, len); | |||
| buf += len; | |||
| ffm->packet_ptr += len; | |||
| size -= len; | |||
| header = 0; | |||
| } | |||
| return size1 - size; | |||
| } | |||
| /* ensure that acutal seeking happens between FFM_PACKET_SIZE | |||
| and file_size - FFM_PACKET_SIZE */ | |||
| static int64_t ffm_seek1(AVFormatContext *s, int64_t pos1) | |||
| { | |||
| FFMContext *ffm = s->priv_data; | |||
| AVIOContext *pb = s->pb; | |||
| int64_t pos; | |||
| pos = FFMIN(pos1, ffm->file_size - FFM_PACKET_SIZE); | |||
| pos = FFMAX(pos, FFM_PACKET_SIZE); | |||
| av_dlog(s, "seek to %"PRIx64" -> %"PRIx64"\n", pos1, pos); | |||
| return avio_seek(pb, pos, SEEK_SET); | |||
| } | |||
| static int64_t get_dts(AVFormatContext *s, int64_t pos) | |||
| { | |||
| AVIOContext *pb = s->pb; | |||
| int64_t dts; | |||
| ffm_seek1(s, pos); | |||
| avio_skip(pb, 4); | |||
| dts = avio_rb64(pb); | |||
| av_dlog(s, "dts=%0.6f\n", dts / 1000000.0); | |||
| return dts; | |||
| } | |||
| static void adjust_write_index(AVFormatContext *s) | |||
| { | |||
| FFMContext *ffm = s->priv_data; | |||
| AVIOContext *pb = s->pb; | |||
| int64_t pts; | |||
| //int64_t orig_write_index = ffm->write_index; | |||
| int64_t pos_min, pos_max; | |||
| int64_t pts_start; | |||
| int64_t ptr = avio_tell(pb); | |||
| pos_min = 0; | |||
| pos_max = ffm->file_size - 2 * FFM_PACKET_SIZE; | |||
| pts_start = get_dts(s, pos_min); | |||
| pts = get_dts(s, pos_max); | |||
| if (pts - 100000 > pts_start) | |||
| goto end; | |||
| ffm->write_index = FFM_PACKET_SIZE; | |||
| pts_start = get_dts(s, pos_min); | |||
| pts = get_dts(s, pos_max); | |||
| if (pts - 100000 <= pts_start) { | |||
| while (1) { | |||
| int64_t newpos; | |||
| int64_t newpts; | |||
| newpos = ((pos_max + pos_min) / (2 * FFM_PACKET_SIZE)) * FFM_PACKET_SIZE; | |||
| if (newpos == pos_min) | |||
| break; | |||
| newpts = get_dts(s, newpos); | |||
| if (newpts - 100000 <= pts) { | |||
| pos_max = newpos; | |||
| pts = newpts; | |||
| } else { | |||
| pos_min = newpos; | |||
| } | |||
| } | |||
| ffm->write_index += pos_max; | |||
| } | |||
| end: | |||
| avio_seek(pb, ptr, SEEK_SET); | |||
| } | |||
| static int ffm_close(AVFormatContext *s) | |||
| { | |||
| int i; | |||
| for (i = 0; i < s->nb_streams; i++) | |||
| av_freep(&s->streams[i]->codec->rc_eq); | |||
| return 0; | |||
| } | |||
| static int ffm_read_header(AVFormatContext *s) | |||
| { | |||
| FFMContext *ffm = s->priv_data; | |||
| AVStream *st; | |||
| AVIOContext *pb = s->pb; | |||
| AVCodecContext *codec; | |||
| int i, nb_streams; | |||
| uint32_t tag; | |||
| /* header */ | |||
| tag = avio_rl32(pb); | |||
| if (tag != MKTAG('F', 'F', 'M', '1')) | |||
| goto fail; | |||
| ffm->packet_size = avio_rb32(pb); | |||
| if (ffm->packet_size != FFM_PACKET_SIZE) | |||
| goto fail; | |||
| ffm->write_index = avio_rb64(pb); | |||
| /* get also filesize */ | |||
| if (pb->seekable) { | |||
| ffm->file_size = avio_size(pb); | |||
| if (ffm->write_index) | |||
| adjust_write_index(s); | |||
| } else { | |||
| ffm->file_size = (UINT64_C(1) << 63) - 1; | |||
| } | |||
| nb_streams = avio_rb32(pb); | |||
| avio_rb32(pb); /* total bitrate */ | |||
| /* read each stream */ | |||
| for(i=0;i<nb_streams;i++) { | |||
| char rc_eq_buf[128]; | |||
| st = avformat_new_stream(s, NULL); | |||
| if (!st) | |||
| goto fail; | |||
| avpriv_set_pts_info(st, 64, 1, 1000000); | |||
| codec = st->codec; | |||
| /* generic info */ | |||
| codec->codec_id = avio_rb32(pb); | |||
| codec->codec_type = avio_r8(pb); /* codec_type */ | |||
| codec->bit_rate = avio_rb32(pb); | |||
| codec->flags = avio_rb32(pb); | |||
| codec->flags2 = avio_rb32(pb); | |||
| codec->debug = avio_rb32(pb); | |||
| /* specific info */ | |||
| switch(codec->codec_type) { | |||
| case AVMEDIA_TYPE_VIDEO: | |||
| codec->time_base.num = avio_rb32(pb); | |||
| codec->time_base.den = avio_rb32(pb); | |||
| codec->width = avio_rb16(pb); | |||
| codec->height = avio_rb16(pb); | |||
| codec->gop_size = avio_rb16(pb); | |||
| codec->pix_fmt = avio_rb32(pb); | |||
| codec->qmin = avio_r8(pb); | |||
| codec->qmax = avio_r8(pb); | |||
| codec->max_qdiff = avio_r8(pb); | |||
| codec->qcompress = avio_rb16(pb) / 10000.0; | |||
| codec->qblur = avio_rb16(pb) / 10000.0; | |||
| codec->bit_rate_tolerance = avio_rb32(pb); | |||
| avio_get_str(pb, INT_MAX, rc_eq_buf, sizeof(rc_eq_buf)); | |||
| codec->rc_eq = av_strdup(rc_eq_buf); | |||
| codec->rc_max_rate = avio_rb32(pb); | |||
| codec->rc_min_rate = avio_rb32(pb); | |||
| codec->rc_buffer_size = avio_rb32(pb); | |||
| codec->i_quant_factor = av_int2double(avio_rb64(pb)); | |||
| codec->b_quant_factor = av_int2double(avio_rb64(pb)); | |||
| codec->i_quant_offset = av_int2double(avio_rb64(pb)); | |||
| codec->b_quant_offset = av_int2double(avio_rb64(pb)); | |||
| codec->dct_algo = avio_rb32(pb); | |||
| codec->strict_std_compliance = avio_rb32(pb); | |||
| codec->max_b_frames = avio_rb32(pb); | |||
| codec->mpeg_quant = avio_rb32(pb); | |||
| codec->intra_dc_precision = avio_rb32(pb); | |||
| codec->me_method = avio_rb32(pb); | |||
| codec->mb_decision = avio_rb32(pb); | |||
| codec->nsse_weight = avio_rb32(pb); | |||
| codec->frame_skip_cmp = avio_rb32(pb); | |||
| codec->rc_buffer_aggressivity = av_int2double(avio_rb64(pb)); | |||
| codec->codec_tag = avio_rb32(pb); | |||
| codec->thread_count = avio_r8(pb); | |||
| codec->coder_type = avio_rb32(pb); | |||
| codec->me_cmp = avio_rb32(pb); | |||
| codec->me_subpel_quality = avio_rb32(pb); | |||
| codec->me_range = avio_rb32(pb); | |||
| codec->keyint_min = avio_rb32(pb); | |||
| codec->scenechange_threshold = avio_rb32(pb); | |||
| codec->b_frame_strategy = avio_rb32(pb); | |||
| codec->qcompress = av_int2double(avio_rb64(pb)); | |||
| codec->qblur = av_int2double(avio_rb64(pb)); | |||
| codec->max_qdiff = avio_rb32(pb); | |||
| codec->refs = avio_rb32(pb); | |||
| break; | |||
| case AVMEDIA_TYPE_AUDIO: | |||
| codec->sample_rate = avio_rb32(pb); | |||
| codec->channels = avio_rl16(pb); | |||
| codec->frame_size = avio_rl16(pb); | |||
| break; | |||
| default: | |||
| goto fail; | |||
| } | |||
| if (codec->flags & CODEC_FLAG_GLOBAL_HEADER) { | |||
| codec->extradata_size = avio_rb32(pb); | |||
| codec->extradata = av_malloc(codec->extradata_size); | |||
| if (!codec->extradata) | |||
| return AVERROR(ENOMEM); | |||
| avio_read(pb, codec->extradata, codec->extradata_size); | |||
| } | |||
| } | |||
| /* get until end of block reached */ | |||
| while ((avio_tell(pb) % ffm->packet_size) != 0) | |||
| avio_r8(pb); | |||
| /* init packet demux */ | |||
| ffm->packet_ptr = ffm->packet; | |||
| ffm->packet_end = ffm->packet; | |||
| ffm->frame_offset = 0; | |||
| ffm->dts = 0; | |||
| ffm->read_state = READ_HEADER; | |||
| ffm->first_packet = 1; | |||
| return 0; | |||
| fail: | |||
| ffm_close(s); | |||
| return -1; | |||
| } | |||
| /* return < 0 if eof */ | |||
| static int ffm_read_packet(AVFormatContext *s, AVPacket *pkt) | |||
| { | |||
| int size; | |||
| FFMContext *ffm = s->priv_data; | |||
| int duration, ret; | |||
| switch(ffm->read_state) { | |||
| case READ_HEADER: | |||
| if ((ret = ffm_is_avail_data(s, FRAME_HEADER_SIZE+4)) < 0) | |||
| return ret; | |||
| av_dlog(s, "pos=%08"PRIx64" spos=%"PRIx64", write_index=%"PRIx64" size=%"PRIx64"\n", | |||
| avio_tell(s->pb), s->pb->pos, ffm->write_index, ffm->file_size); | |||
| if (ffm_read_data(s, ffm->header, FRAME_HEADER_SIZE, 1) != | |||
| FRAME_HEADER_SIZE) | |||
| return -1; | |||
| if (ffm->header[1] & FLAG_DTS) | |||
| if (ffm_read_data(s, ffm->header+16, 4, 1) != 4) | |||
| return -1; | |||
| ffm->read_state = READ_DATA; | |||
| /* fall thru */ | |||
| case READ_DATA: | |||
| size = AV_RB24(ffm->header + 2); | |||
| if ((ret = ffm_is_avail_data(s, size)) < 0) | |||
| return ret; | |||
| duration = AV_RB24(ffm->header + 5); | |||
| av_new_packet(pkt, size); | |||
| pkt->stream_index = ffm->header[0]; | |||
| if ((unsigned)pkt->stream_index >= s->nb_streams) { | |||
| av_log(s, AV_LOG_ERROR, "invalid stream index %d\n", pkt->stream_index); | |||
| av_free_packet(pkt); | |||
| ffm->read_state = READ_HEADER; | |||
| return -1; | |||
| } | |||
| pkt->pos = avio_tell(s->pb); | |||
| if (ffm->header[1] & FLAG_KEY_FRAME) | |||
| pkt->flags |= AV_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 -1; | |||
| } | |||
| pkt->pts = AV_RB64(ffm->header+8); | |||
| if (ffm->header[1] & FLAG_DTS) | |||
| pkt->dts = pkt->pts - AV_RB32(ffm->header+16); | |||
| else | |||
| pkt->dts = pkt->pts; | |||
| pkt->duration = duration; | |||
| break; | |||
| } | |||
| return 0; | |||
| } | |||
| /* seek to a given time in the file. The file read pointer is | |||
| positioned at or before pts. XXX: the following code is quite | |||
| approximative */ | |||
| static int ffm_seek(AVFormatContext *s, int stream_index, int64_t wanted_pts, int flags) | |||
| { | |||
| FFMContext *ffm = s->priv_data; | |||
| int64_t pos_min, pos_max, pos; | |||
| int64_t pts_min, pts_max, pts; | |||
| double pos1; | |||
| av_dlog(s, "wanted_pts=%0.6f\n", wanted_pts / 1000000.0); | |||
| /* find the position using linear interpolation (better than | |||
| dichotomy in typical cases) */ | |||
| pos_min = FFM_PACKET_SIZE; | |||
| pos_max = ffm->file_size - FFM_PACKET_SIZE; | |||
| while (pos_min <= pos_max) { | |||
| pts_min = get_dts(s, pos_min); | |||
| pts_max = get_dts(s, pos_max); | |||
| /* linear interpolation */ | |||
| pos1 = (double)(pos_max - pos_min) * (double)(wanted_pts - pts_min) / | |||
| (double)(pts_max - pts_min); | |||
| pos = (((int64_t)pos1) / FFM_PACKET_SIZE) * FFM_PACKET_SIZE; | |||
| if (pos <= pos_min) | |||
| pos = pos_min; | |||
| else if (pos >= pos_max) | |||
| pos = pos_max; | |||
| pts = get_dts(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 = (flags & AVSEEK_FLAG_BACKWARD) ? pos_min : pos_max; | |||
| found: | |||
| if (ffm_seek1(s, pos) < 0) | |||
| return -1; | |||
| /* reset read state */ | |||
| ffm->read_state = READ_HEADER; | |||
| ffm->packet_ptr = ffm->packet; | |||
| ffm->packet_end = ffm->packet; | |||
| ffm->first_packet = 1; | |||
| return 0; | |||
| } | |||
| static int ffm_probe(AVProbeData *p) | |||
| { | |||
| if ( | |||
| p->buf[0] == 'F' && p->buf[1] == 'F' && p->buf[2] == 'M' && | |||
| p->buf[3] == '1') | |||
| return AVPROBE_SCORE_MAX + 1; | |||
| return 0; | |||
| } | |||
| AVInputFormat ff_ffm_demuxer = { | |||
| .name = "ffm", | |||
| .long_name = NULL_IF_CONFIG_SMALL("FFM (AVserver live feed)"), | |||
| .priv_data_size = sizeof(FFMContext), | |||
| .read_probe = ffm_probe, | |||
| .read_header = ffm_read_header, | |||
| .read_packet = ffm_read_packet, | |||
| .read_close = ffm_close, | |||
| .read_seek = ffm_seek, | |||
| }; | |||
| @@ -1,249 +0,0 @@ | |||
| /* | |||
| * FFM (avserver live feed) muxer | |||
| * Copyright (c) 2001 Fabrice Bellard | |||
| * | |||
| * This file is part of Libav. | |||
| * | |||
| * Libav is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU Lesser General Public | |||
| * License as published by the Free Software Foundation; either | |||
| * version 2.1 of the License, or (at your option) any later version. | |||
| * | |||
| * Libav is distributed in the hope that it will be useful, | |||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
| * Lesser General Public License for more details. | |||
| * | |||
| * You should have received a copy of the GNU Lesser General Public | |||
| * License along with Libav; if not, write to the Free Software | |||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
| */ | |||
| #include <assert.h> | |||
| #include "libavutil/intreadwrite.h" | |||
| #include "libavutil/intfloat.h" | |||
| #include "avformat.h" | |||
| #include "internal.h" | |||
| #include "ffm.h" | |||
| static void flush_packet(AVFormatContext *s) | |||
| { | |||
| FFMContext *ffm = s->priv_data; | |||
| int fill_size, h; | |||
| AVIOContext *pb = s->pb; | |||
| fill_size = ffm->packet_end - ffm->packet_ptr; | |||
| memset(ffm->packet_ptr, 0, fill_size); | |||
| assert(avio_tell(pb) % ffm->packet_size == 0); | |||
| /* put header */ | |||
| avio_wb16(pb, PACKET_ID); | |||
| avio_wb16(pb, fill_size); | |||
| avio_wb64(pb, ffm->dts); | |||
| h = ffm->frame_offset; | |||
| if (ffm->first_packet) | |||
| h |= 0x8000; | |||
| avio_wb16(pb, h); | |||
| avio_write(pb, ffm->packet, ffm->packet_end - ffm->packet); | |||
| avio_flush(pb); | |||
| /* prepare next packet */ | |||
| ffm->frame_offset = 0; /* no key frame */ | |||
| 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, | |||
| const uint8_t *buf, int size, | |||
| int64_t dts, int header) | |||
| { | |||
| FFMContext *ffm = s->priv_data; | |||
| int len; | |||
| if (header && ffm->frame_offset == 0) { | |||
| ffm->frame_offset = ffm->packet_ptr - ffm->packet + FFM_HEADER_SIZE; | |||
| ffm->dts = dts; | |||
| } | |||
| /* 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) | |||
| flush_packet(s); | |||
| } | |||
| } | |||
| static int ffm_write_header(AVFormatContext *s) | |||
| { | |||
| FFMContext *ffm = s->priv_data; | |||
| AVStream *st; | |||
| AVIOContext *pb = s->pb; | |||
| AVCodecContext *codec; | |||
| int bit_rate, i; | |||
| ffm->packet_size = FFM_PACKET_SIZE; | |||
| /* header */ | |||
| avio_wl32(pb, MKTAG('F', 'F', 'M', '1')); | |||
| avio_wb32(pb, ffm->packet_size); | |||
| avio_wb64(pb, 0); /* current write position */ | |||
| avio_wb32(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; | |||
| } | |||
| avio_wb32(pb, bit_rate); | |||
| /* list of streams */ | |||
| for(i=0;i<s->nb_streams;i++) { | |||
| st = s->streams[i]; | |||
| avpriv_set_pts_info(st, 64, 1, 1000000); | |||
| codec = st->codec; | |||
| /* generic info */ | |||
| avio_wb32(pb, codec->codec_id); | |||
| avio_w8(pb, codec->codec_type); | |||
| avio_wb32(pb, codec->bit_rate); | |||
| avio_wb32(pb, codec->flags); | |||
| avio_wb32(pb, codec->flags2); | |||
| avio_wb32(pb, codec->debug); | |||
| /* specific info */ | |||
| switch(codec->codec_type) { | |||
| case AVMEDIA_TYPE_VIDEO: | |||
| avio_wb32(pb, codec->time_base.num); | |||
| avio_wb32(pb, codec->time_base.den); | |||
| avio_wb16(pb, codec->width); | |||
| avio_wb16(pb, codec->height); | |||
| avio_wb16(pb, codec->gop_size); | |||
| avio_wb32(pb, codec->pix_fmt); | |||
| avio_w8(pb, codec->qmin); | |||
| avio_w8(pb, codec->qmax); | |||
| avio_w8(pb, codec->max_qdiff); | |||
| avio_wb16(pb, (int) (codec->qcompress * 10000.0)); | |||
| avio_wb16(pb, (int) (codec->qblur * 10000.0)); | |||
| avio_wb32(pb, codec->bit_rate_tolerance); | |||
| avio_put_str(pb, codec->rc_eq ? codec->rc_eq : "tex^qComp"); | |||
| avio_wb32(pb, codec->rc_max_rate); | |||
| avio_wb32(pb, codec->rc_min_rate); | |||
| avio_wb32(pb, codec->rc_buffer_size); | |||
| avio_wb64(pb, av_double2int(codec->i_quant_factor)); | |||
| avio_wb64(pb, av_double2int(codec->b_quant_factor)); | |||
| avio_wb64(pb, av_double2int(codec->i_quant_offset)); | |||
| avio_wb64(pb, av_double2int(codec->b_quant_offset)); | |||
| avio_wb32(pb, codec->dct_algo); | |||
| avio_wb32(pb, codec->strict_std_compliance); | |||
| avio_wb32(pb, codec->max_b_frames); | |||
| avio_wb32(pb, codec->mpeg_quant); | |||
| avio_wb32(pb, codec->intra_dc_precision); | |||
| avio_wb32(pb, codec->me_method); | |||
| avio_wb32(pb, codec->mb_decision); | |||
| avio_wb32(pb, codec->nsse_weight); | |||
| avio_wb32(pb, codec->frame_skip_cmp); | |||
| avio_wb64(pb, av_double2int(codec->rc_buffer_aggressivity)); | |||
| avio_wb32(pb, codec->codec_tag); | |||
| avio_w8(pb, codec->thread_count); | |||
| avio_wb32(pb, codec->coder_type); | |||
| avio_wb32(pb, codec->me_cmp); | |||
| avio_wb32(pb, codec->me_subpel_quality); | |||
| avio_wb32(pb, codec->me_range); | |||
| avio_wb32(pb, codec->keyint_min); | |||
| avio_wb32(pb, codec->scenechange_threshold); | |||
| avio_wb32(pb, codec->b_frame_strategy); | |||
| avio_wb64(pb, av_double2int(codec->qcompress)); | |||
| avio_wb64(pb, av_double2int(codec->qblur)); | |||
| avio_wb32(pb, codec->max_qdiff); | |||
| avio_wb32(pb, codec->refs); | |||
| break; | |||
| case AVMEDIA_TYPE_AUDIO: | |||
| avio_wb32(pb, codec->sample_rate); | |||
| avio_wl16(pb, codec->channels); | |||
| avio_wl16(pb, codec->frame_size); | |||
| break; | |||
| default: | |||
| return -1; | |||
| } | |||
| if (codec->flags & CODEC_FLAG_GLOBAL_HEADER) { | |||
| avio_wb32(pb, codec->extradata_size); | |||
| avio_write(pb, codec->extradata, codec->extradata_size); | |||
| } | |||
| } | |||
| /* flush until end of block reached */ | |||
| while ((avio_tell(pb) % ffm->packet_size) != 0) | |||
| avio_w8(pb, 0); | |||
| avio_flush(pb); | |||
| /* init packet mux */ | |||
| ffm->packet_ptr = ffm->packet; | |||
| ffm->packet_end = ffm->packet + ffm->packet_size - FFM_HEADER_SIZE; | |||
| assert(ffm->packet_end >= ffm->packet); | |||
| ffm->frame_offset = 0; | |||
| ffm->dts = 0; | |||
| ffm->first_packet = 1; | |||
| return 0; | |||
| } | |||
| static int ffm_write_packet(AVFormatContext *s, AVPacket *pkt) | |||
| { | |||
| int64_t dts; | |||
| uint8_t header[FRAME_HEADER_SIZE+4]; | |||
| int header_size = FRAME_HEADER_SIZE; | |||
| dts = pkt->dts; | |||
| /* packet size & key_frame */ | |||
| header[0] = pkt->stream_index; | |||
| header[1] = 0; | |||
| if (pkt->flags & AV_PKT_FLAG_KEY) | |||
| header[1] |= FLAG_KEY_FRAME; | |||
| AV_WB24(header+2, pkt->size); | |||
| AV_WB24(header+5, pkt->duration); | |||
| AV_WB64(header+8, pkt->pts); | |||
| if (pkt->pts != pkt->dts) { | |||
| header[1] |= FLAG_DTS; | |||
| AV_WB32(header+16, pkt->pts - pkt->dts); | |||
| header_size += 4; | |||
| } | |||
| ffm_write_data(s, header, header_size, dts, 1); | |||
| ffm_write_data(s, pkt->data, pkt->size, dts, 0); | |||
| return 0; | |||
| } | |||
| static int ffm_write_trailer(AVFormatContext *s) | |||
| { | |||
| FFMContext *ffm = s->priv_data; | |||
| /* flush packets */ | |||
| if (ffm->packet_ptr > ffm->packet) | |||
| flush_packet(s); | |||
| return 0; | |||
| } | |||
| AVOutputFormat ff_ffm_muxer = { | |||
| .name = "ffm", | |||
| .long_name = NULL_IF_CONFIG_SMALL("FFM (AVserver live feed)"), | |||
| .mime_type = "", | |||
| .extensions = "ffm", | |||
| .priv_data_size = sizeof(FFMContext), | |||
| .audio_codec = AV_CODEC_ID_MP2, | |||
| .video_codec = AV_CODEC_ID_MPEG1VIDEO, | |||
| .write_header = ffm_write_header, | |||
| .write_packet = ffm_write_packet, | |||
| .write_trailer = ffm_write_trailer, | |||
| .flags = AVFMT_TS_NEGATIVE, | |||
| }; | |||
| @@ -6,7 +6,6 @@ FATE_LAVF-$(call ENCDEC2, MPEG4, MP2, AVI) += avi | |||
| FATE_LAVF-$(call ENCDEC, BMP, IMAGE2) += bmp | |||
| FATE_LAVF-$(call ENCDEC, DPX, IMAGE2) += dpx | |||
| FATE_LAVF-$(call ENCDEC2, DVVIDEO, PCM_S16LE, AVI) += dv_fmt | |||
| FATE_LAVF-$(call ENCDEC2, MPEG1VIDEO, MP2, FFM) += ffm | |||
| FATE_LAVF-$(call ENCDEC, FLV, FLV) += flv_fmt | |||
| FATE_LAVF-$(call ENCDEC, GIF, IMAGE2) += gif | |||
| FATE_LAVF-$(call ENCDEC2, MPEG2VIDEO, PCM_S16LE, GXF) += gxf | |||
| @@ -151,7 +151,6 @@ FATE_SEEK_LAVF-$(call ENCDEC, PCM_S16BE, AU) += au | |||
| FATE_SEEK_LAVF-$(call ENCDEC2, MPEG4, MP2, AVI) += avi | |||
| FATE_SEEK_LAVF-$(call ENCDEC, BMP, IMAGE2) += bmp | |||
| FATE_SEEK_LAVF-$(call ENCDEC2, DVVIDEO, PCM_S16LE, AVI) += dv_fmt | |||
| FATE_SEEK_LAVF-$(call ENCDEC2, MPEG1VIDEO, MP2, FFM) += ffm | |||
| FATE_SEEK_LAVF-$(call ENCDEC, FLV, FLV) += flv_fmt | |||
| FATE_SEEK_LAVF-$(call ENCDEC, GIF, IMAGE2) += gif | |||
| FATE_SEEK_LAVF-$(call ENCDEC2, MPEG2VIDEO, PCM_S16LE, GXF) += gxf | |||
| @@ -188,7 +187,6 @@ fate-seek-lavf-au: SRC = lavf/lavf.au | |||
| fate-seek-lavf-avi: SRC = lavf/lavf.avi | |||
| fate-seek-lavf-bmp: SRC = images/bmp/%02d.bmp | |||
| fate-seek-lavf-dv_fmt: SRC = lavf/lavf.dv | |||
| fate-seek-lavf-ffm: SRC = lavf/lavf.ffm | |||
| fate-seek-lavf-flv_fmt: SRC = lavf/lavf.flv | |||
| fate-seek-lavf-gif: SRC = lavf/lavf.gif | |||
| fate-seek-lavf-gxf: SRC = lavf/lavf.gxf | |||
| @@ -78,10 +78,6 @@ if [ -n "$do_swf" ] ; then | |||
| do_lavf swf "" "-an" | |||
| fi | |||
| if [ -n "$do_ffm" ] ; then | |||
| do_lavf ffm "" "-ar 44100" | |||
| fi | |||
| if [ -n "$do_flv_fmt" ] ; then | |||
| do_lavf flv "" "-an" | |||
| fi | |||
| @@ -1,3 +0,0 @@ | |||
| f3f0c42283b75bc826f499f048085c27 *./tests/data/lavf/lavf.ffm | |||
| 376832 ./tests/data/lavf/lavf.ffm | |||
| ./tests/data/lavf/lavf.ffm CRC=0xdd24439e | |||
| @@ -1,53 +0,0 @@ | |||
| ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 8192 size: 24664 | |||
| ret: 0 st:-1 flags:0 ts:-1.000000 | |||
| ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 8192 size: 24664 | |||
| ret: 0 st:-1 flags:1 ts: 1.894167 | |||
| ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209 | |||
| ret: 0 st: 0 flags:0 ts: 0.788334 | |||
| ret: 0 st: 1 flags:1 dts: 0.772766 pts: 0.772766 pos: 315392 size: 209 | |||
| ret: 0 st: 0 flags:1 ts:-0.317499 | |||
| ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 8192 size: 24664 | |||
| ret: 0 st: 1 flags:0 ts: 2.576668 | |||
| ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209 | |||
| ret: 0 st: 1 flags:1 ts: 1.470835 | |||
| ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209 | |||
| ret: 0 st:-1 flags:0 ts: 0.365002 | |||
| ret: 0 st: 1 flags:1 dts: 0.328685 pts: 0.328685 pos: 155648 size: 209 | |||
| ret: 0 st:-1 flags:1 ts:-0.740831 | |||
| ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 8192 size: 24664 | |||
| ret: 0 st: 0 flags:0 ts: 2.153336 | |||
| ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209 | |||
| ret: 0 st: 0 flags:1 ts: 1.047503 | |||
| ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209 | |||
| ret: 0 st: 1 flags:0 ts:-0.058330 | |||
| ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 8192 size: 24664 | |||
| ret: 0 st: 1 flags:1 ts: 2.835837 | |||
| ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209 | |||
| ret: 0 st:-1 flags:0 ts: 1.730004 | |||
| ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209 | |||
| ret: 0 st:-1 flags:1 ts: 0.624171 | |||
| ret: 0 st: 1 flags:1 dts: 0.642154 pts: 0.642154 pos: 274432 size: 209 | |||
| ret: 0 st: 0 flags:0 ts:-0.481662 | |||
| ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 8192 size: 24664 | |||
| ret: 0 st: 0 flags:1 ts: 2.412505 | |||
| ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209 | |||
| ret: 0 st: 1 flags:0 ts: 1.306672 | |||
| ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209 | |||
| ret: 0 st: 1 flags:1 ts: 0.200839 | |||
| ret: 0 st: 1 flags:1 dts: 0.224195 pts: 0.224195 pos: 114688 size: 209 | |||
| ret: 0 st:-1 flags:0 ts:-0.904994 | |||
| ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 8192 size: 24664 | |||
| ret: 0 st:-1 flags:1 ts: 1.989173 | |||
| ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209 | |||
| ret: 0 st: 0 flags:0 ts: 0.883340 | |||
| ret: 0 st: 1 flags:1 dts: 0.877256 pts: 0.877256 pos: 339968 size: 209 | |||
| ret: 0 st: 0 flags:1 ts:-0.222493 | |||
| ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 8192 size: 24664 | |||
| ret: 0 st: 1 flags:0 ts: 2.671674 | |||
| ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209 | |||
| ret: 0 st: 1 flags:1 ts: 1.565841 | |||
| ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209 | |||
| ret: 0 st:-1 flags:0 ts: 0.460008 | |||
| ret: 0 st: 1 flags:1 dts: 0.459297 pts: 0.459297 pos: 204800 size: 209 | |||
| ret: 0 st:-1 flags:1 ts:-0.645825 | |||
| ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 8192 size: 24664 | |||