FirstFrame 1.0.5__tar.gz → 1.0.6__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.
- {firstframe-1.0.5 → firstframe-1.0.6}/PKG-INFO +1 -1
- {firstframe-1.0.5 → firstframe-1.0.6}/pyproject.toml +1 -1
- firstframe-1.0.6/src/FirstFrame/__init__.py +4 -0
- {firstframe-1.0.5 → firstframe-1.0.6}/src/FirstFrame/cli.py +15 -40
- {firstframe-1.0.5 → firstframe-1.0.6}/src/FirstFrame.egg-info/PKG-INFO +1 -1
- firstframe-1.0.5/src/FirstFrame/__init__.py +0 -4
- {firstframe-1.0.5 → firstframe-1.0.6}/README.md +0 -0
- {firstframe-1.0.5 → firstframe-1.0.6}/setup.cfg +0 -0
- {firstframe-1.0.5 → firstframe-1.0.6}/src/FirstFrame/__main__.py +0 -0
- {firstframe-1.0.5 → firstframe-1.0.6}/src/FirstFrame.egg-info/SOURCES.txt +0 -0
- {firstframe-1.0.5 → firstframe-1.0.6}/src/FirstFrame.egg-info/dependency_links.txt +0 -0
- {firstframe-1.0.5 → firstframe-1.0.6}/src/FirstFrame.egg-info/entry_points.txt +0 -0
- {firstframe-1.0.5 → firstframe-1.0.6}/src/FirstFrame.egg-info/requires.txt +0 -0
- {firstframe-1.0.5 → firstframe-1.0.6}/src/FirstFrame.egg-info/top_level.txt +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "FirstFrame"
|
|
7
|
-
version = "1.0.
|
|
7
|
+
version = "1.0.6"
|
|
8
8
|
description = "FirstFrame is a simple command-line tool for extracting the first frame from MP4 video files using OpenCV (cv2)"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
|
@@ -1,54 +1,30 @@
|
|
|
1
1
|
#!/usr/bin/env python
|
|
2
2
|
from __future__ import print_function, unicode_literals
|
|
3
3
|
|
|
4
|
-
from ChronicleLogger import ChronicleLogger
|
|
5
4
|
import sys
|
|
6
5
|
import cv2
|
|
7
6
|
import os
|
|
8
7
|
import glob
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
|
|
10
|
+
def get_first_frame(video_path, output_path):
|
|
11
|
+
"""Extract the first frame from video and save it."""
|
|
12
12
|
cap = cv2.VideoCapture(video_path)
|
|
13
13
|
if not cap.isOpened():
|
|
14
14
|
print("Error: Cannot open video file.")
|
|
15
15
|
return False
|
|
16
16
|
|
|
17
|
-
#
|
|
18
|
-
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
|
|
19
|
-
if total_frames > 1:
|
|
20
|
-
cap.set(cv2.CAP_PROP_POS_FRAMES, total_frames - 1)
|
|
21
|
-
ret, frame = cap.read()
|
|
22
|
-
if ret:
|
|
23
|
-
cv2.imwrite(output_path, frame)
|
|
24
|
-
cap.release()
|
|
25
|
-
print(f"Success: Last frame saved as '{output_path}'")
|
|
26
|
-
return True
|
|
27
|
-
|
|
28
|
-
# Method 2: Fallback - seek to 99% of video
|
|
29
|
-
cap.set(cv2.CAP_PROP_POS_AVI_RATIO, 0.99)
|
|
17
|
+
# Just read the first available frame
|
|
30
18
|
ret, frame = cap.read()
|
|
31
|
-
if ret:
|
|
32
|
-
|
|
19
|
+
if not ret:
|
|
20
|
+
print("Error: Could not read the first frame.")
|
|
33
21
|
cap.release()
|
|
34
|
-
|
|
35
|
-
return True
|
|
36
|
-
|
|
37
|
-
# Method 3: Use millisecond seek
|
|
38
|
-
fps = cap.get(cv2.CAP_PROP_FPS)
|
|
39
|
-
if fps > 0:
|
|
40
|
-
duration_ms = (total_frames / fps) * 1000
|
|
41
|
-
cap.set(cv2.CAP_PROP_POS_MSEC, duration_ms - 100) # 0.1s before end
|
|
42
|
-
ret, frame = cap.read()
|
|
43
|
-
if ret:
|
|
44
|
-
cv2.imwrite(output_path, frame)
|
|
45
|
-
cap.release()
|
|
46
|
-
print(f"Success: Last frame saved as '{output_path}' (millisecond seek)")
|
|
47
|
-
return True
|
|
22
|
+
return False
|
|
48
23
|
|
|
24
|
+
cv2.imwrite(output_path, frame)
|
|
49
25
|
cap.release()
|
|
50
|
-
print("
|
|
51
|
-
return
|
|
26
|
+
print(f"Success: First frame saved as '{output_path}'")
|
|
27
|
+
return True
|
|
52
28
|
|
|
53
29
|
|
|
54
30
|
def main():
|
|
@@ -84,9 +60,9 @@ def main():
|
|
|
84
60
|
except ValueError:
|
|
85
61
|
print("Invalid input. Please type a number.")
|
|
86
62
|
|
|
87
|
-
# Suggest default output: either output.png or
|
|
63
|
+
# Suggest default output: either output.png or video_name_first.png
|
|
88
64
|
base_name = os.path.splitext(selected_video)[0]
|
|
89
|
-
default_output = "output.png" if os.path.exists("output.png")
|
|
65
|
+
default_output = "output.png" if not os.path.exists("output.png") else f"{base_name}_first.png"
|
|
90
66
|
|
|
91
67
|
print(f"\nSelected: {selected_video}")
|
|
92
68
|
|
|
@@ -101,13 +77,12 @@ def main():
|
|
|
101
77
|
else:
|
|
102
78
|
output_path = user_output
|
|
103
79
|
|
|
104
|
-
print(f"\nExtracting
|
|
105
|
-
|
|
80
|
+
print(f"\nExtracting first frame from '{selected_video}'...")
|
|
81
|
+
get_first_frame(selected_video, output_path)
|
|
106
82
|
|
|
107
83
|
print(f"\nDone! Image saved as: {output_path}")
|
|
108
84
|
input("\nPress Enter to exit...")
|
|
109
85
|
|
|
110
86
|
|
|
111
87
|
if __name__ == "__main__":
|
|
112
|
-
main()
|
|
113
|
-
|
|
88
|
+
main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|