\n",
@@ -209,10 +209,10 @@
"id": "d35452de",
"metadata": {
"execution": {
- "iopub.execute_input": "2025-05-13T11:30:26.472115Z",
- "iopub.status.busy": "2025-05-13T11:30:26.471993Z",
- "iopub.status.idle": "2025-05-13T11:30:26.889987Z",
- "shell.execute_reply": "2025-05-13T11:30:26.889554Z"
+ "iopub.execute_input": "2025-05-15T21:27:20.360150Z",
+ "iopub.status.busy": "2025-05-15T21:27:20.360030Z",
+ "iopub.status.idle": "2025-05-15T21:27:20.791692Z",
+ "shell.execute_reply": "2025-05-15T21:27:20.791163Z"
},
"vscode": {
"languageId": "plaintext"
@@ -322,10 +322,10 @@
"id": "c33d38bc",
"metadata": {
"execution": {
- "iopub.execute_input": "2025-05-13T11:30:26.894851Z",
- "iopub.status.busy": "2025-05-13T11:30:26.894647Z",
- "iopub.status.idle": "2025-05-13T11:30:26.899321Z",
- "shell.execute_reply": "2025-05-13T11:30:26.898913Z"
+ "iopub.execute_input": "2025-05-15T21:27:20.796659Z",
+ "iopub.status.busy": "2025-05-15T21:27:20.796532Z",
+ "iopub.status.idle": "2025-05-15T21:27:20.801742Z",
+ "shell.execute_reply": "2025-05-15T21:27:20.801247Z"
},
"vscode": {
"languageId": "plaintext"
@@ -352,10 +352,10 @@
"id": "ea6ed2dd",
"metadata": {
"execution": {
- "iopub.execute_input": "2025-05-13T11:30:26.901128Z",
- "iopub.status.busy": "2025-05-13T11:30:26.900781Z",
- "iopub.status.idle": "2025-05-13T11:30:27.319418Z",
- "shell.execute_reply": "2025-05-13T11:30:27.318973Z"
+ "iopub.execute_input": "2025-05-15T21:27:20.803824Z",
+ "iopub.status.busy": "2025-05-15T21:27:20.803322Z",
+ "iopub.status.idle": "2025-05-15T21:27:21.237795Z",
+ "shell.execute_reply": "2025-05-15T21:27:21.237411Z"
},
"vscode": {
"languageId": "plaintext"
@@ -461,10 +461,10 @@
"id": "b00a9d85",
"metadata": {
"execution": {
- "iopub.execute_input": "2025-05-13T11:30:27.322333Z",
- "iopub.status.busy": "2025-05-13T11:30:27.322209Z",
- "iopub.status.idle": "2025-05-13T11:30:27.855893Z",
- "shell.execute_reply": "2025-05-13T11:30:27.855442Z"
+ "iopub.execute_input": "2025-05-15T21:27:21.241334Z",
+ "iopub.status.busy": "2025-05-15T21:27:21.241206Z",
+ "iopub.status.idle": "2025-05-15T21:27:21.753263Z",
+ "shell.execute_reply": "2025-05-15T21:27:21.752812Z"
},
"vscode": {
"languageId": "plaintext"
@@ -625,10 +625,10 @@
"id": "9931ba22",
"metadata": {
"execution": {
- "iopub.execute_input": "2025-05-13T11:30:27.859332Z",
- "iopub.status.busy": "2025-05-13T11:30:27.858992Z",
- "iopub.status.idle": "2025-05-13T11:30:28.082316Z",
- "shell.execute_reply": "2025-05-13T11:30:28.081718Z"
+ "iopub.execute_input": "2025-05-15T21:27:21.756417Z",
+ "iopub.status.busy": "2025-05-15T21:27:21.756309Z",
+ "iopub.status.idle": "2025-05-15T21:27:22.330925Z",
+ "shell.execute_reply": "2025-05-15T21:27:22.330337Z"
},
"vscode": {
"languageId": "plaintext"
@@ -663,10 +663,10 @@
"id": "537cfdd2",
"metadata": {
"execution": {
- "iopub.execute_input": "2025-05-13T11:30:28.084053Z",
- "iopub.status.busy": "2025-05-13T11:30:28.083694Z",
- "iopub.status.idle": "2025-05-13T11:30:28.472777Z",
- "shell.execute_reply": "2025-05-13T11:30:28.472296Z"
+ "iopub.execute_input": "2025-05-15T21:27:22.332649Z",
+ "iopub.status.busy": "2025-05-15T21:27:22.332540Z",
+ "iopub.status.idle": "2025-05-15T21:27:22.715198Z",
+ "shell.execute_reply": "2025-05-15T21:27:22.714738Z"
},
"vscode": {
"languageId": "plaintext"
@@ -679,7 +679,7 @@
"\n",
"
\n",
@@ -742,10 +742,10 @@
"id": "417a2589",
"metadata": {
"execution": {
- "iopub.execute_input": "2025-05-13T11:30:28.475480Z",
- "iopub.status.busy": "2025-05-13T11:30:28.475278Z",
- "iopub.status.idle": "2025-05-13T11:30:28.500487Z",
- "shell.execute_reply": "2025-05-13T11:30:28.499892Z"
+ "iopub.execute_input": "2025-05-15T21:27:22.718182Z",
+ "iopub.status.busy": "2025-05-15T21:27:22.718021Z",
+ "iopub.status.idle": "2025-05-15T21:27:22.742904Z",
+ "shell.execute_reply": "2025-05-15T21:27:22.742418Z"
},
"vscode": {
"languageId": "plaintext"
@@ -773,10 +773,10 @@
"id": "b8af663f",
"metadata": {
"execution": {
- "iopub.execute_input": "2025-05-13T11:30:28.501942Z",
- "iopub.status.busy": "2025-05-13T11:30:28.501831Z",
- "iopub.status.idle": "2025-05-13T11:30:29.434996Z",
- "shell.execute_reply": "2025-05-13T11:30:29.434505Z"
+ "iopub.execute_input": "2025-05-15T21:27:22.744404Z",
+ "iopub.status.busy": "2025-05-15T21:27:22.744295Z",
+ "iopub.status.idle": "2025-05-15T21:27:23.611474Z",
+ "shell.execute_reply": "2025-05-15T21:27:23.611046Z"
},
"vscode": {
"languageId": "plaintext"
@@ -847,10 +847,10 @@
"id": "1e2cbf14",
"metadata": {
"execution": {
- "iopub.execute_input": "2025-05-13T11:30:29.442424Z",
- "iopub.status.busy": "2025-05-13T11:30:29.442310Z",
- "iopub.status.idle": "2025-05-13T11:30:29.444747Z",
- "shell.execute_reply": "2025-05-13T11:30:29.444365Z"
+ "iopub.execute_input": "2025-05-15T21:27:23.618664Z",
+ "iopub.status.busy": "2025-05-15T21:27:23.618350Z",
+ "iopub.status.idle": "2025-05-15T21:27:23.620849Z",
+ "shell.execute_reply": "2025-05-15T21:27:23.620356Z"
},
"vscode": {
"languageId": "plaintext"
@@ -876,10 +876,10 @@
"id": "dab0513a",
"metadata": {
"execution": {
- "iopub.execute_input": "2025-05-13T11:30:29.446255Z",
- "iopub.status.busy": "2025-05-13T11:30:29.446056Z",
- "iopub.status.idle": "2025-05-13T11:30:30.235444Z",
- "shell.execute_reply": "2025-05-13T11:30:30.234995Z"
+ "iopub.execute_input": "2025-05-15T21:27:23.622549Z",
+ "iopub.status.busy": "2025-05-15T21:27:23.622358Z",
+ "iopub.status.idle": "2025-05-15T21:27:24.408958Z",
+ "shell.execute_reply": "2025-05-15T21:27:24.408486Z"
},
"vscode": {
"languageId": "plaintext"
@@ -948,7 +948,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.12.10"
+ "version": "3.13.3"
}
},
"nbformat": 4,
diff --git a/examples/cthead.ipynb b/examples/cthead.ipynb
index 34b6461..abc3bf6 100644
--- a/examples/cthead.ipynb
+++ b/examples/cthead.ipynb
@@ -16,10 +16,10 @@
"id": "94b5ef80",
"metadata": {
"execution": {
- "iopub.execute_input": "2025-05-13T11:30:31.941828Z",
- "iopub.status.busy": "2025-05-13T11:30:31.941728Z",
- "iopub.status.idle": "2025-05-13T11:30:32.355719Z",
- "shell.execute_reply": "2025-05-13T11:30:32.355253Z"
+ "iopub.execute_input": "2025-05-15T21:27:26.313901Z",
+ "iopub.status.busy": "2025-05-15T21:27:26.313708Z",
+ "iopub.status.idle": "2025-05-15T21:27:26.574048Z",
+ "shell.execute_reply": "2025-05-15T21:27:26.573730Z"
},
"vscode": {
"languageId": "plaintext"
@@ -44,10 +44,10 @@
"id": "1ee080d3",
"metadata": {
"execution": {
- "iopub.execute_input": "2025-05-13T11:30:32.357299Z",
- "iopub.status.busy": "2025-05-13T11:30:32.357117Z",
- "iopub.status.idle": "2025-05-13T11:30:32.484031Z",
- "shell.execute_reply": "2025-05-13T11:30:32.483644Z"
+ "iopub.execute_input": "2025-05-15T21:27:26.575502Z",
+ "iopub.status.busy": "2025-05-15T21:27:26.575328Z",
+ "iopub.status.idle": "2025-05-15T21:27:26.699765Z",
+ "shell.execute_reply": "2025-05-15T21:27:26.699392Z"
},
"vscode": {
"languageId": "plaintext"
@@ -88,10 +88,10 @@
"id": "7af5a922",
"metadata": {
"execution": {
- "iopub.execute_input": "2025-05-13T11:30:32.485668Z",
- "iopub.status.busy": "2025-05-13T11:30:32.485559Z",
- "iopub.status.idle": "2025-05-13T11:30:32.940363Z",
- "shell.execute_reply": "2025-05-13T11:30:32.940013Z"
+ "iopub.execute_input": "2025-05-15T21:27:26.701258Z",
+ "iopub.status.busy": "2025-05-15T21:27:26.701154Z",
+ "iopub.status.idle": "2025-05-15T21:27:27.153944Z",
+ "shell.execute_reply": "2025-05-15T21:27:27.153581Z"
},
"vscode": {
"languageId": "plaintext"
@@ -104,7 +104,7 @@
"\n",
"
\n",
"
\n",
- "

\n",
+ "

\n",
"
\n",
" \n",
"
\n",
@@ -206,10 +206,10 @@
"id": "493f1153",
"metadata": {
"execution": {
- "iopub.execute_input": "2025-05-13T11:30:32.942033Z",
- "iopub.status.busy": "2025-05-13T11:30:32.941917Z",
- "iopub.status.idle": "2025-05-13T11:30:33.347677Z",
- "shell.execute_reply": "2025-05-13T11:30:33.347213Z"
+ "iopub.execute_input": "2025-05-15T21:27:27.155486Z",
+ "iopub.status.busy": "2025-05-15T21:27:27.155382Z",
+ "iopub.status.idle": "2025-05-15T21:27:27.564193Z",
+ "shell.execute_reply": "2025-05-15T21:27:27.563790Z"
},
"vscode": {
"languageId": "plaintext"
@@ -318,10 +318,10 @@
"id": "696c040a",
"metadata": {
"execution": {
- "iopub.execute_input": "2025-05-13T11:30:33.350375Z",
- "iopub.status.busy": "2025-05-13T11:30:33.350168Z",
- "iopub.status.idle": "2025-05-13T11:30:33.441500Z",
- "shell.execute_reply": "2025-05-13T11:30:33.440988Z"
+ "iopub.execute_input": "2025-05-15T21:27:27.567051Z",
+ "iopub.status.busy": "2025-05-15T21:27:27.566946Z",
+ "iopub.status.idle": "2025-05-15T21:27:27.659501Z",
+ "shell.execute_reply": "2025-05-15T21:27:27.659011Z"
},
"vscode": {
"languageId": "plaintext"
@@ -346,10 +346,10 @@
"id": "fa026447",
"metadata": {
"execution": {
- "iopub.execute_input": "2025-05-13T11:30:33.443055Z",
- "iopub.status.busy": "2025-05-13T11:30:33.442941Z",
- "iopub.status.idle": "2025-05-13T11:30:34.253172Z",
- "shell.execute_reply": "2025-05-13T11:30:34.252573Z"
+ "iopub.execute_input": "2025-05-15T21:27:27.660963Z",
+ "iopub.status.busy": "2025-05-15T21:27:27.660860Z",
+ "iopub.status.idle": "2025-05-15T21:27:28.447397Z",
+ "shell.execute_reply": "2025-05-15T21:27:28.446812Z"
},
"vscode": {
"languageId": "plaintext"
@@ -394,10 +394,10 @@
"id": "6e7f236c",
"metadata": {
"execution": {
- "iopub.execute_input": "2025-05-13T11:30:34.254808Z",
- "iopub.status.busy": "2025-05-13T11:30:34.254696Z",
- "iopub.status.idle": "2025-05-13T11:30:35.014910Z",
- "shell.execute_reply": "2025-05-13T11:30:35.014452Z"
+ "iopub.execute_input": "2025-05-15T21:27:28.449085Z",
+ "iopub.status.busy": "2025-05-15T21:27:28.448976Z",
+ "iopub.status.idle": "2025-05-15T21:27:29.204135Z",
+ "shell.execute_reply": "2025-05-15T21:27:29.203694Z"
},
"vscode": {
"languageId": "plaintext"
@@ -505,10 +505,10 @@
"id": "41f16aea",
"metadata": {
"execution": {
- "iopub.execute_input": "2025-05-13T11:30:35.016862Z",
- "iopub.status.busy": "2025-05-13T11:30:35.016752Z",
- "iopub.status.idle": "2025-05-13T11:30:35.522063Z",
- "shell.execute_reply": "2025-05-13T11:30:35.521595Z"
+ "iopub.execute_input": "2025-05-15T21:27:29.205733Z",
+ "iopub.status.busy": "2025-05-15T21:27:29.205624Z",
+ "iopub.status.idle": "2025-05-15T21:27:29.697097Z",
+ "shell.execute_reply": "2025-05-15T21:27:29.696630Z"
},
"vscode": {
"languageId": "plaintext"
@@ -567,7 +567,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.12.10"
+ "version": "3.13.3"
}
},
"nbformat": 4,
diff --git a/examples/introduction.ipynb b/examples/introduction.ipynb
index 5b82088..6eb9bc6 100644
--- a/examples/introduction.ipynb
+++ b/examples/introduction.ipynb
@@ -14,10 +14,10 @@
"id": "3bf7058d",
"metadata": {
"execution": {
- "iopub.execute_input": "2025-05-13T11:30:37.159368Z",
- "iopub.status.busy": "2025-05-13T11:30:37.159210Z",
- "iopub.status.idle": "2025-05-13T11:30:37.733839Z",
- "shell.execute_reply": "2025-05-13T11:30:37.733418Z"
+ "iopub.execute_input": "2025-05-15T21:27:31.292087Z",
+ "iopub.status.busy": "2025-05-15T21:27:31.291928Z",
+ "iopub.status.idle": "2025-05-15T21:27:31.692969Z",
+ "shell.execute_reply": "2025-05-15T21:27:31.692413Z"
},
"vscode": {
"languageId": "plaintext"
@@ -52,10 +52,10 @@
"id": "cd38b675",
"metadata": {
"execution": {
- "iopub.execute_input": "2025-05-13T11:30:37.735613Z",
- "iopub.status.busy": "2025-05-13T11:30:37.735453Z",
- "iopub.status.idle": "2025-05-13T11:30:37.737396Z",
- "shell.execute_reply": "2025-05-13T11:30:37.737148Z"
+ "iopub.execute_input": "2025-05-15T21:27:31.694352Z",
+ "iopub.status.busy": "2025-05-15T21:27:31.694173Z",
+ "iopub.status.idle": "2025-05-15T21:27:31.696537Z",
+ "shell.execute_reply": "2025-05-15T21:27:31.696148Z"
},
"vscode": {
"languageId": "plaintext"
@@ -84,10 +84,10 @@
"id": "8518d1b2",
"metadata": {
"execution": {
- "iopub.execute_input": "2025-05-13T11:30:37.738879Z",
- "iopub.status.busy": "2025-05-13T11:30:37.738781Z",
- "iopub.status.idle": "2025-05-13T11:30:37.740641Z",
- "shell.execute_reply": "2025-05-13T11:30:37.740403Z"
+ "iopub.execute_input": "2025-05-15T21:27:31.697706Z",
+ "iopub.status.busy": "2025-05-15T21:27:31.697602Z",
+ "iopub.status.idle": "2025-05-15T21:27:31.699966Z",
+ "shell.execute_reply": "2025-05-15T21:27:31.699586Z"
},
"vscode": {
"languageId": "plaintext"
@@ -120,10 +120,10 @@
"id": "df9403bf",
"metadata": {
"execution": {
- "iopub.execute_input": "2025-05-13T11:30:37.742124Z",
- "iopub.status.busy": "2025-05-13T11:30:37.742021Z",
- "iopub.status.idle": "2025-05-13T11:30:37.746048Z",
- "shell.execute_reply": "2025-05-13T11:30:37.745798Z"
+ "iopub.execute_input": "2025-05-15T21:27:31.701092Z",
+ "iopub.status.busy": "2025-05-15T21:27:31.700980Z",
+ "iopub.status.idle": "2025-05-15T21:27:31.705588Z",
+ "shell.execute_reply": "2025-05-15T21:27:31.705204Z"
},
"vscode": {
"languageId": "plaintext"
@@ -133,7 +133,7 @@
{
"data": {
"text/plain": [
- ".Geometry at 0x7c02b5141eb0>"
+ ".Geometry at 0x79040f1b1df0>"
]
},
"execution_count": 4,
@@ -182,10 +182,10 @@
"id": "4a1a1c31",
"metadata": {
"execution": {
- "iopub.execute_input": "2025-05-13T11:30:37.747577Z",
- "iopub.status.busy": "2025-05-13T11:30:37.747480Z",
- "iopub.status.idle": "2025-05-13T11:30:37.749306Z",
- "shell.execute_reply": "2025-05-13T11:30:37.749077Z"
+ "iopub.execute_input": "2025-05-15T21:27:31.706696Z",
+ "iopub.status.busy": "2025-05-15T21:27:31.706593Z",
+ "iopub.status.idle": "2025-05-15T21:27:31.708834Z",
+ "shell.execute_reply": "2025-05-15T21:27:31.708452Z"
},
"vscode": {
"languageId": "plaintext"
@@ -221,10 +221,10 @@
"id": "0ca491a8",
"metadata": {
"execution": {
- "iopub.execute_input": "2025-05-13T11:30:37.750878Z",
- "iopub.status.busy": "2025-05-13T11:30:37.750675Z",
- "iopub.status.idle": "2025-05-13T11:30:37.833847Z",
- "shell.execute_reply": "2025-05-13T11:30:37.833433Z"
+ "iopub.execute_input": "2025-05-15T21:27:31.709922Z",
+ "iopub.status.busy": "2025-05-15T21:27:31.709820Z",
+ "iopub.status.idle": "2025-05-15T21:27:31.782437Z",
+ "shell.execute_reply": "2025-05-15T21:27:31.782093Z"
},
"vscode": {
"languageId": "plaintext"
@@ -253,10 +253,10 @@
"id": "37ff9c22",
"metadata": {
"execution": {
- "iopub.execute_input": "2025-05-13T11:30:37.835247Z",
- "iopub.status.busy": "2025-05-13T11:30:37.835139Z",
- "iopub.status.idle": "2025-05-13T11:30:37.931324Z",
- "shell.execute_reply": "2025-05-13T11:30:37.930910Z"
+ "iopub.execute_input": "2025-05-15T21:27:31.783596Z",
+ "iopub.status.busy": "2025-05-15T21:27:31.783489Z",
+ "iopub.status.idle": "2025-05-15T21:27:31.876948Z",
+ "shell.execute_reply": "2025-05-15T21:27:31.876528Z"
},
"vscode": {
"languageId": "plaintext"
@@ -266,7 +266,7 @@
{
"data": {
"text/plain": [
- ""
+ ""
]
},
"execution_count": 7,
@@ -307,10 +307,10 @@
"id": "10ab7a0a",
"metadata": {
"execution": {
- "iopub.execute_input": "2025-05-13T11:30:37.932674Z",
- "iopub.status.busy": "2025-05-13T11:30:37.932571Z",
- "iopub.status.idle": "2025-05-13T11:30:38.079719Z",
- "shell.execute_reply": "2025-05-13T11:30:38.079276Z"
+ "iopub.execute_input": "2025-05-15T21:27:31.878180Z",
+ "iopub.status.busy": "2025-05-15T21:27:31.878061Z",
+ "iopub.status.idle": "2025-05-15T21:27:32.032392Z",
+ "shell.execute_reply": "2025-05-15T21:27:32.031942Z"
},
"vscode": {
"languageId": "plaintext"
@@ -373,7 +373,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.12.10"
+ "version": "3.13.3"
}
},
"nbformat": 4,
diff --git a/misc/libcarna/_imshow.py b/misc/libcarna/_imshow.py
index 8601ab3..84ef9d0 100644
--- a/misc/libcarna/_imshow.py
+++ b/misc/libcarna/_imshow.py
@@ -8,7 +8,7 @@
import numpngw
import numpy as np
-import skvideo.io
+from .libs.skvideo import io as skvideo_io
try:
from IPython.core.display import HTML as IPythonHTML
@@ -47,7 +47,7 @@ def _render_html_h264(array: np.ndarray | Iterable[np.ndarray], fps: float = 25)
# Encode video
with tempfile.NamedTemporaryFile(suffix='.mp4') as mp4_file:
- with skvideo.io.FFmpegWriter(
+ with skvideo_io.FFmpegWriter(
mp4_file.name,
outputdict={
'-vcodec': 'h264',
diff --git a/misc/libcarna/libs/__init__.py b/misc/libcarna/libs/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/misc/libcarna/libs/skvideo/__init__.py b/misc/libcarna/libs/skvideo/__init__.py
new file mode 100644
index 0000000..b678efb
--- /dev/null
+++ b/misc/libcarna/libs/skvideo/__init__.py
@@ -0,0 +1,200 @@
+__version__ = "1.1.11"
+
+from .utils import check_output, where
+import os
+import warnings
+
+# Run a program-based check to see if all install
+# requirements have been met.
+# Sets environment variables based on programs
+# found.
+
+def which(command):
+ candidates = where(command)
+ if len(candidates) > 0:
+ return os.path.split(candidates[0])[0]
+ else:
+ return ""
+
+
+# only ffprobe exists with ffmpeg
+_FFMPEG_PATH = which("ffprobe")
+
+_MEDIAINFO_PATH = which("mediainfo")
+
+_HAS_FFMPEG = 0
+_HAS_MEDIAINFO = 0
+
+_FFMPEG_MAJOR_VERSION = "0"
+_FFMPEG_MINOR_VERSION = "0"
+_FFMPEG_PATCH_VERSION = "0"
+
+_FFMPEG_SUPPORTED_DECODERS = []
+_FFMPEG_SUPPORTED_ENCODERS = []
+
+_FFPROBE_APPLICATION = "ffprobe"
+_FFMPEG_APPLICATION = "ffmpeg"
+_MEDIAINFO_APPLICATION = "mediainfo"
+
+# Windows compat
+if os.name == "nt":
+ _FFPROBE_APPLICATION += ".exe"
+ _FFMPEG_APPLICATION += ".exe"
+ _MEDIAINFO_APPLICATION += ".exe"
+
+def scan_ffmpeg():
+ global _FFMPEG_MAJOR_VERSION
+ global _FFMPEG_MINOR_VERSION
+ global _FFMPEG_PATCH_VERSION
+ global _FFMPEG_SUPPORTED_DECODERS
+ global _FFMPEG_SUPPORTED_ENCODERS
+ _FFMPEG_MAJOR_VERSION = "0"
+ _FFMPEG_MINOR_VERSION = "0"
+ _FFMPEG_PATCH_VERSION = "0"
+ _FFMPEG_SUPPORTED_DECODERS = []
+ _FFMPEG_SUPPORTED_ENCODERS = []
+ try:
+ # grab program version string
+ version = check_output([os.path.join(_FFMPEG_PATH, _FFMPEG_APPLICATION), "-version"])
+ # only parse the first line returned
+ firstline = version.split(b'\n')[0]
+
+ # the 3rd element in this line is the version number
+ version = firstline.split(b' ')[2].strip()
+ versionparts = version.split(b'.')
+ if version[0] == b'N':
+ # this is the 'git' version of FFmpeg
+ _FFMPEG_MAJOR_VERSION = version
+ else:
+ _FFMPEG_MAJOR_VERSION = versionparts[0]
+ _FFMPEG_MINOR_VERSION = versionparts[1]
+ if len(versionparts) > 2:
+ _FFMPEG_PATCH_VERSION = versionparts[2]
+ except:
+ pass
+
+ # by running the above code block, the bottom arrays are populated
+ # output staticly provided for speed concerns
+ _FFMPEG_SUPPORTED_DECODERS = [
+ b'.264', b'.265', b'.302', b'.3g2', b'.3gp', b'.722', b'.aa', b'.aa3', b'.aac', b'.ac3',
+ b'.acm', b'.adf', b'.adp', b'.ads', b'.adx', b'.aea', b'.afc', b'.aif', b'.aifc', b'.aiff',
+ b'.al', b'.amr', b'.ans', b'.ape', b'.apl', b'.apng', b'.aqt', b'.art', b'.asc', b'.asf',
+ b'.ass', b'.ast', b'.au', b'.avc', b'.avi', b'.avr', b'.bcstm', b'.bfstm', b'.bin', b'.bit',
+ b'.bmp', b'.bmv', b'.brstm', b'.caf', b'.cavs', b'.cdata', b'.cdg', b'.cdxl', b'.cgi',
+ b'.cif', b'.daud', b'.dav', b'.dif', b'.diz', b'.dnxhd', b'.dpx', b'.drc', b'.dss', b'.dtk', b'.dts',
+ b'.dtshd', b'.dv', b'.eac3', b'.fap', b'.ffm', b'.ffmeta', b'.flac', b'.flm', b'.flv',
+ b'.fsb', b'.g722', b'.g723_1', b'.g729', b'.genh', b'.gif', b'.gsm', b'.gxf', b'.h261',
+ b'.h263', b'.h264', b'.h265', b'.h26l', b'.hevc', b'.ice', b'.ico', b'.idf', b'.idx', b'.im1',
+ b'.im24', b'.im8', b'.ircam', b'.ivf', b'.ivr', b'.j2c', b'.j2k', b'.jls', b'.jp2', b'.jpeg',
+ b'.jpg', b'.js', b'.jss', b'.lbc', b'.ljpg', b'.lrc', b'.lvf', b'.m2a', b'.m2t', b'.m2ts',
+ b'.m3u8', b'.m4a', b'.m4v', b'.mac', b'.mj2', b'.mjpeg', b'.mjpg', b'.mk3d', b'.mka', b'.mks',
+ b'.mkv', b'.mlp', b'.mmf', b'.mov', b'.mp2', b'.mp3', b'.mp4', b'.mpa', b'.mpc', b'.mpeg',
+ b'.mpg', b'.mpl2', b'.mpo', b'.msf', b'.mts', b'.mvi', b'.mxf', b'.mxg', b'.nfo', b'.nist',
+ b'.nut', b'.ogg', b'.ogv', b'.oma', b'.omg', b'.paf', b'.pam', b'.pbm', b'.pcx', b'.pgm',
+ b'.pgmyuv', b'.pix', b'.pjs', b'.png', b'.ppm', b'.pvf', b'.qcif', b'.ra', b'.ras', b'.rco',
+ b'.rcv', b'.rgb', b'.rm', b'.roq', b'.rs', b'.rsd', b'.rso', b'.rt', b'.sami', b'.sb', b'.sbg',
+ b'.sdr2', b'.sf', b'.sgi', b'.shn', b'.sln', b'.smi', b'.son', b'.sox', b'.spdif', b'.sph',
+ b'.srt', b'.ss2', b'.ssa', b'.stl', b'.str', b'.sub', b'.sun', b'.sunras', b'.sup', b'.svag',
+ b'.sw', b'.swf', b'.tak', b'.tco', b'.tga', b'.thd', b'.tif', b'.tiff', b'.ts', b'.tta',
+ b'.txt', b'.ub', b'.ul', b'.uw', b'.v', b'.v210', b'.vag', b'.vb', b'.vc1', b'.viv', b'.voc',
+ b'.vpk', b'.vqe', b'.vqf', b'.vql', b'.vt', b'.vtt', b'.w64', b'.wav', b'.webm', b'.wma',
+ b'.wmv', b'.wtv', b'.wv', b'.xbm', b'.xface', b'.xl', b'.xml', b'.xvag', b'.xwd', b'.y',
+ b'.y4m', b'.yop', b'.yuv', b'.yuv10',
+
+ # extra extensions that are known container formats
+ b'.raw',
+ b'.iso'
+ ]
+
+ _FFMPEG_SUPPORTED_ENCODERS = [
+ b'., A64', b'.264', b'.265', b'.302', b'.3g2', b'.3gp', b'.722', b'.a64', b'.aa3', b'.aac',
+ b'.ac3', b'.adts', b'.adx', b'.afc', b'.aif', b'.aifc', b'.aiff', b'.al', b'.amr', b'.apng',
+ b'.asf', b'.ass', b'.ast', b'.au', b'.avc', b'.avi', b'.bit', b'.bmp', b'.caf', b'.cavs',
+ b'.chk', b'.cif', b'.daud', b'.dav', b'.dif', b'.dnxhd', b'.dpx', b'.drc', b'.dts', b'.dv', b'.dvd',
+ b'.eac3', b'.f4v', b'.ffm', b'.ffmeta', b'.flac', b'.flm', b'.flv', b'.g722', b'.g723_1',
+ b'.gif', b'.gxf', b'.h261', b'.h263', b'.h264', b'.h265', b'.h26l', b'.hevc', b'.ico',
+ b'.im1', b'.im24', b'.im8', b'.ircam', b'.isma', b'.ismv', b'.ivf', b'.j2c', b'.j2k', b'.jls',
+ b'.jp2', b'.jpeg', b'.jpg', b'.js', b'.jss', b'.latm', b'.lbc', b'.ljpg', b'.loas', b'.lrc',
+ b'.m1v', b'.m2a', b'.m2t', b'.m2ts', b'.m2v', b'.m3u8', b'.m4a', b'.m4v', b'.mj2', b'.mjpeg',
+ b'.mjpg', b'.mk3d', b'.mka', b'.mks', b'.mkv', b'.mlp', b'.mmf', b'.mov', b'.mp2', b'.mp3',
+ b'.mp4', b'.mpa', b'.mpeg', b'.mpg', b'.mpo', b'.mts', b'.mxf', b'.nut', b'.oga', b'.ogg',
+ b'.ogv', b'.oma', b'.omg', b'.opus', b'.pam', b'.pbm', b'.pcx', b'.pgm', b'.pgmyuv', b'.pix',
+ b'.png', b'.ppm', b'.psp', b'.qcif', b'.ra', b'.ras', b'.rco', b'.rcv', b'.rgb', b'.rm',
+ b'.roq', b'.rs', b'.rso', b'.sb', b'.sf', b'.sgi', b'.sox', b'.spdif', b'.spx', b'.srt',
+ b'.ssa', b'.sub', b'.sun', b'.sunras', b'.sw', b'.swf', b'.tco', b'.tga', b'.thd', b'.tif',
+ b'.tiff', b'.ts', b'.ub', b'.ul', b'.uw', b'.vc1', b'.vob', b'.voc', b'.vtt', b'.w64', b'.wav',
+ b'.webm', b'.webp', b'.wma', b'.wmv', b'.wtv', b'.wv', b'.xbm', b'.xface', b'.xml', b'.xwd',
+ b'.y', b'.y4m', b'.yuv',
+
+ # extra extensions that are known container formats
+ b'.raw'
+ ]
+
+
+if _MEDIAINFO_PATH is not None:
+ _HAS_MEDIAINFO = 1
+
+
+# allow library configuration checking
+def getFFmpegPath():
+ """ Returns the path to the directory containing both ffmpeg and ffprobe
+ """
+ return _FFMPEG_PATH
+
+
+def getFFmpegVersion():
+ """ Returns the version of FFmpeg that is currently being used
+ """
+ if _FFMPEG_MAJOR_VERSION[0] == 'N':
+ return "%s" % (_FFMPEG_MAJOR_VERSION, )
+ else:
+ return "%s.%s.%s" % (_FFMPEG_MAJOR_VERSION, _FFMPEG_MINOR_VERSION, _FFMPEG_PATCH_VERSION)
+
+
+def setFFmpegPath(path):
+ """ Sets up the path to the directory containing both ffmpeg and ffprobe
+
+ Use this function for to specify specific system installs of FFmpeg. All
+ calls to ffmpeg and ffprobe will use this path as a prefix.
+
+ Parameters
+ ----------
+ path : string
+ Path to directory containing ffmpeg and ffprobe
+
+ Returns
+ -------
+ none
+
+ """
+ global _FFMPEG_PATH
+ global _HAS_FFMPEG
+ _FFMPEG_PATH = path
+
+ # check to see if the executables actually exist on these paths
+ if os.path.isfile(os.path.join(_FFMPEG_PATH, _FFMPEG_APPLICATION)) and os.path.isfile(os.path.join(_FFMPEG_PATH, _FFPROBE_APPLICATION)):
+ _HAS_FFMPEG = 1
+ else:
+ warnings.warn("ffmpeg/ffprobe not found in path: " + str(path), UserWarning)
+ _HAS_FFMPEG = 0
+ global _FFMPEG_MAJOR_VERSION
+ global _FFMPEG_MINOR_VERSION
+ global _FFMPEG_PATCH_VERSION
+ _FFMPEG_MAJOR_VERSION = "0"
+ _FFMPEG_MINOR_VERSION = "0"
+ _FFMPEG_PATCH_VERSION = "0"
+ return
+
+ # reload version from new path
+ scan_ffmpeg()
+
+
+if (len(_FFMPEG_PATH) > 0):
+ setFFmpegPath(_FFMPEG_PATH)
+
+
+__all__ = [
+ getFFmpegPath,
+ getFFmpegVersion,
+ setFFmpegPath,
+]
diff --git a/misc/libcarna/libs/skvideo/io/__init__.py b/misc/libcarna/libs/skvideo/io/__init__.py
new file mode 100644
index 0000000..b38cc81
--- /dev/null
+++ b/misc/libcarna/libs/skvideo/io/__init__.py
@@ -0,0 +1,10 @@
+"""Utilities to read/write image/video data.
+
+"""
+
+
+from .ffmpeg import *
+
+__all__ = [
+ 'FFmpegWriter',
+]
diff --git a/misc/libcarna/libs/skvideo/io/abstract.py b/misc/libcarna/libs/skvideo/io/abstract.py
new file mode 100644
index 0000000..d72e6d2
--- /dev/null
+++ b/misc/libcarna/libs/skvideo/io/abstract.py
@@ -0,0 +1,217 @@
+import os
+import warnings
+
+import numpy as np
+
+from ..utils import *
+
+
+class VideoWriterAbstract(object):
+ """Writes frames
+
+ this class provides sane initializations for the default case.
+ """
+ NEED_RGB2GRAY_HACK = False
+ DEFAULT_OUTPUT_PIX_FMT = "yuvj444p"
+
+ def __init__(self, filename, inputdict=None, outputdict=None, verbosity=0):
+ """Prepares parameters
+
+ Does not instantiate the an FFmpeg subprocess, but simply
+ prepares the required parameters.
+
+ Parameters
+ ----------
+ filename : string
+ Video file path for writing
+
+ inputdict : dict
+ Input dictionary parameters, i.e. how to interpret the data coming from python.
+
+ outputdict : dict
+ Output dictionary parameters, i.e. how to encode the data
+ when writing to file.
+
+ Returns
+ -------
+ none
+
+ """
+ self.DEVNULL = open(os.devnull, 'wb')
+
+ filename = os.path.abspath(filename)
+ _, self.extension = os.path.splitext(filename)
+
+ # check that the extension makes sense
+ encoders = self._getSupportedEncoders()
+ if encoders != NotImplemented:
+ assert str.encode(
+ self.extension).lower() in encoders, "Unknown encoder extension: " + self.extension.lower()
+
+ self._filename = filename
+ basepath, _ = os.path.split(filename)
+
+ # check to see if filename is a valid file location
+ assert os.access(basepath, os.W_OK), "Cannot write to directory: " + basepath
+
+ if not inputdict:
+ inputdict = {}
+
+ if not outputdict:
+ outputdict = {}
+
+ self.inputdict = inputdict
+ self.outputdict = outputdict
+ self.verbosity = verbosity
+
+ if "-f" not in self.inputdict:
+ self.inputdict["-f"] = "rawvideo"
+ self.warmStarted = False
+
+ def _warmStart(self, M, N, C, dtype):
+ self.warmStarted = True
+
+ if "-pix_fmt" not in self.inputdict:
+ # check the number channels to guess
+ if dtype.kind == 'u' and dtype.itemsize == 2:
+ suffix = 'le' if dtype.byteorder else 'be'
+ if C == 1:
+ if self.NEED_RGB2GRAY_HACK:
+ self.inputdict["-pix_fmt"] = "rgb48" + suffix
+ self.rgb2grayhack = True
+ C = 3
+ else:
+ self.inputdict["-pix_fmt"] = "gray16" + suffix
+ elif C == 2:
+ self.inputdict["-pix_fmt"] = "ya16" + suffix
+ elif C == 3:
+ self.inputdict["-pix_fmt"] = "rgb48" + suffix
+ elif C == 4:
+ self.inputdict["-pix_fmt"] = "rgba64" + suffix
+ else:
+ raise NotImplemented
+ else:
+ if C == 1:
+ if self.NEED_RGB2GRAY_HACK:
+ self.inputdict["-pix_fmt"] = "rgb24"
+ self.rgb2grayhack = True
+ C = 3
+ else:
+ self.inputdict["-pix_fmt"] = "gray"
+ elif C == 2:
+ self.inputdict["-pix_fmt"] = "ya8"
+ elif C == 3:
+ self.inputdict["-pix_fmt"] = "rgb24"
+ elif C == 4:
+ self.inputdict["-pix_fmt"] = "rgba"
+ else:
+ raise NotImplemented
+
+ self.bpp = bpplut[self.inputdict["-pix_fmt"]][1]
+ self.inputNumChannels = bpplut[self.inputdict["-pix_fmt"]][0]
+ bitpercomponent = self.bpp // self.inputNumChannels
+ if bitpercomponent == 8:
+ self.dtype = np.dtype('u1') # np.uint8
+ elif bitpercomponent == 16:
+ suffix = self.inputdict['-pix_fmt'][-2:]
+ if suffix == 'le':
+ self.dtype = np.dtype('u2')
+ else:
+ raise ValueError(self.inputdict['-pix_fmt'] + 'is not a valid pix_fmt for numpy conversion')
+
+ assert self.inputNumChannels == C, "Failed to pass the correct number of channels %d for the pixel format %s." % (
+ self.inputNumChannels, self.inputdict["-pix_fmt"])
+
+ if ("-s" in self.inputdict):
+ widthheight = self.inputdict["-s"].split('x')
+ self.inputwidth = int(widthheight[0])
+ self.inputheight = int(widthheight[1])
+ else:
+ self.inputdict["-s"] = str(N) + "x" + str(M)
+ self.inputwidth = N
+ self.inputheight = M
+
+ # prepare output parameters, if raw
+ if self.extension == ".yuv":
+ if "-pix_fmt" not in self.outputdict:
+ self.outputdict["-pix_fmt"] = self.DEFAULT_OUTPUT_PIX_FMT
+ if self.verbosity > 0:
+ warnings.warn("No output color space provided. Assuming {}.".format(self.DEFAULT_OUTPUT_PIX_FMT),
+ UserWarning)
+
+ self._createProcess(self.inputdict, self.outputdict, self.verbosity)
+
+ def _createProcess(self, inputdict, outputdict, verbosity):
+ pass
+
+ def _prepareData(self, data):
+ return data # general case : do nothing
+
+ def close(self):
+ """Closes the video and terminates FFmpeg process
+
+ """
+ if self._proc is None: # pragma: no cover
+ return # no process
+ if self._proc.poll() is not None:
+ return # process already dead
+ if self._proc.stdin:
+ self._proc.stdin.close()
+ self._proc.wait()
+ self._proc = None
+ self.DEVNULL.close()
+
+ def writeFrame(self, im):
+ """Sends ndarray frames to FFmpeg
+
+ """
+ vid = vshape(im)
+ T, M, N, C = vid.shape
+ if not self.warmStarted:
+ self._warmStart(M, N, C, im.dtype)
+
+ vid = vid.clip(0, (1 << (self.dtype.itemsize << 3)) - 1).astype(self.dtype)
+ vid = self._prepareData(vid)
+ T, M, N, C = vid.shape # in case of hack ine prepareData to change the image shape (gray2RGB in libAV for exemple)
+
+ # check if we need to do some bit-plane swapping
+ # for the raw data format
+ if self.inputdict["-pix_fmt"].startswith('yuv444p') or self.inputdict["-pix_fmt"].startswith('yuvj444p') or \
+ self.inputdict["-pix_fmt"].startswith('yuva444p'):
+ vid = vid.transpose((0, 3, 1, 2))
+
+ # Check size of image
+ if M != self.inputheight or N != self.inputwidth:
+ raise ValueError('All images in a movie should have same size')
+ if C != self.inputNumChannels:
+ raise ValueError('All images in a movie should have same '
+ 'number of channels')
+
+ assert self._proc is not None # Check status
+
+ # Write
+ try:
+ self._proc.stdin.write(vid.tostring())
+ except IOError as e:
+ # Show the command and stderr from pipe
+ msg = '{0:}\n\nFFMPEG COMMAND:\n{1:}\n\nFFMPEG STDERR ' \
+ 'OUTPUT:\n'.format(e, self._cmd)
+ raise IOError(msg)
+
+ def _getSupportedEncoders(self):
+ return NotImplemented
+
+ def _dict2Args(self, dict):
+ args = []
+ for key in dict.keys():
+ args.append(key)
+ args.append(dict[key])
+ return args
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ self.close()
diff --git a/misc/libcarna/libs/skvideo/io/ffmpeg.py b/misc/libcarna/libs/skvideo/io/ffmpeg.py
new file mode 100755
index 0000000..ffd9bd1
--- /dev/null
+++ b/misc/libcarna/libs/skvideo/io/ffmpeg.py
@@ -0,0 +1,49 @@
+""" Plugin that uses ffmpeg to read and write series of images to
+a wide range of video formats.
+
+"""
+
+# Heavily inspired from Almar Klein's imageio code
+# Copyright (c) 2015, imageio contributors
+# distributed under the terms of the BSD License (included in release).
+
+import subprocess as sp
+
+from .abstract import VideoWriterAbstract
+from .. import _FFMPEG_APPLICATION
+from .. import _FFMPEG_PATH
+from .. import _FFMPEG_SUPPORTED_ENCODERS
+from .. import _HAS_FFMPEG
+from ..utils import *
+
+class FFmpegWriter(VideoWriterAbstract):
+ """Writes frames using FFmpeg
+
+ Using FFmpeg as a backend, this class
+ provides sane initializations for the default case.
+ """
+
+ def __init__(self, *args, **kwargs):
+ assert _HAS_FFMPEG, "Cannot find installation of real FFmpeg (which comes with ffprobe)."
+ super(FFmpegWriter,self).__init__(*args, **kwargs)
+
+ def _getSupportedEncoders(self):
+ return _FFMPEG_SUPPORTED_ENCODERS
+
+ def _createProcess(self, inputdict, outputdict, verbosity):
+ iargs = self._dict2Args(inputdict)
+ oargs = self._dict2Args(outputdict)
+
+ cmd = [_FFMPEG_PATH + "/" + _FFMPEG_APPLICATION, "-y"] + iargs + ["-i", "-"] + oargs + [self._filename]
+
+ self._cmd = " ".join(cmd)
+
+ # Launch process
+ if self.verbosity > 0:
+ print(self._cmd)
+ self._proc = sp.Popen(cmd, stdin=sp.PIPE,
+ stdout=sp.PIPE, stderr=None)
+ else:
+ self._proc = sp.Popen(cmd, stdin=sp.PIPE,
+ stdout=self.DEVNULL, stderr=sp.STDOUT)
+
diff --git a/misc/libcarna/libs/skvideo/utils/__init__.py b/misc/libcarna/libs/skvideo/utils/__init__.py
new file mode 100644
index 0000000..30f7ec0
--- /dev/null
+++ b/misc/libcarna/libs/skvideo/utils/__init__.py
@@ -0,0 +1,293 @@
+""" Various utility functions for manipulating video data
+
+"""
+import os
+import platform
+import itertools
+import subprocess as sp
+
+
+# dictionary based on pix_fmt keys
+# first element is number of components
+# second element is number of bits per pixel
+bpplut = {}
+bpplut["yuv420p"] = [3, 12]
+bpplut["yuyv422"] = [3, 16]
+bpplut["rgb24"] = [3, 24]
+bpplut["bgr24"] = [3, 24]
+bpplut["yuv422p"] = [3, 16]
+bpplut["yuv444p"] = [3, 24]
+bpplut["yuv410p"] = [3, 9]
+bpplut["yuv411p"] = [3, 12]
+bpplut["gray"] = [1, 8]
+bpplut["monow"] = [1, 1]
+bpplut["monob"] = [1, 1]
+bpplut["pal8"] = [1, 8]
+bpplut["yuvj420p"] = [3, 12]
+bpplut["yuvj422p"] = [3, 16]
+bpplut["yuvj444p"] = [3, 24]
+bpplut["xvmcmc"] = [0, 0]
+bpplut["xvmcidct"] = [0, 0]
+bpplut["uyvy422"] = [3, 16]
+bpplut["uyyvyy411"] = [3, 12]
+bpplut["bgr8"] = [3, 8]
+bpplut["bgr4"] = [3, 4]
+bpplut["bgr4_byte"] = [3, 4]
+bpplut["rgb8"] = [3, 8]
+bpplut["rgb4"] = [3, 4]
+bpplut["rgb4_byte"] = [3, 4]
+bpplut["nv12"] = [3, 12]
+bpplut["nv21"] = [3, 12]
+bpplut["argb"] = [4, 32]
+bpplut["rgba"] = [4, 32]
+bpplut["abgr"] = [4, 32]
+bpplut["bgra"] = [4, 32]
+bpplut["gray16be"] = [1, 16]
+bpplut["gray16le"] = [1, 16]
+bpplut["yuv440p"] = [3, 16]
+bpplut["yuvj440p"] = [3, 16]
+bpplut["yuva420p"] = [4, 20]
+bpplut["vdpau_h264"] = [0, 0]
+bpplut["vdpau_mpeg1"] = [0, 0]
+bpplut["vdpau_mpeg2"] = [0, 0]
+bpplut["vdpau_wmv3"] = [0, 0]
+bpplut["vdpau_vc1"] = [0, 0]
+bpplut["rgb48be"] = [3, 48]
+bpplut["rgb48le"] = [3, 48]
+bpplut["rgb565be"] = [3, 16]
+bpplut["rgb565le"] = [3, 16]
+bpplut["rgb555be"] = [3, 15]
+bpplut["rgb555le"] = [3, 15]
+bpplut["bgr565be"] = [3, 16]
+bpplut["bgr565le"] = [3, 16]
+bpplut["bgr555be"] = [3, 15]
+bpplut["bgr555le"] = [3, 15]
+bpplut["vaapi_moco"] = [0, 0]
+bpplut["vaapi_idct"] = [0, 0]
+bpplut["vaapi_vld"] = [0, 0]
+bpplut["yuv420p16le"] = [3, 24]
+bpplut["yuv420p16be"] = [3, 24]
+bpplut["yuv422p16le"] = [3, 32]
+bpplut["yuv422p16be"] = [3, 32]
+bpplut["yuv444p16le"] = [3, 48]
+bpplut["yuv444p16be"] = [3, 48]
+bpplut["vdpau_mpeg4"] = [0, 0]
+bpplut["dxva2_vld"] = [0, 0]
+bpplut["rgb444le"] = [3, 12]
+bpplut["rgb444be"] = [3, 12]
+bpplut["bgr444le"] = [3, 12]
+bpplut["bgr444be"] = [3, 12]
+bpplut["ya8"] = [2, 16]
+bpplut["bgr48be"] = [3, 48]
+bpplut["bgr48le"] = [3, 48]
+bpplut["yuv420p9be"] = [3, 13]
+bpplut["yuv420p9le"] = [3, 13]
+bpplut["yuv420p10be"] = [3, 15]
+bpplut["yuv420p10le"] = [3, 15]
+bpplut["yuv422p10be"] = [3, 20]
+bpplut["yuv422p10le"] = [3, 20]
+bpplut["yuv444p9be"] = [3, 27]
+bpplut["yuv444p9le"] = [3, 27]
+bpplut["yuv444p10be"] = [3, 30]
+bpplut["yuv444p10le"] = [3, 30]
+bpplut["yuv422p9be"] = [3, 18]
+bpplut["yuv422p9le"] = [3, 18]
+bpplut["vda_vld"] = [0, 0]
+bpplut["gbrp"] = [3, 24]
+bpplut["gbrp9be"] = [3, 27]
+bpplut["gbrp9le"] = [3, 27]
+bpplut["gbrp10be"] = [3, 30]
+bpplut["gbrp10le"] = [3, 30]
+bpplut["gbrp16be"] = [3, 48]
+bpplut["gbrp16le"] = [3, 48]
+bpplut["yuva420p9be"] = [4, 22]
+bpplut["yuva420p9le"] = [4, 22]
+bpplut["yuva422p9be"] = [4, 27]
+bpplut["yuva422p9le"] = [4, 27]
+bpplut["yuva444p9be"] = [4, 36]
+bpplut["yuva444p9le"] = [4, 36]
+bpplut["yuva420p10be"] = [4, 25]
+bpplut["yuva420p10le"] = [4, 25]
+bpplut["yuva422p10be"] = [4, 30]
+bpplut["yuva422p10le"] = [4, 30]
+bpplut["yuva444p10be"] = [4, 40]
+bpplut["yuva444p10le"] = [4, 40]
+bpplut["yuva420p16be"] = [4, 40]
+bpplut["yuva420p16le"] = [4, 40]
+bpplut["yuva422p16be"] = [4, 48]
+bpplut["yuva422p16le"] = [4, 48]
+bpplut["yuva444p16be"] = [4, 64]
+bpplut["yuva444p16le"] = [4, 64]
+bpplut["vdpau"] = [0, 0]
+bpplut["xyz12le"] = [3, 36]
+bpplut["xyz12be"] = [3, 36]
+bpplut["nv16"] = [3, 16]
+bpplut["nv20le"] = [3, 20]
+bpplut["nv20be"] = [3, 20]
+bpplut["yvyu422"] = [3, 16]
+bpplut["vda"] = [0, 0]
+bpplut["ya16be"] = [2, 32]
+bpplut["ya16le"] = [2, 32]
+bpplut["qsv"] = [0, 0]
+bpplut["mmal"] = [0, 0]
+bpplut["d3d11va_vld"] = [0, 0]
+bpplut["rgba64be"] = [4, 64]
+bpplut["rgba64le"] = [4, 64]
+bpplut["bgra64be"] = [4, 64]
+bpplut["bgra64le"] = [4, 64]
+bpplut["0rgb"] = [3, 24]
+bpplut["rgb0"] = [3, 24]
+bpplut["0bgr"] = [3, 24]
+bpplut["bgr0"] = [3, 24]
+bpplut["yuva444p"] = [4, 32]
+bpplut["yuva422p"] = [4, 24]
+bpplut["yuv420p12be"] = [3, 18]
+bpplut["yuv420p12le"] = [3, 18]
+bpplut["yuv420p14be"] = [3, 21]
+bpplut["yuv420p14le"] = [3, 21]
+bpplut["yuv422p12be"] = [3, 24]
+bpplut["yuv422p12le"] = [3, 24]
+bpplut["yuv422p14be"] = [3, 28]
+bpplut["yuv422p14le"] = [3, 28]
+bpplut["yuv444p12be"] = [3, 36]
+bpplut["yuv444p12le"] = [3, 36]
+bpplut["yuv444p14be"] = [3, 42]
+bpplut["yuv444p14le"] = [3, 42]
+bpplut["gbrp12be"] = [3, 36]
+bpplut["gbrp12le"] = [3, 36]
+bpplut["gbrp14be"] = [3, 42]
+bpplut["gbrp14le"] = [3, 42]
+bpplut["gbrap"] = [4, 32]
+bpplut["gbrap16be"] = [4, 64]
+bpplut["gbrap16le"] = [4, 64]
+bpplut["yuvj411p"] = [3, 12]
+bpplut["bayer_bggr8"] = [3, 8]
+bpplut["bayer_rggb8"] = [3, 8]
+bpplut["bayer_gbrg8"] = [3, 8]
+bpplut["bayer_grbg8"] = [3, 8]
+bpplut["bayer_bggr16le"] = [3, 16]
+bpplut["bayer_bggr16be"] = [3, 16]
+bpplut["bayer_rggb16le"] = [3, 16]
+bpplut["bayer_rggb16be"] = [3, 16]
+bpplut["bayer_gbrg16le"] = [3, 16]
+bpplut["bayer_gbrg16be"] = [3, 16]
+bpplut["bayer_grbg16le"] = [3, 16]
+bpplut["bayer_grbg16be"] = [3, 16]
+bpplut["yuv440p10le"] = [3, 20]
+bpplut["yuv440p10be"] = [3, 20]
+bpplut["yuv440p12le"] = [3, 24]
+bpplut["yuv440p12be"] = [3, 24]
+bpplut["ayuv64le"] = [4, 64]
+bpplut["ayuv64be"] = [4, 64]
+bpplut["videotoolbox_vld"] = [0, 0]
+
+# patch for python 2.6
+def check_output(*popenargs, **kwargs):
+ closeNULL = 0
+ try:
+ from subprocess import DEVNULL
+ closeNULL = 0
+ except ImportError:
+ import os
+ DEVNULL = open(os.devnull, 'wb')
+ closeNULL = 1
+
+ process = sp.Popen(stdout=sp.PIPE, stderr=DEVNULL, *popenargs, **kwargs)
+ output, unused_err = process.communicate()
+ retcode = process.poll()
+
+ if closeNULL:
+ DEVNULL.close()
+
+ if retcode:
+ cmd = kwargs.get("args")
+ if cmd is None:
+ cmd = popenargs[0]
+ error = sp.CalledProcessError(retcode, cmd)
+ error.output = output
+ raise error
+ return output
+
+def where( filename ):
+ """ Returns all matching file paths. """
+ return list(iwhere(filename))
+
+def iwhere( filename ):
+ possible_paths = _gen_possible_matches(filename)
+ existing_file_paths = filter(os.path.isfile, possible_paths)
+ return existing_file_paths
+
+def iter_unique(iterable):
+ yielded = set()
+ for i in iterable:
+ if i in yielded:
+ continue
+ yield i
+ yielded.add(i)
+
+def imapchain(*a, **kwa):
+ """ Like map but also chains the results. """
+
+ imap_results = map(*a, **kwa)
+ return itertools.chain(*imap_results)
+
+def _gen_possible_matches(filename):
+ path_parts = os.environ.get("PATH", "").split(os.pathsep)
+ path_parts = itertools.chain((os.curdir,), path_parts)
+ possible_paths = map(lambda path_part: os.path.join(path_part, filename), path_parts)
+
+ if platform.system() == "Windows":
+ possible_paths = imapchain(lambda path: (path, path+".bat", path+".com", path+".exe"), possible_paths)
+
+ possible_paths = map(os.path.abspath, possible_paths)
+
+ result = iter_unique(possible_paths)
+
+ return result
+
+def vshape(videodata):
+ """Standardizes the input data shape.
+
+ Transforms video data into the standardized shape (T, M, N, C), where
+ T is number of frames, M is height, N is width, and C is number of
+ channels.
+
+ Parameters
+ ----------
+ videodata : ndarray
+ Input data of shape (T, M, N, C), (T, M, N), (M, N, C), or (M, N), where
+ T is number of frames, M is height, N is width, and C is number of
+ channels.
+
+ Returns
+ -------
+ videodataout : ndarray
+ Standardized version of videodata, shape (T, M, N, C)
+
+ """
+ import numpy as np
+ if not isinstance(videodata, np.ndarray):
+ videodata = np.array(videodata)
+
+ if len(videodata.shape) == 2:
+ a, b = videodata.shape
+ return videodata.reshape(1, a, b, 1)
+ elif len(videodata.shape) == 3:
+ a, b, c = videodata.shape
+ # check the last dimension small
+ # interpret as color channel
+ if c in [1, 2, 3, 4]:
+ return videodata.reshape(1, a, b, c)
+ else:
+ return videodata.reshape(a, b, c, 1)
+ elif len(videodata.shape) == 4:
+ return videodata
+ else:
+ raise ValueError("Improper data input")
+
+__all__ = [
+ 'bpplut',
+ 'where',
+ 'check_output',
+ 'vshape',
+]
diff --git a/setup.py.in b/setup.py.in
index fd8d5d3..5a33bdc 100644
--- a/setup.py.in
+++ b/setup.py.in
@@ -22,11 +22,22 @@ if __name__ == '__main__':
'LICENSE-LibCarna',
'LICENSE-Eigen',
'LICENSE-GLEW',
+ 'LICENSE-skvideo',
],
package_dir = {
'libcarna': 'libcarna',
+ 'libcarna.libs': 'libcarna/libs',
+ 'libcarna.libs.skvideo': 'libcarna/libs/skvideo',
+ 'libcarna.libs.skvideo.io': 'libcarna/libs/skvideo/io',
+ 'libcarna.libs.skvideo.utils': 'libcarna/libs/skvideo/utils',
},
- packages = ['libcarna'],
+ packages = [
+ 'libcarna',
+ 'libcarna.libs',
+ 'libcarna.libs.skvideo',
+ 'libcarna.libs.skvideo.io',
+ 'libcarna.libs.skvideo.utils',
+ ],
package_data = {
'libcarna': ['*.so'],
},
@@ -44,7 +55,6 @@ if __name__ == '__main__':
install_requires = [
'numpy',
'numpngw >=0.1.4, <0.2',
- 'scikit-video >=1.1.11, <1.2',
'scipy',
'scikit-image',
'tifffile',