VideoTimestamps 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- videotimestamps-0.0.1/LICENSE +21 -0
- videotimestamps-0.0.1/PKG-INFO +48 -0
- videotimestamps-0.0.1/README.md +20 -0
- videotimestamps-0.0.1/VideoTimestamps.egg-info/PKG-INFO +48 -0
- videotimestamps-0.0.1/VideoTimestamps.egg-info/SOURCES.txt +27 -0
- videotimestamps-0.0.1/VideoTimestamps.egg-info/dependency_links.txt +1 -0
- videotimestamps-0.0.1/VideoTimestamps.egg-info/requires.txt +6 -0
- videotimestamps-0.0.1/VideoTimestamps.egg-info/top_level.txt +1 -0
- videotimestamps-0.0.1/pyproject.toml +51 -0
- videotimestamps-0.0.1/setup.cfg +4 -0
- videotimestamps-0.0.1/tests/test_convert_time.py +356 -0
- videotimestamps-0.0.1/tests/test_timestamps.py +424 -0
- videotimestamps-0.0.1/video_timestamps/__init__.py +8 -0
- videotimestamps-0.0.1/video_timestamps/_version.py +1 -0
- videotimestamps-0.0.1/video_timestamps/abc_video_parser.py +32 -0
- videotimestamps-0.0.1/video_timestamps/ffprobe/__init__.py +0 -0
- videotimestamps-0.0.1/video_timestamps/ffprobe/ffprobe.py +140 -0
- videotimestamps-0.0.1/video_timestamps/ffprobe/timestamps.py +29 -0
- videotimestamps-0.0.1/video_timestamps/mkvtoolnix/__init__.py +0 -0
- videotimestamps-0.0.1/video_timestamps/mkvtoolnix/exit_code.py +11 -0
- videotimestamps-0.0.1/video_timestamps/mkvtoolnix/mkvextract.py +73 -0
- videotimestamps-0.0.1/video_timestamps/mkvtoolnix/mkvmerge.py +79 -0
- videotimestamps-0.0.1/video_timestamps/mkvtoolnix/timestamps.py +52 -0
- videotimestamps-0.0.1/video_timestamps/mkvtoolnix/utils.py +144 -0
- videotimestamps-0.0.1/video_timestamps/rounding_method.py +22 -0
- videotimestamps-0.0.1/video_timestamps/time_type.py +60 -0
- videotimestamps-0.0.1/video_timestamps/timestamps.py +225 -0
- videotimestamps-0.0.1/video_timestamps/timestamps_factory.py +144 -0
- videotimestamps-0.0.1/video_timestamps/timestamps_file_parser.py +238 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 moi15moi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: VideoTimestamps
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Get video timestamps.
|
|
5
|
+
Author-email: moi15moi <moi15moismokerlolilol@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Source, https://github.com/moi15moi/VideoTimestamps/
|
|
8
|
+
Project-URL: Tracker, https://github.com/moi15moi/VideoTimestamps/issues/
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Programming Language :: Python
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
19
|
+
Classifier: Typing :: Typed
|
|
20
|
+
Requires-Python: >=3.9
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: coverage>=7.0.0; extra == "dev"
|
|
25
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
26
|
+
Requires-Dist: pillow>=10.0.0; extra == "dev"
|
|
27
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
28
|
+
|
|
29
|
+
# VideoTimestamps
|
|
30
|
+
[](https://pypi.org/project/VideoTimestamps)
|
|
31
|
+
[](https://pypi.org/project/VideoTimestamps)
|
|
32
|
+
[](https://app.codecov.io/github/moi15moi/VideoTimestamps)
|
|
33
|
+
[](https://github.com/moi15moi/VideoTimestamps/actions?query=branch:main)
|
|
34
|
+
|
|
35
|
+
This tool allows to recover the timestamps of each frame in a video in milliseconds.
|
|
36
|
+
It also help to convert a frame to a time in milliseconds and vice-versa.
|
|
37
|
+
|
|
38
|
+
## Installation
|
|
39
|
+
```
|
|
40
|
+
pip install VideoTimestamps
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Dependencies
|
|
44
|
+
- [MKVToolNix v82.0 or more](https://mkvtoolnix.download/downloads.html)
|
|
45
|
+
- [ffprobe](https://ffmpeg.org/download.html)
|
|
46
|
+
|
|
47
|
+
## How to use it?
|
|
48
|
+
See the [example file](./examples/get_timestamps.py).
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# VideoTimestamps
|
|
2
|
+
[](https://pypi.org/project/VideoTimestamps)
|
|
3
|
+
[](https://pypi.org/project/VideoTimestamps)
|
|
4
|
+
[](https://app.codecov.io/github/moi15moi/VideoTimestamps)
|
|
5
|
+
[](https://github.com/moi15moi/VideoTimestamps/actions?query=branch:main)
|
|
6
|
+
|
|
7
|
+
This tool allows to recover the timestamps of each frame in a video in milliseconds.
|
|
8
|
+
It also help to convert a frame to a time in milliseconds and vice-versa.
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
```
|
|
12
|
+
pip install VideoTimestamps
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Dependencies
|
|
16
|
+
- [MKVToolNix v82.0 or more](https://mkvtoolnix.download/downloads.html)
|
|
17
|
+
- [ffprobe](https://ffmpeg.org/download.html)
|
|
18
|
+
|
|
19
|
+
## How to use it?
|
|
20
|
+
See the [example file](./examples/get_timestamps.py).
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: VideoTimestamps
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Get video timestamps.
|
|
5
|
+
Author-email: moi15moi <moi15moismokerlolilol@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Source, https://github.com/moi15moi/VideoTimestamps/
|
|
8
|
+
Project-URL: Tracker, https://github.com/moi15moi/VideoTimestamps/issues/
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Programming Language :: Python
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
19
|
+
Classifier: Typing :: Typed
|
|
20
|
+
Requires-Python: >=3.9
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: coverage>=7.0.0; extra == "dev"
|
|
25
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
26
|
+
Requires-Dist: pillow>=10.0.0; extra == "dev"
|
|
27
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
28
|
+
|
|
29
|
+
# VideoTimestamps
|
|
30
|
+
[](https://pypi.org/project/VideoTimestamps)
|
|
31
|
+
[](https://pypi.org/project/VideoTimestamps)
|
|
32
|
+
[](https://app.codecov.io/github/moi15moi/VideoTimestamps)
|
|
33
|
+
[](https://github.com/moi15moi/VideoTimestamps/actions?query=branch:main)
|
|
34
|
+
|
|
35
|
+
This tool allows to recover the timestamps of each frame in a video in milliseconds.
|
|
36
|
+
It also help to convert a frame to a time in milliseconds and vice-versa.
|
|
37
|
+
|
|
38
|
+
## Installation
|
|
39
|
+
```
|
|
40
|
+
pip install VideoTimestamps
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Dependencies
|
|
44
|
+
- [MKVToolNix v82.0 or more](https://mkvtoolnix.download/downloads.html)
|
|
45
|
+
- [ffprobe](https://ffmpeg.org/download.html)
|
|
46
|
+
|
|
47
|
+
## How to use it?
|
|
48
|
+
See the [example file](./examples/get_timestamps.py).
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
VideoTimestamps.egg-info/PKG-INFO
|
|
5
|
+
VideoTimestamps.egg-info/SOURCES.txt
|
|
6
|
+
VideoTimestamps.egg-info/dependency_links.txt
|
|
7
|
+
VideoTimestamps.egg-info/requires.txt
|
|
8
|
+
VideoTimestamps.egg-info/top_level.txt
|
|
9
|
+
tests/test_convert_time.py
|
|
10
|
+
tests/test_timestamps.py
|
|
11
|
+
video_timestamps/__init__.py
|
|
12
|
+
video_timestamps/_version.py
|
|
13
|
+
video_timestamps/abc_video_parser.py
|
|
14
|
+
video_timestamps/rounding_method.py
|
|
15
|
+
video_timestamps/time_type.py
|
|
16
|
+
video_timestamps/timestamps.py
|
|
17
|
+
video_timestamps/timestamps_factory.py
|
|
18
|
+
video_timestamps/timestamps_file_parser.py
|
|
19
|
+
video_timestamps/ffprobe/__init__.py
|
|
20
|
+
video_timestamps/ffprobe/ffprobe.py
|
|
21
|
+
video_timestamps/ffprobe/timestamps.py
|
|
22
|
+
video_timestamps/mkvtoolnix/__init__.py
|
|
23
|
+
video_timestamps/mkvtoolnix/exit_code.py
|
|
24
|
+
video_timestamps/mkvtoolnix/mkvextract.py
|
|
25
|
+
video_timestamps/mkvtoolnix/mkvmerge.py
|
|
26
|
+
video_timestamps/mkvtoolnix/timestamps.py
|
|
27
|
+
video_timestamps/mkvtoolnix/utils.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
video_timestamps
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "VideoTimestamps"
|
|
3
|
+
description = "Get video timestamps."
|
|
4
|
+
authors = [
|
|
5
|
+
{ name = "moi15moi", email = "moi15moismokerlolilol@gmail.com" },
|
|
6
|
+
]
|
|
7
|
+
license = { text = "MIT" }
|
|
8
|
+
readme = "README.md"
|
|
9
|
+
requires-python = ">=3.9"
|
|
10
|
+
classifiers=[
|
|
11
|
+
"Development Status :: 4 - Beta",
|
|
12
|
+
"Intended Audience :: Developers",
|
|
13
|
+
"Programming Language :: Python",
|
|
14
|
+
"Programming Language :: Python :: 3",
|
|
15
|
+
"Programming Language :: Python :: 3.8",
|
|
16
|
+
"Programming Language :: Python :: 3.9",
|
|
17
|
+
"Programming Language :: Python :: 3.10",
|
|
18
|
+
"Programming Language :: Python :: 3.11",
|
|
19
|
+
"Programming Language :: Python :: 3.12",
|
|
20
|
+
"License :: OSI Approved :: MIT License",
|
|
21
|
+
"Typing :: Typed",
|
|
22
|
+
]
|
|
23
|
+
dynamic = ["version"]
|
|
24
|
+
|
|
25
|
+
[project.urls]
|
|
26
|
+
Source = "https://github.com/moi15moi/VideoTimestamps/"
|
|
27
|
+
Tracker = "https://github.com/moi15moi/VideoTimestamps/issues/"
|
|
28
|
+
|
|
29
|
+
[project.optional-dependencies]
|
|
30
|
+
dev = [
|
|
31
|
+
"coverage>=7.0.0",
|
|
32
|
+
"mypy>=1.0.0",
|
|
33
|
+
"pillow>=10.0.0",
|
|
34
|
+
"pytest>=8.0.0",
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
[build-system]
|
|
38
|
+
requires = ["setuptools"]
|
|
39
|
+
build-backend = "setuptools.build_meta"
|
|
40
|
+
|
|
41
|
+
[tool.setuptools.dynamic]
|
|
42
|
+
version = { attr = "video_timestamps._version.__version__" }
|
|
43
|
+
|
|
44
|
+
[tool.setuptools.packages.find]
|
|
45
|
+
include = ["video_timestamps*"]
|
|
46
|
+
|
|
47
|
+
[tool.mypy]
|
|
48
|
+
exclude = "build"
|
|
49
|
+
files = ["."]
|
|
50
|
+
warn_unused_configs = true
|
|
51
|
+
strict = true
|
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from video_timestamps import RoundingMethod, TimestampsFactory, TimeType
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def test_frames_to_ms_vfr() -> None:
|
|
6
|
+
timestamps_str = (
|
|
7
|
+
"# timecode format v2\n"
|
|
8
|
+
"0\n"
|
|
9
|
+
"1000\n"
|
|
10
|
+
"1500\n"
|
|
11
|
+
"2000\n"
|
|
12
|
+
"2001\n"
|
|
13
|
+
"2002\n"
|
|
14
|
+
"2003\n"
|
|
15
|
+
)
|
|
16
|
+
timestamps = TimestampsFactory.from_timestamps_file(timestamps_str)
|
|
17
|
+
|
|
18
|
+
assert 0 == timestamps.frames_to_ms(0, TimeType.EXACT)
|
|
19
|
+
assert 1000 == timestamps.frames_to_ms(1, TimeType.EXACT)
|
|
20
|
+
assert 1500 == timestamps.frames_to_ms(2, TimeType.EXACT)
|
|
21
|
+
assert 2000 == timestamps.frames_to_ms(3, TimeType.EXACT)
|
|
22
|
+
assert 2001 == timestamps.frames_to_ms(4, TimeType.EXACT)
|
|
23
|
+
assert 2002 == timestamps.frames_to_ms(5, TimeType.EXACT)
|
|
24
|
+
assert 2003 == timestamps.frames_to_ms(6, TimeType.EXACT)
|
|
25
|
+
|
|
26
|
+
assert 0 == timestamps.frames_to_ms(0, TimeType.START)
|
|
27
|
+
assert 500 == timestamps.frames_to_ms(1, TimeType.START) # answer must be ]0, 1000]
|
|
28
|
+
assert 1250 == timestamps.frames_to_ms(2, TimeType.START) # answer must be ]1000, 1500]
|
|
29
|
+
assert 1750 == timestamps.frames_to_ms(3, TimeType.START) # answer must be ]1500, 2000]
|
|
30
|
+
assert 2001 == timestamps.frames_to_ms(4, TimeType.START) # answer must be ]2000, 2001]
|
|
31
|
+
assert 2002 == timestamps.frames_to_ms(5, TimeType.START) # answer must be ]2001, 2002]
|
|
32
|
+
assert 2003 == timestamps.frames_to_ms(6, TimeType.START) # answer must be ]2002, 2003]
|
|
33
|
+
|
|
34
|
+
assert 500 == timestamps.frames_to_ms(0, TimeType.END) # answer must be ]0, 1000]
|
|
35
|
+
assert 1250 == timestamps.frames_to_ms(1, TimeType.END) # answer must be ]1000, 1500]
|
|
36
|
+
assert 1750 == timestamps.frames_to_ms(2, TimeType.END) # answer must be ]1500, 2000]
|
|
37
|
+
assert 2001 == timestamps.frames_to_ms(3, TimeType.END) # answer must be ]2000, 2001]
|
|
38
|
+
assert 2002 == timestamps.frames_to_ms(4, TimeType.END) # answer must be ]2001, 2002]
|
|
39
|
+
assert 2003 == timestamps.frames_to_ms(5, TimeType.END) # answer must be ]2002, 2003]
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def test_frames_to_ms_invalid_frame() -> None:
|
|
43
|
+
timestamps_str = (
|
|
44
|
+
"# timecode format v2\n"
|
|
45
|
+
"0\n"
|
|
46
|
+
"1000\n"
|
|
47
|
+
"1500\n"
|
|
48
|
+
"2000\n"
|
|
49
|
+
"2001\n"
|
|
50
|
+
"2002\n"
|
|
51
|
+
"2003\n"
|
|
52
|
+
)
|
|
53
|
+
timestamps = TimestampsFactory.from_timestamps_file(timestamps_str)
|
|
54
|
+
|
|
55
|
+
with pytest.raises(ValueError) as exc_info:
|
|
56
|
+
timestamps.frames_to_ms(-1, TimeType.EXACT)
|
|
57
|
+
assert str(exc_info.value) == "You cannot specify a frame under 0."
|
|
58
|
+
|
|
59
|
+
with pytest.raises(ValueError) as exc_info:
|
|
60
|
+
timestamps.frames_to_ms(-1, TimeType.START)
|
|
61
|
+
assert str(exc_info.value) == "You cannot specify a frame under 0."
|
|
62
|
+
|
|
63
|
+
with pytest.raises(ValueError) as exc_info:
|
|
64
|
+
timestamps.frames_to_ms(-1, TimeType.END)
|
|
65
|
+
assert str(exc_info.value) == "You cannot specify a frame under 0."
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def test_frames_to_ms_approximate() -> None:
|
|
69
|
+
timestamps_str = (
|
|
70
|
+
"# timecode format v2\n"
|
|
71
|
+
"0\n"
|
|
72
|
+
"1000\n"
|
|
73
|
+
"1500\n"
|
|
74
|
+
"2000\n"
|
|
75
|
+
"2001\n"
|
|
76
|
+
"2002\n"
|
|
77
|
+
"2003\n"
|
|
78
|
+
)
|
|
79
|
+
timestamps = TimestampsFactory.from_timestamps_file(timestamps_str)
|
|
80
|
+
|
|
81
|
+
# fpms = 6/2003
|
|
82
|
+
# round(1/fpms * 7) = round(2336.83) = 2337
|
|
83
|
+
assert 2337 == timestamps.frames_to_ms(7, TimeType.EXACT)
|
|
84
|
+
|
|
85
|
+
# 2003 + (2337 - 2003) // 2 = 2170
|
|
86
|
+
assert 2170 == timestamps.frames_to_ms(7, TimeType.START)
|
|
87
|
+
|
|
88
|
+
# fpms = 6/2003
|
|
89
|
+
# round(1/fpms * 8) = round(2670.67) = 2671
|
|
90
|
+
# 2337 + (2671 - 2337) // 2 = 2504
|
|
91
|
+
assert 2504 == timestamps.frames_to_ms(7, TimeType.END)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def test_frames_to_ms_round() -> None:
|
|
95
|
+
timestamps_str = "# timecode format v1\n" "Assume 30\n" "5,10,15\n"
|
|
96
|
+
|
|
97
|
+
timestamps = TimestampsFactory.from_timestamps_file(timestamps_str)
|
|
98
|
+
|
|
99
|
+
# Frame 0 to 5 - 30 fps
|
|
100
|
+
assert 0 == timestamps.frames_to_ms(0, TimeType.EXACT)
|
|
101
|
+
assert 33 == timestamps.frames_to_ms(1, TimeType.EXACT)
|
|
102
|
+
assert 67 == timestamps.frames_to_ms(2, TimeType.EXACT)
|
|
103
|
+
assert 100 == timestamps.frames_to_ms(3, TimeType.EXACT)
|
|
104
|
+
assert 133 == timestamps.frames_to_ms(4, TimeType.EXACT)
|
|
105
|
+
assert 167 == timestamps.frames_to_ms(5, TimeType.EXACT)
|
|
106
|
+
# Frame 6 to 11 - 15 fps
|
|
107
|
+
assert 233 == timestamps.frames_to_ms(6, TimeType.EXACT)
|
|
108
|
+
assert 300 == timestamps.frames_to_ms(7, TimeType.EXACT)
|
|
109
|
+
assert 367 == timestamps.frames_to_ms(8, TimeType.EXACT)
|
|
110
|
+
assert 433 == timestamps.frames_to_ms(9, TimeType.EXACT)
|
|
111
|
+
assert 500 == timestamps.frames_to_ms(10, TimeType.EXACT)
|
|
112
|
+
assert 567 == timestamps.frames_to_ms(11, TimeType.EXACT)
|
|
113
|
+
# From here, we guess the ms from the last frame timestamps and fps
|
|
114
|
+
# The last frame is equal to (5 * 1/30 * 1000 + 6 * 1/15 * 1000) = 1700/3 = 566.666
|
|
115
|
+
assert 600 == timestamps.frames_to_ms(12, TimeType.EXACT) # 1700/3 + 1/30 * 1000 = 600
|
|
116
|
+
assert 633 == timestamps.frames_to_ms(13, TimeType.EXACT) # 1700/3 + 2/30 * 1000 = round(633.33) = 633
|
|
117
|
+
assert 667 == timestamps.frames_to_ms(14, TimeType.EXACT) # 1700/3 + 3/30 * 1000 = round(666.66) = 667
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def test_frames_to_ms_floor() -> None:
|
|
121
|
+
timestamps_str = "# timecode format v1\n" "Assume 30\n" "5,10,15\n"
|
|
122
|
+
|
|
123
|
+
timestamps = TimestampsFactory.from_timestamps_file(
|
|
124
|
+
timestamps_str, rounding_method=RoundingMethod.FLOOR
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
# Frame 0 to 5 - 30 fps
|
|
128
|
+
assert 0 == timestamps.frames_to_ms(0, TimeType.EXACT)
|
|
129
|
+
assert 33 == timestamps.frames_to_ms(1, TimeType.EXACT)
|
|
130
|
+
assert 66 == timestamps.frames_to_ms(2, TimeType.EXACT)
|
|
131
|
+
assert 100 == timestamps.frames_to_ms(3, TimeType.EXACT)
|
|
132
|
+
assert 133 == timestamps.frames_to_ms(4, TimeType.EXACT)
|
|
133
|
+
assert 166 == timestamps.frames_to_ms(5, TimeType.EXACT)
|
|
134
|
+
# Frame 6 to 11 - 15 fps
|
|
135
|
+
assert 233 == timestamps.frames_to_ms(6, TimeType.EXACT)
|
|
136
|
+
assert 300 == timestamps.frames_to_ms(7, TimeType.EXACT)
|
|
137
|
+
assert 366 == timestamps.frames_to_ms(8, TimeType.EXACT)
|
|
138
|
+
assert 433 == timestamps.frames_to_ms(9, TimeType.EXACT)
|
|
139
|
+
assert 500 == timestamps.frames_to_ms(10, TimeType.EXACT)
|
|
140
|
+
assert 566 == timestamps.frames_to_ms(11, TimeType.EXACT)
|
|
141
|
+
# From here, we guess the ms from the last frame timestamps and fps
|
|
142
|
+
# The last frame is equal to (5 * 1/30 * 1000 + 6 * 1/15 * 1000) = 1700/3 = 566.666
|
|
143
|
+
assert 600 == timestamps.frames_to_ms(12, TimeType.EXACT) # 1700/3 + 1/30 * 1000 = 600
|
|
144
|
+
assert 633 == timestamps.frames_to_ms(13, TimeType.EXACT) # 1700/3 + 2/30 * 1000 = floor(633.33) = 633
|
|
145
|
+
assert 666 == timestamps.frames_to_ms(14, TimeType.EXACT) # 1700/3 + 3/30 * 1000 = floor(666.66) = 666
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def test_ms_to_frames_vfr() -> None:
|
|
149
|
+
timestamps_str = (
|
|
150
|
+
"# timecode format v2\n"
|
|
151
|
+
"0\n"
|
|
152
|
+
"1000\n"
|
|
153
|
+
"1500\n"
|
|
154
|
+
"2000\n"
|
|
155
|
+
"2001\n"
|
|
156
|
+
"2002\n"
|
|
157
|
+
"2003\n"
|
|
158
|
+
)
|
|
159
|
+
timestamps = TimestampsFactory.from_timestamps_file(timestamps_str)
|
|
160
|
+
|
|
161
|
+
assert 0 == timestamps.ms_to_frames(0, TimeType.EXACT)
|
|
162
|
+
assert 0 == timestamps.ms_to_frames(999, TimeType.EXACT)
|
|
163
|
+
assert 1 == timestamps.ms_to_frames(1000, TimeType.EXACT)
|
|
164
|
+
assert 1 == timestamps.ms_to_frames(1499, TimeType.EXACT)
|
|
165
|
+
assert 2 == timestamps.ms_to_frames(1500, TimeType.EXACT)
|
|
166
|
+
assert 2 == timestamps.ms_to_frames(1999, TimeType.EXACT)
|
|
167
|
+
assert 3 == timestamps.ms_to_frames(2000, TimeType.EXACT)
|
|
168
|
+
assert 4 == timestamps.ms_to_frames(2001, TimeType.EXACT)
|
|
169
|
+
assert 5 == timestamps.ms_to_frames(2002, TimeType.EXACT)
|
|
170
|
+
assert 6 == timestamps.ms_to_frames(2003, TimeType.EXACT)
|
|
171
|
+
assert 6 == timestamps.ms_to_frames(2004, TimeType.EXACT)
|
|
172
|
+
|
|
173
|
+
assert 0 == timestamps.ms_to_frames(0, TimeType.START)
|
|
174
|
+
assert 1 == timestamps.ms_to_frames(1, TimeType.START)
|
|
175
|
+
assert 1 == timestamps.ms_to_frames(1000, TimeType.START)
|
|
176
|
+
assert 2 == timestamps.ms_to_frames(1001, TimeType.START)
|
|
177
|
+
assert 2 == timestamps.ms_to_frames(1500, TimeType.START)
|
|
178
|
+
assert 3 == timestamps.ms_to_frames(1501, TimeType.START)
|
|
179
|
+
assert 3 == timestamps.ms_to_frames(2000, TimeType.START)
|
|
180
|
+
assert 4 == timestamps.ms_to_frames(2001, TimeType.START)
|
|
181
|
+
assert 5 == timestamps.ms_to_frames(2002, TimeType.START)
|
|
182
|
+
assert 6 == timestamps.ms_to_frames(2003, TimeType.START)
|
|
183
|
+
assert 7 == timestamps.ms_to_frames(2004, TimeType.START)
|
|
184
|
+
|
|
185
|
+
with pytest.raises(ValueError) as exc_info:
|
|
186
|
+
timestamps.ms_to_frames(0, TimeType.END)
|
|
187
|
+
assert str(exc_info.value) == "You cannot specify a time equals to the first timestamps 0 with the TimeType.END."
|
|
188
|
+
assert 0 == timestamps.ms_to_frames(1, TimeType.END)
|
|
189
|
+
assert 1 == timestamps.ms_to_frames(1500, TimeType.END)
|
|
190
|
+
assert 2 == timestamps.ms_to_frames(1501, TimeType.END)
|
|
191
|
+
assert 2 == timestamps.ms_to_frames(2000, TimeType.END)
|
|
192
|
+
assert 3 == timestamps.ms_to_frames(2001, TimeType.END)
|
|
193
|
+
assert 4 == timestamps.ms_to_frames(2002, TimeType.END)
|
|
194
|
+
assert 5 == timestamps.ms_to_frames(2003, TimeType.END)
|
|
195
|
+
assert 6 == timestamps.ms_to_frames(2004, TimeType.END)
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def test_ms_to_frames_invalid_frame() -> None:
|
|
199
|
+
timestamps_str = (
|
|
200
|
+
"# timecode format v2\n"
|
|
201
|
+
"0\n"
|
|
202
|
+
"1000\n"
|
|
203
|
+
"1500\n"
|
|
204
|
+
"2000\n"
|
|
205
|
+
"2001\n"
|
|
206
|
+
"2002\n"
|
|
207
|
+
"2003\n"
|
|
208
|
+
)
|
|
209
|
+
timestamps = TimestampsFactory.from_timestamps_file(timestamps_str)
|
|
210
|
+
|
|
211
|
+
with pytest.raises(ValueError) as exc_info:
|
|
212
|
+
timestamps.ms_to_frames(-1, TimeType.EXACT)
|
|
213
|
+
assert str(exc_info.value) == "You cannot specify a time under the first timestamps: 0."
|
|
214
|
+
|
|
215
|
+
with pytest.raises(ValueError) as exc_info:
|
|
216
|
+
timestamps.ms_to_frames(-1, TimeType.START)
|
|
217
|
+
assert str(exc_info.value) == "You cannot specify a time under the first timestamps: 0."
|
|
218
|
+
|
|
219
|
+
with pytest.raises(ValueError) as exc_info:
|
|
220
|
+
timestamps.ms_to_frames(-1, TimeType.END)
|
|
221
|
+
assert str(exc_info.value) == "You cannot specify a time under the first timestamps: 0."
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def test_ms_to_frames_approximate() -> None:
|
|
225
|
+
timestamps_str = (
|
|
226
|
+
"# timecode format v2\n"
|
|
227
|
+
"0\n"
|
|
228
|
+
"1000\n"
|
|
229
|
+
"1500\n"
|
|
230
|
+
"2000\n"
|
|
231
|
+
"2001\n"
|
|
232
|
+
"2002\n"
|
|
233
|
+
"2003\n"
|
|
234
|
+
)
|
|
235
|
+
timestamps = TimestampsFactory.from_timestamps_file(timestamps_str)
|
|
236
|
+
|
|
237
|
+
# fpms = 6/2003
|
|
238
|
+
# round(1/fpms * 7) = round(2336.83) = 2337
|
|
239
|
+
assert 6 == timestamps.ms_to_frames(2336, TimeType.EXACT)
|
|
240
|
+
assert 7 == timestamps.ms_to_frames(2337, TimeType.EXACT)
|
|
241
|
+
|
|
242
|
+
# 2003 + (2337 - 2003) // 2 = 2170
|
|
243
|
+
assert 7 == timestamps.ms_to_frames(2170, TimeType.START)
|
|
244
|
+
|
|
245
|
+
# fpms = 6/2003
|
|
246
|
+
# round(1/fpms * 8) = round(2670.67) = 2671
|
|
247
|
+
# 2337 + (2671 - 2337) // 2 = 2504
|
|
248
|
+
assert 7 == timestamps.ms_to_frames(2504, TimeType.END)
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def test_ms_to_frames_round() -> None:
|
|
252
|
+
timestamps_str = "# timecode format v1\n" "Assume 30\n" "5,10,15\n"
|
|
253
|
+
|
|
254
|
+
timestamps = TimestampsFactory.from_timestamps_file(timestamps_str)
|
|
255
|
+
|
|
256
|
+
# Frame 0 to 5 - 30 fps
|
|
257
|
+
assert 0 == timestamps.ms_to_frames(0, TimeType.EXACT)
|
|
258
|
+
assert 0 == timestamps.ms_to_frames(32, TimeType.EXACT)
|
|
259
|
+
assert 1 == timestamps.ms_to_frames(33, TimeType.EXACT)
|
|
260
|
+
assert 1 == timestamps.ms_to_frames(66, TimeType.EXACT)
|
|
261
|
+
assert 2 == timestamps.ms_to_frames(67, TimeType.EXACT)
|
|
262
|
+
assert 2 == timestamps.ms_to_frames(99, TimeType.EXACT)
|
|
263
|
+
assert 3 == timestamps.ms_to_frames(100, TimeType.EXACT)
|
|
264
|
+
assert 3 == timestamps.ms_to_frames(132, TimeType.EXACT)
|
|
265
|
+
assert 4 == timestamps.ms_to_frames(133, TimeType.EXACT)
|
|
266
|
+
assert 4 == timestamps.ms_to_frames(166, TimeType.EXACT)
|
|
267
|
+
assert 5 == timestamps.ms_to_frames(167, TimeType.EXACT)
|
|
268
|
+
assert 5 == timestamps.ms_to_frames(232, TimeType.EXACT)
|
|
269
|
+
# Frame 6 to 11 - 15 fps
|
|
270
|
+
assert 6 == timestamps.ms_to_frames(233, TimeType.EXACT)
|
|
271
|
+
assert 6 == timestamps.ms_to_frames(299, TimeType.EXACT)
|
|
272
|
+
assert 7 == timestamps.ms_to_frames(300, TimeType.EXACT)
|
|
273
|
+
assert 7 == timestamps.ms_to_frames(366, TimeType.EXACT)
|
|
274
|
+
assert 8 == timestamps.ms_to_frames(367, TimeType.EXACT)
|
|
275
|
+
assert 8 == timestamps.ms_to_frames(432, TimeType.EXACT)
|
|
276
|
+
assert 9 == timestamps.ms_to_frames(433, TimeType.EXACT)
|
|
277
|
+
assert 9 == timestamps.ms_to_frames(499, TimeType.EXACT)
|
|
278
|
+
assert 10 == timestamps.ms_to_frames(500, TimeType.EXACT)
|
|
279
|
+
assert 10 == timestamps.ms_to_frames(566, TimeType.EXACT)
|
|
280
|
+
assert 11 == timestamps.ms_to_frames(567, TimeType.EXACT)
|
|
281
|
+
# From here, we guess the ms from the last frame timestamps and fps
|
|
282
|
+
# The last frame is equal to (5 * 1/30 * 1000 + 6 * 1/15 * 1000) = 1700/3 = 566.666
|
|
283
|
+
assert 11 == timestamps.ms_to_frames(599, TimeType.EXACT)
|
|
284
|
+
assert 12 == timestamps.ms_to_frames(600, TimeType.EXACT) # 1700/3 + 1/30 * 1000 = 600
|
|
285
|
+
assert 12 == timestamps.ms_to_frames(632, TimeType.EXACT)
|
|
286
|
+
assert 13 == timestamps.ms_to_frames(633, TimeType.EXACT) # 1700/3 + 2/30 * 1000 = round(633.33) = 633
|
|
287
|
+
assert 13 == timestamps.ms_to_frames(666, TimeType.EXACT)
|
|
288
|
+
assert 14 == timestamps.ms_to_frames(667, TimeType.EXACT) # 1700/3 + 3/30 * 1000 = round(666.66) = 667
|
|
289
|
+
|
|
290
|
+
# 16 fps is a "special" fps, because the frame 2 has a exact value
|
|
291
|
+
# - Frame 0: 0 ms
|
|
292
|
+
# - Frame 1: 62.5 ms
|
|
293
|
+
# - Frame 2: 125 ms
|
|
294
|
+
# - Frame 3: 187.5 ms
|
|
295
|
+
timestamps = TimestampsFactory.from_fps(16)
|
|
296
|
+
assert 0 == timestamps.ms_to_frames(62, TimeType.EXACT)
|
|
297
|
+
assert 1 == timestamps.ms_to_frames(63, TimeType.EXACT)
|
|
298
|
+
assert 1 == timestamps.ms_to_frames(124, TimeType.EXACT)
|
|
299
|
+
assert 2 == timestamps.ms_to_frames(125, TimeType.EXACT)
|
|
300
|
+
assert 2 == timestamps.ms_to_frames(187, TimeType.EXACT)
|
|
301
|
+
assert 3 == timestamps.ms_to_frames(188, TimeType.EXACT)
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
def test_ms_to_frames_floor() -> None:
|
|
305
|
+
timestamps_str = "# timecode format v1\n" "Assume 30\n" "5,10,15\n"
|
|
306
|
+
|
|
307
|
+
timestamps = TimestampsFactory.from_timestamps_file(
|
|
308
|
+
timestamps_str, rounding_method=RoundingMethod.FLOOR
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
# Frame 0 to 5 - 30 fps
|
|
312
|
+
assert 0 == timestamps.ms_to_frames(0, TimeType.EXACT)
|
|
313
|
+
assert 0 == timestamps.ms_to_frames(32, TimeType.EXACT)
|
|
314
|
+
assert 1 == timestamps.ms_to_frames(33, TimeType.EXACT)
|
|
315
|
+
assert 1 == timestamps.ms_to_frames(65, TimeType.EXACT)
|
|
316
|
+
assert 2 == timestamps.ms_to_frames(66, TimeType.EXACT)
|
|
317
|
+
assert 2 == timestamps.ms_to_frames(99, TimeType.EXACT)
|
|
318
|
+
assert 3 == timestamps.ms_to_frames(100, TimeType.EXACT)
|
|
319
|
+
assert 3 == timestamps.ms_to_frames(132, TimeType.EXACT)
|
|
320
|
+
assert 4 == timestamps.ms_to_frames(133, TimeType.EXACT)
|
|
321
|
+
assert 4 == timestamps.ms_to_frames(165, TimeType.EXACT)
|
|
322
|
+
assert 5 == timestamps.ms_to_frames(166, TimeType.EXACT)
|
|
323
|
+
assert 5 == timestamps.ms_to_frames(232, TimeType.EXACT)
|
|
324
|
+
# Frame 6 to 11 - 15 fps
|
|
325
|
+
assert 6 == timestamps.ms_to_frames(233, TimeType.EXACT)
|
|
326
|
+
assert 6 == timestamps.ms_to_frames(299, TimeType.EXACT)
|
|
327
|
+
assert 7 == timestamps.ms_to_frames(300, TimeType.EXACT)
|
|
328
|
+
assert 7 == timestamps.ms_to_frames(365, TimeType.EXACT)
|
|
329
|
+
assert 8 == timestamps.ms_to_frames(366, TimeType.EXACT)
|
|
330
|
+
assert 8 == timestamps.ms_to_frames(432, TimeType.EXACT)
|
|
331
|
+
assert 9 == timestamps.ms_to_frames(433, TimeType.EXACT)
|
|
332
|
+
assert 9 == timestamps.ms_to_frames(499, TimeType.EXACT)
|
|
333
|
+
assert 10 == timestamps.ms_to_frames(500, TimeType.EXACT)
|
|
334
|
+
assert 10 == timestamps.ms_to_frames(565, TimeType.EXACT)
|
|
335
|
+
assert 11 == timestamps.ms_to_frames(566, TimeType.EXACT)
|
|
336
|
+
# From here, we guess the ms from the last frame timestamps and fps
|
|
337
|
+
# The last frame is equal to (5 * 1/30 * 1000 + 6 * 1/15 * 1000) = 1700/3 = 566.666
|
|
338
|
+
assert 11 == timestamps.ms_to_frames(599, TimeType.EXACT)
|
|
339
|
+
assert 12 == timestamps.ms_to_frames(600, TimeType.EXACT) # 1700/3 + 1/30 * 1000 = 600
|
|
340
|
+
assert 12 == timestamps.ms_to_frames(632, TimeType.EXACT)
|
|
341
|
+
assert 13 == timestamps.ms_to_frames(633, TimeType.EXACT) # 1700/3 + 2/30 * 1000 = floor(633.33) = 633
|
|
342
|
+
assert 13 == timestamps.ms_to_frames(665, TimeType.EXACT)
|
|
343
|
+
assert 14 == timestamps.ms_to_frames(666, TimeType.EXACT) # 1700/3 + 3/30 * 1000 = floor(666.66) = 666
|
|
344
|
+
|
|
345
|
+
# 15 fps is a "special" fps, because the frame 3 has a exact value
|
|
346
|
+
# - Frame 0: 0 ms
|
|
347
|
+
# - Frame 1: ~66.66 ms
|
|
348
|
+
# - Frame 2: ~133.33 ms
|
|
349
|
+
# - Frame 3: 200 ms
|
|
350
|
+
timestamps = TimestampsFactory.from_fps(15, rounding_method=RoundingMethod.FLOOR)
|
|
351
|
+
assert 0 == timestamps.ms_to_frames(65, TimeType.EXACT)
|
|
352
|
+
assert 1 == timestamps.ms_to_frames(66, TimeType.EXACT)
|
|
353
|
+
assert 1 == timestamps.ms_to_frames(132, TimeType.EXACT)
|
|
354
|
+
assert 2 == timestamps.ms_to_frames(133, TimeType.EXACT)
|
|
355
|
+
assert 2 == timestamps.ms_to_frames(199, TimeType.EXACT)
|
|
356
|
+
assert 3 == timestamps.ms_to_frames(200, TimeType.EXACT)
|