mirror of https://github.com/FFmpeg/FFmpeg.git
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.pull/76/merge
parent
f2ce63246f
commit
894682a973
18 changed files with 7 additions and 6199 deletions
File diff suppressed because it is too large
Load Diff
@ -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 |
|
@ -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, |
|
||||||
}; |
|
@ -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