/* * CINELERRA * Copyright (C) 1997-2012 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 "asset.h" #include "assets.h" #include "atrack.h" #include "autoconf.h" #include "automation.h" #include "awindowgui.inc" #include "bcsignals.h" #include "clip.h" #include "bccmodels.h" #include "bchash.h" #include "edits.h" #include "edl.h" #include "edlsession.h" #include "filexml.h" #include "guicast.h" #include "indexstate.h" #include "interlacemodes.h" #include "labels.h" #include "localsession.h" #include "mutex.h" #include "nestededls.h" #include "panauto.h" #include "panautos.h" #include "playbackconfig.h" #include "playabletracks.h" #include "plugin.h" #include "preferences.h" #include "recordconfig.h" #include "recordlabel.h" #include "sharedlocation.h" #include "theme.h" #include "tracks.h" #include "transportque.inc" #include "versioninfo.h" #include "vedit.h" #include "vtrack.h" Mutex* EDL::id_lock = 0; EDL::EDL(EDL *parent_edl) : Indexable(0) { this->parent_edl = parent_edl; tracks = 0; labels = 0; local_session = 0; // vwindow_edl = 0; // vwindow_edl_shared = 0; folders.set_array_delete(); new_folder(CLIP_FOLDER); new_folder(MEDIA_FOLDER); id = next_id(); path[0] = 0; } EDL::~EDL() { if(tracks) { delete tracks; } if(labels) { delete labels; } if(local_session) { delete local_session; } remove_vwindow_edls(); // if(vwindow_edl && !vwindow_edl_shared) // vwindow_edl->Garbage::remove_user(); if(!parent_edl) { delete assets; delete session; } folders.remove_all_objects(); for(int i = 0; i < clips.size(); i++) clips.get(i)->Garbage::remove_user(); clips.remove_all(); delete nested_edls; } void EDL::create_objects() { tracks = new Tracks(this); if(!parent_edl) { assets = new Assets(this); session = new EDLSession(this); } else { assets = parent_edl->assets; session = parent_edl->session; } local_session = new LocalSession(this); labels = new Labels(this, "LABELS"); nested_edls = new NestedEDLs; // last_playback_position = 0; } EDL& EDL::operator=(EDL &edl) { printf("EDL::operator= 1\n"); copy_all(&edl); return *this; } int EDL::load_defaults(BC_Hash *defaults) { if(!parent_edl) session->load_defaults(defaults); local_session->load_defaults(defaults); return 0; } int EDL::save_defaults(BC_Hash *defaults) { if(!parent_edl) session->save_defaults(defaults); local_session->save_defaults(defaults); return 0; } void EDL::boundaries() { session->boundaries(); local_session->boundaries(); } int EDL::create_default_tracks() { for(int i = 0; i < session->video_tracks; i++) { tracks->add_video_track(0, 0); } for(int i = 0; i < session->audio_tracks; i++) { tracks->add_audio_track(0, 0); } return 0; } int EDL::load_xml(FileXML *file, uint32_t load_flags) { int result = 0; // Track numbering offset for replacing undo data. int track_offset = 0; // Clear objects folders.remove_all_objects(); if((load_flags & LOAD_ALL) == LOAD_ALL) { remove_vwindow_edls(); } // Search for start of master EDL. // The parent_edl test caused clip creation to fail since those XML files // contained an EDL tag. // The parent_edl test is required to make EDL loading work because // when loading an EDL the EDL tag is already read by the parent. if(!parent_edl) { do{ result = file->read_tag(); }while(!result && !file->tag.title_is("XML") && !file->tag.title_is("EDL")); } if(!result) { // Get path for backups // path[0] = 0; file->tag.get_property("path", path); // Erase everything if((load_flags & LOAD_ALL) == LOAD_ALL || (load_flags & LOAD_EDITS) == LOAD_EDITS) { while(tracks->last) delete tracks->last; } if((load_flags & LOAD_ALL) == LOAD_ALL) { for(int i = 0; i < clips.size(); i++) clips.get(i)->Garbage::remove_user(); clips.remove_all(); } if(load_flags & LOAD_TIMEBAR) { while(labels->last) delete labels->last; local_session->unset_inpoint(); local_session->unset_outpoint(); } // This was originally in LocalSession::load_xml if(load_flags & LOAD_SESSION) { local_session->clipboard_length = 0; } do{ result = file->read_tag(); if(!result) { if(file->tag.title_is("/XML") || file->tag.title_is("/EDL") || file->tag.title_is("/CLIP_EDL") || file->tag.title_is("/VWINDOW_EDL")) { result = 1; } else if(file->tag.title_is("CLIPBOARD")) { local_session->clipboard_length = file->tag.get_property("LENGTH", (double)0); } else if(file->tag.title_is("VIDEO")) { if((load_flags & LOAD_VCONFIG) && (load_flags & LOAD_SESSION)) session->load_video_config(file, 0, load_flags); } else if(file->tag.title_is("AUDIO")) { if((load_flags & LOAD_ACONFIG) && (load_flags & LOAD_SESSION)) session->load_audio_config(file, 0, load_flags); } else if(file->tag.title_is("FOLDER")) { char folder[BCTEXTLEN]; strcpy(folder, file->read_text()); new_folder(folder); } else if(file->tag.title_is("ASSETS")) { if(load_flags & LOAD_ASSETS) assets->load(file, load_flags); } else if(file->tag.title_is(labels->xml_tag)) { if(load_flags & LOAD_TIMEBAR) labels->load(file, load_flags); } else if(file->tag.title_is("LOCALSESSION")) { if((load_flags & LOAD_SESSION) || (load_flags & LOAD_TIMEBAR)) local_session->load_xml(file, load_flags); } else if(file->tag.title_is("SESSION")) { if((load_flags & LOAD_SESSION) && !parent_edl) session->load_xml(file, 0, load_flags); } else if(file->tag.title_is("TRACK")) { tracks->load(file, track_offset, load_flags); } else // Sub EDL. // Causes clip creation to fail because that involves an opening EDL tag. if(file->tag.title_is("CLIP_EDL") && !parent_edl) { EDL *new_edl = new EDL(this); new_edl->create_objects(); new_edl->load_xml(file, LOAD_ALL); if((load_flags & LOAD_ALL) == LOAD_ALL) clips.append(new_edl); else new_edl->Garbage::remove_user(); } else if(file->tag.title_is("VWINDOW_EDL") && !parent_edl) { EDL *new_edl = new EDL(this); new_edl->create_objects(); new_edl->load_xml(file, LOAD_ALL); if((load_flags & LOAD_ALL) == LOAD_ALL) { // if(vwindow_edl && !vwindow_edl_shared) // vwindow_edl->Garbage::remove_user(); // vwindow_edl_shared = 0; // vwindow_edl = new_edl; append_vwindow_edl(new_edl, 0); } else // Discard if not replacing EDL { new_edl->Garbage::remove_user(); new_edl = 0; } } } }while(!result); } boundaries(); //dump(); return 0; } // Output path is the path of the output file if name truncation is desired. // It is a "" if complete names should be used. // Called recursively by copy for clips, thus the string can't be terminated. // The string is not terminated in this call. int EDL::save_xml(FileXML *file, const char *output_path, int is_clip, int is_vwindow) { copy(0, tracks->total_length(), 1, is_clip, is_vwindow, file, output_path, 0); return 0; } int EDL::copy_all(EDL *edl) { if(this == edl) return 0; update_index(edl); nested_edls->clear(); copy_session(edl); copy_assets(edl); copy_clips(edl); tracks->copy_from(edl->tracks); labels->copy_from(edl->labels); return 0; } void EDL::copy_clips(EDL *edl) { if(this == edl) return; remove_vwindow_edls(); // if(vwindow_edl && !vwindow_edl_shared) // vwindow_edl->Garbage::remove_user(); // vwindow_edl = 0; // vwindow_edl_shared = 0; for(int i = 0; i < edl->total_vwindow_edls(); i++) { EDL *new_edl = new EDL(this); new_edl->create_objects(); new_edl->copy_all(edl->get_vwindow_edl(i)); append_vwindow_edl(new_edl, 0); } for(int i = 0; i < clips.size(); i++) clips.get(i)->Garbage::remove_user(); clips.remove_all(); for(int i = 0; i < edl->clips.total; i++) { add_clip(edl->clips.values[i]); } } void EDL::copy_assets(EDL *edl) { if(this == edl) return; if(!parent_edl) { assets->copy_from(edl->assets); } } void EDL::copy_session(EDL *edl, int session_only) { if(this == edl) return; if(!session_only) { strcpy(this->path, edl->path); //printf("EDL::copy_session %p %s\n", this, this->path); folders.remove_all_objects(); for(int i = 0; i < edl->folders.total; i++) { char *new_folder; folders.append(new_folder = new char[strlen(edl->folders.values[i]) + 1]); strcpy(new_folder, edl->folders.values[i]); } } if(!parent_edl) { session->copy(edl->session); } if(!session_only) { local_session->copy_from(edl->local_session); } } int EDL::copy_assets(double start, double end, FileXML *file, int all, const char *output_path) { ArrayList asset_list; Track* current; file->tag.set_title("ASSETS"); file->append_tag(); file->append_newline(); // Copy everything for a save if(all) { for(Asset *asset = assets->first; asset; asset = asset->next) { asset_list.append(asset); } } else // Copy just the ones being used. { for(current = tracks->first; current; current = NEXT) { if(current->record) { current->copy_assets(start, end, &asset_list); } } } // Paths relativised here for(int i = 0; i < asset_list.total; i++) { asset_list.values[i]->write(file, 0, output_path); } file->tag.set_title("/ASSETS"); file->append_tag(); file->append_newline(); file->append_newline(); return 0; } int EDL::copy(double start, double end, int all, int is_clip, int is_vwindow, FileXML *file, const char *output_path, int rewind_it) { //printf("EDL::copy 1\n"); // begin file if(is_clip) file->tag.set_title("CLIP_EDL"); else if(is_vwindow) file->tag.set_title("VWINDOW_EDL"); else { file->tag.set_title("EDL"); file->tag.set_property("VERSION", CINELERRA_VERSION); // Save path for restoration of the project title from a backup. if(this->path[0]) { file->tag.set_property("PATH", path); } } file->append_tag(); file->append_newline(); // Set clipboard samples only if copying to clipboard if(!all) { file->tag.set_title("CLIPBOARD"); file->tag.set_property("LENGTH", end - start); file->append_tag(); file->tag.set_title("/CLIPBOARD"); file->append_tag(); file->append_newline(); file->append_newline(); } //printf("EDL::copy 1\n"); // Sessions local_session->save_xml(file, start); //printf("EDL::copy 1\n"); // Top level stuff. // if(!parent_edl) { // Need to copy all this from child EDL if pasting is desired. // Session session->save_xml(file); session->save_video_config(file); session->save_audio_config(file); // Folders for(int i = 0; i < folders.total; i++) { file->tag.set_title("FOLDER"); file->append_tag(); file->append_text(folders.values[i]); file->tag.set_title("/FOLDER"); file->append_tag(); file->append_newline(); } // Media // Don't replicate all assets for every clip. // The assets for the clips are probably in the mane EDL. if(!is_clip) copy_assets(start, end, file, all, output_path); // Clips // Don't want this if using clipboard if(all) { for(int i = 0; i < total_vwindow_edls(); i++) { get_vwindow_edl(i)->save_xml(file, output_path, 0, 1); } for(int i = 0; i < clips.total; i++) clips.values[i]->save_xml(file, output_path, 1, 0); } file->append_newline(); file->append_newline(); } //printf("EDL::copy 1\n"); labels->copy(start, end, file); //printf("EDL::copy 1\n"); tracks->copy(start, end, all, file, output_path); //printf("EDL::copy 2\n"); // terminate file if(is_clip) file->tag.set_title("/CLIP_EDL"); else if(is_vwindow) file->tag.set_title("/VWINDOW_EDL"); else file->tag.set_title("/EDL"); file->append_tag(); file->append_newline(); // For editing operations we want to rewind it for immediate pasting. // For clips and saving to disk leave it alone. if(rewind_it) { file->terminate_string(); file->rewind(); } return 0; } void EDL::rechannel() { for(Track *current = tracks->first; current; current = NEXT) { if(current->data_type == TRACK_AUDIO) { PanAutos *autos = (PanAutos*)current->automation->autos[AUTOMATION_PAN]; ((PanAuto*)autos->default_auto)->rechannel(); for(PanAuto *keyframe = (PanAuto*)autos->first; keyframe; keyframe = (PanAuto*)keyframe->next) { keyframe->rechannel(); } } } } void EDL::resample(double old_rate, double new_rate, int data_type) { for(Track *current = tracks->first; current; current = NEXT) { if(current->data_type == data_type) { current->resample(old_rate, new_rate); } } } void EDL::synchronize_params(EDL *edl) { local_session->synchronize_params(edl->local_session); for(Track *this_track = tracks->first, *that_track = edl->tracks->first; this_track && that_track; this_track = this_track->next, that_track = that_track->next) { this_track->synchronize_params(that_track); } } int EDL::trim_selection(double start, double end, int edit_labels, int edit_plugins, int edit_autos) { if(start != end) { // clear the data clear(0, start, edit_labels, edit_plugins, edit_autos); clear(end - start, tracks->total_length(), edit_labels, edit_plugins, edit_autos); } return 0; } int EDL::equivalent(double position1, double position2) { double threshold = (double).5 / session->frame_rate; if(session->cursor_on_frames) threshold = (double).5 / session->frame_rate; else threshold = (double)1 / session->sample_rate; if(fabs(position2 - position1) < threshold) return 1; else return 0; } double EDL::equivalent_output(EDL *edl) { double result = -1; session->equivalent_output(edl->session, &result); tracks->equivalent_output(edl->tracks, &result); return result; } void EDL::set_path(char *path) { strcpy(this->path, path); } void EDL::set_inpoint(double position) { if(equivalent(local_session->get_inpoint(), position) && local_session->get_inpoint() >= 0) { local_session->unset_inpoint(); } else { local_session->set_inpoint(align_to_frame(position, 0)); if(local_session->get_outpoint() <= local_session->get_inpoint()) local_session->unset_outpoint(); } } void EDL::set_outpoint(double position) { if(equivalent(local_session->get_outpoint(), position) && local_session->get_outpoint() >= 0) { local_session->unset_outpoint(); } else { local_session->set_outpoint(align_to_frame(position, 0)); if(local_session->get_inpoint() >= local_session->get_outpoint()) local_session->unset_inpoint(); } } int EDL::clear(double start, double end, int clear_labels, int clear_plugins, int edit_autos) { if(start == end) { double distance = 0; tracks->clear_handle(start, end, distance, clear_labels, clear_plugins, edit_autos); if(clear_labels && distance > 0) labels->paste_silence(start, start + distance); } else { tracks->clear(start, end, clear_plugins, edit_autos); if(clear_labels) labels->clear(start, end, 1); } // Need to put at beginning so a subsequent paste operation starts at the // right position. double position = local_session->get_selectionstart(); local_session->set_selectionend(position); local_session->set_selectionstart(position); return 0; } void EDL::modify_edithandles(double oldposition, double newposition, int currentend, int handle_mode, int edit_labels, int edit_plugins, int edit_autos) { tracks->modify_edithandles(oldposition, newposition, currentend, handle_mode, edit_labels, edit_plugins, edit_autos); labels->modify_handles(oldposition, newposition, currentend, handle_mode, edit_labels); } void EDL::modify_pluginhandles(double oldposition, double newposition, int currentend, int handle_mode, int edit_labels, int edit_autos, Edits *trim_edits) { tracks->modify_pluginhandles(oldposition, newposition, currentend, handle_mode, edit_labels, edit_autos, trim_edits); optimize(); } void EDL::paste_silence(double start, double end, int edit_labels, int edit_plugins, int edit_autos) { if(edit_labels) labels->paste_silence(start, end); tracks->paste_silence(start, end, edit_plugins, edit_autos); } void EDL::remove_from_project(ArrayList *clips) { for(int i = 0; i < clips->size(); i++) { for(int j = 0; j < this->clips.size(); j++) { if(this->clips.get(j) == clips->values[i]) { EDL *clip = this->clips.get(j); this->clips.remove(clip); clip->Garbage::remove_user(); } } } } void EDL::remove_from_project(ArrayList *assets) { // Remove from clips if(!parent_edl) for(int j = 0; j < clips.total; j++) { clips.values[j]->remove_from_project(assets); } // Remove from VWindow EDLs for(int i = 0; i < total_vwindow_edls(); i++) get_vwindow_edl(i)->remove_from_project(assets); for(int i = 0; i < assets->size(); i++) { // Remove from tracks for(Track *track = tracks->first; track; track = track->next) { track->remove_asset(assets->get(i)); } // Remove from assets if(!parent_edl && assets->get(i)->is_asset) { this->assets->remove_asset((Asset*)assets->get(i)); } else if(!parent_edl && !assets->get(i)->is_asset) { this->nested_edls->remove_edl((EDL*)assets->get(i)); } } } void EDL::update_assets(EDL *src) { for(Asset *current = src->assets->first; current; current = NEXT) { assets->update(current); } } int EDL::get_tracks_height(Theme *theme) { int total_pixels = 0; for(Track *current = tracks->first; current; current = NEXT) { total_pixels += current->vertical_span(theme); } return total_pixels; } int64_t EDL::get_tracks_width() { int64_t total_pixels = 0; for(Track *current = tracks->first; current; current = NEXT) { int64_t pixels = current->horizontal_span(); if(pixels > total_pixels) total_pixels = pixels; } //printf("EDL::get_tracks_width %d\n", total_pixels); return total_pixels; } // int EDL::calculate_output_w(int single_channel) // { // if(single_channel) return session->output_w; // // int widest = 0; // for(int i = 0; i < session->video_channels; i++) // { // if(session->vchannel_x[i] + session->output_w > widest) widest = session->vchannel_x[i] + session->output_w; // } // return widest; // } // // int EDL::calculate_output_h(int single_channel) // { // if(single_channel) return session->output_h; // // int tallest = 0; // for(int i = 0; i < session->video_channels; i++) // { // if(session->vchannel_y[i] + session->output_h > tallest) tallest = session->vchannel_y[i] + session->output_h; // } // return tallest; // } // Get the total output size scaled to aspect ratio void EDL::calculate_conformed_dimensions(int single_channel, float &w, float &h) { w = session->output_w; h = session->output_h; if((float)session->output_w / session->output_h > get_aspect_ratio()) { h = (float)h * (session->output_w / get_aspect_ratio() / session->output_h); } else { w = (float)w * (h * get_aspect_ratio() / session->output_w); } } float EDL::get_aspect_ratio() { return session->aspect_w / session->aspect_h; } int EDL::dump(FILE *fp) { if(parent_edl) fprintf(fp,"CLIP\n"); else fprintf(fp,"EDL\n"); fprintf(fp," clip_title: %s\n" " parent_edl: %p\n", local_session->clip_title, parent_edl); fprintf(fp," selectionstart %f\n selectionend %f\n loop_start %f\n loop_end %f\n", local_session->get_selectionstart(1), local_session->get_selectionend(1), local_session->loop_start, local_session->loop_end); for(int i = 0; i < TOTAL_PANES; i++) { fprintf(fp," pane %d view_start=%jd track_start=%jd\n", i, local_session->view_start[i], local_session->track_start[i]); } if(!parent_edl) { fprintf(fp,"audio_channels: %d audio_tracks: %d sample_rate: %jd\n", session->audio_channels, session->audio_tracks, session->sample_rate); fprintf(fp," video_channels: %d\n" " video_tracks: %d\n" " frame_rate: %.2f\n" " frames_per_foot: %.2f\n" " output_w: %d\n" " output_h: %d\n" " aspect_w: %f\n" " aspect_h: %f\n" " color_model: %d\n", session->video_channels, session->video_tracks, session->frame_rate, session->frames_per_foot, session->output_w, session->output_h, session->aspect_w, session->aspect_h, session->color_model); fprintf(fp," CLIPS\n"); fprintf(fp," total: %d\n", clips.total); for(int i = 0; i < clips.total; i++) { fprintf(fp,"\n\n"); clips.values[i]->dump(fp); fprintf(fp,"\n\n"); } fprintf(fp," VWINDOW EDLS\n"); fprintf(fp," total: %d\n", total_vwindow_edls()); for(int i = 0; i < total_vwindow_edls(); i++) { fprintf(fp," %s\n", get_vwindow_edl(i)->local_session->clip_title); } fprintf(fp," ASSETS\n"); assets->dump(fp); } fprintf(fp," LABELS\n"); labels->dump(fp); fprintf(fp," TRACKS\n"); tracks->dump(fp); //printf("EDL::dump 2\n"); return 0; } EDL* EDL::add_clip(EDL *edl) { // Copy argument. New edls are deleted from MWindow::load_filenames. EDL *new_edl = new EDL(this); new_edl->create_objects(); new_edl->copy_all(edl); clips.append(new_edl); return new_edl; } void EDL::insert_asset(Asset *asset, EDL *nested_edl, double position, Track *first_track, RecordLabels *labels) { // Insert asset into asset table Asset *new_asset = 0; EDL *new_nested_edl = 0; if(asset) new_asset = assets->update(asset); if(nested_edl) new_nested_edl = nested_edls->get_copy(nested_edl); // Paste video int vtrack = 0; Track *current = first_track ? first_track : tracks->first; // Fix length of single frame double length = 0.; int layers = 0; int channels = 0; if(new_nested_edl) { length = new_nested_edl->tracks->total_playable_length(); layers = 1; channels = new_nested_edl->session->audio_channels; } if(new_asset) { // Insert 1 frame for undefined length if(new_asset->video_length < 0) { length = session->si_useduration ? session->si_duration : 1.0 / session->frame_rate; } else { length = new_asset->frame_rate > 0 ? (double)new_asset->video_length / new_asset->frame_rate : 1.0 / session->frame_rate; } layers = new_asset->layers; channels = new_asset->channels; } for( ; current && vtrack < layers; current = NEXT) { if(!current->record || current->data_type != TRACK_VIDEO) continue; current->insert_asset(new_asset, new_nested_edl, length, position, vtrack); vtrack++; } int atrack = 0; if(new_asset) { if(new_asset->audio_length < 0) { // Insert 1 frame for undefined length & video if(new_asset->video_data) length = (double)1.0 / new_asset->frame_rate; else // Insert 1 second for undefined length & no video length = 1.0; } else length = (double)new_asset->audio_length / new_asset->sample_rate; } for(current = tracks->first; current && atrack < channels; current = NEXT) { if(!current->record || current->data_type != TRACK_AUDIO) continue; current->insert_asset(new_asset, new_nested_edl, length, position, atrack); atrack++; } // Insert labels from a recording window. if(labels) { for(RecordLabel *label = labels->first; label; label = label->next) { this->labels->toggle_label(label->position, label->position); } } } void EDL::set_index_file(Indexable *indexable) { if(indexable->is_asset) assets->update_index((Asset*)indexable); else nested_edls->update_index((EDL*)indexable); } void EDL::optimize() { //printf("EDL::optimize 1\n"); if(local_session->preview_start < 0) local_session->preview_start = 0; double length = tracks->total_length(); if(local_session->preview_end > length) local_session->preview_end = length; if(local_session->preview_start >= local_session->preview_end ) { local_session->preview_start = 0; local_session->preview_end = length; } for(Track *current = tracks->first; current; current = NEXT) current->optimize(); } int EDL::next_id() { id_lock->lock("EDL::next_id"); int result = EDLSession::current_id++; id_lock->unlock(); return result; } void EDL::get_shared_plugins(Track *source, ArrayList *plugin_locations, int omit_recordable, int data_type) { for(Track *track = tracks->first; track; track = track->next) { if(!track->record || !omit_recordable) { if(track != source && track->data_type == data_type) { for(int i = 0; i < track->plugin_set.total; i++) { Plugin *plugin = track->get_current_plugin( local_session->get_selectionstart(1), i, PLAY_FORWARD, 1, 0); if(plugin && plugin->plugin_type == PLUGIN_STANDALONE) { plugin_locations->append(new SharedLocation(tracks->number_of(track), i)); } } } } } } void EDL::get_shared_tracks(Track *track, ArrayList *module_locations, int omit_recordable, int data_type) { for(Track *current = tracks->first; current; current = NEXT) { if(!omit_recordable || !current->record) { if(current != track && current->data_type == data_type) { module_locations->append(new SharedLocation(tracks->number_of(current), 0)); } } } } // Convert position to frames if cursor alignment is enabled double EDL::align_to_frame(double position, int round) { //printf("EDL::align_to_frame 1 %f\n", position); if(session->cursor_on_frames) { // Seconds -> Frames double temp = (double)position * session->frame_rate; //printf("EDL::align_to_frame 2 %f\n", temp); // Assert some things if(session->sample_rate == 0) printf("EDL::align_to_frame: sample_rate == 0\n"); if(session->frame_rate == 0) printf("EDL::align_to_frame: frame_rate == 0\n"); // Round frames // Always round down negative numbers // but round up only if requested if(round) { temp = Units::round(temp); } else { // if(temp < 0) // { // temp -= 0.5; // } // else temp = Units::to_int64(temp); } //printf("EDL::align_to_frame 3 %f\n", temp); // Frames -> Seconds temp /= session->frame_rate; //printf("EDL::align_to_frame 5 %f\n", temp); return temp; } //printf("EDL::align_to_frame 3 %d\n", position); return position; } void EDL::new_folder(const char *folder) { for(int i = 0; i < folders.total; i++) { if(!strcasecmp(folders.values[i], folder)) return; } char *new_folder; folders.append(new_folder = new char[strlen(folder) + 1]); strcpy(new_folder, folder); } void EDL::delete_folder(const char *folder) { int i; for(i = 0; i < folders.total; i++) { if(!strcasecmp(folders.values[i], folder)) { break; } } if(i < folders.total) delete folders.values[i]; for( ; i < folders.total - 1; i++) { folders.values[i] = folders.values[i + 1]; } } int EDL::get_use_vconsole(VEdit* *playable_edit, int64_t position, int direction, PlayableTracks *playable_tracks) { int share_playable_tracks = 1; int result = 0; VTrack *playable_track = 0; const int debug = 0; *playable_edit = 0; // Calculate playable tracks when being called as a nested EDL if(!playable_tracks) { share_playable_tracks = 0; playable_tracks = new PlayableTracks(this, position, direction, TRACK_VIDEO, 1); } // Total number of playable tracks is 1 if(playable_tracks->size() != 1) { result = 1; } else { playable_track = (VTrack*)playable_tracks->get(0); } // Don't need playable tracks anymore if(!share_playable_tracks) { delete playable_tracks; } if(debug) printf("EDL::get_use_vconsole %d playable_tracks->size()=%d\n", __LINE__, playable_tracks->size()); if(result) return 1; // Test mutual conditions between direct copy rendering and this. if(!playable_track->direct_copy_possible(position, direction, 1)) return 1; if(debug) printf("EDL::get_use_vconsole %d\n", __LINE__); *playable_edit = (VEdit*)playable_track->edits->editof(position, direction, 0); // No edit at current location if(!*playable_edit) return 1; if(debug) printf("EDL::get_use_vconsole %d\n", __LINE__); // Edit is nested EDL if((*playable_edit)->nested_edl) { // Test nested EDL EDL *nested_edl = (*playable_edit)->nested_edl; int64_t nested_position = (int64_t)((position - (*playable_edit)->startproject + (*playable_edit)->startsource) * nested_edl->session->frame_rate / session->frame_rate); VEdit *playable_edit_temp = 0; if(session->output_w != nested_edl->session->output_w || session->output_h != nested_edl->session->output_h || nested_edl->get_use_vconsole(&playable_edit_temp, nested_position, direction, 0)) return 1; return 0; } if(debug) printf("EDL::get_use_vconsole %d\n", __LINE__); // Edit is not a nested EDL Asset *asset = (*playable_edit)->asset; // Edit is silence if(!asset) return 1; if(debug) printf("EDL::get_use_vconsole %d\n", __LINE__); // Asset and output device must have the same dimensions if( asset->width != session->output_w || asset->height != session->output_h ) return 1; if(debug) printf("EDL::get_use_vconsole %d\n", __LINE__); // Asset and output device must have same resulting de-interlacing method if( ilaceautofixmethod2(session->interlace_mode, asset->interlace_autofixoption, asset->interlace_mode, asset->interlace_fixmethod) != BC_ILACE_FIXMETHOD_NONE ) return 1; // If we get here the frame is going to be directly copied. Whether it is // decompressed in hardware depends on the colormodel. return 0; } // For Indexable int EDL::get_audio_channels() { return session->audio_channels; } int EDL::get_sample_rate() { return session->sample_rate; } int64_t EDL::get_audio_samples() { return (int64_t)(tracks->total_playable_length() * session->sample_rate); } int EDL::have_audio() { return 1; } int EDL::have_video() { return 1; } int EDL::get_w() { return session->output_w; } int EDL::get_h() { return session->output_h; } double EDL::get_frame_rate() { return session->frame_rate; } int EDL::get_video_layers() { return 1; } int64_t EDL::get_video_frames() { return (int64_t)(tracks->total_playable_length() * session->frame_rate); } void EDL::remove_vwindow_edls() { for(int i = 0; i < total_vwindow_edls(); i++) { get_vwindow_edl(i)->Garbage::remove_user(); } vwindow_edls.remove_all(); } void EDL::remove_vwindow_edl(EDL *edl) { if(vwindow_edls.number_of(edl) >= 0) { edl->Garbage::remove_user(); vwindow_edls.remove(edl); } } EDL* EDL::get_vwindow_edl(int number) { return vwindow_edls.get(number); } int EDL::total_vwindow_edls() { return vwindow_edls.size(); } void EDL::append_vwindow_edl(EDL *edl, int increase_counter) { if(vwindow_edls.number_of(edl) >= 0) return; if(increase_counter) edl->Garbage::add_user(); vwindow_edls.append(edl); }