~/bend-docscommunity

pull.bend relies on unsafe/foreign

raw source on the hub · import 0x2355f41b6f5561f50104a75ccca27cf7/pull.bend as Pull

Record a camera or a stream into a file.

bend pull.bend -o pull ./pull rtsp://user:pass@camera.example:554/stream out.ts 10 ./pull rtmp://192.168.0.20/live/cam out.flv 10

The file's name picks the form: .ts is MPEG-TS, with the audio and each frame's time; .flv (RTMP only) is the stream's tags as they come; anything else is the raw video (.h264, .h265). The last argument is how many seconds to record (10 when left out).

It is also the example of the library: open a session, take frames until the time is up, close it. It runs as a native binary only (the sockets are in net.c); rtsps:// and rtmps:// are the same under TLS, and STREAM_CAFILE names a PEM file to trust instead of the system's.

11 imports
import Base
import ./bytes.bend as B
import ./conn.bend as N
import ./opts.bend as E
import ./frame.bend as F
import ./rec.bend as W
import ./rtsp.bend as S
import ./rtsp_core.bend as C
import ./rtmp.bend as M
import ./rtmp_core.bend as K
import ./flv.bend as V

Types

type Stat source · line 33 · raw

Data

What was written: frames (or tags) and bytes; the last frame's time and what is added to a frame's time (a stream that comes back starts its times over); how many times the stream was lost and found; and whether the next tag is the first after one of those (RTMP, whose times start anywhere).

type Sink source · line 227 · raw

Data

Where an RTMP session's tags go: into an FLV as they are (first: the file's header is still to write), or, their frames taken out, into a recorder that is made at the first frame, once the stream is known.

type Sunk source · line 231 · raw

Data

Definitions

def Stat.add source · line 36 · raw

@st:Stat -> @bytes:U32 -> Stat

def Stat.place source · line 41 · raw

@st:Stat -> @f:0x2355f41b6f5561f50104a75ccca27cf7/frame.Frame -> Pair(Stat, 0x2355f41b6f5561f50104a75ccca27cf7/frame.Frame)

The frame at its place in the file, and its time noted.

def Stat.tag source · line 49 · raw

@st:Stat -> @t:0x2355f41b6f5561f50104a75ccca27cf7/rtmp_core.Tag -> Pair(Stat, 0x2355f41b6f5561f50104a75ccca27cf7/rtmp_core.Tag)

The tag at its place in the file: the first after the stream came back goes a tenth of a second after the last one written, and the rest keep their distance from it.

def Stat.found source · line 58 · raw

@st:Stat -> Stat

The stream was lost and found: what comes goes a tenth of a second after the last frame written.

def Stat.show source · line 62 · raw

@st:Stat -> @kind:String -> String

def Pull.error source · line 68 · raw

@e:0x2355f41b6f5561f50104a75ccca27cf7/opts.Err -> @st:Stat -> String

def Wrote source · line 76 · raw

Type

def Pull.save.end source · line 79 · raw

@m:Wrote -> File

def Pull.save source · line 84 · raw

@bs:List<&2, U32> -> @f:File -> IO(File)

Bytes to the file (nothing to do for none).

def Pull.end source · line 94 · raw

@-X:Type -> @x:X -> @f:File -> @stop:(@_:X -> IO(Unit)) -> @words:String -> IO(String)

The session x of any kind ended and the file closed, with these words.

def Pull.timed source · line 100 · raw

@up:Bool -> @-X:Type -> @x:X -> @f:File -> @st:Stat -> @kind:String -> @stop:(@_:X -> IO(Unit)) -> @again:(@_:X -> @_:File -> @_:Stat -> IO(String)) -> IO(String)

def Pull.write source · line 109 · raw

@-X:Type -> @+bs:List<&2, U32> -> @x:X -> @f:File -> @until:Nat -> @st:Stat -> @kind:String -> @stop:(@_:X -> IO(Unit)) -> @again:(@_:X -> @_:File -> @_:Stat -> IO(String)) -> IO(String)

Bytes written, then: stop if the time is up, else around again.

def Pull.rtsp.put source · line 121 · raw

@w:0x2355f41b6f5561f50104a75ccca27cf7/rec.Wrote -> @s:0x2355f41b6f5561f50104a75ccca27cf7/rtsp.Sess -> @f:File -> @until:Nat -> @st:Stat -> @kind:String -> @again:(@_:0x2355f41b6f5561f50104a75ccca27cf7/rtsp.Sess -> @_:File -> @_:0x2355f41b6f5561f50104a75ccca27cf7/rec.Rec -> @_:Stat -> IO(String)) -> IO(String)

def Pull.rtsp.placed source · line 127 · raw

@sf:Pair(Stat, 0x2355f41b6f5561f50104a75ccca27cf7/frame.Frame) -> @rec:0x2355f41b6f5561f50104a75ccca27cf7/rec.Rec -> @s:0x2355f41b6f5561f50104a75ccca27cf7/rtsp.Sess -> @f:File -> @until:Nat -> @kind:String -> @again:(@_:0x2355f41b6f5561f50104a75ccca27cf7/rtsp.Sess -> @_:File -> @_:0x2355f41b6f5561f50104a75ccca27cf7/rec.Rec -> @_:Stat -> IO(String)) -> IO(String)

def Pull.rtsp.found source · line 134 · raw

@r:0x2355f41b6f5561f50104a75ccca27cf7/rtsp.Opened -> @f:File -> @rec:0x2355f41b6f5561f50104a75ccca27cf7/rec.Rec -> @st:Stat -> @+kind:String -> @+e:0x2355f41b6f5561f50104a75ccca27cf7/opts.Err -> @again:(@_:0x2355f41b6f5561f50104a75ccca27cf7/rtsp.Sess -> @_:File -> @_:0x2355f41b6f5561f50104a75ccca27cf7/rec.Rec -> @_:Stat -> IO(String)) -> IO(String)

The session is open again, or it will not be: what was recorded is kept either way, and the file says so.

def Pull.rtsp.lost source · line 146 · raw

@retry:Bool -> @+e:0x2355f41b6f5561f50104a75ccca27cf7/opts.Err -> @f:File -> @rec:0x2355f41b6f5561f50104a75ccca27cf7/rec.Rec -> @+until:Nat -> @st:Stat -> @kind:String -> @o:0x2355f41b6f5561f50104a75ccca27cf7/opts.Opts -> @again:(@_:0x2355f41b6f5561f50104a75ccca27cf7/rtsp.Sess -> @_:File -> @_:0x2355f41b6f5561f50104a75ccca27cf7/rec.Rec -> @_:Stat -> IO(String)) -> IO(String)

The stream was lost. If it had been flowing and the error is not one that lasts, open it again and go on in the same file.

def Stat.any source · line 159 · raw

@st:Stat -> Bool

def Pull.rtsp.got source · line 163 · raw

@r:0x2355f41b6f5561f50104a75ccca27cf7/rtsp.Read -> @f:File -> @rec:0x2355f41b6f5561f50104a75ccca27cf7/rec.Rec -> @until:Nat -> @+st:Stat -> @kind:String -> @o:0x2355f41b6f5561f50104a75ccca27cf7/opts.Opts -> @again:(@_:0x2355f41b6f5561f50104a75ccca27cf7/rtsp.Sess -> @_:File -> @_:0x2355f41b6f5561f50104a75ccca27cf7/rec.Rec -> @_:Stat -> IO(String)) -> IO(String)

def Pull.rtsp.loop source · line 174 · raw

@fuel:Nat -> @s:0x2355f41b6f5561f50104a75ccca27cf7/rtsp.Sess -> @f:File -> @rec:0x2355f41b6f5561f50104a75ccca27cf7/rec.Rec -> @+until:Nat -> @st:Stat -> @+kind:String -> @+o:0x2355f41b6f5561f50104a75ccca27cf7/opts.Opts -> IO(String)

Frame after frame into the file, until the time is up.

def Pull.rtsp.file source · line 185 · raw

@r:Result<&1, &1, Pair(U32, String), File> -> @s:0x2355f41b6f5561f50104a75ccca27cf7/rtsp.Sess -> @rec:0x2355f41b6f5561f50104a75ccca27cf7/rec.Rec -> @until:Nat -> @kind:String -> @o:0x2355f41b6f5561f50104a75ccca27cf7/opts.Opts -> IO(String)

def Pull.kind source · line 197 · raw

@+i:0x2355f41b6f5561f50104a75ccca27cf7/frame.Info -> String

What is being recorded: "H264", or "H264+PCMA" with audio.

def Pull.rtsp.at source · line 201 · raw

@sa:Pair(0x2355f41b6f5561f50104a75ccca27cf7/rtsp.Sess, 0x2355f41b6f5561f50104a75ccca27cf7/frame.Info) -> @+out:String -> @ms:U32 -> @o:0x2355f41b6f5561f50104a75ccca27cf7/opts.Opts -> IO(String)

def Pull.rtsp.opened source · line 209 · raw

@r:0x2355f41b6f5561f50104a75ccca27cf7/rtsp.Opened -> @out:String -> @ms:U32 -> @o:0x2355f41b6f5561f50104a75ccca27cf7/opts.Opts -> IO(String)

def Pull.rtsp source · line 216 · raw

@+o:0x2355f41b6f5561f50104a75ccca27cf7/opts.Opts -> @out:String -> @ms:U32 -> IO(String)

def Sink.for source · line 234 · raw

@+path:String -> Sink

def Sink.rec source · line 238 · raw

@m:Maybe<&2, 0x2355f41b6f5561f50104a75ccca27cf7/rec.Rec> -> @path:String -> @info:0x2355f41b6f5561f50104a75ccca27cf7/frame.Info -> 0x2355f41b6f5561f50104a75ccca27cf7/rec.Rec

def Sink.wrote source · line 245 · raw

@w:0x2355f41b6f5561f50104a75ccca27cf7/rec.Wrote -> @v:0x2355f41b6f5561f50104a75ccca27cf7/flv.Flv -> @path:String -> Sunk

def Sink.frames source · line 249 · raw

@o:0x2355f41b6f5561f50104a75ccca27cf7/flv.Out -> @rec:Maybe<&2, 0x2355f41b6f5561f50104a75ccca27cf7/rec.Rec> -> @+path:String -> Sunk

def Sink.put source · line 256 · raw

@k:Sink -> @t:0x2355f41b6f5561f50104a75ccca27cf7/rtmp_core.Tag -> Sunk

def Pull.rtmp.put source · line 264 · raw

@u:Sunk -> @s:0x2355f41b6f5561f50104a75ccca27cf7/rtmp.Sess -> @f:File -> @until:Nat -> @st:Stat -> @again:(@_:0x2355f41b6f5561f50104a75ccca27cf7/rtmp.Sess -> @_:File -> @_:Sink -> @_:Stat -> IO(String)) -> IO(String)

def Pull.rtmp.placed source · line 270 · raw

@sf:Pair(Stat, 0x2355f41b6f5561f50104a75ccca27cf7/rtmp_core.Tag) -> @k:Sink -> @s:0x2355f41b6f5561f50104a75ccca27cf7/rtmp.Sess -> @f:File -> @until:Nat -> @again:(@_:0x2355f41b6f5561f50104a75ccca27cf7/rtmp.Sess -> @_:File -> @_:Sink -> @_:Stat -> IO(String)) -> IO(String)

def Pull.rtmp.found source · line 275 · raw

@r:0x2355f41b6f5561f50104a75ccca27cf7/rtmp.Opened -> @f:File -> @k:Sink -> @st:Stat -> @+e:0x2355f41b6f5561f50104a75ccca27cf7/opts.Err -> @again:(@_:0x2355f41b6f5561f50104a75ccca27cf7/rtmp.Sess -> @_:File -> @_:Sink -> @_:Stat -> IO(String)) -> IO(String)

def Pull.rtmp.lost source · line 288 · raw

@retry:Bool -> @+e:0x2355f41b6f5561f50104a75ccca27cf7/opts.Err -> @f:File -> @k:Sink -> @+until:Nat -> @st:Stat -> @o:0x2355f41b6f5561f50104a75ccca27cf7/opts.Opts -> @again:(@_:0x2355f41b6f5561f50104a75ccca27cf7/rtmp.Sess -> @_:File -> @_:Sink -> @_:Stat -> IO(String)) -> IO(String)

The stream was lost (or its publisher stopped). If it had been flowing and the error is not one that lasts, open it again and go on in the same file.

def Pull.rtmp.got source · line 300 · raw

@r:0x2355f41b6f5561f50104a75ccca27cf7/rtmp.Read -> @f:File -> @k:Sink -> @until:Nat -> @+st:Stat -> @o:0x2355f41b6f5561f50104a75ccca27cf7/opts.Opts -> @again:(@_:0x2355f41b6f5561f50104a75ccca27cf7/rtmp.Sess -> @_:File -> @_:Sink -> @_:Stat -> IO(String)) -> IO(String)

def Pull.rtmp.loop source · line 311 · raw

@fuel:Nat -> @s:0x2355f41b6f5561f50104a75ccca27cf7/rtmp.Sess -> @f:File -> @k:Sink -> @+until:Nat -> @st:Stat -> @+o:0x2355f41b6f5561f50104a75ccca27cf7/opts.Opts -> IO(String)

Tag after tag into the file, until the time is up.

def Pull.rtmp.file source · line 322 · raw

@r:Result<&1, &1, Pair(U32, String), File> -> @s:0x2355f41b6f5561f50104a75ccca27cf7/rtmp.Sess -> @k:Sink -> @until:Nat -> @o:0x2355f41b6f5561f50104a75ccca27cf7/opts.Opts -> IO(String)

def Pull.rtmp.opened source · line 333 · raw

@r:0x2355f41b6f5561f50104a75ccca27cf7/rtmp.Opened -> @+out:String -> @ms:U32 -> @o:0x2355f41b6f5561f50104a75ccca27cf7/opts.Opts -> IO(String)

def Pull.rtmp source · line 343 · raw

@+o:0x2355f41b6f5561f50104a75ccca27cf7/opts.Opts -> @out:String -> @ms:U32 -> IO(String)

def Pull.secs source · line 351 · raw

@args:List<&2, String> -> U32

def Pull.copy source · line 358 · raw

@xs:List<&1, String> -> List<&2, String>

def Pull.ca source · line 365 · raw

@r:Result<&1, &1, Pair(U32, String), String> -> String

def Pull.by source · line 372 · raw

@rtmp:Bool -> @o:0x2355f41b6f5561f50104a75ccca27cf7/opts.Opts -> @out:String -> @ms:U32 -> IO(String)

def Pull.run source · line 379 · raw

@args:List<&2, String> -> IO(Unit)

def main source · line 391 · raw

IO(Unit)