-
-
Notifications
You must be signed in to change notification settings - Fork 20.4k
openpangu-vl support video input #34134
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 6 commits
dc068bc
5cc32bd
994b97b
8b37e17
0dfdda0
c5fa900
3623ece
f277b23
6f31247
3c3299d
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 | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,6 +1,7 @@ | ||||||||||||||||||||||
| # SPDX-License-Identifier: Apache-2.0 | ||||||||||||||||||||||
| # SPDX-FileCopyrightText: Copyright contributors to the vLLM project | ||||||||||||||||||||||
| import math | ||||||||||||||||||||||
| import warnings | ||||||||||||||||||||||
| from abc import abstractmethod | ||||||||||||||||||||||
| from io import BytesIO | ||||||||||||||||||||||
| from typing import TYPE_CHECKING, Any, cast | ||||||||||||||||||||||
|
|
@@ -747,3 +748,111 @@ def load_bytes( | |||||||||||||||||||||
| **kwargs, | ||||||||||||||||||||||
| ) | ||||||||||||||||||||||
| return out | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
|
|
||||||||||||||||||||||
| @VIDEO_LOADER_REGISTRY.register("opencv_dynamic_openpangu") | ||||||||||||||||||||||
| class OpenCVDynamicOpenPanguVideoBackend(OpenCVVideoBackend): | ||||||||||||||||||||||
| @classmethod | ||||||||||||||||||||||
| def load_bytes( | ||||||||||||||||||||||
| cls, | ||||||||||||||||||||||
| data: bytes, | ||||||||||||||||||||||
| num_frames: int = 32, | ||||||||||||||||||||||
| fps: int = 1, | ||||||||||||||||||||||
| max_duration: int = 300, | ||||||||||||||||||||||
| frame_recovery: bool = False, | ||||||||||||||||||||||
| **kwargs, | ||||||||||||||||||||||
| ) -> tuple[npt.NDArray, dict[str, Any]]: | ||||||||||||||||||||||
| """ | ||||||||||||||||||||||
| Load video frames with dynamic sampling based on duration. | ||||||||||||||||||||||
| Assume that total_num_frames = 10 and fps = 1. | ||||||||||||||||||||||
| The timestamp of frame 0 is 0.0. | ||||||||||||||||||||||
| The timestamp of frame 1 is 1.0.… | ||||||||||||||||||||||
| The timestamp of frame 9 (the last frame) should be 9.0, that is, | ||||||||||||||||||||||
| (total_frames_num – 1) / original_fps. | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| Args: | ||||||||||||||||||||||
| data: Raw video bytes | ||||||||||||||||||||||
| num_frames: Not used in dynamic backend | ||||||||||||||||||||||
| fps: Target FPS for sampling (default: 2) | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| Returns: | ||||||||||||||||||||||
| Tuple of (frames_array, metadata_dict) | ||||||||||||||||||||||
| """ | ||||||||||||||||||||||
| import cv2 | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| backend = cls().get_cv2_video_api() | ||||||||||||||||||||||
| cap = cv2.VideoCapture(BytesIO(data), backend, []) | ||||||||||||||||||||||
| if not cap.isOpened(): | ||||||||||||||||||||||
| raise ValueError("Could not open video stream") | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| total_frames_num = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) | ||||||||||||||||||||||
| original_fps = float(cap.get(cv2.CAP_PROP_FPS)) | ||||||||||||||||||||||
| # The timestamp of the rightmost frame, cannot be used to calculate frame 0. | ||||||||||||||||||||||
| if total_frames_num >= 1 and original_fps > 0: | ||||||||||||||||||||||
| total_duration = (total_frames_num - 1) / original_fps | ||||||||||||||||||||||
| else: | ||||||||||||||||||||||
| total_duration = 0 | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| # `fps` is the FPS parameter passed in for sampling, | ||||||||||||||||||||||
| # -1 indicates that sampling can be performed directly without FPS limitation. | ||||||||||||||||||||||
| if fps > 0: | ||||||||||||||||||||||
| # Num_frames is the maximum number of frames to sample. | ||||||||||||||||||||||
| # If fewer frames are sampled at this sample_fps, the update duration will be longer. # noqa: E501 | ||||||||||||||||||||||
| if num_frames >= int(total_duration * fps) + 1: | ||||||||||||||||||||||
| num_frames = int(total_duration * fps) + 1 | ||||||||||||||||||||||
| # Under the new maximum frame rate, the video duration of the rightmost frame, # noqa: E501 | ||||||||||||||||||||||
| # cannot be calculated for frame 0. | ||||||||||||||||||||||
| total_duration = min(total_duration, (num_frames - 1) / fps) | ||||||||||||||||||||||
| elif fps != -1: | ||||||||||||||||||||||
| raise ValueError( | ||||||||||||||||||||||
| f"requires dataset fps is -1 or greater than 0 but got {fps}" | ||||||||||||||||||||||
| ) | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| sample_frame_timestamps = np.linspace( | ||||||||||||||||||||||
| 0, total_duration, num_frames, dtype=float | ||||||||||||||||||||||
| ) | ||||||||||||||||||||||
| frames_indices = [ | ||||||||||||||||||||||
| min(total_frames_num - 1, round(t * original_fps)) | ||||||||||||||||||||||
| for t in sample_frame_timestamps | ||||||||||||||||||||||
| ] | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) | ||||||||||||||||||||||
| height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) | ||||||||||||||||||||||
| frames = np.empty((len(frames_indices), height, width, 3), dtype=np.uint8) | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| i = 0 | ||||||||||||||||||||||
| for frame_idx in frames_indices: | ||||||||||||||||||||||
| cap.set(cv2.CAP_PROP_POS_FRAMES, frame_idx) | ||||||||||||||||||||||
| ret, frame = cap.read() | ||||||||||||||||||||||
| if ret: | ||||||||||||||||||||||
| frames[i] = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) | ||||||||||||||||||||||
| i += 1 | ||||||||||||||||||||||
| else: | ||||||||||||||||||||||
| # when get a bad frame,continuous finding a next good frame | ||||||||||||||||||||||
| next_idx = frame_idx + 1 | ||||||||||||||||||||||
| while next_idx < total_frames_num: | ||||||||||||||||||||||
| ret, next_frame = cap.read() | ||||||||||||||||||||||
| if ret: | ||||||||||||||||||||||
| frames[i] = cv2.cvtColor(next_frame, cv2.COLOR_BGR2RGB) | ||||||||||||||||||||||
| i += 1 | ||||||||||||||||||||||
| break | ||||||||||||||||||||||
| next_idx += 1 | ||||||||||||||||||||||
|
Contributor
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. The else:
# when get a bad frame,continuous finding a next good frame
next_idx = frame_idx + 1
while next_idx < total_frames_num:
cap.set(cv2.CAP_PROP_POS_FRAMES, next_idx)
ret, next_frame = cap.read()
if ret:
frames[i] = cv2.cvtColor(next_frame, cv2.COLOR_BGR2RGB)
i += 1
break
next_idx += 1
Contributor
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. I tried frames_indices = [10, 11]. After one cap.set and two cap.read operations, the second cap.set operation did not skip the original frame.
Member
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. We can use
Contributor
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. Modified already. |
||||||||||||||||||||||
|
|
||||||||||||||||||||||
| if i != len(frames_indices): | ||||||||||||||||||||||
| warnings.warn( | ||||||||||||||||||||||
| f"Expected reading {len(frames_indices)} frames," | ||||||||||||||||||||||
| f"but only loaded {i} frames from video.", | ||||||||||||||||||||||
| UserWarning, | ||||||||||||||||||||||
| stacklevel=2, | ||||||||||||||||||||||
| ) | ||||||||||||||||||||||
|
Member
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.
Suggested change
Use
Contributor
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. Modified already. |
||||||||||||||||||||||
|
|
||||||||||||||||||||||
| # Use transformers transformers.video_utils.VideoMetadata format | ||||||||||||||||||||||
| metadata = { | ||||||||||||||||||||||
| "total_num_frames": total_frames_num, | ||||||||||||||||||||||
| "fps": original_fps, | ||||||||||||||||||||||
| "duration": total_duration, | ||||||||||||||||||||||
| "video_backend": "opencv_dynamic_openpangu", | ||||||||||||||||||||||
| "frames_indices": frames_indices, | ||||||||||||||||||||||
| "do_sample_frames": False, | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| return frames, metadata | ||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.