Skip to content

Commit b25c866

Browse files
authored
Merge pull request #324 from fisheggg/master
Add support for Gopro .360 format
2 parents 8c2c21a + 6fca90a commit b25c866

File tree

7 files changed

+81
-8
lines changed

7 files changed

+81
-8
lines changed

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "musicalgestures/gopromax-conversion-tools"]
2+
path = musicalgestures/gopromax-conversion-tools
3+
url = https://github.com/alexarje/gopromax-conversion-tools.git

docs/musicalgestures/_360video.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
## Mg360Video
1111

12-
[[find in source code]](https://github.com/fourMs/MGT-python/blob/master/musicalgestures/_360video.py#L91)
12+
[[find in source code]](https://github.com/fourMs/MGT-python/blob/master/musicalgestures/_360video.py#L94)
1313

1414
```python
1515
class Mg360Video(MgVideo):
@@ -30,13 +30,14 @@ Class for 360 videos.
3030

3131
### Mg360Video().convert_projection
3232

33-
[[find in source code]](https://github.com/fourMs/MGT-python/blob/master/musicalgestures/_360video.py#L123)
33+
[[find in source code]](https://github.com/fourMs/MGT-python/blob/master/musicalgestures/_360video.py#L126)
3434

3535
```python
3636
def convert_projection(
3737
target_projection: Union[Projection, str],
3838
options: Dict[str, str] = None,
3939
print_cmd: bool = False,
40+
test: bool = False,
4041
):
4142
```
4243

@@ -54,7 +55,7 @@ options (Dict[str, str], optional): Options for the conversion. Defaults to None
5455

5556
## Projection
5657

57-
[[find in source code]](https://github.com/fourMs/MGT-python/blob/master/musicalgestures/_360video.py#L9)
58+
[[find in source code]](https://github.com/fourMs/MGT-python/blob/master/musicalgestures/_360video.py#L11)
5859

5960
```python
6061
class Projection(Enum):

docs/musicalgestures/_video.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ Creates an average image of all frames in the video.
7979

8080
### MgVideo().extract_frame
8181

82-
[[find in source code]](https://github.com/fourMs/MGT-python/blob/master/musicalgestures/_video.py#L330)
82+
[[find in source code]](https://github.com/fourMs/MGT-python/blob/master/musicalgestures/_video.py#L331)
8383

8484
```python
8585
def extract_frame(**kwargs):
@@ -101,7 +101,7 @@ see _utils.extract_frame for details.
101101

102102
### MgVideo().from_numpy
103103

104-
[[find in source code]](https://github.com/fourMs/MGT-python/blob/master/musicalgestures/_video.py#L290)
104+
[[find in source code]](https://github.com/fourMs/MGT-python/blob/master/musicalgestures/_video.py#L291)
105105

106106
```python
107107
def from_numpy(array, fps, target_name=None):
@@ -119,7 +119,7 @@ Creates a video attribute to the Musical Gestures object with the given correct
119119

120120
### MgVideo().numpy
121121

122-
[[find in source code]](https://github.com/fourMs/MGT-python/blob/master/musicalgestures/_video.py#L277)
122+
[[find in source code]](https://github.com/fourMs/MGT-python/blob/master/musicalgestures/_video.py#L278)
123123

124124
```python
125125
def numpy():

musicalgestures/_360video.py

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import os
2+
import subprocess
23
from enum import Enum
3-
from functools import partial
44
from typing import Dict, Union
5+
from pathlib import Path
6+
from functools import partial
57
from musicalgestures._video import MgVideo
68
from musicalgestures._utils import ffmpeg_cmd, get_length, generate_outfilename
79

@@ -44,6 +46,7 @@ class Projection(Enum):
4446

4547
equirectangular = 30 # extra option for equirectangular
4648
erp = 31
49+
gopro_360 = 32 # special gopro .360 format
4750

4851
def __str__(self):
4952
# collapse all aliases of erp
@@ -125,6 +128,7 @@ def convert_projection(
125128
target_projection: Union[Projection, str],
126129
options: Dict[str, str] = None,
127130
print_cmd: bool = False,
131+
test: bool = False,
128132
):
129133
"""
130134
Convert the video to a different projection.
@@ -138,6 +142,48 @@ def convert_projection(
138142
if target_projection == self.projection:
139143
print(f"{self} is already in target projection {target_projection}.")
140144
return
145+
elif self.projection == Projection.gopro_360:
146+
if test:
147+
print(
148+
f"=> Test mode: would convert {self.filename} to {target_projection} with options {options}."
149+
)
150+
151+
# use special gopro conversion scripts
152+
assert target_projection in [
153+
Projection.equirect,
154+
Projection.equirectangular,
155+
Projection.dfisheye,
156+
], (
157+
f"Invalid target projection from gopro_360: {target_projection}, only equirect, equirectangular, and dfisheye are supported."
158+
)
159+
160+
output_name = generate_outfilename(
161+
f"{self.filename.split('.')[0]}_{target_projection}.mp4"
162+
)
163+
if target_projection == Projection.dfisheye:
164+
script = "ffmpeg-convert-dual-fisheye.sh"
165+
else:
166+
script = "ffmpeg-convert-v3.sh"
167+
script_path = Path(__file__).parent / "gopromax-conversion-tools/scripts" / script
168+
169+
cmds = [
170+
script_path,
171+
"-i",
172+
self.filename,
173+
"-n",
174+
output_name,
175+
]
176+
if options:
177+
for k, v in options.items():
178+
cmds.append(k)
179+
cmds.append(v)
180+
181+
if test:
182+
print(f"=> Command: {' '.join([str(cmd) for cmd in cmds])}")
183+
subprocess.run(cmds)
184+
self.filename = output_name
185+
self.projection = target_projection
186+
141187
else:
142188
output_name = generate_outfilename(
143189
f"{self.filename.split('.')[0]}_{target_projection}.mp4"
@@ -191,3 +237,24 @@ def _parse_projection(self, projection: Union[str, Projection]):
191237
return projection
192238
else:
193239
raise TypeError(f"Unsupported projection type: '{type(projection)}'.")
240+
241+
242+
## testing gopro_360 conversion
243+
if __name__ == "__main__":
244+
video = Mg360Video("2023-01-01-GS010008.360", Projection.gopro_360)
245+
video.convert_projection(
246+
Projection.equirect,
247+
options={"-r": "0:180:0", "-s": "00:01:10", "-t": "00:01:20"},
248+
test=True,
249+
)
250+
print(f"=> Converted video path: {video.filename}")
251+
print(f"=> Converted video projection: {video.projection}")
252+
253+
video = Mg360Video("2023-01-01-GS010008.360", Projection.gopro_360)
254+
video.convert_projection(
255+
Projection.dfisheye,
256+
options={"-s": "00:01:10", "-t": "00:01:20"},
257+
test=True,
258+
)
259+
print(f"=> Converted video path: {video.filename}")
260+
print(f"=> Converted video projection: {video.projection}")

musicalgestures/_video.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ def get_video(self):
230230
".ts",
231231
".wmv",
232232
".3gp",
233+
".360",
233234
]
234235
if self.fex not in video_formats:
235236
# Check if it is an image file

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
setup(
1313
name='musicalgestures',
1414
packages=['musicalgestures'],
15-
version='v1.3.2',
15+
version='v1.3.3',
1616
license='GNU General Public License v3 (GPLv3)',
1717
description='Musical Gestures Toolbox for Python',
1818
long_description=README,

0 commit comments

Comments
 (0)