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)