18 new shapewipe transitions from rafa, rework savefile/confirm for nested edl edits
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / formattools.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2010-2013 Adam Williams <broadcast at earthling dot net>
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 "bcsignals.h"
24 #include "clip.h"
25 #include "guicast.h"
26 #include "file.h"
27 #include "filesystem.h"
28 #include "formattools.h"
29 #include "language.h"
30 #ifdef HAVE_DV
31 #include "libdv.h"
32 #endif
33 #include "libmjpeg.h"
34 #include "maxchannels.h"
35 #include "mwindow.h"
36 #include "preferences.h"
37 #include "theme.h"
38 #include "videodevice.inc"
39 #include <string.h>
40 #include <unistd.h>
41 #include <ctype.h>
42
43
44 FormatTools::FormatTools(MWindow *mwindow,
45                                 BC_WindowBase *window,
46                                 Asset *asset)
47 {
48         this->mwindow = mwindow;
49         this->window = window;
50         this->asset = asset;
51
52         aparams_button = 0;
53         vparams_button = 0;
54         aparams_thread = 0;
55         vparams_thread = 0;
56         audio_switch = 0;
57         video_switch = 0;
58         path_textbox = 0;
59         path_button = 0;
60         path_recent = 0;
61         format_title = 0;
62         format_button = 0;
63         format_text = 0;
64         audio_title = 0;
65         video_title = 0;
66         labeled_files = 0;
67         w = window->get_w();
68
69         recording = 0;
70         use_brender = 0;
71         do_audio = 0;
72         do_video = 0;
73         prompt_audio = 0;
74         prompt_audio_channels = 0;
75         prompt_video = 0;
76         prompt_video_compression = 0;
77         file_per_label = 0;
78         locked_compressor = 0;
79         video_driver = 0;
80 }
81
82 FormatTools::~FormatTools()
83 {
84         delete path_recent;
85 SET_TRACE
86         delete path_button;
87 SET_TRACE
88         delete path_textbox;
89 SET_TRACE
90         delete format_button;
91 SET_TRACE
92
93         if(aparams_button) delete aparams_button;
94 SET_TRACE
95         if(vparams_button) delete vparams_button;
96 SET_TRACE
97         if(aparams_thread) delete aparams_thread;
98 SET_TRACE
99         if(vparams_thread) delete vparams_thread;
100 SET_TRACE
101 }
102
103 void FormatTools::create_objects(
104                 int &init_x, int &init_y,
105                 int do_audio, int do_video,   // Include support for audio, video
106                 int prompt_audio, int prompt_video, // Include checkbox for audio, video
107                 int prompt_audio_channels,
108                 int prompt_video_compression,
109                 const char *locked_compressor,
110                 int recording,
111                 int *file_per_label,
112                 int brender,
113                 int horizontal_layout)
114 {
115         int ys10 = yS(10);
116         int x = init_x;
117         int y = init_y;
118         int ylev = init_y;
119         int margin = mwindow->theme->widget_border;
120
121         this->locked_compressor = locked_compressor;
122         this->recording = recording;
123         this->use_brender = brender;
124         this->do_audio = do_audio;
125         this->do_video = do_video;
126         this->prompt_audio = prompt_audio;
127         this->prompt_audio_channels = prompt_audio_channels;
128         this->prompt_video = prompt_video;
129         this->prompt_video_compression = prompt_video_compression;
130         this->file_per_label = file_per_label;
131
132 //printf("FormatTools::create_objects 1\n");
133
134         if(!recording)
135         {
136                 int px = x;
137                 window->add_subwindow(path_textbox = new FormatPathText(px, y, this));
138                 px += path_textbox->get_w() + 5;
139                 path_recent = new BC_RecentList("PATH", mwindow->defaults,
140                                         path_textbox, 10, px, y, xS(300), yS(100));
141                 window->add_subwindow(path_recent);
142                 path_recent->load_items(File::formattostr(asset->format));
143                 px += path_recent->get_w();
144                 window->add_subwindow(path_button = new BrowseButton(
145                         mwindow->theme, window, path_textbox, px, y, asset->path,
146                         _("Output to file"), _("Select a file to write to:"), 0));
147
148 // Set w for user.
149                 w = MAX(w, xS(305));
150                 y += path_textbox->get_h() + ys10;
151         }
152         else
153         {
154 //              w = x + xS(305);
155                 w = xS(305);
156         }
157
158         x = init_x;
159         window->add_subwindow(format_title = new BC_Title(x, y, _("File Format:")));
160         x += format_title->get_w() + margin;
161         window->add_subwindow(format_text = new BC_TextBox(x, y, xS(160), 1,
162                 File::formattostr(asset->format)));
163         x += format_text->get_w() + margin;
164 //printf("FormatTools::create_objects %d %p\n", __LINE__, window);
165         window->add_subwindow(format_button = new FormatFormat(x, y, this));
166         format_button->create_objects();
167         x += format_button->get_w() + 5;
168         window->add_subwindow(ffmpeg_type = new FFMpegType(x, y, xS(70), 1, asset->fformat));
169         FFMPEG::set_asset_format(asset, mwindow->edl, asset->fformat);
170         x += ffmpeg_type->get_w();
171         window->add_subwindow(format_ffmpeg = new FormatFFMPEG(x, y, this));
172         format_ffmpeg->create_objects();
173         x = init_x;
174         y += format_button->get_h() + ys10;
175         if( do_audio ) {
176                 window->add_subwindow(audio_title = new BC_Title(x, y, _("Audio:"), LARGEFONT,
177                         BC_WindowBase::get_resources()->audiovideo_color));
178                 x += audio_title->get_w() + margin;
179                 window->add_subwindow(aparams_button = new FormatAParams(mwindow, this, x, y));
180                 x += aparams_button->get_w() + margin;
181                 if(prompt_audio) {
182                         window->add_subwindow(audio_switch = new FormatAudio(x, y, this, asset->audio_data));
183                 }
184                 x = init_x;
185                 ylev = y;
186                 y += aparams_button->get_h() + ys10;
187
188 //printf("FormatTools::create_objects 6\n");
189                 aparams_thread = new FormatAThread(this);
190         }
191
192 //printf("FormatTools::create_objects 7\n");
193         if( do_video ) {
194                 if( horizontal_layout && do_audio ) {
195                         x += xS(370);
196                         y = ylev;
197                 }
198
199 //printf("FormatTools::create_objects 8\n");
200                 window->add_subwindow(video_title = new BC_Title(x, y, _("Video:"), LARGEFONT,
201                         BC_WindowBase::get_resources()->audiovideo_color));
202                 x += video_title->get_w() + margin;
203                 if(prompt_video_compression) {
204                         window->add_subwindow(vparams_button = new FormatVParams(mwindow, this, x, y));
205                         x += vparams_button->get_w() + margin;
206                 }
207
208 //printf("FormatTools::create_objects 9\n");
209                 if(prompt_video) {
210                         window->add_subwindow(video_switch = new FormatVideo(x, y, this, asset->video_data));
211                         y += video_switch->get_h();
212                 }
213                 else {
214                         y += vparams_button->get_h();
215                 }
216
217 //printf("FormatTools::create_objects 10\n");
218                 y += ys10;
219                 vparams_thread = new FormatVThread(this);
220         }
221
222 //printf("FormatTools::create_objects 11\n");
223
224         x = init_x;
225         if( file_per_label ) {
226                 labeled_files = new FormatFilePerLabel(this, x, y, file_per_label);
227                 window->add_subwindow(labeled_files);
228                 y += labeled_files->get_h() + ys10;
229         }
230
231 //printf("FormatTools::create_objects 12\n");
232
233         init_y = y;
234         update_format();
235 }
236
237 void FormatTools::update_driver(int driver)
238 {
239         this->video_driver = driver;
240
241         locked_compressor = 0;
242         switch(driver)
243         {
244                 case CAPTURE_DVB:
245                 case VIDEO4LINUX2MPEG:
246 // Just give the user information about how the stream is going to be
247 // stored but don't change the asset.
248 // Want to be able to revert to user settings.
249                         if(asset->format == FILE_MPEG) break;
250                         asset->format = FILE_MPEG;
251                         format_text->update(File::formattostr(asset->format));
252                         asset->audio_data = 1;
253                         asset->video_data = 1;
254                         audio_switch->update(1);
255                         video_switch->update(1);
256                         break;
257
258                 case CAPTURE_IEC61883:
259                 case CAPTURE_FIREWIRE:
260                 case VIDEO4LINUX2JPEG:
261                 case CAPTURE_JPEG_WEBCAM:
262                         asset->format = FILE_FFMPEG;
263                         format_text->update(File::formattostr(asset->format));
264
265                         switch(driver) {
266 #ifdef HAVE_DV
267                         case CAPTURE_IEC61883:
268                         case CAPTURE_FIREWIRE:
269                                 locked_compressor = (char*)CODEC_TAG_DVSD;
270                                 break;
271 #endif
272                         case VIDEO4LINUX2JPEG:
273                                 locked_compressor = (char*)CODEC_TAG_MJPEG;
274                                 break;
275
276                         case CAPTURE_JPEG_WEBCAM:
277                                 locked_compressor = (char*)CODEC_TAG_JPEG;
278                                 break;
279                         }
280                         if( locked_compressor )
281                                 strcpy(asset->vcodec, locked_compressor);
282
283                         audio_switch->update(asset->audio_data);
284                         video_switch->update(asset->video_data);
285                         break;
286
287                 default:
288                         format_text->update(File::formattostr(asset->format));
289                         audio_switch->update(asset->audio_data);
290                         video_switch->update(asset->video_data);
291                         break;
292         }
293         close_format_windows();
294         update_format();
295 }
296
297 void FormatTools::update_format()
298 {
299         if( do_audio && prompt_audio && audio_switch ) {
300                 audio_switch->update(asset->audio_data);
301                 if( File::renders_audio(asset) )
302                         audio_switch->enable();
303                 else
304                         audio_switch->disable();
305         }
306         if( do_video && prompt_video && video_switch ) {
307                 video_switch->update(asset->video_data);
308                 if( File::renders_video(asset) )
309                         video_switch->enable();
310                 else
311                         video_switch->disable();
312         }
313         if( asset->format == FILE_FFMPEG ) {
314                 ffmpeg_type->show();
315                 format_ffmpeg->show();
316         }
317         else {
318                 ffmpeg_type->hide();
319                 format_ffmpeg->hide();
320         }
321 }
322
323 int FormatTools::handle_event()
324 {
325         return 0;
326 }
327
328 Asset* FormatTools::get_asset()
329 {
330         return asset;
331 }
332
333 void FormatTools::update_extension()
334 {
335         const char *extension = File::get_tag(asset->format);
336 // split multiple extensions
337         ArrayList<const char*> extensions;
338         int len = !extension ? -1 : strlen(extension);
339         const char *extension_ptr = extension;
340         for(int i = 0; i <= len; i++)
341         {
342                 if(extension[i] == '/' || extension[i] == 0)
343                 {
344                         extensions.append(extension_ptr);
345                         extension_ptr = extension + i + 1;
346                 }
347         }
348
349         if(extensions.size())
350         {
351                 char *ptr = strrchr(asset->path, '.');
352                 if(!ptr)
353                 {
354                         ptr = asset->path + strlen(asset->path);
355                         *ptr = '.';
356                 }
357                 ptr++;
358
359 // test for equivalent extension
360                 int need_extension = 1;
361                 //int extension_len = 0;
362                 for(int i = 0; i < extensions.size() && need_extension; i++)
363                 {
364                         char *ptr1 = ptr;
365                         extension_ptr = extensions.get(i);
366 // test an extension
367                         need_extension = 0;
368                         while(*ptr1 != 0 && *extension_ptr != 0 && *extension_ptr != '/')
369                         {
370                                 if(tolower(*ptr1) != tolower(*extension_ptr))
371                                 {
372                                         need_extension = 1;
373                                         break;
374                                 }
375                                 ptr1++;
376                                 extension_ptr++;
377                         }
378
379                         if( (!*ptr1 && (*extension_ptr && *extension_ptr != '/')) ||
380                             (*ptr1 && (!*extension_ptr || *extension_ptr == '/')) )
381                                 need_extension = 1;
382                 }
383
384 //printf("FormatTools::update_extension %d %d\n", __LINE__, need_extension);
385 // copy extension
386                 if(need_extension)
387                 {
388                         char *ptr1 = ptr;
389 // change "qt" to "mov" since ffmpeg does not know qt
390                         extension_ptr = asset->format != FILE_FFMPEG ? extensions.get(0) :
391                                 !strcmp(asset->fformat, "qt" ) ||
392                                 !strcmp(asset->fformat, "pro" ) ? "mov" : asset->fformat ;
393                         while(*extension_ptr != 0 && *extension_ptr != '/')
394                                 *ptr1++ = *extension_ptr++;
395                         *ptr1 = 0;
396                 }
397
398                 int character1 = ptr - asset->path;
399                 int character2 = strlen(asset->path);
400 //              *(asset->path + character2) = 0;
401                 if(path_textbox)
402                 {
403                         path_textbox->update(asset->path);
404                         path_textbox->set_selection(character1, character2, character2);
405                 }
406         }
407 }
408
409 void FormatTools::update(Asset *asset, int *file_per_label)
410 {
411         this->asset = asset;
412         this->file_per_label = file_per_label;
413         if( file_per_label ) labeled_files->update(file_per_label);
414         if( path_textbox ) path_textbox->update(asset->path);
415         format_text->update(File::formattostr(asset->format));
416         update_format();
417         close_format_windows();
418 }
419
420 void FormatTools::close_format_windows()
421 {
422 // This is done in ~file
423         if( aparams_thread ) {
424                 if( aparams_thread->running() )
425                         aparams_thread->file->close_window();
426                 aparams_thread->join();
427         }
428         if( vparams_thread ) {
429                 if( vparams_thread->running() )
430                         vparams_thread->file->close_window();
431                 vparams_thread->join();
432         }
433 }
434
435 int FormatTools::get_w()
436 {
437         return asset->format != FILE_FFMPEG ? w :
438                 format_ffmpeg->get_x() + format_ffmpeg->get_w();
439 }
440
441 void FormatTools::set_w(int w)
442 {
443         this->w = w;
444 }
445
446 void FormatTools::reposition_window(int &init_x, int &init_y)
447 {
448         int xs10 = xS(10), xs80 = xS(80);
449         int ys10 = yS(10);
450         int x = init_x;
451         int y = init_y;
452
453         if(path_textbox)
454         {
455                 int px = x;
456                 path_textbox->reposition_window(px, y);
457                 px += path_textbox->get_w() + xS(5);
458                 path_recent->reposition_window(px, y);
459                 px += path_recent->get_w() + xS(8);
460                 path_button->reposition_window(px, y);
461                 y += path_textbox->get_h() + ys10;
462         }
463
464         format_title->reposition_window(x, y);
465         x += xS(90);
466         format_text->reposition_window(x, y);
467         x += format_text->get_w();
468         format_button->reposition_window(x, y);
469         x += format_button->get_w() + 5;
470         ffmpeg_type->reposition_window(x, y);
471         x += ffmpeg_type->get_w();
472         format_ffmpeg->reposition_window(x, y);
473
474         x = init_x;
475         y += format_button->get_h() + ys10;
476
477         if(do_audio)
478         {
479                 audio_title->reposition_window(x, y);
480                 x += xs80;
481                 aparams_button->reposition_window(x, y);
482                 x += aparams_button->get_w() + xs10;
483                 if(prompt_audio) audio_switch->reposition_window(x, y);
484
485                 x = init_x;
486                 y += aparams_button->get_h() + ys10;
487         }
488
489
490         if(do_video)
491         {
492                 video_title->reposition_window(x, y);
493                 x += xs80;
494                 if(prompt_video_compression)
495                 {
496                         vparams_button->reposition_window(x, y);
497                         x += vparams_button->get_w() + xs10;
498                 }
499
500                 if(prompt_video)
501                 {
502                         video_switch->reposition_window(x, y);
503                         y += video_switch->get_h();
504                 }
505                 else
506                 {
507                         y += vparams_button->get_h();
508                 }
509
510                 y += ys10;
511                 x = init_x;
512         }
513
514         if( file_per_label ) {
515                 labeled_files->reposition_window(x, y);
516                 y += labeled_files->get_h() + ys10;
517         }
518
519         init_y = y;
520 }
521
522
523 int FormatTools::set_audio_options()
524 {
525 //      if(video_driver == CAPTURE_DVB)
526 //      {
527 //              return 0;
528 //      }
529
530         if(!aparams_thread->running())
531         {
532                 aparams_thread->start();
533         }
534         else
535         {
536                 aparams_thread->file->raise_window();
537         }
538         return 0;
539 }
540
541 int FormatTools::set_video_options()
542 {
543 //      if(video_driver == CAPTURE_DVB)
544 //      {
545 //              return 0;
546 //      }
547
548         if(!vparams_thread->running())
549         {
550                 vparams_thread->start();
551         }
552         else
553         {
554                 vparams_thread->file->raise_window();
555         }
556
557         return 0;
558 }
559
560
561
562
563
564 FormatAParams::FormatAParams(MWindow *mwindow, FormatTools *format, int x, int y)
565  : BC_Button(x, y, mwindow->theme->get_image_set("wrench"))
566 {
567         this->format = format;
568         set_tooltip(_("Configure audio compression"));
569 }
570
571 FormatAParams::~FormatAParams()
572 {
573 }
574
575 int FormatAParams::handle_event()
576 {
577         format->set_audio_options();
578         format->handle_event();
579         return 1;
580 }
581
582
583
584
585
586 FormatVParams::FormatVParams(MWindow *mwindow, FormatTools *format, int x, int y)
587  : BC_Button(x, y, mwindow->theme->get_image_set("wrench"))
588 {
589         this->format = format;
590         set_tooltip(_("Configure video compression"));
591 }
592
593 FormatVParams::~FormatVParams()
594 {
595 }
596
597 int FormatVParams::handle_event()
598 {
599         format->set_video_options();
600         format->handle_event();
601         return 1;
602 }
603
604
605
606
607
608 FormatAThread::FormatAThread(FormatTools *format)
609  : Thread(1, 0, 0)
610 {
611         this->format = format;
612         file = new File;
613         joined = 1;
614 }
615
616 FormatAThread::~FormatAThread()
617 {
618         delete file;  file = 0;
619         join();
620 }
621
622 void FormatAThread::start()
623 {
624         join();
625         joined = 0;
626         Thread::start();
627 }
628
629
630 void FormatAThread::run()
631 {
632         file->get_options(format, 1, 0);
633 }
634
635
636
637
638 FormatVThread::FormatVThread(FormatTools *format)
639  : Thread(1, 0, 0)
640 {
641         this->format = format;
642         file = new File;
643         joined = 1;
644 }
645
646 FormatVThread::~FormatVThread()
647 {
648         delete file;  file = 0;
649         join();
650 }
651
652 void FormatVThread::start()
653 {
654         join();
655         joined = 0;
656         Thread::start();
657 }
658
659 void FormatVThread::run()
660 {
661         file->get_options(format, 0, 1);
662 }
663
664
665
666
667
668 FormatPathText::FormatPathText(int x, int y, FormatTools *format)
669  : BC_TextBox(x, y, format->w - x -
670                 2*format->mwindow->theme->get_image_set("wrench")[0]->get_w() - xS(20), 1,
671         format->asset->path)
672 {
673         this->format = format;
674 }
675
676 FormatPathText::~FormatPathText()
677 {
678 }
679 int FormatPathText::handle_event()
680 {
681         calculate_suggestions();
682         strcpy(format->asset->path, get_text());
683         format->handle_event();
684         return 1;
685 }
686
687
688
689
690 FormatAudio::FormatAudio(int x, int y, FormatTools *format, int default_)
691  : BC_CheckBox(x,
692         y,
693         default_,
694         (char*)(format->recording ? _("Record audio tracks") : _("Render audio tracks")))
695 {
696         this->format = format;
697 }
698
699 FormatAudio::~FormatAudio() {}
700 int FormatAudio::handle_event()
701 {
702         format->asset->audio_data = get_value();
703         format->handle_event();
704         return 1;
705 }
706
707
708 FormatVideo::FormatVideo(int x, int y, FormatTools *format, int default_)
709  : BC_CheckBox(x,
710         y,
711         default_,
712         (char*)(format->recording ? _("Record video tracks") : _("Render video tracks")))
713 {
714 this->format = format;
715 }
716
717 FormatVideo::~FormatVideo() {}
718 int FormatVideo::handle_event()
719 {
720         format->asset->video_data = get_value();
721         format->handle_event();
722         return 1;
723 }
724
725
726
727
728 FormatFormat::FormatFormat(int x, int y, FormatTools *format)
729  : FormatPopup(x, y, format->do_audio, format->do_video, format->use_brender)
730 {
731         this->format = format;
732 }
733
734 FormatFormat::~FormatFormat()
735 {
736 }
737
738 int FormatFormat::handle_event()
739 {
740         BC_ListBoxItem *selection = get_selection(0, 0);
741         if( selection ) {
742                 int new_format = File::strtoformat(get_selection(0, 0)->get_text());
743 //              if(new_format != format->asset->format)
744                 {
745                         Asset *asset = format->asset;
746                         asset->format = new_format;
747                         asset->audio_data = File::renders_audio(asset);
748                         asset->video_data = File::renders_video(asset);
749                         asset->ff_audio_options[0] = 0;
750                         asset->ff_video_options[0] = 0;
751                         asset->ff_format_options[0] = 0;
752                         format->format_text->update(selection->get_text());
753                         if( !format->use_brender )
754                                 format->update_extension();
755                         format->close_format_windows();
756                         if (format->path_recent) format->path_recent->
757                                 load_items(File::formattostr(format->asset->format));
758                         format->update_format();
759                 }
760                 format->handle_event();
761         }
762         return 1;
763 }
764
765
766 FormatFFMPEG::FormatFFMPEG(int x, int y, FormatTools *format)
767  : FFMPEGPopup(x, y)
768 {
769         this->format = format;
770 }
771
772 FormatFFMPEG::~FormatFFMPEG()
773 {
774 }
775
776 int FormatFFMPEG::handle_event()
777 {
778         BC_ListBoxItem *selection = get_selection(0, 0);
779         if( selection ) {
780                 const char *text = get_selection(0, 0)->get_text();
781                 format->ffmpeg_type->update(text);
782 // forces options load defaults
783                 format->asset->ff_audio_options[0] = 0;
784                 format->asset->ff_video_options[0] = 0;
785                 format->asset->ff_format_options[0] = 0;
786                 FFMPEG::set_asset_format(format->asset, format->mwindow->edl, text);
787                 format->update_extension();
788                 format->close_format_windows();
789                 format->update_format();
790                 format->handle_event();
791         }
792         return 1;
793 }
794
795
796 FormatFilePerLabel::FormatFilePerLabel(FormatTools *format,
797         int x, int y, int *output)
798  : BC_CheckBox(x, y, *output, _("Create new file at each label"))
799 {
800         this->format = format;
801         this->output = output;
802 }
803
804 FormatFilePerLabel::~FormatFilePerLabel()
805 {
806 }
807
808 int FormatFilePerLabel::handle_event()
809 {
810         *output = get_value();
811         format->handle_event();
812         return 1;
813 }
814
815 void FormatFilePerLabel::update(int *output)
816 {
817         this->output = output;
818         set_value(*output ? 1 : 0);
819 }
820
821