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