mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-01-08 13:22:53 +02:00
Remove avserver.
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.
This commit is contained in:
parent
f2ce63246f
commit
894682a973
1
.gitignore
vendored
1
.gitignore
vendored
@ -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:
|
||||
|
3
Makefile
3
Makefile
@ -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))
|
||||
|
4685
avserver.c
4685
avserver.c
File diff suppressed because it is too large
Load Diff
10
configure
vendored
10
configure
vendored
@ -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
|
Loading…
Reference in New Issue
Block a user