Skip to content

Commit

Permalink
increase default periscope to current recommendation. cleanup tests
Browse files Browse the repository at this point in the history
720logo
  • Loading branch information
scivision committed Jan 2, 2020
1 parent 3f0fe50 commit dbf8d6f
Show file tree
Hide file tree
Showing 14 changed files with 67 additions and 69 deletions.
69 changes: 31 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# Python scripted livestreaming using FFmpeg

[![DOI](https://zenodo.org/badge/91214767.svg)](https://zenodo.org/badge/latestdoi/91214767)
[![Actions Status](https://github.com/scivision/pylivestream/workflows/ci/badge.svg)](https://github.com/scivision/pylivestream/actions)

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

# Python scripted livestreaming using FFmpeg

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

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


### PyLivestream benefits
## PyLivestream benefits

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


## Install

Requirements:
Expand All @@ -51,7 +49,6 @@ Requirements:

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


Latest release:

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

### YouTube Live

1. [configure](https://www.youtube.com/live_dashboard) YouTube Live.
2. Edit file `youtube.key` to have the YouTube hexadecimal stream key
3. Run Python script and chosen input will stream on YouTube Live.

1. [configure](https://www.youtube.com/live_dashboard) YouTube Live.
2. Edit file `youtube.key` to have the YouTube hexadecimal stream key
3. Run Python script and chosen input will stream on YouTube Live.

ScreenshareLivestream youtube

### Facebook Live

Facebook Live requires FFmpeg >= 4.2 due to mandatory RTMPS

1. configure your Facebook Live stream
2. Put stream ID from
1. configure your Facebook Live stream
2. Put stream ID from
[<https://www.facebook.com/live/create>](https://www.facebook.com/live/create)
into the file `facebook.key`
3. Run Python script for Facebook with chosen input

3. Run Python script for Facebook with chosen input

ScreenshareLivestream facebook

### Periscope

1. create a new stream by EITHER:
1. create a new stream by EITHER:

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

2. Put the hexadecimal stream key into `periscope.key`
3. Run Python script for Periscope with chosen input

ScreenshareLivestream periscope

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

### Twitch

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).
2. put Twitch stream key into file `twitch.key`
3. Run Python script for Twitch with chosen input

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).
2. put Twitch stream key into file `twitch.key`
3. Run Python script for Twitch with chosen input

ScreenshareLivestream twitch


## Usage

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.
Expand All @@ -171,22 +163,23 @@ Config:

Find webcam name by:

* Windows:
#### Windows

```sh
ffmpeg -list_devices true -f dshow -i dummy
```
* MacOS:
```sh
ffmpeg -list_devices true -f dshow -i dummy
```

```sh
ffmpeg -f avfoundation -list_devices true -i ""
#### MacOS

* Linux:
```sh
ffmpeg -f avfoundation -list_devices true -i ""
```

```sh
v4l2-ctl --list-devices
```
#### Linux

```sh
v4l2-ctl --list-devices
```

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

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


### Screen Share Livestream

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


### Image + Audio Livestream

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

Example: stream all .mp3 audio under `~/music` directory:

```sh
FileGlobLivestream ~/music youtube -glob "*.mp3" -image mylogo.jpg
```

Example: stream all .mp3 audio in `~/music` with an animated GIF or video clip repeating:

```sh
FileGlobLivestream ~/music youtube -glob "*.mp3" -image myclip.avi
```

or

```sh
FileGlobLivestream ~/music youtube -glob "*.mp3" -image animated.gif
```
Expand All @@ -312,7 +307,6 @@ This script saves your screen capture to a file on your disk:

## Utilities


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

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

Binary file added doc/logo720.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 4 additions & 4 deletions pylivestream/pylivestream.ini
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ server: rtmp://a.rtmp.youtube.com/live2/
key: ~/youtube.key

[periscope]
video_kbps: 800
audio_bps: 64k
video_kbps: 2500
audio_bps: 128k
server: rtmp://va.pscp.tv:80/x/
key: ~/periscope.key

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

[restream.io]
audio_bps: 64k
video_kbps: 800
video_kbps: 2500
audio_bps: 128k
server: rtmp://us-east.restream.io/live/
key: ~/restreamio.key

Expand Down
3 changes: 1 addition & 2 deletions pylivestream/stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@
240: 300,
360: 400,
480: 500,
540: 800,
720: 1800,
720: 2500,
1080: 3000,
1440: 6000,
2160: 13000}
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[metadata]
name = pylivestream
version = 1.9.6
version = 1.9.7
author = Michael Hirsch, Ph.D.
author_email = scivision@users.noreply.github.com
description = Livestream using FFmpeg to YouTube Live, Periscope, Facebook Live, Twitch, Mixer, and many more
Expand Down
4 changes: 2 additions & 2 deletions tests/archive/test.ini
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ server: rtmp://localhost
server: rtmp://a.rtmp.youtube.com/live2/

[periscope]
video_kbps: 800
audio_bps: 64k
video_kbps: 2500
audio_bps: 128k
server: rtmp://localhost


Expand Down
6 changes: 6 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import pytest


@pytest.fixture(scope="module")
def periscope_kbps():
return 2500
8 changes: 4 additions & 4 deletions tests/no_audio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ server: rtmp://a.rtmp.youtube.com/live2/
key: ~/youtube.key

[periscope]
video_kbps: 800
audio_bps: 64k
video_kbps: 2500
audio_bps: 128k
server: rtmp://va.pscp.tv:80/x/
key: ~/periscope.key

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

[restream.io]
audio_bps: 64k
video_kbps: 800
video_kbps: 2500
audio_bps: 128k
server: rtmp://us-east.restream.io/live/
key: ~/restreamio.key

Expand Down
2 changes: 1 addition & 1 deletion tests/test_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,4 @@ def test_config_default(tmp_path):


if __name__ == '__main__':
pytest.main(['-x', __file__])
pytest.main([__file__])
2 changes: 1 addition & 1 deletion tests/test_disk.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ def test_props(site):


if __name__ == '__main__':
pytest.main(['-x', __file__])
pytest.main([__file__])
10 changes: 5 additions & 5 deletions tests/test_filein.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,22 @@
CI = os.environ.get('CI', None) in ('true', 'True')


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

if s == 'periscope':
assert S.streams[s].video_kbps == 800
assert S.streams[s].video_kbps == periscope_kbps
else:
if int(S.streams[s].res[1]) == 480:
assert S.streams[s].video_kbps == 500
elif int(S.streams[s].res[1]) == 720:
assert S.streams[s].video_kbps == 1800


def test_audio():
def test_audio(periscope_kbps):
flist = list(R.glob('*.ogg'))

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

if s == 'periscope':
assert S.streams[s].video_kbps == 800
assert S.streams[s].video_kbps == periscope_kbps
else:
assert S.streams[s].video_kbps == 400

Expand Down Expand Up @@ -70,4 +70,4 @@ def test_script():


if __name__ == '__main__':
pytest.main(['-x', __file__])
pytest.main([__file__])
10 changes: 5 additions & 5 deletions tests/test_microphone.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
WSL = 'Microsoft' in platform.uname().release


def test_props():
def test_props(periscope_kbps):
S = pls.Microphone(inifn=None, websites=sites,
image=LOGO, key='abc')

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

if s == 'periscope':
assert S.streams[s].video_kbps == 800
assert S.streams[s].video_kbps == periscope_kbps
else:
assert S.streams[s].video_kbps == 800


def test_4Kbg():
def test_4Kbg(periscope_kbps):
S = pls.Microphone(inifn=None, websites=sites,
image=IMG4K, key='abc')

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

if s == 'periscope':
assert S.streams[s].video_kbps == 800
assert S.streams[s].video_kbps == periscope_kbps
else:
assert S.streams[s].video_kbps == 4000

Expand All @@ -68,4 +68,4 @@ def test_script():


if __name__ == '__main__':
pytest.main(['-x', __file__])
pytest.main([__file__])
6 changes: 3 additions & 3 deletions tests/test_screen.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@
R = Path(__file__).resolve().parent


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

if s == 'periscope':
assert S.streams[s].video_kbps == 800
assert S.streams[s].video_kbps == periscope_kbps
else:
assert S.streams[s].video_kbps == 500

Expand All @@ -42,4 +42,4 @@ def test_script():


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

0 comments on commit dbf8d6f

Please sign in to comment.