From: Good Guy <good1.2guy@gmail.com> Date: Mon, 9 May 2016 22:24:40 +0000 (-0600) Subject: ffmpeg param visibility, high422 x264 profile, bd/dvd enhancements X-Git-Url: http://git.cinelerra-gg.org/git/?a=commitdiff_plain;h=2f28632d8209ef735de1698a596bc94fa9613497;p=goodguy%2Fhistory.git ffmpeg param visibility, high422 x264 profile, bd/dvd enhancements --- diff --git a/cinelerra-5.1/cinelerra/bdcreate.C b/cinelerra-5.1/cinelerra/bdcreate.C index 20ecf587..d487830c 100644 --- a/cinelerra-5.1/cinelerra/bdcreate.C +++ b/cinelerra-5.1/cinelerra/bdcreate.C @@ -30,7 +30,7 @@ #define BD_1920x1080_2500i 1 #define BD_1920x1080_2400p 2 #define BD_1920x1080_23976p 3 -#define BD_1280x720_5997p 4 +#define BD_1280x720_5994p 4 #define BD_1280x720_5000p 5 #define BD_1280x720_23976p 6 #define BD_1280x720_2400p 7 @@ -46,7 +46,7 @@ static struct bd_format { { "1920x1080 25i", 1920,1080, 25 }, { "1920x1080 24p", 1920,1080, 24 }, { "1920x1080 23.976p", 1920,1080, 23.976 }, - { "1280x720 59.97p", 1280,720, 59.97 }, + { "1280x720 59.94p", 1280,720, 59.94 }, { "1280x720 50p", 1280,720, 50 }, { "1280x720 23.976p", 1280,720, 23.976 }, { "1280x720 24p", 1280,720, 24 }, @@ -184,7 +184,8 @@ int CreateBD_Thread::create_bd_jobs(ArrayList<BatchRenderJob*> *jobs, fprintf(fp,"bdwrite $1/udfs $1/bd.m2ts\n"); fprintf(fp,"umount $1/udfs\n"); fprintf(fp,"echo To burn bluray, load writable media and run:\n"); - fprintf(fp,"echo growisofs -dvd-compat -Z /dev/bd=$1/bd.udfs\n"); + fprintf(fp,"echo for WORM: growisofs -dvd-compat -Z /dev/bd=$1/bd.udfs\n"); + fprintf(fp,"echo for RW: dd if=$1/bd.udfs of=/dev/bd bs=2048000\n"); fprintf(fp,"\n"); fclose(fp); @@ -373,7 +374,7 @@ BC_Window* CreateBD_Thread::new_gui() has_standard = i; break; } } - use_standard = has_standard >= 0 ? has_standard : BD_1920x1080_2400p; + use_standard = has_standard >= 0 ? has_standard : BD_1920x1080_23976p; option_presets(); int scr_x = mwindow->gui->get_screen_x(0, -1); @@ -616,6 +617,7 @@ CreateBD_GUI::CreateBD_GUI(CreateBD_Thread *thread, int x, int y, int w, int h) cancel_x = cancel_y = cancel_w = cancel_h = 0; asset_title = 0; tmp_path = 0; + btmp_path = 0; disk_space = 0; need_deinterlace = 0; need_inverse_telecine = 0; @@ -645,11 +647,15 @@ void CreateBD_GUI::create_objects() 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); + title = new BC_Title(x, y, _("Work 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); + tmp_path = new CreateBD_TmpPath(this, tmp_x, tmp_y, get_w()-tmp_x-35); add_subwindow(tmp_path); + btmp_path = new BrowseButton(thread->mwindow, this, tmp_path, + tmp_x+tmp_path->get_w(), tmp_y, "/tmp", + _("Work path"), _("Select a Work directory:"), 1); + add_subwindow(btmp_path); y += title->get_h() + pady/2; disk_space = new CreateBD_DiskSpace(this, x, y); add_subwindow(disk_space); @@ -711,7 +717,8 @@ void CreateBD_GUI::create_objects() 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); + tmp_path->reposition_window(tmp_x, tmp_y, get_w()-tmp_x-35); + btmp_path->reposition_window(tmp_x+tmp_path->get_w(), tmp_y); ok_y = h - ok_h - 10; ok->reposition_window(ok_x, ok_y); cancel_x = w - cancel_w - 10, diff --git a/cinelerra-5.1/cinelerra/bdcreate.h b/cinelerra-5.1/cinelerra/bdcreate.h index 308208dc..f13bee74 100644 --- a/cinelerra-5.1/cinelerra/bdcreate.h +++ b/cinelerra-5.1/cinelerra/bdcreate.h @@ -9,6 +9,7 @@ #include "bclistboxitem.inc" #include "bcmenuitem.h" #include "bctextbox.h" +#include "browsebutton.h" #include "mwindow.h" #include "bdcreate.inc" @@ -209,6 +210,7 @@ public: CreateBD_AssetTitle *asset_title; int tmp_x, tmp_y; CreateBD_TmpPath *tmp_path; + BrowseButton *btmp_path; CreateBD_DiskSpace *disk_space; CreateBD_Format *standard; ArrayList<BC_ListBoxItem *> media_sizes; diff --git a/cinelerra-5.1/cinelerra/bdwrite.C b/cinelerra-5.1/cinelerra/bdwrite.C index 93b65690..a26d56aa 100644 --- a/cinelerra-5.1/cinelerra/bdwrite.C +++ b/cinelerra-5.1/cinelerra/bdwrite.C @@ -2882,8 +2882,8 @@ bd_path(const char *bp, const char *fmt, va_list ap) int Media:: bd_copy(const char *ifn, const char *fmt, ...) { - int n, ret = 1; - char bfr[0x40000]; + int bfrsz = 0x40000, ret = 1; + char bfr[bfrsz]; FILE *ifp = fopen(ifn,"r"); if( ifp ) { va_list ap; @@ -2894,9 +2894,27 @@ bd_copy(const char *ifn, const char *fmt, ...) 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; + int n = bfrsz; + while( !ret && n >= bfrsz ) { + n = fread(bfr,1,bfrsz,ifp); + if( n > 0 && (int)fwrite(bfr,1,n,ofp) != n ) { + fprintf(stderr, "cant write: %s\n",filename); + ret = 1; + } + } + if( ferror(ifp) ) { + fprintf(stderr, "read error: %s = %m\n",ifn); + ret = 1; + } + if( ferror(ofp) ) { + fprintf(stderr, "write error: %s = %m\n",filename); + ret = 1; + } + if( fclose(ofp) ) { + fprintf(stderr, "close error: %s = %m\n",filename); + ret = 1; + } } fclose(ifp); } diff --git a/cinelerra-5.1/cinelerra/cwindowgui.C b/cinelerra-5.1/cinelerra/cwindowgui.C index 73c11dc5..172ee6e3 100644 --- a/cinelerra-5.1/cinelerra/cwindowgui.C +++ b/cinelerra-5.1/cinelerra/cwindowgui.C @@ -1530,6 +1530,14 @@ int CWindowCanvas::do_mask(int &redraw, int &rerender, float x2 = point2->x + point2->control_x1; float y2 = point2->y + point2->control_y1; float x3 = point2->x, y3 = point2->y; + float canvas_x0 = (x0 - half_track_w) * projector_z + projector_x; + float canvas_y0 = (y0 - half_track_h) * projector_z + projector_y; + float canvas_x1 = (x1 - half_track_w) * projector_z + projector_x; + float canvas_y1 = (y1 - half_track_h) * projector_z + projector_y; + float canvas_x2 = (x2 - half_track_w) * projector_z + projector_x; + float canvas_y2 = (y2 - half_track_h) * projector_z + projector_y; + float canvas_x3 = (x3 - half_track_w) * projector_z + projector_x; + float canvas_y3 = (y3 - half_track_h) * projector_z + projector_y; float t = (float)j / segments; float tpow2 = t * t; @@ -1546,9 +1554,8 @@ int CWindowCanvas::do_mask(int &redraw, int &rerender, + 3 * t * invtpow2 * y1 + 3 * tpow2 * invt * y2 + tpow3 * y3); - - x = (x - half_track_w) * projector_z + projector_x; - y = (y - half_track_h) * projector_z + projector_y; + float canvas_x = (x - half_track_w) * projector_z + projector_x; + float canvas_y = (y - half_track_h) * projector_z + projector_y; // Test new point addition if(button_press) { float line_distance = line_dist(x,y, mask_cursor_x,mask_cursor_y); @@ -1565,13 +1572,9 @@ int CWindowCanvas::do_mask(int &redraw, int &rerender, } // Test existing point selection - float canvas_x = (x0 - half_track_w) * projector_z + projector_x; - float canvas_y = (y0 - half_track_h) * projector_z + projector_y; // Test first point if(gui->ctrl_down()) { - float control_x = (x1 - half_track_w) * projector_z + projector_x; - float control_y = (y1 - half_track_h) * projector_z + projector_y; - float distance = line_dist(control_x,control_y, mask_cursor_x,mask_cursor_y); + float distance = line_dist(x1,y1, mask_cursor_x,mask_cursor_y); if(distance < selected_control_point_distance) { selected_point = i; @@ -1581,7 +1584,7 @@ int CWindowCanvas::do_mask(int &redraw, int &rerender, } else { if(!gui->shift_down()) { - if(test_bbox(cursor_x, cursor_y, canvas_x, canvas_y)) { + if(test_bbox(cursor_x, cursor_y, canvas_x0, canvas_y0)) { selected_point = i; } } @@ -1590,13 +1593,8 @@ int CWindowCanvas::do_mask(int &redraw, int &rerender, } } // Test second point - canvas_x = (x3 - half_track_w) * projector_z + projector_x; - canvas_y = (y3 - half_track_h) * projector_z + projector_y; - if(gui->ctrl_down()) { - float control_x = (x2 - half_track_w) * projector_z + projector_x; - float control_y = (y2 - half_track_h) * projector_z + projector_y; - float distance = line_dist(control_x,control_y, mask_cursor_x,mask_cursor_y); + float distance = line_dist(x2,y2, mask_cursor_x,mask_cursor_y); //printf("CWindowCanvas::do_mask %d %f %f\n", i, distance, selected_control_point_distance); if(distance < selected_control_point_distance) { @@ -1607,7 +1605,7 @@ int CWindowCanvas::do_mask(int &redraw, int &rerender, } else if(i < points.size() - 1) { if(!gui->shift_down()) { - if(test_bbox(cursor_x, cursor_y, canvas_x, canvas_y)) { + if(test_bbox(cursor_x, cursor_y, canvas_x3, canvas_y3)) { selected_point = (i < points.size() - 1 ? i + 1 : 0); } } @@ -1617,14 +1615,13 @@ int CWindowCanvas::do_mask(int &redraw, int &rerender, } } - - output_to_canvas(mwindow->edl, 0, x, y); + output_to_canvas(mwindow->edl, 0, canvas_x, canvas_y); if(j > 0) { if(draw) { // Draw joining line - x_points.append((int)x); - y_points.append((int)y); + x_points.append((int)canvas_x); + y_points.append((int)canvas_y); } if(j == segments) { @@ -1632,24 +1629,24 @@ int CWindowCanvas::do_mask(int &redraw, int &rerender, if(i < points.size() - 1) { if(i == gui->affected_point - 1) get_canvas()->draw_disc( - (int)x - CONTROL_W / 2, - (int)y - CONTROL_W / 2, + (int)canvas_x - CONTROL_W / 2, + (int)canvas_y - CONTROL_W / 2, CONTROL_W, CONTROL_H); else get_canvas()->draw_circle( - (int)x - CONTROL_W / 2, - (int)y - CONTROL_W / 2, + (int)canvas_x - CONTROL_W / 2, + (int)canvas_y - CONTROL_W / 2, CONTROL_W, CONTROL_H); // char string[BCTEXTLEN]; // sprintf(string, "%d", (i < points.size() - 1 ? i + 1 : 0)); -// canvas->draw_text((int)x + CONTROL_W, (int)y + CONTROL_W, string); +// canvas->draw_text((int)canvas_x + CONTROL_W, (int)canvas_y + CONTROL_W, string); } // Draw second control point. Discard x2 and y2 after this. - x2 = (x2 - half_track_w) * projector_z + projector_x; - y2 = (y2 - half_track_h) * projector_z + projector_y; output_to_canvas(mwindow->edl, 0, x2, y2); - get_canvas()->draw_line((int)x, (int)y, (int)x2, (int)y2); + get_canvas()->draw_line( + (int)canvas_x, (int)canvas_y, + (int)canvas_x2, (int)canvas_y2); get_canvas()->draw_rectangle( (int)x2 - CONTROL_W / 2, (int)y2 - CONTROL_H / 2, @@ -1664,29 +1661,29 @@ int CWindowCanvas::do_mask(int &redraw, int &rerender, sprintf(mask_label, "%d", mwindow->edl->session->cwindow_mask); get_canvas()->draw_text( - (int)x - FIRST_CONTROL_W, - (int)y - FIRST_CONTROL_H, + (int)canvas_x - FIRST_CONTROL_W, + (int)canvas_y - FIRST_CONTROL_H, mask_label); get_canvas()->draw_disc( - (int)x - FIRST_CONTROL_W / 2, - (int)y - FIRST_CONTROL_H / 2, + (int)canvas_x - FIRST_CONTROL_W / 2, + (int)canvas_y - FIRST_CONTROL_H / 2, FIRST_CONTROL_W, FIRST_CONTROL_H); } -// Draw first control point. Discard x1 and y1 after this. +// Draw first control point. if(draw) { - x1 = (x1 - half_track_w) * projector_z + projector_x; - y1 = (y1 - half_track_h) * projector_z + projector_y; - output_to_canvas(mwindow->edl, 0, x1, y1); - get_canvas()->draw_line((int)x, (int)y, (int)x1, (int)y1); + output_to_canvas(mwindow->edl, 0, canvas_x1, canvas_y1); + get_canvas()->draw_line( + (int)canvas_x, (int)canvas_y, + (int)canvas_x1, (int)canvas_y1); get_canvas()->draw_rectangle( - (int)x1 - CONTROL_W / 2, - (int)y1 - CONTROL_H / 2, + (int)canvas_x1 - CONTROL_W / 2, + (int)canvas_y1 - CONTROL_H / 2, CONTROL_W, CONTROL_H); - x_points.append((int)x); - y_points.append((int)y); + x_points.append((int)canvas_x); + y_points.append((int)canvas_y); } } //printf("CWindowCanvas::do_mask 1\n"); @@ -2006,26 +2003,26 @@ int CWindowCanvas::do_mask(int &redraw, int &rerender, float y1 = point->y + point->control_y1; float x2 = point->x + point->control_x2; float y2 = point->y + point->control_y2; - float canvas_x = (x0 - half_track_w) * projector_z + projector_x; - float canvas_y = (y0 - half_track_h) * projector_z + projector_y; + float canvas_x0 = (x0 - half_track_w) * projector_z + projector_x; + float canvas_y0 = (y0 - half_track_h) * projector_z + projector_y; - output_to_canvas(mwindow->edl, 0, canvas_x, canvas_y); - if(test_bbox(cursor_x, cursor_y, canvas_x, canvas_y)) { + output_to_canvas(mwindow->edl, 0, canvas_x0, canvas_y0); + if(test_bbox(cursor_x, cursor_y, canvas_x0, canvas_y0)) { over_point = 1; } if(!over_point && gui->ctrl_down()) { - canvas_x = (x1 - half_track_w) * projector_z + projector_x; - canvas_y = (y1 - half_track_h) * projector_z + projector_y; - output_to_canvas(mwindow->edl, 0, canvas_x, canvas_y); - if(test_bbox(cursor_x, cursor_y, canvas_x, canvas_y)) { + float canvas_x1 = (x1 - half_track_w) * projector_z + projector_x; + float canvas_y1 = (y1 - half_track_h) * projector_z + projector_y; + output_to_canvas(mwindow->edl, 0, canvas_x1, canvas_y1); + if(test_bbox(cursor_x, cursor_y, canvas_x1, canvas_y1)) { over_point = 1; } else { - canvas_x = (x2 - half_track_w) * projector_z + projector_x; - canvas_y = (y2 - half_track_h) * projector_z + projector_y; - output_to_canvas(mwindow->edl, 0, canvas_x, canvas_y); - if(test_bbox(cursor_x, cursor_y, canvas_x, canvas_y)) { + float canvas_x2 = (x2 - half_track_w) * projector_z + projector_x; + float canvas_y2 = (y2 - half_track_h) * projector_z + projector_y; + output_to_canvas(mwindow->edl, 0, canvas_x2, canvas_y2); + if(test_bbox(cursor_x, cursor_y, canvas_x2, canvas_y2)) { over_point = 1; } } diff --git a/cinelerra-5.1/cinelerra/dvdcreate.C b/cinelerra-5.1/cinelerra/dvdcreate.C index c7477269..66d93793 100644 --- a/cinelerra-5.1/cinelerra/dvdcreate.C +++ b/cinelerra-5.1/cinelerra/dvdcreate.C @@ -187,7 +187,8 @@ int CreateDVD_Thread::create_dvd_jobs(ArrayList<BatchRenderJob*> *jobs, fprintf(fp," </vmgm>\n"); fprintf(fp," <titleset>\n"); fprintf(fp," <titles>\n"); - fprintf(fp," <video format=\"ntsc\" aspect=\"%d:%d\" resolution=\"%dx%d\"/>\n", + fprintf(fp," <video format=\"%s\" aspect=\"%d:%d\" resolution=\"%dx%d\"/>\n", + use_standard == HD_720x576_2500 ? "pal" : "ntsc", (int)session->aspect_w, (int)session->aspect_h, session->output_w, session->output_h); fprintf(fp," <audio format=\"ac3\" lang=\"en\"/>\n"); @@ -705,6 +706,7 @@ CreateDVD_GUI::CreateDVD_GUI(CreateDVD_Thread *thread, int x, int y, int w, int cancel_x = cancel_y = cancel_w = cancel_h = 0; asset_title = 0; tmp_path = 0; + btmp_path = 0; disk_space = 0; need_deinterlace = 0; need_inverse_telecine = 0; @@ -734,11 +736,15 @@ void CreateDVD_GUI::create_objects() 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); + title = new BC_Title(x, y, _("Work 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); + tmp_path = new CreateDVD_TmpPath(this, tmp_x, tmp_y, get_w()-tmp_x-35); add_subwindow(tmp_path); + btmp_path = new BrowseButton(thread->mwindow, this, tmp_path, + tmp_x+tmp_path->get_w(), tmp_y, "/tmp", + _("Work path"), _("Select a Work directory:"), 1); + add_subwindow(btmp_path); y += title->get_h() + pady/2; disk_space = new CreateDVD_DiskSpace(this, x, y); add_subwindow(disk_space); @@ -802,7 +808,8 @@ void CreateDVD_GUI::create_objects() 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); + tmp_path->reposition_window(tmp_x, tmp_y, get_w()-tmp_x-35); + btmp_path->reposition_window(tmp_x+tmp_path->get_w(), tmp_y); ok_y = h - ok_h - 10; ok->reposition_window(ok_x, ok_y); cancel_x = w - cancel_w - 10, diff --git a/cinelerra-5.1/cinelerra/dvdcreate.h b/cinelerra-5.1/cinelerra/dvdcreate.h index b30ff18e..8e267e82 100644 --- a/cinelerra-5.1/cinelerra/dvdcreate.h +++ b/cinelerra-5.1/cinelerra/dvdcreate.h @@ -9,6 +9,7 @@ #include "bclistboxitem.inc" #include "bcmenuitem.h" #include "bctextbox.h" +#include "browsebutton.h" #include "mwindow.h" #include "dvdcreate.inc" @@ -217,6 +218,7 @@ public: CreateDVD_AssetTitle *asset_title; int tmp_x, tmp_y; CreateDVD_TmpPath *tmp_path; + BrowseButton *btmp_path; CreateDVD_DiskSpace *disk_space; CreateDVD_Format *standard; ArrayList<BC_ListBoxItem *> media_sizes; diff --git a/cinelerra-5.1/cinelerra/ffmpeg.C b/cinelerra-5.1/cinelerra/ffmpeg.C index 74d1d745..25cfbe70 100644 --- a/cinelerra-5.1/cinelerra/ffmpeg.C +++ b/cinelerra-5.1/cinelerra/ffmpeg.C @@ -1137,7 +1137,7 @@ void FFMPEG::get_option_path(char *path, const char *type, const char *spec) set_option_path(path, "%s/%s", type, spec); } -int FFMPEG::get_format(char *format, const char *path, char *spec) +int FFMPEG::get_format(char *format, const char *path, const char *spec) { char option_path[BCTEXTLEN], line[BCTEXTLEN], codec[BCTEXTLEN]; get_option_path(option_path, path, spec); @@ -1153,6 +1153,22 @@ int FFMPEG::get_format(char *format, const char *path, char *spec) return ret; } +int FFMPEG::get_codec(char *codec, const char *path, const char *spec) +{ + char option_path[BCTEXTLEN], line[BCTEXTLEN], format[BCTEXTLEN]; + get_option_path(option_path, path, spec); + FILE *fp = fopen(option_path,"r"); + if( !fp ) return 1; + int ret = 0; + if( !fgets(line, sizeof(line), fp) ) ret = 1; + if( !ret ) { + line[sizeof(line)-1] = 0; + ret = scan_option_line(line, format, codec); + } + fclose(fp); + return ret; +} + int FFMPEG::get_file_format() { int ret = 0; diff --git a/cinelerra-5.1/cinelerra/ffmpeg.h b/cinelerra-5.1/cinelerra/ffmpeg.h index 674e2703..d60337fb 100644 --- a/cinelerra-5.1/cinelerra/ffmpeg.h +++ b/cinelerra-5.1/cinelerra/ffmpeg.h @@ -263,7 +263,8 @@ public: static void set_option_path(char *path, const char *fmt, ...); static void get_option_path(char *path, const char *type, const char *spec); - static int get_format(char *format, const char *path, char *spec); + static int get_format(char *format, const char *path, const char *spec); + static int get_codec(char *codec, const char *path, const char *spec); static int scan_option_line(char *cp,char *tag,char *val); static int load_defaults(const char *path, const char *type, char *codec, char *codec_options, int len); diff --git a/cinelerra-5.1/cinelerra/fileffmpeg.C b/cinelerra-5.1/cinelerra/fileffmpeg.C index 660f750e..23e391df 100644 --- a/cinelerra-5.1/cinelerra/fileffmpeg.C +++ b/cinelerra-5.1/cinelerra/fileffmpeg.C @@ -16,6 +16,7 @@ #include "fileffmpeg.h" #include "filesystem.h" #include "indexfile.h" +#include "mainerror.h" #include "mainprogress.h" #include "mutex.h" #include "preferences.h" @@ -162,12 +163,12 @@ void FileFFMPEG::get_info(char *path, char *text, int len) int FileFFMPEG::get_video_info(int track, int &pid, double &framerate, int &width, int &height, char *title) { - if( !ff ) return -1; - pid = ff->ff_video_pid(track); - framerate = ff->ff_frame_rate(track); - width = ff->ff_video_width(track); - height = ff->ff_video_height(track); - if( title ) *title = 0; + if( !ff ) return -1; + pid = ff->ff_video_pid(track); + framerate = ff->ff_frame_rate(track); + width = ff->ff_video_width(track); + height = ff->ff_video_height(track); + if( title ) *title = 0; return 0; } @@ -193,7 +194,7 @@ int FileFFMPEG::select_audio_stream(Asset *asset, int astream) { if( !ff || !asset->audio_data ) return 1; asset->sample_rate = ff->ff_sample_rate(astream); - asset->audio_length = ff->ff_audio_samples(astream); + asset->audio_length = ff->ff_audio_samples(astream); return 0; } @@ -252,7 +253,7 @@ int FileFFMPEG::close_file() int FileFFMPEG::write_samples(double **buffer, int64_t len) { - if( !ff || len < 0 ) return -1; + if( !ff || len < 0 ) return -1; int stream = 0; int ret = ff->encode(stream, buffer, len); return ret; @@ -260,7 +261,7 @@ int FileFFMPEG::write_samples(double **buffer, int64_t len) int FileFFMPEG::write_frames(VFrame ***frames, int len) { - if( !ff ) return -1; + if( !ff ) return -1; int ret = 0, layer = 0; for(int i = 0; i < 1; i++) { for(int j = 0; j < len && !ret; j++) { @@ -274,18 +275,18 @@ int FileFFMPEG::write_frames(VFrame ***frames, int len) int FileFFMPEG::read_samples(double *buffer, int64_t len) { - if( !ff || len < 0 ) return -1; + if( !ff || len < 0 ) return -1; int ch = file->current_channel; int64_t pos = file->current_sample; int ret = ff->decode(ch, pos, buffer, len); if( ret > 0 ) return 0; memset(buffer,0,len*sizeof(*buffer)); - return -1; + return -1; } int FileFFMPEG::read_frame(VFrame *frame) { - if( !ff ) return -1; + if( !ff ) return -1; int layer = file->current_layer; int64_t pos = asset->video_length >= 0 ? file->current_frame : 0; int ret = ff->decode(layer, pos, frame); @@ -311,7 +312,7 @@ int FileFFMPEG::get_best_colormodel(Asset *asset, int driver) switch(driver) { case PLAYBACK_X11: return BC_RGB888; case PLAYBACK_X11_GL: return BC_YUV888; - } + } return BC_YUV420P; } @@ -329,12 +330,14 @@ FFMPEGConfigAudio::FFMPEGConfigAudio(BC_WindowBase *parent_window, Asset *asset) bitrate = 0; audio_options = 0; + ff_options_dialog = 0; } FFMPEGConfigAudio::~FFMPEGConfigAudio() { + delete ff_options_dialog; lock_window("FFMPEGConfigAudio::~FFMPEGConfigAudio"); - if(preset_popup) delete preset_popup; + delete preset_popup; presets.remove_all_objects(); unlock_window(); } @@ -344,20 +347,20 @@ void FFMPEGConfigAudio::create_objects() int x = 10, y = 10; lock_window("FFMPEGConfigAudio::create_objects"); - FileSystem fs; + FileSystem fs; char option_path[BCTEXTLEN]; FFMPEG::set_option_path(option_path, "audio"); - fs.update(option_path); - int total_files = fs.total_files(); - for(int i = 0; i < total_files; i++) { - const char *name = fs.get_entry(i)->get_name(); + fs.update(option_path); + int total_files = fs.total_files(); + for(int i = 0; i < total_files; i++) { + const char *name = fs.get_entry(i)->get_name(); if( asset->fformat[0] != 0 ) { const char *ext = strrchr(name,'.'); if( !ext ) continue; if( strcmp(asset->fformat, ++ext) ) continue; } - presets.append(new BC_ListBoxItem(name)); - } + presets.append(new BC_ListBoxItem(name)); + } if( asset->acodec[0] ) { int k = presets.size(); @@ -379,16 +382,24 @@ void FFMPEGConfigAudio::create_objects() bitrate->set_increment(1000); y += bitrate->get_h() + 10; - add_subwindow(new BC_Title(x, y, _("Audio Options:"))); + BC_Title *title = new BC_Title(x, y, _("Audio Options:")); + add_subwindow(title); + + ff_options_dialog = new FFOptionsAudioDialog(this); + int x1 = x + title->get_w() + 8; + add_subwindow(new FFOptionsViewAudio(this, x1, y, _("view"))); + y += 25; if( !asset->ff_audio_options[0] && asset->acodec[0] ) { FFMPEG::set_option_path(option_path, "audio/%s", asset->acodec); FFMPEG::load_options(option_path, asset->ff_audio_options, sizeof(asset->ff_audio_options)); } - add_subwindow(audio_options = new FFAudioOptions(this, x, y, get_w()-x-20, 10, - sizeof(asset->ff_audio_options)-1, asset->ff_audio_options)); + audio_options = new FFAudioOptions(this, x, y, get_w()-x-20, 10, + sizeof(asset->ff_audio_options)-1, asset->ff_audio_options); + audio_options->create_objects(); add_subwindow(new BC_OKButton(this)); + show_window(1); bitrate->handle_event(); unlock_window(); @@ -400,10 +411,14 @@ int FFMPEGConfigAudio::close_event() return 1; } +void FFMPEGConfigAudio::update_options() +{ + audio_options->update(asset->ff_audio_options); +} FFAudioOptions::FFAudioOptions(FFMPEGConfigAudio *audio_popup, int x, int y, int w, int rows, int size, char *text) - : BC_TextBox(x, y, w, rows, size, text) + : BC_ScrollTextBox(audio_popup, x, y, w, rows, text, size) { this->audio_popup = audio_popup; } @@ -447,7 +462,6 @@ int FFMPEGConfigAudioToggle::handle_event() return 1; } - //====== FFMPEGConfigVideo::FFMPEGConfigVideo(BC_WindowBase *parent_window, Asset *asset) @@ -481,20 +495,20 @@ void FFMPEGConfigVideo::create_objects() add_subwindow(new BC_Title(x, y, _("Compression:"))); y += 25; - FileSystem fs; + FileSystem fs; char option_path[BCTEXTLEN]; FFMPEG::set_option_path(option_path, "video"); - fs.update(option_path); - int total_files = fs.total_files(); - for(int i = 0; i < total_files; i++) { - const char *name = fs.get_entry(i)->get_name(); + fs.update(option_path); + int total_files = fs.total_files(); + for(int i = 0; i < total_files; i++) { + const char *name = fs.get_entry(i)->get_name(); if( asset->fformat[0] != 0 ) { const char *ext = strrchr(name,'.'); if( !ext ) continue; if( strcmp(asset->fformat, ++ext) ) continue; } - presets.append(new BC_ListBoxItem(name)); - } + presets.append(new BC_ListBoxItem(name)); + } if( asset->vcodec[0] ) { int k = presets.size(); @@ -524,15 +538,23 @@ void FFMPEGConfigVideo::create_objects() quality->set_boundaries((int64_t)0, (int64_t)31); y += quality->get_h() + 10; - add_subwindow(new BC_Title(x, y, _("Video Options:"))); + BC_Title *title = new BC_Title(x, y, _("Video Options:")); + add_subwindow(title); + + ff_options_dialog = new FFOptionsVideoDialog(this); + int x1 = x + title->get_w() + 8; + add_subwindow(new FFOptionsViewVideo(this, x1, y, _("view"))); + y += 25; if( !asset->ff_video_options[0] && asset->vcodec[0] ) { FFMPEG::set_option_path(option_path, "video/%s", asset->vcodec); FFMPEG::load_options(option_path, asset->ff_video_options, sizeof(asset->ff_video_options)); } - add_subwindow(video_options = new FFVideoOptions(this, x, y, get_w()-x-20, 10, - sizeof(asset->ff_video_options)-1, asset->ff_video_options)); + + video_options = new FFVideoOptions(this, x, y, get_w()-x-20, 10, + sizeof(asset->ff_video_options)-1, asset->ff_video_options); + video_options->create_objects(); add_subwindow(new BC_OKButton(this)); show_window(1); @@ -549,10 +571,14 @@ int FFMPEGConfigVideo::close_event() return 1; } +void FFMPEGConfigVideo::update_options() +{ + video_options->update(asset->ff_video_options); +} FFVideoOptions::FFVideoOptions(FFMPEGConfigVideo *video_popup, int x, int y, int w, int rows, int size, char *text) - : BC_TextBox(x, y, w, rows, size, text) + : BC_ScrollTextBox(video_popup, x, y, w, rows, text, size) { this->video_popup = video_popup; } @@ -645,7 +671,7 @@ int FileFFMPEG::get_index(IndexFile *index_file, MainProgressBar *progress_bar) index_state->add_audio_stream(aud->channels, aud->length); } - FileSystem fs; + FileSystem fs; int64_t file_bytes = fs.get_size(ff->fmt_ctx->filename); char *index_path = index_file->index_filename; @@ -678,3 +704,790 @@ int FileFFMPEG::get_index(IndexFile *index_file, MainProgressBar *progress_bar) return index_state->create_index(index_path, asset); } + +FFOptions_OptPanel:: +FFOptions_OptPanel(FFOptionsWindow *fwin, int x, int y, int w, int h) + : BC_ListBox(x, y, w, h, LISTBOX_TEXT), opts(items[0]), vals(items[1]) +{ + this->fwin = fwin; + update(); // init col/wid/columns +} + +FFOptions_OptPanel:: +~FFOptions_OptPanel() +{ +} + +void FFOptions_OptPanel::create_objects() +{ + const char *cols[] = { "option", "value", }; + const int col1_w = 150; + int wids[] = { col1_w, get_w()-col1_w }; + BC_ListBox::update(&items[0], &cols[0], &wids[0], sizeof(items)/sizeof(items[0])); +} + +int FFOptions_OptPanel::update() +{ + opts.remove_all(); + vals.remove_all(); + FFOptions &options = fwin->options; + for( int i=0; i<options.size(); ++i ) { + FFOptions_Opt *opt = options[i]; + opts.append(opt->item_name); + vals.append(opt->item_value); + } + draw_items(1); + return 0; +} + +int FFOptions_OptPanel::cursor_leave_event() +{ + hide_tooltip(); + return 0; +} + + +FFOptions_OptName::FFOptions_OptName(FFOptions_Opt *opt, const char *nm) +{ + this->opt = opt; + set_text(nm); +} + +FFOptions_OptName::~FFOptions_OptName() +{ +} + +FFOptions_OptValue::FFOptions_OptValue(FFOptions_Opt *opt) +{ + this->opt = opt; +} + + +void FFOptions_OptValue::update() +{ + if( !opt ) return; + char val[BCTEXTLEN]; val[0] = 0; + opt->get(val, sizeof(val)); + update(val); +} + +void FFOptions_OptValue::update(const char *v) +{ + set_text(v); +} + +FFOptions_Opt::FFOptions_Opt(FFOptions *options, const AVOption *opt, const char *nm) +{ + this->options = options; + this->opt = opt; + item_name = new FFOptions_OptName(this, nm); + item_value = new FFOptions_OptValue(this); +} + +FFOptions_Opt::~FFOptions_Opt() +{ + delete item_name; + delete item_value; +} + +char *FFOptions_Opt::get(char *vp, int sz) +{ + char *cp = vp, *ep = vp+sz-1; + *cp = 0; + if( !opt ) return cp; + + void *obj = (void *)options->obj; + uint8_t *bp = 0; + if( av_opt_get(obj, opt->name, 0, &bp) >= 0 && bp != 0 ) { + const char *val = (const char *)bp; + if( opt->unit && *val ) { + int id = atoi(val); + const char *uid = unit_name(id); + if( uid ) val = uid; + } + cp = sz >= 0 ? strncpy(vp,val,sz) : strcpy(vp, val); + if( sz > 0 ) vp[sz-1] = 0; + av_freep(&bp); + return cp; + } + + *vp = 0; + return cp; +} + +void FFOptions_Opt::set(const char *val) +{ + void *obj = (void *)options->obj; + if( !obj || !opt ) return; + av_opt_set(obj, opt->name, val, 0); +} + + +FFOptionsKindItem::FFOptionsKindItem(FFOptionsKind *kind, const char *text, int idx) + : BC_MenuItem(text) +{ + this->kind = kind; + this->idx = idx; +} + +FFOptionsKindItem::~FFOptionsKindItem() +{ +} + +int FFOptionsKindItem::handle_event() +{ + FFOptionsWindow *fwin = kind->fwin; + FFOptions &options = fwin->options; + options.initialize(fwin, idx); + fwin->draw(); + return 1; +} + +const char *FFOptionsKind::kinds[] = { + N_("codec"), // FF_KIND_CODEC + N_("ffmpeg"), // FF_KIND_FFMPEG +}; + +FFOptionsKind:: +FFOptionsKind(FFOptionsWindow *fwin, int x, int y, int w) + : BC_PopupMenu(x, y, w-calculate_w(0), "") +{ + this->fwin = fwin; +} + +FFOptionsKind:: +~FFOptionsKind() +{ +} + +void FFOptionsKind::create_objects() +{ + for( int i=0; i<(int)(sizeof(kinds)/sizeof(kinds[0])); ++i ) + add_item(new FFOptionsKindItem(this, _(kinds[i]), i)); +} + +int FFOptionsKind::handle_event() +{ + return 1; +} + +void FFOptionsKind::set(int k) +{ + this->kind = k; + set_text(kinds[k]); +} + +FFOptionsText:: +FFOptionsText(FFOptionsWindow *fwin, int x, int y, int w) + : BC_TextBox(x, y, w, 1, (char *)"") +{ + this->fwin = fwin; +} + +FFOptionsText:: +~FFOptionsText() +{ +} + +int FFOptionsText::handle_event() +{ + return 0; +} + +FFOptionsUnits:: +FFOptionsUnits(FFOptionsWindow *fwin, int x, int y, int w) + : BC_PopupMenu(x, y, w, "") +{ + this->fwin = fwin; +} + +FFOptionsUnits:: +~FFOptionsUnits() +{ +} + +int FFOptionsUnits::handle_event() +{ + const char *text = get_text(); + if( text && fwin->selected ) { + fwin->selected->set(text); + fwin->selected->item_value->update(); + av_dict_set(&fwin->dialog->ff_opts, + fwin->selected->item_name->get_text(), + fwin->selected->item_value->get_text(), 0); + fwin->draw(); + } + return 1; +} + +FFOptionsApply:: +FFOptionsApply(FFOptionsWindow *fwin, int x, int y) + : BC_GenericButton(x, y, _("Apply")) +{ + this->fwin = fwin; +} + +FFOptionsApply:: +~FFOptionsApply() +{ +} + +int FFOptionsApply::handle_event() +{ + const char *text = fwin->text->get_text(); + if( text && fwin->selected ) { + fwin->selected->set(text); + fwin->selected->item_value->update(); + av_dict_set(&fwin->dialog->ff_opts, + fwin->selected->item_name->get_text(), + fwin->selected->item_value->get_text(), 0); + fwin->draw(); + } + return 1; +} + +FFOptions::FFOptions() +{ + avctx = 0; + obj = 0; +} + +FFOptions::~FFOptions() +{ + remove_all_objects(); + avcodec_free_context(&avctx); +} + +int FFOptions::cmpr(const void *a, const void *b) +{ + FFOptions_Opt *ap = *(FFOptions_Opt **)a; + FFOptions_Opt *bp = *(FFOptions_Opt **)b; + const char *vap = ap->item_name->get_text(); + const char *vbp = bp->item_name->get_text(); + return strcmp(vap, vbp); +} + +void FFOptions::initialize(FFOptionsWindow *win, int kind) +{ + remove_all_objects(); + this->win = win; + win->selected = 0; + obj = 0; + if( !avctx ) + avctx = avcodec_alloc_context3(win->dialog->codec); + + switch( kind ) { + case FF_KIND_CODEC: + obj = (const void *)avctx->priv_data; + break; + case FF_KIND_FFMPEG: + obj = (const void *)avctx; + break; + } + + if( obj ) { + FFOptions &conf = *this; + const AVOption *opt = 0; + while( (opt=av_opt_next(obj, opt)) != 0 ) { + if( opt->type == AV_OPT_TYPE_CONST ) continue; + int dupl = 0; + for( int i=0; !dupl && i<size(); ++i ) { + FFOptions_Opt *fopt = conf[i]; + const AVOption *op = fopt->opt; + if( op->offset != opt->offset ) continue; + if( op->type != opt->type ) continue; + dupl = 1; + if( strlen(op->name) < strlen(opt->name) ) + fopt->opt = opt; + } + if( dupl ) continue; + FFOptions_Opt *fopt = new FFOptions_Opt(this, opt, opt->name); + append(fopt); + char val[BCTEXTLEN], *vp = fopt->get(val, sizeof(val)); + fopt->item_value->update(vp); + } + } + + qsort(&values[0],size(),sizeof(values[0]),cmpr); + win->kind->set(kind); + win->panel->update(); + win->panel->set_yposition(0); +} + +int FFOptions::update() +{ + int ret = 0; + FFOptions &conf = *this; + + for( int i=0; i<size(); ++i ) { + FFOptions_Opt *fopt = conf[i]; + char val[BCTEXTLEN], *vp = fopt->get(val, sizeof(val)); + if( !vp || !strcmp(val, fopt->item_value->get_text()) ) continue; + fopt->item_value->update(val); + ++ret; + } + return ret; +} + +void FFOptions::dump(FILE *fp) +{ + if( !obj ) return; + const AVOption *opt = 0; + FFOptions &conf = *this; + + while( (opt=av_opt_next(obj, opt)) != 0 ) { + if( opt->type == AV_OPT_TYPE_CONST ) continue; + int k = size(); + while( --k >= 0 && strcmp(opt->name, conf[k]->opt->name) ); + if( k < 0 ) continue; + FFOptions_Opt *fopt = conf[k]; + char val[BCTEXTLEN], *vp = fopt->get(val,sizeof(val)); + fprintf(fp, " %s:=%s", opt->name, vp); + if( opt->unit ) { + char unt[BCTEXTLEN], *up = unt; + fopt->units(up); + fprintf(fp, "%s", unt); + } + fprintf(fp, "\n"); + } +} + + +void FFOptionsWindow::update(FFOptions_Opt *opt) +{ + if( selected != opt ) { + if( selected ) selected->item_name->set_selected(0); + selected = opt; + if( selected ) selected->item_name->set_selected(1); + } + clear_box(0,0, 0,panel->get_y()); + char str[BCTEXTLEN], *sp; + *(sp=str) = 0; + if( opt ) opt->types(sp); + type->update(str); + *(sp=str) = 0; + if( opt ) opt->ranges(sp); + range->update(str); + while( units->total_items() ) units->del_item(0); + char unit[BCSTRLEN]; strcpy(unit, "()"); + if( opt && opt->opt ) { + ArrayList<const char *> names; + int n = 0; + if( opt->opt->unit ) { + n = opt->units(names); + if( n > 0 ) strcpy(unit,opt->opt->unit); + } + for( int i=0; i<n; ++i ) + units->add_item(new BC_MenuItem(names[i], 0)); + } + units->set_text(unit); + char val[BCTEXTLEN]; val[0] = 0; + if( opt ) opt->get(val, sizeof(val)); + text->update(val); + + panel->update(); +} + +int FFOptions_OptPanel::selection_changed() +{ + FFOptions_Opt *opt = 0; + BC_ListBoxItem *item = get_selection(0, 0); + if( item ) { + FFOptions_OptName *opt_name = (FFOptions_OptName *)item; + opt = opt_name->opt; + } + fwin->update(opt); + fwin->panel->set_tooltip(!opt ? 0 : opt->tip()); + fwin->panel->show_tooltip(); + return 1; +} + + +int FFOptions_Opt::types(char *rp) +{ + const char *cp = ""; + if( opt ) switch (opt->type) { + case AV_OPT_TYPE_FLAGS: cp = "<flags>"; break; + case AV_OPT_TYPE_INT: cp = "<int>"; break; + case AV_OPT_TYPE_INT64: cp = "<int64>"; break; + case AV_OPT_TYPE_DOUBLE: cp = "<double>"; break; + case AV_OPT_TYPE_FLOAT: cp = "<float>"; break; + case AV_OPT_TYPE_STRING: cp = "<string>"; break; + case AV_OPT_TYPE_RATIONAL: cp = "<rational>"; break; + case AV_OPT_TYPE_BINARY: cp = "<binary>"; break; + case AV_OPT_TYPE_IMAGE_SIZE: cp = "<image_size>"; break; + case AV_OPT_TYPE_VIDEO_RATE: cp = "<video_rate>"; break; + case AV_OPT_TYPE_PIXEL_FMT: cp = "<pix_fmt>"; break; + case AV_OPT_TYPE_SAMPLE_FMT: cp = "<sample_fmt>"; break; + case AV_OPT_TYPE_DURATION: cp = "<duration>"; break; + case AV_OPT_TYPE_COLOR: cp = "<color>"; break; + case AV_OPT_TYPE_CHANNEL_LAYOUT: cp = "<channel_layout>"; break; + case AV_OPT_TYPE_BOOL: cp = "<bool>"; break; + default: cp = "<undef>"; break; + } + return sprintf(rp, "%s", cp); +} +int FFOptions_Opt::scalar(double d, char *rp) +{ + const char *cp = 0; + if( d == INT_MAX ) cp = "INT_MAX"; + else if( d == INT_MIN ) cp = "INT_MIN"; + else if( d == UINT32_MAX ) cp = "UINT32_MAX"; + else if( d == (double)INT64_MAX ) cp = "I64_MAX"; + else if( d == INT64_MIN ) cp = "I64_MIN"; + else if( d == FLT_MAX ) cp = "FLT_MAX"; + else if( d == FLT_MIN ) cp = "FLT_MIN"; + else if( d == -FLT_MAX ) cp = "-FLT_MAX"; + else if( d == -FLT_MIN ) cp = "-FLT_MIN"; + else if( d == DBL_MAX ) cp = "DBL_MAX"; + else if( d == DBL_MIN ) cp = "DBL_MIN"; + else if( d == -DBL_MAX ) cp = "-DBL_MAX"; + else if( d == -DBL_MIN ) cp = "-DBL_MIN"; + else if( d == 0 ) cp = signbit(d) ? "-0" : "0"; + else if( isnan(d) ) cp = signbit(d) ? "-NAN" : "NAN"; + else if( isinf(d) ) cp = signbit(d) ? "-INF" : "INF"; + else return sprintf(rp, "%g", d); + return sprintf(rp, "%s", cp); +} + +int FFOptions_Opt::ranges(char *rp) +{ + if( !opt ) return 0; + void *obj = (void *)options->obj; + if( !obj ) return 0; + + switch (opt->type) { + case AV_OPT_TYPE_INT: + case AV_OPT_TYPE_INT64: + case AV_OPT_TYPE_DOUBLE: + case AV_OPT_TYPE_FLOAT: break; + default: return 0;; + } + AVOptionRanges *r = 0; + char *cp = rp; + if( av_opt_query_ranges(&r, obj, opt->name, AV_OPT_SEARCH_FAKE_OBJ) < 0 ) return 0; + for( int i=0; i<r->nb_ranges; ++i ) { + cp += sprintf(cp, " ("); cp += scalar(r->range[i]->value_min, cp); + cp += sprintf(cp, ".."); cp += scalar(r->range[i]->value_max, cp); + cp += sprintf(cp, ")"); + } + av_opt_freep_ranges(&r); + return cp - rp; +} + +int FFOptions_Opt::units(ArrayList<const char *> &names) +{ + if( !opt || !opt->unit ) return 0; + const void *obj = options->obj; + if( !obj ) return 0; + + ArrayList<const AVOption *> opts; + const AVOption *opt = NULL; + while( (opt=av_opt_next(obj, opt)) != 0 ) { + if( !opt->unit ) continue; + if( opt->type != AV_OPT_TYPE_CONST ) continue; + if( strcmp(this->opt->unit, opt->unit) ) continue; + int i = opts.size(); + while( --i >= 0 ) { + if( opts[i]->default_val.i64 != opt->default_val.i64 ) continue; + if( strlen(opts[i]->name) < strlen(opt->name) ) opts[i] = opt; + break; + } + if( i >= 0 ) continue; + opts.append(opt); + } + + for( int i=0; i<opts.size(); ++i ) + names.append(opts[i]->name); + + return names.size(); +} + +int FFOptions_Opt::units(char *rp) +{ + ArrayList<const char *> names; + int n = units(names); + if( !n ) return 0; + char *cp = rp; + cp += sprintf(cp, " [%s:", this->opt->unit); + for( int i=0; i<n; ++i ) + cp += sprintf(cp, " %s", names[i]); + cp += sprintf(cp, "]:"); + return cp - rp; +} + +const char *FFOptions_Opt::unit_name(int id) +{ + if( !opt || !opt->unit ) return 0; + const void *obj = options->obj; + if( !obj ) return 0; + + const char *ret = 0; + const AVOption *opt = NULL; + while( (opt=av_opt_next(obj, opt)) != 0 ) { + if( !opt->unit ) continue; + if( opt->type != AV_OPT_TYPE_CONST ) continue; + if( strcmp(this->opt->unit, opt->unit) ) continue; + if( opt->default_val.i64 != id ) continue; + if( !ret ) { ret = opt->name; continue; } + if( strlen(ret) < strlen(opt->name) ) ret = opt->name; + } + + return ret; +} + +const char *FFOptions_Opt::tip() +{ + return !opt ? 0 : opt->help; +} + + +FFOptionsWindow::FFOptionsWindow(FFOptionsDialog *dialog) + : BC_Window(PROGRAM_NAME ": Options", 60, 30, 640, 400) +{ + this->dialog = dialog; + this->selected = 0; +} + +FFOptionsWindow::~FFOptionsWindow() +{ +} + +void FFOptionsWindow::create_objects() +{ + BC_Title *title; + int x = 10, y = 10; + add_subwindow(title = new BC_Title(x, y, dialog->codec_name)); + y += title->get_h() + 10; + int x0 = x, y0 = y; + add_subwindow(title = new BC_Title(x0, y0, _("Type: "))); + x0 += title->get_w() + 8; + add_subwindow(type = new BC_Title(x0, y0, (char *)"")); + x0 = x + 150; + add_subwindow(title = new BC_Title(x0, y0, _("Range: "))); + x0 += title->get_w() + 8; + add_subwindow(range = new BC_Title(x0, y0, (char *)"")); + x0 = x; + y += title->get_h() + 10; + add_subwindow(units = new FFOptionsUnits(this, x0, y, 120)); + x0 += units->get_w() + 8; + int x1 = get_w() - BC_GenericButton::calculate_w(this, _("Apply")) - 8; + add_subwindow(text = new FFOptionsText(this, x0, y, x1-x0 - 8)); + add_subwindow(apply = new FFOptionsApply(this, x1, y)); + y += units->get_h() + 10; + add_subwindow(kind = new FFOptionsKind(this, x1, y0, apply->get_w())); + kind->create_objects(); + const char *kind_text = _("Kind:"); + x1 -= BC_Title::calculate_w(this, kind_text) + 8; + add_subwindow(kind_title = new BC_Title(x1, y0, kind_text)); + + panel_x = x; panel_y = y; + panel_w = get_w()-10 - panel_x; + panel_h = get_h()-10 - panel_y - BC_OKButton::calculate_h(); + panel = new FFOptions_OptPanel(this, panel_x, panel_y, panel_w, panel_h); + add_subwindow(panel); + add_subwindow(new BC_OKButton(this)); + add_subwindow(new BC_CancelButton(this)); + panel->create_objects(); + options.initialize(this, FF_KIND_CODEC); + draw(); + show_window(1); +} + +void FFOptionsWindow::draw() +{ + update(selected); +} + +int FFOptionsWindow::resize_event(int w, int h) +{ + int x1 = w - 8 - kind->get_w(); + int y = kind->get_y(); + kind->reposition_window(x1, y); + x1 -= kind_title->get_w() + 8; + kind_title->reposition_window(x1,y); + x1 = get_w() - apply->get_w() - 8; + int y1 = units->get_y(); + apply->reposition_window(x1, y1); + int x0 = units->get_x() + units->get_w() + 8; + int y0 = units->get_y(); + text->reposition_window(x0,y0, x1-x0-8); + panel_w = get_w()-10 - panel_x; + panel_h = get_h()-10 - panel_y; + panel->reposition_window(panel_x,panel_y, panel_w, panel_h); + return 1; +} + +FFOptionsDialog::FFOptionsDialog() + : BC_DialogThread() +{ + this->options_window = 0; + this->codec_name = 0; + this->codec = 0; + this->ff_options = 0; + this->ff_len = 0; + this->ff_opts = 0; +} + +FFOptionsDialog::~FFOptionsDialog() +{ + close_window(); + delete [] codec_name; +} + +void FFOptionsDialog::load_options() +{ + char line[BCTEXTLEN]; + char key[BCSTRLEN], val[BCTEXTLEN]; + char *bp = ff_options, *dp = bp + ff_len-1; + int no = 0; + while( bp < dp && *bp != 0 ) { + ++no; + char *cp = line, *ep = cp+sizeof(line)-1; + while( *bp && cp<ep && (*cp=*bp++)!='\n' ) ++cp; + *cp = 0; + if( line[0] == '#' ) { + sprintf(key,"#%d", no); + av_dict_set(&ff_opts, key, line, 0); + continue; + } + if( line[0] == '\n' ) continue; + if( FFMPEG::scan_option_line(line, key, val) ) continue; + av_dict_set(&ff_opts, key, val, 0); + } +} + +void FFOptionsDialog::store_options() +{ + char *cp = ff_options, *ep = cp + ff_len-1; + AVDictionaryEntry *elem = 0; + while( (elem=av_dict_get(ff_opts, "", elem, AV_DICT_IGNORE_SUFFIX)) != 0 ) { + if( elem->key[0] == '#' ) { + cp += snprintf(cp,ep-cp, "%s\n", elem->value); + continue; + } + cp += snprintf(cp,ep-cp, "%s=%s\n", elem->key, elem->value); + } + *cp = 0; +} + +void FFOptionsDialog::start(const char *codec_name, AVCodec *codec, char *options, int len) +{ + if( options_window ) { + options_window->lock_window("FFOptionsDialog::start"); + options_window->raise_window(); + options_window->unlock_window(); + return; + } + + this->codec_name = cstrdup(codec_name); + this->codec = codec; + this->ff_opts = 0; + this->ff_options = options; + this->ff_len = len; + load_options(); + + BC_DialogThread::start(); +} + +BC_Window* FFOptionsDialog::new_gui() +{ + options_window = new FFOptionsWindow(this); + options_window->create_objects(); + return options_window; +} + +void FFOptionsDialog::handle_done_event(int result) +{ + if( !result ) { + store_options(); + update_options(); + } + options_window = 0; + delete [] codec_name; codec_name = 0; + av_dict_free(&ff_opts); +} + +FFOptionsAudioDialog::FFOptionsAudioDialog(FFMPEGConfigAudio *aud_config) +{ + this->aud_config = aud_config; +} + +FFOptionsAudioDialog::~FFOptionsAudioDialog() +{ +} + +void FFOptionsAudioDialog::update_options() +{ + aud_config->update_options(); +} + +FFOptionsVideoDialog::FFOptionsVideoDialog(FFMPEGConfigVideo *vid_config) +{ + this->vid_config = vid_config; +} + +FFOptionsVideoDialog::~FFOptionsVideoDialog() +{ +} + +void FFOptionsVideoDialog::update_options() +{ + vid_config->update_options(); +} + + +FFOptionsViewAudio::FFOptionsViewAudio(FFMPEGConfigAudio *aud_config, int x, int y, const char *text) + : BC_GenericButton(x, y, text) +{ + this->aud_config = aud_config; +} + +FFOptionsViewAudio::~FFOptionsViewAudio() +{ +} + +int FFOptionsViewAudio::handle_event() +{ + AVCodec *codec = 0; + char audio_codec[BCSTRLEN]; audio_codec[0] = 0; + Asset *asset = aud_config->asset; + const char *name = asset->acodec; + if( !FFMPEG::get_codec(audio_codec, "audio", name) ) + codec = avcodec_find_encoder_by_name(audio_codec); + if( !codec ) { + eprintf(_("no codec named: %s: %s"), name, audio_codec); + return 1; + } + aud_config->ff_options_dialog->start(audio_codec, codec, + asset->ff_audio_options, sizeof(asset->ff_audio_options)); + return 1; +} + +FFOptionsViewVideo::FFOptionsViewVideo(FFMPEGConfigVideo *vid_config, int x, int y, const char *text) + : BC_GenericButton(x, y, text) +{ + this->vid_config = vid_config; +} + +FFOptionsViewVideo::~FFOptionsViewVideo() +{ +} + +int FFOptionsViewVideo::handle_event() +{ + AVCodec *codec = 0; + char video_codec[BCSTRLEN]; video_codec[0] = 0; + Asset *asset = vid_config->asset; + const char *name = asset->vcodec; + if( !FFMPEG::get_codec(video_codec, "video", name) ) + codec = avcodec_find_encoder_by_name(video_codec); + if( !codec ) { + eprintf(_("no codec named: %s: %s"), name, video_codec); + return 1; + } + vid_config->ff_options_dialog->start(video_codec, codec, + asset->ff_video_options, sizeof(asset->ff_video_options)); + return 1; +} + diff --git a/cinelerra-5.1/cinelerra/fileffmpeg.h b/cinelerra-5.1/cinelerra/fileffmpeg.h index 907a6563..a9ce7d9c 100644 --- a/cinelerra-5.1/cinelerra/fileffmpeg.h +++ b/cinelerra-5.1/cinelerra/fileffmpeg.h @@ -2,8 +2,10 @@ #define __FILEFFMPEG_H__ #include "asset.inc" +#include "bcdialog.h" #include "bcwindowbase.inc" #include "bitspopup.inc" +#include "ffmpeg.h" #include "filebase.h" #include "fileffmpeg.inc" #include "indexfile.inc" @@ -18,20 +20,6 @@ #include <unistd.h> #include <string.h> -class FileFFMPEG; -class FFMpegConfigNum; -class FFMpegAudioNum; -class FFMpegVideoNum; -class FFOkButton; -class FFOptions; -class FFMPEGConfigAudio; -class FFAudioOptions; -class FFMPEGConfigAudioPopup; -class FFMPEGConfigAudioToggle; -class FFMPEGConfigVideo; -class FFVideoOptions; -class FFMPEGConfigVideoPopup; -class FFMPEGConfigVideoToggle; class FileFFMPEG : public FileBase { @@ -129,6 +117,7 @@ public: ~FFMPEGConfigAudio(); void create_objects(); + void update_options(); int close_event(); ArrayList<BC_ListBoxItem*> presets; @@ -137,9 +126,10 @@ public: FFAudioOptions *audio_options; BC_WindowBase *parent_window; Asset *asset; + FFOptionsDialog *ff_options_dialog; }; -class FFAudioOptions : public BC_TextBox +class FFAudioOptions : public BC_ScrollTextBox { public: FFAudioOptions(FFMPEGConfigAudio *audio_popup, @@ -176,6 +166,7 @@ public: ~FFMPEGConfigVideo(); void create_objects(); + void update_options(); int close_event(); ArrayList<BC_ListBoxItem*> presets; @@ -185,9 +176,10 @@ public: FFMpegVideoQuality *quality; FFVideoOptions *video_options; Asset *asset; + FFOptionsDialog *ff_options_dialog; }; -class FFVideoOptions : public BC_TextBox +class FFVideoOptions : public BC_ScrollTextBox { public: FFVideoOptions(FFMPEGConfigVideo *video_popup, @@ -230,4 +222,215 @@ public: void run(); }; + +class FFOptions_OptName : public BC_ListBoxItem { +public: + FFOptions_Opt *opt; + + FFOptions_OptName(FFOptions_Opt *opt, const char *nm); + ~FFOptions_OptName(); + +}; + +class FFOptions_OptValue : public BC_ListBoxItem { +public: + FFOptions_Opt *opt; + + void update(); + void update(const char *v); + FFOptions_OptValue(FFOptions_Opt *opt); +}; + +class FFOptions_Opt { +public: + FFOptions *options; + const AVOption *opt; + FFOptions_OptName *item_name; + FFOptions_OptValue *item_value; + + char *get(char *vp, int sz=-1); + void set(const char *val); + int types(char *rp); + int scalar(double d, char *rp); + int ranges(char *rp); + int units(ArrayList<const char *> &opts); + const char *unit_name(int id); + int units(char *rp); + const char *tip(); + + FFOptions_Opt(FFOptions *options, const AVOption *opt, const char *nm); + ~FFOptions_Opt(); +}; + +class FFOptions : public ArrayList<FFOptions_Opt *> +{ +public: + FFOptions(); + ~FFOptions(); + FFOptionsWindow *win; + AVCodecContext *avctx; + const void *obj; + + void initialize(FFOptionsWindow *win, int k); + static int cmpr(const void *a, const void *b); + int update(); + void dump(FILE *fp); +}; + +class FFOptions_OptPanel : public BC_ListBox { +public: + FFOptions_OptPanel(FFOptionsWindow *fwin, int x, int y, int w, int h); + ~FFOptions_OptPanel(); + void create_objects(); + int cursor_leave_event(); + + FFOptionsWindow *fwin; + ArrayList<BC_ListBoxItem*> items[2]; + ArrayList<BC_ListBoxItem*> &opts; + ArrayList<BC_ListBoxItem*> &vals; + + int selection_changed(); + int update(); +}; + +class FFOptionsKindItem : public BC_MenuItem +{ +public: + FFOptionsKind *kind; + int idx; + int handle_event(); + void show_label(); + + FFOptionsKindItem(FFOptionsKind *kind, const char *name, int idx); + ~FFOptionsKindItem(); +}; + +class FFOptionsKind : public BC_PopupMenu +{ + static const char *kinds[]; +public: + FFOptionsWindow *fwin; + int kind; + + void create_objects(); + int handle_event(); + void set(int k); + + FFOptionsKind(FFOptionsWindow *fwin, int x, int y, int w); + ~FFOptionsKind(); +}; + +class FFOptionsUnits : public BC_PopupMenu { +public: + FFOptionsWindow *fwin; + + FFOptionsUnits(FFOptionsWindow *fwin, int x, int y, int w); + ~FFOptionsUnits(); + int handle_event(); +}; + +class FFOptionsText : public BC_TextBox { +public: + FFOptionsWindow *fwin; + + FFOptionsText(FFOptionsWindow *fwin, int x, int y, int w); + ~FFOptionsText(); + int handle_event(); +}; + +class FFOptionsApply : public BC_GenericButton { +public: + FFOptionsWindow *fwin; + + FFOptionsApply(FFOptionsWindow *fwin, int x, int y); + ~FFOptionsApply(); + int handle_event(); +}; + +class FFOptionsWindow : public BC_Window +{ +public: + FFOptionsWindow(FFOptionsDialog *dialog); + ~FFOptionsWindow(); + + void create_objects(); + void update(FFOptions_Opt *oip); + void draw(); + int resize_event(int w, int h); + + FFOptionsDialog *dialog; + FFOptions options; + + FFOptions_OptPanel *panel; + int panel_x, panel_y, panel_w, panel_h; + BC_Title *type, *range, *kind_title; + FFOptions_Opt *selected; + + FFOptionsKind *kind; + FFOptionsUnits *units; + FFOptionsText *text; + FFOptionsApply *apply; +}; + +class FFOptionsDialog : public BC_DialogThread +{ +public: + FFOptionsDialog(); + ~FFOptionsDialog(); + virtual void update_options() = 0; + + void load_options(); + void store_options(); + void start(const char *codec_name, AVCodec *codec, char *ff_options, int ff_len); + BC_Window* new_gui(); + void handle_done_event(int result); + + FFOptionsWindow *options_window; + const char *codec_name; + AVCodec *codec; + char *ff_options; + int ff_len; + AVDictionary *ff_opts; +}; + +class FFOptionsAudioDialog : public FFOptionsDialog +{ +public: + FFMPEGConfigAudio *aud_config; + void update_options(); + + FFOptionsAudioDialog(FFMPEGConfigAudio *aud_config); + ~FFOptionsAudioDialog(); +}; + +class FFOptionsVideoDialog : public FFOptionsDialog +{ +public: + FFMPEGConfigVideo *vid_config; + void update_options(); + + FFOptionsVideoDialog(FFMPEGConfigVideo *vid_config); + ~FFOptionsVideoDialog(); +}; + +class FFOptionsViewAudio: public BC_GenericButton +{ +public: + FFOptionsViewAudio(FFMPEGConfigAudio *aud_config, int x, int y, const char *text); + ~FFOptionsViewAudio(); + + int handle_event(); + FFMPEGConfigAudio *aud_config; +}; + +class FFOptionsViewVideo : public BC_GenericButton +{ +public: + FFOptionsViewVideo(FFMPEGConfigVideo *vid_config, int x, int y, const char *text); + ~FFOptionsViewVideo(); + + int handle_event(); + FFMPEGConfigVideo *vid_config; +}; + #endif diff --git a/cinelerra-5.1/cinelerra/fileffmpeg.inc b/cinelerra-5.1/cinelerra/fileffmpeg.inc index 529beeea..98006e4f 100644 --- a/cinelerra-5.1/cinelerra/fileffmpeg.inc +++ b/cinelerra-5.1/cinelerra/fileffmpeg.inc @@ -23,11 +23,36 @@ #define FILEFFMPEG_INC class FileFFMPEG; +class FFMpegConfigNum; +class FFMpegAudioNum; +class FFMpegAudioBitrate; +class FFMpegVideoNum; +class FFMpegVideoBitrate; +class FFMpegVideoQuality; class FFMPEGConfigAudio; +class FFAudioOptions; class FFMPEGConfigAudioPopup; class FFMPEGConfigAudioToggle; class FFMPEGConfigVideo; +class FFVideoOptions; class FFMPEGConfigVideoPopup; class FFMPEGConfigVideoToggle; +class FFMPEGScanProgress; + +class FFOptions_OptName; +class FFOptions_OptValue; +class FFOptions_Opt; +class FFOptions; +class FFOptions_OptPanel; +class FFOptionsUnits; +class FFOptionsText; +class FFOptionsApply; +class FFOptionsWindow; +class FFOptionsDialog; +class FFOptionsKindItem; +class FFOptionsKind; + +#define FF_KIND_CODEC 0 +#define FF_KIND_FFMPEG 1 #endif diff --git a/cinelerra-5.1/cinelerra/mwindow.C b/cinelerra-5.1/cinelerra/mwindow.C index cdf80b20..44a7d005 100644 --- a/cinelerra-5.1/cinelerra/mwindow.C +++ b/cinelerra-5.1/cinelerra/mwindow.C @@ -2925,6 +2925,9 @@ int MWindow::create_aspect_ratio(float &w, float &h, int width, int height) { w = 1; h = 1; if(!width || !height) return 1; + if( width == 720 && (height == 480 || height == 576) ) { + w = 4; h = 3; return 0; // for NTSC and PAL + } double ar = (double)width / height; // square-ish pixels if( EQUIV(ar, 1.0000) ) return 0; diff --git a/cinelerra-5.1/ffmpeg/video/bluray1.m2ts b/cinelerra-5.1/ffmpeg/video/bluray1.m2ts new file mode 100644 index 00000000..a388e6f3 --- /dev/null +++ b/cinelerra-5.1/ffmpeg/video/bluray1.m2ts @@ -0,0 +1,8 @@ +mpegts libx264 +id=0x1011 +profile=high422 +pixel_format=yuv422p +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.1/thirdparty/src/ffmpeg.patch2 b/cinelerra-5.1/thirdparty/src/ffmpeg.patch2 new file mode 100644 index 00000000..daa99538 --- /dev/null +++ b/cinelerra-5.1/thirdparty/src/ffmpeg.patch2 @@ -0,0 +1,12 @@ +diff -ru ffmpeg-3.0.orig/libavformat/bluray.c ffmpeg-3.0/libavformat/bluray.c +--- ffmpeg-3.0.orig/libavformat/bluray.c 2015-03-13 11:34:50.000000000 -0600 ++++ ffmpeg-3.0/libavformat/bluray.c 2016-05-09 14:07:34.758713307 -0600 +@@ -28,7 +28,7 @@ + #include "libavutil/opt.h" + + #define BLURAY_PROTO_PREFIX "bluray:" +-#define MIN_PLAYLIST_LENGTH 180 /* 3 min */ ++#define MIN_PLAYLIST_LENGTH 0 + + typedef struct { + const AVClass *class; diff --git a/cinelerra-5.1/thirdparty/src/libbluray.patch1 b/cinelerra-5.1/thirdparty/src/libbluray.patch1 new file mode 100644 index 00000000..24627a1f --- /dev/null +++ b/cinelerra-5.1/thirdparty/src/libbluray.patch1 @@ -0,0 +1,11 @@ +--- a/player_wrappers/xine/input_bluray.c 2016-05-09 14:34:35.934918227 -0600 ++++ b/player_wrappers/xine/input_bluray.c 2016-05-09 14:27:59.880028563 -0600 +@@ -1423,7 +1423,7 @@ + + /* load title list */ + +- this->num_title_idx = bd_get_titles(this->bdh, TITLES_RELEVANT, 0); ++ this->num_title_idx = bd_get_titles(this->bdh, TITLES_RELEVANT, MIN_TITLE_LENGTH); + LOGMSG("%d titles\n", this->num_title_idx); + + if (this->num_title_idx < 1)