usb_direct fix for rev2 shuttle, playbackengine locks again, viewer cursor fix
[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 == 0 &&
379                                 *extension_ptr != 0 &&
380                                 *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                         extension_ptr = asset->format != FILE_FFMPEG ?
390                                 extensions.get(0) : asset->fformat;
391                         while(*extension_ptr != 0 && *extension_ptr != '/')
392                                 *ptr1++ = *extension_ptr++;
393                         *ptr1 = 0;
394                 }
395
396                 int character1 = ptr - asset->path;
397                 int character2 = strlen(asset->path);
398 //              *(asset->path + character2) = 0;
399                 if(path_textbox)
400                 {
401                         path_textbox->update(asset->path);
402                         path_textbox->set_selection(character1, character2, character2);
403                 }
404         }
405 }
406
407 void FormatTools::update(Asset *asset, int *file_per_label)
408 {
409         this->asset = asset;
410         this->file_per_label = file_per_label;
411         if( file_per_label ) labeled_files->update(file_per_label);
412         if( path_textbox ) path_textbox->update(asset->path);
413         format_text->update(File::formattostr(asset->format));
414         update_format();
415         close_format_windows();
416 }
417
418 void FormatTools::close_format_windows()
419 {
420 // This is done in ~file
421         if( aparams_thread ) {
422                 if( aparams_thread->running() )
423                         aparams_thread->file->close_window();
424                 aparams_thread->join();
425         }
426         if( vparams_thread ) {
427                 if( vparams_thread->running() )
428                         vparams_thread->file->close_window();
429                 vparams_thread->join();
430         }
431 }
432
433 int FormatTools::get_w()
434 {
435         return asset->format != FILE_FFMPEG ? w :
436                 format_ffmpeg->get_x() + format_ffmpeg->get_w();
437 }
438
439 void FormatTools::set_w(int w)
440 {
441         this->w = w;
442 }
443
444 void FormatTools::reposition_window(int &init_x, int &init_y)
445 {
446         int x = init_x;
447         int y = init_y;
448
449         if(path_textbox)
450         {
451                 int px = x;
452                 path_textbox->reposition_window(px, y);
453                 px += path_textbox->get_w() + 5;
454                 path_recent->reposition_window(px, y);
455                 px += path_recent->get_w() + 8;
456                 path_button->reposition_window(px, y);
457                 y += path_textbox->get_h() + 10;
458         }
459
460         format_title->reposition_window(x, y);
461         x += 90;
462         format_text->reposition_window(x, y);
463         x += format_text->get_w();
464         format_button->reposition_window(x, y);
465
466         x = init_x;
467         y += format_button->get_h() + 10;
468
469         if(do_audio)
470         {
471                 audio_title->reposition_window(x, y);
472                 x += 80;
473                 aparams_button->reposition_window(x, y);
474                 x += aparams_button->get_w() + 10;
475                 if(prompt_audio) audio_switch->reposition_window(x, y);
476
477                 x = init_x;
478                 y += aparams_button->get_h() + 10;
479         }
480
481
482         if(do_video)
483         {
484                 video_title->reposition_window(x, y);
485                 x += 80;
486                 if(prompt_video_compression)
487                 {
488                         vparams_button->reposition_window(x, y);
489                         x += vparams_button->get_w() + 10;
490                 }
491
492                 if(prompt_video)
493                 {
494                         video_switch->reposition_window(x, y);
495                         y += video_switch->get_h();
496                 }
497                 else
498                 {
499                         y += vparams_button->get_h();
500                 }
501
502                 y += 10;
503                 x = init_x;
504         }
505
506         if( file_per_label ) {
507                 labeled_files->reposition_window(x, y);
508                 y += labeled_files->get_h() + 10;
509         }
510
511         init_y = y;
512 }
513
514
515 int FormatTools::set_audio_options()
516 {
517 //      if(video_driver == CAPTURE_DVB)
518 //      {
519 //              return 0;
520 //      }
521
522         if(!aparams_thread->running())
523         {
524                 aparams_thread->start();
525         }
526         else
527         {
528                 aparams_thread->file->raise_window();
529         }
530         return 0;
531 }
532
533 int FormatTools::set_video_options()
534 {
535 //      if(video_driver == CAPTURE_DVB)
536 //      {
537 //              return 0;
538 //      }
539
540         if(!vparams_thread->running())
541         {
542                 vparams_thread->start();
543         }
544         else
545         {
546                 vparams_thread->file->raise_window();
547         }
548
549         return 0;
550 }
551
552
553
554
555
556 FormatAParams::FormatAParams(MWindow *mwindow, FormatTools *format, int x, int y)
557  : BC_Button(x, y, mwindow->theme->get_image_set("wrench"))
558 {
559         this->format = format;
560         set_tooltip(_("Configure audio compression"));
561 }
562
563 FormatAParams::~FormatAParams()
564 {
565 }
566
567 int FormatAParams::handle_event()
568 {
569         format->set_audio_options();
570         format->handle_event();
571         return 1;
572 }
573
574
575
576
577
578 FormatVParams::FormatVParams(MWindow *mwindow, FormatTools *format, int x, int y)
579  : BC_Button(x, y, mwindow->theme->get_image_set("wrench"))
580 {
581         this->format = format;
582         set_tooltip(_("Configure video compression"));
583 }
584
585 FormatVParams::~FormatVParams()
586 {
587 }
588
589 int FormatVParams::handle_event()
590 {
591         format->set_video_options();
592         format->handle_event();
593         return 1;
594 }
595
596
597
598
599
600 FormatAThread::FormatAThread(FormatTools *format)
601  : Thread(1, 0, 0)
602 {
603         this->format = format;
604         file = new File;
605         joined = 1;
606 }
607
608 FormatAThread::~FormatAThread()
609 {
610         delete file;  file = 0;
611         join();
612 }
613
614 void FormatAThread::start()
615 {
616         join();
617         joined = 0;
618         Thread::start();
619 }
620
621
622 void FormatAThread::run()
623 {
624         file->get_options(format, 1, 0);
625 }
626
627
628
629
630 FormatVThread::FormatVThread(FormatTools *format)
631  : Thread(1, 0, 0)
632 {
633         this->format = format;
634         file = new File;
635         joined = 1;
636 }
637
638 FormatVThread::~FormatVThread()
639 {
640         delete file;  file = 0;
641         join();
642 }
643
644 void FormatVThread::start()
645 {
646         join();
647         joined = 0;
648         Thread::start();
649 }
650
651 void FormatVThread::run()
652 {
653         file->get_options(format, 0, 1);
654 }
655
656
657
658
659
660 FormatPathText::FormatPathText(int x, int y, FormatTools *format)
661  : BC_TextBox(x, y, format->w - x -
662                 2*format->mwindow->theme->get_image_set("wrench")[0]->get_w() - 20, 1,
663         format->asset->path)
664 {
665         this->format = format;
666 }
667
668 FormatPathText::~FormatPathText()
669 {
670 }
671 int FormatPathText::handle_event()
672 {
673         calculate_suggestions();
674         strcpy(format->asset->path, get_text());
675         format->handle_event();
676         return 1;
677 }
678
679
680
681
682 FormatAudio::FormatAudio(int x, int y, FormatTools *format, int default_)
683  : BC_CheckBox(x,
684         y,
685         default_,
686         (char*)(format->recording ? _("Record audio tracks") : _("Render audio tracks")))
687 {
688         this->format = format;
689 }
690
691 FormatAudio::~FormatAudio() {}
692 int FormatAudio::handle_event()
693 {
694         format->asset->audio_data = get_value();
695         format->handle_event();
696         return 1;
697 }
698
699
700 FormatVideo::FormatVideo(int x, int y, FormatTools *format, int default_)
701  : BC_CheckBox(x,
702         y,
703         default_,
704         (char*)(format->recording ? _("Record video tracks") : _("Render video tracks")))
705 {
706 this->format = format;
707 }
708
709 FormatVideo::~FormatVideo() {}
710 int FormatVideo::handle_event()
711 {
712         format->asset->video_data = get_value();
713         format->handle_event();
714         return 1;
715 }
716
717
718
719
720 FormatFormat::FormatFormat(int x, int y, FormatTools *format)
721  : FormatPopup(x, y, format->do_audio, format->do_video, format->use_brender)
722 {
723         this->format = format;
724 }
725
726 FormatFormat::~FormatFormat()
727 {
728 }
729
730 int FormatFormat::handle_event()
731 {
732         BC_ListBoxItem *selection = get_selection(0, 0);
733         if( selection ) {
734                 int new_format = File::strtoformat(get_selection(0, 0)->get_text());
735 //              if(new_format != format->asset->format)
736                 {
737                         Asset *asset = format->asset;
738                         asset->format = new_format;
739                         asset->audio_data = File::renders_audio(asset);
740                         asset->video_data = File::renders_video(asset);
741                         asset->ff_audio_options[0] = 0;
742                         asset->ff_video_options[0] = 0;
743                         format->format_text->update(selection->get_text());
744                         if( !format->use_brender )
745                                 format->update_extension();
746                         format->close_format_windows();
747                         if (format->path_recent) format->path_recent->
748                                 load_items(File::formattostr(format->asset->format));
749                         format->update_format();
750                 }
751                 format->handle_event();
752         }
753         return 1;
754 }
755
756
757 FormatFFMPEG::FormatFFMPEG(int x, int y, FormatTools *format)
758  : FFMPEGPopup(x, y)
759 {
760         this->format = format;
761 }
762
763 FormatFFMPEG::~FormatFFMPEG()
764 {
765 }
766
767 int FormatFFMPEG::handle_event()
768 {
769         BC_ListBoxItem *selection = get_selection(0, 0);
770         if( selection ) {
771                 char *text = get_selection(0, 0)->get_text();
772                 format->ffmpeg_type->update(text);
773                 format->asset->ff_audio_options[0] = 0;
774                 format->asset->ff_video_options[0] = 0;
775                 FFMPEG::set_asset_format(format->asset, format->mwindow->edl, text);
776                 format->update_extension();
777                 format->close_format_windows();
778                 format->update_format();
779                 format->handle_event();
780         }
781         return 1;
782 }
783
784
785 FormatFilePerLabel::FormatFilePerLabel(FormatTools *format,
786         int x, int y, int *output)
787  : BC_CheckBox(x, y, *output, _("Create new file at each label"))
788 {
789         this->format = format;
790         this->output = output;
791 }
792
793 FormatFilePerLabel::~FormatFilePerLabel()
794 {
795 }
796
797 int FormatFilePerLabel::handle_event()
798 {
799         *output = get_value();
800         format->handle_event();
801         return 1;
802 }
803
804 void FormatFilePerLabel::update(int *output)
805 {
806         this->output = output;
807         set_value(*output ? 1 : 0);
808 }
809
810