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 | /avconv | ||||
| /avplay | /avplay | ||||
| /avprobe | /avprobe | ||||
| /avserver | |||||
| /config.* | /config.* | ||||
| /coverage.info | /coverage.info | ||||
| /version.h | /version.h | ||||
| @@ -27,6 +27,7 @@ version <next>: | |||||
| - libbs2b-based stereo-to-binaural audio filter | - libbs2b-based stereo-to-binaural audio filter | ||||
| - native Opus decoder | - native Opus decoder | ||||
| - display matrix export and rotation api | - display matrix export and rotation api | ||||
| - drop avserver, it was unmaintained for years and largely broken | |||||
| version 10: | version 10: | ||||
| @@ -63,12 +63,11 @@ COMPILE_HOSTC = $(call COMPILE,HOSTCC) | |||||
| AVPROGS-$(CONFIG_AVCONV) += avconv | AVPROGS-$(CONFIG_AVCONV) += avconv | ||||
| AVPROGS-$(CONFIG_AVPLAY) += avplay | AVPROGS-$(CONFIG_AVPLAY) += avplay | ||||
| AVPROGS-$(CONFIG_AVPROBE) += avprobe | AVPROGS-$(CONFIG_AVPROBE) += avprobe | ||||
| AVPROGS-$(CONFIG_AVSERVER) += avserver | |||||
| AVPROGS := $(AVPROGS-yes:%=%$(EXESUF)) | AVPROGS := $(AVPROGS-yes:%=%$(EXESUF)) | ||||
| PROGS += $(AVPROGS) | PROGS += $(AVPROGS) | ||||
| AVBASENAMES = avconv avplay avprobe avserver | |||||
| AVBASENAMES = avconv avplay avprobe | |||||
| ALLAVPROGS = $(AVBASENAMES:%=%$(EXESUF)) | ALLAVPROGS = $(AVBASENAMES:%=%$(EXESUF)) | ||||
| $(foreach prog,$(AVBASENAMES),$(eval OBJS-$(prog) += cmdutils.o)) | $(foreach prog,$(AVBASENAMES),$(eval OBJS-$(prog) += cmdutils.o)) | ||||
| @@ -108,7 +108,7 @@ Program options: | |||||
| --disable-avconv disable avconv build | --disable-avconv disable avconv build | ||||
| --disable-avplay disable avplay build | --disable-avplay disable avplay build | ||||
| --disable-avprobe disable avprobe build | --disable-avprobe disable avprobe build | ||||
| --disable-avserver disable avserver build | |||||
| --disable-avserver deprecated, does nothing | |||||
| Component options: | Component options: | ||||
| --disable-doc do not build documentation | --disable-doc do not build documentation | ||||
| @@ -1209,7 +1209,6 @@ PROGRAM_LIST=" | |||||
| avconv | avconv | ||||
| avplay | avplay | ||||
| avprobe | avprobe | ||||
| avserver | |||||
| " | " | ||||
| SUBSYSTEM_LIST=" | SUBSYSTEM_LIST=" | ||||
| @@ -2142,8 +2141,6 @@ avplay_deps="avcodec avformat avresample swscale sdl" | |||||
| avplay_libs='$sdl_libs' | avplay_libs='$sdl_libs' | ||||
| avplay_select="rdft" | avplay_select="rdft" | ||||
| avprobe_deps="avcodec avformat" | avprobe_deps="avcodec avformat" | ||||
| avserver_deps="avformat fork !shared" | |||||
| avserver_select="ffm_muxer rtp_protocol rtsp_demuxer" | |||||
| # documentation | # documentation | ||||
| pod2man_deps="doc" | pod2man_deps="doc" | ||||
| @@ -2380,6 +2377,10 @@ for opt do | |||||
| name=$(echo "${optval}" | sed "s/,/_${thing}|/g")_${thing} | name=$(echo "${optval}" | sed "s/,/_${thing}|/g")_${thing} | ||||
| $action $(filter "$name" $list) | $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-?*) | --enable-?*|--disable-?*) | ||||
| eval $(echo "$opt" | sed 's/--/action=/;s/-/ option=/;s/-/_/g') | eval $(echo "$opt" | sed 's/--/action=/;s/-/ option=/;s/-/_/g') | ||||
| if is_in $option $COMPONENT_LIST; then | if is_in $option $COMPONENT_LIST; then | ||||
| @@ -3539,7 +3540,6 @@ case $target_os in | |||||
| add_compat strtod.o strtod=avpriv_strtod | add_compat strtod.o strtod=avpriv_strtod | ||||
| network_extralibs='-lbsd' | network_extralibs='-lbsd' | ||||
| exeobjs=compat/plan9/main.o | exeobjs=compat/plan9/main.o | ||||
| disable avserver | |||||
| cp_f='cp' | cp_f='cp' | ||||
| ;; | ;; | ||||
| none) | 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 cdata @tab @tab X | ||||
| @item Electronic Arts Multimedia @tab @tab X | @item Electronic Arts Multimedia @tab @tab X | ||||
| @tab Used in various EA games; files have extensions like WVE and UV2. | @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 (SWF) @tab X @tab X | ||||
| @item Flash 9 (AVM2) @tab X @tab X | @item Flash 9 (AVM2) @tab X @tab X | ||||
| @tab Only embedded audio is decoded. | @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_EA_DEMUXER) += electronicarts.o | ||||
| OBJS-$(CONFIG_EAC3_DEMUXER) += ac3dec.o rawdec.o | OBJS-$(CONFIG_EAC3_DEMUXER) += ac3dec.o rawdec.o | ||||
| OBJS-$(CONFIG_EAC3_MUXER) += rawenc.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_DEMUXER) += ffmetadec.o | ||||
| OBJS-$(CONFIG_FFMETADATA_MUXER) += ffmetaenc.o | OBJS-$(CONFIG_FFMETADATA_MUXER) += ffmetaenc.o | ||||
| OBJS-$(CONFIG_FILMSTRIP_DEMUXER) += filmstripdec.o | OBJS-$(CONFIG_FILMSTRIP_DEMUXER) += filmstripdec.o | ||||
| @@ -100,7 +100,6 @@ void av_register_all(void) | |||||
| REGISTER_DEMUXER (EA_CDATA, ea_cdata); | REGISTER_DEMUXER (EA_CDATA, ea_cdata); | ||||
| REGISTER_MUXDEMUX(EAC3, eac3); | REGISTER_MUXDEMUX(EAC3, eac3); | ||||
| REGISTER_MUXER (F4V, f4v); | REGISTER_MUXER (F4V, f4v); | ||||
| REGISTER_MUXDEMUX(FFM, ffm); | |||||
| REGISTER_MUXDEMUX(FFMETADATA, ffmetadata); | REGISTER_MUXDEMUX(FFMETADATA, ffmetadata); | ||||
| REGISTER_MUXDEMUX(FILMSTRIP, filmstrip); | REGISTER_MUXDEMUX(FILMSTRIP, filmstrip); | ||||
| REGISTER_MUXDEMUX(FLAC, flac); | 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, BMP, IMAGE2) += bmp | ||||
| FATE_LAVF-$(call ENCDEC, DPX, IMAGE2) += dpx | FATE_LAVF-$(call ENCDEC, DPX, IMAGE2) += dpx | ||||
| FATE_LAVF-$(call ENCDEC2, DVVIDEO, PCM_S16LE, AVI) += dv_fmt | 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, FLV, FLV) += flv_fmt | ||||
| FATE_LAVF-$(call ENCDEC, GIF, IMAGE2) += gif | FATE_LAVF-$(call ENCDEC, GIF, IMAGE2) += gif | ||||
| FATE_LAVF-$(call ENCDEC2, MPEG2VIDEO, PCM_S16LE, GXF) += gxf | 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 ENCDEC2, MPEG4, MP2, AVI) += avi | ||||
| FATE_SEEK_LAVF-$(call ENCDEC, BMP, IMAGE2) += bmp | FATE_SEEK_LAVF-$(call ENCDEC, BMP, IMAGE2) += bmp | ||||
| FATE_SEEK_LAVF-$(call ENCDEC2, DVVIDEO, PCM_S16LE, AVI) += dv_fmt | 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, FLV, FLV) += flv_fmt | ||||
| FATE_SEEK_LAVF-$(call ENCDEC, GIF, IMAGE2) += gif | FATE_SEEK_LAVF-$(call ENCDEC, GIF, IMAGE2) += gif | ||||
| FATE_SEEK_LAVF-$(call ENCDEC2, MPEG2VIDEO, PCM_S16LE, GXF) += gxf | 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-avi: SRC = lavf/lavf.avi | ||||
| fate-seek-lavf-bmp: SRC = images/bmp/%02d.bmp | fate-seek-lavf-bmp: SRC = images/bmp/%02d.bmp | ||||
| fate-seek-lavf-dv_fmt: SRC = lavf/lavf.dv | 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-flv_fmt: SRC = lavf/lavf.flv | ||||
| fate-seek-lavf-gif: SRC = lavf/lavf.gif | fate-seek-lavf-gif: SRC = lavf/lavf.gif | ||||
| fate-seek-lavf-gxf: SRC = lavf/lavf.gxf | fate-seek-lavf-gxf: SRC = lavf/lavf.gxf | ||||
| @@ -78,10 +78,6 @@ if [ -n "$do_swf" ] ; then | |||||
| do_lavf swf "" "-an" | do_lavf swf "" "-an" | ||||
| fi | fi | ||||
| if [ -n "$do_ffm" ] ; then | |||||
| do_lavf ffm "" "-ar 44100" | |||||
| fi | |||||
| if [ -n "$do_flv_fmt" ] ; then | if [ -n "$do_flv_fmt" ] ; then | ||||
| do_lavf flv "" "-an" | do_lavf flv "" "-an" | ||||
| fi | 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 | |||||