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