Skip to content
This repository was archived by the owner on Mar 6, 2025. It is now read-only.

Commit dbf8d6f

Browse files
committed
increase default periscope to current recommendation. cleanup tests
720logo
1 parent 3f0fe50 commit dbf8d6f

14 files changed

+67
-69
lines changed

README.md

+31-38
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1+
# Python scripted livestreaming using FFmpeg
2+
13
[![DOI](https://zenodo.org/badge/91214767.svg)](https://zenodo.org/badge/latestdoi/91214767)
24
[![Actions Status](https://github.com/scivision/pylivestream/workflows/ci/badge.svg)](https://github.com/scivision/pylivestream/actions)
35

46
[![pypi versions](https://img.shields.io/pypi/pyversions/PyLivestream.svg)](https://pypi.python.org/pypi/PyLivestream)
57
[![Maintainability](https://api.codeclimate.com/v1/badges/b6557d474ec050e74629/maintainability)](https://codeclimate.com/github/scivision/ffmpeg-youtube-live/maintainability)
68
[![PyPi Download stats](http://pepy.tech/badge/pylivestream)](http://pepy.tech/project/pylivestream)
79

8-
# Python scripted livestreaming using FFmpeg
9-
1010
Streams to one or **multiple** streaming sites simultaneously, using pure object-oriented Python (no extra packages) and FFmpeg.
1111
Tested with `flake8`, `mypy` type checking and `pytest`.
1212
`visual_tests.py` is a quick check of several command line scripting scenarios on your laptop.
@@ -20,8 +20,7 @@ FFmpeg is used from Python `subprocess` to stream to sites including:
2020

2121
![PyLivestream diagram showing screen capture or webcam simultaneously livestreaming to multiple services.](./doc/logo.png)
2222

23-
24-
### PyLivestream benefits
23+
## PyLivestream benefits
2524

2625
* Python scripts compute good streaming parameters, and emit the command used to copy and paste if desired.
2726
* Works on any OS (Mac, Linux, Windows) and computing platform, including PC, Mac, and Raspberry Pi.
@@ -41,7 +40,6 @@ Why not do things without the command line, via linking libffmpeg, libgstreamer
4140
* the command-line approach does not require a compiler or OS-dependent libraries
4241
* once you get a setup working once, you don't even need Python anymore--just copy and paste the command line
4342

44-
4543
## Install
4644

4745
Requirements:
@@ -51,7 +49,6 @@ Requirements:
5149

5250
Python ≥ 3.6 is required due to extensive use of type hinting to ensure program quality.
5351

54-
5552
Latest release:
5653

5754
python -m pip install PyLivestream
@@ -102,38 +99,35 @@ Likewise, YouTube expects a file `~/youtube.key` with the hexadecimal stream key
10299

103100
### YouTube Live
104101

105-
1. [configure](https://www.youtube.com/live_dashboard) YouTube Live.
106-
2. Edit file `youtube.key` to have the YouTube hexadecimal stream key
107-
3. Run Python script and chosen input will stream on YouTube Live.
108-
102+
1. [configure](https://www.youtube.com/live_dashboard) YouTube Live.
103+
2. Edit file `youtube.key` to have the YouTube hexadecimal stream key
104+
3. Run Python script and chosen input will stream on YouTube Live.
109105

110106
ScreenshareLivestream youtube
111107

112108
### Facebook Live
113109

114110
Facebook Live requires FFmpeg >= 4.2 due to mandatory RTMPS
115111

116-
1. configure your Facebook Live stream
117-
2. Put stream ID from
112+
1. configure your Facebook Live stream
113+
2. Put stream ID from
118114
[<https://www.facebook.com/live/create>](https://www.facebook.com/live/create)
119115
into the file `facebook.key`
120-
3. Run Python script for Facebook with chosen input
121-
116+
3. Run Python script for Facebook with chosen input
122117

123118
ScreenshareLivestream facebook
124119

125120
### Periscope
126121

127-
1. create a new stream by EITHER:
122+
1. create a new stream by EITHER:
128123

129124
* from phone Periscope app, go to Profile -&gt; Settings -&gt; Periscope Producer and see your Stream Key.
130125
The "checking source" button will go to "preview stream" once you do step #2.
131126
* from computer web browser, go to
132127
[<https://www.periscope.tv/account/producer>](https://www.periscope.tv/account/producer)
133128
and Create New Source.
134-
2. Put the hexadecimal stream key into `periscope.key`
135-
3. Run Python script for Periscope with chosen input
136-
129+
2. Put the hexadecimal stream key into `periscope.key`
130+
3. Run Python script for Periscope with chosen input
137131

138132
ScreenshareLivestream periscope
139133

@@ -143,14 +137,12 @@ come back in, I can comment from my phone etc.
143137

144138
### Twitch
145139

146-
1. create stream from [Twitch Dashboard](http://www.twitch.tv/broadcast/dashboard). If you are not in the Northeast US, edit [pylivestream.ini](./pylivestream/pylivestream.ini) to have the [closest server](http://bashtech.net/twitch/ingest.php).
147-
2. put Twitch stream key into file `twitch.key`
148-
3. Run Python script for Twitch with chosen input
149-
140+
1. create stream from [Twitch Dashboard](http://www.twitch.tv/broadcast/dashboard). If you are not in the Northeast US, edit [pylivestream.ini](./pylivestream/pylivestream.ini) to have the [closest server](http://bashtech.net/twitch/ingest.php).
141+
2. put Twitch stream key into file `twitch.key`
142+
3. Run Python script for Twitch with chosen input
150143

151144
ScreenshareLivestream twitch
152145

153-
154146
## Usage
155147

156148
Due to the complexity of streaming and the non-specific error codes FFmpeg emits, the default behavior is that if FFmpeg detects one stream has failed, ALL streams will stop streaming and the program ends.
@@ -171,22 +163,23 @@ Config:
171163

172164
Find webcam name by:
173165

174-
* Windows:
166+
#### Windows
175167

176-
```sh
177-
ffmpeg -list_devices true -f dshow -i dummy
178-
```
179-
* MacOS:
168+
```sh
169+
ffmpeg -list_devices true -f dshow -i dummy
170+
```
180171

181-
```sh
182-
ffmpeg -f avfoundation -list_devices true -i ""
172+
#### MacOS
183173

184-
* Linux:
174+
```sh
175+
ffmpeg -f avfoundation -list_devices true -i ""
176+
```
185177

186-
```sh
187-
v4l2-ctl --list-devices
188-
```
178+
#### Linux
189179

180+
```sh
181+
v4l2-ctl --list-devices
182+
```
190183

191184
Stream to multiple sites, in this example Periscope and YouTube Live simultaneously:
192185

@@ -200,7 +193,6 @@ or from devlopment code:
200193
python Webcam.py youtube periscope
201194
```
202195

203-
204196
### Screen Share Livestream
205197

206198
Stream to multiple sites, in this example Periscope and YouTube Live simultaneously:
@@ -215,7 +207,6 @@ or from development code:
215207
python Screenshare.py youtube periscope
216208
```
217209

218-
219210
### Image + Audio Livestream
220211

221212
Microphone audio + static image is accomplished by
@@ -291,15 +282,19 @@ FileGlobLivestream path site -glob glob_pattern -image image
291282
* `-image` filename of image to use as stream background (REQUIRED for most websites)
292283

293284
Example: stream all .mp3 audio under `~/music` directory:
285+
294286
```sh
295287
FileGlobLivestream ~/music youtube -glob "*.mp3" -image mylogo.jpg
296288
```
297289

298290
Example: stream all .mp3 audio in `~/music` with an animated GIF or video clip repeating:
291+
299292
```sh
300293
FileGlobLivestream ~/music youtube -glob "*.mp3" -image myclip.avi
301294
```
295+
302296
or
297+
303298
```sh
304299
FileGlobLivestream ~/music youtube -glob "*.mp3" -image animated.gif
305300
```
@@ -312,7 +307,6 @@ This script saves your screen capture to a file on your disk:
312307

313308
## Utilities
314309

315-
316310
* `PyLivestream.get_framerate(vidfn)` gives the frames/sec of a video file.
317311
* `PyLivestream.get_resolution(vidfn)` gives the resolution (width x height) of video file.
318312

@@ -386,4 +380,3 @@ DirectShow didn't work for me on Windows 10, so I used gdigrab instead.
386380
* YouTube: YouTube Brand Resources
387381
* Facebook: Wikimedia Commons
388382
* [Periscope](periscope.tv/press)
389-

doc/logo720.png

276 KB
Loading

pylivestream/pylivestream.ini

+4-4
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ server: rtmp://a.rtmp.youtube.com/live2/
4747
key: ~/youtube.key
4848

4949
[periscope]
50-
video_kbps: 800
51-
audio_bps: 64k
50+
video_kbps: 2500
51+
audio_bps: 128k
5252
server: rtmp://va.pscp.tv:80/x/
5353
key: ~/periscope.key
5454

@@ -57,8 +57,8 @@ server: rtmps://live-api-s.facebook.com:443/rtmp/
5757
key: ~/facebook.key
5858

5959
[restream.io]
60-
audio_bps: 64k
61-
video_kbps: 800
60+
video_kbps: 2500
61+
audio_bps: 128k
6262
server: rtmp://us-east.restream.io/live/
6363
key: ~/restreamio.key
6464

pylivestream/stream.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@
1717
240: 300,
1818
360: 400,
1919
480: 500,
20-
540: 800,
21-
720: 1800,
20+
720: 2500,
2221
1080: 3000,
2322
1440: 6000,
2423
2160: 13000}

setup.cfg

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[metadata]
22
name = pylivestream
3-
version = 1.9.6
3+
version = 1.9.7
44
author = Michael Hirsch, Ph.D.
55
author_email = [email protected]
66
description = Livestream using FFmpeg to YouTube Live, Periscope, Facebook Live, Twitch, Mixer, and many more

tests/archive/test.ini

+2-2
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ server: rtmp://localhost
4949
server: rtmp://a.rtmp.youtube.com/live2/
5050

5151
[periscope]
52-
video_kbps: 800
53-
audio_bps: 64k
52+
video_kbps: 2500
53+
audio_bps: 128k
5454
server: rtmp://localhost
5555

5656

tests/conftest.py

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import pytest
2+
3+
4+
@pytest.fixture(scope="module")
5+
def periscope_kbps():
6+
return 2500

tests/no_audio.ini

+4-4
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ server: rtmp://a.rtmp.youtube.com/live2/
4848
key: ~/youtube.key
4949

5050
[periscope]
51-
video_kbps: 800
52-
audio_bps: 64k
51+
video_kbps: 2500
52+
audio_bps: 128k
5353
server: rtmp://va.pscp.tv:80/x/
5454
key: ~/periscope.key
5555

@@ -58,8 +58,8 @@ server: rtmps://live-api-s.facebook.com:443/rtmp/
5858
key: ~/facebook.key
5959

6060
[restream.io]
61-
audio_bps: 64k
62-
video_kbps: 800
61+
video_kbps: 2500
62+
audio_bps: 128k
6363
server: rtmp://us-east.restream.io/live/
6464
key: ~/restreamio.key
6565

tests/test_class.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,4 @@ def test_config_default(tmp_path):
5858

5959

6060
if __name__ == '__main__':
61-
pytest.main(['-x', __file__])
61+
pytest.main([__file__])

tests/test_disk.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ def test_props(site):
1111

1212

1313
if __name__ == '__main__':
14-
pytest.main(['-x', __file__])
14+
pytest.main([__file__])

tests/test_filein.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,22 @@
1818
CI = os.environ.get('CI', None) in ('true', 'True')
1919

2020

21-
def test_props():
21+
def test_props(periscope_kbps):
2222
S = pls.FileIn(inifn=None, websites=sites, infn=VIDFN, key='abc')
2323
for s in S.streams:
2424
assert '-re' in S.streams[s].cmd
2525
assert S.streams[s].fps == approx(24.)
2626

2727
if s == 'periscope':
28-
assert S.streams[s].video_kbps == 800
28+
assert S.streams[s].video_kbps == periscope_kbps
2929
else:
3030
if int(S.streams[s].res[1]) == 480:
3131
assert S.streams[s].video_kbps == 500
3232
elif int(S.streams[s].res[1]) == 720:
3333
assert S.streams[s].video_kbps == 1800
3434

3535

36-
def test_audio():
36+
def test_audio(periscope_kbps):
3737
flist = list(R.glob('*.ogg'))
3838

3939
S = pls.FileIn(inifn=None, websites=sites, infn=flist[0], image=LOGO, key='abc')
@@ -42,7 +42,7 @@ def test_audio():
4242
assert S.streams[s].fps is None
4343

4444
if s == 'periscope':
45-
assert S.streams[s].video_kbps == 800
45+
assert S.streams[s].video_kbps == periscope_kbps
4646
else:
4747
assert S.streams[s].video_kbps == 400
4848

@@ -70,4 +70,4 @@ def test_script():
7070

7171

7272
if __name__ == '__main__':
73-
pytest.main(['-x', __file__])
73+
pytest.main([__file__])

tests/test_microphone.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
WSL = 'Microsoft' in platform.uname().release
2323

2424

25-
def test_props():
25+
def test_props(periscope_kbps):
2626
S = pls.Microphone(inifn=None, websites=sites,
2727
image=LOGO, key='abc')
2828

@@ -32,12 +32,12 @@ def test_props():
3232
assert S.streams[s].res == [720, 540]
3333

3434
if s == 'periscope':
35-
assert S.streams[s].video_kbps == 800
35+
assert S.streams[s].video_kbps == periscope_kbps
3636
else:
3737
assert S.streams[s].video_kbps == 800
3838

3939

40-
def test_4Kbg():
40+
def test_4Kbg(periscope_kbps):
4141
S = pls.Microphone(inifn=None, websites=sites,
4242
image=IMG4K, key='abc')
4343

@@ -47,7 +47,7 @@ def test_4Kbg():
4747
assert S.streams[s].res == [3840, 2160]
4848

4949
if s == 'periscope':
50-
assert S.streams[s].video_kbps == 800
50+
assert S.streams[s].video_kbps == periscope_kbps
5151
else:
5252
assert S.streams[s].video_kbps == 4000
5353

@@ -68,4 +68,4 @@ def test_script():
6868

6969

7070
if __name__ == '__main__':
71-
pytest.main(['-x', __file__])
71+
pytest.main([__file__])

tests/test_screen.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@
1616
R = Path(__file__).resolve().parent
1717

1818

19-
def test_props():
19+
def test_props(periscope_kbps):
2020
S = pls.Screenshare(inifn=None, websites=sites, key='abc')
2121
for s in S.streams:
2222
assert '-re' not in S.streams[s].cmd
2323
assert S.streams[s].fps == approx(30.0)
2424

2525
if s == 'periscope':
26-
assert S.streams[s].video_kbps == 800
26+
assert S.streams[s].video_kbps == periscope_kbps
2727
else:
2828
assert S.streams[s].video_kbps == 500
2929

@@ -42,4 +42,4 @@ def test_script():
4242

4343

4444
if __name__ == '__main__':
45-
pytest.main(['-x', __file__])
45+
pytest.main([__file__])

0 commit comments

Comments
 (0)