From 0ea5dc979c00da45300634ab79a2db440fb98b76 Mon Sep 17 00:00:00 2001 From: Andraz Tori Date: Sun, 2 Apr 2006 13:33:31 +0000 Subject: [PATCH] r768: Add EDL export - currently only rudimentary CMX 3600 support --- cinelerra/Makefile.am | 2 + cinelerra/exportedl.C | 475 ++++++++++++++++++++++++++++++++++++++++++++++++ cinelerra/exportedl.h | 144 +++++++++++++++ cinelerra/exportedl.inc | 2 + cinelerra/filemov.C | 60 +++--- cinelerra/mainmenu.C | 2 + cinelerra/mwindow.C | 7 + cinelerra/mwindow.h | 8 +- 8 files changed, 673 insertions(+), 27 deletions(-) create mode 100644 cinelerra/exportedl.C create mode 100644 cinelerra/exportedl.h create mode 100644 cinelerra/exportedl.inc diff --git a/cinelerra/Makefile.am b/cinelerra/Makefile.am index 6c48283b..b55fc057 100644 --- a/cinelerra/Makefile.am +++ b/cinelerra/Makefile.am @@ -83,6 +83,7 @@ cinelerra_SOURCES = aattachmentpoint.C \ edits.C \ edl.C \ edlsession.C \ + exportedl.C \ fadeengine.C \ ffmpeg.C \ fileac3.C \ @@ -379,6 +380,7 @@ noinst_HEADERS = aattachmentpoint.h \ edits.h \ edl.h \ edlsession.h \ + exportedl.h \ fadeengine.h \ feather.h \ featheredits.h \ diff --git a/cinelerra/exportedl.C b/cinelerra/exportedl.C new file mode 100644 index 00000000..b84bed6b --- /dev/null +++ b/cinelerra/exportedl.C @@ -0,0 +1,475 @@ +#include "asset.h" +#include "condition.h" +#include "confirmsave.h" +#include "defaults.h" +#include "edits.h" +#include "edl.h" +#include "edlsession.h" +#include "errorbox.h" +#include "file.h" +#include "filesystem.h" +#include "filexml.h" +#include "language.h" +#include "localsession.h" +#include "mainsession.h" +#include "mutex.h" +#include "mwindowgui.h" +#include "mwindow.h" +#include "exportedl.h" +#include "tracks.h" +#include "transition.h" + + +#include +#include + +ExportEDLAsset::ExportEDLAsset(MWindow *mwindow, EDL *edl) +{ + this->mwindow = mwindow; + this->edl = edl; + + path[0] = 0; + edl_type = EDLTYPE_CMX3600; + track_number = -1; +} + +ExportEDLAsset::~ExportEDLAsset() +{ +} + +void ExportEDLAsset::double_to_CMX3600(double seconds, double frame_rate, char *str) +{ + char tmp[20]; + Units::totext(tmp, + seconds, + TIME_HMSF, + 0, // sample_rate ... unnecessary + frame_rate, + 0); // frames per foot + if ((int)(seconds / 3600) <= 9) + { + str[0]='0'; + strcpy(str+1, tmp); + } else + { + strcpy(str, tmp); + } + +// str[8]='.'; + + //sprintf(str, "%02d:%02d:%02d:%02d", hour, minute, second, hundredths); +} + +int ExportEDLAsset::edit_to_timecodes(Edit *edit, char *sourceinpoint, char *sourceoutpoint, char *destinpoint, char *destoutpoint, char *reel_name) +{ + Asset *asset = edit->asset; + Track *track = edit->track; + double frame_rate = edit->track->edl->session->frame_rate; + + double edit_sourcestart; + double edit_sourceend; + double edit_deststart; + double edit_destend; + + if (asset) + { + // reelname should be 8 chars long + + strncpy(reel_name, asset->reel_name, 9); + if (strlen(asset->reel_name) > 8) + { + printf(_("Warning: chopping the reel name to eight characters!\n")); + }; + reel_name[8] = 0; + for (int i = strlen(reel_name); i<8; i++) + reel_name[i] = ' '; + + edit_sourcestart = (double)asset->tcstart / asset->frame_rate + + track->from_units(edit->startsource); + edit_sourceend = (double)asset->tcstart / asset->frame_rate + + track->from_units(edit->startsource + edit->length); + + } else + { + strcpy(reel_name, " BL "); + edit_sourcestart = 0; + edit_sourceend = track->from_units(edit->length); + } + + edit_deststart = track->from_units(edit->startproject); + edit_destend = track->from_units(edit->startproject + edit->length); + + double_to_CMX3600(edit_sourcestart, frame_rate, sourceinpoint); + double_to_CMX3600(edit_sourceend, frame_rate, sourceoutpoint); + double_to_CMX3600(edit_deststart, frame_rate, destinpoint); + double_to_CMX3600(edit_destend, frame_rate, destoutpoint); + + return 0; +} + + +int ExportEDLAsset::export_it() +{ + FILE *fh; + fh = fopen(path, "w+"); + +// We currently only support exporting one track at a time +// Find the track... + int serial = 0; + Track *track; + for(track = edl->tracks->first; + track; + track = track->next) + { + if (serial == track_number) + break; + serial ++; + } + + + int last_dissolve = 1; + + if (edl_type == EDLTYPE_CMX3600) + { + + // TODO: Find docs about exact header for CMX3600 + fprintf(fh, "TITLE: Cinproj FORMAT: CMX 3600 4-Ch\n"); + + int colnum = 1; + + + for (Edit *edit = track->edits->first; + edit; + edit = edit->next) + { + char reel_name[BCTEXTLEN]; + char avselect[5]; + char edittype[5] = "C "; + char cutinfo[4] = " "; + char sourceinpoint[12]; + char sourceoutpoint[12]; + char destinpoint[12]; + char destoutpoint[12]; + if (track->data_type == TRACK_AUDIO) + strcpy(avselect, "A "); + else + strcpy(avselect, "V "); + + //if (edit->transition) + // printf("title: %s, length: %i\n", edit->transition->title, edit->transition->length); + if (edit->transition && !strcmp(edit->transition->title, "Dissolve")) + { + char last_sourceout[12]; + edit_to_timecodes(edit->previous, sourceinpoint, last_sourceout, destinpoint, destoutpoint, reel_name); + edit_to_timecodes(edit, sourceinpoint, sourceoutpoint, destinpoint, destoutpoint, reel_name); + + if (last_dissolve) + { + fprintf(fh, "%03d %8s %s %4s %03s", colnum, reel_name, avselect, edittype, cutinfo); + fprintf(fh, " %s %s", last_sourceout, last_sourceout); + fprintf(fh, " %s %s", destinpoint, destinpoint); + fprintf(fh,"\n"); + } else + { + colnum --; + } + edittype[0] = 'D'; + fprintf(fh, "%03d %8s %s %4s %03d", colnum, reel_name, avselect, edittype, edit->transition->length); + fprintf(fh, " %s %s", sourceinpoint, sourceoutpoint); + fprintf(fh, " %s %s", destinpoint, destoutpoint); + fprintf(fh,"\n"); + last_dissolve = 1; + } else + { + edit_to_timecodes(edit, sourceinpoint, sourceoutpoint, destinpoint, destoutpoint, reel_name); + fprintf(fh, "%03d %8s %s %4s %3s", colnum, reel_name, avselect, edittype, cutinfo); + fprintf(fh, " %s %s", sourceinpoint, sourceoutpoint); + fprintf(fh, " %s %s", destinpoint, destoutpoint); + fprintf(fh,"\n"); + last_dissolve = 0; + } + + colnum ++; + + } + + } + + fclose(fh); + + +} + + + +int ExportEDLAsset::load_defaults() +{ + mwindow->defaults->get("EDLEXPORT_PATH", path); + mwindow->defaults->get("EDLEXPORT_TYPE", edl_type); + mwindow->defaults->get("EDLEXPORT_TRACKNUMBER", track_number); + //load_mode = mwindow->defaults->get("RENDER_LOADMODE", LOAD_NEW_TRACKS); + + + return 0; +} + +int ExportEDLAsset::save_defaults() +{ + mwindow->defaults->update("EDLEXPORT_PATH", path); + mwindow->defaults->update("EDLEXPORT_TYPE", edl_type); + mwindow->defaults->update("EDLEXPORT_TRACKNUMBER", track_number); + return 0; +} + + + + +ExportEDLItem::ExportEDLItem(MWindow *mwindow) + : BC_MenuItem(_("Export EDL..."), "Shift+E", 'E') +{ + this->mwindow = mwindow; + set_shift(1); +} + +int ExportEDLItem::handle_event() +{ + mwindow->exportedl->start_interactive(); + return 1; +} + + + + + +ExportEDL::ExportEDL(MWindow *mwindow) + : Thread(0, 0, 0) +{ + this->mwindow = mwindow; +// package_lock = new Mutex("ExportEDL::package_lock"); +// counter_lock = new Mutex("ExportEDL::counter_lock"); +// completion = new Condition(0, "ExportEDL::completion"); +// progress_timer = new Timer; +} + +ExportEDL::~ExportEDL() +{ +// delete package_lock; +// delete counter_lock; +// delete completion; +/// if(preferences) delete preferences; +// delete progress_timer; +} + +void ExportEDL::start_interactive() +{ + if(!Thread::running()) + { + Thread::start(); + } +} + +void ExportEDL::run() +{ + int result = 0; + exportasset = new ExportEDLAsset(mwindow, mwindow->edl); + + exportasset->load_defaults(); + +// Get format from user + result = 0; + int filesok; + + do { + // FIX + filesok = 0; + exportedl_window = new ExportEDLWindow(mwindow, this, exportasset); + exportedl_window->create_objects(); + result = exportedl_window->run_window(); + if (! result) { + // add to recentlist only on OK + // Fix "EDL"! + exportedl_window->path_recent->add_item("EDLPATH", exportasset->path); + } + exportasset->track_number = exportedl_window->track_list->get_selection_number(0, 0); + + delete exportedl_window; + exportedl_window = 0; + if (!result) + { + ArrayList paths; + + paths.append(exportasset->path); + filesok = ConfirmSave::test_files(mwindow, &paths); + } + + } while (!result && filesok); + mwindow->save_defaults(); + exportasset->save_defaults(); + +// FIX + if(!result) exportasset->export_it(); + + + delete exportasset; + +} + + + + + + + + +#define WIDTH 410 +#define HEIGHT 400 + +static char *list_titles[] = +{ + N_("No."), + N_("Track name") +}; + + +static int list_widths[] = +{ + 40, + 200 +}; + +ExportEDLWindow::ExportEDLWindow(MWindow *mwindow, ExportEDL *exportedl, ExportEDLAsset *exportasset) + : BC_Window(PROGRAM_NAME ": Export EDL", + mwindow->gui->get_root_w(0, 1) / 2 - WIDTH / 2, + mwindow->gui->get_root_h(1) / 2 - HEIGHT / 2, + WIDTH, + HEIGHT, + (int)BC_INFINITY, + (int)BC_INFINITY, + 0, + 0, + 1) +{ + this->mwindow = mwindow; + this->exportasset = exportasset; +} + +ExportEDLWindow::~ExportEDLWindow() +{ +// delete format_tools; +// delete loadmode; +} + + + +int ExportEDLWindow::create_objects() +{ + int x = 5, y = 5; + add_subwindow(new BC_Title(x, + y, + _("Select a file to export to:"))); + y += 25; + + add_subwindow(path_textbox = new ExportEDLPathText(x, y, this)); + x += 300; + path_recent = new BC_RecentList("EDLPATH", mwindow->defaults, + path_textbox, 10, x, y, 300, 100); + add_subwindow(path_recent); +// FIX + path_recent->load_items("EDLPATH"); + + x += 24; + add_subwindow(path_button = new BrowseButton( + mwindow, + this, + path_textbox, + x, + y - 4, + exportasset->path, + _("Output to file"), + _("Select a file to write to:"), + 0)); + + y += 34; + x = 5; + add_subwindow(new BC_Title(x, y, _("Select track to be exported:"))); + y += 25; + + + items_tracks[0].remove_all_objects(); + items_tracks[1].remove_all_objects(); + int serial = 0; + if (exportasset->track_number == -1) + exportasset->track_number = 0; + for(Track *track = mwindow->edl->tracks->first; + track; + track = track->next) + { + + char tmp[10]; + sprintf(tmp, "%i\n", serial+1); + + BC_ListBoxItem *listitem = new BC_ListBoxItem(tmp); + if (serial == exportasset->track_number) + listitem->set_selected(1); + items_tracks[0].append(listitem); + items_tracks[1].append(new BC_ListBoxItem(track->title)); + serial ++; + + } + + + add_subwindow(track_list = new ExportEDLWindowTrackList(this, x, y, 400, 200, items_tracks)); + + y += 5 + track_list->get_h(); + add_subwindow(new BC_Title(x, y, _("Currently only CMX 3600 format is supported"))); + + + add_subwindow(new BC_OKButton(this)); + add_subwindow(new BC_CancelButton(this)); + show_window(); + return 0; +} + + +ExportEDLPathText::ExportEDLPathText(int x, int y, ExportEDLWindow *window) + : BC_TextBox(x, y, 300, 1, window->exportasset->path) +{ + this->window = window; +} +ExportEDLPathText::~ExportEDLPathText() +{ +} +int ExportEDLPathText::handle_event() +{ + strcpy(window->exportasset->path, get_text()); +// window->handle_event(); +} + +ExportEDLWindowTrackList::ExportEDLWindowTrackList(ExportEDLWindow *window, + int x, + int y, + int w, + int h, + ArrayList *track_list) + : BC_ListBox(x, + y, + w, + h, + LISTBOX_TEXT, + track_list, + list_titles, + list_widths, + 2) +{ + this->window = window; +} + +int ExportEDLWindowTrackList::handle_event() +{ +// window->exportasset->track_number = get_selection_number(0, 0); +// printf("aaaaa %i\n", window->exportasset->track_number ); +// window->set_done(0); +} + + + diff --git a/cinelerra/exportedl.h b/cinelerra/exportedl.h new file mode 100644 index 00000000..df00d8e1 --- /dev/null +++ b/cinelerra/exportedl.h @@ -0,0 +1,144 @@ +#ifndef EXPORTEDL_H +#define EXPORTEDL_H + + +#include "asset.inc" +#include "bitspopup.h" +#include "browsebutton.h" +#include "cache.inc" +#include "compresspopup.h" +#include "condition.inc" +#include "defaults.inc" +#include "edit.inc" +#include "errorbox.inc" +#include "file.inc" +#include "guicast.h" +#include "mutex.inc" +#include "mwindow.inc" + +#define EDLTYPE_CMX3600 1 + +class ExportEDLPathText; +class ExportEDLWindowTrackList; +class ExportEDLWindow; + +class ExportEDLAsset +{ +public: + ExportEDLAsset(MWindow *mwindow, EDL *edl); + ~ExportEDLAsset(); + // EDL being exported + EDL *edl; + // path to file + char path[BCTEXTLEN]; + // type of EDL + int edl_type; + + // We are currently exporting a track at once + int track_number; + + + int export_it(); + MWindow *mwindow; + + int load_defaults(); + int save_defaults(); +private: + int edit_to_timecodes(Edit *edit, char *sourceinpoint, char *sourceoutpoint, char *destinpoint, char *destoutpoint, char *reel_name); + void double_to_CMX3600(double seconds, double frame_rate, char *str); + +}; + +class ExportEDLItem : public BC_MenuItem +{ +public: + ExportEDLItem(MWindow *mwindow); + int handle_event(); + MWindow *mwindow; +}; + + + +class ExportEDL : public Thread +{ +public: + ExportEDL(MWindow *mwindow); + ~ExportEDL(); + + void start_interactive(); + void run(); + + +// Force filename to have a 0 padded number if rendering to a list. + + MWindow *mwindow; +// Mutex *package_lock, *counter_lock; +// Copy of mwindow preferences +// Preferences *preferences; +// Total selection to render in seconds + double total_start, total_end; + +// Current open RenderWindow + ExportEDLWindow *exportedl_window; + ExportEDLAsset *exportasset; + +}; + + +class ExportEDLWindow : public BC_Window +{ +public: + ExportEDLWindow(MWindow *mwindow, ExportEDL *exportedl, ExportEDLAsset *exportasset); + ~ExportEDLWindow(); + + int create_objects(); + + ExportEDLAsset *exportasset; + + BrowseButton *path_button; + ExportEDLPathText *path_textbox; + BC_RecentList *path_recent; + ExportEDLWindowTrackList *track_list; + + ArrayList items_tracks[2]; + + MWindow *mwindow; +}; + + + + + +class ExportEDLPathText : public BC_TextBox +{ +public: + ExportEDLPathText(int x, int y, ExportEDLWindow *window); + ~ExportEDLPathText(); + int handle_event(); + + ExportEDLWindow *window; +}; + +class ExportEDLWindowTrackList : public BC_ListBox +{ +public: + ExportEDLWindowTrackList(ExportEDLWindow *window, + int x, + int y, + int w, + int h, + ArrayList *track_list); + + int handle_event(); + ExportEDLWindow *window; +}; + + + + + + + + + +#endif diff --git a/cinelerra/exportedl.inc b/cinelerra/exportedl.inc new file mode 100644 index 00000000..45b1d266 --- /dev/null +++ b/cinelerra/exportedl.inc @@ -0,0 +1,2 @@ + +class ExportEDL; diff --git a/cinelerra/filemov.C b/cinelerra/filemov.C index 4f894236..cfaa4d1c 100644 --- a/cinelerra/filemov.C +++ b/cinelerra/filemov.C @@ -193,32 +193,6 @@ int FileMOV::open_file(int rd, int wr) { format_to_asset(); - // If DV stream, get the timecode - if(match4(asset->vcodec, QUICKTIME_DV)) - { - char tc[12]; - dv_decoder_t *tmp_decoder = dv_decoder_new(0,0,0); - VFrame *frame = new VFrame(0, 0, 0, BC_COMPRESSED); - - read_frame(frame); - set_video_position(0); - - if(dv_parse_header(tmp_decoder, frame->get_data()) > -1) - { - dv_parse_packs(tmp_decoder, frame->get_data()); - dv_get_timestamp(tmp_decoder, tc); - printf("Timestamp %s\n", tc); - - float seconds = Units::text_to_seconds(tc, - 1, // Use 1 as sample rate, doesn't matter - TIME_HMSF, - tmp_decoder->height == 576 ? 25 : 30, // FIXME - 0); - // Get frame number - asset->tcstart = int64_t(seconds * (tmp_decoder->height == 576 ? 25 : 30)); - } - - } } if(wr) asset_to_format(); @@ -418,6 +392,40 @@ void FileMOV::format_to_asset() asset->interlace_mode = quicktime_video_interlacemode(fd, 0); strncpy(asset->vcodec, quicktime_video_compressor(fd, 0), 4); + + // If DV stream, get the timecode + // This should become part of libquicktime functionality... for all formats + if(match4(asset->vcodec, QUICKTIME_DV)) + { + char tc[12]; + dv_decoder_t *tmp_decoder = dv_decoder_new(0,0,0); + VFrame *frame = new VFrame(0, 0, 0, BC_COMPRESSED); + + read_frame(frame); + set_video_position(0); + + if(dv_parse_header(tmp_decoder, frame->get_data()) > -1) + { + dv_parse_packs(tmp_decoder, frame->get_data()); + dv_get_timestamp(tmp_decoder, tc); +// printf("Timestamp %s\n", tc); + + float seconds = Units::text_to_seconds(tc, + 1, // Use 1 as sample rate, doesn't matter + TIME_HMSF, + asset->frame_rate, + 0); + // Set tcstart if it hasn't been set yet, this is a bit problematic + // FIXME: The problem arises if file has nonzero tcstart and user manualy sets it to zero - every time project will load it will be set to nonzero + if (asset->tcstart == 0) + asset->tcstart = int64_t(seconds * asset->frame_rate); + } + delete frame; + dv_decoder_free(tmp_decoder); + + } + + } } diff --git a/cinelerra/mainmenu.C b/cinelerra/mainmenu.C index fe0ed3e8..baa88da7 100644 --- a/cinelerra/mainmenu.C +++ b/cinelerra/mainmenu.C @@ -42,6 +42,7 @@ #include "transportque.h" #include "viewmenu.h" #include "zoombar.h" +#include "exportedl.h" #include @@ -85,6 +86,7 @@ SET_TRACE filemenu->add_item(record = new RecordMenuItem(mwindow)); filemenu->add_item(render = new RenderItem(mwindow)); + filemenu->add_item(new ExportEDLItem(mwindow)); filemenu->add_item(new BatchRenderMenuItem(mwindow)); filemenu->add_item(new BC_MenuItem("-")); filemenu->add_item(quit_program = new Quit(mwindow)); diff --git a/cinelerra/mwindow.C b/cinelerra/mwindow.C index 214a1619..045c7c54 100644 --- a/cinelerra/mwindow.C +++ b/cinelerra/mwindow.C @@ -74,6 +74,7 @@ #include "vwindowgui.h" #include "vwindow.h" #include "zoombar.h" +#include "exportedl.h" #include @@ -694,6 +695,11 @@ void MWindow::init_render() batch_render = new BatchRenderThread(this); } +void MWindow::init_exportedl() +{ + exportedl = new ExportEDL(this); +} + void MWindow::init_brender() { if(preferences->use_brender && !brender) @@ -1223,6 +1229,7 @@ TRACE("MWindow::create_objects 13"); TRACE("MWindow::create_objects 14"); init_render(); init_brender(); + init_exportedl(); mainprogress = new MainProgress(this, gui); undo = new MainUndo(this); diff --git a/cinelerra/mwindow.h b/cinelerra/mwindow.h index bf9bea4e..80fbbfdf 100644 --- a/cinelerra/mwindow.h +++ b/cinelerra/mwindow.h @@ -55,6 +55,7 @@ #include "videowindow.inc" #include "vwindow.inc" #include "bcwindowbase.inc" +#include "exportedl.inc" #include @@ -408,7 +409,11 @@ public: BatchRenderThread *batch_render; - Render *render; + Render *render; + + ExportEDL *exportedl; + + // Master edl EDL *edl; // Main Window GUI @@ -433,6 +438,7 @@ public: // Initialize channel DB's for playback void init_channeldb(); void init_render(); + void init_exportedl(); // These three happen synchronously with each other // Make sure this is called after synchronizing EDL's. void init_brender(); -- 2.11.4.GIT