BD/DVD render setup upgrades
[goodguy/history.git] / cinelerra-5.1 / cinelerra / dvdcreate.C
1 #include "asset.h"
2 #include "clip.h"
3 #include "dvdcreate.h"
4 #include "edl.h"
5 #include "edit.h"
6 #include "edits.h"
7 #include "edlsession.h"
8 #include "filexml.h"
9 #include "keyframe.h"
10 #include "labels.h"
11 #include "mainerror.h"
12 #include "mainundo.h"
13 #include "mwindow.h"
14 #include "mwindowgui.h"
15 #include "plugin.h"
16 #include "pluginset.h"
17 #include "track.h"
18 #include "tracks.h"
19
20 #include <unistd.h>
21 #include <fcntl.h>
22 #include <errno.h>
23 #include <sys/stat.h>
24 #include <sys/statfs.h>
25
26 // DVD Creation
27
28 #define HD_1920x1080_2997       0
29 #define HD_1920x1080_2500       1
30 #define HD_1280x720_5994p       2
31 #define HD_1280x720_5000p       3
32 #define HD_720x576_5000p        4
33 #define HD_720x576_2500         5
34 #define HD_720x480_5994p        6
35 #define HD_720x480_2997         7
36
37 static struct hd_format {
38         const char *name;
39         int w, h;
40         double framerate;
41 } hd_formats[] = {
42         { "1920x1080 29.97",      1920,1080, 29.97  },
43         { "1920x1080 25",         1920,1080, 25     },
44         { "1280x720 59.94p",      1280,720,  59.94  },
45         { "1280x720 50p",         1280,720,  50     },
46         { "720x576 50p(PAL)",      720,576,  50     },
47         { "720x576 25 (PAL)",      720,576,  25     },
48         { "720x480 59.94p(NTSC)",  720,480,  59.94  },
49         { "720x480 29.97 (NTSC)",  720,480,  29.97  },
50 };
51
52 const int64_t CreateDVD_Thread::DVD_SIZE = 4700000000;
53 const int CreateDVD_Thread::DVD_STREAMS = 1;
54 const int CreateDVD_Thread::DVD_WIDTH = 720;
55 const int CreateDVD_Thread::DVD_HEIGHT = 480;
56 const double CreateDVD_Thread::DVD_ASPECT_WIDTH = 4.;
57 const double CreateDVD_Thread::DVD_ASPECT_HEIGHT = 3.;
58 const double CreateDVD_Thread::DVD_WIDE_ASPECT_WIDTH = 16.;
59 const double CreateDVD_Thread::DVD_WIDE_ASPECT_HEIGHT = 9.;
60 const double CreateDVD_Thread::DVD_FRAMERATE = 30000. / 1001.;
61 const int CreateDVD_Thread::DVD_MAX_BITRATE = 8000000;
62 const int CreateDVD_Thread::DVD_CHANNELS = 2;
63 const int CreateDVD_Thread::DVD_WIDE_CHANNELS = 6;
64 const double CreateDVD_Thread::DVD_SAMPLERATE = 48000;
65 const double CreateDVD_Thread::DVD_KAUDIO_RATE = 224;
66
67
68 CreateDVD_MenuItem::CreateDVD_MenuItem(MWindow *mwindow)
69  : BC_MenuItem(_("DVD Render..."), _("Shift-D"), 'D')
70 {
71         set_shift(1); 
72         this->mwindow = mwindow;
73 }
74
75 int CreateDVD_MenuItem::handle_event()
76 {
77         mwindow->create_dvd->start();
78         return 1;
79 }
80
81
82 CreateDVD_Thread::CreateDVD_Thread(MWindow *mwindow)
83  : BC_DialogThread()
84 {
85         this->mwindow = mwindow;
86         this->gui = 0;
87         this->use_deinterlace = 0;
88         this->use_scale = 0;
89         this->use_histogram = 0;
90         this->use_inverse_telecine = 0;
91         this->use_wide_audio = 0;
92         this->use_wide_aspect = 0;
93         this->use_ffmpeg = 0;
94         this->use_resize_tracks = 0;
95         this->use_label_chapters = 0;
96 }
97
98 CreateDVD_Thread::~CreateDVD_Thread()
99 {
100         close_window();
101 }
102
103 int CreateDVD_Thread::create_dvd_jobs(ArrayList<BatchRenderJob*> *jobs,
104         const char *tmp_path, const char *asset_title)
105 {
106         EDL *edl = mwindow->edl;
107         if( !edl || !edl->session ) {
108                 char msg[BCTEXTLEN];
109                 sprintf(msg, _("No EDL/Session"));
110                 MainError::show_error(msg);
111                 return 1;
112         }
113         EDLSession *session = edl->session;
114
115         double total_length = edl->tracks->total_length();
116         if( total_length <= 0 ) {
117                 char msg[BCTEXTLEN];
118                 sprintf(msg, _("No content: %s"), asset_title);
119                 MainError::show_error(msg);
120                 return 1;
121         }
122
123         char asset_dir[BCTEXTLEN];
124         sprintf(asset_dir, "%s/%s", tmp_path, asset_title);
125
126         if( mkdir(asset_dir, 0777) ) {
127                 char err[BCTEXTLEN], msg[BCTEXTLEN];
128                 strerror_r(errno, err, sizeof(err));
129                 sprintf(msg, _("Unable to create directory: %s\n-- %s"), asset_dir, err);
130                 MainError::show_error(msg);
131                 return 1;
132         }
133
134         double old_samplerate = session->sample_rate;
135         double old_framerate = session->frame_rate;
136
137         session->video_channels = DVD_STREAMS;
138         session->video_tracks = DVD_STREAMS;
139         session->frame_rate = dvd_framerate;
140         session->output_w = dvd_width;
141         session->output_h = dvd_height;
142         session->aspect_w = dvd_aspect_width;
143         session->aspect_h = dvd_aspect_height;
144         session->sample_rate = dvd_samplerate;
145         session->audio_channels = session->audio_tracks =
146                 use_wide_audio ? DVD_WIDE_CHANNELS : DVD_CHANNELS;
147
148         char script_filename[BCTEXTLEN];
149         sprintf(script_filename, "%s/dvd.sh", asset_dir);
150         int fd = open(script_filename, O_WRONLY+O_CREAT+O_TRUNC, 0755);
151         FILE *fp = fdopen(fd, "w");
152         if( !fp ) {
153                 char err[BCTEXTLEN], msg[BCTEXTLEN];
154                 strerror_r(errno, err, sizeof(err));
155                 sprintf(msg, _("Unable to save: %s\n-- %s"), script_filename, err);
156                 MainError::show_error(msg);
157                 return 1;
158         }
159         fprintf(fp,"#!/bin/bash\n");
160         fprintf(fp,"echo \"running %s\" $# $*\n", script_filename);
161         fprintf(fp,"\n");
162         char exe_path[BCTEXTLEN];
163         get_exe_path(exe_path);
164         fprintf(fp,"PATH=$PATH:%s\n",exe_path);
165         if( !use_ffmpeg ) {
166                 fprintf(fp,"mplex -f 8 -o $1/dvd.mpg $1/dvd.m2v $1/dvd.ac3\n");
167                 fprintf(fp,"\n");
168         }
169         fprintf(fp,"rm -rf $1/iso\n");
170         fprintf(fp,"mkdir -p $1/iso\n");
171         fprintf(fp,"\n");
172         fprintf(fp,"dvdauthor -x - <<eof\n");
173         fprintf(fp,"<dvdauthor dest=\"$1/iso\">\n");
174         fprintf(fp,"  <vmgm>\n");
175         fprintf(fp,"    <fpc> jump title 1; </fpc>\n");
176         fprintf(fp,"  </vmgm>\n");
177         fprintf(fp,"  <titleset>\n");
178         fprintf(fp,"    <titles>\n");
179         fprintf(fp,"    <video format=\"ntsc\" aspect=\"%d:%d\" resolution=\"%dx%d\"/>\n",
180                 (int)session->aspect_w, (int)session->aspect_h,
181                 session->output_w, session->output_h);
182         fprintf(fp,"    <audio format=\"ac3\" lang=\"en\"/>\n");
183         fprintf(fp,"    <pgc>\n");
184         fprintf(fp,"      <vob file=\"$1/dvd.mpg\" chapters=\"");
185         if( use_label_chapters && edl->labels ) {
186                 Label *label = edl->labels->first;
187                 while( label ) {
188                         int secs = label->position;
189                         int mins = secs / 60;
190                         int frms = (label->position-secs) * session->frame_rate;
191                         fprintf(fp,"%d:%02d:%02d.%d", mins/60, mins%60, secs%60, frms);
192                         if( (label=label->next) != 0 ) fprintf(fp, ",");
193                 }
194         }
195         else {
196                 int mins = 0;
197                 for( int secs=0 ; secs<total_length; secs+=10*60 ) {
198                         mins = secs / 60;
199                         fprintf(fp,"%d:%02d:00,", mins/60, mins%60);
200                 }
201                 fprintf(fp,"%d:%02d:00", mins/60, mins%60);
202         }
203         fprintf(fp,"\"/>\n");
204         fprintf(fp,"    </pgc>\n");
205         fprintf(fp,"    </titles>\n");
206         fprintf(fp,"  </titleset>\n");
207         fprintf(fp,"</dvdauthor>\n");
208         fprintf(fp,"eof\n");
209         fprintf(fp,"\n");
210         fprintf(fp,"echo To burn dvd, load blank media and run:\n");
211         fprintf(fp,"echo growisofs -dvd-compat -Z /dev/dvd -dvd-video $1/iso\n");
212         fprintf(fp,"\n");
213         fclose(fp);
214
215         if( use_wide_audio ) {
216                 session->audio_channels = session->audio_tracks = DVD_WIDE_CHANNELS;
217                 session->achannel_positions[0] = 90;
218                 session->achannel_positions[1] = 150;
219                 session->achannel_positions[2] = 30;
220                 session->achannel_positions[3] = 210;
221                 session->achannel_positions[4] = 330;
222                 session->achannel_positions[5] = 270;
223                 if( edl->tracks->recordable_audio_tracks() == DVD_WIDE_CHANNELS )
224                         mwindow->remap_audio(MWindow::AUDIO_1_TO_1);
225         }
226         else {
227                 session->audio_channels = session->audio_tracks = DVD_CHANNELS;
228                 session->achannel_positions[0] = 180;
229                 session->achannel_positions[1] = 0;
230                 if( edl->tracks->recordable_audio_tracks() == DVD_WIDE_CHANNELS )
231                         mwindow->remap_audio(MWindow::AUDIO_5_1_TO_2);
232         }
233
234         double new_samplerate = session->sample_rate;
235         double new_framerate = session->frame_rate;
236         edl->rechannel();
237         edl->resample(old_samplerate, new_samplerate, TRACK_AUDIO);
238         edl->resample(old_framerate, new_framerate, TRACK_VIDEO);
239
240         int64_t aud_size = ((dvd_kaudio_rate * total_length)/8 + 1000-1) * 1000;
241         int64_t vid_size = dvd_size*0.96 - aud_size;
242         int64_t vid_bitrate = (vid_size * 8) / total_length;
243         vid_bitrate /= 1000;  vid_bitrate *= 1000;
244         if( vid_bitrate > dvd_max_bitrate )
245                 vid_bitrate = dvd_max_bitrate;
246
247         char xml_filename[BCTEXTLEN];
248         sprintf(xml_filename, "%s/dvd.xml", asset_dir);
249         FileXML xml_file;
250         edl->save_xml(&xml_file, xml_filename, 0, 0);
251         xml_file.terminate_string();
252         if( xml_file.write_to_file(xml_filename) ) {
253                 char msg[BCTEXTLEN];
254                 sprintf(msg, _("Unable to save: %s"), xml_filename);
255                 MainError::show_error(msg);
256                 return 1;
257         }
258
259         BatchRenderJob *job = new BatchRenderJob(mwindow->preferences);
260         jobs->append(job);
261         strcpy(&job->edl_path[0], xml_filename);
262         Asset *asset = job->asset;
263
264         asset->layers = DVD_STREAMS;
265         asset->frame_rate = session->frame_rate;
266         asset->width = session->output_w;
267         asset->height = session->output_h;
268         asset->aspect_ratio = session->aspect_w / session->aspect_h;
269
270         if( use_ffmpeg ) {
271                 char option_path[BCTEXTLEN];
272                 sprintf(&asset->path[0],"%s/dvd.mpg", asset_dir);
273                 asset->format = FILE_FFMPEG;
274                 strcpy(asset->fformat, "dvd");
275
276                 asset->audio_data = 1;
277                 strcpy(asset->acodec, "dvd.dvd");
278                 FFMPEG::set_option_path(option_path, "audio/%s", asset->acodec);
279                 FFMPEG::load_options(option_path, asset->ff_audio_options,
280                          sizeof(asset->ff_audio_options));
281                 asset->ff_audio_bitrate = dvd_kaudio_rate * 1000;
282
283                 asset->video_data = 1;
284                 strcpy(asset->vcodec, "dvd.dvd");
285                 FFMPEG::set_option_path(option_path, "video/%s", asset->vcodec);
286                 FFMPEG::load_options(option_path, asset->ff_video_options,
287                          sizeof(asset->ff_video_options));
288                 asset->ff_video_bitrate = vid_bitrate;
289                 asset->ff_video_quality = 0;
290         }
291         else {
292                 sprintf(&asset->path[0],"%s/dvd.m2v", asset_dir);
293                 asset->video_data = 1;
294                 asset->format = FILE_VMPEG;
295                 asset->vmpeg_cmodel = BC_YUV420P;
296                 asset->vmpeg_fix_bitrate = 1;
297                 asset->vmpeg_bitrate = vid_bitrate;
298                 asset->vmpeg_quantization = 15;
299                 asset->vmpeg_iframe_distance = 15;
300                 asset->vmpeg_progressive = 0;
301                 asset->vmpeg_denoise = 0;
302                 asset->vmpeg_seq_codes = 0;
303                 asset->vmpeg_derivative = 2;
304                 asset->vmpeg_preset = 8;
305                 asset->vmpeg_field_order = 0;
306                 asset->vmpeg_pframe_distance = 0;
307                 job = new BatchRenderJob(mwindow->preferences);
308                 jobs->append(job);
309                 strcpy(&job->edl_path[0], xml_filename);
310                 asset = job->asset;
311                 
312                 sprintf(&asset->path[0],"%s/dvd.ac3", asset_dir);
313                 asset->audio_data = 1;
314                 asset->format = FILE_AC3;
315                 asset->channels = session->audio_channels;
316                 asset->sample_rate = session->sample_rate;
317                 asset->bits = 16;
318                 asset->byte_order = 0;
319                 asset->signed_ = 1;
320                 asset->header = 0;
321                 asset->dither = 0;
322                 asset->ac3_bitrate = dvd_kaudio_rate;
323         }
324
325         job = new BatchRenderJob(mwindow->preferences);
326         jobs->append(job);
327         job->edl_path[0] = '@';
328         strcpy(&job->edl_path[1], script_filename);
329         strcpy(&job->asset->path[0], asset_dir);
330
331         return 0;
332 }
333
334 void CreateDVD_Thread::handle_close_event(int result)
335 {
336         if( result ) return;
337         mwindow->batch_render->load_defaults(mwindow->defaults);
338         mwindow->undo->update_undo_before();
339         KeyFrame keyframe;  char data[BCTEXTLEN];
340         if( use_deinterlace ) {
341                 sprintf(data,"<DEINTERLACE MODE=1>");
342                 keyframe.set_data(data);
343                 insert_video_plugin("Deinterlace", &keyframe);
344         }
345         if( use_inverse_telecine ) {
346                 sprintf(data,"<IVTC FRAME_OFFSET=0 FIRST_FIELD=0 "
347                         "AUTOMATIC=1 AUTO_THRESHOLD=2.0e+00 PATTERN=2>");
348                 keyframe.set_data(data);
349                 insert_video_plugin("Inverse Telecine", &keyframe);
350         }
351         if( use_scale ) {
352                 sprintf(data,"<SCALE TYPE=1 X_FACTOR=1 Y_FACTOR=1 "
353                         "WIDTH=%d HEIGHT=%d CONSTRAIN=0>", dvd_width, dvd_height);
354                 keyframe.set_data(data);
355                 insert_video_plugin("Scale", &keyframe);
356         }
357         if( use_resize_tracks )
358                 resize_tracks();
359         if( use_histogram ) {
360 #if 0
361                 sprintf(data, "<HISTOGRAM OUTPUT_MIN_0=0 OUTPUT_MAX_0=1 "
362                         "OUTPUT_MIN_1=0 OUTPUT_MAX_1=1 "
363                         "OUTPUT_MIN_2=0 OUTPUT_MAX_2=1 "
364                         "OUTPUT_MIN_3=0 OUTPUT_MAX_3=1 "
365                         "AUTOMATIC=0 THRESHOLD=9.0-01 PLOT=0 SPLIT=0>"
366                         "<POINTS></POINTS><POINTS></POINTS><POINTS></POINTS>"
367                         "<POINTS><POINT X=6.0e-02 Y=0>"
368                                 "<POINT X=9.4e-01 Y=1></POINTS>");
369 #else
370                 sprintf(data, "<HISTOGRAM AUTOMATIC=0 THRESHOLD=1.0e-01 "
371                         "PLOT=0 SPLIT=0 W=440 H=500 PARADE=0 MODE=3 "
372                         "LOW_OUTPUT_0=0 HIGH_OUTPUT_0=1 LOW_INPUT_0=0 HIGH_INPUT_0=1 GAMMA_0=1 "
373                         "LOW_OUTPUT_1=0 HIGH_OUTPUT_1=1 LOW_INPUT_1=0 HIGH_INPUT_1=1 GAMMA_1=1 "
374                         "LOW_OUTPUT_2=0 HIGH_OUTPUT_2=1 LOW_INPUT_2=0 HIGH_INPUT_2=1 GAMMA_2=1 "
375                         "LOW_OUTPUT_3=0 HIGH_OUTPUT_3=1 LOW_INPUT_3=0.044 HIGH_INPUT_3=0.956 "
376                         "GAMMA_3=1>");
377 #endif
378                 keyframe.set_data(data);
379                 insert_video_plugin("Histogram", &keyframe);
380         }
381         mwindow->batch_render->reset();
382         create_dvd_jobs(&mwindow->batch_render->jobs, tmp_path, asset_title);
383         mwindow->save_backup();
384         mwindow->undo->update_undo_after(_("create dvd"), LOAD_ALL);
385         mwindow->resync_guis();
386         mwindow->batch_render->handle_close_event(0);
387         mwindow->batch_render->start();
388 }
389
390 BC_Window* CreateDVD_Thread::new_gui()
391 {
392         memset(tmp_path,0,sizeof(tmp_path));
393         strcpy(tmp_path,"/tmp");
394         memset(asset_title,0,sizeof(asset_title));
395         time_t dt;  time(&dt);
396         struct tm dtm;  localtime_r(&dt, &dtm);
397         sprintf(asset_title, "dvd_%02d%02d%02d-%02d%02d%02d",
398                 dtm.tm_year+1900, dtm.tm_mon+1, dtm.tm_mday,
399                 dtm.tm_hour, dtm.tm_min, dtm.tm_sec);
400         use_deinterlace = 0;
401         use_scale = 0;
402         use_histogram = 0;
403         use_inverse_telecine = 0;
404         use_wide_audio = 0;
405         use_wide_aspect = 0;
406         use_ffmpeg = 0;
407         use_resize_tracks = 0;
408         use_label_chapters = 0;
409         use_standard = HD_720x480_2997;
410
411         dvd_size = DVD_SIZE;
412         dvd_width = DVD_WIDTH;
413         dvd_height = DVD_HEIGHT;
414         dvd_aspect_width = DVD_ASPECT_WIDTH;
415         dvd_aspect_height = DVD_ASPECT_HEIGHT;
416         dvd_framerate = DVD_FRAMERATE;
417         dvd_samplerate = DVD_SAMPLERATE;
418         dvd_max_bitrate = DVD_MAX_BITRATE;
419         dvd_kaudio_rate = DVD_KAUDIO_RATE;
420
421         int has_standard = -1;
422         if( mwindow->edl ) {
423                 EDLSession *session = mwindow->edl->session;
424 // match the session to any known standard
425                 for( int i=0; i<(int)(sizeof(hd_formats)/sizeof(hd_formats[0])); ++i ) {
426                         if( !EQUIV(session->frame_rate, hd_formats[i].framerate) ) continue;
427                         if( session->output_w != hd_formats[i].w ) continue;
428                         if( session->output_h != hd_formats[i].h ) continue;
429                         has_standard = i;  break;
430                 }
431                 if( has_standard < 0 ) {
432 // or use the default standard
433                         if( !strcmp(mwindow->default_standard, "NTSC") ) has_standard = HD_720x480_2997;
434                         else if( !strcmp(mwindow->default_standard, "PAL") ) has_standard = HD_720x576_2500;
435                 }
436         }
437         use_standard = has_standard >= 0 ? has_standard : HD_720x480_2997;
438
439         option_presets();
440         int scr_x = mwindow->gui->get_screen_x(0, -1);
441         int scr_w = mwindow->gui->get_screen_w(0, -1);
442         int scr_h = mwindow->gui->get_screen_h(0, -1);
443         int w = 500, h = 280;
444         int x = scr_x + scr_w/2 - w/2, y = scr_h/2 - h/2;
445
446         gui = new CreateDVD_GUI(this, x, y, w, h);
447         gui->create_objects();
448         return gui;
449 }
450
451
452 CreateDVD_OK::CreateDVD_OK(CreateDVD_GUI *gui, int x, int y)
453  : BC_OKButton(x, y)
454 {
455         this->gui = gui;
456         set_tooltip(_("end setup, start batch render"));
457 }
458
459 CreateDVD_OK::~CreateDVD_OK()
460 {
461 }
462
463 int CreateDVD_OK::button_press_event()
464 {
465         if(get_buttonpress() == 1 && is_event_win() && cursor_inside()) {
466                 gui->set_done(0);
467                 return 1;
468         }
469         return 0;
470 }
471
472 int CreateDVD_OK::keypress_event()
473 {
474         return 0;
475 }
476
477
478 CreateDVD_Cancel::CreateDVD_Cancel(CreateDVD_GUI *gui, int x, int y)
479  : BC_CancelButton(x, y)
480 {
481         this->gui = gui;
482 }
483
484 CreateDVD_Cancel::~CreateDVD_Cancel()
485 {
486 }
487
488 int CreateDVD_Cancel::button_press_event()
489 {
490         if(get_buttonpress() == 1 && is_event_win() && cursor_inside()) {
491                 gui->set_done(1);
492                 return 1;
493         }
494         return 0;
495 }
496
497
498 CreateDVD_DiskSpace::CreateDVD_DiskSpace(CreateDVD_GUI *gui, int x, int y)
499  : BC_Title(x, y, "", MEDIUMFONT, GREEN)
500 {
501         this->gui = gui;
502 }
503
504 CreateDVD_DiskSpace::~CreateDVD_DiskSpace()
505 {
506 }
507
508 int64_t CreateDVD_DiskSpace::tmp_path_space()
509 {
510         const char *path = gui->tmp_path->get_text();
511         if( access(path,R_OK+W_OK) ) return 0;
512         struct statfs sfs;
513         if( statfs(path, &sfs) ) return 0;
514         return (int64_t)sfs.f_bsize * sfs.f_bfree;
515 }
516
517 void CreateDVD_DiskSpace::update()
518 {
519         static const char *suffix[] = { "", "KB", "MB", "GB", "TB", "PB" };
520         int64_t disk_space = tmp_path_space();
521         double media_size = 15e9, msz = 0, m = 1;
522         char sfx[BCSTRLEN];
523         if( sscanf(gui->media_size->get_text(), "%lf%s", &msz, sfx) == 2 ) {
524                 int i = sizeof(suffix)/sizeof(suffix[0]);
525                 while( --i >= 0 && strcmp(sfx, suffix[i]) );
526                 while( --i >= 0 ) m *= 1000;
527                 media_size = msz * m;
528         }
529         m = gui->thread->use_ffmpeg ? 2 : 3;
530         int color = disk_space < media_size*m ? RED : GREEN;
531         int i = 0;
532         for( int64_t space=disk_space; i<5 && (space/=1000)>0; disk_space=space, ++i );
533         char text[BCTEXTLEN];
534         sprintf(text, "%s%3jd%s", _("disk space: "), disk_space, suffix[i]);
535         gui->disk_space->BC_Title::update(text);
536         gui->disk_space->set_color(color);
537 }
538
539 CreateDVD_TmpPath::CreateDVD_TmpPath(CreateDVD_GUI *gui, int x, int y, int w)
540  : BC_TextBox(x, y, w, 1, -(int)sizeof(gui->thread->tmp_path),
541                 gui->thread->tmp_path, 1, MEDIUMFONT)
542 {
543         this->gui = gui;
544 }
545
546 CreateDVD_TmpPath::~CreateDVD_TmpPath()
547 {
548 }
549
550 int CreateDVD_TmpPath::handle_event()
551 {
552         gui->disk_space->update();
553         return 1;
554 }
555
556
557 CreateDVD_AssetTitle::CreateDVD_AssetTitle(CreateDVD_GUI *gui, int x, int y, int w)
558  : BC_TextBox(x, y, w, 1, 0, gui->thread->asset_title, 1, MEDIUMFONT)
559 {
560         this->gui = gui;
561 }
562
563 CreateDVD_AssetTitle::~CreateDVD_AssetTitle()
564 {
565 }
566
567
568 CreateDVD_Deinterlace::CreateDVD_Deinterlace(CreateDVD_GUI *gui, int x, int y)
569  : BC_CheckBox(x, y, &gui->thread->use_deinterlace, _("Deinterlace"))
570 {
571         this->gui = gui;
572 }
573
574 CreateDVD_Deinterlace::~CreateDVD_Deinterlace()
575 {
576 }
577
578 int CreateDVD_Deinterlace::handle_event()
579 {
580         if( get_value() ) {
581                 gui->need_inverse_telecine->set_value(0);
582                 gui->thread->use_inverse_telecine = 0;
583         }
584         return BC_CheckBox::handle_event();
585 }
586
587
588 CreateDVD_InverseTelecine::CreateDVD_InverseTelecine(CreateDVD_GUI *gui, int x, int y)
589  : BC_CheckBox(x, y, &gui->thread->use_inverse_telecine, _("Inverse Telecine"))
590 {
591         this->gui = gui;
592 }
593
594 CreateDVD_InverseTelecine::~CreateDVD_InverseTelecine()
595 {
596 }
597
598 int CreateDVD_InverseTelecine::handle_event()
599 {
600         if( get_value() ) {
601                 gui->need_deinterlace->set_value(0);
602                 gui->thread->use_deinterlace = 0;
603         }
604         return BC_CheckBox::handle_event();
605 }
606
607
608 CreateDVD_Scale::CreateDVD_Scale(CreateDVD_GUI *gui, int x, int y)
609  : BC_CheckBox(x, y, &gui->thread->use_scale, _("Scale"))
610 {
611         this->gui = gui;
612 }
613
614 CreateDVD_Scale::~CreateDVD_Scale()
615 {
616 }
617
618
619 CreateDVD_ResizeTracks::CreateDVD_ResizeTracks(CreateDVD_GUI *gui, int x, int y)
620  : BC_CheckBox(x, y, &gui->thread->use_resize_tracks, _("Resize Tracks"))
621 {
622         this->gui = gui;
623 }
624
625 CreateDVD_ResizeTracks::~CreateDVD_ResizeTracks()
626 {
627 }
628
629
630 CreateDVD_Histogram::CreateDVD_Histogram(CreateDVD_GUI *gui, int x, int y)
631  : BC_CheckBox(x, y, &gui->thread->use_histogram, _("Histogram"))
632 {
633         this->gui = gui;
634 }
635
636 CreateDVD_Histogram::~CreateDVD_Histogram()
637 {
638 }
639
640 CreateDVD_LabelChapters::CreateDVD_LabelChapters(CreateDVD_GUI *gui, int x, int y)
641  : BC_CheckBox(x, y, &gui->thread->use_label_chapters, _("Chapters at Labels"))
642 {
643         this->gui = gui;
644 }
645
646 CreateDVD_LabelChapters::~CreateDVD_LabelChapters()
647 {
648 }
649
650 CreateDVD_WideAudio::CreateDVD_WideAudio(CreateDVD_GUI *gui, int x, int y)
651  : BC_CheckBox(x, y, &gui->thread->use_wide_audio, _("Audio 5.1"))
652 {
653         this->gui = gui;
654 }
655
656 CreateDVD_WideAudio::~CreateDVD_WideAudio()
657 {
658 }
659
660 CreateDVD_WideAspect::CreateDVD_WideAspect(CreateDVD_GUI *gui, int x, int y)
661  : BC_CheckBox(x, y, &gui->thread->use_wide_aspect, _("Aspect 16x9"))
662 {
663         this->gui = gui;
664 }
665
666 CreateDVD_WideAspect::~CreateDVD_WideAspect()
667 {
668 }
669
670 CreateDVD_UseFFMpeg::CreateDVD_UseFFMpeg(CreateDVD_GUI *gui, int x, int y)
671  : BC_CheckBox(x, y, &gui->thread->use_ffmpeg, _("Use FFMPEG"))
672 {
673         this->gui = gui;
674 }
675
676 CreateDVD_UseFFMpeg::~CreateDVD_UseFFMpeg()
677 {
678 }
679
680
681
682
683 CreateDVD_GUI::CreateDVD_GUI(CreateDVD_Thread *thread, int x, int y, int w, int h)
684  : BC_Window(_(PROGRAM_NAME ": Create DVD"), x, y, w, h, 50, 50, 1, 0, 1)
685 {
686         this->thread = thread;
687         at_x = at_y = tmp_x = tmp_y = 0;
688         ok_x = ok_y = ok_w = ok_h = 0;
689         cancel_x = cancel_y = cancel_w = cancel_h = 0;
690         asset_title = 0;
691         tmp_path = 0;
692         disk_space = 0;
693         need_deinterlace = 0;
694         need_inverse_telecine = 0;
695         need_scale = 0;
696         need_resize_tracks = 0;
697         need_histogram = 0;
698         need_wide_audio = 0;
699         need_wide_aspect = 0;
700         need_label_chapters = 0;
701         ok = 0;
702         cancel = 0;
703 }
704
705 CreateDVD_GUI::~CreateDVD_GUI()
706 {
707 }
708
709 void CreateDVD_GUI::create_objects()
710 {
711         lock_window("CreateDVD_GUI::create_objects");
712         int pady = BC_TextBox::calculate_h(this, MEDIUMFONT, 0, 1) + 5;
713         int padx = BC_Title::calculate_w(this, (char*)"X", MEDIUMFONT);
714         int x = padx/2, y = pady/2;
715         BC_Title *title = new BC_Title(x, y, _("Title:"), MEDIUMFONT, YELLOW);
716         add_subwindow(title);
717         at_x = x + title->get_w();  at_y = y;
718         asset_title = new CreateDVD_AssetTitle(this, at_x, at_y, get_w()-at_x-10);
719         add_subwindow(asset_title);
720         y += title->get_h() + pady/2;
721         title = new BC_Title(x, y, _("tmp path:"), MEDIUMFONT, YELLOW);
722         add_subwindow(title);
723         tmp_x = x + title->get_w();  tmp_y = y;
724         tmp_path = new CreateDVD_TmpPath(this, tmp_x, tmp_y,  get_w()-tmp_x-10);
725         add_subwindow(tmp_path);
726         y += title->get_h() + pady/2;
727         disk_space = new CreateDVD_DiskSpace(this, x, y);
728         add_subwindow(disk_space);
729         int x0 = get_w() - 170;
730         title = new BC_Title(x0, y, _("Media:"), MEDIUMFONT, YELLOW);
731         add_subwindow(title);
732         x0 +=  title->get_w() + padx;
733         media_size = new CreateDVD_MediaSize(this, x0, y);
734         media_size->create_objects();
735         media_sizes.append(new BC_ListBoxItem("4.7GB"));
736         media_sizes.append(new BC_ListBoxItem("8.3GB"));
737         media_size->update_list(&media_sizes);
738         media_size->update(media_sizes[0]->get_text());
739         disk_space->update();
740         x0 = x;
741         y += disk_space->get_h() + pady/2;
742         title = new BC_Title(x0, y, _("Format:"), MEDIUMFONT, YELLOW);
743         add_subwindow(title);
744         x0 +=  title->get_w() + padx;
745         standard = new CreateDVD_Format(this, x0, y);
746         add_subwindow(standard);
747         standard->create_objects();
748         y += standard->get_h() + pady/2;
749         need_deinterlace = new CreateDVD_Deinterlace(this, x, y);
750         add_subwindow(need_deinterlace);
751         int x1 = x + 150, x2 = x1 + 150;
752         need_inverse_telecine = new CreateDVD_InverseTelecine(this, x1, y);
753         add_subwindow(need_inverse_telecine);
754         need_use_ffmpeg = new CreateDVD_UseFFMpeg(this, x2, y);
755         add_subwindow(need_use_ffmpeg);
756         y += need_deinterlace->get_h() + pady/2;
757         need_scale = new CreateDVD_Scale(this, x, y);
758         add_subwindow(need_scale);
759         need_wide_audio = new CreateDVD_WideAudio(this, x1, y);
760         add_subwindow(need_wide_audio);
761         need_resize_tracks = new CreateDVD_ResizeTracks(this, x2, y);
762         add_subwindow(need_resize_tracks);
763         y += need_scale->get_h() + pady/2;
764         need_histogram = new CreateDVD_Histogram(this, x, y);
765         add_subwindow(need_histogram);
766         need_wide_aspect = new CreateDVD_WideAspect(this, x1, y);
767         add_subwindow(need_wide_aspect);
768         need_label_chapters = new CreateDVD_LabelChapters(this, x2, y);
769         add_subwindow(need_label_chapters);
770         ok_w = BC_OKButton::calculate_w();
771         ok_h = BC_OKButton::calculate_h();
772         ok_x = 10;
773         ok_y = get_h() - ok_h - 10;
774         ok = new CreateDVD_OK(this, ok_x, ok_y);
775         add_subwindow(ok);
776         cancel_w = BC_CancelButton::calculate_w();
777         cancel_h = BC_CancelButton::calculate_h();
778         cancel_x = get_w() - cancel_w - 10,
779         cancel_y = get_h() - cancel_h - 10;
780         cancel = new CreateDVD_Cancel(this, cancel_x, cancel_y);
781         add_subwindow(cancel);
782         show_window();
783         unlock_window();
784 }
785
786 int CreateDVD_GUI::resize_event(int w, int h)
787 {
788         asset_title->reposition_window(at_x, at_y, get_w()-at_x-10);
789         tmp_path->reposition_window(tmp_x, tmp_y,  get_w()-tmp_x-10);
790         ok_y = h - ok_h - 10;
791         ok->reposition_window(ok_x, ok_y);
792         cancel_x = w - cancel_w - 10,
793         cancel_y = h - cancel_h - 10;
794         cancel->reposition_window(cancel_x, cancel_y);
795         return 0;
796 }
797
798 int CreateDVD_GUI::translation_event()
799 {
800         return 1;
801 }
802
803 int CreateDVD_GUI::close_event()
804 {
805         set_done(1);
806         return 1;
807 }
808
809 void CreateDVD_GUI::update()
810 {
811         need_deinterlace->set_value(thread->use_deinterlace);
812         need_inverse_telecine->set_value(thread->use_inverse_telecine);
813         need_scale->set_value(thread->use_scale);
814         need_use_ffmpeg->set_value(thread->use_ffmpeg);
815         need_resize_tracks->set_value(thread->use_resize_tracks);
816         need_histogram->set_value(thread->use_histogram);
817         need_wide_audio->set_value(thread->use_wide_audio);
818         need_wide_aspect->set_value(thread->use_wide_aspect);
819         need_label_chapters->set_value(thread->use_label_chapters);
820 }
821
822 int CreateDVD_Thread::
823 insert_video_plugin(const char *title, KeyFrame *default_keyframe)
824 {
825         Tracks *tracks = mwindow->edl->tracks;
826         for( Track *vtrk=tracks->first; vtrk; vtrk=vtrk->next ) {
827                 if( vtrk->data_type != TRACK_VIDEO ) continue;
828                 if( !vtrk->record ) continue;
829                 vtrk->expand_view = 1;
830                 PluginSet *plugin_set = new PluginSet(mwindow->edl, vtrk);
831                 vtrk->plugin_set.append(plugin_set);
832                 Edits *edits = vtrk->edits;
833                 for( Edit *edit=edits->first; edit; edit=edit->next ) {
834                         plugin_set->insert_plugin(_(title),
835                                 edit->startproject, edit->length,
836                                 PLUGIN_STANDALONE, 0, default_keyframe, 0);
837                 }
838                 vtrk->optimize();
839         }
840         return 0;
841 }
842
843 int CreateDVD_Thread::
844 resize_tracks()
845 {
846         Tracks *tracks = mwindow->edl->tracks;
847         int max_w = 0, max_h = 0;
848         for( Track *vtrk=tracks->first; vtrk; vtrk=vtrk->next ) {
849                 if( vtrk->data_type != TRACK_VIDEO ) continue;
850                 if( !vtrk->record ) continue;
851                 Edits *edits = vtrk->edits;
852                 for( Edit *edit=edits->first; edit; edit=edit->next ) {
853                         Indexable *indexable = edit->get_source();
854                         int w = indexable->get_w();
855                         if( w > max_w ) max_w = w;
856                         int h = indexable->get_h();
857                         if( h > max_h ) max_h = h;
858                 }
859         }
860
861         for( Track *vtrk=tracks->first; vtrk; vtrk=vtrk->next ) {
862                 if( vtrk->data_type != TRACK_VIDEO ) continue;
863                 if( !vtrk->record ) continue;
864                 vtrk->track_w = max_w;
865                 vtrk->track_h = max_h;
866         }
867         return 0;
868 }
869
870 int CreateDVD_Thread::
871 option_presets()
872 {
873 // reset only probed options
874         use_deinterlace = 0;
875         use_scale = 0;
876         use_resize_tracks = 0;
877         use_wide_audio = 0;
878         use_wide_aspect = 0;
879         use_label_chapters = 0;
880
881         if( !mwindow->edl ) return 1;
882
883         dvd_width = hd_formats[use_standard].w;
884         dvd_height = hd_formats[use_standard].h;
885         dvd_framerate = hd_formats[use_standard].framerate;
886
887         Tracks *tracks = mwindow->edl->tracks;
888         int max_w = 0, max_h = 0;
889         int has_deinterlace = 0, has_scale = 0;
890         for( Track *trk=tracks->first; trk; trk=trk->next ) {
891                 if( !trk->record ) continue;
892                 Edits *edits = trk->edits;
893                 switch( trk->data_type ) {
894                 case TRACK_VIDEO:
895                         for( Edit *edit=edits->first; edit; edit=edit->next ) {
896                                 if( edit->silence() ) continue;
897                                 Indexable *indexable = edit->get_source();
898                                 int w = indexable->get_w();
899                                 if( w > max_w ) max_w = w;
900                                 if( w != dvd_width ) use_scale = 1;
901                                 int h = indexable->get_h();
902                                 if( h > max_h ) max_h = h;
903                                 if( h != dvd_height ) use_scale = 1;
904                         }
905                         for( int i=0; i<trk->plugin_set.size(); ++i ) {
906                                 for(Plugin *plugin = (Plugin*)trk->plugin_set[i]->first;
907                                                 plugin;
908                                                 plugin = (Plugin*)plugin->next) {
909                                         if( !strcmp(plugin->title, _("Deinterlace")) )
910                                                 has_deinterlace = 1;
911                                         if( !strcmp(plugin->title, _("Auto Scale")) ||
912                                             !strcmp(plugin->title, _("Scale")) )
913                                                 has_scale = 1;
914                                 }
915                         }
916                         break;
917                 }
918         }
919         if( has_scale )
920                 use_scale = 0;
921         if( use_scale ) {
922                 if( max_w != dvd_width ) use_resize_tracks = 1;
923                 if( max_h != dvd_height ) use_resize_tracks = 1;
924         }
925         for( Track *trk=tracks->first; trk && !use_resize_tracks; trk=trk->next ) {
926                 if( !trk->record ) continue;
927                 switch( trk->data_type ) {
928                 case TRACK_VIDEO:
929                         if( trk->track_w != max_w ) use_resize_tracks = 1;
930                         if( trk->track_h != max_h ) use_resize_tracks = 1;
931                         break;
932                 }
933         }
934         if( !has_deinterlace && max_h > 2*dvd_height ) use_deinterlace = 1;
935         Labels *labels = mwindow->edl->labels;
936         use_label_chapters = labels && labels->first ? 1 : 0;
937
938         float aw, ah;
939         MWindow::create_aspect_ratio(aw, ah, max_w, max_h);
940         if( aw == DVD_WIDE_ASPECT_WIDTH && ah == DVD_WIDE_ASPECT_HEIGHT )
941                 use_wide_aspect = 1;
942         dvd_aspect_width = use_wide_aspect ? DVD_WIDE_ASPECT_WIDTH : DVD_ASPECT_WIDTH;
943         dvd_aspect_height = use_wide_aspect ? DVD_WIDE_ASPECT_HEIGHT : DVD_ASPECT_HEIGHT;
944
945         if( tracks->recordable_audio_tracks() == DVD_WIDE_CHANNELS )
946                 use_wide_audio = 1;
947
948         return 0;
949 }
950
951
952
953 CreateDVD_FormatItem::CreateDVD_FormatItem(CreateDVD_Format *popup,
954                 int standard, const char *name)
955  : BC_MenuItem(name)
956 {
957         this->popup = popup;
958         this->standard = standard;
959 }
960
961 CreateDVD_FormatItem::~CreateDVD_FormatItem()
962 {
963 }
964
965 int CreateDVD_FormatItem::handle_event()
966 {
967         popup->set_text(get_text());
968         popup->gui->thread->use_standard = standard;
969         return popup->handle_event();
970 }
971
972
973 CreateDVD_Format::CreateDVD_Format(CreateDVD_GUI *gui, int x, int y)
974  : BC_PopupMenu(x, y, 180, hd_formats[gui->thread->use_standard].name, 1)
975 {
976         this->gui = gui;
977 }
978
979 CreateDVD_Format::~CreateDVD_Format()
980 {
981 }
982
983 void CreateDVD_Format::create_objects()
984 {
985         for( int i=0; i<(int)(sizeof(hd_formats)/sizeof(hd_formats[0])); ++i ) {
986                 add_item(new CreateDVD_FormatItem(this, i, hd_formats[i].name));
987         }
988 }
989
990 int CreateDVD_Format::handle_event()
991 {
992         gui->thread->option_presets();
993         gui->update();
994         return 1;
995 }
996
997 CreateDVD_MediaSize::CreateDVD_MediaSize(CreateDVD_GUI *gui, int x, int y)
998  : BC_PopupTextBox(gui, 0, 0, x, y, 70,50)
999 {
1000         this->gui = gui;
1001 }
1002
1003 CreateDVD_MediaSize::~CreateDVD_MediaSize()
1004 {
1005 }
1006
1007 int CreateDVD_MediaSize::handle_event()
1008 {
1009         gui->disk_space->update();
1010         return 1;
1011 }
1012