From: Good Guy Date: Tue, 19 Sep 2017 17:19:31 +0000 (-0600) Subject: add proxy X-Git-Url: https://cinelerra-gg.org/git/?a=commitdiff_plain;h=0c36fdb4fc4d4a2efe353e2b6eb0bf5a1b1485d6;p=goodguy%2Fhistory.git add proxy --- diff --git a/cinelerra-5.1/cinelerra/Makefile b/cinelerra-5.1/cinelerra/Makefile index 240a8c7e..6fe88355 100644 --- a/cinelerra-5.1/cinelerra/Makefile +++ b/cinelerra-5.1/cinelerra/Makefile @@ -231,6 +231,7 @@ OBJS = \ $(OBJDIR)/preferences.o \ $(OBJDIR)/preferencesthread.o \ $(OBJDIR)/probeprefs.o \ + $(OBJDIR)/proxy.o \ $(OBJDIR)/question.o \ $(OBJDIR)/quit.o \ $(OBJDIR)/recconfirmdelete.o \ diff --git a/cinelerra-5.1/cinelerra/edl.C b/cinelerra-5.1/cinelerra/edl.C index 5d9ff496..591b4ca9 100644 --- a/cinelerra-5.1/cinelerra/edl.C +++ b/cinelerra-5.1/cinelerra/edl.C @@ -1061,7 +1061,8 @@ int EDL::dump(FILE *fp) " output_h: %d\n" " aspect_w: %f\n" " aspect_h: %f\n" - " color_model: %d\n", + " color_model: %d\n" + " proxy_scale: %d\n", session->video_channels, session->video_tracks, session->frame_rate, @@ -1070,7 +1071,8 @@ int EDL::dump(FILE *fp) session->output_h, session->aspect_w, session->aspect_h, - session->color_model); + session->color_model, + session->proxy_scale); fprintf(fp," CLIPS\n"); fprintf(fp," total: %d\n", clips.total); diff --git a/cinelerra-5.1/cinelerra/edlsession.C b/cinelerra-5.1/cinelerra/edlsession.C index 1a83545e..c65e53f1 100644 --- a/cinelerra-5.1/cinelerra/edlsession.C +++ b/cinelerra-5.1/cinelerra/edlsession.C @@ -98,6 +98,7 @@ EDLSession::EDLSession(EDL *edl) playback_buffer = 4096; playback_cursor_visible = 0; playback_preload = 0; + proxy_scale = 1; decode_subtitles = 0; subtitle_number = 0; label_cells = 0; @@ -165,21 +166,23 @@ int EDLSession::need_rerender(EDLSession *ptr) (decode_subtitles != ptr->decode_subtitles) || (subtitle_number != ptr->subtitle_number) || (interpolate_raw != ptr->interpolate_raw) || - (white_balance_raw != ptr->white_balance_raw)); + (white_balance_raw != ptr->white_balance_raw) || + (proxy_scale != ptr->proxy_scale)); } void EDLSession::equivalent_output(EDLSession *session, double *result) { - if(session->output_w != output_w || - session->output_h != output_h || - !EQUIV(session->frame_rate, frame_rate) || - session->color_model != color_model || - session->interpolation_type != interpolation_type || - session->interpolate_raw != interpolate_raw || - session->white_balance_raw != white_balance_raw || - session->mpeg4_deblock != mpeg4_deblock || - session->decode_subtitles != decode_subtitles || - session->subtitle_number != subtitle_number) + if( session->output_w != output_w || + session->output_h != output_h || + !EQUIV(session->frame_rate, frame_rate) || + session->color_model != color_model || + session->interpolation_type != interpolation_type || + session->interpolate_raw != interpolate_raw || + session->white_balance_raw != white_balance_raw || + session->mpeg4_deblock != mpeg4_deblock || + session->decode_subtitles != decode_subtitles || + session->subtitle_number != subtitle_number || + session->proxy_scale != proxy_scale ) *result = 0; // If it's before the current brender_start, render extra data. @@ -281,6 +284,7 @@ int EDLSession::load_defaults(BC_Hash *defaults) delete playback_config; playback_config = new PlaybackConfig; playback_config->load_defaults(defaults); +// proxy_scale = defaults->get("PROXY_SCALE", 1); real_time_playback = defaults->get("PLAYBACK_REALTIME", 0); real_time_record = defaults->get("REALTIME_RECORD", 0); record_positioning = defaults->get("RECORD_POSITIONING", 1); @@ -422,6 +426,7 @@ int EDLSession::save_defaults(BC_Hash *defaults) defaults->update("PLAYBACK_SOFTWARE_POSITION", playback_software_position); playback_config->save_defaults(defaults); defaults->update("PLAYBACK_REALTIME", real_time_playback); +// defaults->update("PROXY_SCALE", proxy_scale); defaults->update("REALTIME_RECORD", real_time_record); defaults->update("RECORD_POSITIONING", record_positioning); defaults->update("RECORD_RAW_STREAM", record_raw_stream); @@ -489,6 +494,7 @@ void EDLSession::boundaries() Workarounds::clamp(min_meter_db, -80, -20); Workarounds::clamp(max_meter_db, 0, 10); Workarounds::clamp(frames_per_foot, 1, 32); + Workarounds::clamp(proxy_scale, 1, 32); Workarounds::clamp(output_w, 16, (int)BC_INFINITY); Workarounds::clamp(output_h, 16, (int)BC_INFINITY); Workarounds::clamp(video_write_length, 1, 1000); @@ -546,6 +552,7 @@ int EDLSession::load_video_config(FileXML *file, int append_mode, uint32_t load_ output_h = file->tag.get_property("OUTPUTH", output_h); aspect_w = file->tag.get_property("ASPECTW", aspect_w); aspect_h = file->tag.get_property("ASPECTH", aspect_h); + proxy_scale = file->tag.get_property("PROXY_SCALE", proxy_scale); return 0; } @@ -735,6 +742,7 @@ int EDLSession::save_video_config(FileXML *file) file->tag.set_property("OUTPUTH", output_h); file->tag.set_property("ASPECTW", aspect_w); file->tag.set_property("ASPECTH", aspect_h); + file->tag.set_property("PROXY_SCALE", proxy_scale); file->append_tag(); file->tag.set_title("/VIDEO"); file->append_tag(); @@ -873,6 +881,7 @@ int EDLSession::copy(EDLSession *session) view_follows_playback = session->view_follows_playback; vwindow_meter = session->vwindow_meter; vwindow_zoom = session->vwindow_zoom; + proxy_scale = session->proxy_scale; subtitle_number = session->subtitle_number; decode_subtitles = session->decode_subtitles; @@ -887,9 +896,11 @@ void EDLSession::dump() printf("EDLSession::dump\n"); printf(" audio_tracks=%d audio_channels=%d sample_rate=%jd\n" " video_tracks=%d frame_rate=%f output_w=%d output_h=%d aspect_w=%f aspect_h=%f\n" - " decode subtitles=%d subtitle_number=%d label_cells=%d program_no=%d\n", + " decode subtitles=%d subtitle_number=%d label_cells=%d program_no=%d\n" + " proxy_scale=%d\n", audio_tracks, audio_channels, sample_rate, video_tracks, frame_rate, output_w, output_h, aspect_w, aspect_h, - decode_subtitles, subtitle_number, label_cells, program_no); + decode_subtitles, subtitle_number, label_cells, program_no, + proxy_scale); } diff --git a/cinelerra-5.1/cinelerra/edlsession.h b/cinelerra-5.1/cinelerra/edlsession.h index 44838fa8..eddced8e 100644 --- a/cinelerra-5.1/cinelerra/edlsession.h +++ b/cinelerra-5.1/cinelerra/edlsession.h @@ -159,6 +159,8 @@ public: int label_cells; int program_no; int playback_software_position; +// current settings are scaled this much from the original settings + int proxy_scale; // int playback_strategy; // Play audio in realtime priority int real_time_playback; diff --git a/cinelerra-5.1/cinelerra/floatauto.h b/cinelerra-5.1/cinelerra/floatauto.h index 7049c59e..be0b304e 100644 --- a/cinelerra-5.1/cinelerra/floatauto.h +++ b/cinelerra-5.1/cinelerra/floatauto.h @@ -32,6 +32,7 @@ class FloatAuto; class FloatAuto : public Auto { + friend class FloatAutos; public: FloatAuto() {}; FloatAuto(EDL *edl, FloatAutos *autos); diff --git a/cinelerra-5.1/cinelerra/floatautos.C b/cinelerra-5.1/cinelerra/floatautos.C index fde4a155..4ee1d407 100644 --- a/cinelerra-5.1/cinelerra/floatautos.C +++ b/cinelerra-5.1/cinelerra/floatautos.C @@ -409,6 +409,22 @@ void FloatAutos::get_extents(float *min, } } +void FloatAutos::set_proxy(int orig_scale, int new_scale) +{ + float orig_value; + orig_value = ((FloatAuto*)default_auto)->value * orig_scale; + ((FloatAuto*)default_auto)->value = orig_value / new_scale; + + for( FloatAuto *current= (FloatAuto*)first; current; current=(FloatAuto*)NEXT ) { + orig_value = current->value * orig_scale; + current->value = orig_value / new_scale; + orig_value = current->control_in_value * orig_scale; + current->control_in_value = orig_value / new_scale; + orig_value = current->control_out_value * orig_scale; + current->control_out_value = orig_value / new_scale; + } +} + void FloatAutos::dump() { printf(" FloatAutos::dump %p\n", this); diff --git a/cinelerra-5.1/cinelerra/floatautos.h b/cinelerra-5.1/cinelerra/floatautos.h index d83f1509..96d06d63 100644 --- a/cinelerra-5.1/cinelerra/floatautos.h +++ b/cinelerra-5.1/cinelerra/floatautos.h @@ -63,6 +63,7 @@ public: int64_t unit_end); void set_automation_mode(int64_t start, int64_t end, int mode); + void set_proxy(int orig_scale, int new_scale); double automation_integral(int64_t start, int64_t length, int direction); void dump(); diff --git a/cinelerra-5.1/cinelerra/indexable.C b/cinelerra-5.1/cinelerra/indexable.C index e7f090c4..a038b330 100644 --- a/cinelerra-5.1/cinelerra/indexable.C +++ b/cinelerra-5.1/cinelerra/indexable.C @@ -54,7 +54,7 @@ int64_t Indexable::get_audio_samples() return 0; } -void Indexable::update_path(char *new_path) +void Indexable::update_path(const char *new_path) { strcpy(path, new_path); } diff --git a/cinelerra-5.1/cinelerra/indexable.h b/cinelerra-5.1/cinelerra/indexable.h index a9b13277..fa9db6ae 100644 --- a/cinelerra-5.1/cinelerra/indexable.h +++ b/cinelerra-5.1/cinelerra/indexable.h @@ -49,7 +49,7 @@ public: virtual int64_t get_video_frames(); void copy_indexable(Indexable *src); - void update_path(char *new_path); + void update_path(const char *new_path); void update_index(Indexable *src); IndexState *index_state; diff --git a/cinelerra-5.1/cinelerra/mainmenu.C b/cinelerra-5.1/cinelerra/mainmenu.C index a3fb4038..a36efcce 100644 --- a/cinelerra-5.1/cinelerra/mainmenu.C +++ b/cinelerra-5.1/cinelerra/mainmenu.C @@ -60,6 +60,7 @@ #include "patchbay.h" #include "playbackengine.h" #include "preferences.h" +#include "proxy.h" #include "preferencesthread.h" #include "quit.h" #include "record.h" @@ -203,6 +204,9 @@ void MainMenu::create_objects() settingsmenu->add_item(new SetFormat(mwindow)); settingsmenu->add_item(preferences = new PreferencesMenuitem(mwindow)); + ProxyMenuItem *proxy; + settingsmenu->add_item(proxy = new ProxyMenuItem(mwindow)); + proxy->create_objects(); mwindow->preferences_thread = preferences->thread; settingsmenu->add_item(labels_follow_edits = new LabelsFollowEdits(mwindow)); settingsmenu->add_item(plugins_follow_edits = new PluginsFollowEdits(mwindow)); diff --git a/cinelerra-5.1/cinelerra/maskautos.C b/cinelerra-5.1/cinelerra/maskautos.C index e67c4ea2..843d76ee 100644 --- a/cinelerra-5.1/cinelerra/maskautos.C +++ b/cinelerra-5.1/cinelerra/maskautos.C @@ -294,4 +294,11 @@ void MaskAutos::translate_masks(float translate_x, float translate_y) } } +void MaskAutos::set_proxy(int orig_scale, int new_scale) +{ + ((MaskAuto *)default_auto)->scale_submasks(orig_scale, new_scale); + for( MaskAuto* current=(MaskAuto*)first; current; current=(MaskAuto*)NEXT ) { + current->scale_submasks(orig_scale, new_scale); + } +} diff --git a/cinelerra-5.1/cinelerra/maskautos.h b/cinelerra-5.1/cinelerra/maskautos.h index e28c0233..fcac125a 100644 --- a/cinelerra-5.1/cinelerra/maskautos.h +++ b/cinelerra-5.1/cinelerra/maskautos.h @@ -60,9 +60,7 @@ public: int total_submasks(int64_t position, int direction); // Translates all mask points void translate_masks(float translate_x, float translate_y); + void set_proxy(int orig_scale, int new_scale); }; - - - #endif diff --git a/cinelerra-5.1/cinelerra/mwindow.h b/cinelerra-5.1/cinelerra/mwindow.h index 0bbcfe2c..22f43e54 100644 --- a/cinelerra-5.1/cinelerra/mwindow.h +++ b/cinelerra-5.1/cinelerra/mwindow.h @@ -492,6 +492,8 @@ public: int modify_edithandles(); int modify_pluginhandles(); void finish_modify_handles(); + void set_proxy(int new_scale, + ArrayList *orig_assets, ArrayList *proxy_assets); void dump_plugins(FILE *fp=stdout); void dump_edl(FILE *fp=stdout); diff --git a/cinelerra-5.1/cinelerra/mwindow.inc b/cinelerra-5.1/cinelerra/mwindow.inc index f685d018..48d26484 100644 --- a/cinelerra-5.1/cinelerra/mwindow.inc +++ b/cinelerra-5.1/cinelerra/mwindow.inc @@ -106,6 +106,7 @@ N_("Cinelerra: Preferences") N_("Cinelerra: Probes") N_("Cinelerra: Program") N_("Cinelerra: Projector") +N_("Cinelerra: Proxy settings") N_("Cinelerra: Question") N_("Cinelerra: Record") N_("Cinelerra: Recording") diff --git a/cinelerra-5.1/cinelerra/mwindowedit.C b/cinelerra-5.1/cinelerra/mwindowedit.C index 7710d4ad..a0e9b955 100644 --- a/cinelerra-5.1/cinelerra/mwindowedit.C +++ b/cinelerra-5.1/cinelerra/mwindowedit.C @@ -2274,6 +2274,53 @@ void MWindow::remap_audio(int pattern) } } +void MWindow::set_proxy(int new_scale, + ArrayList *orig_assets, ArrayList *proxy_assets) +{ + int orig_scale = edl->session->proxy_scale; + edl->session->proxy_scale = new_scale; + +// project size + float orig_w = (float)edl->session->output_w * orig_scale; + float orig_h = (float)edl->session->output_h * orig_scale; + edl->session->output_w = Units::round(orig_w / new_scale); + edl->session->output_h = Units::round(orig_h / new_scale); + +// track sizes + for( Track *track=edl->tracks->first; track; track=track->next ) { + if( track->data_type != TRACK_VIDEO ) continue; + orig_w = (float)track->track_w * orig_scale; + orig_h = (float)track->track_h * orig_scale; + track->track_w = Units::round(orig_w / new_scale); + track->track_h = Units::round(orig_h / new_scale); + ((MaskAutos*)track->automation->autos[AUTOMATION_MASK])-> + set_proxy(orig_scale, new_scale); + ((FloatAutos*)track->automation->autos[AUTOMATION_CAMERA_X])-> + set_proxy(orig_scale, new_scale); + ((FloatAutos*)track->automation->autos[AUTOMATION_CAMERA_Y])-> + set_proxy(orig_scale, new_scale); + ((FloatAutos*)track->automation->autos[AUTOMATION_PROJECTOR_X])-> + set_proxy(orig_scale, new_scale); + ((FloatAutos*)track->automation->autos[AUTOMATION_PROJECTOR_Y])-> + set_proxy(orig_scale, new_scale); + } + +// assets + for( int i=0; isize(); i++ ) { + Asset *proxy_asset = edl->assets->update((Asset*)proxy_assets->get(i)); +// replace track contents + for( Track *track = edl->tracks->first; track; track = track->next ) { + if( track->data_type != TRACK_VIDEO ) continue; + for( Edit *edit = track->edits->first; edit; edit = edit->next ) { + if( !edit->asset ) continue; + if( !strcmp(edit->asset->path, orig_assets->get(i)->path) ) { + edit->asset = proxy_asset; + } + } + } + } +} + void MWindow::cut_commercials() { undo->update_undo_before(); diff --git a/cinelerra-5.1/cinelerra/proxy.C b/cinelerra-5.1/cinelerra/proxy.C new file mode 100644 index 00000000..b9a5ef59 --- /dev/null +++ b/cinelerra-5.1/cinelerra/proxy.C @@ -0,0 +1,715 @@ + +/* + * CINELERRA + * Copyright (C) 2015 Adam Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "assets.h" +#include "bcsignals.h" +#include "clip.h" +#include "confirmsave.h" +#include "cstrdup.h" +#include "edl.h" +#include "edlsession.h" +#include "errorbox.h" +#include "file.h" +#include "filesystem.h" +#include "formattools.h" +#include "language.h" +#include "mainprogress.h" +#include "mainundo.h" +#include "mutex.h" +#include "mwindow.h" +#include "mwindowgui.h" +#include "overlayframe.h" +#include "preferences.h" +#include "proxy.h" +#include "theme.h" + +#define WIDTH 400 +#define HEIGHT 320 +#define MAX_SCALE 16 + +ProxyMenuItem::ProxyMenuItem(MWindow *mwindow) + : BC_MenuItem(_("Proxy settings..."), _("Alt-P"), 'p') +{ + this->mwindow = mwindow; + set_alt(); +} + +void ProxyMenuItem::create_objects() +{ + thread = new ProxyThread(mwindow); +} + +int ProxyMenuItem::handle_event() +{ + mwindow->gui->unlock_window(); + thread->start(); + mwindow->gui->lock_window("ProxyMenuItem::handle_event"); + + return 1; +} + +ProxyThread::ProxyThread(MWindow *mwindow) +{ + this->mwindow = mwindow; + gui = 0; + asset = new Asset; + progress = 0; + counter_lock = new Mutex("ProxyThread::counter_lock"); + bzero(size_text, sizeof(char*) * MAX_SIZES); + bzero(size_factors, sizeof(int) * MAX_SIZES); + total_sizes = 0; +} +ProxyThread::~ProxyThread() +{ + for( int i=0; iformat = FILE_FFMPEG; + asset->load_defaults(mwindow->defaults, "PROXY_", 1, 1, 0, 0, 0); + mwindow->gui->lock_window("ProxyThread::new_gui"); + int x = mwindow->gui->get_abs_cursor_x(0) - WIDTH / 2; + int y = mwindow->gui->get_abs_cursor_y(0) - HEIGHT / 2; + + gui = new ProxyWindow(mwindow, this, x, y); + gui->create_objects(); + mwindow->gui->unlock_window(); + return gui; +} + +void ProxyThread::scale_to_text(char *string, int scale) +{ + calculate_sizes(); + strcpy(string, size_text[0]); + for( int i = 0; i < total_sizes; i++ ) { + if( scale == size_factors[i] ) { + strcpy(string, size_text[i]); + break; + } + } +} + + +void ProxyThread::calculate_sizes() +{ +// delete old values + for( int i = 0; i < MAX_SIZES; i++ ) { + if( size_text[i] ) delete [] size_text[i]; + } + bzero(size_text, sizeof(char*) * MAX_SIZES); + bzero(size_factors, sizeof(int) * MAX_SIZES); + + int orig_w = mwindow->edl->session->output_w * orig_scale; + int orig_h = mwindow->edl->session->output_h * orig_scale; + total_sizes = 0; + + size_text[0] = cstrdup(_("Original size")); + size_factors[0] = 1; + + int current_factor = 2; + total_sizes = 1; + for( current_factor = 2; current_factor < MAX_SCALE; current_factor++ ) { + if( current_factor * (orig_w / current_factor) == orig_w && + current_factor * (orig_h / current_factor) == orig_h ) { +//printf("ProxyThread::calculate_sizes %d\n", current_factor); + char string[BCTEXTLEN]; + sprintf(string, "1/%d", current_factor); + size_text[total_sizes] = cstrdup(string); + size_factors[total_sizes] = current_factor; + total_sizes++; + } + + current_factor++; + } +} + +void ProxyThread::handle_close_event(int result) +{ + asset->save_defaults(mwindow->defaults, "PROXY_", 1, 1, 0, 0, 0); + + if( !result ) { + to_proxy(); + } +} + +void ProxyThread::to_proxy() +{ +// test for new files + ArrayList confirm_paths; + confirm_paths.set_array_delete(); +// all proxy assets + ArrayList proxy_assets; +// assets which must be created + ArrayList needed_assets; +// original assets + ArrayList orig_assets; +// original assets which match the needed_assets + ArrayList needed_orig_assets; + Asset *proxy_asset = 0; + Asset *orig_asset = 0; + + mwindow->edl->Garbage::add_user(); + mwindow->save_backup(); + mwindow->undo->update_undo_before(_("proxy"), this); + +// revert project to original size from current size + if( mwindow->edl->session->proxy_scale > 1 ) { + for( orig_asset = mwindow->edl->assets->first; + orig_asset; + orig_asset = orig_asset->next ) { + char new_path[BCTEXTLEN]; + to_proxy_path(new_path, orig_asset, mwindow->edl->session->proxy_scale); + +// test if proxy asset was already added to proxy assets + int got_it = 0; + proxy_asset = 0; + for( int i = 0; i < proxy_assets.size(); i++ ) { + if( !strcmp(proxy_assets.get(i)->path, new_path) ) { + got_it = 1; + break; + } + } + +// add pointer to existing EDL asset if it exists +// EDL won't delete it unless it's the same pointer. + if( !got_it ) { + proxy_asset = mwindow->edl->assets->get_asset(new_path); + + if( proxy_asset ) { + proxy_assets.append(proxy_asset); + proxy_asset->Garbage::add_user(); + + orig_assets.append(orig_asset); + orig_asset->Garbage::add_user(); + } + + } + } + +// convert from the proxy assets to the original assets + mwindow->set_proxy(1, &proxy_assets, &orig_assets); + +// remove the proxy assets + mwindow->remove_assets_from_project(0, 0, &proxy_assets, NULL); + + + for( int i = 0; i < proxy_assets.size(); i++ ) { + proxy_assets.get(i)->Garbage::remove_user(); + } + proxy_assets.remove_all(); + + for( int i = 0; i < orig_assets.size(); i++ ) { + orig_assets.get(i)->Garbage::remove_user(); + } + orig_assets.remove_all(); + } + +// convert to new size if not original size + if( new_scale != 1 ) { + for( orig_asset = mwindow->edl->assets->first; + orig_asset; + orig_asset = orig_asset->next ) { + if( orig_asset->video_data ) { + char new_path[BCTEXTLEN]; + to_proxy_path(new_path, orig_asset, new_scale); +// add to proxy_assets & orig_assets if it isn't already there. + int got_it = 0; + proxy_asset = 0; + for( int i = 0; i < proxy_assets.size(); i++ ) { + if( !strcmp(proxy_assets.get(i)->path, new_path) ) { + got_it = 1; + proxy_asset = (Asset*)proxy_assets.get(i); + break; + } + } + + if( !got_it ) { + proxy_asset = new Asset; +// new compression parameters + proxy_asset->copy_format(asset, 0); + proxy_asset->update_path(new_path); + proxy_asset->audio_data = 0; + proxy_asset->video_data = 1; + proxy_asset->layers = 1; + proxy_asset->width = orig_asset->width / new_scale; + proxy_asset->height = orig_asset->height / new_scale; + proxy_asset->frame_rate = orig_asset->frame_rate; + proxy_asset->video_length = orig_asset->video_length; + + proxy_assets.append(proxy_asset); + orig_asset->add_user(); + orig_assets.append(orig_asset); + } + +// test if proxy file exists. + int exists = 0; + FILE *fd = fopen(new_path, "r"); + if( fd ) { + got_it = 1; + exists = 1; + fclose(fd); + + FileSystem fs; +// test if proxy file is newer than original. + if( fs.get_date(new_path) < fs.get_date(asset->path) ) { + got_it = 0; + } + } + else { +// proxy doesn't exist + got_it = 0; + } + + if( !got_it ) { +// prompt user to overwrite + if( exists ) { + confirm_paths.append(cstrdup(new_path)); + } + + needed_assets.append(proxy_asset); + proxy_asset->add_user(); + needed_orig_assets.append(orig_asset); + orig_asset->add_user(); + } +//printf("ProxyThread::handle_close_event %d %s\n", __LINE__, new_path); + } + } + +// test for existing files + int result = 0; + if( confirm_paths.size() ) { + result = ConfirmSave::test_files(mwindow, &confirm_paths); + confirm_paths.remove_all_objects(); + } + + if( !result ) { + int canceled = 0; + failed = 0; + +// create proxy assets which don't already exist + if( needed_orig_assets.size() > 0 ) { + int64_t total_len = 0; + for( int i = 0; i < needed_orig_assets.size(); i++ ) + total_len += needed_orig_assets.get(i)->video_length; +// start progress bar. MWindow is locked inside this + progress = mwindow->mainprogress-> + start_progress(_("Creating proxy files..."), total_len); + total_rendered = 0; + + ProxyFarm engine(mwindow, + this, + &needed_assets, + &needed_orig_assets); + engine.process_packages(); + +printf("failed=%d canceled=%d\n", failed, progress->is_cancelled()); + + // stop progress bar + canceled = progress->is_cancelled(); + progress->stop_progress(); + delete progress; + progress = 0; + + if( failed && !canceled ) { + ErrorBox error_box(PROGRAM_NAME ": Error", + mwindow->gui->get_abs_cursor_x(1), + mwindow->gui->get_abs_cursor_y(1)); + error_box.create_objects(_("Error making proxy.")); + error_box.raise_window(); + error_box.run_window(); + } + } + +// resize project + if( !failed && !canceled ) { + mwindow->set_proxy(new_scale, &orig_assets, &proxy_assets); + } + } + + for( int i = 0; i < proxy_assets.size(); i++ ) { + proxy_assets.get(i)->Garbage::remove_user(); + } + + for( int i = 0; i < orig_assets.size(); i++ ) { + orig_assets.get(i)->Garbage::remove_user(); + } + + for( int i = 0; i < needed_assets.size(); i++ ) { + needed_assets.get(i)->Garbage::remove_user(); + } + + for( int i = 0; i < needed_orig_assets.size(); i++ ) { + needed_orig_assets.get(i)->Garbage::remove_user(); + } + } + + mwindow->undo->update_undo_after(_("proxy"), LOAD_ALL); + + mwindow->edl->Garbage::remove_user(); + + mwindow->restart_brender(); + + mwindow->gui->lock_window("ProxyThread::to_proxy"); + mwindow->update_project(LOAD_ALL); + mwindow->gui->unlock_window(); +} + + +void ProxyThread::to_proxy_path(char *new_path, Asset *asset, int scale) +{ + strcpy(new_path, asset->path); + char prxy[BCTEXTLEN]; + sprintf(prxy, ".proxy%d", scale); +// path is already a proxy + if( strstr(new_path, prxy) ) return; + int len = strlen(new_path); +// insert proxy prxy + char *ptr = strrchr(new_path, '.'); + if( ptr ) { + char *cp = new_path + len; + int n = strlen(prxy); + char *bp = cp + n; + for( *bp=0; cp>ptr; ) *--bp = *--cp; + for( cp= prxy+n; bp>ptr; ) *--bp = *--cp; +//printf("ProxyThread::to_proxy_path %d %s %s\n", __LINE__, new_path), asset->path); + } + else + strcpy(new_path+len, prxy); +} + +void ProxyThread::from_proxy_path(char *new_path, Asset *asset, int scale) +{ + char prxy[BCTEXTLEN]; + sprintf(prxy, ".proxy%d", scale); + strcpy(new_path, asset->path); + char *ptr = strstr(asset->path, prxy); + if( !ptr ) return; + int n = strlen(prxy); + for( char *cp=ptr+n; --n>=0; ++ptr,++cp ) *ptr = *cp; + *ptr = 0; +} + +void ProxyThread::update_progress() +{ + counter_lock->lock(); + total_rendered++; + counter_lock->unlock(); + progress->update(total_rendered); +} + +int ProxyThread::is_canceled() +{ + return progress->is_cancelled(); +} + + + +ProxyWindow::ProxyWindow(MWindow *mwindow, ProxyThread *thread, int x, int y) + : BC_Window(_(PROGRAM_NAME ": Proxy settings"), x, y, WIDTH, HEIGHT, + -1, -1, 0, 0, 1) +{ + this->mwindow = mwindow; + this->thread = thread; + format_tools = 0; +} + +ProxyWindow::~ProxyWindow() +{ + lock_window("ProxyWindow::~ProxyWindow"); + delete format_tools; + unlock_window(); +} + + +void ProxyWindow::create_objects() +{ + lock_window("ProxyWindow::create_objects"); + + int margin = mwindow->theme->widget_border; + int x = margin; + int y = margin; + thread->orig_scale = + thread->new_scale = + mwindow->edl->session->proxy_scale; + + BC_Title *text; + add_subwindow(text = new BC_Title(x, y, + _("What size should the project\n" + "be scaled to for editing?"))); + y += text->get_h() * 2 + margin; + + + add_subwindow(text = new BC_Title(x, y, _("Scale factor:"))); + x += text->get_w() + margin; + + + thread->calculate_sizes(); + int popupmenu_w = BC_PopupMenu::calculate_w(get_text_width(MEDIUMFONT, thread->size_text[0])); + add_subwindow(scale_factor = new ProxyMenu(mwindow, this, x, y, popupmenu_w, "")); + for( int i = 0; i < thread->total_sizes; i++ ) { + scale_factor->add_item(new BC_MenuItem(thread->size_text[i])); + } + x += scale_factor->get_w() + margin; + + ProxyTumbler *tumbler; + add_subwindow(tumbler = new ProxyTumbler(mwindow, this, x, y)); + + x = margin; + y += tumbler->get_h() + margin; + ProxyReset *reset; + add_subwindow(reset = new ProxyReset(mwindow, this, x, y)); + + y += reset->get_h() * 2 + margin; + x = margin; + add_subwindow(text = new BC_Title(x, y, _("New project dimensions: "))); + x += text->get_w() + margin; + add_subwindow(new_dimensions = new BC_Title(x, y, "")); + + x = margin; + y += new_dimensions->get_h() * 2 + margin; + + + format_tools = new FormatTools(mwindow, this, thread->asset); + format_tools->create_objects(x, y, 0, 1, 0, 0, 0, 1, 0, 1, // skip the path + 0, 0); + + update(); + + add_subwindow(new BC_OKButton(this)); + add_subwindow(new BC_CancelButton(this)); + show_window(1); + unlock_window(); +} + +void ProxyWindow::update() +{ +// preview the new size + char string[BCTEXTLEN]; +//printf("ProxyWindow::update %d %d %d %d %d\n", +// __LINE__, mwindow->edl->session->output_w, mwindow->edl->session->output_h, +// thread->orig_scale, thread->new_scale); + int orig_w = mwindow->edl->session->output_w * thread->orig_scale; + int orig_h = mwindow->edl->session->output_h * thread->orig_scale; + sprintf(string, "%dx%d", + orig_w / thread->new_scale, orig_h / thread->new_scale); + new_dimensions->update(string); + thread->scale_to_text(string, thread->new_scale); + scale_factor->set_text(string); +} + + +ProxyReset::ProxyReset(MWindow *mwindow, ProxyWindow *pwindow, int x, int y) + : BC_GenericButton(x, y, _("Reset")) +{ + this->mwindow = mwindow; + this->pwindow = pwindow; +} + +int ProxyReset::handle_event() +{ + pwindow->thread->new_scale = pwindow->thread->orig_scale; + pwindow->update(); + return 1; +} + + +ProxyMenu::ProxyMenu(MWindow *mwindow, ProxyWindow *pwindow, + int x, int y, int w, const char *text) + : BC_PopupMenu(x, y, w, text, 1) +{ + this->mwindow = mwindow; + this->pwindow = pwindow; +} + +int ProxyMenu::handle_event() +{ + for( int i = 0; i < pwindow->thread->total_sizes; i++ ) { + if( !strcmp(get_text(), pwindow->thread->size_text[i]) ) { + pwindow->thread->new_scale = pwindow->thread->size_factors[i]; + pwindow->update(); + break; + } + } + return 1; +} + + +ProxyTumbler::ProxyTumbler(MWindow *mwindow, ProxyWindow *pwindow, int x, int y) + : BC_Tumbler(x, y, 0) +{ + this->mwindow = mwindow; + this->pwindow = pwindow; +} + +int ProxyTumbler::handle_up_event() +{ + if( pwindow->thread->new_scale > 1 ) { + int i; + for( i = 0; i < pwindow->thread->total_sizes; i++ ) { + if( pwindow->thread->new_scale == pwindow->thread->size_factors[i] ) { + i--; + pwindow->thread->new_scale = pwindow->thread->size_factors[i]; + pwindow->update(); + return 1; + } + } + } + + return 0; +} + +int ProxyTumbler::handle_down_event() +{ + int i; + for( i = 0; i < pwindow->thread->total_sizes - 1; i++ ) { + if( pwindow->thread->new_scale == pwindow->thread->size_factors[i] ) { + i++; + pwindow->thread->new_scale = pwindow->thread->size_factors[i]; + pwindow->update(); + return 1; + } + } + + return 0; +} + + +ProxyPackage::ProxyPackage() + : LoadPackage() +{ +} + +ProxyClient::ProxyClient(MWindow *mwindow, ProxyThread *thread, ProxyFarm *server) + : LoadClient(server) +{ + this->mwindow = mwindow; + this->thread = thread; +} + +void ProxyClient::process_package(LoadPackage *ptr) +{ + ProxyPackage *package = (ProxyPackage*)ptr; + if( thread->failed ) return; + + File src_file; + File dst_file; + EDL *edl = mwindow->edl; + Preferences *preferences = mwindow->preferences; + int processors = 1; + + int result; + src_file.set_processors(processors); + src_file.set_preload(edl->session->playback_preload); + src_file.set_subtitle(edl->session->decode_subtitles ? + edl->session->subtitle_number : -1); + src_file.set_interpolate_raw(edl->session->interpolate_raw); + src_file.set_white_balance_raw(edl->session->white_balance_raw); + +//printf("%s %s\n", package->orig_asset->path, package->proxy_asset->path); + + + result = src_file.open_file(preferences, package->orig_asset, 1, 0); + if( result ) { +// go to the next asset if the reader fails +// thread->failed = 1; + return; + } + + dst_file.set_processors(processors); + result = dst_file.open_file(preferences, package->proxy_asset, 0, 1); + if( result ) { + thread->failed = 1; + return; + } + + dst_file.start_video_thread(1, edl->session->color_model, + processors > 1 ? 2 : 1, 0); + + VFrame src_frame(0, -1, + package->orig_asset->width, package->orig_asset->height, + edl->session->color_model, -1); + + OverlayFrame scaler(processors); + + for( int64_t i = 0; i < package->orig_asset->video_length && + !thread->failed && !thread->is_canceled(); i++ ) { + src_file.set_video_position(i, 0); + result = src_file.read_frame(&src_frame); +//printf("result=%d\n", result); + + if( result ) { +// go to the next asset if the reader fails +// thread->failed = 1; + break; + } + +// have to write after getting the video buffer or it locks up + VFrame ***dst_frames = dst_file.get_video_buffer(); + VFrame *dst_frame = dst_frames[0][0]; + scaler.overlay(dst_frame, &src_frame, + 0, 0, src_frame.get_w(), src_frame.get_h(), + 0, 0, dst_frame->get_w(), dst_frame->get_h(), + 1.0, TRANSFER_REPLACE, NEAREST_NEIGHBOR); + result = dst_file.write_video_buffer(1); + if( result ) { +// only fail if the writer fails + thread->failed = 1; + break; + } + else { + thread->update_progress(); + } + } +} + + +ProxyFarm::ProxyFarm(MWindow *mwindow, ProxyThread *thread, + ArrayList *proxy_assets, ArrayList *orig_assets) + : LoadServer(MIN(mwindow->preferences->processors, proxy_assets->size()), + proxy_assets->size()) +{ + this->mwindow = mwindow; + this->thread = thread; + this->proxy_assets = proxy_assets; + this->orig_assets = orig_assets; +} + +void ProxyFarm::init_packages() +{ + for( int i = 0; i < get_total_packages(); i++ ) { + ProxyPackage *package = (ProxyPackage*)get_package(i); + package->proxy_asset = proxy_assets->get(i); + package->orig_asset = orig_assets->get(i); + } +} + +LoadClient* ProxyFarm::new_client() +{ + return new ProxyClient(mwindow, thread, this); +} + +LoadPackage* ProxyFarm::new_package() +{ + return new ProxyPackage; +} + diff --git a/cinelerra-5.1/cinelerra/proxy.h b/cinelerra-5.1/cinelerra/proxy.h new file mode 100644 index 00000000..5436daf9 --- /dev/null +++ b/cinelerra-5.1/cinelerra/proxy.h @@ -0,0 +1,183 @@ +#ifndef __PROXY_H__ +#define __PROXY_H__ + +/* + * CINELERRA + * Copyright (C) 2015 Adam Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +// functions for handling proxies + +#include "arraylist.h" +#include "asset.h" +#include "bcdialog.h" +#include "formattools.inc" +#include "loadbalance.h" +#include "mutex.inc" +#include "mwindow.inc" + +class ProxyThread; +class ProxyWindow; + +#define MAX_SIZES 16 + +class ProxyMenuItem : public BC_MenuItem +{ +public: + ProxyMenuItem(MWindow *mwindow); + + int handle_event(); + void create_objects(); + + MWindow *mwindow; + ProxyThread *thread; +}; + +class FromProxyMenuItem : public BC_MenuItem +{ +public: + FromProxyMenuItem(MWindow *mwindow); + + int handle_event(); + MWindow *mwindow; +}; + +class ProxyThread : public BC_DialogThread +{ +public: + ProxyThread(MWindow *mwindow); + ~ProxyThread(); + BC_Window* new_gui(); + void handle_close_event(int result); + static void to_proxy_path(char *new_path, Asset *asset, int scale); + static void from_proxy_path(char *new_path, Asset *asset, int scale); + void from_proxy(); + void to_proxy(); +// increment the frame count by 1 + void update_progress(); +// if user canceled progress bar + int is_canceled(); +// calculate possible sizes based on the original size + void calculate_sizes(); + void scale_to_text(char *string, int scale); + + MWindow *mwindow; + ProxyWindow *gui; + MainProgressBar *progress; + Mutex *counter_lock; + Asset *asset; + int new_scale; + int orig_scale; + int total_rendered; + int failed; + char *size_text[MAX_SIZES]; + int size_factors[MAX_SIZES]; + int total_sizes; +}; + +class ProxyReset : public BC_GenericButton +{ +public: + ProxyReset(MWindow *mwindow, ProxyWindow *pwindow, + int x, int y); + int handle_event(); + MWindow *mwindow; + ProxyWindow *pwindow; +}; + +class ProxyMenu : public BC_PopupMenu +{ +public: + ProxyMenu(MWindow *mwindow, ProxyWindow *pwindow, + int x, int y, int w, const char *text); + int handle_event(); + MWindow *mwindow; + ProxyWindow *pwindow; +}; + + +class ProxyTumbler : public BC_Tumbler +{ +public: + ProxyTumbler(MWindow *mwindow, ProxyWindow *pwindow, int x, int y); + + int handle_up_event(); + int handle_down_event(); + + ProxyWindow *pwindow; + MWindow *mwindow; +}; + + +class ProxyWindow : public BC_Window +{ +public: + ProxyWindow(MWindow *mwindow, ProxyThread *thread, + int x, int y); + ~ProxyWindow(); + + void create_objects(); + void update(); + + MWindow *mwindow; + ProxyThread *thread; + FormatTools *format_tools; + BC_Title *new_dimensions; + BC_PopupMenu *scale_factor; + ProxyReset *reset; +}; + +class ProxyFarm; + +class ProxyPackage : public LoadPackage +{ +public: + ProxyPackage(); + Asset *orig_asset; + Asset *proxy_asset; +}; + +class ProxyClient : public LoadClient +{ +public: + ProxyClient(MWindow *mwindow, ProxyThread *thread, + ProxyFarm *server); + void process_package(LoadPackage *package); + + MWindow *mwindow; + ProxyThread *thread; +}; + + +class ProxyFarm : public LoadServer +{ +public: + ProxyFarm(MWindow *mwindow, ProxyThread *thread, + ArrayList *proxy_assets, ArrayList *orig_assets); + + void init_packages(); + LoadClient* new_client(); + LoadPackage* new_package(); + + MWindow *mwindow; + ProxyThread *thread; + ArrayList *proxy_assets; + ArrayList *orig_assets; +}; + +#endif