Skip to content

Commit

Permalink
0.1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
jneilliii committed Aug 11, 2018
0 parents commit a2a7bff
Show file tree
Hide file tree
Showing 15 changed files with 526 additions and 0 deletions.
16 changes: 16 additions & 0 deletions .github/stale.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 14
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- enhancement
- bug
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
activity in 14 days. It will be closed if no further activity occurs in 7 days.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include README.md
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# OctoPrint-RTMPStreamer
**Overview:** Plugin that adds a tab to OctoPrint for viewing, starting, and stopping a re-encoded stream to any RTMP server.

**Details:** Based on the work found [here](https://blog.alexellis.io/live-stream-with-docker/).

**Notes:**
- Plugin requires that OctoPrint's webcam stream uses a full url path including the ip address, ie `http://192.168.1.2/webcam/?action=stream`
- Only tested streaming to Twitch from a Pi3.
- Plugin does not provide a streaming application, it just re-encodes the mjpg stream (included with ocotpi) to a flv stream and transmits to configured RTMP server url.
- Although resolution is configurable in the plugin, the mjpg input stream being re-encoded may have a lower resolution and therefore not really be as high as you set it in the plugin settings.

<img src="https://raw.githubusercontent.com/jneilliii/Octoprint-RTMPStreamer/master/tab_screenshot.jpg">

## Prerequisites for Streaming
Follow the instructions found [here](docker_instructions.md) to install and configure docker/ffmpeg for use with this plugin for Live streaming. This is not necessary if you just want to view a url in an iframe on a tab.

## Setup
Once the prerequisites are met and the test command is successfull enter the resolution, stream url, and view url in the RTMP Streamer settings.

<img src="https://raw.githubusercontent.com/jneilliii/Octoprint-RTMPStreamer/master/settings_screenshot.jpg">

## TODO:
* [ ] Additional testing.

## Support My Efforts
I programmed this plugin for fun and do my best effort to support those that have issues with it, please return the favor and support me.

[![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://paypal.me/jneilliii)
6 changes: 6 additions & 0 deletions babel.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[python: */**.py]
[jinja2: */**.jinja2]
extensions=jinja2.ext.autoescape, jinja2.ext.with_

[javascript: */**.js]
extract_messages = gettext, ngettext
31 changes: 31 additions & 0 deletions docker_instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
**Install docker**

curl -sSL https://get.docker.com | sh
sudo usermod pi -aG docker
sudo reboot

**Clone Repository and Build Docker Image**

cd ~
git clone https://github.com/jneilliii/rtmpstreamer --depth 1
cd rtmpstreamer
docker build -t octoprint/rtmpstreamer .

**Test**

Run the following command replacing `<ip>`, `<stream_url>` and `<stream_resolution>` with appropriate values. For the resolution setting use the format equivalent to 640x480.

docker run --privileged --name RTMPStreamer -ti octoprint/rtmpstreamer:latest http://<ip>/webcam/?action=stream <stream_resolution> <stream_url> null

Stream should go live and re-encode the OctoPrint stream to provided url. Once verified close ffmpeg and remove docker container.

ctrl+c
docker rm RTMPStreamer

**OctoPrint Settings**

- Enter your stream url used above in the OctoPrint-RTMPStreamer plugin settings.
- Change your webcam stream url to a fully quliafied url using the ip address of your pi like

`http://192.168.1.101/webcam/?action=stream`

23 changes: 23 additions & 0 deletions instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
**Install build tools**

sudo apt-get update
sudo apt-get install build-essential git libomxil-bellagio-dev

**Clone git repository**

cd ~
git clone https://github.com/ffmpeg/FFMpeg --depth 1

**Configure build for mmjpeg**

cd ~/FFMpeg
./configure --arch=armel --target-os=linux --enable-gpl --enable-omx --enable-omx-rpi --enable-nonfree

**Make using 4 processors (pi2/3)**

make -j4

**Test**

cd ~/FFMpeg
./ffmpeg -re -f mjpeg -framerate 5 -i "http://localhost:8080/?action=stream" -ar 44100 -ac 2 -acodec pcm_s16le -f s16le -ac 2 -i /dev/zero -acodec aac -ab 128k -strict experimental -s 640x480 -vcodec h264 -pix_fmt yuv420p -g 10 -vb 700k -framerate 5 -f flv rtmp://a.rtmp.youtube.com/live2/<STREAM_ID>
131 changes: 131 additions & 0 deletions octoprint_rtmpstreamer/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# coding=utf-8
from __future__ import absolute_import

import octoprint.plugin
from octoprint.server import user_permission
import docker

class rtmpstreamer(octoprint.plugin.StartupPlugin,
octoprint.plugin.TemplatePlugin,
octoprint.plugin.AssetPlugin,
octoprint.plugin.SettingsPlugin,
octoprint.plugin.SimpleApiPlugin,
octoprint.plugin.EventHandlerPlugin):

def __init__(self):
self.client = docker.from_env()
self.container = None

##~~ StartupPlugin
def on_after_startup(self):
self._logger.info("OctoPrint-RTMPStreamer loaded! Checking stream status.")
try:
self.container = self.client.containers.get('RTMPStreamer')
self._logger.info("%s is streaming " % self.container.name)
self._plugin_manager.send_plugin_message(self._identifier, dict(status=True,streaming=True))
except Exception, e:
self._logger.error(str(e))
self._plugin_manager.send_plugin_message(self._identifier, dict(status=True,streaming=False))

##~~ TemplatePlugin
def get_template_configs(self):
return [dict(type="settings",custom_bindings=False)]

##~~ AssetPlugin
def get_assets(self):
return dict(
js=["js/rtmpstreamer.js"],
css=["css/rtmpstreamer.css"]
)

##-- EventHandlerPlugin
def on_event(self, event, payload):
if event == "PrintStarted" and self._settings.get(["auto_start"]):
self.startStream()

if event in ["PrintDone","PrintCancelled"] and self._settings.get(["auto_start"]):
self.stopStream()

##~~ SettingsPlugin
def get_settings_defaults(self):
return dict(view_url="",stream_url="",stream_resolution="640x480",streaming=False,auto_start=False)

##~~ SimpleApiPlugin
def get_api_commands(self):
return dict(startStream=[],stopStream=[],checkStream=[])

def on_api_command(self, command, data):
if not user_permission.can():
from flask import make_response
return make_response("Insufficient rights", 403)

if command == 'startStream':
self._logger.info("Start stream command received.")
self.startStream()
return
if command == 'stopStream':
self._logger.info("Stop stream command received.")
self.stopStream()
if command == 'checkStream':
self._logger.info("Checking stream status.")
if self.container:
self._plugin_manager.send_plugin_message(self._identifier, dict(status=True,streaming=True))
else:
self._plugin_manager.send_plugin_message(self._identifier, dict(status=True,streaming=False))

##~~ General Functions
def startStream(self):
if not self.container:
filters = []
if self._settings.global_get(["webcam","flipH"]):
filters.append("hflip")
if self._settings.global_get(["webcam","flipV"]):
filters.append("vflip")
if self._settings.global_get(["webcam","rotate90"]):
filters.append("transpose=cclock")
if len(filters) == 0:
filters.append("null")
try:
self.container = self.client.containers.run("octoprint/rtmpstreamer:latest",command=[self._settings.global_get(["webcam","stream"]),self._settings.get(["stream_resolution"]),self._settings.get(["stream_url"]),",".join(filters)],detach=True,privileged=True,name="RTMPStreamer",auto_remove=True)
self._plugin_manager.send_plugin_message(self._identifier, dict(status=True,streaming=True))
except Exception, e:
self._plugin_manager.send_plugin_message(self._identifier, dict(error=str(e),status=True,streaming=False))

def stopStream(self):
if self.container:
try:
self.container.stop()
self.container = None
self._plugin_manager.send_plugin_message(self._identifier, dict(status=True,streaming=False))
except Exception, e:
self._plugin_manager.send_plugin_message(self._identifier, dict(error=str(e),status=True,streaming=False))
else:
self._plugin_manager.send_plugin_message(self._identifier, dict(status=True,streaming=False))
##~~ Softwareupdate hook
def get_update_information(self):
return dict(
rtmpstreamer=dict(
displayName="RTMP Streamer",
displayVersion=self._plugin_version,

# version check: github repository
type="github_release",
user="jneilliii",
repo="OctoPrint-RTMPStreamer",
current=self._plugin_version,

# update method: pip
pip="https://github.com/jneilliii/OctoPrint-RTMPStreamer/archive/{target_version}.zip"
)
)

__plugin_name__ = "RTMP Streamer"

def __plugin_load__():
global __plugin_implementation__
__plugin_implementation__ = rtmpstreamer()

global __plugin_hooks__
__plugin_hooks__ = {
"octoprint.plugin.softwareupdate.check_config": __plugin_implementation__.get_update_information
}
14 changes: 14 additions & 0 deletions octoprint_rtmpstreamer/static/css/rtmpstreamer.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#rtmpstreamer_wrapper {
position: relative;
padding-bottom: 56.25%;
width: 100%;
height: 100%;
}

#rtmpstreamer_wrapper iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
Loading

0 comments on commit a2a7bff

Please sign in to comment.