mirror of
https://github.com/storytold/artcraft.git
synced 2026-10-20 17:02:53 -04:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b3da60aa3a | ||
|
|
342ab2302c |
-2
@@ -1,5 +1,3 @@
|
||||
pub mod process_job;
|
||||
pub mod steps;
|
||||
pub mod video_paths;
|
||||
pub mod write_workflow_prompt;
|
||||
pub mod util;
|
||||
|
||||
+51
-49
@@ -52,10 +52,11 @@ use crate::job::job_types::workflow::comfy_ui::video_style_transfer::steps::post
|
||||
use crate::job::job_types::workflow::comfy_ui::video_style_transfer::steps::preprocess_save_audio::{preprocess_save_audio, ProcessSaveAudioArgs};
|
||||
use crate::job::job_types::workflow::comfy_ui::video_style_transfer::steps::preprocess_trim_and_resample_videos::{preprocess_trim_and_resample_videos, ProcessTrimAndResampleVideoArgs};
|
||||
use crate::job::job_types::workflow::comfy_ui::video_style_transfer::steps::validate_and_save_results::{SaveResultsArgs, validate_and_save_results};
|
||||
use crate::job::job_types::workflow::comfy_ui::video_style_transfer::util::comfy_dirs::ComfyDirs;
|
||||
use crate::job::job_types::workflow::comfy_ui::video_style_transfer::util::comfy_ui_inference_command::{InferenceArgs, InferenceDetails};
|
||||
use crate::job::job_types::workflow::comfy_ui::video_style_transfer::util::video_pathing::{InputVideoAndPaths, VideoDownloads};
|
||||
use crate::job::job_types::workflow::comfy_ui::video_style_transfer::video_paths::VideoPaths;
|
||||
use crate::job::job_types::workflow::comfy_ui::video_style_transfer::write_workflow_prompt::{WorkflowPromptArgs, write_workflow_prompt};
|
||||
use crate::job::job_types::workflow::comfy_ui::video_style_transfer::util::video_pathing::{PrimaryInputVideoAndPaths, SecondaryInputVideoAndPaths, VideoDownloads};
|
||||
use crate::job::job_types::workflow::comfy_ui::video_style_transfer::util::video_pathing_deprecated::VideoPaths;
|
||||
use crate::job::job_types::workflow::comfy_ui::video_style_transfer::util::write_workflow_prompt::{WorkflowPromptArgs, write_workflow_prompt};
|
||||
use crate::job_dependencies::JobDependencies;
|
||||
use crate::util::common_commands::ffmpeg_audio_replace_args::FfmpegAudioReplaceArgs;
|
||||
use crate::util::common_commands::ffmpeg_logo_watermark_command::WatermarkArgs;
|
||||
@@ -70,7 +71,7 @@ pub async fn process_job(args: ComfyProcessJobArgs<'_>) -> Result<JobSuccessResu
|
||||
.new_generic_inference(job.inference_job_token.as_str())
|
||||
.map_err(|e| ProcessSingleJobError::Other(anyhow!(e)))?;
|
||||
|
||||
let model_dependencies = args
|
||||
let comfy_deps = args
|
||||
.job_dependencies
|
||||
.job
|
||||
.job_specific_dependencies
|
||||
@@ -96,7 +97,10 @@ pub async fn process_job(args: ComfyProcessJobArgs<'_>) -> Result<JobSuccessResu
|
||||
|
||||
// ===================== DOWNLOAD REQUIRED MODELS IF NOT EXIST ===================== //
|
||||
|
||||
let root_comfy_path = model_dependencies.inference_command.mounts_directory.clone();
|
||||
// TODO: Replace all other paths with this
|
||||
let comfy_dirs = ComfyDirs::new(&comfy_deps);
|
||||
|
||||
let root_comfy_path = comfy_deps.inference_command.mounts_directory.clone();
|
||||
|
||||
let remote_cloud_file_client = RemoteCloudFileClient::get_remote_cloud_file_client().await;
|
||||
let remote_cloud_file_client = match remote_cloud_file_client {
|
||||
@@ -159,7 +163,7 @@ pub async fn process_job(args: ComfyProcessJobArgs<'_>) -> Result<JobSuccessResu
|
||||
workflow_path = write_workflow_prompt(WorkflowPromptArgs {
|
||||
workflow_path: &workflow_path,
|
||||
comfy_args: &comfy_args,
|
||||
model_dependencies: &model_dependencies,
|
||||
model_dependencies: &comfy_deps,
|
||||
maybe_positive_prompt: comfy_args.positive_prompt.as_deref(),
|
||||
maybe_negative_prompt: comfy_args.negative_prompt.as_deref(),
|
||||
})?;
|
||||
@@ -216,7 +220,7 @@ pub async fn process_job(args: ComfyProcessJobArgs<'_>) -> Result<JobSuccessResu
|
||||
info!("Root comfy path: {:?}", &root_comfy_path);
|
||||
info!("Job output path will be (fix this code! the job shouldn't set this path!): {:?}", &job_args.output_path);
|
||||
|
||||
let mut videos = VideoPaths::new(&root_comfy_path, job_args.output_path);
|
||||
//let mut videos = VideoPaths::new(&root_comfy_path, job_args.output_path);
|
||||
|
||||
// TODO(bt,2024-04-20): Clean up this mess.
|
||||
|
||||
@@ -239,18 +243,18 @@ pub async fn process_job(args: ComfyProcessJobArgs<'_>) -> Result<JobSuccessResu
|
||||
|
||||
// ==================== DOWNLOAD VIDEOS ==================== //
|
||||
|
||||
let mut download_videos = download_input_videos(DownloadInputVideoArgs {
|
||||
let mut videos = download_input_videos(DownloadInputVideoArgs {
|
||||
job_args: &job_args,
|
||||
videos: &videos,
|
||||
comfy_dirs: &comfy_dirs,
|
||||
mysql_pool: &deps.db.mysql_pool,
|
||||
remote_cloud_file_client: &remote_cloud_file_client,
|
||||
}).await?;
|
||||
|
||||
info!("Downloaded video!");
|
||||
|
||||
videos.debug_print_paths_after_download();
|
||||
//videos.debug_print_paths_after_download();
|
||||
|
||||
if let Ok(Some(dimensions)) = ffprobe_get_dimensions(&download_videos.input_video.original_download_path) {
|
||||
if let Ok(Some(dimensions)) = ffprobe_get_dimensions(&videos.input_video.original_download_path) {
|
||||
info!("Download video dimensions: {}x{}", dimensions.width, dimensions.height);
|
||||
}
|
||||
|
||||
@@ -258,16 +262,16 @@ pub async fn process_job(args: ComfyProcessJobArgs<'_>) -> Result<JobSuccessResu
|
||||
|
||||
preprocess_trim_and_resample_videos(ProcessTrimAndResampleVideoArgs {
|
||||
comfy_args,
|
||||
comfy_deps: model_dependencies,
|
||||
primary_video_paths: &videos,
|
||||
download_videos: &mut download_videos,
|
||||
comfy_deps,
|
||||
comfy_dirs: &comfy_dirs,
|
||||
videos: &mut videos,
|
||||
})?;
|
||||
|
||||
// ========================= PREPROCESS AUDIO ======================== //
|
||||
|
||||
let mut lipsync_enabled = comfy_args.lipsync_enabled.unwrap_or(false);
|
||||
if let Err(err) = preprocess_save_audio(ProcessSaveAudioArgs {
|
||||
comfy_deps: model_dependencies,
|
||||
comfy_deps,
|
||||
videos: &mut videos,
|
||||
}) {
|
||||
error!("Audio extraction failed: {:?}", err);
|
||||
@@ -336,7 +340,7 @@ pub async fn process_job(args: ComfyProcessJobArgs<'_>) -> Result<JobSuccessResu
|
||||
|
||||
info!("Running ComfyUI inference...");
|
||||
|
||||
let command_exit_status = model_dependencies
|
||||
let command_exit_status = comfy_deps
|
||||
.inference_command
|
||||
.execute_inference(InferenceArgs {
|
||||
stderr_output_file: &stderr_output_file,
|
||||
@@ -353,13 +357,13 @@ pub async fn process_job(args: ComfyProcessJobArgs<'_>) -> Result<JobSuccessResu
|
||||
.as_ref()
|
||||
.map(|image| path_to_string(&image.ipa_image_path)),
|
||||
global_ipa_strength: None, // TODO: Expose a UI slider
|
||||
depth_video_path: download_videos.maybe_depth.as_ref()
|
||||
depth_video_path: videos.maybe_depth.as_ref()
|
||||
.map(|v| v.maybe_processed_path.as_deref())
|
||||
.flatten(),
|
||||
normal_video_path: download_videos.maybe_normal.as_ref()
|
||||
normal_video_path: videos.maybe_normal.as_ref()
|
||||
.map(|v| v.maybe_processed_path.as_deref())
|
||||
.flatten(),
|
||||
outline_video_path: download_videos.maybe_outline.as_ref()
|
||||
outline_video_path: videos.maybe_outline.as_ref()
|
||||
.map(|v| v.maybe_processed_path.as_deref())
|
||||
.flatten(),
|
||||
});
|
||||
@@ -375,15 +379,15 @@ pub async fn process_job(args: ComfyProcessJobArgs<'_>) -> Result<JobSuccessResu
|
||||
info!("Captured stduout output: {}", contents);
|
||||
}
|
||||
|
||||
videos.debug_print_paths_after_comfy();
|
||||
//videos.debug_print_paths_after_comfy();
|
||||
|
||||
if let Ok(Some(dimensions)) = ffprobe_get_dimensions(&videos.comfy_output_video_path) {
|
||||
if let Ok(Some(dimensions)) = ffprobe_get_dimensions(&videos.input_video.comfy_output_video_path) {
|
||||
info!("Comfy output video dimensions: {}x{}", dimensions.width, dimensions.height);
|
||||
}
|
||||
|
||||
// ==================== CHECK OUTPUT FILE ======================== //
|
||||
|
||||
if let Err(err) = check_file_exists(&videos.comfy_output_video_path) {
|
||||
if let Err(err) = check_file_exists(&videos.input_video.comfy_output_video_path) {
|
||||
error!("Output file does not exist: {:?}", err);
|
||||
|
||||
error!("Inference failed: {:?}", command_exit_status);
|
||||
@@ -396,7 +400,7 @@ pub async fn process_job(args: ComfyProcessJobArgs<'_>) -> Result<JobSuccessResu
|
||||
safe_delete_temp_file(&stdout_output_file);
|
||||
safe_delete_temp_directory(&work_temp_dir);
|
||||
safe_delete_temp_file(&workflow_path);
|
||||
safe_delete_all_input_videos(&download_videos);
|
||||
safe_delete_all_input_videos(&videos);
|
||||
|
||||
// TODO(bt,2024-04-21): Not sure we want to delete the LoRA?
|
||||
if let Some(lora_path) = maybe_lora_path {
|
||||
@@ -407,37 +411,31 @@ pub async fn process_job(args: ComfyProcessJobArgs<'_>) -> Result<JobSuccessResu
|
||||
safe_delete_temp_file(ipa_path.ipa_image_path);
|
||||
}
|
||||
|
||||
safe_delete_temp_file(&videos.comfy_input_video_path);
|
||||
safe_delete_temp_file(&videos.trimmed_resampled_video_path);
|
||||
safe_delete_temp_file(&videos.trimmed_audio_path);
|
||||
//safe_delete_temp_file(&videos.original_video_path);
|
||||
|
||||
let output_dir = root_comfy_path.join("output");
|
||||
safe_recursively_delete_files(&output_dir);
|
||||
safe_recursively_delete_files(&comfy_dirs.comfy_output_dir);
|
||||
|
||||
return Err(ProcessSingleJobError::Other(anyhow!("Output file did not exist: {:?}",
|
||||
&videos.comfy_output_video_path)));
|
||||
&videos.input_video.comfy_output_video_path)));
|
||||
}
|
||||
|
||||
// ==================== COPY BACK AUDIO ==================== //
|
||||
|
||||
post_process_restore_audio(PostProcessRestoreVideoArgs {
|
||||
comfy_deps: model_dependencies,
|
||||
comfy_deps,
|
||||
videos: &mut videos,
|
||||
});
|
||||
|
||||
// ==================== OPTIONAL WATERMARK ==================== //
|
||||
|
||||
post_process_add_watermark(PostProcessAddWatermarkArgs {
|
||||
comfy_deps: model_dependencies,
|
||||
comfy_deps,
|
||||
videos: &mut videos,
|
||||
});
|
||||
|
||||
// ==================== DEBUG ======================== //
|
||||
|
||||
videos.debug_print_paths_after_post_processing();
|
||||
//videos.debug_print_paths_after_post_processing();
|
||||
|
||||
if let Ok(Some(dimensions)) = ffprobe_get_dimensions(&videos.get_final_video_to_upload()) {
|
||||
if let Ok(Some(dimensions)) = ffprobe_get_dimensions(&videos.input_video.get_final_video_to_upload()) {
|
||||
info!("Final video upload dimensions: {}x{}", dimensions.width, dimensions.height);
|
||||
}
|
||||
|
||||
@@ -447,11 +445,10 @@ pub async fn process_job(args: ComfyProcessJobArgs<'_>) -> Result<JobSuccessResu
|
||||
job,
|
||||
deps: &deps,
|
||||
job_args: &job_args,
|
||||
comfy_deps: model_dependencies,
|
||||
comfy_deps,
|
||||
comfy_args,
|
||||
videos: &videos,
|
||||
job_progress_reporter: &mut job_progress_reporter,
|
||||
download_videos: &download_videos,
|
||||
inference_duration,
|
||||
}).await?;
|
||||
|
||||
@@ -468,13 +465,7 @@ pub async fn process_job(args: ComfyProcessJobArgs<'_>) -> Result<JobSuccessResu
|
||||
|
||||
safe_delete_temp_file(&stderr_output_file);
|
||||
safe_delete_temp_file(&stdout_output_file);
|
||||
//safe_delete_temp_file(&videos.original_video_path);
|
||||
safe_delete_temp_file(&videos.trimmed_resampled_video_path);
|
||||
safe_delete_temp_file(&videos.comfy_output_video_path);
|
||||
safe_delete_temp_file(videos.video_to_watermark());
|
||||
safe_delete_temp_file(videos.get_final_video_to_upload());
|
||||
safe_delete_temp_file(videos.get_non_watermarked_video_to_upload());
|
||||
safe_delete_all_input_videos(&download_videos);
|
||||
safe_delete_all_input_videos(&videos);
|
||||
|
||||
// TODO(bt,2024-03-01): Do we really want to delete the workflow, models, etc.?
|
||||
|
||||
@@ -516,22 +507,33 @@ pub async fn process_job(args: ComfyProcessJobArgs<'_>) -> Result<JobSuccessResu
|
||||
}
|
||||
|
||||
fn safe_delete_all_input_videos(videos: &VideoDownloads) {
|
||||
safe_delete_videos(&videos.input_video);
|
||||
safe_delete_primary_videos(&videos.input_video);
|
||||
|
||||
if let Some(depth) = &videos.maybe_depth {
|
||||
safe_delete_videos(depth);
|
||||
safe_delete_secondary_videos(depth);
|
||||
}
|
||||
|
||||
if let Some(normal) = &videos.maybe_normal {
|
||||
safe_delete_videos(normal);
|
||||
safe_delete_secondary_videos(normal);
|
||||
}
|
||||
|
||||
if let Some(outline) = &videos.maybe_outline {
|
||||
safe_delete_videos(outline);
|
||||
safe_delete_secondary_videos(outline);
|
||||
}
|
||||
}
|
||||
|
||||
fn safe_delete_videos(video: &InputVideoAndPaths) {
|
||||
fn safe_delete_primary_videos(video: &PrimaryInputVideoAndPaths) {
|
||||
safe_delete_temp_file(&video.original_download_path);
|
||||
safe_delete_temp_file(&video.comfy_output_video_path);
|
||||
safe_delete_temp_file(video.video_to_watermark());
|
||||
safe_delete_temp_file(video.get_final_video_to_upload());
|
||||
safe_delete_temp_file(video.get_non_watermarked_video_to_upload());
|
||||
if let Some(processed_path) = &video.maybe_processed_path {
|
||||
safe_delete_temp_file(processed_path);
|
||||
}
|
||||
}
|
||||
|
||||
fn safe_delete_secondary_videos(video: &SecondaryInputVideoAndPaths) {
|
||||
safe_delete_temp_file(&video.original_download_path);
|
||||
if let Some(processed_path) = &video.maybe_processed_path {
|
||||
safe_delete_temp_file(processed_path);
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ use videos::ffprobe_get_dimensions::ffprobe_get_dimensions;
|
||||
|
||||
use crate::job::job_loop::process_single_job_error::ProcessSingleJobError;
|
||||
use crate::job::job_types::workflow::comfy_ui::video_style_transfer::steps::check_and_validate_job::JobArgs;
|
||||
use crate::job::job_types::workflow::comfy_ui::video_style_transfer::video_paths::VideoPaths;
|
||||
use crate::job::job_types::workflow::comfy_ui::video_style_transfer::util::video_pathing_deprecated::VideoPaths;
|
||||
|
||||
const DEFAULT_SUFFIX : &str = ".jpg";
|
||||
|
||||
|
||||
+20
-17
@@ -1,4 +1,4 @@
|
||||
use std::path::PathBuf;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use anyhow::anyhow;
|
||||
use log::{error, info};
|
||||
@@ -14,13 +14,15 @@ use tokens::tokens::media_files::MediaFileToken;
|
||||
use videos::ffprobe_get_dimensions::ffprobe_get_dimensions;
|
||||
|
||||
use crate::job::job_loop::process_single_job_error::ProcessSingleJobError;
|
||||
use crate::job::job_types::workflow::comfy_ui::comfy_ui_dependencies::ComfyDependencies;
|
||||
use crate::job::job_types::workflow::comfy_ui::video_style_transfer::steps::check_and_validate_job::JobArgs;
|
||||
use crate::job::job_types::workflow::comfy_ui::video_style_transfer::util::video_pathing::{InputVideoAndPaths, VideoDownloads, VideoMediaFileRecord};
|
||||
use crate::job::job_types::workflow::comfy_ui::video_style_transfer::video_paths::VideoPaths;
|
||||
use crate::job::job_types::workflow::comfy_ui::video_style_transfer::util::comfy_dirs::ComfyDirs;
|
||||
use crate::job::job_types::workflow::comfy_ui::video_style_transfer::util::video_pathing::{PrimaryInputVideoAndPaths, SecondaryInputVideoAndPaths, VideoDownloads};
|
||||
use crate::job::job_types::workflow::comfy_ui::video_style_transfer::util::video_pathing_deprecated::VideoPaths;
|
||||
|
||||
pub struct DownloadInputVideoArgs<'a> {
|
||||
pub job_args: &'a JobArgs<'a>,
|
||||
pub videos: &'a VideoPaths,
|
||||
pub comfy_dirs: &'a ComfyDirs,
|
||||
pub mysql_pool: &'a MySqlPool,
|
||||
pub remote_cloud_file_client: &'a RemoteCloudFileClient,
|
||||
}
|
||||
@@ -35,7 +37,7 @@ pub async fn download_input_videos(
|
||||
|
||||
// TODO: Consolidate primary video download with secondary download logic.
|
||||
async fn download_primary_video(
|
||||
args: &DownloadInputVideoArgs<'_>
|
||||
args: &DownloadInputVideoArgs<'_>,
|
||||
) -> Result<VideoDownloads, ProcessSingleJobError> {
|
||||
let input_media_file_token = match args.job_args.maybe_input_file {
|
||||
None => return Err(ProcessSingleJobError::InvalidJob(anyhow!("No primary input video file provided"))),
|
||||
@@ -81,7 +83,7 @@ async fn download_primary_video(
|
||||
|
||||
// NB(bt,2024-07-09): This convention is muddled with the python side.
|
||||
// We may not have flexibility to change this pathing for a while.
|
||||
let download_path = args.videos.comfy_input_dir.join("video.mp4");
|
||||
let download_path = args.comfy_dirs.comfy_input_dir.join("video.mp4");
|
||||
|
||||
info!("Downloading primary input file to {:?}", download_path);
|
||||
|
||||
@@ -92,12 +94,13 @@ async fn download_primary_video(
|
||||
|
||||
info!("Downloaded primary input video!");
|
||||
|
||||
// TODO: This monumentally sucks.
|
||||
// The upstream shouldn't be telling us what to do about this at all.
|
||||
let job_output_path = args.job_args.output_path;
|
||||
|
||||
Ok(VideoDownloads {
|
||||
input_video: InputVideoAndPaths {
|
||||
record: VideoMediaFileRecord::Single(input_media_file),
|
||||
original_download_path: download_path,
|
||||
maybe_processed_path: None,
|
||||
},
|
||||
input_video: PrimaryInputVideoAndPaths::new(
|
||||
input_media_file, &args.comfy_dirs, job_output_path),
|
||||
maybe_depth: None,
|
||||
maybe_normal: None,
|
||||
maybe_outline: None,
|
||||
@@ -164,7 +167,7 @@ async fn download_secondary_video(
|
||||
desired_token: &MediaFileToken,
|
||||
all_video_media_files: &[MediaFilesByTokensRecord],
|
||||
args: &DownloadInputVideoArgs<'_>
|
||||
) -> Result<Option<InputVideoAndPaths>, ProcessSingleJobError> {
|
||||
) -> Result<Option<SecondaryInputVideoAndPaths>, ProcessSingleJobError> {
|
||||
|
||||
let file_description = match secondary_video_type {
|
||||
SecondaryVideoType::Depth => "depth video",
|
||||
@@ -173,9 +176,9 @@ async fn download_secondary_video(
|
||||
};
|
||||
|
||||
let download_path = match secondary_video_type {
|
||||
SecondaryVideoType::Depth => args.videos.comfy_input_dir.join("depth_download.mp4"),
|
||||
SecondaryVideoType::Normal => args.videos.comfy_input_dir.join("normal_download.mp4"),
|
||||
SecondaryVideoType::Outline => args.videos.comfy_input_dir.join("outline_download.mp4"),
|
||||
SecondaryVideoType::Depth => args.comfy_dirs.comfy_input_dir.join("depth_download.mp4"),
|
||||
SecondaryVideoType::Normal => args.comfy_dirs.comfy_input_dir.join("normal_download.mp4"),
|
||||
SecondaryVideoType::Outline => args.comfy_dirs.comfy_input_dir.join("outline_download.mp4"),
|
||||
};
|
||||
|
||||
let maybe_media_file = all_video_media_files
|
||||
@@ -205,8 +208,8 @@ async fn download_secondary_video(
|
||||
path_to_string(&download_path)
|
||||
).await?;
|
||||
|
||||
Ok(Some(InputVideoAndPaths {
|
||||
record: VideoMediaFileRecord::Bulk(media_file.clone()),
|
||||
Ok(Some(SecondaryInputVideoAndPaths {
|
||||
record: media_file.clone(),
|
||||
original_download_path: download_path,
|
||||
maybe_processed_path: None,
|
||||
}))
|
||||
|
||||
+6
-4
@@ -3,12 +3,13 @@ use log::{error, info};
|
||||
use filesys::check_file_exists::check_file_exists;
|
||||
|
||||
use crate::job::job_types::workflow::comfy_ui::comfy_ui_dependencies::ComfyDependencies;
|
||||
use crate::job::job_types::workflow::comfy_ui::video_style_transfer::video_paths::VideoPaths;
|
||||
use crate::job::job_types::workflow::comfy_ui::video_style_transfer::util::video_pathing::VideoDownloads;
|
||||
use crate::job::job_types::workflow::comfy_ui::video_style_transfer::util::video_pathing_deprecated::VideoPaths;
|
||||
use crate::util::common_commands::ffmpeg_logo_watermark_command::WatermarkArgs;
|
||||
|
||||
pub struct PostProcessAddWatermarkArgs<'a> {
|
||||
pub comfy_deps: &'a ComfyDependencies,
|
||||
pub videos: &'a mut VideoPaths,
|
||||
pub videos: &'a mut VideoDownloads,
|
||||
}
|
||||
|
||||
/// NB: Purposefully infallible.
|
||||
@@ -21,13 +22,14 @@ pub fn post_process_add_watermark(
|
||||
info!("Adding watermark...");
|
||||
|
||||
let output_video_fs_path_watermark = args.videos
|
||||
.input_video
|
||||
.comfy_output_video_path
|
||||
.with_extension("_watermark.mp4");
|
||||
|
||||
let command_exit_status = args.comfy_deps
|
||||
.ffmpeg_watermark_command
|
||||
.execute(WatermarkArgs {
|
||||
video_path: args.videos.video_to_watermark(),
|
||||
video_path: args.videos.input_video.video_to_watermark(),
|
||||
maybe_override_logo_path: None,
|
||||
alpha: 0.6,
|
||||
scale: 0.1, // NB: 0.1 is good for the Storyteller logo @ 2653x512 placed on 1024x576 output.
|
||||
@@ -49,6 +51,6 @@ pub fn post_process_add_watermark(
|
||||
|
||||
if use_watermarked_file {
|
||||
info!("Success generating watermarked file: {:?}", output_video_fs_path_watermark);
|
||||
args.videos.watermarked_video_path = Some(output_video_fs_path_watermark);
|
||||
args.videos.input_video.watermarked_video_path = Some(output_video_fs_path_watermark);
|
||||
}
|
||||
}
|
||||
|
||||
+17
-5
@@ -6,12 +6,13 @@ use subprocess_common::command_runner::command_runner_args::{RunAsSubprocessArgs
|
||||
|
||||
use crate::job::job_loop::process_single_job_error::ProcessSingleJobError;
|
||||
use crate::job::job_types::workflow::comfy_ui::comfy_ui_dependencies::ComfyDependencies;
|
||||
use crate::job::job_types::workflow::comfy_ui::video_style_transfer::video_paths::VideoPaths;
|
||||
use crate::job::job_types::workflow::comfy_ui::video_style_transfer::util::video_pathing::VideoDownloads;
|
||||
use crate::job::job_types::workflow::comfy_ui::video_style_transfer::util::video_pathing_deprecated::VideoPaths;
|
||||
use crate::util::common_commands::ffmpeg_audio_replace_args::FfmpegAudioReplaceArgs;
|
||||
|
||||
pub struct PostProcessRestoreVideoArgs<'a> {
|
||||
pub comfy_deps: &'a ComfyDependencies,
|
||||
pub videos: &'a mut VideoPaths,
|
||||
pub videos: &'a mut VideoDownloads,
|
||||
}
|
||||
|
||||
/// NB: Purposefully infallible.
|
||||
@@ -20,7 +21,18 @@ pub fn post_process_restore_audio(
|
||||
) -> () {
|
||||
info!("Restoring audio...");
|
||||
|
||||
// Use the original downloaded video if we didn't trim and resample it.
|
||||
let input_video_file = args
|
||||
.videos
|
||||
.input_video
|
||||
.maybe_processed_path
|
||||
.as_deref()
|
||||
.unwrap_or(
|
||||
&args.videos.input_video.original_download_path
|
||||
);
|
||||
|
||||
let output_video_fs_path_restored = args.videos
|
||||
.input_video
|
||||
.comfy_output_video_path
|
||||
.with_extension("_restored.mp4");
|
||||
|
||||
@@ -29,8 +41,8 @@ pub fn post_process_restore_audio(
|
||||
.ffmpeg_command_runner
|
||||
.run_with_subprocess(RunAsSubprocessArgs {
|
||||
args: Box::new(&FfmpegAudioReplaceArgs {
|
||||
input_video_file: &args.videos.comfy_output_video_path,
|
||||
input_audio_file: &args.videos.trimmed_resampled_video_path,
|
||||
input_video_file: &args.videos.input_video.comfy_output_video_path,
|
||||
input_audio_file: &input_video_file,
|
||||
output_video_file: &output_video_fs_path_restored,
|
||||
}),
|
||||
stderr: StreamRedirection::None,
|
||||
@@ -52,6 +64,6 @@ pub fn post_process_restore_audio(
|
||||
|
||||
if use_restored_audio {
|
||||
info!("Success generating restored audio file: {:?}", output_video_fs_path_restored);
|
||||
args.videos.audio_restored_video_path = Some(output_video_fs_path_restored);
|
||||
args.videos.input_video.audio_restored_video_path = Some(output_video_fs_path_restored);
|
||||
}
|
||||
}
|
||||
|
||||
+14
-4
@@ -7,13 +7,14 @@ use subprocess_common::command_runner::command_runner_args::{RunAsSubprocessArgs
|
||||
|
||||
use crate::job::job_loop::process_single_job_error::ProcessSingleJobError;
|
||||
use crate::job::job_types::workflow::comfy_ui::comfy_ui_dependencies::ComfyDependencies;
|
||||
use crate::job::job_types::workflow::comfy_ui::video_style_transfer::video_paths::VideoPaths;
|
||||
use crate::job::job_types::workflow::comfy_ui::video_style_transfer::util::video_pathing::VideoDownloads;
|
||||
use crate::job::job_types::workflow::comfy_ui::video_style_transfer::util::video_pathing_deprecated::VideoPaths;
|
||||
use crate::util::common_commands::ffmpeg_audio_replace_args::FfmpegAudioReplaceArgs;
|
||||
use crate::util::common_commands::ffmpeg_extract_audio_args::FfmpegExtractAudioArgs;
|
||||
|
||||
pub struct ProcessSaveAudioArgs<'a> {
|
||||
pub comfy_deps: &'a ComfyDependencies,
|
||||
pub videos: &'a mut VideoPaths,
|
||||
pub videos: &'a mut VideoDownloads,
|
||||
}
|
||||
|
||||
pub fn preprocess_save_audio(
|
||||
@@ -21,14 +22,23 @@ pub fn preprocess_save_audio(
|
||||
) -> Result<(), ProcessSingleJobError> {
|
||||
info!("Extracting audio...");
|
||||
|
||||
// Use the original downloaded video if we didn't trim and resample it.
|
||||
let input_video_file = args
|
||||
.videos
|
||||
.input_video
|
||||
.maybe_processed_path
|
||||
.as_deref()
|
||||
.unwrap_or(
|
||||
&args.videos.input_video.original_download_path
|
||||
);
|
||||
|
||||
let command_exit_status = args
|
||||
.comfy_deps
|
||||
.ffmpeg_command_runner
|
||||
.run_with_subprocess(RunAsSubprocessArgs {
|
||||
args: Box::new(&FfmpegExtractAudioArgs {
|
||||
input_video_file: &args.videos.trimmed_resampled_video_path,
|
||||
output_file: &args.videos.trimmed_audio_path
|
||||
input_video_file,
|
||||
output_file: &args.videos.input_video.trimmed_audio_path
|
||||
}),
|
||||
stderr: StreamRedirection::None,
|
||||
stdout: StreamRedirection::None,
|
||||
|
||||
+33
-24
@@ -13,21 +13,15 @@ use videos::ffprobe_get_dimensions::ffprobe_get_dimensions;
|
||||
|
||||
use crate::job::job_loop::process_single_job_error::ProcessSingleJobError;
|
||||
use crate::job::job_types::workflow::comfy_ui::comfy_ui_dependencies::ComfyDependencies;
|
||||
use crate::job::job_types::workflow::comfy_ui::video_style_transfer::util::video_pathing::{InputVideoAndPaths, VideoDownloads};
|
||||
use crate::job::job_types::workflow::comfy_ui::video_style_transfer::video_paths::VideoPaths;
|
||||
use crate::job::job_types::workflow::comfy_ui::video_style_transfer::util::comfy_dirs::ComfyDirs;
|
||||
use crate::job::job_types::workflow::comfy_ui::video_style_transfer::util::video_pathing::{SecondaryInputVideoAndPaths, VideoDownloads};
|
||||
use crate::job::job_types::workflow::comfy_ui::video_style_transfer::util::video_pathing_deprecated::VideoPaths;
|
||||
|
||||
pub struct ProcessTrimAndResampleVideoArgs<'a> {
|
||||
pub comfy_args: &'a WorkflowArgs,
|
||||
pub comfy_deps: &'a ComfyDependencies,
|
||||
|
||||
// TODO(bt,2024-07-09): This is going to need refatoring and consolidation for clarity.
|
||||
// 'VideoPaths' was for the original video and all of its resamplings, outputs,
|
||||
// watermarkings, etc. Now that we have depth, normal, and outline map videos (and
|
||||
// possibly more), we're going to need to group these. Those files are referenced by
|
||||
// `VideoDownloadDetails`, which is a better system to keep track of the videos as they
|
||||
// pass through the system.
|
||||
pub primary_video_paths: &'a VideoPaths,
|
||||
pub download_videos: &'a mut VideoDownloads,
|
||||
pub comfy_dirs: &'a ComfyDirs,
|
||||
pub videos: &'a mut VideoDownloads,
|
||||
}
|
||||
|
||||
pub fn preprocess_trim_and_resample_videos(
|
||||
@@ -55,10 +49,18 @@ pub fn preprocess_trim_and_resample_videos(
|
||||
|
||||
let skip_resampling_video = args.comfy_args.skip_process_video.unwrap_or(false);
|
||||
|
||||
preprocess_trim_and_resample_primary_video(&args, &resample_details, skip_resampling_video)?;
|
||||
preprocess_trim_and_resample_primary_video(
|
||||
&args.comfy_deps,
|
||||
&args.comfy_dirs,
|
||||
&resample_details,
|
||||
skip_resampling_video,
|
||||
args.videos)?;
|
||||
|
||||
if !skip_resampling_video {
|
||||
preprocess_trim_and_resample_secondary_videos(&args.comfy_deps, &resample_details, args.download_videos)?;
|
||||
preprocess_trim_and_resample_secondary_videos(
|
||||
&args.comfy_deps,
|
||||
&resample_details,
|
||||
args.videos)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -71,22 +73,26 @@ struct ResampleDetails {
|
||||
}
|
||||
|
||||
fn preprocess_trim_and_resample_primary_video(
|
||||
args: &ProcessTrimAndResampleVideoArgs<'_>,
|
||||
comfy_deps: &ComfyDependencies,
|
||||
comfy_dirs: &ComfyDirs,
|
||||
resample_details: &ResampleDetails,
|
||||
skip_process_video: bool,
|
||||
videos: &mut VideoDownloads,
|
||||
) -> Result<(), ProcessSingleJobError> {
|
||||
|
||||
let resampled_path = comfy_dirs.comfy_input_dir.join("trimmed.mp4");
|
||||
|
||||
if skip_process_video {
|
||||
info!("Skipping video trim / resample...");
|
||||
info!("(This might break if we need to copy the video path. Salt's code implicitly expects videos to be in certain places, but doesn't allow passing of config, and that's horrible.)");
|
||||
|
||||
std::fs::copy(&args.download_videos.input_video.original_download_path, &args.primary_video_paths.trimmed_resampled_video_path)
|
||||
std::fs::copy(&videos.input_video.original_download_path, &resampled_path)
|
||||
.map_err(|err| {
|
||||
error!("Error copying video (1): {:?}", err);
|
||||
ProcessSingleJobError::IoError(err)
|
||||
})?;
|
||||
|
||||
std::fs::copy(&args.download_videos.input_video.original_download_path, &args.primary_video_paths.comfy_output_video_path)
|
||||
std::fs::copy(&videos.input_video.original_download_path, &videos.input_video.comfy_output_video_path)
|
||||
.map_err(|err| {
|
||||
error!("Error copying video (2): {:?}", err);
|
||||
ProcessSingleJobError::IoError(err)
|
||||
@@ -94,23 +100,23 @@ fn preprocess_trim_and_resample_primary_video(
|
||||
|
||||
} else {
|
||||
info!("Calling video trim / resample...");
|
||||
info!("Script: {:?}", &args.comfy_deps.inference_command.processing_script);
|
||||
info!("Script: {:?}", &comfy_deps.inference_command.processing_script);
|
||||
|
||||
// NB(bt,2024-07-09): Despite what the comments on this field say, the script `format_video.py` writes
|
||||
// to a file named 'input.mp4', not 'trimmed.mp4'. This pathing really needs to be cleaned up.
|
||||
let comfy_input_video_path = args.primary_video_paths.comfy_input_dir.join("input.mp4");
|
||||
let comfy_input_video_path = comfy_dirs.comfy_input_dir.join("input.mp4");
|
||||
|
||||
// shell out to python script
|
||||
let output = Command::new("python3")
|
||||
.stdout(Stdio::inherit()) // NB: This should emit to the rust job's stdout
|
||||
.stderr(Stdio::inherit()) // NB: This should emit to the rust job's stderr
|
||||
.arg(path_to_string(&args.comfy_deps.inference_command.processing_script))
|
||||
.arg(path_to_string(&comfy_deps.inference_command.processing_script))
|
||||
.arg("DO_NOT_USE_THIS_ARG_ANYMORE")
|
||||
.arg(format!("{:?}", resample_details.trim_start_millis))
|
||||
.arg(format!("{:?}", resample_details.trim_end_millis))
|
||||
.arg(format!("{:?}", resample_details.target_fps))
|
||||
.arg("--input")
|
||||
.arg(path_to_string(&args.download_videos.input_video.original_download_path))
|
||||
.arg(path_to_string(&videos.input_video.original_download_path))
|
||||
.arg("--output")
|
||||
// NB(bt,2024-07-09): Despite what the comments on this field say, the script `format_video.py` writes
|
||||
// to a file named 'input.mp4', not 'trimmed.mp4'. This pathing really needs to be cleaned up.
|
||||
@@ -134,19 +140,22 @@ fn preprocess_trim_and_resample_primary_video(
|
||||
|
||||
// NB: The process video script implicitly saves the above video as "input.mp4"
|
||||
// Comfy sometimes overwrites this, so we need to make a copy.
|
||||
std::fs::copy(&comfy_input_video_path, &args.primary_video_paths.trimmed_resampled_video_path)
|
||||
std::fs::copy(&comfy_input_video_path, &resampled_path)
|
||||
.map_err(|err| {
|
||||
error!("Error copying trimmed video: {:?}", err);
|
||||
ProcessSingleJobError::IoError(err)
|
||||
})?;
|
||||
}
|
||||
|
||||
args.primary_video_paths.debug_print_paths_after_trim();
|
||||
//primary_video_paths.debug_print_paths_after_trim();
|
||||
|
||||
if let Ok(Some(dimensions)) = ffprobe_get_dimensions(&args.primary_video_paths.trimmed_resampled_video_path) {
|
||||
if let Ok(Some(dimensions)) = ffprobe_get_dimensions(&resampled_path) {
|
||||
info!("Trimmed / resampled video dimensions: {}x{}", dimensions.width, dimensions.height);
|
||||
}
|
||||
|
||||
// NB(bt,2024-07-10): Even if we don't resample, the python side still expects certain pathing for now
|
||||
videos.input_video.maybe_processed_path = Some(resampled_path);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -177,7 +186,7 @@ fn preprocess_trim_and_resample_secondary_videos(
|
||||
fn preprocess_trim_and_resample_secondary_video(
|
||||
comfy_deps: &ComfyDependencies,
|
||||
resample_details: &ResampleDetails,
|
||||
video: &InputVideoAndPaths,
|
||||
video: &SecondaryInputVideoAndPaths,
|
||||
) -> Result<PathBuf, ProcessSingleJobError> {
|
||||
info!("Calling video trim / resample...");
|
||||
info!("Script: {:?}", &comfy_deps.inference_command.processing_script);
|
||||
|
||||
+10
-11
@@ -34,7 +34,7 @@ use crate::job::job_types::workflow::comfy_ui::comfy_process_job_args::ComfyProc
|
||||
use crate::job::job_types::workflow::comfy_ui::comfy_ui_dependencies::ComfyDependencies;
|
||||
use crate::job::job_types::workflow::comfy_ui::video_style_transfer::steps::check_and_validate_job::JobArgs;
|
||||
use crate::job::job_types::workflow::comfy_ui::video_style_transfer::util::video_pathing::VideoDownloads;
|
||||
use crate::job::job_types::workflow::comfy_ui::video_style_transfer::video_paths::VideoPaths;
|
||||
use crate::job::job_types::workflow::comfy_ui::video_style_transfer::util::video_pathing_deprecated::VideoPaths;
|
||||
use crate::job_dependencies::JobDependencies;
|
||||
|
||||
fn get_file_extension(mimetype: &str) -> anyhow::Result<&'static str> {
|
||||
@@ -55,8 +55,7 @@ pub struct SaveResultsArgs<'a> {
|
||||
pub comfy_deps: &'a ComfyDependencies,
|
||||
pub job_progress_reporter: &'a mut Box<dyn JobProgressReporter>,
|
||||
|
||||
pub download_videos: &'a VideoDownloads,
|
||||
pub videos: &'a VideoPaths,
|
||||
pub videos: &'a VideoDownloads,
|
||||
pub inference_duration: Duration,
|
||||
|
||||
pub comfy_args: &'a WorkflowArgs,
|
||||
@@ -71,7 +70,7 @@ pub async fn validate_and_save_results(args: SaveResultsArgs<'_>) -> Result<Medi
|
||||
|
||||
info!("Interrogating result file size ...");
|
||||
|
||||
let final_video = args.videos.get_final_video_to_upload();
|
||||
let final_video = args.videos.input_video.get_final_video_to_upload();
|
||||
|
||||
let file_size_bytes = file_size(final_video)
|
||||
.map_err(|err| ProcessSingleJobError::Other(err))?;
|
||||
@@ -175,7 +174,7 @@ pub async fn validate_and_save_results(args: SaveResultsArgs<'_>) -> Result<Medi
|
||||
|
||||
let result = args.deps.buckets.public_bucket_client.upload_filename_with_content_type(
|
||||
&result_bucket_object_pathbuf.with_extension("no_watermark.mp4"),
|
||||
&args.videos.get_non_watermarked_video_to_upload(),
|
||||
&args.videos.input_video.get_non_watermarked_video_to_upload(),
|
||||
&mimetype) // TODO: We should check the mimetype to make sure bad payloads can't get uploaded
|
||||
.await;
|
||||
|
||||
@@ -200,9 +199,9 @@ pub async fn validate_and_save_results(args: SaveResultsArgs<'_>) -> Result<Medi
|
||||
// This also lets us hide the engine renders from users.
|
||||
// This shouldn't ever become a deeply nested tree of children, but rather a single root
|
||||
// with potentially many direct children.
|
||||
let style_transfer_source_media_file_token = args.download_videos
|
||||
.input_video.record.maybe_style_transfer_source_media_file_token()?
|
||||
.unwrap_or_else(|| args.download_videos.input_video.record.token());
|
||||
let style_transfer_source_media_file_token = args.videos
|
||||
.input_video.record.maybe_style_transfer_source_media_file_token.as_ref()
|
||||
.unwrap_or_else(|| &args.videos.input_video.record.token);
|
||||
|
||||
let prompt_token = PromptToken::generate();
|
||||
|
||||
@@ -210,10 +209,10 @@ pub async fn validate_and_save_results(args: SaveResultsArgs<'_>) -> Result<Medi
|
||||
pool: &args.deps.db.mysql_pool,
|
||||
job: &args.job,
|
||||
maybe_mime_type: Some(&mimetype),
|
||||
maybe_title: args.download_videos.input_video.record.maybe_title(),
|
||||
maybe_title: args.videos.input_video.record.maybe_title.as_deref(),
|
||||
maybe_style_transfer_source_media_file_token: Some(&style_transfer_source_media_file_token),
|
||||
maybe_scene_source_media_file_token: args.download_videos
|
||||
.input_video.record.maybe_scene_source_media_file_token()?,
|
||||
maybe_scene_source_media_file_token: args.videos
|
||||
.input_video.record.maybe_scene_source_media_file_token.as_ref(),
|
||||
file_size_bytes,
|
||||
sha256_checksum: &file_checksum,
|
||||
maybe_prompt_token: Some(&prompt_token),
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::job::job_types::workflow::comfy_ui::comfy_ui_dependencies::ComfyDependencies;
|
||||
|
||||
/// This is a temporary measure until we start using tempdirs for intermediate inputs and outputs.
|
||||
pub struct ComfyDirs {
|
||||
pub comfy_input_dir: PathBuf,
|
||||
pub comfy_output_dir: PathBuf,
|
||||
|
||||
}
|
||||
|
||||
impl ComfyDirs {
|
||||
pub fn new(comfy_deps: &ComfyDependencies) -> Self {
|
||||
// TODO(bt,2024-04-21): The pathing for this job is complicated. ComfyUI
|
||||
// was set up with some of these expectations, which is bad. Worse, the
|
||||
// jobs enqueue the expected output path -- no idea why that was done.
|
||||
// This should all be fixed.
|
||||
let root_comfy_path = comfy_deps.inference_command.mounts_directory.as_path();
|
||||
Self {
|
||||
comfy_input_dir: root_comfy_path.join("input"),
|
||||
comfy_output_dir: root_comfy_path.join("output"),
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-1
@@ -1,2 +1,5 @@
|
||||
pub mod comfy_dirs;
|
||||
pub mod comfy_ui_inference_command;
|
||||
pub mod video_pathing;
|
||||
pub mod video_pathing;
|
||||
pub mod video_pathing_deprecated;
|
||||
pub mod write_workflow_prompt;
|
||||
+151
-43
@@ -1,4 +1,4 @@
|
||||
use std::path::PathBuf;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use anyhow::anyhow;
|
||||
|
||||
@@ -7,63 +7,171 @@ use mysql_queries::queries::media_files::get::get_media_file::MediaFile;
|
||||
use tokens::tokens::media_files::MediaFileToken;
|
||||
|
||||
use crate::job::job_loop::process_single_job_error::ProcessSingleJobError;
|
||||
use crate::job::job_types::workflow::comfy_ui::video_style_transfer::util::comfy_dirs::ComfyDirs;
|
||||
|
||||
/// Keep track of where we download videos to and where they end up after processing.
|
||||
pub struct VideoDownloads {
|
||||
/// The main video
|
||||
pub input_video: InputVideoAndPaths,
|
||||
pub input_video: PrimaryInputVideoAndPaths,
|
||||
|
||||
// Secondary videos that provide enrichment signals.
|
||||
pub maybe_depth: Option<InputVideoAndPaths>,
|
||||
pub maybe_normal: Option<InputVideoAndPaths>,
|
||||
pub maybe_outline: Option<InputVideoAndPaths>,
|
||||
pub maybe_depth: Option<SecondaryInputVideoAndPaths>,
|
||||
pub maybe_normal: Option<SecondaryInputVideoAndPaths>,
|
||||
pub maybe_outline: Option<SecondaryInputVideoAndPaths>,
|
||||
}
|
||||
|
||||
/// This is the primary input video for style transfer.
|
||||
pub struct PrimaryInputVideoAndPaths {
|
||||
/// Media file record.
|
||||
pub record: MediaFile,
|
||||
|
||||
/// Filesystem path of the downloaded original video
|
||||
/// This is the input.
|
||||
pub original_download_path: PathBuf,
|
||||
|
||||
// TODO: Rename back to `trimmed_resampled...`
|
||||
/// Filesystem path of the trimmed and resampled video
|
||||
/// This is the first output we generate.
|
||||
/// We'll use this downstream once it's available.
|
||||
pub maybe_processed_path: Option<PathBuf>, //pub trimmed_resampled_video_path: PathBuf,
|
||||
|
||||
/// Filesystem path of the trimmed audio
|
||||
pub trimmed_audio_path: PathBuf,
|
||||
|
||||
/// This is the input into Comfy.
|
||||
/// This is typically the `trimmed_resampled_video_path`, but since Comfy
|
||||
/// can overwrite the source, we'll keep a separate copy of that file for
|
||||
/// later downstream sound restoration (since comfy wipes sound).
|
||||
pub comfy_input_video_path: PathBuf,
|
||||
|
||||
/// Filesystem path of the style transfer output
|
||||
/// This is the main purpose of the job, and the second output we generate.
|
||||
pub comfy_output_video_path: PathBuf,
|
||||
|
||||
/// Filesystem path of the audio-restored output
|
||||
/// This is the third output we generate.
|
||||
/// We'll want to upload this as a result, if available.
|
||||
pub audio_restored_video_path: Option<PathBuf>,
|
||||
|
||||
/// Watermarked final result
|
||||
/// This is the fourth output we generate.
|
||||
/// We'll want to upload this as a result, if available.
|
||||
pub watermarked_video_path: Option<PathBuf>,
|
||||
|
||||
// Nasty hack to reuse this elsewhere.
|
||||
pub comfy_input_dir: PathBuf,
|
||||
}
|
||||
|
||||
|
||||
/// This is for the secondary depth, normal, and outline videos.
|
||||
/// We attach metadata as these videos progress through the system (if they're present).
|
||||
pub struct InputVideoAndPaths {
|
||||
pub record: VideoMediaFileRecord,
|
||||
pub struct SecondaryInputVideoAndPaths {
|
||||
/// Media file record.
|
||||
pub record: MediaFilesByTokensRecord,
|
||||
|
||||
/// Filesystem path of the downloaded original video
|
||||
pub original_download_path: PathBuf,
|
||||
|
||||
/// Filesystem path of the trimmed and resampled video
|
||||
pub maybe_processed_path: Option<PathBuf>,
|
||||
}
|
||||
|
||||
// Adapter enum
|
||||
pub enum VideoMediaFileRecord {
|
||||
// Records returned by single lookup
|
||||
Single(MediaFile),
|
||||
// Records returned by batch query
|
||||
Bulk(MediaFilesByTokensRecord),
|
||||
// pub enum VideoMediaFileRecord {
|
||||
// // Records returned by single lookup
|
||||
// Single(MediaFile),
|
||||
// // Records returned by batch query
|
||||
// Bulk(MediaFilesByTokensRecord),
|
||||
// }
|
||||
|
||||
pub trait CommonVideoPathing {
|
||||
fn original_video_path(&self) -> &Path;
|
||||
}
|
||||
|
||||
impl VideoMediaFileRecord {
|
||||
pub fn token(&self) -> &MediaFileToken {
|
||||
match self {
|
||||
VideoMediaFileRecord::Single(m) => &m.token,
|
||||
VideoMediaFileRecord::Bulk(m) => &m.token,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn maybe_title(&self) -> Option<&str> {
|
||||
match self {
|
||||
VideoMediaFileRecord::Single(m) => m.maybe_title.as_deref(),
|
||||
VideoMediaFileRecord::Bulk(m) => m.maybe_title.as_deref(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn maybe_style_transfer_source_media_file_token(&self) -> Result<Option<&MediaFileToken>, ProcessSingleJobError> {
|
||||
// TODO(bt,2024-07-09): Future proofing this to deliberately explode in case I query the
|
||||
// primary input media files with the bulk query.
|
||||
match self {
|
||||
VideoMediaFileRecord::Single(m) => Ok(m.maybe_style_transfer_source_media_file_token.as_ref()),
|
||||
VideoMediaFileRecord::Bulk(_m) => Err(ProcessSingleJobError::Other(anyhow!("bad refactor?: failed to query foreign key"))),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn maybe_scene_source_media_file_token(&self) -> Result<Option<&MediaFileToken>, ProcessSingleJobError> {
|
||||
// TODO(bt,2024-07-09): Future proofing this to deliberately explode in case I query the
|
||||
// primary input media files with the bulk query.
|
||||
match self {
|
||||
VideoMediaFileRecord::Single(m) => Ok(m.maybe_scene_source_media_file_token.as_ref()),
|
||||
VideoMediaFileRecord::Bulk(_m) => Err(ProcessSingleJobError::Other(anyhow!("bad refactor?: failed to query foreign key"))),
|
||||
}
|
||||
impl CommonVideoPathing for PrimaryInputVideoAndPaths {
|
||||
fn original_video_path(&self) -> &Path {
|
||||
self.original_download_path.as_path()
|
||||
}
|
||||
}
|
||||
|
||||
impl CommonVideoPathing for SecondaryInputVideoAndPaths {
|
||||
fn original_video_path(&self) -> &Path {
|
||||
self.original_download_path.as_path()
|
||||
}
|
||||
}
|
||||
|
||||
impl PrimaryInputVideoAndPaths {
|
||||
pub fn new(media_file_record: MediaFile, comfy_dirs: &ComfyDirs, job_output_path: &str) -> Self {
|
||||
let original_video_path = comfy_dirs.comfy_input_dir.join("video.mp4");
|
||||
let trimmed_resampled_video_path = comfy_dirs.comfy_input_dir.join("trimmed.mp4");
|
||||
let trimmed_audio_path = comfy_dirs.comfy_input_dir.join("trimmed.wav");
|
||||
let comfy_input_video_path = comfy_dirs.comfy_input_dir.join("input.mp4");
|
||||
let comfy_output_video_path = comfy_dirs.comfy_output_dir.join(job_output_path); // TODO: This sucks.
|
||||
|
||||
Self {
|
||||
record: media_file_record,
|
||||
original_download_path: original_video_path,
|
||||
maybe_processed_path: Some(trimmed_resampled_video_path),
|
||||
trimmed_audio_path,
|
||||
comfy_input_video_path,
|
||||
comfy_output_video_path,
|
||||
audio_restored_video_path: None,
|
||||
watermarked_video_path: None,
|
||||
comfy_input_dir: comfy_dirs.comfy_input_dir.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn video_to_watermark(&self) -> &PathBuf {
|
||||
// Try to use the audio-restored video if it's available
|
||||
self.audio_restored_video_path.as_ref()
|
||||
.unwrap_or(&self.comfy_output_video_path)
|
||||
}
|
||||
|
||||
pub fn get_final_video_to_upload(&self) -> &PathBuf {
|
||||
// This is the video to upload as the result and save in the media_files table.
|
||||
self.watermarked_video_path.as_ref()
|
||||
.or(self.audio_restored_video_path.as_ref())
|
||||
.unwrap_or(&self.comfy_output_video_path)
|
||||
}
|
||||
|
||||
pub fn get_non_watermarked_video_to_upload(&self) -> &PathBuf {
|
||||
// We'll upload this for internal use and for premium users.
|
||||
// Same as "video_to_watermark()"
|
||||
self.audio_restored_video_path.as_ref()
|
||||
.unwrap_or(&self.comfy_output_video_path)
|
||||
}
|
||||
}
|
||||
|
||||
// impl VideoMediaFileRecord {
|
||||
// pub fn token(&self) -> &MediaFileToken {
|
||||
// match self {
|
||||
// VideoMediaFileRecord::Single(m) => &m.token,
|
||||
// VideoMediaFileRecord::Bulk(m) => &m.token,
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// pub fn maybe_title(&self) -> Option<&str> {
|
||||
// match self {
|
||||
// VideoMediaFileRecord::Single(m) => m.maybe_title.as_deref(),
|
||||
// VideoMediaFileRecord::Bulk(m) => m.maybe_title.as_deref(),
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// pub fn maybe_style_transfer_source_media_file_token(&self) -> Result<Option<&MediaFileToken>, ProcessSingleJobError> {
|
||||
// // TODO(bt,2024-07-09): Future proofing this to deliberately explode in case I query the
|
||||
// // primary input media files with the bulk query.
|
||||
// match self {
|
||||
// VideoMediaFileRecord::Single(m) => Ok(m.maybe_style_transfer_source_media_file_token.as_ref()),
|
||||
// VideoMediaFileRecord::Bulk(_m) => Err(ProcessSingleJobError::Other(anyhow!("bad refactor?: failed to query foreign key"))),
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// pub fn maybe_scene_source_media_file_token(&self) -> Result<Option<&MediaFileToken>, ProcessSingleJobError> {
|
||||
// // TODO(bt,2024-07-09): Future proofing this to deliberately explode in case I query the
|
||||
// // primary input media files with the bulk query.
|
||||
// match self {
|
||||
// VideoMediaFileRecord::Single(m) => Ok(m.maybe_scene_source_media_file_token.as_ref()),
|
||||
// VideoMediaFileRecord::Bulk(_m) => Err(ProcessSingleJobError::Other(anyhow!("bad refactor?: failed to query foreign key"))),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
+1
-2
@@ -4,10 +4,10 @@ use log::info;
|
||||
|
||||
use filesys::file_exists::file_exists;
|
||||
|
||||
#[deprecated]
|
||||
pub struct VideoPaths {
|
||||
/// Filesystem path of the downloaded original video
|
||||
/// This is the input.
|
||||
#[deprecated(note = "Use InputVideoAndPaths")]
|
||||
original_video_path: PathBuf,
|
||||
|
||||
/// Filesystem path of the trimmed and resampled video
|
||||
@@ -22,7 +22,6 @@ pub struct VideoPaths {
|
||||
/// This is typically the `trimmed_resampled_video_path`, but since Comfy
|
||||
/// can overwrite the source, we'll keep a separate copy of that file for
|
||||
/// later downstream sound restoration (since comfy wipes sound).
|
||||
#[deprecated(note = "Use InputVideoAndPaths")]
|
||||
pub comfy_input_video_path: PathBuf,
|
||||
|
||||
/// Filesystem path of the style transfer output
|
||||
Reference in New Issue
Block a user