Fix GPU encoding black frames and improve debug logging
- Add CUDA sync before encoding to ensure RGB->NV12 kernel completes - Add debug logging for frame data validation (sum check) - Handle GPUFrame objects in GPUHLSOutput.write() - Fix cv2.resize for CuPy arrays (use cupyx.scipy.ndimage.zoom) - Fix fused pipeline parameter ordering (geometric first, color second) - Add raindrop-style ripple with random position/freq/decay/amp - Generate final VOD playlist with #EXT-X-ENDLIST Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -894,7 +894,7 @@ def prim_fused_pipeline(img, effects_list, **dynamic_params):
|
||||
Returns:
|
||||
Processed image as GPU array
|
||||
|
||||
Supported ops: rotate, zoom, ripple, invert, hue_shift, brightness
|
||||
Supported ops: rotate, zoom, ripple, invert, hue_shift, brightness, resize
|
||||
"""
|
||||
global _FUSED_CALL_COUNT
|
||||
_FUSED_CALL_COUNT += 1
|
||||
@@ -904,8 +904,34 @@ def prim_fused_pipeline(img, effects_list, **dynamic_params):
|
||||
# Normalize effects list - convert Keyword keys to strings
|
||||
effects_list = [_normalize_effect_dict(e) for e in effects_list]
|
||||
|
||||
# Handle resize separately - it changes dimensions so must happen before fused kernel
|
||||
resize_ops = [e for e in effects_list if e.get('op') == 'resize']
|
||||
other_effects = [e for e in effects_list if e.get('op') != 'resize']
|
||||
|
||||
# Apply resize first if needed
|
||||
if resize_ops:
|
||||
for resize_op in resize_ops:
|
||||
target_w = int(resize_op.get('width', 640))
|
||||
target_h = int(resize_op.get('height', 360))
|
||||
# Wrap in GPUFrame if needed
|
||||
if isinstance(img, GPUFrame):
|
||||
img = gpu_resize(img, (target_w, target_h))
|
||||
img = img.gpu if img.is_on_gpu else img.cpu
|
||||
else:
|
||||
frame = GPUFrame(img, on_gpu=hasattr(img, '__cuda_array_interface__'))
|
||||
img = gpu_resize(frame, (target_w, target_h))
|
||||
img = img.gpu if img.is_on_gpu else img.cpu
|
||||
|
||||
# If no other effects, just return the resized image
|
||||
if not other_effects:
|
||||
return img
|
||||
|
||||
# Update effects list to exclude resize ops
|
||||
effects_list = other_effects
|
||||
|
||||
if not _FUSED_KERNELS_AVAILABLE:
|
||||
# Fallback: apply effects one by one
|
||||
print(f"[FUSED FALLBACK] Using fallback path for {len(effects_list)} effects", file=sys.stderr)
|
||||
# Wrap in GPUFrame if needed (GPU functions expect GPUFrame objects)
|
||||
if isinstance(img, GPUFrame):
|
||||
result = img
|
||||
@@ -922,20 +948,27 @@ def prim_fused_pipeline(img, effects_list, **dynamic_params):
|
||||
result = gpu_zoom(result, amount)
|
||||
elif op == 'hue_shift':
|
||||
degrees = effect.get('degrees', 0)
|
||||
result = gpu_hue_shift(result, degrees)
|
||||
if abs(degrees) > 0.1: # Only apply if significant shift
|
||||
result = gpu_hue_shift(result, degrees)
|
||||
elif op == 'ripple':
|
||||
result = gpu_ripple(result,
|
||||
amplitude=dynamic_params.get('ripple_amplitude', effect.get('amplitude', 10)),
|
||||
frequency=effect.get('frequency', 8),
|
||||
decay=effect.get('decay', 2),
|
||||
phase=dynamic_params.get('ripple_phase', effect.get('phase', 0)),
|
||||
cx=effect.get('center_x'),
|
||||
cy=effect.get('center_y'))
|
||||
amplitude = dynamic_params.get('ripple_amplitude', effect.get('amplitude', 10))
|
||||
if amplitude > 0.1: # Only apply if amplitude is significant
|
||||
result = gpu_ripple(result,
|
||||
amplitude=amplitude,
|
||||
frequency=effect.get('frequency', 8),
|
||||
decay=effect.get('decay', 2),
|
||||
phase=dynamic_params.get('ripple_phase', effect.get('phase', 0)),
|
||||
cx=effect.get('center_x'),
|
||||
cy=effect.get('center_y'))
|
||||
elif op == 'brightness':
|
||||
factor = effect.get('factor', 1.0)
|
||||
result = gpu_contrast(result, factor, 0)
|
||||
elif op == 'invert':
|
||||
result = gpu_invert(result)
|
||||
amount = effect.get('amount', 0)
|
||||
if amount > 0.5: # Only invert if amount > 0.5
|
||||
result = gpu_invert(result)
|
||||
else:
|
||||
raise ValueError(f"Unsupported fused pipeline operation: '{op}'. Supported ops: rotate, zoom, hue_shift, ripple, brightness, invert, resize")
|
||||
# Return raw array, not GPUFrame (downstream expects arrays with .flags attribute)
|
||||
if isinstance(result, GPUFrame):
|
||||
return result.gpu if result.is_on_gpu else result.cpu
|
||||
|
||||
Reference in New Issue
Block a user