mp4保存
This commit is contained in:
+81
-26
@@ -143,54 +143,109 @@ class SEQUENCER_OT_generate_face_mask(Operator):
|
||||
|
||||
def _check_cache(self, cache_dir: str, expected_frames: int) -> bool:
|
||||
"""Check if cached masks exist and are complete.
|
||||
|
||||
|
||||
Args:
|
||||
cache_dir: Path to cache directory
|
||||
expected_frames: Number of frames expected
|
||||
|
||||
|
||||
Returns:
|
||||
True if cache exists and has at least 90% of expected frames
|
||||
True if cache exists and is valid
|
||||
"""
|
||||
if not os.path.exists(cache_dir):
|
||||
return False
|
||||
|
||||
mask_files = [f for f in os.listdir(cache_dir)
|
||||
|
||||
# Check for MP4 video (new format)
|
||||
mask_video = os.path.join(cache_dir, "mask.mp4")
|
||||
if os.path.exists(mask_video):
|
||||
# Verify video has expected number of frames
|
||||
import cv2
|
||||
cap = cv2.VideoCapture(mask_video)
|
||||
if cap.isOpened():
|
||||
frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
|
||||
cap.release()
|
||||
# Accept cache if at least 90% of frames exist
|
||||
return frame_count >= expected_frames * 0.9
|
||||
cap.release()
|
||||
return False
|
||||
|
||||
# Fallback: check for PNG sequence (backward compatibility)
|
||||
mask_files = [f for f in os.listdir(cache_dir)
|
||||
if f.startswith("mask_") and f.endswith(".png")]
|
||||
|
||||
|
||||
# Accept cache if at least 90% of frames exist
|
||||
# (some frames may have been skipped due to read errors)
|
||||
return len(mask_files) >= expected_frames * 0.9
|
||||
|
||||
def _add_mask_strip(self, context, source_strip_name: str, mask_dir: str):
|
||||
"""Add mask image sequence as a new strip."""
|
||||
def _add_mask_strip(self, context, source_strip_name: str, mask_path: str):
|
||||
"""Add mask video as a new strip.
|
||||
|
||||
Args:
|
||||
context: Blender context
|
||||
source_strip_name: Name of the source video strip
|
||||
mask_path: Path to mask video file or directory (for backward compatibility)
|
||||
"""
|
||||
scene = context.scene
|
||||
seq_editor = scene.sequence_editor
|
||||
|
||||
|
||||
if not seq_editor:
|
||||
return
|
||||
|
||||
|
||||
# Find source strip (Blender 5.0 uses 'strips' instead of 'sequences')
|
||||
source_strip = seq_editor.strips.get(source_strip_name)
|
||||
if not source_strip:
|
||||
return
|
||||
|
||||
# Get first mask image
|
||||
mask_files = sorted([
|
||||
f for f in os.listdir(mask_dir)
|
||||
if f.startswith("mask_") and f.endswith(".png")
|
||||
])
|
||||
|
||||
if not mask_files:
|
||||
return
|
||||
|
||||
first_mask = os.path.join(mask_dir, mask_files[0])
|
||||
|
||||
|
||||
# Check if mask_path is a video file or directory (backward compatibility)
|
||||
if os.path.isfile(mask_path):
|
||||
# New format: single MP4 file
|
||||
mask_video = mask_path
|
||||
else:
|
||||
# Old format: directory with PNG sequence (backward compatibility)
|
||||
mask_video = os.path.join(mask_path, "mask.mp4")
|
||||
if not os.path.exists(mask_video):
|
||||
# Fallback to PNG sequence
|
||||
mask_files = sorted([
|
||||
f for f in os.listdir(mask_path)
|
||||
if f.startswith("mask_") and f.endswith(".png")
|
||||
])
|
||||
if not mask_files:
|
||||
return
|
||||
first_mask = os.path.join(mask_path, mask_files[0])
|
||||
self._add_mask_strip_png_sequence(context, source_strip_name, mask_path, mask_files, first_mask)
|
||||
return
|
||||
|
||||
# Find an empty channel
|
||||
used_channels = {s.channel for s in seq_editor.strips}
|
||||
new_channel = source_strip.channel + 1
|
||||
while new_channel in used_channels:
|
||||
new_channel += 1
|
||||
|
||||
|
||||
# Add movie strip (Blender 5.0 API)
|
||||
mask_strip = seq_editor.strips.new_movie(
|
||||
name=f"{source_strip_name}_mask",
|
||||
filepath=mask_video,
|
||||
channel=new_channel,
|
||||
frame_start=source_strip.frame_final_start,
|
||||
)
|
||||
|
||||
# Set blend mode for mask
|
||||
mask_strip.blend_type = 'ALPHA_OVER'
|
||||
mask_strip.blend_alpha = 0.5
|
||||
|
||||
def _add_mask_strip_png_sequence(self, context, source_strip_name, mask_dir, mask_files, first_mask):
|
||||
"""Backward compatibility: Add PNG sequence as mask strip."""
|
||||
scene = context.scene
|
||||
seq_editor = scene.sequence_editor
|
||||
source_strip = seq_editor.strips.get(source_strip_name)
|
||||
|
||||
if not source_strip:
|
||||
return
|
||||
|
||||
# Find an empty channel
|
||||
used_channels = {s.channel for s in seq_editor.strips}
|
||||
new_channel = source_strip.channel + 1
|
||||
while new_channel in used_channels:
|
||||
new_channel += 1
|
||||
|
||||
# Add image sequence (Blender 5.0 API)
|
||||
mask_strip = seq_editor.strips.new_image(
|
||||
name=f"{source_strip_name}_mask",
|
||||
@@ -198,11 +253,11 @@ class SEQUENCER_OT_generate_face_mask(Operator):
|
||||
channel=new_channel,
|
||||
frame_start=source_strip.frame_final_start,
|
||||
)
|
||||
|
||||
|
||||
# Add remaining frames
|
||||
for mask_file in mask_files[1:]:
|
||||
mask_strip.elements.append(mask_file)
|
||||
|
||||
|
||||
# Set blend mode for mask
|
||||
mask_strip.blend_type = 'ALPHA_OVER'
|
||||
mask_strip.blend_alpha = 0.5
|
||||
|
||||
Reference in New Issue
Block a user