no longer need ffmpeg patch0 which was for Termux
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / exportedl.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2006 Andraz Tori
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "asset.h"
23 #include "bchash.h"
24 #include "condition.h"
25 #include "confirmsave.h"
26 #include "edits.h"
27 #include "edl.h"
28 #include "edlsession.h"
29 #include "file.h"
30 #include "filesystem.h"
31 #include "filexml.h"
32 #include "language.h"
33 #include "localsession.h"
34 #include "mainerror.h"
35 #include "mainsession.h"
36 #include "mutex.h"
37 #include "mwindowgui.h"
38 #include "mwindow.h"
39 #include "exportedl.h"
40 #include "tracks.h"
41 #include "transition.h"
42
43 #include <ctype.h>
44 #include <string.h>
45
46 ExportEDLAsset::ExportEDLAsset(MWindow *mwindow, EDL *edl)
47 {
48         this->mwindow = mwindow;
49         this->edl = edl;
50
51         path[0] = 0;
52         edl_type = EDLTYPE_CMX3600;
53         track_number = -1;
54 }
55
56 ExportEDLAsset::~ExportEDLAsset()
57 {
58 }
59
60 void ExportEDLAsset::double_to_CMX3600(double seconds, double frame_rate, char *str)
61 {
62         char tmp[20];
63         Units::totext(tmp,
64                         seconds,
65                         TIME_HMSF,
66                         0, // sample_rate ... unnecessary
67                         frame_rate,
68                         0); // frames per foot
69         if ((int)(seconds / 3600) <= 9)
70         {
71                 str[0]='0';
72                 strcpy(str+1, tmp);
73         } else
74         {
75                 strcpy(str, tmp);
76         }
77
78 //      str[8]='.';
79
80         //sprintf(str, "%02d:%02d:%02d:%02d", hour, minute, second, hundredths);
81 }
82
83 int ExportEDLAsset::edit_to_timecodes(Edit *edit,
84         char *sourceinpoint, char *sourceoutpoint,
85         char *destinpoint, char *destoutpoint,
86         char *reel_name)
87 {
88         Track *track = edit->track;
89         double frame_rate = edit->track->edl->session->frame_rate;
90
91         double edit_sourcestart;
92         double edit_sourceend;
93         double edit_deststart;
94         double edit_destend;
95         double timecode_offset;
96         
97         // timecode_offset in seconds
98         timecode_offset = edit->track->edl->session->timecode_offset;
99         //printf("tc offset %f, \n", timecode_offset);
100         
101         
102         if(!strcmp(reel_name,""))
103         strcpy(reel_name, "   BL   ");
104         edit_sourcestart = track->from_units(edit->startsource);
105         edit_sourceend = track->from_units(edit->length + edit->startsource);
106         
107         edit_deststart = track->from_units(edit->startproject);
108         edit_destend = track->from_units(edit->startproject + edit->length);
109
110         double_to_CMX3600(edit_sourcestart, frame_rate, sourceinpoint);
111         double_to_CMX3600(edit_sourceend, frame_rate, sourceoutpoint);
112         double_to_CMX3600(edit_deststart + timecode_offset, frame_rate, destinpoint);
113         double_to_CMX3600(edit_destend + timecode_offset, frame_rate, destoutpoint);
114
115         return 0;
116 }
117
118
119 void ExportEDLAsset::export_it()
120 {
121         FILE *fh;
122         fh = fopen(path, "w+");
123         if( !fh ) {
124                 eprintf("unable to open file: %s", path);
125                 return;
126         }
127
128 // We currently only support exporting one track at a time
129 // Find the track...
130         int serial = 0;
131         Track *track;
132         for(track = edl->tracks->first;
133                 track;
134                 track = track->next)
135         {
136                 if (serial == track_number)
137                         break;
138                 serial ++;
139         }
140
141
142         int last_dissolve = 1;
143
144         if (edl_type == EDLTYPE_CMX3600)
145         {
146
147                 // TODO: Find docs about exact header for CMX3600
148                 // https://xmil.biz/EDL-X/CMX3600.pdf
149                 double frame_rate = edl->session->frame_rate;
150                 int frame_rate_int = (int)frame_rate;
151                 char proj_title[BCTEXTLEN];
152                 strcpy(proj_title,basename(mwindow->session->filename));
153                 fprintf(fh, "TITLE: %s fps: %f\n", proj_title, frame_rate);
154                 switch(frame_rate_int) {
155                 case 24:
156                 case 25:
157                 case 50:
158                 case 60:
159                 case 30:
160                 {
161                 if (frame_rate - frame_rate_int < 0.001)
162                 fprintf(fh, "FCM: NON-DROP FRAME\n"); // fixme: select depending on fps
163                 break;
164                 }
165                 default:
166                 {
167                 if ((frame_rate - frame_rate_int) > 0.001)
168                 fprintf(fh, "FCM: DROP FRAME\n");
169                 }
170                 }
171                 // newline after FCM
172                 fprintf(fh, "\n");
173                 
174                 int colnum = 1;
175
176
177                 for (Edit *edit = track->edits->first;
178                         edit;
179                         edit = edit->next)
180                 {
181                 
182                 // max number of entries in cmx3600
183                 if (colnum > 999)
184                 return;
185                 
186                         char reel_name[BCTEXTLEN];
187                         char avselect[5];
188                         char edittype[5] = "C   ";
189                         char cutinfo[4] = "   ";
190                         char sourceinpoint[12];
191                         char sourceoutpoint[12];
192                         char destinpoint[12];
193                         char destoutpoint[12];
194                         
195                         char filename[1024];
196                         if (edit->asset)
197                         strcpy(filename,basename(edit->asset->path));
198                         
199                         if(!edit->asset)
200                         strcpy(reel_name,"BL  ");
201                         else
202                         strcpy(reel_name,"AX  ");
203                         
204                         if (track->data_type == TRACK_AUDIO)
205                                 strcpy(avselect, "A   ");
206                         else
207                                 strcpy(avselect, "V   ");
208
209                         //if (edit->transition)
210                         //      printf("title: %s, length: %i\n", edit->transition->title, edit->transition->length);
211                         if (edit->transition && !strcmp(edit->transition->title, "Dissolve"))
212                         {
213                                 char last_sourceout[12];
214                                 edit_to_timecodes(edit->previous, sourceinpoint, last_sourceout, destinpoint, destoutpoint, reel_name);
215                                 edit_to_timecodes(edit, sourceinpoint, sourceoutpoint, destinpoint, destoutpoint, reel_name);
216
217                                 if (last_dissolve)
218                                 {
219                                         fprintf(fh, "%03d %8s %s %4s %3s", colnum, reel_name, avselect, edittype, cutinfo);
220                                         fprintf(fh, " %s %s", last_sourceout, last_sourceout);
221                                         fprintf(fh, " %s %s", destinpoint, destinpoint);
222                                         fprintf(fh,"\n");
223                                         if(edit->asset)
224                                         fprintf(fh,"* FROM CLIP NAME: %s\n", filename);
225                                 } else
226                                 {
227                                         colnum --;
228                                 }
229                                 edittype[0] = 'D';
230                                 fprintf(fh, "%03d %8s %s %4s %03jd", colnum, reel_name, avselect, edittype, edit->transition->length);
231                                 fprintf(fh, " %s %s", sourceinpoint, sourceoutpoint);
232                                 fprintf(fh, " %s %s", destinpoint, destoutpoint);
233                                 fprintf(fh,"\n");
234                                 if(edit->asset)
235                                 fprintf(fh,"* FROM CLIP NAME: %s\n", filename);
236                                 last_dissolve = 1;
237                         } else
238                         {
239                                 edit_to_timecodes(edit, sourceinpoint, sourceoutpoint, destinpoint, destoutpoint, reel_name);
240                                 fprintf(fh, "%03d %8s %s %4s %3s", colnum, reel_name, avselect, edittype, cutinfo);
241                                 fprintf(fh, " %s %s", sourceinpoint, sourceoutpoint);
242                                 fprintf(fh, " %s %s", destinpoint, destoutpoint);
243                                 fprintf(fh,"\n");
244                                 if(edit->asset)
245                                 fprintf(fh,"* FROM CLIP NAME: %s\n", filename);
246                                 last_dissolve = 0;
247                         }
248
249                         colnum ++;
250
251                 }
252                 
253                 fprintf(fh, "\n");
254                 
255                 // file end for final cut pro 1.2.5 ?
256                 fprintf(fh, "\x0D");
257                 fprintf(fh, "\x0A");
258                 fprintf(fh, "\x1A");
259                 fprintf(fh, "\x1A");
260
261         }
262
263         fclose(fh);
264
265
266 }
267
268
269
270 int ExportEDLAsset::load_defaults()
271 {
272         mwindow->defaults->get("EDLEXPORT_PATH", path);
273         mwindow->defaults->get("EDLEXPORT_TYPE", edl_type);
274         mwindow->defaults->get("EDLEXPORT_TRACKNUMBER", track_number);
275         //load_mode = mwindow->defaults->get("RENDER_LOADMODE", LOADMODE_NEW_TRACKS);
276
277
278         return 0;
279 }
280
281 int ExportEDLAsset::save_defaults()
282 {
283         mwindow->defaults->update("EDLEXPORT_PATH", path);
284         mwindow->defaults->update("EDLEXPORT_TYPE", edl_type);
285         mwindow->defaults->update("EDLEXPORT_TRACKNUMBER", track_number);
286         return 0;
287 }
288
289
290
291
292 ExportEDLItem::ExportEDLItem(MWindow *mwindow)
293  : BC_MenuItem(_("Export EDL..."), "Shift-E", 'E')
294 {
295         this->mwindow = mwindow;
296         set_shift(1);
297 }
298
299 int ExportEDLItem::handle_event()
300 {
301         mwindow->exportedl->start_interactive();
302         return 1;
303 }
304
305
306
307
308
309 ExportEDL::ExportEDL(MWindow *mwindow)
310  : Thread(0, 0, 0)
311 {
312         this->mwindow = mwindow;
313 //      package_lock = new Mutex("ExportEDL::package_lock");
314 //      counter_lock = new Mutex("ExportEDL::counter_lock");
315 //      completion = new Condition(0, "ExportEDL::completion");
316 //      progress_timer = new Timer;
317 }
318
319 ExportEDL::~ExportEDL()
320 {
321 //      delete package_lock;
322 //      delete counter_lock;
323 //      delete completion;
324 ///     if(preferences) delete preferences;
325 //      delete progress_timer;
326 }
327
328 void ExportEDL::start_interactive()
329 {
330         if(!Thread::running())
331         {
332                 Thread::start();
333         }
334 }
335
336 void ExportEDL::run()
337 {
338         int result = 0;
339         exportasset = new ExportEDLAsset(mwindow, mwindow->edl);
340
341         exportasset->load_defaults();
342
343 // Get format from user
344                 result = 0;
345                 int filesok;
346
347                 do {
348                 // FIX
349                         filesok = 0;
350                         exportedl_window = new ExportEDLWindow(mwindow, this, exportasset);
351                         exportedl_window->create_objects();
352                         result = exportedl_window->run_window();
353                         if (! result) {
354                                 // add to recentlist only on OK
355                                 // Fix "EDL"!
356                                 exportedl_window->path_recent->add_item("EDLPATH", exportasset->path);
357                         }
358                         exportasset->track_number = exportedl_window->track_list->get_selection_number(0, 0);
359
360                         delete exportedl_window;
361                         exportedl_window = 0;
362                         if (!result)
363                         {
364                                 ArrayList<char*> paths;
365
366                                 paths.append(exportasset->path);
367                                 filesok = ConfirmSave::test_files(mwindow, &paths);
368                         }
369
370                 } while (!result && filesok);
371         mwindow->save_defaults();
372         exportasset->save_defaults();
373
374 // FIX
375         if(!result) exportasset->export_it();
376
377
378         delete exportasset;
379
380 }
381
382 #define WIDTH xS(410)
383 #define HEIGHT yS(400)
384
385 static const char *default_list_titles[] = {
386         N_("No."),
387         N_("Track name")
388 };
389
390 static int default_list_widths[] = {
391         40,
392         200
393 };
394
395
396 ExportEDLWindow::ExportEDLWindow(MWindow *mwindow, ExportEDL *exportedl, ExportEDLAsset *exportasset)
397  : BC_Window(_(PROGRAM_NAME ": Export EDL"),
398         mwindow->gui->get_screen_w(1, 0) / 2 - WIDTH / 2,
399         mwindow->gui->get_root_h(1) / 2 - HEIGHT / 2,
400         WIDTH, HEIGHT, (int)BC_INFINITY, (int)BC_INFINITY, 0, 0, 1)
401 {
402         this->mwindow = mwindow;
403         this->exportasset = exportasset;
404 // *** CONTEXT_HELP ***
405         context_help_set_keyword("Export to EDL");
406         for( int i=0; i<2; ++i ) {
407                 list_titles[i] = _(default_list_titles[i]);
408                 list_widths[i] = xS(default_list_widths[i]);
409         }
410 }
411
412 ExportEDLWindow::~ExportEDLWindow()
413 {
414 //      delete format_tools;
415 //      delete loadmode;
416 }
417
418
419 void ExportEDLWindow::create_objects()
420 {
421         int xs5 = xS(5);
422         int ys5 = yS(5), ys25 = yS(25);
423         lock_window("ExportEDLWindow::create_objects");
424         int x = xs5, y = ys5;
425         add_subwindow(new BC_Title(x, y,
426                         _("Select a file to export to:")));
427         y += ys25;
428
429         add_subwindow(path_textbox = new ExportEDLPathText(x, y, this));
430         x += xS(300);
431         path_recent = new BC_RecentList("EDLPATH", mwindow->defaults,
432                                         path_textbox, 10, x, y, xS(300), yS(100));
433         add_subwindow(path_recent);
434 // FIX
435         path_recent->load_items("EDLPATH");
436
437         x += xS(24);
438         add_subwindow(path_button = new BrowseButton(
439                 mwindow->theme, this, path_textbox, x, y - 4, exportasset->path,
440                 _("Output to file"), _("Select a file to write to:"), 0));
441
442         y += xS(34);
443         x = xs5;
444         add_subwindow(new BC_Title(x, y, _("Select track to be exported:")));
445         y += ys25;
446
447
448         items_tracks[0].remove_all_objects();
449         items_tracks[1].remove_all_objects();
450         int serial = 0;
451         if (exportasset->track_number == -1)
452                 exportasset->track_number = 0;
453         for(Track *track = mwindow->edl->tracks->first;
454                 track;
455                 track = track->next)
456         {
457
458                 char tmp[16];
459                 sprintf(tmp, "%i\n", serial+1);
460
461                 BC_ListBoxItem *listitem = new BC_ListBoxItem(tmp);
462                 if (serial == exportasset->track_number)
463                         listitem->set_selected(1);
464                 items_tracks[0].append(listitem);
465                 items_tracks[1].append(new BC_ListBoxItem(track->title));
466                 serial ++;
467
468         }
469
470
471         add_subwindow(track_list = new ExportEDLWindowTrackList(this, x, y, xS(400), yS(200)));
472
473         y += 5 + track_list->get_h();
474         add_subwindow(new BC_Title(x, y, _("Currently only CMX 3600 format is supported")));
475
476
477         add_subwindow(new BC_OKButton(this));
478         add_subwindow(new BC_CancelButton(this));
479         show_window();
480         unlock_window();
481 }
482
483
484 ExportEDLPathText::ExportEDLPathText(int x, int y, ExportEDLWindow *window)
485  : BC_TextBox(x, y, xS(300), 1, window->exportasset->path)
486 {
487         this->window = window;
488 }
489 ExportEDLPathText::~ExportEDLPathText()
490 {
491 }
492 int ExportEDLPathText::handle_event()
493 {
494         strcpy(window->exportasset->path, get_text());
495 //      window->handle_event();
496         return 1;
497 }
498
499 ExportEDLWindowTrackList::ExportEDLWindowTrackList(ExportEDLWindow *window,
500         int x, int y, int w, int h)
501  : BC_ListBox(x, y, w, h, LISTBOX_TEXT,
502                 window->items_tracks,
503                 window->list_titles,
504                 window->list_widths,
505                 2)
506 {
507         this->window = window;
508 }
509
510 int ExportEDLWindowTrackList::handle_event()
511 {
512 //      window->exportasset->track_number = get_selection_number(0, 0);
513 //      printf("aaaaa %i\n", window->exportasset->track_number );
514 //      window->set_done(0);
515         return 1;
516 }
517