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