Skip to content

Commit 2f9dfeb

Browse files
WyattBlueclaude
andcommitted
Fix device_id access and retain CudaContext on frame
- Add _device_id field to VideoFrame, set it in from_dlpack and HW decode path - Store CudaContext on frame (_cuda_ctx) to prevent premature GC - Fix plane.py to use frame._device_id Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 8d36039 commit 2f9dfeb

5 files changed

Lines changed: 9 additions & 8 deletions

File tree

av/codec/hwaccel.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ def __init__(
130130
self.allow_software_fallback = allow_software_fallback
131131

132132
self.options = {} if not options else dict(options)
133-
if self._device_type == HWDeviceType.cuda and self.is_hw_owned == True:
133+
if self._device_type == HWDeviceType.cuda and self.is_hw_owned:
134134
self.options.setdefault("primary_ctx", "1")
135135
self.flags = 0 if not flags else flags
136136
self.ptr = cython.NULL
@@ -174,7 +174,6 @@ def create(self, codec: Codec) -> HWAccel:
174174
device=self._device,
175175
allow_software_fallback=self.allow_software_fallback,
176176
options=self.options,
177-
output_format=self.output_format,
178177
)
179178
ret._initialize_hw_context(codec)
180179
return ret

av/video/codeccontext.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ def _transfer_hwframe(self, frame: Frame):
128128
return frame
129129

130130
if self.hwaccel_ctx.is_hw_owned:
131+
cython.cast(VideoFrame, frame)._device_id = self.hwaccel_ctx.device_id
131132
return frame
132133

133134
frame_sw: Frame = self._alloc_next_frame()

av/video/frame.pxd

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@ cdef class VideoFrame(Frame):
2424
# We don't ever actually access it directly.
2525
cdef uint8_t *_buffer
2626
cdef object _np_buffer
27+
cdef object _cuda_ctx
2728

2829
cdef VideoReformatter reformatter
2930
cdef readonly VideoFormat format
31+
cdef readonly int _device_id
3032

3133
cdef _init(self, lib.AVPixelFormat format, unsigned int width, unsigned int height)
3234
cdef _init_user_attributes(self)

av/video/frame.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -628,10 +628,7 @@ def to_ndarray(self, channel_last=False, **kwargs):
628628

629629
frame: VideoFrame = self.reformat(**kwargs2)
630630
if frame.ptr.hw_frames_ctx:
631-
raise ValueError(
632-
"Cannot convert a hardware frame to numpy directly. "
633-
"Specify a software format (e.g. format='rgb24') or decode with HWAccel(output_format='sw')."
634-
)
631+
raise ValueError("Cannot convert a hardware frame to numpy directly.")
635632

636633
import numpy as np
637634

@@ -1542,6 +1539,8 @@ def from_dlpack(
15421539
frames_ref = ctx.get_frames_ctx(sw_fmt, width, height)
15431540
frame.ptr.format = get_pix_fmt(b"cuda")
15441541
frame.ptr.hw_frames_ctx = frames_ref
1542+
frame._device_id = device_id
1543+
frame._cuda_ctx = ctx
15451544
else:
15461545
frame.ptr.format = sw_fmt
15471546

av/video/plane.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ def __dlpack_device__(self):
8383
raise NotImplementedError(
8484
"DLPack export is only implemented for CUDA hw frames"
8585
)
86-
return (kCuda, self.frame.device_id)
86+
return (kCuda, self.frame._device_id)
8787
return (kCPU, 0)
8888

8989
def __dlpack__(self, stream: int | None = None):
@@ -109,7 +109,7 @@ def __dlpack__(self, stream: int | None = None):
109109
)
110110
sw_fmt = frames_ctx.sw_format
111111
device_type = kCuda
112-
device_id = self.frame.hwaccel_ctx.device_id
112+
device_id = self.frame._device_id
113113
else:
114114
sw_fmt = cython.cast(lib.AVPixelFormat, self.frame.ptr.format)
115115
device_type = kCPU

0 commit comments

Comments
 (0)