@@ -24,7 +24,7 @@ class VideoStreamMetadata:
24
24
"""Metadata of a single video stream."""
25
25
26
26
duration_seconds_from_header : Optional [float ]
27
- """Duration of the stream, in seconds obtained from the header (float or
27
+ """Duration of the stream, in seconds, obtained from the header (float or
28
28
None). This could be inaccurate."""
29
29
bit_rate : Optional [float ]
30
30
"""Bit rate of the stream, in seconds (float or None)."""
@@ -37,36 +37,38 @@ class VideoStreamMetadata:
37
37
content (the scan doesn't involve decoding). This is more accurate
38
38
than ``num_frames_from_header``. We recommend using the
39
39
``num_frames`` attribute instead. (int or None)."""
40
- begin_stream_from_content_seconds : Optional [float ]
41
- """Beginning of the stream in seconds (float or None).
42
- This is min(frame.pts) for all frames in this stream."""
43
- end_stream_from_content_seconds : Optional [float ]
44
- """End of the stream in seconds (float or None).
45
- This is max(frame.pts + frame.duration) for all frames in this stream.
46
- Note that frames have a pts and duration and the interval defined by
47
- [pts, pts + duration) is a half-open interval (the right boundary is open).
48
- Therefore no frame is displayed at this time value.
49
- Calling
50
- SimpleVideoDecoder.get_frame_displayed_at(end_stream_from_content_seconds)
51
- will raise a StopIteration exception.
52
- If you want to get the last frame you can use [-1] on a SimpleVideoDecoder
53
- object."""
40
+ begin_stream_seconds : Optional [float ]
41
+ """Beginning of the stream, in seconds (float or None).
42
+ Conceptually, this corresponds to the first frame's :term:`pts`. It is
43
+ computed as min(frame.pts) across all frames in the stream. Usually, this is
44
+ equal to 0."""
45
+ end_stream_seconds : Optional [float ]
46
+ """End of the stream, in seconds (float or None).
47
+ Conceptually, this corresponds to last_frame.pts + last_frame.duration. It
48
+ is computed as max(frame.pts + frame.duration) across all frames in the
49
+ stream. Note that no frame is displayed at this time value, so calling
50
+ :meth:`~torchcodec.decoders.SimpleVideoDecoder.get_frame_displayed_at` with
51
+ this value would result in an error. Retrieving the last frame is best done
52
+ by simply indexing the :class:`~torchcodec.decoders.SimpleVideoDecoder`
53
+ object with ``[-1]``.
54
+ """
54
55
codec : Optional [str ]
55
56
"""Codec (str or None)."""
56
57
width : Optional [int ]
57
58
"""Width of the frames (int or None)."""
58
59
height : Optional [int ]
59
60
"""Height of the frames (int or None)."""
60
61
average_fps_from_header : Optional [float ]
61
- """Averate fps of the stream (float or None)."""
62
+ """Averate fps of the stream, obtained from the header (float or None).
63
+ We recommend using the ``average_fps`` attribute instead."""
62
64
stream_index : int
63
65
"""Index of the stream within the video (int)."""
64
66
65
67
@property
66
68
def num_frames (self ) -> Optional [int ]:
67
69
"""Number of frames in the stream. This corresponds to
68
- ``num_frames_from_content`` if it's not None , otherwise it corresponds
69
- to ``num_frames_from_header``.
70
+ ``num_frames_from_content`` if a :term:`scan` was made , otherwise it
71
+ corresponds to ``num_frames_from_header``.
70
72
"""
71
73
if self .num_frames_from_content is not None :
72
74
return self .num_frames_from_content
@@ -76,35 +78,26 @@ def num_frames(self) -> Optional[int]:
76
78
@property
77
79
def duration_seconds (self ) -> Optional [float ]:
78
80
"""Duration of the stream in seconds. We try to calculate the duration
79
- from the actual frames if we scanned the frames . Otherwise we fall back
80
- to the duration obtained from the header .
81
+ from the actual frames if a :term:`scan` was performed . Otherwise we
82
+ fall back to ``duration_seconds_from_header`` .
81
83
"""
82
- if (
83
- self .end_stream_from_content_seconds is None
84
- or self .begin_stream_from_content_seconds is None
85
- ):
84
+ if self .end_stream_seconds is None or self .begin_stream_seconds is None :
86
85
return self .duration_seconds_from_header
87
- return (
88
- self .end_stream_from_content_seconds
89
- - self .begin_stream_from_content_seconds
90
- )
86
+ return self .end_stream_seconds - self .begin_stream_seconds
91
87
92
88
@property
93
89
def average_fps (self ) -> Optional [float ]:
94
- """Average fps of the stream. We try to get the average fps from the
95
- actual frames if we scanned the frames. Otherwise we fall back to the
96
- fps obtained from the header .
90
+ """Average fps of the stream. If a :term:`scan` was perfomed, this is
91
+ computed from the number of frames and the duration of the stream.
92
+ Otherwise we fall back to ``average_fps_from_header`` .
97
93
"""
98
94
if (
99
- self .end_stream_from_content_seconds is None
100
- or self .begin_stream_from_content_seconds is None
95
+ self .end_stream_seconds is None
96
+ or self .begin_stream_seconds is None
101
97
or self .num_frames is None
102
98
):
103
99
return self .average_fps_from_header
104
- return self .num_frames / (
105
- self .end_stream_from_content_seconds
106
- - self .begin_stream_from_content_seconds
107
- )
100
+ return self .num_frames / (self .end_stream_seconds - self .begin_stream_seconds )
108
101
109
102
def __repr__ (self ):
110
103
# Overridden because properites are not printed by default.
@@ -159,12 +152,8 @@ def get_video_metadata(decoder: torch.Tensor) -> VideoMetadata:
159
152
bit_rate = stream_dict .get ("bitRate" ),
160
153
num_frames_from_header = stream_dict .get ("numFrames" ),
161
154
num_frames_from_content = stream_dict .get ("numFramesFromScan" ),
162
- begin_stream_from_content_seconds = stream_dict .get (
163
- "minPtsSecondsFromScan"
164
- ),
165
- end_stream_from_content_seconds = stream_dict .get (
166
- "maxPtsSecondsFromScan"
167
- ),
155
+ begin_stream_seconds = stream_dict .get ("minPtsSecondsFromScan" ),
156
+ end_stream_seconds = stream_dict .get ("maxPtsSecondsFromScan" ),
168
157
codec = stream_dict .get ("codec" ),
169
158
width = stream_dict .get ("width" ),
170
159
height = stream_dict .get ("height" ),
0 commit comments