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