nvidia-codec 0.0.22__tar.gz → 0.0.23__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.
Files changed (36) hide show
  1. {nvidia_codec-0.0.22/src/nvidia_codec.egg-info → nvidia_codec-0.0.23}/PKG-INFO +19 -2
  2. {nvidia_codec-0.0.22 → nvidia_codec-0.0.23}/README.md +18 -1
  3. {nvidia_codec-0.0.22 → nvidia_codec-0.0.23}/setup.cfg +1 -1
  4. {nvidia_codec-0.0.22 → nvidia_codec-0.0.23}/src/nvidia_codec/ffmpeg/include/libavformat.py +1 -0
  5. {nvidia_codec-0.0.22 → nvidia_codec-0.0.23}/src/nvidia_codec/ffmpeg/include/libavutil.py +7 -5
  6. {nvidia_codec-0.0.22 → nvidia_codec-0.0.23}/src/nvidia_codec/ffmpeg/libavformat.py +0 -10
  7. {nvidia_codec-0.0.22 → nvidia_codec-0.0.23}/src/nvidia_codec/utils/decode.py +42 -2
  8. {nvidia_codec-0.0.22 → nvidia_codec-0.0.23}/src/nvidia_codec/utils/demux.py +23 -8
  9. {nvidia_codec-0.0.22 → nvidia_codec-0.0.23}/src/nvidia_codec/utils/player.py +4 -1
  10. {nvidia_codec-0.0.22 → nvidia_codec-0.0.23/src/nvidia_codec.egg-info}/PKG-INFO +19 -2
  11. {nvidia_codec-0.0.22 → nvidia_codec-0.0.23}/tests/test_smoke.py +57 -0
  12. {nvidia_codec-0.0.22 → nvidia_codec-0.0.23}/LICENSE +0 -0
  13. {nvidia_codec-0.0.22 → nvidia_codec-0.0.23}/pyproject.toml +0 -0
  14. {nvidia_codec-0.0.22 → nvidia_codec-0.0.23}/src/nvidia_codec/__init__.py +0 -0
  15. {nvidia_codec-0.0.22 → nvidia_codec-0.0.23}/src/nvidia_codec/common.py +0 -0
  16. {nvidia_codec-0.0.22 → nvidia_codec-0.0.23}/src/nvidia_codec/core/__init__.py +0 -0
  17. {nvidia_codec-0.0.22 → nvidia_codec-0.0.23}/src/nvidia_codec/core/common.py +0 -0
  18. {nvidia_codec-0.0.22 → nvidia_codec-0.0.23}/src/nvidia_codec/core/cuda.py +0 -0
  19. {nvidia_codec-0.0.22 → nvidia_codec-0.0.23}/src/nvidia_codec/core/cuviddec.py +0 -0
  20. {nvidia_codec-0.0.22 → nvidia_codec-0.0.23}/src/nvidia_codec/core/decode.py +0 -0
  21. {nvidia_codec-0.0.22 → nvidia_codec-0.0.23}/src/nvidia_codec/core/nvcuvid.py +0 -0
  22. {nvidia_codec-0.0.22 → nvidia_codec-0.0.23}/src/nvidia_codec/ffmpeg/__init__.py +0 -0
  23. {nvidia_codec-0.0.22 → nvidia_codec-0.0.23}/src/nvidia_codec/ffmpeg/adapt.py +0 -0
  24. {nvidia_codec-0.0.22 → nvidia_codec-0.0.23}/src/nvidia_codec/ffmpeg/common.py +0 -0
  25. {nvidia_codec-0.0.22 → nvidia_codec-0.0.23}/src/nvidia_codec/ffmpeg/include/__init__.py +0 -0
  26. {nvidia_codec-0.0.22 → nvidia_codec-0.0.23}/src/nvidia_codec/ffmpeg/include/libavcodec.py +0 -0
  27. {nvidia_codec-0.0.22 → nvidia_codec-0.0.23}/src/nvidia_codec/ffmpeg/libavcodec.py +0 -0
  28. {nvidia_codec-0.0.22 → nvidia_codec-0.0.23}/src/nvidia_codec/ffmpeg/libavutil.py +0 -0
  29. {nvidia_codec-0.0.22 → nvidia_codec-0.0.23}/src/nvidia_codec/ffmpeg/test.py +0 -0
  30. {nvidia_codec-0.0.22 → nvidia_codec-0.0.23}/src/nvidia_codec/utils/__init__.py +0 -0
  31. {nvidia_codec-0.0.22 → nvidia_codec-0.0.23}/src/nvidia_codec/utils/color.py +0 -0
  32. {nvidia_codec-0.0.22 → nvidia_codec-0.0.23}/src/nvidia_codec/utils/compat.py +0 -0
  33. {nvidia_codec-0.0.22 → nvidia_codec-0.0.23}/src/nvidia_codec.egg-info/SOURCES.txt +0 -0
  34. {nvidia_codec-0.0.22 → nvidia_codec-0.0.23}/src/nvidia_codec.egg-info/dependency_links.txt +0 -0
  35. {nvidia_codec-0.0.22 → nvidia_codec-0.0.23}/src/nvidia_codec.egg-info/requires.txt +0 -0
  36. {nvidia_codec-0.0.22 → nvidia_codec-0.0.23}/src/nvidia_codec.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nvidia-codec
3
- Version: 0.0.22
3
+ Version: 0.0.23
4
4
  Summary: Pythonic interface to Nvidia Codec
5
5
  Home-page: https://github.com/riaqn/python-nvidia-codec
6
6
  Author: Zesen Qian
@@ -124,6 +124,23 @@ Codec support depends on your GPU:
124
124
  - VPF allocates the bare minimum of resources needed for most decoding tasks. PNC allows the user to specify the amount of resources to be allocated for advanced applications. Users own the resources and decide when and whether to deal with them.
125
125
  - Managing resources is not painful: similar to `pycuda`, we shift the burden of managing host/device resources to the Python garbage collector. Resources (such as `Picture` and `Surface`) are automatically freed when the user drops the reference.
126
126
 
127
+ ## Limitations
128
+
129
+ - **One consumer per `Decoder`.** A `Decoder`/`Player` instance serves one
130
+ `frames()`, `screenshots()` or `screenshot()` call at a time. Use separate
131
+ instances (from any threads) for concurrent decodes of the same or different
132
+ files.
133
+ - **No mid-stream resolution or codec changes.** The NVDEC decoder is created
134
+ from the first sequence header; a later sequence with a different coded
135
+ size, chroma format or bit depth raises `decoder already initialized with
136
+ different format`. Split such files per segment.
137
+ - **Timestamp-less elementary streams** (e.g. raw Annex-B `.h264`/`.hevc`)
138
+ carry no pts: `frames()` yields `AV_NOPTS_VALUE` for every frame,
139
+ `pts2time` returns `None`, and `screenshot()` cannot locate a time. Mux
140
+ into a container first.
141
+ - **Embedded cover art** (`attached_pic` streams) is skipped by `Player`
142
+ and reported by `VideoTrack.attached_pic` from `parse()`.
143
+
127
144
  ## Roadmap
128
145
 
129
146
  - [x] Decoding
@@ -133,7 +150,7 @@ Codec support depends on your GPU:
133
150
  - Color Ranges: MPEG (limited), JPEG (full)
134
151
  - Color Space: BT.601, BT.709, BT.2020
135
152
  - [x] Built-in cropping and scaling via NV decoder
136
- - [x] Thread-safe and thread-friendly
153
+ - [x] Thread-friendly (one consumer per decoder; decoders are independent)
137
154
  - [ ] Encoder
138
155
  - [x] PyTorch integration
139
156
 
@@ -107,6 +107,23 @@ Codec support depends on your GPU:
107
107
  - VPF allocates the bare minimum of resources needed for most decoding tasks. PNC allows the user to specify the amount of resources to be allocated for advanced applications. Users own the resources and decide when and whether to deal with them.
108
108
  - Managing resources is not painful: similar to `pycuda`, we shift the burden of managing host/device resources to the Python garbage collector. Resources (such as `Picture` and `Surface`) are automatically freed when the user drops the reference.
109
109
 
110
+ ## Limitations
111
+
112
+ - **One consumer per `Decoder`.** A `Decoder`/`Player` instance serves one
113
+ `frames()`, `screenshots()` or `screenshot()` call at a time. Use separate
114
+ instances (from any threads) for concurrent decodes of the same or different
115
+ files.
116
+ - **No mid-stream resolution or codec changes.** The NVDEC decoder is created
117
+ from the first sequence header; a later sequence with a different coded
118
+ size, chroma format or bit depth raises `decoder already initialized with
119
+ different format`. Split such files per segment.
120
+ - **Timestamp-less elementary streams** (e.g. raw Annex-B `.h264`/`.hevc`)
121
+ carry no pts: `frames()` yields `AV_NOPTS_VALUE` for every frame,
122
+ `pts2time` returns `None`, and `screenshot()` cannot locate a time. Mux
123
+ into a container first.
124
+ - **Embedded cover art** (`attached_pic` streams) is skipped by `Player`
125
+ and reported by `VideoTrack.attached_pic` from `parse()`.
126
+
110
127
  ## Roadmap
111
128
 
112
129
  - [x] Decoding
@@ -116,7 +133,7 @@ Codec support depends on your GPU:
116
133
  - Color Ranges: MPEG (limited), JPEG (full)
117
134
  - Color Space: BT.601, BT.709, BT.2020
118
135
  - [x] Built-in cropping and scaling via NV decoder
119
- - [x] Thread-safe and thread-friendly
136
+ - [x] Thread-friendly (one consumer per decoder; decoders are independent)
120
137
  - [ ] Encoder
121
138
  - [x] PyTorch integration
122
139
 
@@ -1,6 +1,6 @@
1
1
  [metadata]
2
2
  name = nvidia-codec
3
- version = 0.0.22
3
+ version = 0.0.23
4
4
  author = Zesen Qian
5
5
  author_email = nvidia-codec@riaqn.org
6
6
  description = Pythonic interface to Nvidia Codec
@@ -19,6 +19,7 @@ class AVIndexEntry(Structure):
19
19
  return (self.flags_size >> 2) & 0x3FFFFFFF
20
20
 
21
21
  AVINDEX_KEYFRAME = 0x0001
22
+ AV_DISPOSITION_ATTACHED_PIC = 0x0400
22
23
 
23
24
  class AVStream(Structure):
24
25
  _fields_ = [
@@ -63,10 +63,12 @@ class AVColorRange(TypedCEnumeration(c_int)):
63
63
  # NB = 3
64
64
 
65
65
  class AVPixelFormat(TypedCEnumeration(c_int)):
66
- NONE = -1,
67
- RGB24 = 0,
68
- YUV420P = 1,
69
- YUV444P = 5,
70
- YUV420P16LE = 45,
66
+ # values per libavutil/pixfmt.h (ffmpeg 9); no trailing commas — they
67
+ # would make the members 1-tuples, not ints
68
+ NONE = -1
69
+ YUV420P = 0
70
+ RGB24 = 2
71
+ YUV444P = 5
72
+ YUV420P16LE = 45
71
73
  YUV444P16LE = 49
72
74
  # other omitted
@@ -3,7 +3,6 @@
3
3
  # not pyav
4
4
 
5
5
  from ctypes import *
6
- from fractions import Fraction
7
6
 
8
7
  from .include.libavutil import *
9
8
  from .include.libavcodec import *
@@ -104,15 +103,6 @@ class FormatContext:
104
103
  return result.contents
105
104
  return None
106
105
 
107
- def infer_start_time(self):
108
- # log.warning('infering start time from first packet')
109
- # in this case, we get the first packet
110
- pkt = Packet()
111
- self.read_packet(pkt)
112
- start_time = pkt.av.pts
113
- time_base = pkt.av.time_base
114
- return start_time * Fraction(time_base.num, time_base.den)
115
-
116
106
  @property
117
107
  def streams(self):
118
108
  for i in range(self.av.nb_streams):
@@ -2,6 +2,7 @@
2
2
 
3
3
  import collections
4
4
  from datetime import timedelta
5
+ from fractions import Fraction
5
6
  import numpy as np
6
7
  from queue import Queue, ShutDown
7
8
  import threading
@@ -9,6 +10,7 @@ import weakref
9
10
 
10
11
  from ..ffmpeg.libavcodec import BSFContext
11
12
  from ..ffmpeg.libavformat import FormatContext, AVCodecID
13
+ from ..ffmpeg.include.libavcodec import AV_PKT_FLAG_KEY
12
14
  from ..ffmpeg.include.libavutil import (
13
15
  AV_NOPTS_VALUE,
14
16
  AVColorRange,
@@ -180,6 +182,11 @@ class Decoder(BaseDecoder):
180
182
  coded_height=track.height,
181
183
  )
182
184
 
185
+ @property
186
+ def duration(self):
187
+ """Track duration as a timedelta, or None if the container doesn't say."""
188
+ return self.track.duration
189
+
183
190
  def pre_decode(self, idx):
184
191
  """NVDEC reclaims slot idx. Clear tracking, wait for consumer if held."""
185
192
  self._slots.pop(idx, None)
@@ -247,8 +254,7 @@ class Decoder(BaseDecoder):
247
254
  packet/frame traversal. Only if avformat cannot seek the container at all do we
248
255
  fall back to the in-memory-index path (then BOF)."""
249
256
  try:
250
- self.track.fc.seek_file(self.track.stream, target_pts,
251
- min_ts=-(2**63), max_ts=target_pts)
257
+ self._native_seek_to_keyframe(target_pts)
252
258
  except AVException:
253
259
  kts = self._keyframe_before(target_pts)
254
260
  if kts is None:
@@ -258,6 +264,40 @@ class Decoder(BaseDecoder):
258
264
  self.with_callbacks(lambda: self.send(None), post_decode=lambda pic: None)
259
265
  self._recent.clear()
260
266
 
267
+ def _native_seek_to_keyframe(self, target_pts, max_tries=16):
268
+ """avformat_seek_file(max_ts=target) positions on the last packet with
269
+ dts <= target. Indexed containers (MP4 / MKV) snap that to a keyframe.
270
+ Index-less ones (MPEG-TS / M2TS) use the generic dts bisection — which
271
+ is NOT keyframe-aware ("FIXME keyframe?" in mpegts.c) — and land
272
+ mid-GOP; NVDEC then discards everything up to the NEXT IDR, so the
273
+ frame we hand back is up to a GOP late. (ffmpeg's CLI papers over this
274
+ with a fixed 3/23 s dts heuristic.)
275
+
276
+ Peek at the landing packet; if it isn't a keyframe, back off by a
277
+ growing number of frame-durations and retry. Landing on an earlier
278
+ keyframe than strictly needed only costs decode-forward time, so
279
+ overshooting backwards is safe. The peek consumes a packet, so the
280
+ final seek re-runs to restore the position. Raises AVException if the
281
+ container can't seek at all (caller falls back to the in-memory index).
282
+ """
283
+ fc, stream = self.track.fc, self.track.stream
284
+ tb = self.track._time_base
285
+ afr = stream.avg_frame_rate
286
+ fps = Fraction(afr.num, afr.den) if afr.num > 0 and afr.den > 0 else Fraction(25)
287
+ step = max(1, int(1 / (fps * tb))) # one frame, in pts units
288
+ ts = target_pts
289
+ for _ in range(max_tries):
290
+ fc.seek_file(stream, ts, min_ts=-(2**63), max_ts=ts)
291
+ first = next(fc.read_packets(stream), None)
292
+ if first is None or first.av.flags & AV_PKT_FLAG_KEY:
293
+ break # keyframe (or EOF — nothing to fix)
294
+ landed = first.av.dts if first.av.dts != AV_NOPTS_VALUE else first.av.pts
295
+ if landed == AV_NOPTS_VALUE:
296
+ break # can't reason about position
297
+ ts = min(ts, landed) - step
298
+ step *= 2
299
+ fc.seek_file(stream, ts, min_ts=-(2**63), max_ts=ts)
300
+
261
301
  def _map_and_convert(self, pic, dtype, pixel_format='rgb'):
262
302
  """Map a Picture (or OwnedPicture) to a tensor. Frees pic and surface.
263
303
  Returns (timedelta, frame) on success, (timedelta, exception) on error.
@@ -10,6 +10,7 @@ from fractions import Fraction
10
10
  import functools
11
11
 
12
12
  from ..ffmpeg.libavformat import FormatContext, AVMediaType, AVCodecID
13
+ from ..ffmpeg.include.libavformat import AV_DISPOSITION_ATTACHED_PIC
13
14
  from ..ffmpeg.include.libavutil import (
14
15
  AV_NOPTS_VALUE,
15
16
  AV_TIME_BASE,
@@ -36,6 +37,7 @@ class VideoTrack:
36
37
  extradata: Codec extradata bytes, or None.
37
38
  color_space: AVColorSpace enum value.
38
39
  color_range: AVColorRange enum value.
40
+ attached_pic: True if this is embedded cover art, not real video.
39
41
  """
40
42
 
41
43
  def __init__(self, fc, stream):
@@ -51,20 +53,33 @@ class VideoTrack:
51
53
  # Time base
52
54
  self._time_base = Fraction(stream.time_base.num, stream.time_base.den)
53
55
 
54
- # Start time
56
+ # Start time. Lazy containers (MPEG-TS, raw elementary streams) leave
57
+ # both the stream and the format start_time unset until probed;
58
+ # probing buffers the packets it reads, so nothing is lost. (The old
59
+ # path read the first packet directly — which both computed 0 via the
60
+ # packet's unset 0/1 time_base AND swallowed the IDR, dropping the
61
+ # whole first GOP from decode.)
55
62
  self._start_time = stream.start_time
56
63
  if self._start_time == AV_NOPTS_VALUE:
57
- self._start_time = fc.av.start_time
58
- if self._start_time == AV_NOPTS_VALUE:
59
- start_time = fc.infer_start_time()
60
- self._start_time = int(start_time / self._time_base)
61
- else:
64
+ fc.probe()
65
+ self._start_time = stream.start_time
66
+ if self._start_time == AV_NOPTS_VALUE:
67
+ if fc.av.start_time != AV_NOPTS_VALUE:
62
68
  self._start_time = int(
63
- self._start_time / AV_TIME_BASE / self._time_base
69
+ fc.av.start_time / AV_TIME_BASE / self._time_base
64
70
  )
71
+ else:
72
+ # Timestamp-less stream (e.g. raw Annex-B .h264): packets carry
73
+ # no pts at all; frames() yields AV_NOPTS_VALUE and pts2time
74
+ # returns None. Anchor at 0 so time2pts is at least defined.
75
+ self._start_time = 0
65
76
 
66
- # Duration (lazy — probes only if needed)
67
77
 
78
+ @property
79
+ def attached_pic(self):
80
+ """True for cover-art / thumbnail "video" streams (AV_DISPOSITION_ATTACHED_PIC):
81
+ a single still image, not a decodable video track."""
82
+ return bool(self.stream.disposition & AV_DISPOSITION_ATTACHED_PIC)
68
83
 
69
84
  @functools.cached_property
70
85
  def width(self):
@@ -22,7 +22,10 @@ class Player(Decoder):
22
22
  track_idx=None,
23
23
  **decoder_kwargs,
24
24
  ):
25
- tracks = [t for t in parse(url) if isinstance(t, VideoTrack)]
25
+ # Cover art (attached_pic) is a "video" stream to ffmpeg but a single
26
+ # still image; never pick it, and don't count it as ambiguity.
27
+ tracks = [t for t in parse(url)
28
+ if isinstance(t, VideoTrack) and not t.attached_pic]
26
29
  if not tracks:
27
30
  raise ValueError(f"{url} has no video stream")
28
31
  if track_idx is not None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nvidia-codec
3
- Version: 0.0.22
3
+ Version: 0.0.23
4
4
  Summary: Pythonic interface to Nvidia Codec
5
5
  Home-page: https://github.com/riaqn/python-nvidia-codec
6
6
  Author: Zesen Qian
@@ -124,6 +124,23 @@ Codec support depends on your GPU:
124
124
  - VPF allocates the bare minimum of resources needed for most decoding tasks. PNC allows the user to specify the amount of resources to be allocated for advanced applications. Users own the resources and decide when and whether to deal with them.
125
125
  - Managing resources is not painful: similar to `pycuda`, we shift the burden of managing host/device resources to the Python garbage collector. Resources (such as `Picture` and `Surface`) are automatically freed when the user drops the reference.
126
126
 
127
+ ## Limitations
128
+
129
+ - **One consumer per `Decoder`.** A `Decoder`/`Player` instance serves one
130
+ `frames()`, `screenshots()` or `screenshot()` call at a time. Use separate
131
+ instances (from any threads) for concurrent decodes of the same or different
132
+ files.
133
+ - **No mid-stream resolution or codec changes.** The NVDEC decoder is created
134
+ from the first sequence header; a later sequence with a different coded
135
+ size, chroma format or bit depth raises `decoder already initialized with
136
+ different format`. Split such files per segment.
137
+ - **Timestamp-less elementary streams** (e.g. raw Annex-B `.h264`/`.hevc`)
138
+ carry no pts: `frames()` yields `AV_NOPTS_VALUE` for every frame,
139
+ `pts2time` returns `None`, and `screenshot()` cannot locate a time. Mux
140
+ into a container first.
141
+ - **Embedded cover art** (`attached_pic` streams) is skipped by `Player`
142
+ and reported by `VideoTrack.attached_pic` from `parse()`.
143
+
127
144
  ## Roadmap
128
145
 
129
146
  - [x] Decoding
@@ -133,7 +150,7 @@ Codec support depends on your GPU:
133
150
  - Color Ranges: MPEG (limited), JPEG (full)
134
151
  - Color Space: BT.601, BT.709, BT.2020
135
152
  - [x] Built-in cropping and scaling via NV decoder
136
- - [x] Thread-safe and thread-friendly
153
+ - [x] Thread-friendly (one consumer per decoder; decoders are independent)
137
154
  - [ ] Encoder
138
155
  - [x] PyTorch integration
139
156
 
@@ -86,6 +86,63 @@ def test_screenshots(clip):
86
86
  assert frame.shape == (3, H, W)
87
87
 
88
88
 
89
+ def test_duration_property(clip):
90
+ with Player(clip) as p:
91
+ assert abs(p.duration.total_seconds() - SECONDS) < 0.2
92
+
93
+
94
+ def test_cover_art_skipped(clip):
95
+ """A PNG attached_pic stream must not be selected or count as ambiguity."""
96
+ d = tempfile.mkdtemp(prefix="nvc-smoke-cover-")
97
+ try:
98
+ png = os.path.join(d, "cover.png")
99
+ out = os.path.join(d, "cover.mp4")
100
+ subprocess.run(["ffmpeg", "-v", "error", "-y", "-f", "lavfi",
101
+ "-i", "color=c=red:size=64x64:duration=1", "-frames:v", "1", png],
102
+ check=True, timeout=60)
103
+ subprocess.run(["ffmpeg", "-v", "error", "-y", "-i", clip, "-i", png,
104
+ "-map", "0", "-map", "1", "-c", "copy",
105
+ "-disposition:v:1", "attached_pic", out], check=True, timeout=60)
106
+ vids = [t for t in parse(out) if isinstance(t, VideoTrack)]
107
+ assert [t.attached_pic for t in vids] == [False, True]
108
+ with Player(out) as p:
109
+ assert p.track.index == 0
110
+ n = sum(1 for _ in p.frames(torch.uint8))
111
+ assert n == FPS * SECONDS
112
+ finally:
113
+ shutil.rmtree(d, ignore_errors=True)
114
+
115
+
116
+ def test_mpegts_start_time_and_first_gop(clip):
117
+ """MPEG-TS leaves start_time unset until probed. Probing must not swallow
118
+ the IDR (which used to drop the first GOP) and start_time must be real."""
119
+ d = tempfile.mkdtemp(prefix="nvc-smoke-ts-")
120
+ try:
121
+ out = os.path.join(d, "clip.ts")
122
+ subprocess.run(["ffmpeg", "-v", "error", "-y", "-i", clip, "-c", "copy", out],
123
+ check=True, timeout=60)
124
+ with Player(out) as p:
125
+ assert p.track._start_time > 0 # ffmpeg's TS muxer starts at 1.4 s
126
+ frames = list(p.frames(torch.uint8))
127
+ assert len(frames) == FPS * SECONDS
128
+ first_t = p.track.pts2time(frames[0][0])
129
+ assert abs(first_t.total_seconds()) < 1 / FPS
130
+ # TS seeks by dts with no keyframe awareness; the decoder must still
131
+ # produce the frame actually on screen at 1.0 s, not the next IDR.
132
+ t, _ = p.screenshot(timedelta(seconds=1), torch.uint8, accurate=True)
133
+ assert abs(t.total_seconds() - 1.0) < 1 / FPS + 1e-3
134
+ pts0, _ = next(iter(p.frames(torch.uint8, start=timedelta(seconds=1))))
135
+ assert abs(p.track.pts2time(pts0).total_seconds() - 1.0) < 1 / FPS + 1e-3
136
+ finally:
137
+ shutil.rmtree(d, ignore_errors=True)
138
+
139
+
140
+ def test_pixel_format_enum_values():
141
+ from nvidia_codec.ffmpeg.include.libavutil import AVPixelFormat
142
+ assert AVPixelFormat.YUV420P == 0 and AVPixelFormat.RGB24 == 2
143
+ assert isinstance(AVPixelFormat.YUV444P, int)
144
+
145
+
89
146
  def _has_encoder(name):
90
147
  out = subprocess.run(["ffmpeg", "-hide_banner", "-encoders"],
91
148
  capture_output=True, text=True, timeout=30).stdout
File without changes