diff --git a/docs/_build/doctrees/lesson_1.doctree b/docs/_build/doctrees/lesson_1.doctree index 98975e3..ea5817c 100644 Binary files a/docs/_build/doctrees/lesson_1.doctree and b/docs/_build/doctrees/lesson_1.doctree differ diff --git a/docs/_build/doctrees/lesson_10.doctree b/docs/_build/doctrees/lesson_10.doctree index 8bd8843..5adbf49 100644 Binary files a/docs/_build/doctrees/lesson_10.doctree and b/docs/_build/doctrees/lesson_10.doctree differ diff --git a/docs/_build/doctrees/lesson_11.doctree b/docs/_build/doctrees/lesson_11.doctree index 03af14b..712186e 100644 Binary files a/docs/_build/doctrees/lesson_11.doctree and b/docs/_build/doctrees/lesson_11.doctree differ diff --git a/docs/_build/doctrees/lesson_2.doctree b/docs/_build/doctrees/lesson_2.doctree index 7dc04f0..6f7a105 100644 Binary files a/docs/_build/doctrees/lesson_2.doctree and b/docs/_build/doctrees/lesson_2.doctree differ diff --git a/docs/_build/doctrees/lesson_3.doctree b/docs/_build/doctrees/lesson_3.doctree index 591e872..c5a4f4d 100644 Binary files a/docs/_build/doctrees/lesson_3.doctree and b/docs/_build/doctrees/lesson_3.doctree differ diff --git a/docs/_build/doctrees/lesson_4.doctree b/docs/_build/doctrees/lesson_4.doctree index 5daef79..4e394a1 100644 Binary files a/docs/_build/doctrees/lesson_4.doctree and b/docs/_build/doctrees/lesson_4.doctree differ diff --git a/docs/_build/doctrees/lesson_5.doctree b/docs/_build/doctrees/lesson_5.doctree index a28cf4d..98fa716 100644 Binary files a/docs/_build/doctrees/lesson_5.doctree and b/docs/_build/doctrees/lesson_5.doctree differ diff --git a/docs/_build/doctrees/lesson_6.doctree b/docs/_build/doctrees/lesson_6.doctree index 0a997f6..2ef9617 100644 Binary files a/docs/_build/doctrees/lesson_6.doctree and b/docs/_build/doctrees/lesson_6.doctree differ diff --git a/docs/_build/doctrees/lesson_7.doctree b/docs/_build/doctrees/lesson_7.doctree index d5f93ba..0ea005e 100644 Binary files a/docs/_build/doctrees/lesson_7.doctree and b/docs/_build/doctrees/lesson_7.doctree differ diff --git a/docs/_build/doctrees/lesson_8.doctree b/docs/_build/doctrees/lesson_8.doctree index 3682294..5d54aa2 100644 Binary files a/docs/_build/doctrees/lesson_8.doctree and b/docs/_build/doctrees/lesson_8.doctree differ diff --git a/docs/_build/doctrees/lesson_9.doctree b/docs/_build/doctrees/lesson_9.doctree index bf832ab..2260dd0 100644 Binary files a/docs/_build/doctrees/lesson_9.doctree and b/docs/_build/doctrees/lesson_9.doctree differ diff --git a/docs/_build/doctrees/onvif.doctree b/docs/_build/doctrees/onvif.doctree index 698aa54..e632e30 100644 Binary files a/docs/_build/doctrees/onvif.doctree and b/docs/_build/doctrees/onvif.doctree differ diff --git a/docs/_build/html/.buildinfo b/docs/_build/html/.buildinfo index 9fb91ef..0269098 100644 --- a/docs/_build/html/.buildinfo +++ b/docs/_build/html/.buildinfo @@ -1,4 +1,4 @@ # Sphinx build info version 1 # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. -config: dc072c669c53fef6eaccb203fe82be79 +config: 0ff432d1cf68f56d5ad7e7c005f8f32e tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/docs/_build/html/_static/_sphinx_javascript_frameworks_compat.js b/docs/_build/html/_static/_sphinx_javascript_frameworks_compat.js new file mode 100644 index 0000000..8141580 --- /dev/null +++ b/docs/_build/html/_static/_sphinx_javascript_frameworks_compat.js @@ -0,0 +1,123 @@ +/* Compatability shim for jQuery and underscores.js. + * + * Copyright Sphinx contributors + * Released under the two clause BSD licence + */ + +/** + * small helper function to urldecode strings + * + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL + */ +jQuery.urldecode = function(x) { + if (!x) { + return x + } + return decodeURIComponent(x.replace(/\+/g, ' ')); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && + !jQuery(node.parentNode).hasClass(className) && + !jQuery(node.parentNode).hasClass("nohighlight")) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + var bbox = node.parentElement.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} diff --git a/docs/_build/html/_static/alabaster.css b/docs/_build/html/_static/alabaster.css deleted file mode 100644 index 51b213b..0000000 --- a/docs/_build/html/_static/alabaster.css +++ /dev/null @@ -1,708 +0,0 @@ -@import url("basic.css"); - -/* -- page layout ----------------------------------------------------------- */ - -body { - font-family: Georgia, serif; - font-size: 17px; - background-color: #fff; - color: #000; - margin: 0; - padding: 0; -} - - -div.document { - width: 60%; - margin: 30px auto 0 auto; -} - -div.documentwrapper { - float: left; - width: 100%; -} - -div.bodywrapper { - margin: 0 0 0 220px; -} - -div.sphinxsidebar { - width: 220px; - font-size: 14px; - line-height: 1.5; -} - -hr { - border: 1px solid #B1B4B6; -} - -div.body { - background-color: #fff; - color: #3E4349; - padding: 0 30px 0 30px; -} - -div.body > .section { - text-align: left; -} - -div.footer { - width: 60%; - margin: 20px auto 30px auto; - font-size: 14px; - color: #888; - text-align: right; -} - -div.footer a { - color: #888; -} - -p.caption { - font-family: inherit; - font-size: inherit; -} - - -div.relations { - display: none; -} - - -div.sphinxsidebar { - max-height: 100%; - overflow-y: auto; -} - -div.sphinxsidebar a { - color: #444; - text-decoration: none; - border-bottom: 1px dotted #999; -} - -div.sphinxsidebar a:hover { - border-bottom: 1px solid #999; -} - -div.sphinxsidebarwrapper { - padding: 18px 10px; -} - -div.sphinxsidebarwrapper p.logo { - padding: 0; - margin: -10px 0 0 0px; - text-align: center; -} - -div.sphinxsidebarwrapper h1.logo { - margin-top: -10px; - text-align: center; - margin-bottom: 5px; - text-align: left; -} - -div.sphinxsidebarwrapper h1.logo-name { - margin-top: 0px; -} - -div.sphinxsidebarwrapper p.blurb { - margin-top: 0; - font-style: normal; -} - -div.sphinxsidebar h3, -div.sphinxsidebar h4 { - font-family: Georgia, serif; - color: #444; - font-size: 24px; - font-weight: normal; - margin: 0 0 5px 0; - padding: 0; -} - -div.sphinxsidebar h4 { - font-size: 20px; -} - -div.sphinxsidebar h3 a { - color: #444; -} - -div.sphinxsidebar p.logo a, -div.sphinxsidebar h3 a, -div.sphinxsidebar p.logo a:hover, -div.sphinxsidebar h3 a:hover { - border: none; -} - -div.sphinxsidebar p { - color: #555; - margin: 10px 0; -} - -div.sphinxsidebar ul { - margin: 10px 0; - padding: 0; - color: #000; -} - -div.sphinxsidebar ul li.toctree-l1 > a { - font-size: 120%; -} - -div.sphinxsidebar ul li.toctree-l2 > a { - font-size: 110%; -} - -div.sphinxsidebar input { - border: 1px solid #CCC; - font-family: Georgia, serif; - font-size: 1em; -} - -div.sphinxsidebar #searchbox input[type="text"] { - width: 160px; -} - -div.sphinxsidebar .search > div { - display: table-cell; -} - -div.sphinxsidebar hr { - border: none; - height: 1px; - color: #AAA; - background: #AAA; - - text-align: left; - margin-left: 0; - width: 50%; -} - -div.sphinxsidebar .badge { - border-bottom: none; -} - -div.sphinxsidebar .badge:hover { - border-bottom: none; -} - -/* To address an issue with donation coming after search */ -div.sphinxsidebar h3.donation { - margin-top: 10px; -} - -/* -- body styles ----------------------------------------------------------- */ - -a { - color: #004B6B; - text-decoration: underline; -} - -a:hover { - color: #6D4100; - text-decoration: underline; -} - -div.body h1, -div.body h2, -div.body h3, -div.body h4, -div.body h5, -div.body h6 { - font-family: Georgia, serif; - font-weight: normal; - margin: 30px 0px 10px 0px; - padding: 0; -} - -div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; } -div.body h2 { font-size: 180%; } -div.body h3 { font-size: 150%; } -div.body h4 { font-size: 130%; } -div.body h5 { font-size: 100%; } -div.body h6 { font-size: 100%; } - -a.headerlink { - color: #DDD; - padding: 0 4px; - text-decoration: none; -} - -a.headerlink:hover { - color: #444; - background: #EAEAEA; -} - -div.body p, div.body dd, div.body li { - line-height: 1.4em; -} - -div.admonition { - margin: 20px 0px; - padding: 10px 30px; - background-color: #EEE; - border: 1px solid #CCC; -} - -div.admonition tt.xref, div.admonition code.xref, div.admonition a tt { - background-color: #FBFBFB; - border-bottom: 1px solid #fafafa; -} - -div.admonition p.admonition-title { - font-family: Georgia, serif; - font-weight: normal; - font-size: 24px; - margin: 0 0 10px 0; - padding: 0; - line-height: 1; -} - -div.admonition p.last { - margin-bottom: 0; -} - -div.highlight { - background-color: #fff; -} - -dt:target, .highlight { - background: #FAF3E8; -} - -div.warning { - background-color: #FCC; - border: 1px solid #FAA; -} - -div.danger { - background-color: #FCC; - border: 1px solid #FAA; - -moz-box-shadow: 2px 2px 4px #D52C2C; - -webkit-box-shadow: 2px 2px 4px #D52C2C; - box-shadow: 2px 2px 4px #D52C2C; -} - -div.error { - background-color: #FCC; - border: 1px solid #FAA; - -moz-box-shadow: 2px 2px 4px #D52C2C; - -webkit-box-shadow: 2px 2px 4px #D52C2C; - box-shadow: 2px 2px 4px #D52C2C; -} - -div.caution { - background-color: #FCC; - border: 1px solid #FAA; -} - -div.attention { - background-color: #FCC; - border: 1px solid #FAA; -} - -div.important { - background-color: #EEE; - border: 1px solid #CCC; -} - -div.note { - background-color: #EEE; - border: 1px solid #CCC; -} - -div.tip { - background-color: #EEE; - border: 1px solid #CCC; -} - -div.hint { - background-color: #EEE; - border: 1px solid #CCC; -} - -div.seealso { - background-color: #EEE; - border: 1px solid #CCC; -} - -div.topic { - background-color: #EEE; -} - -p.admonition-title { - display: inline; -} - -p.admonition-title:after { - content: ":"; -} - -pre, tt, code { - font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; - font-size: 0.9em; -} - -.hll { - background-color: #FFC; - margin: 0 -12px; - padding: 0 12px; - display: block; -} - -img.screenshot { -} - -tt.descname, tt.descclassname, code.descname, code.descclassname { - font-size: 0.95em; -} - -tt.descname, code.descname { - padding-right: 0.08em; -} - -img.screenshot { - -moz-box-shadow: 2px 2px 4px #EEE; - -webkit-box-shadow: 2px 2px 4px #EEE; - box-shadow: 2px 2px 4px #EEE; -} - -table.docutils { - border: 1px solid #888; - -moz-box-shadow: 2px 2px 4px #EEE; - -webkit-box-shadow: 2px 2px 4px #EEE; - box-shadow: 2px 2px 4px #EEE; -} - -table.docutils td, table.docutils th { - border: 1px solid #888; - padding: 0.25em 0.7em; -} - -table.field-list, table.footnote { - border: none; - -moz-box-shadow: none; - -webkit-box-shadow: none; - box-shadow: none; -} - -table.footnote { - margin: 15px 0; - width: 100%; - border: 1px solid #EEE; - background: #FDFDFD; - font-size: 0.9em; -} - -table.footnote + table.footnote { - margin-top: -15px; - border-top: none; -} - -table.field-list th { - padding: 0 0.8em 0 0; -} - -table.field-list td { - padding: 0; -} - -table.field-list p { - margin-bottom: 0.8em; -} - -/* Cloned from - * https://github.com/sphinx-doc/sphinx/commit/ef60dbfce09286b20b7385333d63a60321784e68 - */ -.field-name { - -moz-hyphens: manual; - -ms-hyphens: manual; - -webkit-hyphens: manual; - hyphens: manual; -} - -table.footnote td.label { - width: .1px; - padding: 0.3em 0 0.3em 0.5em; -} - -table.footnote td { - padding: 0.3em 0.5em; -} - -dl { - margin-left: 0; - margin-right: 0; - margin-top: 0; - padding: 0; -} - -dl dd { - margin-left: 30px; -} - -blockquote { - margin: 0 0 0 30px; - padding: 0; -} - -ul, ol { - /* Matches the 30px from the narrow-screen "li > ul" selector below */ - margin: 10px 0 10px 30px; - padding: 0; -} - -pre { - background: #EEE; - padding: 7px 30px; - margin: 15px 0px; - line-height: 1.3em; -} - -div.viewcode-block:target { - background: #ffd; -} - -dl pre, blockquote pre, li pre { - margin-left: 0; - padding-left: 30px; -} - -tt, code { - background-color: #ecf0f3; - color: #222; - /* padding: 1px 2px; */ -} - -tt.xref, code.xref, a tt { - background-color: #FBFBFB; - border-bottom: 1px solid #fff; -} - -a.reference { - text-decoration: none; - border-bottom: 1px dotted #004B6B; -} - -/* Don't put an underline on images */ -a.image-reference, a.image-reference:hover { - border-bottom: none; -} - -a.reference:hover { - border-bottom: 1px solid #6D4100; -} - -a.footnote-reference { - text-decoration: none; - font-size: 0.7em; - vertical-align: top; - border-bottom: 1px dotted #004B6B; -} - -a.footnote-reference:hover { - border-bottom: 1px solid #6D4100; -} - -a:hover tt, a:hover code { - background: #EEE; -} - - -@media screen and (max-width: 870px) { - - div.sphinxsidebar { - display: none; - } - - div.document { - width: 100%; - - } - - div.documentwrapper { - margin-left: 0; - margin-top: 0; - margin-right: 0; - margin-bottom: 0; - } - - div.bodywrapper { - margin-top: 0; - margin-right: 0; - margin-bottom: 0; - margin-left: 0; - } - - ul { - margin-left: 0; - } - - li > ul { - /* Matches the 30px from the "ul, ol" selector above */ - margin-left: 30px; - } - - .document { - width: auto; - } - - .footer { - width: auto; - } - - .bodywrapper { - margin: 0; - } - - .footer { - width: auto; - } - - .github { - display: none; - } - - - -} - - - -@media screen and (max-width: 875px) { - - body { - margin: 0; - padding: 20px 30px; - } - - div.documentwrapper { - float: none; - background: #fff; - } - - div.sphinxsidebar { - display: block; - float: none; - width: 102.5%; - margin: 50px -30px -20px -30px; - padding: 10px 20px; - background: #333; - color: #FFF; - } - - div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p, - div.sphinxsidebar h3 a { - color: #fff; - } - - div.sphinxsidebar a { - color: #AAA; - } - - div.sphinxsidebar p.logo { - display: none; - } - - div.document { - width: 100%; - margin: 0; - } - - div.footer { - display: none; - } - - div.bodywrapper { - margin: 0; - } - - div.body { - min-height: 0; - padding: 0; - } - - .rtd_doc_footer { - display: none; - } - - .document { - width: auto; - } - - .footer { - width: auto; - } - - .footer { - width: auto; - } - - .github { - display: none; - } -} - - -/* misc. */ - -.revsys-inline { - display: none!important; -} - -/* Hide ugly table cell borders in ..bibliography:: directive output */ -table.docutils.citation, table.docutils.citation td, table.docutils.citation th { - border: none; - /* Below needed in some edge cases; if not applied, bottom shadows appear */ - -moz-box-shadow: none; - -webkit-box-shadow: none; - box-shadow: none; -} - - -/* relbar */ - -.related { - line-height: 30px; - width: 100%; - font-size: 0.9rem; -} - -.related.top { - border-bottom: 1px solid #EEE; - margin-bottom: 20px; -} - -.related.bottom { - border-top: 1px solid #EEE; -} - -.related ul { - padding: 0; - margin: 0; - list-style: none; -} - -.related li { - display: inline; -} - -nav#rellinks { - float: right; -} - -nav#rellinks li+li:before { - content: "|"; -} - -nav#breadcrumbs li+li:before { - content: "\00BB"; -} - -/* Hide certain items when printing */ -@media print { - div.related { - display: none; - } -} \ No newline at end of file diff --git a/docs/_build/html/_static/basic.css b/docs/_build/html/_static/basic.css index 14241a6..30fee9d 100644 --- a/docs/_build/html/_static/basic.css +++ b/docs/_build/html/_static/basic.css @@ -222,8 +222,8 @@ table.modindextable td { /* -- general body styles --------------------------------------------------- */ div.body { - min-width: inherit; - max-width: 100%; + min-width: 360px; + max-width: 800px; } div.body p, div.body dd, div.body li, div.body blockquote { diff --git a/docs/_build/html/_static/check-solid.svg b/docs/_build/html/_static/check-solid.svg new file mode 100644 index 0000000..92fad4b --- /dev/null +++ b/docs/_build/html/_static/check-solid.svg @@ -0,0 +1,4 @@ + + + + diff --git a/docs/_build/html/_static/clipboard.min.js b/docs/_build/html/_static/clipboard.min.js new file mode 100644 index 0000000..54b3c46 --- /dev/null +++ b/docs/_build/html/_static/clipboard.min.js @@ -0,0 +1,7 @@ +/*! + * clipboard.js v2.0.8 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return o}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),c=n.n(e);function a(t){try{return document.execCommand(t)}catch(t){return}}var f=function(t){t=c()(t);return a("cut"),t};var l=function(t){var e,n,o,r=1 + + + + diff --git a/docs/_build/html/_static/copybutton.css b/docs/_build/html/_static/copybutton.css new file mode 100644 index 0000000..f1916ec --- /dev/null +++ b/docs/_build/html/_static/copybutton.css @@ -0,0 +1,94 @@ +/* Copy buttons */ +button.copybtn { + position: absolute; + display: flex; + top: .3em; + right: .3em; + width: 1.7em; + height: 1.7em; + opacity: 0; + transition: opacity 0.3s, border .3s, background-color .3s; + user-select: none; + padding: 0; + border: none; + outline: none; + border-radius: 0.4em; + /* The colors that GitHub uses */ + border: #1b1f2426 1px solid; + background-color: #f6f8fa; + color: #57606a; +} + +button.copybtn.success { + border-color: #22863a; + color: #22863a; +} + +button.copybtn svg { + stroke: currentColor; + width: 1.5em; + height: 1.5em; + padding: 0.1em; +} + +div.highlight { + position: relative; +} + +/* Show the copybutton */ +.highlight:hover button.copybtn, button.copybtn.success { + opacity: 1; +} + +.highlight button.copybtn:hover { + background-color: rgb(235, 235, 235); +} + +.highlight button.copybtn:active { + background-color: rgb(187, 187, 187); +} + +/** + * A minimal CSS-only tooltip copied from: + * https://codepen.io/mildrenben/pen/rVBrpK + * + * To use, write HTML like the following: + * + *

Short

+ */ + .o-tooltip--left { + position: relative; + } + + .o-tooltip--left:after { + opacity: 0; + visibility: hidden; + position: absolute; + content: attr(data-tooltip); + padding: .2em; + font-size: .8em; + left: -.2em; + background: grey; + color: white; + white-space: nowrap; + z-index: 2; + border-radius: 2px; + transform: translateX(-102%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); +} + +.o-tooltip--left:hover:after { + display: block; + opacity: 1; + visibility: visible; + transform: translateX(-100%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); + transition-delay: .5s; +} + +/* By default the copy button shouldn't show up when printing a page */ +@media print { + button.copybtn { + display: none; + } +} diff --git a/docs/_build/html/_static/copybutton.js b/docs/_build/html/_static/copybutton.js new file mode 100644 index 0000000..2ea7ff3 --- /dev/null +++ b/docs/_build/html/_static/copybutton.js @@ -0,0 +1,248 @@ +// Localization support +const messages = { + 'en': { + 'copy': 'Copy', + 'copy_to_clipboard': 'Copy to clipboard', + 'copy_success': 'Copied!', + 'copy_failure': 'Failed to copy', + }, + 'es' : { + 'copy': 'Copiar', + 'copy_to_clipboard': 'Copiar al portapapeles', + 'copy_success': '¡Copiado!', + 'copy_failure': 'Error al copiar', + }, + 'de' : { + 'copy': 'Kopieren', + 'copy_to_clipboard': 'In die Zwischenablage kopieren', + 'copy_success': 'Kopiert!', + 'copy_failure': 'Fehler beim Kopieren', + }, + 'fr' : { + 'copy': 'Copier', + 'copy_to_clipboard': 'Copier dans le presse-papier', + 'copy_success': 'Copié !', + 'copy_failure': 'Échec de la copie', + }, + 'ru': { + 'copy': 'Скопировать', + 'copy_to_clipboard': 'Скопировать в буфер', + 'copy_success': 'Скопировано!', + 'copy_failure': 'Не удалось скопировать', + }, + 'zh-CN': { + 'copy': '复制', + 'copy_to_clipboard': '复制到剪贴板', + 'copy_success': '复制成功!', + 'copy_failure': '复制失败', + }, + 'it' : { + 'copy': 'Copiare', + 'copy_to_clipboard': 'Copiato negli appunti', + 'copy_success': 'Copiato!', + 'copy_failure': 'Errore durante la copia', + } +} + +let locale = 'en' +if( document.documentElement.lang !== undefined + && messages[document.documentElement.lang] !== undefined ) { + locale = document.documentElement.lang +} + +let doc_url_root = DOCUMENTATION_OPTIONS.URL_ROOT; +if (doc_url_root == '#') { + doc_url_root = ''; +} + +/** + * SVG files for our copy buttons + */ +let iconCheck = ` + ${messages[locale]['copy_success']} + + +` + +// If the user specified their own SVG use that, otherwise use the default +let iconCopy = ``; +if (!iconCopy) { + iconCopy = ` + ${messages[locale]['copy_to_clipboard']} + + + +` +} + +/** + * Set up copy/paste for code blocks + */ + +const runWhenDOMLoaded = cb => { + if (document.readyState != 'loading') { + cb() + } else if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', cb) + } else { + document.attachEvent('onreadystatechange', function() { + if (document.readyState == 'complete') cb() + }) + } +} + +const codeCellId = index => `codecell${index}` + +// Clears selected text since ClipboardJS will select the text when copying +const clearSelection = () => { + if (window.getSelection) { + window.getSelection().removeAllRanges() + } else if (document.selection) { + document.selection.empty() + } +} + +// Changes tooltip text for a moment, then changes it back +// We want the timeout of our `success` class to be a bit shorter than the +// tooltip and icon change, so that we can hide the icon before changing back. +var timeoutIcon = 2000; +var timeoutSuccessClass = 1500; + +const temporarilyChangeTooltip = (el, oldText, newText) => { + el.setAttribute('data-tooltip', newText) + el.classList.add('success') + // Remove success a little bit sooner than we change the tooltip + // So that we can use CSS to hide the copybutton first + setTimeout(() => el.classList.remove('success'), timeoutSuccessClass) + setTimeout(() => el.setAttribute('data-tooltip', oldText), timeoutIcon) +} + +// Changes the copy button icon for two seconds, then changes it back +const temporarilyChangeIcon = (el) => { + el.innerHTML = iconCheck; + setTimeout(() => {el.innerHTML = iconCopy}, timeoutIcon) +} + +const addCopyButtonToCodeCells = () => { + // If ClipboardJS hasn't loaded, wait a bit and try again. This + // happens because we load ClipboardJS asynchronously. + if (window.ClipboardJS === undefined) { + setTimeout(addCopyButtonToCodeCells, 250) + return + } + + // Add copybuttons to all of our code cells + const COPYBUTTON_SELECTOR = 'div.highlight pre'; + const codeCells = document.querySelectorAll(COPYBUTTON_SELECTOR) + codeCells.forEach((codeCell, index) => { + const id = codeCellId(index) + codeCell.setAttribute('id', id) + + const clipboardButton = id => + `` + codeCell.insertAdjacentHTML('afterend', clipboardButton(id)) + }) + +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +/** + * Removes excluded text from a Node. + * + * @param {Node} target Node to filter. + * @param {string} exclude CSS selector of nodes to exclude. + * @returns {DOMString} Text from `target` with text removed. + */ +function filterText(target, exclude) { + const clone = target.cloneNode(true); // clone as to not modify the live DOM + if (exclude) { + // remove excluded nodes + clone.querySelectorAll(exclude).forEach(node => node.remove()); + } + return clone.innerText; +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} + + +var copyTargetText = (trigger) => { + var target = document.querySelector(trigger.attributes['data-clipboard-target'].value); + + // get filtered text + let exclude = '.linenos'; + + let text = filterText(target, exclude); + return formatCopyText(text, '', false, true, true, true, '', '') +} + + // Initialize with a callback so we can modify the text before copy + const clipboard = new ClipboardJS('.copybtn', {text: copyTargetText}) + + // Update UI with error/success messages + clipboard.on('success', event => { + clearSelection() + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_success']) + temporarilyChangeIcon(event.trigger) + }) + + clipboard.on('error', event => { + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_failure']) + }) +} + +runWhenDOMLoaded(addCopyButtonToCodeCells) \ No newline at end of file diff --git a/docs/_build/html/_static/copybutton_funcs.js b/docs/_build/html/_static/copybutton_funcs.js new file mode 100644 index 0000000..dbe1aaa --- /dev/null +++ b/docs/_build/html/_static/copybutton_funcs.js @@ -0,0 +1,73 @@ +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +/** + * Removes excluded text from a Node. + * + * @param {Node} target Node to filter. + * @param {string} exclude CSS selector of nodes to exclude. + * @returns {DOMString} Text from `target` with text removed. + */ +export function filterText(target, exclude) { + const clone = target.cloneNode(true); // clone as to not modify the live DOM + if (exclude) { + // remove excluded nodes + clone.querySelectorAll(exclude).forEach(node => node.remove()); + } + return clone.innerText; +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +export function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} diff --git a/docs/_build/html/_static/css/badge_only.css b/docs/_build/html/_static/css/badge_only.css new file mode 100644 index 0000000..c718cee --- /dev/null +++ b/docs/_build/html/_static/css/badge_only.css @@ -0,0 +1 @@ +.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}} \ No newline at end of file diff --git a/docs/_build/html/_static/css/fonts/Roboto-Slab-Bold.woff b/docs/_build/html/_static/css/fonts/Roboto-Slab-Bold.woff new file mode 100644 index 0000000..6cb6000 Binary files /dev/null and b/docs/_build/html/_static/css/fonts/Roboto-Slab-Bold.woff differ diff --git a/docs/_build/html/_static/css/fonts/Roboto-Slab-Bold.woff2 b/docs/_build/html/_static/css/fonts/Roboto-Slab-Bold.woff2 new file mode 100644 index 0000000..7059e23 Binary files /dev/null and b/docs/_build/html/_static/css/fonts/Roboto-Slab-Bold.woff2 differ diff --git a/docs/_build/html/_static/css/fonts/Roboto-Slab-Regular.woff b/docs/_build/html/_static/css/fonts/Roboto-Slab-Regular.woff new file mode 100644 index 0000000..f815f63 Binary files /dev/null and b/docs/_build/html/_static/css/fonts/Roboto-Slab-Regular.woff differ diff --git a/docs/_build/html/_static/css/fonts/Roboto-Slab-Regular.woff2 b/docs/_build/html/_static/css/fonts/Roboto-Slab-Regular.woff2 new file mode 100644 index 0000000..f2c76e5 Binary files /dev/null and b/docs/_build/html/_static/css/fonts/Roboto-Slab-Regular.woff2 differ diff --git a/docs/_build/html/_static/css/fonts/fontawesome-webfont.eot b/docs/_build/html/_static/css/fonts/fontawesome-webfont.eot new file mode 100644 index 0000000..e9f60ca Binary files /dev/null and b/docs/_build/html/_static/css/fonts/fontawesome-webfont.eot differ diff --git a/docs/_build/html/_static/css/fonts/fontawesome-webfont.svg b/docs/_build/html/_static/css/fonts/fontawesome-webfont.svg new file mode 100644 index 0000000..855c845 --- /dev/null +++ b/docs/_build/html/_static/css/fonts/fontawesome-webfont.svg @@ -0,0 +1,2671 @@ + + + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/_build/html/_static/css/fonts/fontawesome-webfont.ttf b/docs/_build/html/_static/css/fonts/fontawesome-webfont.ttf new file mode 100644 index 0000000..35acda2 Binary files /dev/null and b/docs/_build/html/_static/css/fonts/fontawesome-webfont.ttf differ diff --git a/docs/_build/html/_static/css/fonts/fontawesome-webfont.woff b/docs/_build/html/_static/css/fonts/fontawesome-webfont.woff new file mode 100644 index 0000000..400014a Binary files /dev/null and b/docs/_build/html/_static/css/fonts/fontawesome-webfont.woff differ diff --git a/docs/_build/html/_static/css/fonts/fontawesome-webfont.woff2 b/docs/_build/html/_static/css/fonts/fontawesome-webfont.woff2 new file mode 100644 index 0000000..4d13fc6 Binary files /dev/null and b/docs/_build/html/_static/css/fonts/fontawesome-webfont.woff2 differ diff --git a/docs/_build/html/_static/css/fonts/lato-bold-italic.woff b/docs/_build/html/_static/css/fonts/lato-bold-italic.woff new file mode 100644 index 0000000..88ad05b Binary files /dev/null and b/docs/_build/html/_static/css/fonts/lato-bold-italic.woff differ diff --git a/docs/_build/html/_static/css/fonts/lato-bold-italic.woff2 b/docs/_build/html/_static/css/fonts/lato-bold-italic.woff2 new file mode 100644 index 0000000..c4e3d80 Binary files /dev/null and b/docs/_build/html/_static/css/fonts/lato-bold-italic.woff2 differ diff --git a/docs/_build/html/_static/css/fonts/lato-bold.woff b/docs/_build/html/_static/css/fonts/lato-bold.woff new file mode 100644 index 0000000..c6dff51 Binary files /dev/null and b/docs/_build/html/_static/css/fonts/lato-bold.woff differ diff --git a/docs/_build/html/_static/css/fonts/lato-bold.woff2 b/docs/_build/html/_static/css/fonts/lato-bold.woff2 new file mode 100644 index 0000000..bb19504 Binary files /dev/null and b/docs/_build/html/_static/css/fonts/lato-bold.woff2 differ diff --git a/docs/_build/html/_static/css/fonts/lato-normal-italic.woff b/docs/_build/html/_static/css/fonts/lato-normal-italic.woff new file mode 100644 index 0000000..76114bc Binary files /dev/null and b/docs/_build/html/_static/css/fonts/lato-normal-italic.woff differ diff --git a/docs/_build/html/_static/css/fonts/lato-normal-italic.woff2 b/docs/_build/html/_static/css/fonts/lato-normal-italic.woff2 new file mode 100644 index 0000000..3404f37 Binary files /dev/null and b/docs/_build/html/_static/css/fonts/lato-normal-italic.woff2 differ diff --git a/docs/_build/html/_static/css/fonts/lato-normal.woff b/docs/_build/html/_static/css/fonts/lato-normal.woff new file mode 100644 index 0000000..ae1307f Binary files /dev/null and b/docs/_build/html/_static/css/fonts/lato-normal.woff differ diff --git a/docs/_build/html/_static/css/fonts/lato-normal.woff2 b/docs/_build/html/_static/css/fonts/lato-normal.woff2 new file mode 100644 index 0000000..3bf9843 Binary files /dev/null and b/docs/_build/html/_static/css/fonts/lato-normal.woff2 differ diff --git a/docs/_build/html/_static/css/theme.css b/docs/_build/html/_static/css/theme.css new file mode 100644 index 0000000..19a446a --- /dev/null +++ b/docs/_build/html/_static/css/theme.css @@ -0,0 +1,4 @@ +html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden],audio:not([controls]){display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;text-decoration:none}ins,mark{color:#000}mark{background:#ff0;font-style:italic;font-weight:700}.rst-content code,.rst-content tt,code,kbd,pre,samp{font-family:monospace,serif;_font-family:courier new,monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:after,q:before{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}dl,ol,ul{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure,form{margin:0}label{cursor:pointer}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type=button],input[type=reset],input[type=submit]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}textarea{resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:.2em 0;background:#ccc;color:#000;padding:.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none!important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{body,html,section{background:none!important}*{box-shadow:none!important;text-shadow:none!important;filter:none!important;-ms-filter:none!important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}.rst-content .toctree-wrapper>p.caption,h2,h3,p{orphans:3;widows:3}.rst-content .toctree-wrapper>p.caption,h2,h3{page-break-after:avoid}}.btn,.fa:before,.icon:before,.rst-content .admonition,.rst-content .admonition-title:before,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .code-block-caption .headerlink:before,.rst-content .danger,.rst-content .eqno .headerlink:before,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-alert,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before,input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week],select,textarea{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:FontAwesome;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713);src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix&v=4.7.0) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#fontawesomeregular) format("svg");font-weight:400;font-style:normal}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14286em;width:2.14286em;top:.14286em;text-align:center}.fa-li.fa-lg{left:-1.85714em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa-pull-left.icon,.fa.fa-pull-left,.rst-content .code-block-caption .fa-pull-left.headerlink,.rst-content .eqno .fa-pull-left.headerlink,.rst-content .fa-pull-left.admonition-title,.rst-content code.download span.fa-pull-left:first-child,.rst-content dl dt .fa-pull-left.headerlink,.rst-content h1 .fa-pull-left.headerlink,.rst-content h2 .fa-pull-left.headerlink,.rst-content h3 .fa-pull-left.headerlink,.rst-content h4 .fa-pull-left.headerlink,.rst-content h5 .fa-pull-left.headerlink,.rst-content h6 .fa-pull-left.headerlink,.rst-content p .fa-pull-left.headerlink,.rst-content table>caption .fa-pull-left.headerlink,.rst-content tt.download span.fa-pull-left:first-child,.wy-menu-vertical li.current>a button.fa-pull-left.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-left.toctree-expand,.wy-menu-vertical li button.fa-pull-left.toctree-expand{margin-right:.3em}.fa-pull-right.icon,.fa.fa-pull-right,.rst-content .code-block-caption .fa-pull-right.headerlink,.rst-content .eqno .fa-pull-right.headerlink,.rst-content .fa-pull-right.admonition-title,.rst-content code.download span.fa-pull-right:first-child,.rst-content dl dt .fa-pull-right.headerlink,.rst-content h1 .fa-pull-right.headerlink,.rst-content h2 .fa-pull-right.headerlink,.rst-content h3 .fa-pull-right.headerlink,.rst-content h4 .fa-pull-right.headerlink,.rst-content h5 .fa-pull-right.headerlink,.rst-content h6 .fa-pull-right.headerlink,.rst-content p .fa-pull-right.headerlink,.rst-content table>caption .fa-pull-right.headerlink,.rst-content tt.download span.fa-pull-right:first-child,.wy-menu-vertical li.current>a button.fa-pull-right.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-right.toctree-expand,.wy-menu-vertical li button.fa-pull-right.toctree-expand{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.pull-left.icon,.rst-content .code-block-caption .pull-left.headerlink,.rst-content .eqno .pull-left.headerlink,.rst-content .pull-left.admonition-title,.rst-content code.download span.pull-left:first-child,.rst-content dl dt .pull-left.headerlink,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content p .pull-left.headerlink,.rst-content table>caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.wy-menu-vertical li.current>a button.pull-left.toctree-expand,.wy-menu-vertical li.on a button.pull-left.toctree-expand,.wy-menu-vertical li button.pull-left.toctree-expand{margin-right:.3em}.fa.pull-right,.pull-right.icon,.rst-content .code-block-caption .pull-right.headerlink,.rst-content .eqno .pull-right.headerlink,.rst-content .pull-right.admonition-title,.rst-content code.download span.pull-right:first-child,.rst-content dl dt .pull-right.headerlink,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content p .pull-right.headerlink,.rst-content table>caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.wy-menu-vertical li.current>a button.pull-right.toctree-expand,.wy-menu-vertical li.on a button.pull-right.toctree-expand,.wy-menu-vertical li button.pull-right.toctree-expand{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);-ms-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scaleY(-1);-ms-transform:scaleY(-1);transform:scaleY(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-close:before,.fa-remove:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-cog:before,.fa-gear:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-repeat:before,.fa-rotate-right:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.rst-content .admonition-title:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-exclamation-triangle:before,.fa-warning:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-cogs:before,.fa-gears:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook-f:before,.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-feed:before,.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-floppy-o:before,.fa-save:before{content:""}.fa-square:before{content:""}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.icon-caret-down:before,.wy-dropdown .caret:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-sort:before,.fa-unsorted:before{content:""}.fa-sort-desc:before,.fa-sort-down:before{content:""}.fa-sort-asc:before,.fa-sort-up:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-gavel:before,.fa-legal:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-bolt:before,.fa-flash:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-clipboard:before,.fa-paste:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-chain-broken:before,.fa-unlink:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:""}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:""}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:""}.fa-eur:before,.fa-euro:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-inr:before,.fa-rupee:before{content:""}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:""}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:""}.fa-krw:before,.fa-won:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before,.fa-gratipay:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-try:before,.fa-turkish-lira:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li button.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-bank:before,.fa-institution:before,.fa-university:before{content:""}.fa-graduation-cap:before,.fa-mortar-board:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper-pp:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:""}.fa-file-archive-o:before,.fa-file-zip-o:before{content:""}.fa-file-audio-o:before,.fa-file-sound-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-rebel:before,.fa-resistance:before{content:""}.fa-empire:before,.fa-ge:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-hacker-news:before,.fa-y-combinator-square:before,.fa-yc-square:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-paper-plane:before,.fa-send:before{content:""}.fa-paper-plane-o:before,.fa-send-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:""}.fa-meanpath:before{content:""}.fa-buysellads:before{content:""}.fa-connectdevelop:before{content:""}.fa-dashcube:before{content:""}.fa-forumbee:before{content:""}.fa-leanpub:before{content:""}.fa-sellsy:before{content:""}.fa-shirtsinbulk:before{content:""}.fa-simplybuilt:before{content:""}.fa-skyatlas:before{content:""}.fa-cart-plus:before{content:""}.fa-cart-arrow-down:before{content:""}.fa-diamond:before{content:""}.fa-ship:before{content:""}.fa-user-secret:before{content:""}.fa-motorcycle:before{content:""}.fa-street-view:before{content:""}.fa-heartbeat:before{content:""}.fa-venus:before{content:""}.fa-mars:before{content:""}.fa-mercury:before{content:""}.fa-intersex:before,.fa-transgender:before{content:""}.fa-transgender-alt:before{content:""}.fa-venus-double:before{content:""}.fa-mars-double:before{content:""}.fa-venus-mars:before{content:""}.fa-mars-stroke:before{content:""}.fa-mars-stroke-v:before{content:""}.fa-mars-stroke-h:before{content:""}.fa-neuter:before{content:""}.fa-genderless:before{content:""}.fa-facebook-official:before{content:""}.fa-pinterest-p:before{content:""}.fa-whatsapp:before{content:""}.fa-server:before{content:""}.fa-user-plus:before{content:""}.fa-user-times:before{content:""}.fa-bed:before,.fa-hotel:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-y-combinator:before,.fa-yc:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery-full:before,.fa-battery:before{content:""}.fa-battery-3:before,.fa-battery-three-quarters:before{content:""}.fa-battery-2:before,.fa-battery-half:before{content:""}.fa-battery-1:before,.fa-battery-quarter:before{content:""}.fa-battery-0:before,.fa-battery-empty:before{content:""}.fa-mouse-pointer:before{content:""}.fa-i-cursor:before{content:""}.fa-object-group:before{content:""}.fa-object-ungroup:before{content:""}.fa-sticky-note:before{content:""}.fa-sticky-note-o:before{content:""}.fa-cc-jcb:before{content:""}.fa-cc-diners-club:before{content:""}.fa-clone:before{content:""}.fa-balance-scale:before{content:""}.fa-hourglass-o:before{content:""}.fa-hourglass-1:before,.fa-hourglass-start:before{content:""}.fa-hourglass-2:before,.fa-hourglass-half:before{content:""}.fa-hourglass-3:before,.fa-hourglass-end:before{content:""}.fa-hourglass:before{content:""}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:""}.fa-hand-paper-o:before,.fa-hand-stop-o:before{content:""}.fa-hand-scissors-o:before{content:""}.fa-hand-lizard-o:before{content:""}.fa-hand-spock-o:before{content:""}.fa-hand-pointer-o:before{content:""}.fa-hand-peace-o:before{content:""}.fa-trademark:before{content:""}.fa-registered:before{content:""}.fa-creative-commons:before{content:""}.fa-gg:before{content:""}.fa-gg-circle:before{content:""}.fa-tripadvisor:before{content:""}.fa-odnoklassniki:before{content:""}.fa-odnoklassniki-square:before{content:""}.fa-get-pocket:before{content:""}.fa-wikipedia-w:before{content:""}.fa-safari:before{content:""}.fa-chrome:before{content:""}.fa-firefox:before{content:""}.fa-opera:before{content:""}.fa-internet-explorer:before{content:""}.fa-television:before,.fa-tv:before{content:""}.fa-contao:before{content:""}.fa-500px:before{content:""}.fa-amazon:before{content:""}.fa-calendar-plus-o:before{content:""}.fa-calendar-minus-o:before{content:""}.fa-calendar-times-o:before{content:""}.fa-calendar-check-o:before{content:""}.fa-industry:before{content:""}.fa-map-pin:before{content:""}.fa-map-signs:before{content:""}.fa-map-o:before{content:""}.fa-map:before{content:""}.fa-commenting:before{content:""}.fa-commenting-o:before{content:""}.fa-houzz:before{content:""}.fa-vimeo:before{content:""}.fa-black-tie:before{content:""}.fa-fonticons:before{content:""}.fa-reddit-alien:before{content:""}.fa-edge:before{content:""}.fa-credit-card-alt:before{content:""}.fa-codiepie:before{content:""}.fa-modx:before{content:""}.fa-fort-awesome:before{content:""}.fa-usb:before{content:""}.fa-product-hunt:before{content:""}.fa-mixcloud:before{content:""}.fa-scribd:before{content:""}.fa-pause-circle:before{content:""}.fa-pause-circle-o:before{content:""}.fa-stop-circle:before{content:""}.fa-stop-circle-o:before{content:""}.fa-shopping-bag:before{content:""}.fa-shopping-basket:before{content:""}.fa-hashtag:before{content:""}.fa-bluetooth:before{content:""}.fa-bluetooth-b:before{content:""}.fa-percent:before{content:""}.fa-gitlab:before,.icon-gitlab:before{content:""}.fa-wpbeginner:before{content:""}.fa-wpforms:before{content:""}.fa-envira:before{content:""}.fa-universal-access:before{content:""}.fa-wheelchair-alt:before{content:""}.fa-question-circle-o:before{content:""}.fa-blind:before{content:""}.fa-audio-description:before{content:""}.fa-volume-control-phone:before{content:""}.fa-braille:before{content:""}.fa-assistive-listening-systems:before{content:""}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before{content:""}.fa-deaf:before,.fa-deafness:before,.fa-hard-of-hearing:before{content:""}.fa-glide:before{content:""}.fa-glide-g:before{content:""}.fa-sign-language:before,.fa-signing:before{content:""}.fa-low-vision:before{content:""}.fa-viadeo:before{content:""}.fa-viadeo-square:before{content:""}.fa-snapchat:before{content:""}.fa-snapchat-ghost:before{content:""}.fa-snapchat-square:before{content:""}.fa-pied-piper:before{content:""}.fa-first-order:before{content:""}.fa-yoast:before{content:""}.fa-themeisle:before{content:""}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:""}.fa-fa:before,.fa-font-awesome:before{content:""}.fa-handshake-o:before{content:""}.fa-envelope-open:before{content:""}.fa-envelope-open-o:before{content:""}.fa-linode:before{content:""}.fa-address-book:before{content:""}.fa-address-book-o:before{content:""}.fa-address-card:before,.fa-vcard:before{content:""}.fa-address-card-o:before,.fa-vcard-o:before{content:""}.fa-user-circle:before{content:""}.fa-user-circle-o:before{content:""}.fa-user-o:before{content:""}.fa-id-badge:before{content:""}.fa-drivers-license:before,.fa-id-card:before{content:""}.fa-drivers-license-o:before,.fa-id-card-o:before{content:""}.fa-quora:before{content:""}.fa-free-code-camp:before{content:""}.fa-telegram:before{content:""}.fa-thermometer-4:before,.fa-thermometer-full:before,.fa-thermometer:before{content:""}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:""}.fa-thermometer-2:before,.fa-thermometer-half:before{content:""}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:""}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:""}.fa-shower:before{content:""}.fa-bath:before,.fa-bathtub:before,.fa-s15:before{content:""}.fa-podcast:before{content:""}.fa-window-maximize:before{content:""}.fa-window-minimize:before{content:""}.fa-window-restore:before{content:""}.fa-times-rectangle:before,.fa-window-close:before{content:""}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:""}.fa-bandcamp:before{content:""}.fa-grav:before{content:""}.fa-etsy:before{content:""}.fa-imdb:before{content:""}.fa-ravelry:before{content:""}.fa-eercast:before{content:""}.fa-microchip:before{content:""}.fa-snowflake-o:before{content:""}.fa-superpowers:before{content:""}.fa-wpexplorer:before{content:""}.fa-meetup:before{content:""}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{font-family:inherit}.fa:before,.icon:before,.rst-content .admonition-title:before,.rst-content .code-block-caption .headerlink:before,.rst-content .eqno .headerlink:before,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before{font-family:FontAwesome;display:inline-block;font-style:normal;font-weight:400;line-height:1;text-decoration:inherit}.rst-content .code-block-caption a .headerlink,.rst-content .eqno a .headerlink,.rst-content a .admonition-title,.rst-content code.download a span:first-child,.rst-content dl dt a .headerlink,.rst-content h1 a .headerlink,.rst-content h2 a .headerlink,.rst-content h3 a .headerlink,.rst-content h4 a .headerlink,.rst-content h5 a .headerlink,.rst-content h6 a .headerlink,.rst-content p.caption a .headerlink,.rst-content p a .headerlink,.rst-content table>caption a .headerlink,.rst-content tt.download a span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li a button.toctree-expand,a .fa,a .icon,a .rst-content .admonition-title,a .rst-content .code-block-caption .headerlink,a .rst-content .eqno .headerlink,a .rst-content code.download span:first-child,a .rst-content dl dt .headerlink,a .rst-content h1 .headerlink,a .rst-content h2 .headerlink,a .rst-content h3 .headerlink,a .rst-content h4 .headerlink,a .rst-content h5 .headerlink,a .rst-content h6 .headerlink,a .rst-content p.caption .headerlink,a .rst-content p .headerlink,a .rst-content table>caption .headerlink,a .rst-content tt.download span:first-child,a .wy-menu-vertical li button.toctree-expand{display:inline-block;text-decoration:inherit}.btn .fa,.btn .icon,.btn .rst-content .admonition-title,.btn .rst-content .code-block-caption .headerlink,.btn .rst-content .eqno .headerlink,.btn .rst-content code.download span:first-child,.btn .rst-content dl dt .headerlink,.btn .rst-content h1 .headerlink,.btn .rst-content h2 .headerlink,.btn .rst-content h3 .headerlink,.btn .rst-content h4 .headerlink,.btn .rst-content h5 .headerlink,.btn .rst-content h6 .headerlink,.btn .rst-content p .headerlink,.btn .rst-content table>caption .headerlink,.btn .rst-content tt.download span:first-child,.btn .wy-menu-vertical li.current>a button.toctree-expand,.btn .wy-menu-vertical li.on a button.toctree-expand,.btn .wy-menu-vertical li button.toctree-expand,.nav .fa,.nav .icon,.nav .rst-content .admonition-title,.nav .rst-content .code-block-caption .headerlink,.nav .rst-content .eqno .headerlink,.nav .rst-content code.download span:first-child,.nav .rst-content dl dt .headerlink,.nav .rst-content h1 .headerlink,.nav .rst-content h2 .headerlink,.nav .rst-content h3 .headerlink,.nav .rst-content h4 .headerlink,.nav .rst-content h5 .headerlink,.nav .rst-content h6 .headerlink,.nav .rst-content p .headerlink,.nav .rst-content table>caption .headerlink,.nav .rst-content tt.download span:first-child,.nav .wy-menu-vertical li.current>a button.toctree-expand,.nav .wy-menu-vertical li.on a button.toctree-expand,.nav .wy-menu-vertical li button.toctree-expand,.rst-content .btn .admonition-title,.rst-content .code-block-caption .btn .headerlink,.rst-content .code-block-caption .nav .headerlink,.rst-content .eqno .btn .headerlink,.rst-content .eqno .nav .headerlink,.rst-content .nav .admonition-title,.rst-content code.download .btn span:first-child,.rst-content code.download .nav span:first-child,.rst-content dl dt .btn .headerlink,.rst-content dl dt .nav .headerlink,.rst-content h1 .btn .headerlink,.rst-content h1 .nav .headerlink,.rst-content h2 .btn .headerlink,.rst-content h2 .nav .headerlink,.rst-content h3 .btn .headerlink,.rst-content h3 .nav .headerlink,.rst-content h4 .btn .headerlink,.rst-content h4 .nav .headerlink,.rst-content h5 .btn .headerlink,.rst-content h5 .nav .headerlink,.rst-content h6 .btn .headerlink,.rst-content h6 .nav .headerlink,.rst-content p .btn .headerlink,.rst-content p .nav .headerlink,.rst-content table>caption .btn .headerlink,.rst-content table>caption .nav .headerlink,.rst-content tt.download .btn span:first-child,.rst-content tt.download .nav span:first-child,.wy-menu-vertical li .btn button.toctree-expand,.wy-menu-vertical li.current>a .btn button.toctree-expand,.wy-menu-vertical li.current>a .nav button.toctree-expand,.wy-menu-vertical li .nav button.toctree-expand,.wy-menu-vertical li.on a .btn button.toctree-expand,.wy-menu-vertical li.on a .nav button.toctree-expand{display:inline}.btn .fa-large.icon,.btn .fa.fa-large,.btn .rst-content .code-block-caption .fa-large.headerlink,.btn .rst-content .eqno .fa-large.headerlink,.btn .rst-content .fa-large.admonition-title,.btn .rst-content code.download span.fa-large:first-child,.btn .rst-content dl dt .fa-large.headerlink,.btn .rst-content h1 .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.btn .rst-content p .fa-large.headerlink,.btn .rst-content table>caption .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.btn .wy-menu-vertical li button.fa-large.toctree-expand,.nav .fa-large.icon,.nav .fa.fa-large,.nav .rst-content .code-block-caption .fa-large.headerlink,.nav .rst-content .eqno .fa-large.headerlink,.nav .rst-content .fa-large.admonition-title,.nav .rst-content code.download span.fa-large:first-child,.nav .rst-content dl dt .fa-large.headerlink,.nav .rst-content h1 .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.nav .rst-content p .fa-large.headerlink,.nav .rst-content table>caption .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.nav .wy-menu-vertical li button.fa-large.toctree-expand,.rst-content .btn .fa-large.admonition-title,.rst-content .code-block-caption .btn .fa-large.headerlink,.rst-content .code-block-caption .nav .fa-large.headerlink,.rst-content .eqno .btn .fa-large.headerlink,.rst-content .eqno .nav .fa-large.headerlink,.rst-content .nav .fa-large.admonition-title,.rst-content code.download .btn span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.rst-content dl dt .btn .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.rst-content p .btn .fa-large.headerlink,.rst-content p .nav .fa-large.headerlink,.rst-content table>caption .btn .fa-large.headerlink,.rst-content table>caption .nav .fa-large.headerlink,.rst-content tt.download .btn span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.wy-menu-vertical li .btn button.fa-large.toctree-expand,.wy-menu-vertical li .nav button.fa-large.toctree-expand{line-height:.9em}.btn .fa-spin.icon,.btn .fa.fa-spin,.btn .rst-content .code-block-caption .fa-spin.headerlink,.btn .rst-content .eqno .fa-spin.headerlink,.btn .rst-content .fa-spin.admonition-title,.btn .rst-content code.download span.fa-spin:first-child,.btn .rst-content dl dt .fa-spin.headerlink,.btn .rst-content h1 .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.btn .rst-content p .fa-spin.headerlink,.btn .rst-content table>caption .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.btn .wy-menu-vertical li button.fa-spin.toctree-expand,.nav .fa-spin.icon,.nav .fa.fa-spin,.nav .rst-content .code-block-caption .fa-spin.headerlink,.nav .rst-content .eqno .fa-spin.headerlink,.nav .rst-content .fa-spin.admonition-title,.nav .rst-content code.download span.fa-spin:first-child,.nav .rst-content dl dt .fa-spin.headerlink,.nav .rst-content h1 .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.nav .rst-content p .fa-spin.headerlink,.nav .rst-content table>caption .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.nav .wy-menu-vertical li button.fa-spin.toctree-expand,.rst-content .btn .fa-spin.admonition-title,.rst-content .code-block-caption .btn .fa-spin.headerlink,.rst-content .code-block-caption .nav .fa-spin.headerlink,.rst-content .eqno .btn .fa-spin.headerlink,.rst-content .eqno .nav .fa-spin.headerlink,.rst-content .nav .fa-spin.admonition-title,.rst-content code.download .btn span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.rst-content dl dt .btn .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.rst-content p .btn .fa-spin.headerlink,.rst-content p .nav .fa-spin.headerlink,.rst-content table>caption .btn .fa-spin.headerlink,.rst-content table>caption .nav .fa-spin.headerlink,.rst-content tt.download .btn span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.wy-menu-vertical li .btn button.fa-spin.toctree-expand,.wy-menu-vertical li .nav button.fa-spin.toctree-expand{display:inline-block}.btn.fa:before,.btn.icon:before,.rst-content .btn.admonition-title:before,.rst-content .code-block-caption .btn.headerlink:before,.rst-content .eqno .btn.headerlink:before,.rst-content code.download span.btn:first-child:before,.rst-content dl dt .btn.headerlink:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content p .btn.headerlink:before,.rst-content table>caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.wy-menu-vertical li button.btn.toctree-expand:before{opacity:.5;-webkit-transition:opacity .05s ease-in;-moz-transition:opacity .05s ease-in;transition:opacity .05s ease-in}.btn.fa:hover:before,.btn.icon:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content .code-block-caption .btn.headerlink:hover:before,.rst-content .eqno .btn.headerlink:hover:before,.rst-content code.download span.btn:first-child:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content p .btn.headerlink:hover:before,.rst-content table>caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.wy-menu-vertical li button.btn.toctree-expand:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .icon:before,.btn-mini .rst-content .admonition-title:before,.btn-mini .rst-content .code-block-caption .headerlink:before,.btn-mini .rst-content .eqno .headerlink:before,.btn-mini .rst-content code.download span:first-child:before,.btn-mini .rst-content dl dt .headerlink:before,.btn-mini .rst-content h1 .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.btn-mini .rst-content p .headerlink:before,.btn-mini .rst-content table>caption .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.btn-mini .wy-menu-vertical li button.toctree-expand:before,.rst-content .btn-mini .admonition-title:before,.rst-content .code-block-caption .btn-mini .headerlink:before,.rst-content .eqno .btn-mini .headerlink:before,.rst-content code.download .btn-mini span:first-child:before,.rst-content dl dt .btn-mini .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.rst-content p .btn-mini .headerlink:before,.rst-content table>caption .btn-mini .headerlink:before,.rst-content tt.download .btn-mini span:first-child:before,.wy-menu-vertical li .btn-mini button.toctree-expand:before{font-size:14px;vertical-align:-15%}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.wy-alert{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.rst-content .admonition-title,.wy-alert-title{font-weight:700;display:block;color:#fff;background:#6ab0de;padding:6px 12px;margin:-12px -12px 12px}.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.admonition,.rst-content .wy-alert-danger.admonition-todo,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.wy-alert.wy-alert-danger{background:#fdf3f2}.rst-content .danger .admonition-title,.rst-content .danger .wy-alert-title,.rst-content .error .admonition-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.rst-content .wy-alert-danger.admonition .admonition-title,.rst-content .wy-alert-danger.admonition .wy-alert-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.wy-alert.wy-alert-danger .wy-alert-title{background:#f29f97}.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .warning,.rst-content .wy-alert-warning.admonition,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.note,.rst-content .wy-alert-warning.seealso,.rst-content .wy-alert-warning.tip,.wy-alert.wy-alert-warning{background:#ffedcc}.rst-content .admonition-todo .admonition-title,.rst-content .admonition-todo .wy-alert-title,.rst-content .attention .admonition-title,.rst-content .attention .wy-alert-title,.rst-content .caution .admonition-title,.rst-content .caution .wy-alert-title,.rst-content .warning .admonition-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.admonition .admonition-title,.rst-content .wy-alert-warning.admonition .wy-alert-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.wy-alert.wy-alert-warning .wy-alert-title{background:#f0b37e}.rst-content .note,.rst-content .seealso,.rst-content .wy-alert-info.admonition,.rst-content .wy-alert-info.admonition-todo,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.wy-alert.wy-alert-info{background:#e7f2fa}.rst-content .note .admonition-title,.rst-content .note .wy-alert-title,.rst-content .seealso .admonition-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .admonition-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.rst-content .wy-alert-info.admonition .admonition-title,.rst-content .wy-alert-info.admonition .wy-alert-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.wy-alert.wy-alert-info .wy-alert-title{background:#6ab0de}.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.admonition,.rst-content .wy-alert-success.admonition-todo,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.warning,.wy-alert.wy-alert-success{background:#dbfaf4}.rst-content .hint .admonition-title,.rst-content .hint .wy-alert-title,.rst-content .important .admonition-title,.rst-content .important .wy-alert-title,.rst-content .tip .admonition-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .admonition-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.rst-content .wy-alert-success.admonition .admonition-title,.rst-content .wy-alert-success.admonition .wy-alert-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.wy-alert.wy-alert-success .wy-alert-title{background:#1abc9c}.rst-content .wy-alert-neutral.admonition,.rst-content .wy-alert-neutral.admonition-todo,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.wy-alert.wy-alert-neutral{background:#f3f6f6}.rst-content .wy-alert-neutral.admonition-todo .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.rst-content .wy-alert-neutral.admonition .admonition-title,.rst-content .wy-alert-neutral.admonition .wy-alert-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.wy-alert.wy-alert-neutral .wy-alert-title{color:#404040;background:#e1e4e5}.rst-content .wy-alert-neutral.admonition-todo a,.rst-content .wy-alert-neutral.admonition a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.wy-alert.wy-alert-neutral a{color:#2980b9}.rst-content .admonition-todo p:last-child,.rst-content .admonition p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .note p:last-child,.rst-content .seealso p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.wy-alert p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all .3s ease-in;-moz-transition:all .3s ease-in;transition:all .3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27ae60}.wy-tray-container li.wy-tray-item-info{background:#2980b9}.wy-tray-container li.wy-tray-item-warning{background:#e67e22}.wy-tray-container li.wy-tray-item-danger{background:#e74c3c}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width:768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px;color:#fff;border:1px solid rgba(0,0,0,.1);background-color:#27ae60;text-decoration:none;font-weight:400;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 2px -1px hsla(0,0%,100%,.5),inset 0 -2px 0 0 rgba(0,0,0,.1);outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all .1s linear;-moz-transition:all .1s linear;transition:all .1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:inset 0 -1px 0 0 rgba(0,0,0,.05),inset 0 2px 0 0 rgba(0,0,0,.1);padding:8px 12px 6px}.btn:visited{color:#fff}.btn-disabled,.btn-disabled:active,.btn-disabled:focus,.btn-disabled:hover,.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980b9!important}.btn-info:hover{background-color:#2e8ece!important}.btn-neutral{background-color:#f3f6f6!important;color:#404040!important}.btn-neutral:hover{background-color:#e5ebeb!important;color:#404040}.btn-neutral:visited{color:#404040!important}.btn-success{background-color:#27ae60!important}.btn-success:hover{background-color:#295!important}.btn-danger{background-color:#e74c3c!important}.btn-danger:hover{background-color:#ea6153!important}.btn-warning{background-color:#e67e22!important}.btn-warning:hover{background-color:#e98b39!important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f!important}.btn-link{background-color:transparent!important;color:#2980b9;box-shadow:none;border-color:transparent!important}.btn-link:active,.btn-link:hover{background-color:transparent!important;color:#409ad5!important;box-shadow:none}.btn-link:visited{color:#9b59b6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:after,.wy-btn-group:before{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:1px solid #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980b9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:1px solid #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type=search]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980b9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned .wy-help-inline,.wy-form-aligned input,.wy-form-aligned label,.wy-form-aligned select,.wy-form-aligned textarea{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{margin:0}fieldset,legend{border:0;padding:0}legend{width:100%;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label,legend{display:block}label{margin:0 0 .3125em;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;max-width:1200px;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:after,.wy-control-group:before{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#e74c3c}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full input[type=color],.wy-control-group .wy-form-full input[type=date],.wy-control-group .wy-form-full input[type=datetime-local],.wy-control-group .wy-form-full input[type=datetime],.wy-control-group .wy-form-full input[type=email],.wy-control-group .wy-form-full input[type=month],.wy-control-group .wy-form-full input[type=number],.wy-control-group .wy-form-full input[type=password],.wy-control-group .wy-form-full input[type=search],.wy-control-group .wy-form-full input[type=tel],.wy-control-group .wy-form-full input[type=text],.wy-control-group .wy-form-full input[type=time],.wy-control-group .wy-form-full input[type=url],.wy-control-group .wy-form-full input[type=week],.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves input[type=color],.wy-control-group .wy-form-halves input[type=date],.wy-control-group .wy-form-halves input[type=datetime-local],.wy-control-group .wy-form-halves input[type=datetime],.wy-control-group .wy-form-halves input[type=email],.wy-control-group .wy-form-halves input[type=month],.wy-control-group .wy-form-halves input[type=number],.wy-control-group .wy-form-halves input[type=password],.wy-control-group .wy-form-halves input[type=search],.wy-control-group .wy-form-halves input[type=tel],.wy-control-group .wy-form-halves input[type=text],.wy-control-group .wy-form-halves input[type=time],.wy-control-group .wy-form-halves input[type=url],.wy-control-group .wy-form-halves input[type=week],.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds input[type=color],.wy-control-group .wy-form-thirds input[type=date],.wy-control-group .wy-form-thirds input[type=datetime-local],.wy-control-group .wy-form-thirds input[type=datetime],.wy-control-group .wy-form-thirds input[type=email],.wy-control-group .wy-form-thirds input[type=month],.wy-control-group .wy-form-thirds input[type=number],.wy-control-group .wy-form-thirds input[type=password],.wy-control-group .wy-form-thirds input[type=search],.wy-control-group .wy-form-thirds input[type=tel],.wy-control-group .wy-form-thirds input[type=text],.wy-control-group .wy-form-thirds input[type=time],.wy-control-group .wy-form-thirds input[type=url],.wy-control-group .wy-form-thirds input[type=week],.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full{float:left;display:block;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.35765%;width:48.82117%}.wy-control-group .wy-form-halves:last-child,.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(odd){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.35765%;width:31.76157%}.wy-control-group .wy-form-thirds:last-child,.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control,.wy-control-no-input{margin:6px 0 0;font-size:90%}.wy-control-no-input{display:inline-block}.wy-control-group.fluid-input input[type=color],.wy-control-group.fluid-input input[type=date],.wy-control-group.fluid-input input[type=datetime-local],.wy-control-group.fluid-input input[type=datetime],.wy-control-group.fluid-input input[type=email],.wy-control-group.fluid-input input[type=month],.wy-control-group.fluid-input input[type=number],.wy-control-group.fluid-input input[type=password],.wy-control-group.fluid-input input[type=search],.wy-control-group.fluid-input input[type=tel],.wy-control-group.fluid-input input[type=text],.wy-control-group.fluid-input input[type=time],.wy-control-group.fluid-input input[type=url],.wy-control-group.fluid-input input[type=week]{width:100%}.wy-form-message-inline{padding-left:.3em;color:#666;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;*overflow:visible}input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}input[type=datetime-local]{padding:.34375em .625em}input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{padding:0;margin-right:.3125em;*height:13px;*width:13px}input[type=checkbox],input[type=radio],input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}input[type=color]:focus,input[type=date]:focus,input[type=datetime-local]:focus,input[type=datetime]:focus,input[type=email]:focus,input[type=month]:focus,input[type=number]:focus,input[type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=time]:focus,input[type=url]:focus,input[type=week]:focus{outline:0;outline:thin dotted\9;border-color:#333}input.no-focus:focus{border-color:#ccc!important}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:thin dotted #333;outline:1px auto #129fea}input[type=color][disabled],input[type=date][disabled],input[type=datetime-local][disabled],input[type=datetime][disabled],input[type=email][disabled],input[type=month][disabled],input[type=number][disabled],input[type=password][disabled],input[type=search][disabled],input[type=tel][disabled],input[type=text][disabled],input[type=time][disabled],input[type=url][disabled],input[type=week][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,select:focus:invalid,textarea:focus:invalid{color:#e74c3c;border:1px solid #e74c3c}input:focus:invalid:focus,select:focus:invalid:focus,textarea:focus:invalid:focus{border-color:#e74c3c}input[type=checkbox]:focus:invalid:focus,input[type=file]:focus:invalid:focus,input[type=radio]:focus:invalid:focus{outline-color:#e74c3c}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif}select,textarea{padding:.5em .625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}input[readonly],select[disabled],select[readonly],textarea[disabled],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type=checkbox][disabled],input[type=radio][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:1px solid #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{position:relative;display:block;height:24px;margin-top:12px;cursor:pointer}.wy-switch:before{left:0;top:0;width:36px;height:12px;background:#ccc}.wy-switch:after,.wy-switch:before{position:absolute;content:"";display:block;border-radius:4px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch:after{width:18px;height:18px;background:#999;left:-3px;top:-3px}.wy-switch span{position:absolute;left:48px;display:block;font-size:12px;color:#ccc;line-height:1}.wy-switch.active:before{background:#1e8449}.wy-switch.active:after{left:24px;background:#27ae60}.wy-switch.disabled{cursor:not-allowed;opacity:.8}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#e74c3c}.wy-control-group.wy-control-group-error input[type=color],.wy-control-group.wy-control-group-error input[type=date],.wy-control-group.wy-control-group-error input[type=datetime-local],.wy-control-group.wy-control-group-error input[type=datetime],.wy-control-group.wy-control-group-error input[type=email],.wy-control-group.wy-control-group-error input[type=month],.wy-control-group.wy-control-group-error input[type=number],.wy-control-group.wy-control-group-error input[type=password],.wy-control-group.wy-control-group-error input[type=search],.wy-control-group.wy-control-group-error input[type=tel],.wy-control-group.wy-control-group-error input[type=text],.wy-control-group.wy-control-group-error input[type=time],.wy-control-group.wy-control-group-error input[type=url],.wy-control-group.wy-control-group-error input[type=week],.wy-control-group.wy-control-group-error textarea{border:1px solid #e74c3c}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:.5em .625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27ae60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#e74c3c}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#e67e22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980b9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width:480px){.wy-form button[type=submit]{margin:.7em 0 0}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=text],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week],.wy-form label{margin-bottom:.3em;display:block}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0}.wy-form-message,.wy-form-message-inline,.wy-form .wy-help-inline{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width:768px){.tablet-hide{display:none}}@media screen and (max-width:480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.rst-content table.docutils,.rst-content table.field-list,.wy-table{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.rst-content table.docutils caption,.rst-content table.field-list caption,.wy-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.rst-content table.docutils td,.rst-content table.docutils th,.rst-content table.field-list td,.rst-content table.field-list th,.wy-table td,.wy-table th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.rst-content table.docutils td:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list td:first-child,.rst-content table.field-list th:first-child,.wy-table td:first-child,.wy-table th:first-child{border-left-width:0}.rst-content table.docutils thead,.rst-content table.field-list thead,.wy-table thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.rst-content table.docutils thead th,.rst-content table.field-list thead th,.wy-table thead th{font-weight:700;border-bottom:2px solid #e1e4e5}.rst-content table.docutils td,.rst-content table.field-list td,.wy-table td{background-color:transparent;vertical-align:middle}.rst-content table.docutils td p,.rst-content table.field-list td p,.wy-table td p{line-height:18px}.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child,.wy-table td p:last-child{margin-bottom:0}.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min,.wy-table .wy-table-cell-min{width:1%;padding-right:0}.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:grey;font-size:90%}.wy-table-tertiary{color:grey;font-size:80%}.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td,.wy-table-backed,.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td{background-color:#f3f6f6}.rst-content table.docutils,.wy-table-bordered-all{border:1px solid #e1e4e5}.rst-content table.docutils td,.wy-table-bordered-all td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.rst-content table.docutils tbody>tr:last-child td,.wy-table-bordered-all tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0!important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980b9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9b59b6}html{height:100%}body,html{overflow-x:hidden}body{font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;font-weight:400;color:#404040;min-height:100%;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#e67e22!important}a.wy-text-warning:hover{color:#eb9950!important}.wy-text-info{color:#2980b9!important}a.wy-text-info:hover{color:#409ad5!important}.wy-text-success{color:#27ae60!important}a.wy-text-success:hover{color:#36d278!important}.wy-text-danger{color:#e74c3c!important}a.wy-text-danger:hover{color:#ed7669!important}.wy-text-neutral{color:#404040!important}a.wy-text-neutral:hover{color:#595959!important}.rst-content .toctree-wrapper>p.caption,h1,h2,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif}p{line-height:24px;font-size:16px;margin:0 0 24px}h1{font-size:175%}.rst-content .toctree-wrapper>p.caption,h2{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}.rst-content code,.rst-content tt,code{white-space:nowrap;max-width:100%;background:#fff;border:1px solid #e1e4e5;font-size:75%;padding:0 5px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#e74c3c;overflow-x:auto}.rst-content tt.code-large,code.code-large{font-size:90%}.rst-content .section ul,.rst-content .toctree-wrapper ul,.rst-content section ul,.wy-plain-list-disc,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.rst-content .section ul li,.rst-content .toctree-wrapper ul li,.rst-content section ul li,.wy-plain-list-disc li,article ul li{list-style:disc;margin-left:24px}.rst-content .section ul li p:last-child,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li p:last-child,.rst-content .toctree-wrapper ul li ul,.rst-content section ul li p:last-child,.rst-content section ul li ul,.wy-plain-list-disc li p:last-child,.wy-plain-list-disc li ul,article ul li p:last-child,article ul li ul{margin-bottom:0}.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,.rst-content section ul li li,.wy-plain-list-disc li li,article ul li li{list-style:circle}.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,.rst-content section ul li li li,.wy-plain-list-disc li li li,article ul li li li{list-style:square}.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,.rst-content section ul li ol li,.wy-plain-list-disc li ol li,article ul li ol li{list-style:decimal}.rst-content .section ol,.rst-content .section ol.arabic,.rst-content .toctree-wrapper ol,.rst-content .toctree-wrapper ol.arabic,.rst-content section ol,.rst-content section ol.arabic,.wy-plain-list-decimal,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.rst-content .section ol.arabic li,.rst-content .section ol li,.rst-content .toctree-wrapper ol.arabic li,.rst-content .toctree-wrapper ol li,.rst-content section ol.arabic li,.rst-content section ol li,.wy-plain-list-decimal li,article ol li{list-style:decimal;margin-left:24px}.rst-content .section ol.arabic li ul,.rst-content .section ol li p:last-child,.rst-content .section ol li ul,.rst-content .toctree-wrapper ol.arabic li ul,.rst-content .toctree-wrapper ol li p:last-child,.rst-content .toctree-wrapper ol li ul,.rst-content section ol.arabic li ul,.rst-content section ol li p:last-child,.rst-content section ol li ul,.wy-plain-list-decimal li p:last-child,.wy-plain-list-decimal li ul,article ol li p:last-child,article ol li ul{margin-bottom:0}.rst-content .section ol.arabic li ul li,.rst-content .section ol li ul li,.rst-content .toctree-wrapper ol.arabic li ul li,.rst-content .toctree-wrapper ol li ul li,.rst-content section ol.arabic li ul li,.rst-content section ol li ul li,.wy-plain-list-decimal li ul li,article ol li ul li{list-style:disc}.wy-breadcrumbs{*zoom:1}.wy-breadcrumbs:after,.wy-breadcrumbs:before{display:table;content:""}.wy-breadcrumbs:after{clear:both}.wy-breadcrumbs>li{display:inline-block;padding-top:5px}.wy-breadcrumbs>li.wy-breadcrumbs-aside{float:right}.rst-content .wy-breadcrumbs>li code,.rst-content .wy-breadcrumbs>li tt,.wy-breadcrumbs>li .rst-content tt,.wy-breadcrumbs>li code{all:inherit;color:inherit}.breadcrumb-item:before{content:"/";color:#bbb;font-size:13px;padding:0 6px 0 3px}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width:480px){.wy-breadcrumbs-extra,.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}html{font-size:16px}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:after,.wy-menu-horiz:before{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz li,.wy-menu-horiz ul{display:inline-block}.wy-menu-horiz li:hover{background:hsla(0,0%,100%,.1)}.wy-menu-horiz li.divide-left{border-left:1px solid #404040}.wy-menu-horiz li.divide-right{border-right:1px solid #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{color:#55a5d9;height:32px;line-height:32px;padding:0 1.618em;margin:12px 0 0;display:block;font-weight:700;text-transform:uppercase;font-size:85%;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:1px solid #404040}.wy-menu-vertical li.divide-bottom{border-bottom:1px solid #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:grey;border-right:1px solid #c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.rst-content .wy-menu-vertical li tt,.wy-menu-vertical li .rst-content tt,.wy-menu-vertical li code{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li button.toctree-expand{display:block;float:left;margin-left:-1.2em;line-height:18px;color:#4d4d4d;border:none;background:none;padding:0}.wy-menu-vertical li.current>a,.wy-menu-vertical li.on a{color:#404040;font-weight:700;position:relative;background:#fcfcfc;border:none;padding:.4045em 1.618em}.wy-menu-vertical li.current>a:hover,.wy-menu-vertical li.on a:hover{background:#fcfcfc}.wy-menu-vertical li.current>a:hover button.toctree-expand,.wy-menu-vertical li.on a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand{display:block;line-height:18px;color:#333}.wy-menu-vertical li.toctree-l1.current>a{border-bottom:1px solid #c9c9c9;border-top:1px solid #c9c9c9}.wy-menu-vertical .toctree-l1.current .toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .toctree-l11>ul{display:none}.wy-menu-vertical .toctree-l1.current .current.toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .current.toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .current.toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .current.toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .current.toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .current.toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .current.toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .current.toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .current.toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .current.toctree-l11>ul{display:block}.wy-menu-vertical li.toctree-l3,.wy-menu-vertical li.toctree-l4{font-size:.9em}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l4 a,.wy-menu-vertical li.toctree-l5 a,.wy-menu-vertical li.toctree-l6 a,.wy-menu-vertical li.toctree-l7 a,.wy-menu-vertical li.toctree-l8 a,.wy-menu-vertical li.toctree-l9 a,.wy-menu-vertical li.toctree-l10 a{color:#404040}.wy-menu-vertical li.toctree-l2 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l3 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l4 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l5 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l6 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l7 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l8 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l9 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l10 a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a,.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a,.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a,.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a,.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a,.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a,.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a,.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{display:block}.wy-menu-vertical li.toctree-l2.current>a{padding:.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{padding:.4045em 1.618em .4045em 4.045em}.wy-menu-vertical li.toctree-l3.current>a{padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{padding:.4045em 1.618em .4045em 5.663em}.wy-menu-vertical li.toctree-l4.current>a{padding:.4045em 5.663em}.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a{padding:.4045em 1.618em .4045em 7.281em}.wy-menu-vertical li.toctree-l5.current>a{padding:.4045em 7.281em}.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a{padding:.4045em 1.618em .4045em 8.899em}.wy-menu-vertical li.toctree-l6.current>a{padding:.4045em 8.899em}.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a{padding:.4045em 1.618em .4045em 10.517em}.wy-menu-vertical li.toctree-l7.current>a{padding:.4045em 10.517em}.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a{padding:.4045em 1.618em .4045em 12.135em}.wy-menu-vertical li.toctree-l8.current>a{padding:.4045em 12.135em}.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a{padding:.4045em 1.618em .4045em 13.753em}.wy-menu-vertical li.toctree-l9.current>a{padding:.4045em 13.753em}.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a{padding:.4045em 1.618em .4045em 15.371em}.wy-menu-vertical li.toctree-l10.current>a{padding:.4045em 15.371em}.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{padding:.4045em 1.618em .4045em 16.989em}.wy-menu-vertical li.toctree-l2.current>a,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{background:#c9c9c9}.wy-menu-vertical li.toctree-l2 button.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3.current>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{background:#bdbdbd}.wy-menu-vertical li.toctree-l3 button.toctree-expand{color:#969696}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical li ul li a{margin-bottom:0;color:#d9d9d9;font-weight:400}.wy-menu-vertical a{line-height:18px;padding:.4045em 1.618em;display:block;position:relative;font-size:90%;color:#d9d9d9}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover button.toctree-expand{color:#d9d9d9}.wy-menu-vertical a:active{background-color:#2980b9;cursor:pointer;color:#fff}.wy-menu-vertical a:active button.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:.809em;margin-bottom:.809em;z-index:200;background-color:#2980b9;text-align:center;color:#fcfcfc}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto .809em;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-side-nav-search .wy-dropdown>a,.wy-side-nav-search>a{color:#fcfcfc;font-size:100%;font-weight:700;display:inline-block;padding:4px 6px;margin-bottom:.809em;max-width:100%}.wy-side-nav-search .wy-dropdown>a:hover,.wy-side-nav-search>a:hover{background:hsla(0,0%,100%,.1)}.wy-side-nav-search .wy-dropdown>a img.logo,.wy-side-nav-search>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search .wy-dropdown>a.icon img.logo,.wy-side-nav-search>a.icon img.logo{margin-top:.85em}.wy-side-nav-search>div.version{margin-top:-.4045em;margin-bottom:.809em;font-weight:400;color:hsla(0,0%,100%,.3)}.wy-nav .wy-menu-vertical header{color:#2980b9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980b9;color:#fff}[data-menu-wrap]{-webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;transition:all .2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:#fcfcfc}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;color:#9b9b9b;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980b9;color:#fff;padding:.4045em .809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:after,.wy-nav-top:before{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:700}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer;padding-top:inherit}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:grey}footer p{margin-bottom:12px}.rst-content footer span.commit tt,footer span.commit .rst-content tt,footer span.commit code{padding:0;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:1em;background:none;border:none;color:grey}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:after,.rst-footer-buttons:before{width:100%;display:table;content:""}.rst-footer-buttons:after{clear:both}.rst-breadcrumbs-buttons{margin-top:12px;*zoom:1}.rst-breadcrumbs-buttons:after,.rst-breadcrumbs-buttons:before{display:table;content:""}.rst-breadcrumbs-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:1px solid #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:1px solid #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:grey;font-size:90%}.genindextable li>ul{margin-left:24px}@media screen and (max-width:768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-menu.wy-menu-vertical,.wy-side-nav-search,.wy-side-scroll{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width:1100px){.wy-nav-content-wrap{background:rgba(0,0,0,.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,.wy-nav-side,footer{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60;*zoom:1}.rst-versions .rst-current-version:after,.rst-versions .rst-current-version:before{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-content .code-block-caption .rst-versions .rst-current-version .headerlink,.rst-content .eqno .rst-versions .rst-current-version .headerlink,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-content p .rst-versions .rst-current-version .headerlink,.rst-content table>caption .rst-versions .rst-current-version .headerlink,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .icon,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-versions .rst-current-version .rst-content .code-block-caption .headerlink,.rst-versions .rst-current-version .rst-content .eqno .headerlink,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-versions .rst-current-version .rst-content p .headerlink,.rst-versions .rst-current-version .rst-content table>caption .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-versions .rst-current-version .wy-menu-vertical li button.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version button.toctree-expand{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}.rst-content .toctree-wrapper>p.caption,.rst-content h1,.rst-content h2,.rst-content h3,.rst-content h4,.rst-content h5,.rst-content h6{margin-bottom:24px}.rst-content img{max-width:100%;height:auto}.rst-content div.figure,.rst-content figure{margin-bottom:24px}.rst-content div.figure .caption-text,.rst-content figure .caption-text{font-style:italic}.rst-content div.figure p:last-child.caption,.rst-content figure p:last-child.caption{margin-bottom:0}.rst-content div.figure.align-center,.rst-content figure.align-center{text-align:center}.rst-content .section>a>img,.rst-content .section>img,.rst-content section>a>img,.rst-content section>img{margin-bottom:24px}.rst-content abbr[title]{text-decoration:none}.rst-content.style-external-links a.reference.external:after{font-family:FontAwesome;content:"\f08e";color:#b3b3b3;vertical-align:super;font-size:60%;margin:0 .2em}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content pre.literal-block{white-space:pre;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;display:block;overflow:auto}.rst-content div[class^=highlight],.rst-content pre.literal-block{border:1px solid #e1e4e5;overflow-x:auto;margin:1px 0 24px}.rst-content div[class^=highlight] div[class^=highlight],.rst-content pre.literal-block div[class^=highlight]{padding:0;border:none;margin:0}.rst-content div[class^=highlight] td.code{width:100%}.rst-content .linenodiv pre{border-right:1px solid #e6e9ea;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;user-select:none;pointer-events:none}.rst-content div[class^=highlight] pre{white-space:pre;margin:0;padding:12px;display:block;overflow:auto}.rst-content div[class^=highlight] pre .hll{display:block;margin:0 -12px;padding:0 12px}.rst-content .linenodiv pre,.rst-content div[class^=highlight] pre,.rst-content pre.literal-block{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:12px;line-height:1.4}.rst-content div.highlight .gp,.rst-content div.highlight span.linenos{user-select:none;pointer-events:none}.rst-content div.highlight span.linenos{display:inline-block;padding-left:0;padding-right:12px;margin-right:12px;border-right:1px solid #e6e9ea}.rst-content .code-block-caption{font-style:italic;font-size:85%;line-height:1;padding:1em 0;text-align:center}@media print{.rst-content .codeblock,.rst-content div[class^=highlight],.rst-content div[class^=highlight] pre{white-space:pre-wrap}}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning{clear:both}.rst-content .admonition-todo .last,.rst-content .admonition-todo>:last-child,.rst-content .admonition .last,.rst-content .admonition>:last-child,.rst-content .attention .last,.rst-content .attention>:last-child,.rst-content .caution .last,.rst-content .caution>:last-child,.rst-content .danger .last,.rst-content .danger>:last-child,.rst-content .error .last,.rst-content .error>:last-child,.rst-content .hint .last,.rst-content .hint>:last-child,.rst-content .important .last,.rst-content .important>:last-child,.rst-content .note .last,.rst-content .note>:last-child,.rst-content .seealso .last,.rst-content .seealso>:last-child,.rst-content .tip .last,.rst-content .tip>:last-child,.rst-content .warning .last,.rst-content .warning>:last-child{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent!important;border-color:rgba(0,0,0,.1)!important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha>li,.rst-content .toctree-wrapper ol.loweralpha,.rst-content .toctree-wrapper ol.loweralpha>li,.rst-content section ol.loweralpha,.rst-content section ol.loweralpha>li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha>li,.rst-content .toctree-wrapper ol.upperalpha,.rst-content .toctree-wrapper ol.upperalpha>li,.rst-content section ol.upperalpha,.rst-content section ol.upperalpha>li{list-style:upper-alpha}.rst-content .section ol li>*,.rst-content .section ul li>*,.rst-content .toctree-wrapper ol li>*,.rst-content .toctree-wrapper ul li>*,.rst-content section ol li>*,.rst-content section ul li>*{margin-top:12px;margin-bottom:12px}.rst-content .section ol li>:first-child,.rst-content .section ul li>:first-child,.rst-content .toctree-wrapper ol li>:first-child,.rst-content .toctree-wrapper ul li>:first-child,.rst-content section ol li>:first-child,.rst-content section ul li>:first-child{margin-top:0}.rst-content .section ol li>p,.rst-content .section ol li>p:last-child,.rst-content .section ul li>p,.rst-content .section ul li>p:last-child,.rst-content .toctree-wrapper ol li>p,.rst-content .toctree-wrapper ol li>p:last-child,.rst-content .toctree-wrapper ul li>p,.rst-content .toctree-wrapper ul li>p:last-child,.rst-content section ol li>p,.rst-content section ol li>p:last-child,.rst-content section ul li>p,.rst-content section ul li>p:last-child{margin-bottom:12px}.rst-content .section ol li>p:only-child,.rst-content .section ol li>p:only-child:last-child,.rst-content .section ul li>p:only-child,.rst-content .section ul li>p:only-child:last-child,.rst-content .toctree-wrapper ol li>p:only-child,.rst-content .toctree-wrapper ol li>p:only-child:last-child,.rst-content .toctree-wrapper ul li>p:only-child,.rst-content .toctree-wrapper ul li>p:only-child:last-child,.rst-content section ol li>p:only-child,.rst-content section ol li>p:only-child:last-child,.rst-content section ul li>p:only-child,.rst-content section ul li>p:only-child:last-child{margin-bottom:0}.rst-content .section ol li>ol,.rst-content .section ol li>ul,.rst-content .section ul li>ol,.rst-content .section ul li>ul,.rst-content .toctree-wrapper ol li>ol,.rst-content .toctree-wrapper ol li>ul,.rst-content .toctree-wrapper ul li>ol,.rst-content .toctree-wrapper ul li>ul,.rst-content section ol li>ol,.rst-content section ol li>ul,.rst-content section ul li>ol,.rst-content section ul li>ul{margin-bottom:12px}.rst-content .section ol.simple li>*,.rst-content .section ol.simple li ol,.rst-content .section ol.simple li ul,.rst-content .section ul.simple li>*,.rst-content .section ul.simple li ol,.rst-content .section ul.simple li ul,.rst-content .toctree-wrapper ol.simple li>*,.rst-content .toctree-wrapper ol.simple li ol,.rst-content .toctree-wrapper ol.simple li ul,.rst-content .toctree-wrapper ul.simple li>*,.rst-content .toctree-wrapper ul.simple li ol,.rst-content .toctree-wrapper ul.simple li ul,.rst-content section ol.simple li>*,.rst-content section ol.simple li ol,.rst-content section ol.simple li ul,.rst-content section ul.simple li>*,.rst-content section ul.simple li ol,.rst-content section ul.simple li ul{margin-top:0;margin-bottom:0}.rst-content .line-block{margin-left:0;margin-bottom:24px;line-height:24px}.rst-content .line-block .line-block{margin-left:24px;margin-bottom:0}.rst-content .topic-title{font-weight:700;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0 0 24px 24px}.rst-content .align-left{float:left;margin:0 24px 24px 0}.rst-content .align-center{margin:auto}.rst-content .align-center:not(table){display:block}.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink{opacity:0;font-size:14px;font-family:FontAwesome;margin-left:.5em}.rst-content .code-block-caption .headerlink:focus,.rst-content .code-block-caption:hover .headerlink,.rst-content .eqno .headerlink:focus,.rst-content .eqno:hover .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink:focus,.rst-content .toctree-wrapper>p.caption:hover .headerlink,.rst-content dl dt .headerlink:focus,.rst-content dl dt:hover .headerlink,.rst-content h1 .headerlink:focus,.rst-content h1:hover .headerlink,.rst-content h2 .headerlink:focus,.rst-content h2:hover .headerlink,.rst-content h3 .headerlink:focus,.rst-content h3:hover .headerlink,.rst-content h4 .headerlink:focus,.rst-content h4:hover .headerlink,.rst-content h5 .headerlink:focus,.rst-content h5:hover .headerlink,.rst-content h6 .headerlink:focus,.rst-content h6:hover .headerlink,.rst-content p.caption .headerlink:focus,.rst-content p.caption:hover .headerlink,.rst-content p .headerlink:focus,.rst-content p:hover .headerlink,.rst-content table>caption .headerlink:focus,.rst-content table>caption:hover .headerlink{opacity:1}.rst-content p a{overflow-wrap:anywhere}.rst-content .wy-table td p,.rst-content .wy-table td ul,.rst-content .wy-table th p,.rst-content .wy-table th ul,.rst-content table.docutils td p,.rst-content table.docutils td ul,.rst-content table.docutils th p,.rst-content table.docutils th ul,.rst-content table.field-list td p,.rst-content table.field-list td ul,.rst-content table.field-list th p,.rst-content table.field-list th ul{font-size:inherit}.rst-content .btn:focus{outline:2px solid}.rst-content table>caption .headerlink:after{font-size:12px}.rst-content .centered{text-align:center}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:1px solid #e1e4e5}.rst-content .sidebar dl,.rst-content .sidebar p,.rst-content .sidebar ul{font-size:90%}.rst-content .sidebar .last,.rst-content .sidebar>:last-child{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif;font-weight:700;background:#e1e4e5;padding:6px 12px;margin:-24px -24px 24px;font-size:100%}.rst-content .highlighted{background:#f1c40f;box-shadow:0 0 0 2px #f1c40f;display:inline;font-weight:700}.rst-content .citation-reference,.rst-content .footnote-reference{vertical-align:baseline;position:relative;top:-.4em;line-height:0;font-size:90%}.rst-content .citation-reference>span.fn-bracket,.rst-content .footnote-reference>span.fn-bracket{display:none}.rst-content .hlist{width:100%}.rst-content dl dt span.classifier:before{content:" : "}.rst-content dl dt span.classifier-delimiter{display:none!important}html.writer-html4 .rst-content table.docutils.citation,html.writer-html4 .rst-content table.docutils.footnote{background:none;border:none}html.writer-html4 .rst-content table.docutils.citation td,html.writer-html4 .rst-content table.docutils.citation tr,html.writer-html4 .rst-content table.docutils.footnote td,html.writer-html4 .rst-content table.docutils.footnote tr{border:none;background-color:transparent!important;white-space:normal}html.writer-html4 .rst-content table.docutils.citation td.label,html.writer-html4 .rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{display:grid;grid-template-columns:auto minmax(80%,95%)}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{display:inline-grid;grid-template-columns:max-content auto}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{display:grid;grid-template-columns:auto auto minmax(.65rem,auto) minmax(40%,95%)}html.writer-html5 .rst-content aside.citation>span.label,html.writer-html5 .rst-content aside.footnote>span.label,html.writer-html5 .rst-content div.citation>span.label{grid-column-start:1;grid-column-end:2}html.writer-html5 .rst-content aside.citation>span.backrefs,html.writer-html5 .rst-content aside.footnote>span.backrefs,html.writer-html5 .rst-content div.citation>span.backrefs{grid-column-start:2;grid-column-end:3;grid-row-start:1;grid-row-end:3}html.writer-html5 .rst-content aside.citation>p,html.writer-html5 .rst-content aside.footnote>p,html.writer-html5 .rst-content div.citation>p{grid-column-start:4;grid-column-end:5}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{margin-bottom:24px}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{padding-left:1rem}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dd,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dd,html.writer-html5 .rst-content dl.footnote>dt{margin-bottom:0}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{font-size:.9rem}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.footnote>dt{margin:0 .5rem .5rem 0;line-height:1.2rem;word-break:break-all;font-weight:400}html.writer-html5 .rst-content dl.citation>dt>span.brackets:before,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:before{content:"["}html.writer-html5 .rst-content dl.citation>dt>span.brackets:after,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:after{content:"]"}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a{word-break:keep-all}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a:not(:first-child):before,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.footnote>dd{margin:0 0 .5rem;line-height:1.2rem}html.writer-html5 .rst-content dl.citation>dd p,html.writer-html5 .rst-content dl.footnote>dd p{font-size:.9rem}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{padding-left:1rem;padding-right:1rem;font-size:.9rem;line-height:1.2rem}html.writer-html5 .rst-content aside.citation p,html.writer-html5 .rst-content aside.footnote p,html.writer-html5 .rst-content div.citation p{font-size:.9rem;line-height:1.2rem;margin-bottom:12px}html.writer-html5 .rst-content aside.citation span.backrefs,html.writer-html5 .rst-content aside.footnote span.backrefs,html.writer-html5 .rst-content div.citation span.backrefs{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content aside.citation span.backrefs>a,html.writer-html5 .rst-content aside.footnote span.backrefs>a,html.writer-html5 .rst-content div.citation span.backrefs>a{word-break:keep-all}html.writer-html5 .rst-content aside.citation span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content aside.footnote span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content div.citation span.backrefs>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content aside.citation span.label,html.writer-html5 .rst-content aside.footnote span.label,html.writer-html5 .rst-content div.citation span.label{line-height:1.2rem}html.writer-html5 .rst-content aside.citation-list,html.writer-html5 .rst-content aside.footnote-list,html.writer-html5 .rst-content div.citation-list{margin-bottom:24px}html.writer-html5 .rst-content dl.option-list kbd{font-size:.9rem}.rst-content table.docutils.footnote,html.writer-html4 .rst-content table.docutils.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content aside.footnote-list aside.footnote,html.writer-html5 .rst-content div.citation-list>div.citation,html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{color:grey}.rst-content table.docutils.footnote code,.rst-content table.docutils.footnote tt,html.writer-html4 .rst-content table.docutils.citation code,html.writer-html4 .rst-content table.docutils.citation tt,html.writer-html5 .rst-content aside.footnote-list aside.footnote code,html.writer-html5 .rst-content aside.footnote-list aside.footnote tt,html.writer-html5 .rst-content aside.footnote code,html.writer-html5 .rst-content aside.footnote tt,html.writer-html5 .rst-content div.citation-list>div.citation code,html.writer-html5 .rst-content div.citation-list>div.citation tt,html.writer-html5 .rst-content dl.citation code,html.writer-html5 .rst-content dl.citation tt,html.writer-html5 .rst-content dl.footnote code,html.writer-html5 .rst-content dl.footnote tt{color:#555}.rst-content .wy-table-responsive.citation,.rst-content .wy-table-responsive.footnote{margin-bottom:0}.rst-content .wy-table-responsive.citation+:not(.citation),.rst-content .wy-table-responsive.footnote+:not(.footnote){margin-top:24px}.rst-content .wy-table-responsive.citation:last-child,.rst-content .wy-table-responsive.footnote:last-child{margin-bottom:24px}.rst-content table.docutils th{border-color:#e1e4e5}html.writer-html5 .rst-content table.docutils th{border:1px solid #e1e4e5}html.writer-html5 .rst-content table.docutils td>p,html.writer-html5 .rst-content table.docutils th>p{line-height:1rem;margin-bottom:0;font-size:.9rem}.rst-content table.docutils td .last,.rst-content table.docutils td .last>:last-child{margin-bottom:0}.rst-content table.field-list,.rst-content table.field-list td{border:none}.rst-content table.field-list td p{line-height:inherit}.rst-content table.field-list td>strong{display:inline-block}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left}.rst-content code,.rst-content tt{color:#000;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;padding:2px 5px}.rst-content code big,.rst-content code em,.rst-content tt big,.rst-content tt em{font-size:100%!important;line-height:normal}.rst-content code.literal,.rst-content tt.literal{color:#e74c3c;white-space:normal}.rst-content code.xref,.rst-content tt.xref,a .rst-content code,a .rst-content tt{font-weight:700;color:#404040;overflow-wrap:normal}.rst-content kbd,.rst-content pre,.rst-content samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace}.rst-content a code,.rst-content a tt{color:#2980b9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:700;margin-bottom:12px}.rst-content dl ol,.rst-content dl p,.rst-content dl table,.rst-content dl ul{margin-bottom:12px}.rst-content dl dd{margin:0 0 12px 24px;line-height:24px}.rst-content dl dd>ol:last-child,.rst-content dl dd>p:last-child,.rst-content dl dd>table:last-child,.rst-content dl dd>ul:last-child{margin-bottom:0}html.writer-html4 .rst-content dl:not(.docutils),html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple){margin-bottom:24px}html.writer-html4 .rst-content dl:not(.docutils)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{display:table;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980b9;border-top:3px solid #6ab0de;padding:6px;position:relative}html.writer-html4 .rst-content dl:not(.docutils)>dt:before,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:before{color:#6ab0de}html.writer-html4 .rst-content dl:not(.docutils)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{margin-bottom:6px;border:none;border-left:3px solid #ccc;background:#f0f0f0;color:#555}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils)>dt:first-child,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:first-child{margin-top:0}html.writer-html4 .rst-content dl:not(.docutils) code.descclassname,html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descclassname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{background-color:transparent;border:none;padding:0;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .optional,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .property,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .property{display:inline-block;padding-right:8px;max-width:100%}html.writer-html4 .rst-content dl:not(.docutils) .k,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .k{font-style:italic}html.writer-html4 .rst-content dl:not(.docutils) .descclassname,html.writer-html4 .rst-content dl:not(.docutils) .descname,html.writer-html4 .rst-content dl:not(.docutils) .sig-name,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .sig-name{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#000}.rst-content .viewcode-back,.rst-content .viewcode-link{display:inline-block;color:#27ae60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:700}.rst-content code.download,.rst-content tt.download{background:inherit;padding:inherit;font-weight:400;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content code.download span:first-child,.rst-content tt.download span:first-child{-webkit-font-smoothing:subpixel-antialiased}.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{margin-right:4px}.rst-content .guilabel,.rst-content .menuselection{font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}.rst-content .guilabel,.rst-content .menuselection{border:1px solid #7fbbe3;background:#e7f2fa}.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>.kbd,.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>kbd{color:inherit;font-size:80%;background-color:#fff;border:1px solid #a6a6a6;border-radius:4px;box-shadow:0 2px grey;padding:2.4px 6px;margin:auto 0}.rst-content .versionmodified{font-style:italic}@media screen and (max-width:480px){.rst-content .sidebar{width:100%}}span[id*=MathJax-Span]{color:#404040}.math{text-align:center}@font-face{font-family:Lato;src:url(fonts/lato-normal.woff2?bd03a2cc277bbbc338d464e679fe9942) format("woff2"),url(fonts/lato-normal.woff?27bd77b9162d388cb8d4c4217c7c5e2a) format("woff");font-weight:400;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold.woff2?cccb897485813c7c256901dbca54ecf2) format("woff2"),url(fonts/lato-bold.woff?d878b6c29b10beca227e9eef4246111b) format("woff");font-weight:700;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold-italic.woff2?0b6bb6725576b072c5d0b02ecdd1900d) format("woff2"),url(fonts/lato-bold-italic.woff?9c7e4e9eb485b4a121c760e61bc3707c) format("woff");font-weight:700;font-style:italic;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-normal-italic.woff2?4eb103b4d12be57cb1d040ed5e162e9d) format("woff2"),url(fonts/lato-normal-italic.woff?f28f2d6482446544ef1ea1ccc6dd5892) format("woff");font-weight:400;font-style:italic;font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:400;src:url(fonts/Roboto-Slab-Regular.woff2?7abf5b8d04d26a2cafea937019bca958) format("woff2"),url(fonts/Roboto-Slab-Regular.woff?c1be9284088d487c5e3ff0a10a92e58c) format("woff");font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:700;src:url(fonts/Roboto-Slab-Bold.woff2?9984f4a9bda09be08e83f2506954adbe) format("woff2"),url(fonts/Roboto-Slab-Bold.woff?bed5564a116b05148e3b3bea6fb1162a) format("woff");font-display:block} \ No newline at end of file diff --git a/docs/_build/html/_static/custom.css b/docs/_build/html/_static/custom.css deleted file mode 100644 index 2a924f1..0000000 --- a/docs/_build/html/_static/custom.css +++ /dev/null @@ -1 +0,0 @@ -/* This file intentionally left blank. */ diff --git a/docs/_build/html/_static/jquery.js b/docs/_build/html/_static/jquery.js new file mode 100644 index 0000000..c4c6022 --- /dev/null +++ b/docs/_build/html/_static/jquery.js @@ -0,0 +1,2 @@ +/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=y.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=y.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),y.elements=c+" "+a,j(b)}function f(a){var b=x[a[v]];return b||(b={},w++,a[v]=w,x[w]=b),b}function g(a,c,d){if(c||(c=b),q)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():u.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||t.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),q)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return y.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(y,b.frag)}function j(a){a||(a=b);var d=f(a);return!y.shivCSS||p||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),q||i(a,d),a}function k(a){for(var b,c=a.getElementsByTagName("*"),e=c.length,f=RegExp("^(?:"+d().join("|")+")$","i"),g=[];e--;)b=c[e],f.test(b.nodeName)&&g.push(b.applyElement(l(b)));return g}function l(a){for(var b,c=a.attributes,d=c.length,e=a.ownerDocument.createElement(A+":"+a.nodeName);d--;)b=c[d],b.specified&&e.setAttribute(b.nodeName,b.nodeValue);return e.style.cssText=a.style.cssText,e}function m(a){for(var b,c=a.split("{"),e=c.length,f=RegExp("(^|[\\s,>+~])("+d().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),g="$1"+A+"\\:$2";e--;)b=c[e]=c[e].split("}"),b[b.length-1]=b[b.length-1].replace(f,g),c[e]=b.join("}");return c.join("{")}function n(a){for(var b=a.length;b--;)a[b].removeNode()}function o(a){function b(){clearTimeout(g._removeSheetTimer),d&&d.removeNode(!0),d=null}var d,e,g=f(a),h=a.namespaces,i=a.parentWindow;return!B||a.printShived?a:("undefined"==typeof h[A]&&h.add(A),i.attachEvent("onbeforeprint",function(){b();for(var f,g,h,i=a.styleSheets,j=[],l=i.length,n=Array(l);l--;)n[l]=i[l];for(;h=n.pop();)if(!h.disabled&&z.test(h.media)){try{f=h.imports,g=f.length}catch(o){g=0}for(l=0;g>l;l++)n.push(f[l]);try{j.push(h.cssText)}catch(o){}}j=m(j.reverse().join("")),e=k(a),d=c(a,j)}),i.attachEvent("onafterprint",function(){n(e),clearTimeout(g._removeSheetTimer),g._removeSheetTimer=setTimeout(b,500)}),a.printShived=!0,a)}var p,q,r="3.7.3",s=a.html5||{},t=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,u=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",w=0,x={};!function(){try{var a=b.createElement("a");a.innerHTML="",p="hidden"in a,q=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){p=!0,q=!0}}();var y={elements:s.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:r,shivCSS:s.shivCSS!==!1,supportsUnknownElements:q,shivMethods:s.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=y,j(b);var z=/^$|\b(?:all|print)\b/,A="html5shiv",B=!q&&function(){var c=b.documentElement;return!("undefined"==typeof b.namespaces||"undefined"==typeof b.parentWindow||"undefined"==typeof c.applyElement||"undefined"==typeof c.removeNode||"undefined"==typeof a.attachEvent)}();y.type+=" print",y.shivPrint=o,o(b),"object"==typeof module&&module.exports&&(module.exports=y)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/docs/_build/html/_static/js/html5shiv.min.js b/docs/_build/html/_static/js/html5shiv.min.js new file mode 100644 index 0000000..cd1c674 --- /dev/null +++ b/docs/_build/html/_static/js/html5shiv.min.js @@ -0,0 +1,4 @@ +/** +* @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed +*/ +!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3-pre",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/docs/_build/html/_static/js/theme.js b/docs/_build/html/_static/js/theme.js new file mode 100644 index 0000000..1fddb6e --- /dev/null +++ b/docs/_build/html/_static/js/theme.js @@ -0,0 +1 @@ +!function(n){var e={};function t(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return n[i].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=n,t.c=e,t.d=function(n,e,i){t.o(n,e)||Object.defineProperty(n,e,{enumerable:!0,get:i})},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.t=function(n,e){if(1&e&&(n=t(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var i=Object.create(null);if(t.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var o in n)t.d(i,o,function(e){return n[e]}.bind(null,o));return i},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.p="",t(t.s=0)}([function(n,e,t){t(1),n.exports=t(3)},function(n,e,t){(function(){var e="undefined"!=typeof window?window.jQuery:t(2);n.exports.ThemeNav={navBar:null,win:null,winScroll:!1,winResize:!1,linkScroll:!1,winPosition:0,winHeight:null,docHeight:null,isRunning:!1,enable:function(n){var t=this;void 0===n&&(n=!0),t.isRunning||(t.isRunning=!0,e((function(e){t.init(e),t.reset(),t.win.on("hashchange",t.reset),n&&t.win.on("scroll",(function(){t.linkScroll||t.winScroll||(t.winScroll=!0,requestAnimationFrame((function(){t.onScroll()})))})),t.win.on("resize",(function(){t.winResize||(t.winResize=!0,requestAnimationFrame((function(){t.onResize()})))})),t.onResize()})))},enableSticky:function(){this.enable(!0)},init:function(n){n(document);var e=this;this.navBar=n("div.wy-side-scroll:first"),this.win=n(window),n(document).on("click","[data-toggle='wy-nav-top']",(function(){n("[data-toggle='wy-nav-shift']").toggleClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift")})).on("click",".wy-menu-vertical .current ul li a",(function(){var t=n(this);n("[data-toggle='wy-nav-shift']").removeClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift"),e.toggleCurrent(t),e.hashChange()})).on("click","[data-toggle='rst-current-version']",(function(){n("[data-toggle='rst-versions']").toggleClass("shift-up")})),n("table.docutils:not(.field-list,.footnote,.citation)").wrap("
"),n("table.docutils.footnote").wrap("
"),n("table.docutils.citation").wrap("
"),n(".wy-menu-vertical ul").not(".simple").siblings("a").each((function(){var t=n(this);expand=n(''),expand.on("click",(function(n){return e.toggleCurrent(t),n.stopPropagation(),!1})),t.prepend(expand)}))},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),t=e.find('[href="'+n+'"]');if(0===t.length){var i=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(t=e.find('[href="#'+i.attr("id")+'"]')).length&&(t=e.find('[href="#"]'))}if(t.length>0){$(".wy-menu-vertical .current").removeClass("current").attr("aria-expanded","false"),t.addClass("current").attr("aria-expanded","true"),t.closest("li.toctree-l1").parent().addClass("current").attr("aria-expanded","true");for(let n=1;n<=10;n++)t.closest("li.toctree-l"+n).addClass("current").attr("aria-expanded","true");t[0].scrollIntoView()}}catch(n){console.log("Error expanding nav for anchor",n)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,t=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(t),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",(function(){this.linkScroll=!1}))},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current").attr("aria-expanded","false"),e.siblings().find("li.current").removeClass("current").attr("aria-expanded","false");var t=e.find("> ul li");t.length&&(t.removeClass("current").attr("aria-expanded","false"),e.toggleClass("current").attr("aria-expanded",(function(n,e){return"true"==e?"false":"true"})))}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:n.exports.ThemeNav,StickyNav:n.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],t=0;t + + + - - - - - - Authors — Python Media Streaming Framework for Linux documentation - - - - - + + Authors — Python Media Streaming Framework for Linux documentation + + + + + + + + + + + + + + + - - - - - - - - - - -
-
-
- - -
- -
-

Authors

-

Sampsa Riikonen (sampsa.riikonen _at_ iki.fi)

-
+ + + + + + + + + + +
+
- -
-
- + + +
+ +
+
+
+ +
+
+
+
+ +
+

Authors

+

Sampsa Riikonen (sampsa.riikonen _at_ iki.fi)

+
- - - - - + +
+
+
+
+ + + \ No newline at end of file diff --git a/docs/_build/html/benchmarking.html b/docs/_build/html/benchmarking.html index ac5c679..62ffd8e 100644 --- a/docs/_build/html/benchmarking.html +++ b/docs/_build/html/benchmarking.html @@ -1,37 +1,165 @@ + + + - - - - + + Benchmarking — Python Media Streaming Framework for Linux documentation + + + - Benchmarking — Python Media Streaming Framework for Linux documentation - - - - - + + + + + + + + + + + - - - + + + - - + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+
-

Benchmarking

+

Benchmarking

not up-do-date / maintained

Here you will find some tabulated benchmark tests. Tests are performed (if not otherwise mentioned) with the PyQt testsuite program “test_studio_1.py”. Parameters are same as in that program. Some abbreviations are used:

@@ -54,7 +182,7 @@

Benchmarking -

Benchmarks

+

Benchmarks

(in newest-first order)

@@ -152,118 +280,31 @@

Benchmarks -
- - +
-
- - - - - - - - - - + \ No newline at end of file diff --git a/docs/_build/html/cloud.html b/docs/_build/html/cloud.html index 58df4d9..8a8dbab 100644 --- a/docs/_build/html/cloud.html +++ b/docs/_build/html/cloud.html @@ -1,39 +1,167 @@ + + + - - - - - - Cloud Streaming — Python Media Streaming Framework for Linux documentation - - - - - + + Cloud Streaming — Python Media Streaming Framework for Linux documentation + + + + + + + + + + + + + + + - - - + + + - - + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+
-

Cloud Streaming

+

Cloud Streaming

Here we describe how to stream live, low latency video from your IP cameras to cloud and how to visualize the live video in a web browser.

A good video container format for this is “fragmented MP4” (frag-MP4 aka FMP4). This is basically the same format you have in those .mp4 files of yours, but it is fragmented into smaller chunks (aka “boxes”), so that it can be sent, chunk-by-chunk, @@ -62,118 +190,34 @@

+
- -
-
- -
-
- - - - - - - - + + + + + \ No newline at end of file diff --git a/docs/_build/html/debugging.html b/docs/_build/html/debugging.html index 4dea9d7..ec41fb2 100644 --- a/docs/_build/html/debugging.html +++ b/docs/_build/html/debugging.html @@ -1,39 +1,167 @@ + + + - - - - - - Debugging — Python Media Streaming Framework for Linux documentation - - - - - + + Debugging — Python Media Streaming Framework for Linux documentation + + + + + + + + + + + + + + + - - - + + + - - + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+
-

Debugging

+

Debugging

segfaults, memleaks, etc.

LibValkka is rigorously “valgrinded” to remove any memory leaks at the cpp level. However, combining cpp and python (with swig) and throwing into the mix multithreading, multiprocessing and sharing memory between processes, can (and will) give surprises.

@@ -76,118 +204,34 @@

Debugging -
- - - - - - - - - +

-
-
- - - - - - - - +
+
+ + + \ No newline at end of file diff --git a/docs/_build/html/decoding.html b/docs/_build/html/decoding.html index 20b80f9..b647383 100644 --- a/docs/_build/html/decoding.html +++ b/docs/_build/html/decoding.html @@ -1,46 +1,180 @@ + + + - - - - - - Decoding — Python Media Streaming Framework for Linux documentation - - - - - + + Decoding — Python Media Streaming Framework for Linux documentation + + + + + + + + + + + + + + + - - - + + + - - + + + + + + + +
+ + +
-
- +
+
+
+ +
+
+
+
+
-

Decoding

+

Decoding

-

Single thread

+

Single thread

By default, libValkka uses only a single core per decoder (the decoding threads can also be bound to a certain core - see the testsuite for more details).

This is a good idea if you have a large number of light streams. What is exactly a light stream depends on your linux box, but let’s assume here that it is a 1080p video running approx. at 20 frames per second.

-

Multithread

+

Multithread

If you need to use a single heavy stream, then you might want to dedicate several cores in decoding a single stream. A heavy stream could be example that 4000x3000 4K camera of yours running at 60 frames per second (!)

However, before using such a beast, you must ask yourself, do you really need something like that?

The biggest screen you’ll ever be viewing the video from, is probably 1080p, while a framerate of 15 fps is good for the human eye. Modern convoluted neural networks (yolo, for example), are using typically a resolution of ~ 600x600 pixels and analyzing max. 30 frames per seconds. And we still haven’t talked about clogging up your LAN.

@@ -52,7 +186,7 @@

Multithread -

GPU Accelerated

+

GPU Accelerated

Hardware (hw) accelerated decoders are available in libValkka. For more details, please see here. However, before using them, you should ask yourself if you really need them. Maybe it is better to save all GPU muscle for deep learning inference instead?

Video hw acceleration libraries are typically closed-source implementations, and the underlying “black-box” can be poorly implemented and suffer from @@ -62,7 +196,7 @@

Multithread -

Queueing frames

+

Queueing frames

Typically, when decoding H264 video, handling the intra-frame takes much more time than decoding the consecutive B- and P-frames. This is very pronounced for heavy streams (see above).

Because of that the intra frame will arrive late for the presentation, while the consecutive frames arrive in a burst.

This problem can be solved with buffering. Modify tutorial’s lesson 3 like this:

@@ -103,124 +237,34 @@

Multithread -

-
-
- - - - - - - - - + \ No newline at end of file diff --git a/docs/_build/html/genindex.html b/docs/_build/html/genindex.html index 6c6937f..74c6b9e 100644 --- a/docs/_build/html/genindex.html +++ b/docs/_build/html/genindex.html @@ -1,91 +1,119 @@ + + + + + Index — Python Media Streaming Framework for Linux documentation + + + - - - - - Index — Python Media Streaming Framework for Linux documentation - - - - - - - - - - - - - - + + + + + + + + + + + + + + -
-
-
- - -
- - -

Index

- -
- -
- + + + + + + + +
+
- -
-
- + + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+
+
+ + +

Index

+ +
+ +
+ - +
+
+
- - - - +
+
+
+
+
+ + + \ No newline at end of file diff --git a/docs/_build/html/hardware.html b/docs/_build/html/hardware.html index bb738f9..c0354b7 100644 --- a/docs/_build/html/hardware.html +++ b/docs/_build/html/hardware.html @@ -1,41 +1,176 @@ + + + - - - - - - Supported hardware — Python Media Streaming Framework for Linux documentation - - - - - + + Supported hardware — Python Media Streaming Framework for Linux documentation + + + + + + + + + + + + + + + - - - + + + - - + + + + + + + +
+ + +
-
- +
+
+
+ +
+
+
+
+
-

Supported hardware

+

Supported hardware

-

IP Cameras

+

IP Cameras

OnVif compliant IP cameras (supporting the RTSP protocol)

Initial configuration of IP cameras can be a hurdle:

Many IP cameras typically require a half-broken Active-X (!) web-extension you have to download @@ -48,16 +183,16 @@

IP Cameras -

USB Cameras

+

USB Cameras

USB Cameras capable of streaming H264

We have tested against Logitech HD Pro Webcam C920

-

Codecs

+

Codecs

For the moment, the only supported codec is H264

-

Linux clients

+

Linux clients

libValkka uses OpenGL and OpenGL texture streaming, so it needs a robust OpenGL implementation. The current situation is:

-
-
- - - - - - - - - + \ No newline at end of file diff --git a/docs/_build/html/index.html b/docs/_build/html/index.html index 9b3af34..df15e16 100644 --- a/docs/_build/html/index.html +++ b/docs/_build/html/index.html @@ -1,40 +1,168 @@ - - - - - + + + - Valkka — Python Media Streaming Framework for Linux documentation - - - - - + + Valkka — Python Media Streaming Framework for Linux documentation + + + + + + + + + + + + + + + - - - + + + - - + + + + + + + +
+ -
-
-
- +
-
- +
+
+
+ +
+
+
+
+
-

Valkka

+

Valkka

Valkka is a python media streaming framework

Create video streaming and surveillance solutions purely in Python. No need to go C++ ever again.

Some highlights of Valkka

@@ -165,118 +293,33 @@

Valkka +

- -
-
- -
-
- - - - - - - - - + \ No newline at end of file diff --git a/docs/_build/html/intro.html b/docs/_build/html/intro.html index 5841449..954684f 100644 --- a/docs/_build/html/intro.html +++ b/docs/_build/html/intro.html @@ -1,41 +1,174 @@ + + + - - - - - - About Valkka — Python Media Streaming Framework for Linux documentation - - - - - + + About Valkka — Python Media Streaming Framework for Linux documentation + + + + + + + + + + + + + + + - - - + + + - - + + + + + + + +
+ -
- +
+ +
+
+
+ +
+
+
+
+
-

About Valkka

+

About Valkka

-

Why this library?

+

Why this library?

So, yet another media player? I need to stream video from my IP camera into my python/Qt program and I want something that can be developed fast and is easy to integrate into my code. What’s here for me?

If you just need to stream video from your IP cameras, decode it and show it on the screen, we recommend a standard media player, @@ -50,7 +183,7 @@

Why this library? -

Valkka API

+

Valkka API

Valkka will solve the problem for you; It is a programming library and an API to do just that - large scale video surveillance, management and analysis programs, from the comfort of python3.

With Valkka, you can create complex pipings (“filtergraphs”) of media streams from the camera, to screen, machine vision subroutines, to disk, to the net, etc. The code runs at the cpp level with threads, thread-safe queues, mutexes, semaphores, etc. All those gory details are hidden from the API user that programs filtergraphs at the python level only. Valkka can also share frames between python processes (and from there, with OpenCV, TensorFlow, etc.)

If you got interested, we recommend that you do the tutorial, and use it together with the PyQt testsuite, @@ -73,7 +206,7 @@

Valkka API -

The Project

+

The Project

In Valkka, the “streaming pipeline” from IP cameras to decoders and to the GPU has been completely re-thinked and written from scratch:

-
-
- - - - - - - - - + \ No newline at end of file diff --git a/docs/_build/html/knowledge.html b/docs/_build/html/knowledge.html index 93ebc73..c41205e 100644 --- a/docs/_build/html/knowledge.html +++ b/docs/_build/html/knowledge.html @@ -1,41 +1,177 @@ + + + - - - - + + Knowledge Base — Python Media Streaming Framework for Linux documentation + + + - Knowledge Base — Python Media Streaming Framework for Linux documentation - - - - - + + + + + + + + + + + - - - + + + - - + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+
-

Knowledge Base

+

Knowledge Base

Tips, instructions, etc. for compiling libValkka, Qt & Yolo on out-of-the-ordinary hardware

-

General

+

General

When compiling and generating yourself python binary packages these commands come handy:

pip3 wheel --wheel-dir=YOUR_DIRECTORY -r requirements.txt
 pip3 install --no-index --find-links=YOUR_DIRECTORY -r requirements.txt
@@ -50,7 +186,7 @@ 

General

-

OpenCV & OpenCV contrib

+

OpenCV & OpenCV contrib

Normally you might install OpenCV & its python bindings just with

pip3 install --user --upgrade opencv-python opencv-contrib-python
 
@@ -109,9 +245,9 @@

OpenCV & OpenCV contrib -

Jetson Nano

+

Jetson Nano

-

Qt Python Bindings

+

Qt Python Bindings

There are two flavors of Qt Python bindings, namely, PyQt and PySide2. Here we deal with the latter. If you have information on PyQt on JetsonNano, please do send us an email.

PySide2 Qt python bindings are not available for all architectures simply from pypi using pip3 install command. This is the case for Jetson Nano. So we have to compile ourselves.

Install clang, build tools, Qt module clang header files, etc:

@@ -163,123 +299,33 @@

Qt Python Bindings -

-
-
- - - - - - - - - + \ No newline at end of file diff --git a/docs/_build/html/lesson_1.html b/docs/_build/html/lesson_1.html index ecde6c2..b173010 100644 --- a/docs/_build/html/lesson_1.html +++ b/docs/_build/html/lesson_1.html @@ -1,65 +1,219 @@ + + + - - - - - - Lesson 1 : Receiving frames from an IP camera — Python Media Streaming Framework for Linux documentation - - - - - + + Lesson 1 : Receiving frames from an IP camera — Python Media Streaming Framework for Linux documentation + + + + + + + + + + + + + + + - - - + + + - - + + + + + + + +
+ -
- +
+ +
+
+
+ +
+
+
+
+
-

Lesson 1 : Receiving frames from an IP camera

+

Lesson 1 : Receiving frames from an IP camera

-

A single FrameFilter

+

A single FrameFilter

Download lesson [here]

Import the valkka level 1 API:

-
import time
+
import time
 from valkka.core import *
 

Create a starting point for a FrameFilter chain:

-
live_out_filter =InfoFrameFilter("live_out_filter")
+
live_out_filter =InfoFrameFilter("live_out_filter")
 

This is the “entry point” where we receive all the frames.

InfoFrameFilter does nothing fancy - it just prints out the frames it receives.

However, as you will learn during this tutorial, FrameFilters can do a lot of stuff. You can chain them together. They can be used to fork and copy the stream into complex graphs, etc.

Next we need a thread that feeds the frames into our FrameFilter, so we instantiate a LiveThread:

-
livethread =LiveThread("livethread")
+
livethread =LiveThread("livethread")
 

We also need a context describing the connection to an IP camera:

-
ctx =LiveConnectionContext(LiveConnectionType_rtsp, "rtsp://admin:nordic12345@192.168.1.41", 1, live_out_filter)
+
ctx =LiveConnectionContext(LiveConnectionType_rtsp, "rtsp://admin:nordic12345@192.168.1.41", 1, live_out_filter)
 

The first parameter defines the device type, which in this case is an IP camera using the rtsp protocol. Note that we include the “entry point” live_out_filter. The integer parameter “1” is the slot number - it will be discussed in detail later on in this tutorial.

Finally, we can start streaming frames from the IP camera:

-
livethread.startCall()
+
livethread.startCall()
 livethread.registerStreamCall(ctx)
 livethread.playStreamCall(ctx)
 time.sleep(5)
@@ -93,12 +247,9 @@ 

Lesson 1 : Receiving frames from an IP cameraNote

The code itself (LiveThread, InfoFrameFilter) runs in c++, while the connections are programmed here, at the python level

-
.. end of inclusion from "snippets/lesson_1_a.py_"
-
-
-

Chaining FrameFilters

+

Chaining FrameFilters

Download lesson [here]

In the previous example, we had a thread (LiveThread), feeding a single FrameFilter (InfoFrameFilter). The “filtergraph” for this case looks like this:

(LiveThread:livethread) --> {InfoFrameFilter:live_out_filter}
@@ -110,7 +261,7 @@ 

Chaining FrameFilters

That chain can be created in python like this:

-
-

Forking FrameFilters

+

Forking FrameFilters

Download lesson [here]

As a final trivial example for this lesson, we fork the FrameFilter chain into two:

-

FrameFilter reference

+

FrameFilter reference

API level 1 considered in this lesson, is nothing but cpp code wrapped to python.

To see all available FrameFilters, refer to the cpp documentation.

In the cpp docs, only a small part of the member methods are wrapped and visible from python (these are marked with the “pyapi” tag)

@@ -214,7 +359,7 @@

FrameFilter reference

-

Controlling verbosity

+

Controlling verbosity

If libValkka dumps too much to your terminal, you can shut if off by using loglevel_silent.

Verbosity can be controlled like this:

from valkka.api2.logging import setValkkaLogLevel, setLogLevel_livelogger, loglevel_silent, loglevel_normal
@@ -227,123 +372,34 @@ 

Controlling verbosity +

- -
-
- -
-
- - - - - - - - - + \ No newline at end of file diff --git a/docs/_build/html/lesson_10.html b/docs/_build/html/lesson_10.html index d83037f..d50ec4b 100644 --- a/docs/_build/html/lesson_10.html +++ b/docs/_build/html/lesson_10.html @@ -1,39 +1,186 @@ + + + - - - - - - Lesson 10 : USB Cameras — Python Media Streaming Framework for Linux documentation - - - - - + + Lesson 10 : USB Cameras — Python Media Streaming Framework for Linux documentation + + + + + + + + + + + + + + + - - - + + + - - + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+
-

Lesson 10 : USB Cameras

+

Lesson 10 : USB Cameras

Valkka has experimental support for H264 streaming USB Cameras. To see if your camera supports H264 streaming, use the following command:

v4l2-ctl --list-formats -d /dev/video2
 
@@ -44,7 +191,7 @@

Lesson 10 : USB Cameras

The only difference to handling IP cameras is that a different thread (USBDeviceThread) is used to stream the video.

Download lesson [here]

-
import time
+
import time
 from valkka.core import *
 glthread        =OpenGLThread ("glthread")
 gl_in_filter    =glthread.getFrameFilter()
@@ -54,11 +201,11 @@ 

Lesson 10 : USB Cameras

USBDeviceThread reads and multiplexes all USB cameras

-
usbthread       =USBDeviceThread("usbthread")
+
usbthread       =USBDeviceThread("usbthread")
 

Define the usb camera (/dev/video2) and where it is going to be streamed (to av_in_filter with slot number 1):

-
- - - - - - - - +

+
+ + + \ No newline at end of file diff --git a/docs/_build/html/lesson_11.html b/docs/_build/html/lesson_11.html index 5979e88..963820f 100644 --- a/docs/_build/html/lesson_11.html +++ b/docs/_build/html/lesson_11.html @@ -1,39 +1,194 @@ + + + - - - - - - Lesson 11 : ValkkaFS — Python Media Streaming Framework for Linux documentation - - - - - + + Lesson 11 : ValkkaFS — Python Media Streaming Framework for Linux documentation + + + + + + + + + + + + + + + - - - + + + - - + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+
-

Lesson 11 : ValkkaFS

+

Lesson 11 : ValkkaFS

As you learned from earlier lessons, you can redirect video streams to matroska (.mkv) video files.

Here we’ll be streaming video to the custom ValkkaFS filesystem.

ValkkaFS dumps video to a dedicated file, or to an entire partition or disk. Arriving H264 frames are written in their arriving time order, into the same (large) file that is organized in blocks. @@ -41,7 +196,7 @@

Here we provide several examples for writing to and reading from ValkkaFS. These include importing video from ValkkaFS to matroska, and caching frames from ValkkaFS and passing them downstream at play speed.

In a typical VMS application, writing and reading run concurrently: writing thread dumps frames continuously to the disk, while reading thread is evoked only at user’s request.

-

Writing

+

Writing

Let’s start by dumping video from IP cameras into ValkkaFS.

Download lesson [here]

This will be our filtergraph:

@@ -49,19 +204,19 @@

Writing

Let’s import valkka level 1 API, and ValkkaSingleFS from level 2 API:

-
import time
+
import time
 from valkka.core import *
 from valkka.fs import ValkkaSingleFS
 from valkka.api2 import loglevel_debug, loglevel_normal, loglevel_crazy
 

Let’s set our IP camera’s address:

-
rtsp_address="rtsp://admin:12345@192.168.0.157"
+
rtsp_address="rtsp://admin:12345@192.168.0.157"
 

If you want to see the filesystem writing each frame, enable these debugging loggers:

-
#setLogLevel_filelogger(loglevel_crazy)
+
#setLogLevel_filelogger(loglevel_crazy)
 #setLogLevel_valkkafslogger(loglevel_crazy)
 
@@ -71,7 +226,7 @@

Writing¶ file.

The ValkkaSingleFS instance handles the metadata of the filesystem. Let’s create a new filesystem and save the metadata into directory /tmp/testvalkkafs

-
valkkafs = ValkkaSingleFS.newFromDirectory(
+
 

Next, we create and start (1) the thread responsible for writing the frames into ValkkaFS and (2) LiveThread that is reading the cameras:

-
writerthread = ValkkaFSWriterThread("writer", valkkafs.core)
+
writerthread = ValkkaFSWriterThread("writer", valkkafs.core)
 livethread = LiveThread("livethread")
 

All cameras write to the same FrameFilter, handled by the writing thread:

-

-

Reading 1

+

Reading 1

In these following two examples, we request frames from ValkkaFS

Download lesson [here]

Same imports as before:

-
import time, sys
+
import time, sys
 from valkka.core import *
 from valkka.fs import ValkkaSingleFS
 

Load ValkkaFS metadata:

-
valkkafs = ValkkaSingleFS.loadFromDirectory(dirname="/tmp/testvalkkafs")
+
valkkafs = ValkkaSingleFS.loadFromDirectory(dirname="/tmp/testvalkkafs")
 

Let’s take a look at the blocktable:

-
a = valkkafs.getBlockTable()
+
a = valkkafs.getBlockTable()
 print(a)
 

Construct the filterchain: write from the reader thread into the verbose InfoFrameFilter

-
out_filter =InfoFrameFilter("reader_out_filter")
+
out_filter =InfoFrameFilter("reader_out_filter")
 readerthread = ValkkaFSReaderThread("reader", valkkafs.core, out_filter)
 

Start the reader thread:

-
readerthread.startCall()
+
readerthread.startCall()
 

Frames with id number 925412 are mapped into slot 1:

-
readerthread.setSlotIdCall(1, 925412)
+
readerthread.setSlotIdCall(1, 925412)
 

Request blocks 0, 1 from the reader thread. Information of frames from these blocks are dumped on the terminal

-
readerthread.pullBlocksPyCall([0,1])
+
readerthread.pullBlocksPyCall([0,1])
 time.sleep(1)
 

Exit the thread:

-
readerthread.stopCall()
+
readerthread.stopCall()
 print("bye")
 
-

Reading 2

+

Reading 2

Download lesson [here]

-
import time, sys
+
import time, sys
 from valkka.core import *
 from valkka.fs import ValkkaSingleFS
 

Load ValkkaFS metadata:

-
valkkafs = ValkkaSingleFS.loadFromDirectory(dirname="/tmp/testvalkkafs")
+
valkkafs = ValkkaSingleFS.loadFromDirectory(dirname="/tmp/testvalkkafs")
 

Let’s take a look at the blocktable:

-
a = valkkafs.getBlockTable()
+
a = valkkafs.getBlockTable()
 print(a)
 

Instantiate ValkkaFSTool that allows us to peek into the written data

-
-

Matroska export

+

Matroska export

Let’s start by recalling the very first lesson. There we saw how LiveThread sends Setup Frames at streaming initialization. Setup frames are used all over the libValkka infrastructure, to carry information about the video stream, to signal the stream start and to initialize decoders, muxers, etc.

On the other hand, ValkkaFSReaderThread is designed to be a simple beast: it does not have any notion of stream initialization. It simply provides frames on a per-block basis.

We must use a special FrameFilter called InitStreamFrameFilter, in order to add the Setup Frames into the stream.

Download lesson [here]

Same imports as before:

-
-

Playing frames

+

Playing frames

As you learned in the previous examples of this section, ValkkaFSReader pushes frames downstream in “bursts”, several blocks worth of frames in a single shot.

However, we also need something that passes recorded frames downstream (say, for visualization and/or for transmission) at “play speed” (say, at that 25 fps).

This is achieved with FrameCacherThread, which caches, seeks and passes frames downstream at play speed.

@@ -349,7 +501,7 @@

Playing frames[here]

Same imports as before:

-
import time, sys
+
import time, sys
 from valkka.core import *
 from valkka.api2 import loglevel_debug, loglevel_normal
 from valkka.fs import ValkkaSingleFS
@@ -358,11 +510,11 @@ 

Playing frames
valkkafs = ValkkaSingleFS.loadFromDirectory(dirname="/tmp/testvalkkafs")
+
valkkafs = ValkkaSingleFS.loadFromDirectory(dirname="/tmp/testvalkkafs")
 

Let’s take a look at the blocktable:

-
a = valkkafs.getBlockTable()
+
a = valkkafs.getBlockTable()
 print(a)
 
@@ -378,18 +530,18 @@

Playing frames
out_filter   = InfoFrameFilter("out_filter") # will be registered later with cacherthread
+
out_filter   = InfoFrameFilter("out_filter") # will be registered later with cacherthread
 cacherthread = FileCacheThread("cacher")
 readerthread = ValkkaFSReaderThread("reader", valkkafs.core, cacherthread.getFrameFilter()) # ValkkaFSReaderThread => FileCacheThread
 

Next, define callbacks for FileCacheThread

Define a global variable: a tuple that holds the min and max millisecond timestamps of cached frames:

-
current_time_limits = None
+
current_time_limits = None
 

This following function will be called frequently by FileCacheThread to inform us about the current millisecond timestamp:

-
def current_time_callback(mstime: int):
+
def current_time_callback(mstime: int):
     global current_time_limits
     try:
         print("current time", mstime)
@@ -410,7 +562,7 @@ 

Playing frames
def time_limits_callback(times: tuple):
+
def time_limits_callback(times: tuple):
     global current_time_limits
     try:
         print("new time limits", times)
@@ -432,42 +584,42 @@ 

Playing frames
cacherthread.setPyCallback(current_time_callback)
+
cacherthread.setPyCallback(current_time_callback)
 cacherthread.setPyCallback2(time_limits_callback)
 

Start the threads

-
cacherthread.startCall()
+
cacherthread.startCall()
 readerthread.startCall()
 

Frames saved with id number 925412 to ValkkaFS are mapped into slot number 1:

-
readerthread.setSlotIdCall(1, 925412)
+
readerthread.setSlotIdCall(1, 925412)
 

FileCacheThread will write frames with slot number 1 into InfoFrameFilter:

-
ctx = FileStreamContext(1, out_filter)
+
ctx = FileStreamContext(1, out_filter)
 cacherthread.registerStreamCall(ctx)
 

Request blocks 0-4 from the reader thread. The frames will be cached by FileCacheThread.

-
readerthread.pullBlocksPyCall([0,1,3,4])
+
readerthread.pullBlocksPyCall([0,1,3,4])
 

Before frames can be played, a seek must be performed to set a time reference.

-
mstimestamp = int(a[1,0]) # take the first timestamp from the blocktable.  Use int() to convert to normal python integer.
+
mstimestamp = int(a[1,0]) # take the first timestamp from the blocktable.  Use int() to convert to normal python integer.
 print("seeking to", mstimestamp)
 cacherthread.seekStreamsCall(mstimestamp)
 

It’s up to the API user to assure that the used mstimestamp is within the correct limits (i.e. requested blocks).

Next, let the stream play for 10 seconds

-
cacherthread.playStreamsCall()
+
cacherthread.playStreamsCall()
 time.sleep(10)
 

Stop threads

-
cacherthread.stopCall()
+
-    
-
-    
-
-    
-    
-    
-  
+    

+
+ + + \ No newline at end of file diff --git a/docs/_build/html/lesson_2.html b/docs/_build/html/lesson_2.html index 089d320..28aff3a 100644 --- a/docs/_build/html/lesson_2.html +++ b/docs/_build/html/lesson_2.html @@ -1,39 +1,186 @@ + + + - - - - + + Lesson 2 : Decoding — Python Media Streaming Framework for Linux documentation + + + - Lesson 2 : Decoding — Python Media Streaming Framework for Linux documentation - - - - - + + + + + + + + + + + - - - + + + - - + + + + + + -
-
-
- +
+ + +
+ +
+
+
+ +
+
+
+
+
-

Lesson 2 : Decoding

+

Lesson 2 : Decoding

Download lesson [here]

Let’s consider the following filtergraph:

Streaming part               | Decoding part
@@ -67,7 +214,7 @@ 

Lesson 2 : Decoding
# decoding part
+
# decoding part
 info_filter     =InfoFrameFilter("info_filter")
 avthread        =AVThread("avthread",info_filter)
 
@@ -76,17 +223,17 @@

Lesson 2 : Decodinghardware accelerator, then you could substitute AVThread with VAAPIThread instead.

Next, we need a framefilter to feed the frames into AVThread. This framefilter is requested from the AVThread itself:

-
# streaming part
+
# streaming part
 av_in_filter    =avthread.getFrameFilter()
 livethread      =LiveThread("livethread")
 

Finally, proceed as before: pass av_in_filter as a parameter to the connection context, start threads, etc.

-
ctx =LiveConnectionContext(LiveConnectionType_rtsp, "rtsp://admin:nordic12345@192.168.1.41", 1, av_in_filter)
+
ctx =LiveConnectionContext(LiveConnectionType_rtsp, "rtsp://admin:nordic12345@192.168.1.41", 1, av_in_filter)
 

Start threads. Starting the threads should be done in end-to-beginning order (in the same order we constructed the filterchain).

-
avthread.startCall()
+
avthread.startCall()
 livethread.startCall()
 
 # start decoding
@@ -101,7 +248,7 @@ 

Lesson 2 : Decoding
livethread.stopCall()
+

When using the API to pass frames between threads, that’s all you need to know for now.

“Under the hood”, however, things are a bit more complex.

The framefilter requested from AVThread writes into AVThread’s internal FrameFifo. This is a first-in-first-out queue where a copy of the incoming frame is placed. Frames are copied into pre-reserved frames, taken from a pre-reserved stack. Both the fifo and the stack are thread-safe and mutex-protected. The user has the possibility to define the size of the stack when instantiating AVThread.

@@ -139,123 +283,34 @@

Lesson 2 : Decoding -

-
-
- - - - - - - - - + \ No newline at end of file diff --git a/docs/_build/html/lesson_3.html b/docs/_build/html/lesson_3.html index e0b9577..f2240c1 100644 --- a/docs/_build/html/lesson_3.html +++ b/docs/_build/html/lesson_3.html @@ -1,41 +1,193 @@ + + + - - - - - - Lesson 3 : Streaming to the X-window system — Python Media Streaming Framework for Linux documentation - - - - - + + Lesson 3 : Streaming to the X-window system — Python Media Streaming Framework for Linux documentation + + + + + + + + + + + + + + + - - - + + + - - + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+
-

Lesson 3 : Streaming to the X-window system

+

Lesson 3 : Streaming to the X-window system

-

One camera to one window

+

One camera to one window

Download lesson [here]

Let’s consider the following filtergraph with streaming, decoding and presentation:

Streaming part
@@ -54,13 +206,13 @@ 

Lesson 3 : Streaming to the X-window system
# presentation part
+
# presentation part
 glthread        =OpenGLThread ("glthread")
 gl_in_filter    =glthread.getFrameFilter()
 

We requested a framefilter from the OpenGLThread. It is passed to the AVThread:

-
# decoding part
+
# decoding part
 avthread        =AVThread("avthread",gl_in_filter)
 av_in_filter    =avthread.getFrameFilter()
 
@@ -69,12 +221,12 @@ 

Lesson 3 : Streaming to the X-window system
# ctx =LiveConnectionContext(LiveConnectionType_rtsp, "rtsp://admin:nordic12345@192.168.1.41", 1, av_in_filter)
+
# ctx =LiveConnectionContext(LiveConnectionType_rtsp, "rtsp://admin:nordic12345@192.168.1.41", 1, av_in_filter)
 ctx =LiveConnectionContext(LiveConnectionType_rtsp, "rtsp://admin:12345@192.168.0.157", 1, av_in_filter)
 

Start all threads, start decoding, and register the live stream. Starting the threads should be done in end-to-beginning order (in the same order we constructed the filterchain).

-
glthread.startCall()
+

-

One camera to several windows

+

One camera to several windows

Download lesson [here]

Streaming the same camera to several X windows is trivial; we just need to add more render groups (aka x windows) and render contexes (mappings):

-
id_list=[]
+
id_list=[]
 
 for i in range(10):
   window_id =glthread.createWindow()
@@ -166,7 +318,7 @@ 

One camera to several windows -

Decoding multiple streams

+

Decoding multiple streams

Download lesson [here]

Let’s consider decoding the H264 streams from multiple RTSP cameras. For that, we’ll be needing several decoding AVThreads. Let’s take another look at the filtergraph:

Streaming part
@@ -181,7 +333,7 @@ 

Decoding multiple streamslibrary architecture page

It’s a good idea to encapsulate the decoding part into its own class. This class takes as an input, the framefilter where it writes the decoded frames and as an input, the stream rtsp address:

-

+
- -
-
- -
-
- - - - - - - - +

+
+ + + \ No newline at end of file diff --git a/docs/_build/html/lesson_4.html b/docs/_build/html/lesson_4.html index d926d3b..08b643b 100644 --- a/docs/_build/html/lesson_4.html +++ b/docs/_build/html/lesson_4.html @@ -1,45 +1,201 @@ + + + - - - - - - Lesson 4 : Receiving Frames at Python — Python Media Streaming Framework for Linux documentation - - - - - + + Lesson 4 : Receiving Frames at Python — Python Media Streaming Framework for Linux documentation + + + + + + + + + + + + + + + - - - + + + - - + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+
-

Lesson 4 : Receiving Frames at Python

+

Lesson 4 : Receiving Frames at Python

Here we start with two separate python programs: (1) a server that reads RTSP cameras and writes RGB frames into shared memory and (2) a client that reads those RGB frames from memory. For the client program, two versions are provided, the API level 2 being the most compact one.

Such scheme is only for demo/tutorial purposes. Normally you would start both the server and client from within the same python program. We give an example of that as well.

-

Server side

+

Server side

Download server side [here]

By now, we have learned how to receive, decode and send streams to the x window system. In this chapter, we do all that, but at the same time, also send copies of the decoded frames to another python process.

The filtergraph looks like this:

@@ -58,7 +214,7 @@

Server side
# define yuv=>rgb interpolation interval
+
# define yuv=>rgb interpolation interval
 image_interval=1000  # YUV => RGB interpolation to the small size is done each 1000 milliseconds and passed on to the shmem ringbuffer
 
 # define rgb image dimensions
@@ -67,13 +223,13 @@ 

Server side
# posix shared memory
+
# posix shared memory
 shmem_name    ="lesson_4"      # This identifies posix shared memory - must be unique
 shmem_buffers =10              # Size of the shmem ringbuffer
 

Next, we construct the filterchain as usual, from end-to-beginning:

-
# branch 1
+
# branch 1
 glthread        =OpenGLThread("glthread")
 gl_in_filter    =glthread.getFrameFilter()
 
@@ -93,12 +249,12 @@ 

Server side
# ctx =LiveConnectionContext(LiveConnectionType_rtsp, "rtsp://admin:nordic12345@192.168.1.41", 1, av_in_filter)
+
# ctx =LiveConnectionContext(LiveConnectionType_rtsp, "rtsp://admin:nordic12345@192.168.1.41", 1, av_in_filter)
 ctx =LiveConnectionContext(LiveConnectionType_rtsp, "rtsp://admin:123456@192.168.0.134", 1, av_in_filter)
 

Start processes, stream for 60 seconds and exit:

-

-

Client side: openCV

+

Client side: openCV

Download client side openCV example [here]

OpenCV is a popular machine vision library. We modify the previous example to make it work with openCV like this:

-
-

Server + Client

+

Server + Client

Download server + client example [here]

Here we have a complete example running both server & client within the same python file.

You could wrap the client part further into a python thread, releasing your main python process @@ -284,7 +441,7 @@

Server + Client

-
# define yuv=>rgb interpolation interval
+
# define yuv=>rgb interpolation interval
 image_interval=1000  # YUV => RGB interpolation to the small size is done each 1000 milliseconds and passed on to the shmem ringbuffer
 
 # define rgb image dimensions
@@ -308,13 +465,13 @@ 

Server + Client
# posix shared memory
+
# posix shared memory
 shmem_name    ="lesson_4"      # This identifies posix shared memory - must be unique
 shmem_buffers =10              # Size of the shmem ringbuffer
 

Next, we construct the filterchain as usual, from end-to-beginning:

-
# branch 1
+
# branch 1
 glthread        =OpenGLThread("glthread")
 gl_in_filter    =glthread.getFrameFilter()
 
@@ -334,12 +491,12 @@ 

Server + Client
# ctx =LiveConnectionContext(LiveConnectionType_rtsp, "rtsp://admin:nordic12345@192.168.1.41", 1, av_in_filter)
+
# ctx =LiveConnectionContext(LiveConnectionType_rtsp, "rtsp://admin:nordic12345@192.168.1.41", 1, av_in_filter)
 ctx =LiveConnectionContext(LiveConnectionType_rtsp, "rtsp://admin:123456@192.168.0.134", 1, av_in_filter)
 

Start threads:

-
glthread.startCall()
+
glthread.startCall()
 avthread.startCall()
 livethread.startCall()
 
@@ -357,7 +514,7 @@ 

Server + Client
client = ShmemRGBClient(
+
client = ShmemRGBClient(
     name=shmem_name,
     n_ringbuffer=shmem_buffers,
     width=width,
@@ -368,11 +525,11 @@ 

Server + Client
livethread.playStreamCall(ctx)
+
livethread.playStreamCall(ctx)
 

Read 10 frames & exit

-
print("client starting")
+
print("client starting")
 cc = 0
 while True:
     index, meta = client.pullFrame()
@@ -390,7 +547,7 @@ 

Server + Client
glthread.delRenderContextCall(context_id)
+
-
shmem_buffers = 10 # 10 element in the ring-buffer
+
shmem_buffers = 10 # 10 element in the ring-buffer
 shmem_name = "lesson_4_c" # unique name identifying the shared memory
 cellsize = 1024*1024*3 # max size for each MP4 fragment
 timeout = 1000 # in ms
@@ -456,12 +613,12 @@ 

Server + Client
# ctx =LiveConnectionContext(LiveConnectionType_rtsp, "rtsp://admin:nordic12345@192.168.1.41", 1, fork_filter)
+
# ctx =LiveConnectionContext(LiveConnectionType_rtsp, "rtsp://admin:nordic12345@192.168.1.41", 1, fork_filter)
 ctx =LiveConnectionContext(LiveConnectionType_rtsp, "rtsp://admin:123456@192.168.0.134", 1, fork_filter)
 

Start threads:

-
glthread.startCall()
+
glthread.startCall()
 avthread.startCall()
 livethread.startCall()
 
@@ -479,7 +636,7 @@ 

Server + Client
client = FragMP4ShmemClient(
+
client = FragMP4ShmemClient(
     name=shmem_name,
     n_ringbuffer=shmem_buffers,
     n_size=cellsize,
@@ -489,11 +646,11 @@ 

Server + Client
livethread.playStreamCall(ctx)
+
livethread.playStreamCall(ctx)
 

Read 10 frames & exit

-
print("client starting")
+
print("client starting")
 cc = 0
 while True:
     index, meta = client.pullFrame()
@@ -512,7 +669,7 @@ 

Server + Client
glthread.delRenderContextCall(context_id)
+
-    
-
-    
-
-    
-    
-    
-  
+    

+
+ + + \ No newline at end of file diff --git a/docs/_build/html/lesson_5.html b/docs/_build/html/lesson_5.html index 5acbc87..98a939e 100644 --- a/docs/_build/html/lesson_5.html +++ b/docs/_build/html/lesson_5.html @@ -1,83 +1,234 @@ + + + - - - - + + Lesson 5 : Transmitting stream — Python Media Streaming Framework for Linux documentation + + + - Lesson 5 : Transmitting stream — Python Media Streaming Framework for Linux documentation - - - - - + + + + + + + + + + + - - - + + + - - + + + + + + -
-
-
- +
+ + +
+ +
+
+
+ +
+
+
+
+
-

Lesson 5 : Transmitting stream

+

Lesson 5 : Transmitting stream

-

Sending multicast

+

Sending multicast

Download lesson [here]

In this lesson, we are receiving frames from an IP camera using LiveThread and recast those frames to a multicast address using another LiveThread. The filterchain looks like this:

(LiveThread:livethread) --> {InfoFrameFilter:info_filter) -->> (LiveThread:livethread2)
 

Let’s start by importing Valkka:

-
import time
+
import time
 from valkka.core import *
 

Live555’s default output packet buffer size might be too small, so let’s make it bigger before instantiating any LiveThreads:

-
setLiveOutPacketBuffermaxSize(95000)
+
setLiveOutPacketBuffermaxSize(95000)
 

Construct the filtergraph from end-to-beginning:

-
livethread2    =LiveThread("livethread2")
+
livethread2    =LiveThread("livethread2")
 live_in_filter =livethread2.getFrameFilter()
 info_filter    =InfoFrameFilter("info_filter",live_in_filter)
 livethread     =LiveThread("livethread")
 

Start threads

-
livethread2.startCall()
+
livethread2.startCall()
 livethread. startCall()
 

Define stream source: incoming frames from IP camera 192.168.1.41 are tagged with slot number “2” and they are written to “info_filter”:

-
ctx     =LiveConnectionContext(LiveConnectionType_rtsp, "rtsp://admin:nordic12345@192.168.1.41", 2, info_filter)
+
ctx     =LiveConnectionContext(LiveConnectionType_rtsp, "rtsp://admin:nordic12345@192.168.1.41", 2, info_filter)
 

Define stream sink: all outgoing frames with slot number “2” are sent to port 50000:

-
out_ctx =LiveOutboundContext(LiveConnectionType_sdp, "224.1.168.91", 2, 50000)
+
out_ctx =LiveOutboundContext(LiveConnectionType_sdp, "224.1.168.91", 2, 50000)
 

Start playing:

-
livethread2.registerOutboundCall(out_ctx)
+
livethread2.registerOutboundCall(out_ctx)
 livethread. registerStreamCall(ctx)
 livethread. playStreamCall(ctx)
 

Stream and recast to multicast for a while:

-
time.sleep(60)
+
time.sleep(60)
 
 livethread. stopStreamCall(ctx)
 livethread. deregisterStreamCall(ctx)
@@ -85,7 +236,7 @@ 

Sending multicast
livethread. stopCall();
+
livethread. stopCall();
 livethread2.stopCall();
 
 print("bye")
@@ -115,7 +266,7 @@ 

Sending multicast -

Using the RTSP server

+

Using the RTSP server

Download lesson [here]

In this lesson, we establish an on-demand RTSP server at the localhost.

Stream is read from an IP camera and then re-streamed (shared) to a local RTSP server that serves at port 8554. While this snippet is running, you can test the RTSP server with:

@@ -123,46 +274,46 @@

Using the RTSP server

Let’s start by importing Valkka:

-
import time
+
import time
 from valkka.core import *
 

Live555’s default output packet buffer size might be too small, so let’s make it bigger before instantiating any LiveThreads:

-
setLiveOutPacketBuffermaxSize(95000)
+
setLiveOutPacketBuffermaxSize(95000)
 

Construct the filtergraph from end-to-beginning:

-
livethread2    =LiveThread("livethread2")
+
livethread2    =LiveThread("livethread2")
 live_in_filter =livethread2.getFrameFilter()
 info_filter    =InfoFrameFilter("info_filter",live_in_filter)
 livethread     =LiveThread("livethread")
 

Before starting the threads, establish an RTSP server on livethread2 at port 8554:

-
livethread2.setRTSPServer(8554);
+
livethread2.setRTSPServer(8554);
 

Start threads

-
livethread2.startCall()
+
livethread2.startCall()
 livethread. startCall()
 

Define stream source: incoming frames from IP camera 192.168.1.41 are tagged with slot number “2” and they are written to “info_filter”:

-
ctx     =LiveConnectionContext(LiveConnectionType_rtsp, "rtsp://admin:nordic12345@192.168.1.41", 2, info_filter)
+
ctx     =LiveConnectionContext(LiveConnectionType_rtsp, "rtsp://admin:nordic12345@192.168.1.41", 2, info_filter)
 

Define stream sink: all outgoing frames with slot number “2” are sent to the RTSP server, with substream id “stream1”:

-
out_ctx =LiveOutboundContext(LiveConnectionType_rtsp, "stream1", 2, 0)
+
out_ctx =LiveOutboundContext(LiveConnectionType_rtsp, "stream1", 2, 0)
 

Start playing:

-
livethread2.registerOutboundCall(out_ctx)
+
livethread2.registerOutboundCall(out_ctx)
 livethread. registerStreamCall(ctx)
 livethread. playStreamCall(ctx)
 

Stream and recast to the RTSP server for a while:

-
- - - - - - - - - + \ No newline at end of file diff --git a/docs/_build/html/lesson_6.html b/docs/_build/html/lesson_6.html index 5808896..2a54b85 100644 --- a/docs/_build/html/lesson_6.html +++ b/docs/_build/html/lesson_6.html @@ -1,39 +1,186 @@ + + + - - - - - - Lesson 6 : Writing / reading stream — Python Media Streaming Framework for Linux documentation - - - - - + + Lesson 6 : Writing / reading stream — Python Media Streaming Framework for Linux documentation + + + + + + + + + + + + + + + - - - + + + - - + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+
-

Lesson 6 : Writing / reading stream

+

Lesson 6 : Writing / reading stream

Download lesson [here]

In this lesson, we are (a) writing from a live stream to a file and (b) reading the file, decoding the stream and presenting it on the screen. The filtergraph goes like this:

*** (a) writing ***
@@ -55,25 +202,25 @@ 

Lesson 6 : Writing / reading stream
import time
+
import time
 from valkka.core import *
 
 debug_log_all()
 

Writing is done by piping the stream into a FileFrameFilter:

-
file_filter  =FileFrameFilter("file_filter")
+
file_filter  =FileFrameFilter("file_filter")
 livethread   =LiveThread("livethread")
 

For reading, decoding and presenting, we construct the filtergraph as usual, from end-to-beginning:

-
# presentation part
+
# presentation part
 glthread      =OpenGLThread ("glthread")
 gl_in_filter  =glthread.getFrameFilter()
 

For file streams, the execution should block for frame bursts, so we request a blocking input FrameFilter from the AVThread:

-
avthread      =AVThread("avthread",gl_in_filter)
+
avthread      =AVThread("avthread",gl_in_filter)
 av_in_filter  =avthread.getBlockingFrameFilter()
 
 # reading part
@@ -81,7 +228,7 @@ 

Lesson 6 : Writing / reading stream
livethread .startCall()
+
livethread .startCall()
 
 ctx          =LiveConnectionContext(LiveConnectionType_rtsp, "rtsp://admin:nordic12345@192.168.1.41", 1, file_filter)
 # stream from 192.168.1.41, tag frames with slot number 1 and write to file_filter
@@ -91,7 +238,7 @@ 

Lesson 6 : Writing / reading stream
print("writing to file during 30 secs")
+
print("writing to file during 30 secs")
 file_filter.activate("kokkelis.mkv")
 
 # stream for 30 secs
@@ -105,7 +252,7 @@ 

Lesson 6 : Writing / reading stream
print("reading file")
+
print("reading file")
 glthread   .startCall()
 filethread .startCall()
 avthread   .startCall()
@@ -122,13 +269,13 @@ 

Lesson 6 : Writing / reading stream
print("open file")
+
print("open file")
 file_ctx =FileContext("kokkelis.mkv", 1, av_in_filter) # read from file "kokkelis.mkv", tag frames with slot number 1 and write to av_in_filter
 filethread.openFileStreamCall(file_ctx)
 

Playing, seeking and stopping is done as follows:

-
print("play file")
+
print("play file")
 filethread.playFileStreamCall(file_ctx)
 
 # play the file for 10 secs
@@ -151,7 +298,7 @@ 

Lesson 6 : Writing / reading stream
glthread.delRenderContextCall(context_id)
+
-    
-
-    
-
-    
-    
-    
-  
+    

+
+ + + \ No newline at end of file diff --git a/docs/_build/html/lesson_7.html b/docs/_build/html/lesson_7.html index 8aacda0..2409d0d 100644 --- a/docs/_build/html/lesson_7.html +++ b/docs/_build/html/lesson_7.html @@ -1,39 +1,186 @@ + + + - - - - - - Lesson 7 : Decode, save, visualize, analyze and re-transmit — Python Media Streaming Framework for Linux documentation - - - - - + + Lesson 7 : Decode, save, visualize, analyze and re-transmit — Python Media Streaming Framework for Linux documentation + + + + + + + + + + + + + + + - - - + + + - - + + + + + + + +
+ -
-
-
- +
-
- +
+
+
+ +
+
+
+
+
-

Lesson 7 : Decode, save, visualize, analyze and re-transmit

+

Lesson 7 : Decode, save, visualize, analyze and re-transmit

Download lesson [here]

In this example, we do simultaneously a lot of stuff, namely, save the stream to disk, decode it to bitmap, visualize it in two different x windows, pass the decoded frames to an OpenCV analyzer and re-transmit the stream to a multicast address.

Only a single connection to the IP camera is required and the stream is decoded only once.

@@ -65,7 +212,7 @@

Lesson 7 : Decode, save, visualize, analyze and re-transmit
# *** branch 1 ***
+
-    
-
-    
-
-    
-     
 
-    
-    
-  
+
 
\ No newline at end of file
diff --git a/docs/_build/html/lesson_8.html b/docs/_build/html/lesson_8.html
index 4fce21c..a1cdab7 100644
--- a/docs/_build/html/lesson_8.html
+++ b/docs/_build/html/lesson_8.html
@@ -1,41 +1,192 @@
 
+
+
+  
 
-
-  
-    
-    
-
-    Lesson 8: API level 2 — Python Media Streaming Framework for Linux  documentation
-    
-    
-    
-    
-    
+  
+  Lesson 8: API level 2 — Python Media Streaming Framework for Linux  documentation
+      
+      
+      
+
+  
+  
+  
+        
+        
+        
+        
+        
+        
+        
+    
     
     
     
     
-   
-  
-  
+
+
+
 
-  
-  
+
+
+
+
+
+
+
+  
+ -
-
-
- +
-
- +
+
+
+ +
+
+
+
+
-

Lesson 8: API level 2

+

Lesson 8: API level 2

-

General aspects

+

General aspects

API level 2 tutorial codes are available at:

cd valkka_examples/api_level_2/tutorial
 python3 lesson_8_a.py
@@ -64,16 +215,16 @@ 

General aspectsPyQT testsuite serves also as API level 2 reference.

-

A simple example

+

A simple example

Download lesson [here]

First, import API level 2:

-
import time
+
import time
 from valkka.api2 import LiveThread, OpenGLThread
 from valkka.api2 import BasicFilterchain
 

Instantiating the API level 2 LiveThread starts running the underlying cpp thread:

-
livethread=LiveThread( # starts live stream services (using live555)
+
livethread=LiveThread( # starts live stream services (using live555)
   name   ="live_thread",
   verbose=False,
   affinity=-1
@@ -81,7 +232,7 @@ 

A simple example
openglthread=OpenGLThread(
+
openglthread=OpenGLThread(
   name    ="glthread",
   n_720p   =20,   # reserve stacks of YUV video frames for various resolutions
   n_1080p  =20,
@@ -94,7 +245,7 @@ 

A simple example
chain=BasicFilterchain( # decoding and branching the stream happens here
+
chain=BasicFilterchain( # decoding and branching the stream happens here
   livethread  =livethread,
   openglthread=openglthread,
   address     ="rtsp://admin:nordic12345@192.168.1.41",
@@ -107,7 +258,7 @@ 

A simple example
# create a window
+
# create a window
 win_id =openglthread.createWindow()
 
 # create a stream-to-window mapping
@@ -120,7 +271,7 @@ 

A simple example
livethread.close()
+
-    
-
-    
-
-    
-     
 
-    
-    
-  
+
 
\ No newline at end of file
diff --git a/docs/_build/html/lesson_9.html b/docs/_build/html/lesson_9.html
index b49bf7f..fc831f2 100644
--- a/docs/_build/html/lesson_9.html
+++ b/docs/_build/html/lesson_9.html
@@ -1,43 +1,190 @@
 
+
+
+  
 
-
-  
-    
-    
-
-    Lesson 9 : Drawing Bounding Boxes — Python Media Streaming Framework for Linux  documentation
-    
-    
-    
-    
-    
+  
+  Lesson 9 : Drawing Bounding Boxes — Python Media Streaming Framework for Linux  documentation
+      
+      
+      
+
+  
+  
+  
+        
+        
+        
+        
+        
+        
+        
+    
     
     
     
     
-   
-  
-  
+
+
+
 
-  
-  
+
+
+
+
+
+
+
+  
+ + +
+ +
+
+
+ +
+
+
+
+
-

Lesson 9 : Drawing Bounding Boxes

+

Lesson 9 : Drawing Bounding Boxes

Here we stream video to a single X-window just like in tutorial example 3, but we also draw some bounding boxes on the video.

Download lesson [here]

First, business as usual (and like in tutorial example 3)

-
import time
+
import time
 from valkka.core import *
 glthread        =OpenGLThread ("glthread")
 gl_in_filter    =glthread.getFrameFilter()
@@ -69,18 +216,18 @@ 

Lesson 9 : Drawing Bounding Boxes
bbox=(0.25, 0.75, 0.75, 0.25) # left, right, top, bottom
+
bbox=(0.25, 0.75, 0.75, 0.25) # left, right, top, bottom
 
 glthread.addRectangleCall(context_id, bbox[0], bbox[1], bbox[2], bbox[3])
 

You could add more bounding boxes with consecutive calls to glthread.addRectangleCall

Let’s play video for 10 seconds

-
time.sleep(10)
+
time.sleep(10)
 

Finally, clear the bounding boxes and exit

-
glthread.clearObjectsCall(context_id)
+
-    
-
-    
-
-    
-    
-    
-  
+    

+
+ + + \ No newline at end of file diff --git a/docs/_build/html/lesson_pre.html b/docs/_build/html/lesson_pre.html index c758934..6621190 100644 --- a/docs/_build/html/lesson_pre.html +++ b/docs/_build/html/lesson_pre.html @@ -1,86 +1,120 @@ + + + - - - - - - <no title> — Python Media Streaming Framework for Linux documentation - - - - - - - - - - + + <no title> — Python Media Streaming Framework for Linux documentation + + + + + + + + + + + + + + + + + - - - -
-
-
- + + + + + + + +
+
- + + +
+ +
+
+
+ +
+
+
+
+ + - +
+
+
- - - - +
+
+
+
+
+ + + \ No newline at end of file diff --git a/docs/_build/html/license.html b/docs/_build/html/license.html index 1f0222e..72f2566 100644 --- a/docs/_build/html/license.html +++ b/docs/_build/html/license.html @@ -1,93 +1,122 @@ + + + - - - - - - Licence & Copyright — Python Media Streaming Framework for Linux documentation - - - - - + + Licence & Copyright — Python Media Streaming Framework for Linux documentation + + + + + + + + + + + + + + + - - - - - - - - - - -
-
-
- - -
- - + + + + + + + + + + +
+
- -
-
- + + +
+ +
+
+
+ +
+
+
+
+ + - - - - - + +
+
+
+
+ + + \ No newline at end of file diff --git a/docs/_build/html/modules.html b/docs/_build/html/modules.html index b302d80..b886c0b 100644 --- a/docs/_build/html/modules.html +++ b/docs/_build/html/modules.html @@ -1,40 +1,168 @@ + + + - - - - - - Modules — Python Media Streaming Framework for Linux documentation - - - - - - - - - - + + Modules — Python Media Streaming Framework for Linux documentation + + + + + + + + + + + + + + + + + - - + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+
-

Modules

+

Modules

Valkka consists of python modules, organized under the valkka. namespace, i.e. we’re using the python “namespace packaging” scheme.

-

Cpp modules

+

Cpp modules

Modules written in cpp are installed as debian packages, and the python parts are installed “globally” under

/usr/lib/python3/dist-packages/valkka/
 
@@ -43,12 +171,12 @@

Cpp modules -

Pure python modules

+

Pure python modules

These are just normal python modules, installed typically with pip3 install –user

A scaffold for creating python-only modules, can be found here

-

Module list

+

Module list

List of currently available modules. cpp stands for a module written in cpp, while python indicates a pure python module.

@@ -83,118 +211,31 @@

Module list -
- - - - - - - - - +
-
- - - - - - - - - + + + + + \ No newline at end of file diff --git a/docs/_build/html/multi_gpu.html b/docs/_build/html/multi_gpu.html index 6cd9e10..4109720 100644 --- a/docs/_build/html/multi_gpu.html +++ b/docs/_build/html/multi_gpu.html @@ -1,42 +1,176 @@ + + + - - - - - - Multi-GPU systems — Python Media Streaming Framework for Linux documentation - - - - - + + Multi-GPU systems — Python Media Streaming Framework for Linux documentation + + + + + + + + + + + + + + + - - - + + + - - + + + + + + + +
+ + +
-
- +
+
+
+ +
+
+
+
+
-

Multi-GPU systems

+

Multi-GPU systems

(If you just have monitors connected to a single graphics card, no need to be here)

-

Introduction

+

Introduction

Consider the following setup:

  • You have 2 graphic cards (GPUs)

  • @@ -69,7 +203,7 @@

    Introductionthis rather frustrating discussion thread / bug report on the subject.

-

Our approach

+

Our approach

As you learned from the tutorials and from the PyQt testsuite, Valkka uses a dedicated thread (OpenGLThread) to pre-reserve resources from the GPU and to communicate with it.

In a multi-gpu case, one simply launches an OpenGLThread for each GPU: OpenGLThread takes as a parameter a string defining the connection to the X-server (e.g. “:0.0”, “:0.1”, .. “:0.n”, where n is the GPU number).

It is up to the API user to send the decoded frames to the correct OpenGLThread (and GPU). A simple example, where all decoded frames are sent to all GPUs in the system can be found in

@@ -80,7 +214,7 @@

Our approach -

Configuration

+

Configuration

We’ve been succesful in setting up multi-gpu systems with the following setup:

Here is an example on how to create your own class for an OnVif device service, based on the class OnVif:

-
-

Service classes

+

Service classes

You can create your own OnVif subclass as described above.

However, we have done some of the work for you. Take a look at the column “Subclass” in the table above, and you’ll find them:

from valkka.onvif import Media
@@ -153,7 +290,7 @@ 

Service classes -

Example call

+

Example call

Let’s try a remote protocol call.

If you look at that specification in http://www.onvif.org/ver10/device/wsdl, there is a remote protocol call name GetCapabilities. Let’s call it:

from valkka.onvif import DeviceManagement
@@ -188,7 +325,7 @@ 

Example call -

Onvif Pitfalls

+

Onvif Pitfalls

Axis cameras

Although Axis is the brand that created OnVif, their cameras are extremely picky on the onvif calls: if your client machine’s walltime differs even slightly on the camera’s time, axis cameras (at least the model I have), reject the call (you’ll get “Sender not Authorized”).

@@ -203,7 +340,7 @@

Onvif Pitfallstimeout can be used with OnVif calls.

-

Discovery

+

Discovery

Discovery module uses arp-scan and/or the WSDiscovery protocol.

The API is subject to change and is explained in detail at the valkka-onvif main readme

Most importantly, you need to give normal users the ability to perform arp-scans, so before using discovery tools, @@ -216,127 +353,34 @@

Discovery -

-
-
- - - - - - - - - + \ No newline at end of file diff --git a/docs/_build/html/pitfalls.html b/docs/_build/html/pitfalls.html index 86ebfa8..d045aef 100644 --- a/docs/_build/html/pitfalls.html +++ b/docs/_build/html/pitfalls.html @@ -1,41 +1,175 @@ + + + - - - - + + Common problems — Python Media Streaming Framework for Linux documentation + + + - Common problems — Python Media Streaming Framework for Linux documentation - - - - - + + + + + + + + + + + - - - + + + - - + + + + + + -
-
-
- +
+ + +
+ +
+
+
+ +
+
+
+
+
-

Common problems

+

Common problems

-

Pitfalls

+

Pitfalls

Valkka has been designed for massive video streaming. If your linux box, running a Valkka-based program, starts to choke up and you get frame jittering, stuttering / video freezes, and typically, this:

OpenGLThread: handleFifo: DISCARDING late frame ...
@@ -77,7 +211,7 @@ 

Common problems -

Bottlenecks

+

Bottlenecks

Once you ramp up the number of streams, you might start to experience some real performance issues. Some typical problems include:

8. Your LAN and/or the LiveThread process sending frames in bursts

@@ -123,7 +257,7 @@

Bottlenecks -

System tuning

+

System tuning

Adding the following lines into /etc/syscntl.conf

vm.swappiness = 1
 net.core.wmem_max=2097152
@@ -138,7 +272,7 @@ 

System tuning -

FAQ

+

FAQ

(a) How can I stream over internet, instead of just LAN?

By default, stream is transported through UDP sockets. When streaming over internet, most of the ports are closed due to firewalls, etc., so you have to stream through the same TCP port that is used for the RTSP negotiation (typically port 554).

@@ -190,124 +324,34 @@

FAQ

+
- -
-
- -
-
- - - - - - - - - + \ No newline at end of file diff --git a/docs/_build/html/qt_notes.html b/docs/_build/html/qt_notes.html index 8c3ae94..0970dfa 100644 --- a/docs/_build/html/qt_notes.html +++ b/docs/_build/html/qt_notes.html @@ -1,41 +1,175 @@ + + + - - - - + + Integrating with Qt and multiprocessing — Python Media Streaming Framework for Linux documentation + + + - Integrating with Qt and multiprocessing — Python Media Streaming Framework for Linux documentation - - - - - + + + + + + + + + + + - - - + + + - - + + + + + + -
-
-
- +
+ + +
+ +
+
+
+ +
+
+
+
+
-

Integrating with Qt and multiprocessing

+

Integrating with Qt and multiprocessing

-

Qt integration

+

Qt integration

Valkka can be used with any GUI framework, say, with GTK or Qt. Here we have an emphasis on Qt, but the general guidelines discussed here, apply to any other GUI framework as well. Concrete examples are provided only for Qt.

At the GUI’s main window constructor:

@@ -53,7 +187,7 @@

Qt integrationthe PyQt testsuite together with several filtergraph classes.

-

Drawing video into a widget

+

Drawing video into a widget

X-windows, i.e. “widgets” in the Qt slang, can be created at the Qt side and passed to Valkka. Alternatively, x-windows can be created at the Valkka side and passed to Qt as “foreign widgets”.

As you learned in the tutorial, we use the X-window window ids like this:

context_id=glthread.newRenderContextCall(1,window_id,0)
@@ -80,7 +214,7 @@ 

Drawing video into a widget -

Python multiprocessing

+

Python multiprocessing

In lesson 4 of the tutorial, we launched a separate python interpreter running a client program that was using decoded and shared frames.

That approach works for Qt programs as well, but it is more convenient to use multiprocesses constructed with Python3’s multiprocessing library.

@@ -162,7 +296,7 @@

Python multiprocessingA more full-blown multiprocess orchestration example can be found as in this python package.

-

C++ API

+

C++ API

There is no obligation to use Valkka from python - the API is usable from cpp as well: all python libValkka threads and filters are just swig-wrapped cpp code.

If programming in Qt with C++ is your thing, then you can just forget all that multiprocessing considered here and use cpp threads instead.

Say, you can use Valkka’s FrameFifo and Thread infrastructure to create threads that read frames and feed them to an OpenCV analyzer (written in cpp).

@@ -177,124 +311,34 @@

C++ API +

- -
-
- -
-
- - - - - - - - - + \ No newline at end of file diff --git a/docs/_build/html/repos.html b/docs/_build/html/repos.html index e0818d1..2bc07e4 100644 --- a/docs/_build/html/repos.html +++ b/docs/_build/html/repos.html @@ -1,39 +1,167 @@ + + + - - - - + + Repository Index — Python Media Streaming Framework for Linux documentation + + + - Repository Index — Python Media Streaming Framework for Linux documentation - - - - - + + + + + + + + + + + - - - + + + - - + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+
-

Repository Index

+

Repository Index

@@ -152,118 +280,34 @@

Repository Index -
- - - - - - - - - +
-
- - - - - - - - - - + \ No newline at end of file diff --git a/docs/_build/html/requirements.html b/docs/_build/html/requirements.html index 6aaa55b..dc96677 100644 --- a/docs/_build/html/requirements.html +++ b/docs/_build/html/requirements.html @@ -1,39 +1,178 @@ + + + - - - - + + Installing — Python Media Streaming Framework for Linux documentation + + + - Installing — Python Media Streaming Framework for Linux documentation - - - - - + + + + + + + + + + + - - - + + + - - + -
-
-
- -
- + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+
-

Installing

+

Installing

The debian package includes the core library, its python bindings and some API level 2 python code. The python part is installed “globally” into /usr/lib/python3/dist-packages/

Note

@@ -41,7 +180,7 @@ python version of that distribution. Using custom-installed python versions, anacondas and whatnot might cause dependency problems.

-

A. Install using PPA

+

A. Install using PPA

the preferred way

For recent ubuntu distributions, the core library binary packages and python bindings are provided by a PPA repository. Subscribe to the PPA repo (do this only once) with:

sudo apt-add-repository ppa:sampsa-riikonen/valkka
@@ -59,7 +198,7 @@ 

A. Install using PPA

-

B. Install using releases

+

B. Install using releases

if you don’t like PPAs

You can download and install the required .deb packages “manually” from the releases page

@@ -71,13 +210,13 @@

B. Install using releases -

C. Compile yourself

+

C. Compile yourself

the last resort

If you’re not using a recent Ubuntu distro and need to build libValkka and it’s python bindings yourself, please refer to the valkka-core github page.

-

Test your installation

+

Test your installation

Test the installation with:

curl https://raw.githubusercontent.com/elsampsa/valkka-examples/master/quicktest.py -o quicktest.py
 python3 quicktest.py
@@ -85,13 +224,13 @@ 

Test your installation

-

Numpy

+

Numpy

Valkka-core binaries has been compiled with the numpy version that comes with the corresponding Ubuntu distro, i.e. the numpy you would install with sudo apt-get install python3-numpy.

That version is automatically installed when you install valkka core with sudo apt-get, but it might be “shadowed” by your locally installed numpy.

If you get errors about numpy import, try removing your locally installed numpy (i.e. the version you installed with pip install --user).

-

Install the testsuite

+

Install the testsuite

First, install some debian packages:

sudo apt-get install python3-pip git mesa-utils ffmpeg vlc
 
@@ -122,14 +261,14 @@

Install the testsuiteNext, try out the PyQt test/demo suite or learn to program with the tutorial.

-

GTK

+

GTK

If you wan’t to use GTK as your graphical user interface, you must install the PyGObject python bindings, as instructed here, namely:

sudo apt-get install python-gi python-gi-cairo python3-gi python3-gi-cairo gir1.2-gtk-3.0
 
-

OpenCV

+

OpenCV

Install with:

pip3 uninstall opencv-python
 sudo pip3 uninstall opencv-python # just in case!
@@ -140,7 +279,7 @@ 

GTK

-

Development version

+

Development version

As described above, for the current stable version of valkka-core, just use the repository.

For the development version (with experimental and unstable features) you have to compile from source. You might need to do this also for architectures other than x86.

@@ -149,129 +288,34 @@

Development version -

-
-
- - - - - - - - - + \ No newline at end of file diff --git a/docs/_build/html/search.html b/docs/_build/html/search.html index 1baced5..3598a39 100644 --- a/docs/_build/html/search.html +++ b/docs/_build/html/search.html @@ -1,120 +1,122 @@ + + + + + Search — Python Media Streaming Framework for Linux documentation + + + - - - - - Search — Python Media Streaming Framework for Linux documentation - - + - - - + + + + + + + + + + - - - - - - - - - - - - - -
-
-
- + + + -
- -

Search

- - - - -

- Searching for multiple words only shows matches that contain - all words. -

- - -
- - - - - - - -
- -
- + + + + + + + +
+
- -
-
- + + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+
+
+ + - + +
+ +
- - - - + Built with Sphinx using a + theme + provided by Read the Docs. + + + +
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/docs/_build/html/searchindex.js b/docs/_build/html/searchindex.js index 5179772..25ad73c 100644 --- a/docs/_build/html/searchindex.js +++ b/docs/_build/html/searchindex.js @@ -1 +1 @@ -Search.setIndex({"docnames": ["authors", "benchmarking", "cloud", "debugging", "decoding", "hardware", "index", "intro", "knowledge", "lesson_1", "lesson_10", "lesson_11", "lesson_2", "lesson_3", "lesson_4", "lesson_5", "lesson_6", "lesson_7", "lesson_8", "lesson_9", "lesson_pre", "license", "modules", "multi_gpu", "onvif", "pitfalls", "qt_notes", "repos", "requirements", "testsuite", "tutorial", "valkkafs"], "filenames": ["authors.rst", "benchmarking.rst", "cloud.rst", "debugging.rst", "decoding.rst", "hardware.rst", "index.rst", "intro.rst", "knowledge.rst", "lesson_1.rst", "lesson_10.rst", "lesson_11.rst", "lesson_2.rst", "lesson_3.rst", "lesson_4.rst", "lesson_5.rst", "lesson_6.rst", "lesson_7.rst", "lesson_8.rst", "lesson_9.rst", "lesson_pre.rst", "license.rst", "modules.rst", "multi_gpu.rst", "onvif.rst", "pitfalls.rst", "qt_notes.rst", "repos.rst", "requirements.rst", "testsuite.rst", "tutorial.rst", "valkkafs.rst"], "titles": ["Authors", "Benchmarking", "Cloud Streaming", "Debugging", "Decoding", "Supported hardware", "Valkka", "About Valkka", "Knowledge Base", "Lesson 1 : Receiving frames from an IP camera", "Lesson 10 : USB Cameras", "Lesson 11 : ValkkaFS", "Lesson 2 : Decoding", "Lesson 3 : Streaming to the X-window system", "Lesson 4 : Receiving Frames at Python", "Lesson 5 : Transmitting stream", "Lesson 6 : Writing / reading stream", "Lesson 7 : Decode, save, visualize, analyze and re-transmit", "Lesson 8: API level 2", "Lesson 9 : Drawing Bounding Boxes", "<no title>", "Licence & Copyright", "Modules", "Multi-GPU systems", "OnVif & Discovery", "Common problems", "Integrating with Qt and multiprocessing", "Repository Index", "Installing", "The PyQt testsuite", "Tutorial", "ValkkaFS"], "terms": {"sampsa": [0, 21, 28, 31], "riikonen": [0, 21, 28], "_at_": 0, "iki": 0, "fi": 0, "up": [1, 3, 4, 8, 11, 23, 24, 25, 28, 29], "do": [1, 2, 4, 5, 7, 8, 9, 11, 14, 17, 18, 23, 24, 25, 26, 28, 29], "date": [1, 24], "maintain": [1, 25], "here": [1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31], "you": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 18, 19, 23, 24, 25, 26, 27, 28, 29, 30, 31], "find": [1, 3, 8, 24, 26], "some": [1, 2, 5, 6, 9, 11, 14, 18, 19, 24, 25, 28, 29, 31], "tabul": 1, "test": [1, 4, 5, 6, 13, 15, 17, 23, 25, 27, 29, 31], "ar": [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 22, 23, 24, 25, 26, 28, 29, 30, 31], "perform": [1, 11, 12, 14, 23, 24, 25, 29], "otherwis": [1, 14, 29], "mention": [1, 3, 31], "pyqt": [1, 6, 7, 8, 11, 18, 23, 25, 26, 28, 31], "testsuit": [1, 4, 6, 7, 11, 18, 23, 25, 26, 31], "program": [1, 4, 6, 7, 9, 13, 14, 17, 22, 23, 25, 26, 27, 28, 29], "test_studio_1": [1, 4, 6], "py": [1, 3, 4, 6, 8, 11, 18, 23, 25, 26, 28, 30], "paramet": [1, 9, 11, 12, 14, 23, 24, 26], "same": [1, 2, 3, 7, 11, 12, 13, 14, 18, 24, 25, 26, 29, 31], "abbrevi": 1, "us": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 18, 22, 23, 24, 25, 26, 27, 29], "liva": 1, "live": [1, 2, 3, 4, 6, 13, 14, 16, 18, 22, 25, 27, 29], "affin": [1, 18, 29], "gla": 1, "opengl": [1, 5, 7, 13, 23, 25, 29], "d1a": 1, "decod": [1, 6, 7, 11, 14, 16, 18, 23, 25, 26, 29, 30, 31], "start": [1, 4, 5, 6, 7, 9, 11, 12, 13, 14, 15, 16, 17, 18, 24, 25, 26, 29, 30, 31], "dna": 1, "stop": [1, 11, 12, 13, 14, 15, 16, 29], "uptim": 1, "how": [1, 2, 4, 7, 11, 14, 18, 22, 24, 25, 26, 29, 30, 31], "long": [1, 24, 25, 29], "wa": [1, 14, 17, 25, 26], "run": [1, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 18, 23, 25, 26, 29, 30], "newest": 1, "first": [1, 3, 5, 8, 9, 11, 12, 13, 14, 18, 19, 24, 28, 29, 31], "order": [1, 5, 7, 11, 12, 13, 14, 15, 16, 18, 19, 26, 29, 31], "n": [1, 11, 23, 29, 31], "pc": [1, 25], "gf_driver": 1, "camera": [1, 2, 4, 6, 7, 11, 12, 14, 15, 17, 24, 25, 29, 30, 31], "n_720p": [1, 4, 13, 18], "n_1080p": [1, 4, 13, 18], "n_1440p": [1, 4, 13, 18], "n_4k": [1, 4, 13, 18], "n_audio": 1, "msbuftim": [1, 4, 18, 29], "replic": [1, 13, 29], "kernel": [1, 5, 29], "comment": [1, 8], "2": [1, 3, 4, 5, 7, 9, 13, 15, 16, 17, 19, 22, 23, 24, 25, 27, 28, 29, 30, 31], "ubuntu": [1, 5, 8, 28, 30], "18": [1, 8], "04": 1, "lt": [1, 8, 30], "8xi7": 1, "7700hq": 1, "laptop": [1, 30], "nvidia": [1, 5, 13, 23, 25], "x": [1, 4, 5, 7, 14, 16, 17, 18, 19, 23, 25, 26, 29, 30], "2560p": 1, "25": [1, 11, 14, 19], "fp": [1, 4, 11, 13, 14, 25], "600": 1, "10": [1, 11, 13, 14, 16, 17, 19, 24, 25, 29, 30, 31], "0": [1, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 19, 23, 24, 25, 26, 28, 29], "500": [1, 4, 11, 14], "1": [1, 3, 7, 10, 12, 13, 15, 16, 17, 18, 19, 23, 24, 25, 26, 27, 29, 30, 31], "4": [1, 3, 4, 7, 8, 11, 17, 23, 25, 26, 29, 30], "15": [1, 4], "51": 1, "gener": [1, 2, 6, 25, 26, 30], "libvalkka": [1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 21, 25, 26, 27, 28], "v0": 1, "12": [1, 9, 12, 13], "16": [1, 11], "4770": 1, "i915": [1, 5], "1920p": 1, "400": 1, "7": [1, 9, 11, 25, 29, 30], "5": [1, 3, 8, 9, 11, 12, 14, 16, 17, 23, 25, 29, 30], "we": [2, 4, 5, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17, 19, 22, 23, 24, 25, 26, 28, 29, 31], "describ": [2, 9, 24, 28], "low": 2, "latenc": 2, "video": [2, 4, 5, 6, 7, 9, 10, 11, 13, 14, 15, 18, 19, 22, 23, 25, 27, 29, 30, 31], "from": [2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 23, 24, 25, 26, 27, 28, 29, 30, 31], "your": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 23, 24, 25, 26, 27, 29, 30, 31], "ip": [2, 6, 7, 10, 11, 12, 13, 14, 15, 17, 24, 25, 29, 30], "visual": [2, 11, 14, 24, 26, 30], "web": [2, 5, 14, 25], "browser": [2, 14], "A": [2, 4, 5, 6, 12, 13, 14, 22, 23, 25, 26, 27, 29, 30], "good": [2, 4, 5, 7, 8, 13, 28], "contain": [2, 9, 14, 29], "format": [2, 9, 10, 14, 23, 31], "thi": [2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 22, 23, 24, 25, 26, 28, 29, 30, 31], "i": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31], "fragment": [2, 14, 31], "mp4": [2, 30], "frag": [2, 30], "aka": [2, 13, 23], "fmp4": 2, "basic": [2, 5, 24, 30], "have": [2, 3, 4, 5, 7, 8, 11, 12, 13, 14, 18, 23, 24, 25, 26, 28, 29, 30, 31], "those": [2, 5, 7, 14, 15], "file": [2, 3, 6, 8, 9, 11, 14, 15, 16, 24, 29], "smaller": 2, "chunk": [2, 31], "box": [2, 4, 25, 30], "so": [2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 18, 23, 24, 25, 28, 29, 30, 31], "can": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 17, 18, 22, 23, 24, 25, 26, 28, 29, 30, 31], "sent": [2, 15, 23, 29], "over": [2, 3, 4, 11, 16, 23, 25, 29, 31], "lan": [2, 4, 25], "wan": [2, 11, 28, 31], "abl": [2, 8, 24, 29], "produc": 2, "while": [2, 4, 6, 8, 9, 11, 13, 14, 15, 22, 28, 31], "read": [2, 4, 5, 6, 8, 9, 10, 12, 13, 14, 15, 17, 25, 26, 29, 30, 31], "them": [2, 3, 4, 7, 9, 11, 12, 13, 14, 23, 24, 26, 28, 31], "one": [2, 3, 8, 11, 14, 18, 23, 25, 28, 29, 30, 31], "python": [2, 3, 6, 7, 9, 11, 15, 25, 27, 28, 29, 30], "code": [2, 7, 8, 9, 11, 14, 17, 18, 24, 26, 27, 28, 30], "pleas": [2, 4, 5, 6, 8, 11, 14, 25, 26, 27, 28, 31], "refer": [2, 3, 8, 11, 18, 25, 26, 28, 30, 31], "tutori": [2, 4, 6, 7, 9, 14, 18, 19, 23, 25, 26, 28, 29, 31], "after": [2, 3, 5, 8, 9, 11, 14, 25, 28, 29, 31], "obtain": 2, "just": [2, 3, 4, 5, 7, 8, 9, 11, 13, 14, 18, 19, 22, 23, 25, 26, 27, 28, 29, 31], "imagin": [2, 24, 29], "send": [2, 6, 8, 10, 11, 13, 14, 16, 23, 24, 25, 26, 30], "internet": [2, 5, 25], "websocket": 2, "grrp": 2, "ani": [2, 3, 4, 8, 9, 11, 14, 15, 26, 29, 31], "protocol": [2, 5, 9, 24, 30], "choic": [2, 6], "also": [2, 3, 4, 7, 9, 10, 11, 13, 14, 15, 16, 18, 19, 23, 24, 25, 26, 28, 29, 31], "dump": [2, 9, 11, 12, 29, 31], "an": [2, 6, 7, 8, 11, 12, 13, 14, 15, 16, 17, 18, 23, 24, 25, 26, 27, 28, 29, 30], "understood": 2, "all": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 23, 24, 25, 26, 28, 29, 31], "media": [2, 6, 7, 9, 13, 24, 30, 31], "client": [2, 3, 6, 7, 17, 24, 26, 30], "rememb": [2, 3, 4, 8, 14, 25], "cach": [2, 11, 31], "write": [2, 7, 9, 12, 13, 14, 25, 26, 30, 31], "ftyp": 2, "moov": 2, "packet": [2, 12, 15, 25], "begin": [2, 5, 9, 11, 12, 13, 14, 15, 16, 18], "For": [2, 4, 5, 6, 7, 8, 11, 12, 13, 14, 16, 22, 23, 24, 25, 28, 29, 30, 31], "creat": [2, 3, 6, 7, 8, 9, 11, 12, 13, 14, 16, 18, 22, 23, 24, 26, 27, 31], "pipelin": [2, 7, 25], "like": [2, 4, 5, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 24, 25, 26, 28, 29, 30, 31], "take": [2, 4, 6, 8, 11, 13, 14, 18, 23, 24, 25, 26, 29, 30, 31], "look": [2, 4, 6, 8, 9, 11, 13, 14, 15, 17, 24, 26, 31], "To": [2, 7, 9, 10, 11, 14, 15, 31], "plai": [2, 9, 13, 14, 15, 16, 19, 29, 30, 31], "sourc": [2, 4, 8, 9, 13, 15, 25, 26, 28, 29], "extens": [2, 3, 5, 7, 27], "mse": 2, "receiv": [2, 11, 15, 25, 26, 30], "through": [2, 12, 14, 25], "push": [2, 11, 14], "api": [2, 4, 6, 9, 11, 12, 13, 22, 23, 24, 25, 27, 28, 30, 31], "achiev": [2, 11, 13, 25], "true": [2, 8, 11, 14, 25], "cross": [2, 23], "platform": [2, 25], "solut": [2, 6, 7, 14, 23, 31], "work": [2, 5, 6, 8, 14, 24, 25, 26, 30, 31], "linux": [2, 3, 4, 6, 23, 24, 25, 28, 29, 30, 31], "window": [2, 7, 14, 16, 17, 18, 19, 23, 25, 26, 29, 30], "desktop": [2, 6, 23, 25, 30], "mac": 2, "io": [2, 8], "As": [2, 7, 9, 11, 23, 26, 28, 29], "septemb": 2, "2020": [2, 21], "iphon": 2, "still": [2, 4, 5, 13, 25, 31], "lack": 2, "onli": [2, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 22, 24, 25, 26, 28, 29, 31], "devic": [2, 5, 9, 11, 24, 31], "where": [2, 9, 10, 11, 12, 13, 14, 23, 26, 29, 31], "approach": [2, 6, 26, 31], "doesn": [2, 25], "t": [2, 4, 7, 8, 11, 14, 15, 23, 25, 28, 29, 31], "In": [2, 3, 5, 7, 9, 11, 12, 14, 15, 16, 17, 23, 24, 25, 26, 28, 29, 31], "case": [2, 8, 9, 13, 14, 18, 23, 25, 28, 31], "should": [2, 3, 4, 5, 7, 8, 9, 11, 12, 13, 14, 16, 25, 29, 30, 31], "dynam": 2, "hl": 2, "playlist": 2, "again": [2, 6, 9, 11, 14, 16, 25, 28, 31], "conveni": [2, 14, 26], "more": [2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 19, 25, 26, 29, 31], "inform": [2, 7, 8, 9, 10, 11, 14, 25], "about": [2, 4, 5, 6, 9, 10, 11, 14, 24, 27, 28, 31], "structur": [2, 8, 10], "see": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 22, 23, 24, 25, 26, 27, 29, 31], "stack": [2, 7, 12, 13, 18, 25, 26], "overflow": 2, "post": 2, "github": [2, 7, 8, 28], "repositori": [2, 6, 7, 28], "document": [2, 6, 9, 11, 12, 13, 14, 26], "codec": [2, 6, 9], "combin": [2, 3, 26], "support": [2, 6, 7, 10, 16, 30], "major": 2, "most": [2, 8, 14, 24, 25, 30], "typic": [2, 4, 5, 6, 7, 11, 12, 13, 22, 25, 26, 31], "h264": [2, 4, 5, 9, 10, 11, 12, 13, 14, 15, 29, 30, 31], "list": [2, 10, 12, 14, 24], "link": [2, 8, 24], "note": [2, 6, 9, 11, 16, 26], "h265": [2, 30], "behind": 2, "subject": [2, 23, 24, 29], "segfault": 3, "memleak": [3, 4], "etc": [3, 4, 6, 7, 8, 9, 11, 12, 13, 14, 16, 18, 25, 26, 29, 30], "rigor": 3, "valgrind": 3, "remov": [3, 8, 28, 29], "memori": [3, 4, 5, 6, 7, 11, 13, 14, 17, 18, 26, 29, 30, 31], "leak": [3, 4, 5], "cpp": [3, 6, 7, 8, 9, 11, 12, 13, 14, 18, 26, 27], "level": [3, 4, 6, 7, 9, 11, 13, 22, 27, 28, 30], "howev": [3, 4, 7, 8, 9, 11, 12, 13, 14, 24, 25, 26], "swig": [3, 14, 26], "throw": 3, "mix": [3, 26], "multithread": [3, 6, 14], "multiprocess": [3, 6, 14, 27], "share": [3, 6, 7, 14, 15, 17, 18, 23, 26, 29], "between": [3, 6, 7, 12, 14, 18, 23, 24], "process": [3, 6, 7, 14, 18, 25, 26, 28, 29], "give": [3, 14, 24, 29], "surpris": [3, 5], "check": [3, 5, 6, 7, 8, 11, 23, 24, 25, 28], "pull": [3, 7, 14, 25, 28], "frame": [3, 6, 7, 12, 13, 15, 16, 17, 18, 23, 25, 26, 29, 30, 31], "channel": 3, "than": [3, 4, 8, 28, 29], "gdb": 3, "instal": [3, 5, 6, 8, 14, 22, 23, 25, 26, 29, 30], "python3": [3, 6, 7, 8, 14, 18, 22, 25, 26, 27, 28, 29, 30], "symbol": [3, 12], "sudo": [3, 5, 8, 23, 24, 25, 28, 31], "apt": [3, 8, 23, 24, 25, 28], "get": [3, 4, 7, 8, 9, 11, 14, 23, 24, 25, 28, 29, 31], "dbg": 3, "Then": [3, 9, 14, 15, 25, 31], "custom": [3, 6, 7, 11, 26, 28], "build": [3, 6, 8, 23, 28], "enabl": [3, 11, 23, 25], "final": [3, 5, 7, 8, 9, 11, 12, 13, 14, 16, 19, 23, 26, 28, 29, 31], "applic": [3, 4, 6, 7, 11, 13, 25, 26], "": [3, 4, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 19, 23, 24, 25, 26, 28, 29, 31], "entri": [3, 9], "point": [3, 7, 9, 11, 18, 31], "arg": 3, "python_program": 3, "backtrac": 3, "bt": 3, "If": [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 23, 24, 25, 26, 27, 28, 29, 30], "trace": [3, 25], "object": [3, 7, 11, 12, 14, 24, 31], "obmalloc": 3, "c": [3, 5, 6, 9, 15, 21, 25, 29], "mess": [3, 29], "count": 3, "3": [3, 4, 5, 7, 11, 14, 16, 17, 18, 19, 23, 25, 28, 29, 30], "clear": [3, 14, 19], "semaphor": [3, 6, 7, 14, 29], "everi": [3, 11], "now": [3, 11, 12, 13, 14, 18, 24, 29, 31], "dev": [3, 5, 6, 8, 10, 31], "shm": 3, "valkka": [3, 4, 5, 9, 10, 11, 12, 14, 15, 16, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31], "follow": [3, 5, 7, 9, 10, 11, 12, 13, 14, 16, 23, 25, 26, 28, 29, 31], "consumpt": [3, 29], "setproctitl": [3, 28], "modul": [3, 6, 7, 8, 14, 24, 25, 27], "name": [3, 4, 5, 6, 8, 9, 11, 14, 15, 17, 18, 24, 28, 29], "wai": [3, 5, 8, 13, 14, 23, 25, 26, 28, 31], "easili": [3, 18, 26], "standard": [3, 5, 7, 25, 29, 30], "monitor": [3, 13, 23, 25], "tool": [3, 8, 11, 15, 24, 25, 31], "htop": 3, "smem": 3, "set": [3, 5, 8, 9, 10, 11, 13, 23, 24, 25, 28, 29, 31], "cours": [3, 14], "happen": [3, 5, 18, 23], "fork": [3, 11, 14, 26, 30], "exampl": [3, 4, 6, 7, 8, 9, 11, 13, 14, 17, 19, 23, 26, 27, 28, 29, 30, 31], "script": [3, 14, 15], "memwatch": 3, "bash": [3, 8, 25], "aux": 3, "directori": [3, 8, 10, 11, 29, 31], "Or": 3, "launch": [3, 8, 15, 23, 25, 26, 29], "go": [3, 5, 6, 10, 11, 13, 14, 24, 25, 26], "setup": [3, 8, 9, 11, 16, 23], "displai": [3, 6, 25], "option": [3, 23, 24, 25], "hide": 3, "userland": 3, "thread": [3, 6, 7, 9, 10, 11, 12, 13, 14, 15, 17, 18, 23, 26, 29, 31], "make": [3, 8, 11, 14, 15, 23, 25, 27, 31], "output": [3, 9, 11, 12, 15], "readabl": 3, "adequ": 3, "prefer": [3, 25, 28, 29, 30], "pyqt5": [3, 23, 28], "pyside2": [3, 6, 8, 23, 28], "instead": [3, 4, 5, 11, 12, 14, 23, 25, 26, 29], "The": [3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 21, 22, 23, 24, 25, 26, 28, 31], "former": [3, 11], "significantli": 3, "stabl": [3, 5, 8, 28], "handl": [3, 4, 10, 11, 14, 23], "tricki": 3, "qt": [3, 6, 7, 11, 23, 25, 27, 28, 29], "v": [3, 5, 14, 15, 29], "correctli": [3, 11, 25, 26], "especi": [3, 5, 12], "thing": [3, 7, 11, 12, 14, 24, 26, 29, 31], "consid": [3, 9, 12, 13, 23, 25, 26, 29, 31], "switch": [3, 25, 29], "By": [4, 14, 25, 29], "default": [4, 8, 10, 15, 18, 25, 28, 29], "core": [4, 5, 7, 9, 10, 11, 14, 15, 16, 18, 19, 21, 22, 25, 27, 28, 29, 31], "per": [4, 6, 11, 13, 25, 29], "bound": [4, 29, 30], "certain": [4, 11, 13, 24, 28, 29], "detail": [4, 5, 7, 9, 11, 12, 13, 24, 26, 31], "idea": [4, 7, 8, 11, 13], "larg": [4, 6, 7, 11, 25, 29, 31], "number": [4, 6, 9, 10, 11, 13, 14, 15, 16, 18, 23, 25, 26, 29, 31], "light": 4, "stream": [4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 17, 18, 19, 25, 29, 30], "what": [4, 7, 9, 13, 14, 23, 25, 26, 29, 30, 31], "exactli": [4, 14, 25], "depend": [4, 5, 7, 8, 11, 13, 14, 25, 28], "let": [4, 9, 11, 12, 13, 14, 15, 16, 19, 23, 24, 26, 29, 31], "assum": [4, 28, 31], "1080p": [4, 29], "approx": 4, "20": [4, 7, 13, 18, 24, 25], "second": [4, 8, 11, 13, 14, 16, 18, 19, 24, 25, 28, 29, 31], "need": [4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 23, 24, 25, 26, 27, 28, 29, 30, 31], "heavi": [4, 12], "might": [4, 6, 7, 8, 11, 14, 15, 25, 28, 29], "want": [4, 5, 6, 7, 10, 11, 13, 14, 23, 25, 29, 31], "dedic": [4, 11, 23, 26, 31], "sever": [4, 11, 12, 14, 15, 23, 25, 26, 29, 30, 31], "could": [4, 8, 11, 12, 13, 14, 16, 19, 25], "4000x3000": 4, "4k": 4, "60": [4, 10, 14, 15], "befor": [4, 8, 9, 11, 12, 14, 15, 24, 25, 29, 30], "beast": [4, 11], "must": [4, 5, 6, 8, 11, 14, 16, 17, 24, 28], "ask": 4, "yourself": [4, 6, 8, 10, 23], "realli": [4, 5, 25], "someth": [4, 7, 11, 23, 26, 31], "biggest": 4, "screen": [4, 6, 7, 9, 12, 13, 14, 16, 18, 23, 29], "ll": [4, 7, 11, 12, 13, 14, 24, 29, 31], "ever": [4, 6], "view": [4, 6, 13, 14], "probabl": [4, 23, 25], "framer": [4, 13, 23], "human": 4, "ey": [4, 7], "modern": [4, 30], "convolut": 4, "neural": 4, "network": [4, 25], "yolo": [4, 8, 14, 27], "resolut": [4, 10, 13, 14, 18, 24, 25, 29], "600x600": 4, "pixel": [4, 7], "analyz": [4, 6, 7, 26, 30], "max": [4, 11, 14], "30": [4, 11, 16], "And": [4, 5, 7, 14, 25, 26], "haven": 4, "talk": [4, 5], "clog": 4, "modifi": [4, 14, 24, 25], "lesson": [4, 6, 26], "avthread": [4, 5, 7, 10, 12, 13, 14, 16, 17, 18, 19, 25], "info_filt": [4, 9, 12, 15], "setnumberofthread": 4, "That": [4, 8, 9, 11, 12, 24, 26, 28], "four": [4, 23], "call": [4, 6, 9, 11, 12, 16, 19, 25], "instanc": [4, 9, 11, 18], "hardwar": [4, 6, 8, 12, 25, 29], "hw": [4, 25], "avail": [4, 5, 7, 8, 9, 13, 18, 22, 25, 29, 31], "mayb": [4, 25], "better": [4, 25], "save": [4, 11, 13, 15, 29, 30, 31], "muscl": 4, "deep": [4, 6], "learn": [4, 6, 7, 9, 11, 14, 18, 23, 26, 28, 29], "infer": 4, "librari": [4, 5, 6, 8, 9, 13, 14, 24, 26, 28], "close": [4, 9, 13, 16, 18, 25, 26], "implement": [4, 5, 7, 9, 14, 24, 25], "underli": [4, 18, 31], "black": 4, "poorli": 4, "suffer": 4, "slowli": 4, "accumul": 4, "poison": 4, "which": [4, 5, 7, 9, 11, 24, 25, 26, 31], "suppos": [4, 6, 11, 31], "continu": [4, 7, 9, 11, 14, 16, 29, 31], "dai": 4, "week": 4, "even": [4, 7, 11, 13, 14, 24, 25, 29, 31], "forev": 4, "sometim": 4, "proprietari": [4, 5, 13, 23, 25], "mai": [4, 28], "restrict": 4, "mani": [4, 5, 7, 13, 23, 25, 29], "simultan": [4, 6, 7, 11, 13, 14, 15, 17, 18, 25, 29, 31], "cpu": [4, 7, 12, 14, 17, 25], "sole": 4, "decent": [4, 5, 30], "don": [4, 14, 23, 25, 28, 29], "obsess": 4, "when": [4, 5, 8, 9, 11, 12, 13, 14, 23, 24, 25, 28, 29, 31], "intra": 4, "much": [4, 9], "time": [4, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 19, 24, 25, 29, 31], "consecut": [4, 19], "b": [4, 6, 16, 25], "p": [4, 25], "veri": [4, 5, 11, 14, 25, 29, 31], "pronounc": 4, "abov": [4, 11, 14, 24, 25, 28, 29], "becaus": 4, "arriv": [4, 11, 13, 25, 29], "late": [4, 25], "present": [4, 6, 7, 11, 13, 16, 18, 25, 29, 31], "burst": [4, 11, 16, 25], "problem": [4, 6, 7, 14, 28, 29, 31], "solv": [4, 6, 7, 26, 31], "buffer": [4, 7, 13, 14, 15, 25, 29, 31], "import": [4, 5, 9, 10, 11, 13, 14, 15, 16, 18, 19, 24, 26, 28], "glthread": [4, 7, 10, 13, 14, 16, 17, 18, 19, 26], "openglthread": [4, 7, 10, 13, 14, 16, 17, 18, 19, 23, 25, 26], "gl_ctx": [4, 13], "openglframefifocontext": [4, 13], "40": 4, "reserv": [4, 7, 12, 13, 18, 23, 25, 29, 31], "millisecond": [4, 11, 13, 14, 17, 29, 31], "would": [4, 11, 13, 14, 25, 28, 31], "api2": [4, 9, 11, 14, 18, 22, 27], "class": [4, 6, 9, 10, 11, 12, 13, 14, 18, 25, 26, 31], "720p": [4, 10, 13, 29], "pre": [4, 7, 12, 13, 23, 25, 29, 31], "total": [4, 11, 13, 30, 31], "other": [4, 5, 7, 8, 11, 14, 25, 26, 28, 29], "issu": [4, 5, 25], "well": [4, 5, 14, 23, 26, 31], "imag": [4, 6, 12, 14, 24, 25], "termin": [4, 9, 11, 25], "scream": [4, 25], "enhanc": 4, "onvif": [5, 6, 27, 30], "compliant": [5, 6, 30], "rtsp": [5, 9, 11, 12, 13, 14, 16, 18, 19, 25, 29, 30], "initi": [5, 11], "configur": [5, 6, 25, 29], "hurdl": 5, "requir": [5, 7, 8, 17, 28, 29, 30, 31], "half": [5, 25], "broken": [5, 25], "activ": [5, 9, 11, 14, 16], "download": [5, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 28], "outdat": 5, "version": [5, 6, 8, 14, 23, 24, 25], "explor": 5, "onc": [5, 7, 11, 13, 14, 17, 25, 28, 29, 30, 31], "sort": 5, "out": [5, 6, 7, 8, 9, 12, 13, 14, 23, 24, 28, 29, 30, 31], "manufactur": 5, "axi": [5, 24], "hand": [5, 11], "javascript": 5, "interfac": [5, 6, 14, 18, 22, 25, 28, 29], "done": [5, 12, 13, 14, 15, 16, 17, 24, 26], "succesful": 5, "connect": [5, 7, 9, 11, 12, 13, 14, 17, 18, 23, 25, 26, 29, 30, 31], "sai": [5, 7, 9, 11, 14, 25, 26, 29, 30], "ffmpeg": [5, 7, 28, 29], "user": [5, 6, 7, 8, 11, 12, 13, 18, 22, 23, 24, 25, 28, 29, 31], "password": [5, 24, 29], "address": [5, 11, 13, 14, 15, 17, 18, 24], "capabl": [5, 31], "against": [5, 25, 29], "logitech": 5, "hd": [5, 10, 14, 25], "pro": [5, 10], "webcam": [5, 10], "c920": [5, 10], "moment": [5, 9, 11, 30], "textur": [5, 7, 13], "robust": [5, 23], "current": [5, 11, 22, 26, 28, 29, 31], "situat": [5, 11, 13, 25], "intel": [5, 13, 25], "stock": [5, 6, 7, 25], "driver": [5, 13, 23, 25], "ok": [5, 14], "ati": 5, "greater": [5, 23], "command": [5, 8, 10, 13, 15, 24, 25, 31], "glxinfo": 5, "word": [5, 12], "warn": [5, 31], "vaapi": [5, 25], "come": [5, 8, 13, 24, 26, 28], "libav": [5, 7], "infrastructur": [5, 11, 14, 26], "addit": [5, 29], "packag": [5, 8, 13, 22, 24, 26, 28], "belong": [5, 22], "group": [5, 10, 13, 19, 29], "doe": [5, 9, 10, 11, 12, 14, 18, 26, 29], "appear": [5, 7, 8, 25, 31], "usermod": [5, 31], "g": [5, 23, 30, 31], "logout": [5, 25, 31], "login": [5, 25, 31], "replac": 5, "vaapithread": [5, 12], "e": [5, 9, 11, 12, 13, 14, 18, 22, 23, 24, 25, 26, 28, 30, 31], "target_filt": 5, "oftentim": 5, "latest": [5, 25], "distribut": [5, 8, 28], "itself": [5, 6, 9, 12], "whatev": 5, "minim": [5, 25, 31], "try": [5, 7, 11, 18, 24, 25, 26, 28, 29, 31], "came": 5, "distro": [5, 25, 28, 30], "libva_driver_nam": [5, 25], "i965": [5, 25], "hwaccel": 5, "passwd": [5, 30], "rawvideo": 5, "pix_fmt": 5, "yuv420p": 5, "f": [5, 11, 12, 27, 31], "sdl": 5, "bust": 5, "seem": [5, 25], "featur": [5, 7, 8, 9, 14, 28], "bug": [5, 8, 23], "discuss": [5, 9, 11, 23, 25, 26], "confirm": 5, "myself": 5, "libva": 5, "6": [5, 25, 29, 30], "opensourc": [5, 6, 7, 24], "mesa": [5, 13, 25, 28], "enforc": 5, "intern": [5, 9, 12, 31], "environ": [5, 23, 25], "variabl": [5, 11, 23, 24], "export": [5, 13, 25, 30], "valkka_libva_driver_nam": 5, "wish": 5, "docker": [5, 25], "dri": 5, "sure": [5, 11, 25, 31], "host": [5, 23], "machin": [5, 6, 7, 14, 22, 24, 25, 26], "ha": [5, 7, 9, 10, 11, 12, 13, 14, 16, 25, 26, 28], "relat": 5, "easiest": 5, "gpu": [5, 6, 7, 13, 14, 25, 29], "usag": [5, 25], "realtim": 5, "intel_gpu_top": 5, "cuda": 5, "provid": [5, 11, 13, 14, 18, 24, 25, 26, 28, 30], "separ": [5, 14, 18, 23, 24, 26], "nv": 5, "namespac": [5, 11, 22, 24, 27], "nvthread": 5, "gpu_index": 5, "huawei": 5, "cann": 5, "experiment": [5, 10, 28, 29, 31], "guarante": 5, "video surveil": 6, "video manag": 6, "video analysi": 6, "machine vis": 6, "framework": [6, 26], "surveil": [6, 7, 13, 14, 25, 27], "pure": 6, "No": [6, 7, 15], "highlight": 6, "background": [6, 11, 26], "queue": [6, 7, 12, 13], "hidden": [6, 7], "complex": [6, 7, 9, 12, 13, 18, 24, 31], "filtergraph": [6, 7, 9, 11, 12, 13, 14, 15, 16, 17, 18, 26], "disk": [6, 7, 9, 11, 16, 17, 31], "via": [6, 26], "across": 6, "system": [6, 7, 8, 9, 14, 26, 29, 30, 31], "plug": 6, "base": [6, 7, 12, 13, 14, 24, 25], "vision": [6, 7, 14, 22, 26], "agnost": 6, "everyth": [6, 7, 14, 25, 29], "goe": [6, 7, 11, 14, 16, 18], "pytorch": 6, "tensorflow": [6, 7], "design": [6, 7, 11, 13, 25], "massiv": [6, 25], "recast": [6, 7, 15, 17, 29], "either": [6, 8, 25, 29], "multicast": [6, 7, 16, 17, 29, 30], "unicast": [6, 29], "graphic": [6, 23, 26, 28], "interact": [6, 29, 31], "signal": [6, 7, 11, 26, 29], "slot": [6, 7, 9, 10, 11, 12, 13, 14, 15, 16, 18, 19, 26, 29, 31], "highli": [6, 26], "gui": [6, 11, 14, 26, 31], "develop": [6, 7, 24, 29, 31], "wonder": 6, "why": [6, 31], "cool": 6, "econom": 6, "benefit": 6, "investor": 6, "perhap": 6, "vm": [6, 11, 25], "whitepap": 6, "alreadi": 6, "involv": 6, "knee": 6, "busi": [6, 19], "quickstart": 6, "recommend": [6, 7, 13, 26, 31], "articl": 6, "re": [6, 7, 11, 13, 15, 22, 25, 26, 27, 28, 29, 30], "cloud": [6, 14], "app": 6, "streamer": 6, "demo": [6, 14, 23, 27, 28], "project": [6, 14], "usb": [6, 25, 30, 31], "acceler": [6, 12], "ppa": 6, "releas": [6, 8, 14], "compil": [6, 8, 25], "numpi": [6, 8, 14], "gtk": [6, 26], "opencv": [6, 7, 17, 25, 26, 29, 30], "test_studio_detector": [6, 26], "prerequisit": 6, "singl": [6, 11, 14, 15, 17, 18, 19, 23, 26, 29, 30, 31], "integr": [6, 7], "draw": [6, 30], "widget": [6, 7, 29], "multi": [6, 29], "introduct": 6, "our": [6, 9, 11, 14, 26], "valkkaf": [6, 7, 29, 30], "architectur": [6, 7, 8, 13, 28], "filesystem": [6, 7, 11], "multipl": [6, 11, 14, 23, 29, 30], "entir": [6, 11], "partit": [6, 11], "discoveri": [6, 27], "intro": [6, 7], "zeep": 6, "servic": [6, 8, 18], "pitfal": [6, 26], "common": [6, 14, 18, 29], "bottleneck": [6, 23], "tune": 6, "faq": 6, "debug": [6, 7, 11, 14, 25, 29], "index": [6, 8, 14, 29], "licenc": 6, "copyright": 6, "author": [6, 24], "knowledg": [6, 30], "contrib": 6, "jetson": 6, "nano": 6, "search": [6, 11], "page": [6, 7, 13, 22, 23, 25, 28], "yet": [7, 11, 14], "anoth": [7, 9, 11, 12, 13, 14, 15, 23, 29], "player": [7, 9, 29, 30], "my": 7, "fast": 7, "easi": 7, "me": 7, "show": [7, 14], "vlc": [7, 25, 28, 29, 30], "its": [7, 8, 13, 26, 28, 30], "bind": [7, 27, 28, 29, 30], "won": [7, 8], "Such": [7, 14], "scale": 7, "manag": [7, 9, 13, 23, 25, 31], "analysi": [7, 14, 26], "demand": [7, 15], "grow": 7, "rapidli": 7, "due": [7, 25], "declin": 7, "price": 7, "comput": [7, 24], "power": [7, 25], "burn": 7, "noth": [7, 9, 14, 25], "avoid": [7, 31], "too": [7, 9, 10, 13, 15, 25], "limit": [7, 11, 13], "desper": 7, "luck": 7, "loopback": 7, "ve": [7, 23], "been": [7, 8, 13, 14, 16, 23, 25, 26, 28], "pluggin": 7, "favorit": [7, 8, 9], "written": [7, 9, 11, 14, 15, 22, 26, 31], "It": [7, 9, 11, 12, 13, 14, 18, 23, 25, 26], "comfort": 7, "With": [7, 13, 14, 23, 25], "pipe": [7, 16, 26], "subroutin": 7, "net": [7, 16, 25], "safe": [7, 12], "mutex": [7, 12], "gori": [7, 12], "got": [7, 14], "interest": [7, 27], "togeth": [7, 9, 26, 29, 31], "own": [7, 13, 14, 23, 24, 26, 27, 29], "manual": [7, 8, 24, 28], "special": [7, 11], "emphasi": [7, 9, 26], "subprogram": 7, "beyond": 7, "technic": 7, "small": [7, 9, 12, 14, 15, 17, 25, 31], "sampl": [7, 26], "main": [7, 9, 11, 14, 17, 24, 26], "branch": [7, 9, 11, 14, 17, 18], "livethread": [7, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 25, 26, 29], "forkframefilt": [7, 9, 14, 17], "fork_filt": [7, 11, 14, 17], "intervalframefilt": [7, 14, 17], "interval_filt": [7, 14, 17], "swscaleframefilt": [7, 14, 17], "sws_filter": [7, 14, 17], "rgbsharedmemframefilt": [7, 14, 17], "shmem_filt": [7, 14], "complet": [7, 11, 14], "think": 7, "scratch": 7, "extern": [7, 31], "glx": 7, "dure": [7, 9, 16], "futur": 7, "fish": 7, "algorithm": [7, 8], "alpha": 7, "stage": [7, 12, 31], "lot": [7, 9, 14, 17], "stuff": [7, 9, 11, 14, 17], "least": [7, 8, 10, 24, 25, 30], "promis": 7, "organ": [7, 11, 13, 22, 31], "codebas": 7, "licens": [7, 21, 27, 28], "under": [7, 10, 11, 12, 13, 21, 22, 31], "lgpl": [7, 21, 27], "mit": [7, 27], "function": [7, 11], "demonstr": [7, 29], "updat": [7, 28], "new": [7, 11, 13, 14, 17], "Near": 7, "term": [7, 28], "goal": [7, 14], "interserv": 7, "commun": [7, 14, 23, 24, 26], "server": [7, 23, 24, 25, 29, 30], "record": [7, 11, 29, 31], "amount": [7, 31], "fulli": 7, "oper": [7, 29], "synchron": [7, 11, 13, 24, 25, 31], "fishey": 7, "sound": 7, "technologi": 7, "live555": [7, 15, 18], "tip": [8, 25], "instruct": [8, 22, 28, 29, 30], "ordinari": 8, "binari": [8, 28, 31], "handi": 8, "pip3": [8, 22, 23, 25, 28], "wheel": [8, 29], "dir": 8, "your_directori": 8, "r": [8, 29], "txt": 8, "whl": 8, "defin": [8, 9, 10, 11, 12, 13, 14, 15, 23, 24, 29], "pypi": 8, "org": [8, 13, 24, 25], "next": [8, 9, 11, 12, 13, 14, 16, 18, 28, 31], "put": 8, "http": [8, 24, 28], "pip": [8, 24, 28], "readthedoc": 8, "en": 8, "user_guid": 8, "normal": [8, 9, 11, 14, 22, 24, 29, 31], "upgrad": [8, 28], "includ": [8, 9, 11, 24, 25, 26, 28], "non": [8, 11], "free": [8, 15], "part": [8, 9, 12, 13, 14, 16, 18, 22, 25, 28], "patent": 8, "sinc": [8, 14], "disabl": [8, 13, 25], "There": [8, 11, 12, 13, 17, 26, 31], "essenti": 8, "cmake": 8, "git": [8, 28, 30], "libgtk2": 8, "pkg": 8, "config": [8, 25], "libavcodec": 8, "libavformat": [8, 15], "libswscal": 8, "libv4l": 8, "libtbb2": 8, "libtbb": 8, "libjpeg": 8, "libpng": 8, "libtiff": 8, "libjasp": 8, "libdc1394": 8, "22": [8, 11, 12], "libxvidcor": 8, "libx264": 8, "add": [8, 11, 13, 19, 28, 29], "therein": [8, 26], "run_cmak": [8, 25], "bin": 8, "d": [8, 10, 31], "with_cuda": 8, "off": [8, 9, 18, 23, 25], "opencv_extra_modules_path": 8, "opencv_contrib": 8, "opencv_enable_nonfre": 8, "ON": 8, "with_gstream": 8, "with_libv4l": 8, "build_opencv_python2": 8, "build_opencv_python3": 8, "cpack_binary_deb": 8, "build_test": 8, "build_perf_test": 8, "build_exampl": 8, "cmake_build_typ": 8, "cmake_install_prefix": 8, "usr": [8, 22, 24, 28], "local": [8, 15, 24, 28, 29], "j": 8, "emploi": 8, "trick": 8, "debian": [8, 22, 28], "line": [8, 10, 13, 24, 25, 28, 29], "cpack_debian_package_shlibdep": 8, "cpackconfig": 8, "deb": [8, 28], "dpkg": [8, 28], "two": [8, 9, 11, 12, 13, 14, 17, 18, 23, 28, 29, 31], "flavor": [8, 11, 28], "deal": [8, 9, 13], "latter": [8, 11, 25], "jetsonnano": 8, "u": [8, 11, 24, 25, 27], "email": 8, "simpli": [8, 9, 11, 14, 23, 29], "ourselv": 8, "clang": 8, "header": 8, "libclang": 8, "qt5": 8, "qtscript5": 8, "libssl": 8, "qttools5": 8, "qtmultimedia5": 8, "libqt5svg5": 8, "libqt5webkit5": 8, "libsdl2": 8, "libasound2": 8, "libxmu": 8, "libxi": 8, "freeglut3": 8, "libjack": 8, "jackd2": 8, "libxrandr": 8, "libqt5xmlpatterns5": 8, "qtdeclarative5": 8, "privat": 8, "qtbase5": 8, "qtwebengine5": 8, "clone": [8, 28], "pysid": 8, "cd": [8, 18, 28, 29, 30], "pyside_setup": 8, "compat": 8, "qmake": 8, "9": [8, 9, 25, 29, 30], "checkout": 8, "edit": 8, "qtgui": [8, 26], "cmakelist": 8, "qtgui_gen_dir": 8, "qopengltimemonitor_wrapp": 8, "qopengltimerquery_wrapp": 8, "8": [8, 9, 11, 14, 23, 25, 29, 30], "hr": 8, "movi": 8, "wrapper": 8, "bdist_wheel": 8, "dist": [8, 22, 28], "packagenam": 8, "com": [8, 28], "wiki": 8, "qt_for_python": 8, "within": [8, 11, 14], "bugreport": 8, "brows": 8, "568": 8, "live_out_filt": [9, 14, 25], "infoframefilt": [9, 11, 12, 15], "fanci": [9, 12], "print": [9, 10, 11, 12, 13, 14, 15, 16, 18, 19, 24], "thei": [9, 11, 15, 23, 25, 28, 29, 31], "copi": [9, 12, 14, 29], "graph": 9, "feed": [9, 12, 14, 26], "instanti": [9, 11, 12, 13, 14, 15, 18, 24, 26, 31], "context": [9, 12, 13], "ctx": [9, 10, 11, 12, 13, 14, 15, 16, 19, 25], "liveconnectioncontext": [9, 11, 12, 13, 14, 15, 16, 19, 25], "liveconnectiontype_rtsp": [9, 11, 12, 13, 14, 15, 16, 19, 25], "admin": [9, 11, 12, 13, 14, 15, 16, 18, 19, 24, 25], "nordic12345": [9, 12, 13, 14, 15, 16, 18, 19, 25], "192": [9, 11, 12, 13, 14, 15, 16, 18, 19, 24, 25], "168": [9, 11, 12, 13, 14, 15, 16, 18, 19, 24, 25], "41": [9, 12, 13, 14, 15, 16, 18, 19, 25], "type": [9, 22, 31], "integ": [9, 11], "later": [9, 11], "startcal": [9, 10, 11, 12, 13, 14, 15, 16, 19], "registerstreamcal": [9, 11, 12, 13, 14, 15, 16, 19], "playstreamcal": [9, 11, 12, 13, 14, 15, 16, 19], "sleep": [9, 10, 11, 12, 13, 14, 15, 16, 18, 19], "stopcal": [9, 10, 11, 12, 13, 14, 15, 16, 19], "bye": [9, 10, 11, 12, 13, 14, 15, 16, 18, 19], "setupfram": 9, "timestamp": [9, 11, 12, 25, 29, 31], "1525870891068": 9, "subsession_index": [9, 11, 12], "media_typ": 9, "codec_id": 9, "27": 9, "payload": [9, 11, 12, 14], "timediff": [9, 12], "end": [9, 11, 12, 13, 14, 15, 16, 18, 31], "basicfram": [9, 11], "size": [9, 11, 12, 14, 15, 17, 25, 29, 31], "45": 9, "slice_typ": [9, 11], "103": [9, 11], "100": [9, 11, 14, 15, 18, 25], "42": [9, 13], "173": 9, "132": 9, "32": [9, 11], "97": 9, "67": 9, "24": [9, 24, 29], "104": [9, 11], "238": [9, 11], "49": 9, "178": 9, "few": [9, 11, 24], "byte": [9, 11, 14, 29, 31], "kei": [9, 11, 31], "flow": [9, 31], "sink": [9, 15], "consist": [9, 22, 25, 28, 29], "pcmu": 9, "inclus": [9, 11, 12, 13], "snippet": [9, 11, 12, 13, 15], "lesson_1_a": [9, 30], "py_": [9, 11, 12, 13], "previou": [9, 11, 12, 13, 14], "had": 9, "notat": [9, 11], "mark": [9, 11, 12], "parenthesi": 9, "curli": 9, "bracket": 9, "both": [9, 12, 14, 25, 26, 29, 31], "filter_2": 9, "filter_3": 9, "programmat": 9, "last": [9, 25, 26, 28, 29, 31], "pass": [9, 11, 12, 13, 14, 17, 24, 26, 29, 31], "target": [9, 11, 31], "confus": 9, "rule": 9, "thumb": 9, "info": [9, 11], "onto": 9, "correct": [9, 11, 14, 23, 25, 26, 29], "given": [9, 11, 19], "lesson_1_b": 9, "trivial": [9, 13], "gateframefilt": 9, "gate_filt": 9, "fileframefilt": [9, 11, 16, 17], "file_filt": [9, 11, 16], "fed": 9, "At": [9, 10, 11, 26, 30], "gate": 9, "further": [9, 14, 31], "construct": [9, 11, 12, 13, 14, 15, 16, 18, 24, 26], "outer": [9, 17], "leaf": 9, "tree": [9, 17], "move": [9, 17, 23], "edg": 9, "toward": [9, 17], "unset": 9, "mkv": [9, 11, 16, 29], "exit": [9, 11, 13, 14, 16, 19], "deactiv": [9, 14, 16], "method": [9, 11, 12, 16, 25, 26], "sec": [9, 11, 13, 16, 18], "turn": [9, 14, 23, 25], "result": [9, 26], "mediaplay": 9, "understand": [9, 13, 26], "thousand": 9, "enough": [9, 11, 25], "accept": [9, 29], "matroska": [9, 16, 29, 30], "lesson_1_c": 9, "wrap": [9, 14, 18, 26, 31], "doc": 9, "member": 9, "visibl": 9, "pyapi": [9, 12], "tag": [9, 12, 13, 14, 15, 16, 17], "callback": [9, 11], "cascad": 9, "block": [9, 11, 16, 31], "execut": [9, 16, 26], "independ": [9, 12], "shut": 9, "loglevel_sil": 9, "log": 9, "setvalkkaloglevel": 9, "setloglevel_livelogg": 9, "loglevel_norm": [9, 11], "logger": [9, 11], "silent": 9, "individu": [9, 11, 13], "v4l2": 10, "ctl": 10, "video2": 10, "found": [10, 14, 17, 22, 23, 24, 25, 26, 31], "sy": [10, 11, 25], "video4linux": 10, "differ": [10, 13, 14, 17, 23, 24], "usbdevicethread": 10, "gl_in_filt": [10, 13, 14, 16, 19], "getframefilt": [10, 11, 12, 13, 14, 15, 16, 17, 19], "av_in_filt": [10, 12, 13, 14, 16, 19], "multiplex": [10, 14], "usbthread": 10, "usbcameraconnectioncontext": 10, "width": [10, 14, 17], "height": [10, 14, 17], "uncom": 10, "1920": [10, 12, 14, 17], "1080": [10, 12, 14, 17], "decodingoncal": [10, 12, 13, 14, 16, 19], "window_id": [10, 13, 14, 16, 18, 19, 26], "createwindow": [10, 13, 14, 16, 18, 19], "newrendergroupcal": [10, 13, 14, 16, 19], "context_id": [10, 13, 14, 16, 19, 26], "newrendercontextcal": [10, 13, 14, 16, 19, 26], "render": [10, 13, 19, 25], "z": [10, 13, 19, 26], "playcamerastreamcal": 10, "minut": 10, "patienc": 10, "keyfram": [10, 25, 31], "often": 10, "stopcamerastreamcal": 10, "delrendercontextcal": [10, 13, 14, 16, 19], "delrendergroupcal": [10, 13, 14, 16, 19], "decodingoffcal": [10, 12, 13, 14, 19], "earlier": 11, "redirect": 11, "consult": [11, 31], "section": [11, 25], "These": [11, 12, 13, 14, 22, 25], "downstream": 11, "speed": [11, 25, 31], "concurr": 11, "evok": 11, "request": [11, 12, 13, 16, 31], "valkkafswriterthread": [11, 31], "writerthread": 11, "valkkasinglef": [11, 29, 31], "loglevel_debug": 11, "loglevel_crazi": 11, "rtsp_address": 11, "12345": [11, 13, 24], "157": [11, 13], "each": [11, 13, 14, 17, 23, 24, 25, 29, 31], "setloglevel_filelogg": 11, "setloglevel_valkkafslogg": 11, "valkkamultif": [11, 29, 31], "metadata": [11, 14, 31], "tmp": [11, 31], "testvalkkaf": [11, 31], "newfromdirectori": [11, 31], "dirnam": [11, 31], "blocksiz": [11, 31], "2048": [11, 25, 31], "1024": [11, 14, 31], "divis": 11, "kilobit": 11, "n_block": 11, "verbos": [11, 14, 18, 29, 30], "hold": 11, "kbit": 11, "256": 11, "kbyte": 11, "data": [11, 14, 23, 31], "1024kbit": 11, "kbp": [11, 25], "finish": 11, "necessari": [11, 29], "condit": 11, "effici": [11, 14, 25, 31], "seek": [11, 16, 31], "256kb": 11, "2560": 11, "kb": 11, "skip": 11, "directli": [11, 14, 24, 25, 29, 31], "device_s": [11, 31], "blockfil": [11, 31], "tabl": [11, 24, 31], "dumpfil": [11, 31], "json": [11, 31], "respons": [11, 13, 24], "writer": 11, "framefilt": [11, 12, 13, 16, 18, 25, 30], "file_input_framefilt": 11, "identifi": [11, 14, 16, 17, 31], "id": [11, 13, 14, 15, 26, 31], "925412": 11, "invent": 11, "setslotidcal": 11, "idl": 11, "blocktabl": 11, "getblockt": 11, "Not": 11, "far": [11, 25], "updatet": 11, "disk_writ": 11, "definit": 11, "book": [11, 31], "keep": [11, 13, 18, 23, 25, 31], "forc": 11, "fill": 11, "load": [11, 25, 29], "loadfromdirectori": 11, "filterchain": [11, 12, 13, 14, 15, 18, 26, 31], "reader": 11, "out_filt": 11, "reader_out_filt": 11, "readerthread": 11, "valkkafsreaderthread": [11, 31], "map": [11, 13, 14, 16, 18, 26], "pullblockspycal": 11, "valkkafstool": 11, "allow": [11, 25], "peek": 11, "content": 11, "inspect": 11, "dumpblock": 11, "1543314164986": 11, "29": 11, "31": 11, "172": 11, "17": 11, "160": 11, "80": [11, 13, 24], "186": 11, "64": 11, "56": [11, 15], "176": 11, "1543314165135": 11, "19460": 11, "101": 11, "136": 11, "128": 11, "191": 11, "180": 11, "142": 11, "114": 11, "255": 11, "79": 11, "52": 11, "19": 11, "1543314165215": 11, "19408": 11, "193": 11, "200": [11, 29], "71": 11, "1543314165335": 11, "4928": 11, "65": 11, "154": 11, "127": [11, 15, 29], "208": 11, "117": 11, "223": 11, "181": 11, "129": 11, "206": 11, "84": 11, "indic": [11, 22, 29, 31], "column": [11, 24, 31], "asterix": 11, "row": [11, 31], "actual": [11, 14, 23], "shown": [11, 13], "min": [11, 14, 25, 29], "t0": 11, "t1": 11, "gettimerang": 11, "struct_tim": 11, "gmtime": 11, "1000": [11, 13, 14, 17, 25], "correspond": [11, 12, 28], "rang": [11, 13, 14], "req": 11, "block_indic": 11, "getind": 11, "recov": 11, "interv": [11, 14, 31], "useful": 11, "getindneigh": 11, "return": [11, 14, 26], "neighborhood": 11, "plu": 11, "surround": 11, "instant": [11, 31], "lesson_11_c": 11, "recal": 11, "saw": 11, "carri": 11, "muxer": 11, "On": [11, 13, 23, 25, 29], "simpl": [11, 13, 23, 29, 30, 31], "notion": 11, "basi": [11, 16, 29], "initstreamframefilt": 11, "forkframefiltern": 11, "passslotframefilt": 11, "slot_filt": 11, "init_stream": 11, "introduc": 11, "arbitrari": 11, "disconnect": 11, "init_filt": 11, "kokk": [11, 16], "valkkafsread": 11, "worth": 11, "shot": 11, "transmiss": 11, "framecacherthread": 11, "origin": 11, "were": 11, "being": [11, 14, 29, 31], "chang": [11, 24], "forward": 11, "similar": [11, 13, 14, 16, 29], "filecachethread": 11, "cacherthread": 11, "setpycallback": 11, "int": [11, 26], "mstime": 11, "freq": 11, "m": [11, 14, 15], "setpycallback2": 11, "tupl": [11, 14], "mstimestamp": [11, 14], "regist": [11, 13], "proce": [11, 12], "input": [11, 13, 16], "cacher": 11, "global": [11, 22, 28], "current_time_limit": 11, "none": [11, 14, 25], "frequent": [11, 25], "def": [11, 13, 26], "current_time_callback": 11, "rewindcal": 11, "todo": 11, "altern": [11, 25, 26], "your_list_of_block": 11, "except": 11, "fail": 11, "str": 11, "minimum": [11, 24], "maximum": [11, 25], "time_limits_callback": 11, "kept": 11, "asap": 11, "possibl": [11, 12, 14], "immedi": 11, "filestreamcontext": 11, "convert": [11, 26, 29], "seekstreamscal": 11, "assur": 11, "playstreamscal": 11, "behaviour": [11, 14, 29], "respect": 11, "playback": [11, 29, 31], "challeng": 11, "aris": 11, "easier": [11, 31], "test_studio_6": [11, 29], "churn": 12, "seri": 12, "filter": [12, 17, 26], "until": [12, 13], "explan": [12, 22, 29], "crossov": 12, "usual": [12, 13, 14, 16, 17, 19], "lift": 12, "bitmap": [12, 13, 14, 17, 25], "substitut": 12, "left": [12, 13, 15, 19, 29], "right": [12, 13, 19, 25, 29], "avbitmapfram": 12, "1525870759898": 12, "h": [12, 14], "w": [12, 14], "l": [12, 31], "960": 12, "47": 12, "1525870759938": 12, "11": [12, 23, 25, 30], "lesson_2_a": 12, "know": [12, 25], "hood": [12, 13], "bit": [12, 13, 26], "framefifo": [12, 26], "incom": [12, 15, 26], "place": [12, 13, 14, 26, 29, 31], "taken": [12, 14], "fifo": [12, 17], "protect": 12, "concern": 12, "inherit": 12, "diagram": 12, "subset": 12, "compar": 13, "continui": 13, "yuv": [13, 14, 17, 18], "interpol": [13, 14, 17, 25], "rgb": [13, 14, 17], "shader": 13, "languag": 13, "exist": [13, 26], "argument": [13, 18], "nice": [13, 14, 23, 24, 25, 29], "openglframefifo": 13, "adjust": [13, 14, 25, 31], "300": [13, 29], "math": [13, 25], "hard": [13, 25, 31], "hundr": 13, "extrem": [13, 24], "ambiti": 13, "who": 13, "brand": [13, 24], "8k": 13, "contex": [13, 23], "id_list": 13, "append": [13, 14], "variou": [13, 18, 25], "mind": [13, 18], "vertic": [13, 25], "refresh": [13, 25], "vsync": [13, 25], "rate": [13, 14, 25], "around": [13, 30], "50": 13, "nouveau": [13, 25], "vblank_mod": [13, 25], "glxgear": [13, 23, 25], "util": [13, 28], "report": [13, 23, 25], "encapsul": [13, 18, 31], "livestream": 13, "__init__": 13, "self": 13, "stream1": [13, 15], "stream2": 13, "window_id1": 13, "context_id1": 13, "window_id2": 13, "context_id2": 13, "quit": 13, "flexibl": 13, "opt": 13, "readi": [13, 14, 25], "made": 13, "purpos": [13, 14], "lesson_3_c": 13, "compact": [14, 18], "scheme": [14, 22, 25, 31], "chapter": 14, "regular": [14, 31], "observ": [14, 23, 25], "posix": [14, 17, 18, 29], "summar": 14, "dimens": 14, "quarter": 14, "full": [14, 17, 18, 25, 26], "image_interv": [14, 17], "shmem": [14, 17], "ringbuff": [14, 17], "uniqu": [14, 17], "ring": 14, "shmem_nam": [14, 17], "lesson_4": [14, 17], "shmem_buff": [14, 17], "rgbshmemframefilt": [14, 17], "briefinfoframefilt": 14, "timeintervalframefilt": [14, 17], "123456": 14, "134": 14, "ultim": [14, 29], "high": 14, "routin": 14, "below": [14, 25], "undefin": 14, "occur": 14, "pair": [14, 29], "shmemrgbclient": 14, "n_ringbuff": 14, "mstimeout": 14, "timeout": [14, 24], "fals": [14, 18], "meta": 14, "pullfram": 14, "els": [14, 24], "shmem_list": 14, "reshap": 14, "shape": 14, "arrai": 14, "isiz": 14, "extent": 14, "ten": [14, 18, 29, 31], "popular": [14, 29], "cv2": [14, 25], "img": 14, "img2": 14, "imutil": [14, 28], "resiz": 14, "gaussianblur": 14, "21": 14, "risk": 14, "imshow": 14, "valkka_opencv_demo": 14, "waitkei": 14, "gaussian": 14, "blur": 14, "appli": [14, 26, 29, 31], "went": 14, "extra": [14, 18, 24], "lowest": 14, "plain": 14, "sharedmemringbufferrgb": 14, "getnumpyshmem": 14, "element": 14, "clientpullpi": 14, "tup": 14, "careful": 14, "spawn": 14, "reli": 14, "heavili": 14, "known": 14, "resolv": 14, "deepli": 14, "But": 14, "back": 14, "aliv": 14, "cc": 14, "break": 14, "suitabl": 14, "mux": 14, "fly": 14, "rgb24": 14, "clariti": 14, "fragmp4shmemcli": 14, "fragmp4muxframefilt": 14, "fragmp4mux": 14, "fragmp4shmemframefilt": 14, "fragmp4shmem": 14, "lesson_4_c": 14, "cellsiz": 14, "mux_filt": 14, "forget": [14, 26], "n_size": 14, "utf": 14, "seriou": [14, 29], "span": [14, 23], "arrang": 14, "interprocess": [14, 26], "descriptor": 14, "listen": [14, 26], "o": [14, 15, 28], "select": 14, "advantag": [14, 23, 31], "joggl": 14, "establish": [14, 15, 24], "master": [14, 28], "detector": [14, 29], "livethread2": 15, "bigger": [15, 29], "setliveoutpacketbuffermaxs": 15, "95000": 15, "live_in_filt": 15, "outgo": [15, 26], "port": [15, 24, 25], "50000": 15, "out_ctx": 15, "liveoutboundcontext": 15, "liveconnectiontype_sdp": 15, "224": 15, "91": 15, "registeroutboundcal": 15, "stopstreamcal": 15, "deregisterstreamcal": 15, "deregisteroutboundcal": 15, "sdp": [15, 29, 30], "IN": 15, "ip4": 15, "36": 15, "rtp": [15, 30], "avp": 15, "96": 15, "rtpmap": 15, "90000": 15, "fmtp": 15, "mode": 15, "control": [15, 24, 26, 30], "streamid": 15, "ffplai": [15, 25, 29, 30], "feel": 15, "excercis": 15, "localhost": 15, "serv": [15, 18], "8554": [15, 29], "setrtspserv": 15, "substream": [15, 25], "filethread": 16, "treat": 16, "equal": [16, 24], "debug_log_al": 16, "getblockingframefilt": 16, "filenam": [16, 29], "open": [16, 24, 29], "filecontext": 16, "file_ctx": 16, "openfilestreamcal": 16, "playfilestreamcal": 16, "seekpoint": 16, "seektime_": 16, "2000": 16, "seekfilestreamcal": 16, "paus": 16, "stopfilestreamcal": 16, "forkframefilter3": 17, "livethread2_1": 17, "file_filter_2": 17, "avthread_3": 17, "fork_filter_3": 17, "glthread_3_1": 17, "interval_filter_3_2": 17, "sws_filter_3_2": 17, "shmem_filter_3_2": 17, "convent": 17, "_branch_sub": 17, "leav": 17, "live2_in_filt": 17, "gl_in_filter_3_1": 17, "fork_3": 17, "av3_in_filt": 17, "livethread_1": 17, "explain": [17, 24], "valkka_exampl": [18, 23, 26, 29, 30], "api_level_2": [18, 23, 26, 29], "lesson_8_a": 18, "access": [18, 25, 29, 31], "live_thread": 18, "valkka_cor": 18, "never": 18, "indent": 18, "basicfilterchain": 18, "chain": [18, 30], "msreconnect": 18, "10000": 18, "reconnect": 18, "relev": 18, "win_id": [18, 26], "token": 18, "decodingon": 18, "overlai": 19, "parameter": 19, "bottom": 19, "top": [19, 24, 26], "coordin": 19, "rel": [19, 23], "bbox": 19, "75": 19, "addrectanglecal": 19, "clearobjectscal": 19, "2017": 21, "secur": 21, "ltd": 21, "compon": [21, 26, 31], "lib": [22, 28], "categori": [22, 24], "scaffold": 22, "stand": [22, 26], "url": 22, "mvision": [22, 27], "card": 23, "wall": 23, "physic": 23, "entiti": [23, 31], "resourc": 23, "sens": [23, 31], "softwar": [23, 25], "side": [23, 26, 30], "offer": [23, 25], "ancient": 23, "state": [23, 26], "gpu1": 23, "gpu2": 23, "disadvantag": 23, "mous": [23, 26, 29], "pointer": 23, "contrari": 23, "form": 23, "macro": 23, "prepar": 23, "deeper": [23, 26], "unfortun": [23, 25], "kde": [23, 25], "deprec": 23, "abil": [23, 24], "rather": [23, 24], "frustrat": 23, "string": 23, "test_studio_3": [23, 29], "succes": 23, "ident": [23, 28, 31], "applet": 23, "xinerama": 23, "absolut": 23, "posit": 23, "xcfe": [23, 25], "kwin": [23, 25], "xubuntu": 23, "composit": [23, 25], "tweak": [23, 25], "compositor": [23, 25], "uncheck": [23, 25], "environment": 23, "logic": 23, "short": 24, "primer": 24, "soap": 24, "remot": [24, 25], "manipul": [24, 31], "ptz": 24, "pan": 24, "tilt": 24, "zoom": 24, "credenti": 24, "almost": [24, 25], "anyth": [24, 28], "xml": 24, "messag": [24, 26], "wsdl": 24, "offici": 24, "visit": 24, "declar": 24, "sub": [24, 25], "subclass": [24, 26], "www": 24, "ver10": 24, "device_servic": 24, "devicemgmt": 24, "devicemanag": 24, "event": [24, 26], "ver20": 24, "deviceio": 24, "analyt": 24, "getwsdlpath": 24, "wsdl_file": 24, "sub_xaddr": 24, "devicebind": 24, "specif": 24, "third": 24, "subaddress": 24, "media_servic": 24, "getcap": 24, "cap": 24, "ws_client": 24, "nest": 24, "factori": 24, "zeep_client": 24, "type_factori": 24, "schema": 24, "capabilitycategori": 24, "cut": 24, "getvari": 24, "One": [24, 29, 30], "bonu": 24, "firefox": 24, "openspec": 24, "although": 24, "picki": 24, "walltim": 24, "slightli": 24, "model": [24, 26], "reject": 24, "sender": 24, "ntp": [24, 25], "tell": [24, 25], "durat": 24, "specifi": [24, 29], "isod": 24, "arp": 24, "scan": 24, "wsdiscoveri": 24, "readm": 24, "importantli": 24, "chmod": 24, "sbin": 24, "choke": 25, "jitter": [25, 29], "stutter": 25, "freez": 25, "handlefifo": 25, "discard": 25, "quicktest": [25, 28], "nowadai": 25, "qualiti": 25, "impress": 25, "buggi": 25, "blame": 25, "benchmark": [25, 28, 29], "ksysguard": 25, "processor": [25, 29], "told": 25, "startup": 25, "restart": 25, "ctrl": 25, "alt": 25, "f12": 25, "dbu": 25, "suspend": 25, "tri": 25, "stamp": 25, "incorrectli": 25, "clock": 25, "sync": [25, 31], "gigabit": 25, "nic": 25, "old": 25, "dongl": 25, "capac": 25, "cat": 25, "device_nam": 25, "ramp": 25, "experi": 25, "real": 25, "increas": 25, "wifi": 25, "bandwith": 25, "upload": 25, "expect": 25, "stall": 25, "suggest": 25, "particularli": 25, "ones": 25, "profile_tim": 25, "opengl_tim": 25, "culprit": 25, "drop": 25, "slow": 25, "fix": 25, "commerci": 25, "lower": 25, "suck": 25, "choppi": 25, "mainstream": 25, "grid": 25, "exagger": 25, "strategi": [25, 26], "satur": 25, "valu": [25, 29], "mbp": 25, "4096kbp": 25, "tcp": 25, "udp": 25, "choos": [25, 31], "ad": 25, "syscntl": 25, "conf": 25, "swappi": 25, "wmem_max": 25, "2097152": 25, "rmem_max": 25, "sysctl": 25, "swap": [25, 31], "socket": [25, 29], "mb": 25, "associ": 25, "transport": 25, "firewal": 25, "negoti": 25, "554": 25, "request_tcp": 25, "plugin": 25, "xcb": 25, "error": [25, 28], "qpa": 25, "though": 25, "headless": 25, "fact": 25, "echo": 25, "xdg_session_typ": 25, "x11": 25, "persist": 25, "miss": [25, 31], "whole": 25, "kate": 25, "editor": 25, "uninstal": [25, 28], "alwai": [25, 28], "revert": 25, "vainfo": 25, "drm": 25, "direct": [25, 26], "weirdo": 25, "ssh": 25, "shell": 25, "dockerhub": 25, "guidelin": 26, "concret": 26, "constructor": 26, "did": 26, "qthread": 26, "translat": 26, "loop": 26, "slang": 26, "foreign": 26, "some_widget": 26, "winid": 26, "strip": 26, "down": [26, 31], "api_level_1": [26, 30], "single_stream_rtsp": 26, "xsignal": 26, "emb": 26, "foreign_window": 26, "qwindow": 26, "fromwinid": 26, "foreign_widget": 26, "qtwidget": 26, "qwidget": 26, "createwindowcontain": 26, "parent": 26, "catch": 26, "gestur": 26, "dummi": 26, "layout": 26, "interpret": [26, 29], "complic": 26, "multiprocess_1": 26, "multiprocess_2": 26, "multiprocess_3": 26, "messageprocess": 26, "dig": 26, "watch": 26, "ping": 26, "frontend": 26, "pong": 26, "sendsign": 26, "backend": 26, "virtual": 26, "space": [26, 31], "sendsignal__": 26, "childpip": 26, "pong__": 26, "deriv": 26, "classic": 26, "lead": 26, "leaki": 26, "crashi": 26, "alon": 26, "without": [26, 29], "multiprocessing_demo": 26, "magic": 26, "movementdetectorprocess": 26, "qhandlerthread": 26, "blown": 26, "orchestr": 26, "oblig": 26, "usabl": 26, "testthread": 26, "cpp_thread_demo": 26, "mirror": 27, "agpl": 27, "skeleton": 27, "darknet": 27, "pretti": 27, "obsolet": 27, "turk": 27, "contact": 27, "precompil": 28, "mean": 28, "anaconda": 28, "whatnot": 28, "caus": 28, "recent": [28, 30], "subscrib": 28, "repo": 28, "fy": 28, "repeat": 28, "resort": 28, "curl": 28, "raw": 28, "githubusercont": 28, "elsampsa": 28, "automat": [28, 31], "shadow": 28, "fresh": 28, "manner": 28, "awar": [28, 29, 31], "suit": 28, "numer": 28, "mismatch": 28, "conflict": 28, "virtualenv": 28, "pygobject": 28, "gi": 28, "cairo": 28, "gir1": 28, "deinstal": 28, "unstabl": 28, "x86": 28, "intend": 29, "materia": 29, "prima": 29, "usernam": [29, 30, 31], "your_ip": 29, "test_studio_2": 29, "float": 29, "test_studio_4": 29, "menu": 29, "test_studio_fil": 29, "your_video_fil": 29, "preset": 29, "ultrafast": 29, "profil": 29, "baselin": 29, "bsf": 29, "h264_mp4toannexb": 29, "x264": 29, "param": 29, "keyint": 29, "outfil": 29, "test_studio_multicast": 29, "test_studio_rtsp": 29, "streamn": 29, "test_studio_5": 29, "click": 29, "navig": 29, "timelin": 29, "fs_directori": 29, "refus": 29, "fs_directory_": 29, "field": 29, "cam": 29, "n720p": 29, "n1080p": 29, "n1440p": 29, "n4k": 29, "naudio": 29, "gl": 29, "dec": 29, "smart": 29, "restamp": 29, "upon": 29, "touch": 29, "millisec": 29, "plan": 29, "queu": 29, "de": 29, "among": [29, 31], "lag": 29, "degrad": 29, "unbound": 29, "stai": 29, "help": 29, "afford": 29, "luxuri": 29, "balanc": 29, "button": 29, "ye": 29, "THE": 29, "press": [29, 31], "movement": 29, "detect": 29, "gold": 29, "period": 29, "excess": 29, "instabl": 29, "fairli": 30, "gb": [30, 31], "router": 30, "market": 30, "ip_address": 30, "advanc": 30, "topic": 30, "transmit": 30, "aspect": 30, "valkkafsmanag": [30, 31], "encount": 31, "match": 31, "tempor": 31, "finit": 31, "store": 31, "rewind": 31, "surprisingli": 31, "nasti": 31, "overview": 31, "valkkafs2": 31, "filecacherthread": 31, "decoderthread": 31, "matter": 31, "simpler": 31, "fsgroup": 31, "hierarch": 31, "life": 31, "contrast": 31, "huge": 31, "segment": 31, "predefin": 31, "resum": 31, "oldest": 31, "overwritten": 31, "repres": 31, "mstime1": 31, "mstime2": 31, "emit": 31, "Be": 31, "bitrat": 31, "ideal": 31, "variant": 31, "wear": 31, "tear": 31, "hdd": 31, "modif": 31, "drive": 31, "sdb": 31, "grant": 31, "verifi": 31, "head": 31, "gpt": 31, "locat": 31, "gpart": 31, "fdisk": 31, "sector": 31, "sdb1": 31, "976773134": 31, "976771087": 31, "465": 31, "8g": 31, "exact": 31, "blockdev": 31, "getsize64": 31, "uuid": 31, "identif": 31, "blkid": 31, "db572185": 31, "2ac1": 31, "4ef5": 31, "b8af": 31, "c2763e639a67": 31, "partuuid": 31, "37c591e3": 31, "b33b": 31, "4548": 31, "a1eb": 31, "81add9da8a58": 31, "home": 31, "partition_uuid": 31, "your_blocks": 31}, "objects": {}, "objtypes": {}, "objnames": {}, "titleterms": {"author": 0, "benchmark": 1, "cloud": 2, "stream": [2, 13, 15, 16, 31], "debug": 3, "decod": [4, 12, 13, 17], "singl": [4, 9], "thread": 4, "multithread": 4, "gpu": [4, 23], "acceler": [4, 5], "queue": 4, "frame": [4, 9, 11, 14], "support": 5, "hardwar": 5, "ip": [5, 9], "camera": [5, 9, 10, 13], "usb": [5, 10], "codec": 5, "linux": 5, "client": [5, 14], "valkka": [6, 7], "about": 7, "why": 7, "thi": 7, "librari": 7, "api": [7, 14, 18, 26], "The": [7, 29], "project": 7, "knowledg": 8, "base": 8, "gener": [8, 18], "opencv": [8, 14, 28], "contrib": 8, "jetson": 8, "nano": 8, "qt": [8, 26], "python": [8, 14, 22, 24, 26], "bind": 8, "lesson": [9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 30], "1": [9, 11, 14], "receiv": [9, 14], "from": 9, "an": [9, 31], "A": [9, 18, 28], "framefilt": 9, "chain": 9, "fork": 9, "refer": 9, "control": 9, "verbos": 9, "10": 10, "11": 11, "valkkaf": [11, 31], "write": [11, 16], "read": [11, 16], "2": [11, 12, 14, 18], "matroska": 11, "export": 11, "plai": 11, "valkkafsmanag": 11, "3": 13, "x": 13, "window": 13, "system": [13, 23, 25], "One": 13, "one": 13, "sever": 13, "multipl": [13, 31], "4": 14, "server": [14, 15], "side": 14, "level": [14, 18], "frag": 14, "mp4": 14, "advanc": 14, "topic": 14, "5": 15, "transmit": [15, 17], "send": 15, "multicast": 15, "us": [15, 28, 30, 31], "rtsp": 15, "6": 16, "7": 17, "save": 17, "visual": 17, "analyz": 17, "re": 17, "8": 18, "aspect": 18, "simpl": 18, "exampl": [18, 24], "9": 19, "draw": [19, 26], "bound": 19, "box": 19, "licenc": 21, "copyright": 21, "modul": 22, "cpp": 22, "pure": 22, "list": 22, "multi": 23, "introduct": 23, "our": 23, "approach": 23, "configur": 23, "note": 23, "displai": 23, "onvif": 24, "discoveri": 24, "instal": [24, 28], "intro": 24, "zeep": 24, "servic": 24, "class": 24, "call": 24, "pitfal": [24, 25], "common": 25, "problem": 25, "bottleneck": 25, "tune": 25, "faq": 25, "integr": 26, "multiprocess": 26, "video": 26, "widget": 26, "c": [26, 28], "repositori": 27, "index": 27, "ppa": 28, "b": 28, "releas": 28, "compil": 28, "yourself": 28, "test": 28, "your": 28, "numpi": 28, "testsuit": [28, 29], "gtk": 28, "develop": 28, "version": 28, "pyqt": 29, "test_studio_1": 29, "py": 29, "test_studio_detector": 29, "tutori": 30, "prerequisit": 30, "vm": 31, "architectur": 31, "filesystem": 31, "per": 31, "file": 31, "entir": 31, "partit": 31}, "envversion": {"sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx.ext.todo": 2, "sphinx.ext.viewcode": 1, "sphinx": 60}, "alltitles": {"Authors": [[0, "authors"]], "Benchmarking": [[1, "benchmarking"]], "Benchmarks": [[1, "benchmarks"]], "Cloud Streaming": [[2, "cloud-streaming"]], "Debugging": [[3, "debugging"]], "Decoding": [[4, "decoding"]], "Single thread": [[4, "single-thread"]], "Multithread": [[4, "multithread"]], "GPU Accelerated": [[4, "gpu-accelerated"]], "Queueing frames": [[4, "queueing-frames"]], "Supported hardware": [[5, "supported-hardware"]], "IP Cameras": [[5, "ip-cameras"]], "USB Cameras": [[5, "usb-cameras"]], "Codecs": [[5, "codecs"]], "Linux clients": [[5, "linux-clients"]], "Hardware Acceleration": [[5, "hardware-acceleration"]], "Valkka": [[6, "valkka"]], "About Valkka": [[7, "about-valkka"]], "Why this library?": [[7, "why-this-library"]], "Valkka API": [[7, "valkka-api"]], "The Project": [[7, "the-project"]], "Knowledge Base": [[8, "knowledge-base"]], "General": [[8, "general"]], "OpenCV & OpenCV contrib": [[8, "opencv-opencv-contrib"]], "Jetson Nano": [[8, "jetson-nano"]], "Qt Python Bindings": [[8, "qt-python-bindings"]], "Licence & Copyright": [[21, "licence-copyright"]], "Modules": [[22, "modules"]], "Cpp modules": [[22, "cpp-modules"]], "Pure python modules": [[22, "pure-python-modules"]], "Module list": [[22, "module-list"]], "Multi-GPU systems": [[23, "multi-gpu-systems"]], "Introduction": [[23, "introduction"]], "Our approach": [[23, "our-approach"]], "Configuration": [[23, "configuration"]], "Note on $DISPLAY": [[23, "note-on-display"]], "Common problems": [[25, "common-problems"]], "Pitfalls": [[25, "pitfalls"]], "Bottlenecks": [[25, "bottlenecks"]], "System tuning": [[25, "system-tuning"]], "FAQ": [[25, "faq"]], "Integrating with Qt and multiprocessing": [[26, "integrating-with-qt-and-multiprocessing"]], "Qt integration": [[26, "qt-integration"]], "Drawing video into a widget": [[26, "drawing-video-into-a-widget"]], "Python multiprocessing": [[26, "python-multiprocessing"]], "C++ API": [[26, "c-api"]], "Repository Index": [[27, "repository-index"]], "Installing": [[28, "installing"], [24, "installing"]], "A. Install using PPA": [[28, "a-install-using-ppa"]], "B. Install using releases": [[28, "b-install-using-releases"]], "C. Compile yourself": [[28, "c-compile-yourself"]], "Test your installation": [[28, "test-your-installation"]], "Numpy": [[28, "numpy"]], "Install the testsuite": [[28, "install-the-testsuite"]], "GTK": [[28, "gtk"]], "OpenCV": [[28, "opencv"]], "Development version": [[28, "development-version"]], "The PyQt testsuite": [[29, "the-pyqt-testsuite"]], "test_studio_1.py": [[29, "test-studio-1-py"]], "test_studio_detector.py": [[29, "test-studio-detector-py"]], "Tutorial": [[30, "tutorial"]], "Using the tutorial": [[30, "using-the-tutorial"]], "Prerequisites": [[30, "prerequisites"]], "Lessons": [[30, "lessons"]], "ValkkaFS": [[31, "valkkafs"]], "VMS Architecture": [[31, "vms-architecture"]], "Filesystem": [[31, "filesystem"]], "Multiple Streams per File": [[31, "multiple-streams-per-file"]], "Using an entire partition": [[31, "using-an-entire-partition"]], "Lesson 1 : Receiving frames from an IP camera": [[9, "lesson-1-receiving-frames-from-an-ip-camera"]], "A single FrameFilter": [[9, "a-single-framefilter"]], "Chaining FrameFilters": [[9, "chaining-framefilters"]], "Forking FrameFilters": [[9, "forking-framefilters"]], "FrameFilter reference": [[9, "framefilter-reference"]], "Controlling verbosity": [[9, "controlling-verbosity"]], "Lesson 10 : USB Cameras": [[10, "lesson-10-usb-cameras"]], "Lesson 11 : ValkkaFS": [[11, "lesson-11-valkkafs"]], "Writing": [[11, "writing"]], "Reading 1": [[11, "reading-1"]], "Reading 2": [[11, "reading-2"]], "Matroska export": [[11, "matroska-export"]], "Playing frames": [[11, "playing-frames"]], "ValkkaFSManager": [[11, "valkkafsmanager"]], "Lesson 2 : Decoding": [[12, "lesson-2-decoding"]], "Lesson 3 : Streaming to the X-window system": [[13, "lesson-3-streaming-to-the-x-window-system"]], "One camera to one window": [[13, "one-camera-to-one-window"]], "One camera to several windows": [[13, "one-camera-to-several-windows"]], "Decoding multiple streams": [[13, "decoding-multiple-streams"]], "Lesson 4 : Receiving Frames at Python": [[14, "lesson-4-receiving-frames-at-python"]], "Server side": [[14, "server-side"]], "Client side: API level 2": [[14, "client-side-api-level-2"]], "Client side: openCV": [[14, "client-side-opencv"]], "Client side: API level 1": [[14, "client-side-api-level-1"]], "Server + Client": [[14, "server-client"]], "Receiving frag-MP4 at Python": [[14, "receiving-frag-mp4-at-python"]], "Advanced topics": [[14, "advanced-topics"]], "Lesson 5 : Transmitting stream": [[15, "lesson-5-transmitting-stream"]], "Sending multicast": [[15, "sending-multicast"]], "Using the RTSP server": [[15, "using-the-rtsp-server"]], "Lesson 6 : Writing / reading stream": [[16, "lesson-6-writing-reading-stream"]], "Lesson 7 : Decode, save, visualize, analyze and re-transmit": [[17, "lesson-7-decode-save-visualize-analyze-and-re-transmit"]], "Lesson 8: API level 2": [[18, "lesson-8-api-level-2"]], "General aspects": [[18, "general-aspects"]], "A simple example": [[18, "a-simple-example"]], "Lesson 9 : Drawing Bounding Boxes": [[19, "lesson-9-drawing-bounding-boxes"]], "OnVif & Discovery": [[24, "onvif-discovery"]], "Intro": [[24, "intro"]], "Python OnVif with Zeep": [[24, "python-onvif-with-zeep"]], "Service classes": [[24, "service-classes"]], "Example call": [[24, "example-call"]], "Onvif Pitfalls": [[24, "onvif-pitfalls"]], "Discovery": [[24, "discovery"]]}, "indexentries": {}}) \ No newline at end of file +Search.setIndex({"docnames": ["authors", "benchmarking", "cloud", "debugging", "decoding", "hardware", "index", "intro", "knowledge", "lesson_1", "lesson_10", "lesson_11", "lesson_2", "lesson_3", "lesson_4", "lesson_5", "lesson_6", "lesson_7", "lesson_8", "lesson_9", "lesson_pre", "license", "modules", "multi_gpu", "onvif", "pitfalls", "qt_notes", "repos", "requirements", "testsuite", "tutorial", "valkkafs"], "filenames": ["authors.rst", "benchmarking.rst", "cloud.rst", "debugging.rst", "decoding.rst", "hardware.rst", "index.rst", "intro.rst", "knowledge.rst", "lesson_1.rst", "lesson_10.rst", "lesson_11.rst", "lesson_2.rst", "lesson_3.rst", "lesson_4.rst", "lesson_5.rst", "lesson_6.rst", "lesson_7.rst", "lesson_8.rst", "lesson_9.rst", "lesson_pre.rst", "license.rst", "modules.rst", "multi_gpu.rst", "onvif.rst", "pitfalls.rst", "qt_notes.rst", "repos.rst", "requirements.rst", "testsuite.rst", "tutorial.rst", "valkkafs.rst"], "titles": ["Authors", "Benchmarking", "Cloud Streaming", "Debugging", "Decoding", "Supported hardware", "Valkka", "About Valkka", "Knowledge Base", "Lesson 1 : Receiving frames from an IP camera", "Lesson 10 : USB Cameras", "Lesson 11 : ValkkaFS", "Lesson 2 : Decoding", "Lesson 3 : Streaming to the X-window system", "Lesson 4 : Receiving Frames at Python", "Lesson 5 : Transmitting stream", "Lesson 6 : Writing / reading stream", "Lesson 7 : Decode, save, visualize, analyze and re-transmit", "Lesson 8: API level 2", "Lesson 9 : Drawing Bounding Boxes", "<no title>", "Licence & Copyright", "Modules", "Multi-GPU systems", "OnVif & Discovery", "Common problems", "Integrating with Qt and multiprocessing", "Repository Index", "Installing", "The PyQt testsuite", "Tutorial", "ValkkaFS"], "terms": {"sampsa": [0, 21, 28, 31], "riikonen": [0, 21, 28], "_at_": 0, "iki": 0, "fi": 0, "up": [1, 3, 4, 8, 11, 23, 24, 25, 28, 29], "do": [1, 2, 4, 5, 7, 8, 9, 11, 14, 17, 18, 23, 24, 25, 26, 28, 29], "date": [1, 24], "maintain": [1, 25], "here": [1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31], "you": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 18, 19, 23, 24, 25, 26, 27, 28, 29, 30, 31], "find": [1, 3, 8, 24, 26], "some": [1, 2, 5, 6, 9, 11, 14, 18, 19, 24, 25, 28, 29, 31], "tabul": 1, "test": [1, 4, 5, 6, 13, 15, 17, 23, 25, 27, 29, 31], "ar": [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 22, 23, 24, 25, 26, 28, 29, 30, 31], "perform": [1, 11, 12, 14, 23, 24, 25, 29], "otherwis": [1, 14, 29], "mention": [1, 3, 31], "pyqt": [1, 6, 7, 8, 11, 18, 23, 25, 26, 28, 31], "testsuit": [1, 4, 6, 7, 11, 18, 23, 25, 26, 31], "program": [1, 4, 6, 7, 9, 13, 14, 17, 22, 23, 25, 26, 27, 28, 29], "test_studio_1": [1, 4, 6], "py": [1, 3, 4, 6, 8, 11, 18, 23, 25, 26, 28, 30], "paramet": [1, 9, 11, 12, 14, 23, 24, 26], "same": [1, 2, 3, 7, 11, 12, 13, 14, 18, 24, 25, 26, 29, 31], "abbrevi": 1, "us": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 18, 22, 23, 24, 25, 26, 27, 29], "liva": 1, "live": [1, 2, 3, 4, 6, 13, 14, 16, 18, 22, 25, 27, 29], "affin": [1, 18, 29], "gla": 1, "opengl": [1, 5, 7, 13, 23, 25, 29], "d1a": 1, "decod": [1, 6, 7, 11, 14, 16, 18, 23, 25, 26, 29, 30, 31], "start": [1, 4, 5, 6, 7, 9, 11, 12, 13, 14, 15, 16, 17, 18, 24, 25, 26, 29, 30, 31], "dna": 1, "stop": [1, 11, 12, 13, 14, 15, 16, 29], "uptim": 1, "how": [1, 2, 4, 7, 11, 14, 18, 22, 24, 25, 26, 29, 30, 31], "long": [1, 24, 25, 29], "wa": [1, 14, 17, 25, 26], "run": [1, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 18, 23, 25, 26, 29, 30], "newest": 1, "first": [1, 3, 5, 8, 9, 11, 12, 13, 14, 18, 19, 24, 28, 29, 31], "order": [1, 5, 7, 11, 12, 13, 14, 15, 16, 18, 19, 26, 29, 31], "n": [1, 11, 23, 29, 31], "pc": [1, 25], "gf_driver": 1, "camera": [1, 2, 4, 6, 7, 11, 12, 14, 15, 17, 24, 25, 29, 30, 31], "n_720p": [1, 4, 13, 18], "n_1080p": [1, 4, 13, 18], "n_1440p": [1, 4, 13, 18], "n_4k": [1, 4, 13, 18], "n_audio": 1, "msbuftim": [1, 4, 18, 29], "replic": [1, 13, 29], "kernel": [1, 5, 29], "comment": [1, 8], "2": [1, 3, 4, 5, 7, 9, 13, 15, 16, 17, 19, 22, 23, 24, 25, 27, 28, 29, 30, 31], "ubuntu": [1, 5, 8, 28, 30], "18": [1, 8], "04": 1, "lt": [1, 8, 30], "8xi7": 1, "7700hq": 1, "laptop": [1, 30], "nvidia": [1, 5, 13, 23, 25], "x": [1, 4, 5, 7, 14, 16, 17, 18, 19, 23, 25, 26, 29, 30], "2560p": 1, "25": [1, 11, 14, 19], "fp": [1, 4, 11, 13, 14, 25], "600": 1, "10": [1, 11, 13, 14, 16, 17, 19, 24, 25, 29, 30, 31], "0": [1, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 19, 23, 24, 25, 26, 28, 29], "500": [1, 4, 11, 14], "1": [1, 3, 7, 10, 12, 13, 15, 16, 17, 18, 19, 23, 24, 25, 26, 27, 29, 30, 31], "4": [1, 3, 4, 7, 8, 11, 17, 23, 25, 26, 29, 30], "15": [1, 4], "51": 1, "gener": [1, 2, 6, 25, 26, 30], "libvalkka": [1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 21, 25, 26, 27, 28], "v0": 1, "12": [1, 9, 12, 13], "16": [1, 11], "4770": 1, "i915": [1, 5], "1920p": 1, "400": 1, "7": [1, 9, 11, 25, 29, 30], "5": [1, 3, 8, 9, 11, 12, 14, 16, 17, 23, 25, 29, 30], "we": [2, 4, 5, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17, 19, 22, 23, 24, 25, 26, 28, 29, 31], "describ": [2, 9, 24, 28], "low": 2, "latenc": 2, "video": [2, 4, 5, 6, 7, 9, 10, 11, 13, 14, 15, 18, 19, 22, 23, 25, 27, 29, 30, 31], "from": [2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 23, 24, 25, 26, 27, 28, 29, 30, 31], "your": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 23, 24, 25, 26, 27, 29, 30, 31], "ip": [2, 6, 7, 10, 11, 12, 13, 14, 15, 17, 24, 25, 29, 30], "visual": [2, 11, 14, 24, 26, 30], "web": [2, 5, 14, 25], "browser": [2, 14], "A": [2, 4, 5, 6, 12, 13, 14, 22, 23, 25, 26, 27, 29, 30], "good": [2, 4, 5, 7, 8, 13, 28], "contain": [2, 9, 14, 29], "format": [2, 9, 10, 14, 23, 31], "thi": [2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 22, 23, 24, 25, 26, 28, 29, 30, 31], "i": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31], "fragment": [2, 14, 31], "mp4": [2, 30], "frag": [2, 30], "aka": [2, 13, 23], "fmp4": 2, "basic": [2, 5, 24, 30], "have": [2, 3, 4, 5, 7, 8, 11, 12, 13, 14, 18, 23, 24, 25, 26, 28, 29, 30, 31], "those": [2, 5, 7, 14, 15], "file": [2, 3, 6, 8, 9, 11, 14, 15, 16, 24, 29], "smaller": 2, "chunk": [2, 31], "box": [2, 4, 25, 30], "so": [2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 18, 23, 24, 25, 28, 29, 30, 31], "can": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 17, 18, 22, 23, 24, 25, 26, 28, 29, 30, 31], "sent": [2, 15, 23, 29], "over": [2, 3, 4, 11, 16, 23, 25, 29, 31], "lan": [2, 4, 25], "wan": [2, 11, 28, 31], "abl": [2, 8, 24, 29], "produc": 2, "while": [2, 4, 6, 8, 9, 11, 13, 14, 15, 22, 28, 31], "read": [2, 4, 5, 6, 8, 9, 10, 12, 13, 14, 15, 17, 25, 26, 29, 30, 31], "them": [2, 3, 4, 7, 9, 11, 12, 13, 14, 23, 24, 26, 28, 31], "one": [2, 3, 8, 11, 14, 18, 23, 25, 28, 29, 30, 31], "python": [2, 3, 6, 7, 9, 11, 15, 25, 27, 28, 29, 30], "code": [2, 7, 8, 9, 11, 14, 17, 18, 24, 26, 27, 28, 30], "pleas": [2, 4, 5, 6, 8, 11, 14, 25, 26, 27, 28, 31], "refer": [2, 3, 8, 11, 18, 25, 26, 28, 30, 31], "tutori": [2, 4, 6, 7, 9, 14, 18, 19, 23, 25, 26, 28, 29, 31], "after": [2, 3, 5, 8, 9, 11, 14, 25, 28, 29, 31], "obtain": 2, "just": [2, 3, 4, 5, 7, 8, 9, 11, 13, 14, 18, 19, 22, 23, 25, 26, 27, 28, 29, 31], "imagin": [2, 24, 29], "send": [2, 6, 8, 10, 11, 13, 14, 16, 23, 24, 25, 26, 30], "internet": [2, 5, 25], "websocket": 2, "grrp": 2, "ani": [2, 3, 4, 8, 9, 11, 14, 15, 26, 29, 31], "protocol": [2, 5, 9, 24, 30], "choic": [2, 6], "also": [2, 3, 4, 7, 9, 10, 11, 13, 14, 15, 16, 18, 19, 23, 24, 25, 26, 28, 29, 31], "dump": [2, 9, 11, 12, 29, 31], "an": [2, 6, 7, 8, 11, 12, 13, 14, 15, 16, 17, 18, 23, 24, 25, 26, 27, 28, 29, 30], "understood": 2, "all": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 23, 24, 25, 26, 28, 29, 31], "media": [2, 6, 7, 9, 13, 24, 30, 31], "client": [2, 3, 6, 7, 17, 24, 26, 30], "rememb": [2, 3, 4, 8, 14, 25], "cach": [2, 11, 31], "write": [2, 7, 9, 12, 13, 14, 25, 26, 30, 31], "ftyp": 2, "moov": 2, "packet": [2, 12, 15, 25], "begin": [2, 5, 9, 11, 12, 13, 14, 15, 16, 18], "For": [2, 4, 5, 6, 7, 8, 11, 12, 13, 14, 16, 22, 23, 24, 25, 28, 29, 30, 31], "creat": [2, 3, 6, 7, 8, 9, 11, 12, 13, 14, 16, 18, 22, 23, 24, 26, 27, 31], "pipelin": [2, 7, 25], "like": [2, 4, 5, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 24, 25, 26, 28, 29, 30, 31], "take": [2, 4, 6, 8, 11, 13, 14, 18, 23, 24, 25, 26, 29, 30, 31], "look": [2, 4, 6, 8, 9, 11, 13, 14, 15, 17, 24, 26, 31], "To": [2, 7, 9, 10, 11, 14, 15, 31], "plai": [2, 9, 13, 14, 15, 16, 19, 29, 30, 31], "sourc": [2, 4, 8, 9, 13, 15, 25, 26, 28, 29], "extens": [2, 3, 5, 7, 27], "mse": 2, "receiv": [2, 11, 15, 25, 26, 30], "through": [2, 12, 14, 25], "push": [2, 11, 14], "api": [2, 4, 6, 9, 11, 12, 13, 22, 23, 24, 25, 27, 28, 30, 31], "achiev": [2, 11, 13, 25], "true": [2, 8, 11, 14, 25], "cross": [2, 23], "platform": [2, 25], "solut": [2, 6, 7, 14, 23, 31], "work": [2, 5, 6, 8, 14, 24, 25, 26, 30, 31], "linux": [2, 3, 4, 6, 23, 24, 25, 28, 29, 30, 31], "window": [2, 7, 14, 16, 17, 18, 19, 23, 25, 26, 29, 30], "desktop": [2, 6, 23, 25, 30], "mac": 2, "io": [2, 8], "As": [2, 7, 9, 11, 23, 26, 28, 29], "septemb": 2, "2020": [2, 21], "iphon": 2, "still": [2, 4, 5, 13, 25, 31], "lack": 2, "onli": [2, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 22, 24, 25, 26, 28, 29, 31], "devic": [2, 5, 9, 11, 24, 31], "where": [2, 9, 10, 11, 12, 13, 14, 23, 26, 29, 31], "approach": [2, 6, 26, 31], "doesn": [2, 25], "t": [2, 4, 7, 8, 11, 14, 15, 23, 25, 28, 29, 31], "In": [2, 3, 5, 7, 9, 11, 12, 14, 15, 16, 17, 23, 24, 25, 26, 28, 29, 31], "case": [2, 8, 9, 13, 14, 18, 23, 25, 28, 31], "should": [2, 3, 4, 5, 7, 8, 9, 11, 12, 13, 14, 16, 25, 29, 30, 31], "dynam": 2, "hl": 2, "playlist": 2, "again": [2, 6, 9, 11, 14, 16, 25, 28, 31], "conveni": [2, 14, 26], "more": [2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 19, 25, 26, 29, 31], "inform": [2, 7, 8, 9, 10, 11, 14, 25], "about": [2, 4, 5, 6, 9, 10, 11, 14, 24, 27, 28, 31], "structur": [2, 8, 10], "see": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 22, 23, 24, 25, 26, 27, 29, 31], "stack": [2, 7, 12, 13, 18, 25, 26], "overflow": 2, "post": 2, "github": [2, 7, 8, 28], "repositori": [2, 6, 7, 28], "document": [2, 6, 9, 11, 12, 13, 14, 26], "codec": [2, 6, 9], "combin": [2, 3, 26], "support": [2, 6, 7, 10, 16, 30], "major": 2, "most": [2, 8, 14, 24, 25, 30], "typic": [2, 4, 5, 6, 7, 11, 12, 13, 22, 25, 26, 31], "h264": [2, 4, 5, 9, 10, 11, 12, 13, 14, 15, 29, 30, 31], "list": [2, 10, 12, 14, 24], "link": [2, 8, 24], "note": [2, 6, 9, 11, 16, 26], "h265": [2, 30], "behind": 2, "subject": [2, 23, 24, 29], "segfault": 3, "memleak": [3, 4], "etc": [3, 4, 6, 7, 8, 9, 11, 12, 13, 14, 16, 18, 25, 26, 29, 30], "rigor": 3, "valgrind": 3, "remov": [3, 8, 28, 29], "memori": [3, 4, 5, 6, 7, 11, 13, 14, 17, 18, 26, 29, 30, 31], "leak": [3, 4, 5], "cpp": [3, 6, 7, 8, 9, 11, 12, 13, 14, 18, 26, 27], "level": [3, 4, 6, 7, 9, 11, 13, 22, 27, 28, 30], "howev": [3, 4, 7, 8, 9, 11, 12, 13, 14, 24, 25, 26], "swig": [3, 14, 26], "throw": 3, "mix": [3, 26], "multithread": [3, 6, 14], "multiprocess": [3, 6, 14, 27], "share": [3, 6, 7, 14, 15, 17, 18, 23, 26, 29], "between": [3, 6, 7, 12, 14, 18, 23, 24], "process": [3, 6, 7, 14, 18, 25, 26, 28, 29], "give": [3, 14, 24, 29], "surpris": [3, 5], "check": [3, 5, 6, 7, 8, 11, 23, 24, 25, 28], "pull": [3, 7, 14, 25, 28], "frame": [3, 6, 7, 12, 13, 15, 16, 17, 18, 23, 25, 26, 29, 30, 31], "channel": 3, "than": [3, 4, 8, 28, 29], "gdb": 3, "instal": [3, 5, 6, 8, 14, 22, 23, 25, 26, 29, 30], "python3": [3, 6, 7, 8, 14, 18, 22, 25, 26, 27, 28, 29, 30], "symbol": [3, 12], "sudo": [3, 5, 8, 23, 24, 25, 28, 31], "apt": [3, 8, 23, 24, 25, 28], "get": [3, 4, 7, 8, 9, 11, 14, 23, 24, 25, 28, 29, 31], "dbg": 3, "Then": [3, 9, 14, 15, 25, 31], "custom": [3, 6, 7, 11, 26, 28], "build": [3, 6, 8, 23, 28], "enabl": [3, 11, 23, 25], "final": [3, 5, 7, 8, 9, 11, 12, 13, 14, 16, 19, 23, 26, 28, 29, 31], "applic": [3, 4, 6, 7, 11, 13, 25, 26], "": [3, 4, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 19, 23, 24, 25, 26, 28, 29, 31], "entri": [3, 9], "point": [3, 7, 9, 11, 18, 31], "arg": 3, "python_program": 3, "backtrac": 3, "bt": 3, "If": [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 23, 24, 25, 26, 27, 28, 29, 30], "trace": [3, 25], "object": [3, 7, 11, 12, 14, 24, 31], "obmalloc": 3, "c": [3, 5, 6, 9, 15, 21, 25, 29], "mess": [3, 29], "count": 3, "3": [3, 4, 5, 7, 11, 14, 16, 17, 18, 19, 23, 25, 28, 29, 30], "clear": [3, 14, 19], "semaphor": [3, 6, 7, 14, 29], "everi": [3, 11], "now": [3, 11, 12, 13, 14, 18, 24, 29, 31], "dev": [3, 5, 6, 8, 10, 31], "shm": 3, "valkka": [3, 4, 5, 9, 10, 11, 12, 14, 15, 16, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31], "follow": [3, 5, 7, 9, 10, 11, 12, 13, 14, 16, 23, 25, 26, 28, 29, 31], "consumpt": [3, 29], "setproctitl": [3, 28], "modul": [3, 6, 7, 8, 14, 24, 25, 27], "name": [3, 4, 5, 6, 8, 9, 11, 14, 15, 17, 18, 24, 28, 29], "wai": [3, 5, 8, 13, 14, 23, 25, 26, 28, 31], "easili": [3, 18, 26], "standard": [3, 5, 7, 25, 29, 30], "monitor": [3, 13, 23, 25], "tool": [3, 8, 11, 15, 24, 25, 31], "htop": 3, "smem": 3, "set": [3, 5, 8, 9, 10, 11, 13, 23, 24, 25, 28, 29, 31], "cours": [3, 14], "happen": [3, 5, 18, 23], "fork": [3, 11, 14, 26, 30], "exampl": [3, 4, 6, 7, 8, 9, 11, 13, 14, 17, 19, 23, 26, 27, 28, 29, 30, 31], "script": [3, 14, 15], "memwatch": 3, "bash": [3, 8, 25], "aux": 3, "directori": [3, 8, 10, 11, 29, 31], "Or": 3, "launch": [3, 8, 15, 23, 25, 26, 29], "go": [3, 5, 6, 10, 11, 13, 14, 24, 25, 26], "setup": [3, 8, 9, 11, 16, 23], "displai": [3, 6, 25], "option": [3, 23, 24, 25], "hide": 3, "userland": 3, "thread": [3, 6, 7, 9, 10, 11, 12, 13, 14, 15, 17, 18, 23, 26, 29, 31], "make": [3, 8, 11, 14, 15, 23, 25, 27, 31], "output": [3, 9, 11, 12, 15], "readabl": 3, "adequ": 3, "prefer": [3, 25, 28, 29, 30], "pyqt5": [3, 23, 28], "pyside2": [3, 6, 8, 23, 28], "instead": [3, 4, 5, 11, 12, 14, 23, 25, 26, 29], "The": [3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 21, 22, 23, 24, 25, 26, 28, 31], "former": [3, 11], "significantli": 3, "stabl": [3, 5, 8, 28], "handl": [3, 4, 10, 11, 14, 23], "tricki": 3, "qt": [3, 6, 7, 11, 23, 25, 27, 28, 29], "v": [3, 5, 14, 15, 29], "correctli": [3, 11, 25, 26], "especi": [3, 5, 12], "thing": [3, 7, 11, 12, 14, 24, 26, 29, 31], "consid": [3, 9, 12, 13, 23, 25, 26, 29, 31], "switch": [3, 25, 29], "By": [4, 14, 25, 29], "default": [4, 8, 10, 15, 18, 25, 28, 29], "core": [4, 5, 7, 9, 10, 11, 14, 15, 16, 18, 19, 21, 22, 25, 27, 28, 29, 31], "per": [4, 6, 11, 13, 25, 29], "bound": [4, 29, 30], "certain": [4, 11, 13, 24, 28, 29], "detail": [4, 5, 7, 9, 11, 12, 13, 24, 26, 31], "idea": [4, 7, 8, 11, 13], "larg": [4, 6, 7, 11, 25, 29, 31], "number": [4, 6, 9, 10, 11, 13, 14, 15, 16, 18, 23, 25, 26, 29, 31], "light": 4, "stream": [4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 17, 18, 19, 25, 29, 30], "what": [4, 7, 9, 13, 14, 23, 25, 26, 29, 30, 31], "exactli": [4, 14, 25], "depend": [4, 5, 7, 8, 11, 13, 14, 25, 28], "let": [4, 9, 11, 12, 13, 14, 15, 16, 19, 23, 24, 26, 29, 31], "assum": [4, 28, 31], "1080p": [4, 29], "approx": 4, "20": [4, 7, 13, 18, 24, 25], "second": [4, 8, 11, 13, 14, 16, 18, 19, 24, 25, 28, 29, 31], "need": [4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 23, 24, 25, 26, 27, 28, 29, 30, 31], "heavi": [4, 12], "might": [4, 6, 7, 8, 11, 14, 15, 25, 28, 29], "want": [4, 5, 6, 7, 10, 11, 13, 14, 23, 25, 29, 31], "dedic": [4, 11, 23, 26, 31], "sever": [4, 11, 12, 14, 15, 23, 25, 26, 29, 30, 31], "could": [4, 8, 11, 12, 13, 14, 16, 19, 25], "4000x3000": 4, "4k": 4, "60": [4, 10, 14, 15], "befor": [4, 8, 9, 11, 12, 14, 15, 24, 25, 29, 30], "beast": [4, 11], "must": [4, 5, 6, 8, 11, 14, 16, 17, 24, 28], "ask": 4, "yourself": [4, 6, 8, 10, 23], "realli": [4, 5, 25], "someth": [4, 7, 11, 23, 26, 31], "biggest": 4, "screen": [4, 6, 7, 9, 12, 13, 14, 16, 18, 23, 29], "ll": [4, 7, 11, 12, 13, 14, 24, 29, 31], "ever": [4, 6], "view": [4, 6, 13, 14], "probabl": [4, 23, 25], "framer": [4, 13, 23], "human": 4, "ey": [4, 7], "modern": [4, 30], "convolut": 4, "neural": 4, "network": [4, 25], "yolo": [4, 8, 14, 27], "resolut": [4, 10, 13, 14, 18, 24, 25, 29], "600x600": 4, "pixel": [4, 7], "analyz": [4, 6, 7, 26, 30], "max": [4, 11, 14], "30": [4, 11, 16], "And": [4, 5, 7, 14, 25, 26], "haven": 4, "talk": [4, 5], "clog": 4, "modifi": [4, 14, 24, 25], "lesson": [4, 6, 26], "avthread": [4, 5, 7, 10, 12, 13, 14, 16, 17, 18, 19, 25], "info_filt": [4, 9, 12, 15], "setnumberofthread": 4, "That": [4, 8, 9, 11, 12, 24, 26, 28], "four": [4, 23], "call": [4, 6, 9, 11, 12, 16, 19, 25], "instanc": [4, 9, 11, 18], "hardwar": [4, 6, 8, 12, 25, 29], "hw": [4, 25], "avail": [4, 5, 7, 8, 9, 13, 18, 22, 25, 29, 31], "mayb": [4, 25], "better": [4, 25], "save": [4, 11, 13, 15, 29, 30, 31], "muscl": 4, "deep": [4, 6], "learn": [4, 6, 7, 9, 11, 14, 18, 23, 26, 28, 29], "infer": 4, "librari": [4, 5, 6, 8, 9, 13, 14, 24, 26, 28], "close": [4, 9, 13, 16, 18, 25, 26], "implement": [4, 5, 7, 9, 14, 24, 25], "underli": [4, 18, 31], "black": 4, "poorli": 4, "suffer": 4, "slowli": 4, "accumul": 4, "poison": 4, "which": [4, 5, 7, 9, 11, 24, 25, 26, 31], "suppos": [4, 6, 11, 31], "continu": [4, 7, 9, 11, 14, 16, 29, 31], "dai": 4, "week": 4, "even": [4, 7, 11, 13, 14, 24, 25, 29, 31], "forev": 4, "sometim": 4, "proprietari": [4, 5, 13, 23, 25], "mai": [4, 28], "restrict": 4, "mani": [4, 5, 7, 13, 23, 25, 29], "simultan": [4, 6, 7, 11, 13, 14, 15, 17, 18, 25, 29, 31], "cpu": [4, 7, 12, 14, 17, 25], "sole": 4, "decent": [4, 5, 30], "don": [4, 14, 23, 25, 28, 29], "obsess": 4, "when": [4, 5, 8, 9, 11, 12, 13, 14, 23, 24, 25, 28, 29, 31], "intra": 4, "much": [4, 9], "time": [4, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 19, 24, 25, 29, 31], "consecut": [4, 19], "b": [4, 6, 16, 25], "p": [4, 25], "veri": [4, 5, 11, 14, 25, 29, 31], "pronounc": 4, "abov": [4, 11, 14, 24, 25, 28, 29], "becaus": 4, "arriv": [4, 11, 13, 25, 29], "late": [4, 25], "present": [4, 6, 7, 11, 13, 16, 18, 25, 29, 31], "burst": [4, 11, 16, 25], "problem": [4, 6, 7, 14, 28, 29, 31], "solv": [4, 6, 7, 26, 31], "buffer": [4, 7, 13, 14, 15, 25, 29, 31], "import": [4, 5, 9, 10, 11, 13, 14, 15, 16, 18, 19, 24, 26, 28], "glthread": [4, 7, 10, 13, 14, 16, 17, 18, 19, 26], "openglthread": [4, 7, 10, 13, 14, 16, 17, 18, 19, 23, 25, 26], "gl_ctx": [4, 13], "openglframefifocontext": [4, 13], "40": 4, "reserv": [4, 7, 12, 13, 18, 23, 25, 29, 31], "millisecond": [4, 11, 13, 14, 17, 29, 31], "would": [4, 11, 13, 14, 25, 28, 31], "api2": [4, 9, 11, 14, 18, 22, 27], "class": [4, 6, 9, 10, 11, 12, 13, 14, 18, 25, 26, 31], "720p": [4, 10, 13, 29], "pre": [4, 7, 12, 13, 23, 25, 29, 31], "total": [4, 11, 13, 30, 31], "other": [4, 5, 7, 8, 11, 14, 25, 26, 28, 29], "issu": [4, 5, 25], "well": [4, 5, 14, 23, 26, 31], "imag": [4, 6, 12, 14, 24, 25], "termin": [4, 9, 11, 25], "scream": [4, 25], "enhanc": 4, "onvif": [5, 6, 27, 30], "compliant": [5, 6, 30], "rtsp": [5, 9, 11, 12, 13, 14, 16, 18, 19, 25, 29, 30], "initi": [5, 11], "configur": [5, 6, 25, 29], "hurdl": 5, "requir": [5, 7, 8, 17, 28, 29, 30, 31], "half": [5, 25], "broken": [5, 25], "activ": [5, 9, 11, 14, 16], "download": [5, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 28], "outdat": 5, "version": [5, 6, 8, 14, 23, 24, 25], "explor": 5, "onc": [5, 7, 11, 13, 14, 17, 25, 28, 29, 30, 31], "sort": 5, "out": [5, 6, 7, 8, 9, 12, 13, 14, 23, 24, 28, 29, 30, 31], "manufactur": 5, "axi": [5, 24], "hand": [5, 11], "javascript": 5, "interfac": [5, 6, 14, 18, 22, 25, 28, 29], "done": [5, 12, 13, 14, 15, 16, 17, 24, 26], "succesful": 5, "connect": [5, 7, 9, 11, 12, 13, 14, 17, 18, 23, 25, 26, 29, 30, 31], "sai": [5, 7, 9, 11, 14, 25, 26, 29, 30], "ffmpeg": [5, 7, 28, 29], "user": [5, 6, 7, 8, 11, 12, 13, 18, 22, 23, 24, 25, 28, 29, 31], "password": [5, 24, 29], "address": [5, 11, 13, 14, 15, 17, 18, 24], "capabl": [5, 31], "against": [5, 25, 29], "logitech": 5, "hd": [5, 10, 14, 25], "pro": [5, 10], "webcam": [5, 10], "c920": [5, 10], "moment": [5, 9, 11, 30], "textur": [5, 7, 13], "robust": [5, 23], "current": [5, 11, 22, 26, 28, 29, 31], "situat": [5, 11, 13, 25], "intel": [5, 13, 25], "stock": [5, 6, 7, 25], "driver": [5, 13, 23, 25], "ok": [5, 14], "ati": 5, "greater": [5, 23], "command": [5, 8, 10, 13, 15, 24, 25, 31], "glxinfo": 5, "word": [5, 12], "warn": [5, 31], "vaapi": [5, 25], "come": [5, 8, 13, 24, 26, 28], "libav": [5, 7], "infrastructur": [5, 11, 14, 26], "addit": [5, 29], "packag": [5, 8, 13, 22, 24, 26, 28], "belong": [5, 22], "group": [5, 10, 13, 19, 29], "doe": [5, 9, 10, 11, 12, 14, 18, 26, 29], "appear": [5, 7, 8, 25, 31], "usermod": [5, 31], "g": [5, 23, 30, 31], "logout": [5, 25, 31], "login": [5, 25, 31], "replac": 5, "vaapithread": [5, 12], "e": [5, 9, 11, 12, 13, 14, 18, 22, 23, 24, 25, 26, 28, 30, 31], "target_filt": 5, "oftentim": 5, "latest": [5, 25], "distribut": [5, 8, 28], "itself": [5, 6, 9, 12], "whatev": 5, "minim": [5, 25, 31], "try": [5, 7, 11, 18, 24, 25, 26, 28, 29, 31], "came": 5, "distro": [5, 25, 28, 30], "libva_driver_nam": [5, 25], "i965": [5, 25], "hwaccel": 5, "passwd": [5, 30], "rawvideo": 5, "pix_fmt": 5, "yuv420p": 5, "f": [5, 11, 12, 27, 31], "sdl": 5, "bust": 5, "seem": [5, 25], "featur": [5, 7, 8, 9, 14, 28], "bug": [5, 8, 23], "discuss": [5, 9, 11, 23, 25, 26], "confirm": 5, "myself": 5, "libva": 5, "6": [5, 25, 29, 30], "opensourc": [5, 6, 7, 24], "mesa": [5, 13, 25, 28], "enforc": 5, "intern": [5, 9, 12, 31], "environ": [5, 23, 25], "variabl": [5, 11, 23, 24], "export": [5, 13, 25, 30], "valkka_libva_driver_nam": 5, "wish": 5, "docker": [5, 25], "dri": 5, "sure": [5, 11, 25, 31], "host": [5, 23], "machin": [5, 6, 7, 14, 22, 24, 25, 26], "ha": [5, 7, 9, 10, 11, 12, 13, 14, 16, 25, 26, 28], "relat": 5, "easiest": 5, "gpu": [5, 6, 7, 13, 14, 25, 29], "usag": [5, 25], "realtim": 5, "intel_gpu_top": 5, "cuda": 5, "provid": [5, 11, 13, 14, 18, 24, 25, 26, 28, 30], "separ": [5, 14, 18, 23, 24, 26], "nv": 5, "namespac": [5, 11, 22, 24, 27], "nvthread": 5, "gpu_index": 5, "huawei": 5, "cann": 5, "experiment": [5, 10, 28, 29, 31], "guarante": 5, "video surveil": 6, "video manag": 6, "video analysi": 6, "machine vis": 6, "framework": [6, 26], "surveil": [6, 7, 13, 14, 25, 27], "pure": 6, "No": [6, 7, 15], "highlight": 6, "background": [6, 11, 26], "queue": [6, 7, 12, 13], "hidden": [6, 7], "complex": [6, 7, 9, 12, 13, 18, 24, 31], "filtergraph": [6, 7, 9, 11, 12, 13, 14, 15, 16, 17, 18, 26], "disk": [6, 7, 9, 11, 16, 17, 31], "via": [6, 26], "across": 6, "system": [6, 7, 8, 9, 14, 26, 29, 30, 31], "plug": 6, "base": [6, 7, 12, 13, 14, 24, 25], "vision": [6, 7, 14, 22, 26], "agnost": 6, "everyth": [6, 7, 14, 25, 29], "goe": [6, 7, 11, 14, 16, 18], "pytorch": 6, "tensorflow": [6, 7], "design": [6, 7, 11, 13, 25], "massiv": [6, 25], "recast": [6, 7, 15, 17, 29], "either": [6, 8, 25, 29], "multicast": [6, 7, 16, 17, 29, 30], "unicast": [6, 29], "graphic": [6, 23, 26, 28], "interact": [6, 29, 31], "signal": [6, 7, 11, 26, 29], "slot": [6, 7, 9, 10, 11, 12, 13, 14, 15, 16, 18, 19, 26, 29, 31], "highli": [6, 26], "gui": [6, 11, 14, 26, 31], "develop": [6, 7, 24, 29, 31], "wonder": 6, "why": [6, 31], "cool": 6, "econom": 6, "benefit": 6, "investor": 6, "perhap": 6, "vm": [6, 11, 25], "whitepap": 6, "alreadi": 6, "involv": 6, "knee": 6, "busi": [6, 19], "quickstart": 6, "recommend": [6, 7, 13, 26, 31], "articl": 6, "re": [6, 7, 11, 13, 15, 22, 25, 26, 27, 28, 29, 30], "cloud": [6, 14], "app": 6, "streamer": 6, "demo": [6, 14, 23, 27, 28], "project": [6, 14], "usb": [6, 25, 30, 31], "acceler": [6, 12], "ppa": 6, "releas": [6, 8, 14], "compil": [6, 8, 25], "numpi": [6, 8, 14], "gtk": [6, 26], "opencv": [6, 7, 17, 25, 26, 29, 30], "test_studio_detector": [6, 26], "prerequisit": 6, "singl": [6, 11, 14, 15, 17, 18, 19, 23, 26, 29, 30, 31], "integr": [6, 7], "draw": [6, 30], "widget": [6, 7, 29], "multi": [6, 29], "introduct": 6, "our": [6, 9, 11, 14, 26], "valkkaf": [6, 7, 29, 30], "architectur": [6, 7, 8, 13, 28], "filesystem": [6, 7, 11], "multipl": [6, 11, 14, 23, 29, 30], "entir": [6, 11], "partit": [6, 11], "discoveri": [6, 27], "intro": [6, 7], "zeep": 6, "servic": [6, 8, 18], "pitfal": [6, 26], "common": [6, 14, 18, 29], "bottleneck": [6, 23], "tune": 6, "faq": 6, "debug": [6, 7, 11, 14, 25, 29], "index": [6, 8, 14, 29], "licenc": 6, "copyright": 6, "author": [6, 24], "knowledg": [6, 30], "contrib": 6, "jetson": 6, "nano": 6, "search": [6, 11], "page": [6, 7, 13, 22, 23, 25, 28], "yet": [7, 11, 14], "anoth": [7, 9, 11, 12, 13, 14, 15, 23, 29], "player": [7, 9, 29, 30], "my": 7, "fast": 7, "easi": 7, "me": 7, "show": [7, 14], "vlc": [7, 25, 28, 29, 30], "its": [7, 8, 13, 26, 28, 30], "bind": [7, 27, 28, 29, 30], "won": [7, 8], "Such": [7, 14], "scale": 7, "manag": [7, 9, 13, 23, 25, 31], "analysi": [7, 14, 26], "demand": [7, 15], "grow": 7, "rapidli": 7, "due": [7, 25], "declin": 7, "price": 7, "comput": [7, 24], "power": [7, 25], "burn": 7, "noth": [7, 9, 14, 25], "avoid": [7, 31], "too": [7, 9, 10, 13, 15, 25], "limit": [7, 11, 13], "desper": 7, "luck": 7, "loopback": 7, "ve": [7, 23], "been": [7, 8, 13, 14, 16, 23, 25, 26, 28], "pluggin": 7, "favorit": [7, 8, 9], "written": [7, 9, 11, 14, 15, 22, 26, 31], "It": [7, 9, 11, 12, 13, 14, 18, 23, 25, 26], "comfort": 7, "With": [7, 13, 14, 23, 25], "pipe": [7, 16, 26], "subroutin": 7, "net": [7, 16, 25], "safe": [7, 12], "mutex": [7, 12], "gori": [7, 12], "got": [7, 14], "interest": [7, 27], "togeth": [7, 9, 26, 29, 31], "own": [7, 13, 14, 23, 24, 26, 27, 29], "manual": [7, 8, 24, 28], "special": [7, 11], "emphasi": [7, 9, 26], "subprogram": 7, "beyond": 7, "technic": 7, "small": [7, 9, 12, 14, 15, 17, 25, 31], "sampl": [7, 26], "main": [7, 9, 11, 14, 17, 24, 26], "branch": [7, 9, 11, 14, 17, 18], "livethread": [7, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 25, 26, 29], "forkframefilt": [7, 9, 14, 17], "fork_filt": [7, 11, 14, 17], "intervalframefilt": [7, 14, 17], "interval_filt": [7, 14, 17], "swscaleframefilt": [7, 14, 17], "sws_filter": [7, 14, 17], "rgbsharedmemframefilt": [7, 14, 17], "shmem_filt": [7, 14], "complet": [7, 11, 14], "think": 7, "scratch": 7, "extern": [7, 31], "glx": 7, "dure": [7, 9, 16], "futur": 7, "fish": 7, "algorithm": [7, 8], "alpha": 7, "stage": [7, 12, 31], "lot": [7, 9, 14, 17], "stuff": [7, 9, 11, 14, 17], "least": [7, 8, 10, 24, 25, 30], "promis": 7, "organ": [7, 11, 13, 22, 31], "codebas": 7, "licens": [7, 21, 27, 28], "under": [7, 10, 11, 12, 13, 21, 22, 31], "lgpl": [7, 21, 27], "mit": [7, 27], "function": [7, 11], "demonstr": [7, 29], "updat": [7, 28], "new": [7, 11, 13, 14, 17], "Near": 7, "term": [7, 28], "goal": [7, 14], "interserv": 7, "commun": [7, 14, 23, 24, 26], "server": [7, 23, 24, 25, 29, 30], "record": [7, 11, 29, 31], "amount": [7, 31], "fulli": 7, "oper": [7, 29], "synchron": [7, 11, 13, 24, 25, 31], "fishey": 7, "sound": 7, "technologi": 7, "live555": [7, 15, 18], "tip": [8, 25], "instruct": [8, 22, 28, 29, 30], "ordinari": 8, "binari": [8, 28, 31], "handi": 8, "pip3": [8, 22, 23, 25, 28], "wheel": [8, 29], "dir": 8, "your_directori": 8, "r": [8, 29], "txt": 8, "whl": 8, "defin": [8, 9, 10, 11, 12, 13, 14, 15, 23, 24, 29], "pypi": 8, "org": [8, 13, 24, 25], "next": [8, 9, 11, 12, 13, 14, 16, 18, 28, 31], "put": 8, "http": [8, 24, 28], "pip": [8, 24, 28], "readthedoc": 8, "en": 8, "user_guid": 8, "normal": [8, 9, 11, 14, 22, 24, 29, 31], "upgrad": [8, 28], "includ": [8, 9, 11, 24, 25, 26, 28], "non": [8, 11], "free": [8, 15], "part": [8, 9, 12, 13, 14, 16, 18, 22, 25, 28], "patent": 8, "sinc": [8, 14], "disabl": [8, 13, 25], "There": [8, 11, 12, 13, 17, 26, 31], "essenti": 8, "cmake": 8, "git": [8, 28, 30], "libgtk2": 8, "pkg": 8, "config": [8, 25], "libavcodec": 8, "libavformat": [8, 15], "libswscal": 8, "libv4l": 8, "libtbb2": 8, "libtbb": 8, "libjpeg": 8, "libpng": 8, "libtiff": 8, "libjasp": 8, "libdc1394": 8, "22": [8, 11, 12], "libxvidcor": 8, "libx264": 8, "add": [8, 11, 13, 19, 28, 29], "therein": [8, 26], "run_cmak": [8, 25], "bin": 8, "d": [8, 10, 31], "with_cuda": 8, "off": [8, 9, 18, 23, 25], "opencv_extra_modules_path": 8, "opencv_contrib": 8, "opencv_enable_nonfre": 8, "ON": 8, "with_gstream": 8, "with_libv4l": 8, "build_opencv_python2": 8, "build_opencv_python3": 8, "cpack_binary_deb": 8, "build_test": 8, "build_perf_test": 8, "build_exampl": 8, "cmake_build_typ": 8, "cmake_install_prefix": 8, "usr": [8, 22, 24, 28], "local": [8, 15, 24, 28, 29], "j": 8, "emploi": 8, "trick": 8, "debian": [8, 22, 28], "line": [8, 10, 13, 24, 25, 28, 29], "cpack_debian_package_shlibdep": 8, "cpackconfig": 8, "deb": [8, 28], "dpkg": [8, 28], "two": [8, 9, 11, 12, 13, 14, 17, 18, 23, 28, 29, 31], "flavor": [8, 11, 28], "deal": [8, 9, 13], "latter": [8, 11, 25], "jetsonnano": 8, "u": [8, 11, 24, 25, 27], "email": 8, "simpli": [8, 9, 11, 14, 23, 29], "ourselv": 8, "clang": 8, "header": 8, "libclang": 8, "qt5": 8, "qtscript5": 8, "libssl": 8, "qttools5": 8, "qtmultimedia5": 8, "libqt5svg5": 8, "libqt5webkit5": 8, "libsdl2": 8, "libasound2": 8, "libxmu": 8, "libxi": 8, "freeglut3": 8, "libjack": 8, "jackd2": 8, "libxrandr": 8, "libqt5xmlpatterns5": 8, "qtdeclarative5": 8, "privat": 8, "qtbase5": 8, "qtwebengine5": 8, "clone": [8, 28], "pysid": 8, "cd": [8, 18, 28, 29, 30], "pyside_setup": 8, "compat": 8, "qmake": 8, "9": [8, 9, 25, 29, 30], "checkout": 8, "edit": 8, "qtgui": [8, 26], "cmakelist": 8, "qtgui_gen_dir": 8, "qopengltimemonitor_wrapp": 8, "qopengltimerquery_wrapp": 8, "8": [8, 9, 11, 14, 23, 25, 29, 30], "hr": 8, "movi": 8, "wrapper": 8, "bdist_wheel": 8, "dist": [8, 22, 28], "packagenam": 8, "com": [8, 28], "wiki": 8, "qt_for_python": 8, "within": [8, 11, 14], "bugreport": 8, "brows": 8, "568": 8, "live_out_filt": [9, 14, 25], "infoframefilt": [9, 11, 12, 15], "fanci": [9, 12], "print": [9, 10, 11, 12, 13, 14, 15, 16, 18, 19, 24], "thei": [9, 11, 15, 23, 25, 28, 29, 31], "copi": [9, 12, 14, 29], "graph": 9, "feed": [9, 12, 14, 26], "instanti": [9, 11, 12, 13, 14, 15, 18, 24, 26, 31], "context": [9, 12, 13], "ctx": [9, 10, 11, 12, 13, 14, 15, 16, 19, 25], "liveconnectioncontext": [9, 11, 12, 13, 14, 15, 16, 19, 25], "liveconnectiontype_rtsp": [9, 11, 12, 13, 14, 15, 16, 19, 25], "admin": [9, 11, 12, 13, 14, 15, 16, 18, 19, 24, 25], "nordic12345": [9, 12, 13, 14, 15, 16, 18, 19, 25], "192": [9, 11, 12, 13, 14, 15, 16, 18, 19, 24, 25], "168": [9, 11, 12, 13, 14, 15, 16, 18, 19, 24, 25], "41": [9, 12, 13, 14, 15, 16, 18, 19, 25], "type": [9, 22, 31], "integ": [9, 11], "later": [9, 11], "startcal": [9, 10, 11, 12, 13, 14, 15, 16, 19], "registerstreamcal": [9, 11, 12, 13, 14, 15, 16, 19], "playstreamcal": [9, 11, 12, 13, 14, 15, 16, 19], "sleep": [9, 10, 11, 12, 13, 14, 15, 16, 18, 19], "stopcal": [9, 10, 11, 12, 13, 14, 15, 16, 19], "bye": [9, 10, 11, 12, 13, 14, 15, 16, 18, 19], "setupfram": 9, "timestamp": [9, 11, 12, 25, 29, 31], "1525870891068": 9, "subsession_index": [9, 11, 12], "media_typ": 9, "codec_id": 9, "27": 9, "payload": [9, 11, 12, 14], "timediff": [9, 12], "end": [9, 11, 12, 13, 14, 15, 16, 18, 31], "basicfram": [9, 11], "size": [9, 11, 12, 14, 15, 17, 25, 29, 31], "45": 9, "slice_typ": [9, 11], "103": [9, 11], "100": [9, 11, 14, 15, 18, 25], "42": [9, 13], "173": 9, "132": 9, "32": [9, 11], "97": 9, "67": 9, "24": [9, 24, 29], "104": [9, 11], "238": [9, 11], "49": 9, "178": 9, "few": [9, 11, 24], "byte": [9, 11, 14, 29, 31], "kei": [9, 11, 31], "flow": [9, 31], "sink": [9, 15], "consist": [9, 22, 25, 28, 29], "pcmu": 9, "previou": [9, 11, 12, 13, 14], "had": 9, "notat": [9, 11], "mark": [9, 11, 12], "parenthesi": 9, "curli": 9, "bracket": 9, "both": [9, 12, 14, 25, 26, 29, 31], "filter_2": 9, "filter_3": 9, "programmat": 9, "last": [9, 25, 26, 28, 29, 31], "pass": [9, 11, 12, 13, 14, 17, 24, 26, 29, 31], "target": [9, 11, 31], "confus": 9, "rule": 9, "thumb": 9, "info": [9, 11], "onto": 9, "correct": [9, 11, 14, 23, 25, 26, 29], "given": [9, 11, 19], "trivial": [9, 13], "gateframefilt": 9, "gate_filt": 9, "fileframefilt": [9, 11, 16, 17], "file_filt": [9, 11, 16], "fed": 9, "At": [9, 10, 11, 26, 30], "gate": 9, "further": [9, 14, 31], "construct": [9, 11, 12, 13, 14, 15, 16, 18, 24, 26], "outer": [9, 17], "leaf": 9, "tree": [9, 17], "move": [9, 17, 23], "edg": 9, "toward": [9, 17], "unset": 9, "mkv": [9, 11, 16, 29], "exit": [9, 11, 13, 14, 16, 19], "deactiv": [9, 14, 16], "method": [9, 11, 12, 16, 25, 26], "sec": [9, 11, 13, 16, 18], "turn": [9, 14, 23, 25], "result": [9, 26], "mediaplay": 9, "understand": [9, 13, 26], "thousand": 9, "enough": [9, 11, 25], "accept": [9, 29], "matroska": [9, 16, 29, 30], "wrap": [9, 14, 18, 26, 31], "doc": 9, "member": 9, "visibl": 9, "pyapi": [9, 12], "tag": [9, 12, 13, 14, 15, 16, 17], "callback": [9, 11], "cascad": 9, "block": [9, 11, 16, 31], "execut": [9, 16, 26], "independ": [9, 12], "shut": 9, "loglevel_sil": 9, "log": 9, "setvalkkaloglevel": 9, "setloglevel_livelogg": 9, "loglevel_norm": [9, 11], "logger": [9, 11], "silent": 9, "individu": [9, 11, 13], "v4l2": 10, "ctl": 10, "video2": 10, "found": [10, 14, 17, 22, 23, 24, 25, 26, 31], "sy": [10, 11, 25], "video4linux": 10, "differ": [10, 13, 14, 17, 23, 24], "usbdevicethread": 10, "gl_in_filt": [10, 13, 14, 16, 19], "getframefilt": [10, 11, 12, 13, 14, 15, 16, 17, 19], "av_in_filt": [10, 12, 13, 14, 16, 19], "multiplex": [10, 14], "usbthread": 10, "usbcameraconnectioncontext": 10, "width": [10, 14, 17], "height": [10, 14, 17], "uncom": 10, "1920": [10, 12, 14, 17], "1080": [10, 12, 14, 17], "decodingoncal": [10, 12, 13, 14, 16, 19], "window_id": [10, 13, 14, 16, 18, 19, 26], "createwindow": [10, 13, 14, 16, 18, 19], "newrendergroupcal": [10, 13, 14, 16, 19], "context_id": [10, 13, 14, 16, 19, 26], "newrendercontextcal": [10, 13, 14, 16, 19, 26], "render": [10, 13, 19, 25], "z": [10, 13, 19, 26], "playcamerastreamcal": 10, "minut": 10, "patienc": 10, "keyfram": [10, 25, 31], "often": 10, "stopcamerastreamcal": 10, "delrendercontextcal": [10, 13, 14, 16, 19], "delrendergroupcal": [10, 13, 14, 16, 19], "decodingoffcal": [10, 12, 13, 14, 19], "earlier": 11, "redirect": 11, "consult": [11, 31], "section": [11, 25], "These": [11, 12, 13, 14, 22, 25], "downstream": 11, "speed": [11, 25, 31], "concurr": 11, "evok": 11, "request": [11, 12, 13, 16, 31], "valkkafswriterthread": [11, 31], "writerthread": 11, "valkkasinglef": [11, 29, 31], "loglevel_debug": 11, "loglevel_crazi": 11, "rtsp_address": 11, "12345": [11, 13, 24], "157": [11, 13], "each": [11, 13, 14, 17, 23, 24, 25, 29, 31], "setloglevel_filelogg": 11, "setloglevel_valkkafslogg": 11, "valkkamultif": [11, 29, 31], "metadata": [11, 14, 31], "tmp": [11, 31], "testvalkkaf": [11, 31], "newfromdirectori": [11, 31], "dirnam": [11, 31], "blocksiz": [11, 31], "2048": [11, 25, 31], "1024": [11, 14, 31], "divis": 11, "kilobit": 11, "n_block": 11, "verbos": [11, 14, 18, 29, 30], "hold": 11, "kbit": 11, "256": 11, "kbyte": 11, "data": [11, 14, 23, 31], "1024kbit": 11, "kbp": [11, 25], "finish": 11, "necessari": [11, 29], "condit": 11, "effici": [11, 14, 25, 31], "seek": [11, 16, 31], "256kb": 11, "2560": 11, "kb": 11, "skip": 11, "directli": [11, 14, 24, 25, 29, 31], "device_s": [11, 31], "blockfil": [11, 31], "tabl": [11, 24, 31], "dumpfil": [11, 31], "json": [11, 31], "respons": [11, 13, 24], "writer": 11, "framefilt": [11, 12, 13, 16, 18, 25, 30], "file_input_framefilt": 11, "identifi": [11, 14, 16, 17, 31], "id": [11, 13, 14, 15, 26, 31], "925412": 11, "invent": 11, "setslotidcal": 11, "idl": 11, "blocktabl": 11, "getblockt": 11, "Not": 11, "far": [11, 25], "updatet": 11, "disk_writ": 11, "definit": 11, "book": [11, 31], "keep": [11, 13, 18, 23, 25, 31], "forc": 11, "fill": 11, "load": [11, 25, 29], "loadfromdirectori": 11, "filterchain": [11, 12, 13, 14, 15, 18, 26, 31], "reader": 11, "out_filt": 11, "reader_out_filt": 11, "readerthread": 11, "valkkafsreaderthread": [11, 31], "map": [11, 13, 14, 16, 18, 26], "pullblockspycal": 11, "valkkafstool": 11, "allow": [11, 25], "peek": 11, "content": 11, "inspect": 11, "dumpblock": 11, "1543314164986": 11, "29": 11, "31": 11, "172": 11, "17": 11, "160": 11, "80": [11, 13, 24], "186": 11, "64": 11, "56": [11, 15], "176": 11, "1543314165135": 11, "19460": 11, "101": 11, "136": 11, "128": 11, "191": 11, "180": 11, "142": 11, "114": 11, "255": 11, "79": 11, "52": 11, "19": 11, "1543314165215": 11, "19408": 11, "193": 11, "200": [11, 29], "71": 11, "1543314165335": 11, "4928": 11, "65": 11, "154": 11, "127": [11, 15, 29], "208": 11, "117": 11, "223": 11, "181": 11, "129": 11, "206": 11, "84": 11, "indic": [11, 22, 29, 31], "column": [11, 24, 31], "asterix": 11, "row": [11, 31], "actual": [11, 14, 23], "shown": [11, 13], "min": [11, 14, 25, 29], "t0": 11, "t1": 11, "gettimerang": 11, "struct_tim": 11, "gmtime": 11, "1000": [11, 13, 14, 17, 25], "correspond": [11, 12, 28], "rang": [11, 13, 14], "req": 11, "block_indic": 11, "getind": 11, "recov": 11, "interv": [11, 14, 31], "useful": 11, "getindneigh": 11, "return": [11, 14, 26], "neighborhood": 11, "plu": 11, "surround": 11, "instant": [11, 31], "recal": 11, "saw": 11, "carri": 11, "muxer": 11, "On": [11, 13, 23, 25, 29], "simpl": [11, 13, 23, 29, 30, 31], "notion": 11, "basi": [11, 16, 29], "initstreamframefilt": 11, "forkframefiltern": 11, "passslotframefilt": 11, "slot_filt": 11, "init_stream": 11, "introduc": 11, "arbitrari": 11, "disconnect": 11, "init_filt": 11, "kokk": [11, 16], "valkkafsread": 11, "worth": 11, "shot": 11, "transmiss": 11, "framecacherthread": 11, "origin": 11, "were": 11, "being": [11, 14, 29, 31], "chang": [11, 24], "forward": 11, "similar": [11, 13, 14, 16, 29], "filecachethread": 11, "cacherthread": 11, "setpycallback": 11, "int": [11, 26], "mstime": 11, "freq": 11, "m": [11, 14, 15], "setpycallback2": 11, "tupl": [11, 14], "mstimestamp": [11, 14], "regist": [11, 13], "proce": [11, 12], "input": [11, 13, 16], "cacher": 11, "global": [11, 22, 28], "current_time_limit": 11, "none": [11, 14, 25], "frequent": [11, 25], "def": [11, 13, 26], "current_time_callback": 11, "rewindcal": 11, "todo": 11, "altern": [11, 25, 26], "your_list_of_block": 11, "except": 11, "fail": 11, "str": 11, "minimum": [11, 24], "maximum": [11, 25], "time_limits_callback": 11, "kept": 11, "asap": 11, "possibl": [11, 12, 14], "immedi": 11, "filestreamcontext": 11, "convert": [11, 26, 29], "seekstreamscal": 11, "assur": 11, "playstreamscal": 11, "behaviour": [11, 14, 29], "respect": 11, "playback": [11, 29, 31], "challeng": 11, "aris": 11, "easier": [11, 31], "test_studio_6": [11, 29], "churn": 12, "seri": 12, "filter": [12, 17, 26], "until": [12, 13], "explan": [12, 22, 29], "crossov": 12, "usual": [12, 13, 14, 16, 17, 19], "lift": 12, "bitmap": [12, 13, 14, 17, 25], "substitut": 12, "left": [12, 13, 15, 19, 29], "right": [12, 13, 19, 25, 29], "avbitmapfram": 12, "1525870759898": 12, "h": [12, 14], "w": [12, 14], "l": [12, 31], "960": 12, "47": 12, "1525870759938": 12, "11": [12, 23, 25, 30], "know": [12, 25], "hood": [12, 13], "bit": [12, 13, 26], "framefifo": [12, 26], "incom": [12, 15, 26], "place": [12, 13, 14, 26, 29, 31], "taken": [12, 14], "fifo": [12, 17], "protect": 12, "concern": 12, "inherit": 12, "diagram": 12, "subset": 12, "compar": 13, "continui": 13, "yuv": [13, 14, 17, 18], "interpol": [13, 14, 17, 25], "rgb": [13, 14, 17], "shader": 13, "languag": 13, "exist": [13, 26], "argument": [13, 18], "nice": [13, 14, 23, 24, 25, 29], "openglframefifo": 13, "adjust": [13, 14, 25, 31], "300": [13, 29], "math": [13, 25], "hard": [13, 25, 31], "hundr": 13, "extrem": [13, 24], "ambiti": 13, "who": 13, "brand": [13, 24], "8k": 13, "contex": [13, 23], "id_list": 13, "append": [13, 14], "variou": [13, 18, 25], "mind": [13, 18], "vertic": [13, 25], "refresh": [13, 25], "vsync": [13, 25], "rate": [13, 14, 25], "around": [13, 30], "50": 13, "nouveau": [13, 25], "vblank_mod": [13, 25], "glxgear": [13, 23, 25], "util": [13, 28], "report": [13, 23, 25], "encapsul": [13, 18, 31], "livestream": 13, "__init__": 13, "self": 13, "stream1": [13, 15], "stream2": 13, "window_id1": 13, "context_id1": 13, "window_id2": 13, "context_id2": 13, "quit": 13, "flexibl": 13, "opt": 13, "readi": [13, 14, 25], "made": 13, "purpos": [13, 14], "compact": [14, 18], "scheme": [14, 22, 25, 31], "chapter": 14, "regular": [14, 31], "observ": [14, 23, 25], "posix": [14, 17, 18, 29], "summar": 14, "dimens": 14, "quarter": 14, "full": [14, 17, 18, 25, 26], "image_interv": [14, 17], "shmem": [14, 17], "ringbuff": [14, 17], "uniqu": [14, 17], "ring": 14, "shmem_nam": [14, 17], "lesson_4": [14, 17], "shmem_buff": [14, 17], "rgbshmemframefilt": [14, 17], "briefinfoframefilt": 14, "timeintervalframefilt": [14, 17], "123456": 14, "134": 14, "ultim": [14, 29], "high": 14, "routin": 14, "below": [14, 25], "undefin": 14, "occur": 14, "pair": [14, 29], "shmemrgbclient": 14, "n_ringbuff": 14, "mstimeout": 14, "timeout": [14, 24], "fals": [14, 18], "meta": 14, "pullfram": 14, "els": [14, 24], "shmem_list": 14, "reshap": 14, "shape": 14, "arrai": 14, "isiz": 14, "extent": 14, "ten": [14, 18, 29, 31], "rtf": 14, "popular": [14, 29], "cv2": [14, 25], "img": 14, "img2": 14, "imutil": [14, 28], "resiz": 14, "gaussianblur": 14, "21": 14, "risk": 14, "imshow": 14, "valkka_opencv_demo": 14, "waitkei": 14, "gaussian": 14, "blur": 14, "appli": [14, 26, 29, 31], "went": 14, "extra": [14, 18, 24], "lowest": 14, "plain": 14, "sharedmemringbufferrgb": 14, "getnumpyshmem": 14, "element": 14, "clientpullpi": 14, "tup": 14, "careful": 14, "spawn": 14, "reli": 14, "heavili": 14, "known": 14, "resolv": 14, "deepli": 14, "But": 14, "back": 14, "aliv": 14, "cc": 14, "break": 14, "suitabl": 14, "mux": 14, "fly": 14, "rgb24": 14, "clariti": 14, "fragmp4shmemcli": 14, "fragmp4muxframefilt": 14, "fragmp4mux": 14, "fragmp4shmemframefilt": 14, "fragmp4shmem": 14, "lesson_4_c": 14, "cellsiz": 14, "mux_filt": 14, "forget": [14, 26], "n_size": 14, "utf": 14, "seriou": [14, 29], "span": [14, 23], "arrang": 14, "interprocess": [14, 26], "descriptor": 14, "listen": [14, 26], "o": [14, 15, 28], "select": 14, "advantag": [14, 23, 31], "joggl": 14, "establish": [14, 15, 24], "master": [14, 28], "detector": [14, 29], "livethread2": 15, "bigger": [15, 29], "setliveoutpacketbuffermaxs": 15, "95000": 15, "live_in_filt": 15, "outgo": [15, 26], "port": [15, 24, 25], "50000": 15, "out_ctx": 15, "liveoutboundcontext": 15, "liveconnectiontype_sdp": 15, "224": 15, "91": 15, "registeroutboundcal": 15, "stopstreamcal": 15, "deregisterstreamcal": 15, "deregisteroutboundcal": 15, "sdp": [15, 29, 30], "IN": 15, "ip4": 15, "36": 15, "rtp": [15, 30], "avp": 15, "96": 15, "rtpmap": 15, "90000": 15, "fmtp": 15, "mode": 15, "control": [15, 24, 26, 30], "streamid": 15, "ffplai": [15, 25, 29, 30], "feel": 15, "excercis": 15, "localhost": 15, "serv": [15, 18], "8554": [15, 29], "snippet": 15, "setrtspserv": 15, "substream": [15, 25], "filethread": 16, "treat": 16, "equal": [16, 24], "debug_log_al": 16, "getblockingframefilt": 16, "filenam": [16, 29], "open": [16, 24, 29], "filecontext": 16, "file_ctx": 16, "openfilestreamcal": 16, "playfilestreamcal": 16, "seekpoint": 16, "seektime_": 16, "2000": 16, "seekfilestreamcal": 16, "paus": 16, "stopfilestreamcal": 16, "forkframefilter3": 17, "livethread2_1": 17, "file_filter_2": 17, "avthread_3": 17, "fork_filter_3": 17, "glthread_3_1": 17, "interval_filter_3_2": 17, "sws_filter_3_2": 17, "shmem_filter_3_2": 17, "convent": 17, "_branch_sub": 17, "leav": 17, "live2_in_filt": 17, "gl_in_filter_3_1": 17, "fork_3": 17, "av3_in_filt": 17, "livethread_1": 17, "explain": [17, 24], "valkka_exampl": [18, 23, 26, 29, 30], "api_level_2": [18, 23, 26, 29], "lesson_8_a": 18, "access": [18, 25, 29, 31], "live_thread": 18, "valkka_cor": 18, "never": 18, "indent": 18, "basicfilterchain": 18, "chain": [18, 30], "msreconnect": 18, "10000": 18, "reconnect": 18, "relev": 18, "win_id": [18, 26], "token": 18, "decodingon": 18, "overlai": 19, "parameter": 19, "bottom": 19, "top": [19, 24, 26], "coordin": 19, "rel": [19, 23], "bbox": 19, "75": 19, "addrectanglecal": 19, "clearobjectscal": 19, "2017": 21, "secur": 21, "ltd": 21, "compon": [21, 26, 31], "lib": [22, 28], "categori": [22, 24], "scaffold": 22, "stand": [22, 26], "url": 22, "mvision": [22, 27], "card": 23, "wall": 23, "physic": 23, "entiti": [23, 31], "resourc": 23, "sens": [23, 31], "softwar": [23, 25], "side": [23, 26, 30], "offer": [23, 25], "ancient": 23, "state": [23, 26], "gpu1": 23, "gpu2": 23, "disadvantag": 23, "mous": [23, 26, 29], "pointer": 23, "contrari": 23, "form": 23, "macro": 23, "prepar": 23, "deeper": [23, 26], "unfortun": [23, 25], "kde": [23, 25], "deprec": 23, "abil": [23, 24], "rather": [23, 24], "frustrat": 23, "string": 23, "test_studio_3": [23, 29], "succes": 23, "ident": [23, 28, 31], "applet": 23, "xinerama": 23, "absolut": 23, "posit": 23, "xcfe": [23, 25], "kwin": [23, 25], "xubuntu": 23, "composit": [23, 25], "tweak": [23, 25], "compositor": [23, 25], "uncheck": [23, 25], "environment": 23, "logic": 23, "short": 24, "primer": 24, "soap": 24, "remot": [24, 25], "manipul": [24, 31], "ptz": 24, "pan": 24, "tilt": 24, "zoom": 24, "credenti": 24, "almost": [24, 25], "anyth": [24, 28], "xml": 24, "messag": [24, 26], "wsdl": 24, "offici": 24, "visit": 24, "declar": 24, "sub": [24, 25], "subclass": [24, 26], "www": 24, "ver10": 24, "device_servic": 24, "devicemgmt": 24, "devicemanag": 24, "event": [24, 26], "ver20": 24, "deviceio": 24, "analyt": 24, "getwsdlpath": 24, "wsdl_file": 24, "sub_xaddr": 24, "devicebind": 24, "specif": 24, "third": 24, "subaddress": 24, "media_servic": 24, "getcap": 24, "cap": 24, "ws_client": 24, "nest": 24, "factori": 24, "zeep_client": 24, "type_factori": 24, "schema": 24, "capabilitycategori": 24, "cut": 24, "getvari": 24, "One": [24, 29, 30], "bonu": 24, "firefox": 24, "openspec": 24, "although": 24, "picki": 24, "walltim": 24, "slightli": 24, "model": [24, 26], "reject": 24, "sender": 24, "ntp": [24, 25], "tell": [24, 25], "durat": 24, "specifi": [24, 29], "isod": 24, "arp": 24, "scan": 24, "wsdiscoveri": 24, "readm": 24, "importantli": 24, "chmod": 24, "sbin": 24, "choke": 25, "jitter": [25, 29], "stutter": 25, "freez": 25, "handlefifo": 25, "discard": 25, "quicktest": [25, 28], "nowadai": 25, "qualiti": 25, "impress": 25, "buggi": 25, "blame": 25, "benchmark": [25, 28, 29], "ksysguard": 25, "processor": [25, 29], "told": 25, "startup": 25, "restart": 25, "ctrl": 25, "alt": 25, "f12": 25, "dbu": 25, "suspend": 25, "tri": 25, "stamp": 25, "incorrectli": 25, "clock": 25, "sync": [25, 31], "gigabit": 25, "nic": 25, "old": 25, "dongl": 25, "capac": 25, "cat": 25, "device_nam": 25, "ramp": 25, "experi": 25, "real": 25, "increas": 25, "wifi": 25, "bandwith": 25, "upload": 25, "expect": 25, "stall": 25, "suggest": 25, "particularli": 25, "ones": 25, "profile_tim": 25, "opengl_tim": 25, "culprit": 25, "drop": 25, "slow": 25, "fix": 25, "commerci": 25, "lower": 25, "suck": 25, "choppi": 25, "mainstream": 25, "grid": 25, "exagger": 25, "strategi": [25, 26], "satur": 25, "valu": [25, 29], "mbp": 25, "4096kbp": 25, "tcp": 25, "udp": 25, "choos": [25, 31], "ad": 25, "syscntl": 25, "conf": 25, "swappi": 25, "wmem_max": 25, "2097152": 25, "rmem_max": 25, "sysctl": 25, "swap": [25, 31], "socket": [25, 29], "mb": 25, "associ": 25, "transport": 25, "firewal": 25, "negoti": 25, "554": 25, "request_tcp": 25, "plugin": 25, "xcb": 25, "error": [25, 28], "qpa": 25, "though": 25, "headless": 25, "fact": 25, "echo": 25, "xdg_session_typ": 25, "x11": 25, "persist": 25, "miss": [25, 31], "whole": 25, "kate": 25, "editor": 25, "uninstal": [25, 28], "alwai": [25, 28], "revert": 25, "vainfo": 25, "drm": 25, "direct": [25, 26], "weirdo": 25, "ssh": 25, "shell": 25, "dockerhub": 25, "guidelin": 26, "concret": 26, "constructor": 26, "did": 26, "qthread": 26, "translat": 26, "loop": 26, "slang": 26, "foreign": 26, "some_widget": 26, "winid": 26, "strip": 26, "down": [26, 31], "api_level_1": [26, 30], "single_stream_rtsp": 26, "xsignal": 26, "emb": 26, "foreign_window": 26, "qwindow": 26, "fromwinid": 26, "foreign_widget": 26, "qtwidget": 26, "qwidget": 26, "createwindowcontain": 26, "parent": 26, "catch": 26, "gestur": 26, "dummi": 26, "layout": 26, "interpret": [26, 29], "complic": 26, "multiprocess_1": 26, "multiprocess_2": 26, "multiprocess_3": 26, "messageprocess": 26, "dig": 26, "watch": 26, "ping": 26, "frontend": 26, "pong": 26, "sendsign": 26, "backend": 26, "virtual": 26, "space": [26, 31], "sendsignal__": 26, "childpip": 26, "pong__": 26, "deriv": 26, "classic": 26, "lead": 26, "leaki": 26, "crashi": 26, "alon": 26, "without": [26, 29], "multiprocessing_demo": 26, "magic": 26, "movementdetectorprocess": 26, "qhandlerthread": 26, "blown": 26, "orchestr": 26, "oblig": 26, "usabl": 26, "testthread": 26, "cpp_thread_demo": 26, "mirror": 27, "agpl": 27, "skeleton": 27, "darknet": 27, "pretti": 27, "obsolet": 27, "turk": 27, "contact": 27, "precompil": 28, "mean": 28, "anaconda": 28, "whatnot": 28, "caus": 28, "recent": [28, 30], "subscrib": 28, "repo": 28, "fy": 28, "repeat": 28, "resort": 28, "curl": 28, "raw": 28, "githubusercont": 28, "elsampsa": 28, "automat": [28, 31], "shadow": 28, "fresh": 28, "manner": 28, "awar": [28, 29, 31], "suit": 28, "numer": 28, "mismatch": 28, "conflict": 28, "virtualenv": 28, "pygobject": 28, "gi": 28, "cairo": 28, "gir1": 28, "deinstal": 28, "unstabl": 28, "x86": 28, "intend": 29, "materia": 29, "prima": 29, "usernam": [29, 30, 31], "your_ip": 29, "test_studio_2": 29, "float": 29, "test_studio_4": 29, "menu": 29, "test_studio_fil": 29, "your_video_fil": 29, "preset": 29, "ultrafast": 29, "profil": 29, "baselin": 29, "bsf": 29, "h264_mp4toannexb": 29, "x264": 29, "param": 29, "keyint": 29, "outfil": 29, "test_studio_multicast": 29, "test_studio_rtsp": 29, "streamn": 29, "test_studio_5": 29, "click": 29, "navig": 29, "timelin": 29, "fs_directori": 29, "refus": 29, "fs_directory_": 29, "field": 29, "cam": 29, "n720p": 29, "n1080p": 29, "n1440p": 29, "n4k": 29, "naudio": 29, "gl": 29, "dec": 29, "smart": 29, "restamp": 29, "upon": 29, "touch": 29, "millisec": 29, "plan": 29, "queu": 29, "de": 29, "among": [29, 31], "lag": 29, "degrad": 29, "unbound": 29, "stai": 29, "help": 29, "afford": 29, "luxuri": 29, "balanc": 29, "button": 29, "ye": 29, "THE": 29, "press": [29, 31], "movement": 29, "detect": 29, "gold": 29, "period": 29, "excess": 29, "instabl": 29, "lesson_1_a": 30, "fairli": 30, "gb": [30, 31], "router": 30, "market": 30, "ip_address": 30, "advanc": 30, "topic": 30, "transmit": 30, "aspect": 30, "valkkafsmanag": [30, 31], "encount": 31, "match": 31, "tempor": 31, "finit": 31, "store": 31, "rewind": 31, "surprisingli": 31, "nasti": 31, "overview": 31, "valkkafs2": 31, "filecacherthread": 31, "decoderthread": 31, "matter": 31, "simpler": 31, "fsgroup": 31, "hierarch": 31, "life": 31, "contrast": 31, "huge": 31, "segment": 31, "predefin": 31, "resum": 31, "oldest": 31, "overwritten": 31, "repres": 31, "mstime1": 31, "mstime2": 31, "emit": 31, "Be": 31, "bitrat": 31, "ideal": 31, "variant": 31, "wear": 31, "tear": 31, "hdd": 31, "modif": 31, "drive": 31, "sdb": 31, "grant": 31, "verifi": 31, "head": 31, "gpt": 31, "locat": 31, "gpart": 31, "fdisk": 31, "sector": 31, "sdb1": 31, "976773134": 31, "976771087": 31, "465": 31, "8g": 31, "exact": 31, "blockdev": 31, "getsize64": 31, "uuid": 31, "identif": 31, "blkid": 31, "db572185": 31, "2ac1": 31, "4ef5": 31, "b8af": 31, "c2763e639a67": 31, "partuuid": 31, "37c591e3": 31, "b33b": 31, "4548": 31, "a1eb": 31, "81add9da8a58": 31, "home": 31, "partition_uuid": 31, "your_blocks": 31}, "objects": {}, "objtypes": {}, "objnames": {}, "titleterms": {"author": 0, "benchmark": 1, "cloud": 2, "stream": [2, 13, 15, 16, 31], "debug": 3, "decod": [4, 12, 13, 17], "singl": [4, 9], "thread": 4, "multithread": 4, "gpu": [4, 23], "acceler": [4, 5], "queue": 4, "frame": [4, 9, 11, 14], "support": 5, "hardwar": 5, "ip": [5, 9], "camera": [5, 9, 10, 13], "usb": [5, 10], "codec": 5, "linux": 5, "client": [5, 14], "valkka": [6, 7], "about": 7, "why": 7, "thi": 7, "librari": 7, "api": [7, 14, 18, 26], "The": [7, 29], "project": 7, "knowledg": 8, "base": 8, "gener": [8, 18], "opencv": [8, 14, 28], "contrib": 8, "jetson": 8, "nano": 8, "qt": [8, 26], "python": [8, 14, 22, 24, 26], "bind": 8, "lesson": [9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 30], "1": [9, 11, 14], "receiv": [9, 14], "from": 9, "an": [9, 31], "A": [9, 18, 28], "framefilt": 9, "chain": 9, "fork": 9, "refer": 9, "control": 9, "verbos": 9, "10": 10, "11": 11, "valkkaf": [11, 31], "write": [11, 16], "read": [11, 16], "2": [11, 12, 14, 18], "matroska": 11, "export": 11, "plai": 11, "valkkafsmanag": 11, "3": 13, "x": 13, "window": 13, "system": [13, 23, 25], "One": 13, "one": 13, "sever": 13, "multipl": [13, 31], "4": 14, "server": [14, 15], "side": 14, "level": [14, 18], "frag": 14, "mp4": 14, "advanc": 14, "topic": 14, "5": 15, "transmit": [15, 17], "send": 15, "multicast": 15, "us": [15, 28, 30, 31], "rtsp": 15, "6": 16, "7": 17, "save": 17, "visual": 17, "analyz": 17, "re": 17, "8": 18, "aspect": 18, "simpl": 18, "exampl": [18, 24], "9": 19, "draw": [19, 26], "bound": 19, "box": 19, "licenc": 21, "copyright": 21, "modul": 22, "cpp": 22, "pure": 22, "list": 22, "multi": 23, "introduct": 23, "our": 23, "approach": 23, "configur": 23, "note": 23, "displai": 23, "onvif": 24, "discoveri": 24, "instal": [24, 28], "intro": 24, "zeep": 24, "servic": 24, "class": 24, "call": 24, "pitfal": [24, 25], "common": 25, "problem": 25, "bottleneck": 25, "tune": 25, "faq": 25, "integr": 26, "multiprocess": 26, "video": 26, "widget": 26, "c": [26, 28], "repositori": 27, "index": 27, "ppa": 28, "b": 28, "releas": 28, "compil": 28, "yourself": 28, "test": 28, "your": 28, "numpi": 28, "testsuit": [28, 29], "gtk": 28, "develop": 28, "version": 28, "pyqt": 29, "test_studio_1": 29, "py": 29, "test_studio_detector": 29, "tutori": 30, "prerequisit": 30, "vm": 31, "architectur": 31, "filesystem": 31, "per": 31, "file": 31, "entir": 31, "partit": 31}, "envversion": {"sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx.ext.todo": 2, "sphinx.ext.viewcode": 1, "sphinx": 60}, "alltitles": {"Authors": [[0, "authors"]], "Benchmarking": [[1, "benchmarking"]], "Benchmarks": [[1, "benchmarks"]], "Cloud Streaming": [[2, "cloud-streaming"]], "Debugging": [[3, "debugging"]], "Decoding": [[4, "decoding"]], "Single thread": [[4, "single-thread"]], "Multithread": [[4, "multithread"]], "GPU Accelerated": [[4, "gpu-accelerated"]], "Queueing frames": [[4, "queueing-frames"]], "Supported hardware": [[5, "supported-hardware"]], "IP Cameras": [[5, "ip-cameras"]], "USB Cameras": [[5, "usb-cameras"]], "Codecs": [[5, "codecs"]], "Linux clients": [[5, "linux-clients"]], "Hardware Acceleration": [[5, "hardware-acceleration"]], "Valkka": [[6, "valkka"]], "About Valkka": [[7, "about-valkka"]], "Why this library?": [[7, "why-this-library"]], "Valkka API": [[7, "valkka-api"]], "The Project": [[7, "the-project"]], "Knowledge Base": [[8, "knowledge-base"]], "General": [[8, "general"]], "OpenCV & OpenCV contrib": [[8, "opencv-opencv-contrib"]], "Jetson Nano": [[8, "jetson-nano"]], "Qt Python Bindings": [[8, "qt-python-bindings"]], "Lesson 1 : Receiving frames from an IP camera": [[9, "lesson-1-receiving-frames-from-an-ip-camera"]], "A single FrameFilter": [[9, "a-single-framefilter"]], "Chaining FrameFilters": [[9, "chaining-framefilters"]], "Forking FrameFilters": [[9, "forking-framefilters"]], "FrameFilter reference": [[9, "framefilter-reference"]], "Controlling verbosity": [[9, "controlling-verbosity"]], "Lesson 10 : USB Cameras": [[10, "lesson-10-usb-cameras"]], "Lesson 11 : ValkkaFS": [[11, "lesson-11-valkkafs"]], "Writing": [[11, "writing"]], "Reading 1": [[11, "reading-1"]], "Reading 2": [[11, "reading-2"]], "Matroska export": [[11, "matroska-export"]], "Playing frames": [[11, "playing-frames"]], "ValkkaFSManager": [[11, "valkkafsmanager"]], "Lesson 2 : Decoding": [[12, "lesson-2-decoding"]], "Lesson 3 : Streaming to the X-window system": [[13, "lesson-3-streaming-to-the-x-window-system"]], "One camera to one window": [[13, "one-camera-to-one-window"]], "One camera to several windows": [[13, "one-camera-to-several-windows"]], "Decoding multiple streams": [[13, "decoding-multiple-streams"]], "Lesson 4 : Receiving Frames at Python": [[14, "lesson-4-receiving-frames-at-python"]], "Server side": [[14, "server-side"]], "Client side: API level 2": [[14, "client-side-api-level-2"]], "Client side: openCV": [[14, "client-side-opencv"]], "Client side: API level 1": [[14, "client-side-api-level-1"]], "Server + Client": [[14, "server-client"]], "Receiving frag-MP4 at Python": [[14, "receiving-frag-mp4-at-python"]], "Advanced topics": [[14, "advanced-topics"]], "Lesson 5 : Transmitting stream": [[15, "lesson-5-transmitting-stream"]], "Sending multicast": [[15, "sending-multicast"]], "Using the RTSP server": [[15, "using-the-rtsp-server"]], "Lesson 6 : Writing / reading stream": [[16, "lesson-6-writing-reading-stream"]], "Lesson 7 : Decode, save, visualize, analyze and re-transmit": [[17, "lesson-7-decode-save-visualize-analyze-and-re-transmit"]], "Lesson 8: API level 2": [[18, "lesson-8-api-level-2"]], "General aspects": [[18, "general-aspects"]], "A simple example": [[18, "a-simple-example"]], "Lesson 9 : Drawing Bounding Boxes": [[19, "lesson-9-drawing-bounding-boxes"]], "Licence & Copyright": [[21, "licence-copyright"]], "Modules": [[22, "modules"]], "Cpp modules": [[22, "cpp-modules"]], "Pure python modules": [[22, "pure-python-modules"]], "Module list": [[22, "module-list"]], "Multi-GPU systems": [[23, "multi-gpu-systems"]], "Introduction": [[23, "introduction"]], "Our approach": [[23, "our-approach"]], "Configuration": [[23, "configuration"]], "Note on $DISPLAY": [[23, "note-on-display"]], "OnVif & Discovery": [[24, "onvif-discovery"]], "Installing": [[24, "installing"], [28, "installing"]], "Intro": [[24, "intro"]], "Python OnVif with Zeep": [[24, "python-onvif-with-zeep"]], "Service classes": [[24, "service-classes"]], "Example call": [[24, "example-call"]], "Onvif Pitfalls": [[24, "onvif-pitfalls"]], "Discovery": [[24, "discovery"]], "Common problems": [[25, "common-problems"]], "Pitfalls": [[25, "pitfalls"]], "Bottlenecks": [[25, "bottlenecks"]], "System tuning": [[25, "system-tuning"]], "FAQ": [[25, "faq"]], "Integrating with Qt and multiprocessing": [[26, "integrating-with-qt-and-multiprocessing"]], "Qt integration": [[26, "qt-integration"]], "Drawing video into a widget": [[26, "drawing-video-into-a-widget"]], "Python multiprocessing": [[26, "python-multiprocessing"]], "C++ API": [[26, "c-api"]], "Repository Index": [[27, "repository-index"]], "A. Install using PPA": [[28, "a-install-using-ppa"]], "B. Install using releases": [[28, "b-install-using-releases"]], "C. Compile yourself": [[28, "c-compile-yourself"]], "Test your installation": [[28, "test-your-installation"]], "Numpy": [[28, "numpy"]], "Install the testsuite": [[28, "install-the-testsuite"]], "GTK": [[28, "gtk"]], "OpenCV": [[28, "opencv"]], "Development version": [[28, "development-version"]], "The PyQt testsuite": [[29, "the-pyqt-testsuite"]], "test_studio_1.py": [[29, "test-studio-1-py"]], "test_studio_detector.py": [[29, "test-studio-detector-py"]], "Tutorial": [[30, "tutorial"]], "Using the tutorial": [[30, "using-the-tutorial"]], "Prerequisites": [[30, "prerequisites"]], "Lessons": [[30, "lessons"]], "ValkkaFS": [[31, "valkkafs"]], "VMS Architecture": [[31, "vms-architecture"]], "Filesystem": [[31, "filesystem"]], "Multiple Streams per File": [[31, "multiple-streams-per-file"]], "Using an entire partition": [[31, "using-an-entire-partition"]]}, "indexentries": {}}) \ No newline at end of file diff --git a/docs/_build/html/testsuite.html b/docs/_build/html/testsuite.html index 9c7aad1..aa34a5c 100644 --- a/docs/_build/html/testsuite.html +++ b/docs/_build/html/testsuite.html @@ -1,39 +1,171 @@ + + + - - - - + + The PyQt testsuite — Python Media Streaming Framework for Linux documentation + + + - The PyQt testsuite — Python Media Streaming Framework for Linux documentation - - - - - + + + + + + + + + + + - - - + + + - - + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+
-

The PyQt testsuite

+

The PyQt testsuite

So, you have installed valkka-core and valkka-examples as instructed here. The same hardware requirements apply here as in the tutorial.

The PyQt testsuite is available at

valkka_examples/api_level_2/qt/
@@ -177,7 +309,7 @@
 

Repository

Before launching any of the testsuite programs you should be aware of the common problems of linux video streaming.

-

test_studio_1.py

+

test_studio_1.py

Do this:

cd valkka_examples/api_level_2/qt/
 python3 test_studio_1.py
@@ -321,7 +453,7 @@ 

test_studio_1.py -

test_studio_detector.py

+

test_studio_detector.py

The detector test program uses OpenCV, so you need to have it installed

Launch the program like this:

cd valkka_examples/api_level_2/qt/
@@ -334,122 +466,34 @@ 

test_studio_detector.py +

- -
-
- -
-
- - - - - - - - - + \ No newline at end of file diff --git a/docs/_build/html/tutorial.html b/docs/_build/html/tutorial.html index d0fbc7d..5cde80b 100644 --- a/docs/_build/html/tutorial.html +++ b/docs/_build/html/tutorial.html @@ -1,41 +1,187 @@ + + + - - - - - - Tutorial — Python Media Streaming Framework for Linux documentation - - - - - + + Tutorial — Python Media Streaming Framework for Linux documentation + + + + + + + + + + + + + + + - - - + + + - - + + + + + + + +
+ -
-
-
- +
-
- +
+
+
+ +
+
+
+
+
-

Tutorial

+

Tutorial

-

Using the tutorial

+

Using the tutorial

Once you have installed valkka-examples with git as instructed in here, the example codes of this tutorial can be run like this:

cd valkka_examples/api_level_1/tutorial
 python3 lesson_1_a.py
@@ -43,7 +189,7 @@ 

Using the tutorial -

Prerequisites

+

Prerequisites

Before starting with the tutorial, you need at least:

+
- -
-
- -
-
- - - - - - - - - + \ No newline at end of file diff --git a/docs/_build/html/valkkafs.html b/docs/_build/html/valkkafs.html index 936e2ca..cb14df3 100644 --- a/docs/_build/html/valkkafs.html +++ b/docs/_build/html/valkkafs.html @@ -1,41 +1,175 @@ + + + - - - - + + ValkkaFS — Python Media Streaming Framework for Linux documentation + + + - ValkkaFS — Python Media Streaming Framework for Linux documentation - - - - - + + + + + + + + + + + - - - + + + - - + + + + + + -
-
-
- +
+ + +
+ +
+
+
+ +
+
+
+
+
-

ValkkaFS

+

ValkkaFS

-

VMS Architecture

+

VMS Architecture

When creating a video management system capable of recording and playing simultaneously a large number of streams, here are some of the problems one encounters:

  • Recorded video streams are playbacked in sync, i.e. their timestamps are matched together

  • @@ -90,7 +224,7 @@

    VMS ArchitecturePyQt testsuite on how to use FSGroup and ValkkaFSManager.

-

Filesystem

+

Filesystem

ValkkaSingleFS is a simple filesystem for storing streaming media data. Video frames (H264) are organized in “blocks” and written into a “dumpfile”. The dumpfile can be a regular file or a dedicated disk partition.

Dumpfile is pre-reserved, which makes the life easier for the underlying filesystem and avoids fragmentation (in contrast to creating a huge amount of small, timestamped video segment files).

@@ -118,7 +252,7 @@

Filesystemthe tutorial for more details.

-

Multiple Streams per File

+

Multiple Streams per File

You can also dump multiple streams into a single ValkkaFS. The variant for this is valkka.fs.ValkkaMultiFS.

This requires that all cameras have the same bitrate and key-frame interval!

The advantage of this approach is, that all frames from all your cameras are streamed continuously into the same (large) file or a dedicated block device, @@ -128,7 +262,7 @@

Multiple Streams per File -

Using an entire partition

+

Using an entire partition

WARNING: this makes sense only if you are using ValkkaMultiFS, i.e. streaming several cameras into a same ValkkaFS

An entire hard-drive/partition can be dedicated to ValkkaFS. In the following example, we assume that your external hard-disk appears under /dev/sdb

To grant access to a linux user to read and write block devices directly, use the following command:

@@ -184,124 +318,34 @@

Using an entire partition -

-
-
- - - - - - - - - + \ No newline at end of file diff --git a/docs/_static/logo.png b/docs/_static/logo.png new file mode 100644 index 0000000..524d75e Binary files /dev/null and b/docs/_static/logo.png differ diff --git a/docs/_static/rtd_override.css b/docs/_static/rtd_override.css new file mode 100644 index 0000000..8aa6c28 --- /dev/null +++ b/docs/_static/rtd_override.css @@ -0,0 +1,3 @@ +.wy-nav-content { + max-width: 1200px !important; +} diff --git a/docs/_static/valkka2.png b/docs/_static/valkka2.png new file mode 100644 index 0000000..524d75e Binary files /dev/null and b/docs/_static/valkka2.png differ diff --git a/docs/_templates/sidebar-bottom.html b/docs/_templates/alabaster/sidebar-bottom.html similarity index 100% rename from docs/_templates/sidebar-bottom.html rename to docs/_templates/alabaster/sidebar-bottom.html diff --git a/docs/_templates/sidebar-intro.html b/docs/_templates/alabaster/sidebar-intro.html similarity index 100% rename from docs/_templates/sidebar-intro.html rename to docs/_templates/alabaster/sidebar-intro.html diff --git a/docs/_templates/rtd/layout.html b/docs/_templates/rtd/layout.html new file mode 100644 index 0000000..c6298e2 --- /dev/null +++ b/docs/_templates/rtd/layout.html @@ -0,0 +1,111 @@ +{% extends "!layout.html" %} + +{%- block extrabody %} +{% endblock %} + +{% block extrahead %} + + + + + + +{% endblock %} + +{%- block sidebartitle %} + + + + + + + + + + +{%- if theme_display_version %} + {%- set nav_version = version %} + {%- if READTHEDOCS and current_version %} + {%- set nav_version = current_version %} + {%- endif %} + {%- if nav_version %} +
+ {{ nav_version }} +
+ {%- endif %} +{%- endif %} + + + + + +{%- include "searchbox.html" %} + +{%- endblock %} diff --git a/docs/cloud.rst b/docs/cloud.rst index 2a64f03..4bf119f 100644 --- a/docs/cloud.rst +++ b/docs/cloud.rst @@ -12,7 +12,7 @@ for low-latency live video streaming over your LAN or WAN. LibValkka is able produce the fragmented MP4 "boxes" for you, while you can read them one-by-one, in your python code. How to do this, please refer to the :ref:`tutorial `. -After obtaining the MP4 boxes, just use your imagination. You can send them over the internet using websockets, `gRRP `_, or any protocol of your choice. +After obtaining the MP4 boxes, just use your imagination. You can send them over the internet using websockets, `gRPC `_, or any protocol of your choice. You can also dump them into an .mp4 file, and that file is understood by all media clients (just remember to cache and write the ftyp and moov packets in the beginning of the file). For creating a pipelines like that, please take a look `here `_. diff --git a/docs/conf.py b/docs/conf.py index 2eca904..ea92269 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -45,7 +45,8 @@ 'sphinx.ext.doctest', 'sphinx.ext.todo', 'sphinx.ext.viewcode', - 'sphinx.ext.autosummary' + 'sphinx.ext.autosummary', + 'sphinx_copybutton' ] autodoc_default_flags = ['members'] @@ -135,29 +136,25 @@ # """ # html_theme_path = ["themes"] # html_theme = 'alabaster_' -html_theme = 'alabaster' +# html_theme = 'alabaster' # sucks +html_theme="sphinx_rtd_theme" # you might need to install with pip3 -""" -html_sidebars = { - '**': [ - 'about.html', - 'navigation.html', - 'relations.html', - 'searchbox.html', - 'donate.html', - ] -} -""" +## WARNING: choose overriding as per correct style + +templates_path = ['_templates/rtd'] +# templates_path = ['_templates/alabaster'] +# templates_path = ['_templates/nada'] # keep empty.. :) html_sidebars = { '**': [ 'sidebar-intro.html', 'globaltoc.html', # 'sourcelink.html', - 'searchbox.html' + # 'searchbox.html' # 'sidebar-bottom.html', ] } - +""" +# alabaster html_theme_options = { 'github_user' : 'elsampsa', 'github_repo' : 'valkka-core', @@ -165,7 +162,13 @@ 'page_width' : '60%', 'body_max_width': '100%' } - +""" + +html_theme_options = { + "logo_only": True, # style: RTD +} + + # """ """ diff --git a/docs/snippets/form_snippets.bash b/docs/snippets/form_snippets.bash index f9318f1..e51996e 100755 --- a/docs/snippets/form_snippets.bash +++ b/docs/snippets/form_snippets.bash @@ -10,5 +10,5 @@ codes="*.py" for i in $codes do echo $i - $exe pyeval.py -f $i > $i"_" + $exe pyeval.py $i > $i"_" done diff --git a/docs/snippets/lesson_10.py_ b/docs/snippets/lesson_10.py_ index 9b90d7a..dc8e7ff 100644 --- a/docs/snippets/lesson_10.py_ +++ b/docs/snippets/lesson_10.py_ @@ -1,5 +1,5 @@ -:: +.. code:: python import time from valkka.core import * @@ -12,14 +12,14 @@ USBDeviceThread reads and multiplexes all USB cameras -:: +.. code:: python usbthread =USBDeviceThread("usbthread") Define the usb camera (/dev/video2) and where it is going to be streamed (to av_in_filter with slot number 1): -:: +.. code:: python ctx = USBCameraConnectionContext("/dev/video2", 1, av_in_filter) # The default resolution is 720p @@ -45,7 +45,7 @@ Define the usb camera (/dev/video2) and where it is going to be streamed (to av_ Stream for a minute. Patience. At least the HD Pro Webcam C920 does not send keyframes too often .. -:: +.. code:: python time.sleep(60) diff --git a/docs/snippets/lesson_11_a.py_ b/docs/snippets/lesson_11_a.py_ index 188309a..38ed29c 100644 --- a/docs/snippets/lesson_11_a.py_ +++ b/docs/snippets/lesson_11_a.py_ @@ -9,7 +9,7 @@ This will be our filtergraph: Let's import valkka level 1 API, and ValkkaSingleFS from level 2 API: -:: +.. code:: python import time from valkka.core import * @@ -19,7 +19,7 @@ Let's import valkka level 1 API, and ValkkaSingleFS from level 2 API: Let's set our IP camera's address: -:: +.. code:: python rtsp_address="rtsp://admin:12345@192.168.0.157" @@ -27,7 +27,7 @@ Let's set our IP camera's address: If you want to see the filesystem writing each frame, enable these debugging loggers: -:: +.. code:: python #setLogLevel_filelogger(loglevel_crazy) #setLogLevel_valkkafslogger(loglevel_crazy) @@ -41,7 +41,7 @@ file. The ValkkaSingleFS instance handles the metadata of the filesystem. Let's create a new filesystem and save the metadata into directory */tmp/testvalkkafs* -:: +.. code:: python valkkafs = ValkkaSingleFS.newFromDirectory( dirname = "/tmp/testvalkkafs", @@ -73,7 +73,7 @@ Now the directory has the following files: Next, we create and start (1) the thread responsible for writing the frames into ValkkaFS and (2) LiveThread that is reading the cameras: -:: +.. code:: python writerthread = ValkkaFSWriterThread("writer", valkkafs.core) livethread = LiveThread("livethread") @@ -81,21 +81,21 @@ Next, we create and start (1) the thread responsible for writing the frames into All cameras write to the same FrameFilter, handled by the writing thread: -:: +.. code:: python file_input_framefilter = writerthread.getFrameFilter() Read camera and designate it with slot number 1 -:: +.. code:: python ctx = LiveConnectionContext(LiveConnectionType_rtsp, rtsp_address, 1, file_input_framefilter) Next, start threads -:: +.. code:: python writerthread.startCall() livethread.startCall() @@ -103,7 +103,7 @@ Next, start threads Frames with slot number 1 are identified in the filesystem with id number 925412 (which we just invented): -:: +.. code:: python writerthread.setSlotIdCall(1, 925412) @@ -113,7 +113,7 @@ Frames with slot number 1 are identified in the filesystem with id number 925412 Idle for some secs while the threads run in the background -:: +.. code:: python print("recording!") time.sleep(3) @@ -121,7 +121,7 @@ Idle for some secs while the threads run in the background At this moment, let's take a look at the blocktable -:: +.. code:: python a=valkkafs.getBlockTable() print(a) @@ -141,7 +141,7 @@ In the code above, we force a block write even if the block has not filled up. Let's continue & let the threads do their stuff for some more time -:: +.. code:: python print("recording some more") time.sleep(30) @@ -152,7 +152,7 @@ Let's continue & let the threads do their stuff for some more time Let's take a look at the blocktable again: -:: +.. code:: python print(a) diff --git a/docs/snippets/lesson_11_b.py_ b/docs/snippets/lesson_11_b.py_ index 6d079ac..14b2649 100644 --- a/docs/snippets/lesson_11_b.py_ +++ b/docs/snippets/lesson_11_b.py_ @@ -2,7 +2,7 @@ Same imports as before: -:: +.. code:: python import time, sys from valkka.core import * @@ -11,14 +11,14 @@ Same imports as before: Load ValkkaFS metadata: -:: +.. code:: python valkkafs = ValkkaSingleFS.loadFromDirectory(dirname="/tmp/testvalkkafs") Let's take a look at the blocktable: -:: +.. code:: python a = valkkafs.getBlockTable() print(a) @@ -26,7 +26,7 @@ Let's take a look at the blocktable: Construct the filterchain: write from the reader thread into the verbose InfoFrameFilter -:: +.. code:: python out_filter =InfoFrameFilter("reader_out_filter") readerthread = ValkkaFSReaderThread("reader", valkkafs.core, out_filter) @@ -34,21 +34,21 @@ Construct the filterchain: write from the reader thread into the verbose InfoFra Start the reader thread: -:: +.. code:: python readerthread.startCall() Frames with id number 925412 are mapped into slot 1: -:: +.. code:: python readerthread.setSlotIdCall(1, 925412) Request blocks 0, 1 from the reader thread. Information of frames from these blocks are dumped on the terminal -:: +.. code:: python readerthread.pullBlocksPyCall([0,1]) time.sleep(1) @@ -56,7 +56,7 @@ Request blocks 0, 1 from the reader thread. Information of frames from these bl Exit the thread: -:: +.. code:: python readerthread.stopCall() print("bye") diff --git a/docs/snippets/lesson_11_c.py_ b/docs/snippets/lesson_11_c.py_ index 2b4bcae..1b0e4c5 100644 --- a/docs/snippets/lesson_11_c.py_ +++ b/docs/snippets/lesson_11_c.py_ @@ -1,5 +1,5 @@ -:: +.. code:: python import time, sys from valkka.core import * @@ -8,14 +8,14 @@ Load ValkkaFS metadata: -:: +.. code:: python valkkafs = ValkkaSingleFS.loadFromDirectory(dirname="/tmp/testvalkkafs") Let's take a look at the blocktable: -:: +.. code:: python a = valkkafs.getBlockTable() print(a) @@ -23,14 +23,14 @@ Let's take a look at the blocktable: Instantiate ValkkaFSTool that allows us to peek into the written data -:: +.. code:: python tool = ValkkaFSTool(valkkafs.core) Contents of individual blocks can now be inspected like this: -:: +.. code:: python tool.dumpBlock(0) tool.dumpBlock(1) @@ -55,13 +55,9 @@ You'll get output like this: Frame id number is indicated in the first column. Asterix (*) marks the seek points. In the final rows, first few bytes of the actual payload are shown. -:: - - - Let's see the min and max time of frames written in this ValkkaFS -:: +.. code:: python (t0, t1) = valkkafs.getTimeRange() print("Min and Max time in milliseconds:", t0, t1) @@ -69,7 +65,7 @@ Let's see the min and max time of frames written in this ValkkaFS These are milliseconds, so to get *struct_time* object we need to do this: -:: +.. code:: python print("Min time:", time.gmtime(t0/1000)) print("Max time:", time.gmtime(t1/1000)) @@ -77,7 +73,7 @@ These are milliseconds, so to get *struct_time* object we need to do this: Block numbers corresponding to a certain time range can be searched like this: -:: +.. code:: python req = (t0, t1) block_indices = valkkafs.getInd(req) @@ -88,7 +84,7 @@ Now you could pass to indices to the ValkkaFSReaderThread method **pullBlocksPyC Another usefull method is *getIndNeigh*. It returns blocks from the neighborhood of a certain target time: -:: +.. code:: python req = (t1+t0)//2 block_indices = valkkafs.getIndNeigh(n=2, time=req) @@ -98,6 +94,3 @@ Another usefull method is *getIndNeigh*. It returns blocks from the neighborhoo That will return the target block plus two blocks surrounding it. You would call this method when a user requests a seek to a certain time and you want to be sure that there are enough frames surrounding that time instant - -:: - diff --git a/docs/snippets/lesson_11_d.py_ b/docs/snippets/lesson_11_d.py_ index e733e51..7cb3836 100644 --- a/docs/snippets/lesson_11_d.py_ +++ b/docs/snippets/lesson_11_d.py_ @@ -2,7 +2,7 @@ Same imports as before: -:: +.. code:: python import time, sys from valkka.core import * @@ -14,14 +14,14 @@ Same imports as before: Load ValkkaFS metadata: -:: +.. code:: python valkkafs = ValkkaSingleFS.loadFromDirectory(dirname="/tmp/testvalkkafs") Let's take a look at the blocktable: -:: +.. code:: python a = valkkafs.getBlockTable() print(a) @@ -44,7 +44,7 @@ Here we have introduced yet another FrameFilter that performs forking. An arbit The PassSlotFrameFilter passes frames with a certain slot number as we want frames only from a single stream to the final output file. -:: +.. code:: python # main branch @@ -65,21 +65,21 @@ The PassSlotFrameFilter passes frames with a certain slot number as we want fram Start the reader thread: -:: +.. code:: python readerthread.startCall() Frames with id number 925412 are mapped into slot 1: -:: +.. code:: python readerthread.setSlotIdCall(1, 925412) Request blocks 0-4 from the reader thread. Information of frames from these blocks are dumped on the terminal -:: +.. code:: python readerthread.pullBlocksPyCall([0,1,3,4]) time.sleep(1) @@ -87,7 +87,7 @@ Request blocks 0-4 from the reader thread. Information of frames from these blo Exit the thread: -:: +.. code:: python readerthread.stopCall() print("bye") diff --git a/docs/snippets/lesson_11_e.py_ b/docs/snippets/lesson_11_e.py_ index 2aefb4b..2d37f2d 100644 --- a/docs/snippets/lesson_11_e.py_ +++ b/docs/snippets/lesson_11_e.py_ @@ -2,7 +2,7 @@ Same imports as before: -:: +.. code:: python import time, sys from valkka.core import * @@ -14,14 +14,14 @@ Same imports as before: Load ValkkaFS metadata: -:: +.. code:: python valkkafs = ValkkaSingleFS.loadFromDirectory(dirname="/tmp/testvalkkafs") Let's take a look at the blocktable: -:: +.. code:: python a = valkkafs.getBlockTable() print(a) @@ -46,7 +46,7 @@ Next, we proceed in constructing the filterchain in end-to-beginning order. ValkkaFSReaderThread will write all it's frames into FileCacheThread's input FrameFilter. -:: +.. code:: python out_filter = InfoFrameFilter("out_filter") # will be registered later with cacherthread cacherthread = FileCacheThread("cacher") @@ -57,14 +57,14 @@ Next, define callbacks for FileCacheThread Define a global variable: a tuple that holds the min and max millisecond timestamps of cached frames: -:: +.. code:: python current_time_limits = None This following function will be called frequently by FileCacheThread to inform us about the current millisecond timestamp: -:: +.. code:: python def current_time_callback(mstime: int): global current_time_limits @@ -88,7 +88,7 @@ This following function will be called frequently by FileCacheThread to inform u The next callback is evoked when FileCacheThread receives new frames for caching. It informs us about the minimum and maximum millisecond timestamps: -:: +.. code:: python def time_limits_callback(times: tuple): global current_time_limits @@ -117,7 +117,7 @@ Typically, they should use only the following methods of the libValkka API: Register the callbacks into the FileCacheThread -:: +.. code:: python cacherthread.setPyCallback(current_time_callback) cacherthread.setPyCallback2(time_limits_callback) @@ -125,7 +125,7 @@ Register the callbacks into the FileCacheThread Start the threads -:: +.. code:: python cacherthread.startCall() readerthread.startCall() @@ -133,14 +133,14 @@ Start the threads Frames saved with id number 925412 to ValkkaFS are mapped into slot number 1: -:: +.. code:: python readerthread.setSlotIdCall(1, 925412) FileCacheThread will write frames with slot number 1 into InfoFrameFilter: -:: +.. code:: python ctx = FileStreamContext(1, out_filter) cacherthread.registerStreamCall(ctx) @@ -148,14 +148,14 @@ FileCacheThread will write frames with slot number 1 into InfoFrameFilter: Request blocks 0-4 from the reader thread. The frames will be cached by FileCacheThread. -:: +.. code:: python readerthread.pullBlocksPyCall([0,1,3,4]) Before frames can be played, a seek must be performed to set a time reference. -:: +.. code:: python mstimestamp = int(a[1,0]) # take the first timestamp from the blocktable. Use int() to convert to normal python integer. print("seeking to", mstimestamp) @@ -166,7 +166,7 @@ It's up to the API user to assure that the used mstimestamp is within the correc Next, let the stream play for 10 seconds -:: +.. code:: python cacherthread.playStreamsCall() time.sleep(10) @@ -174,7 +174,7 @@ Next, let the stream play for 10 seconds Stop threads -:: +.. code:: python cacherthread.stopCall() readerthread.stopCall() diff --git a/docs/snippets/lesson_1_a.py_ b/docs/snippets/lesson_1_a.py_ index 980bff4..0bf610e 100644 --- a/docs/snippets/lesson_1_a.py_ +++ b/docs/snippets/lesson_1_a.py_ @@ -1,7 +1,7 @@ Import the valkka level 1 API: -:: +.. code:: python import time from valkka.core import * @@ -9,7 +9,7 @@ Import the valkka level 1 API: Create a starting point for a FrameFilter chain: -:: +.. code:: python live_out_filter =InfoFrameFilter("live_out_filter") @@ -22,14 +22,14 @@ However, as you will learn during this tutorial, FrameFilters can do a lot of st Next we need a thread that feeds the frames into our FrameFilter, so we instantiate a LiveThread: -:: +.. code:: python livethread =LiveThread("livethread") We also need a context describing the connection to an IP camera: -:: +.. code:: python ctx =LiveConnectionContext(LiveConnectionType_rtsp, "rtsp://admin:nordic12345@192.168.1.41", 1, live_out_filter) @@ -38,7 +38,7 @@ The first parameter defines the device type, which in this case is an IP camera Finally, we can start streaming frames from the IP camera: -:: +.. code:: python livethread.startCall() livethread.registerStreamCall(ctx) @@ -75,6 +75,3 @@ InfoFrameFilter simply prints the frame type and first few bytes of it's payload The first frame we get is a setup frame. This is a key feature of Valkka: the stream of frames that flows from source to the final sink, consists, not only of payload (say, H264 or PCMU), but of frames that are used to inform the system about the stream type, codec, etc. .. note:: The code itself (LiveThread, InfoFrameFilter) runs in c++, while the connections are programmed here, at the python level - -:: - diff --git a/docs/snippets/lesson_1_b.py_ b/docs/snippets/lesson_1_b.py_ index 1cf906e..a4bbf64 100644 --- a/docs/snippets/lesson_1_b.py_ +++ b/docs/snippets/lesson_1_b.py_ @@ -15,7 +15,7 @@ Next, let's chain some FrameFilters like this: That chain can be created in python like this: -:: +.. code:: python filter_3 =InfoFrameFilter("filter_3") filter_2 =InfoFrameFilter("filter_2",filter_3) @@ -41,6 +41,3 @@ The output when running the python code looks like this: So, live_out_filter gets frame from livethread. It prints out info about the frame. Then it passes it to filter_2 that again prints information about the frame. filter_2 passes the frame onto filter_3, etc. .. note:: LiveThread has an internal FrameFilter chain that is used to correct the timestamps given by your IP camera - -:: - diff --git a/docs/snippets/lesson_1_c.py_ b/docs/snippets/lesson_1_c.py_ index 68b77e6..b96690e 100644 --- a/docs/snippets/lesson_1_c.py_ +++ b/docs/snippets/lesson_1_c.py_ @@ -20,7 +20,7 @@ At branch 2, frames are written to a file The filtergraph can be implemented in python like this: -:: +.. code:: python # branch 1 info_filter =InfoFrameFilter("info_filter") @@ -38,7 +38,7 @@ Like in the previous example, when constructing programmatically the framefilter Let's run it like this: -:: +.. code:: python # close the gate before streaming @@ -70,6 +70,3 @@ Here we first close the gate, so no information about the frames is printed to t You can play the resulting "stream.mkv" with your favorite media player. .. note:: Valkka is *not* a mediaplayer that understands thousands of codecs and container formats. Emphasis is on an internally consistent (for that a single or a few codec/container formats are enough, i.e. what we write we can also read) video management library. At the moment only H264 video is accepted. Container format is matroska (mkv). - -:: - diff --git a/docs/snippets/lesson_2_a.py_ b/docs/snippets/lesson_2_a.py_ index 44c037c..4d0f6ed 100644 --- a/docs/snippets/lesson_2_a.py_ +++ b/docs/snippets/lesson_2_a.py_ @@ -24,7 +24,7 @@ That's all you need to create complex filtergraphs with Valkka. We start as usual, by constructing the filterchain from end-to-beginning: -:: +.. code:: python # decoding part info_filter =InfoFrameFilter("info_filter") @@ -37,7 +37,7 @@ then you could substitute `AVThread` with `VAAPIThread` instead. Next, we need a framefilter to feed the frames into AVThread. This framefilter is requested from the AVThread itself: -:: +.. code:: python # streaming part av_in_filter =avthread.getFrameFilter() @@ -46,14 +46,14 @@ Next, we need a framefilter to feed the frames into AVThread. This framefilter Finally, proceed as before: pass *av_in_filter* as a parameter to the connection context, start threads, etc. -:: +.. code:: python ctx =LiveConnectionContext(LiveConnectionType_rtsp, "rtsp://admin:nordic12345@192.168.1.41", 1, av_in_filter) Start threads. Starting the threads should be done in end-to-beginning order (in the same order we constructed the filterchain). -:: +.. code:: python avthread.startCall() livethread.startCall() @@ -71,7 +71,7 @@ Start threads. Starting the threads should be done in end-to-beginning order (i Stop threads. Stop threads in beginning-to-end order (i.e., following the filtergraph from left to right). -:: +.. code:: python livethread.stopCall() avthread.stopCall() @@ -101,7 +101,3 @@ You will see output like this: So, instead of H264 packets, we have decoded bitmap frames here. In the next lesson, we'll dump them on the screen. - -:: - - diff --git a/docs/snippets/lesson_3_a.py_ b/docs/snippets/lesson_3_a.py_ index dfd2da6..ab17da8 100644 --- a/docs/snippets/lesson_3_a.py_ +++ b/docs/snippets/lesson_3_a.py_ @@ -19,7 +19,7 @@ Compared to the previous lesson, we're continuying the filterchain from AVThread Start constructing the filterchain from end-to-beginning: -:: +.. code:: python # presentation part glthread =OpenGLThread ("glthread") @@ -29,7 +29,7 @@ Start constructing the filterchain from end-to-beginning: We requested a framefilter from the OpenGLThread. It is passed to the AVThread: -:: +.. code:: python # decoding part avthread =AVThread("avthread",gl_in_filter) @@ -43,7 +43,7 @@ Define the connection to the IP camera as usual, with **slot number** "1": .. _connection: -:: +.. code:: python # ctx =LiveConnectionContext(LiveConnectionType_rtsp, "rtsp://admin:nordic12345@192.168.1.41", 1, av_in_filter) ctx =LiveConnectionContext(LiveConnectionType_rtsp, "rtsp://admin:12345@192.168.0.157", 1, av_in_filter) @@ -51,7 +51,7 @@ Define the connection to the IP camera as usual, with **slot number** "1": Start all threads, start decoding, and register the live stream. Starting the threads should be done in end-to-beginning order (in the same order we constructed the filterchain). -:: +.. code:: python glthread.startCall() avthread.startCall() @@ -66,7 +66,7 @@ Start all threads, start decoding, and register the live stream. Starting the t Now comes the new bit. First, we create a new X window on the screen: -:: +.. code:: python window_id =glthread.createWindow() @@ -75,14 +75,14 @@ We could also use the window id of an existing X window. Next, we create a new "render group" to the OpenGLThread. Render group is a place where we can render bitmaps - in this case it's just the X window. -:: +.. code:: python glthread.newRenderGroupCall(window_id) We still need a "render context". Render context is a mapping from a frame source (in this case, the IP camera) to a certain render group (X window) on the screen: -:: +.. code:: python context_id=glthread.newRenderContextCall(1,window_id,0) # slot, render group, z @@ -93,7 +93,7 @@ Now, each time a frame with slot number "1" arrives to OpenGLThread it will be r Stream for a while, and finally, close all threads: -:: +.. code:: python time.sleep(10) @@ -106,7 +106,7 @@ Stream for a while, and finally, close all threads: Close threads. Stop threads in beginning-to-end order (i.e., following the filtergraph from left to right). -:: +.. code:: python livethread.stopCall() avthread.stopCall() diff --git a/docs/snippets/lesson_3_b.py_ b/docs/snippets/lesson_3_b.py_ index f66ded2..2aaaef0 100644 --- a/docs/snippets/lesson_3_b.py_ +++ b/docs/snippets/lesson_3_b.py_ @@ -2,7 +2,7 @@ Streaming the same camera to several X windows is trivial; we just need to add more render groups (aka x windows) and render contexes (mappings): -:: +.. code:: python id_list=[] diff --git a/docs/snippets/lesson_3_c.py_ b/docs/snippets/lesson_3_c.py_ index 065142d..fab7122 100644 --- a/docs/snippets/lesson_3_c.py_ +++ b/docs/snippets/lesson_3_c.py_ @@ -17,7 +17,7 @@ LiveThread and OpenGLThread can deal with several simultaneous media streams, wh It's a good idea to encapsulate the decoding part into its own class. This class takes as an input, the framefilter where it writes the decoded frames and as an input, the stream rtsp address: -:: +.. code:: python class LiveStream: @@ -46,7 +46,7 @@ It's a good idea to encapsulate the decoding part into its own class. This clas Construct the filtergraph from end-to-beginning: -:: +.. code:: python # presentation part glthread =OpenGLThread ("glthread") @@ -62,7 +62,7 @@ Construct the filtergraph from end-to-beginning: Instantiate LiveStreams. This will also start the AVThreads. Frames from the first camera are tagged with slot number 1, while frames from the second camera are tagged with slot number 2: -:: +.. code:: python stream1 = LiveStream(gl_in_filter, "rtsp://admin:nordic12345@192.168.1.41", 1) # slot 1 stream2 = LiveStream(gl_in_filter, "rtsp://admin:nordic12345@192.168.1.42", 2) # slot 2 @@ -70,7 +70,7 @@ Instantiate LiveStreams. This will also start the AVThreads. Frames from the f Register streams to LiveThread and start playing them: -:: +.. code:: python livethread.registerStreamCall(stream1.ctx) livethread.playStreamCall(stream1.ctx) @@ -81,7 +81,7 @@ Register streams to LiveThread and start playing them: Create x windows, and map slot numbers to certain x windows: -:: +.. code:: python # stream1 uses slot 1 window_id1 =glthread.createWindow() @@ -96,7 +96,7 @@ Create x windows, and map slot numbers to certain x windows: Render video for a while, stop threads and exit: -:: +.. code:: python time.sleep(10) @@ -120,6 +120,3 @@ There are many ways to organize threads, render contexes (slot to x window mappi One could even opt for an architecture, where there is a LiveThread and OpenGLThread for each individual stream (however, this is not recommended). The level 2 API provides ready-made filtergraph classes for different purposes (similar to class LiveStream constructed here). - -:: - diff --git a/docs/snippets/lesson_4_a.py_ b/docs/snippets/lesson_4_a.py_ index 18111c0..825c27c 100644 --- a/docs/snippets/lesson_4_a.py_ +++ b/docs/snippets/lesson_4_a.py_ @@ -26,7 +26,7 @@ To summarize, branch 1 interpolates once a second a frame to RGB and passes it t Let's start the construction of the filtergraph by defining some parameters. Frames are passed to SwScaleFrameFilter at 1000 millisecond intervals. The image dimensions of the frame passed into shared memory, will be one quarter of a full-hd frame: -:: +.. code:: python # define yuv=>rgb interpolation interval image_interval=1000 # YUV => RGB interpolation to the small size is done each 1000 milliseconds and passed on to the shmem ringbuffer @@ -38,7 +38,7 @@ Let's start the construction of the filtergraph by defining some parameters. Fr RGBSharedMemFrameFilter needs also a unique name and the size of the shared memory ring-buffer: -:: +.. code:: python # posix shared memory shmem_name ="lesson_4" # This identifies posix shared memory - must be unique @@ -47,7 +47,7 @@ RGBSharedMemFrameFilter needs also a unique name and the size of the shared memo Next, we construct the filterchain as usual, from end-to-beginning: -:: +.. code:: python # branch 1 glthread =OpenGLThread("glthread") @@ -70,14 +70,14 @@ Next, we construct the filterchain as usual, from end-to-beginning: Define connection to camera: frames from 192.168.1.41 are written to live_out_filter and tagged with slot number 1: -:: +.. code:: python # ctx =LiveConnectionContext(LiveConnectionType_rtsp, "rtsp://admin:nordic12345@192.168.1.41", 1, av_in_filter) ctx =LiveConnectionContext(LiveConnectionType_rtsp, "rtsp://admin:123456@192.168.0.134", 1, av_in_filter) Start processes, stream for 60 seconds and exit: -:: +.. code:: python glthread.startCall() avthread.startCall() diff --git a/docs/snippets/lesson_4_a_client.py_ b/docs/snippets/lesson_4_a_client.py_ index 2ba8e89..93a56a7 100644 --- a/docs/snippets/lesson_4_a_client.py_ +++ b/docs/snippets/lesson_4_a_client.py_ @@ -1,5 +1,5 @@ -:: +.. code:: python from valkka.core import * @@ -12,7 +12,7 @@ The wrapped cpp class is *SharedMemRingBufferRGB* (at the server side, RGBShmemFrameFilter is using SharedMemRingBufferRGB): -:: +.. code:: python shmem = SharedMemRingBufferRGB(shmem_name, shmem_buffers, width, height, 1000, False) # shmem id, buffers, w, h, timeout, False=this is a client @@ -20,7 +20,7 @@ The wrapped cpp class is *SharedMemRingBufferRGB* (at the server side, RGBShmemF Next, get handles to the shared memory as numpy arrays: -:: +.. code:: python shmem_list = [] for i in range(shmem_buffers): @@ -35,7 +35,7 @@ shmem.clientPullPy() returns a tuple with the shared memory ringbuffer index and metadata. -:: +.. code:: python while True: tup = shmem.clientPullPy() diff --git a/docs/snippets/lesson_4_a_client_0_11_0.py_ b/docs/snippets/lesson_4_a_client_0_11_0.py_ index 6e1a446..f186528 100644 --- a/docs/snippets/lesson_4_a_client_0_11_0.py_ +++ b/docs/snippets/lesson_4_a_client_0_11_0.py_ @@ -1,5 +1,5 @@ -:: +.. code:: python from valkka.core import * @@ -12,7 +12,7 @@ The wrapped cpp class is *SharedMemRingBufferRGB* (at the server side, RGBShmemFrameFilter is using SharedMemRingBufferRGB): -:: +.. code:: python shmem = SharedMemRingBufferRGB(shmem_name, shmem_buffers, width, height, 1000, False) # shmem id, buffers, w, h, timeout, False=this is a client @@ -20,7 +20,7 @@ The wrapped cpp class is *SharedMemRingBufferRGB* (at the server side, RGBShmemF We are using integer pointers from python: -:: +.. code:: python index_p = new_intp() # shmem index isize_p = new_intp() # size of data @@ -28,7 +28,7 @@ We are using integer pointers from python: Next, get handles to the shared memory as numpy arrays: -:: +.. code:: python shmem_list = [] for i in range(shmem_buffers): @@ -43,7 +43,7 @@ shmem.clientPullPy() returns a tuple with the shared memory ringbuffer index and metadata. -:: +.. code:: python while True: tup = shmem.clientPullPy() diff --git a/docs/snippets/lesson_4_a_client_api2.py_ b/docs/snippets/lesson_4_a_client_api2.py_ index 6efdf12..5e2959e 100644 --- a/docs/snippets/lesson_4_a_client_api2.py_ +++ b/docs/snippets/lesson_4_a_client_api2.py_ @@ -5,7 +5,7 @@ The parameters used both in the server side (above) and on the client side (belo The used shmem_name(s) should be same in both server and client, but different for another server/client pair. -:: +.. code:: python from valkka.api2 import ShmemRGBClient @@ -28,7 +28,7 @@ The used shmem_name(s) should be same in both server and client, but different f The *mstimeout* defines the semaphore timeout in milliseconds, i.e. the time when the client returns even if no frame was received: -:: +.. code:: python while True: index, meta = client.pullFrame() @@ -41,4 +41,4 @@ The *mstimeout* defines the semaphore timeout in milliseconds, i.e. the time whe The *client.shmem_list* is a list of numpy arrays, while *isize* defines the extent of data in the array. This example simply prints out the first ten bytes of the RGB image. - +""" diff --git a/docs/snippets/lesson_4_a_client_api2_0_11_0.py_ b/docs/snippets/lesson_4_a_client_api2_0_11_0.py_ index 6efdf12..5e2959e 100644 --- a/docs/snippets/lesson_4_a_client_api2_0_11_0.py_ +++ b/docs/snippets/lesson_4_a_client_api2_0_11_0.py_ @@ -5,7 +5,7 @@ The parameters used both in the server side (above) and on the client side (belo The used shmem_name(s) should be same in both server and client, but different for another server/client pair. -:: +.. code:: python from valkka.api2 import ShmemRGBClient @@ -28,7 +28,7 @@ The used shmem_name(s) should be same in both server and client, but different f The *mstimeout* defines the semaphore timeout in milliseconds, i.e. the time when the client returns even if no frame was received: -:: +.. code:: python while True: index, meta = client.pullFrame() @@ -41,4 +41,4 @@ The *mstimeout* defines the semaphore timeout in milliseconds, i.e. the time whe The *client.shmem_list* is a list of numpy arrays, while *isize* defines the extent of data in the array. This example simply prints out the first ten bytes of the RGB image. - +""" diff --git a/docs/snippets/lesson_4_a_client_opencv.py_ b/docs/snippets/lesson_4_a_client_opencv.py_ index 5c91c82..e978d07 100644 --- a/docs/snippets/lesson_4_a_client_opencv.py_ +++ b/docs/snippets/lesson_4_a_client_opencv.py_ @@ -1,5 +1,5 @@ -:: +.. code:: python import cv2 from valkka.api2 import ShmemRGBClient diff --git a/docs/snippets/lesson_4_a_client_opencv_0_11_0.py_ b/docs/snippets/lesson_4_a_client_opencv_0_11_0.py_ index 8ef4d7a..7aaefbc 100644 --- a/docs/snippets/lesson_4_a_client_opencv_0_11_0.py_ +++ b/docs/snippets/lesson_4_a_client_opencv_0_11_0.py_ @@ -1,5 +1,5 @@ -:: +.. code:: python import cv2 from valkka.api2 import ShmemRGBClient diff --git a/docs/snippets/lesson_4_b.py_ b/docs/snippets/lesson_4_b.py_ index 4a7f108..eab62a6 100644 --- a/docs/snippets/lesson_4_b.py_ +++ b/docs/snippets/lesson_4_b.py_ @@ -1,5 +1,5 @@ -:: +.. code:: python import time from valkka.core import * @@ -20,7 +20,7 @@ The filtergraph, once again: branch 2 +--> {IntervalFrameFilter: interval_filter} --> {SwScaleFrameFilter: sws_filter} --> {RGBSharedMemFrameFilter: shmem_filter} -:: +.. code:: python # define yuv=>rgb interpolation interval image_interval=1000 # YUV => RGB interpolation to the small size is done each 1000 milliseconds and passed on to the shmem ringbuffer @@ -32,7 +32,7 @@ The filtergraph, once again: RGBSharedMemFrameFilter needs unique name and the size of the shared memory ring-buffer: -:: +.. code:: python # posix shared memory shmem_name ="lesson_4" # This identifies posix shared memory - must be unique @@ -41,7 +41,7 @@ RGBSharedMemFrameFilter needs unique name and the size of the shared memory ring Next, we construct the filterchain as usual, from end-to-beginning: -:: +.. code:: python # branch 1 glthread =OpenGLThread("glthread") @@ -64,14 +64,14 @@ Next, we construct the filterchain as usual, from end-to-beginning: Define connection to camera: frames from the IP camera are written to live_out_filter and tagged with slot number 1: -:: +.. code:: python # ctx =LiveConnectionContext(LiveConnectionType_rtsp, "rtsp://admin:nordic12345@192.168.1.41", 1, av_in_filter) ctx =LiveConnectionContext(LiveConnectionType_rtsp, "rtsp://admin:123456@192.168.0.134", 1, av_in_filter) Start threads: -:: +.. code:: python glthread.startCall() avthread.startCall() @@ -92,7 +92,7 @@ Start threads: Ok, the server is alive and running. Let's do the client part for receiving frames. -:: +.. code:: python client = ShmemRGBClient( name=shmem_name, @@ -106,14 +106,14 @@ Ok, the server is alive and running. Let's do the client part for receiving fra The client is ready to go. Before starting to receive frames, start playing the RTSP camera -:: +.. code:: python livethread.playStreamCall(ctx) Read 10 frames & exit -:: +.. code:: python print("client starting") cc = 0 @@ -134,7 +134,7 @@ Read 10 frames & exit Clear the server -:: +.. code:: python glthread.delRenderContextCall(context_id) glthread.delRenderGroupCall(window_id) diff --git a/docs/snippets/lesson_4_c.py_ b/docs/snippets/lesson_4_c.py_ index d7dee34..76b233f 100644 --- a/docs/snippets/lesson_4_c.py_ +++ b/docs/snippets/lesson_4_c.py_ @@ -1,5 +1,5 @@ -:: +.. code:: python import time from valkka.core import * @@ -20,7 +20,7 @@ The filtergraph for simultaneous video viewing and frag-MP4 muxing looks like th +--> {FragMP4MuxFrameFilter:fragmp4muxer} --> {FragMP4ShmemFrameFilter:fragmp4shmem} -:: +.. code:: python shmem_buffers = 10 # 10 element in the ring-buffer @@ -48,14 +48,14 @@ The filtergraph for simultaneous video viewing and frag-MP4 muxing looks like th Define connection to camera: frames from the IP camera are written to live_out_filter and tagged with slot number 1: -:: +.. code:: python # ctx =LiveConnectionContext(LiveConnectionType_rtsp, "rtsp://admin:nordic12345@192.168.1.41", 1, fork_filter) ctx =LiveConnectionContext(LiveConnectionType_rtsp, "rtsp://admin:123456@192.168.0.134", 1, fork_filter) Start threads: -:: +.. code:: python glthread.startCall() avthread.startCall() @@ -76,7 +76,7 @@ Start threads: Ok, the server is alive and running. Let's do the client part for receiving frames. -:: +.. code:: python client = FragMP4ShmemClient( name=shmem_name, @@ -89,14 +89,14 @@ Ok, the server is alive and running. Let's do the client part for receiving fra The client is ready to go. Before starting to receive frames, start playing the RTSP camera -:: +.. code:: python livethread.playStreamCall(ctx) Read 10 frames & exit -:: +.. code:: python print("client starting") cc = 0 @@ -117,7 +117,7 @@ Read 10 frames & exit Clear the server -:: +.. code:: python glthread.delRenderContextCall(context_id) glthread.delRenderGroupCall(window_id) diff --git a/docs/snippets/lesson_5_a.py_ b/docs/snippets/lesson_5_a.py_ index 8b14f7e..b951a65 100644 --- a/docs/snippets/lesson_5_a.py_ +++ b/docs/snippets/lesson_5_a.py_ @@ -8,7 +8,7 @@ In this lesson, we are receiving frames from an IP camera using LiveThread and r Let's start by importing Valkka: -:: +.. code:: python import time from valkka.core import * @@ -16,14 +16,14 @@ Let's start by importing Valkka: Live555's default output packet buffer size might be too small, so let's make it bigger before instantiating any LiveThreads: -:: +.. code:: python setLiveOutPacketBuffermaxSize(95000) Construct the filtergraph from end-to-beginning: -:: +.. code:: python livethread2 =LiveThread("livethread2") live_in_filter =livethread2.getFrameFilter() @@ -33,7 +33,7 @@ Construct the filtergraph from end-to-beginning: Start threads -:: +.. code:: python livethread2.startCall() livethread. startCall() @@ -41,21 +41,21 @@ Start threads Define stream source: incoming frames from IP camera 192.168.1.41 are tagged with slot number "2" and they are written to "info_filter": -:: +.. code:: python ctx =LiveConnectionContext(LiveConnectionType_rtsp, "rtsp://admin:nordic12345@192.168.1.41", 2, info_filter) Define stream sink: all outgoing frames with slot number "2" are sent to port 50000: -:: +.. code:: python out_ctx =LiveOutboundContext(LiveConnectionType_sdp, "224.1.168.91", 2, 50000) Start playing: -:: +.. code:: python livethread2.registerOutboundCall(out_ctx) livethread. registerStreamCall(ctx) @@ -64,7 +64,7 @@ Start playing: Stream and recast to multicast for a while: -:: +.. code:: python time.sleep(60) @@ -75,7 +75,7 @@ Stream and recast to multicast for a while: Stop threads in beginning-to-end order -:: +.. code:: python livethread. stopCall(); livethread2.stopCall(); diff --git a/docs/snippets/lesson_5_b.py_ b/docs/snippets/lesson_5_b.py_ index 077fabd..6a6413c 100644 --- a/docs/snippets/lesson_5_b.py_ +++ b/docs/snippets/lesson_5_b.py_ @@ -10,7 +10,7 @@ Stream is read from an IP camera and then re-streamed (shared) to a local RTSP s Let's start by importing Valkka: -:: +.. code:: python import time from valkka.core import * @@ -18,14 +18,14 @@ Let's start by importing Valkka: Live555's default output packet buffer size might be too small, so let's make it bigger before instantiating any LiveThreads: -:: +.. code:: python setLiveOutPacketBuffermaxSize(95000) Construct the filtergraph from end-to-beginning: -:: +.. code:: python livethread2 =LiveThread("livethread2") live_in_filter =livethread2.getFrameFilter() @@ -35,14 +35,14 @@ Construct the filtergraph from end-to-beginning: *Before* starting the threads, establish an RTSP server on livethread2 at port 8554: -:: +.. code:: python livethread2.setRTSPServer(8554); Start threads -:: +.. code:: python livethread2.startCall() livethread. startCall() @@ -50,21 +50,21 @@ Start threads Define stream source: incoming frames from IP camera 192.168.1.41 are tagged with slot number "2" and they are written to "info_filter": -:: +.. code:: python ctx =LiveConnectionContext(LiveConnectionType_rtsp, "rtsp://admin:nordic12345@192.168.1.41", 2, info_filter) Define stream sink: all outgoing frames with slot number "2" are sent to the RTSP server, with substream id "stream1": -:: +.. code:: python out_ctx =LiveOutboundContext(LiveConnectionType_rtsp, "stream1", 2, 0) Start playing: -:: +.. code:: python livethread2.registerOutboundCall(out_ctx) livethread. registerStreamCall(ctx) @@ -73,7 +73,7 @@ Start playing: Stream and recast to the RTSP server for a while: -:: +.. code:: python time.sleep(60) @@ -84,7 +84,7 @@ Stream and recast to the RTSP server for a while: Stop threads in beginning-to-end order -:: +.. code:: python livethread. stopCall(); livethread2.stopCall(); diff --git a/docs/snippets/lesson_6_a.py_ b/docs/snippets/lesson_6_a.py_ index 1074b31..1d686cd 100644 --- a/docs/snippets/lesson_6_a.py_ +++ b/docs/snippets/lesson_6_a.py_ @@ -23,7 +23,7 @@ Note that live and file streams are treated on an equal basis and with a similar Let's start by importing Valkka: -:: +.. code:: python import time from valkka.core import * @@ -33,7 +33,7 @@ Let's start by importing Valkka: Writing is done by piping the stream into a FileFrameFilter: -:: +.. code:: python file_filter =FileFrameFilter("file_filter") livethread =LiveThread("livethread") @@ -41,7 +41,7 @@ Writing is done by piping the stream into a FileFrameFilter: For reading, decoding and presenting, we construct the filtergraph as usual, from end-to-beginning: -:: +.. code:: python # presentation part glthread =OpenGLThread ("glthread") @@ -50,7 +50,7 @@ For reading, decoding and presenting, we construct the filtergraph as usual, fro For file streams, the execution should block for frame bursts, so we request a blocking input FrameFilter from the AVThread: -:: +.. code:: python avthread =AVThread("avthread",gl_in_filter) av_in_filter =avthread.getBlockingFrameFilter() @@ -61,7 +61,7 @@ For file streams, the execution should block for frame bursts, so we request a b Starting LiveThread will stream the frames to FileFrameFilter: -:: +.. code:: python livethread .startCall() @@ -74,7 +74,7 @@ Starting LiveThread will stream the frames to FileFrameFilter: In order to start writing to disk, FileFrameFilter's "activate" method must be called with the filename. Only matroska (.mkv) files are supported: -:: +.. code:: python print("writing to file during 30 secs") file_filter.activate("kokkelis.mkv") @@ -91,7 +91,7 @@ In order to start writing to disk, FileFrameFilter's "activate" method must be c File "kokkelis.mkv" has been created. Next, let's setup stream decoding, presenting, etc. as usual and read the file: -:: +.. code:: python print("reading file") glthread .startCall() @@ -111,7 +111,7 @@ File "kokkelis.mkv" has been created. Next, let's setup stream decoding, presen Open the file by sending it a call with the FileContext (file_ctx) identifying the file stream: -:: +.. code:: python print("open file") file_ctx =FileContext("kokkelis.mkv", 1, av_in_filter) # read from file "kokkelis.mkv", tag frames with slot number 1 and write to av_in_filter @@ -120,7 +120,7 @@ Open the file by sending it a call with the FileContext (file_ctx) identifying t Playing, seeking and stopping is done as follows: -:: +.. code:: python print("play file") filethread.playFileStreamCall(file_ctx) @@ -146,7 +146,7 @@ Playing, seeking and stopping is done as follows: Finally, exit: -:: +.. code:: python glthread.delRenderContextCall(context_id) glthread.delRenderGroupCall(window_id) diff --git a/docs/snippets/lesson_6_a_read.py_ b/docs/snippets/lesson_6_a_read.py_ index e1a252f..365ce08 100644 --- a/docs/snippets/lesson_6_a_read.py_ +++ b/docs/snippets/lesson_6_a_read.py_ @@ -23,7 +23,7 @@ Note that live and file streams are treated on an equal basis and with a similar Let's start by importing Valkka: -:: +.. code:: python import time from valkka.core import * @@ -33,7 +33,7 @@ Let's start by importing Valkka: Writing is done by piping the stream into a FileFrameFilter: -:: +.. code:: python file_filter =FileFrameFilter("file_filter") livethread =LiveThread("livethread") @@ -41,7 +41,7 @@ Writing is done by piping the stream into a FileFrameFilter: For reading, decoding and presenting, we construct the filtergraph as usual, from end-to-beginning: -:: +.. code:: python # presentation part glthread =OpenGLThread ("glthread") @@ -50,7 +50,7 @@ For reading, decoding and presenting, we construct the filtergraph as usual, fro For file streams, the execution should block for frame bursts, so we request a blocking input FrameFilter from the AVThread: -:: +.. code:: python avthread =AVThread("avthread",gl_in_filter) av_in_filter =avthread.getBlockingFrameFilter() @@ -61,7 +61,7 @@ For file streams, the execution should block for frame bursts, so we request a b Starting LiveThread will stream the frames to FileFrameFilter: -:: +.. code:: python #livethread .startCall() # @@ -74,7 +74,7 @@ Starting LiveThread will stream the frames to FileFrameFilter: In order to start writing to disk, FileFrameFilter's "activate" method must be called with the filename. Only matroska (.mkv) files are supported: -:: +.. code:: python #print("writing to file during 30 secs") #file_filter.activate("kokkelis.mkv") @@ -91,7 +91,7 @@ In order to start writing to disk, FileFrameFilter's "activate" method must be c File "kokkelis.mkv" has been created. Next, let's setup stream decoding, presenting, etc. as usual and read the file: -:: +.. code:: python print("reading file") glthread .startCall() @@ -111,7 +111,7 @@ File "kokkelis.mkv" has been created. Next, let's setup stream decoding, presen Open the file by sending it a call with the FileContext (file_ctx) identifying the file stream: -:: +.. code:: python print("open file") file_ctx =FileContext("kokkelis.mkv", 1, av_in_filter) # read from file "kokkelis.mkv", tag frames with slot number 1 and write to av_in_filter @@ -120,7 +120,7 @@ Open the file by sending it a call with the FileContext (file_ctx) identifying t Playing, seeking and stopping is done as follows: -:: +.. code:: python print("play file") filethread.playFileStreamCall(file_ctx) @@ -146,7 +146,7 @@ Playing, seeking and stopping is done as follows: Finally, exit: -:: +.. code:: python glthread.delRenderContextCall(context_id) glthread.delRenderGroupCall(window_id) diff --git a/docs/snippets/lesson_7_a.py_ b/docs/snippets/lesson_7_a.py_ index 2d78156..5abff1d 100644 --- a/docs/snippets/lesson_7_a.py_ +++ b/docs/snippets/lesson_7_a.py_ @@ -35,7 +35,7 @@ There is a new naming convention: the names of filters, threads and fifos are ta Programming the filtergraph tree is started as usual, from the outer leaves, moving towards the main branch: -:: +.. code:: python # *** branch 1 *** livethread2_1 =LiveThread("livethread2_1") diff --git a/docs/snippets/lesson_8_a.py_ b/docs/snippets/lesson_8_a.py_ index f8216b9..3af471e 100644 --- a/docs/snippets/lesson_8_a.py_ +++ b/docs/snippets/lesson_8_a.py_ @@ -1,7 +1,7 @@ First, import API level 2: -:: +.. code:: python import time from valkka.api2 import LiveThread, OpenGLThread @@ -10,7 +10,7 @@ First, import API level 2: Instantiating the API level 2 LiveThread starts running the underlying cpp thread: -:: +.. code:: python livethread=LiveThread( # starts live stream services (using live555) name ="live_thread", @@ -21,7 +21,7 @@ Instantiating the API level 2 LiveThread starts running the underlying cpp threa Same goes for OpenGLThread: -:: +.. code:: python openglthread=OpenGLThread( name ="glthread", @@ -38,7 +38,7 @@ Same goes for OpenGLThread: The filterchain and decoder (AVThread) are encapsulated into a single class. Instantiating starts the AVThread (decoding is off by default): -:: +.. code:: python chain=BasicFilterchain( # decoding and branching the stream happens here livethread =livethread, @@ -55,7 +55,7 @@ BasicFilterchain takes as an argument the LiveThread and OpenGLThread instances. Next, create an x-window, map stream to the screen, and start decoding: -:: +.. code:: python # create a window win_id =openglthread.createWindow() @@ -71,7 +71,7 @@ Next, create an x-window, map stream to the screen, and start decoding: Close threads in beginning-to-end order -:: +.. code:: python livethread.close() chain.close() diff --git a/docs/snippets/lesson_9.py_ b/docs/snippets/lesson_9.py_ index 0fa4e95..452a558 100644 --- a/docs/snippets/lesson_9.py_ +++ b/docs/snippets/lesson_9.py_ @@ -1,7 +1,7 @@ First, business as usual (and like in tutorial example 3) -:: +.. code:: python import time from valkka.core import * @@ -37,7 +37,7 @@ Let's add a bounding box, overlaying the video. Parameteres for bounding box (l Coordinates are relative coordinates from 0 to 1. -:: +.. code:: python bbox=(0.25, 0.75, 0.75, 0.25) # left, right, top, bottom @@ -48,7 +48,7 @@ You could add more bounding boxes with consecutive calls to **glthread.addRectan Let's play video for 10 seconds -:: +.. code:: python time.sleep(10) @@ -56,7 +56,7 @@ Let's play video for 10 seconds Finally, clear the bounding boxes and exit -:: +.. code:: python glthread.clearObjectsCall(context_id) diff --git a/docs/snippets/onvif_test.py_ b/docs/snippets/onvif_test.py_ index 882d68c..6442d1c 100644 --- a/docs/snippets/onvif_test.py_ +++ b/docs/snippets/onvif_test.py_ @@ -1,5 +1,5 @@ -:: +.. code:: python from valkka.onvif import OnVif, getWSDLPath diff --git a/docs/snippets/pyeval.py b/docs/snippets/pyeval.py index e2275fc..4ecdbe1 100644 --- a/docs/snippets/pyeval.py +++ b/docs/snippets/pyeval.py @@ -1,83 +1,101 @@ +#!/usr/bin/python3 +"""Script's first argument: input file +""" import sys -# pyeval.py -o/f/h filename.py -if (sys.argv[1]=="-h"): - print("pyeval.py -o/f/h filename.py") - print() - print("for creating automatic .rst files from a .py file") - print() - print("o: make output, f: fix output, h: this help") - print() - print("pyeval.py -o routine.py > tmp.txt") - print("pyeval.py -f tmp.txt > routine.rst") - print() -elif (sys.argv[1]=="-o"): - f=open(sys.argv[2]) - lines=[] - c=0 - cc=0 - inst="" - csec=False +def main(): + hide = False + rst_mode = False + empty = None # checks if found comment or code sections were empty or not + leadspace = 0 + f = open(sys.argv[1]) + lines = [] + c = 0 # line counter + last_csec = 0 # last line where a code section started + inst = " " + newlines = [] for line in f.readlines(): - if (line.strip()==""): - print(inst) + st = line[:-1] # remove newline + if st.strip().lower() in ["#"]: + hide = False + c+=1 + continue + elif st.strip().lower() in ["#HIDE>", "#"]: + hide = True + if hide: + c+=1 + continue + if (c == 0 and st.strip() != '"""'): + # first line and NOT starting with comment section + # so start with code section + """print("") + print(".. code:: python") + print("") + print(inst+st)""" + newlines += [ + "", + ".. code:: python", + "", + inst+st + ] + elif (st.strip() == '"""'): + # comment section starts + # let's see how many empty lines we had in the prepending code section + if empty: + # new comment section starts but the previous code + # section was empty .. so let's remote it + for i in range(0, empty): + newlines.pop(-1) + rst_mode = True + # check how many leading spaces + leadspace = len(st) - len(st.lstrip()) + # print("") + newlines.append("") + empty = 1 # only empty lines in this comment section for the moment + elif (st.strip() == '"""'): + # rtf comment section stops - start code section again + if empty: + # new code section starts but the previous comment + # section was empty .. so let's remote it + for i in range(0, empty): + newlines.pop(-1) + last_csec=len(newlines) + rst_mode = False + """print("") + print(".. code:: python") + print("")""" + newlines += [ + "", + ".. code:: python", + "" + ] + empty = 3 # only empty lines in this code section for the moment + elif (rst_mode == False): + # print into code section + # print(inst+st) + if (empty is not None) and len(st.strip()) == 0: # empty line in this code section + empty += 1 + else: + empty = None # ok.. all the lines were not empty + newlines.append(inst+st) else: - st=line[:-1] - if (st[0]=="#"): - if (csec==False): # entering comment section.. add extra line - print - print(st) - csec=True + # print into comment section + # print(st[leadspace:]) + if (empty is not None) and len(st.strip()) == 0: # empty line in this comment section + empty += 1 else: - #if (csec==True): # just left comments section.. add extra line - # print() - csec=False - print - print(inst+"["+str(cc)+"]: "+st) - exec(st) - cc=cc+1 - c=c+1 -else: - rst_mode=False - hide_mode=False - f=open(sys.argv[2]) - lines=[] - c=0 - inst=" " - #print - #print(":: ") - #print - for line in f.readlines(): - # print("rst_mode>", rst_mode) - st=line[:-1] - if (st.strip()=='#'): - hide_mode=True - elif (st.strip()=='#'): - hide_mode=False - elif (c==0 and st.strip()!='"""'): - # print("fuck>") - print("") - print(":: ") - print("") - print(inst+st) - elif (st.strip()=='"""'): - rst_mode=True - print("") - elif (st.strip()=='"""'): - # print("fuck2>") - rst_mode=False - print("") - print(":: ") - print("") - elif (st.strip()=='"""'): - rst_mode=False - print("") - elif (hide_mode==False and rst_mode==False): - print(inst+st) - elif (hide_mode==False): - print(st) - c=c+1 - print - - - + empty = None # ok.. all the lines were not empty + newlines.append(st[leadspace:]) + c+=1 + + if empty: + # previous section was empty .. so let's remote it + for i in range(0, empty): + newlines.pop(-1) + + for line in newlines: + print(line) + +if __name__ == "__main__": + main() + diff --git a/docs/snippets/pyeval.py_ b/docs/snippets/pyeval.py_ index 35275b2..4df3089 100644 --- a/docs/snippets/pyeval.py_ +++ b/docs/snippets/pyeval.py_ @@ -1,86 +1,104 @@ -:: +.. code:: python + #!/usr/bin/python3 + """Script's first argument: input file + """ import sys - # pyeval.py -o/f/h filename.py - if (sys.argv[1]=="-h"): - print("pyeval.py -o/f/h filename.py") - print() - print("for creating automatic .rst files from a .py file") - print() - print("o: make output, f: fix output, h: this help") - print() - print("pyeval.py -o routine.py > tmp.txt") - print("pyeval.py -f tmp.txt > routine.rst") - print() - elif (sys.argv[1]=="-o"): - f=open(sys.argv[2]) - lines=[] - c=0 - cc=0 - inst="" - csec=False + def main(): + hide = False + rst_mode = False + empty = None # checks if found comment or code sections were empty or not + leadspace = 0 + f = open(sys.argv[1]) + lines = [] + c = 0 # line counter + last_csec = 0 # last line where a code section started + inst = " " + newlines = [] for line in f.readlines(): - if (line.strip()==""): - print(inst) + st = line[:-1] # remove newline + if st.strip().lower() in ["#"]: + hide = False + c+=1 + continue + elif st.strip().lower() in ["#HIDE>", "#"]: + hide = True + if hide: + c+=1 + continue + if (c == 0 and st.strip() != '"""'): + # first line and NOT starting with comment section + # so start with code section + """print("") + print(".. code:: python") + print("") + print(inst+st)""" + newlines += [ + "", + ".. code:: python", + "", + inst+st + ] + elif (st.strip() == '"""'): + # comment section starts + # let's see how many empty lines we had in the prepending code section + if empty: + # new comment section starts but the previous code + # section was empty .. so let's remote it + for i in range(0, empty): + newlines.pop(-1) + rst_mode = True + # check how many leading spaces + leadspace = len(st) - len(st.lstrip()) + # print("") + newlines.append("") + empty = 1 # only empty lines in this comment section for the moment + elif (st.strip() == '"""'): + # rtf comment section stops - start code section again + if empty: + # new code section starts but the previous comment + # section was empty .. so let's remote it + for i in range(0, empty): + newlines.pop(-1) + last_csec=len(newlines) + rst_mode = False + """print("") + print(".. code:: python") + print("")""" + newlines += [ + "", + ".. code:: python", + "" + ] + empty = 3 # only empty lines in this code section for the moment + elif (rst_mode == False): + # print into code section + # print(inst+st) + if (empty is not None) and len(st.strip()) == 0: # empty line in this code section + empty += 1 + else: + empty = None # ok.. all the lines were not empty + newlines.append(inst+st) else: - st=line[:-1] - if (st[0]=="#"): - if (csec==False): # entering comment section.. add extra line - print - print(st) - csec=True + # print into comment section + # print(st[leadspace:]) + if (empty is not None) and len(st.strip()) == 0: # empty line in this comment section + empty += 1 else: - #if (csec==True): # just left comments section.. add extra line - # print() - csec=False - print - print(inst+"["+str(cc)+"]: "+st) - exec(st) - cc=cc+1 - c=c+1 - else: - rst_mode=False - hide_mode=False - f=open(sys.argv[2]) - lines=[] - c=0 - inst=" " - #print - #print(":: ") - #print - for line in f.readlines(): - # print("rst_mode>", rst_mode) - st=line[:-1] - if (st.strip()=='#'): - hide_mode=True - elif (st.strip()=='#'): - hide_mode=False - elif (c==0 and st.strip()!='"""'): - # print("fuck>") - print("") - print(":: ") - print("") - print(inst+st) - elif (st.strip()=='"""'): - rst_mode=True - print("") - elif (st.strip()=='"""'): - # print("fuck2>") - rst_mode=False - print("") - print(":: ") - print("") - elif (st.strip()=='"""'): - rst_mode=False - print("") - elif (hide_mode==False and rst_mode==False): - print(inst+st) - elif (hide_mode==False): - print(st) - c=c+1 - print - - - + empty = None # ok.. all the lines were not empty + newlines.append(st[leadspace:]) + c+=1 + + if empty: + # previous section was empty .. so let's remote it + for i in range(0, empty): + newlines.pop(-1) + + for line in newlines: + print(line) + + if __name__ == "__main__": + main() + diff --git a/docs/snippets/template.py_ b/docs/snippets/template.py_ index fb8bbf5..a5d9104 100644 --- a/docs/snippets/template.py_ +++ b/docs/snippets/template.py_ @@ -1,5 +1,5 @@ -:: +.. code:: python import time from valkka.api2.threads import LiveThread, OpenGLThread diff --git a/docs/snippets/tutorial_variables.py_ b/docs/snippets/tutorial_variables.py_ index 1aaf655..10775b3 100644 --- a/docs/snippets/tutorial_variables.py_ +++ b/docs/snippets/tutorial_variables.py_ @@ -1,4 +1,4 @@ -:: +.. code:: python address="rtsp://admin:nordic12345@192.168.1.41"