add bluray support, add dialog close fixes, scale fix
authorGood Guy <good1.2guy@gmail.com>
Sun, 16 Aug 2015 01:17:49 +0000 (19:17 -0600)
committerGood Guy <good1.2guy@gmail.com>
Sun, 16 Aug 2015 01:17:49 +0000 (19:17 -0600)
54 files changed:
cinelerra-5.0/build/Makefile.cinelerra
cinelerra-5.0/cinelerra/Makefile
cinelerra-5.0/cinelerra/assetedit.C
cinelerra-5.0/cinelerra/awindowgui.C
cinelerra-5.0/cinelerra/batchrender.C
cinelerra-5.0/cinelerra/batchrender.h
cinelerra-5.0/cinelerra/batchrender.inc
cinelerra-5.0/cinelerra/bdcreate.C [new file with mode: 0644]
cinelerra-5.0/cinelerra/bdcreate.h [new file with mode: 0644]
cinelerra-5.0/cinelerra/bdcreate.inc [new file with mode: 0644]
cinelerra-5.0/cinelerra/bdwrite.C [new file with mode: 0644]
cinelerra-5.0/cinelerra/channeledit.C
cinelerra-5.0/cinelerra/channeledit.h
cinelerra-5.0/cinelerra/clipedit.C
cinelerra-5.0/cinelerra/dvdcreate.C [new file with mode: 0644]
cinelerra-5.0/cinelerra/dvdcreate.h [new file with mode: 0644]
cinelerra-5.0/cinelerra/dvdcreate.inc [new file with mode: 0644]
cinelerra-5.0/cinelerra/editlength.C
cinelerra-5.0/cinelerra/ffmpeg.C
cinelerra-5.0/cinelerra/ffmpeg.h
cinelerra-5.0/cinelerra/file.C
cinelerra-5.0/cinelerra/file.inc
cinelerra-5.0/cinelerra/fileffmpeg.C
cinelerra-5.0/cinelerra/filescene.C
cinelerra-5.0/cinelerra/keyframegui.C
cinelerra-5.0/cinelerra/keyframegui.h
cinelerra-5.0/cinelerra/loadfile.C
cinelerra-5.0/cinelerra/main.C
cinelerra-5.0/cinelerra/mainerror.C
cinelerra-5.0/cinelerra/mainmenu.C
cinelerra-5.0/cinelerra/menuattachtransition.C
cinelerra-5.0/cinelerra/menuattachtransition.h
cinelerra-5.0/cinelerra/mwindow.C
cinelerra-5.0/cinelerra/mwindow.h
cinelerra-5.0/cinelerra/mwindowgui.C
cinelerra-5.0/cinelerra/new.C
cinelerra-5.0/cinelerra/plugindialog.C
cinelerra-5.0/cinelerra/preferences.C
cinelerra-5.0/cinelerra/preferencesthread.C
cinelerra-5.0/cinelerra/presetsgui.C
cinelerra-5.0/cinelerra/record.C
cinelerra-5.0/cinelerra/recordscopes.C
cinelerra-5.0/cinelerra/render.C
cinelerra-5.0/cinelerra/shbtnprefs.C
cinelerra-5.0/cinelerra/tipwindow.C
cinelerra-5.0/cinelerra/tipwindow.h
cinelerra-5.0/cinelerra/transitionpopup.C
cinelerra-5.0/cinelerra/vwindow.C
cinelerra-5.0/cinelerra/wwindow.C
cinelerra-5.0/cinelerra/wwindow.h
cinelerra-5.0/ffmpeg/audio/bluray.m2ts
cinelerra-5.0/ffmpeg/video/bluray.m2ts
cinelerra-5.0/guicast/bcpopupmenu.C
cinelerra-5.0/plugins/scale/scale.C

index f2db54be99bcc8ff67cae8a65d62d4763c6c2b3e..a46f218254fee1fe499e1eefe9c617956e5db454 100644 (file)
@@ -69,8 +69,8 @@ ifeq ($(STATIC_LIBRARIES), y)
 endif
        cp -a models bin
        cd bin && find -name '.svn' -exec rm -r {} \; -prune
-       rm -f bin/cutads
-       cp -a cinelerra/$(OBJDIR)/cutads bin/.
+       rm -f bin/cutads bin/bdwrite bin/manual.pdf
+       cp -a cinelerra/$(OBJDIR)/cutads cinelerra/$(OBJDIR)/bdwrite bin/.
        cp -a doc/manual.pdf bin/.
        rm -f bin/new_db
        $(MAKE) -C db/utils new_db
index 8fb3bcda24c0ebce0593f1cf1c7f7b7148e91f45..9d7c8c14d770617b5c7e7555bbd3617facfc802b 100644 (file)
@@ -306,25 +306,27 @@ OBJS = \
        $(OBJDIR)/zoombar.o \
        $(OBJDIR)/zoompanel.o \
 \
-       $(OBJDIR)/devicempeginput.o \
-       $(OBJDIR)/devicev4l2base.o \
-       $(OBJDIR)/devicev4l2input.o \
-       $(OBJDIR)/audiov4l2mpeg.o \
-       $(OBJDIR)/vdevicev4l2mpeg.o \
-       $(OBJDIR)/vdevicempeg.o \
        $(OBJDIR)/audiompeg.o \
+       $(OBJDIR)/audiov4l2mpeg.o \
+       $(OBJDIR)/bdcreate.o \
        $(OBJDIR)/channelinfo.o \
-       $(OBJDIR)/recordbatches.o \
-       $(OBJDIR)/remotecontrol.o \
-       $(OBJDIR)/mediadb.o \
        $(OBJDIR)/commercials.o \
        $(OBJDIR)/dbwindow.o \
+       $(OBJDIR)/devicempeginput.o \
+       $(OBJDIR)/devicev4l2base.o \
+       $(OBJDIR)/devicev4l2input.o \
+       $(OBJDIR)/dvdcreate.o \
        $(OBJDIR)/filedb.o \
+       $(OBJDIR)/mediadb.o \
+       $(OBJDIR)/recordbatches.o \
+       $(OBJDIR)/remotecontrol.o \
+       $(OBJDIR)/shbtnprefs.o \
        $(OBJDIR)/signalstatus.o \
        $(OBJDIR)/strack.o \
        $(OBJDIR)/swindow.o \
+       $(OBJDIR)/vdevicempeg.o \
+       $(OBJDIR)/vdevicev4l2mpeg.o \
        $(OBJDIR)/wwindow.o \
-       $(OBJDIR)/shbtnprefs.o \
 
 #      $(OBJDIR)/renderfarmfsclient.o \
 #      $(OBJDIR)/renderfarmfsserver.o \
@@ -335,15 +337,6 @@ THEME_DATA := $(OBJDIR)/theme_data.o
 OUTPUT_G = $(OBJDIR)/cinelerra.debuginfo
 OUTPUT = ../bin/cinelerra
 
-CUTADS = $(OBJDIR)/cutads
-CUTOBJ = $(OBJDIR)/cutads.o
-CUTOBJS = $(CUTOBJ) \
-       $(OBJDIR)/mediadb.o \
-       $(OBJDIR)/filexml.o
-CUTLIBS = \
-       ../libzmpeg3/$(OBJDIR)/libzmpeg3.a -lX11 \
-       ../db/$(OBJDIR)/db.a
-
 ifeq ($(HAVE_AVIFILE), y)
 AVIFILE_DIR := $(shell cd ../avifile* ; pwd)
 endif
@@ -358,8 +351,9 @@ LIBRARIES := \
        ../db/$(OBJDIR)/db.a \
        $(THEME_DATA) \
 
-LIBS := $(LIBRARIES)
-
+LIBS = $(LIBRARIES)
+LIBS += $(thirdparty_libraries)
+LIBS += $(thirdparty_libraries)
 LIBS += \
        -lX11 \
        -lXext \
@@ -376,6 +370,18 @@ LIBS += \
        -lfreetype \
        $(EXTRA_LIBS)
 
+CUTADS = $(OBJDIR)/cutads
+CUTOBJ = $(OBJDIR)/cutads.o
+CUTOBJS = $(CUTOBJ) \
+       $(OBJDIR)/mediadb.o \
+       $(OBJDIR)/filexml.o
+CUTLIBS = \
+       ../libzmpeg3/$(OBJDIR)/libzmpeg3.a -lX11 \
+       ../db/$(OBJDIR)/db.a
+
+BDWRITE = $(OBJDIR)/bdwrite
+BDWOBJS = $(OBJDIR)/bdwrite.o
+
 ifeq ($(HAVE_GL), y)
 LIBS += -lGL -lGLU
 endif
@@ -391,7 +397,6 @@ endif
 
 
 CFLAGS += \
-       -c \
        -I../guicast \
        -I../quicktime \
        -I../libzmpeg3 \
@@ -447,12 +452,12 @@ endif
 FFMPEG_CFLAGS := \
        -include /usr/include/time.h \
 
-$(shell echo $(CFLAGS) > $(OBJDIR)/c_flags)
-$(shell echo $(CFLAGS) $(FFMPEG_CFLAGS) > $(OBJDIR)/ffmpeg_cflags)
-$(shell echo $(LDFLAGS1) $(OBJS) $(DCRAW) $(FILEEXR) $(FILEFLAC) $(FFMPEG_OBJS) $(AVIOBJS) \
- $(thirdparty_libraries) $(thirdparty_libraries) $(LIBS) $(LDFLAGS2) > $(OBJDIR)/objs)
+$(shell echo $(CFLAGS) -c > $(OBJDIR)/c_flags)
+$(shell echo $(CFLAGS) -c $(FFMPEG_CFLAGS) > $(OBJDIR)/ffmpeg_cflags)
+$(shell echo $(LDFLAGS1) $(OBJS) $(DCRAW) $(FILEEXR) $(FILEFLAC) $(AVIOBJS) \
+ $(FFMPEG_OBJS) $(LIBS) $(LDFLAGS2) > $(OBJDIR)/objs)
 
-all:   $(OUTPUT) $(CUTADS)
+all:   $(OUTPUT) $(CUTADS) $(BDWRITE)
 
 # Static linking is not possible because the plugins depend on symbols
 # in the main executable.
@@ -463,7 +468,12 @@ $(OUTPUT): $(OBJS) $(DCRAW) $(FILEEXR) $(FFMPEG_OBJS) $(FILEFLAC) $(LIBRARIES)
        $(if $(findstring -ggdb,$(CFLAGS)),,strip $(OUTPUT))
 
 $(CUTADS):     $(CUTOBJS) $(CUTLIBS)
-       g++ -pthread -o $(OBJDIR)/cutads $(CUTOBJS) $(CUTLIBS)
+       @echo g++ -o $@ $(CUTOBJS)
+       @g++ $(CFLAGS) -pthread -o $@ $(CUTOBJS) $(CUTLIBS)
+
+$(BDWRITE):    $(BDWOBJS)
+       @echo g++ -o $@ $(BDWOBJS)
+       @g++ $(CFLAGS) -pthread -o $@ $(BDWOBJS) $(LIBS)
 
 $(OBJDIR)/test:
        $(CC) -shared -o $(OBJDIR)/test.so \
index 443733cc18d4df3714b59b5fc3059e8a6198e2c4..e52f39c7b0e6d9aa0a5276df2529e9efeb14d66a 100644 (file)
@@ -68,6 +68,7 @@ AssetEdit::AssetEdit(MWindow *mwindow)
 
 AssetEdit::~AssetEdit()
 {
+       close_window();
        changed_params->remove_user();
 }
 
@@ -76,7 +77,7 @@ void AssetEdit::edit_asset(Indexable *indexable)
 {
        if(this->indexable)
        {
-               BC_DialogThread::close_window();
+               close_window();
        }
 
        this->indexable = indexable;
index 70f32f7fb7d0b7fc958344d5956f024907175663..fdcb4cd3c76b07bf74a8ab1bee1acd1007bf68d7 100644 (file)
@@ -679,6 +679,7 @@ AWindowRemovePlugin(AWindow *awindow, PluginServer *plugin)
 AWindowRemovePlugin::
 ~AWindowRemovePlugin()
 {
+       close_window();
 }
 
 BC_Window* AWindowRemovePlugin::new_gui()
index eee744179a450f830ebed63ac11b021114c55706..cede6c9627280b70f7ca121f819b58b774527a5a 100644 (file)
 #include "transportque.h"
 #include "vframe.h"
 
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <sys/stat.h>
-#include <sys/statfs.h>
-
-
 
 static const char *list_titles[] = 
 {
@@ -224,6 +217,11 @@ BatchRenderThread::BatchRenderThread()
        file_entries = 0;
 }
 
+BatchRenderThread::~BatchRenderThread()
+{
+       close_window();
+}
+
 void BatchRenderThread::handle_close_event(int result)
 {
 // Save settings
@@ -1305,813 +1303,3 @@ int BatchRenderCancel::keypress_event()
        return 0;
 }
 
-
-
-
-
-// DVD Creation
-
-const int64_t CreateDVD_Thread::DVD_SIZE = 4700000000;
-const int CreateDVD_Thread::DVD_STREAMS = 1;
-const int CreateDVD_Thread::DVD_WIDTH = 720;
-const int CreateDVD_Thread::DVD_HEIGHT = 480;
-const double CreateDVD_Thread::DVD_ASPECT_WIDTH = 4.;
-const double CreateDVD_Thread::DVD_ASPECT_HEIGHT = 3.;
-const double CreateDVD_Thread::DVD_WIDE_ASPECT_WIDTH = 16.;
-const double CreateDVD_Thread::DVD_WIDE_ASPECT_HEIGHT = 9.;
-const double CreateDVD_Thread::DVD_FRAMERATE = 30000. / 1001.;
-const int CreateDVD_Thread::DVD_MAX_BITRATE = 8000000;
-const int CreateDVD_Thread::DVD_CHANNELS = 2;
-const int CreateDVD_Thread::DVD_WIDE_CHANNELS = 6;
-const double CreateDVD_Thread::DVD_SAMPLERATE = 48000;
-const double CreateDVD_Thread::DVD_KAUDIO_RATE = 224;
-
-
-CreateDVD_MenuItem::CreateDVD_MenuItem(MWindow *mwindow)
- : BC_MenuItem(_("DVD Render..."), _("Shift-D"), 'D')
-{
-       set_shift(1); 
-       this->mwindow = mwindow;
-}
-
-int CreateDVD_MenuItem::handle_event()
-{
-       mwindow->create_dvd->start();
-       return 1;
-}
-
-
-CreateDVD_Thread::CreateDVD_Thread(MWindow *mwindow)
- : BC_DialogThread()
-{
-       this->mwindow = mwindow;
-       this->gui = 0;
-       this->use_deinterlace = 0;
-       this->use_inverse_telecine = 0;
-       this->use_scale = 0;
-       this->use_resize_tracks = 0;
-       this->use_histogram = 0;
-       this->use_wide_audio = 0;
-       this->use_wide_aspect = 0;
-       this->use_label_chapters = 0;
-       this->use_ffmpeg = 0;
-}
-
-CreateDVD_Thread::~CreateDVD_Thread()
-{
-}
-
-int CreateDVD_Thread::create_dvd_jobs(ArrayList<BatchRenderJob*> *jobs,
-       const char *tmp_path, const char *asset_title)
-{
-       EDL *edl = mwindow->edl;
-       if( !edl || !edl->session ) {
-               char msg[BCTEXTLEN];
-                sprintf(msg, _("No EDL/Session"));
-                MainError::show_error(msg);
-                return 1;
-        }
-       EDLSession *session = edl->session;
-
-       double total_length = edl->tracks->total_length();
-        if( total_length <= 0 ) {
-               char msg[BCTEXTLEN];
-                sprintf(msg, _("No content: %s"), asset_title);
-                MainError::show_error(msg);
-                return 1;
-        }
-
-       char asset_dir[BCTEXTLEN];
-       sprintf(asset_dir, "%s/%s", tmp_path, asset_title);
-
-       if( mkdir(asset_dir, 0777) ) {
-               char err[BCTEXTLEN], msg[BCTEXTLEN];
-               strerror_r(errno, err, sizeof(err));
-               sprintf(msg, _("Unable to create directory: %s\n-- %s"), asset_dir, err);
-               MainError::show_error(msg);
-               return 1;
-       }
-
-       double old_samplerate = session->sample_rate;
-       double old_framerate = session->frame_rate;
-
-        session->video_channels = DVD_STREAMS;
-        session->video_tracks = DVD_STREAMS;
-        session->frame_rate = DVD_FRAMERATE;
-        session->output_w = DVD_WIDTH;
-        session->output_h = DVD_HEIGHT;
-        session->aspect_w = use_wide_aspect ? DVD_WIDE_ASPECT_WIDTH : DVD_ASPECT_WIDTH;
-        session->aspect_h = use_wide_aspect ? DVD_WIDE_ASPECT_HEIGHT : DVD_ASPECT_HEIGHT;
-        session->sample_rate = DVD_SAMPLERATE;
-        session->audio_channels = session->audio_tracks =
-               use_wide_audio ? DVD_WIDE_CHANNELS : DVD_CHANNELS;
-
-       char script_filename[BCTEXTLEN];
-       sprintf(script_filename, "%s/dvd.sh", asset_dir);
-       int fd = open(script_filename, O_WRONLY+O_CREAT+O_TRUNC, 0755);
-       FILE *fp = fdopen(fd, "w");
-       if( !fp ) {
-               char err[BCTEXTLEN], msg[BCTEXTLEN];
-               strerror_r(errno, err, sizeof(err));
-               sprintf(msg, _("Unable to save: %s\n-- %s"), script_filename, err);
-               MainError::show_error(msg);
-               return 1;
-       }
-       fprintf(fp,"#!/bin/bash\n");
-       fprintf(fp,"echo \"running %s\" $# $*\n", script_filename);
-       fprintf(fp,"\n");
-       if( !use_ffmpeg ) {
-               fprintf(fp,"mplex -f 8 -o $1/dvd.mpg $1/dvd.m2v $1/dvd.ac3\n");
-               fprintf(fp,"\n");
-       }
-       fprintf(fp,"rm -rf $1/iso\n");
-       fprintf(fp,"mkdir -p $1/iso\n");
-       fprintf(fp,"\n");
-       fprintf(fp,"dvdauthor -x - <<eof\n");
-       fprintf(fp,"<dvdauthor dest=\"$1/iso\">\n");
-       fprintf(fp,"  <vmgm>\n");
-       fprintf(fp,"    <fpc> jump title 1; </fpc>\n");
-       fprintf(fp,"  </vmgm>\n");
-       fprintf(fp,"  <titleset>\n");
-       fprintf(fp,"    <titles>\n");
-       fprintf(fp,"    <video format=\"ntsc\" aspect=\"%d:%d\" resolution=\"%dx%d\"/>\n",
-               (int)session->aspect_w, (int)session->aspect_h,
-               session->output_w, session->output_h);
-       fprintf(fp,"    <audio format=\"ac3\" lang=\"en\"/>\n");
-       fprintf(fp,"    <pgc>\n");
-       fprintf(fp,"      <vob file=\"$1/dvd.mpg\" chapters=\"");
-       if( use_label_chapters && edl->labels ) {
-               Label *label = edl->labels->first;
-               while( label ) {
-                       int secs = label->position;
-                       int mins = secs / 60;
-                       int frms = (label->position-secs) * session->frame_rate;
-                       fprintf(fp,"%d:%02d:%02d.%d", mins/60, mins%60, secs%60, frms);
-                       if( (label=label->next) != 0 ) fprintf(fp, ",");
-               }
-       }
-       else {
-               int mins = 0;
-               for( int secs=0 ; secs<total_length; secs+=10*60 ) {
-                       mins = secs / 60;
-                       fprintf(fp,"%d:%02d:00,", mins/60, mins%60);
-               }
-               fprintf(fp,"%d:%02d:00", mins/60, mins%60);
-       }
-       fprintf(fp,"\"/>\n");
-       fprintf(fp,"    </pgc>\n");
-       fprintf(fp,"    </titles>\n");
-       fprintf(fp,"  </titleset>\n");
-       fprintf(fp,"</dvdauthor>\n");
-       fprintf(fp,"eof\n");
-       fprintf(fp,"\n");
-       fprintf(fp,"echo To burn dvd, load blank media and run:\n");
-       fprintf(fp,"echo growisofs -dvd-compat -Z /dev/dvd -dvd-video $1/iso\n");
-       fprintf(fp,"\n");
-       fclose(fp);
-
-       if( use_wide_audio ) {
-               session->audio_channels = session->audio_tracks = DVD_WIDE_CHANNELS;
-               session->achannel_positions[0] = 90;
-               session->achannel_positions[1] = 150;
-               session->achannel_positions[2] = 30;
-               session->achannel_positions[3] = 210;
-               session->achannel_positions[4] = 330;
-               session->achannel_positions[5] = 270;
-               if( edl->tracks->recordable_audio_tracks() == DVD_WIDE_CHANNELS )
-                       mwindow->remap_audio(MWindow::AUDIO_1_TO_1);
-       }
-       else {
-               session->audio_channels = session->audio_tracks = DVD_CHANNELS;
-               session->achannel_positions[0] = 180;
-               session->achannel_positions[1] = 0;
-               if( edl->tracks->recordable_audio_tracks() == DVD_WIDE_CHANNELS )
-                       mwindow->remap_audio(MWindow::AUDIO_5_1_TO_2);
-       }
-
-       double new_samplerate = session->sample_rate;
-       double new_framerate = session->frame_rate;
-       edl->rechannel();
-       edl->resample(old_samplerate, new_samplerate, TRACK_AUDIO);
-       edl->resample(old_framerate, new_framerate, TRACK_VIDEO);
-
-       int64_t aud_size = ((DVD_KAUDIO_RATE * total_length)/8 + 1000-1) * 1000;
-       int64_t vid_size = DVD_SIZE*0.96 - aud_size;
-       int vid_bitrate = (vid_size * 8) / total_length;
-       vid_bitrate /= 1000;  vid_bitrate *= 1000;
-       if( vid_bitrate > DVD_MAX_BITRATE ) vid_bitrate = DVD_MAX_BITRATE;
-
-       char xml_filename[BCTEXTLEN];
-       sprintf(xml_filename, "%s/dvd.xml", asset_dir);
-        FileXML xml_file;
-        edl->save_xml(&xml_file, xml_filename, 0, 0);
-        xml_file.terminate_string();
-        if( xml_file.write_to_file(xml_filename) ) {
-               char msg[BCTEXTLEN];
-               sprintf(msg, _("Unable to save: %s"), xml_filename);
-               MainError::show_error(msg);
-               return 1;
-       }
-
-       BatchRenderJob *job = new BatchRenderJob(mwindow->preferences);
-       jobs->append(job);
-       strcpy(&job->edl_path[0], xml_filename);
-       Asset *asset = job->asset;
-
-       asset->layers = DVD_STREAMS;
-       asset->frame_rate = session->frame_rate;
-       asset->width = session->output_w;
-       asset->height = session->output_h;
-       asset->aspect_ratio = session->aspect_w / session->aspect_h;
-
-       if( use_ffmpeg ) {
-               char option_path[BCTEXTLEN];
-               sprintf(&asset->path[0],"%s/dvd.mpg", asset_dir);
-               asset->format = FILE_FFMPEG;
-               strcpy(asset->fformat, "dvd");
-
-               asset->audio_data = 1;
-               strcpy(asset->acodec, "dvd.dvd");
-               FFMPEG::set_option_path(option_path, "audio/%s", asset->acodec);
-               FFMPEG::load_options(option_path, asset->ff_audio_options,
-                        sizeof(asset->ff_audio_options));
-               asset->ff_audio_bitrate = DVD_KAUDIO_RATE * 1000;
-
-               asset->video_data = 1;
-               strcpy(asset->vcodec, "dvd.dvd");
-               FFMPEG::set_option_path(option_path, "video/%s", asset->vcodec);
-               FFMPEG::load_options(option_path, asset->ff_video_options,
-                        sizeof(asset->ff_video_options));
-               asset->ff_video_bitrate = vid_bitrate;
-               asset->ff_video_quality = 0;
-
-               int len = strlen(asset->ff_video_options);
-               char *cp = asset->ff_video_options + len;
-               snprintf(cp, sizeof(asset->ff_video_options)-len-1,
-                       "aspect %.5f\n", asset->aspect_ratio);
-       }
-       else {
-               sprintf(&asset->path[0],"%s/dvd.m2v", asset_dir);
-               asset->video_data = 1;
-               asset->format = FILE_VMPEG;
-               asset->vmpeg_cmodel = BC_YUV420P;
-               asset->vmpeg_fix_bitrate = 1;
-               asset->vmpeg_bitrate = vid_bitrate;
-               asset->vmpeg_quantization = 15;
-               asset->vmpeg_iframe_distance = 15;
-               asset->vmpeg_progressive = 0;
-               asset->vmpeg_denoise = 0;
-               asset->vmpeg_seq_codes = 0;
-               asset->vmpeg_derivative = 2;
-               asset->vmpeg_preset = 8;
-               asset->vmpeg_field_order = 0;
-               asset->vmpeg_pframe_distance = 0;
-               job = new BatchRenderJob(mwindow->preferences);
-               jobs->append(job);
-               strcpy(&job->edl_path[0], xml_filename);
-               asset = job->asset;
-               
-               sprintf(&asset->path[0],"%s/dvd.ac3", asset_dir);
-               asset->audio_data = 1;
-               asset->format = FILE_AC3;
-               asset->channels = session->audio_channels;
-               asset->sample_rate = session->sample_rate;
-               asset->bits = 16;
-               asset->byte_order = 0;
-               asset->signed_ = 1;
-               asset->header = 0;
-               asset->dither = 0;
-               asset->ac3_bitrate = DVD_KAUDIO_RATE;
-       }
-
-       job = new BatchRenderJob(mwindow->preferences);
-       jobs->append(job);
-       job->edl_path[0] = '@';
-       strcpy(&job->edl_path[1], script_filename);
-       strcpy(&job->asset->path[0], asset_dir);
-
-       return 0;
-}
-
-void CreateDVD_Thread::handle_close_event(int result)
-{
-       if( result ) return;
-       mwindow->batch_render->load_defaults(mwindow->defaults);
-        mwindow->undo->update_undo_before();
-       KeyFrame keyframe;  char data[BCTEXTLEN];
-       if( use_deinterlace ) {
-               sprintf(data,"<DEINTERLACE MODE=1>");
-               keyframe.set_data(data);
-               insert_video_plugin("Deinterlace", &keyframe);
-       }
-       if( use_inverse_telecine ) {
-               sprintf(data,"<IVTC FRAME_OFFSET=0 FIRST_FIELD=0 "
-                       "AUTOMATIC=1 AUTO_THRESHOLD=2.0e+00 PATTERN=2>");
-               keyframe.set_data(data);
-               insert_video_plugin("Inverse Telecine", &keyframe);
-       }
-       if( use_scale ) {
-               sprintf(data,"<SCALE TYPE=1 X_FACTOR=1 Y_FACTOR=1 "
-                       "WIDTH=%d HEIGHT=%d CONSTRAIN=0>", DVD_WIDTH, DVD_HEIGHT);
-               keyframe.set_data(data);
-               insert_video_plugin("Scale", &keyframe);
-       }
-       if( use_resize_tracks )
-               resize_tracks();
-       if( use_histogram ) {
-#if 0
-               sprintf(data, "<HISTOGRAM OUTPUT_MIN_0=0 OUTPUT_MAX_0=1 "
-                       "OUTPUT_MIN_1=0 OUTPUT_MAX_1=1 "
-                       "OUTPUT_MIN_2=0 OUTPUT_MAX_2=1 "
-                       "OUTPUT_MIN_3=0 OUTPUT_MAX_3=1 "
-                       "AUTOMATIC=0 THRESHOLD=9.0-01 PLOT=0 SPLIT=0>"
-                       "<POINTS></POINTS><POINTS></POINTS><POINTS></POINTS>"
-                       "<POINTS><POINT X=6.0e-02 Y=0>"
-                               "<POINT X=9.4e-01 Y=1></POINTS>");
-#else
-               sprintf(data, "<HISTOGRAM AUTOMATIC=0 THRESHOLD=1.0e-01 "
-                       "PLOT=0 SPLIT=0 W=440 H=500 PARADE=0 MODE=3 "
-                       "LOW_OUTPUT_0=0 HIGH_OUTPUT_0=1 LOW_INPUT_0=0 HIGH_INPUT_0=1 GAMMA_0=1 "
-                       "LOW_OUTPUT_1=0 HIGH_OUTPUT_1=1 LOW_INPUT_1=0 HIGH_INPUT_1=1 GAMMA_1=1 "
-                       "LOW_OUTPUT_2=0 HIGH_OUTPUT_2=1 LOW_INPUT_2=0 HIGH_INPUT_2=1 GAMMA_2=1 "
-                       "LOW_OUTPUT_3=0 HIGH_OUTPUT_3=1 LOW_INPUT_3=0.06 HIGH_INPUT_3=0.94 "
-                       "GAMMA_3=1>");
-#endif
-               keyframe.set_data(data);
-               insert_video_plugin("Histogram", &keyframe);
-       }
-       create_dvd_jobs(&mwindow->batch_render->jobs, tmp_path, asset_title);
-       mwindow->save_backup();
-       mwindow->undo->update_undo_after(_("create dvd"), LOAD_ALL);
-       mwindow->resync_guis();
-       mwindow->batch_render->handle_close_event(0);
-       mwindow->batch_render->start();
-}
-
-BC_Window* CreateDVD_Thread::new_gui()
-{
-       memset(tmp_path,0,sizeof(tmp_path));
-       strcpy(tmp_path,"/tmp");
-       memset(asset_title,0,sizeof(asset_title));
-       time_t dt;      time(&dt);
-       struct tm dtm;  localtime_r(&dt, &dtm);
-       sprintf(asset_title, "dvd_%02d%02d%02d-%02d%02d%02d",
-               dtm.tm_year+1900, dtm.tm_mon+1, dtm.tm_mday,
-               dtm.tm_hour, dtm.tm_min, dtm.tm_sec);
-       use_deinterlace = 0;
-       use_inverse_telecine = 0;
-       use_scale = 0;
-       use_resize_tracks = 0;
-       use_histogram = 0;
-       use_wide_audio = 0;
-       use_wide_aspect = 0;
-       use_label_chapters = 0;
-       use_ffmpeg = 0;
-       option_presets();
-        int scr_x = mwindow->gui->get_screen_x(0, -1);
-        int scr_w = mwindow->gui->get_screen_w(0, -1);
-        int scr_h = mwindow->gui->get_screen_h(0, -1);
-        int w = 500, h = 250;
-       int x = scr_x + scr_w/2 - w/2, y = scr_h/2 - h/2;
-
-       gui = new CreateDVD_GUI(this, x, y, w, h);
-       gui->create_objects();
-       return gui;
-}
-
-
-CreateDVD_OK::CreateDVD_OK(CreateDVD_GUI *gui, int x, int y)
- : BC_OKButton(x, y)
-{
-        this->gui = gui;
-        set_tooltip(_("end setup, start batch render"));
-}
-
-CreateDVD_OK::~CreateDVD_OK()
-{
-}
-
-int CreateDVD_OK::button_press_event()
-{
-        if(get_buttonpress() == 1 && is_event_win() && cursor_inside()) {
-                gui->set_done(0);
-                return 1;
-        }
-        return 0;
-}
-
-int CreateDVD_OK::keypress_event()
-{
-        return 0;
-}
-
-
-CreateDVD_Cancel::CreateDVD_Cancel(CreateDVD_GUI *gui, int x, int y)
- : BC_CancelButton(x, y)
-{
-        this->gui = gui;
-}
-
-CreateDVD_Cancel::~CreateDVD_Cancel()
-{
-}
-
-int CreateDVD_Cancel::button_press_event()
-{
-        if(get_buttonpress() == 1 && is_event_win() && cursor_inside()) {
-                gui->set_done(1);
-                return 1;
-        }
-        return 0;
-}
-
-
-CreateDVD_DiskSpace::CreateDVD_DiskSpace(CreateDVD_GUI *gui, int x, int y)
- : BC_Title(x, y, "", MEDIUMFONT, GREEN)
-{
-        this->gui = gui;
-}
-
-CreateDVD_DiskSpace::~CreateDVD_DiskSpace()
-{
-}
-
-int64_t CreateDVD_DiskSpace::tmp_path_space()
-{
-       const char *path = gui->tmp_path->get_text();
-       if( access(path,R_OK+W_OK) ) return 0;
-       struct statfs sfs;
-       if( statfs(path, &sfs) ) return 0;
-       return (int64_t)sfs.f_bsize * sfs.f_bfree;
-}
-
-void CreateDVD_DiskSpace::update()
-{
-//     gui->disk_space->set_color(get_bg_color());
-       int64_t disk_space = tmp_path_space();
-       int color = disk_space<gui->needed_disk_space ? RED : GREEN;
-       static const char *suffix[] = { "", "KB", "MB", "GB", "TB", "PB" };
-       int i = 0;
-       for( int64_t space=disk_space; i<5 && (space/=1000)>0; disk_space=space, ++i );
-       char text[BCTEXTLEN];
-       sprintf(text, "%s" _LDv(3) "%s", _("disk space: "), disk_space, suffix[i]);
-       gui->disk_space->BC_Title::update(text);
-       gui->disk_space->set_color(color);
-}
-
-CreateDVD_TmpPath::CreateDVD_TmpPath(CreateDVD_GUI *gui, int x, int y, int w)
- : BC_TextBox(x, y, w, 1, -sizeof(gui->thread->tmp_path),
-               gui->thread->tmp_path, 1, MEDIUMFONT)
-{
-        this->gui = gui;
-}
-
-CreateDVD_TmpPath::~CreateDVD_TmpPath()
-{
-}
-
-int CreateDVD_TmpPath::handle_event()
-{
-       gui->disk_space->update();
-        return 1;
-}
-
-
-CreateDVD_AssetTitle::CreateDVD_AssetTitle(CreateDVD_GUI *gui, int x, int y, int w)
- : BC_TextBox(x, y, w, 1, 0, gui->thread->asset_title, 1, MEDIUMFONT)
-{
-        this->gui = gui;
-}
-
-CreateDVD_AssetTitle::~CreateDVD_AssetTitle()
-{
-}
-
-
-CreateDVD_Deinterlace::CreateDVD_Deinterlace(CreateDVD_GUI *gui, int x, int y)
- : BC_CheckBox(x, y, &gui->thread->use_deinterlace, _("Deinterlace"))
-{
-       this->gui = gui;
-}
-
-CreateDVD_Deinterlace::~CreateDVD_Deinterlace()
-{
-}
-
-int CreateDVD_Deinterlace::handle_event()
-{
-       if( get_value() ) {
-               gui->need_inverse_telecine->set_value(0);
-               gui->thread->use_inverse_telecine = 0;
-       }
-       return BC_CheckBox::handle_event();
-}
-
-
-CreateDVD_InverseTelecine::CreateDVD_InverseTelecine(CreateDVD_GUI *gui, int x, int y)
- : BC_CheckBox(x, y, &gui->thread->use_inverse_telecine, _("Inverse Telecine"))
-{
-       this->gui = gui;
-}
-
-CreateDVD_InverseTelecine::~CreateDVD_InverseTelecine()
-{
-}
-
-int CreateDVD_InverseTelecine::handle_event()
-{
-       if( get_value() ) {
-               gui->need_deinterlace->set_value(0);
-               gui->thread->use_deinterlace = 0;
-       }
-       return BC_CheckBox::handle_event();
-}
-
-
-CreateDVD_Scale::CreateDVD_Scale(CreateDVD_GUI *gui, int x, int y)
- : BC_CheckBox(x, y, &gui->thread->use_scale, _("Scale"))
-{
-       this->gui = gui;
-}
-
-CreateDVD_Scale::~CreateDVD_Scale()
-{
-}
-
-
-CreateDVD_ResizeTracks::CreateDVD_ResizeTracks(CreateDVD_GUI *gui, int x, int y)
- : BC_CheckBox(x, y, &gui->thread->use_resize_tracks, _("Resize Tracks"))
-{
-       this->gui = gui;
-}
-
-CreateDVD_ResizeTracks::~CreateDVD_ResizeTracks()
-{
-}
-
-
-CreateDVD_Histogram::CreateDVD_Histogram(CreateDVD_GUI *gui, int x, int y)
- : BC_CheckBox(x, y, &gui->thread->use_histogram, _("Histogram"))
-{
-       this->gui = gui;
-}
-
-CreateDVD_Histogram::~CreateDVD_Histogram()
-{
-}
-
-CreateDVD_LabelChapters::CreateDVD_LabelChapters(CreateDVD_GUI *gui, int x, int y)
- : BC_CheckBox(x, y, &gui->thread->use_label_chapters, _("Chapters at Labels"))
-{
-       this->gui = gui;
-}
-
-CreateDVD_LabelChapters::~CreateDVD_LabelChapters()
-{
-}
-
-CreateDVD_WideAudio::CreateDVD_WideAudio(CreateDVD_GUI *gui, int x, int y)
- : BC_CheckBox(x, y, &gui->thread->use_wide_audio, _("Audio 5.1"))
-{
-       this->gui = gui;
-}
-
-CreateDVD_WideAudio::~CreateDVD_WideAudio()
-{
-}
-
-CreateDVD_WideAspect::CreateDVD_WideAspect(CreateDVD_GUI *gui, int x, int y)
- : BC_CheckBox(x, y, &gui->thread->use_wide_aspect, _("Aspect 16x9"))
-{
-       this->gui = gui;
-}
-
-CreateDVD_WideAspect::~CreateDVD_WideAspect()
-{
-}
-
-CreateDVD_UseFFMpeg::CreateDVD_UseFFMpeg(CreateDVD_GUI *gui, int x, int y)
- : BC_CheckBox(x, y, &gui->thread->use_ffmpeg, _("Use FFMPEG"))
-{
-       this->gui = gui;
-}
-
-CreateDVD_UseFFMpeg::~CreateDVD_UseFFMpeg()
-{
-}
-
-
-
-
-CreateDVD_GUI::CreateDVD_GUI(CreateDVD_Thread *thread, int x, int y, int w, int h)
- : BC_Window(_(PROGRAM_NAME ": Create DVD"), x, y, w, h, 50, 50, 1, 0, 1)
-{
-       this->thread = thread;
-       at_x = at_y = tmp_x = tmp_y = 0;
-       ok_x = ok_y = ok_w = ok_h = 0;
-       cancel_x = cancel_y = cancel_w = cancel_h = 0;
-       asset_title = 0;
-       tmp_path = 0;
-       disk_space = 0;
-       needed_disk_space = 15e9;
-       need_deinterlace = 0;
-       need_inverse_telecine = 0;
-       need_scale = 0;
-       need_resize_tracks = 0;
-       need_histogram = 0;
-       need_wide_audio = 0;
-       need_wide_aspect = 0;
-       need_label_chapters = 0;
-       ok = 0;
-       cancel = 0;
-}
-
-CreateDVD_GUI::~CreateDVD_GUI()
-{
-}
-
-void CreateDVD_GUI::create_objects()
-{
-       lock_window("CreateDVD_GUI::create_objects");
-       int pady = BC_TextBox::calculate_h(this, MEDIUMFONT, 0, 1) + 5;
-       int padx = BC_Title::calculate_w(this, (char*)"X", MEDIUMFONT);
-       int x = padx/2, y = pady/2;
-       BC_Title *title = new BC_Title(x, y, _("Title:"), MEDIUMFONT, YELLOW);
-       add_subwindow(title);
-       at_x = x + title->get_w();  at_y = y;
-       asset_title = new CreateDVD_AssetTitle(this, at_x, at_y, get_w()-at_x-10);
-       add_subwindow(asset_title);
-       y += title->get_h() + pady/2;
-       title = new BC_Title(x, y, _("tmp path:"), MEDIUMFONT, YELLOW);
-       add_subwindow(title);
-       tmp_x = x + title->get_w();  tmp_y = y;
-       tmp_path = new CreateDVD_TmpPath(this, tmp_x, tmp_y,  get_w()-tmp_x-10);
-       add_subwindow(tmp_path);
-       y += title->get_h() + pady/2;
-       disk_space = new CreateDVD_DiskSpace(this, x, y);
-       add_subwindow(disk_space);
-       disk_space->update();
-       y += disk_space->get_h() + pady/2;
-       need_deinterlace = new CreateDVD_Deinterlace(this, x, y);
-       add_subwindow(need_deinterlace);
-       int x1 = x + 150, x2 = x1 + 150;
-       need_inverse_telecine = new CreateDVD_InverseTelecine(this, x1, y);
-       add_subwindow(need_inverse_telecine);
-       need_use_ffmpeg = new CreateDVD_UseFFMpeg(this, x2, y);
-       add_subwindow(need_use_ffmpeg);
-       y += need_deinterlace->get_h() + pady/2;
-       need_scale = new CreateDVD_Scale(this, x, y);
-       add_subwindow(need_scale);
-       need_wide_audio = new CreateDVD_WideAudio(this, x1, y);
-       add_subwindow(need_wide_audio);
-       need_resize_tracks = new CreateDVD_ResizeTracks(this, x2, y);
-       add_subwindow(need_resize_tracks);
-       y += need_scale->get_h() + pady/2;
-       need_histogram = new CreateDVD_Histogram(this, x, y);
-       add_subwindow(need_histogram);
-       need_wide_aspect = new CreateDVD_WideAspect(this, x1, y);
-       add_subwindow(need_wide_aspect);
-       need_label_chapters = new CreateDVD_LabelChapters(this, x2, y);
-       add_subwindow(need_label_chapters);
-       ok_w = BC_OKButton::calculate_w();
-       ok_h = BC_OKButton::calculate_h();
-       ok_x = 10;
-       ok_y = get_h() - ok_h - 10;
-       ok = new CreateDVD_OK(this, ok_x, ok_y);
-       add_subwindow(ok);
-       cancel_w = BC_CancelButton::calculate_w();
-       cancel_h = BC_CancelButton::calculate_h();
-       cancel_x = get_w() - cancel_w - 10,
-       cancel_y = get_h() - cancel_h - 10;
-       cancel = new CreateDVD_Cancel(this, cancel_x, cancel_y);
-       add_subwindow(cancel);
-       show_window();
-       unlock_window();
-}
-
-int CreateDVD_GUI::resize_event(int w, int h)
-{
-       asset_title->reposition_window(at_x, at_y, get_w()-at_x-10);
-       tmp_path->reposition_window(tmp_x, tmp_y,  get_w()-tmp_x-10);
-        ok_y = h - ok_h - 10;
-        ok->reposition_window(ok_x, ok_y);
-       cancel_x = w - cancel_w - 10,
-       cancel_y = h - cancel_h - 10;
-        cancel->reposition_window(cancel_x, cancel_y);
-       return 0;
-}
-
-int CreateDVD_GUI::translation_event()
-{
-       return 1;
-}
-
-int CreateDVD_GUI::close_event()
-{
-        set_done(1);
-        return 1;
-}
-
-int CreateDVD_Thread::
-insert_video_plugin(const char *title, KeyFrame *default_keyframe)
-{
-       Tracks *tracks = mwindow->edl->tracks;
-       for( Track *vtrk=tracks->first; vtrk; vtrk=vtrk->next ) {
-               if( vtrk->data_type != TRACK_VIDEO ) continue;
-               if( !vtrk->record ) continue;
-               vtrk->expand_view = 1;
-               PluginSet *plugin_set = new PluginSet(mwindow->edl, vtrk);
-               vtrk->plugin_set.append(plugin_set);
-               Edits *edits = vtrk->edits;
-               for( Edit *edit=edits->first; edit; edit=edit->next ) {
-                       plugin_set->insert_plugin(title,
-                               edit->startproject, edit->length,
-                               PLUGIN_STANDALONE, 0, default_keyframe, 0);
-               }
-               vtrk->optimize();
-       }
-        return 0;
-}
-
-int CreateDVD_Thread::
-resize_tracks()
-{
-        Tracks *tracks = mwindow->edl->tracks;
-       int max_w = 0, max_h = 0;
-        for( Track *vtrk=tracks->first; vtrk; vtrk=vtrk->next ) {
-               if( vtrk->data_type != TRACK_VIDEO ) continue;
-               if( !vtrk->record ) continue;
-               Edits *edits = vtrk->edits;
-               for( Edit *edit=edits->first; edit; edit=edit->next ) {
-                       Indexable *indexable = edit->get_source();
-                       int w = indexable->get_w();
-                       if( w > max_w ) max_w = w;
-                       int h = indexable->get_h();
-                       if( h > max_h ) max_h = h;
-               }
-        }
-        for( Track *vtrk=tracks->first; vtrk; vtrk=vtrk->next ) {
-                if( vtrk->data_type != TRACK_VIDEO ) continue;
-                if( !vtrk->record ) continue;
-               vtrk->track_w = max_w;
-               vtrk->track_h = max_h;
-       }
-        return 0;
-}
-
-int CreateDVD_Thread::
-option_presets()
-{
-       if( !mwindow->edl ) return 1;
-        Tracks *tracks = mwindow->edl->tracks;
-       int max_w = 0, max_h = 0;
-       int has_deinterlace = 0, has_scale = 0;
-        for( Track *trk=tracks->first; trk; trk=trk->next ) {
-               if( !trk->record ) continue;
-               Edits *edits = trk->edits;
-               switch( trk->data_type ) {
-               case TRACK_VIDEO:
-                       for( Edit *edit=edits->first; edit; edit=edit->next ) {
-                               Indexable *indexable = edit->get_source();
-                               int w = indexable->get_w();
-                               if( w > max_w ) max_w = w;
-                               if( w != DVD_WIDTH ) use_scale = 1;
-                               int h = indexable->get_h();
-                               if( h > max_h ) max_h = h;
-                               if( h != DVD_HEIGHT ) use_scale = 1;
-                       }
-                       for( int i=0; i<trk->plugin_set.size(); ++i ) {
-                               for(Plugin *plugin = (Plugin*)trk->plugin_set[i]->first;
-                                                plugin;
-                                                plugin = (Plugin*)plugin->next) {
-                                       if( !strcmp(plugin->title, "Deinterlace") )
-                                               has_deinterlace = 1;
-                                       if( !strcmp(plugin->title, "Scale") )
-                                               has_scale = 1;
-                               }
-                       }
-                       break;
-               }
-        }
-       if( has_scale ) use_scale = 0;
-        for( Track *trk=tracks->first; trk && !use_resize_tracks; trk=trk->next ) {
-               if( !trk->record ) continue;
-               switch( trk->data_type ) {
-               case TRACK_VIDEO:
-                       if( trk->track_w != max_w ) use_resize_tracks = 1;
-                       if( trk->track_h != max_h ) use_resize_tracks = 1;
-                       break;
-               }
-        }
-       if( !has_deinterlace && max_h > 2*DVD_HEIGHT ) use_deinterlace = 1;
-       Labels *labels = mwindow->edl->labels;
-       use_label_chapters = labels && labels->first ? 1 : 0;
-       float w, h;
-       MWindow::create_aspect_ratio(w, h, max_w, max_h);
-       if( w == DVD_WIDE_ASPECT_WIDTH && h == DVD_WIDE_ASPECT_HEIGHT )
-               use_wide_aspect = 1;
-       if( tracks->recordable_audio_tracks() == DVD_WIDE_CHANNELS )
-               use_wide_audio = 1;
-       return 0;
-}
-
index 3fa7418bbb9331c8c20fd9f2e34e17564f0fa98e..e426decc4dbedebc76cf839e88b8cfd98eebf836 100644 (file)
@@ -84,6 +84,7 @@ class BatchRenderThread : public BC_DialogThread
 public:
        BatchRenderThread(MWindow *mwindow);
        BatchRenderThread();
+       ~BatchRenderThread();
 
        void handle_close_event(int result);
        BC_Window* new_gui();
@@ -305,218 +306,4 @@ public:
 };
 
 
-
-
-class CreateDVD_MenuItem : public BC_MenuItem
-{
-public:
-       CreateDVD_MenuItem(MWindow *mwindow);
-       int handle_event();
-       MWindow *mwindow;
-};
-
-
-class CreateDVD_Thread : public BC_DialogThread
-{
-       static const int64_t DVD_SIZE;
-       static const int DVD_STREAMS, DVD_WIDTH, DVD_HEIGHT;
-       static const double DVD_ASPECT_WIDTH, DVD_ASPECT_HEIGHT;
-       static const double DVD_WIDE_ASPECT_WIDTH, DVD_WIDE_ASPECT_HEIGHT;
-       static const int DVD_MAX_BITRATE, DVD_CHANNELS, DVD_WIDE_CHANNELS;
-       static const double DVD_FRAMERATE, DVD_SAMPLERATE, DVD_KAUDIO_RATE;
-public:
-       CreateDVD_Thread(MWindow *mwindow);
-       ~CreateDVD_Thread();
-       void handle_close_event(int result);
-       BC_Window* new_gui();
-       int option_presets();
-       int create_dvd_jobs(ArrayList<BatchRenderJob*> *jobs,
-               const char *tmp_path, const char *asset_title);
-       int insert_video_plugin(const char *title, KeyFrame *default_keyframe);
-       int resize_tracks();
-
-       MWindow *mwindow;
-       CreateDVD_GUI *gui;
-       char asset_title[BCTEXTLEN];
-       char tmp_path[BCTEXTLEN];
-       int use_deinterlace, use_inverse_telecine;
-       int use_scale, use_resize_tracks;
-       int use_wide_audio, use_wide_aspect;
-       int use_histogram, use_label_chapters;
-       int use_ffmpeg;
-};
-
-class CreateDVD_OK : public BC_OKButton
-{
-public:
-       CreateDVD_OK(CreateDVD_GUI *gui, int x, int y);
-       ~CreateDVD_OK();
-       int button_press_event();
-       int keypress_event();
-
-       CreateDVD_GUI *gui;
-};
-
-class CreateDVD_Cancel : public BC_CancelButton
-{
-public:
-       CreateDVD_Cancel(CreateDVD_GUI *gui, int x, int y);
-       ~CreateDVD_Cancel();
-       int button_press_event();
-
-       CreateDVD_GUI *gui;
-};
-
-
-class CreateDVD_DiskSpace : public BC_Title
-{
-public:
-       CreateDVD_DiskSpace(CreateDVD_GUI *gui, int x, int y);
-       ~CreateDVD_DiskSpace();
-       int64_t tmp_path_space();
-       void update();
-
-       CreateDVD_GUI *gui;
-};
-
-class CreateDVD_TmpPath : public BC_TextBox
-{
-public:
-       CreateDVD_TmpPath(CreateDVD_GUI *gui, int x, int y, int w);
-       ~CreateDVD_TmpPath();
-       int handle_event();
-
-       CreateDVD_GUI *gui;
-};
-
-
-class CreateDVD_AssetTitle : public BC_TextBox
-{
-public:
-       CreateDVD_AssetTitle(CreateDVD_GUI *gui, int x, int y, int w);
-       ~CreateDVD_AssetTitle();
-
-       CreateDVD_GUI *gui;
-};
-
-class CreateDVD_Deinterlace : public BC_CheckBox
-{
-public:
-       CreateDVD_Deinterlace(CreateDVD_GUI *gui, int x, int y);
-       ~CreateDVD_Deinterlace();
-       int handle_event();
-
-       CreateDVD_GUI *gui;
-};
-
-class CreateDVD_InverseTelecine : public BC_CheckBox
-{
-public:
-       CreateDVD_InverseTelecine(CreateDVD_GUI *gui, int x, int y);
-       ~CreateDVD_InverseTelecine();
-       int handle_event();
-
-       CreateDVD_GUI *gui;
-};
-
-class CreateDVD_Scale : public BC_CheckBox
-{
-public:
-       CreateDVD_Scale(CreateDVD_GUI *gui, int x, int y);
-       ~CreateDVD_Scale();
-
-       CreateDVD_GUI *gui;
-};
-
-class CreateDVD_ResizeTracks : public BC_CheckBox
-{
-public:
-       CreateDVD_ResizeTracks(CreateDVD_GUI *gui, int x, int y);
-       ~CreateDVD_ResizeTracks();
-
-       CreateDVD_GUI *gui;
-};
-
-class CreateDVD_Histogram : public BC_CheckBox
-{
-public:
-       CreateDVD_Histogram(CreateDVD_GUI *gui, int x, int y);
-       ~CreateDVD_Histogram();
-
-       CreateDVD_GUI *gui;
-};
-
-class CreateDVD_LabelChapters : public BC_CheckBox
-{
-public:
-       CreateDVD_LabelChapters(CreateDVD_GUI *gui, int x, int y);
-       ~CreateDVD_LabelChapters();
-
-       CreateDVD_GUI *gui;
-};
-
-class CreateDVD_WideAudio : public BC_CheckBox
-{
-public:
-       CreateDVD_WideAudio(CreateDVD_GUI *gui, int x, int y);
-       ~CreateDVD_WideAudio();
-
-       CreateDVD_GUI *gui;
-};
-
-class CreateDVD_WideAspect : public BC_CheckBox
-{
-public:
-       CreateDVD_WideAspect(CreateDVD_GUI *gui, int x, int y);
-       ~CreateDVD_WideAspect();
-
-       CreateDVD_GUI *gui;
-};
-
-class CreateDVD_UseFFMpeg : public BC_CheckBox
-{
-public:
-       CreateDVD_UseFFMpeg(CreateDVD_GUI *gui, int x, int y);
-       ~CreateDVD_UseFFMpeg();
-
-       CreateDVD_GUI *gui;
-};
-
-class CreateDVD_GUI : public BC_Window
-{
-public:
-       CreateDVD_GUI(CreateDVD_Thread *thread,
-               int x, int y, int w, int h);
-       ~CreateDVD_GUI();
-
-       void create_objects();
-       int resize_event(int w, int h);
-       int translation_event();
-       int close_event();
-
-       int64_t needed_disk_space;
-       CreateDVD_Thread *thread;
-       int at_x, at_y;
-       CreateDVD_AssetTitle *asset_title;
-       int tmp_x, tmp_y;
-       CreateDVD_TmpPath *tmp_path;
-       CreateDVD_DiskSpace *disk_space;
-       CreateDVD_Deinterlace *need_deinterlace;
-       CreateDVD_InverseTelecine *need_inverse_telecine;
-       CreateDVD_Scale *need_scale;
-       CreateDVD_UseFFMpeg *need_use_ffmpeg;
-       CreateDVD_ResizeTracks *need_resize_tracks;
-       CreateDVD_Histogram *need_histogram;
-       CreateDVD_WideAudio *need_wide_audio;
-       CreateDVD_WideAspect *need_wide_aspect;
-       CreateDVD_LabelChapters *need_label_chapters;
-       int ok_x, ok_y, ok_w, ok_h;
-       CreateDVD_OK *ok;
-       int cancel_x, cancel_y, cancel_w, cancel_h;
-       CreateDVD_Cancel *cancel;
-};
-
-
-
-
 #endif
index a4d2721e2ac3933945212f7e1bdd13f59a725b5d..3d4d753d7eea0791a44b028347d8c187e1a20230 100644 (file)
@@ -27,10 +27,6 @@ class BatchRenderJob;
 class BatchRenderThread;
 class BatchRenderGUI;
 
-class CreateDVD_MenuItem;
-class CreateDVD_Thread;
-class CreateDVD_GUI;
-
 #define BATCH_PATH "batchrender.rc"
 
 
diff --git a/cinelerra-5.0/cinelerra/bdcreate.C b/cinelerra-5.0/cinelerra/bdcreate.C
new file mode 100644 (file)
index 0000000..5074849
--- /dev/null
@@ -0,0 +1,754 @@
+#include "asset.h"
+#include "bdcreate.h"
+#include "edl.h"
+#include "edit.h"
+#include "edits.h"
+#include "edlsession.h"
+#include "file.inc"
+#include "filexml.h"
+#include "format.inc"
+#include "keyframe.h"
+#include "labels.h"
+#include "mainerror.h"
+#include "mainundo.h"
+#include "mwindow.h"
+#include "mwindowgui.h"
+#include "plugin.h"
+#include "pluginset.h"
+#include "track.h"
+#include "tracks.h"
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+
+// BD Creation
+
+const int64_t CreateBD_Thread::BD_SIZE = 25000000000;
+const int CreateBD_Thread::BD_STREAMS = 1;
+const int CreateBD_Thread::BD_WIDTH = 1920;
+const int CreateBD_Thread::BD_HEIGHT = 1080;
+const double CreateBD_Thread::BD_ASPECT_WIDTH = 4.;
+const double CreateBD_Thread::BD_ASPECT_HEIGHT = 3.;
+const double CreateBD_Thread::BD_WIDE_ASPECT_WIDTH = 16.;
+const double CreateBD_Thread::BD_WIDE_ASPECT_HEIGHT = 9.;
+const double CreateBD_Thread::BD_FRAMERATE = 24000. / 1001.;
+//const int CreateBD_Thread::BD_MAX_BITRATE = 40000000;
+const int CreateBD_Thread::BD_MAX_BITRATE = 8000000;
+const int CreateBD_Thread::BD_CHANNELS = 2;
+const int CreateBD_Thread::BD_WIDE_CHANNELS = 6;
+const double CreateBD_Thread::BD_SAMPLERATE = 48000;
+const double CreateBD_Thread::BD_KAUDIO_RATE = 224;
+
+
+CreateBD_MenuItem::CreateBD_MenuItem(MWindow *mwindow)
+ : BC_MenuItem(_("BD Render..."), _("Ctrl-d"), 'd')
+{
+       set_ctrl(1); 
+       this->mwindow = mwindow;
+}
+
+int CreateBD_MenuItem::handle_event()
+{
+       mwindow->create_bd->start();
+       return 1;
+}
+
+
+CreateBD_Thread::CreateBD_Thread(MWindow *mwindow)
+ : BC_DialogThread()
+{
+       this->mwindow = mwindow;
+       this->gui = 0;
+       this->use_deinterlace = 0;
+       this->use_inverse_telecine = 0;
+       this->use_scale = 0;
+       this->use_resize_tracks = 0;
+       this->use_histogram = 0;
+       this->use_wide_audio = 0;
+       this->use_wide_aspect = 0;
+       this->use_label_chapters = 0;
+}
+
+CreateBD_Thread::~CreateBD_Thread()
+{
+       close_window();
+}
+
+int CreateBD_Thread::create_bd_jobs(ArrayList<BatchRenderJob*> *jobs,
+       const char *tmp_path, const char *asset_title)
+{
+       EDL *edl = mwindow->edl;
+       if( !edl || !edl->session ) {
+               char msg[BCTEXTLEN];
+                sprintf(msg, _("No EDL/Session"));
+                MainError::show_error(msg);
+                return 1;
+        }
+       EDLSession *session = edl->session;
+
+       double total_length = edl->tracks->total_length();
+        if( total_length <= 0 ) {
+               char msg[BCTEXTLEN];
+                sprintf(msg, _("No content: %s"), asset_title);
+                MainError::show_error(msg);
+                return 1;
+        }
+
+       char asset_dir[BCTEXTLEN];
+       sprintf(asset_dir, "%s/%s", tmp_path, asset_title);
+
+       if( mkdir(asset_dir, 0777) ) {
+               char err[BCTEXTLEN], msg[BCTEXTLEN];
+               strerror_r(errno, err, sizeof(err));
+               sprintf(msg, _("Unable to create directory: %s\n-- %s"), asset_dir, err);
+               MainError::show_error(msg);
+               return 1;
+       }
+
+       double old_samplerate = session->sample_rate;
+       double old_framerate = session->frame_rate;
+
+        session->video_channels = BD_STREAMS;
+        session->video_tracks = BD_STREAMS;
+// use session framerate
+//      session->frame_rate = BD_FRAMERATE;
+        session->output_w = BD_WIDTH;
+        session->output_h = BD_HEIGHT;
+        session->aspect_w = use_wide_aspect ? BD_WIDE_ASPECT_WIDTH : BD_ASPECT_WIDTH;
+        session->aspect_h = use_wide_aspect ? BD_WIDE_ASPECT_HEIGHT : BD_ASPECT_HEIGHT;
+        session->sample_rate = BD_SAMPLERATE;
+        session->audio_channels = session->audio_tracks =
+               use_wide_audio ? BD_WIDE_CHANNELS : BD_CHANNELS;
+
+       char script_filename[BCTEXTLEN];
+       sprintf(script_filename, "%s/bd.sh", asset_dir);
+       int fd = open(script_filename, O_WRONLY+O_CREAT+O_TRUNC, 0755);
+       FILE *fp = fdopen(fd, "w");
+       if( !fp ) {
+               char err[BCTEXTLEN], msg[BCTEXTLEN];
+               strerror_r(errno, err, sizeof(err));
+               sprintf(msg, _("Unable to save: %s\n-- %s"), script_filename, err);
+               MainError::show_error(msg);
+               return 1;
+       }
+       char exe_path[BCTEXTLEN];
+       get_exe_path(exe_path);
+       fprintf(fp,"#!/bin/bash -ex\n");
+       fprintf(fp,"mkdir -p $1/udfs\n");
+       fprintf(fp,"sz=`du -sb $1/bd.m2ts | sed -e 's/[ \t].*//'`\n");
+       fprintf(fp,"blks=$((sz/2048 + 512))\n");
+       fprintf(fp,"mkudffs $1/bd.udfs $blks\n");
+       fprintf(fp,"mount -o loop $1/bd.udfs $1/udfs\n");
+       fprintf(fp,"%s/bdwrite $1/udfs $1/bd.m2ts\n",exe_path);
+       fprintf(fp,"umount $1/udfs\n");
+       fprintf(fp,"echo To burn bluray, load blank media and run:\n");
+       fprintf(fp,"echo dd if=$1/bd.udfs 0f=/dev/bd bs=2048000\n");
+       fprintf(fp,"\n");
+       fclose(fp);
+
+       if( use_wide_audio ) {
+               session->audio_channels = session->audio_tracks = BD_WIDE_CHANNELS;
+               session->achannel_positions[0] = 90;
+               session->achannel_positions[1] = 150;
+               session->achannel_positions[2] = 30;
+               session->achannel_positions[3] = 210;
+               session->achannel_positions[4] = 330;
+               session->achannel_positions[5] = 270;
+               if( edl->tracks->recordable_audio_tracks() == BD_WIDE_CHANNELS )
+                       mwindow->remap_audio(MWindow::AUDIO_1_TO_1);
+       }
+       else {
+               session->audio_channels = session->audio_tracks = BD_CHANNELS;
+               session->achannel_positions[0] = 180;
+               session->achannel_positions[1] = 0;
+               if( edl->tracks->recordable_audio_tracks() == BD_WIDE_CHANNELS )
+                       mwindow->remap_audio(MWindow::AUDIO_5_1_TO_2);
+       }
+
+       double new_samplerate = session->sample_rate;
+       double new_framerate = session->frame_rate;
+       edl->rechannel();
+       edl->resample(old_samplerate, new_samplerate, TRACK_AUDIO);
+       edl->resample(old_framerate, new_framerate, TRACK_VIDEO);
+
+       int64_t aud_size = ((BD_KAUDIO_RATE * total_length)/8 + 1000-1) * 1000;
+       int64_t vid_size = BD_SIZE*0.96 - aud_size;
+       int64_t vid_bitrate = (vid_size * 8) / total_length;
+       vid_bitrate /= 1000;  vid_bitrate *= 1000;
+       if( vid_bitrate > BD_MAX_BITRATE ) vid_bitrate = BD_MAX_BITRATE;
+
+       char xml_filename[BCTEXTLEN];
+       sprintf(xml_filename, "%s/bd.xml", asset_dir);
+        FileXML xml_file;
+        edl->save_xml(&xml_file, xml_filename, 0, 0);
+        xml_file.terminate_string();
+        if( xml_file.write_to_file(xml_filename) ) {
+               char msg[BCTEXTLEN];
+               sprintf(msg, _("Unable to save: %s"), xml_filename);
+               MainError::show_error(msg);
+               return 1;
+       }
+
+       BatchRenderJob *job = new BatchRenderJob(mwindow->preferences);
+       jobs->append(job);
+       strcpy(&job->edl_path[0], xml_filename);
+       Asset *asset = job->asset;
+
+       asset->layers = BD_STREAMS;
+       asset->frame_rate = session->frame_rate;
+       asset->width = session->output_w;
+       asset->height = session->output_h;
+       asset->aspect_ratio = session->aspect_w / session->aspect_h;
+
+       char option_path[BCTEXTLEN];
+       sprintf(&asset->path[0],"%s/bd.m2ts", asset_dir);
+       asset->format = FILE_FFMPEG;
+       strcpy(asset->fformat, "m2ts");
+
+       asset->audio_data = 1;
+       strcpy(asset->acodec, "bluray.m2ts");
+       FFMPEG::set_option_path(option_path, "audio/%s", asset->acodec);
+       FFMPEG::load_options(option_path, asset->ff_audio_options,
+                        sizeof(asset->ff_audio_options));
+       asset->ff_audio_bitrate = BD_KAUDIO_RATE * 1000;
+
+       asset->video_data = 1;
+       strcpy(asset->vcodec, "bluray.m2ts");
+       FFMPEG::set_option_path(option_path, "video/%s", asset->vcodec);
+       FFMPEG::load_options(option_path, asset->ff_video_options,
+                sizeof(asset->ff_video_options));
+       asset->ff_video_bitrate = vid_bitrate;
+       asset->ff_video_quality = 0;
+
+       int len = strlen(asset->ff_video_options);
+       char *cp = asset->ff_video_options + len;
+       snprintf(cp, sizeof(asset->ff_video_options)-len-1,
+               "aspect %.5f\n", asset->aspect_ratio);
+
+       job = new BatchRenderJob(mwindow->preferences);
+       jobs->append(job);
+       job->edl_path[0] = '@';
+       strcpy(&job->edl_path[1], script_filename);
+       strcpy(&job->asset->path[0], asset_dir);
+
+       return 0;
+}
+
+void CreateBD_Thread::handle_close_event(int result)
+{
+       if( result ) return;
+       mwindow->batch_render->load_defaults(mwindow->defaults);
+        mwindow->undo->update_undo_before();
+       KeyFrame keyframe;  char data[BCTEXTLEN];
+       if( use_deinterlace ) {
+               sprintf(data,"<DEINTERLACE MODE=1>");
+               keyframe.set_data(data);
+               insert_video_plugin("Deinterlace", &keyframe);
+       }
+       if( use_inverse_telecine ) {
+               sprintf(data,"<IVTC FRAME_OFFSET=0 FIRST_FIELD=0 "
+                       "AUTOMATIC=1 AUTO_THRESHOLD=2.0e+00 PATTERN=2>");
+               keyframe.set_data(data);
+               insert_video_plugin("Inverse Telecine", &keyframe);
+       }
+       if( use_scale ) {
+               sprintf(data,"<PHOTOSCALE WIDTH=%d HEIGHT=%d USE_FILE=1>", BD_WIDTH, BD_HEIGHT);
+               keyframe.set_data(data);
+               insert_video_plugin("Auto Scale", &keyframe);
+       }
+       if( use_resize_tracks )
+               resize_tracks();
+       if( use_histogram ) {
+#if 0
+               sprintf(data, "<HISTOGRAM OUTPUT_MIN_0=0 OUTPUT_MAX_0=1 "
+                       "OUTPUT_MIN_1=0 OUTPUT_MAX_1=1 "
+                       "OUTPUT_MIN_2=0 OUTPUT_MAX_2=1 "
+                       "OUTPUT_MIN_3=0 OUTPUT_MAX_3=1 "
+                       "AUTOMATIC=0 THRESHOLD=9.0-01 PLOT=0 SPLIT=0>"
+                       "<POINTS></POINTS><POINTS></POINTS><POINTS></POINTS>"
+                       "<POINTS><POINT X=6.0e-02 Y=0>"
+                               "<POINT X=9.4e-01 Y=1></POINTS>");
+#else
+               sprintf(data, "<HISTOGRAM AUTOMATIC=0 THRESHOLD=1.0e-01 "
+                       "PLOT=0 SPLIT=0 W=440 H=500 PARADE=0 MODE=3 "
+                       "LOW_OUTPUT_0=0 HIGH_OUTPUT_0=1 LOW_INPUT_0=0 HIGH_INPUT_0=1 GAMMA_0=1 "
+                       "LOW_OUTPUT_1=0 HIGH_OUTPUT_1=1 LOW_INPUT_1=0 HIGH_INPUT_1=1 GAMMA_1=1 "
+                       "LOW_OUTPUT_2=0 HIGH_OUTPUT_2=1 LOW_INPUT_2=0 HIGH_INPUT_2=1 GAMMA_2=1 "
+                       "LOW_OUTPUT_3=0 HIGH_OUTPUT_3=1 LOW_INPUT_3=0.044 HIGH_INPUT_3=0.956 "
+                       "GAMMA_3=1>");
+#endif
+               keyframe.set_data(data);
+               insert_video_plugin("Histogram", &keyframe);
+       }
+       create_bd_jobs(&mwindow->batch_render->jobs, tmp_path, asset_title);
+       mwindow->save_backup();
+       mwindow->undo->update_undo_after(_("create bd"), LOAD_ALL);
+       mwindow->resync_guis();
+       mwindow->batch_render->handle_close_event(0);
+       mwindow->batch_render->start();
+}
+
+BC_Window* CreateBD_Thread::new_gui()
+{
+       memset(tmp_path,0,sizeof(tmp_path));
+       strcpy(tmp_path,"/tmp");
+       memset(asset_title,0,sizeof(asset_title));
+       time_t dt;      time(&dt);
+       struct tm dtm;  localtime_r(&dt, &dtm);
+       sprintf(asset_title, "bd_%02d%02d%02d-%02d%02d%02d",
+               dtm.tm_year+1900, dtm.tm_mon+1, dtm.tm_mday,
+               dtm.tm_hour, dtm.tm_min, dtm.tm_sec);
+       use_deinterlace = 0;
+       use_inverse_telecine = 0;
+       use_scale = 0;
+       use_resize_tracks = 0;
+       use_histogram = 0;
+       use_wide_audio = 0;
+       use_wide_aspect = 0;
+       use_label_chapters = 0;
+       option_presets();
+        int scr_x = mwindow->gui->get_screen_x(0, -1);
+        int scr_w = mwindow->gui->get_screen_w(0, -1);
+        int scr_h = mwindow->gui->get_screen_h(0, -1);
+        int w = 500, h = 250;
+       int x = scr_x + scr_w/2 - w/2, y = scr_h/2 - h/2;
+
+       gui = new CreateBD_GUI(this, x, y, w, h);
+       gui->create_objects();
+       return gui;
+}
+
+
+CreateBD_OK::CreateBD_OK(CreateBD_GUI *gui, int x, int y)
+ : BC_OKButton(x, y)
+{
+        this->gui = gui;
+        set_tooltip(_("end setup, start batch render"));
+}
+
+CreateBD_OK::~CreateBD_OK()
+{
+}
+
+int CreateBD_OK::button_press_event()
+{
+        if(get_buttonpress() == 1 && is_event_win() && cursor_inside()) {
+                gui->set_done(0);
+                return 1;
+        }
+        return 0;
+}
+
+int CreateBD_OK::keypress_event()
+{
+        return 0;
+}
+
+
+CreateBD_Cancel::CreateBD_Cancel(CreateBD_GUI *gui, int x, int y)
+ : BC_CancelButton(x, y)
+{
+        this->gui = gui;
+}
+
+CreateBD_Cancel::~CreateBD_Cancel()
+{
+}
+
+int CreateBD_Cancel::button_press_event()
+{
+        if(get_buttonpress() == 1 && is_event_win() && cursor_inside()) {
+                gui->set_done(1);
+                return 1;
+        }
+        return 0;
+}
+
+
+CreateBD_DiskSpace::CreateBD_DiskSpace(CreateBD_GUI *gui, int x, int y)
+ : BC_Title(x, y, "", MEDIUMFONT, GREEN)
+{
+        this->gui = gui;
+}
+
+CreateBD_DiskSpace::~CreateBD_DiskSpace()
+{
+}
+
+int64_t CreateBD_DiskSpace::tmp_path_space()
+{
+       const char *path = gui->tmp_path->get_text();
+       if( access(path,R_OK+W_OK) ) return 0;
+       struct statfs sfs;
+       if( statfs(path, &sfs) ) return 0;
+       return (int64_t)sfs.f_bsize * sfs.f_bfree;
+}
+
+void CreateBD_DiskSpace::update()
+{
+//     gui->disk_space->set_color(get_bg_color());
+       int64_t disk_space = tmp_path_space();
+       int color = disk_space<gui->needed_disk_space ? RED : GREEN;
+       static const char *suffix[] = { "", "KB", "MB", "GB", "TB", "PB" };
+       int i = 0;
+       for( int64_t space=disk_space; i<5 && (space/=1000)>0; disk_space=space, ++i );
+       char text[BCTEXTLEN];
+       sprintf(text, "%s" _LDv(3) "%s", _("disk space: "), disk_space, suffix[i]);
+       gui->disk_space->BC_Title::update(text);
+       gui->disk_space->set_color(color);
+}
+
+CreateBD_TmpPath::CreateBD_TmpPath(CreateBD_GUI *gui, int x, int y, int w)
+ : BC_TextBox(x, y, w, 1, -sizeof(gui->thread->tmp_path),
+               gui->thread->tmp_path, 1, MEDIUMFONT)
+{
+        this->gui = gui;
+}
+
+CreateBD_TmpPath::~CreateBD_TmpPath()
+{
+}
+
+int CreateBD_TmpPath::handle_event()
+{
+       gui->disk_space->update();
+        return 1;
+}
+
+
+CreateBD_AssetTitle::CreateBD_AssetTitle(CreateBD_GUI *gui, int x, int y, int w)
+ : BC_TextBox(x, y, w, 1, 0, gui->thread->asset_title, 1, MEDIUMFONT)
+{
+        this->gui = gui;
+}
+
+CreateBD_AssetTitle::~CreateBD_AssetTitle()
+{
+}
+
+
+CreateBD_Deinterlace::CreateBD_Deinterlace(CreateBD_GUI *gui, int x, int y)
+ : BC_CheckBox(x, y, &gui->thread->use_deinterlace, _("Deinterlace"))
+{
+       this->gui = gui;
+}
+
+CreateBD_Deinterlace::~CreateBD_Deinterlace()
+{
+}
+
+int CreateBD_Deinterlace::handle_event()
+{
+       if( get_value() ) {
+               gui->need_inverse_telecine->set_value(0);
+               gui->thread->use_inverse_telecine = 0;
+       }
+       return BC_CheckBox::handle_event();
+}
+
+
+CreateBD_InverseTelecine::CreateBD_InverseTelecine(CreateBD_GUI *gui, int x, int y)
+ : BC_CheckBox(x, y, &gui->thread->use_inverse_telecine, _("Inverse Telecine"))
+{
+       this->gui = gui;
+}
+
+CreateBD_InverseTelecine::~CreateBD_InverseTelecine()
+{
+}
+
+int CreateBD_InverseTelecine::handle_event()
+{
+       if( get_value() ) {
+               gui->need_deinterlace->set_value(0);
+               gui->thread->use_deinterlace = 0;
+       }
+       return BC_CheckBox::handle_event();
+}
+
+
+CreateBD_Scale::CreateBD_Scale(CreateBD_GUI *gui, int x, int y)
+ : BC_CheckBox(x, y, &gui->thread->use_scale, _("Scale"))
+{
+       this->gui = gui;
+}
+
+CreateBD_Scale::~CreateBD_Scale()
+{
+}
+
+
+CreateBD_ResizeTracks::CreateBD_ResizeTracks(CreateBD_GUI *gui, int x, int y)
+ : BC_CheckBox(x, y, &gui->thread->use_resize_tracks, _("Resize Tracks"))
+{
+       this->gui = gui;
+}
+
+CreateBD_ResizeTracks::~CreateBD_ResizeTracks()
+{
+}
+
+
+CreateBD_Histogram::CreateBD_Histogram(CreateBD_GUI *gui, int x, int y)
+ : BC_CheckBox(x, y, &gui->thread->use_histogram, _("Histogram"))
+{
+       this->gui = gui;
+}
+
+CreateBD_Histogram::~CreateBD_Histogram()
+{
+}
+
+CreateBD_LabelChapters::CreateBD_LabelChapters(CreateBD_GUI *gui, int x, int y)
+ : BC_CheckBox(x, y, &gui->thread->use_label_chapters, _("Chapters at Labels"))
+{
+       this->gui = gui;
+}
+
+CreateBD_LabelChapters::~CreateBD_LabelChapters()
+{
+}
+
+CreateBD_WideAudio::CreateBD_WideAudio(CreateBD_GUI *gui, int x, int y)
+ : BC_CheckBox(x, y, &gui->thread->use_wide_audio, _("Audio 5.1"))
+{
+       this->gui = gui;
+}
+
+CreateBD_WideAudio::~CreateBD_WideAudio()
+{
+}
+
+CreateBD_WideAspect::CreateBD_WideAspect(CreateBD_GUI *gui, int x, int y)
+ : BC_CheckBox(x, y, &gui->thread->use_wide_aspect, _("Aspect 16x9"))
+{
+       this->gui = gui;
+}
+
+CreateBD_WideAspect::~CreateBD_WideAspect()
+{
+}
+
+
+
+CreateBD_GUI::CreateBD_GUI(CreateBD_Thread *thread, int x, int y, int w, int h)
+ : BC_Window(_(PROGRAM_NAME ": Create BD"), x, y, w, h, 50, 50, 1, 0, 1)
+{
+       this->thread = thread;
+       at_x = at_y = tmp_x = tmp_y = 0;
+       ok_x = ok_y = ok_w = ok_h = 0;
+       cancel_x = cancel_y = cancel_w = cancel_h = 0;
+       asset_title = 0;
+       tmp_path = 0;
+       disk_space = 0;
+       needed_disk_space = 100e9;
+       need_deinterlace = 0;
+       need_inverse_telecine = 0;
+       need_scale = 0;
+       need_resize_tracks = 0;
+       need_histogram = 0;
+       need_wide_audio = 0;
+       need_wide_aspect = 0;
+       need_label_chapters = 0;
+       ok = 0;
+       cancel = 0;
+}
+
+CreateBD_GUI::~CreateBD_GUI()
+{
+}
+
+void CreateBD_GUI::create_objects()
+{
+       lock_window("CreateBD_GUI::create_objects");
+       int pady = BC_TextBox::calculate_h(this, MEDIUMFONT, 0, 1) + 5;
+       int padx = BC_Title::calculate_w(this, (char*)"X", MEDIUMFONT);
+       int x = padx/2, y = pady/2;
+       BC_Title *title = new BC_Title(x, y, _("Title:"), MEDIUMFONT, YELLOW);
+       add_subwindow(title);
+       at_x = x + title->get_w();  at_y = y;
+       asset_title = new CreateBD_AssetTitle(this, at_x, at_y, get_w()-at_x-10);
+       add_subwindow(asset_title);
+       y += title->get_h() + pady/2;
+       title = new BC_Title(x, y, _("tmp path:"), MEDIUMFONT, YELLOW);
+       add_subwindow(title);
+       tmp_x = x + title->get_w();  tmp_y = y;
+       tmp_path = new CreateBD_TmpPath(this, tmp_x, tmp_y,  get_w()-tmp_x-10);
+       add_subwindow(tmp_path);
+       y += title->get_h() + pady/2;
+       disk_space = new CreateBD_DiskSpace(this, x, y);
+       add_subwindow(disk_space);
+       disk_space->update();
+       y += disk_space->get_h() + pady/2;
+       need_deinterlace = new CreateBD_Deinterlace(this, x, y);
+       add_subwindow(need_deinterlace);
+       int x1 = x + 150, x2 = x1 + 150;
+       need_inverse_telecine = new CreateBD_InverseTelecine(this, x1, y);
+       add_subwindow(need_inverse_telecine);
+       y += need_deinterlace->get_h() + pady/2;
+       need_scale = new CreateBD_Scale(this, x, y);
+       add_subwindow(need_scale);
+       need_wide_audio = new CreateBD_WideAudio(this, x1, y);
+       add_subwindow(need_wide_audio);
+       need_resize_tracks = new CreateBD_ResizeTracks(this, x2, y);
+       add_subwindow(need_resize_tracks);
+       y += need_scale->get_h() + pady/2;
+       need_histogram = new CreateBD_Histogram(this, x, y);
+       add_subwindow(need_histogram);
+       need_wide_aspect = new CreateBD_WideAspect(this, x1, y);
+       add_subwindow(need_wide_aspect);
+//     need_label_chapters = new CreateBD_LabelChapters(this, x2, y);
+//     add_subwindow(need_label_chapters);
+       ok_w = BC_OKButton::calculate_w();
+       ok_h = BC_OKButton::calculate_h();
+       ok_x = 10;
+       ok_y = get_h() - ok_h - 10;
+       ok = new CreateBD_OK(this, ok_x, ok_y);
+       add_subwindow(ok);
+       cancel_w = BC_CancelButton::calculate_w();
+       cancel_h = BC_CancelButton::calculate_h();
+       cancel_x = get_w() - cancel_w - 10,
+       cancel_y = get_h() - cancel_h - 10;
+       cancel = new CreateBD_Cancel(this, cancel_x, cancel_y);
+       add_subwindow(cancel);
+       show_window();
+       unlock_window();
+}
+
+int CreateBD_GUI::resize_event(int w, int h)
+{
+       asset_title->reposition_window(at_x, at_y, get_w()-at_x-10);
+       tmp_path->reposition_window(tmp_x, tmp_y,  get_w()-tmp_x-10);
+        ok_y = h - ok_h - 10;
+        ok->reposition_window(ok_x, ok_y);
+       cancel_x = w - cancel_w - 10,
+       cancel_y = h - cancel_h - 10;
+        cancel->reposition_window(cancel_x, cancel_y);
+       return 0;
+}
+
+int CreateBD_GUI::translation_event()
+{
+       return 1;
+}
+
+int CreateBD_GUI::close_event()
+{
+        set_done(1);
+        return 1;
+}
+
+int CreateBD_Thread::
+insert_video_plugin(const char *title, KeyFrame *default_keyframe)
+{
+       Tracks *tracks = mwindow->edl->tracks;
+       for( Track *vtrk=tracks->first; vtrk; vtrk=vtrk->next ) {
+               if( vtrk->data_type != TRACK_VIDEO ) continue;
+               if( !vtrk->record ) continue;
+               vtrk->expand_view = 1;
+               PluginSet *plugin_set = new PluginSet(mwindow->edl, vtrk);
+               vtrk->plugin_set.append(plugin_set);
+               Edits *edits = vtrk->edits;
+               for( Edit *edit=edits->first; edit; edit=edit->next ) {
+                       plugin_set->insert_plugin(title,
+                               edit->startproject, edit->length,
+                               PLUGIN_STANDALONE, 0, default_keyframe, 0);
+               }
+               vtrk->optimize();
+       }
+        return 0;
+}
+
+int CreateBD_Thread::
+resize_tracks()
+{
+        Tracks *tracks = mwindow->edl->tracks;
+#if 0
+       int max_w = 0, max_h = 0;
+        for( Track *vtrk=tracks->first; vtrk; vtrk=vtrk->next ) {
+               if( vtrk->data_type != TRACK_VIDEO ) continue;
+               if( !vtrk->record ) continue;
+               Edits *edits = vtrk->edits;
+               for( Edit *edit=edits->first; edit; edit=edit->next ) {
+                       Indexable *indexable = edit->get_source();
+                       int w = indexable->get_w();
+                       if( w > max_w ) max_w = w;
+                       int h = indexable->get_h();
+                       if( h > max_h ) max_h = h;
+               }
+        }
+#endif
+        for( Track *vtrk=tracks->first; vtrk; vtrk=vtrk->next ) {
+                if( vtrk->data_type != TRACK_VIDEO ) continue;
+                if( !vtrk->record ) continue;
+               vtrk->track_w = BD_WIDTH; // max_w;
+               vtrk->track_h = BD_HEIGHT; // max_h;
+       }
+        return 0;
+}
+
+int CreateBD_Thread::
+option_presets()
+{
+       if( !mwindow->edl ) return 1;
+        Tracks *tracks = mwindow->edl->tracks;
+       int max_w = 0, max_h = 0;
+       int has_deinterlace = 0, has_scale = 0;
+        for( Track *trk=tracks->first; trk; trk=trk->next ) {
+               if( !trk->record ) continue;
+               Edits *edits = trk->edits;
+               switch( trk->data_type ) {
+               case TRACK_VIDEO:
+                       for( Edit *edit=edits->first; edit; edit=edit->next ) {
+                               Indexable *indexable = edit->get_source();
+                               int w = indexable->get_w();
+                               if( w > max_w ) max_w = w;
+                               if( w != BD_WIDTH ) use_scale = 1;
+                               int h = indexable->get_h();
+                               if( h > max_h ) max_h = h;
+                               if( h != BD_HEIGHT ) use_scale = 1;
+                       }
+                       for( int i=0; i<trk->plugin_set.size(); ++i ) {
+                               for(Plugin *plugin = (Plugin*)trk->plugin_set[i]->first;
+                                                plugin;
+                                                plugin = (Plugin*)plugin->next) {
+                                       if( !strcmp(plugin->title, "Deinterlace") )
+                                               has_deinterlace = 1;
+                                       if( !strcmp(plugin->title, "Auto Scale") ||
+                                           !strcmp(plugin->title, "Scale") )
+                                               has_scale = 1;
+                               }
+                       }
+                       break;
+               }
+        }
+       if( has_scale )
+               use_scale = 0;
+       if( use_scale ) {
+               if( max_w != BD_WIDTH ) use_resize_tracks = 1;
+               if( max_h != BD_HEIGHT ) use_resize_tracks = 1;
+       }
+        for( Track *trk=tracks->first; trk && !use_resize_tracks; trk=trk->next ) {
+               if( !trk->record ) continue;
+               switch( trk->data_type ) {
+               case TRACK_VIDEO:
+                       if( trk->track_w != max_w ) use_resize_tracks = 1;
+                       if( trk->track_h != max_h ) use_resize_tracks = 1;
+                       break;
+               }
+        }
+       if( !has_deinterlace && max_h > 2*BD_HEIGHT ) use_deinterlace = 1;
+       // Labels *labels = mwindow->edl->labels;
+       // use_label_chapters = labels && labels->first ? 1 : 0;
+       float w, h;
+       MWindow::create_aspect_ratio(w, h, max_w, max_h);
+       if( w == BD_WIDE_ASPECT_WIDTH && h == BD_WIDE_ASPECT_HEIGHT )
+               use_wide_aspect = 1;
+       if( tracks->recordable_audio_tracks() == BD_WIDE_CHANNELS )
+               use_wide_audio = 1;
+       return 0;
+}
+
diff --git a/cinelerra-5.0/cinelerra/bdcreate.h b/cinelerra-5.0/cinelerra/bdcreate.h
new file mode 100644 (file)
index 0000000..cdea066
--- /dev/null
@@ -0,0 +1,216 @@
+#ifndef __BDCREATE_H__
+#define __BDCREATE_H__
+
+#include "arraylist.h"
+#include "batchrender.h"
+#include "bcwindowbase.h"
+#include "bcbutton.h"
+#include "bcdialog.h"
+#include "bcmenuitem.h"
+#include "bctextbox.h"
+#include "mwindow.h"
+
+#include "bdcreate.inc"
+
+
+
+
+class CreateBD_MenuItem : public BC_MenuItem
+{
+public:
+       CreateBD_MenuItem(MWindow *mwindow);
+       int handle_event();
+       MWindow *mwindow;
+};
+
+
+class CreateBD_Thread : public BC_DialogThread
+{
+       static const int64_t BD_SIZE;
+       static const int BD_STREAMS, BD_WIDTH, BD_HEIGHT;
+       static const double BD_ASPECT_WIDTH, BD_ASPECT_HEIGHT;
+       static const double BD_WIDE_ASPECT_WIDTH, BD_WIDE_ASPECT_HEIGHT;
+       static const int BD_MAX_BITRATE, BD_CHANNELS, BD_WIDE_CHANNELS;
+       static const double BD_FRAMERATE, BD_SAMPLERATE, BD_KAUDIO_RATE;
+public:
+       CreateBD_Thread(MWindow *mwindow);
+       ~CreateBD_Thread();
+       void handle_close_event(int result);
+       BC_Window* new_gui();
+       int option_presets();
+       int create_bd_jobs(ArrayList<BatchRenderJob*> *jobs,
+               const char *tmp_path, const char *asset_title);
+       int insert_video_plugin(const char *title, KeyFrame *default_keyframe);
+       int resize_tracks();
+
+       MWindow *mwindow;
+       CreateBD_GUI *gui;
+       char asset_title[BCTEXTLEN];
+       char tmp_path[BCTEXTLEN];
+       int use_deinterlace, use_inverse_telecine;
+       int use_scale, use_resize_tracks;
+       int use_wide_audio, use_wide_aspect;
+       int use_histogram, use_label_chapters;
+};
+
+class CreateBD_OK : public BC_OKButton
+{
+public:
+       CreateBD_OK(CreateBD_GUI *gui, int x, int y);
+       ~CreateBD_OK();
+       int button_press_event();
+       int keypress_event();
+
+       CreateBD_GUI *gui;
+};
+
+class CreateBD_Cancel : public BC_CancelButton
+{
+public:
+       CreateBD_Cancel(CreateBD_GUI *gui, int x, int y);
+       ~CreateBD_Cancel();
+       int button_press_event();
+
+       CreateBD_GUI *gui;
+};
+
+
+class CreateBD_DiskSpace : public BC_Title
+{
+public:
+       CreateBD_DiskSpace(CreateBD_GUI *gui, int x, int y);
+       ~CreateBD_DiskSpace();
+       int64_t tmp_path_space();
+       void update();
+
+       CreateBD_GUI *gui;
+};
+
+class CreateBD_TmpPath : public BC_TextBox
+{
+public:
+       CreateBD_TmpPath(CreateBD_GUI *gui, int x, int y, int w);
+       ~CreateBD_TmpPath();
+       int handle_event();
+
+       CreateBD_GUI *gui;
+};
+
+
+class CreateBD_AssetTitle : public BC_TextBox
+{
+public:
+       CreateBD_AssetTitle(CreateBD_GUI *gui, int x, int y, int w);
+       ~CreateBD_AssetTitle();
+
+       CreateBD_GUI *gui;
+};
+
+class CreateBD_Deinterlace : public BC_CheckBox
+{
+public:
+       CreateBD_Deinterlace(CreateBD_GUI *gui, int x, int y);
+       ~CreateBD_Deinterlace();
+       int handle_event();
+
+       CreateBD_GUI *gui;
+};
+
+class CreateBD_InverseTelecine : public BC_CheckBox
+{
+public:
+       CreateBD_InverseTelecine(CreateBD_GUI *gui, int x, int y);
+       ~CreateBD_InverseTelecine();
+       int handle_event();
+
+       CreateBD_GUI *gui;
+};
+
+class CreateBD_Scale : public BC_CheckBox
+{
+public:
+       CreateBD_Scale(CreateBD_GUI *gui, int x, int y);
+       ~CreateBD_Scale();
+
+       CreateBD_GUI *gui;
+};
+
+class CreateBD_ResizeTracks : public BC_CheckBox
+{
+public:
+       CreateBD_ResizeTracks(CreateBD_GUI *gui, int x, int y);
+       ~CreateBD_ResizeTracks();
+
+       CreateBD_GUI *gui;
+};
+
+class CreateBD_Histogram : public BC_CheckBox
+{
+public:
+       CreateBD_Histogram(CreateBD_GUI *gui, int x, int y);
+       ~CreateBD_Histogram();
+
+       CreateBD_GUI *gui;
+};
+
+class CreateBD_LabelChapters : public BC_CheckBox
+{
+public:
+       CreateBD_LabelChapters(CreateBD_GUI *gui, int x, int y);
+       ~CreateBD_LabelChapters();
+
+       CreateBD_GUI *gui;
+};
+
+class CreateBD_WideAudio : public BC_CheckBox
+{
+public:
+       CreateBD_WideAudio(CreateBD_GUI *gui, int x, int y);
+       ~CreateBD_WideAudio();
+
+       CreateBD_GUI *gui;
+};
+
+class CreateBD_WideAspect : public BC_CheckBox
+{
+public:
+       CreateBD_WideAspect(CreateBD_GUI *gui, int x, int y);
+       ~CreateBD_WideAspect();
+
+       CreateBD_GUI *gui;
+};
+
+class CreateBD_GUI : public BC_Window
+{
+public:
+       CreateBD_GUI(CreateBD_Thread *thread,
+               int x, int y, int w, int h);
+       ~CreateBD_GUI();
+
+       void create_objects();
+       int resize_event(int w, int h);
+       int translation_event();
+       int close_event();
+
+       int64_t needed_disk_space;
+       CreateBD_Thread *thread;
+       int at_x, at_y;
+       CreateBD_AssetTitle *asset_title;
+       int tmp_x, tmp_y;
+       CreateBD_TmpPath *tmp_path;
+       CreateBD_DiskSpace *disk_space;
+       CreateBD_Deinterlace *need_deinterlace;
+       CreateBD_InverseTelecine *need_inverse_telecine;
+       CreateBD_Scale *need_scale;
+       CreateBD_ResizeTracks *need_resize_tracks;
+       CreateBD_Histogram *need_histogram;
+       CreateBD_WideAudio *need_wide_audio;
+       CreateBD_WideAspect *need_wide_aspect;
+       CreateBD_LabelChapters *need_label_chapters;
+       int ok_x, ok_y, ok_w, ok_h;
+       CreateBD_OK *ok;
+       int cancel_x, cancel_y, cancel_w, cancel_h;
+       CreateBD_Cancel *cancel;
+};
+
+#endif
diff --git a/cinelerra-5.0/cinelerra/bdcreate.inc b/cinelerra-5.0/cinelerra/bdcreate.inc
new file mode 100644 (file)
index 0000000..77bb254
--- /dev/null
@@ -0,0 +1,29 @@
+
+/*
+ * CINELERRA
+ * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
+
+#ifndef __BDCREATE_INC__
+#define __BDCREATE_INC__
+
+class CreateBD_MenuItem;
+class CreateBD_Thread;
+class CreateBD_GUI;
+
+#endif
diff --git a/cinelerra-5.0/cinelerra/bdwrite.C b/cinelerra-5.0/cinelerra/bdwrite.C
new file mode 100644 (file)
index 0000000..3ac4b0f
--- /dev/null
@@ -0,0 +1,3012 @@
+//#include "bd.h"
+//This program was created by inverting libbluray, without any docs,
+//  so it is probably got problems.  Still, works on my Samsung player.
+//  thanks to: Petri Hintukainen, William Hahne, John Stebbinsm, et.al.
+//
+//Usage:
+// ./bd <tgt_dir_path> <playlist-0> <sep> <playlistp1> <sep> ... <sep> <playlist-n>
+//    <sep> == -<pgm_pid> | --<pgm_pid> | ---<pgm_pid>
+//    <pgm_pid> may be empty string, or a numeric pgm_pid for curr title clip
+//    <pgm_pid> defaults to first pgm probed.
+//    <playlist-x> == <clip-0.m2ts> <clip-1.m2ts> ... <clip-n.m2ts>
+// eg:
+// ./brwrite /tmp/dir /path/menu.m2ts --- /path/clip0.m2ts /path/clip1.m2ts -- /path/clip2.m2ts
+//
+// one title is built for each playlist
+// playlist-0 is used as first-play item
+//
+// the basic idea is to use playlist-0 as a menu / directions to
+// use the bluray player remote-control to select the desired title
+// and start the play, avoiding the need for a menu system.
+//
+// if the first play item is the main title, that is ok also.
+// ./brwrite /tmp/dir /path/title.m2ts
+//
+//
+//To use a bluray bd-re rewriteable: (such as for /dev/sr1)
+// dvd+rw-format /dev/sr1  (only done once to init the media)
+// mkudffs /dev/sr1 $((`cat /sys/block/sr1/size`*512/2048-1))
+// mount /dev/sr1 /mnt1
+// cp -av <tgd_dir_path>/BDMV /mnt1/.
+// umount /mnt1
+// eject sr1
+//
+#ifndef __BD_H__
+#define __BD_H__
+#include <stdio.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <endian.h>
+#include <limits.h>
+#include <sys/stat.h>
+
+#include "arraylist.h"
+#include "cstrdup.h"
+#define BCTEXTLEN 1024
+#define BLURAY_TS_PKTSZ 192L
+
+
+extern "C" {
+#include "libavfilter/buffersrc.h"
+#include "libavfilter/buffersink.h"
+#include "libavformat/avformat.h"
+#include "libavformat/avio.h"
+#include "libavcodec/avcodec.h"
+#include "libavfilter/avfilter.h"
+#include "libavutil/avutil.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "libswresample/swresample.h"
+#include "libswscale/swscale.h"
+}
+
+class stream;
+
+enum {
+  obj_hdmv = 1,
+  obj_bdj = 2,
+  title_len = 20,
+  pb_typ_movie = 0,
+  pb_typ_iactv = 1,
+  pb_len = 16,
+
+  BLURAY_APP_TYPE_MAIN_MOVIE = 1,
+  BLURAY_APP_TYPE_MAIN_TIMED_SLIDE_SHOW = 2,
+  BLURAY_APP_TYPE_MAIN_BROWSED_SLIDE_SHOW = 3,
+  BLURAY_APP_TYPE_SUBPATH_BROWSED_SLIDE_SHOW = 4,
+  BLURAY_APP_TYPE_SUBPATH_IG_MENU = 5,
+  BLURAY_APP_TYPE_SUBPATH_TEXT_SUBTITLE = 6,
+  BLURAY_APP_TYPE_SUBPATH_ELEMENTARY_STREAM = 7,
+
+  BLURAY_STREAM_TYPE_VIDEO_MPEG1 = 0x01,
+  BLURAY_STREAM_TYPE_VIDEO_MPEG2 = 0x02,
+  BLURAY_STREAM_TYPE_AUDIO_MPEG1 = 0x03,
+  BLURAY_STREAM_TYPE_AUDIO_MPEG2 = 0x04,
+  BLURAY_STREAM_TYPE_AUDIO_LPCM = 0x80,
+  BLURAY_STREAM_TYPE_AUDIO_AC3 = 0x81,
+  BLURAY_STREAM_TYPE_AUDIO_DTS = 0x82,
+  BLURAY_STREAM_TYPE_AUDIO_TRUHD = 0x83,
+  BLURAY_STREAM_TYPE_AUDIO_AC3PLUS = 0x84,
+  BLURAY_STREAM_TYPE_AUDIO_DTSHD = 0x85,
+  BLURAY_STREAM_TYPE_AUDIO_DTSHD_MASTER = 0x86,
+  BLURAY_STREAM_TYPE_VIDEO_VC1 = 0xea,
+  BLURAY_STREAM_TYPE_VIDEO_H264 = 0x1b,
+  BLURAY_STREAM_TYPE_VIDEO_H264_MVC = 0x20,
+  BLURAY_STREAM_TYPE_SUB_PG = 0x90,
+  BLURAY_STREAM_TYPE_SUB_IG = 0x91,
+  BLURAY_STREAM_TYPE_SUB_TEXT = 0x92,
+  BLURAY_STREAM_TYPE_AUDIO_AC3PLUS_SECONDARY = 0xa1,
+  BLURAY_STREAM_TYPE_AUDIO_DTSHD_SECONDARY = 0xa2,
+
+  BLURAY_MARK_TYPE_ENTRY = 0x01,
+  BLURAY_MARK_TYPE_LINK  = 0x02,
+
+  BLURAY_PLAYBACK_TYPE_SEQUENTIAL = 1,
+  BLURAY_PLAYBACK_TYPE_RANDOM = 2,
+  BLURAY_PLAYBACK_TYPE_SHUFFLE = 3,
+
+  BLURAY_VIDEO_FORMAT_480I = 1,  // ITU-R BT.601-5
+  BLURAY_VIDEO_FORMAT_576I = 2,  // ITU-R BT.601-4
+  BLURAY_VIDEO_FORMAT_480P = 3,  // SMPTE 293M
+  BLURAY_VIDEO_FORMAT_1080I = 4, // SMPTE 274M
+  BLURAY_VIDEO_FORMAT_720P = 5,  // SMPTE 296M
+  BLURAY_VIDEO_FORMAT_1080P = 6, // SMPTE 274M
+  BLURAY_VIDEO_FORMAT_576P = 7,  // ITU-R BT.1358
+
+  BLURAY_VIDEO_RATE_24000_1001 = 1, // 23.976
+  BLURAY_VIDEO_RATE_24 = 2,
+  BLURAY_VIDEO_RATE_25 = 3,
+  BLURAY_VIDEO_RATE_30000_1001 = 4, // 29.97
+  BLURAY_VIDEO_RATE_50 = 6,
+  BLURAY_VIDEO_RATE_60000_1001 = 7, // 59.94
+
+  BLURAY_ASPECT_RATIO_4_3 = 2,
+  BLURAY_ASPECT_RATIO_16_9 = 3,
+
+  BLURAY_AUDIO_FORMAT_MONO = 1,
+  BLURAY_AUDIO_FORMAT_STEREO = 3,
+  BLURAY_AUDIO_FORMAT_MULTI_CHAN = 6,
+  BLURAY_AUDIO_FORMAT_COMBO = 12,   // Stereo ac3/dts, 
+
+  BLURAY_AUDIO_RATE_48 = 1,
+  BLURAY_AUDIO_RATE_96 = 4,
+  BLURAY_AUDIO_RATE_192 = 5,
+  BLURAY_AUDIO_RATE_192_COMBO = 12, // 48 or 96 ac3/dts, 192 mpl/dts-hd
+  BLURAY_AUDIO_RATE_96_COMBO = 14,  // 48 ac3/dts, 96 mpl/dts-hd
+  BLURAY_TEXT_CHAR_CODE_UTF8 = 0x01,
+  BLURAY_TEXT_CHAR_CODE_UTF16BE = 0x02,
+  BLURAY_TEXT_CHAR_CODE_SHIFT_JIS = 0x03,
+  BLURAY_TEXT_CHAR_CODE_EUC_KR = 0x04,
+  BLURAY_TEXT_CHAR_CODE_GB18030_20001 = 0x05,
+  BLURAY_TEXT_CHAR_CODE_CN_GB = 0x06,
+  BLURAY_TEXT_CHAR_CODE_BIG5 = 0x07,
+
+  BLURAY_STILL_NONE = 0x00,
+  BLURAY_STILL_TIME = 0x01,
+  BLURAY_STILL_INFINITE = 0x02,
+
+  BLURAY_PG_TEXTST_STREAM = 0x01,
+  BLURAY_SECONDARY_VIDEO_STREAM = 0x02,
+  BLURAY_SECONDARY_AUDIO_STREAM = 0x03,
+};
+
+class bs_file {
+  FILE *fp;
+  uint32_t reg, len;
+  int64_t fpos, fsz;
+public:
+  bs_file() { fp = 0; }
+  ~bs_file() {}
+
+  void init();
+  int  open(const char *fn);
+  void close();
+  void write(uint32_t v, int n);
+  void pad(int n);
+  void padb(int n) { pad(n*8); }
+  int64_t posb() { return fpos; }
+  void posb(int64_t n);
+  int64_t pos() { return posb()*8 + len; }
+  void writeb(uint8_t * bp, int n);
+  void writeb(const char *cp, int n) {
+    writeb((uint8_t *) cp, n);
+  }
+};
+
+class bs_length {
+  int64_t fpos, len;
+public:
+  bs_length() { fpos = len = 0; }
+  void bs_len(bs_file &bs, int n) {
+    bs.write(len, n);  fpos = bs.posb();
+  }
+  void bs_end(bs_file &bs) {
+    len = bs.posb() - fpos;
+  }
+  void bs_ofs(bs_file &bs, int n) {
+    bs.write(fpos-n/8, n);
+  }
+};
+
+class _bd_stream_info {
+public:
+  uint8_t coding_type;
+  uint8_t format;
+  uint8_t rate;
+  uint8_t char_code;
+  uint8_t lang[4];
+  uint16_t pid;
+  uint8_t aspect;
+  uint8_t subpath_id;
+
+  _bd_stream_info() { memset(this, 0, sizeof(*this)); }
+  ~_bd_stream_info() {}
+};
+
+class bd_stream_info : public _bd_stream_info {
+public:
+  bd_stream_info() {}
+  ~bd_stream_info() {}
+};
+
+class _bd_clip_info {
+public:
+  uint32_t pkt_count;
+  uint8_t still_mode;
+  uint16_t still_time;          /* seconds */
+  uint64_t start_time;
+  uint64_t in_time;
+  uint64_t out_time;
+
+  _bd_clip_info() { memset(this, 0, sizeof(*this)); }
+  ~_bd_clip_info() {}
+};
+
+class bd_clip_info : public _bd_clip_info {
+public:
+  ArrayList<bd_stream_info *> video_streams;
+  ArrayList<bd_stream_info *> audio_streams;
+  ArrayList<bd_stream_info *> pg_streams;
+  ArrayList<bd_stream_info *> ig_streams;
+  ArrayList<bd_stream_info *> sec_audio_streams;
+  ArrayList<bd_stream_info *> sec_video_streams;
+
+  bd_clip_info() {}
+  ~bd_clip_info() {
+    video_streams.remove_all_objects();
+    audio_streams.remove_all_objects();
+    pg_streams.remove_all_objects();
+    ig_streams.remove_all_objects();
+    sec_audio_streams.remove_all_objects();
+    sec_video_streams.remove_all_objects();
+  }
+};
+
+class _bd_title_chapter {
+public:
+  uint32_t idx;
+  uint64_t start;
+  uint64_t duration;
+  uint64_t offset;
+  unsigned clip_ref;
+
+  _bd_title_chapter() { memset(this, 0, sizeof(*this)); }
+  ~_bd_title_chapter() {}
+};
+
+class bd_title_chapter : public _bd_title_chapter {
+public:
+  bd_title_chapter() {}
+  ~bd_title_chapter() {}
+};
+
+class _bd_title_mark {
+public:
+  uint32_t idx;
+  int type;
+  uint64_t start;
+  uint64_t duration;
+  uint64_t offset;
+  unsigned clip_ref;
+
+  _bd_title_mark() { memset(this, 0, sizeof(*this)); }
+  ~_bd_title_mark() {}
+};
+
+class bd_title_mark : public _bd_title_mark {
+public:
+  bd_title_mark() {}
+  ~bd_title_mark() {}
+};
+
+class _bd_title_info {
+public:
+  uint32_t idx;
+  uint32_t playlist;
+  uint64_t duration;
+  uint8_t angle_count;
+
+  _bd_title_info() { memset(this, 0, sizeof(*this)); }
+  ~_bd_title_info() {}
+};
+
+class bd_title_info : public _bd_title_info {
+public:
+  ArrayList<bd_clip_info *> clips;
+  ArrayList<bd_title_chapter *> chapters;
+  ArrayList<bd_title_mark *> marks;
+
+  bd_title_info() {}
+  ~bd_title_info() {
+    clips.remove_all_objects();
+    chapters.remove_all_objects();
+    marks.remove_all_objects();
+  }
+};
+
+class _clpi_stc_seq {
+public:
+  uint16_t pcr_pid;
+  uint32_t spn_stc_start;
+  uint32_t presentation_start_time;
+  uint32_t presentation_end_time;
+
+  _clpi_stc_seq() { memset(this, 0, sizeof(*this)); }
+  ~_clpi_stc_seq() {}
+};
+
+class clpi_stc_seq : public _clpi_stc_seq {
+public:
+  int write();
+
+  clpi_stc_seq() {}
+  ~clpi_stc_seq() {}
+};
+
+class _clpi_atc_seq {
+public:
+  uint32_t spn_atc_start;
+  uint8_t offset_stc_id;
+
+  _clpi_atc_seq() { memset(this, 0, sizeof(*this)); }
+  ~_clpi_atc_seq() {}
+};
+
+class clpi_atc_seq : public _clpi_atc_seq {
+public:
+  ArrayList<clpi_stc_seq *> stc_seq;
+  int write();
+
+  clpi_atc_seq() {}
+  ~clpi_atc_seq() {
+    stc_seq.remove_all_objects();
+  }
+};
+
+class clpi_sequences : public bs_length,
+                       public ArrayList<clpi_atc_seq *> {
+public:
+  int write();
+
+  clpi_sequences() {}
+  ~clpi_sequences() { remove_all_objects(); }
+};
+
+class _clpi_ts_type {
+public:
+  uint8_t validity;
+  char format_id[5];
+
+  _clpi_ts_type() { memset(this, 0, sizeof(*this)); }
+  ~_clpi_ts_type() {}
+};
+
+class clpi_ts_type : public _clpi_ts_type {
+public:
+  clpi_ts_type() {}
+  ~clpi_ts_type() {}
+};
+
+class _clpi_atc_delta {
+public:
+  uint32_t delta;
+  char file_id[6];
+  char file_code[5];
+
+  _clpi_atc_delta() { memset(this, 0, sizeof(*this)); }
+  ~_clpi_atc_delta() {}
+};
+
+class clpi_atc_delta : public _clpi_atc_delta {
+public:
+  int write();
+
+  clpi_atc_delta() {}
+  ~clpi_atc_delta() {}
+};
+
+class _clpi_font {
+public:
+  char file_id[6];
+
+  _clpi_font() { memset(this, 0, sizeof(*this)); }
+  ~_clpi_font() {}
+};
+
+class clpi_font : public _clpi_font {
+public:
+  clpi_font() {}
+  ~clpi_font() {}
+};
+
+class clpi_font_info {
+public:
+  ArrayList<clpi_font *> font;
+
+  clpi_font_info() {}
+  ~clpi_font_info() {
+    font.remove_all_objects();
+  }
+};
+
+class _clpi_clip_info {
+public:
+  uint8_t clip_stream_type;
+  uint8_t application_type;
+  uint8_t is_atc_delta;
+  uint32_t ts_recording_rate;
+  uint32_t num_source_packets;
+
+  _clpi_clip_info() { memset(this, 0, sizeof(*this)); }
+  ~_clpi_clip_info() {}
+};
+
+class clpi_clip_info : public bs_length, public _clpi_clip_info {
+public:
+  clpi_ts_type ts_type_info;
+  clpi_font_info font_info;
+  ArrayList<clpi_atc_delta *> atc_delta;
+  int write();
+
+  clpi_clip_info() {}
+  ~clpi_clip_info() {
+    atc_delta.remove_all_objects();
+  }
+};
+
+class _clpi_prog_stream {
+public:
+  uint16_t pid;
+  uint8_t coding_type;
+  uint8_t format;
+  uint8_t rate;
+  uint8_t aspect;
+  uint8_t oc_flag;
+  uint8_t char_code;
+  char lang[4];
+
+  _clpi_prog_stream() { memset(this, 0, sizeof(*this)); }
+  ~_clpi_prog_stream() {}
+};
+
+class clpi_prog_stream : public bs_length, public _clpi_prog_stream {
+public:
+  int write();
+
+  clpi_prog_stream() {}
+  ~clpi_prog_stream() {}
+};
+
+class _clpi_ep_coarse {
+public:
+  int ref_ep_fine_id;
+  int pts_ep;
+  uint32_t spn_ep;
+
+  _clpi_ep_coarse() { memset(this, 0, sizeof(*this)); }
+  ~_clpi_ep_coarse() {}
+};
+
+class clpi_ep_coarse : public _clpi_ep_coarse {
+public:
+  int write();
+
+  clpi_ep_coarse() {}
+  ~clpi_ep_coarse() {}
+};
+
+class _clpi_ep_fine {
+public:
+  uint8_t is_angle_change_point;
+  uint8_t i_end_position_offset;
+  int pts_ep;
+  int spn_ep;
+
+  _clpi_ep_fine() { memset(this, 0, sizeof(*this)); }
+  ~_clpi_ep_fine() {}
+};
+
+class clpi_ep_fine : public _clpi_ep_fine {
+public:
+  int write();
+
+  clpi_ep_fine() {}
+  ~clpi_ep_fine() {}
+};
+
+class _clpi_ep_map_entry {
+public:
+  uint8_t ep_stream_type;
+  uint32_t ep_map_stream_start_addr;
+
+  _clpi_ep_map_entry() { memset(this, 0, sizeof(*this)); }
+  ~_clpi_ep_map_entry() {}
+};
+
+class clpi_ep_map_entry : public _clpi_ep_map_entry {
+public:
+  uint32_t fine_start;
+  uint16_t pid;
+  ArrayList<clpi_ep_coarse *> coarse;
+  ArrayList<clpi_ep_fine *> fine;
+  int write(uint32_t ep_map_pos);
+  int write_map();
+
+  clpi_ep_map_entry(int id) { fine_start = 0;  pid = id; }
+  ~clpi_ep_map_entry() {
+    coarse.remove_all_objects();
+    fine.remove_all_objects();
+  }
+};
+
+class _clpi_prog {
+public:
+  uint32_t spn_program_sequence_start;
+  uint8_t num_groups;
+  _clpi_prog() { memset(this, 0, sizeof(*this)); }
+  ~_clpi_prog() {}
+};
+
+class clpi_prog : public _clpi_prog {
+public:
+  ArrayList<clpi_prog_stream *> streams;
+  uint16_t program_map_pid;
+
+  int write();
+  clpi_prog(int pmt_pid) { program_map_pid = pmt_pid; }
+  ~clpi_prog() { streams.remove_all_objects(); }
+};
+
+class clpi_programs : public bs_length,
+                       public ArrayList<clpi_prog *> {
+public:
+  int write();
+
+  clpi_programs() {}
+  ~clpi_programs() { remove_all_objects(); }
+};
+
+class clpi_extents : public bs_length,
+                       public ArrayList<uint32_t> {
+public:
+  int write();
+
+  clpi_extents() {}
+  ~clpi_extents() {}
+};
+class _clpi_cpi {
+public:
+  uint8_t type;
+
+  _clpi_cpi() { type = 0; }
+  ~_clpi_cpi() {}
+};
+
+class clpi_cpi : public bs_length, public _clpi_cpi,
+                       public ArrayList<clpi_ep_map_entry *> {
+public:
+  int write();
+
+  clpi_cpi() {}
+  ~clpi_cpi() { remove_all_objects(); }
+};
+
+class bd_uo_mask {
+public:
+  unsigned int menu_call : 1;
+  unsigned int title_search : 1;
+  unsigned int chapter_search : 1;
+  unsigned int time_search : 1;
+  unsigned int skip_to_next_point : 1;
+  unsigned int skip_to_prev_point : 1;
+  unsigned int play_firstplay : 1;
+  unsigned int stop : 1;
+  unsigned int pause_on : 1;
+  unsigned int pause_off : 1;
+  unsigned int still_off : 1;
+  unsigned int forward : 1;
+  unsigned int backward : 1;
+  unsigned int resume : 1;
+  unsigned int move_up : 1;
+  unsigned int move_down : 1;
+  unsigned int move_left : 1;
+  unsigned int move_right : 1;
+  unsigned int select : 1;
+  unsigned int activate : 1;
+  unsigned int select_and_activate : 1;
+  unsigned int primary_audio_change : 1;
+  unsigned int reserved0 : 1;
+  unsigned int angle_change : 1;
+  unsigned int popup_on : 1;
+  unsigned int popup_off : 1;
+  unsigned int pg_enable_disable : 1;
+  unsigned int pg_change : 1;
+  unsigned int secondary_video_enable_disable : 1;
+  unsigned int secondary_video_change : 1;
+  unsigned int secondary_audio_enable_disable : 1;
+  unsigned int secondary_audio_change : 1;
+  unsigned int reserved1 : 1;
+  unsigned int pip_pg_change : 1;
+
+  int write();
+  bd_uo_mask() {
+    memset(this, 0, sizeof(*this));
+  }
+  ~bd_uo_mask() {
+  }
+};
+
+class _mpls_stream {
+public:
+  uint8_t stream_type;
+  uint8_t coding_type;
+  uint16_t pid;
+  uint8_t subpath_id;
+  uint8_t subclip_id;
+  uint8_t format;
+  uint8_t rate;
+  uint8_t char_code;
+  char lang[4];
+
+  _mpls_stream() { memset(this, 0, sizeof(*this)); }
+  ~_mpls_stream() {}
+};
+
+class mpls_stream : public _mpls_stream {
+public:
+  bs_length strm, code;
+  int write();
+
+  mpls_stream() {}
+  ~mpls_stream() {}
+};
+
+class _mpls_stn {
+public:
+  uint8_t num_pip_pg;
+  _mpls_stn() {
+    num_pip_pg = 0;
+  }
+  ~_mpls_stn() {}
+};
+
+class mpls_stn : public bs_length, public _mpls_stn {
+public:
+  ArrayList<mpls_stream *> video;
+  ArrayList<mpls_stream *> audio;
+  ArrayList<mpls_stream *> pg;
+  ArrayList<mpls_stream *> ig;
+  ArrayList<mpls_stream *> secondary_audio;
+  ArrayList<mpls_stream *> secondary_video;
+  // Secondary audio specific fields
+  ArrayList<uint8_t> sa_primary_audio_ref;
+  // Secondary video specific fields
+  ArrayList<uint8_t> sv_secondary_audio_ref;
+  ArrayList<uint8_t> sv_pip_pg_ref;
+
+  int write();
+  mpls_stn() {}
+  ~mpls_stn() {
+    video.remove_all_objects();
+    audio.remove_all_objects();
+    pg.remove_all_objects();
+    ig.remove_all_objects();
+    secondary_audio.remove_all_objects();
+    secondary_video.remove_all_objects();
+  }
+};
+
+class _mpls_clip {
+public:
+  char clip_id[6];
+  char codec_id[5];
+  uint8_t stc_id;
+
+  _mpls_clip() { memset(this, 0, sizeof(*this)); }
+  ~_mpls_clip() {}
+};
+
+class mpls_clip : public _mpls_clip {
+public:
+  mpls_clip() { strcpy(codec_id, "M2TS"); }
+  ~mpls_clip() {}
+};
+
+class _mpls_pi {
+public:
+  uint8_t is_multi_angle;
+  uint8_t connection_condition;
+  uint32_t in_time;
+  uint32_t out_time;
+  uint8_t random_access_flag;
+  uint8_t still_mode;
+  uint16_t still_time;
+  uint8_t is_different_audio;
+  uint8_t is_seamless_angle;
+
+  _mpls_pi() { memset(this, 0, sizeof(*this)); }
+  ~_mpls_pi() {}
+};
+
+class mpls_pi : public bs_length, public _mpls_pi {
+public:
+  bd_uo_mask uo_mask;
+  ArrayList<mpls_clip *> clip;
+  mpls_stn stn;
+
+  int write();
+
+  mpls_pi() {}
+  ~mpls_pi() {}
+};
+
+class _mpls_plm {
+public:
+  uint8_t mark_id;
+  uint8_t mark_type;
+  uint16_t play_item_ref;
+  uint32_t time;
+  uint16_t entry_es_pid;
+  uint32_t duration;
+
+  _mpls_plm() { memset(this, 0, sizeof(*this)); }
+  ~_mpls_plm() {}
+};
+
+class mpls_plm : public _mpls_plm {
+public:
+  int write();
+
+  mpls_plm() {}
+  ~mpls_plm() {}
+};
+
+class _mpls_ai {
+public:
+  uint8_t playback_type;
+  uint16_t playback_count;
+  uint8_t random_access_flag;
+  uint8_t audio_mix_flag;
+  uint8_t lossless_bypass_flag;
+
+  _mpls_ai() { memset(this, 0, sizeof(*this)); }
+  ~_mpls_ai() {}
+};
+
+class mpls_ai : public bs_length, public _mpls_ai {
+public:
+  bd_uo_mask uo_mask;
+  int write();
+
+  mpls_ai() {}
+  ~mpls_ai() {}
+};
+
+class _mpls_sub_pi {
+public:
+  uint8_t connection_condition;
+  uint8_t is_multi_clip;
+  uint32_t in_time;
+  uint32_t out_time;
+  uint16_t sync_play_item_id;
+  uint32_t sync_pts;
+
+  _mpls_sub_pi() { memset(this, 0, sizeof(*this)); }
+  ~_mpls_sub_pi() {}
+};
+
+class mpls_sub_pi : public bs_length, public _mpls_sub_pi {
+public:
+  ArrayList<mpls_clip *> clip;
+  int write();
+
+  mpls_sub_pi() {}
+  ~mpls_sub_pi() {
+    clip.remove_all_objects();
+  }
+};
+
+class _mpls_sub {
+public:
+  uint8_t type;
+  uint8_t is_repeat;
+
+  _mpls_sub() { memset(this, 0, sizeof(*this)); }
+  ~_mpls_sub() {}
+};
+
+class mpls_sub : public bs_length, public _mpls_sub {
+public:
+  ArrayList<mpls_sub_pi *> sub_play_item;
+
+  int write();
+  mpls_sub() {}
+  ~mpls_sub() {
+   sub_play_item.remove_all_objects();
+  }
+};
+
+class _mpls_pip_data {
+public:
+  uint32_t time;
+  uint16_t xpos;
+  uint16_t ypos;
+  uint8_t scale_factor;
+
+  _mpls_pip_data() { memset(this, 0, sizeof(*this)); }
+  ~_mpls_pip_data() {}
+};
+
+class mpls_pip_data : public _mpls_pip_data {
+public:
+  int write();
+
+  mpls_pip_data() {}
+  ~mpls_pip_data() {}
+};
+
+class _mpls_pip_metadata {
+public:
+  uint16_t clip_ref;
+  uint8_t secondary_video_ref;
+  uint8_t timeline_type;
+  uint8_t luma_key_flag;
+  uint8_t upper_limit_luma_key;
+  uint8_t trick_play_flag;
+
+  _mpls_pip_metadata() { memset(this, 0, sizeof(*this)); }
+  ~_mpls_pip_metadata() {}
+};
+
+class mpls_pip_metadata : public _mpls_pip_metadata {
+public:
+  ArrayList<mpls_pip_data *> data;
+
+  int write(uint32_t start_address);
+  mpls_pip_metadata() {}
+  ~mpls_pip_metadata() {
+    data.remove_all_objects();
+  }
+};
+
+class _mpls_pl {
+public:
+  uint32_t list_pos;
+  uint32_t mark_pos;
+  uint32_t ext_pos;
+
+  _mpls_pl() { memset(this, 0, sizeof(*this)); }
+  ~_mpls_pl() {}
+};
+
+class mpls_pl : public _mpls_pl {
+public:
+  int sig;
+  bs_length play, mark, subx, pipm;
+  mpls_ai app_info;
+  ArrayList<mpls_pi *> play_item;
+  ArrayList<mpls_sub *> sub_path;
+  ArrayList<mpls_plm *> play_mark;
+  // extension data (profile 5, version 2.4)
+  ArrayList<mpls_sub *> ext_sub_path;
+  // extension data (Picture-In-Picture metadata)
+  ArrayList<mpls_pip_metadata *> ext_pip_data;
+
+  int write_header();
+  int write_playlist();
+  int write_playlistmark();
+  int write_subpath_extension();
+  int write_pip_metadata_extension();
+  int write();
+
+  mpls_pl() { sig = 1; }
+  ~mpls_pl() {
+    play_item.remove_all_objects();
+    sub_path.remove_all_objects();
+    play_mark.remove_all_objects();
+    ext_sub_path.remove_all_objects();
+    ext_pip_data.remove_all_objects();
+  }
+};
+
+class _clpi_cl {
+public:
+  uint32_t sequence_info_start_addr;
+  uint32_t program_info_start_addr;
+  uint32_t cpi_start_addr;
+  uint32_t clip_mark_start_addr;
+  uint32_t ext_data_start_addr;
+
+  _clpi_cl() { memset(this, 0, sizeof(*this)); }
+  ~_clpi_cl() {}
+};
+
+class clpi_cl : public _clpi_cl {
+public:
+  int sig;
+  clpi_clip_info clip;
+  clpi_sequences sequences;
+  clpi_programs programs;
+  clpi_cpi cpi;
+  clpi_extents extents;
+  clpi_programs programs_ss;
+  clpi_cpi cpi_ss;
+
+  int write_header();
+  int write();
+
+  int write_clpi_extension(int id1, int id2, void *handle);
+  int write_mpls_extension(int id1, int id2, void *handle);
+
+  clpi_cl() { sig = 1; }
+  ~clpi_cl() {}
+};
+
+class command_obj {
+public:
+  union {
+    uint32_t cmd;
+    struct {
+      uint32_t sub_grp:3;       /* command sub-group */
+      uint32_t grp:2;           /* command group */
+      uint32_t op_cnt:3;        /* operand count */
+      uint32_t branch_opt:4;    /* branch option */
+      uint32_t rsvd1:2;
+      uint32_t imm_op2:1;       /* I-flag for operand 2 */
+      uint32_t imm_op1:1;       /* I-flag for operand 1 */
+      uint32_t cmp_opt:4;       /* compare option */
+      uint32_t rsvd2:4;
+      uint32_t set_opt:5;       /* set option */
+      uint32_t rsvd3:3;
+    };
+  };
+  uint32_t dst;
+  uint32_t src;
+
+  command_obj() { cmd = dst = src = 0; }
+  ~command_obj() {}
+};
+
+class _movie_obj {
+public:
+  int resume_intention_flag;
+  int menu_call_mask;
+  int title_search_mask;
+
+  _movie_obj() { memset(this, 0, sizeof(*this)); }
+  ~_movie_obj() {}
+};
+
+class movie_obj : public _movie_obj {
+public:
+  ArrayList<command_obj *> cmds;
+
+  movie_obj() {}
+  ~movie_obj() {
+    cmds.remove_all_objects();
+  }
+};
+
+class movie_file : public bs_length {
+public:
+  int sig;
+  ArrayList<movie_obj *> movies;
+
+  movie_file() { sig = 1; }
+  ~movie_file() {
+    movies.remove_all_objects();
+  }
+
+  int write();
+};
+
+class _pb_obj {
+public:
+  int obj_typ;
+  int pb_typ;
+  int hdmv_id;
+
+  _pb_obj() { memset(this, 0, sizeof(*this)); }
+  ~_pb_obj() {}
+};
+
+class pb_obj : public _pb_obj {
+public:
+  int last;
+  char *bdj_name;
+  void write_obj();
+
+  pb_obj() {
+    last = 0;
+    bdj_name = 0;
+  }
+  ~pb_obj() {
+    delete [] bdj_name;
+  }
+
+  void set_hdmv(int id, int pt);
+  void set_bdj(char *nm, int pt);
+  void write_hdmv_obj(int id_ref);
+  void write_bdj_obj(char *name);
+};
+
+class _title_obj {
+public:
+  int acc_typ;
+  _title_obj() { acc_typ = 0; }
+  ~_title_obj() {}
+};
+
+class title_obj : public pb_obj, public _title_obj {
+public:
+  title_obj() {}
+  ~title_obj() {}
+
+  void write_obj();
+};
+
+class _index_file {
+public:
+  int sig;
+  int initial_output_mode_preference;
+  int content_exist_flag;
+  int video_format;
+  int frame_rate;
+
+  _index_file() { memset(this, 0, sizeof(*this)); }
+  ~_index_file() {}
+};
+
+class index_file : public bs_length, public _index_file {
+public:
+  ArrayList<title_obj *> titles;
+  pb_obj first_play;
+  pb_obj top_menu;
+  char user_data[32];
+  bs_length exten, appinf;
+
+  void write_hdmv_obj(int hdmv_typ, int id_ref);
+  void write_bdj_obj(int bdj_typ, char *name);
+  void write_pb_obj(pb_obj * pb);
+  int write();
+
+  index_file() {
+    sig = 1;
+    memset(user_data, 0, sizeof(user_data));
+  }
+  ~index_file() {
+    titles.remove_all_objects();
+  }
+};
+
+class _bdid {
+public:
+  uint32_t data_start;
+  uint32_t extension_data_start;
+  char org_id[4];
+  char disc_id[16];
+
+  _bdid() { memset(this, 0, sizeof(*this)); }
+  ~_bdid() {}
+};
+
+class bdid : public _bdid {
+public:
+  int sig;
+  int write();
+
+  bdid() { sig = 1; }
+  ~bdid() {}
+};
+
+class stream : public bd_stream_info {
+public:
+  int av_idx;
+  AVMediaType type;
+  AVCodecID codec_id;
+  int64_t start_pts;
+  int64_t end_pts;
+  int64_t last_pts;
+  int64_t duration;
+
+  stream(AVMediaType ty, int i) {
+    type = ty;  av_idx = i;
+    start_pts = INT64_MAX; end_pts = INT64_MIN;
+    last_pts = -1;
+  }
+  ~stream() {}
+};
+
+class mark {
+public:
+  static int cmpr(mark **, mark **);
+  int64_t sample, pos, pts;
+  uint32_t pkt, pid;
+  mark(int64_t s, int64_t p, int64_t ts, uint32_t pk, int id) {
+    sample = s;  pos = p;  pts = ts; pkt = pk;  pid = id;
+  }
+};
+
+int mark::cmpr(mark **a, mark **b)
+{
+  mark *ap = *(mark **)a,  *bp = *(mark **)b;
+  return ap->pts > bp->pts ? 1 : ap->pts < bp->pts ? -1 : 0;
+}
+
+class _program {
+public:
+  int pmt_pid, pcr_pid, ep_pid;
+  int64_t start_time, end_time;
+  int64_t duration;
+  _program() {
+    memset(this, 0, sizeof(*this));
+    start_time = INT64_MAX; end_time = INT64_MIN;
+  }
+  ~_program() {}
+};
+
+class program : public _program {
+public:
+  int idx;
+  uint16_t pid;
+  ArrayList<int> strm_idx;
+  ArrayList<mark*> marks;
+  int64_t curr_pos;
+  int build_toc(clpi_ep_map_entry *map);
+  void add_label(uint32_t pk, int64_t p, int64_t ts, int id) {
+    marks.append(new mark(curr_pos, p, ts, pk, id));
+  }
+
+  program(int i, int id) { idx = i;  pid = id;  curr_pos = 0; }
+  ~program() { marks.remove_all_objects(); }
+};
+
+class _media_info {
+public:
+  int bit_rate;
+  int64_t file_size;
+
+  _media_info() {
+    memset(this, 0, sizeof(*this));
+  }
+  ~_media_info() {}
+};
+
+class media_info : public _media_info {
+public:
+  static const AVRational clk45k;
+  char filename[BCTEXTLEN];
+  int pgm_pid;
+  int brk, pidx, still;
+  ArrayList<stream *> streams;
+  ArrayList<program *> programs;
+  program *prog()  { return programs[pidx]; }
+
+  media_info(const char *fn) {
+    strcpy(filename, fn);
+    brk = 0;  pidx = 0;  pgm_pid = -1;  still = 0;
+  }
+  ~media_info() { streams.remove_all_objects(); }
+
+  int scan();
+  int scan(AVFormatContext *fmt_ctx);
+};
+
+class Media : public ArrayList<media_info *> {
+public:
+  char *path;
+  char filename[BCTEXTLEN];
+  int bd_path(const char *bp, const char *fmt, va_list ap);
+  int bd_open(const char *fmt, ...);
+  int bd_backup(const char *fmt, ...);
+  int bd_copy(const char *ifn, const char *fmt, ...);
+
+  index_file idx;
+  movie_file mov;
+  ArrayList<clpi_cl *> cl;
+  ArrayList<mpls_pl *> pl;
+
+  int compose();
+  int write(char *fn);
+
+  Media() { path = 0;  filename[0] = 0; }
+  ~Media() {
+    remove_all_objects();
+    cl.remove_all_objects();
+    pl.remove_all_objects();
+  }
+};
+
+#endif
+
+void bs_file::init()
+{
+  fp = 0;
+  reg = len = 0;
+  fpos = fsz = 0;
+}
+
+int
+bs_file::open(const char *fn)
+{
+  fp = fopen(fn,"w");
+  if( !fp ) perror(fn);
+  return fp != 0 ? 0 : 1;
+}
+
+void
+bs_file::close()
+{
+  if( fp ) { fclose(fp); fp = 0; }
+}
+
+void
+bs_file::write(uint32_t v, int n)
+{
+  uint64_t vv = reg;
+  vv <<= n;  vv |= v;
+  reg = vv;  len += n;
+  while( len >= 8 ) {
+    len -= 8;
+    if( fp ) fputc((vv >> len), fp);
+    if( ++fpos > fsz ) fsz = fpos;
+  }
+}
+
+void
+bs_file::writeb(uint8_t * bp, int n)
+{
+  while( --n >= 0 ) write(*bp++, 8);
+}
+
+void
+bs_file::pad(int n)
+{
+  while( n > 32 ) { write(0, 32);  n -= 32; }
+  if( n > 0 ) write(0, n);
+}
+
+void
+bs_file::posb(int64_t n)
+{
+  if( fpos == fsz && n > fpos ) {
+    padb(n-fpos);
+    return;
+  }
+  fpos = n;
+  if( fp ) fseek(fp, fpos, SEEK_SET);
+}
+
+static bs_file bs;
+
+
+int
+movie_file::write()
+{
+  // output header
+  bs.writeb("MOBJ", 4);
+  bs.writeb(sig == 1 ? "0100" : "0200", 4);
+  int movie_start = 0x0028;
+  bs.posb(movie_start);
+  bs_len(bs, 32);
+  bs.write(0, 32);
+  bs.write(movies.size(), 16);
+
+  for (int i = 0; i < movies.size(); ++i) {
+    movie_obj *mov = movies[i];
+    bs.write(mov->resume_intention_flag, 1);
+    bs.write(mov->menu_call_mask, 1);
+    bs.write(mov->title_search_mask, 1);
+    bs.write(0, 13);
+    ArrayList<command_obj *> &cmds = mov->cmds;
+    int num_cmds = cmds.size();
+    bs.write(num_cmds, 16);
+    for (int j = 0; j < num_cmds; ++j) {
+      command_obj *cmd = cmds[j];
+      bs.write(cmd->op_cnt, 3);
+      bs.write(cmd->grp, 2);
+      bs.write(cmd->sub_grp, 3);
+      bs.write(cmd->imm_op1, 1);
+      bs.write(cmd->imm_op2, 1);
+      bs.write(0, 2);
+      bs.write(cmd->branch_opt, 4);
+      bs.write(0, 4);
+      bs.write(cmd->cmp_opt, 4);
+      bs.write(0, 3);
+      bs.write(cmd->set_opt, 5);
+      //bs.write(cmd->cmd, 32);
+      bs.write(cmd->dst, 32);
+      bs.write(cmd->src, 32);
+    }
+  }
+//in sony AVCHD
+//  bs.write('l', 8);
+//  bs.writebcd(year, 16);
+//  bs.writebcd(month, 8);
+//  bs.writebcd(day, 8);
+//  bs.writebcd(hour, 8);
+//  bs.writebcd(min, 8);
+//  bs.writebcd(sec, 8);
+  bs_end(bs);
+  return 0;
+}
+
+void
+pb_obj::set_hdmv(int id, int pt)
+{
+  obj_typ = obj_hdmv;
+  pb_typ = pt;
+  delete [] bdj_name;
+  bdj_name = 0;
+  hdmv_id = id;
+}
+
+void
+pb_obj::set_bdj(char *nm, int pt)
+{
+  obj_typ = obj_bdj;
+  pb_typ = pt;
+  delete [] bdj_name;
+  bdj_name = 0;
+  bdj_name = cstrdup(nm);
+}
+
+void 
+pb_obj::write_hdmv_obj(int id_ref)
+{
+  bs.write(pb_typ, 2);
+  bs.write(0, 14);
+  bs.write(id_ref, 16);
+  bs.write(0, 32);
+}
+
+void
+pb_obj::write_bdj_obj(char *name)
+{
+  bs.write(pb_typ, 2);
+  bs.write(0, 14);
+  bs.writeb(name, 5);
+  bs.write(0, 8);
+}
+
+void
+pb_obj::write_obj()
+{
+  switch (obj_typ) {
+  case obj_bdj:
+    write_bdj_obj(bdj_name);
+    break;
+  case obj_hdmv:
+  default:
+    write_hdmv_obj(hdmv_id);
+    break;
+  }
+}
+
+void
+title_obj::write_obj()
+{
+  bs.write(obj_typ, 2);
+  bs.write(acc_typ, 2);
+  bs.write(0, 28);
+  pb_obj::write_obj();
+}
+
+
+void
+index_file::write_pb_obj(pb_obj * pb)
+{
+  bs.write(pb->obj_typ, 2);
+  bs.write(0, 30);
+  pb->write_obj();
+}
+
+int
+index_file::write()
+{
+  // output header
+  bs.writeb("INDX", 4);
+  bs.writeb(sig == 1 ? "0100" : "0200", 4);
+  bs_ofs(bs, 32);
+  exten.bs_ofs(bs, 32);
+  int appinfo_start = 0x28;
+  bs.posb(appinfo_start);
+  appinf.bs_len(bs, 32);
+  bs.write(1, 1);
+  bs.write(initial_output_mode_preference, 1);
+  bs.write(content_exist_flag, 1);
+  bs.write(0, 5);
+  bs.write(video_format, 4);
+  bs.write(frame_rate, 4);
+  bs.writeb(user_data, 32);
+  appinf.bs_end(bs);
+
+  // output index
+  bs_len(bs, 32);
+  write_pb_obj(&first_play);
+  write_pb_obj(&top_menu);
+  bs.write(titles.size(), 16);
+
+  for (int i = 0; i < titles.size(); ++i)
+    titles[i]->write_obj();
+  bs_end(bs);
+  exten.bs_len(bs,32);
+  exten.bs_end(bs);
+  return 0;
+}
+
+
+
+int
+bdid::write()
+{
+  bs.writeb("BDID",4);
+  bs.writeb(sig == 1 ? "0100" : "0200", 4);
+  bs.write(data_start, 32);
+  bs.write(extension_data_start, 32);
+  bs.posb(40 - 16);
+  bs.writeb(org_id, sizeof(org_id));
+  bs.writeb(disc_id, sizeof(disc_id));
+  return 0;
+}
+
+// XXX - not current referenced
+#if 0
+int
+bdmv_write_extension_data(int start_address,
+       int (*handler) (int, int, void *), void *handle)
+{
+  int64_t length;
+  int num_entries, n;
+
+  bs.write(length, 32);   /* length of extension data block */
+  if( length < 1 )
+    return 1;
+
+  bs.pad(32);             /* relative start address of extension data */
+  bs.pad(24);             /* padding */
+  bs.write(num_entries, 8);
+
+  for (n = 0; n < num_entries; n++) {
+    bs.write(id1, 16);
+    bs.write(id2, 16);
+    bs.write(ext_start, 32);
+    bs.write(ext_len, 32);
+    saved_pos = bs.pos() >> 3;
+    bs.posb(start_address + ext_start);
+    handler(id1, id2, handle);
+    bs.posb(saved_pos);
+  }
+
+  return 0;
+}
+#endif
+
+int
+clpi_prog_stream::write()
+{
+  bs.write(pid, 16);
+  bs_len(bs, 8);
+
+  bs.write(coding_type, 8);
+  switch (coding_type) {
+  case BLURAY_STREAM_TYPE_VIDEO_MPEG1:
+  case BLURAY_STREAM_TYPE_VIDEO_MPEG2:
+  case BLURAY_STREAM_TYPE_VIDEO_VC1:
+  case BLURAY_STREAM_TYPE_VIDEO_H264:
+  case 0x20:
+    bs.write(format, 4);
+    bs.write(rate, 4);
+    bs.write(aspect, 4);
+    bs.pad(2);
+    bs.write(oc_flag, 1);
+    bs.pad(1);
+    break;
+
+  case BLURAY_STREAM_TYPE_AUDIO_MPEG1:
+  case BLURAY_STREAM_TYPE_AUDIO_MPEG2:
+  case BLURAY_STREAM_TYPE_AUDIO_LPCM:
+  case BLURAY_STREAM_TYPE_AUDIO_AC3:
+  case BLURAY_STREAM_TYPE_AUDIO_DTS:
+  case BLURAY_STREAM_TYPE_AUDIO_TRUHD:
+  case BLURAY_STREAM_TYPE_AUDIO_AC3PLUS:
+  case BLURAY_STREAM_TYPE_AUDIO_DTSHD:
+  case BLURAY_STREAM_TYPE_AUDIO_DTSHD_MASTER:
+  case BLURAY_STREAM_TYPE_AUDIO_AC3PLUS_SECONDARY:
+  case BLURAY_STREAM_TYPE_AUDIO_DTSHD_SECONDARY:
+    bs.write(format, 4);
+    bs.write(rate, 4);
+    bs.writeb(lang, 3);
+    break;
+
+  case BLURAY_STREAM_TYPE_SUB_PG:
+  case BLURAY_STREAM_TYPE_SUB_IG:
+  case 0xa0:
+    bs.writeb(lang, 3);
+    break;
+
+  case BLURAY_STREAM_TYPE_SUB_TEXT:
+    bs.write(char_code, 8);
+    bs.writeb(lang, 3);
+    break;
+
+  default:
+    fprintf(stderr, "clpi_prog_stream: unrecognized coding type %02x\n",
+            coding_type);
+    return 1;
+  };
+
+  bs_end(bs);
+  return 0;
+}
+
+int
+clpi_cl::write_header()
+{
+  bs.writeb("HDMV", 4);
+  bs.writeb(sig == 1 ? "0100" : "0200", 4);
+  bs.write(sequence_info_start_addr, 32);
+  bs.write(program_info_start_addr, 32);
+  bs.write(cpi_start_addr, 32);
+  bs.write(clip_mark_start_addr, 32);
+  bs.write(ext_data_start_addr, 32);
+  return 0;
+}
+
+int
+clpi_atc_delta::write()
+{
+  bs.write(delta, 32);
+  bs.writeb(file_id, 5);
+  bs.writeb(file_code, 4);
+  bs.pad(8);
+  return 0;
+}
+
+int
+clpi_clip_info::write()
+{
+  bs.posb(40);
+  bs_len(bs, 32);
+
+  bs.pad(16);                   // reserved
+  bs.write(clip_stream_type, 8);
+  bs.write(application_type, 8);
+  bs.pad(31);                   // skip reserved 31 bits
+  bs.write(is_atc_delta, 1);
+  bs.write(ts_recording_rate, 32);
+  bs.write(num_source_packets, 32);
+
+  bs.padb(128);                 // Skip reserved 128 bytes
+
+  // ts type info block
+  int ts_len = 30;
+  bs.write(ts_len, 16);
+  int64_t pos = bs.posb();
+  if( ts_len ) {
+    bs.write(ts_type_info.validity, 8);
+    bs.writeb(ts_type_info.format_id, 4);
+    // pad the stuff we don't know anything about
+    bs.padb(ts_len - (bs.posb() - pos));
+  }
+
+  if( is_atc_delta ) {
+    bs.pad(8);                  // Skip reserved byte
+    bs.write(atc_delta.size(), 8);
+    for( int ii=0; ii < atc_delta.size(); ++ii )
+      if( atc_delta[ii]->write() ) return 1;
+  }
+
+  // font info
+  if( application_type == 6 /* Sub TS for a sub-path of Text subtitle */  ) {
+    bs.pad(8);
+    bs.write(font_info.font.size(), 8);
+    if( font_info.font.size() ) {
+      for( int ii=0; ii < font_info.font.size(); ++ii ) {
+        bs.writeb(font_info.font[ii]->file_id, 5);
+        bs.pad(8);
+      }
+    }
+  }
+
+  bs_end(bs);
+  return 0;
+}
+
+int
+clpi_stc_seq::write()
+{
+  bs.write(pcr_pid, 16);
+  bs.write(spn_stc_start, 32);
+  bs.write(presentation_start_time, 32);
+  bs.write(presentation_end_time, 32);
+  return 0;
+}
+
+int
+clpi_atc_seq::write()
+{
+  bs.write(spn_atc_start, 32);
+  bs.write(stc_seq.size(), 8);
+  bs.write(offset_stc_id, 8);
+
+  for( int ii=0; ii < stc_seq.size(); ++ii )
+    if( stc_seq[ii]->write() ) return 1;
+  return 0;
+}
+
+int
+clpi_sequences::write()
+{
+  bs_len(bs, 32);
+  bs.padb(1);                   // reserved byte
+  bs.write(size(), 8);
+  for( int ii=0; ii < size(); ++ii )
+    if( get(ii)->write() ) return 1;
+  bs_end(bs);
+  return 0;
+}
+
+int
+clpi_prog::write()
+{
+  bs.write(spn_program_sequence_start, 32);
+  bs.write(program_map_pid, 16);
+  bs.write(streams.size(), 8);
+  bs.write(num_groups, 8);
+  for( int ii=0; ii < streams.size(); ++ii )
+    if( streams[ii]->write() ) return 1;
+  return 0;
+}
+
+int
+clpi_programs::write()
+{
+  bs_len(bs, 32);
+  bs.padb(1);                   // reserved byte
+  bs.write(size(), 8);
+  for( int ii=0; ii < size(); ++ii )
+    if( get(ii)->write() ) return 1;
+  bs_end(bs);
+  return 0;
+}
+
+int
+clpi_ep_coarse::write()
+{
+  bs.write(ref_ep_fine_id, 18);
+  bs.write(pts_ep, 14);
+  bs.write(spn_ep, 32);
+  return 0;
+}
+
+int
+clpi_ep_fine::write()
+{
+  bs.write(is_angle_change_point, 1);
+  bs.write(i_end_position_offset, 3);
+  bs.write(pts_ep, 11);
+  bs.write(spn_ep, 17);
+  return 0;
+}
+
+int
+clpi_ep_map_entry::write(uint32_t ep_map_pos)
+{
+  bs.write(pid, 16);
+  bs.pad(10);
+  bs.write(ep_stream_type, 4);
+  bs.write(coarse.size(), 16);
+  bs.write(fine.size(), 18);
+  bs.write(ep_map_stream_start_addr - ep_map_pos, 32);
+  return 0;
+}
+
+int
+clpi_ep_map_entry::write_map()
+{
+  ep_map_stream_start_addr = bs.posb();
+  bs.write(fine_start, 32);
+
+  for( int ii=0; ii < coarse.size(); ++ii )
+    if( coarse[ii]->write() ) return 1;
+
+  fine_start = bs.posb() - ep_map_stream_start_addr;
+  for( int ii=0; ii < fine.size(); ++ii )
+    if( fine[ii]->write() ) return 1;
+
+  return 0;
+}
+
+int
+clpi_cpi::write()
+{
+  bs_len(bs, 32);
+  bs.pad(12);
+  bs.write(type, 4);
+  uint32_t ep_map_pos = bs.posb();
+
+  // EP Map starts here
+  bs.pad(8);
+  bs.write(size(), 8);
+
+  for( int ii=0; ii < size(); ++ii )
+    if( get(ii)->write(ep_map_pos) ) return 1;
+
+  for( int ii=0; ii < size(); ++ii )
+    if( get(ii)->write_map() ) return 1;
+
+  bs_end(bs);
+  return 0;
+}
+
+int
+clpi_extents::write()
+{
+  bs_len(bs, 32);
+  bs.write(size(), 32);
+  for( int ii=0; ii < size(); ++ii )
+    bs.write(get(ii), 32);
+  return 0;
+}
+
+int
+clpi_cl::write_clpi_extension(int id1, int id2, void *handle)
+{
+  clpi_cl *cl = (clpi_cl *) handle;
+
+  if( id1 == 1 ) {
+    if( id2 == 2 ) {
+      // LPCM down mix coefficient
+      //write_lpcm_down_mix_coeff(&cl->lpcm_down_mix_coeff);
+      return 0;
+    }
+  }
+
+  if( id1 == 2 ) {
+    if( id2 == 4 ) {
+      // Extent start point
+      return cl->extents.write();
+    }
+    if( id2 == 5 ) {
+      // ProgramInfo SS
+      return cl->programs_ss.write();
+    }
+    if( id2 == 6 ) {
+      // CPI SS
+      return cl->cpi_ss.write();
+    }
+  }
+
+  fprintf(stderr, "write_clpi_extension(): unhandled extension %d.%d\n", id1, id2);
+  return 1;
+}
+
+int
+clpi_cl::write()
+{
+  if( write_header() ) return 1;
+  if( clip.write() ) return 1;
+  sequence_info_start_addr = bs.posb();
+  if( sequences.write() ) return 1;
+  program_info_start_addr = bs.posb();
+  if( programs.write() ) return 1;
+  cpi_start_addr = bs.posb();
+  if( cpi.write() ) return 1;
+//if( has_ext_data ) {
+//  ext_data_start_addr = bs.pos();
+//  bdmv_write_extension_data(write_clpi_extension, this);
+//}
+  return 0;
+}
+
+int
+bd_uo_mask::write()
+{
+  bs.write(menu_call, 1);
+  bs.write(title_search, 1);
+  bs.write(chapter_search, 1);
+  bs.write(time_search, 1);
+  bs.write(skip_to_next_point, 1);
+  bs.write(skip_to_prev_point, 1);
+  bs.write(play_firstplay, 1);
+  bs.write(stop, 1);
+  bs.write(pause_on, 1);
+  bs.write(pause_off, 1);
+  bs.write(still_off, 1);
+  bs.write(forward, 1);
+  bs.write(backward, 1);
+  bs.write(resume, 1);
+  bs.write(move_up, 1);
+  bs.write(move_down, 1);
+  bs.write(move_left, 1);
+  bs.write(move_right, 1);
+  bs.write(select, 1);
+  bs.write(activate, 1);
+  bs.write(select_and_activate, 1);
+  bs.write(primary_audio_change, 1);
+  bs.pad(1);
+  bs.write(angle_change, 1);
+  bs.write(popup_on, 1);
+  bs.write(popup_off, 1);
+  bs.write(pg_enable_disable, 1);
+  bs.write(pg_change, 1);
+  bs.write(secondary_video_enable_disable, 1);
+  bs.write(secondary_video_change, 1);
+  bs.write(secondary_audio_enable_disable, 1);
+  bs.write(secondary_audio_change, 1);
+  bs.pad(1);
+  bs.write(pip_pg_change, 1);
+  bs.pad(30);
+  return 0;
+}
+
+int
+mpls_ai::write()
+{
+  bs_len(bs, 32);
+  bs.pad(8);              // Reserved
+  bs.write(playback_type, 8);
+  if (playback_type == BLURAY_PLAYBACK_TYPE_RANDOM ||
+      playback_type == BLURAY_PLAYBACK_TYPE_SHUFFLE ) {
+    bs.write(playback_count, 16);
+  }
+  else {
+    bs.pad(16);           // Reserved
+  }
+  uo_mask.write();
+  bs.write(random_access_flag, 1);
+  bs.write(audio_mix_flag, 1);
+  bs.write(lossless_bypass_flag, 1);
+  bs.pad(13);             // Reserved
+  bs_end(bs);
+  return 0;
+}
+
+int
+mpls_pl::write_header()
+{
+  bs.writeb("MPLS", 4);
+  bs.writeb(sig == 1 ? "0100" : "0200", 4);
+  bs.write(list_pos, 32);
+  bs.write(mark_pos, 32);
+  bs.write(ext_pos, 32);
+  bs.pad(160);            // Skip 160 reserved bits
+  app_info.write();
+  return 0;
+}
+
+int mpls_stream::
+write()
+{
+  strm.bs_len(bs, 8);
+
+  bs.write(stream_type, 8);
+  switch (stream_type) {
+  case 0x01:
+    bs.write(pid, 16);
+    break;
+
+  case 0x02:
+  case 0x04:
+    bs.write(subpath_id, 8);
+    bs.write(subclip_id, 8);
+    bs.write(pid, 16);
+    break;
+
+  case 0x03:
+    bs.write(subpath_id, 8);
+    bs.write(pid, 16);
+    break;
+
+  default:
+    fprintf(stderr, "unrecognized stream type %02x\n", stream_type);
+    break;
+  };
+  strm.bs_end(bs);
+
+  code.bs_len(bs, 8);
+  bs.write(coding_type, 8);
+  switch (coding_type) {
+  case BLURAY_STREAM_TYPE_VIDEO_MPEG1:
+  case BLURAY_STREAM_TYPE_VIDEO_MPEG2:
+  case BLURAY_STREAM_TYPE_VIDEO_VC1:
+  case BLURAY_STREAM_TYPE_VIDEO_H264:
+    bs.write(format, 4);
+    bs.write(rate, 4);
+    break;
+
+  case BLURAY_STREAM_TYPE_AUDIO_MPEG1:
+  case BLURAY_STREAM_TYPE_AUDIO_MPEG2:
+  case BLURAY_STREAM_TYPE_AUDIO_LPCM:
+  case BLURAY_STREAM_TYPE_AUDIO_AC3:
+  case BLURAY_STREAM_TYPE_AUDIO_DTS:
+  case BLURAY_STREAM_TYPE_AUDIO_TRUHD:
+  case BLURAY_STREAM_TYPE_AUDIO_AC3PLUS:
+  case BLURAY_STREAM_TYPE_AUDIO_DTSHD:
+  case BLURAY_STREAM_TYPE_AUDIO_DTSHD_MASTER:
+  case BLURAY_STREAM_TYPE_AUDIO_AC3PLUS_SECONDARY:
+  case BLURAY_STREAM_TYPE_AUDIO_DTSHD_SECONDARY:
+    bs.write(format, 4);
+    bs.write(rate, 4);
+    bs.writeb(lang, 3);
+    break;
+
+  case BLURAY_STREAM_TYPE_SUB_PG:
+  case BLURAY_STREAM_TYPE_SUB_IG:
+    bs.writeb(lang, 3);
+    break;
+
+  case BLURAY_STREAM_TYPE_SUB_TEXT:
+    bs.write(char_code, 8);
+    bs.writeb(lang, 3);
+    break;
+
+  default:
+    fprintf(stderr, "mpls_stream: unrecognized coding type %02x\n", coding_type);
+    break;
+  };
+  code.bs_end(bs);
+  return 0;
+}
+
+int
+mpls_stn::write()
+{
+  bs_len(bs, 16);
+  bs.pad(16);             // Skip 2 reserved bytes
+
+  bs.write(video.size(), 8);
+  bs.write(audio.size(), 8);
+  bs.write(pg.size() - num_pip_pg, 8);
+  bs.write(ig.size(), 8);
+  bs.write(secondary_audio.size(), 8);
+  bs.write(secondary_video.size(), 8);
+  bs.write(num_pip_pg, 8);
+
+  // 5 reserve bytes
+  bs.pad(5 * 8);
+
+  // Primary Video Streams
+  for( int ii=0; ii < video.size(); ++ii )
+    if( video[ii]->write() ) return 1;
+
+  // Primary Audio Streams
+  for( int ii=0; ii < audio.size(); ++ii )
+    if( audio[ii]->write() ) return 1;
+
+  // Presentation Graphic Streams
+  for( int ii=0; ii < pg.size(); ++ii )
+    if( pg[ii]->write() ) return 1;
+
+  // Interactive Graphic Streams
+  for( int ii=0; ii < ig.size(); ++ii )
+    if( ig[ii]->write() ) return 1;
+
+  // Secondary Audio Streams
+  for( int ii=0; ii < secondary_audio.size(); ++ii ) {
+    if( secondary_audio[ii]->write() ) return 1;
+    // Read Secondary Audio Extra Attributes
+    bs.write(sa_primary_audio_ref.size(), 8);
+    bs.pad(8);
+    for( int jj=0; jj < sa_primary_audio_ref.size(); ++jj )
+      bs.write(sa_primary_audio_ref[jj], 8);
+    if( sa_primary_audio_ref.size() % 2) bs.pad(8 );
+  }
+
+  // Secondary Video Streams
+  for( int ii=0; ii < secondary_video.size(); ++ii ) {
+    if( secondary_video[ii]->write() ) return 1;
+    // Read Secondary Video Extra Attributes
+    bs.write(sv_secondary_audio_ref.size(), 8);
+    bs.pad(8);
+    for( int jj=0; jj < sv_secondary_audio_ref.size(); ++jj )
+      bs.write(sv_secondary_audio_ref[jj], 8);
+    if( sv_secondary_audio_ref.size() % 2) bs.pad(8 );
+    bs.write(sv_pip_pg_ref.size(), 8);
+    bs.pad(8);
+    for( int jj=0; jj < sv_pip_pg_ref.size(); ++jj )
+      bs.write(sv_pip_pg_ref[jj], 8);
+    if( sv_pip_pg_ref.size() % 2) bs.pad(8 );
+  }
+
+  bs_end(bs);
+  return 0;
+}
+
+int
+mpls_pi::write()
+{
+  bs_len(bs, 16);
+  // Primary Clip identifer
+  bs.writeb(clip[0]->clip_id, 5);
+  bs.writeb(clip[0]->codec_id, 4); // "M2TS"
+  bs.pad(11); // Skip reserved 11 bits
+
+  bs.write(is_multi_angle, 1);
+  bs.write(connection_condition, 4);  // 0x01, 0x05, 0x06
+
+  bs.write(clip[0]->stc_id, 8);
+  bs.write(in_time, 32);
+  bs.write(out_time, 32);
+
+  uo_mask.write();
+  bs.write(random_access_flag, 1);
+  bs.pad(7);
+  bs.write(still_mode, 8);
+  if( still_mode == 0x01 ) {
+    bs.write(still_time, 16);
+  }
+  else {
+    bs.pad(16);
+  }
+
+  if( is_multi_angle ) {
+    bs.write(clip.size(), 8);
+    bs.pad(6);
+    bs.write(is_different_audio, 1);
+    bs.write(is_seamless_angle, 1);
+  }
+
+  for( int ii=1; ii < clip.size(); ++ii ) {
+    bs.writeb(clip[ii]->clip_id, 5);
+    bs.writeb(clip[ii]->codec_id, 4); // "M2TS"
+    bs.write(clip[ii]->stc_id, 8);
+  }
+
+  if( stn.write() ) return 1;
+
+  bs_end(bs);
+  return 0;
+}
+
+int
+mpls_sub_pi::write()
+{
+  bs_len(bs, 16);
+  // Primary Clip identifer
+  bs.writeb(clip[0]->clip_id, 5);
+  bs.writeb(clip[0]->codec_id, 4); // "M2TS"
+  bs.pad(27);
+
+  bs.write(connection_condition, 4); // 0x01, 0x05, 0x06
+
+  bs.write(is_multi_clip, 1);
+  bs.write(clip[0]->stc_id, 8);
+  bs.write(in_time, 32);
+  bs.write(out_time, 32);
+  bs.write(sync_play_item_id, 16);
+  bs.write(sync_pts, 32);
+
+  if( is_multi_clip )
+    bs.write(clip.size(), 8);
+
+  for( int ii=1; ii < clip.size(); ++ii ) {
+    // Primary Clip identifer
+    bs.writeb(clip[ii]->clip_id, 5);
+    bs.writeb(clip[ii]->codec_id, 4); // "M2TS"
+    bs.write(clip[ii]->stc_id, 8);
+  }
+
+  bs_end(bs);
+  return 0;
+}
+
+int
+mpls_sub::write()
+{
+  bs_len(bs, 32);
+  bs.pad(8);
+  bs.write(type, 8);
+  bs.pad(15);
+  bs.write(is_repeat, 1);
+  bs.pad(8);
+  bs.write(sub_play_item.size(), 8);
+
+  for( int ii=0; ii < sub_play_item.size(); ++ii )
+    if( sub_play_item[ii]->write() ) return 1;
+
+  bs_end(bs);
+  return 0;
+}
+
+int
+mpls_plm::write()
+{
+  bs.write(mark_id, 8);
+  bs.write(mark_type, 8);
+  bs.write(play_item_ref, 16);
+  bs.write(time, 32);
+  bs.write(entry_es_pid, 16);
+  bs.write(duration, 32);
+  return 0;
+}
+
+int
+mpls_pl::write_playlistmark()
+{
+  mark.bs_len(bs, 32);
+  // Then get the number of marks
+  bs.write(play_mark.size(), 16);
+
+  for( int ii=0; ii < play_mark.size(); ++ii )
+    if( play_mark[ii]->write() ) return 1;
+
+  mark.bs_end(bs);
+  return 0;
+}
+
+int
+mpls_pl::write_playlist()
+{
+  play.bs_len(bs,32);
+
+  // Skip reserved bytes
+  bs.pad(16);
+
+  bs.write(play_item.size(), 16);
+  bs.write(sub_path.size(), 16);
+
+  for( int ii=0; ii < play_item.size(); ++ii )
+    if( play_item[ii]->write() ) return 1;
+
+  for( int ii=0; ii < sub_path.size(); ++ii )
+    if( sub_path[ii]->write() ) return 1;
+
+  play.bs_end(bs);
+  return 0;
+}
+
+int
+mpls_pip_data::write()
+{
+  bs.write(time, 32);
+  bs.write(xpos, 12);
+  bs.write(ypos, 12);
+  bs.write(scale_factor, 4);
+  bs.pad(4);
+  return 0;
+}
+
+int
+mpls_pip_metadata::write(uint32_t start_address)
+{
+
+  bs.write(clip_ref, 16);
+  bs.write(secondary_video_ref, 8);
+  bs.pad(8);
+  bs.write(timeline_type, 4);
+  bs.write(luma_key_flag, 1);
+  bs.write(trick_play_flag, 1);
+  bs.pad(10);
+  if( luma_key_flag ) {
+    bs.pad(8);
+    bs.write(upper_limit_luma_key, 8);
+  }
+  else {
+    bs.pad(16);
+  }
+  bs.pad(16);
+
+  uint32_t data_address = 0;  // XXX
+  bs.write(data_address, 32);
+
+  int64_t pos = bs.pos() / 8;
+  bs.posb(start_address + data_address);
+
+  bs.write(data.size(), 16);
+  if( data.size() < 1 ) return 1;
+
+  for( int ii=0; ii < data.size(); ++ii )
+    if( data[ii]->write() ) return 1;
+
+  bs.posb(pos);
+  return 0;
+}
+
+int
+mpls_pl::write_pip_metadata_extension()
+{
+  uint32_t pos = bs.posb();
+  pipm.bs_len(bs, 32);
+
+  bs.write(ext_pip_data.size(), 16);
+  for( int ii=0; ii < ext_pip_data.size(); ++ii )
+    if( ext_pip_data[ii]->write(pos) ) return 1;
+
+  pipm.bs_end(bs);
+  return 0;
+}
+
+int
+mpls_pl::write_subpath_extension()
+{
+  subx.bs_len(bs, 32);
+
+  bs.write(ext_sub_path.size(), 16);
+  for( int ii=0; ii < ext_sub_path.size(); ++ii )
+    if( ext_sub_path[ii]->write() ) return 1;
+
+  subx.bs_end(bs);
+  return 0;
+}
+
+int
+clpi_cl::write_mpls_extension(int id1, int id2, void *handle)
+{
+  mpls_pl *pl = (mpls_pl *) handle;
+
+  if( id1 == 1 ) {
+    if( id2 == 1 ) {
+      // PiP metadata extension
+      return pl->write_pip_metadata_extension();
+    }
+  }
+
+  if( id1 == 2 ) {
+    if( id2 == 1 ) {
+      return 0;
+    }
+    if( id2 == 2 ) {
+      // SubPath entries extension
+      return pl->write_subpath_extension();
+    }
+  }
+
+  return 0;
+}
+
+int mpls_pl::
+write()
+{
+  int ret = write_header();
+  list_pos = bs.posb();;
+  if( !ret ) ret = write_playlist();
+  mark_pos = bs.posb();
+  if( !ret ) ret = write_playlistmark();
+//if( has_pls_extension ) {
+//  ext_pos = bs.posb();
+//  bdmv_write_extension_data(write_mpls_extension, pl);
+  return ret;
+}
+
+static int
+mk_dir(char *path)
+{
+  if( !mkdir(path, 0777) )
+    return 0;
+  perror(path);
+  return 1;
+}
+
+static int
+mk_bdmv_dir(char *bdmv_path)
+{
+  if( mk_dir(bdmv_path) )
+    return 1;
+  char bdjo_path[BCTEXTLEN];
+  sprintf(bdjo_path, "%s/BDJO", bdmv_path);
+  if( mk_dir(bdjo_path) )
+    return 1;
+  char clipinf_path[BCTEXTLEN];
+  sprintf(clipinf_path, "%s/CLIPINF", bdmv_path);
+  if( mk_dir(clipinf_path) )
+    return 1;
+  char jar_path[BCTEXTLEN];
+  sprintf(jar_path, "%s/JAR", bdmv_path);
+  if( mk_dir(jar_path) )
+    return 1;
+  char playlist_path[BCTEXTLEN];
+  sprintf(playlist_path, "%s/PLAYLIST", bdmv_path);
+  if( mk_dir(playlist_path) )
+    return 1;
+  return 0;
+}
+
+static int
+mkbdmv(char *path)
+{
+  char bdmv_path[BCTEXTLEN];
+  sprintf(bdmv_path, "%s/BDMV", path);
+  if( mk_bdmv_dir(bdmv_path) ) return 1;
+  char stream_path[BCTEXTLEN];
+  sprintf(stream_path, "%s/BDMV/STREAM", path);
+  if( mk_dir(stream_path) ) return 1;
+  char auxdata_path[BCTEXTLEN];
+  sprintf(auxdata_path, "%s/BDMV/AUXDATA", path);
+  if( mk_dir(auxdata_path) ) return 1;
+  char meta_path[BCTEXTLEN];
+  sprintf(meta_path, "%s/BDMV/META", path);
+  if( mk_dir(meta_path) ) return 1;
+  char backup_path[BCTEXTLEN];
+  sprintf(backup_path, "%s/BACKUP", bdmv_path);
+  if( mk_bdmv_dir(backup_path) ) return 1;
+  return 0;
+}
+
+int program::
+build_toc(clpi_ep_map_entry *map)
+{
+  clpi_ep_coarse *cp = 0;
+  marks.sort(mark::cmpr);
+  uint16_t ep_pid = map->pid;
+  int64_t last_pts = -1, last_pkt = -1;
+  for( int ii=0; ii<marks.size(); ++ii ) {
+    mark *mp = marks[ii];
+    if( mp->pid != ep_pid ) continue;
+    int64_t pts = mp->pts;
+    if( last_pts >= pts ) continue;
+    last_pts = pts;
+    uint32_t pkt = mp->pos / BLURAY_TS_PKTSZ;
+    if( last_pkt >= pkt ) continue;
+    last_pkt = pkt;
+    int64_t coarse_pts = (pts >> 18) & ~0x01;
+    int64_t fine_pts = (pts & 0x7ffff) >> 8;
+    uint32_t mpkt = pkt & ~0x1ffff;
+    if( !cp || cp->pts_ep != coarse_pts || cp->spn_ep != mpkt ) {
+      cp = new clpi_ep_coarse();
+      map->coarse.append(cp);
+      cp->ref_ep_fine_id = map->fine.size();
+      cp->pts_ep = coarse_pts;
+      cp->spn_ep = mpkt;
+    }
+    clpi_ep_fine *fp = new clpi_ep_fine();
+    map->fine.append(fp);
+    fp->is_angle_change_point = 0;
+// XXX - dont know what this is
+    fp->i_end_position_offset = 1;
+    fp->pts_ep = fine_pts;
+    fp->spn_ep = pkt & 0x1ffff;
+  }
+  return 0;
+}
+
+const AVRational media_info::clk45k = { 1, 45000 };
+
+static int bd_stream_type(AVCodecID codec_id)
+{
+  int stream_type = 0;
+  switch (codec_id) {
+  case AV_CODEC_ID_MPEG1VIDEO:
+  case AV_CODEC_ID_MPEG2VIDEO:
+    stream_type = BLURAY_STREAM_TYPE_VIDEO_MPEG2;
+    break;
+  case AV_CODEC_ID_H264:
+    stream_type = BLURAY_STREAM_TYPE_VIDEO_H264;
+    break;
+  case AV_CODEC_ID_MP2:
+  case AV_CODEC_ID_MP3:
+    stream_type = BLURAY_STREAM_TYPE_AUDIO_MPEG1;
+    break;
+  case AV_CODEC_ID_AC3:
+    stream_type = BLURAY_STREAM_TYPE_AUDIO_AC3;
+    break;
+  case AV_CODEC_ID_DTS:
+    stream_type = BLURAY_STREAM_TYPE_AUDIO_DTS;
+    break;
+  case AV_CODEC_ID_TRUEHD:
+    stream_type = BLURAY_STREAM_TYPE_AUDIO_TRUHD;
+    break;
+  default:
+    fprintf(stderr, "unknown bluray stream type %s\n", avcodec_get_name(codec_id));
+    exit(1);
+  }
+  return stream_type;
+}
+
+static int bd_audio_format(int channels)
+{
+  int audio_format = 0;
+  switch( channels ) {
+  case 1:
+    audio_format = BLURAY_AUDIO_FORMAT_MONO;
+    break;
+  case 2:
+    audio_format = BLURAY_AUDIO_FORMAT_STEREO;
+    break;
+  case 6:
+    audio_format = BLURAY_AUDIO_FORMAT_MULTI_CHAN;
+    break;
+  default:
+    fprintf(stderr, "unknown bluray audio format %d ch\n", channels);
+    exit(1);
+  }
+  return audio_format;
+}
+
+static int bd_audio_rate(int rate)
+{
+  int audio_rate = 0;
+  switch( rate ) {
+  case 48000:  audio_rate = BLURAY_AUDIO_RATE_48;  break;
+  case 96000:  audio_rate = BLURAY_AUDIO_RATE_96;  break;
+  case 192000: audio_rate = BLURAY_AUDIO_RATE_192; break;
+  default:
+    fprintf(stderr, "unknown bluray audio rate %d\n", rate);
+    exit(1);
+  }
+  return audio_rate;
+}
+
+static int bd_video_format(int w, int h, int ilace)
+{
+  if( w == 720 && h == 480 && ilace ) return BLURAY_VIDEO_FORMAT_480I;
+  if( w == 720 && h == 576 && ilace ) return BLURAY_VIDEO_FORMAT_576I;
+  if( w == 720 && h == 480 && !ilace ) return BLURAY_VIDEO_FORMAT_480P;
+  if( w == 1920 && h == 1080 && ilace ) return BLURAY_VIDEO_FORMAT_1080I;
+  if( w == 1280 && h == 720 && !ilace ) return BLURAY_VIDEO_FORMAT_720P;
+  if( w == 1920 && h == 1080 && !ilace ) return BLURAY_VIDEO_FORMAT_1080P;
+  if( w == 720 && h == 576 && !ilace ) return BLURAY_VIDEO_FORMAT_576P;
+  fprintf(stderr, "unknown bluray video format %dx%d %silace\n",
+    w, h, !ilace ? "not " : "");
+  exit(1);
+}
+
+static int bd_video_rate(double rate)
+{
+  if( fabs(rate-23.976) < 0.01 ) return BLURAY_VIDEO_RATE_24000_1001;
+  if( fabs(rate-24.000) < 0.01 ) return BLURAY_VIDEO_RATE_24;
+  if( fabs(rate-25.000) < 0.01 ) return BLURAY_VIDEO_RATE_25;
+  if( fabs(rate-29.970) < 0.01 ) return BLURAY_VIDEO_RATE_30000_1001;
+  if( fabs(rate-50.000) < 0.01 ) return BLURAY_VIDEO_RATE_50;
+  if( fabs(rate-59.940) < 0.01 ) return BLURAY_VIDEO_RATE_60000_1001;
+  fprintf(stderr, "unknown bluray video framerate %5.2f\n",rate);
+  exit(1);
+}
+
+static int bd_aspect_ratio(int w, double ratio)
+{
+  if( fabs(ratio-1.333) < 0.01 ) return BLURAY_ASPECT_RATIO_4_3;
+  if( fabs(ratio-1.777) < 0.01 ) return BLURAY_ASPECT_RATIO_16_9;
+  return w == 720 ? BLURAY_ASPECT_RATIO_4_3 : BLURAY_ASPECT_RATIO_16_9; 
+  fprintf(stderr, "unknown bluray aspect ratio %5.3f\n",ratio);
+  exit(1);
+}
+
+int media_info::scan()
+{
+  struct stat st;
+  if( stat(filename, &st) ) return 1;
+  file_size = st.st_size;
+
+  AVFormatContext *fmt_ctx = 0;
+  AVDictionary *fopts = 0;
+  av_dict_set(&fopts, "formatprobesize", "5000000", 0);
+  av_dict_set(&fopts, "scan_all_pmts", "1", 0);
+  av_dict_set(&fopts, "threads", "auto", 0);
+  int ret = avformat_open_input(&fmt_ctx, filename, NULL, &fopts);
+  av_dict_free(&fopts);
+
+  if( ret >= 0 )
+    ret = avformat_find_stream_info(fmt_ctx, NULL);
+
+  if( ret >= 0 ) {
+    bit_rate = fmt_ctx->bit_rate;
+  }
+
+  int ep_pid = -1;
+  for( int i=0; ret>=0 && i<(int)fmt_ctx->nb_streams; ++i ) {
+    AVStream *st = fmt_ctx->streams[i];
+    AVMediaType type = st->codec->codec_type;
+    switch( type ) {
+    case AVMEDIA_TYPE_VIDEO: break;
+    case AVMEDIA_TYPE_AUDIO: break;
+    default: continue;
+    }
+    stream *s = new stream(type, i);
+    s->pid = st->id;
+    AVCodecID codec_id = st->codec->codec_id;
+    switch( type ) {
+    case AVMEDIA_TYPE_VIDEO: {
+      if( ep_pid < 0 ) ep_pid = st->id;
+      s->coding_type = bd_stream_type(codec_id);
+      s->format = bd_video_format(st->codec->width, st->codec->height,
+               st->codec->flags & CODEC_FLAG_INTERLACED_ME);
+      s->rate = bd_video_rate(!st->codec->framerate.den ? 0 :
+               (double)st->codec->framerate.num / st->codec->framerate.den);
+      s->aspect = bd_aspect_ratio(st->codec->width,!st->sample_aspect_ratio.den ? 0 :
+               (double)st->sample_aspect_ratio.num / st->sample_aspect_ratio.den);
+      break; }
+    case AVMEDIA_TYPE_AUDIO: {
+      s->coding_type = bd_stream_type(codec_id);
+      s->format = bd_audio_format(st->codec->channels);
+      s->rate = bd_audio_rate(st->codec->sample_rate);
+      strcpy((char*)s->lang, "und");
+      break; }
+    default:
+      break;
+    }
+    if( bit_rate > 0 && st->duration == AV_NOPTS_VALUE &&
+        st->time_base.num < INT64_MAX / bit_rate ) {
+      st->duration = av_rescale(8*file_size, st->time_base.den,
+          bit_rate * (int64_t) st->time_base.num);
+    }
+    s->duration = av_rescale_q(st->duration, st->time_base, clk45k);
+    streams.append(s);
+
+    AVCodec *decoder = avcodec_find_decoder(codec_id);
+    AVDictionary *copts = 0;
+    ret = avcodec_open2(st->codec, decoder, &copts);
+  }
+  if( ep_pid < 0 )
+    ep_pid = fmt_ctx->nb_streams > 0 ? fmt_ctx->streams[0]->id : 0;
+
+  int npgm = fmt_ctx->nb_programs;
+  if( npgm < 1 ) {
+    program *pgm = new program(-1, 1);
+    pgm->ep_pid = ep_pid;
+    pgm->pmt_pid = 0x1000;
+    pgm->pcr_pid = 0x100;
+    for( int jj=0; jj<streams.size(); ++jj )
+      pgm->strm_idx.append(jj);
+  }
+
+  for( int ii=0; ii<npgm; ++ii ) {
+    AVProgram *pgrm = fmt_ctx->programs[ii];
+    program *pgm = new program(ii, pgrm->id);
+    pgm->pmt_pid = pgrm->pmt_pid;
+    pgm->pcr_pid = pgrm->pcr_pid;
+    pgm->duration = 0;
+    ep_pid = -1;
+    for( int jj=0; jj<(int)pgrm->nb_stream_indexes; ++jj ) {
+      int av_idx = pgrm->stream_index[jj];
+      AVStream *st = fmt_ctx->streams[av_idx];
+      AVMediaType type = st->codec->codec_type;
+      switch( type ) {
+      case AVMEDIA_TYPE_VIDEO:
+        if( ep_pid < 0 ) ep_pid = st->id;
+        break;
+      case AVMEDIA_TYPE_AUDIO:
+        break;
+      default:
+        continue;
+      }
+      int sidx = streams.size();
+      while( --sidx>=0 && streams[sidx]->av_idx!=av_idx );
+      if( sidx < 0 ) {
+        fprintf(stderr, "bad stream idx %d in pgm %d\n",av_idx, ii);
+        continue;
+      }
+      if( pgm->duration < st->duration )
+        pgm->duration = av_rescale_q(st->duration, st->time_base, clk45k);
+      pgm->strm_idx.append(sidx);
+    }
+    if( ep_pid < 0 ) {
+      AVProgram *pgrm = fmt_ctx->programs[0];
+      ep_pid = pgrm->nb_stream_indexes > 0 ?
+          fmt_ctx->streams[pgrm->stream_index[0]]->id : 0;
+    }
+    pgm->ep_pid = ep_pid;
+    programs.append(pgm);
+  }
+
+  if( ret >= 0 )
+    ret = scan(fmt_ctx);
+
+  if( fmt_ctx )
+    avformat_close_input(&fmt_ctx);
+
+  return ret;
+}
+
+int media_info::scan(AVFormatContext *fmt_ctx)
+{
+  int ret = 0;
+  AVPacket ipkt;
+  av_init_packet(&ipkt);
+
+  for( int64_t count=0; ret>=0; ++count ) {
+    av_packet_unref(&ipkt);
+    ipkt.data = 0; ipkt.size = 0;
+
+    ret = av_read_frame(fmt_ctx, &ipkt);
+    if( ret < 0 ) {
+      if( ret == AVERROR_EOF ) break;
+      ret = 0;
+      continue;
+    }
+    if( !ipkt.data ) continue;
+    if( (ipkt.flags & AV_PKT_FLAG_CORRUPT) ) continue;
+    if( ipkt.pts == AV_NOPTS_VALUE ) continue;
+    int i = ipkt.stream_index;
+    if( i < 0 || i >= streams.size() ) continue;
+
+    stream *sp = 0;
+    program *pgm = 0;
+    for( int ii=0; !pgm && ii<programs.size(); ++ii ) {
+      program *p = programs[ii];
+      for( int jj=0; jj<p->strm_idx.size(); ++jj ) {
+        sp = streams[p->strm_idx[jj]];
+        if( sp->av_idx == i ) { pgm = p;  break; }
+      }
+    }
+    if( !pgm ) continue;
+    AVStream *st = fmt_ctx->streams[i];
+    if( pgm->ep_pid != st->id ) continue;
+    int64_t pts45k = av_rescale_q(ipkt.pts, st->time_base, clk45k);
+    if( sp->start_pts > pts45k ) sp->start_pts = pts45k;
+    if( sp->end_pts < pts45k ) sp->end_pts = pts45k;
+    if( pgm->start_time > pts45k ) pgm->start_time = pts45k;
+    if( pgm->end_time < pts45k ) pgm->end_time = pts45k;
+
+    if( !(ipkt.flags & AV_PKT_FLAG_KEY) ) continue;
+
+    if( sp->last_pts != pts45k ) {
+      sp->last_pts = pts45k;
+      pgm->add_label(count, ipkt.pos, pts45k, st->id);
+    }
+  }
+
+  for( int ii=0; ii<programs.size(); ++ii ) {
+    program *pgm = programs[ii];
+    if( pgm->end_time > pgm->start_time )
+      pgm->duration = pgm->end_time - pgm->start_time;
+  }
+
+  return ret != AVERROR_EOF ? -1 : 0;
+}
+
+int
+Media::compose()
+{
+// index
+  bs.init();
+  idx.sig = 1;
+  idx.first_play.set_hdmv(0, pb_typ_movie);
+  idx.top_menu.set_hdmv(0xffff, pb_typ_iactv);
+
+// movie
+  bs.init();
+  mov.sig = 1;
+  movie_obj *mp = new movie_obj();
+  mp->resume_intention_flag = 1;
+  command_obj *cmd = new command_obj();
+  cmd->cmd = htobe32(0x21810000); cmd->dst = 1; cmd->src = 0;
+  mp->cmds.append(cmd);  // JUMP_TITLE 1
+  cmd = new command_obj();
+  cmd->cmd = htobe32(0x00020000); cmd->dst = 0; cmd->src = 0;
+  mp->cmds.append(cmd);
+  mov.movies.append(mp); // BREAK
+
+  
+  for( int ii=0; ii<size(); ++ii ) {
+    mp = new movie_obj();
+    mp->resume_intention_flag = 1;
+    cmd = new command_obj();
+    cmd->cmd = htobe32(0x22800000); cmd->dst = ii; cmd->src = 0;
+    mp->cmds.append(cmd);  // PLAY_PL   ii
+    cmd = new command_obj();
+    cmd->cmd = htobe32(0x00020000); cmd->dst = 0; cmd->src = 0;
+    mp->cmds.append(cmd);
+    mov.movies.append(mp); // BREAK
+  }
+
+  mp = new movie_obj();
+  mp->resume_intention_flag = 1;
+  cmd = new command_obj();
+  cmd->cmd = htobe32(0x21810000); cmd->dst = 1; cmd->src = 0;
+  mp->cmds.append(cmd);  // JUMP_TITLE 1
+  cmd = new command_obj();
+  cmd->cmd = htobe32(0x00020000); cmd->dst = 0; cmd->src = 0;
+  mp->cmds.append(cmd);
+  mov.movies.append(mp); // BREAK
+
+  title_obj *tp = 0;
+// clips
+  for( int ii=0; ii<size(); ++ii ) {
+    if( !tp ) {
+      tp = new title_obj();
+      tp->set_hdmv(idx.titles.size()+1, pb_typ_movie);
+      idx.titles.append(tp);
+    }
+    bs.init();
+    media_info *ip = get(ii);
+// clip program, if specified
+    int pidx = ip->programs.size();
+    while( --pidx>=0 && ip->programs[pidx]->pid != ip->pgm_pid );
+    if( pidx < 0 ) pidx = 0;
+    ip->pidx = pidx;
+    ip->pgm_pid = ip->prog()->pid;
+
+    clpi_cl *cp = new clpi_cl();
+    cp->clip.clip_stream_type = 1;
+    cp->clip.application_type = BLURAY_APP_TYPE_MAIN_MOVIE;
+    cp->clip.ts_recording_rate = ip->bit_rate;
+    uint32_t ts_pkt_count = ip->file_size / BLURAY_TS_PKTSZ + 1;
+    cp->clip.num_source_packets = ts_pkt_count;
+    cp->clip.ts_type_info.validity = 0x80;
+    strcpy(cp->clip.ts_type_info.format_id, "HDMV");
+    cp->cpi.type = 1;
+
+    for( int jj=0; jj<ip->programs.size(); ++jj ) {
+      program *pgm = ip->programs[jj];
+      clpi_prog *p = new clpi_prog(pgm->pmt_pid);
+      for( int kk=0; kk<pgm->strm_idx.size(); ++kk ) {
+        int k = pgm->strm_idx[kk];
+        stream *sp = ip->streams[k];
+        clpi_prog_stream *s = new clpi_prog_stream();
+        s->pid = sp->pid;
+        s->coding_type = sp->coding_type;
+        s->format = sp->format;
+//use unspecified (0)
+//      if( !idx.video_format ) idx.video_format = s->format;
+        s->rate = sp->rate;
+//      if( !idx.frame_rate ) idx.frame_rate = s->rate;
+        switch( sp->type ) {
+        case AVMEDIA_TYPE_VIDEO:
+          s->aspect = sp->aspect;
+          break;
+        case AVMEDIA_TYPE_AUDIO:
+          memcpy(s->lang,sp->lang,sizeof(s->lang));
+          break;
+        default:
+          break;
+        }
+        p->streams.append(s);
+      }
+      clpi_ep_map_entry *map = new clpi_ep_map_entry(pgm->ep_pid);
+      pgm->build_toc(map);
+      cp->cpi.append(map);
+      cp->programs.append(p);
+
+      clpi_atc_seq *atc_seq = new clpi_atc_seq();
+      clpi_stc_seq *stc_seq = new clpi_stc_seq();
+      stc_seq->pcr_pid = pgm->pcr_pid;
+      stc_seq->presentation_start_time = pgm->start_time;
+      stc_seq->presentation_end_time = pgm->end_time;
+      atc_seq->stc_seq.append(stc_seq);
+      cp->sequences.append(atc_seq);
+    }
+
+    cl.append(cp);
+    tp->last = ii;
+    if( ip->brk ) tp = 0;
+  }
+
+// playlists, one per title
+//   one playitem per media clip
+  int clip_id = 0;
+  for( int ii=0; ii<idx.titles.size(); ++ii ) {
+    bs.init();
+    media_info *ip = get(clip_id);
+    program *pgm = ip->prog();
+    mpls_pl *pp = new mpls_pl();
+    pp->app_info.playback_type = BLURAY_PLAYBACK_TYPE_SEQUENTIAL;
+//  pp->app_info.uo_mask.xxx = 1;
+    int last = idx.titles[ii]->last;
+    for( ; clip_id<=last; ++clip_id ) {
+      ip = get(clip_id);
+      pgm = ip->prog();
+      mpls_pi *pi = new mpls_pi();
+      pi->connection_condition = 1; // seamless
+      pi->in_time = pgm->start_time;
+      pi->out_time = pgm->end_time;
+      if( ip->still )
+        pi->still_mode = BLURAY_STILL_INFINITE;
+      int64_t end_time = pgm->start_time + pgm->duration;
+      if( pi->out_time < end_time ) pi->out_time = end_time;
+      mpls_clip *cp = new mpls_clip();
+      sprintf(cp->clip_id,"%05d", clip_id);
+      pi->clip.append(cp);
+      for( int kk=0; kk<ip->streams.size(); ++kk ) {
+        stream *sp = ip->streams[kk];
+        switch( sp->type ) {
+        case AVMEDIA_TYPE_VIDEO: break;
+        case AVMEDIA_TYPE_AUDIO: break;
+        default: continue;
+        }
+        mpls_stream *ps = new mpls_stream();
+        ps->pid = sp->pid;
+        ps->stream_type = BLURAY_PG_TEXTST_STREAM;
+        ps->coding_type = sp->coding_type;
+        ps->format = sp->format;
+        ps->rate = sp->rate;
+        switch( sp->type ) {
+        case AVMEDIA_TYPE_VIDEO:
+          pi->stn.video.append(ps);
+          break;
+        case AVMEDIA_TYPE_AUDIO:
+          memcpy(ps->lang, sp->lang, sizeof(ps->lang));
+          pi->stn.audio.append(ps);
+          break;
+        default:
+          break;
+        }
+      }
+      pp->play_item.append(pi);
+    }
+// chapter marks every ch_duration ticks
+    int64_t ch_duration = 45000 * 60*10;
+    int64_t mrktm = ch_duration;
+    int64_t plytm = 0;
+    int pmark = 0, pitem = 0;
+    mpls_pi *pi = pp->play_item[pitem];
+    mpls_plm *pm = new mpls_plm();
+    pm->mark_id = pmark++;
+    pm->mark_type = BLURAY_MARK_TYPE_ENTRY;
+    pm->play_item_ref = pitem;
+    pm->time = pi->in_time;
+    pm->entry_es_pid = 0;
+    pp->play_mark.append(pm);
+    for( int jj=0; jj < pp->play_item.size(); ++jj ) {
+      pitem = jj;
+      pi = pp->play_item[pitem];
+      int64_t pi_duration = pi->out_time - pi->in_time;
+      int64_t endtm = plytm + pi_duration;
+      while( mrktm < endtm ) {
+        pm = new mpls_plm();
+        pm->mark_id = pmark++;
+        pm->mark_type = BLURAY_MARK_TYPE_ENTRY;
+        pm->play_item_ref = pitem;
+        pm->time = pi->in_time + mrktm - plytm;
+        pm->entry_es_pid = 0;
+        pp->play_mark.append(pm);
+        mrktm += ch_duration;
+      }
+      plytm = endtm;
+    }
+    pm = new mpls_plm();
+    pm->mark_id = pmark;
+    pm->mark_type = BLURAY_MARK_TYPE_ENTRY;
+    pm->play_item_ref = pitem;
+    pm->time = pi->out_time;
+    pm->entry_es_pid = 0;
+    pp->play_mark.append(pm);
+
+    pl.append(pp);
+  }
+  return 0;
+}
+
+int Media::
+bd_path(const char *bp, const char *fmt, va_list ap)
+{
+  int n = sizeof(filename)-1;
+  char *cp = filename;
+  const char *pp = path;
+  while( n>0 && (*cp=*pp)!=0 ) { --n;  ++cp;  ++pp; }
+  while( n>0 && (*cp=*bp)!=0 ) { --n;  ++cp;  ++bp; }
+  n -= vsnprintf(cp, n, fmt, ap);
+  va_end(ap);
+  return n > 0 ? 0 : 1;
+}
+
+int Media::
+bd_copy(const char *ifn, const char *fmt, ...)
+{
+  int n, ret = 1;
+  char bfr[0x40000];
+  FILE *ifp = fopen(ifn,"r");
+  if( ifp ) {
+    va_list ap;
+    va_start(ap, fmt);
+    if( bd_path("/BDMV/", fmt, ap) ) return 1;
+    va_end(ap);
+    FILE *ofp = fopen(filename,"w");
+    if( ofp ) {
+      setvbuf(ifp, 0, _IOFBF, 0x80000);
+      setvbuf(ofp, 0, _IOFBF, 0x80000);
+      while( (n=fread(bfr,1,sizeof(bfr),ifp)) > 0 ) fwrite(bfr,1,n,ofp);
+      fclose(ofp);
+      ret = 0;
+    }
+    fclose(ifp);
+  }
+  if( ret )
+    fprintf(stderr, "cant copy clip %s\n",ifn);
+  return ret;
+}
+
+int Media::
+bd_open(const char *fmt, ...)
+{
+  bs.init();
+  if( !path ) return 0;
+  va_list ap;
+  va_start(ap, fmt);
+  if( bd_path("/BDMV/", fmt, ap) ) return 1;
+  va_end(ap);
+  if( bs.open(filename) ) {
+    fprintf(stderr, "cant open file %s\n",filename);
+    return 1;
+  }
+  return 0;
+}
+
+int Media::
+bd_backup(const char *fmt, ...)
+{
+  bs.close();
+  if( !path ) return 0;
+  int n, ret = 1;
+  char bfr[0x10000];
+  FILE *ifp = fopen(filename,"r");
+  if( ifp ) {
+    va_list ap;
+    va_start(ap, fmt);
+    if( bd_path("/BDMV/BACKUP/", fmt, ap) ) return 1;
+    va_end(ap);
+    FILE *ofp = fopen(filename,"w");
+    if( ofp ) {
+      while( (n=fread(bfr,1,sizeof(bfr),ifp)) > 0 ) fwrite(bfr,1,n,ofp);
+      fclose(ofp);
+      ret = 0;
+    }
+    fclose(ifp);
+  }
+  if( ret )
+    fprintf(stderr, "cant backup %s\n",filename);
+  return ret;
+}
+
+int Media::write(char *fn)
+{
+  this->path = fn;
+// index
+  if( bd_open("index.bdmv") ) return 1;
+  if( idx.write() ) return 1;
+  if( bd_backup("index.bdmv") ) return 1;
+// movie
+  if( bd_open("MovieObject.bdmv") ) return 1;
+  if( mov.write() ) return 1;
+  if( bd_backup("MovieObject.bdmv") ) return 1;
+// clips
+  for( int ii=0; ii<cl.size(); ++ii ) {
+    if( bd_open("CLIPINF/%05d.clpi", ii) ) return 1;
+    if( cl[ii]->write() ) return 1;
+    if( bd_backup("CLIPINF/%05d.clpi", ii) ) return 1;
+  }
+// playlists
+  for( int ii=0; ii<pl.size(); ++ii ) {
+    if( bd_open("PLAYLIST/%05d.mpls", ii) ) return 1;
+    if( pl[ii]->write() ) return 1;
+    if( bd_backup("PLAYLIST/%05d.mpls", ii) ) return 1;
+  }
+  return 0;
+}
+
+int
+main(int ac, char **av)
+{
+  char *path = av[1];
+  if( mkbdmv(path) ) return 1;
+  av_register_all();
+  av_log_set_level(AV_LOG_FATAL);
+  //av_log_set_level(AV_LOG_VERBOSE);
+  //av_log_set_level(AV_LOG_DEBUG);
+  Media media;
+  media_info *mp = 0;
+
+  for( int ii=2; ii<ac; ++ii ) {
+    char *ap = av[ii];
+    // any dash seq followed by number sets curr title pgm_pid
+    // single dash only sets title pgm_pid
+    // double dash ends curr title, starts a new title
+    // triple dash ends curr title as infinite still
+    if( *ap == '-' ) {
+      if( !mp ) continue;
+      if( *++ap == '-' ) {
+        mp->brk = 1;
+        if( *++ap == '-' ) { ++ap;  mp->still = 1; }
+      }
+      if( *ap >= '0' && *ap <= '9' )
+        mp->pgm_pid = strtoul(ap,&ap,0);
+      if( mp->brk ) mp = 0;
+      if( !ap || *ap ) {
+        fprintf(stderr, "err arg %d: %s\n",ii,av[ii]);
+        return 1;
+      }
+      continue;
+    }
+    mp = new media_info(av[ii]);
+    media.append(mp);
+    if( mp->scan() ) {
+      fprintf(stderr, "cant scan media: %s\n", av[ii]);
+      return 1;
+    }
+  }
+
+  if( mp ) mp->brk = 1;
+
+  if( media.compose() ) {
+    fprintf(stderr, "cant compose media\n");
+    return 1;
+  }
+  if( media.write(0) ) {
+    fprintf(stderr, "cant prepare media\n");
+    return 1;
+  }
+  if( media.write(path) ) {
+    fprintf(stderr, "cant write media\n");
+    return 1;
+  }
+
+  for( int ii=0; ii<media.size(); ++ii )
+    if( media.bd_copy(media[ii]->filename, "STREAM/%05d.m2ts", ii) )
+      return 1;
+
+  return 0;
+}
+
index 1e1184c278b468a610b012bbd0ab19a5a2077aa4..643bd7280a1c8a137ae6ef4a749a75fc3e6ce534 100644 (file)
@@ -739,6 +739,11 @@ void ConfirmScanThread::handle_done_event(int result)
        }
 }
 
+ConfirmScanThread::~ConfirmScanThread()
+{
+       close_window();
+}
+
 BC_Window* ConfirmScanThread::new_gui()
 {
        int x = gui->get_abs_cursor_x(1);
index 4a2f2f3955d73b56ff52b0b29e306fb05568c295..2d88ad8b281c1761a5b007b1a2e2345b20cbe746 100644 (file)
@@ -210,6 +210,7 @@ class ConfirmScanThread : public BC_DialogThread
 {
 public:
        ConfirmScanThread(ChannelEditWindow *gui);
+       ~ConfirmScanThread();
        void handle_done_event(int result);
        BC_Window* new_gui();
        ChannelEditWindow *gui;
index 23c756af80ee914a7ab7ebbbf8170c625c24348d..76cd8744421802d91683388fc602a44a44723087 100644 (file)
@@ -48,6 +48,7 @@ ClipEdit::ClipEdit(MWindow *mwindow, AWindow *awindow, VWindow *vwindow)
 
 ClipEdit::~ClipEdit()
 {
+       close_window();
 }
 
 // After the window is closed and deleted, this is called.
diff --git a/cinelerra-5.0/cinelerra/dvdcreate.C b/cinelerra-5.0/cinelerra/dvdcreate.C
new file mode 100644 (file)
index 0000000..ad3a8a2
--- /dev/null
@@ -0,0 +1,840 @@
+#include "asset.h"
+#include "dvdcreate.h"
+#include "edl.h"
+#include "edit.h"
+#include "edits.h"
+#include "edlsession.h"
+#include "filexml.h"
+#include "format.inc"
+#include "keyframe.h"
+#include "labels.h"
+#include "mainerror.h"
+#include "mainundo.h"
+#include "mwindow.h"
+#include "mwindowgui.h"
+#include "plugin.h"
+#include "pluginset.h"
+#include "track.h"
+#include "tracks.h"
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+
+// DVD Creation
+
+
+const int64_t CreateDVD_Thread::DVD_SIZE = 4700000000;
+const int CreateDVD_Thread::DVD_STREAMS = 1;
+const int CreateDVD_Thread::DVD_WIDTH = 720;
+const int CreateDVD_Thread::DVD_HEIGHT = 480;
+const double CreateDVD_Thread::DVD_ASPECT_WIDTH = 4.;
+const double CreateDVD_Thread::DVD_ASPECT_HEIGHT = 3.;
+const double CreateDVD_Thread::DVD_WIDE_ASPECT_WIDTH = 16.;
+const double CreateDVD_Thread::DVD_WIDE_ASPECT_HEIGHT = 9.;
+const double CreateDVD_Thread::DVD_FRAMERATE = 30000. / 1001.;
+const int CreateDVD_Thread::DVD_MAX_BITRATE = 8000000;
+const int CreateDVD_Thread::DVD_CHANNELS = 2;
+const int CreateDVD_Thread::DVD_WIDE_CHANNELS = 6;
+const double CreateDVD_Thread::DVD_SAMPLERATE = 48000;
+const double CreateDVD_Thread::DVD_KAUDIO_RATE = 224;
+
+
+CreateDVD_MenuItem::CreateDVD_MenuItem(MWindow *mwindow)
+ : BC_MenuItem(_("DVD Render..."), _("Shift-D"), 'D')
+{
+       set_shift(1); 
+       this->mwindow = mwindow;
+}
+
+int CreateDVD_MenuItem::handle_event()
+{
+       mwindow->create_dvd->start();
+       return 1;
+}
+
+
+CreateDVD_Thread::CreateDVD_Thread(MWindow *mwindow)
+ : BC_DialogThread()
+{
+       this->mwindow = mwindow;
+       this->gui = 0;
+       this->use_deinterlace = 0;
+       this->use_inverse_telecine = 0;
+       this->use_scale = 0;
+       this->use_resize_tracks = 0;
+       this->use_histogram = 0;
+       this->use_wide_audio = 0;
+       this->use_wide_aspect = 0;
+       this->use_label_chapters = 0;
+       this->use_ffmpeg = 0;
+}
+
+CreateDVD_Thread::~CreateDVD_Thread()
+{
+       close_window();
+}
+
+int CreateDVD_Thread::create_dvd_jobs(ArrayList<BatchRenderJob*> *jobs,
+       const char *tmp_path, const char *asset_title)
+{
+       EDL *edl = mwindow->edl;
+       if( !edl || !edl->session ) {
+               char msg[BCTEXTLEN];
+                sprintf(msg, _("No EDL/Session"));
+                MainError::show_error(msg);
+                return 1;
+        }
+       EDLSession *session = edl->session;
+
+       double total_length = edl->tracks->total_length();
+        if( total_length <= 0 ) {
+               char msg[BCTEXTLEN];
+                sprintf(msg, _("No content: %s"), asset_title);
+                MainError::show_error(msg);
+                return 1;
+        }
+
+       char asset_dir[BCTEXTLEN];
+       sprintf(asset_dir, "%s/%s", tmp_path, asset_title);
+
+       if( mkdir(asset_dir, 0777) ) {
+               char err[BCTEXTLEN], msg[BCTEXTLEN];
+               strerror_r(errno, err, sizeof(err));
+               sprintf(msg, _("Unable to create directory: %s\n-- %s"), asset_dir, err);
+               MainError::show_error(msg);
+               return 1;
+       }
+
+       double old_samplerate = session->sample_rate;
+       double old_framerate = session->frame_rate;
+
+        session->video_channels = DVD_STREAMS;
+        session->video_tracks = DVD_STREAMS;
+        session->frame_rate = DVD_FRAMERATE;
+        session->output_w = DVD_WIDTH;
+        session->output_h = DVD_HEIGHT;
+        session->aspect_w = use_wide_aspect ? DVD_WIDE_ASPECT_WIDTH : DVD_ASPECT_WIDTH;
+        session->aspect_h = use_wide_aspect ? DVD_WIDE_ASPECT_HEIGHT : DVD_ASPECT_HEIGHT;
+        session->sample_rate = DVD_SAMPLERATE;
+        session->audio_channels = session->audio_tracks =
+               use_wide_audio ? DVD_WIDE_CHANNELS : DVD_CHANNELS;
+
+       char script_filename[BCTEXTLEN];
+       sprintf(script_filename, "%s/dvd.sh", asset_dir);
+       int fd = open(script_filename, O_WRONLY+O_CREAT+O_TRUNC, 0755);
+       FILE *fp = fdopen(fd, "w");
+       if( !fp ) {
+               char err[BCTEXTLEN], msg[BCTEXTLEN];
+               strerror_r(errno, err, sizeof(err));
+               sprintf(msg, _("Unable to save: %s\n-- %s"), script_filename, err);
+               MainError::show_error(msg);
+               return 1;
+       }
+       fprintf(fp,"#!/bin/bash\n");
+       fprintf(fp,"echo \"running %s\" $# $*\n", script_filename);
+       fprintf(fp,"\n");
+       if( !use_ffmpeg ) {
+               fprintf(fp,"mplex -f 8 -o $1/dvd.mpg $1/dvd.m2v $1/dvd.ac3\n");
+               fprintf(fp,"\n");
+       }
+       fprintf(fp,"rm -rf $1/iso\n");
+       fprintf(fp,"mkdir -p $1/iso\n");
+       fprintf(fp,"\n");
+       fprintf(fp,"dvdauthor -x - <<eof\n");
+       fprintf(fp,"<dvdauthor dest=\"$1/iso\">\n");
+       fprintf(fp,"  <vmgm>\n");
+       fprintf(fp,"    <fpc> jump title 1; </fpc>\n");
+       fprintf(fp,"  </vmgm>\n");
+       fprintf(fp,"  <titleset>\n");
+       fprintf(fp,"    <titles>\n");
+       fprintf(fp,"    <video format=\"ntsc\" aspect=\"%d:%d\" resolution=\"%dx%d\"/>\n",
+               (int)session->aspect_w, (int)session->aspect_h,
+               session->output_w, session->output_h);
+       fprintf(fp,"    <audio format=\"ac3\" lang=\"en\"/>\n");
+       fprintf(fp,"    <pgc>\n");
+       fprintf(fp,"      <vob file=\"$1/dvd.mpg\" chapters=\"");
+       if( use_label_chapters && edl->labels ) {
+               Label *label = edl->labels->first;
+               while( label ) {
+                       int secs = label->position;
+                       int mins = secs / 60;
+                       int frms = (label->position-secs) * session->frame_rate;
+                       fprintf(fp,"%d:%02d:%02d.%d", mins/60, mins%60, secs%60, frms);
+                       if( (label=label->next) != 0 ) fprintf(fp, ",");
+               }
+       }
+       else {
+               int mins = 0;
+               for( int secs=0 ; secs<total_length; secs+=10*60 ) {
+                       mins = secs / 60;
+                       fprintf(fp,"%d:%02d:00,", mins/60, mins%60);
+               }
+               fprintf(fp,"%d:%02d:00", mins/60, mins%60);
+       }
+       fprintf(fp,"\"/>\n");
+       fprintf(fp,"    </pgc>\n");
+       fprintf(fp,"    </titles>\n");
+       fprintf(fp,"  </titleset>\n");
+       fprintf(fp,"</dvdauthor>\n");
+       fprintf(fp,"eof\n");
+       fprintf(fp,"\n");
+       fprintf(fp,"echo To burn dvd, load blank media and run:\n");
+       fprintf(fp,"echo growisofs -dvd-compat -Z /dev/dvd -dvd-video $1/iso\n");
+       fprintf(fp,"\n");
+       fclose(fp);
+
+       if( use_wide_audio ) {
+               session->audio_channels = session->audio_tracks = DVD_WIDE_CHANNELS;
+               session->achannel_positions[0] = 90;
+               session->achannel_positions[1] = 150;
+               session->achannel_positions[2] = 30;
+               session->achannel_positions[3] = 210;
+               session->achannel_positions[4] = 330;
+               session->achannel_positions[5] = 270;
+               if( edl->tracks->recordable_audio_tracks() == DVD_WIDE_CHANNELS )
+                       mwindow->remap_audio(MWindow::AUDIO_1_TO_1);
+       }
+       else {
+               session->audio_channels = session->audio_tracks = DVD_CHANNELS;
+               session->achannel_positions[0] = 180;
+               session->achannel_positions[1] = 0;
+               if( edl->tracks->recordable_audio_tracks() == DVD_WIDE_CHANNELS )
+                       mwindow->remap_audio(MWindow::AUDIO_5_1_TO_2);
+       }
+
+       double new_samplerate = session->sample_rate;
+       double new_framerate = session->frame_rate;
+       edl->rechannel();
+       edl->resample(old_samplerate, new_samplerate, TRACK_AUDIO);
+       edl->resample(old_framerate, new_framerate, TRACK_VIDEO);
+
+       int64_t aud_size = ((DVD_KAUDIO_RATE * total_length)/8 + 1000-1) * 1000;
+       int64_t vid_size = DVD_SIZE*0.96 - aud_size;
+       int64_t vid_bitrate = (vid_size * 8) / total_length;
+       vid_bitrate /= 1000;  vid_bitrate *= 1000;
+       if( vid_bitrate > DVD_MAX_BITRATE ) vid_bitrate = DVD_MAX_BITRATE;
+
+       char xml_filename[BCTEXTLEN];
+       sprintf(xml_filename, "%s/dvd.xml", asset_dir);
+        FileXML xml_file;
+        edl->save_xml(&xml_file, xml_filename, 0, 0);
+        xml_file.terminate_string();
+        if( xml_file.write_to_file(xml_filename) ) {
+               char msg[BCTEXTLEN];
+               sprintf(msg, _("Unable to save: %s"), xml_filename);
+               MainError::show_error(msg);
+               return 1;
+       }
+
+       BatchRenderJob *job = new BatchRenderJob(mwindow->preferences);
+       jobs->append(job);
+       strcpy(&job->edl_path[0], xml_filename);
+       Asset *asset = job->asset;
+
+       asset->layers = DVD_STREAMS;
+       asset->frame_rate = session->frame_rate;
+       asset->width = session->output_w;
+       asset->height = session->output_h;
+       asset->aspect_ratio = session->aspect_w / session->aspect_h;
+
+       if( use_ffmpeg ) {
+               char option_path[BCTEXTLEN];
+               sprintf(&asset->path[0],"%s/dvd.mpg", asset_dir);
+               asset->format = FILE_FFMPEG;
+               strcpy(asset->fformat, "dvd");
+
+               asset->audio_data = 1;
+               strcpy(asset->acodec, "dvd.dvd");
+               FFMPEG::set_option_path(option_path, "audio/%s", asset->acodec);
+               FFMPEG::load_options(option_path, asset->ff_audio_options,
+                        sizeof(asset->ff_audio_options));
+               asset->ff_audio_bitrate = DVD_KAUDIO_RATE * 1000;
+
+               asset->video_data = 1;
+               strcpy(asset->vcodec, "dvd.dvd");
+               FFMPEG::set_option_path(option_path, "video/%s", asset->vcodec);
+               FFMPEG::load_options(option_path, asset->ff_video_options,
+                        sizeof(asset->ff_video_options));
+               asset->ff_video_bitrate = vid_bitrate;
+               asset->ff_video_quality = 0;
+
+               int len = strlen(asset->ff_video_options);
+               char *cp = asset->ff_video_options + len;
+               snprintf(cp, sizeof(asset->ff_video_options)-len-1,
+                       "aspect %.5f\n", asset->aspect_ratio);
+       }
+       else {
+               sprintf(&asset->path[0],"%s/dvd.m2v", asset_dir);
+               asset->video_data = 1;
+               asset->format = FILE_VMPEG;
+               asset->vmpeg_cmodel = BC_YUV420P;
+               asset->vmpeg_fix_bitrate = 1;
+               asset->vmpeg_bitrate = vid_bitrate;
+               asset->vmpeg_quantization = 15;
+               asset->vmpeg_iframe_distance = 15;
+               asset->vmpeg_progressive = 0;
+               asset->vmpeg_denoise = 0;
+               asset->vmpeg_seq_codes = 0;
+               asset->vmpeg_derivative = 2;
+               asset->vmpeg_preset = 8;
+               asset->vmpeg_field_order = 0;
+               asset->vmpeg_pframe_distance = 0;
+               job = new BatchRenderJob(mwindow->preferences);
+               jobs->append(job);
+               strcpy(&job->edl_path[0], xml_filename);
+               asset = job->asset;
+               
+               sprintf(&asset->path[0],"%s/dvd.ac3", asset_dir);
+               asset->audio_data = 1;
+               asset->format = FILE_AC3;
+               asset->channels = session->audio_channels;
+               asset->sample_rate = session->sample_rate;
+               asset->bits = 16;
+               asset->byte_order = 0;
+               asset->signed_ = 1;
+               asset->header = 0;
+               asset->dither = 0;
+               asset->ac3_bitrate = DVD_KAUDIO_RATE;
+       }
+
+       job = new BatchRenderJob(mwindow->preferences);
+       jobs->append(job);
+       job->edl_path[0] = '@';
+       strcpy(&job->edl_path[1], script_filename);
+       strcpy(&job->asset->path[0], asset_dir);
+
+       return 0;
+}
+
+void CreateDVD_Thread::handle_close_event(int result)
+{
+       if( result ) return;
+       mwindow->batch_render->load_defaults(mwindow->defaults);
+        mwindow->undo->update_undo_before();
+       KeyFrame keyframe;  char data[BCTEXTLEN];
+       if( use_deinterlace ) {
+               sprintf(data,"<DEINTERLACE MODE=1>");
+               keyframe.set_data(data);
+               insert_video_plugin("Deinterlace", &keyframe);
+       }
+       if( use_inverse_telecine ) {
+               sprintf(data,"<IVTC FRAME_OFFSET=0 FIRST_FIELD=0 "
+                       "AUTOMATIC=1 AUTO_THRESHOLD=2.0e+00 PATTERN=2>");
+               keyframe.set_data(data);
+               insert_video_plugin("Inverse Telecine", &keyframe);
+       }
+       if( use_scale ) {
+               sprintf(data,"<PHOTOSCALE WIDTH=%d HEIGHT=%d USE_FILE=1>", DVD_WIDTH, DVD_HEIGHT);
+               keyframe.set_data(data);
+               insert_video_plugin("Auto Scale", &keyframe);
+       }
+       if( use_resize_tracks )
+               resize_tracks();
+       if( use_histogram ) {
+#if 0
+               sprintf(data, "<HISTOGRAM OUTPUT_MIN_0=0 OUTPUT_MAX_0=1 "
+                       "OUTPUT_MIN_1=0 OUTPUT_MAX_1=1 "
+                       "OUTPUT_MIN_2=0 OUTPUT_MAX_2=1 "
+                       "OUTPUT_MIN_3=0 OUTPUT_MAX_3=1 "
+                       "AUTOMATIC=0 THRESHOLD=9.0-01 PLOT=0 SPLIT=0>"
+                       "<POINTS></POINTS><POINTS></POINTS><POINTS></POINTS>"
+                       "<POINTS><POINT X=6.0e-02 Y=0>"
+                               "<POINT X=9.4e-01 Y=1></POINTS>");
+#else
+               sprintf(data, "<HISTOGRAM AUTOMATIC=0 THRESHOLD=1.0e-01 "
+                       "PLOT=0 SPLIT=0 W=440 H=500 PARADE=0 MODE=3 "
+                       "LOW_OUTPUT_0=0 HIGH_OUTPUT_0=1 LOW_INPUT_0=0 HIGH_INPUT_0=1 GAMMA_0=1 "
+                       "LOW_OUTPUT_1=0 HIGH_OUTPUT_1=1 LOW_INPUT_1=0 HIGH_INPUT_1=1 GAMMA_1=1 "
+                       "LOW_OUTPUT_2=0 HIGH_OUTPUT_2=1 LOW_INPUT_2=0 HIGH_INPUT_2=1 GAMMA_2=1 "
+                       "LOW_OUTPUT_3=0 HIGH_OUTPUT_3=1 LOW_INPUT_3=0.044 HIGH_INPUT_3=0.956 "
+                       "GAMMA_3=1>");
+#endif
+               keyframe.set_data(data);
+               insert_video_plugin("Histogram", &keyframe);
+       }
+       create_dvd_jobs(&mwindow->batch_render->jobs, tmp_path, asset_title);
+       mwindow->save_backup();
+       mwindow->undo->update_undo_after(_("create dvd"), LOAD_ALL);
+       mwindow->resync_guis();
+       mwindow->batch_render->handle_close_event(0);
+       mwindow->batch_render->start();
+}
+
+BC_Window* CreateDVD_Thread::new_gui()
+{
+       memset(tmp_path,0,sizeof(tmp_path));
+       strcpy(tmp_path,"/tmp");
+       memset(asset_title,0,sizeof(asset_title));
+       time_t dt;      time(&dt);
+       struct tm dtm;  localtime_r(&dt, &dtm);
+       sprintf(asset_title, "dvd_%02d%02d%02d-%02d%02d%02d",
+               dtm.tm_year+1900, dtm.tm_mon+1, dtm.tm_mday,
+               dtm.tm_hour, dtm.tm_min, dtm.tm_sec);
+       use_deinterlace = 0;
+       use_inverse_telecine = 0;
+       use_scale = 0;
+       use_resize_tracks = 0;
+       use_histogram = 0;
+       use_wide_audio = 0;
+       use_wide_aspect = 0;
+       use_label_chapters = 0;
+       use_ffmpeg = 0;
+       option_presets();
+        int scr_x = mwindow->gui->get_screen_x(0, -1);
+        int scr_w = mwindow->gui->get_screen_w(0, -1);
+        int scr_h = mwindow->gui->get_screen_h(0, -1);
+        int w = 500, h = 250;
+       int x = scr_x + scr_w/2 - w/2, y = scr_h/2 - h/2;
+
+       gui = new CreateDVD_GUI(this, x, y, w, h);
+       gui->create_objects();
+       return gui;
+}
+
+
+CreateDVD_OK::CreateDVD_OK(CreateDVD_GUI *gui, int x, int y)
+ : BC_OKButton(x, y)
+{
+        this->gui = gui;
+        set_tooltip(_("end setup, start batch render"));
+}
+
+CreateDVD_OK::~CreateDVD_OK()
+{
+}
+
+int CreateDVD_OK::button_press_event()
+{
+        if(get_buttonpress() == 1 && is_event_win() && cursor_inside()) {
+                gui->set_done(0);
+                return 1;
+        }
+        return 0;
+}
+
+int CreateDVD_OK::keypress_event()
+{
+        return 0;
+}
+
+
+CreateDVD_Cancel::CreateDVD_Cancel(CreateDVD_GUI *gui, int x, int y)
+ : BC_CancelButton(x, y)
+{
+        this->gui = gui;
+}
+
+CreateDVD_Cancel::~CreateDVD_Cancel()
+{
+}
+
+int CreateDVD_Cancel::button_press_event()
+{
+        if(get_buttonpress() == 1 && is_event_win() && cursor_inside()) {
+                gui->set_done(1);
+                return 1;
+        }
+        return 0;
+}
+
+
+CreateDVD_DiskSpace::CreateDVD_DiskSpace(CreateDVD_GUI *gui, int x, int y)
+ : BC_Title(x, y, "", MEDIUMFONT, GREEN)
+{
+        this->gui = gui;
+}
+
+CreateDVD_DiskSpace::~CreateDVD_DiskSpace()
+{
+}
+
+int64_t CreateDVD_DiskSpace::tmp_path_space()
+{
+       const char *path = gui->tmp_path->get_text();
+       if( access(path,R_OK+W_OK) ) return 0;
+       struct statfs sfs;
+       if( statfs(path, &sfs) ) return 0;
+       return (int64_t)sfs.f_bsize * sfs.f_bfree;
+}
+
+void CreateDVD_DiskSpace::update()
+{
+//     gui->disk_space->set_color(get_bg_color());
+       int64_t disk_space = tmp_path_space();
+       int color = disk_space<gui->needed_disk_space ? RED : GREEN;
+       static const char *suffix[] = { "", "KB", "MB", "GB", "TB", "PB" };
+       int i = 0;
+       for( int64_t space=disk_space; i<5 && (space/=1000)>0; disk_space=space, ++i );
+       char text[BCTEXTLEN];
+       sprintf(text, "%s" _LDv(3) "%s", _("disk space: "), disk_space, suffix[i]);
+       gui->disk_space->BC_Title::update(text);
+       gui->disk_space->set_color(color);
+}
+
+CreateDVD_TmpPath::CreateDVD_TmpPath(CreateDVD_GUI *gui, int x, int y, int w)
+ : BC_TextBox(x, y, w, 1, -sizeof(gui->thread->tmp_path),
+               gui->thread->tmp_path, 1, MEDIUMFONT)
+{
+        this->gui = gui;
+}
+
+CreateDVD_TmpPath::~CreateDVD_TmpPath()
+{
+}
+
+int CreateDVD_TmpPath::handle_event()
+{
+       gui->disk_space->update();
+        return 1;
+}
+
+
+CreateDVD_AssetTitle::CreateDVD_AssetTitle(CreateDVD_GUI *gui, int x, int y, int w)
+ : BC_TextBox(x, y, w, 1, 0, gui->thread->asset_title, 1, MEDIUMFONT)
+{
+        this->gui = gui;
+}
+
+CreateDVD_AssetTitle::~CreateDVD_AssetTitle()
+{
+}
+
+
+CreateDVD_Deinterlace::CreateDVD_Deinterlace(CreateDVD_GUI *gui, int x, int y)
+ : BC_CheckBox(x, y, &gui->thread->use_deinterlace, _("Deinterlace"))
+{
+       this->gui = gui;
+}
+
+CreateDVD_Deinterlace::~CreateDVD_Deinterlace()
+{
+}
+
+int CreateDVD_Deinterlace::handle_event()
+{
+       if( get_value() ) {
+               gui->need_inverse_telecine->set_value(0);
+               gui->thread->use_inverse_telecine = 0;
+       }
+       return BC_CheckBox::handle_event();
+}
+
+
+CreateDVD_InverseTelecine::CreateDVD_InverseTelecine(CreateDVD_GUI *gui, int x, int y)
+ : BC_CheckBox(x, y, &gui->thread->use_inverse_telecine, _("Inverse Telecine"))
+{
+       this->gui = gui;
+}
+
+CreateDVD_InverseTelecine::~CreateDVD_InverseTelecine()
+{
+}
+
+int CreateDVD_InverseTelecine::handle_event()
+{
+       if( get_value() ) {
+               gui->need_deinterlace->set_value(0);
+               gui->thread->use_deinterlace = 0;
+       }
+       return BC_CheckBox::handle_event();
+}
+
+
+CreateDVD_Scale::CreateDVD_Scale(CreateDVD_GUI *gui, int x, int y)
+ : BC_CheckBox(x, y, &gui->thread->use_scale, _("Scale"))
+{
+       this->gui = gui;
+}
+
+CreateDVD_Scale::~CreateDVD_Scale()
+{
+}
+
+
+CreateDVD_ResizeTracks::CreateDVD_ResizeTracks(CreateDVD_GUI *gui, int x, int y)
+ : BC_CheckBox(x, y, &gui->thread->use_resize_tracks, _("Resize Tracks"))
+{
+       this->gui = gui;
+}
+
+CreateDVD_ResizeTracks::~CreateDVD_ResizeTracks()
+{
+}
+
+
+CreateDVD_Histogram::CreateDVD_Histogram(CreateDVD_GUI *gui, int x, int y)
+ : BC_CheckBox(x, y, &gui->thread->use_histogram, _("Histogram"))
+{
+       this->gui = gui;
+}
+
+CreateDVD_Histogram::~CreateDVD_Histogram()
+{
+}
+
+CreateDVD_LabelChapters::CreateDVD_LabelChapters(CreateDVD_GUI *gui, int x, int y)
+ : BC_CheckBox(x, y, &gui->thread->use_label_chapters, _("Chapters at Labels"))
+{
+       this->gui = gui;
+}
+
+CreateDVD_LabelChapters::~CreateDVD_LabelChapters()
+{
+}
+
+CreateDVD_WideAudio::CreateDVD_WideAudio(CreateDVD_GUI *gui, int x, int y)
+ : BC_CheckBox(x, y, &gui->thread->use_wide_audio, _("Audio 5.1"))
+{
+       this->gui = gui;
+}
+
+CreateDVD_WideAudio::~CreateDVD_WideAudio()
+{
+}
+
+CreateDVD_WideAspect::CreateDVD_WideAspect(CreateDVD_GUI *gui, int x, int y)
+ : BC_CheckBox(x, y, &gui->thread->use_wide_aspect, _("Aspect 16x9"))
+{
+       this->gui = gui;
+}
+
+CreateDVD_WideAspect::~CreateDVD_WideAspect()
+{
+}
+
+CreateDVD_UseFFMpeg::CreateDVD_UseFFMpeg(CreateDVD_GUI *gui, int x, int y)
+ : BC_CheckBox(x, y, &gui->thread->use_ffmpeg, _("Use FFMPEG"))
+{
+       this->gui = gui;
+}
+
+CreateDVD_UseFFMpeg::~CreateDVD_UseFFMpeg()
+{
+}
+
+
+
+
+CreateDVD_GUI::CreateDVD_GUI(CreateDVD_Thread *thread, int x, int y, int w, int h)
+ : BC_Window(_(PROGRAM_NAME ": Create DVD"), x, y, w, h, 50, 50, 1, 0, 1)
+{
+       this->thread = thread;
+       at_x = at_y = tmp_x = tmp_y = 0;
+       ok_x = ok_y = ok_w = ok_h = 0;
+       cancel_x = cancel_y = cancel_w = cancel_h = 0;
+       asset_title = 0;
+       tmp_path = 0;
+       disk_space = 0;
+       needed_disk_space = 15e9;
+       need_deinterlace = 0;
+       need_inverse_telecine = 0;
+       need_scale = 0;
+       need_resize_tracks = 0;
+       need_histogram = 0;
+       need_wide_audio = 0;
+       need_wide_aspect = 0;
+       need_label_chapters = 0;
+       ok = 0;
+       cancel = 0;
+}
+
+CreateDVD_GUI::~CreateDVD_GUI()
+{
+}
+
+void CreateDVD_GUI::create_objects()
+{
+       lock_window("CreateDVD_GUI::create_objects");
+       int pady = BC_TextBox::calculate_h(this, MEDIUMFONT, 0, 1) + 5;
+       int padx = BC_Title::calculate_w(this, (char*)"X", MEDIUMFONT);
+       int x = padx/2, y = pady/2;
+       BC_Title *title = new BC_Title(x, y, _("Title:"), MEDIUMFONT, YELLOW);
+       add_subwindow(title);
+       at_x = x + title->get_w();  at_y = y;
+       asset_title = new CreateDVD_AssetTitle(this, at_x, at_y, get_w()-at_x-10);
+       add_subwindow(asset_title);
+       y += title->get_h() + pady/2;
+       title = new BC_Title(x, y, _("tmp path:"), MEDIUMFONT, YELLOW);
+       add_subwindow(title);
+       tmp_x = x + title->get_w();  tmp_y = y;
+       tmp_path = new CreateDVD_TmpPath(this, tmp_x, tmp_y,  get_w()-tmp_x-10);
+       add_subwindow(tmp_path);
+       y += title->get_h() + pady/2;
+       disk_space = new CreateDVD_DiskSpace(this, x, y);
+       add_subwindow(disk_space);
+       disk_space->update();
+       y += disk_space->get_h() + pady/2;
+       need_deinterlace = new CreateDVD_Deinterlace(this, x, y);
+       add_subwindow(need_deinterlace);
+       int x1 = x + 150, x2 = x1 + 150;
+       need_inverse_telecine = new CreateDVD_InverseTelecine(this, x1, y);
+       add_subwindow(need_inverse_telecine);
+       need_use_ffmpeg = new CreateDVD_UseFFMpeg(this, x2, y);
+       add_subwindow(need_use_ffmpeg);
+       y += need_deinterlace->get_h() + pady/2;
+       need_scale = new CreateDVD_Scale(this, x, y);
+       add_subwindow(need_scale);
+       need_wide_audio = new CreateDVD_WideAudio(this, x1, y);
+       add_subwindow(need_wide_audio);
+       need_resize_tracks = new CreateDVD_ResizeTracks(this, x2, y);
+       add_subwindow(need_resize_tracks);
+       y += need_scale->get_h() + pady/2;
+       need_histogram = new CreateDVD_Histogram(this, x, y);
+       add_subwindow(need_histogram);
+       need_wide_aspect = new CreateDVD_WideAspect(this, x1, y);
+       add_subwindow(need_wide_aspect);
+       need_label_chapters = new CreateDVD_LabelChapters(this, x2, y);
+       add_subwindow(need_label_chapters);
+       ok_w = BC_OKButton::calculate_w();
+       ok_h = BC_OKButton::calculate_h();
+       ok_x = 10;
+       ok_y = get_h() - ok_h - 10;
+       ok = new CreateDVD_OK(this, ok_x, ok_y);
+       add_subwindow(ok);
+       cancel_w = BC_CancelButton::calculate_w();
+       cancel_h = BC_CancelButton::calculate_h();
+       cancel_x = get_w() - cancel_w - 10,
+       cancel_y = get_h() - cancel_h - 10;
+       cancel = new CreateDVD_Cancel(this, cancel_x, cancel_y);
+       add_subwindow(cancel);
+       show_window();
+       unlock_window();
+}
+
+int CreateDVD_GUI::resize_event(int w, int h)
+{
+       asset_title->reposition_window(at_x, at_y, get_w()-at_x-10);
+       tmp_path->reposition_window(tmp_x, tmp_y,  get_w()-tmp_x-10);
+        ok_y = h - ok_h - 10;
+        ok->reposition_window(ok_x, ok_y);
+       cancel_x = w - cancel_w - 10,
+       cancel_y = h - cancel_h - 10;
+        cancel->reposition_window(cancel_x, cancel_y);
+       return 0;
+}
+
+int CreateDVD_GUI::translation_event()
+{
+       return 1;
+}
+
+int CreateDVD_GUI::close_event()
+{
+        set_done(1);
+        return 1;
+}
+
+int CreateDVD_Thread::
+insert_video_plugin(const char *title, KeyFrame *default_keyframe)
+{
+       Tracks *tracks = mwindow->edl->tracks;
+       for( Track *vtrk=tracks->first; vtrk; vtrk=vtrk->next ) {
+               if( vtrk->data_type != TRACK_VIDEO ) continue;
+               if( !vtrk->record ) continue;
+               vtrk->expand_view = 1;
+               PluginSet *plugin_set = new PluginSet(mwindow->edl, vtrk);
+               vtrk->plugin_set.append(plugin_set);
+               Edits *edits = vtrk->edits;
+               for( Edit *edit=edits->first; edit; edit=edit->next ) {
+                       plugin_set->insert_plugin(title,
+                               edit->startproject, edit->length,
+                               PLUGIN_STANDALONE, 0, default_keyframe, 0);
+               }
+               vtrk->optimize();
+       }
+        return 0;
+}
+
+int CreateDVD_Thread::
+resize_tracks()
+{
+        Tracks *tracks = mwindow->edl->tracks;
+#if 0
+       int max_w = 0, max_h = 0;
+        for( Track *vtrk=tracks->first; vtrk; vtrk=vtrk->next ) {
+               if( vtrk->data_type != TRACK_VIDEO ) continue;
+               if( !vtrk->record ) continue;
+               Edits *edits = vtrk->edits;
+               for( Edit *edit=edits->first; edit; edit=edit->next ) {
+                       Indexable *indexable = edit->get_source();
+                       int w = indexable->get_w();
+                       if( w > max_w ) max_w = w;
+                       int h = indexable->get_h();
+                       if( h > max_h ) max_h = h;
+               }
+        }
+#endif
+        for( Track *vtrk=tracks->first; vtrk; vtrk=vtrk->next ) {
+                if( vtrk->data_type != TRACK_VIDEO ) continue;
+                if( !vtrk->record ) continue;
+               vtrk->track_w = DVD_WIDTH; // max_w;
+               vtrk->track_h = DVD_HEIGHT; // max_h;
+       }
+        return 0;
+}
+
+int CreateDVD_Thread::
+option_presets()
+{
+       if( !mwindow->edl ) return 1;
+        Tracks *tracks = mwindow->edl->tracks;
+       int max_w = 0, max_h = 0;
+       int has_deinterlace = 0, has_scale = 0;
+        for( Track *trk=tracks->first; trk; trk=trk->next ) {
+               if( !trk->record ) continue;
+               Edits *edits = trk->edits;
+               switch( trk->data_type ) {
+               case TRACK_VIDEO:
+                       for( Edit *edit=edits->first; edit; edit=edit->next ) {
+                               Indexable *indexable = edit->get_source();
+                               int w = indexable->get_w();
+                               if( w > max_w ) max_w = w;
+                               if( w != DVD_WIDTH ) use_scale = 1;
+                               int h = indexable->get_h();
+                               if( h > max_h ) max_h = h;
+                               if( h != DVD_HEIGHT ) use_scale = 1;
+                       }
+                       for( int i=0; i<trk->plugin_set.size(); ++i ) {
+                               for(Plugin *plugin = (Plugin*)trk->plugin_set[i]->first;
+                                                plugin;
+                                                plugin = (Plugin*)plugin->next) {
+                                       if( !strcmp(plugin->title, "Deinterlace") )
+                                               has_deinterlace = 1;
+                                       if( !strcmp(plugin->title, "Auto Scale") ||
+                                           !strcmp(plugin->title, "Scale") )
+                                               has_scale = 1;
+                               }
+                       }
+                       break;
+               }
+        }
+       if( has_scale )
+               use_scale = 0;
+       if( use_scale ) {
+               if( max_w != DVD_WIDTH ) use_resize_tracks = 1;
+               if( max_h != DVD_HEIGHT ) use_resize_tracks = 1;
+       }
+        for( Track *trk=tracks->first; trk && !use_resize_tracks; trk=trk->next ) {
+               if( !trk->record ) continue;
+               switch( trk->data_type ) {
+               case TRACK_VIDEO:
+                       if( trk->track_w != max_w ) use_resize_tracks = 1;
+                       if( trk->track_h != max_h ) use_resize_tracks = 1;
+                       break;
+               }
+        }
+       if( !has_deinterlace && max_h > 2*DVD_HEIGHT ) use_deinterlace = 1;
+       Labels *labels = mwindow->edl->labels;
+       use_label_chapters = labels && labels->first ? 1 : 0;
+       float w, h;
+       MWindow::create_aspect_ratio(w, h, max_w, max_h);
+       if( w == DVD_WIDE_ASPECT_WIDTH && h == DVD_WIDE_ASPECT_HEIGHT )
+               use_wide_aspect = 1;
+       if( tracks->recordable_audio_tracks() == DVD_WIDE_CHANNELS )
+               use_wide_audio = 1;
+       return 0;
+}
+
diff --git a/cinelerra-5.0/cinelerra/dvdcreate.h b/cinelerra-5.0/cinelerra/dvdcreate.h
new file mode 100644 (file)
index 0000000..a0d331f
--- /dev/null
@@ -0,0 +1,225 @@
+#ifndef __DVDCREATE_H__
+#define __DVDCREATE_H__
+
+#include "arraylist.h"
+#include "batchrender.h"
+#include "bcwindowbase.h"
+#include "bcbutton.h"
+#include "bcdialog.h"
+#include "bcmenuitem.h"
+#include "bctextbox.h"
+#include "mwindow.h"
+
+#include "dvdcreate.inc"
+
+
+class CreateDVD_MenuItem : public BC_MenuItem
+{
+public:
+       CreateDVD_MenuItem(MWindow *mwindow);
+       int handle_event();
+       MWindow *mwindow;
+};
+
+
+class CreateDVD_Thread : public BC_DialogThread
+{
+       static const int64_t DVD_SIZE;
+       static const int DVD_STREAMS, DVD_WIDTH, DVD_HEIGHT;
+       static const double DVD_ASPECT_WIDTH, DVD_ASPECT_HEIGHT;
+       static const double DVD_WIDE_ASPECT_WIDTH, DVD_WIDE_ASPECT_HEIGHT;
+       static const int DVD_MAX_BITRATE, DVD_CHANNELS, DVD_WIDE_CHANNELS;
+       static const double DVD_FRAMERATE, DVD_SAMPLERATE, DVD_KAUDIO_RATE;
+public:
+       CreateDVD_Thread(MWindow *mwindow);
+       ~CreateDVD_Thread();
+       void handle_close_event(int result);
+       BC_Window* new_gui();
+       int option_presets();
+       int create_dvd_jobs(ArrayList<BatchRenderJob*> *jobs,
+               const char *tmp_path, const char *asset_title);
+       int insert_video_plugin(const char *title, KeyFrame *default_keyframe);
+       int resize_tracks();
+
+       MWindow *mwindow;
+       CreateDVD_GUI *gui;
+       char asset_title[BCTEXTLEN];
+       char tmp_path[BCTEXTLEN];
+       int use_deinterlace, use_inverse_telecine;
+       int use_scale, use_resize_tracks;
+       int use_wide_audio, use_wide_aspect;
+       int use_histogram, use_label_chapters;
+       int use_ffmpeg;
+};
+
+class CreateDVD_OK : public BC_OKButton
+{
+public:
+       CreateDVD_OK(CreateDVD_GUI *gui, int x, int y);
+       ~CreateDVD_OK();
+       int button_press_event();
+       int keypress_event();
+
+       CreateDVD_GUI *gui;
+};
+
+class CreateDVD_Cancel : public BC_CancelButton
+{
+public:
+       CreateDVD_Cancel(CreateDVD_GUI *gui, int x, int y);
+       ~CreateDVD_Cancel();
+       int button_press_event();
+
+       CreateDVD_GUI *gui;
+};
+
+
+class CreateDVD_DiskSpace : public BC_Title
+{
+public:
+       CreateDVD_DiskSpace(CreateDVD_GUI *gui, int x, int y);
+       ~CreateDVD_DiskSpace();
+       int64_t tmp_path_space();
+       void update();
+
+       CreateDVD_GUI *gui;
+};
+
+class CreateDVD_TmpPath : public BC_TextBox
+{
+public:
+       CreateDVD_TmpPath(CreateDVD_GUI *gui, int x, int y, int w);
+       ~CreateDVD_TmpPath();
+       int handle_event();
+
+       CreateDVD_GUI *gui;
+};
+
+
+class CreateDVD_AssetTitle : public BC_TextBox
+{
+public:
+       CreateDVD_AssetTitle(CreateDVD_GUI *gui, int x, int y, int w);
+       ~CreateDVD_AssetTitle();
+
+       CreateDVD_GUI *gui;
+};
+
+class CreateDVD_Deinterlace : public BC_CheckBox
+{
+public:
+       CreateDVD_Deinterlace(CreateDVD_GUI *gui, int x, int y);
+       ~CreateDVD_Deinterlace();
+       int handle_event();
+
+       CreateDVD_GUI *gui;
+};
+
+class CreateDVD_InverseTelecine : public BC_CheckBox
+{
+public:
+       CreateDVD_InverseTelecine(CreateDVD_GUI *gui, int x, int y);
+       ~CreateDVD_InverseTelecine();
+       int handle_event();
+
+       CreateDVD_GUI *gui;
+};
+
+class CreateDVD_Scale : public BC_CheckBox
+{
+public:
+       CreateDVD_Scale(CreateDVD_GUI *gui, int x, int y);
+       ~CreateDVD_Scale();
+
+       CreateDVD_GUI *gui;
+};
+
+class CreateDVD_ResizeTracks : public BC_CheckBox
+{
+public:
+       CreateDVD_ResizeTracks(CreateDVD_GUI *gui, int x, int y);
+       ~CreateDVD_ResizeTracks();
+
+       CreateDVD_GUI *gui;
+};
+
+class CreateDVD_Histogram : public BC_CheckBox
+{
+public:
+       CreateDVD_Histogram(CreateDVD_GUI *gui, int x, int y);
+       ~CreateDVD_Histogram();
+
+       CreateDVD_GUI *gui;
+};
+
+class CreateDVD_LabelChapters : public BC_CheckBox
+{
+public:
+       CreateDVD_LabelChapters(CreateDVD_GUI *gui, int x, int y);
+       ~CreateDVD_LabelChapters();
+
+       CreateDVD_GUI *gui;
+};
+
+class CreateDVD_WideAudio : public BC_CheckBox
+{
+public:
+       CreateDVD_WideAudio(CreateDVD_GUI *gui, int x, int y);
+       ~CreateDVD_WideAudio();
+
+       CreateDVD_GUI *gui;
+};
+
+class CreateDVD_WideAspect : public BC_CheckBox
+{
+public:
+       CreateDVD_WideAspect(CreateDVD_GUI *gui, int x, int y);
+       ~CreateDVD_WideAspect();
+
+       CreateDVD_GUI *gui;
+};
+
+class CreateDVD_UseFFMpeg : public BC_CheckBox
+{
+public:
+       CreateDVD_UseFFMpeg(CreateDVD_GUI *gui, int x, int y);
+       ~CreateDVD_UseFFMpeg();
+
+       CreateDVD_GUI *gui;
+};
+
+class CreateDVD_GUI : public BC_Window
+{
+public:
+       CreateDVD_GUI(CreateDVD_Thread *thread,
+               int x, int y, int w, int h);
+       ~CreateDVD_GUI();
+
+       void create_objects();
+       int resize_event(int w, int h);
+       int translation_event();
+       int close_event();
+
+       int64_t needed_disk_space;
+       CreateDVD_Thread *thread;
+       int at_x, at_y;
+       CreateDVD_AssetTitle *asset_title;
+       int tmp_x, tmp_y;
+       CreateDVD_TmpPath *tmp_path;
+       CreateDVD_DiskSpace *disk_space;
+       CreateDVD_Deinterlace *need_deinterlace;
+       CreateDVD_InverseTelecine *need_inverse_telecine;
+       CreateDVD_Scale *need_scale;
+       CreateDVD_UseFFMpeg *need_use_ffmpeg;
+       CreateDVD_ResizeTracks *need_resize_tracks;
+       CreateDVD_Histogram *need_histogram;
+       CreateDVD_WideAudio *need_wide_audio;
+       CreateDVD_WideAspect *need_wide_aspect;
+       CreateDVD_LabelChapters *need_label_chapters;
+       int ok_x, ok_y, ok_w, ok_h;
+       CreateDVD_OK *ok;
+       int cancel_x, cancel_y, cancel_w, cancel_h;
+       CreateDVD_Cancel *cancel;
+};
+
+#endif
diff --git a/cinelerra-5.0/cinelerra/dvdcreate.inc b/cinelerra-5.0/cinelerra/dvdcreate.inc
new file mode 100644 (file)
index 0000000..041404f
--- /dev/null
@@ -0,0 +1,29 @@
+
+/*
+ * CINELERRA
+ * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
+
+#ifndef __DVDCREATE_INC__
+#define __DVDCREATE_INC__
+
+class CreateDVD_MenuItem;
+class CreateDVD_Thread;
+class CreateDVD_GUI;
+
+#endif
index e3dd870d244aec43a37d57984f8c55301acc5cd9..3de5b8e79c6f2dc672354c9de8f24fad72eb1d37 100644 (file)
@@ -42,6 +42,7 @@ EditLengthThread::EditLengthThread(MWindow *mwindow)
 
 EditLengthThread::~EditLengthThread()
 {
+       close_window();
 }
 
 void EditLengthThread::start(Edit *edit)
index ce3d704461ffd0b009b27ed187df70880fe2ee57..68ff296d0013581d695f2bb713d75d4554f764eb 100644 (file)
@@ -958,8 +958,6 @@ AVRational FFMPEG::to_time_base(int sample_rate)
        return (AVRational){1, sample_rate};
 }
 
-extern void get_exe_path(char *result); // from main.C
-
 void FFMPEG::set_option_path(char *path, const char *fmt, ...)
 {
        get_exe_path(path);
@@ -1075,12 +1073,14 @@ int FFMPEG::read_options(const char *options, AVDictionary *&opts)
        return ret;
 }
 
-int FFMPEG::scan_options(const char *options, AVDictionary *&opts)
+int FFMPEG::scan_options(const char *options, AVDictionary *&opts, AVStream *st)
 {
        FILE *fp = fmemopen((void *)options,strlen(options),"r");
        if( !fp ) return 0;
        int ret = read_options(fp, options, opts);
        fclose(fp);
+       AVDictionaryEntry *tag = av_dict_get(opts, "id", NULL, 0);
+       if( tag ) st->id = strtol(tag->value,0,0);
        return ret;
 }
 
@@ -1437,7 +1437,7 @@ int FFMPEG::open_encoder(const char *type, const char *spec)
                                break;
                        }
                        has_audio = 1;
-                       if( scan_options(asset->ff_audio_options, sopts) ) {
+                       if( scan_options(asset->ff_audio_options, sopts, st) ) {
                                eprintf("FFMPEG::open_encoder: bad audio options %s:%s\n",
                                        codec_name, filename);
                                ret = 1;
@@ -1483,7 +1483,7 @@ int FFMPEG::open_encoder(const char *type, const char *spec)
                                break;
                        }
                        has_video = 1;
-                       if( scan_options(asset->ff_video_options, sopts) ) {
+                       if( scan_options(asset->ff_video_options, sopts, st) ) {
                                eprintf("FFMPEG::open_encoder: bad video options %s:%s\n",
                                        codec_name, filename);
                                ret = 1;
index 040bdcda3dfd148e16e0baa049f4eb04a33e6ad7..28b191489c950117049afe3c0ba23ddc2009a7fe 100644 (file)
@@ -235,7 +235,7 @@ public:
        int get_encoder(FILE *fp,
                char *format, char *codec, char *bsfilter, char *bsargs);
        int read_options(const char *options, AVDictionary *&opts);
-       int scan_options(const char *options, AVDictionary *&opts);
+       int scan_options(const char *options, AVDictionary *&opts, AVStream *st);
        int read_options(FILE *fp, const char *options, AVDictionary *&opts);
        int load_options(const char *options, AVDictionary *&opts);
        static int load_options(const char *path, char *bfr, int len);
index b7d816d9b79618a848a75f22653728dc45b0ab71..c574921886e30ae954913b338e2e37f8a703a7dc 100644 (file)
@@ -2560,3 +2560,22 @@ int File::record_fd()
 }
 
 
+void get_exe_path(char *result)
+{
+// Get executable path
+       pid_t pid = getpid();
+       char proc_path[BCTEXTLEN];
+       int len = 0;
+       result[0] = 0;
+       sprintf(proc_path, "/proc/%d/exe", pid);
+       if((len = readlink(proc_path, result, BCTEXTLEN)) >= 0)
+       {
+               result[len] = 0;
+//printf("Preferences::Preferences %d %s\n", __LINE__, result);
+               char *ptr = strrchr(result, '/');
+               if(ptr) *ptr = 0;
+       }
+
+}
+
+
index 232a1453030bd6afbecb7bea87b4b68a67f49300..3651e74d7d20d4f92323147bdb741ffba54e9240 100644 (file)
@@ -187,4 +187,6 @@ class File;
 //result<0: continue skimming, result>=0: exit return code
 typedef int (*skim_fn)(void *vp, int track);
 
+void get_exe_path(char *result);
+
 #endif
index 280ed9d72107d85ca3344effb7c519cc4b5733f6..6a8681d4fe01cc530a7fdb075abc519c48528d9a 100644 (file)
@@ -319,7 +319,6 @@ int FileFFMPEG::get_best_colormodel(Asset *asset, int driver)
 }
 
 //======
-extern void get_exe_path(char *result); // from main.C
 
 FFMPEGConfigAudio::FFMPEGConfigAudio(BC_WindowBase *parent_window, Asset *asset)
  : BC_Window(_(PROGRAM_NAME ": Audio Preset"),
index ddd8fee17b34686614251445238cb1b85867d7e6..fd9a6e95d3dfad383a8475286569fcde2c024a01 100644 (file)
@@ -43,8 +43,6 @@ extern "C"
 }
 
 
-extern void get_exe_path(char *result);
-
 // Paths relative to the exe path
 #define FESTIVAL_PATH "/festival"
 #define FESTIVAL_LIB_PATH "/lib/"
index 9fa52dcd173df119f2b67f9d75d1795856504c49..ff14ae50849ca23109f9b5e98f4a7af29df10697 100644 (file)
@@ -60,6 +60,7 @@ KeyFrameThread::KeyFrameThread(MWindow *mwindow)
 
 KeyFrameThread::~KeyFrameThread()
 {
+       close_window();
        for(int i = 0; i < KEYFRAME_COLUMNS; i++)
                keyframe_data[i].remove_all_objects();
        delete [] keyframe_data;
@@ -206,18 +207,6 @@ void KeyFrameThread::handle_close_event(int result)
        keyframe = 0;
 }
 
-void KeyFrameThread::close_window()
-{
-       lock_window("KeyFrameThread::close_window");
-       if(get_gui())
-       {
-               get_gui()->lock_window("KeyFrameThread::close_window");
-               get_gui()->set_done(1);
-               get_gui()->unlock_window();
-       }
-       unlock_window();
-}
-
 
 
 void KeyFrameThread::calculate_preset_list()
index a2fffdc1a3343b561dff2a97dfcfe51a748b9dc5..4d65c16a31e19eb83c6367713fb5eade966ede01 100644 (file)
@@ -55,7 +55,6 @@ public:
        void apply_value();
        void calculate_preset_list();
        void update_gui(int update_value_text = 1);
-       void close_window();
 
        ArrayList<BC_ListBoxItem*> *keyframe_data;
        Plugin *plugin;
index f45e171599bd0a217bfe31c832885e9289dd70eb..18e2975ca874160fc4d16738ec80344c339b9943 100644 (file)
@@ -80,6 +80,7 @@ LoadFileThread::LoadFileThread(MWindow *mwindow, Load *load)
 
 LoadFileThread::~LoadFileThread()
 {
+       close_window();
 }
 
 BC_Window* LoadFileThread::new_gui()
index 1df7ff000662e95091655442cfe2bb70c0664fe7..2f167ac0df30019fc80c63701d11e6cd6ccd3016 100644 (file)
@@ -22,6 +22,7 @@
 #include "batchrender.h"
 #include "bcsignals.h"
 #include "edl.h"
+#include "file.inc"
 #include "filexml.h"
 #include "fileserver.h"
 #include "filesystem.h"
@@ -91,25 +92,6 @@ public:
 };
 
 
-void get_exe_path(char *result)
-{
-// Get executable path
-       pid_t pid = getpid();
-       char proc_path[BCTEXTLEN];
-       int len = 0;
-       result[0] = 0;
-       sprintf(proc_path, "/proc/%d/exe", pid);
-       if((len = readlink(proc_path, result, BCTEXTLEN)) >= 0)
-       {
-               result[len] = 0;
-//printf("Preferences::Preferences %d %s\n", __LINE__, result);
-               char *ptr = strrchr(result, '/');
-               if(ptr) *ptr = 0;
-       }
-
-}
-
-
 int main(int argc, char *argv[])
 {
 // handle command line arguments first
index f62e8549e0c4b22159a8164a2c67eaa42b2367d8..38ae3ac12104429905a40d07ee021c2432865a50 100644 (file)
@@ -127,6 +127,7 @@ MainError::MainError(MWindow *mwindow)
 
 MainError::~MainError()
 {
+       close_window();
        delete errors_lock;
 }
 
index 4912aadb38cf06ffb949a19469a36b00aa9ec5a2..0759654c8ce564f9d99f93d3043f1c8327d6ba7f 100644 (file)
@@ -25,6 +25,7 @@
 #include "bcdisplayinfo.h"
 #include "bchash.h"
 #include "bcsignals.h"
+#include "bdcreate.h"
 #include "cache.h"
 #include "channelinfo.h"
 #include "cplayback.h"
@@ -32,6 +33,7 @@
 #include "cwindow.h"
 #include "cwindowgui.h"
 #include "dbwindow.h"
+#include "dvdcreate.h"
 #include "edl.h"
 #include "edlsession.h"
 #include "featheredits.h"
@@ -116,6 +118,7 @@ void MainMenu::create_objects()
 
        filemenu->add_item(render = new RenderItem(mwindow));
        filemenu->add_item(new BatchRenderMenuItem(mwindow));
+       filemenu->add_item(new CreateBD_MenuItem(mwindow));
        filemenu->add_item(new CreateDVD_MenuItem(mwindow));
        filemenu->add_item(new BC_MenuItem("-"));
        filemenu->add_item(quit_program = new Quit(mwindow));
@@ -241,7 +244,7 @@ void MainMenu::create_objects()
        windowmenu->add_item(show_lwindow = new ShowLWindow(mwindow));
        windowmenu->add_item(split_x = new SplitX(mwindow));
        windowmenu->add_item(split_y = new SplitY(mwindow));
-       windowmenu->add_item(new TileWindows(mwindow,_("Default positions"),-1,_("Ctrl+d"),'d'));
+       windowmenu->add_item(new TileWindows(mwindow,_("Default positions"),-1,_("Ctrl+P"),'p'));
        windowmenu->add_item(new TileWindows(mwindow,_("Tile left"),0));
        windowmenu->add_item(new TileWindows(mwindow,_("Tile right"),1));
 }
index 7461d1e578a71ae972736dd8b0f294dd1394d882..fa1e89659bf52c0b0c09b723350534d3c6bfe95a 100644 (file)
@@ -63,6 +63,11 @@ TransitionDialogThread::TransitionDialogThread(MWindow *mwindow, int data_type)
        this->data_type = data_type;
 }
 
+TransitionDialogThread::~TransitionDialogThread()
+{
+       close_window();
+}
+
 void TransitionDialogThread::start()
 {
        if(!transition_names.total)
index 64c5c51c8dcc01b3417c0b65d653a29ba118300d..1e02fd5125ea7a0c1c0a94624261357a9c36f1d8 100644 (file)
@@ -52,6 +52,7 @@ class TransitionDialogThread : public BC_DialogThread
 {
 public:
        TransitionDialogThread(MWindow *mwindow, int data_type);
+       ~TransitionDialogThread();
        BC_Window* new_gui();
        void handle_close_event(int result);
        void start();
index 8fffe15fd88eab00d98ce7cfdcb28c59cf4e64d0..4c3bf0bc4f880fd2dd81db5f6aff844819e71e95 100644 (file)
@@ -27,6 +27,7 @@
 #include "bcdisplayinfo.h"
 #include "bcsignals.h"
 #include "bctimer.h"
+#include "bdcreate.h"
 #include "brender.h"
 #include "cache.h"
 #include "channel.h"
@@ -41,6 +42,7 @@
 #include "cwindow.h"
 #include "bchash.h"
 #include "devicedvbinput.inc"
+#include "dvdcreate.h"
 #include "editpanel.h"
 #include "edl.h"
 #include "edlsession.h"
@@ -192,6 +194,7 @@ MWindow::MWindow()
        plugin_guis = 0;
        dead_plugins = 0;
        keyframe_threads = 0;
+       create_bd = 0;
        create_dvd = 0;
        batch_render = 0;
        render = 0;
@@ -222,6 +225,7 @@ MWindow::~MWindow()
        brender_lock->lock("MWindow::quit");
        delete brender;         brender = 0;
        brender_lock->unlock();
+       delete create_bd;       create_bd = 0;
        delete create_dvd;      create_dvd = 0;
        delete batch_render;    batch_render = 0;
        commit_commercial();
@@ -847,6 +851,7 @@ ENABLE_BUFFER
 void MWindow::init_render()
 {
        render = new Render(this);
+       create_bd = new CreateBD_Thread(this);
        create_dvd = new CreateDVD_Thread(this);
        batch_render = new BatchRenderThread(this);
 }
@@ -1990,6 +1995,7 @@ int MWindow::set_editing_mode(int new_editing_mode, int lock_mwindow, int lock_c
 
 void MWindow::sync_parameters(int change_type)
 {
+       if( in_destructor ) return;
 
 // Sync engines which are playing back
        if(cwindow->playback_engine->is_playing_back)
index e6bd368f7dafda06256a23f13f2462bcd4f8e224..79ef49da3f3cfec8562042adc65a09809cdc93ad 100644 (file)
@@ -31,6 +31,7 @@
 #include "awindow.inc"
 #include "batchrender.inc"
 #include "bcwindowbase.inc"
+#include "bdcreate.inc"
 #include "brender.inc"
 #include "cache.inc"
 #include "channel.inc"
@@ -40,6 +41,7 @@
 #include "bchash.inc"
 #include "devicedvbinput.inc"
 #include "devicempeginput.inc"
+#include "dvdcreate.inc"
 #include "edit.inc"
 #include "edl.inc"
 #include "fileserver.inc"
@@ -537,6 +539,7 @@ public:
                int64_t samples_in);
 
 
+       CreateBD_Thread *create_bd;
        CreateDVD_Thread *create_dvd;
        BatchRenderThread *batch_render;
        Render *render;
index 882fe8264dd0a68970368efc6deaf00c2fe3be86..86a41fcc8459ca611ac30b9d7a8facc496dd1306 100644 (file)
@@ -259,7 +259,7 @@ void MWindowGUI::create_objects()
        
        if(debug) printf("MWindowGUI::create_objects %d\n", __LINE__);
 
-       int x = get_w() - MainShBtns::calculate_w(1);
+       int x = get_w() - MainShBtns::calculate_w(0);
        add_subwindow(mainmenu = new MainMenu(mwindow, this, x));
        add_subwindow(mainshbtns = new MainShBtns(mwindow, x, 0));
        mainshbtns->load(mwindow->preferences);
index 6dc520be4a19b0e33584050d90e5ee3f85d90a5f..fe1376442b4f4b4569317d38db750d53a9ed2179 100644 (file)
@@ -147,6 +147,7 @@ NewThread::NewThread(MWindow *mwindow, New *new_project)
 
 NewThread::~NewThread()
 {
+       close_window();
 }
 
 
index 0a6927d30fecbb892e85d0197f017635a51c5cbe..c7b3e3b132bb8a0c5d2c352f8398f5c93f49ff6a 100644 (file)
@@ -49,6 +49,7 @@ PluginDialogThread::PluginDialogThread(MWindow *mwindow)
 
 PluginDialogThread::~PluginDialogThread()
 {
+       close_window();
 }
 
 void PluginDialogThread::start_window(Track *track,
index dbee6ccf292e6e845bd81f76e7e78f01b13ced65..0a8d33748ab8607d05a0726ee1516adb52cffe85 100644 (file)
@@ -51,8 +51,6 @@
 
 
 
-extern void get_exe_path(char *result);
-
 
 
 
index 867898b49f84cf6aafb0f61c1054853a548cbd95..f418ba25af742fd8510dff18ad94b5f6a2f0b1b9 100644 (file)
@@ -100,6 +100,7 @@ PreferencesThread::PreferencesThread(MWindow *mwindow)
 
 PreferencesThread::~PreferencesThread()
 {
+       close_window();
 }
 
 BC_Window* PreferencesThread::new_gui()
index 5fc8d1ebbddc98d01e73e03a9e72b4a8fd47cfb9..dad7f35cd920cf703399bca539cbd2c294e7c220 100644 (file)
@@ -63,6 +63,7 @@ PresetsThread::PresetsThread(MWindow *mwindow)
 
 PresetsThread::~PresetsThread()
 {
+       close_window();
        delete data;
 }
 
index 933e7ef04e71f1e54eaa0829421eb57ab3e7861b..42cd9da4e3ff94d2aa4a114ec25d38bf1be7f124 100644 (file)
@@ -1898,8 +1898,6 @@ int Record::stop_commercial_capture(int run_job)
        return result;
 }
 
-extern void get_exe_path(char *result); // from main.C
-
 int Record::
 spawn(const char *fmt, ...)
 {
index e0ee79139a2be191e285e716439c66444934da36..4a3cebf9258bde18d0e1c033fa6ad7fa7db10255 100644 (file)
@@ -39,6 +39,7 @@ RecordScopeThread::RecordScopeThread(MWindow *mwindow, RecordMonitor *record_mon
 
 RecordScopeThread::~RecordScopeThread()
 {
+       close_window();
        delete gui_lock;
 }
 
index f664512e7d0bab7a42d2239788576798583c0d97..d4dabf3de9316c72d5b9ba6ae3b8b052e59864f9 100644 (file)
@@ -267,6 +267,7 @@ Render::Render(MWindow *mwindow)
 
 Render::~Render()
 {
+       close_window();
        delete package_lock;
        delete counter_lock;
        delete completion;
index 54d71acdb82b369eb2e27fcc11fe44f8d1e40ea3..7c6a5f4120ed63bccc93e3177ce3f823c052fc9e 100644 (file)
@@ -338,7 +338,7 @@ static VFrame *shbtn_images[] = {
 };
 
 MainShBtns::MainShBtns(MWindow *mwindow, int x, int y)
- : BC_PopupMenu(x, y, 32, "", 1, shbtn_images)
+ : BC_PopupMenu(x, y, 0, "", -1, shbtn_images)
 {
        this->mwindow = mwindow;
        set_tooltip(_("shell cmds"));
index c416dd519f96d3c523372df7309d9b796b420dd4..b326ce0b3fa5252848484ac918b0fe01af46ada1 100644 (file)
@@ -87,6 +87,11 @@ TipWindow::TipWindow(MWindow *mwindow)
        this->mwindow = mwindow;
 }
 
+TipWindow::~TipWindow()
+{
+       close_window();
+}
+
 void TipWindow::handle_close_event(int result)
 {
        gui = 0;
index d5b98435cd58ec18fcef88ec000ee9a3330e3242..87f594dcf53ec91426b27b7d0c66ff0520363767 100644 (file)
@@ -36,6 +36,7 @@ class TipWindow : public BC_DialogThread
 {
 public:
        TipWindow(MWindow *mwindow);
+       ~TipWindow();
        void handle_close_event(int result);
 
        BC_Window* new_gui();
index 3c1b8e683f7969a627700e466f6fe39f3a1455ef..1418d705ae54c2bc4711b146551006c8ac9666aa 100644 (file)
@@ -42,6 +42,7 @@ TransitionLengthThread::TransitionLengthThread(MWindow *mwindow)
 
 TransitionLengthThread::~TransitionLengthThread()
 {
+       close_window();
 }
 
 void TransitionLengthThread::start(Transition *transition, 
index a7e7fa78ea18fe341366f902323526e4ff2c9a10..57459ef9d154087f0e4099b64e2a11493a79be96 100644 (file)
@@ -46,7 +46,8 @@
 #include "vwindowgui.h"
 
 
-VWindow::VWindow(MWindow *mwindow) : BC_DialogThread()
+VWindow::VWindow(MWindow *mwindow)
+ : BC_DialogThread()
 {
        this->mwindow = mwindow;
        gui = 0;
@@ -60,10 +61,7 @@ VWindow::VWindow(MWindow *mwindow) : BC_DialogThread()
 
 VWindow::~VWindow()
 {
-       if(is_running()) {
-               close_window();
-               join();
-       }
+       close_window();
 //printf("VWindow::~VWindow 1\n");
        delete playback_engine;
 //printf("VWindow::~VWindow 1\n");
index b34ebdf0e02fbf13a826bfb27eb680704c680830..e0db1b7ca4d0ab1101625c68795da36e4457a480 100644 (file)
@@ -33,6 +33,11 @@ WWindow::WWindow(MWindow *mwindow)
        this->mwindow = mwindow;
 }
 
+WWindow::~WWindow()
+{
+       close_window();
+}
+
 void WWindow::show_warning(int *do_warning, const char *warn_text)
 {
        if( running() ) return;
index b7db85b8de778f0c38d4339416b3936b69b6aae0..b1f9b67251273993fa266f6277d672e14d7e43c1 100644 (file)
@@ -37,6 +37,7 @@ class WWindow : public BC_DialogThread
 {
 public:
        WWindow(MWindow *mwindow);
+       ~WWindow();
        void handle_close_event(int result);
        void show_warning(int *do_warning, const char *warn_text);
        BC_Window* new_gui();
index df43a8fb2cda20a6fbb0dc13df128df908440cfe..45fd78be92f13cfdbfc052ae8a247367cff7fff2 100644 (file)
@@ -1,4 +1,5 @@
 mpegts ac3
+id 0x1100
 maxrate 9000000
 minrate 0
 bufsize 1835008
index be70ceff2474cf5b12b1bff74e1245190b935e9f..90de1b93317e6a96d1ff8bb5c0bf559947a8f6fa 100644 (file)
@@ -1,24 +1,7 @@
 mpegts libx264
-partitions=i8x8,i4x4,p8x8,b8x8
-me_method=hex
-subq=7
-me_range=16
-g=250
-keyint_min=25
-sc_threshold=40
-i_qfactor=0.71
-b_strategy=1
-qcomp=0.6
-qmin=10
-qmax=51
-qdiff=4
-bf=3
-refs=3
-directpred=1
-trellis=1
-mixed-refs=1
-weightp=2
-8x8dct=1
-fast-pskip=1
-mbtree=1
+id=0x1011
+profile=baseline
+level=3.0
+preset=medium
 bluray-compat=1
+x264opts keyint=25:min-keyint=4:qpmin=3:qpmax=33:qp_step=4:merange=8
index 59688e6cbbf3124604d469a88945620c590fdd5f..e65b40d6552b11d7ecfb5ee0f507376c9148ba7e 100644 (file)
@@ -86,7 +86,7 @@ BC_PopupMenu::BC_PopupMenu(int x,
                images[i] = 0;
        }
        this->data = data;
-       this->w_argument = 0;
+       this->w_argument = -1;
        status = BUTTON_UP;
 }
 
@@ -166,7 +166,7 @@ int BC_PopupMenu::set_images(VFrame **data)
                images[i] = new BC_Pixmap(parent_window, data[i], PIXMAP_ALPHA);
        }
 
-       if(w_argument > 0)
+       if(w_argument >= 0)
                w = w_argument +
                        margin +
                        resources->popupmenu_triangle_margin;
@@ -257,9 +257,9 @@ int BC_PopupMenu::draw_title(int flush)
                        get_h() / 2 - icon->get_h() / 2 + offset);
        }
 
-       draw_triangle_down_flat(get_w() - margin - resources->popupmenu_triangle_margin,
-               get_h() / 2 - TRIANGLE_H / 2,
-               TRIANGLE_W, TRIANGLE_H);
+       if( use_title >= 0 )
+               draw_triangle_down_flat(get_w() - margin - resources->popupmenu_triangle_margin,
+                       get_h() / 2 - TRIANGLE_H / 2, TRIANGLE_W, TRIANGLE_H);
 
        flash(flush);
        return 0;
index ec51f20675a085d8594a07c706cd860b4945c066..6f4ffb263e1ab80f6562896269e4673d7dabc9b8 100644 (file)
@@ -247,7 +247,7 @@ void ScaleMain::calculate_transfer(VFrame *frame,
        }
 
        if(out_y1 < 0) {
-               in_y1 = y_factor>0 ? in_y1 - out_y1/config.y_factor : 0;
+               in_y1 = y_factor>0 ? in_y1 - out_y1/y_factor : 0;
                out_y1 = 0;
        }