Repository navigation
[Bugfix][Frontend] Preserve generated audio in ComfyUI video output #5905
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -152,48 +152,52 @@ def bytes_to_video(video_bytes: bytes) -> VideoInput: | |
| if video_stream is None: | ||
| raise ValueError("No video stream found in decoded payload.") | ||
|
|
||
| audio_stream = container.streams.audio[-1] if len(container.streams.audio) else None | ||
|
|
||
| frames = [] | ||
| for frame in container.decode(video_stream): | ||
| if not isinstance(frame, VideoFrame): | ||
| continue | ||
| image = frame.to_ndarray(format="rgb24") | ||
| frames.append(torch.from_numpy(image).float() / 255.0) | ||
| audio_frames = [] | ||
| resampler = AudioResampler(format="fltp") if audio_stream is not None else None | ||
|
|
||
| if len(frames) == 0: | ||
| raise ValueError("No video frames found in decoded payload.") | ||
| streams = [video_stream] | ||
| if audio_stream is not None: | ||
| streams.append(audio_stream) | ||
|
|
||
| images = torch.stack(frames, dim=0) | ||
| frame_rate = Fraction(video_stream.average_rate) if video_stream.average_rate else Fraction(1) | ||
| for frame in container.decode(*streams): | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [P2] Audio-preserving decode has no regression pin Evidence and suggested fixThe bugfix replaces sequential |
||
| if isinstance(frame, VideoFrame): | ||
| image = frame.to_ndarray(format="rgb24") | ||
| frames.append(torch.from_numpy(image).float() / 255.0) | ||
|
|
||
| audio: AudioInput | None = None | ||
| if len(container.streams.audio): | ||
| audio_stream = container.streams.audio[-1] | ||
| audio_frames = [] | ||
| resampler = AudioResampler(format="fltp") | ||
| for frame in container.decode(audio_stream): | ||
| if not isinstance(frame, AudioFrame): | ||
| continue | ||
| elif isinstance(frame, AudioFrame) and resampler is not None: | ||
| resampled = resampler.resample(frame) | ||
| if not isinstance(resampled, list): | ||
| resampled = [resampled] | ||
|
|
||
| for audio_frame in resampled: | ||
| if audio_frame is not None: | ||
| audio_frames.append(audio_frame.to_ndarray()) | ||
|
|
||
| if len(audio_frames) > 0: | ||
| audio_data = np.concatenate(audio_frames, axis=1) | ||
| sample_rate = int(audio_stream.sample_rate) if audio_stream.sample_rate else 1 | ||
| audio = { | ||
| "waveform": torch.from_numpy(audio_data).unsqueeze(0), | ||
| "sample_rate": sample_rate, | ||
| } | ||
| if len(frames) == 0: | ||
| raise ValueError("No video frames found in decoded payload.") | ||
|
|
||
| images = torch.stack(frames, dim=0) | ||
| frame_rate = Fraction(video_stream.average_rate) if video_stream.average_rate else Fraction(1) | ||
|
|
||
| audio: AudioInput | None = None | ||
| if audio_stream is not None and len(audio_frames) > 0: | ||
| audio_data = np.concatenate(audio_frames, axis=1) | ||
| sample_rate = int(audio_stream.sample_rate) if audio_stream.sample_rate else 1 | ||
| audio = { | ||
| "waveform": torch.from_numpy(audio_data).unsqueeze(0), | ||
| "sample_rate": sample_rate, | ||
| } | ||
|
|
||
| components = Types.VideoComponents( | ||
| images=images, | ||
| frame_rate=frame_rate, | ||
| audio=audio, | ||
| metadata=container.metadata if container.metadata else None, | ||
| ) | ||
|
|
||
| except Exception as e: | ||
| raise RuntimeError(f"Failed to decode video: {e}") | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update the video tests to pass generate_sound; all six existing cases now raise TypeError.