Capturing VOD from a file¶
WCS offers possibility to capture a media stream from an MP4 file located on the local disk of the server (Video on Demand, VOD). The received stream can be played, republished, managed just like any stream on the WCS server. First of all, this option is intended to play previously recorded broadcasts in a browsers or a mobile application on the client side.
Overview¶
To capture VOD from a file, specify a link to the vod file as a stream name when calling the session.createStream()
function, as follows:
where sample.mp4
is the name of the file that should be located in /usr/local/FlashphonerWebCallServer/media
folder. Since build 5.2.687, a custom folder can specified with the following parameter in flashphoner.properties file
If a file with such name does not exist, the server returns the STREAM_STATUS.FAILED
event, where the info
field has the reason: File not found
.
A stream created this way can be displayed to one user (personal VOD). Second viewer cannot subscribe to personal VOD stream, such stream cannot be transcoded, added to mixer or played by HLS.
If a full-featured online-broadcast is required, provide the link to a file as follows:
Multiple user can connect to such a stream simultaneously. VOD live stream can be transcoded, added to mixer or played by HLS.
Supported formats and codecs¶
- Container: MP4
- Video: H.264
- Audio: AAC
Operation flowchart¶
- The browser connects to the server via WebSocket and sends the
publishStream
command. - The browser captures the microphone and the camera and sends the WebRTC stream as H.264 + AAC to the server, enabling recording with the parameter
record: true
. - The WCS server records the stream to a file.
- The browser stops publishing.
- The second browser establishes a connection via WebSocket, creates a stream, specifies the file name, and sends the
playStream
command. - The second browser receives the WebRTC stream and plays this stream on the page.
Quick manual on testing¶
-
For the test we use the Player web application to play the file.
-
Upload the file to the
/usr/local/FlashphonerWebCallServer/media/
directory. -
Open the Player web application and enter the name of the file in the
Stream
field:
-
Click
Start
. The file starts playing:
-
Click Stop to stop the playback.
-
Delete the file from
/usr/local/FlashphonerWebCallServer/media/
-
Click
Start
. You should see theFAILED
status and theFile not found
message:
Call flow¶
Below is the call flow when using:
- the Stream Recording example to publish the stream and record the file
- recording.html
-
the Player example to play the VOD stream
- player.html
- player.js
-
Establishing a connection to the server to publish and record the stream
Flashphoner.createSession()
code
-
Receiving from the server an event confirming successful connection
SESSION_STATUS.ESTABLISHED
code
-
Publishing the stream with recording enabled
Stream.publish()
code -
Receiving from the server an event confirming successful publishing of the stream
STREAM_STATUS.PUBLISHING
code
session.createStream({ name: streamName, display: localVideo, record: true, receiveVideo: false, receiveAudio: false }).on(STREAM_STATUS.PUBLISHING, function(stream) { setStatus(stream.status()); onStarted(stream); }).on(STREAM_STATUS.UNPUBLISHED, function(stream) { ... }).on(STREAM_STATUS.FAILED, function(stream) { ... }).publish();
-
Sending audio and video stream via WebRTC
-
Stopping publishing the stream
Stream.stop()
code
-
Receiving from the server an event confirming unpublishing of the stream
STREAM_STATUS.UNPUBLISHED
code
session.createStream({ name: streamName, display: localVideo, record: true, receiveVideo: false, receiveAudio: false }).on(STREAM_STATUS.PUBLISHING, function(stream) { ... }).on(STREAM_STATUS.UNPUBLISHED, function(stream) { setStatus(stream.status()); showDownloadLink(stream.getRecordInfo()); onStopped(); }).on(STREAM_STATUS.FAILED, function(stream) { ... }).publish();
-
Establishing a connection to the server to play the stream
Flashphoner.createSession()
code -
Receiving from the server an event confirming successful connection
SESSION_STATUS.ESTABLISHED
code
-
Playing the stream
Stream.play()
code
if (Flashphoner.getMediaProviders()[0] === "MSE" && mseCutByIFrameOnly) { options.mediaConnectionConstraints = { cutByIFrameOnly: mseCutByIFrameOnly } } if (resolution_for_wsplayer) { options.playWidth = resolution_for_wsplayer.playWidth; options.playHeight = resolution_for_wsplayer.playHeight; } else if (resolution) { options.playWidth = resolution.split("x")[0]; options.playHeight = resolution.split("x")[1]; } stream = session.createStream(options).on(STREAM_STATUS.PENDING, function(stream) { ... }); stream.play();
-
Receiving from the server an event confirming successful playing of the stream
STREAM_STATUS.PLAYING
code
stream = session.createStream(options).on(STREAM_STATUS.PENDING, function(stream) { ... }).on(STREAM_STATUS.PLAYING, function(stream) { $("#preloader").show(); setStatus(stream.status()); onStarted(stream); }).on(STREAM_STATUS.STOPPED, function() { ... }).on(STREAM_STATUS.FAILED, function(stream) { ... }).on(STREAM_STATUS.NOT_ENOUGH_BANDWIDTH, function(stream){ ... }); stream.play();
-
Receiving of the audio-video stream via Websocket and playing it via WebRTC
-
Stopping publishing the stream
Stream.stop()
code
-
Receiving from the server an event confirming successful stopping of the playback of the stream
STREAM_STATUS.STOPPED code
stream = session.createStream(options).on(STREAM_STATUS.PENDING, function(stream) { ... }).on(STREAM_STATUS.PLAYING, function(stream) { ... }).on(STREAM_STATUS.STOPPED, function() { setStatus(STREAM_STATUS.STOPPED); onStopped(); }).on(STREAM_STATUS.FAILED, function(stream) { ... }).on(STREAM_STATUS.NOT_ENOUGH_BANDWIDTH, function(stream){ ... }); stream.play();
VOD loop¶
VOD live translation supports VOD loop: after end of file, capturing starts from file begin. This feature is enabled with the following parameter in flashphoner.properties file
VOD capturing from AWS S3 or from other S3 compatible storage¶
VOD stream can be captured from file placed to AWS S3 storage. Comparing with VOD capture from local disk, file from external storage is downloaded and captured sequentally.
To capture VOD from AWS S3 file, specify a link to the VOD file as a stream name when calling the session.createStream()
function, as follows:
where
bucket
is S3 bucket namesample.mp4
is file name
Since build 5.2.939 it is possible to set the full file URL in S3 storage, this allows to capture VOD from other S3 compatible storages (Digital Ocean, Selectel etc)
Digital Ocean Spaces URL example
Selectel URL example
Operation flowchart¶
- Browser requests VOD capture from AWS file
- WCS server sends request to AWS
- File is downloaded to WCS server
- WebRTC stream from file is sending to browser for playback
Set up¶
S3 credentials configuration¶
AWS¶
To download files from AWS S3 bucket, S3 credentials must be set in flashphoner.properties file
Where
zone
- AWS region where bucket is placedlogin
- Access Key IDhash
- Secret Accesss Key
S3 credentials setting example:
Digital Ocean Spaces¶
To download files from DO Spaces set the credentials as
Where
ams3
- digitaloceanspaces.com subdomainaccess_key
- storage access keysecret
- storage access secret code
Selectel¶
To download files from Selectel S3 set the credentials as
Where
ru-1a
- storage regionlogin
- user namepassword
- password
Capturing VOD stream from file while it is downloading¶
To capture stream from file while it is downloading, the following parameter should be set
If channel bandwidth between WCS and S3 storage is low, or this channel is not stable enough, file bufferization may be enabled. The buffer size is set in milliseconds with the following parameter
In this case, buffer size is 10 seconds.
File format requirements¶
Header section (moov) should always be before data section (mdat). File structure should be like this:
Atom ftyp @ 0 of size: 32, ends @ 32
Atom moov @ 32 of size: 357961, ends @ 357993
...
Atom free @ 357993 of size: 8, ends @ 358001
Atom mdat @ 358001 of size: 212741950, ends @ 213099951
File structure can be checked with AtomicParsley utility
If the file structure does not match the requiremets, this file will not be played. Wrong file structure can be fixed if necessary with ffmpeg without reencoding
File name requirements¶
Official AWS S3 documentation does not recommend to use spaces along another special characters, but does not prohibits them. If the file name contains spaces, they should be replaced by %20
, for example
VOD capture management with REST API¶
REST query should be HTTP/HTTPS POST request as:
- HTTP:
http://test.flashphoner.com:8081/rest-api/vod/startup
- HTTPS:
https://test.flashphoner.com:8444/rest-api/vod/startup
Where:
test.flashphoner.com
- WCS server address8081
- standard REST / HTTP port8444
- standard HTTPS portrest-api
- mandatory part of URL/vod/startup
- REST method used
REST queries and responses¶
/vod/startup¶
Capture VOD stream from file
Request example¶
POST /rest-api/vod/startup HTTP/1.1
Host: localhost:8081
Content-Type: application/json
{
"uri":"vod-live://sample.mp4",
"localStreamName": "test"
}
Response example¶
Return codes¶
Code | Reason |
---|---|
200 | OK |
404 | Not found |
409 | Conflict |
500 | Internal error |
/vod/find¶
Find VOD streams by criteria
Request example¶
POST /rest-api/vod/find HTTP/1.1
Host: localhost:8081
Content-Type: application/json
{
"localStreamName": "test"
}
Response example¶
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Type: application/json
[
{
"localMediaSessionId": "29ec3236-1093-42bb-88d6-d4ac37af3ac0",
"localStreamName": "test",
"uri": "vod-live://sample.mp4",
"status": "PROCESSED_LOCAL",
"hasAudio": true,
"hasVideo": true,
"record": false,
"loop": false
}
]
Return codes¶
Code | Reason |
---|---|
200 | OK |
404 | Not found |
/vod/find_all¶
Find all VOD streams
Request example¶
Response example¶
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Type: application/json
[
{
"localMediaSessionId": "29ec3236-1093-42bb-88d6-d4ac37af3ac0",
"localStreamName": "test",
"uri": "vod-live://sample.mp4",
"status": "PROCESSED_LOCAL",
"hasAudio": true,
"hasVideo": true,
"record": false,
"loop": false
}
]
Return codes¶
Code | Reason |
---|---|
200 | OK |
404 | Not found |
/vod/terminate¶
Stop VOD stream
Request example¶
POST /rest-api/vod/find_all HTTP/1.1
Host: localhost:8081
Content-Type: application/json
{
"uri":"vod://sample.mp4",
"localStreamName": "test"
}
Response example¶
Return codes¶
Code | Reason |
---|---|
200 | OK |
404 | Not found |
Parameters¶
Parameter | Description | Example |
---|---|---|
uri | File name to capture |
vod://sample.mp4
|
localStreamName | Stream name |
test
|
status | Stream status |
PROCESSED_LOCAL
|
localMediaSessionId | Mediasession Id |
29ec3236-1093-42bb-88d6-d4ac37af3ac0
|
hasAudio | Stream has audio |
true
|
hasVideo | Stream has video |
true
|
record | Stream is recording |
false
|
loop | Stream is looping |
false
|
VOD looping on demand¶
Since build 5.2.1528 it is possible to enable VOD looping while creating VOD live translation via REST API
By default, if loop
parameter is not set, vod_live_loop
is applied. If the parameter is set, its value is applied as follows
true
- file will be loopedfalse
- file will be played once, then VOD live translation will stop
The loop parameter has a precedence over vod_live_loop
value.
Known limits¶
/vod/startup
query can be used for VOD live translations creation only. However, /vod/find
, /vod/find_all
and /vod/terminate
queries can be applied both to VOD and VOD live translations.
VOD stream publishing timeout after all subscribers gone off¶
By default, VOD stream stays published on server during 30 seconds after last subscriber gone off, if file duration exceeds this interval. This timeout can be changed with the following parameter
In this case, VOD stream stays published during 60 seconds.
Known issues¶
1. AAC frames of type 0 are not supported by ffmpeg decoder and will be ignored while stream pulled playback¶
Symptoms
Warnings in the client log:
2. Files with B-frames can be played unsmoothly, with artifacts and freezes¶
Symptoms
Periodic freezes and artifacts while playing VOD file, warnings in the client log
Solution
Reencode this file to exclude B-frames, for example
3. VOD playback may require a lot of memory¶
When VOD is captured from a long-duration file, or a number of VOD streams are captured simultaneously, server process can terminate with Out of memory
Symptoms
Server process terminates with Map failed
in server log and in error*.log
19:30:53,277 ERROR DefaultMp4SampleList - Thread-34 java.io.IOException: Map failed
at sun.nio.ch.FileChannelImpl.map(FileChannelImpl.java:940)
at com.googlecode.mp4parser.FileDataSourceImpl.map(FileDataSourceImpl.java:62)
at com.googlecode.mp4parser.BasicContainer.getByteBuffer(BasicContainer.java:223)
at com.googlecode.mp4parser.authoring.samples.DefaultMp4SampleList$SampleImpl.asByteBuffer(DefaultMp4SampleList.java:204)
at com.flashphoner.media.F.A.A.A$1.A(Unknown Source)
at com.flashphoner.media.M.B.C.D(Unknown Source)
at com.flashphoner.server.C.A.B.A(Unknown Source)
at com.flashphoner.server.C.A.B.C(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.OutOfMemoryError: Map failed
at sun.nio.ch.FileChannelImpl.map0(Native Method)
at sun.nio.ch.FileChannelImpl.map(FileChannelImpl.java:937)
... 8 more