From 91efd376233a15f6572e6f68d28a5bee69797e87 Mon Sep 17 00:00:00 2001 From: Good Guy Date: Sat, 15 Aug 2015 19:17:49 -0600 Subject: [PATCH] add bluray support, add dialog close fixes, scale fix --- cinelerra-5.0/build/Makefile.cinelerra | 4 +- cinelerra-5.0/cinelerra/Makefile | 66 +- cinelerra-5.0/cinelerra/assetedit.C | 3 +- cinelerra-5.0/cinelerra/awindowgui.C | 1 + cinelerra-5.0/cinelerra/batchrender.C | 822 +---- cinelerra-5.0/cinelerra/batchrender.h | 215 +- cinelerra-5.0/cinelerra/batchrender.inc | 4 - cinelerra-5.0/cinelerra/bdcreate.C | 754 +++++ cinelerra-5.0/cinelerra/bdcreate.h | 216 ++ cinelerra-5.0/cinelerra/bdcreate.inc | 29 + cinelerra-5.0/cinelerra/bdwrite.C | 3012 +++++++++++++++++ cinelerra-5.0/cinelerra/channeledit.C | 5 + cinelerra-5.0/cinelerra/channeledit.h | 1 + cinelerra-5.0/cinelerra/clipedit.C | 1 + cinelerra-5.0/cinelerra/dvdcreate.C | 840 +++++ cinelerra-5.0/cinelerra/dvdcreate.h | 225 ++ cinelerra-5.0/cinelerra/dvdcreate.inc | 29 + cinelerra-5.0/cinelerra/editlength.C | 1 + cinelerra-5.0/cinelerra/ffmpeg.C | 10 +- cinelerra-5.0/cinelerra/ffmpeg.h | 2 +- cinelerra-5.0/cinelerra/file.C | 19 + cinelerra-5.0/cinelerra/file.inc | 2 + cinelerra-5.0/cinelerra/fileffmpeg.C | 1 - cinelerra-5.0/cinelerra/filescene.C | 2 - cinelerra-5.0/cinelerra/keyframegui.C | 13 +- cinelerra-5.0/cinelerra/keyframegui.h | 1 - cinelerra-5.0/cinelerra/loadfile.C | 1 + cinelerra-5.0/cinelerra/main.C | 20 +- cinelerra-5.0/cinelerra/mainerror.C | 1 + cinelerra-5.0/cinelerra/mainmenu.C | 5 +- .../cinelerra/menuattachtransition.C | 5 + .../cinelerra/menuattachtransition.h | 1 + cinelerra-5.0/cinelerra/mwindow.C | 6 + cinelerra-5.0/cinelerra/mwindow.h | 3 + cinelerra-5.0/cinelerra/mwindowgui.C | 2 +- cinelerra-5.0/cinelerra/new.C | 1 + cinelerra-5.0/cinelerra/plugindialog.C | 1 + cinelerra-5.0/cinelerra/preferences.C | 2 - cinelerra-5.0/cinelerra/preferencesthread.C | 1 + cinelerra-5.0/cinelerra/presetsgui.C | 1 + cinelerra-5.0/cinelerra/record.C | 2 - cinelerra-5.0/cinelerra/recordscopes.C | 1 + cinelerra-5.0/cinelerra/render.C | 1 + cinelerra-5.0/cinelerra/shbtnprefs.C | 2 +- cinelerra-5.0/cinelerra/tipwindow.C | 5 + cinelerra-5.0/cinelerra/tipwindow.h | 1 + cinelerra-5.0/cinelerra/transitionpopup.C | 1 + cinelerra-5.0/cinelerra/vwindow.C | 8 +- cinelerra-5.0/cinelerra/wwindow.C | 5 + cinelerra-5.0/cinelerra/wwindow.h | 1 + cinelerra-5.0/ffmpeg/audio/bluray.m2ts | 1 + cinelerra-5.0/ffmpeg/video/bluray.m2ts | 27 +- cinelerra-5.0/guicast/bcpopupmenu.C | 10 +- cinelerra-5.0/plugins/scale/scale.C | 2 +- 54 files changed, 5248 insertions(+), 1147 deletions(-) create mode 100644 cinelerra-5.0/cinelerra/bdcreate.C create mode 100644 cinelerra-5.0/cinelerra/bdcreate.h create mode 100644 cinelerra-5.0/cinelerra/bdcreate.inc create mode 100644 cinelerra-5.0/cinelerra/bdwrite.C create mode 100644 cinelerra-5.0/cinelerra/dvdcreate.C create mode 100644 cinelerra-5.0/cinelerra/dvdcreate.h create mode 100644 cinelerra-5.0/cinelerra/dvdcreate.inc diff --git a/cinelerra-5.0/build/Makefile.cinelerra b/cinelerra-5.0/build/Makefile.cinelerra index f2db54be..a46f2182 100644 --- a/cinelerra-5.0/build/Makefile.cinelerra +++ b/cinelerra-5.0/build/Makefile.cinelerra @@ -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 diff --git a/cinelerra-5.0/cinelerra/Makefile b/cinelerra-5.0/cinelerra/Makefile index 8fb3bcda..9d7c8c14 100644 --- a/cinelerra-5.0/cinelerra/Makefile +++ b/cinelerra-5.0/cinelerra/Makefile @@ -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 \ diff --git a/cinelerra-5.0/cinelerra/assetedit.C b/cinelerra-5.0/cinelerra/assetedit.C index 443733cc..e52f39c7 100644 --- a/cinelerra-5.0/cinelerra/assetedit.C +++ b/cinelerra-5.0/cinelerra/assetedit.C @@ -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; diff --git a/cinelerra-5.0/cinelerra/awindowgui.C b/cinelerra-5.0/cinelerra/awindowgui.C index 70f32f7f..fdcb4cd3 100644 --- a/cinelerra-5.0/cinelerra/awindowgui.C +++ b/cinelerra-5.0/cinelerra/awindowgui.C @@ -679,6 +679,7 @@ AWindowRemovePlugin(AWindow *awindow, PluginServer *plugin) AWindowRemovePlugin:: ~AWindowRemovePlugin() { + close_window(); } BC_Window* AWindowRemovePlugin::new_gui() diff --git a/cinelerra-5.0/cinelerra/batchrender.C b/cinelerra-5.0/cinelerra/batchrender.C index eee74417..cede6c96 100644 --- a/cinelerra-5.0/cinelerra/batchrender.C +++ b/cinelerra-5.0/cinelerra/batchrender.C @@ -54,13 +54,6 @@ #include "transportque.h" #include "vframe.h" -#include -#include -#include -#include -#include - - 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 *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 - <\n"); - fprintf(fp," \n"); - fprintf(fp," jump title 1; \n"); - fprintf(fp," \n"); - fprintf(fp," \n"); - fprintf(fp," \n"); - fprintf(fp," \n"); - fprintf(fp," \n"); - fprintf(fp,"\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,""); - keyframe.set_data(data); - insert_video_plugin("Deinterlace", &keyframe); - } - if( use_inverse_telecine ) { - sprintf(data,""); - keyframe.set_data(data); - insert_video_plugin("Inverse Telecine", &keyframe); - } - if( use_scale ) { - sprintf(data,"", 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, "" - "" - "" - ""); -#else - sprintf(data, ""); -#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_spaceneeded_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; iplugin_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; -} - diff --git a/cinelerra-5.0/cinelerra/batchrender.h b/cinelerra-5.0/cinelerra/batchrender.h index 3fa7418b..e426decc 100644 --- a/cinelerra-5.0/cinelerra/batchrender.h +++ b/cinelerra-5.0/cinelerra/batchrender.h @@ -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 *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/batchrender.inc b/cinelerra-5.0/cinelerra/batchrender.inc index a4d2721e..3d4d753d 100644 --- a/cinelerra-5.0/cinelerra/batchrender.inc +++ b/cinelerra-5.0/cinelerra/batchrender.inc @@ -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 index 00000000..50748492 --- /dev/null +++ b/cinelerra-5.0/cinelerra/bdcreate.C @@ -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 +#include +#include +#include +#include + +// 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 *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,""); + keyframe.set_data(data); + insert_video_plugin("Deinterlace", &keyframe); + } + if( use_inverse_telecine ) { + sprintf(data,""); + keyframe.set_data(data); + insert_video_plugin("Inverse Telecine", &keyframe); + } + if( use_scale ) { + sprintf(data,"", 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, "" + "" + "" + ""); +#else + sprintf(data, ""); +#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_spaceneeded_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; iplugin_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 index 00000000..cdea0665 --- /dev/null +++ b/cinelerra-5.0/cinelerra/bdcreate.h @@ -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 *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 index 00000000..77bb2546 --- /dev/null +++ b/cinelerra-5.0/cinelerra/bdcreate.inc @@ -0,0 +1,29 @@ + +/* + * CINELERRA + * Copyright (C) 2008 Adam Williams + * + * 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 index 00000000..3ac4b0ff --- /dev/null +++ b/cinelerra-5.0/cinelerra/bdwrite.C @@ -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 ... +// == - | -- | --- +// may be empty string, or a numeric pgm_pid for curr title clip +// defaults to first pgm probed. +// == ... +// 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 /BDMV /mnt1/. +// umount /mnt1 +// eject sr1 +// +#ifndef __BD_H__ +#define __BD_H__ +#include +#include +#include +#include +#include +#include +#include +#include + +#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 video_streams; + ArrayList audio_streams; + ArrayList pg_streams; + ArrayList ig_streams; + ArrayList sec_audio_streams; + ArrayList 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 clips; + ArrayList chapters; + ArrayList 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 stc_seq; + int write(); + + clpi_atc_seq() {} + ~clpi_atc_seq() { + stc_seq.remove_all_objects(); + } +}; + +class clpi_sequences : public bs_length, + public ArrayList { +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 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 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 coarse; + ArrayList 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 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 { +public: + int write(); + + clpi_programs() {} + ~clpi_programs() { remove_all_objects(); } +}; + +class clpi_extents : public bs_length, + public ArrayList { +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 { +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 video; + ArrayList audio; + ArrayList pg; + ArrayList ig; + ArrayList secondary_audio; + ArrayList secondary_video; + // Secondary audio specific fields + ArrayList sa_primary_audio_ref; + // Secondary video specific fields + ArrayList sv_secondary_audio_ref; + ArrayList 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 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 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 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 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 play_item; + ArrayList sub_path; + ArrayList play_mark; + // extension data (profile 5, version 2.4) + ArrayList ext_sub_path; + // extension data (Picture-In-Picture metadata) + ArrayList 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 cmds; + + movie_obj() {} + ~movie_obj() { + cmds.remove_all_objects(); + } +}; + +class movie_file : public bs_length { +public: + int sig; + ArrayList 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 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 strm_idx; + ArrayList 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 streams; + ArrayList 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 { +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 cl; + ArrayList 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 &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; iipid != 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; jjstrm_idx.append(jj); + } + + for( int ii=0; iiprograms[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 && iistrm_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; iiend_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; iiresume_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; iiset_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; jjprograms.size(); ++jj ) { + program *pgm = ip->programs[jj]; + clpi_prog *p = new clpi_prog(pgm->pmt_pid); + for( int kk=0; kkstrm_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; iiprog(); + 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; kkstreams.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; iiwrite() ) return 1; + if( bd_backup("CLIPINF/%05d.clpi", ii) ) return 1; + } +// playlists + for( int ii=0; iiwrite() ) 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; iibrk = 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; iifilename, "STREAM/%05d.m2ts", ii) ) + return 1; + + return 0; +} + diff --git a/cinelerra-5.0/cinelerra/channeledit.C b/cinelerra-5.0/cinelerra/channeledit.C index 1e1184c2..643bd728 100644 --- a/cinelerra-5.0/cinelerra/channeledit.C +++ b/cinelerra-5.0/cinelerra/channeledit.C @@ -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); diff --git a/cinelerra-5.0/cinelerra/channeledit.h b/cinelerra-5.0/cinelerra/channeledit.h index 4a2f2f39..2d88ad8b 100644 --- a/cinelerra-5.0/cinelerra/channeledit.h +++ b/cinelerra-5.0/cinelerra/channeledit.h @@ -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; diff --git a/cinelerra-5.0/cinelerra/clipedit.C b/cinelerra-5.0/cinelerra/clipedit.C index 23c756af..76cd8744 100644 --- a/cinelerra-5.0/cinelerra/clipedit.C +++ b/cinelerra-5.0/cinelerra/clipedit.C @@ -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 index 00000000..ad3a8a20 --- /dev/null +++ b/cinelerra-5.0/cinelerra/dvdcreate.C @@ -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 +#include +#include +#include +#include + +// 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 *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 - <\n"); + fprintf(fp," \n"); + fprintf(fp," jump title 1; \n"); + fprintf(fp," \n"); + fprintf(fp," \n"); + fprintf(fp," \n"); + fprintf(fp," \n"); + fprintf(fp," \n"); + fprintf(fp,"\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,""); + keyframe.set_data(data); + insert_video_plugin("Deinterlace", &keyframe); + } + if( use_inverse_telecine ) { + sprintf(data,""); + keyframe.set_data(data); + insert_video_plugin("Inverse Telecine", &keyframe); + } + if( use_scale ) { + sprintf(data,"", 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, "" + "" + "" + ""); +#else + sprintf(data, ""); +#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_spaceneeded_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; iplugin_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 index 00000000..a0d331f7 --- /dev/null +++ b/cinelerra-5.0/cinelerra/dvdcreate.h @@ -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 *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 index 00000000..041404fc --- /dev/null +++ b/cinelerra-5.0/cinelerra/dvdcreate.inc @@ -0,0 +1,29 @@ + +/* + * CINELERRA + * Copyright (C) 2008 Adam Williams + * + * 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 diff --git a/cinelerra-5.0/cinelerra/editlength.C b/cinelerra-5.0/cinelerra/editlength.C index e3dd870d..3de5b8e7 100644 --- a/cinelerra-5.0/cinelerra/editlength.C +++ b/cinelerra-5.0/cinelerra/editlength.C @@ -42,6 +42,7 @@ EditLengthThread::EditLengthThread(MWindow *mwindow) EditLengthThread::~EditLengthThread() { + close_window(); } void EditLengthThread::start(Edit *edit) diff --git a/cinelerra-5.0/cinelerra/ffmpeg.C b/cinelerra-5.0/cinelerra/ffmpeg.C index ce3d7044..68ff296d 100644 --- a/cinelerra-5.0/cinelerra/ffmpeg.C +++ b/cinelerra-5.0/cinelerra/ffmpeg.C @@ -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; diff --git a/cinelerra-5.0/cinelerra/ffmpeg.h b/cinelerra-5.0/cinelerra/ffmpeg.h index 040bdcda..28b19148 100644 --- a/cinelerra-5.0/cinelerra/ffmpeg.h +++ b/cinelerra-5.0/cinelerra/ffmpeg.h @@ -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); diff --git a/cinelerra-5.0/cinelerra/file.C b/cinelerra-5.0/cinelerra/file.C index b7d816d9..c5749218 100644 --- a/cinelerra-5.0/cinelerra/file.C +++ b/cinelerra-5.0/cinelerra/file.C @@ -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; + } + +} + + diff --git a/cinelerra-5.0/cinelerra/file.inc b/cinelerra-5.0/cinelerra/file.inc index 232a1453..3651e74d 100644 --- a/cinelerra-5.0/cinelerra/file.inc +++ b/cinelerra-5.0/cinelerra/file.inc @@ -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 diff --git a/cinelerra-5.0/cinelerra/fileffmpeg.C b/cinelerra-5.0/cinelerra/fileffmpeg.C index 280ed9d7..6a8681d4 100644 --- a/cinelerra-5.0/cinelerra/fileffmpeg.C +++ b/cinelerra-5.0/cinelerra/fileffmpeg.C @@ -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"), diff --git a/cinelerra-5.0/cinelerra/filescene.C b/cinelerra-5.0/cinelerra/filescene.C index ddd8fee1..fd9a6e95 100644 --- a/cinelerra-5.0/cinelerra/filescene.C +++ b/cinelerra-5.0/cinelerra/filescene.C @@ -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/" diff --git a/cinelerra-5.0/cinelerra/keyframegui.C b/cinelerra-5.0/cinelerra/keyframegui.C index 9fa52dcd..ff14ae50 100644 --- a/cinelerra-5.0/cinelerra/keyframegui.C +++ b/cinelerra-5.0/cinelerra/keyframegui.C @@ -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() diff --git a/cinelerra-5.0/cinelerra/keyframegui.h b/cinelerra-5.0/cinelerra/keyframegui.h index a2fffdc1..4d65c16a 100644 --- a/cinelerra-5.0/cinelerra/keyframegui.h +++ b/cinelerra-5.0/cinelerra/keyframegui.h @@ -55,7 +55,6 @@ public: void apply_value(); void calculate_preset_list(); void update_gui(int update_value_text = 1); - void close_window(); ArrayList *keyframe_data; Plugin *plugin; diff --git a/cinelerra-5.0/cinelerra/loadfile.C b/cinelerra-5.0/cinelerra/loadfile.C index f45e1715..18e2975c 100644 --- a/cinelerra-5.0/cinelerra/loadfile.C +++ b/cinelerra-5.0/cinelerra/loadfile.C @@ -80,6 +80,7 @@ LoadFileThread::LoadFileThread(MWindow *mwindow, Load *load) LoadFileThread::~LoadFileThread() { + close_window(); } BC_Window* LoadFileThread::new_gui() diff --git a/cinelerra-5.0/cinelerra/main.C b/cinelerra-5.0/cinelerra/main.C index 1df7ff00..2f167ac0 100644 --- a/cinelerra-5.0/cinelerra/main.C +++ b/cinelerra-5.0/cinelerra/main.C @@ -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 diff --git a/cinelerra-5.0/cinelerra/mainerror.C b/cinelerra-5.0/cinelerra/mainerror.C index f62e8549..38ae3ac1 100644 --- a/cinelerra-5.0/cinelerra/mainerror.C +++ b/cinelerra-5.0/cinelerra/mainerror.C @@ -127,6 +127,7 @@ MainError::MainError(MWindow *mwindow) MainError::~MainError() { + close_window(); delete errors_lock; } diff --git a/cinelerra-5.0/cinelerra/mainmenu.C b/cinelerra-5.0/cinelerra/mainmenu.C index 4912aadb..0759654c 100644 --- a/cinelerra-5.0/cinelerra/mainmenu.C +++ b/cinelerra-5.0/cinelerra/mainmenu.C @@ -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)); } diff --git a/cinelerra-5.0/cinelerra/menuattachtransition.C b/cinelerra-5.0/cinelerra/menuattachtransition.C index 7461d1e5..fa1e8965 100644 --- a/cinelerra-5.0/cinelerra/menuattachtransition.C +++ b/cinelerra-5.0/cinelerra/menuattachtransition.C @@ -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) diff --git a/cinelerra-5.0/cinelerra/menuattachtransition.h b/cinelerra-5.0/cinelerra/menuattachtransition.h index 64c5c51c..1e02fd51 100644 --- a/cinelerra-5.0/cinelerra/menuattachtransition.h +++ b/cinelerra-5.0/cinelerra/menuattachtransition.h @@ -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(); diff --git a/cinelerra-5.0/cinelerra/mwindow.C b/cinelerra-5.0/cinelerra/mwindow.C index 8fffe15f..4c3bf0bc 100644 --- a/cinelerra-5.0/cinelerra/mwindow.C +++ b/cinelerra-5.0/cinelerra/mwindow.C @@ -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) diff --git a/cinelerra-5.0/cinelerra/mwindow.h b/cinelerra-5.0/cinelerra/mwindow.h index e6bd368f..79ef49da 100644 --- a/cinelerra-5.0/cinelerra/mwindow.h +++ b/cinelerra-5.0/cinelerra/mwindow.h @@ -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; diff --git a/cinelerra-5.0/cinelerra/mwindowgui.C b/cinelerra-5.0/cinelerra/mwindowgui.C index 882fe826..86a41fcc 100644 --- a/cinelerra-5.0/cinelerra/mwindowgui.C +++ b/cinelerra-5.0/cinelerra/mwindowgui.C @@ -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); diff --git a/cinelerra-5.0/cinelerra/new.C b/cinelerra-5.0/cinelerra/new.C index 6dc520be..fe137644 100644 --- a/cinelerra-5.0/cinelerra/new.C +++ b/cinelerra-5.0/cinelerra/new.C @@ -147,6 +147,7 @@ NewThread::NewThread(MWindow *mwindow, New *new_project) NewThread::~NewThread() { + close_window(); } diff --git a/cinelerra-5.0/cinelerra/plugindialog.C b/cinelerra-5.0/cinelerra/plugindialog.C index 0a6927d3..c7b3e3b1 100644 --- a/cinelerra-5.0/cinelerra/plugindialog.C +++ b/cinelerra-5.0/cinelerra/plugindialog.C @@ -49,6 +49,7 @@ PluginDialogThread::PluginDialogThread(MWindow *mwindow) PluginDialogThread::~PluginDialogThread() { + close_window(); } void PluginDialogThread::start_window(Track *track, diff --git a/cinelerra-5.0/cinelerra/preferences.C b/cinelerra-5.0/cinelerra/preferences.C index dbee6ccf..0a8d3374 100644 --- a/cinelerra-5.0/cinelerra/preferences.C +++ b/cinelerra-5.0/cinelerra/preferences.C @@ -51,8 +51,6 @@ -extern void get_exe_path(char *result); - diff --git a/cinelerra-5.0/cinelerra/preferencesthread.C b/cinelerra-5.0/cinelerra/preferencesthread.C index 867898b4..f418ba25 100644 --- a/cinelerra-5.0/cinelerra/preferencesthread.C +++ b/cinelerra-5.0/cinelerra/preferencesthread.C @@ -100,6 +100,7 @@ PreferencesThread::PreferencesThread(MWindow *mwindow) PreferencesThread::~PreferencesThread() { + close_window(); } BC_Window* PreferencesThread::new_gui() diff --git a/cinelerra-5.0/cinelerra/presetsgui.C b/cinelerra-5.0/cinelerra/presetsgui.C index 5fc8d1eb..dad7f35c 100644 --- a/cinelerra-5.0/cinelerra/presetsgui.C +++ b/cinelerra-5.0/cinelerra/presetsgui.C @@ -63,6 +63,7 @@ PresetsThread::PresetsThread(MWindow *mwindow) PresetsThread::~PresetsThread() { + close_window(); delete data; } diff --git a/cinelerra-5.0/cinelerra/record.C b/cinelerra-5.0/cinelerra/record.C index 933e7ef0..42cd9da4 100644 --- a/cinelerra-5.0/cinelerra/record.C +++ b/cinelerra-5.0/cinelerra/record.C @@ -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, ...) { diff --git a/cinelerra-5.0/cinelerra/recordscopes.C b/cinelerra-5.0/cinelerra/recordscopes.C index e0ee7913..4a3cebf9 100644 --- a/cinelerra-5.0/cinelerra/recordscopes.C +++ b/cinelerra-5.0/cinelerra/recordscopes.C @@ -39,6 +39,7 @@ RecordScopeThread::RecordScopeThread(MWindow *mwindow, RecordMonitor *record_mon RecordScopeThread::~RecordScopeThread() { + close_window(); delete gui_lock; } diff --git a/cinelerra-5.0/cinelerra/render.C b/cinelerra-5.0/cinelerra/render.C index f664512e..d4dabf3d 100644 --- a/cinelerra-5.0/cinelerra/render.C +++ b/cinelerra-5.0/cinelerra/render.C @@ -267,6 +267,7 @@ Render::Render(MWindow *mwindow) Render::~Render() { + close_window(); delete package_lock; delete counter_lock; delete completion; diff --git a/cinelerra-5.0/cinelerra/shbtnprefs.C b/cinelerra-5.0/cinelerra/shbtnprefs.C index 54d71acd..7c6a5f41 100644 --- a/cinelerra-5.0/cinelerra/shbtnprefs.C +++ b/cinelerra-5.0/cinelerra/shbtnprefs.C @@ -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")); diff --git a/cinelerra-5.0/cinelerra/tipwindow.C b/cinelerra-5.0/cinelerra/tipwindow.C index c416dd51..b326ce0b 100644 --- a/cinelerra-5.0/cinelerra/tipwindow.C +++ b/cinelerra-5.0/cinelerra/tipwindow.C @@ -87,6 +87,11 @@ TipWindow::TipWindow(MWindow *mwindow) this->mwindow = mwindow; } +TipWindow::~TipWindow() +{ + close_window(); +} + void TipWindow::handle_close_event(int result) { gui = 0; diff --git a/cinelerra-5.0/cinelerra/tipwindow.h b/cinelerra-5.0/cinelerra/tipwindow.h index d5b98435..87f594dc 100644 --- a/cinelerra-5.0/cinelerra/tipwindow.h +++ b/cinelerra-5.0/cinelerra/tipwindow.h @@ -36,6 +36,7 @@ class TipWindow : public BC_DialogThread { public: TipWindow(MWindow *mwindow); + ~TipWindow(); void handle_close_event(int result); BC_Window* new_gui(); diff --git a/cinelerra-5.0/cinelerra/transitionpopup.C b/cinelerra-5.0/cinelerra/transitionpopup.C index 3c1b8e68..1418d705 100644 --- a/cinelerra-5.0/cinelerra/transitionpopup.C +++ b/cinelerra-5.0/cinelerra/transitionpopup.C @@ -42,6 +42,7 @@ TransitionLengthThread::TransitionLengthThread(MWindow *mwindow) TransitionLengthThread::~TransitionLengthThread() { + close_window(); } void TransitionLengthThread::start(Transition *transition, diff --git a/cinelerra-5.0/cinelerra/vwindow.C b/cinelerra-5.0/cinelerra/vwindow.C index a7e7fa78..57459ef9 100644 --- a/cinelerra-5.0/cinelerra/vwindow.C +++ b/cinelerra-5.0/cinelerra/vwindow.C @@ -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"); diff --git a/cinelerra-5.0/cinelerra/wwindow.C b/cinelerra-5.0/cinelerra/wwindow.C index b34ebdf0..e0db1b7c 100644 --- a/cinelerra-5.0/cinelerra/wwindow.C +++ b/cinelerra-5.0/cinelerra/wwindow.C @@ -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; diff --git a/cinelerra-5.0/cinelerra/wwindow.h b/cinelerra-5.0/cinelerra/wwindow.h index b7db85b8..b1f9b672 100644 --- a/cinelerra-5.0/cinelerra/wwindow.h +++ b/cinelerra-5.0/cinelerra/wwindow.h @@ -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(); diff --git a/cinelerra-5.0/ffmpeg/audio/bluray.m2ts b/cinelerra-5.0/ffmpeg/audio/bluray.m2ts index df43a8fb..45fd78be 100644 --- a/cinelerra-5.0/ffmpeg/audio/bluray.m2ts +++ b/cinelerra-5.0/ffmpeg/audio/bluray.m2ts @@ -1,4 +1,5 @@ mpegts ac3 +id 0x1100 maxrate 9000000 minrate 0 bufsize 1835008 diff --git a/cinelerra-5.0/ffmpeg/video/bluray.m2ts b/cinelerra-5.0/ffmpeg/video/bluray.m2ts index be70ceff..90de1b93 100644 --- a/cinelerra-5.0/ffmpeg/video/bluray.m2ts +++ b/cinelerra-5.0/ffmpeg/video/bluray.m2ts @@ -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 diff --git a/cinelerra-5.0/guicast/bcpopupmenu.C b/cinelerra-5.0/guicast/bcpopupmenu.C index 59688e6c..e65b40d6 100644 --- a/cinelerra-5.0/guicast/bcpopupmenu.C +++ b/cinelerra-5.0/guicast/bcpopupmenu.C @@ -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; diff --git a/cinelerra-5.0/plugins/scale/scale.C b/cinelerra-5.0/plugins/scale/scale.C index ec51f206..6f4ffb26 100644 --- a/cinelerra-5.0/plugins/scale/scale.C +++ b/cinelerra-5.0/plugins/scale/scale.C @@ -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; } -- 2.26.2