Spaces:
Sleeping
Sleeping
again changed videprocessing class and tab3
Browse files
app.py
CHANGED
|
@@ -443,43 +443,60 @@ class VideoProcessor:
|
|
| 443 |
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
|
| 444 |
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
|
| 445 |
|
| 446 |
-
# Create temporary output file
|
| 447 |
-
temp_output = tempfile.NamedTemporaryFile(suffix='.
|
| 448 |
temp_output.close()
|
| 449 |
|
| 450 |
-
# Try different codecs
|
| 451 |
codecs_to_try = [
|
| 452 |
-
('
|
| 453 |
-
('
|
| 454 |
-
('
|
| 455 |
-
('
|
| 456 |
-
(
|
|
|
|
|
|
|
|
|
|
| 457 |
]
|
| 458 |
|
| 459 |
out = None
|
| 460 |
output_path = None
|
|
|
|
| 461 |
|
| 462 |
for codec_str, ext in codecs_to_try:
|
| 463 |
try:
|
| 464 |
# Update output filename with appropriate extension
|
| 465 |
-
|
|
|
|
|
|
|
|
|
|
| 466 |
|
| 467 |
if codec_str == 0:
|
| 468 |
-
# Uncompressed fallback
|
| 469 |
fourcc = 0
|
| 470 |
print("Using uncompressed video (larger file size)")
|
| 471 |
else:
|
| 472 |
fourcc = cv2.VideoWriter_fourcc(*codec_str)
|
| 473 |
-
print(f"Trying codec: {codec_str}")
|
| 474 |
|
| 475 |
-
|
|
|
|
| 476 |
|
| 477 |
if out.isOpened():
|
| 478 |
-
|
| 479 |
-
|
| 480 |
-
|
| 481 |
out.release()
|
| 482 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 483 |
except Exception as e:
|
| 484 |
print(f"Failed with codec {codec_str}: {e}")
|
| 485 |
if out:
|
|
@@ -488,11 +505,12 @@ class VideoProcessor:
|
|
| 488 |
continue
|
| 489 |
|
| 490 |
if out is None or not out.isOpened():
|
| 491 |
-
|
|
|
|
|
|
|
| 492 |
|
| 493 |
# Process frames
|
| 494 |
frame_count = 0
|
| 495 |
-
processed_frames = []
|
| 496 |
|
| 497 |
while True:
|
| 498 |
ret, frame = cap.read()
|
|
@@ -510,13 +528,11 @@ class VideoProcessor:
|
|
| 510 |
styled_array = np.array(styled_frame)
|
| 511 |
bgr_frame = cv2.cvtColor(styled_array, cv2.COLOR_RGB2BGR)
|
| 512 |
|
| 513 |
-
#
|
| 514 |
-
|
| 515 |
-
|
| 516 |
-
# Also keep frames in memory for fallback
|
| 517 |
-
if len(processed_frames) < 300: # Limit to prevent memory issues
|
| 518 |
-
processed_frames.append(bgr_frame.copy())
|
| 519 |
|
|
|
|
| 520 |
frame_count += 1
|
| 521 |
|
| 522 |
if progress_callback and frame_count % 10 == 0:
|
|
@@ -527,34 +543,17 @@ class VideoProcessor:
|
|
| 527 |
out.release()
|
| 528 |
|
| 529 |
# Verify the output file
|
| 530 |
-
if not os.path.exists(output_path) or os.path.getsize(output_path)
|
| 531 |
-
print("Output file is
|
| 532 |
-
|
| 533 |
-
# Try to create a simple video from frames as fallback
|
| 534 |
-
if processed_frames:
|
| 535 |
-
print("Attempting fallback: creating video from frames")
|
| 536 |
-
fallback_path = tempfile.NamedTemporaryFile(suffix='_fallback.mp4', delete=False).name
|
| 537 |
-
|
| 538 |
-
# Try creating with the most basic settings
|
| 539 |
-
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
|
| 540 |
-
out_fallback = cv2.VideoWriter(fallback_path, fourcc, fps, (width, height))
|
| 541 |
-
|
| 542 |
-
if out_fallback.isOpened():
|
| 543 |
-
for frame in processed_frames:
|
| 544 |
-
out_fallback.write(frame)
|
| 545 |
-
out_fallback.release()
|
| 546 |
-
|
| 547 |
-
if os.path.exists(fallback_path) and os.path.getsize(fallback_path) > 0:
|
| 548 |
-
os.unlink(output_path)
|
| 549 |
-
return fallback_path
|
| 550 |
-
|
| 551 |
return None
|
| 552 |
|
| 553 |
-
print(f"Video saved to: {output_path}")
|
| 554 |
print(f"File size: {os.path.getsize(output_path) / 1024 / 1024:.2f} MB")
|
|
|
|
|
|
|
| 555 |
|
| 556 |
-
# Clean up original temp file if
|
| 557 |
-
if output_path != temp_output.name:
|
| 558 |
try:
|
| 559 |
os.unlink(temp_output.name)
|
| 560 |
except:
|
|
@@ -566,6 +565,74 @@ class VideoProcessor:
|
|
| 566 |
print(f"Error processing video: {e}")
|
| 567 |
traceback.print_exc()
|
| 568 |
return None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 569 |
|
| 570 |
# ===========================
|
| 571 |
# MAIN STYLE TRANSFER SYSTEM
|
|
@@ -1911,6 +1978,7 @@ with tab2:
|
|
| 1911 |
# TAB 3: Video Processing
|
| 1912 |
# TAB 3: Video Processing
|
| 1913 |
# TAB 3: Video Processing
|
|
|
|
| 1914 |
with tab3:
|
| 1915 |
st.header("π¬ Video Processing")
|
| 1916 |
|
|
@@ -1971,29 +2039,23 @@ with tab3:
|
|
| 1971 |
)
|
| 1972 |
|
| 1973 |
if output_path and os.path.exists(output_path):
|
| 1974 |
-
# Read the video file immediately
|
| 1975 |
try:
|
| 1976 |
with open(output_path, 'rb') as f:
|
| 1977 |
video_bytes = f.read()
|
| 1978 |
|
| 1979 |
# Determine file extension
|
| 1980 |
-
file_ext = os.path.splitext(output_path)[1]
|
| 1981 |
|
| 1982 |
# Store in session state
|
| 1983 |
st.session_state['video_result_bytes'] = video_bytes
|
| 1984 |
st.session_state['video_result_ext'] = file_ext
|
| 1985 |
st.session_state['video_result_available'] = True
|
|
|
|
| 1986 |
|
| 1987 |
-
|
| 1988 |
-
if file_ext.lower() != '.mp4':
|
| 1989 |
-
st.info(f"Video saved as {file_ext} format. Converting for web playback...")
|
| 1990 |
-
|
| 1991 |
-
# For non-MP4, we'll provide download but may have playback issues
|
| 1992 |
-
st.warning("Note: Video playback may not work for non-MP4 formats. Use the download button to save the file.")
|
| 1993 |
-
|
| 1994 |
-
st.success("Video processing complete!")
|
| 1995 |
|
| 1996 |
-
# Clean up
|
| 1997 |
try:
|
| 1998 |
os.unlink(output_path)
|
| 1999 |
except:
|
|
@@ -2002,7 +2064,7 @@ with tab3:
|
|
| 2002 |
st.error(f"Failed to read processed video: {str(e)}")
|
| 2003 |
st.session_state['video_result_available'] = False
|
| 2004 |
else:
|
| 2005 |
-
st.error("Failed to process video. Please
|
| 2006 |
st.session_state['video_result_available'] = False
|
| 2007 |
|
| 2008 |
# Cleanup input file
|
|
@@ -2021,12 +2083,37 @@ with tab3:
|
|
| 2021 |
if st.session_state.get('video_result_available', False) and 'video_result_bytes' in st.session_state:
|
| 2022 |
try:
|
| 2023 |
file_ext = st.session_state.get('video_result_ext', '.mp4')
|
|
|
|
| 2024 |
|
| 2025 |
-
#
|
| 2026 |
-
|
| 2027 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2028 |
else:
|
| 2029 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2030 |
|
| 2031 |
# Always provide download button
|
| 2032 |
mime_types = {
|
|
@@ -2034,47 +2121,47 @@ with tab3:
|
|
| 2034 |
'.avi': 'video/x-msvideo',
|
| 2035 |
'.mov': 'video/quicktime'
|
| 2036 |
}
|
| 2037 |
-
mime_type = mime_types.get(file_ext
|
| 2038 |
|
| 2039 |
-
st.
|
| 2040 |
-
label="π₯ Download Processed Video",
|
| 2041 |
-
data=st.session_state['video_result_bytes'],
|
| 2042 |
-
file_name=f"styled_video_{datetime.datetime.now().strftime('%Y%m%d_%H%M%S')}{file_ext}",
|
| 2043 |
-
mime=mime_type
|
| 2044 |
-
)
|
| 2045 |
|
| 2046 |
-
|
| 2047 |
-
|
| 2048 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2049 |
|
| 2050 |
-
|
| 2051 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2052 |
|
| 2053 |
-
#
|
| 2054 |
-
if st.
|
| 2055 |
-
|
| 2056 |
-
if 'video_result_ext' in st.session_state:
|
| 2057 |
-
del st.session_state['video_result_ext']
|
| 2058 |
-
st.session_state['video_result_available'] = False
|
| 2059 |
-
st.rerun()
|
| 2060 |
|
| 2061 |
except Exception as e:
|
| 2062 |
st.error(f"Error displaying video: {str(e)}")
|
| 2063 |
|
| 2064 |
-
#
|
| 2065 |
if 'video_result_bytes' in st.session_state:
|
| 2066 |
-
file_ext = st.session_state.get('video_result_ext', '.mp4')
|
| 2067 |
st.download_button(
|
| 2068 |
-
label="π₯ Download
|
| 2069 |
data=st.session_state['video_result_bytes'],
|
| 2070 |
-
file_name=f"styled_video_{datetime.datetime.now().strftime('%Y%m%d_%H%M%S')}
|
| 2071 |
mime="application/octet-stream"
|
| 2072 |
)
|
| 2073 |
-
else:
|
| 2074 |
-
st.error("Video data not available")
|
| 2075 |
|
| 2076 |
elif st.session_state.get('video_result_available', False):
|
| 2077 |
-
st.warning("Video data not found
|
| 2078 |
if st.button("Clear State"):
|
| 2079 |
st.session_state['video_result_available'] = False
|
| 2080 |
st.rerun()
|
|
|
|
| 443 |
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
|
| 444 |
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
|
| 445 |
|
| 446 |
+
# Create temporary output file - always start with mp4
|
| 447 |
+
temp_output = tempfile.NamedTemporaryFile(suffix='.mp4', delete=False)
|
| 448 |
temp_output.close()
|
| 449 |
|
| 450 |
+
# Try different codecs - prioritize MP4-compatible ones
|
| 451 |
codecs_to_try = [
|
| 452 |
+
('mp4v', '.mp4'), # MPEG-4 - most compatible MP4 codec
|
| 453 |
+
('MP4V', '.mp4'), # Alternative case
|
| 454 |
+
('FMP4', '.mp4'), # Another MPEG-4 variant
|
| 455 |
+
('DIVX', '.mp4'), # DivX (sometimes works with MP4)
|
| 456 |
+
('XVID', '.avi'), # If MP4 fails, try AVI
|
| 457 |
+
('MJPG', '.avi'), # Motion JPEG - fallback
|
| 458 |
+
('DIV3', '.avi'), # DivX3
|
| 459 |
+
(0, '.avi') # Uncompressed (last resort)
|
| 460 |
]
|
| 461 |
|
| 462 |
out = None
|
| 463 |
output_path = None
|
| 464 |
+
used_codec = None
|
| 465 |
|
| 466 |
for codec_str, ext in codecs_to_try:
|
| 467 |
try:
|
| 468 |
# Update output filename with appropriate extension
|
| 469 |
+
if ext == '.mp4':
|
| 470 |
+
output_path = temp_output.name
|
| 471 |
+
else:
|
| 472 |
+
output_path = temp_output.name.replace('.mp4', ext)
|
| 473 |
|
| 474 |
if codec_str == 0:
|
|
|
|
| 475 |
fourcc = 0
|
| 476 |
print("Using uncompressed video (larger file size)")
|
| 477 |
else:
|
| 478 |
fourcc = cv2.VideoWriter_fourcc(*codec_str)
|
| 479 |
+
print(f"Trying codec: {codec_str} for {ext}")
|
| 480 |
|
| 481 |
+
# Create writer with specific parameters
|
| 482 |
+
out = cv2.VideoWriter(output_path, fourcc, fps, (width, height), isColor=True)
|
| 483 |
|
| 484 |
if out.isOpened():
|
| 485 |
+
# Test write a black frame to ensure it really works
|
| 486 |
+
test_frame = np.zeros((height, width, 3), dtype=np.uint8)
|
| 487 |
+
out.write(test_frame)
|
| 488 |
out.release()
|
| 489 |
+
|
| 490 |
+
# Re-open for actual writing
|
| 491 |
+
out = cv2.VideoWriter(output_path, fourcc, fps, (width, height), isColor=True)
|
| 492 |
+
if out.isOpened():
|
| 493 |
+
used_codec = codec_str
|
| 494 |
+
print(f"β Successfully using codec: {codec_str} with {ext}")
|
| 495 |
+
break
|
| 496 |
+
|
| 497 |
+
out.release()
|
| 498 |
+
out = None
|
| 499 |
+
|
| 500 |
except Exception as e:
|
| 501 |
print(f"Failed with codec {codec_str}: {e}")
|
| 502 |
if out:
|
|
|
|
| 505 |
continue
|
| 506 |
|
| 507 |
if out is None or not out.isOpened():
|
| 508 |
+
# Last resort: save frames as images and create video differently
|
| 509 |
+
print("Standard codecs failed. Trying alternative approach...")
|
| 510 |
+
return self._process_with_frame_saving(cap, style_configs, blend_mode, fps, width, height, total_frames, progress_callback)
|
| 511 |
|
| 512 |
# Process frames
|
| 513 |
frame_count = 0
|
|
|
|
| 514 |
|
| 515 |
while True:
|
| 516 |
ret, frame = cap.read()
|
|
|
|
| 528 |
styled_array = np.array(styled_frame)
|
| 529 |
bgr_frame = cv2.cvtColor(styled_array, cv2.COLOR_RGB2BGR)
|
| 530 |
|
| 531 |
+
# Ensure frame is correct size and type
|
| 532 |
+
if bgr_frame.shape[:2] != (height, width):
|
| 533 |
+
bgr_frame = cv2.resize(bgr_frame, (width, height))
|
|
|
|
|
|
|
|
|
|
| 534 |
|
| 535 |
+
out.write(bgr_frame)
|
| 536 |
frame_count += 1
|
| 537 |
|
| 538 |
if progress_callback and frame_count % 10 == 0:
|
|
|
|
| 543 |
out.release()
|
| 544 |
|
| 545 |
# Verify the output file
|
| 546 |
+
if not os.path.exists(output_path) or os.path.getsize(output_path) < 1000:
|
| 547 |
+
print(f"Output file is too small or doesn't exist (size: {os.path.getsize(output_path) if os.path.exists(output_path) else 0} bytes)")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 548 |
return None
|
| 549 |
|
| 550 |
+
print(f"Video successfully saved to: {output_path}")
|
| 551 |
print(f"File size: {os.path.getsize(output_path) / 1024 / 1024:.2f} MB")
|
| 552 |
+
print(f"Format: {os.path.splitext(output_path)[1]}")
|
| 553 |
+
print(f"Codec used: {used_codec}")
|
| 554 |
|
| 555 |
+
# Clean up original temp file if different
|
| 556 |
+
if output_path != temp_output.name and os.path.exists(temp_output.name):
|
| 557 |
try:
|
| 558 |
os.unlink(temp_output.name)
|
| 559 |
except:
|
|
|
|
| 565 |
print(f"Error processing video: {e}")
|
| 566 |
traceback.print_exc()
|
| 567 |
return None
|
| 568 |
+
|
| 569 |
+
def _process_with_frame_saving(self, cap, style_configs, blend_mode, fps, width, height, total_frames, progress_callback):
|
| 570 |
+
"""Alternative processing method: save frames then combine"""
|
| 571 |
+
try:
|
| 572 |
+
print("Using frame-saving fallback method...")
|
| 573 |
+
temp_dir = tempfile.mkdtemp()
|
| 574 |
+
frame_count = 0
|
| 575 |
+
frame_paths = []
|
| 576 |
+
|
| 577 |
+
# Process and save frames
|
| 578 |
+
while True:
|
| 579 |
+
ret, frame = cap.read()
|
| 580 |
+
if not ret:
|
| 581 |
+
break
|
| 582 |
+
|
| 583 |
+
# Process frame
|
| 584 |
+
rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
| 585 |
+
pil_frame = Image.fromarray(rgb_frame)
|
| 586 |
+
styled_frame = self.system.blend_styles(pil_frame, style_configs, blend_mode)
|
| 587 |
+
|
| 588 |
+
# Save frame
|
| 589 |
+
frame_path = os.path.join(temp_dir, f"frame_{frame_count:06d}.png")
|
| 590 |
+
styled_frame.save(frame_path)
|
| 591 |
+
frame_paths.append(frame_path)
|
| 592 |
+
|
| 593 |
+
frame_count += 1
|
| 594 |
+
if progress_callback and frame_count % 10 == 0:
|
| 595 |
+
progress = frame_count / total_frames
|
| 596 |
+
progress_callback(progress, f"Processing frame {frame_count}/{total_frames}")
|
| 597 |
+
|
| 598 |
+
cap.release()
|
| 599 |
+
|
| 600 |
+
if not frame_paths:
|
| 601 |
+
return None
|
| 602 |
+
|
| 603 |
+
# Try to create video from frames
|
| 604 |
+
output_path = tempfile.NamedTemporaryFile(suffix='.mp4', delete=False).name
|
| 605 |
+
|
| 606 |
+
# Read first frame to get size
|
| 607 |
+
first_frame = cv2.imread(frame_paths[0])
|
| 608 |
+
h, w = first_frame.shape[:2]
|
| 609 |
+
|
| 610 |
+
# Try simple mp4v codec
|
| 611 |
+
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
|
| 612 |
+
out = cv2.VideoWriter(output_path, fourcc, fps, (w, h))
|
| 613 |
+
|
| 614 |
+
if out.isOpened():
|
| 615 |
+
for frame_path in frame_paths:
|
| 616 |
+
frame = cv2.imread(frame_path)
|
| 617 |
+
out.write(frame)
|
| 618 |
+
out.release()
|
| 619 |
+
|
| 620 |
+
# Clean up frames
|
| 621 |
+
shutil.rmtree(temp_dir)
|
| 622 |
+
|
| 623 |
+
if os.path.exists(output_path) and os.path.getsize(output_path) > 1000:
|
| 624 |
+
print(f"Successfully created video using frame-saving method")
|
| 625 |
+
return output_path
|
| 626 |
+
|
| 627 |
+
# Clean up
|
| 628 |
+
shutil.rmtree(temp_dir)
|
| 629 |
+
return None
|
| 630 |
+
|
| 631 |
+
except Exception as e:
|
| 632 |
+
print(f"Frame-saving method failed: {e}")
|
| 633 |
+
if 'temp_dir' in locals() and os.path.exists(temp_dir):
|
| 634 |
+
shutil.rmtree(temp_dir)
|
| 635 |
+
return None
|
| 636 |
|
| 637 |
# ===========================
|
| 638 |
# MAIN STYLE TRANSFER SYSTEM
|
|
|
|
| 1978 |
# TAB 3: Video Processing
|
| 1979 |
# TAB 3: Video Processing
|
| 1980 |
# TAB 3: Video Processing
|
| 1981 |
+
# TAB 3: Video Processing
|
| 1982 |
with tab3:
|
| 1983 |
st.header("π¬ Video Processing")
|
| 1984 |
|
|
|
|
| 2039 |
)
|
| 2040 |
|
| 2041 |
if output_path and os.path.exists(output_path):
|
| 2042 |
+
# Read the video file immediately
|
| 2043 |
try:
|
| 2044 |
with open(output_path, 'rb') as f:
|
| 2045 |
video_bytes = f.read()
|
| 2046 |
|
| 2047 |
# Determine file extension
|
| 2048 |
+
file_ext = os.path.splitext(output_path)[1].lower()
|
| 2049 |
|
| 2050 |
# Store in session state
|
| 2051 |
st.session_state['video_result_bytes'] = video_bytes
|
| 2052 |
st.session_state['video_result_ext'] = file_ext
|
| 2053 |
st.session_state['video_result_available'] = True
|
| 2054 |
+
st.session_state['video_is_mp4'] = (file_ext == '.mp4')
|
| 2055 |
|
| 2056 |
+
st.success(f"β
Video processing complete! Format: {file_ext.upper()}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2057 |
|
| 2058 |
+
# Clean up files
|
| 2059 |
try:
|
| 2060 |
os.unlink(output_path)
|
| 2061 |
except:
|
|
|
|
| 2064 |
st.error(f"Failed to read processed video: {str(e)}")
|
| 2065 |
st.session_state['video_result_available'] = False
|
| 2066 |
else:
|
| 2067 |
+
st.error("Failed to process video. Please try a different video or reduce the resolution.")
|
| 2068 |
st.session_state['video_result_available'] = False
|
| 2069 |
|
| 2070 |
# Cleanup input file
|
|
|
|
| 2083 |
if st.session_state.get('video_result_available', False) and 'video_result_bytes' in st.session_state:
|
| 2084 |
try:
|
| 2085 |
file_ext = st.session_state.get('video_result_ext', '.mp4')
|
| 2086 |
+
video_bytes = st.session_state['video_result_bytes']
|
| 2087 |
|
| 2088 |
+
# File info
|
| 2089 |
+
file_size_mb = len(video_bytes) / (1024 * 1024)
|
| 2090 |
+
|
| 2091 |
+
# Try to display video
|
| 2092 |
+
if st.session_state.get('video_is_mp4', False):
|
| 2093 |
+
# For MP4, should work in browser
|
| 2094 |
+
st.video(video_bytes)
|
| 2095 |
+
st.success(f"β
Video ready! Size: {file_size_mb:.2f} MB")
|
| 2096 |
else:
|
| 2097 |
+
# For non-MP4, show info and download
|
| 2098 |
+
st.info(f"Video format ({file_ext}) may not play in browser. Please download to view.")
|
| 2099 |
+
|
| 2100 |
+
# Show preview image if possible
|
| 2101 |
+
try:
|
| 2102 |
+
# Try to extract a frame for preview
|
| 2103 |
+
temp_preview = tempfile.NamedTemporaryFile(delete=False, suffix=file_ext)
|
| 2104 |
+
temp_preview.write(video_bytes)
|
| 2105 |
+
temp_preview.close()
|
| 2106 |
+
|
| 2107 |
+
cap = cv2.VideoCapture(temp_preview.name)
|
| 2108 |
+
ret, frame = cap.read()
|
| 2109 |
+
if ret:
|
| 2110 |
+
# Convert frame to RGB and display
|
| 2111 |
+
rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
| 2112 |
+
st.image(rgb_frame, caption="Video Preview (First Frame)", use_column_width=True)
|
| 2113 |
+
cap.release()
|
| 2114 |
+
os.unlink(temp_preview.name)
|
| 2115 |
+
except:
|
| 2116 |
+
pass
|
| 2117 |
|
| 2118 |
# Always provide download button
|
| 2119 |
mime_types = {
|
|
|
|
| 2121 |
'.avi': 'video/x-msvideo',
|
| 2122 |
'.mov': 'video/quicktime'
|
| 2123 |
}
|
| 2124 |
+
mime_type = mime_types.get(file_ext, 'application/octet-stream')
|
| 2125 |
|
| 2126 |
+
col_dl1, col_dl2 = st.columns(2)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2127 |
|
| 2128 |
+
with col_dl1:
|
| 2129 |
+
st.download_button(
|
| 2130 |
+
label=f"π₯ Download Video ({file_ext.upper()})",
|
| 2131 |
+
data=video_bytes,
|
| 2132 |
+
file_name=f"styled_video_{datetime.datetime.now().strftime('%Y%m%d_%H%M%S')}{file_ext}",
|
| 2133 |
+
mime=mime_type,
|
| 2134 |
+
use_container_width=True
|
| 2135 |
+
)
|
| 2136 |
|
| 2137 |
+
with col_dl2:
|
| 2138 |
+
if st.button("ποΈ Clear Result", use_container_width=True):
|
| 2139 |
+
del st.session_state['video_result_bytes']
|
| 2140 |
+
st.session_state['video_result_available'] = False
|
| 2141 |
+
if 'video_result_ext' in st.session_state:
|
| 2142 |
+
del st.session_state['video_result_ext']
|
| 2143 |
+
if 'video_is_mp4' in st.session_state:
|
| 2144 |
+
del st.session_state['video_is_mp4']
|
| 2145 |
+
st.rerun()
|
| 2146 |
|
| 2147 |
+
# Info about playback
|
| 2148 |
+
if not st.session_state.get('video_is_mp4', False):
|
| 2149 |
+
st.caption("π‘ For best compatibility, download and use VLC or another video player.")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2150 |
|
| 2151 |
except Exception as e:
|
| 2152 |
st.error(f"Error displaying video: {str(e)}")
|
| 2153 |
|
| 2154 |
+
# Emergency download button
|
| 2155 |
if 'video_result_bytes' in st.session_state:
|
|
|
|
| 2156 |
st.download_button(
|
| 2157 |
+
label="π₯ Download Video (Error occurred)",
|
| 2158 |
data=st.session_state['video_result_bytes'],
|
| 2159 |
+
file_name=f"styled_video_{datetime.datetime.now().strftime('%Y%m%d_%H%M%S')}.mp4",
|
| 2160 |
mime="application/octet-stream"
|
| 2161 |
)
|
|
|
|
|
|
|
| 2162 |
|
| 2163 |
elif st.session_state.get('video_result_available', False):
|
| 2164 |
+
st.warning("Video data not found. Please process the video again.")
|
| 2165 |
if st.button("Clear State"):
|
| 2166 |
st.session_state['video_result_available'] = False
|
| 2167 |
st.rerun()
|