Compare commits
9 commits
Author | SHA1 | Date | |
---|---|---|---|
b32f4f47a5 | |||
57db5315f4 | |||
dece0922a6 | |||
a229b7b46b | |||
ff7447440c | |||
15bac63561 | |||
936dcc1f25 | |||
97e345d888 | |||
ee82c7082c |
6 changed files with 76 additions and 41 deletions
|
@ -1,7 +1,6 @@
|
||||||
# vod-rtmp
|
# vod-rtmp
|
||||||
|
|
||||||
## How to run
|
## How to run
|
||||||
|
|
||||||
1. `apt install docker.io docker-compose`
|
1. `apt install docker.io docker-compose`
|
||||||
2. `cp docker-compose.yml.dist docker-compose.yml` and edit the env variables
|
2. `cp docker-compose.yml.dist docker-compose.yml` and edit the env variables
|
||||||
3. `cd config/frontend && cp config.yml.dist config.yml` and edit the variables
|
3. `cd config/frontend && cp config.yml.dist config.yml` and edit the variables
|
||||||
|
@ -14,7 +13,7 @@
|
||||||
|
|
||||||
## Setup client
|
## Setup client
|
||||||
1. Encoder server = `rtmp://example:1935/live/` key = `stream?pass=supersecret`
|
1. Encoder server = `rtmp://example:1935/live/` key = `stream?pass=supersecret`
|
||||||
2. Open a browser and go to `https://example.com` to view your live stream via flv.js
|
2. Open a browser and go to `https://example.com` to view your live stream via hls.js
|
||||||
|
|
||||||
### Powered by
|
### Powered by
|
||||||
- https://github.com/tiangolo/nginx-rtmp-docker
|
- https://github.com/tiangolo/nginx-rtmp-docker
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# This is the title and Subtitle displayed on the Head of the Page
|
# This is the title and Subtitle displayed on the Head of the Page
|
||||||
pagetitle: vod-rtmp
|
pagetitle: vod-rtmp
|
||||||
subtitle: v1
|
subtitle: v0.70
|
||||||
|
|
||||||
# the footer
|
# the footer
|
||||||
footer: "© 2021 by the zom.bi Team"
|
footer: "© 2021 by the zom.bi Team"
|
||||||
|
|
|
@ -15,9 +15,13 @@ RUN mkdir -p /tmp/hls.js && \
|
||||||
cd /tmp/hls.js && \
|
cd /tmp/hls.js && \
|
||||||
wget -O hls.js.zip https://github.com/video-dev/hls.js/releases/download/v1.0.11/release.zip && \
|
wget -O hls.js.zip https://github.com/video-dev/hls.js/releases/download/v1.0.11/release.zip && \
|
||||||
unzip hls.js.zip && \
|
unzip hls.js.zip && \
|
||||||
|
cp dist/hls.js /code/static/hls.js && \
|
||||||
|
cp dist/hls.js.map /code/static/hls.js.map && \
|
||||||
cp dist/hls.min.js /code/static/hls.min.js && \
|
cp dist/hls.min.js /code/static/hls.min.js && \
|
||||||
cp dist/hls.min.js.map /code/static/hls.min.js.map
|
cp dist/hls.min.js.map /code/static/hls.min.js.map
|
||||||
|
|
||||||
|
RUN chmod 644 /code/static/hls.js
|
||||||
|
RUN chmod 644 /code/static/hls.js.map
|
||||||
RUN chmod 644 /code/static/hls.min.js
|
RUN chmod 644 /code/static/hls.min.js
|
||||||
RUN chmod 644 /code/static/hls.min.js.map
|
RUN chmod 644 /code/static/hls.min.js.map
|
||||||
|
|
||||||
|
|
|
@ -13,21 +13,48 @@ frontend = flask.Blueprint('frontend', __name__)
|
||||||
@frontend.route("/")
|
@frontend.route("/")
|
||||||
def start():
|
def start():
|
||||||
mainTemplate = '%s/main.html.j2' % zomstream.configuration['template_folder']
|
mainTemplate = '%s/main.html.j2' % zomstream.configuration['template_folder']
|
||||||
streamList = zomstream.getStreamNames()
|
itemList = zomstream.getStreamNames()
|
||||||
|
|
||||||
|
applications = []
|
||||||
|
appnames = []
|
||||||
|
for item in itemList:
|
||||||
|
if item[0] not in appnames:
|
||||||
|
appnames.append(item[0])
|
||||||
|
|
||||||
|
for appname in appnames:
|
||||||
|
streamnames = []
|
||||||
|
for item in itemList:
|
||||||
|
streamitem=item[1].split('_')[0]
|
||||||
|
if streamitem not in streamnames and item[0] == appname:
|
||||||
|
streamnames.append(streamitem)
|
||||||
|
|
||||||
|
streams = []
|
||||||
|
for streamname in streamnames:
|
||||||
|
substreams = []
|
||||||
|
for item in itemList:
|
||||||
|
if item[0] == appname:
|
||||||
|
if item[1].split('_')[0] == streamname:
|
||||||
|
substreams.append(item[1])
|
||||||
|
stream = [streamname, substreams]
|
||||||
|
streams.append(stream)
|
||||||
|
|
||||||
|
app = [appname, streams]
|
||||||
|
applications.append(app)
|
||||||
|
|
||||||
page = flask.render_template(
|
page = flask.render_template(
|
||||||
mainTemplate,
|
mainTemplate,
|
||||||
items=streamList,
|
applications=applications,
|
||||||
configuration=zomstream.configuration
|
configuration=zomstream.configuration
|
||||||
)
|
)
|
||||||
return page
|
return page
|
||||||
|
|
||||||
@frontend.route("/player/<appname>/<streamname>")
|
@frontend.route("/player/<appname>/<stream>")
|
||||||
def show_player(appname, streamname):
|
def show_player(appname, stream):
|
||||||
playerTemplate = '%s/player.html.j2' % zomstream.configuration['template_folder']
|
playerTemplate = '%s/player.html.j2' % zomstream.configuration['template_folder']
|
||||||
page = flask.render_template(
|
page = flask.render_template(
|
||||||
playerTemplate,
|
playerTemplate,
|
||||||
streamname=streamname,
|
|
||||||
appname=appname,
|
appname=appname,
|
||||||
|
stream=stream,
|
||||||
configuration=zomstream.configuration
|
configuration=zomstream.configuration
|
||||||
)
|
)
|
||||||
return page
|
return page
|
||||||
|
|
|
@ -11,35 +11,39 @@
|
||||||
<h2>{{ configuration["subtitle"] }}</h2>
|
<h2>{{ configuration["subtitle"] }}</h2>
|
||||||
</header>
|
</header>
|
||||||
<main>
|
<main>
|
||||||
{% if items == [] %}
|
{% if applications == [] %}
|
||||||
<p style="margin-top: 20px; margin-bottom: 150px;">
|
<p style="margin-top: 20px; margin-bottom: 150px;">
|
||||||
<span style="color: #888; font-size: 14pt;">There are currently no streams running</span>
|
<span style="color: #888; font-size: 14pt;">There are currently no streams running</span>
|
||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% for item in items %}
|
{% for application in applications %}
|
||||||
<article>
|
<h1>{{ application[0] }}</h1>
|
||||||
<h1>{{ item[1] }}</h1>
|
{% for stream in application[1] %}
|
||||||
<table>
|
<article>
|
||||||
<tbody>
|
<h2> stream {{ stream[0] }}</h2>
|
||||||
<tr>
|
<table>
|
||||||
<th>Protocol</th>
|
<tbody>
|
||||||
<th>URL</th>
|
<tr>
|
||||||
<th></th>
|
<th>Protocol</th>
|
||||||
</tr>
|
<th>URL</th>
|
||||||
<tr>
|
<th></th>
|
||||||
<td>RTMP url</td>
|
</tr>
|
||||||
<td><em class="url">rtmp://{{ configuration["rtmp_base"] }}/{{ item[0] }}/{{ item[1] }}</em></td>
|
{% for substream in stream[1] %}
|
||||||
<td class="btn"><a href="rtmp://{{ configuration['rtmp_base'] }}/{{ item[0] }}/{{ item[1] }}" class="btn btn-red">▶<br/>RTMP</a></td>
|
<tr>
|
||||||
</tr>
|
<td>RTMP {{ substream }}</td>
|
||||||
<tr>
|
<td><em class="url">rtmp://{{ configuration["rtmp_base"] }}/{{ application[0] }}/{{ substream }}</em></td>
|
||||||
<td>HLS m3u8</td>
|
<td class="btn"><a href="rtmp://{{ configuration['rtmp_base'] }}/{{ application[0] }}/{{ substream }}" class="btn btn-red">▶<br/>RTMP</a></td>
|
||||||
<td><em class="url">{{ configuration['web_proto'] }}://{{ configuration['base_url'] }}/hls/{{ item[1] }}/index.m3u8</em></td>
|
</tr>
|
||||||
<!-- <td class="btn"><a href="{{ configuration['web_proto'] }}://{{ configuration['base_url'] }}/player/{{ item[1] }}" class="btn btn-green">▶<br/>HLS.js</a></td> -->
|
{% endfor %}
|
||||||
<td class="btn"><a href="{{ url_for('frontend.show_player', streamname=item[1], appname=item[0]) }}" class="btn btn-green">▶<br/>HLS.js</a></td>
|
<tr>
|
||||||
</tr>
|
<td>HLS m3u8</td>
|
||||||
</tbody>
|
<td><em class="url">{{ configuration['web_proto'] }}://{{ configuration['base_url'] }}/hls/{{ stream[0] }}.m3u8</em></td>
|
||||||
</table>
|
<td class="btn"><a href="{{ url_for('frontend.show_player', appname=application[0], stream=stream[0]) }}" class="btn btn-green">▶<br/>HLS.js</a></td>
|
||||||
</article>
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</article>
|
||||||
|
{% endfor %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</main>
|
</main>
|
||||||
<footer>
|
<footer>
|
||||||
|
|
|
@ -2,27 +2,29 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0' />
|
<meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0' />
|
||||||
<title>{{ configuration['pagetitle'] }} - {{ appname }}: {{ streamname }}</title>
|
<title>{{ configuration['pagetitle'] }} - {{ appname }}: {{ stream }}</title>
|
||||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='style.default.css') }}">
|
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='style.default.css') }}">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<script src="{{ url_for('static', filename='hls.min.js') }}"></script>
|
||||||
|
|
||||||
<header>
|
<header>
|
||||||
<a href="{{ url_for('frontend.start') }}"><h1>{{ configuration["pagetitle"] }}</h1></a>
|
<a href="{{ url_for('frontend.start') }}"><h1>{{ configuration["pagetitle"] }}</h1></a>
|
||||||
<h2>{{ configuration["subtitle"] }}</h2>
|
<h2>{{ configuration["subtitle"] }}</h2>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div id="videocontainer">
|
<div id="videocontainer">
|
||||||
<h1>{{ streamname }}</h1>
|
<h1>{{ stream }}</h1>
|
||||||
<video id="player" controls>
|
<video height="1080" id="player" controls>
|
||||||
</video>
|
</video>
|
||||||
</div>
|
</div>
|
||||||
<script src="{{ url_for('static', filename='hls.min.js') }}"></script>
|
|
||||||
<script>
|
<script>
|
||||||
var video = document.getElementById('video');
|
var video = document.getElementById('player');
|
||||||
if (Hls.isSupported()) {
|
if (Hls.isSupported()) {
|
||||||
var hls = new Hls({
|
var hls = new Hls({
|
||||||
debug: true,
|
debug: true,
|
||||||
});
|
});
|
||||||
hls.loadSource("{{ configuration['web_proto'] }}://{{ configuration['base_url'] }}/hls/{{ streamname }}/index.m3u8");
|
hls.loadSource("{{ configuration['web_proto'] }}://{{ configuration['base_url'] }}/hls/{{ stream }}.m3u8");
|
||||||
hls.attachMedia(video);
|
hls.attachMedia(video);
|
||||||
hls.on(Hls.Events.MEDIA_ATTACHED, function () {
|
hls.on(Hls.Events.MEDIA_ATTACHED, function () {
|
||||||
video.muted = true;
|
video.muted = true;
|
||||||
|
@ -33,12 +35,11 @@
|
||||||
// When the browser has built-in HLS support (check using `canPlayType`), we can provide an HLS manifest (i.e. .m3u8 URL) directly to the video element throught the `src` property.
|
// When the browser has built-in HLS support (check using `canPlayType`), we can provide an HLS manifest (i.e. .m3u8 URL) directly to the video element throught the `src` property.
|
||||||
// This is using the built-in support of the plain video element, without using hls.js.
|
// This is using the built-in support of the plain video element, without using hls.js.
|
||||||
else if (video.canPlayType('application/vnd.apple.mpegurl')) {
|
else if (video.canPlayType('application/vnd.apple.mpegurl')) {
|
||||||
video.src = "{{ configuration['web_proto'] }}://{{ configuration['base_url'] }}/hls/{{ streamname }}/index.m3u8";
|
video.src = "{{ configuration['web_proto'] }}://{{ configuration['base_url'] }}/hls/{{ stream }}.m3u8";
|
||||||
video.addEventListener('canplay', function () {
|
video.addEventListener('canplay', function () {
|
||||||
video.play();
|
video.play();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
//url: '{{ configuration["web_proto"] }}://{{ configuration["base_url"] }}/flv?app={{ appname }}&stream={{ streamname }}'
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
Loading…
Add table
Reference in a new issue