summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--gtk/src/callbacks.c36
-rw-r--r--gtk/src/hb-backend.c128
-rw-r--r--libhb/bd.c9
-rw-r--r--libhb/common.c71
-rw-r--r--libhb/common.h202
-rw-r--r--libhb/cropscale.c16
-rw-r--r--libhb/deblock.c4
-rw-r--r--libhb/decavcodec.c42
-rw-r--r--libhb/deccc608sub.c8
-rw-r--r--libhb/declpcm.c4
-rw-r--r--libhb/decomb.c42
-rw-r--r--libhb/decsrtsub.c4
-rw-r--r--libhb/dectx3gsub.c4
-rw-r--r--libhb/decutf8sub.c4
-rw-r--r--libhb/deinterlace.c4
-rw-r--r--libhb/detelecine.c21
-rw-r--r--libhb/dvd.c11
-rw-r--r--libhb/dvdnav.c11
-rw-r--r--libhb/enc_qsv.c21
-rw-r--r--libhb/encavcodec.c25
-rw-r--r--libhb/enctheora.c21
-rw-r--r--libhb/encx264.c24
-rw-r--r--libhb/encx265.c32
-rw-r--r--libhb/hb.c270
-rw-r--r--libhb/hb.h14
-rw-r--r--libhb/hb_json.c1186
-rw-r--r--libhb/hb_json.h32
-rw-r--r--libhb/muxavformat.c47
-rw-r--r--libhb/muxcommon.c2
-rw-r--r--libhb/qsv_filter.c12
-rw-r--r--libhb/qsv_filter_pp.c28
-rw-r--r--libhb/reader.c7
-rw-r--r--libhb/rendersub.c10
-rw-r--r--libhb/rotate.c29
-rw-r--r--libhb/scan.c106
-rw-r--r--libhb/stream.c4
-rw-r--r--libhb/sync.c7
-rw-r--r--libhb/vadxva2.h9
-rw-r--r--libhb/vfr.c40
-rw-r--r--libhb/work.c125
-rw-r--r--macosx/Controller.m61
-rw-r--r--macosx/HBPicture.h12
-rw-r--r--macosx/HBPreviewController.m12
-rw-r--r--macosx/HBPreviewGenerator.m11
-rw-r--r--macosx/HBVideo.m6
-rw-r--r--macosx/HBVideoController.m4
-rw-r--r--macosx/PictureController.m80
-rw-r--r--test/test.c109
48 files changed, 1988 insertions, 979 deletions
diff --git a/gtk/src/callbacks.c b/gtk/src/callbacks.c
index d73913921..4a0afea64 100644
--- a/gtk/src/callbacks.c
+++ b/gtk/src/callbacks.c
@@ -964,7 +964,7 @@ update_title_duration(signal_user_data_t *ud)
start = ghb_settings_get_int(ud->settings, "start_point");
end = ghb_settings_get_int(ud->settings, "end_point");
frames = end - start + 1;
- duration = frames * title->rate_base / title->rate;
+ duration = frames * title->vrate.den / title->vrate.num;
break_duration(duration, &hh, &mm, &ss);
}
else
@@ -1068,8 +1068,8 @@ ghb_set_widget_ranges(signal_user_data_t *ud, GValue *settings)
// Set the limits of cropping. hb_set_anamorphic_size crashes if
// you pass it a cropped width or height == 0.
gint vbound, hbound;
- vbound = title->height;
- hbound = title->width;
+ vbound = title->geometry.height;
+ hbound = title->geometry.width;
val = ghb_settings_get_int(ud->settings, "PictureTopCrop");
spin_configure(ud, "PictureTopCrop", val, 0, vbound);
@@ -1101,7 +1101,8 @@ ghb_set_widget_ranges(signal_user_data_t *ud, GValue *settings)
else if (ghb_settings_combo_int(ud->settings, "PtoPType") == 2)
{
gdouble max_frames;
- max_frames = (gdouble)duration * title->rate / title->rate_base;
+ max_frames = (gdouble)duration *
+ title->vrate.num / title->vrate.den;
val = ghb_settings_get_int(ud->settings, "start_point");
spin_configure(ud, "start_point", val, 1, max_frames);
@@ -1658,9 +1659,9 @@ get_aspect_string(gint aspect_n, gint aspect_d)
}
static gchar*
-get_rate_string(gint rate_base, gint rate)
+get_rate_string(gint rate_num, gint rate_den)
{
- gdouble rate_f = (gdouble)rate / rate_base;
+ gdouble rate_f = (gdouble)rate_num / rate_den;
gchar *rate_s;
rate_s = g_strdup_printf("%.6g", rate_f);
@@ -1718,8 +1719,8 @@ update_crop_info(signal_user_data_t *ud)
crop[1] = ghb_settings_get_int(ud->settings, "PictureBottomCrop");
crop[2] = ghb_settings_get_int(ud->settings, "PictureLeftCrop");
crop[3] = ghb_settings_get_int(ud->settings, "PictureRightCrop");
- width = title->width - crop[2] - crop[3];
- height = title->height - crop[0] - crop[1];
+ width = title->geometry.width - crop[2] - crop[3];
+ height = title->geometry.height - crop[0] - crop[1];
widget = GHB_WIDGET(ud->builder, "crop_dimensions");
text = g_strdup_printf ("%d x %d", width, height);
gtk_label_set_text(GTK_LABEL(widget), text);
@@ -1770,21 +1771,21 @@ ghb_update_title_info(signal_user_data_t *ud)
gtk_label_set_text (GTK_LABEL(widget), _("Unknown"));
widget = GHB_WIDGET (ud->builder, "source_dimensions");
- text = g_strdup_printf ("%d x %d", title->width, title->height);
+ text = g_strdup_printf ("%d x %d", title->geometry.width, title->geometry.height);
gtk_label_set_text (GTK_LABEL(widget), text);
g_free(text);
widget = GHB_WIDGET (ud->builder, "source_aspect");
gint aspect_n, aspect_d;
hb_reduce(&aspect_n, &aspect_d,
- title->width * title->pixel_aspect_width,
- title->height * title->pixel_aspect_height);
+ title->geometry.width * title->geometry.par.num,
+ title->geometry.height * title->geometry.par.den);
text = get_aspect_string(aspect_n, aspect_d);
gtk_label_set_text (GTK_LABEL(widget), text);
g_free(text);
widget = GHB_WIDGET (ud->builder, "source_frame_rate");
- text = (gchar*)get_rate_string(title->rate_base, title->rate);
+ text = (gchar*)get_rate_string(title->vrate.num, title->vrate.den);
gtk_label_set_text (GTK_LABEL(widget), text);
g_free(text);
@@ -1816,8 +1817,8 @@ set_title_settings(signal_user_data_t *ud, GValue *settings)
ghb_settings_set_int(settings, "PtoPType", 0);
ghb_settings_set_int(settings, "start_point", 1);
ghb_settings_set_int(settings, "end_point", num_chapters);
- ghb_settings_set_int(settings, "source_width", title->width);
- ghb_settings_set_int(settings, "source_height", title->height);
+ ghb_settings_set_int(settings, "source_width", title->geometry.width);
+ ghb_settings_set_int(settings, "source_height", title->geometry.height);
ghb_settings_set_string(settings, "source", title->path);
if (title->type == HB_STREAM_TYPE || title->type == HB_FF_STREAM_TYPE)
{
@@ -1837,7 +1838,7 @@ set_title_settings(signal_user_data_t *ud, GValue *settings)
ghb_settings_get_value(ud->settings, "volume_label"));
}
ghb_settings_set_int(settings, "scale_width",
- title->width - title->crop[2] - title->crop[3]);
+ title->geometry.width - title->crop[2] - title->crop[3]);
// If anamorphic or keep_aspect, the hight will
// be automatically calculated
@@ -1848,7 +1849,7 @@ set_title_settings(signal_user_data_t *ud, GValue *settings)
if (!(keep_aspect || pic_par) || pic_par == 3)
{
ghb_settings_set_int(settings, "scale_height",
- title->width - title->crop[0] - title->crop[1]);
+ title->geometry.width - title->crop[0] - title->crop[1]);
}
ghb_set_scale_settings(settings, GHB_PIC_KEEP_PAR|GHB_PIC_USE_MAX);
@@ -2039,7 +2040,8 @@ ptop_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
}
else if (ghb_settings_combo_int(ud->settings, "PtoPType") == 2)
{
- gdouble max_frames = (gdouble)duration * title->rate / title->rate_base;
+ gdouble max_frames = (gdouble)duration *
+ title->vrate.num / title->vrate.den;
spin_configure(ud, "start_point", 1, 1, max_frames);
spin_configure(ud, "end_point", max_frames, 1, max_frames);
}
diff --git a/gtk/src/hb-backend.c b/gtk/src/hb-backend.c
index 3d2ca35f0..d7a56155e 100644
--- a/gtk/src/hb-backend.c
+++ b/gtk/src/hb-backend.c
@@ -3538,12 +3538,11 @@ ghb_set_scale_settings(GValue *settings, gint mode)
if (title == NULL) return;
hb_geometry_t srcGeo, resultGeo;
- hb_ui_geometry_t uiGeo;
+ hb_geometry_settings_t uiGeo;
- srcGeo.width = title->width;
- srcGeo.height = title->height;
- srcGeo.par.num = title->pixel_aspect_width;
- srcGeo.par.den = title->pixel_aspect_height;
+ srcGeo.width = title->geometry.width;
+ srcGeo.height = title->geometry.height;
+ srcGeo.par = title->geometry.par;
// First configure widgets
mod = ghb_settings_combo_int(settings, "PictureModulus");
@@ -3552,8 +3551,8 @@ ghb_set_scale_settings(GValue *settings, gint mode)
keep_aspect = ghb_settings_get_boolean(settings, "PictureKeepRatio");
autocrop = ghb_settings_get_boolean(settings, "PictureAutoCrop");
autoscale = ghb_settings_get_boolean(settings, "autoscale");
- // "Noscale" is a flag that says we prefer to crop extra to satisfy
- // alignment constraints rather than scaling to satisfy them.
+ // "PictureLooseCrop" is a flag that says we prefer to crop extra to
+ // satisfy alignment constraints rather than scaling to satisfy them.
loosecrop = ghb_settings_get_boolean(settings, "PictureLooseCrop");
// Align dimensions to either 16 or 2 pixels
// The scaler crashes if the dimensions are not divisible by 2
@@ -3582,13 +3581,13 @@ ghb_set_scale_settings(GValue *settings, gint mode)
crop[2] = ghb_settings_get_int(settings, "PictureLeftCrop");
crop[3] = ghb_settings_get_int(settings, "PictureRightCrop");
// Prevent manual crop from creating too small an image
- if (title->height - crop[0] < crop[1] + 16)
+ if (title->geometry.height - crop[0] < crop[1] + 16)
{
- crop[0] = title->height - crop[1] - 16;
+ crop[0] = title->geometry.height - crop[1] - 16;
}
- if (title->width - crop[2] < crop[3] + 16)
+ if (title->geometry.width - crop[2] < crop[3] + 16)
{
- crop[2] = title->width - crop[3] - 16;
+ crop[2] = title->geometry.width - crop[3] - 16;
}
}
if (loosecrop)
@@ -3596,8 +3595,8 @@ ghb_set_scale_settings(GValue *settings, gint mode)
gint need1, need2;
// Adjust the cropping to accomplish the desired width and height
- crop_width = title->width - crop[2] - crop[3];
- crop_height = title->height - crop[0] - crop[1];
+ crop_width = title->geometry.width - crop[2] - crop[3];
+ crop_height = title->geometry.height - crop[0] - crop[1];
width = MOD_DOWN(crop_width, mod);
height = MOD_DOWN(crop_height, mod);
@@ -3619,8 +3618,8 @@ ghb_set_scale_settings(GValue *settings, gint mode)
uiGeo.crop[2] = crop[2];
uiGeo.crop[3] = crop[3];
- crop_width = title->width - crop[2] - crop[3];
- crop_height = title->height - crop[0] - crop[1];
+ crop_width = title->geometry.width - crop[2] - crop[3];
+ crop_height = title->geometry.height - crop[0] - crop[1];
if (autoscale)
{
width = crop_width;
@@ -3658,31 +3657,28 @@ ghb_set_scale_settings(GValue *settings, gint mode)
uiGeo.keep |= HB_KEEP_DISPLAY_ASPECT;
uiGeo.itu_par = 0;
uiGeo.modulus = mod;
- uiGeo.width = width;
- uiGeo.height = height;
+ uiGeo.geometry.width = width;
+ uiGeo.geometry.height = height;
+ uiGeo.geometry.par = title->geometry.par;
uiGeo.maxWidth = max_width;
uiGeo.maxHeight = max_height;
- uiGeo.par.num = title->pixel_aspect_width;
- uiGeo.par.den = title->pixel_aspect_height;
- uiGeo.dar.num = 0;
- uiGeo.dar.den = 0;
if (pic_par != HB_ANAMORPHIC_NONE)
{
if (pic_par == HB_ANAMORPHIC_CUSTOM && !keep_aspect)
{
if (mode & GHB_PIC_KEEP_PAR)
{
- uiGeo.par.num =
+ uiGeo.geometry.par.num =
ghb_settings_get_int(settings, "PicturePARWidth");
- uiGeo.par.den =
+ uiGeo.geometry.par.den =
ghb_settings_get_int(settings, "PicturePARHeight");
}
else if (mode & (GHB_PIC_KEEP_DISPLAY_HEIGHT |
GHB_PIC_KEEP_DISPLAY_WIDTH))
{
- uiGeo.dar.num =
- ghb_settings_get_int(settings, "PictureDisplayWidth");
- uiGeo.dar.den = height;
+ uiGeo.geometry.par.num =
+ ghb_settings_get_int(settings, "PictureDisplayWidth");
+ uiGeo.geometry.par.den = width;
}
}
else
@@ -3757,8 +3753,8 @@ ghb_set_scale(signal_user_data_t *ud, gint mode)
widget = GHB_WIDGET (ud->builder, "scale_height");
gtk_spin_button_set_increments (GTK_SPIN_BUTTON(widget), mod, 16);
- // "Noscale" is a flag that says we prefer to crop extra to satisfy
- // alignment constraints rather than scaling to satisfy them.
+ // "PictureLooseCrop" is a flag that says we prefer to crop extra to
+ // satisfy alignment constraints rather than scaling to satisfy them.
gboolean loosecrop = ghb_settings_get_boolean(ud->settings, "PictureLooseCrop");
if (loosecrop)
{
@@ -3806,12 +3802,11 @@ ghb_set_scale(signal_user_data_t *ud, gint mode)
static void
get_preview_geometry(signal_user_data_t *ud, const hb_title_t *title,
- hb_geometry_t *srcGeo, hb_ui_geometry_t *uiGeo)
+ hb_geometry_t *srcGeo, hb_geometry_settings_t *uiGeo)
{
- srcGeo->width = title->width;
- srcGeo->height = title->height;
- srcGeo->par.num = title->pixel_aspect_width;
- srcGeo->par.den = title->pixel_aspect_height;
+ srcGeo->width = title->geometry.width;
+ srcGeo->height = title->geometry.height;
+ srcGeo->par = title->geometry.par;
uiGeo->mode = ghb_settings_combo_int(ud->settings, "PicturePAR");
uiGeo->keep = ghb_settings_get_boolean(ud->settings, "PictureKeepRatio") ||
@@ -3823,23 +3818,21 @@ get_preview_geometry(signal_user_data_t *ud, const hb_title_t *title,
uiGeo->crop[1] = ghb_settings_get_int(ud->settings, "PictureBottomCrop");
uiGeo->crop[2] = ghb_settings_get_int(ud->settings, "PictureLeftCrop");
uiGeo->crop[3] = ghb_settings_get_int(ud->settings, "PictureRightCrop");
- uiGeo->width = ghb_settings_get_int(ud->settings, "scale_width");
- uiGeo->height = ghb_settings_get_int(ud->settings, "scale_height");
+ uiGeo->geometry.width = ghb_settings_get_int(ud->settings, "scale_width");
+ uiGeo->geometry.height = ghb_settings_get_int(ud->settings, "scale_height");
+ uiGeo->geometry.par.num = ghb_settings_get_int(ud->settings, "PicturePARWidth");
+ uiGeo->geometry.par.den = ghb_settings_get_int(ud->settings, "PicturePARHeight");
uiGeo->maxWidth = 0;
uiGeo->maxHeight = 0;
- uiGeo->par.num = ghb_settings_get_int(ud->settings, "PicturePARWidth");
- uiGeo->par.den = ghb_settings_get_int(ud->settings, "PicturePARHeight");
- uiGeo->dar.num = 0;
- uiGeo->dar.den = 0;
if (ghb_settings_get_boolean(ud->prefs, "preview_show_crop"))
{
- gdouble xscale = (gdouble)uiGeo->width /
- (title->width - uiGeo->crop[2] - uiGeo->crop[3]);
- gdouble yscale = (gdouble)uiGeo->height /
- (title->height - uiGeo->crop[0] - uiGeo->crop[1]);
+ gdouble xscale = (gdouble)uiGeo->geometry.width /
+ (title->geometry.width - uiGeo->crop[2] - uiGeo->crop[3]);
+ gdouble yscale = (gdouble)uiGeo->geometry.height /
+ (title->geometry.height - uiGeo->crop[0] - uiGeo->crop[1]);
- uiGeo->width += xscale * (uiGeo->crop[2] + uiGeo->crop[3]);
- uiGeo->height += yscale * (uiGeo->crop[0] + uiGeo->crop[1]);
+ uiGeo->geometry.width += xscale * (uiGeo->crop[2] + uiGeo->crop[3]);
+ uiGeo->geometry.height += yscale * (uiGeo->crop[0] + uiGeo->crop[1]);
uiGeo->crop[0] = 0;
uiGeo->crop[1] = 0;
uiGeo->crop[2] = 0;
@@ -4257,7 +4250,7 @@ add_job(hb_handle_t *h, GValue *js, gint unique_id, int titleindex)
start = ghb_settings_get_int(js, "start_point");
end = ghb_settings_get_int(js, "end_point");
gint64 max_frames;
- max_frames = (gint64)(duration * title->rate / title->rate_base);
+ max_frames = (gint64)duration * title->vrate.num / title->vrate.den;
job->frame_to_start = (int64_t)MIN(max_frames-1, start-1);
job->frame_to_stop = (int64_t)MAX(start, end-1) -
job->frame_to_start;
@@ -4299,19 +4292,10 @@ add_job(hb_handle_t *h, GValue *js, gint unique_id, int titleindex)
gboolean decomb_deint = ghb_settings_get_boolean(js, "PictureDecombDeinterlace");
gint decomb = ghb_settings_combo_int(js, "PictureDecomb");
gint deint = ghb_settings_combo_int(js, "PictureDeinterlace");
- if (!decomb_deint)
- job->deinterlace = (deint != 0) ? 1 : 0;
- else
- job->deinterlace = 0;
job->grayscale = ghb_settings_get_boolean(js, "VideoGrayScale");
- job->anamorphic.mode = ghb_settings_combo_int(js, "PicturePAR");
- job->modulus = ghb_settings_combo_int(js, "PictureModulus");
- job->anamorphic.par_width = ghb_settings_get_int(js, "PicturePARWidth");
- job->anamorphic.par_height = ghb_settings_get_int(js, "PicturePARHeight");
- job->anamorphic.dar_width = job->anamorphic.dar_height = 0;
- job->anamorphic.keep_display_aspect =
- ghb_settings_get_boolean(js, "PictureKeepRatio");
+ job->par.num = ghb_settings_get_int(js, "PicturePARWidth");
+ job->par.den = ghb_settings_get_int(js, "PicturePARHeight");
int width, height, crop[4];
width = ghb_settings_get_int(js, "scale_width");
@@ -4358,7 +4342,7 @@ add_job(hb_handle_t *h, GValue *js, gint unique_id, int titleindex)
hb_add_filter( job, filter, filter_str );
g_free(filter_str);
}
- if( job->deinterlace )
+ if ( !decomb_deint && deint )
{
filter_str = NULL;
if (deint != 1)
@@ -4429,8 +4413,8 @@ add_job(hb_handle_t *h, GValue *js, gint unique_id, int titleindex)
job->vbitrate = ghb_settings_get_int(js, "VideoAvgBitrate");
}
- gint vrate;
- gint vrate_base = ghb_settings_video_framerate_rate(js, "VideoFramerate");
+ gint vrate_num;
+ gint vrate_den = ghb_settings_video_framerate_rate(js, "VideoFramerate");
gint cfr;
if (ghb_settings_get_boolean(js, "VideoFrameratePFR"))
cfr = 2;
@@ -4446,16 +4430,16 @@ add_job(hb_handle_t *h, GValue *js, gint unique_id, int titleindex)
ghb_log("zerolatency x264 tune selected, forcing constant framerate");
}
- if( vrate_base == 0 )
+ if( vrate_den == 0 )
{
- vrate = title->rate;
- vrate_base = title->rate_base;
+ vrate_num = title->vrate.num;
+ vrate_den = title->vrate.den;
}
else
{
- vrate = 27000000;
+ vrate_num = 27000000;
}
- filter_str = g_strdup_printf("%d:%d:%d", cfr, vrate, vrate_base);
+ filter_str = g_strdup_printf("%d:%d:%d", cfr, vrate_num, vrate_den);
filter = hb_filter_init(HB_FILTER_VFR);
hb_add_filter( job, filter, filter_str );
g_free(filter_str);
@@ -4971,7 +4955,7 @@ ghb_get_preview_image(
gint *out_height)
{
hb_geometry_t srcGeo, resultGeo;
- hb_ui_geometry_t uiGeo;
+ hb_geometry_settings_t uiGeo;
if( title == NULL ) return NULL;
@@ -4995,10 +4979,10 @@ ghb_get_preview_image(
hb_set_anamorphic_size2(&srcGeo, &uiGeo, &resultGeo);
// Rescale preview dimensions to adjust for screen PAR and settings PAR
- ghb_par_scale(ud, &uiGeo.width, &uiGeo.height,
+ ghb_par_scale(ud, &uiGeo.geometry.width, &uiGeo.geometry.height,
resultGeo.par.num, resultGeo.par.den);
- uiGeo.par.num = 1;
- uiGeo.par.den = 1;
+ uiGeo.geometry.par.num = 1;
+ uiGeo.geometry.par.den = 1;
GdkPixbuf *preview;
hb_image_t *image;
@@ -5007,7 +4991,7 @@ ghb_get_preview_image(
if (image == NULL)
{
preview = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
- title->width, title->height);
+ title->geometry.width, title->geometry.height);
return preview;
}
@@ -5052,8 +5036,8 @@ ghb_get_preview_image(
c2 = ghb_settings_get_int(ud->settings, "PictureLeftCrop");
c3 = ghb_settings_get_int(ud->settings, "PictureRightCrop");
- gdouble xscale = (gdouble)w / (gdouble)(title->width - c2 - c3);
- gdouble yscale = (gdouble)h / (gdouble)(title->height - c0 - c1);
+ gdouble xscale = (gdouble)w / (gdouble)(title->geometry.width - c2 - c3);
+ gdouble yscale = (gdouble)h / (gdouble)(title->geometry.height - c0 - c1);
*out_width = w;
*out_height = h;
diff --git a/libhb/bd.c b/libhb/bd.c
index 06d4feaef..26d4b6839 100644
--- a/libhb/bd.c
+++ b/libhb/bd.c
@@ -361,16 +361,19 @@ hb_title_t * hb_bd_title_scan( hb_bd_t * d, int tt, uint64_t min_duration )
switch ( bdvideo->aspect )
{
case BLURAY_ASPECT_RATIO_4_3:
- title->container_aspect = 4. / 3.;
+ title->container_dar.num = 4;
+ title->container_dar.den = 3;
break;
case BLURAY_ASPECT_RATIO_16_9:
- title->container_aspect = 16. / 9.;
+ title->container_dar.num = 16;
+ title->container_dar.den = 9;
break;
default:
hb_log( "bd: unknown aspect" );
goto fail;
}
- hb_log( "bd: aspect = %g", title->container_aspect );
+ hb_log("bd: aspect = %d:%d",
+ title->container_dar.num, title->container_dar.den);
/* Detect audio */
// Max primary BD audios is 32
diff --git a/libhb/common.c b/libhb/common.c
index 79be58758..ee4c566ba 100644
--- a/libhb/common.c
+++ b/libhb/common.c
@@ -2877,14 +2877,14 @@ hb_title_t * hb_title_init( char * path, int index )
t->list_subtitle = hb_list_init();
t->list_attachment = hb_list_init();
t->metadata = hb_metadata_init();
- strcat( t->path, path );
+ strncat(t->path, path, sizeof(t->path) - 1);
// default to decoding mpeg2
t->video_id = 0xE0;
t->video_codec = WORK_DECAVCODECV;
t->video_codec_param = AV_CODEC_ID_MPEG2VIDEO;
t->angle_count = 1;
- t->pixel_aspect_width = 1;
- t->pixel_aspect_height = 1;
+ t->geometry.par.num = 1;
+ t->geometry.par.den = 1;
return t;
}
@@ -2967,8 +2967,7 @@ static void job_reset_for_mac_ui( hb_job_t * job, hb_title_t * title )
job->vquality = -1.0;
job->vbitrate = 1000;
job->pass = 0;
- job->vrate = title->rate;
- job->vrate_base = title->rate_base;
+ job->vrate = title->vrate;
job->list_audio = hb_list_init();
job->list_subtitle = hb_list_init();
@@ -2979,7 +2978,7 @@ static void job_reset_for_mac_ui( hb_job_t * job, hb_title_t * title )
}
-static void job_setup( hb_job_t * job, hb_title_t * title )
+static void job_setup(hb_job_t * job, hb_title_t * title)
{
if ( job == NULL || title == NULL )
return;
@@ -2995,36 +2994,47 @@ static void job_setup( hb_job_t * job, hb_title_t * title )
memcpy( job->crop, title->crop, 4 * sizeof( int ) );
/* Preserve a source's pixel aspect, if it's available. */
- if( title->pixel_aspect_width && title->pixel_aspect_height )
+ if (title->geometry.par.num && title->geometry.par.den)
{
- job->anamorphic.par_width = title->pixel_aspect_width;
- job->anamorphic.par_height = title->pixel_aspect_height;
+ job->par = title->geometry.par;
}
-
- if( title->aspect != 0 && title->aspect != 1. &&
- !job->anamorphic.par_width && !job->anamorphic.par_height)
+ else if (title->dar.num && title->dar.den)
{
- hb_reduce( &job->anamorphic.par_width, &job->anamorphic.par_height,
- (int)(title->aspect * title->height + 0.5), title->width );
+ hb_reduce(&job->par.num, &job->par.den,
+ title->geometry.height * title->dar.num,
+ title->geometry.width * title->dar.den);
}
- job->width = title->width - job->crop[2] - job->crop[3];
- job->height = title->height - job->crop[0] - job->crop[1];
+ job->width = title->geometry.width - title->crop[2] - title->crop[3];
+ job->height = title->geometry.height - title->crop[0] - title->crop[1];
+#ifdef HB_DEPRECATE_JOB_SETTINGS
job->anamorphic.keep_display_aspect = 1;
+#endif
+
+ hb_geometry_t resultGeo, srcGeo;
+ hb_geometry_settings_t uiGeo;
+
+ srcGeo.width = title->geometry.width;
+ srcGeo.height = title->geometry.height;
+ srcGeo.par = title->geometry.par;
- int width, height, par_width, par_height;
- hb_set_anamorphic_size(job, &width, &height, &par_width, &par_height);
- job->width = width;
- job->height = height;
- job->anamorphic.par_width = par_width;
- job->anamorphic.par_height = par_height;
+ uiGeo.geometry.width = job->width;
+ uiGeo.geometry.height = job->height;
+ uiGeo.geometry.par = job->par;
+ uiGeo.mode = 0;
+ uiGeo.keep = HB_KEEP_DISPLAY_ASPECT;
+ uiGeo.itu_par = 0;
+
+ hb_set_anamorphic_size2(&srcGeo, &uiGeo, &resultGeo);
+ job->width = resultGeo.width;
+ job->height = resultGeo.height;
+ job->par = resultGeo.par;
job->vcodec = HB_VCODEC_FFMPEG_MPEG4;
job->vquality = -1.0;
job->vbitrate = 1000;
job->pass = 0;
- job->vrate = title->rate;
- job->vrate_base = title->rate_base;
+ job->vrate = title->vrate;
job->mux = HB_MUX_MP4;
@@ -3133,10 +3143,10 @@ hb_title_t * hb_find_title_by_index( hb_handle_t *h, int title_index )
*/
hb_job_t * hb_job_init_by_index( hb_handle_t * h, int title_index )
{
- hb_title_set_t *title_set = hb_get_title_set( h );
- hb_title_t * title = hb_list_item( title_set->list_title,
- title_index - 1 );
- return hb_job_init( title );
+ hb_title_t * title = hb_find_title_by_index(h, title_index);
+ if (title == NULL)
+ return NULL;
+ return hb_job_init(title);
}
hb_job_t * hb_job_init( hb_title_t * title )
@@ -3574,6 +3584,8 @@ int hb_audio_add(const hb_job_t * job, const hb_audio_config_t * audiocfg)
* HandBrakeCLI assumes this value is preserved in the jobs
* audio list, but in.track in the title's audio list is not
* required to be the same. */
+ // "track" in title->list_audio is an index into the source's tracks.
+ // "track" in job->list_audio is an index into title->list_audio
audio->config.in.track = audiocfg->in.track;
/* Really shouldn't ignore the passed out track, but there is currently no
@@ -3739,6 +3751,9 @@ int hb_subtitle_add(const hb_job_t * job, const hb_subtitle_config_t * subtitlec
return 0;
}
+ // "track" in title->list_audio is an index into the source's tracks.
+ // "track" in job->list_audio is an index into title->list_audio
+ subtitle->track = track;
subtitle->config = *subtitlecfg;
subtitle->out_track = hb_list_count(job->list_subtitle) + 1;
hb_list_add(job->list_subtitle, subtitle);
diff --git a/libhb/common.h b/libhb/common.h
index 77a5b9b31..1b86cf4e1 100644
--- a/libhb/common.h
+++ b/libhb/common.h
@@ -79,7 +79,7 @@ typedef struct hb_encoder_s hb_encoder_t;
typedef struct hb_container_s hb_container_t;
typedef struct hb_rational_s hb_rational_t;
typedef struct hb_geometry_s hb_geometry_t;
-typedef struct hb_ui_geometry_s hb_ui_geometry_t;
+typedef struct hb_geometry_settings_s hb_geometry_settings_t;
typedef struct hb_image_s hb_image_t;
typedef struct hb_job_s hb_job_t;
typedef struct hb_title_set_s hb_title_set_t;
@@ -250,19 +250,16 @@ struct hb_geometry_s
hb_rational_t par;
};
-struct hb_ui_geometry_s
+struct hb_geometry_settings_s
{
int mode; // Anamorphic mode, see job struct anamorphic
int keep; // Specifies settings that shouldn't be changed
int itu_par; // use dvd dimensions to determine PAR
int modulus; // pixel alignment for loose anamorphic
int crop[4]; // Pixels cropped from source before scaling
- int width; // destination storage width
- int height; // destination storage height
int maxWidth; // max destination storage width
int maxHeight; // max destination storage height
- hb_rational_t par; // Pixel aspect used in custom anamorphic
- hb_rational_t dar; // Display aspect used in custom anamorphic
+ hb_geometry_t geometry;
};
struct hb_image_s
@@ -460,45 +457,41 @@ struct hb_job_s
/* Include chapter marker track in mp4? */
int chapter_markers;
- /* Picture settings:
- crop: must be multiples of 2 (top/bottom/left/right)
- deinterlace: 0 or 1
- width: must be a multiple of 2
- height: must be a multiple of 2
- grayscale: black and white encoding
- pixel_ratio: store pixel aspect ratio in the video
- pixel_aspect_width: numerator for pixel aspect ratio
- pixel_aspect_height: denominator for pixel aspect ratio
- modulus: set a number for dimensions to be multiples of
- maxWidth: keep width below this
- maxHeight: keep height below this */
- int crop[4];
- int deinterlace;
+ // Video filters
+ int grayscale; // Black and white encoding
hb_list_t * list_filter;
+
+// These job settings should be depricated, but the mac ui is still using them.
+// hb_set_anamorphic_mode2 should be used during job setup which makes
+// these settings unnecessary
+#define HB_DEPRECATE_JOB_SETTINGS
+#ifdef HB_DEPRECATE_JOB_SETTINGS
+ int crop[4];
int width;
int height;
- int grayscale;
+ hb_rational_t par;
+ int modulus;
+ int maxWidth;
+ int maxHeight;
struct
{
hb_anamorphic_mode_t mode;
int itu_par;
- int par_width;
- int par_height;
- int dar_width; // 0 if normal
- int dar_height; // 0 if normal
int keep_display_aspect;
} anamorphic;
-
- int modulus;
- int maxWidth;
- int maxHeight;
+#else
+ PRIVATE int crop[4];
+ PRIVATE int width;
+ PRIVATE int height;
+ hb_rational_t par;
+#endif
/* Video settings:
vcodec: output codec
vquality: output quality (if < 0.0, bitrate is used instead)
vbitrate: output bitrate (Kbps)
- vrate, vrate_base: output framerate is vrate / vrate_base
+ vrate: output framerate
cfr: 0 (vfr), 1 (cfr), 2 (pfr) [see render.c]
pass: 0, 1 or 2 (or -1 for scan)
areBframes: boolean to note if b-frames are used */
@@ -515,10 +508,9 @@ struct hb_job_s
#define HB_VCODEC_H264_MASK (HB_VCODEC_X264|HB_VCODEC_QSV_H264)
int vcodec;
- float vquality;
+ double vquality;
int vbitrate;
- int vrate;
- int vrate_base;
+ hb_rational_t vrate;
int cfr;
int pass;
int fastfirstpass;
@@ -718,8 +710,8 @@ struct hb_audio_config_s
int samplerate; /* Output sample rate (Hz) */
int samples_per_frame; /* Number of samples per frame */
int bitrate; /* Output bitrate (Kbps) */
- float quality; /* Output quality (encoder-specific) */
- float compression_level; /* Output compression level (encoder-specific) */
+ double quality; /* Output quality (encoder-specific) */
+ double compression_level; /* Output compression level (encoder-specific) */
double dynamic_range_compression; /* Amount of DRC applied to this track */
double gain; /* Gain (in dB), negative is quieter */
int normalize_mix_level; /* mix level normalization (boolean) */
@@ -920,79 +912,75 @@ struct hb_metadata_s
struct hb_title_s
{
enum { HB_DVD_TYPE, HB_BD_TYPE, HB_STREAM_TYPE, HB_FF_STREAM_TYPE } type;
- uint32_t reg_desc;
- char path[1024];
- char name[1024];
- int index;
- int playlist;
- int vts;
- int ttn;
- int cell_start;
- int cell_end;
- uint64_t block_start;
- uint64_t block_end;
- uint64_t block_count;
- int angle_count;
- void *opaque_priv;
+ uint32_t reg_desc;
+ char path[1024];
+ char name[1024];
+ int index;
+ int playlist;
+ int vts;
+ int ttn;
+ int cell_start;
+ int cell_end;
+ uint64_t block_start;
+ uint64_t block_end;
+ uint64_t block_count;
+ int angle_count;
+ void * opaque_priv;
/* Visual-friendly duration */
- int hours;
- int minutes;
- int seconds;
+ int hours;
+ int minutes;
+ int seconds;
/* Exact duration (in 1/90000s) */
- uint64_t duration;
-
- double aspect; // aspect ratio for the title's video
- double container_aspect; // aspect ratio from container (0 if none)
- int has_resolution_change;
- int width;
- int height;
- int pixel_aspect_width;
- int pixel_aspect_height;
- int color_prim;
- int color_transfer;
- int color_matrix;
- int rate;
- int rate_base;
- int crop[4];
+ uint64_t duration;
+
+ int has_resolution_change;
+ hb_geometry_t geometry;
+ hb_rational_t dar; // aspect ratio for the title's video
+ hb_rational_t container_dar; // aspect ratio from container (0 if none)
+ int color_prim;
+ int color_transfer;
+ int color_matrix;
+ hb_rational_t vrate;
+ int crop[4];
enum {HB_DVD_DEMUXER, HB_TS_DEMUXER, HB_PS_DEMUXER, HB_NULL_DEMUXER} demuxer;
- int detected_interlacing;
- int pcr_pid; /* PCR PID for TS streams */
- int video_id; /* demuxer stream id for video */
- int video_codec; /* worker object id of video codec */
- uint32_t video_stream_type; /* stream type from source stream */
- int video_codec_param; /* codec specific config */
- char *video_codec_name;
- int video_bitrate;
- char *container_name;
- int data_rate;
+ int detected_interlacing;
+ int pcr_pid; /* PCR PID for TS streams */
+ int video_id; /* demuxer stream id for video */
+ int video_codec; /* worker object id of video codec */
+ uint32_t video_stream_type; /* stream type from source stream */
+ int video_codec_param; /* codec specific config */
+ char * video_codec_name;
+ int video_bitrate;
+ char * container_name;
+ int data_rate;
// additional supported video decoders (e.g. HW-accelerated implementations)
- int video_decode_support;
+ int video_decode_support;
#define HB_DECODE_SUPPORT_SW 0x01 // software (libavcodec or mpeg2dec)
#define HB_DECODE_SUPPORT_QSV 0x02 // Intel Quick Sync Video
- hb_metadata_t *metadata;
+ hb_metadata_t * metadata;
- hb_list_t * list_chapter;
- hb_list_t * list_audio;
- hb_list_t * list_subtitle;
- hb_list_t * list_attachment;
+ hb_list_t * list_chapter;
+ hb_list_t * list_audio;
+ hb_list_t * list_subtitle;
+ hb_list_t * list_attachment;
#define HB_TITLE_JOBS
#if defined(HB_TITLE_JOBS)
- hb_job_t * job;
+ hb_job_t * job;
#endif
- uint32_t flags;
+ uint32_t flags;
// set if video stream doesn't have IDR frames
#define HBTF_NO_IDR (1 << 0)
#define HBTF_SCAN_COMPLETE (1 << 1)
// whether OpenCL scaling is supported for this source
- int opencl_support;
- int hwd_support; // TODO: merge to video_decode_support
+ int opencl_support;
+ int hwd_support; // TODO: merge to video_decode_support
};
// Update win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/hb_state_s.cs when changing this struct
@@ -1050,27 +1038,23 @@ struct hb_state_s
typedef struct hb_work_info_s
{
- const char * name;
- int profile;
- int level;
- int bitrate;
- int rate;
- int rate_base;
- uint32_t version;
- uint32_t flags;
- uint32_t mode;
+ const char * name;
+ int profile;
+ int level;
+ int bitrate;
+ hb_rational_t rate;
+ uint32_t version;
+ uint32_t flags;
+ uint32_t mode;
union
{
struct
{ // info only valid for video decoders
- int width;
- int height;
- int pixel_aspect_width;
- int pixel_aspect_height;
- int color_prim;
- int color_transfer;
- int color_matrix;
- int video_decode_support;
+ hb_geometry_t geometry;
+ int color_prim;
+ int color_transfer;
+ int color_matrix;
+ int video_decode_support;
};
struct
{ // info only valid for audio decoders
@@ -1167,13 +1151,9 @@ typedef struct hb_filter_init_s
{
hb_job_t * job;
int pix_fmt;
- int width;
- int height;
- int par_width;
- int par_height;
+ hb_geometry_t geometry;
int crop[4];
- int vrate_base;
- int vrate;
+ hb_rational_t vrate;
int cfr;
int use_dxva;
} hb_filter_init_t;
@@ -1222,6 +1202,7 @@ struct hb_filter_object_s
enum
{
// for QSV - important to have before other filters
+ HB_FILTER_FIRST = 1,
HB_FILTER_QSV_PRE = 1,
// First, filters that may change the framerate (drop or dup frames)
@@ -1245,6 +1226,7 @@ enum
HB_FILTER_QSV_POST,
// default MSDK VPP filter
HB_FILTER_QSV,
+ HB_FILTER_LAST = HB_FILTER_QSV
};
hb_filter_object_t * hb_filter_init( int filter_id );
diff --git a/libhb/cropscale.c b/libhb/cropscale.c
index 4fa026628..d6badd360 100644
--- a/libhb/cropscale.c
+++ b/libhb/cropscale.c
@@ -65,10 +65,10 @@ static int hb_crop_scale_init( hb_filter_object_t * filter,
// TODO: add pix format option to settings
pv->job = init->job;
pv->pix_fmt_out = init->pix_fmt;
- pv->width_in = init->width;
- pv->height_in = init->height;
- pv->width_out = init->width - (init->crop[2] + init->crop[3]);
- pv->height_out = init->height - (init->crop[0] + init->crop[1]);
+ pv->width_in = init->geometry.width;
+ pv->height_in = init->geometry.height;
+ pv->width_out = init->geometry.width - (init->crop[2] + init->crop[3]);
+ pv->height_out = init->geometry.height - (init->crop[0] + init->crop[1]);
/* OpenCL/DXVA2 */
pv->use_dxva = init->use_dxva;
@@ -91,8 +91,8 @@ static int hb_crop_scale_init( hb_filter_object_t * filter,
// Set init values so the next stage in the pipline
// knows what it will be getting
init->pix_fmt = pv->pix_fmt;
- init->width = pv->width_out;
- init->height = pv->height_out;
+ init->geometry.width = pv->width_out;
+ init->geometry.height = pv->height_out;
memcpy( init->crop, pv->crop, sizeof( int[4] ) );
return 0;
@@ -110,8 +110,8 @@ static int hb_crop_scale_info( hb_filter_object_t * filter,
// knows what it will be getting
memset( info, 0, sizeof( hb_filter_info_t ) );
info->out.pix_fmt = pv->pix_fmt;
- info->out.width = pv->width_out;
- info->out.height = pv->height_out;
+ info->out.geometry.width = pv->width_out;
+ info->out.geometry.height = pv->height_out;
memcpy( info->out.crop, pv->crop, sizeof( int[4] ) );
int cropped_width = pv->width_in - ( pv->crop[2] + pv->crop[3] );
diff --git a/libhb/deblock.c b/libhb/deblock.c
index 1d50fc552..5acb3f5d0 100644
--- a/libhb/deblock.c
+++ b/libhb/deblock.c
@@ -371,9 +371,9 @@ static int hb_deblock_init( hb_filter_object_t * filter,
break;
}
- int h = (init->height+16+15)&(~15);
+ int h = (init->geometry.height + 16 + 15) & (~15);
- pv->pp7_temp_stride = (init->width+16+15)&(~15);
+ pv->pp7_temp_stride = (init->geometry.width + 16 + 15) & (~15);
pv->pp7_src = (uint8_t*)malloc( pv->pp7_temp_stride*(h+8)*sizeof(uint8_t) );
diff --git a/libhb/decavcodec.c b/libhb/decavcodec.c
index 324b665c3..f1d0c3477 100644
--- a/libhb/decavcodec.c
+++ b/libhb/decavcodec.c
@@ -592,8 +592,8 @@ static int decavcodecaInfo( hb_work_object_t *w, hb_work_info_t *info )
{
AVCodecContext *context = pv->context;
info->bitrate = context->bit_rate;
- info->rate = context->time_base.num;
- info->rate_base = context->time_base.den;
+ info->rate.num = context->time_base.num;
+ info->rate.den = context->time_base.den;
info->profile = context->profile;
info->level = context->level;
return 1;
@@ -710,15 +710,15 @@ static int decavcodecaBSInfo( hb_work_object_t *w, const hb_buffer_t *buf,
}
if (dec_len > 0 && got_frame)
{
- info->rate_base = 1;
+ info->rate.den = 1;
// libavcoded doesn't consistently set frame->sample_rate
if (frame->sample_rate != 0)
{
- info->rate = frame->sample_rate;
+ info->rate.num = frame->sample_rate;
}
else
{
- info->rate = context->sample_rate;
+ info->rate.num = context->sample_rate;
hb_log("decavcodecaBSInfo: warning: invalid frame sample_rate! Using context sample_rate.");
}
info->samples_per_frame = frame->nb_samples;
@@ -727,7 +727,7 @@ static int decavcodecaBSInfo( hb_work_object_t *w, const hb_buffer_t *buf,
int channels = av_get_channel_layout_nb_channels(frame->channel_layout);
if (bps > 0)
{
- info->bitrate = (bps * channels * info->rate);
+ info->bitrate = bps * channels * info->rate.num;
}
else if (context->bit_rate > 0)
{
@@ -842,8 +842,8 @@ static hb_buffer_t *copy_frame( hb_work_private_t *pv )
}
else
{
- w = pv->job->title->width;
- h = pv->job->title->height;
+ w = pv->job->title->geometry.width;
+ h = pv->job->title->geometry.height;
}
#ifdef USE_HWD
@@ -860,7 +860,7 @@ static hb_buffer_t *copy_frame( hb_work_private_t *pv )
{
pv->dst_frame = malloc( ww * hh * 3 / 2 );
}
- if( hb_va_extract( pv->dxva2, pv->dst_frame, pv->frame, pv->job->width, pv->job->height, pv->job->title->crop, pv->opencl_scale, pv->job->use_opencl, pv->job->use_decomb, pv->job->use_detelecine ) == HB_WORK_ERROR )
+ if( hb_va_extract( pv->dxva2, pv->dst_frame, pv->frame, pv->job->geometry.width, pv->job->geometry.height, pv->job->title->crop, pv->opencl_scale, pv->job->use_opencl, pv->job->use_decomb, pv->job->use_detelecine ) == HB_WORK_ERROR )
{
hb_log( "hb_va_Extract failed!!!!!!" );
}
@@ -1360,7 +1360,7 @@ static int decodeFrame( hb_work_object_t *w, uint8_t *data, int size, int sequen
if (subtitle == NULL)
{
subtitle = calloc(sizeof( hb_subtitle_t ), 1);
- subtitle->track = 0;
+ subtitle->track = hb_list_count(pv->title->list_subtitle);
subtitle->id = 0;
subtitle->format = TEXTSUB;
subtitle->source = CC608SUB;
@@ -1998,15 +1998,15 @@ static int decavcodecvInfo( hb_work_object_t *w, hb_work_info_t *info )
// HandBrake's video pipeline uses yuv420 color. This means all
// dimensions must be even. So we must adjust the dimensions
// of incoming video if not even.
- info->width = pv->context->width & ~1;
- info->height = pv->context->height & ~1;
+ info->geometry.width = pv->context->width & ~1;
+ info->geometry.height = pv->context->height & ~1;
- info->pixel_aspect_width = pv->context->sample_aspect_ratio.num;
- info->pixel_aspect_height = pv->context->sample_aspect_ratio.den;
+ info->geometry.par.num = pv->context->sample_aspect_ratio.num;
+ info->geometry.par.den = pv->context->sample_aspect_ratio.den;
compute_frame_duration( pv );
- info->rate = 27000000;
- info->rate_base = pv->duration * 300.;
+ info->rate.num = 27000000;
+ info->rate.den = pv->duration * 300.;
info->profile = pv->context->profile;
info->level = pv->context->level;
@@ -2027,11 +2027,11 @@ static int decavcodecvInfo( hb_work_object_t *w, hb_work_info_t *info )
break;
default:
{
- if( ( info->width >= 1280 || info->height >= 720 ) ||
- ( info->width > 720 && info->height > 576 ) )
+ if ((info->geometry.width >= 1280 || info->geometry.height >= 720)||
+ (info->geometry.width > 720 && info->geometry.height > 576 ))
// ITU BT.709 HD content
info->color_prim = HB_COLR_PRI_BT709;
- else if( info->rate_base == 1080000 )
+ else if( info->rate.den == 1080000 )
// ITU BT.601 DVD or SD TV content (PAL)
info->color_prim = HB_COLR_PRI_EBUTECH;
else
@@ -2068,8 +2068,8 @@ static int decavcodecvInfo( hb_work_object_t *w, hb_work_info_t *info )
break;
default:
{
- if( ( info->width >= 1280 || info->height >= 720 ) ||
- ( info->width > 720 && info->height > 576 ) )
+ if ((info->geometry.width >= 1280 || info->geometry.height >= 720)||
+ (info->geometry.width > 720 && info->geometry.height > 576 ))
// ITU BT.709 HD content
info->color_matrix = HB_COLR_MAT_BT709;
else
diff --git a/libhb/deccc608sub.c b/libhb/deccc608sub.c
index 081eb6b89..ecf60473c 100644
--- a/libhb/deccc608sub.c
+++ b/libhb/deccc608sub.c
@@ -1741,8 +1741,8 @@ static int decccInit( hb_work_object_t * w, hb_job_t * job )
if( pv->cc608 )
{
- pv->cc608->width = job->title->width;
- pv->cc608->height = job->title->height;
+ pv->cc608->width = job->title->geometry.width;
+ pv->cc608->height = job->title->geometry.height;
memcpy(pv->cc608->crop, job->crop, sizeof(int[4]));
retval = general_608_init(pv->cc608);
if( !retval )
@@ -1759,8 +1759,8 @@ static int decccInit( hb_work_object_t * w, hb_job_t * job )
if (!retval)
{
// Generate generic SSA Script Info.
- int height = job->title->height - job->crop[0] - job->crop[1];
- int width = job->title->width - job->crop[2] - job->crop[3];
+ int height = job->title->geometry.height - job->crop[0] - job->crop[1];
+ int width = job->title->geometry.width - job->crop[2] - job->crop[3];
hb_subtitle_add_ssa_header(w->subtitle, width, height);
}
// When rendering subs, we need to push rollup subtitles out
diff --git a/libhb/declpcm.c b/libhb/declpcm.c
index 95705225e..bec7aaca5 100644
--- a/libhb/declpcm.c
+++ b/libhb/declpcm.c
@@ -374,8 +374,8 @@ static int declpcmBSInfo( hb_work_object_t *w, const hb_buffer_t *b,
memset( info, 0, sizeof(*info) );
info->name = "LPCM";
- info->rate = rate;
- info->rate_base = 1;
+ info->rate.num = rate;
+ info->rate.den = 1;
info->bitrate = bitrate;
info->flags = ( b->data[3] << 16 ) | ( b->data[4] << 8 ) | b->data[5];
info->matrix_encoding = AV_MATRIX_ENCODING_NONE;
diff --git a/libhb/decomb.c b/libhb/decomb.c
index 42feaa8d6..f5698a963 100644
--- a/libhb/decomb.c
+++ b/libhb/decomb.c
@@ -2024,15 +2024,18 @@ static int hb_decomb_init( hb_filter_object_t * filter,
pv->cpu_count = hb_get_cpu_count();
// Make segment sizes an even number of lines
- int height = hb_image_height(init->pix_fmt, init->height, 0);
+ int height = hb_image_height(init->pix_fmt, init->geometry.height, 0);
pv->segment_height[0] = (height / pv->cpu_count) & ~1;
pv->segment_height[1] = hb_image_height(init->pix_fmt, pv->segment_height[0], 1);
pv->segment_height[2] = hb_image_height(init->pix_fmt, pv->segment_height[0], 2);
/* Allocate buffers to store comb masks. */
- pv->mask = hb_frame_buffer_init(init->pix_fmt, init->width, init->height);
- pv->mask_filtered = hb_frame_buffer_init(init->pix_fmt, init->width, init->height);
- pv->mask_temp = hb_frame_buffer_init(init->pix_fmt, init->width, init->height);
+ pv->mask = hb_frame_buffer_init(init->pix_fmt,
+ init->geometry.width, init->geometry.height);
+ pv->mask_filtered = hb_frame_buffer_init(init->pix_fmt,
+ init->geometry.width, init->geometry.height);
+ pv->mask_temp = hb_frame_buffer_init(init->pix_fmt,
+ init->geometry.width, init->geometry.height);
memset(pv->mask->data, 0, pv->mask->size);
memset(pv->mask_filtered->data, 0, pv->mask_filtered->size);
memset(pv->mask_temp->data, 0, pv->mask_temp->size);
@@ -2044,14 +2047,14 @@ static int hb_decomb_init( hb_filter_object_t * filter,
for( ii = 0; ii < 4; ii++ )
{
pv->eedi_half[ii] = hb_frame_buffer_init(
- init->pix_fmt, init->width, init->height / 2);
+ init->pix_fmt, init->geometry.width, init->geometry.height / 2);
}
/* Allocate full-height eedi2 buffers */
for( ii = 0; ii < 5; ii++ )
{
pv->eedi_full[ii] = hb_frame_buffer_init(
- init->pix_fmt, init->width, init->height);
+ init->pix_fmt, init->geometry.width, init->geometry.height);
}
}
@@ -2090,7 +2093,7 @@ static int hb_decomb_init( hb_filter_object_t * filter,
* Final segment
*/
thread_args->segment_height[pp] =
- hb_image_height(init->pix_fmt, init->height, pp) -
+ hb_image_height(init->pix_fmt, init->geometry.height, pp) -
thread_args->segment_start[pp];
} else {
thread_args->segment_height[pp] = pv->segment_height[pp];
@@ -2140,7 +2143,7 @@ static int hb_decomb_init( hb_filter_object_t * filter,
* Final segment
*/
thread_args->segment_height[pp] =
- hb_image_height(init->pix_fmt, init->height, pp) -
+ hb_image_height(init->pix_fmt, init->geometry.height, pp) -
thread_args->segment_start[pp];
} else {
thread_args->segment_height[pp] = pv->segment_height[pp];
@@ -2158,7 +2161,7 @@ static int hb_decomb_init( hb_filter_object_t * filter,
decomb_prev_thread_args = thread_args;
}
- pv->comb_check_nthreads = init->height / pv->block_height;
+ pv->comb_check_nthreads = init->geometry.height / pv->block_height;
if (pv->comb_check_nthreads > pv->cpu_count)
pv->comb_check_nthreads = pv->cpu_count;
@@ -2194,7 +2197,7 @@ static int hb_decomb_init( hb_filter_object_t * filter,
}
// Make segment hight a multiple of block_height
- int h = hb_image_height(init->pix_fmt, init->height, pp) / pv->comb_check_nthreads;
+ int h = hb_image_height(init->pix_fmt, init->geometry.height, pp) / pv->comb_check_nthreads;
h = h / pv->block_height * pv->block_height;
if (h == 0)
h = pv->block_height;
@@ -2205,7 +2208,7 @@ static int hb_decomb_init( hb_filter_object_t * filter,
* Final segment
*/
thread_args->segment_height[pp] =
- hb_image_height(init->pix_fmt, init->height, pp) -
+ hb_image_height(init->pix_fmt, init->geometry.height, pp) -
thread_args->segment_start[pp];
} else {
thread_args->segment_height[pp] = h;
@@ -2256,7 +2259,7 @@ static int hb_decomb_init( hb_filter_object_t * filter,
* Final segment
*/
thread_args->segment_height[pp] =
- hb_image_height(init->pix_fmt, init->height, pp) -
+ hb_image_height(init->pix_fmt, init->geometry.height, pp) -
thread_args->segment_start[pp];
} else {
thread_args->segment_height[pp] = pv->segment_height[pp];
@@ -2307,7 +2310,7 @@ static int hb_decomb_init( hb_filter_object_t * filter,
* Final segment
*/
thread_args->segment_height[pp] =
- hb_image_height(init->pix_fmt, init->height, pp) -
+ hb_image_height(init->pix_fmt, init->geometry.height, pp) -
thread_args->segment_start[pp];
} else {
thread_args->segment_height[pp] = pv->segment_height[pp];
@@ -2356,7 +2359,7 @@ static int hb_decomb_init( hb_filter_object_t * filter,
* Final segment
*/
thread_args->segment_height[pp] =
- hb_image_height(init->pix_fmt, init->height, pp) -
+ hb_image_height(init->pix_fmt, init->geometry.height, pp) -
thread_args->segment_start[pp];
} else {
thread_args->segment_height[pp] = pv->segment_height[pp];
@@ -2389,19 +2392,20 @@ static int hb_decomb_init( hb_filter_object_t * filter,
if( pv->post_processing > 1 )
{
- int stride = hb_image_stride(init->pix_fmt, init->width, 0);
+ int stride;
+ stride = hb_image_stride(init->pix_fmt, init->geometry.width, 0);
pv->cx2 = (int*)eedi2_aligned_malloc(
- init->height * stride * sizeof(int), 16);
+ init->geometry.height * stride * sizeof(int), 16);
pv->cy2 = (int*)eedi2_aligned_malloc(
- init->height * stride * sizeof(int), 16);
+ init->geometry.height * stride * sizeof(int), 16);
pv->cxy = (int*)eedi2_aligned_malloc(
- init->height * stride * sizeof(int), 16);
+ init->geometry.height * stride * sizeof(int), 16);
pv->tmpc = (int*)eedi2_aligned_malloc(
- init->height * stride * sizeof(int), 16);
+ init->geometry.height * stride * sizeof(int), 16);
if( !pv->cx2 || !pv->cy2 || !pv->cxy || !pv->tmpc )
hb_log("EEDI2: failed to malloc derivative arrays");
diff --git a/libhb/decsrtsub.c b/libhb/decsrtsub.c
index da58c9616..ffb737bdf 100644
--- a/libhb/decsrtsub.c
+++ b/libhb/decsrtsub.c
@@ -697,8 +697,8 @@ static int decsrtInit( hb_work_object_t * w, hb_job_t * job )
if (!retval)
{
// Generate generic SSA Script Info.
- int height = job->title->height - job->crop[0] - job->crop[1];
- int width = job->title->width - job->crop[2] - job->crop[3];
+ int height = job->title->geometry.height - job->crop[0] - job->crop[1];
+ int width = job->title->geometry.width - job->crop[2] - job->crop[3];
hb_subtitle_add_ssa_header(w->subtitle, width, height);
}
return retval;
diff --git a/libhb/dectx3gsub.c b/libhb/dectx3gsub.c
index 9cfc031ac..13955e803 100644
--- a/libhb/dectx3gsub.c
+++ b/libhb/dectx3gsub.c
@@ -248,8 +248,8 @@ static int dectx3gInit( hb_work_object_t * w, hb_job_t * job )
// parse w->subtitle->extradata txg3 sample description into
// SSA format and replace extradata.
// For now we just create a generic SSA Script Info.
- int height = job->title->height - job->crop[0] - job->crop[1];
- int width = job->title->width - job->crop[2] - job->crop[3];
+ int height = job->title->geometry.height - job->crop[0] - job->crop[1];
+ int width = job->title->geometry.width - job->crop[2] - job->crop[3];
hb_subtitle_add_ssa_header(w->subtitle, width, height);
return 0;
diff --git a/libhb/decutf8sub.c b/libhb/decutf8sub.c
index b8ea9bf5f..0d8ac5066 100644
--- a/libhb/decutf8sub.c
+++ b/libhb/decutf8sub.c
@@ -35,8 +35,8 @@ static int decutf8Init(hb_work_object_t *w, hb_job_t *job)
w->private_data = pv;
// Generate generic SSA Script Info.
- int height = job->title->height - job->crop[0] - job->crop[1];
- int width = job->title->width - job->crop[2] - job->crop[3];
+ int height = job->title->geometry.height - job->crop[0] - job->crop[1];
+ int width = job->title->geometry.width - job->crop[2] - job->crop[3];
hb_subtitle_add_ssa_header(w->subtitle, width, height);
return 0;
diff --git a/libhb/deinterlace.c b/libhb/deinterlace.c
index 44ff88d90..dadbd397d 100644
--- a/libhb/deinterlace.c
+++ b/libhb/deinterlace.c
@@ -454,8 +454,8 @@ static int hb_deinterlace_init( hb_filter_object_t * filter,
filter->private_data = calloc( 1, sizeof(struct hb_filter_private_s) );
hb_filter_private_t * pv = filter->private_data;
- pv->width = init->width;
- pv->height = init->height;
+ pv->width = init->geometry.width;
+ pv->height = init->geometry.height;
pv->yadif_ready = 0;
pv->yadif_mode = YADIF_MODE_DEFAULT;
diff --git a/libhb/detelecine.c b/libhb/detelecine.c
index a27c48e09..161149422 100644
--- a/libhb/detelecine.c
+++ b/libhb/detelecine.c
@@ -846,19 +846,20 @@ static int hb_detelecine_init( hb_filter_object_t * filter,
ctx->bpp[0] = ctx->bpp[1] = ctx->bpp[2] = 8;
ctx->background[1] = ctx->background[2] = 128;
- ctx->w[0] = init->width;
- ctx->h[0] = hb_image_height( init->pix_fmt, init->height, 0 );
- ctx->stride[0] = hb_image_stride( init->pix_fmt, init->width, 0 );
+ ctx->w[0] = init->geometry.width;
+ ctx->h[0] = hb_image_height( init->pix_fmt, init->geometry.height, 0 );
+ ctx->stride[0] = hb_image_stride( init->pix_fmt, init->geometry.width, 0 );
- ctx->w[1] = init->width >> 1;
- ctx->h[1] = hb_image_height( init->pix_fmt, init->height, 1 );
- ctx->stride[1] = hb_image_stride( init->pix_fmt, init->width, 1 );
+ ctx->w[1] = init->geometry.width >> 1;
+ ctx->h[1] = hb_image_height( init->pix_fmt, init->geometry.height, 1 );
+ ctx->stride[1] = hb_image_stride( init->pix_fmt, init->geometry.width, 1 );
- ctx->w[1] = init->width >> 1;
- ctx->h[2] = hb_image_height( init->pix_fmt, init->height, 2 );
- ctx->stride[2] = hb_image_stride( init->pix_fmt, init->width, 2 );
+ ctx->w[1] = init->geometry.width >> 1;
+ ctx->h[2] = hb_image_height( init->pix_fmt, init->geometry.height, 2 );
+ ctx->stride[2] = hb_image_stride( init->pix_fmt, init->geometry.width, 2 );
- ctx->w[3] = ((init->width+15)/16) * ((init->height+15)/16);
+ ctx->w[3] = ((init->geometry.width + 15) / 16) *
+ ((init->geometry.height + 15) / 16);
ctx->h[3] = 2;
ctx->stride[3] = ctx->w[3];
diff --git a/libhb/dvd.c b/libhb/dvd.c
index 0e0fccf7a..29ae0c34a 100644
--- a/libhb/dvd.c
+++ b/libhb/dvd.c
@@ -491,7 +491,7 @@ static hb_title_t * hb_dvdread_title_scan( hb_dvd_t * e, int t, uint64_t min_dur
lang = lang_for_code( vts->vtsi_mat->vts_subp_attr[i].lang_code );
subtitle = calloc( sizeof( hb_subtitle_t ), 1 );
- subtitle->track = i+1;
+ subtitle->track = i;
subtitle->id = ( ( 0x20 + position ) << 8 ) | 0xbd;
snprintf( subtitle->lang, sizeof( subtitle->lang ), "%s",
strlen(lang->native_name) ? lang->native_name : lang->eng_name);
@@ -623,17 +623,20 @@ static hb_title_t * hb_dvdread_title_scan( hb_dvd_t * e, int t, uint64_t min_dur
switch( vts->vtsi_mat->vts_video_attr.display_aspect_ratio )
{
case 0:
- title->container_aspect = 4. / 3.;
+ title->container_dar.num = 4;
+ title->container_dar.den = 3;
break;
case 3:
- title->container_aspect = 16. / 9.;
+ title->container_dar.num = 16;
+ title->container_dar.den = 9;
break;
default:
hb_log( "scan: unknown aspect" );
goto fail;
}
- hb_log( "scan: aspect = %g", title->container_aspect );
+ hb_log("scan: aspect = %d:%d",
+ title->container_dar.num, title->container_dar.den);
/* This title is ok so far */
goto cleanup;
diff --git a/libhb/dvdnav.c b/libhb/dvdnav.c
index 2e7973c0d..f7153177c 100644
--- a/libhb/dvdnav.c
+++ b/libhb/dvdnav.c
@@ -664,7 +664,7 @@ static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * e, int t, uint64_t min_dura
lang = lang_for_code( ifo->vtsi_mat->vts_subp_attr[i].lang_code );
subtitle = calloc( sizeof( hb_subtitle_t ), 1 );
- subtitle->track = i+1;
+ subtitle->track = i;
subtitle->id = ( ( 0x20 + position ) << 8 ) | 0xbd;
snprintf( subtitle->lang, sizeof( subtitle->lang ), "%s",
strlen(lang->native_name) ? lang->native_name : lang->eng_name);
@@ -809,17 +809,20 @@ static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * e, int t, uint64_t min_dura
switch( ifo->vtsi_mat->vts_video_attr.display_aspect_ratio )
{
case 0:
- title->container_aspect = 4. / 3.;
+ title->container_dar.num = 4;
+ title->container_dar.den = 3;
break;
case 3:
- title->container_aspect = 16. / 9.;
+ title->container_dar.num = 16;
+ title->container_dar.den = 9;
break;
default:
hb_log( "scan: unknown aspect" );
goto fail;
}
- hb_log( "scan: aspect = %g", title->container_aspect );
+ hb_log("scan: aspect = %d:%d",
+ title->container_dar.num, title->container_dar.den);
/* This title is ok so far */
goto cleanup;
diff --git a/libhb/enc_qsv.c b/libhb/enc_qsv.c
index 04d3bf99b..ddf1cf664 100644
--- a/libhb/enc_qsv.c
+++ b/libhb/enc_qsv.c
@@ -267,11 +267,12 @@ int qsv_enc_init(hb_work_private_t *pv)
}
else
{
- pv->sws_context_to_nv12 = hb_sws_get_context(job->width, job->height,
- AV_PIX_FMT_YUV420P,
- job->width, job->height,
- AV_PIX_FMT_NV12,
- SWS_LANCZOS|SWS_ACCURATE_RND);
+ pv->sws_context_to_nv12 = hb_sws_get_context(
+ job->geometry.width, job->geometry.height,
+ AV_PIX_FMT_YUV420P,
+ job->geometry.width, job->geometry.height,
+ AV_PIX_FMT_NV12,
+ SWS_LANCZOS|SWS_ACCURATE_RND);
}
// allocate tasks
@@ -515,13 +516,13 @@ int encqsvInit(hb_work_object_t *w, hb_job_t *job)
// some encoding parameters are used by filters to configure their output
if (pv->param.videoParam->mfx.FrameInfo.PicStruct != MFX_PICSTRUCT_PROGRESSIVE)
{
- job->qsv.enc_info.align_height = AV_QSV_ALIGN32(job->height);
+ job->qsv.enc_info.align_height = AV_QSV_ALIGN32(job->geometry.height);
}
else
{
- job->qsv.enc_info.align_height = AV_QSV_ALIGN16(job->height);
+ job->qsv.enc_info.align_height = AV_QSV_ALIGN16(job->geometry.height);
}
- job->qsv.enc_info.align_width = AV_QSV_ALIGN16(job->width);
+ job->qsv.enc_info.align_width = AV_QSV_ALIGN16(job->geometry.width);
job->qsv.enc_info.pic_struct = pv->param.videoParam->mfx.FrameInfo.PicStruct;
job->qsv.enc_info.is_init_done = 1;
@@ -537,8 +538,8 @@ int encqsvInit(hb_work_object_t *w, hb_job_t *job)
pv->param.videoParam->mfx.FrameInfo.AspectRatioH = par_height;
pv->param.videoParam->mfx.FrameInfo.CropX = 0;
pv->param.videoParam->mfx.FrameInfo.CropY = 0;
- pv->param.videoParam->mfx.FrameInfo.CropW = job->width;
- pv->param.videoParam->mfx.FrameInfo.CropH = job->height;
+ pv->param.videoParam->mfx.FrameInfo.CropW = job->geometry.width;
+ pv->param.videoParam->mfx.FrameInfo.CropH = job->geometry.height;
pv->param.videoParam->mfx.FrameInfo.PicStruct = job->qsv.enc_info.pic_struct;
pv->param.videoParam->mfx.FrameInfo.Width = job->qsv.enc_info.align_width;
pv->param.videoParam->mfx.FrameInfo.Height = job->qsv.enc_info.align_height;
diff --git a/libhb/encavcodec.c b/libhb/encavcodec.c
index 271d6f3d0..45645c8d5 100644
--- a/libhb/encavcodec.c
+++ b/libhb/encavcodec.c
@@ -102,13 +102,13 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job )
if( job->pass == 2 )
{
hb_interjob_t * interjob = hb_interjob_get( job->h );
- fps.den = interjob->vrate_base;
- fps.num = interjob->vrate;
+ fps.den = interjob->vrate.den;
+ fps.num = interjob->vrate.num;
}
else
{
- fps.den = job->vrate_base;
- fps.num = job->vrate;
+ fps.den = job->vrate.den;
+ fps.num = job->vrate.num;
}
// If the fps.num is 27000000, there's a good chance this is
@@ -160,7 +160,7 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job )
context->time_base.den = fps.num;
context->time_base.num = fps.den;
- context->gop_size = 10 * (int)( (double)job->vrate / (double)job->vrate_base + 0.5 );
+ context->gop_size = 10 * ((double)job->vrate.num / job->vrate.den + 0.5);
/* place job->encoder_options in an hb_dict_t for convenience */
hb_dict_t * lavc_opts = NULL;
@@ -209,7 +209,7 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job )
//This value was chosen to make the bitrate high enough
//for libvpx to "turn off" the maximum bitrate feature
//that is normally applied to constant quality.
- context->bit_rate = job->width*job->height*( (double)fps.num / (double)fps.den );
+ context->bit_rate = job->width * job->height * fps.num / fps.den;
hb_log( "encavcodec: encoding at CQ %.2f", job->vquality );
}
else
@@ -222,14 +222,11 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job )
context->height = job->height;
context->pix_fmt = AV_PIX_FMT_YUV420P;
- if( job->anamorphic.mode )
- {
- context->sample_aspect_ratio.num = job->anamorphic.par_width;
- context->sample_aspect_ratio.den = job->anamorphic.par_height;
+ context->sample_aspect_ratio.num = job->par.num;
+ context->sample_aspect_ratio.den = job->par.den;
- hb_log( "encavcodec: encoding with stored aspect %d/%d",
- job->anamorphic.par_width, job->anamorphic.par_height );
- }
+ hb_log( "encavcodec: encoding with stored aspect %d/%d",
+ job->par.num, job->par.den );
if( job->mux & HB_MUX_MASK_MP4 )
{
@@ -560,7 +557,7 @@ int encavcodecWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
{
av_init_packet(&pkt);
/* Should be way too large */
- buf = hb_video_buffer_init( job->width, job->height );
+ buf = hb_video_buffer_init(job->width, job->height);
pkt.data = buf->data;
pkt.size = buf->alloc;
diff --git a/libhb/enctheora.c b/libhb/enctheora.c
index bc4d61d25..7737cb884 100644
--- a/libhb/enctheora.c
+++ b/libhb/enctheora.c
@@ -74,23 +74,16 @@ int enctheoraInit( hb_work_object_t * w, hb_job_t * job )
if( job->pass == 2 )
{
hb_interjob_t * interjob = hb_interjob_get( job->h );
- ti.fps_numerator = interjob->vrate;
- ti.fps_denominator = interjob->vrate_base;
+ ti.fps_numerator = interjob->vrate.num;
+ ti.fps_denominator = interjob->vrate.den;
}
else
{
- ti.fps_numerator = job->vrate;
- ti.fps_denominator = job->vrate_base;
- }
- if( job->anamorphic.mode )
- {
- ti.aspect_numerator = job->anamorphic.par_width;
- ti.aspect_denominator = job->anamorphic.par_height;
- }
- else
- {
- ti.aspect_numerator = ti.aspect_denominator = 1;
+ ti.fps_numerator = job->vrate.num;
+ ti.fps_denominator = job->vrate.den;
}
+ ti.aspect_numerator = job->par.num;
+ ti.aspect_denominator = job->par.den;
ti.colorspace = TH_CS_UNSPECIFIED;
ti.pixel_fmt = TH_PF_420;
if (job->vquality < 0.0)
@@ -104,7 +97,7 @@ int enctheoraInit( hb_work_object_t * w, hb_job_t * job )
ti.quality = job->vquality;
}
- keyframe_frequency = 10 * (int)( (double)job->vrate / (double)job->vrate_base + 0.5 );
+ keyframe_frequency = 10 * ((double)job->vrate.num / job->vrate.den + 0.5);
hb_log("theora: keyint: %i", keyframe_frequency);
diff --git a/libhb/encx264.c b/libhb/encx264.c
index 64c202d01..1dcac19a4 100644
--- a/libhb/encx264.c
+++ b/libhb/encx264.c
@@ -126,13 +126,13 @@ int encx264Init( hb_work_object_t * w, hb_job_t * job )
if( job->pass == 2 && job->cfr != 1 )
{
hb_interjob_t * interjob = hb_interjob_get( job->h );
- param.i_fps_num = interjob->vrate;
- param.i_fps_den = interjob->vrate_base;
+ param.i_fps_num = interjob->vrate.num;
+ param.i_fps_den = interjob->vrate.den;
}
else
{
- param.i_fps_num = job->vrate;
- param.i_fps_den = job->vrate_base;
+ param.i_fps_num = job->vrate.num;
+ param.i_fps_den = job->vrate.den;
}
if ( job->cfr == 1 )
{
@@ -149,7 +149,7 @@ int encx264Init( hb_work_object_t * w, hb_job_t * job )
/* Set min:max keyframe intervals to 1:10 of fps;
* adjust +0.5 for when fps has remainder to bump
* { 23.976, 29.976, 59.94 } to { 24, 30, 60 }. */
- param.i_keyint_min = (int)( (double)job->vrate / (double)job->vrate_base + 0.5 );
+ param.i_keyint_min = (double)job->vrate.num / job->vrate.den + 0.5;
param.i_keyint_max = 10 * param.i_keyint_min;
param.i_log_level = X264_LOG_INFO;
@@ -252,11 +252,8 @@ int encx264Init( hb_work_object_t * w, hb_job_t * job )
param.i_width = job->width;
param.i_height = job->height;
- if( job->anamorphic.mode )
- {
- param.vui.i_sar_width = job->anamorphic.par_width;
- param.vui.i_sar_height = job->anamorphic.par_height;
- }
+ param.vui.i_sar_width = job->par.num;
+ param.vui.i_sar_height = job->par.den;
if( job->vquality >= 0 )
{
@@ -336,7 +333,8 @@ int encx264Init( hb_work_object_t * w, hb_job_t * job )
job->encoder_options,
job->encoder_profile,
job->encoder_level,
- job->width, job->height);
+ job->width,
+ job->height);
if( x264_opts_unparsed != NULL )
{
hb_log( "encx264: unparsed options: %s", x264_opts_unparsed );
@@ -370,8 +368,8 @@ int encx264Init( hb_work_object_t * w, hb_job_t * job )
if( job->grayscale )
{
- int uvsize = (hb_image_stride(AV_PIX_FMT_YUV420P, job->width, 1) *
- hb_image_height(AV_PIX_FMT_YUV420P, job->height, 1));
+ int uvsize = hb_image_stride(AV_PIX_FMT_YUV420P, job->width, 1) *
+ hb_image_height(AV_PIX_FMT_YUV420P, job->height, 1);
pv->grey_data = malloc(uvsize);
memset(pv->grey_data, 0x80, uvsize);
pv->pic_in.img.plane[1] = pv->pic_in.img.plane[2] = pv->grey_data;
diff --git a/libhb/encx265.c b/libhb/encx265.c
index 60c1b38aa..588dc4343 100644
--- a/libhb/encx265.c
+++ b/libhb/encx265.c
@@ -94,7 +94,8 @@ int encx265Init(hb_work_object_t *w, hb_job_t *job)
pv->delayed_chapters = hb_list_init();
pv->job = job;
w->private_data = pv;
- int ret, vrate, vrate_base;
+ int ret;
+ hb_rational_t vrate;
x265_nal *nal;
uint32_t nnal;
@@ -133,10 +134,10 @@ int encx265Init(hb_work_object_t *w, hb_job_t *job)
* Some HandBrake-specific defaults; users can override them
* using the encoder_options string.
*/
- hb_reduce(&vrate, &vrate_base, job->vrate, job->vrate_base);
- param->fpsNum = vrate;
- param->fpsDenom = vrate_base;
- param->keyframeMin = (int)((double)vrate / (double)vrate_base + 0.5);
+ hb_reduce(&vrate.num, &vrate.den, job->vrate.num, job->vrate.den);
+ param->fpsNum = vrate.num;
+ param->fpsDenom = vrate.den;
+ param->keyframeMin = (double)vrate.num / vrate.den + 0.5;
param->keyframeMax = param->keyframeMin * 10;
/*
@@ -211,19 +212,16 @@ int encx265Init(hb_work_object_t *w, hb_job_t *job)
param->bRepeatHeaders = 0;
param->sourceWidth = job->width;
param->sourceHeight = job->height;
- if (job->anamorphic.mode)
+
+ /*
+ * Let x265 determnine whether to use an aspect ratio
+ * index vs. the extended SAR index + SAR width/height.
+ */
+ char sar[22];
+ snprintf(sar, sizeof(sar), "%d:%d", job->par.num, job->par.den);
+ if (param_parse(param, "sar", sar))
{
- /*
- * Let x265 determnine whether to use an aspect ratio
- * index vs. the extended SAR index + SAR width/height.
- */
- char sar[22];
- snprintf(sar, sizeof(sar), "%d:%d",
- job->anamorphic.par_width, job->anamorphic.par_height);
- if (param_parse(param, "sar", sar))
- {
- goto fail;
- }
+ goto fail;
}
if (job->vquality > 0)
diff --git a/libhb/hb.c b/libhb/hb.c
index 1ba78d774..2ae9e7e4c 100644
--- a/libhb/hb.c
+++ b/libhb/hb.c
@@ -687,7 +687,8 @@ hb_buffer_t * hb_read_preview(hb_handle_t * h, hb_title_t *title, int preview)
}
hb_buffer_t * buf;
- buf = hb_frame_buffer_init(AV_PIX_FMT_YUV420P, title->width, title->height);
+ buf = hb_frame_buffer_init(AV_PIX_FMT_YUV420P,
+ title->geometry.width, title->geometry.height);
int pp, hh;
for (pp = 0; pp < 3; pp++)
@@ -709,7 +710,7 @@ hb_buffer_t * hb_read_preview(hb_handle_t * h, hb_title_t *title, int preview)
}
hb_image_t* hb_get_preview2(hb_handle_t * h, int title_idx, int picture,
- hb_ui_geometry_t *ui_geo, int deinterlace)
+ hb_geometry_settings_t *geo, int deinterlace)
{
char filename[1024];
hb_buffer_t * in_buf, * deint_buf = NULL, * preview_buf;
@@ -717,8 +718,9 @@ hb_image_t* hb_get_preview2(hb_handle_t * h, int title_idx, int picture,
AVPicture pic_in, pic_preview, pic_deint, pic_crop;
struct SwsContext * context;
- int width = ui_geo->width * ui_geo->par.num / ui_geo->par.den;
- int height = ui_geo->height;
+ int width = geo->geometry.width *
+ geo->geometry.par.num / geo->geometry.par.den;
+ int height = geo->geometry.height;
swsflags = SWS_LANCZOS | SWS_ACCURATE_RND;
@@ -749,31 +751,30 @@ hb_image_t* hb_get_preview2(hb_handle_t * h, int title_idx, int picture,
{
// Deinterlace and crop
deint_buf = hb_frame_buffer_init( AV_PIX_FMT_YUV420P,
- title->width, title->height );
+ title->geometry.width, title->geometry.height );
hb_deinterlace(deint_buf, in_buf);
hb_avpicture_fill( &pic_deint, deint_buf );
av_picture_crop(&pic_crop, &pic_deint, AV_PIX_FMT_YUV420P,
- ui_geo->crop[0], ui_geo->crop[2] );
+ geo->crop[0], geo->crop[2] );
}
else
{
// Crop
av_picture_crop(&pic_crop, &pic_in, AV_PIX_FMT_YUV420P,
- ui_geo->crop[0], ui_geo->crop[2] );
+ geo->crop[0], geo->crop[2] );
}
// Get scaling context
context = hb_sws_get_context(
- title->width - (ui_geo->crop[2] + ui_geo->crop[3]),
- title->height - (ui_geo->crop[0] + ui_geo->crop[1]),
- AV_PIX_FMT_YUV420P, width, height, AV_PIX_FMT_RGB32,
- swsflags);
+ title->geometry.width - (geo->crop[2] + geo->crop[3]),
+ title->geometry.height - (geo->crop[0] + geo->crop[1]),
+ AV_PIX_FMT_YUV420P, width, height, AV_PIX_FMT_RGB32, swsflags);
// Scale
sws_scale(context,
(const uint8_t* const *)pic_crop.data, pic_crop.linesize,
- 0, title->height - (ui_geo->crop[0] + ui_geo->crop[1]),
+ 0, title->geometry.height - (geo->crop[0] + geo->crop[1]),
pic_preview.data, pic_preview.linesize);
// Free context
@@ -789,91 +790,6 @@ hb_image_t* hb_get_preview2(hb_handle_t * h, int title_idx, int picture,
return image;
}
-/**
- * Create preview image of desired title a index of picture.
- * @param h Handle to hb_handle_t.
- * @param title Handle to hb_title_t of desired title.
- * @param picture Index in title.
- * @param buffer Handle to buffer were image will be drawn.
- */
-void hb_get_preview( hb_handle_t * h, hb_job_t * job, int picture,
- uint8_t * buffer )
-{
- hb_title_t * title = job->title;
- char filename[1024];
- hb_buffer_t * in_buf, * deint_buf = NULL, * preview_buf;
- uint8_t * pen;
- uint32_t swsflags;
- AVPicture pic_in, pic_preview, pic_deint, pic_crop;
- struct SwsContext * context;
- int i;
- int preview_size;
-
- swsflags = SWS_LANCZOS | SWS_ACCURATE_RND;
-
- preview_buf = hb_frame_buffer_init( AV_PIX_FMT_RGB32,
- job->width, job->height );
- hb_avpicture_fill( &pic_preview, preview_buf );
-
- // Allocate the AVPicture frames and fill in
-
- memset( filename, 0, 1024 );
-
- in_buf = hb_read_preview( h, title, picture );
- if ( in_buf == NULL )
- {
- return;
- }
-
- hb_avpicture_fill( &pic_in, in_buf );
-
- if( job->deinterlace )
- {
- // Deinterlace and crop
- deint_buf = hb_frame_buffer_init( AV_PIX_FMT_YUV420P,
- title->width, title->height );
- hb_deinterlace(deint_buf, in_buf);
- hb_avpicture_fill( &pic_deint, deint_buf );
-
- av_picture_crop( &pic_crop, &pic_deint, AV_PIX_FMT_YUV420P,
- job->crop[0], job->crop[2] );
- }
- else
- {
- // Crop
- av_picture_crop( &pic_crop, &pic_in, AV_PIX_FMT_YUV420P, job->crop[0], job->crop[2] );
- }
-
- // Get scaling context
- context = hb_sws_get_context(title->width - (job->crop[2] + job->crop[3]),
- title->height - (job->crop[0] + job->crop[1]),
- AV_PIX_FMT_YUV420P,
- job->width, job->height, AV_PIX_FMT_RGB32,
- swsflags);
-
- // Scale
- sws_scale(context,
- (const uint8_t* const *)pic_crop.data, pic_crop.linesize,
- 0, title->height - (job->crop[0] + job->crop[1]),
- pic_preview.data, pic_preview.linesize);
-
- // Free context
- sws_freeContext( context );
-
- preview_size = pic_preview.linesize[0];
- pen = buffer;
- for( i = 0; i < job->height; i++ )
- {
- memcpy( pen, pic_preview.data[0] + preview_size * i, 4 * job->width );
- pen += 4 * job->width;
- }
-
- // Clean up
- hb_buffer_close( &in_buf );
- hb_buffer_close( &deint_buf );
- hb_buffer_close( &preview_buf );
-}
-
/**
* Analyzes a frame to detect interlacing artifacts
* and returns true if interlacing (combing) is found.
@@ -977,24 +893,25 @@ int hb_detect_comb( hb_buffer_t * buf, int color_equal, int color_diff, int thre
*
* Returns calculated geometry
* @param source_geometry - Pointer to source geometry info
- * @param ui_geometry - Pointer to requested destination parameters
+ * @param geometry - Pointer to requested destination parameters
*/
void hb_set_anamorphic_size2(hb_geometry_t *src_geo,
- hb_ui_geometry_t *ui_geo,
+ hb_geometry_settings_t *geo,
hb_geometry_t *result)
{
hb_rational_t in_par, out_par;
- int keep_display_aspect = !!(ui_geo->keep & HB_KEEP_DISPLAY_ASPECT);
- int keep_height = !!(ui_geo->keep & HB_KEEP_HEIGHT);
+ int keep_display_aspect = !!(geo->keep & HB_KEEP_DISPLAY_ASPECT);
+ int keep_height = !!(geo->keep & HB_KEEP_HEIGHT);
/* Set up some variables to make the math easier to follow. */
- int cropped_width = src_geo->width - ui_geo->crop[2] - ui_geo->crop[3];
- int cropped_height = src_geo->height - ui_geo->crop[0] - ui_geo->crop[1];
+ int cropped_width = src_geo->width - geo->crop[2] - geo->crop[3];
+ int cropped_height = src_geo->height - geo->crop[0] - geo->crop[1];
double storage_aspect = (double)cropped_width / cropped_height;
- int mod = ui_geo->modulus ? EVEN(ui_geo->modulus) : 2;
+ int mod = geo->modulus ? EVEN(geo->modulus) : 2;
// Use 64 bits to avoid overflow till the final hb_reduce() call
- hb_reduce(&in_par.num, &in_par.den, ui_geo->par.num, ui_geo->par.den);
+ hb_reduce(&in_par.num, &in_par.den,
+ geo->geometry.par.num, geo->geometry.par.den);
int64_t dst_par_num = in_par.num;
int64_t dst_par_den = in_par.den;
@@ -1002,7 +919,7 @@ void hb_set_anamorphic_size2(hb_geometry_t *src_geo,
/* If a source was really NTSC or PAL and the user specified ITU PAR
values, replace the standard PAR values with the ITU broadcast ones. */
- if (src_geo->width == 720 && ui_geo->itu_par)
+ if (src_geo->width == 720 && geo->itu_par)
{
// convert aspect to a scaled integer so we can test for 16:9 & 4:3
// aspect ratios ignoring insignificant differences in the LSBs of
@@ -1054,14 +971,14 @@ void hb_set_anamorphic_size2(hb_geometry_t *src_geo,
int width, height;
int maxWidth, maxHeight;
- maxWidth = MULTIPLE_MOD_DOWN(ui_geo->maxWidth, mod);
- maxHeight = MULTIPLE_MOD_DOWN(ui_geo->maxHeight, mod);
+ maxWidth = MULTIPLE_MOD_DOWN(geo->maxWidth, mod);
+ maxHeight = MULTIPLE_MOD_DOWN(geo->maxHeight, mod);
if (maxWidth && maxWidth < 32)
maxWidth = 32;
if (maxHeight && maxHeight < 32)
maxHeight = 32;
- switch (ui_geo->mode)
+ switch (geo->mode)
{
case HB_ANAMORPHIC_NONE:
{
@@ -1078,19 +995,19 @@ void hb_set_anamorphic_size2(hb_geometry_t *src_geo,
{
if (!keep_height)
{
- width = MULTIPLE_MOD_UP(ui_geo->width, mod);
+ width = MULTIPLE_MOD_UP(geo->geometry.width, mod);
height = MULTIPLE_MOD(width / dar, mod);
}
else
{
- height = MULTIPLE_MOD_UP(ui_geo->height, mod);
+ height = MULTIPLE_MOD_UP(geo->geometry.height, mod);
width = MULTIPLE_MOD(height * dar, mod);
}
}
else
{
- width = MULTIPLE_MOD_UP(ui_geo->width, mod);
- height = MULTIPLE_MOD_UP(ui_geo->height, mod);
+ width = MULTIPLE_MOD_UP(geo->geometry.width, mod);
+ height = MULTIPLE_MOD_UP(geo->geometry.height, mod);
}
if (maxWidth && (width > maxWidth))
{
@@ -1140,12 +1057,12 @@ void hb_set_anamorphic_size2(hb_geometry_t *src_geo,
*/
if (!keep_height)
{
- width = MULTIPLE_MOD_UP(ui_geo->width, mod);
+ width = MULTIPLE_MOD_UP(geo->geometry.width, mod);
height = MULTIPLE_MOD_UP(width / storage_aspect + 0.5, mod);
}
else
{
- height = MULTIPLE_MOD_UP(ui_geo->height, mod);
+ height = MULTIPLE_MOD_UP(geo->geometry.height, mod);
width = MULTIPLE_MOD_UP(height * storage_aspect + 0.5, mod);
}
@@ -1173,11 +1090,11 @@ void hb_set_anamorphic_size2(hb_geometry_t *src_geo,
- Set everything based on specified values */
/* Use specified storage dimensions */
- storage_aspect = (double)ui_geo->width / ui_geo->height;
+ storage_aspect = (double)geo->geometry.width / geo->geometry.height;
/* Time to get picture dimensions that divide cleanly.*/
- width = MULTIPLE_MOD_UP(ui_geo->width, mod);
- height = MULTIPLE_MOD_UP(ui_geo->height, mod);
+ width = MULTIPLE_MOD_UP(geo->geometry.width, mod);
+ height = MULTIPLE_MOD_UP(geo->geometry.height, mod);
/* Bind to max dimensions */
if (maxWidth && width > maxWidth)
@@ -1207,41 +1124,29 @@ void hb_set_anamorphic_size2(hb_geometry_t *src_geo,
width = MULTIPLE_MOD(width, mod);
}
}
-
- /* That finishes the storage dimensions. On to display. */
- if (ui_geo->dar.num && ui_geo->dar.den)
+ if (keep_display_aspect)
{
- /* We need to adjust the PAR to produce this aspect. */
- dst_par_num = (int64_t)height * ui_geo->dar.num /
- ui_geo->dar.den;
- dst_par_den = width;
+ /* We can ignore the possibility of a PAR change
+ * Adjust the output PAR for new width/height
+ * See comment in HB_ANAMORPHIC_STRICT
+ */
+ dst_par_num = (int64_t)height * cropped_width *
+ src_par.num;
+ dst_par_den = (int64_t)width * cropped_height *
+ src_par.den;
}
else
{
- if (keep_display_aspect)
- {
- /* We can ignore the possibility of a PAR change
- * Adjust the output PAR for new width/height
- * See comment in HB_ANAMORPHIC_STRICT
- */
- dst_par_num = (int64_t)height * cropped_width *
- src_par.num;
- dst_par_den = (int64_t)width * cropped_height *
- src_par.den;
- }
- else
- {
- /* If the dimensions were changed by the modulus
- * or by maxWidth/maxHeight, we also change the
- * output PAR so that the DAR is unchanged.
- *
- * PAR is the requested output display width / storage width
- * requested output display width is the original
- * requested width * original requested PAR
- */
- dst_par_num = ui_geo->width * dst_par_num;
- dst_par_den = width * dst_par_den;
- }
+ /* If the dimensions were changed by the modulus
+ * or by maxWidth/maxHeight, we also change the
+ * output PAR so that the DAR is unchanged.
+ *
+ * PAR is the requested output display width / storage width
+ * requested output display width is the original
+ * requested width * original requested PAR
+ */
+ dst_par_num = geo->geometry.width * dst_par_num;
+ dst_par_den = width * dst_par_den;
}
} break;
}
@@ -1257,11 +1162,11 @@ void hb_set_anamorphic_size2(hb_geometry_t *src_geo,
/* If the user is directling updating PAR, don't override his values */
hb_reduce(&out_par.num, &out_par.den, dst_par_num, dst_par_den);
- if (ui_geo->mode == HB_ANAMORPHIC_CUSTOM && !keep_display_aspect &&
+ if (geo->mode == HB_ANAMORPHIC_CUSTOM && !keep_display_aspect &&
out_par.num == in_par.num && out_par.den == in_par.den)
{
- result->par.num = ui_geo->par.num;
- result->par.den = ui_geo->par.den;
+ result->par.num = geo->geometry.par.num;
+ result->par.den = geo->geometry.par.den;
}
else
{
@@ -1270,52 +1175,6 @@ void hb_set_anamorphic_size2(hb_geometry_t *src_geo,
}
/**
- * Calculates job width and height for anamorphic content,
- *
- * @param job Handle to hb_job_t
- * @param output_width Pointer to returned storage width
- * @param output_height Pointer to returned storage height
- * @param output_par_width Pointer to returned pixel width
- * @param output_par_height Pointer to returned pixel height
- */
-void hb_set_anamorphic_size( hb_job_t * job,
- int *output_width, int *output_height,
- int *output_par_width, int *output_par_height )
-{
- hb_geometry_t result;
- hb_geometry_t src;
- hb_ui_geometry_t ui_geo;
-
- src.width = job->title->width;
- src.height = job->title->height;
- src.par.num = job->title->pixel_aspect_width;
- src.par.den = job->title->pixel_aspect_height;
-
- ui_geo.width = job->width;
- ui_geo.height = job->height;
- ui_geo.par.num = job->anamorphic.par_width;
- ui_geo.par.den = job->anamorphic.par_height;
-
- ui_geo.modulus = job->modulus;
- memcpy(ui_geo.crop, job->crop, sizeof(int[4]));
- ui_geo.maxWidth = job->maxWidth;
- ui_geo.maxHeight = job->maxHeight;
- ui_geo.mode = job->anamorphic.mode;
- ui_geo.keep = 0;
- if (job->anamorphic.keep_display_aspect)
- ui_geo.keep = HB_KEEP_DISPLAY_ASPECT;
- ui_geo.itu_par = job->anamorphic.itu_par;
- ui_geo.dar.num = job->anamorphic.dar_width;
- ui_geo.dar.den = job->anamorphic.dar_height;
-
- hb_set_anamorphic_size2(&src, &ui_geo, &result);
- *output_width = result.width;
- *output_height = result.height;
- *output_par_width = result.par.num;
- *output_par_height = result.par.den;
-}
-
-/**
* Add a filter to a jobs filter list
*
* @param job Handle to hb_job_t
@@ -1355,21 +1214,6 @@ void hb_add_filter( hb_job_t * job, hb_filter_object_t * filter, const char * se
}
/**
- * Validate and adjust dimensions if necessary
- *
- * @param job Handle to hb_job_t
- */
-void hb_validate_size( hb_job_t * job )
-{
- int width, height, par_width, par_height;
- hb_set_anamorphic_size(job, &width, &height, &par_width, &par_height);
- job->width = width;
- job->height = height;
- job->anamorphic.par_width = par_width;
- job->anamorphic.par_height = par_height;
-}
-
-/**
* Returns the number of jobs in the queue.
* @param h Handle to hb_handle_t.
* @return Number of jobs.
diff --git a/libhb/hb.h b/libhb/hb.h
index 2d32e1aef..dfbcc25a0 100644
--- a/libhb/hb.h
+++ b/libhb/hb.h
@@ -17,6 +17,7 @@ extern "C" {
#include "project.h"
#include "common.h"
#include "hb_dict.h"
+#include "hb_json.h"
/* hb_init()
Initializes a libhb session (launches his own thread, detects CPUs,
@@ -70,17 +71,11 @@ int hb_save_preview( hb_handle_t * h, int title, int preview,
hb_buffer_t *buf );
hb_buffer_t * hb_read_preview( hb_handle_t * h, hb_title_t *title,
int preview );
-void hb_get_preview( hb_handle_t *, hb_job_t *, int,
- uint8_t * );
hb_image_t * hb_get_preview2(hb_handle_t * h, int title_idx, int picture,
- hb_ui_geometry_t *ui_geo, int deinterlace);
+ hb_geometry_settings_t *geo, int deinterlace);
void hb_set_anamorphic_size2(hb_geometry_t *src_geo,
- hb_ui_geometry_t *ui_geo,
+ hb_geometry_settings_t *geo,
hb_geometry_t *result);
-void hb_set_anamorphic_size( hb_job_t *,
- int *output_width, int *output_height,
- int *output_par_width, int *output_par_height );
-void hb_validate_size( hb_job_t * job );
void hb_add_filter( hb_job_t * job, hb_filter_object_t * filter,
const char * settings );
@@ -111,8 +106,7 @@ typedef struct hb_interjob_s
int frame_count; /* number of frames counted by sync */
int out_frame_count; /* number of frames counted by render */
uint64_t total_time; /* real length in 90kHz ticks (i.e. seconds / 90000) */
- int vrate; /* actual measured output vrate from 1st pass */
- int vrate_base; /* actual measured output vrate_base from 1st pass */
+ hb_rational_t vrate; /* actual measured output vrate from 1st pass */
hb_subtitle_t *select_subtitle; /* foreign language scan subtitle */
} hb_interjob_t;
diff --git a/libhb/hb_json.c b/libhb/hb_json.c
new file mode 100644
index 000000000..769ca3eef
--- /dev/null
+++ b/libhb/hb_json.c
@@ -0,0 +1,1186 @@
+/* json.c
+
+ Copyright (c) 2003-2014 HandBrake Team
+ This file is part of the HandBrake source code
+ Homepage: <http://handbrake.fr/>.
+ It may be used under the terms of the GNU General Public License v2.
+ For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html
+ */
+
+#include <jansson.h>
+#include "hb_json.h"
+
+/**
+ * Convert an hb_state_t to a jansson dict
+ * @param state - Pointer to hb_state_t to convert
+ */
+static json_t* hb_state_to_dict( hb_state_t * state)
+{
+ json_t *dict = NULL;
+ json_error_t error;
+
+ switch (state->state)
+ {
+ case HB_STATE_IDLE:
+ dict = json_pack_ex(&error, 0, "{s:o}",
+ "State", json_integer(state->state));
+ break;
+ case HB_STATE_SCANNING:
+ case HB_STATE_SCANDONE:
+ dict = json_pack_ex(&error, 0,
+ "{s:o, s{s:o, s:o, s:o, s:o, s:o}}",
+ "State", json_integer(state->state),
+ "Scanning",
+ "Progress", json_real(state->param.scanning.progress),
+ "Preview", json_integer(state->param.scanning.preview_cur),
+ "PreviewCount", json_integer(state->param.scanning.preview_count),
+ "Title", json_integer(state->param.scanning.title_cur),
+ "TitleCount", json_integer(state->param.scanning.title_count));
+ break;
+ case HB_STATE_WORKING:
+ case HB_STATE_PAUSED:
+ case HB_STATE_SEARCHING:
+ dict = json_pack_ex(&error, 0,
+ "{s:o, s{s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o}}",
+ "State", json_integer(state->state),
+ "Working",
+ "Progress", json_real(state->param.working.progress),
+ "Job", json_integer(state->param.working.job_cur),
+ "JobCount", json_integer(state->param.working.job_count),
+ "Rate", json_real(state->param.working.rate_cur),
+ "RateAvg", json_real(state->param.working.rate_avg),
+ "Hours", json_integer(state->param.working.hours),
+ "Minutes", json_integer(state->param.working.minutes),
+ "Seconds", json_integer(state->param.working.seconds),
+ "SequenceID", json_integer(state->param.working.sequence_id));
+ break;
+ case HB_STATE_WORKDONE:
+ dict = json_pack_ex(&error, 0,
+ "{s:o, s{s:o}}",
+ "State", json_integer(state->state),
+ "WorkDone",
+ "Error", json_integer(state->param.workdone.error));
+ break;
+ case HB_STATE_MUXING:
+ dict = json_pack_ex(&error, 0,
+ "{s:o, s{s:o}}",
+ "State", json_integer(state->state),
+ "Muxing",
+ "Progress", json_real(state->param.muxing.progress));
+ break;
+ default:
+ hb_error("hb_state_to_json: unrecognized state %d", state->state);
+ break;
+ }
+ if (dict == NULL)
+ {
+ hb_error("json pack failure: %s", error.text);
+ }
+ return dict;
+}
+
+/**
+ * Get the current state of an hb instance as a json string
+ * @param h - Pointer to an hb_handle_t hb instance
+ */
+char* hb_get_state_json( hb_handle_t * h )
+{
+ hb_state_t state;
+
+ hb_get_state(h, &state);
+ json_t *dict = hb_state_to_dict(&state);
+
+ char *json_state = json_dumps(dict, JSON_INDENT(4)|JSON_PRESERVE_ORDER);
+ json_decref(dict);
+
+ return json_state;
+}
+
+/**
+ * Convert an hb_title_t to a jansson dict
+ * @param title - Pointer to the hb_title_t to convert
+ */
+static json_t* hb_title_to_dict( const hb_title_t * title )
+{
+ json_t *dict;
+ json_error_t error;
+ int ii;
+
+ dict = json_pack_ex(&error, 0,
+ "{"
+ // Type, Path, Name, Index, Playlist, AngleCount
+ "s:o, s:o, s:o, s:o, s:o, s:o,"
+ // Duration {Ticks, Hours, Minutes, Seconds}
+ "s:{s:o, s:o, s:o, s:o},"
+ // Geometry {Width, Height, PAR {Num, Den},
+ "s:{s:o, s:o, s:{s:o, s:o}},"
+ // Crop[Top, Bottom, Left, Right]}
+ "s:[oooo],"
+ // Color {Primary, Transfer, Matrix}
+ "s:{s:o, s:o, s:o},"
+ // FrameRate {Num, Den}
+ "s:{s:o, s:o},"
+ // InterlaceDetected, VideoCodec
+ "s:o, s:o,"
+ // MetaData
+ "s:{}"
+ "}",
+ "Type", json_integer(title->type),
+ "Path", json_string(title->path),
+ "Name", json_string(title->name),
+ "Index", json_integer(title->index),
+ "Playlist", json_integer(title->playlist),
+ "AngleCount", json_integer(title->angle_count),
+ "Duration",
+ "Ticks", json_integer(title->duration),
+ "Hours", json_integer(title->hours),
+ "Minutes", json_integer(title->minutes),
+ "Seconds", json_integer(title->seconds),
+ "Geometry",
+ "Width", json_integer(title->geometry.width),
+ "Height", json_integer(title->geometry.height),
+ "PAR",
+ "Num", json_integer(title->geometry.par.num),
+ "Den", json_integer(title->geometry.par.den),
+ "Crop", json_integer(title->crop[0]),
+ json_integer(title->crop[1]),
+ json_integer(title->crop[2]),
+ json_integer(title->crop[3]),
+ "Color",
+ "Primary", json_integer(title->color_prim),
+ "Transfer", json_integer(title->color_transfer),
+ "Matrix", json_integer(title->color_matrix),
+ "FrameRate",
+ "Num", json_integer(title->vrate.num),
+ "Den", json_integer(title->vrate.den),
+ "InterlaceDetected", json_boolean(title->detected_interlacing),
+ "VideoCodec", json_string(title->video_codec_name),
+ "MetaData"
+ );
+ if (dict == NULL)
+ {
+ hb_error("json pack failure: %s", error.text);
+ return NULL;
+ }
+
+ if (title->container_name != NULL)
+ {
+ json_object_set_new(dict, "Container",
+ json_string(title->container_name));
+ }
+
+ // Add metadata
+ json_t *meta_dict = json_object_get(dict, "MetaData");
+ if (title->metadata->name != NULL)
+ {
+ json_object_set_new(meta_dict, "Name",
+ json_string(title->metadata->name));
+ }
+ if (title->metadata->artist != NULL)
+ {
+ json_object_set_new(meta_dict, "Artist",
+ json_string(title->metadata->artist));
+ }
+ if (title->metadata->composer != NULL)
+ {
+ json_object_set_new(meta_dict, "Composer",
+ json_string(title->metadata->composer));
+ }
+ if (title->metadata->comment != NULL)
+ {
+ json_object_set_new(meta_dict, "Comment",
+ json_string(title->metadata->comment));
+ }
+ if (title->metadata->genre != NULL)
+ {
+ json_object_set_new(meta_dict, "Genre",
+ json_string(title->metadata->genre));
+ }
+ if (title->metadata->album != NULL)
+ {
+ json_object_set_new(meta_dict, "Album",
+ json_string(title->metadata->album));
+ }
+ if (title->metadata->album_artist != NULL)
+ {
+ json_object_set_new(meta_dict, "AlbumArtist",
+ json_string(title->metadata->album_artist));
+ }
+ if (title->metadata->description != NULL)
+ {
+ json_object_set_new(meta_dict, "Description",
+ json_string(title->metadata->description));
+ }
+ if (title->metadata->long_description != NULL)
+ {
+ json_object_set_new(meta_dict, "LongDescription",
+ json_string(title->metadata->long_description));
+ }
+
+ // process chapter list
+ json_t * chapter_list = json_array();
+ for (ii = 0; ii < hb_list_count(title->list_chapter); ii++)
+ {
+ json_t *chapter_dict;
+ char *name = "";
+ hb_chapter_t *chapter = hb_list_item(title->list_chapter, ii);
+ if (chapter->title != NULL)
+ name = chapter->title;
+
+ chapter_dict = json_pack_ex(&error, 0,
+ "{s:o, s:{s:o, s:o, s:o, s:o}}",
+ "Name", json_string(name),
+ "Duration",
+ "Ticks", json_integer(chapter->duration),
+ "Hours", json_integer(chapter->hours),
+ "Minutes", json_integer(chapter->minutes),
+ "Seconds", json_integer(chapter->seconds)
+ );
+ if (chapter_dict == NULL)
+ {
+ hb_error("json pack failure: %s", error.text);
+ return NULL;
+ }
+ json_array_append_new(chapter_list, chapter_dict);
+ }
+ json_object_set_new(dict, "ChapterList", chapter_list);
+
+ // process audio list
+ json_t * audio_list = json_array();
+ for (ii = 0; ii < hb_list_count(title->list_audio); ii++)
+ {
+ json_t *audio_dict;
+ hb_audio_t *audio = hb_list_item(title->list_audio, ii);
+
+ audio_dict = json_pack_ex(&error, 0,
+ "{s:o, s:o, s:o, s:o, s:o, s:o}",
+ "Description", json_string(audio->config.lang.description),
+ "Language", json_string(audio->config.lang.simple),
+ "LanguageCode", json_string(audio->config.lang.iso639_2),
+ "SampleRate", json_integer(audio->config.in.samplerate),
+ "BitRate", json_integer(audio->config.in.bitrate),
+ "ChannelLayout", json_integer(audio->config.in.channel_layout));
+ if (audio_dict == NULL)
+ {
+ hb_error("json pack failure: %s", error.text);
+ return NULL;
+ }
+ json_array_append_new(audio_list, audio_dict);
+ }
+ json_object_set_new(dict, "AudioList", audio_list);
+
+ // process subtitle list
+ json_t * subtitle_list = json_array();
+ for (ii = 0; ii < hb_list_count(title->list_subtitle); ii++)
+ {
+ json_t *subtitle_dict;
+ hb_subtitle_t *subtitle = hb_list_item(title->list_subtitle, ii);
+
+ subtitle_dict = json_pack_ex(&error, 0,
+ "{s:o, s:o, s:o, s:o}",
+ "Format", json_integer(subtitle->format),
+ "Source", json_integer(subtitle->source),
+ "Language", json_string(subtitle->lang),
+ "LanguageCode", json_string(subtitle->iso639_2));
+ if (subtitle_dict == NULL)
+ {
+ hb_error("json pack failure: %s", error.text);
+ return NULL;
+ }
+ json_array_append_new(subtitle_list, subtitle_dict);
+ }
+ json_object_set_new(dict, "SubtitleList", subtitle_list);
+
+ return dict;
+}
+
+/**
+ * Convert an hb_title_set_t to a jansson dict
+ * @param title - Pointer to the hb_title_set_t to convert
+ */
+static json_t* hb_title_set_to_dict( const hb_title_set_t * title_set )
+{
+ json_t *dict;
+ json_error_t error;
+ int ii;
+
+ dict = json_pack_ex(&error, 0,
+ "{s:o, s:[]}",
+ "MainFeature", json_integer(title_set->feature),
+ "TitleList");
+ // process title list
+ json_t *title_list = json_object_get(dict, "TitleList");
+ for (ii = 0; ii < hb_list_count(title_set->list_title); ii++)
+ {
+ hb_title_t *title = hb_list_item(title_set->list_title, ii);
+ json_t *title_dict = hb_title_to_dict(title);
+ json_array_append_new(title_list, title_dict);
+ }
+
+ return dict;
+}
+
+/**
+ * Convert an hb_title_t to a json string
+ * @param title - Pointer to hb_title_t to convert
+ */
+char* hb_title_to_json( const hb_title_t * title )
+{
+ json_t *dict = hb_title_to_dict(title);
+
+ char *json_title = json_dumps(dict, JSON_INDENT(4)|JSON_PRESERVE_ORDER);
+ json_decref(dict);
+
+ return json_title;
+}
+
+/**
+ * Get the current title set of an hb instance as a json string
+ * @param h - Pointer to hb_handle_t hb instance
+ */
+char* hb_get_title_set_json( hb_handle_t * h )
+{
+ json_t *dict = hb_title_set_to_dict(hb_get_title_set(h));
+
+ char *json_title_set = json_dumps(dict, JSON_INDENT(4)|JSON_PRESERVE_ORDER);
+ json_decref(dict);
+
+ return json_title_set;
+}
+
+/**
+ * Convert an hb_job_t to a json string
+ * @param job - Pointer to the hb_job_t to convert
+ */
+char* hb_job_to_json( const hb_job_t * job )
+{
+ json_t * dict;
+ json_error_t error;
+ int subtitle_search_burn;
+ int ii;
+
+ if (job == NULL || job->title == NULL)
+ return NULL;
+
+ // Assumes that the UI has reduced geometry settings to only the
+ // necessary PAR value
+
+ subtitle_search_burn = job->select_subtitle_config.dest == RENDERSUB;
+
+ dict = json_pack_ex(&error, 0,
+ "{"
+ // SequenceID
+ "s:o,"
+ // Destination {Mux, ChapterMarkers, ChapterList}
+ "s:{s:o, s:o, s[]},"
+ // Source {Title, Angle}
+ "s:{s:o, s:o,},"
+ // PAR {Num, Den}
+ "s:{s:o, s:o},"
+ // Video {Codec}
+ "s:{s:o},"
+ // Audio {CopyMask, FallbackEncoder, AudioList []}
+ "s:{s:o, s:o, s:[]},"
+ // Subtitles {Search {Enable, Forced, Default, Burn}, SubtitleList []}
+ "s:{s:{s:o, s:o, s:o, s:o}, s:[]},"
+ // MetaData
+ "s:{},"
+ // Filters {Grayscale, FilterList []}
+ "s:{s:o, s:[]}"
+ "}",
+ "SequenceID", json_integer(job->sequence_id),
+ "Destination",
+ "Mux", json_integer(job->mux),
+ "ChapterMarkers", json_boolean(job->chapter_markers),
+ "ChapterList",
+ "Source",
+ "Title", json_integer(job->title->index),
+ "Angle", json_integer(job->angle),
+ "PAR",
+ "Num", json_integer(job->par.num),
+ "Den", json_integer(job->par.den),
+ "Video",
+ "Codec", json_integer(job->vcodec),
+ "Audio",
+ "CopyMask", json_integer(job->acodec_copy_mask),
+ "FallbackEncoder", json_integer(job->acodec_fallback),
+ "AudioList",
+ "Subtitle",
+ "Search",
+ "Enable", json_boolean(job->indepth_scan),
+ "Forced", json_boolean(job->select_subtitle_config.force),
+ "Default", json_boolean(job->select_subtitle_config.default_track),
+ "Burn", json_boolean(subtitle_search_burn),
+ "SubtitleList",
+ "MetaData",
+ "Filter",
+ "Grayscale", json_boolean(job->grayscale),
+ "FilterList"
+ );
+ if (dict == NULL)
+ {
+ hb_error("json pack failure: %s", error.text);
+ return NULL;
+ }
+ json_t *dest_dict = json_object_get(dict, "Destination");
+ if (job->file != NULL)
+ {
+ json_object_set_new(dest_dict, "File", json_string(job->file));
+ }
+ if (job->mux & HB_MUX_MASK_MP4)
+ {
+ json_t *mp4_dict;
+ mp4_dict = json_pack_ex(&error, 0, "{s:o, s:o, s:o}",
+ "Mp4Optimize", json_boolean(job->mp4_optimize),
+ "LargeFileSize", json_boolean(job->largeFileSize),
+ "IpodAtom", json_boolean(job->ipod_atom));
+ json_object_set_new(dest_dict, "Mp4Options", mp4_dict);
+ }
+ json_t *source_dict = json_object_get(dict, "Source");
+ json_t *range_dict;
+ if (job->start_at_preview > 0)
+ {
+ range_dict = json_pack_ex(&error, 0, "{s:o, s:o, s:o}",
+ "StartAtPreview", json_integer(job->start_at_preview),
+ "PtsToStop", json_integer(job->pts_to_stop),
+ "SeekPoints", json_integer(job->seek_points));
+ }
+ else if (job->pts_to_start != 0)
+ {
+ range_dict = json_pack_ex(&error, 0, "{s:o, s:o}",
+ "PtsToStart", json_integer(job->pts_to_start),
+ "PtsToStop", json_integer(job->pts_to_stop));
+ }
+ else if (job->frame_to_start != 0)
+ {
+ range_dict = json_pack_ex(&error, 0, "{s:o, s:o}",
+ "FrameToStart", json_integer(job->frame_to_start),
+ "FrameToStop", json_integer(job->frame_to_stop));
+ }
+ else
+ {
+ range_dict = json_pack_ex(&error, 0, "{s:o, s:o}",
+ "ChapterStart", json_integer(job->chapter_start),
+ "ChapterEnd", json_integer(job->chapter_end));
+ }
+ json_object_set_new(source_dict, "Range", range_dict);
+
+ json_t *video_dict = json_object_get(dict, "Video");
+ if (job->color_matrix_code > 0)
+ {
+ json_object_set_new(video_dict, "ColorMatrixCode",
+ json_integer(job->color_matrix_code));
+ }
+ if (job->vquality >= 0)
+ {
+ json_object_set_new(video_dict, "Quality", json_real(job->vquality));
+ }
+ else
+ {
+ json_object_set_new(video_dict, "Bitrate", json_integer(job->vbitrate));
+ json_object_set_new(video_dict, "Pass", json_integer(job->pass));
+ json_object_set_new(video_dict, "Turbo",
+ json_boolean(job->fastfirstpass));
+ }
+ if (job->encoder_preset != NULL)
+ {
+ json_object_set_new(video_dict, "Preset",
+ json_string(job->encoder_preset));
+ }
+ if (job->encoder_tune != NULL)
+ {
+ json_object_set_new(video_dict, "Tune",
+ json_string(job->encoder_tune));
+ }
+ if (job->encoder_profile != NULL)
+ {
+ json_object_set_new(video_dict, "Profile",
+ json_string(job->encoder_profile));
+ }
+ if (job->encoder_level != NULL)
+ {
+ json_object_set_new(video_dict, "Level",
+ json_string(job->encoder_level));
+ }
+ if (job->encoder_options != NULL)
+ {
+ json_object_set_new(video_dict, "Options",
+ json_string(job->encoder_options));
+ }
+ json_t *meta_dict = json_object_get(dict, "MetaData");
+ if (job->metadata->name != NULL)
+ {
+ json_object_set_new(meta_dict, "Name",
+ json_string(job->metadata->name));
+ }
+ if (job->metadata->artist != NULL)
+ {
+ json_object_set_new(meta_dict, "Artist",
+ json_string(job->metadata->artist));
+ }
+ if (job->metadata->composer != NULL)
+ {
+ json_object_set_new(meta_dict, "Composer",
+ json_string(job->metadata->composer));
+ }
+ if (job->metadata->comment != NULL)
+ {
+ json_object_set_new(meta_dict, "Comment",
+ json_string(job->metadata->comment));
+ }
+ if (job->metadata->genre != NULL)
+ {
+ json_object_set_new(meta_dict, "Genre",
+ json_string(job->metadata->genre));
+ }
+ if (job->metadata->album != NULL)
+ {
+ json_object_set_new(meta_dict, "Album",
+ json_string(job->metadata->album));
+ }
+ if (job->metadata->album_artist != NULL)
+ {
+ json_object_set_new(meta_dict, "AlbumArtist",
+ json_string(job->metadata->album_artist));
+ }
+ if (job->metadata->description != NULL)
+ {
+ json_object_set_new(meta_dict, "Description",
+ json_string(job->metadata->description));
+ }
+ if (job->metadata->long_description != NULL)
+ {
+ json_object_set_new(meta_dict, "LongDescription",
+ json_string(job->metadata->long_description));
+ }
+
+ // process chapter list
+ json_t *chapter_list = json_object_get(dest_dict, "ChapterList");
+ for (ii = 0; ii < hb_list_count(job->list_chapter); ii++)
+ {
+ json_t *chapter_dict;
+ char *title = "";
+ hb_chapter_t *chapter = hb_list_item(job->list_chapter, ii);
+ if (chapter->title != NULL)
+ title = chapter->title;
+
+ chapter_dict = json_pack_ex(&error, 0, "{s:o}",
+ "Name", json_string(title));
+ json_array_append_new(chapter_list, chapter_dict);
+ }
+
+ // process filter list
+ json_t *filters_dict = json_object_get(dict, "Filter");
+ json_t *filter_list = json_object_get(filters_dict, "FilterList");
+ for (ii = 0; ii < hb_list_count(job->list_filter); ii++)
+ {
+ json_t *filter_dict;
+ hb_filter_object_t *filter = hb_list_item(job->list_filter, ii);
+
+ filter_dict = json_pack_ex(&error, 0, "{s:o}",
+ "ID", json_integer(filter->id));
+ if (filter->settings != NULL)
+ {
+ json_object_set_new(filter_dict, "Settings",
+ json_string(filter->settings));
+ }
+
+ json_array_append_new(filter_list, filter_dict);
+ }
+
+ // process audio list
+ json_t *audios_dict = json_object_get(dict, "Audio");
+ json_t *audio_list = json_object_get(audios_dict, "AudioList");
+ for (ii = 0; ii < hb_list_count(job->list_audio); ii++)
+ {
+ json_t *audio_dict;
+ hb_audio_t *audio = hb_list_item(job->list_audio, ii);
+
+ audio_dict = json_pack_ex(&error, 0,
+ "{s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o}",
+ "Track", json_integer(audio->config.in.track),
+ "Encoder", json_integer(audio->config.out.codec),
+ "Gain", json_real(audio->config.out.gain),
+ "DRC", json_real(audio->config.out.dynamic_range_compression),
+ "Mixdown", json_integer(audio->config.out.mixdown),
+ "NormalizeMixLevel", json_boolean(audio->config.out.normalize_mix_level),
+ "Samplerate", json_integer(audio->config.out.samplerate),
+ "Bitrate", json_integer(audio->config.out.bitrate),
+ "Quality", json_real(audio->config.out.quality),
+ "CompressionLevel", json_real(audio->config.out.compression_level));
+ if (audio->config.out.name != NULL)
+ {
+ json_object_set_new(audio_dict, "Name",
+ json_string(audio->config.out.name));
+ }
+
+ json_array_append_new(audio_list, audio_dict);
+ }
+
+ // process subtitle list
+ json_t *subtitles_dict = json_object_get(dict, "Subtitle");
+ json_t *subtitle_list = json_object_get(subtitles_dict, "SubtitleList");
+ for (ii = 0; ii < hb_list_count(job->list_subtitle); ii++)
+ {
+ json_t *subtitle_dict;
+ hb_subtitle_t *subtitle = hb_list_item(job->list_subtitle, ii);
+
+ if (subtitle->source == SRTSUB)
+ {
+ subtitle_dict = json_pack_ex(&error, 0,
+ "{s:o, s:o, s:o, s:{s:o, s:o, s:o}}",
+ "Default", json_boolean(subtitle->config.default_track),
+ "Burn", json_boolean(subtitle->config.dest == RENDERSUB),
+ "Offset", json_integer(subtitle->config.offset),
+ "SRT",
+ "Filename", json_string(subtitle->config.src_filename),
+ "Language", json_string(subtitle->iso639_2),
+ "Codeset", json_string(subtitle->config.src_codeset));
+ }
+ else
+ {
+ subtitle_dict = json_pack_ex(&error, 0,
+ "{s:o, s:o, s:o, s:o, s:o, s:o}",
+ "ID", json_integer(subtitle->id),
+ "Track", json_integer(subtitle->track),
+ "Default", json_boolean(subtitle->config.default_track),
+ "Force", json_boolean(subtitle->config.force),
+ "Burn", json_boolean(subtitle->config.dest == RENDERSUB),
+ "Offset", json_integer(subtitle->config.offset));
+ }
+ json_array_append_new(subtitle_list, subtitle_dict);
+ }
+
+ char *json_job = json_dumps(dict, JSON_INDENT(4));
+ json_decref(dict);
+
+ return json_job;
+}
+
+// These functions exist only to perform type checking when using
+// json_unpack_ex().
+static double* unpack_f(double *f) { return f; }
+static int* unpack_i(int *i) { return i; }
+static json_int_t* unpack_I(json_int_t *i) { return i; }
+static int * unpack_b(int *b) { return b; }
+static char** unpack_s(char **s) { return s; }
+static json_t** unpack_o(json_t** o) { return o; }
+
+/**
+ * Convert a json string representation of a job to an hb_job_t
+ * @param h - Pointer to the hb_hanle_t hb instance which contains the
+ * title that the job refers to.
+ * @param json_job - Pointer to json string representation of a job
+ */
+hb_job_t* hb_json_to_job( hb_handle_t * h, const char * json_job )
+{
+ json_t * dict;
+ hb_job_t * job;
+ int result;
+ json_error_t error;
+ int titleindex;
+
+ dict = json_loads(json_job, 0, NULL);
+
+ result = json_unpack_ex(dict, &error, 0, "{s:{s:i}}",
+ "Source", "Title", unpack_i(&titleindex));
+ if (result < 0)
+ {
+ hb_error("json unpack failure, failed to find title: %s", error.text);
+ return NULL;
+ }
+
+ job = hb_job_init_by_index(h, titleindex);
+
+ char *destfile = NULL;
+ char *video_preset = NULL, *video_tune = NULL;
+ char *video_profile = NULL, *video_level = NULL;
+ char *video_options = NULL;
+ int subtitle_search_burn = 0;
+ char *meta_name = NULL, *meta_artist = NULL, *meta_album_artist = NULL;
+ char *meta_release = NULL, *meta_comment = NULL, *meta_genre = NULL;
+ char *meta_composer = NULL, *meta_desc = NULL, *meta_long_desc = NULL;
+ json_int_t pts_to_start = 0, pts_to_stop = 0;
+
+ result = json_unpack_ex(dict, &error, 0,
+ "{"
+ "s:i,"
+ // Destination {File, Mux, ChapterMarkers, Mp4Options {
+ // Mp4Optimize, LargeFileSize, IpodAtom}
+ "s:{s?s, s:i, s:b s?{s?b, s?b, s?b}},"
+ // Source {Angle, Range {ChapterStart, ChapterEnd, PtsToStart, PtsToStop,
+ // FrameToStart, FrameToStop, StartAtPreview, SeekPoints}
+ "s:{s?i, s:{s?i, s?i, s?I, s?I, s?i, s?i, s?i, s?i}},"
+ // PAR {Num, Den}
+ "s?{s:i, s:i},"
+ // Video {Codec, Quality, Bitrate, Preset, Tune, Profile, Level,
+ // Options, Pass, Turbo, ColorMatrixCode}
+ "s:{s:i, s?f, s?i, s?s, s?s, s?s, s?s, s?s, s?i, s?b, s?i},"
+ // Audio {CopyMask, FallbackEncoder}
+ "s?{s?i, s?i},"
+ // Subtitle {Search {Enable, Forced, Default, Burn}}
+ "s?{s?{s:b, s?b, s?b, s?b}},"
+ // MetaData {Name, Artist, Composer, AlbumArtist, ReleaseDate,
+ // Comment, Genre, Description, LongDescription}
+ "s?{s?s, s?s, s?s, s?s, s?s, s?s, s?s, s?s, s?s},"
+ // Filters {}
+ "s?{s?b}"
+ "}",
+ "SequenceID", unpack_i(&job->sequence_id),
+ "Destination",
+ "File", unpack_s(&destfile),
+ "Mux", unpack_i(&job->mux),
+ "ChapterMarkers", unpack_b(&job->chapter_markers),
+ "Mp4Options",
+ "Mp4Optimize", unpack_b(&job->mp4_optimize),
+ "LargeFileSize", unpack_b(&job->largeFileSize),
+ "IpodAtom", unpack_b(&job->ipod_atom),
+ "Source",
+ "Angle", unpack_i(&job->angle),
+ "Range",
+ "ChapterStart", unpack_i(&job->chapter_start),
+ "ChapterEnd", unpack_i(&job->chapter_end),
+ "PtsToStart", unpack_I(&pts_to_start),
+ "PtsToStop", unpack_I(&pts_to_stop),
+ "FrameToStart", unpack_i(&job->frame_to_start),
+ "FrameToStop", unpack_i(&job->frame_to_stop),
+ "StartAtPreview", unpack_i(&job->start_at_preview),
+ "SeekPoints", unpack_i(&job->seek_points),
+ "PAR",
+ "Num", unpack_i(&job->par.num),
+ "Den", unpack_i(&job->par.den),
+ "Video",
+ "Codec", unpack_i(&job->vcodec),
+ "Quality", unpack_f(&job->vquality),
+ "Bitrate", unpack_i(&job->vbitrate),
+ "Preset", unpack_s(&video_preset),
+ "Tune", unpack_s(&video_tune),
+ "Profile", unpack_s(&video_profile),
+ "Level", unpack_s(&video_level),
+ "Options", unpack_s(&video_options),
+ "Pass", unpack_i(&job->pass),
+ "Turbo", unpack_b(&job->fastfirstpass),
+ "ColorMatrixCode", unpack_i(&job->color_matrix_code),
+ "Audio",
+ "CopyMask", unpack_i(&job->acodec_copy_mask),
+ "FallbackEncoder", unpack_i(&job->acodec_fallback),
+ "Subtitle",
+ "Search",
+ "Enable", unpack_b(&job->indepth_scan),
+ "Forced", unpack_b(&job->select_subtitle_config.force),
+ "Default", unpack_b(&job->select_subtitle_config.default_track),
+ "Burn", unpack_b(&subtitle_search_burn),
+ "MetaData",
+ "Name", unpack_s(&meta_name),
+ "Artist", unpack_s(&meta_artist),
+ "Composer", unpack_s(&meta_composer),
+ "AlbumArtist", unpack_s(&meta_album_artist),
+ "ReleaseDate", unpack_s(&meta_release),
+ "Comment", unpack_s(&meta_comment),
+ "Genre", unpack_s(&meta_genre),
+ "Description", unpack_s(&meta_desc),
+ "LongDescription", unpack_s(&meta_long_desc),
+ "Filter",
+ "Grayscale", unpack_b(&job->grayscale)
+ );
+ if (result < 0)
+ {
+ hb_error("json unpack failure: %s", error.text);
+ hb_job_close(&job);
+ return NULL;
+ }
+ job->pts_to_start = pts_to_start;
+ job->pts_to_stop = pts_to_stop;
+
+ if (destfile != NULL && destfile[0] != 0)
+ {
+ hb_job_set_file(job, destfile);
+ }
+
+ hb_job_set_encoder_preset(job, video_preset);
+ hb_job_set_encoder_tune(job, video_tune);
+ hb_job_set_encoder_profile(job, video_profile);
+ hb_job_set_encoder_level(job, video_level);
+ hb_job_set_encoder_options(job, video_options);
+
+ job->select_subtitle_config.dest = subtitle_search_burn ?
+ RENDERSUB : PASSTHRUSUB;
+ if (meta_name != NULL && meta_name[0] != 0)
+ {
+ hb_metadata_set_name(job->metadata, meta_name);
+ }
+ if (meta_artist != NULL && meta_artist[0] != 0)
+ {
+ hb_metadata_set_artist(job->metadata, meta_artist);
+ }
+ if (meta_composer != NULL && meta_composer[0] != 0)
+ {
+ hb_metadata_set_composer(job->metadata, meta_composer);
+ }
+ if (meta_album_artist != NULL && meta_album_artist[0] != 0)
+ {
+ hb_metadata_set_album_artist(job->metadata, meta_album_artist);
+ }
+ if (meta_release != NULL && meta_release[0] != 0)
+ {
+ hb_metadata_set_release_date(job->metadata, meta_release);
+ }
+ if (meta_comment != NULL && meta_comment[0] != 0)
+ {
+ hb_metadata_set_comment(job->metadata, meta_comment);
+ }
+ if (meta_genre != NULL && meta_genre[0] != 0)
+ {
+ hb_metadata_set_genre(job->metadata, meta_genre);
+ }
+ if (meta_desc != NULL && meta_desc[0] != 0)
+ {
+ hb_metadata_set_description(job->metadata, meta_desc);
+ }
+ if (meta_long_desc != NULL && meta_long_desc[0] != 0)
+ {
+ hb_metadata_set_long_description(job->metadata, meta_long_desc);
+ }
+
+ if (job->indepth_scan == 1)
+ {
+ job->pass = -1;
+ hb_job_set_encoder_options(job, NULL);
+ }
+ // process chapter list
+ json_t * chapter_list = NULL;
+ result = json_unpack_ex(dict, &error, 0,
+ "{s:{s:o}}",
+ "Destination",
+ "ChapterList", unpack_o(&chapter_list));
+ if (result < 0)
+ {
+ hb_error("json unpack failure: %s", error.text);
+ hb_job_close(&job);
+ return NULL;
+ }
+ if (json_is_array(chapter_list))
+ {
+ int ii;
+ json_t *chapter_dict;
+ json_array_foreach(chapter_list, ii, chapter_dict)
+ {
+ char *name = NULL;
+ result = json_unpack_ex(chapter_dict, &error, 0,
+ "{s:s}", "Name", unpack_s(&name));
+ if (result < 0)
+ {
+ hb_error("json unpack failure: %s", error.text);
+ hb_job_close(&job);
+ return NULL;
+ }
+ if (name != NULL && name[0] != 0)
+ {
+ hb_chapter_t *chapter;
+ chapter = hb_list_item(job->list_chapter, ii);
+ if (chapter != NULL)
+ {
+ hb_chapter_set_title(chapter, name);
+ }
+ }
+ }
+ }
+
+ // process filter list
+ json_t * filter_list = NULL;
+ result = json_unpack_ex(dict, &error, 0,
+ "{s:{s:o}}",
+ "Filter", "FilterList", unpack_o(&filter_list));
+ if (result < 0)
+ {
+ hb_error("json unpack failure: %s", error.text);
+ hb_job_close(&job);
+ return NULL;
+ }
+ if (json_is_array(filter_list))
+ {
+ int ii;
+ json_t *filter_dict;
+ json_array_foreach(filter_list, ii, filter_dict)
+ {
+ int filter_id = -1;
+ char *filter_settings = NULL;
+ result = json_unpack_ex(filter_dict, &error, 0, "{s:i, s?s}",
+ "ID", unpack_i(&filter_id),
+ "Settings", unpack_s(&filter_settings));
+ if (result < 0)
+ {
+ hb_error("json unpack failure: %s", error.text);
+ hb_job_close(&job);
+ return NULL;
+ }
+ if (filter_id >= HB_FILTER_FIRST && filter_id <= HB_FILTER_LAST)
+ {
+ hb_filter_object_t *filter;
+ filter = hb_filter_init(filter_id);
+ hb_add_filter(job, filter, filter_settings);
+ }
+ }
+ }
+
+ // process audio list
+ json_t * audio_list = NULL;
+ result = json_unpack_ex(dict, &error, 0, "{s:{s:o}}",
+ "Audio", "AudioList", unpack_o(&audio_list));
+ if (result < 0)
+ {
+ hb_error("json unpack failure: %s", error.text);
+ hb_job_close(&job);
+ return NULL;
+ }
+ if (json_is_array(audio_list))
+ {
+ int ii;
+ json_t *audio_dict;
+ json_array_foreach(audio_list, ii, audio_dict)
+ {
+ hb_audio_config_t audio;
+
+ hb_audio_config_init(&audio);
+ result = json_unpack_ex(audio_dict, &error, 0,
+ "{s:i, s?s, s?i, s?F, s?F, s?i, s?b, s?i, s?i, s?F, s?F}",
+ "Track", unpack_i(&audio.in.track),
+ "Name", unpack_s(&audio.out.name),
+ "Encoder", unpack_i((int*)&audio.out.codec),
+ "Gain", unpack_f(&audio.out.gain),
+ "DRC", unpack_f(&audio.out.dynamic_range_compression),
+ "Mixdown", unpack_i(&audio.out.mixdown),
+ "NormalizeMixLevel", unpack_b(&audio.out.normalize_mix_level),
+ "Samplerate", unpack_i(&audio.out.samplerate),
+ "Bitrate", unpack_i(&audio.out.bitrate),
+ "Quality", unpack_f(&audio.out.quality),
+ "CompressionLevel", unpack_f(&audio.out.compression_level));
+ if (result < 0)
+ {
+ hb_error("json unpack failure: %s", error.text);
+ hb_job_close(&job);
+ return NULL;
+ }
+ if (audio.in.track >= 0)
+ {
+ audio.out.track = ii;
+ hb_audio_add(job, &audio);
+ }
+ }
+ }
+
+ // process subtitle list
+ json_t * subtitle_list = NULL;
+ result = json_unpack_ex(dict, &error, 0,
+ "{s:{s:o}}",
+ "Subtitle",
+ "SubtitleList", unpack_o(&subtitle_list));
+ if (result < 0)
+ {
+ hb_error("json unpack failure: %s", error.text);
+ hb_job_close(&job);
+ return NULL;
+ }
+ if (json_is_array(subtitle_list))
+ {
+ int ii;
+ json_t *subtitle_dict;
+ json_array_foreach(subtitle_list, ii, subtitle_dict)
+ {
+ hb_subtitle_config_t sub_config;
+ int track = -1;
+ int burn = 0;
+ char *srtfile = NULL;
+ json_int_t offset = 0;
+
+ result = json_unpack_ex(subtitle_dict, &error, 0,
+ "{s?i, s?{s:s}}",
+ "Track", unpack_i(&track),
+ "SRT",
+ "Filename", unpack_s(&srtfile));
+ if (result < 0)
+ {
+ hb_error("json unpack failure: %s", error.text);
+ hb_job_close(&job);
+ return NULL;
+ }
+ // Embedded subtitle track
+ if (track >= 0)
+ {
+ hb_subtitle_t *subtitle;
+ subtitle = hb_list_item(job->title->list_subtitle, track);
+ if (subtitle != NULL)
+ {
+ sub_config = subtitle->config;
+ result = json_unpack_ex(subtitle_dict, &error, 0,
+ "{s?b, s?b, s?b, s?i}",
+ "Default", unpack_i(&sub_config.default_track),
+ "Force", unpack_b(&sub_config.force),
+ "Burn", unpack_b(&burn),
+ "Offset", unpack_I(&offset));
+ if (result < 0)
+ {
+ hb_error("json unpack failure: %s", error.text);
+ hb_job_close(&job);
+ return NULL;
+ }
+ sub_config.offset = offset;
+ sub_config.dest = burn ? RENDERSUB : PASSTHRUSUB;
+ hb_subtitle_add(job, &sub_config, track);
+ }
+ }
+ else if (srtfile != NULL)
+ {
+ strncpy(sub_config.src_filename, srtfile, 255);
+ sub_config.src_filename[255] = 0;
+
+ char *srtlang = "und";
+ char *srtcodeset = "UTF-8";
+ result = json_unpack_ex(subtitle_dict, &error, 0,
+ "{s?b, s?b, s?i, " // Common
+ "s?{s?s, s?s, s?s}}", // SRT
+ "Default", unpack_b(&sub_config.default_track),
+ "Burn", unpack_b(&burn),
+ "Offset", unpack_I(&offset),
+ "SRT",
+ "Filename", unpack_s(&srtfile),
+ "Language", unpack_s(&srtlang),
+ "Codeset", unpack_s(&srtcodeset));
+ if (result < 0)
+ {
+ hb_error("json unpack failure: %s", error.text);
+ hb_job_close(&job);
+ return NULL;
+ }
+ sub_config.offset = offset;
+ sub_config.dest = burn ? RENDERSUB : PASSTHRUSUB;
+ strncpy(sub_config.src_codeset, srtcodeset, 39);
+ sub_config.src_filename[39] = 0;
+ hb_srt_add(job, &sub_config, srtlang);
+ }
+ }
+ }
+
+ return job;
+}
+
+/**
+ * Initialize an hb_job_t and return a json string representation of the job
+ * @param h - Pointer to hb_handle_t instance that contains the
+ * specified title_index
+ * @param title_index - Index of hb_title_t to use for job initialization.
+ * Index comes from title->index or "Index" key
+ * in json representation of a title.
+ */
+char* hb_job_init_json(hb_handle_t *h, int title_index)
+{
+ hb_job_t *job = hb_job_init_by_index(h, title_index);
+ char *json_job = hb_job_to_json(job);
+ hb_job_close(&job);
+ return json_job;
+}
+
+/**
+ * Add a json string job to the hb queue
+ * @param h - Pointer to hb_handle_t instance that job is added to
+ * @param json_job - json string representation of job to add
+ */
+int hb_add_json( hb_handle_t * h, const char * json_job )
+{
+ hb_job_t *job = hb_json_to_job(h, json_job);
+ if (job == NULL)
+ return -1;
+
+ hb_add(h, job);
+ hb_job_close(&job);
+
+ return 0;
+}
+
+
+/**
+ * Calculates destination width and height for anamorphic content
+ *
+ * Returns geometry as json string {Width, Height, PAR {Num, Den}}
+ * @param json_param - contains source and destination geometry params.
+ * This encapsulates the values that are in
+ * hb_geometry_t and hb_geometry_settings_t
+ */
+char* hb_set_anamorphic_size_json(const char * json_param)
+{
+ int json_result;
+ json_error_t error;
+ json_t * dict;
+ hb_geometry_t geo_result;
+ hb_geometry_t src;
+ hb_geometry_settings_t ui_geo;
+
+ // Clear dest geometry since some fields are optional.
+ memset(&ui_geo, 0, sizeof(ui_geo));
+
+ dict = json_loads(json_param, 0, NULL);
+ json_result = json_unpack_ex(dict, &error, 0,
+ "{"
+ // SourceGeometry
+ // {Width, Height, PAR {Num, Den}}
+ "s:{s:i, s:i, s:{s:i, s:i}},"
+ // DestSettings
+ "s:{"
+ // {
+ // Geometry {Width, Height, PAR {Num, Den}},
+ "s:{s:i, s:i, s:{s:i, s:i}},"
+ // AnamorphicMode, Keep, ItuPAR, Modulus, MaxWidth, MaxHeight,
+ "s:i, s?i, s?b, s:i, s:i, s:i,"
+ // Crop [Top, Bottom, Left, Right]
+ "s?[iiii]"
+ // }
+ "}",
+ "SourceGeometry",
+ "Width", unpack_i(&src.width),
+ "Height", unpack_i(&src.height),
+ "PAR",
+ "Num", unpack_i(&src.par.num),
+ "Den", unpack_i(&src.par.den),
+ "DestSettings",
+ "Geometry",
+ "Width", unpack_i(&ui_geo.geometry.width),
+ "Height", unpack_i(&ui_geo.geometry.height),
+ "PAR",
+ "Num", unpack_i(&ui_geo.geometry.par.num),
+ "Den", unpack_i(&ui_geo.geometry.par.den),
+ "AnamorphicMode", unpack_i(&ui_geo.mode),
+ "Keep", unpack_i(&ui_geo.keep),
+ "ItuPAR", unpack_b(&ui_geo.itu_par),
+ "Modulus", unpack_i(&ui_geo.modulus),
+ "MaxWidth", unpack_i(&ui_geo.maxWidth),
+ "MaxHeight", unpack_i(&ui_geo.maxHeight),
+ "Crop", unpack_i(&ui_geo.crop[0]),
+ unpack_i(&ui_geo.crop[1]),
+ unpack_i(&ui_geo.crop[2]),
+ unpack_i(&ui_geo.crop[3])
+ );
+ if (json_result < 0)
+ {
+ hb_error("json unpack failure: %s", error.text);
+ return NULL;
+ }
+
+ hb_set_anamorphic_size2(&src, &ui_geo, &geo_result);
+
+ dict = json_pack_ex(&error, 0,
+ "{s:o, s:o, s:{s:o, s:o}}",
+ "Width", json_integer(geo_result.width),
+ "Height", json_integer(geo_result.height),
+ "PAR",
+ "Num", json_integer(geo_result.par.num),
+ "Den", json_integer(geo_result.par.den));
+ if (dict == NULL)
+ {
+ hb_error("hb_set_anamorphic_size_json: pack failure: %s", error.text);
+ return NULL;
+ }
+ char *result = json_dumps(dict, JSON_INDENT(4)|JSON_PRESERVE_ORDER);
+ json_decref(dict);
+
+ return result;
+}
diff --git a/libhb/hb_json.h b/libhb/hb_json.h
new file mode 100644
index 000000000..c67566cb1
--- /dev/null
+++ b/libhb/hb_json.h
@@ -0,0 +1,32 @@
+/* hb_json.h
+
+ Copyright (c) 2003-2014 HandBrake Team
+ This file is part of the HandBrake source code
+ Homepage: <http://handbrake.fr/>.
+ It may be used under the terms of the GNU General Public License v2.
+ For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html
+ */
+
+#ifndef HB_JSON_H
+#define HB_JSON_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "hb.h"
+
+char * hb_get_title_set_json(hb_handle_t * h);
+char * hb_title_to_json(const hb_title_t * title);
+char * hb_job_init_json(hb_handle_t *h, int title_index);
+char * hb_job_to_json(const hb_job_t * job);
+hb_job_t * hb_json_to_job(hb_handle_t * h, const char * json_job);
+int hb_add_json(hb_handle_t *h, const char * json_job);
+char * hb_set_anamorphic_size_json(const char * json_param);
+char * hb_get_state_json(hb_handle_t * h);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // HB_JSON_H
diff --git a/libhb/muxavformat.c b/libhb/muxavformat.c
index 8186c5bd2..a494bf0ef 100644
--- a/libhb/muxavformat.c
+++ b/libhb/muxavformat.c
@@ -341,34 +341,22 @@ static int avformatInit( hb_mux_object_t * m )
track->st->codec->extradata = priv_data;
track->st->codec->extradata_size = priv_size;
- if (job->anamorphic.mode > 0)
- {
- track->st->sample_aspect_ratio.num = job->anamorphic.par_width;
- track->st->sample_aspect_ratio.den = job->anamorphic.par_height;
- track->st->codec->sample_aspect_ratio.num = job->anamorphic.par_width;
- track->st->codec->sample_aspect_ratio.den = job->anamorphic.par_height;
- }
- else
- {
- track->st->sample_aspect_ratio.num = 1;
- track->st->sample_aspect_ratio.den = 1;
- track->st->codec->sample_aspect_ratio.num = 1;
- track->st->codec->sample_aspect_ratio.den = 1;
- }
- track->st->codec->width = job->width;
- track->st->codec->height = job->height;
+ track->st->sample_aspect_ratio.num = job->par.num;
+ track->st->sample_aspect_ratio.den = job->par.den;
+ track->st->codec->sample_aspect_ratio.num = job->par.num;
+ track->st->codec->sample_aspect_ratio.den = job->par.den;
+ track->st->codec->width = job->width;
+ track->st->codec->height = job->height;
track->st->disposition |= AV_DISPOSITION_DEFAULT;
- int vrate_base, vrate;
+ hb_rational_t vrate;
if( job->pass == 2 )
{
hb_interjob_t * interjob = hb_interjob_get( job->h );
- vrate_base = interjob->vrate_base;
vrate = interjob->vrate;
}
else
{
- vrate_base = job->vrate_base;
vrate = job->vrate;
}
@@ -378,32 +366,32 @@ static int avformatInit( hb_mux_object_t * m )
// measuring framerate, the actual value may not be exact. So
// we look for rates that are "close" and make an adjustment
// to fps.den.
- if (vrate == 27000000)
+ if (vrate.num == 27000000)
{
const hb_rate_t *video_framerate = NULL;
while ((video_framerate = hb_video_framerate_get_next(video_framerate)) != NULL)
{
- if (abs(vrate_base - video_framerate->rate) < 10)
+ if (abs(vrate.den - video_framerate->rate) < 10)
{
- vrate_base = video_framerate->rate;
+ vrate.den = video_framerate->rate;
break;
}
}
}
- hb_reduce(&vrate_base, &vrate, vrate_base, vrate);
+ hb_reduce(&vrate.num, &vrate.den, vrate.num, vrate.den);
if (job->mux == HB_MUX_AV_MP4)
{
// libavformat mp4 muxer requires that the codec time_base have the
// same denominator as the stream time_base, it uses it for the
// mdhd timescale.
- double scale = (double)track->st->time_base.den / vrate;
+ double scale = (double)track->st->time_base.den / vrate.num;
track->st->codec->time_base.den = track->st->time_base.den;
- track->st->codec->time_base.num = vrate_base * scale;
+ track->st->codec->time_base.num = vrate.den * scale;
}
else
{
- track->st->codec->time_base.num = vrate_base;
- track->st->codec->time_base.den = vrate;
+ track->st->codec->time_base.num = vrate.den;
+ track->st->codec->time_base.den = vrate.num;
}
/* add the audio tracks */
@@ -751,10 +739,7 @@ static int avformatInit( hb_mux_object_t * m )
};
int width, height = 60;
- if (job->anamorphic.mode)
- width = job->width * ((float)job->anamorphic.par_width / job->anamorphic.par_height);
- else
- width = job->width;
+ width = job->width * job->par.num / job->par.den;
track->st->codec->width = width;
track->st->codec->height = height;
properties[14] = height >> 8;
diff --git a/libhb/muxcommon.c b/libhb/muxcommon.c
index 98c67acbe..e3cdab1b0 100644
--- a/libhb/muxcommon.c
+++ b/libhb/muxcommon.c
@@ -608,7 +608,7 @@ hb_work_object_t * hb_muxer_init( hb_job_t * job )
// set up to interleave track data in blocks of 1 video frame time.
// (the best case for buffering and playout latency). The container-
// specific muxers can reblock this into bigger chunks if necessary.
- mux->interleave = 90000. * (double)job->vrate_base / (double)job->vrate;
+ mux->interleave = 90000. * (double)job->vrate.den / job->vrate.num;
mux->pts = mux->interleave;
/* Get a real muxer */
diff --git a/libhb/qsv_filter.c b/libhb/qsv_filter.c
index c0e0e0b51..6c78a5f2d 100644
--- a/libhb/qsv_filter.c
+++ b/libhb/qsv_filter.c
@@ -341,10 +341,10 @@ static int hb_qsv_filter_init( hb_filter_object_t * filter,
pv->list = hb_list_init();
// list of init params provided at work.c:~700
- pv->width_in = init->width;
- pv->height_in = init->height;
- pv->width_out = init->width;
- pv->height_out = init->height;
+ pv->width_in = init->geometry.width;
+ pv->height_in = init->geometry.height;
+ pv->width_out = init->geometry.width;
+ pv->height_out = init->geometry.height;
memcpy( pv->crop, init->crop, sizeof( int[4] ) );
if (filter->settings != NULL)
@@ -368,8 +368,8 @@ static int hb_qsv_filter_init( hb_filter_object_t * filter,
init->cfr = 0;
init->pix_fmt = pv->pix_fmt;
- init->width = pv->width_out;
- init->height = pv->height_out;
+ init->geometry.width = pv->width_out;
+ init->geometry.height = pv->height_out;
memcpy( init->crop, pv->crop, sizeof( int[4] ) );
return 0;
diff --git a/libhb/qsv_filter_pp.c b/libhb/qsv_filter_pp.c
index c9323bff9..1703281a8 100644
--- a/libhb/qsv_filter_pp.c
+++ b/libhb/qsv_filter_pp.c
@@ -144,29 +144,29 @@ static int filter_pre_init( av_qsv_context* qsv, hb_filter_private_t * pv ){
qsv_vpp->m_mfxVideoParam.vpp.In.ChromaFormat = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.ChromaFormat;
qsv_vpp->m_mfxVideoParam.vpp.In.CropX = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.CropX;
qsv_vpp->m_mfxVideoParam.vpp.In.CropY = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.CropY;
- qsv_vpp->m_mfxVideoParam.vpp.In.CropW = pv->job->title->width;
- qsv_vpp->m_mfxVideoParam.vpp.In.CropH = pv->job->title->height;
+ qsv_vpp->m_mfxVideoParam.vpp.In.CropW = pv->job->title->geometry.width;
+ qsv_vpp->m_mfxVideoParam.vpp.In.CropH = pv->job->title->geometry.height;
qsv_vpp->m_mfxVideoParam.vpp.In.PicStruct = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.PicStruct;
qsv_vpp->m_mfxVideoParam.vpp.In.FrameRateExtN = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FrameRateExtN;
qsv_vpp->m_mfxVideoParam.vpp.In.FrameRateExtD = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FrameRateExtD;
qsv_vpp->m_mfxVideoParam.vpp.In.AspectRatioW = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.AspectRatioW;
qsv_vpp->m_mfxVideoParam.vpp.In.AspectRatioH = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.AspectRatioH;
- qsv_vpp->m_mfxVideoParam.vpp.In.Width = AV_QSV_ALIGN16(pv->job->title->width);
+ qsv_vpp->m_mfxVideoParam.vpp.In.Width = AV_QSV_ALIGN16(pv->job->title->geometry.width);
qsv_vpp->m_mfxVideoParam.vpp.In.Height = (MFX_PICSTRUCT_PROGRESSIVE == qsv_vpp->m_mfxVideoParam.vpp.In.PicStruct)?
- AV_QSV_ALIGN16(pv->job->title->height) : AV_QSV_ALIGN32(pv->job->title->height);
+ AV_QSV_ALIGN16(pv->job->title->height) : AV_QSV_ALIGN32(pv->job->title->geometry.height);
qsv_vpp->m_mfxVideoParam.vpp.Out.FourCC = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FourCC;
qsv_vpp->m_mfxVideoParam.vpp.Out.ChromaFormat = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.ChromaFormat;
qsv_vpp->m_mfxVideoParam.vpp.Out.CropX = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.CropX;
qsv_vpp->m_mfxVideoParam.vpp.Out.CropY = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.CropY;
- qsv_vpp->m_mfxVideoParam.vpp.Out.CropW = pv->job->title->width;
+ qsv_vpp->m_mfxVideoParam.vpp.Out.CropW = pv->job->title->geometry.width;
qsv_vpp->m_mfxVideoParam.vpp.Out.CropH = pv->job->title->height;
qsv_vpp->m_mfxVideoParam.vpp.Out.PicStruct = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.PicStruct;
qsv_vpp->m_mfxVideoParam.vpp.Out.FrameRateExtN = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FrameRateExtN;
qsv_vpp->m_mfxVideoParam.vpp.Out.FrameRateExtD = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FrameRateExtD;
qsv_vpp->m_mfxVideoParam.vpp.Out.AspectRatioW = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.AspectRatioW;
qsv_vpp->m_mfxVideoParam.vpp.Out.AspectRatioH = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.AspectRatioH;
- qsv_vpp->m_mfxVideoParam.vpp.Out.Width = AV_QSV_ALIGN16(pv->job->title->width);
+ qsv_vpp->m_mfxVideoParam.vpp.Out.Width = AV_QSV_ALIGN16(pv->job->title->geometry.width);
qsv_vpp->m_mfxVideoParam.vpp.Out.Height = (MFX_PICSTRUCT_PROGRESSIVE == qsv_vpp->m_mfxVideoParam.vpp.In.PicStruct)?
AV_QSV_ALIGN16(pv->job->title->height) : AV_QSV_ALIGN32(pv->job->title->height);
@@ -280,13 +280,17 @@ static int hb_qsv_filter_pre_init( hb_filter_object_t * filter,
// PIX_FMT_YUV420P, ///< planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples) , 3 planes: Y, U, V
// PIX_FMT_NV12, ///< planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (first byte U and the following byte V)
pv->sws_context_from_nv12 = hb_sws_get_context(
- pv->job->title->width, pv->job->title->height, AV_PIX_FMT_NV12,
- pv->job->title->width, pv->job->title->height, AV_PIX_FMT_YUV420P,
- SWS_LANCZOS|SWS_ACCURATE_RND);
+ pv->job->title->geometry.width, pv->job->title->geometry.height,
+ AV_PIX_FMT_NV12,
+ pv->job->title->geometry.width, pv->job->title->geometry.height,
+ AV_PIX_FMT_YUV420P,
+ SWS_LANCZOS|SWS_ACCURATE_RND);
pv->sws_context_to_nv12 = hb_sws_get_context(
- pv->job->title->width, pv->job->title->height, AV_PIX_FMT_YUV420P,
- pv->job->title->width, pv->job->title->height, AV_PIX_FMT_NV12,
- SWS_LANCZOS|SWS_ACCURATE_RND);
+ pv->job->title->geometry.width, pv->job->title->geometry.height,
+ AV_PIX_FMT_YUV420P,
+ pv->job->title->geometry.width, pv->job->title->geometry.height,
+ AV_PIX_FMT_NV12,
+ SWS_LANCZOS|SWS_ACCURATE_RND);
return 0;
}
int pre_process_frame(hb_buffer_t *in, av_qsv_context* qsv, hb_filter_private_t * pv ){
diff --git a/libhb/reader.c b/libhb/reader.c
index 11729601c..72c27e34f 100644
--- a/libhb/reader.c
+++ b/libhb/reader.c
@@ -111,8 +111,8 @@ static int hb_reader_init( hb_work_object_t * w, hb_job_t * job )
r->st_slots = 4;
r->stream_timing = calloc( sizeof(stream_timing_t), r->st_slots );
r->stream_timing[0].id = r->title->video_id;
- r->stream_timing[0].average = 90000. * (double)job->vrate_base /
- (double)job->vrate;
+ r->stream_timing[0].average = 90000. * (double)job->vrate.den /
+ job->vrate.num;
r->stream_timing[0].filtered_average = r->stream_timing[0].average;
r->stream_timing[0].last = -r->stream_timing[0].average;
r->stream_timing[0].valid = 1;
@@ -139,7 +139,8 @@ static int hb_reader_init( hb_work_object_t * w, hb_job_t * job )
else if (job->frame_to_stop)
{
int frames = job->frame_to_start + job->frame_to_stop;
- r->duration = (int64_t)frames * job->title->rate_base * 90000 / job->title->rate;
+ r->duration = (int64_t)frames * job->title->vrate.den * 90000 /
+ job->title->vrate.num;
}
else
{
diff --git a/libhb/rendersub.c b/libhb/rendersub.c
index 1ca7ac7bc..6bf56f451 100644
--- a/libhb/rendersub.c
+++ b/libhb/rendersub.c
@@ -509,11 +509,11 @@ static int ssa_init( hb_filter_object_t * filter,
return 1;
}
- int width = init->width - ( pv->crop[2] + pv->crop[3] );
- int height = init->height - ( pv->crop[0] + pv->crop[1] );
+ int width = init->geometry.width - ( pv->crop[2] + pv->crop[3] );
+ int height = init->geometry.height - ( pv->crop[0] + pv->crop[1] );
ass_set_frame_size( pv->renderer, width, height);
- double par = (double)init->par_width / init->par_height;
+ double par = (double)init->geometry.par.num / init->geometry.par.den;
ass_set_aspect_ratio( pv->renderer, 1, par );
return 0;
@@ -592,8 +592,8 @@ static int textsub_init( hb_filter_object_t * filter,
{
hb_filter_private_t * pv = filter->private_data;
- int width = init->width - pv->crop[2] - pv->crop[3];
- int height = init->height - pv->crop[0] - pv->crop[1];
+ int width = init->geometry.width - pv->crop[2] - pv->crop[3];
+ int height = init->geometry.height - pv->crop[0] - pv->crop[1];
// Text subtitles for which we create a dummy ASS header need
// to have the header rewritten with the correct dimensions.
diff --git a/libhb/rotate.c b/libhb/rotate.c
index ba849c09d..654668fe2 100644
--- a/libhb/rotate.c
+++ b/libhb/rotate.c
@@ -26,8 +26,7 @@ struct hb_filter_private_s
int mode;
int width;
int height;
- int par_width;
- int par_height;
+ hb_rational_t par;
int cpu_count;
@@ -267,18 +266,17 @@ static int hb_rotate_init( hb_filter_object_t * filter,
if( pv->mode & 4 )
{
// 90 degree rotation, exchange width and height
- int tmp = init->width;
- init->width = init->height;
- init->height = tmp;
+ int tmp = init->geometry.width;
+ init->geometry.width = init->geometry.height;
+ init->geometry.height = tmp;
- tmp = init->par_width;
- init->par_width = init->par_height;
- init->par_height = tmp;
+ tmp = init->geometry.par.num;
+ init->geometry.par.num = init->geometry.par.den;
+ init->geometry.par.den = tmp;
}
- pv->width = init->width;
- pv->height = init->height;
- pv->par_width = init->par_width;
- pv->par_height = init->par_height;
+ pv->width = init->geometry.width;
+ pv->height = init->geometry.height;
+ pv->par = init->geometry.par;
return 0;
}
@@ -291,10 +289,9 @@ static int hb_rotate_info( hb_filter_object_t * filter,
return 1;
memset( info, 0, sizeof( hb_filter_info_t ) );
- info->out.width = pv->width;
- info->out.height = pv->height;
- info->out.par_width = pv->par_width;
- info->out.par_height = pv->par_height;
+ info->out.geometry.width = pv->width;
+ info->out.geometry.height = pv->height;
+ info->out.geometry.par = pv->par;
int pos = 0;
if( pv->mode & 1 )
pos += sprintf( &info->human_readable_desc[pos], "flip vertical" );
diff --git a/libhb/scan.c b/libhb/scan.c
index 8c8ce433f..d57f3ecba 100644
--- a/libhb/scan.c
+++ b/libhb/scan.c
@@ -42,15 +42,19 @@ static void UpdateState1(hb_scan_t *scan, int title);
static void UpdateState2(hb_scan_t *scan, int title);
static void UpdateState3(hb_scan_t *scan, int preview);
-static const char *aspect_to_string( double aspect )
+static const char *aspect_to_string(hb_rational_t *dar)
{
+ double aspect = (double)dar->num / dar->den;
switch ( (int)(aspect * 9.) )
{
case 9 * 4 / 3: return "4:3";
case 9 * 16 / 9: return "16:9";
}
static char arstr[32];
- sprintf( arstr, aspect >= 1.? "%.2f:1" : "1:%.2f", aspect );
+ if (aspect >= 1)
+ sprintf(arstr, "%.2f:1", aspect);
+ else
+ sprintf(arstr, "1:%.2f", 1. / aspect );
return arstr;
}
@@ -249,8 +253,8 @@ static void ScanFunc( void * _data )
hb_subtitle_t *subtitle = hb_list_item( title->list_subtitle, j );
if ( subtitle->source == VOBSUB || subtitle->source == PGSSUB )
{
- subtitle->width = title->width;
- subtitle->height = title->height;
+ subtitle->width = title->geometry.width;
+ subtitle->height = title->geometry.height;
}
}
}
@@ -460,11 +464,12 @@ static int has_resolution_change( info_list_t *info_list )
if( !info_list[0].count )
return 0;
- w = info_list[0].info.width;
- h = info_list[0].info.height;
+ w = info_list[0].info.geometry.width;
+ h = info_list[0].info.geometry.height;
for ( i = 1; info_list[i].count; ++i )
{
- if ( w != info_list[i].info.width || h != info_list[i].info.height )
+ if (w != info_list[i].info.geometry.width ||
+ h != info_list[i].info.geometry.height)
return 1;
}
return 0;
@@ -726,7 +731,7 @@ static int DecodePreviews( hb_scan_t * data, hb_title_t * title, int flush )
remember_info( info_list, &vid_info );
- if( is_close_to( vid_info.rate_base, 900900, 100 ) &&
+ if( is_close_to( vid_info.rate.den, 900900, 100 ) &&
( vid_buf->s.flags & PIC_FLAG_REPEAT_FIRST_FIELD ) )
{
/* Potentially soft telecine material */
@@ -741,7 +746,7 @@ static int DecodePreviews( hb_scan_t * data, hb_title_t * title, int flush )
doubled_frame_count++;
}
- if( is_close_to( vid_info.rate_base, 1126125, 100 ) )
+ if( is_close_to( vid_info.rate.den, 1126125, 100 ) )
{
// Frame FPS is 23.976 (meaning it's progressive), so start keeping
// track of how many are reporting at that speed. When enough
@@ -770,7 +775,7 @@ static int DecodePreviews( hb_scan_t * data, hb_title_t * title, int flush )
/* Detect black borders */
int top, bottom, left, right;
- int h4 = vid_info.height / 4, w4 = vid_info.width / 4;
+ int h4 = vid_info.geometry.height / 4, w4 = vid_info.geometry.width / 4;
// When widescreen content is matted to 16:9 or 4:3 there's sometimes
// a thin border on the outer edge of the matte. On TV content it can be
@@ -780,7 +785,7 @@ static int DecodePreviews( hb_scan_t * data, hb_title_t * title, int flush )
// we can crop the matte. The border width depends on the resolution
// (12 pixels on 1080i looks visually the same as 4 pixels on 480i)
// so we allow the border to be up to 1% of the frame height.
- const int border = vid_info.height / 100;
+ const int border = vid_info.geometry.height / 100;
for ( top = border; top < h4; ++top )
{
@@ -803,14 +808,14 @@ static int DecodePreviews( hb_scan_t * data, hb_title_t * title, int flush )
}
for ( bottom = border; bottom < h4; ++bottom )
{
- if ( ! row_all_dark( vid_buf, vid_info.height - 1 - bottom ) )
+ if ( ! row_all_dark( vid_buf, vid_info.geometry.height - 1 - bottom ) )
break;
}
if ( bottom <= border )
{
for ( bottom = 0; bottom < border; ++bottom )
{
- if ( ! row_all_dark( vid_buf, vid_info.height - 1 - bottom ) )
+ if ( ! row_all_dark( vid_buf, vid_info.geometry.height - 1 - bottom ) )
break;
}
if ( bottom >= border )
@@ -825,7 +830,7 @@ static int DecodePreviews( hb_scan_t * data, hb_title_t * title, int flush )
}
for ( right = 0; right < w4; ++right )
{
- if ( ! column_all_dark( vid_buf, top, bottom, vid_info.width - 1 - right ) )
+ if ( ! column_all_dark( vid_buf, top, bottom, vid_info.geometry.width - 1 - right ) )
break;
}
@@ -878,36 +883,36 @@ skip_preview:
{
title->video_codec_name = strdup( vid_info.name );
}
- title->width = vid_info.width;
- title->height = vid_info.height;
- if ( vid_info.rate && vid_info.rate_base )
+ title->geometry.width = vid_info.geometry.width;
+ title->geometry.height = vid_info.geometry.height;
+ if (vid_info.rate.num && vid_info.rate.den)
{
- // if the frame rate is very close to one of our "common" framerates,
- // assume it actually is said frame rate; e.g. some 24000/1001 sources
- // may have a rate_base of 1126124 (instead of 1126125)
+ // if the frame rate is very close to one of our "common"
+ // framerates, assume it actually is said frame rate;
+ // e.g. some 24000/1001 sources may have a rate.den of 1126124
+ // instead of 1126125
const hb_rate_t *video_framerate = NULL;
while ((video_framerate = hb_video_framerate_get_next(video_framerate)) != NULL)
{
- if (is_close_to(vid_info.rate_base, video_framerate->rate, 100))
+ if (is_close_to(vid_info.rate.den, video_framerate->rate, 100))
{
- vid_info.rate_base = video_framerate->rate;
+ vid_info.rate.den = video_framerate->rate;
break;
}
}
- title->rate = vid_info.rate;
- title->rate_base = vid_info.rate_base;
- if( vid_info.rate_base == 900900 )
+ title->vrate = vid_info.rate;
+ if( vid_info.rate.den == 900900 )
{
if( npreviews >= 4 && pulldown_count >= npreviews / 4 )
{
- title->rate_base = 1126125;
+ title->vrate.den = 1126125;
hb_deep_log( 2, "Pulldown detected, setting fps to 23.976" );
}
if( npreviews >= 2 && progressive_count >= npreviews / 2 )
{
// We've already deduced that the frame rate is 23.976,
// so set it back again.
- title->rate_base = 1126125;
+ title->vrate.den = 1126125;
hb_deep_log( 2, "Title's mostly NTSC Film, setting fps to 23.976" );
}
}
@@ -915,16 +920,16 @@ skip_preview:
{
// We've detected that a significant number of the frames
// have been doubled in duration by repeat flags.
- title->rate_base = 2 * vid_info.rate_base;
- hb_deep_log( 2, "Repeat frames detected, setting fps to %.3f", (float)title->rate / title->rate_base );
+ title->vrate.den = 2 * vid_info.rate.den;
+ hb_deep_log(2, "Repeat frames detected, setting fps to %.3f",
+ (float)title->vrate.num / title->vrate.den );
}
}
title->video_bitrate = vid_info.bitrate;
- if( vid_info.pixel_aspect_width && vid_info.pixel_aspect_height )
+ if( vid_info.geometry.par.num && vid_info.geometry.par.den )
{
- title->pixel_aspect_width = vid_info.pixel_aspect_width;
- title->pixel_aspect_height = vid_info.pixel_aspect_height;
+ title->geometry.par = vid_info.geometry.par;
}
title->color_prim = vid_info.color_prim;
title->color_transfer = vid_info.color_transfer;
@@ -935,11 +940,10 @@ skip_preview:
// TODO: check video dimensions
title->opencl_support = !!hb_opencl_available();
- // compute the aspect ratio based on the storage dimensions and the
- // pixel aspect ratio (if supplied) or just storage dimensions if no PAR.
- title->aspect = (double)title->width / (double)title->height;
- title->aspect *= (double)title->pixel_aspect_width /
- (double)title->pixel_aspect_height;
+ // compute the aspect ratio based on the storage dimensions and PAR.
+ hb_reduce(&title->dar.num, &title->dar.den,
+ title->geometry.par.num * title->geometry.width,
+ title->geometry.height * title->geometry.par.den);
// For unknown reasons some French PAL DVDs put the original
// content's aspect ratio into the mpeg PAR even though it's
@@ -948,14 +952,18 @@ skip_preview:
// aspect ratio from the DVD metadata. So, if the aspect computed
// from the PAR is different from the container's aspect we use
// the container's aspect & recompute the PAR from it.
- if( title->container_aspect && (int)(title->aspect * 9) != (int)(title->container_aspect * 9) )
+ if (data->dvd &&
+ (title->dar.num != title->container_dar.num ||
+ title->dar.den != title->container_dar.den))
{
- hb_log("scan: content PAR gives wrong aspect %.2f; "
- "using container aspect %.2f", title->aspect,
- title->container_aspect );
- title->aspect = title->container_aspect;
- hb_reduce( &title->pixel_aspect_width, &title->pixel_aspect_height,
- (int)(title->aspect * title->height + 0.5), title->width );
+ hb_log("scan: content PAR gives wrong aspect %d:%d; "
+ "using container aspect %d:%d",
+ title->dar.num, title->dar.den,
+ title->container_dar.num, title->container_dar.den);
+ title->dar = title->container_dar;
+ hb_reduce(&title->geometry.par.num, &title->geometry.par.den,
+ title->geometry.height * title->dar.num,
+ title->geometry.width * title->dar.den);
}
// don't try to crop unless we got at least 3 previews
@@ -977,11 +985,11 @@ skip_preview:
hb_log( "scan: %d previews, %dx%d, %.3f fps, autocrop = %d/%d/%d/%d, "
"aspect %s, PAR %d:%d",
- npreviews, title->width, title->height, (float) title->rate /
- (float) title->rate_base,
+ npreviews, title->geometry.width, title->geometry.height,
+ (float)title->vrate.num / title->vrate.den,
title->crop[0], title->crop[1], title->crop[2], title->crop[3],
- aspect_to_string( title->aspect ), title->pixel_aspect_width,
- title->pixel_aspect_height );
+ aspect_to_string(&title->dar),
+ title->geometry.par.num, title->geometry.par.den);
if( interlaced_preview_count >= ( npreviews / 2 ) )
{
@@ -1092,7 +1100,7 @@ static void LookForAudio( hb_title_t * title, hb_buffer_t * b )
hb_fifo_flush( audio->priv.scan_cache );
hb_fifo_close( &audio->priv.scan_cache );
- audio->config.in.samplerate = info.rate;
+ audio->config.in.samplerate = info.rate.num;
audio->config.in.samples_per_frame = info.samples_per_frame;
audio->config.in.bitrate = info.bitrate;
audio->config.in.matrix_encoding = info.matrix_encoding;
diff --git a/libhb/stream.c b/libhb/stream.c
index 0d1bec226..fc3bb7b4a 100644
--- a/libhb/stream.c
+++ b/libhb/stream.c
@@ -5435,8 +5435,8 @@ static hb_title_t *ffmpeg_title_scan( hb_stream_t *stream, hb_title_t *title )
if ( ic->streams[i]->sample_aspect_ratio.num &&
ic->streams[i]->sample_aspect_ratio.den )
{
- title->pixel_aspect_width = ic->streams[i]->sample_aspect_ratio.num;
- title->pixel_aspect_height = ic->streams[i]->sample_aspect_ratio.den;
+ title->geometry.par.num = ic->streams[i]->sample_aspect_ratio.num;
+ title->geometry.par.den = ic->streams[i]->sample_aspect_ratio.den;
}
title->video_codec = WORK_DECAVCODECV;
diff --git a/libhb/sync.c b/libhb/sync.c
index 5f7cbd4e6..e62a742fc 100644
--- a/libhb/sync.c
+++ b/libhb/sync.c
@@ -171,7 +171,8 @@ hb_work_object_t * hb_sync_init( hb_job_t * job )
else if( job->frame_to_stop )
{
/* Set the duration to a rough estimate */
- duration = ( job->frame_to_stop / ( title->rate / title->rate_base ) ) * 90000;
+ duration = (int64_t)job->frame_to_stop * title->vrate.den * 90000 /
+ title->vrate.num;
}
else
{
@@ -182,7 +183,7 @@ hb_work_object_t * hb_sync_init( hb_job_t * job )
duration += chapter->duration;
}
}
- sync->count_frames_max = duration * title->rate / title->rate_base / 90000;
+ sync->count_frames_max = duration * title->vrate.num / title->vrate.den / 90000;
}
hb_log( "sync: expecting %d video frames", sync->count_frames_max );
@@ -697,7 +698,7 @@ int syncVideoWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
pv->common->first_pts[0] = INT64_MAX - 1;
cur->s.start = sync->next_start;
- cur->s.stop = cur->s.start + 90000. / ((double)job->vrate / (double)job->vrate_base);
+ cur->s.stop = cur->s.start + 90000L * job->vrate.den / job->vrate.num;
sync->next_start += cur->s.stop - cur->s.start;;
/* Make sure last frame is reflected in frame count */
diff --git a/libhb/vadxva2.h b/libhb/vadxva2.h
index fd93e979e..540aea423 100644
--- a/libhb/vadxva2.h
+++ b/libhb/vadxva2.h
@@ -60,15 +60,6 @@ static const GUID DXVA2_ModeVC1_D = { 0x1b81beA3, 0xa0c7, 0x11d3, {0xb9, 0x84, 0
typedef struct
{
- int width;
- int height;
- int rate;
- int rate_base;
-
-}hb_dx_format;
-
-typedef struct
-{
LPDIRECT3DSURFACE9 d3d;
int refcount;
unsigned int order;
diff --git a/libhb/vfr.c b/libhb/vfr.c
index 592310548..f45fd57e9 100644
--- a/libhb/vfr.c
+++ b/libhb/vfr.c
@@ -13,10 +13,8 @@ struct hb_filter_private_s
{
hb_job_t * job;
int cfr;
- int input_vrate;
- int input_vrate_base;
- int vrate;
- int vrate_base;
+ hb_rational_t input_vrate;
+ hb_rational_t vrate;
hb_fifo_t * delay_queue;
int dropped_frames;
int extended_frames;
@@ -142,12 +140,12 @@ static float motion_metric( hb_filter_private_t * pv, hb_buffer_t * a, hb_buffer
// 0 - Variable Frame Rate (VFR) or 'same as source': frame times
// are left alone
// 1 - Constant Frame Rate (CFR): Frame timings are adjusted so that all
-// frames are exactly vrate_base ticks apart. Frames are dropped
+// frames are exactly vrate.den ticks apart. Frames are dropped
// or duplicated if necessary to maintain this spacing.
-// 2 - Peak Frame Rate (PFR): vrate_base is treated as the peak
+// 2 - Peak Frame Rate (PFR): vrate.den is treated as the peak
// average frame rate. I.e., the average frame rate (current frame
// end time divided by number of frames so far) is never allowed to be
-// greater than vrate_base and frames are dropped if necessary
+// greater than vrate.den and frames are dropped if necessary
// to keep the average under this value. Other than those drops, frame
// times are left alone.
//
@@ -309,11 +307,10 @@ static int hb_vfr_init(hb_filter_object_t *filter, hb_filter_init_t *init)
pv->cfr = init->cfr;
pv->input_vrate = pv->vrate = init->vrate;
- pv->input_vrate_base = pv->vrate_base = init->vrate_base;
if (filter->settings != NULL)
{
sscanf(filter->settings, "%d:%d:%d",
- &pv->cfr, &pv->vrate, &pv->vrate_base);
+ &pv->cfr, &pv->vrate.num, &pv->vrate.den);
}
pv->job = init->job;
@@ -339,22 +336,20 @@ static int hb_vfr_init(hb_filter_object_t *filter, hb_filter_init_t *init)
{
// For PFR, we want the framerate based on the source's actual
// framerate, unless it's higher than the specified peak framerate.
- double source_fps = (double)init->vrate / init->vrate_base;
- double peak_fps = (double)pv->vrate / pv->vrate_base;
+ double source_fps = (double)init->vrate.num / init->vrate.den;
+ double peak_fps = (double)pv->vrate.num / pv->vrate.den;
if (source_fps > peak_fps)
{
// peak framerate is lower than the source framerate.
// so signal that the framerate will be the peak fps.
init->vrate = pv->vrate;
- init->vrate_base = pv->vrate_base;
}
}
else
{
init->vrate = pv->vrate;
- init->vrate_base = pv->vrate_base;
}
- pv->frame_rate = (double)pv->vrate_base * 90000. / pv->vrate;
+ pv->frame_rate = (double)pv->vrate.den * 90000. / pv->vrate.num;
init->cfr = pv->cfr;
return 0;
@@ -369,26 +364,23 @@ static int hb_vfr_info( hb_filter_object_t * filter,
return 1;
memset( info, 0, sizeof( hb_filter_info_t ) );
- info->out.vrate_base = pv->input_vrate_base;
info->out.vrate = pv->input_vrate;
if (pv->cfr == 2)
{
// For PFR, we want the framerate based on the source's actual
// framerate, unless it's higher than the specified peak framerate.
- double source_fps = (double)pv->input_vrate / pv->input_vrate_base;
- double peak_fps = (double)pv->vrate / pv->vrate_base;
+ double source_fps = (double)pv->input_vrate.num / pv->input_vrate.den;
+ double peak_fps = (double)pv->vrate.num / pv->vrate.den;
if (source_fps > peak_fps)
{
// peak framerate is lower than the source framerate.
// so signal that the framerate will be the peak fps.
info->out.vrate = pv->vrate;
- info->out.vrate_base = pv->vrate_base;
}
}
else
{
info->out.vrate = pv->vrate;
- info->out.vrate_base = pv->vrate_base;
}
info->out.cfr = pv->cfr;
if ( pv->cfr == 0 )
@@ -396,14 +388,14 @@ static int hb_vfr_info( hb_filter_object_t * filter,
/* Ensure we're using "Same as source" FPS */
sprintf( info->human_readable_desc,
"frame rate: same as source (around %.3f fps)",
- (float)pv->vrate / pv->vrate_base );
+ (float)pv->vrate.num / pv->vrate.den );
}
else if ( pv->cfr == 2 )
{
// For PFR, we want the framerate based on the source's actual
// framerate, unless it's higher than the specified peak framerate.
- double source_fps = (double)pv->input_vrate / pv->input_vrate_base;
- double peak_fps = (double)pv->vrate / pv->vrate_base;
+ double source_fps = (double)pv->input_vrate.num / pv->input_vrate.den;
+ double peak_fps = (double)pv->vrate.num / pv->vrate.den;
sprintf( info->human_readable_desc,
"frame rate: %.3f fps -> peak rate limited to %.3f fps",
source_fps , peak_fps );
@@ -411,8 +403,8 @@ static int hb_vfr_info( hb_filter_object_t * filter,
else
{
// Constant framerate. Signal the framerate we are using.
- double source_fps = (double)pv->input_vrate / pv->input_vrate_base;
- double constant_fps = (double)pv->vrate / pv->vrate_base;
+ double source_fps = (double)pv->input_vrate.num / pv->input_vrate.den;
+ double constant_fps = (double)pv->vrate.num / pv->vrate.den;
sprintf( info->human_readable_desc,
"frame rate: %.3f fps -> constant %.3f fps",
source_fps , constant_fps );
diff --git a/libhb/work.c b/libhb/work.c
index 7e117df30..2860233c6 100644
--- a/libhb/work.c
+++ b/libhb/work.c
@@ -274,31 +274,15 @@ void hb_display_job_info(hb_job_t *job)
}
}
- if( job->anamorphic.mode )
- {
- hb_log( " + %s anamorphic", job->anamorphic.mode == 1 ? "strict" : job->anamorphic.mode == 2? "loose" : "custom" );
- if( job->anamorphic.mode == 3 && job->anamorphic.keep_display_aspect )
- {
- hb_log( " + keeping source display aspect ratio");
- }
- hb_log( " + storage dimensions: %d * %d, mod %i",
- job->width, job->height, job->modulus );
- if( job->anamorphic.itu_par )
- {
- hb_log( " + using ITU pixel aspect ratio values");
- }
- hb_log( " + pixel aspect ratio: %i / %i", job->anamorphic.par_width, job->anamorphic.par_height );
- hb_log( " + display dimensions: %.0f * %i",
- (float)( job->width * job->anamorphic.par_width / job->anamorphic.par_height ), job->height );
- }
- else
- {
- hb_log( " + dimensions: %d * %d, mod %i",
- job->width, job->height, job->modulus );
- }
-
if ( job->grayscale )
- hb_log( " + grayscale mode" );
+ hb_log( " + grayscale mode" );
+
+ hb_log( " + Output geometry" );
+ hb_log( " + storage dimensions: %d x %d", job->width, job->height );
+ hb_log( " + pixel aspect ratio: %d : %d", job->par.num, job->par.den );
+ hb_log( " + display dimensions: %d x %d",
+ job->width * job->par.num / job->par.den, job->height );
+
if( !job->indepth_scan )
{
@@ -521,8 +505,9 @@ void correct_framerate( hb_job_t * job )
return; // Interjob information is for a different encode.
// compute actual output vrate from first pass
- interjob->vrate = job->vrate_base * ( (double)interjob->out_frame_count * 90000 / interjob->total_time );
- interjob->vrate_base = job->vrate_base;
+ interjob->vrate.den = (int64_t)job->vrate.num * interjob->total_time /
+ ((int64_t)interjob->out_frame_count * 90000);
+ interjob->vrate.num = job->vrate.num;
}
/**
@@ -698,19 +683,30 @@ static void do_job(hb_job_t *job)
}
if (one_burned)
{
- // Add subtitle rendering filter
- // Note that if the filter is already in the filter chain, this
- // has no effect. Note also that this means the front-end is
- // not required to add the subtitle rendering filter since
- // we will always try to do it here.
- hb_filter_object_t *filter = hb_filter_init(HB_FILTER_RENDER_SUB);
- char *filter_settings = hb_strdup_printf("%d:%d:%d:%d",
- job->crop[0],
- job->crop[1],
- job->crop[2],
- job->crop[3]);
- hb_add_filter(job, filter, filter_settings);
- free(filter_settings);
+ int found = 0;
+ // Check that the HB_FILTER_RENDER_SUB is in the filter chain.
+ // We can not add it automatically because it needs crop
+ // values which only the frontend knows.
+ if (job->list_filter != NULL)
+ {
+ int ii;
+ for (ii = 0; ii < hb_list_count(job->list_filter); ii++)
+ {
+ hb_filter_object_t *filter;
+ filter = hb_list_item(job->list_filter, ii);
+ if (filter->id == HB_FILTER_RENDER_SUB)
+ {
+ found = 1;
+ break;
+ }
+ }
+ }
+ if (!found)
+ {
+ // If this happens, it is a programming error that
+ // needs to be fixed in the frontend
+ hb_error("Subtitle burned, but no rendering filter");
+ }
}
}
@@ -879,17 +875,15 @@ static void do_job(hb_job_t *job)
init.job = job;
init.pix_fmt = AV_PIX_FMT_YUV420P;
- init.width = title->width;
- init.height = title->height;
+ init.geometry.width = title->geometry.width;
+ init.geometry.height = title->geometry.height;
/* DXVA2 */
init.use_dxva = hb_use_dxva(title);
- init.par_width = job->anamorphic.par_width;
- init.par_height = job->anamorphic.par_height;
+ init.geometry.par = job->par;
memcpy(init.crop, title->crop, sizeof(int[4]));
- init.vrate_base = title->rate_base;
- init.vrate = title->rate;
+ init.vrate = title->vrate;
init.cfr = 0;
for( i = 0; i < hb_list_count( job->list_filter ); )
{
@@ -904,36 +898,31 @@ static void do_job(hb_job_t *job)
}
i++;
}
- job->width = init.width;
- job->height = init.height;
- job->anamorphic.par_width = init.par_width;
- job->anamorphic.par_height = init.par_height;
+ job->width = init.geometry.width;
+ job->height = init.geometry.height;
+ job->par = init.geometry.par;
memcpy(job->crop, init.crop, sizeof(int[4]));
- job->vrate_base = init.vrate_base;
job->vrate = init.vrate;
job->cfr = init.cfr;
}
- if( job->anamorphic.mode )
+ /* While x264 is smart enough to reduce fractions on its own, libavcodec
+ * needs some help with the math, so lose superfluous factors. */
+ hb_reduce(&job->par.num, &job->par.den,
+ job->par.num, job->par.den);
+ if (job->vcodec & HB_VCODEC_FFMPEG_MASK)
{
- /* While x264 is smart enough to reduce fractions on its own, libavcodec and
- * the MacGUI need some help with the math, so lose superfluous factors. */
- hb_reduce( &job->anamorphic.par_width, &job->anamorphic.par_height,
- job->anamorphic.par_width, job->anamorphic.par_height );
- if( job->vcodec & HB_VCODEC_FFMPEG_MASK )
+ /* Just to make working with ffmpeg even more fun,
+ * lavc's MPEG-4 encoder can't handle PAR values >= 255,
+ * even though AVRational does. Adjusting downwards
+ * distorts the display aspect slightly, but such is life. */
+ while ((job->par.num & ~0xFF) ||
+ (job->par.den & ~0xFF))
{
- /* Just to make working with ffmpeg even more fun,
- * lavc's MPEG-4 encoder can't handle PAR values >= 255,
- * even though AVRational does. Adjusting downwards
- * distorts the display aspect slightly, but such is life. */
- while( ( job->anamorphic.par_width & ~0xFF ) ||
- ( job->anamorphic.par_height & ~0xFF ) )
- {
- job->anamorphic.par_width >>= 1;
- job->anamorphic.par_height >>= 1;
- hb_reduce( &job->anamorphic.par_width, &job->anamorphic.par_height,
- job->anamorphic.par_width, job->anamorphic.par_height );
- }
+ job->par.num >>= 1;
+ job->par.den >>= 1;
+ hb_reduce(&job->par.num, &job->par.den,
+ job->par.num, job->par.den);
}
}
diff --git a/macosx/Controller.m b/macosx/Controller.m
index 4ceddb617..f7a291e6d 100644
--- a/macosx/Controller.m
+++ b/macosx/Controller.m
@@ -2091,8 +2091,8 @@ static void queueFSEventStreamCallback(
[queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->anamorphic.keep_display_aspect] forKey:@"PictureKeepRatio"];
[queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->anamorphic.mode] forKey:@"PicturePAR"];
[queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->modulus] forKey:@"PictureModulus"];
- [queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->anamorphic.par_width] forKey:@"PicturePARPixelWidth"];
- [queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->anamorphic.par_height] forKey:@"PicturePARPixelHeight"];
+ [queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->par.num] forKey:@"PicturePARPixelWidth"];
+ [queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->par.den] forKey:@"PicturePARPixelHeight"];
/* Text summaries of various settings */
[queueFileJob setObject:[NSString stringWithString:[self pictureSettingsSummary]]
@@ -2154,8 +2154,8 @@ static void queueFSEventStreamCallback(
/* Codecs */
/* Framerate */
- [queueFileJob setObject:[NSNumber numberWithInt:title->rate] forKey:@"JobVrate"];
- [queueFileJob setObject:[NSNumber numberWithInt:title->rate_base] forKey:@"JobVrateBase"];
+ [queueFileJob setObject:[NSNumber numberWithInt:title->vrate.num] forKey:@"JobVrate"];
+ [queueFileJob setObject:[NSNumber numberWithInt:title->vrate.den] forKey:@"JobVrateBase"];
/* we need to auto relase the queueFileJob and return it */
[queueFileJob autorelease];
@@ -2845,7 +2845,7 @@ static void queueFSEventStreamCallback(
/* Add Crop/Scale filter */
hb_filter_object_t *filter = hb_filter_init( HB_FILTER_CROP_SCALE );
hb_add_filter( job, filter, [[NSString stringWithFormat:@"%d:%d:%d:%d:%d:%d",
- job->width,job->height,
+ job->width, job->height,
job->crop[0], job->crop[1],
job->crop[2], job->crop[3]] UTF8String] );
}
@@ -3020,9 +3020,8 @@ static void queueFSEventStreamCallback(
job->anamorphic.keep_display_aspect = [[queueToApply objectForKey:@"PictureKeepRatio"] intValue];
job->anamorphic.mode = [[queueToApply objectForKey:@"PicturePAR"] intValue];
job->modulus = [[queueToApply objectForKey:@"PictureModulus"] intValue];
- job->anamorphic.par_width = [[queueToApply objectForKey:@"PicturePARPixelWidth"] intValue];
- job->anamorphic.par_height = [[queueToApply objectForKey:@"PicturePARPixelHeight"] intValue];
- job->anamorphic.dar_width = job->anamorphic.dar_height = 0;
+ job->par.num = [[queueToApply objectForKey:@"PicturePARPixelWidth"] intValue];
+ job->par.den = [[queueToApply objectForKey:@"PicturePARPixelHeight"] intValue];
/* Here we use the crop values saved at the time the preset was saved */
job->crop[0] = [[queueToApply objectForKey:@"PictureTopCrop"] intValue];
@@ -3343,7 +3342,7 @@ static void queueFSEventStreamCallback(
/* Add Crop/Scale filter */
filter = hb_filter_init( HB_FILTER_CROP_SCALE );
hb_add_filter( job, filter, [[NSString stringWithFormat:@"%d:%d:%d:%d:%d:%d",
- job->width,job->height,
+ job->width, job->height,
job->crop[0], job->crop[1],
job->crop[2], job->crop[3]] UTF8String] );
@@ -3829,7 +3828,7 @@ static void queueFSEventStreamCallback(
/* For point a to point b frame encoding, set the start and end fields to 0 and the title duration * announced fps in seconds respectively */
[fSrcFrameStartEncodingField setStringValue: [NSString stringWithFormat: @"%d", 1]];
//[fSrcFrameEndEncodingField setStringValue: [NSString stringWithFormat: @"%d", ((title->hours * 3600) + (title->minutes * 60) + (title->seconds)) * 24]];
- [fSrcFrameEndEncodingField setStringValue: [NSString stringWithFormat: @"%d", duration * (title->rate / title->rate_base)]];
+ [fSrcFrameEndEncodingField setStringValue: [NSString stringWithFormat: @"%d", duration * (title->vrate.num / title->vrate.den)]];
/* Update encode start / stop variables */
@@ -3986,7 +3985,7 @@ static void queueFSEventStreamCallback(
hb_title_t * title = (hb_title_t*)
hb_list_item( list, (int)[fSrcTitlePopUp indexOfSelectedItem] );
- int duration = ([fSrcFrameEndEncodingField intValue] - [fSrcFrameStartEncodingField intValue]) / (title->rate / title->rate_base);
+ int duration = ([fSrcFrameEndEncodingField intValue] - [fSrcFrameStartEncodingField intValue]) / (title->vrate.num / title->vrate.den);
[fSrcDuration2Field setStringValue: [NSString stringWithFormat:
@"%02d:%02d:%02d", duration / 3600, ( duration / 60 ) % 60,
duration % 60]];
@@ -4301,8 +4300,8 @@ the user is using "Custom" settings by determining the sender*/
* height, width, keep ar, anamorphic and crop settings.
* picture filters are handled separately below.
*/
- int maxWidth = fTitle->width - job->crop[2] - job->crop[3];
- int maxHeight = fTitle->height - job->crop[0] - job->crop[1];
+ int maxWidth = fTitle->geometry.width - job->crop[2] - job->crop[3];
+ int maxHeight = fTitle->geometry.height - job->crop[0] - job->crop[1];
job->maxWidth = job->maxHeight = 0;
/* Check to see if the objectForKey:@"UsesPictureSettings is greater than 0, as 0 means use picture sizing "None"
* ( 2 is use max for source and 1 is use exact size when the preset was created ) and the
@@ -4334,8 +4333,8 @@ the user is using "Custom" settings by determining the sender*/
}
/* crop may have changed, reset maxWidth/maxHeight */
- maxWidth = fTitle->width - job->crop[2] - job->crop[3];
- maxHeight = fTitle->height - job->crop[0] - job->crop[1];
+ maxWidth = fTitle->geometry.width - job->crop[2] - job->crop[3];
+ maxHeight = fTitle->geometry.height - job->crop[0] - job->crop[1];
/* Set modulus */
if ([chosenPreset objectForKey:@"PictureModulus"])
@@ -4351,8 +4350,8 @@ the user is using "Custom" settings by determining the sender*/
* Assume max picture settings initially
*/
job->anamorphic.mode = [[chosenPreset objectForKey:@"PicturePAR"] intValue];
- job->width = fTitle->width - job->crop[2] - job->crop[3];
- job->height = fTitle->height - job->crop[0] - job->crop[1];
+ job->width = fTitle->geometry.width - job->crop[2] - job->crop[3];
+ job->height = fTitle->geometry.height - job->crop[0] - job->crop[1];
job->anamorphic.keep_display_aspect = [[chosenPreset objectForKey:@"PictureKeepRatio"] intValue];
/* Check to see if the objectForKey:@"UsesPictureSettings" is 2,
@@ -4392,12 +4391,28 @@ the user is using "Custom" settings by determining the sender*/
if (job->maxHeight == 0 || job->maxHeight > maxHeight)
job->maxHeight = maxHeight;
- int width, height, par_width, par_height;
- hb_set_anamorphic_size(job, &width, &height, &par_width, &par_height);
- job->width = width;
- job->height = height;
- job->anamorphic.par_width = par_width;
- job->anamorphic.par_height = par_height;
+ hb_geometry_t srcGeo, resultGeo;
+ hb_geometry_settings_t uiGeo;
+
+ srcGeo.width = fTitle->geometry.width;
+ srcGeo.height = fTitle->geometry.height;
+ srcGeo.par = fTitle->geometry.par;
+
+ uiGeo.mode = job->anamorphic.mode;
+ uiGeo.keep = !!job->anamorphic.keep_display_aspect * HB_KEEP_DISPLAY_ASPECT;
+ uiGeo.itu_par = 0;
+ uiGeo.modulus = job->modulus;
+ memcpy(uiGeo.crop, job->crop, sizeof(int[4]));
+ uiGeo.geometry.width = job->width;
+ uiGeo.geometry.height = job->height;
+ uiGeo.geometry.par = job->par;
+ uiGeo.maxWidth = job->maxWidth;
+ uiGeo.maxHeight = job->maxHeight;
+ hb_set_anamorphic_size2(&srcGeo, &uiGeo, &resultGeo);
+
+ job->width = resultGeo.width;
+ job->height = resultGeo.height;
+ job->par = resultGeo.par;
/* we call SetTitle: in fPictureController so we get an instant update in the Picture Settings window */
[fPictureController setTitle:fTitle];
diff --git a/macosx/HBPicture.h b/macosx/HBPicture.h
index 24c695877..beb045768 100644
--- a/macosx/HBPicture.h
+++ b/macosx/HBPicture.h
@@ -24,10 +24,14 @@
anamorphic {
mode
keepDisplayAspect
- par_width
- par_height
- dar_width
- dar_height
+ par {
+ num
+ den
+ }
+ dar {
+ num
+ den
+ }
}
modulus
*/
diff --git a/macosx/HBPreviewController.m b/macosx/HBPreviewController.m
index 43128ac20..2d4174ef7 100644
--- a/macosx/HBPreviewController.m
+++ b/macosx/HBPreviewController.m
@@ -671,35 +671,35 @@ typedef enum ViewMode : NSUInteger {
NSSize imageScaledSize = [fPreviewImage size];
[self.pictureLayer setContents:fPreviewImage];
- NSSize displaySize = NSMakeSize( ( CGFloat )title->width, ( CGFloat )title->height );
+ NSSize displaySize = NSMakeSize( ( CGFloat )title->geometry.width, ( CGFloat )title->geometry.height );
NSString *sizeInfoString;
/* Set the picture size display fields below the Preview Picture*/
int display_width;
- display_width = title->job->width * title->job->anamorphic.par_width / title->job->anamorphic.par_height;
+ display_width = title->job->width * title->job->par.num / title->job->par.den;
if (title->job->anamorphic.mode == HB_ANAMORPHIC_STRICT) // Original PAR Implementation
{
sizeInfoString = [NSString stringWithFormat:
@"Source: %dx%d, Output: %dx%d, Anamorphic: %dx%d Strict",
- title->width, title->height, title->job->width, title->job->height, display_width, title->job->height];
+ title->geometry.width, title->geometry.height, title->job->width, title->job->height, display_width, title->job->height];
}
else if (title->job->anamorphic.mode == HB_ANAMORPHIC_LOOSE) // Loose Anamorphic
{
sizeInfoString = [NSString stringWithFormat:
@"Source: %dx%d, Output: %dx%d, Anamorphic: %dx%d Loose",
- title->width, title->height, title->job->width, title->job->height, display_width, title->job->height];
+ title->geometry.width, title->geometry.height, title->job->width, title->job->height, display_width, title->job->height];
}
else if (title->job->anamorphic.mode == HB_ANAMORPHIC_CUSTOM) // Custom Anamorphic
{
sizeInfoString = [NSString stringWithFormat:
@"Source: %dx%d, Output: %dx%d, Anamorphic: %dx%d Custom",
- title->width, title->height, title->job->width, title->job->height, display_width, title->job->height];
+ title->geometry.width, title->geometry.height, title->job->width, title->job->height, display_width, title->job->height];
}
else // No Anamorphic
{
sizeInfoString = [NSString stringWithFormat:
@"Source: %dx%d, Output: %dx%d",
- title->width, title->height, title->job->width, title->job->height];
+ title->geometry.width, title->geometry.height, title->job->width, title->job->height];
}
displaySize.width = display_width;
displaySize.height = title->job->height;
diff --git a/macosx/HBPreviewGenerator.m b/macosx/HBPreviewGenerator.m
index ccbe7473c..3e9adbe9b 100644
--- a/macosx/HBPreviewGenerator.m
+++ b/macosx/HBPreviewGenerator.m
@@ -104,13 +104,14 @@ typedef enum EncodeState : NSUInteger {
{
NSImage *img = nil;
- hb_ui_geometry_t geo;
- geo.width = title->job->width;
- geo.height = title->job->height;
+ hb_geometry_settings_t geo;
+ memset(&geo, 0, sizeof(geo));
+ geo.geometry.width = title->job->width;
+ geo.geometry.height = title->job->height;
// HBPreviewController will scale the image later,
// ignore the par.
- geo.par.num = 1;
- geo.par.den = 1;
+ geo.geometry.par.num = 1;
+ geo.geometry.par.den = 1;
memcpy(geo.crop, title->job->crop, sizeof(int[4]));
hb_image_t *image;
diff --git a/macosx/HBVideo.m b/macosx/HBVideo.m
index 0319174f7..b697dc773 100644
--- a/macosx/HBVideo.m
+++ b/macosx/HBVideo.m
@@ -776,8 +776,8 @@
else
{
/* same as source */
- fps_num = title->rate;
- fps_den = title->rate_base;
+ fps_num = title->vrate.num;
+ fps_den = title->vrate.den;
if (self.frameRateMode == 1)
{
// CFR
@@ -996,4 +996,4 @@
}
}
-@end \ No newline at end of file
+@end
diff --git a/macosx/HBVideoController.m b/macosx/HBVideoController.m
index 6bcbfb4c2..4bbd1499e 100644
--- a/macosx/HBVideoController.m
+++ b/macosx/HBVideoController.m
@@ -726,8 +726,8 @@ NSString *HBVideoEncoderChangedNotification = @"HBVideoEncoderChangedNotificatio
else
{
/* same as source */
- fps_num = title->rate;
- fps_den = title->rate_base;
+ fps_num = title->vrate.num;
+ fps_den = title->vrate.den;
if ([fFramerateMatrix selectedRow] == 1)
{
// CFR
diff --git a/macosx/PictureController.m b/macosx/PictureController.m
index 7472307aa..779cff60e 100644
--- a/macosx/PictureController.m
+++ b/macosx/PictureController.m
@@ -289,23 +289,22 @@ static void *HBPictureControllerContext = &HBPictureControllerContext;
[fCropLeftField setEditable: !self.autoCrop];
[fCropRightField setEditable: !self.autoCrop];
- [fWidthStepper setMaxValue: title->width - job->crop[2] - job->crop[3]];
+ [fWidthStepper setMaxValue: title->geometry.width - job->crop[2] - job->crop[3]];
[fWidthStepper setIntValue: job->width];
[fWidthField setIntValue: job->width];
- [fHeightStepper setMaxValue: title->height - job->crop[0] - job->crop[1]];
+ [fHeightStepper setMaxValue: title->geometry.height - job->crop[0] - job->crop[1]];
[fHeightStepper setIntValue: job->height];
[fHeightField setIntValue: job->height];
- [fCropTopStepper setMaxValue: title->height/2-2];
- [fCropBottomStepper setMaxValue: title->height/2-2];
- [fCropLeftStepper setMaxValue: title->width/2-2];
- [fCropRightStepper setMaxValue: title->width/2-2];
+ [fCropTopStepper setMaxValue: title->geometry.height/2-2];
+ [fCropBottomStepper setMaxValue: title->geometry.height/2-2];
+ [fCropLeftStepper setMaxValue: title->geometry.width/2-2];
+ [fCropRightStepper setMaxValue: title->geometry.width/2-2];
- [fParWidthField setIntValue: job->anamorphic.par_width];
- [fParHeightField setIntValue: job->anamorphic.par_height];
+ [fParWidthField setIntValue: job->par.num];
+ [fParHeightField setIntValue: job->par.den];
int display_width;
- display_width = job->width * job->anamorphic.par_width /
- job->anamorphic.par_height;
+ display_width = job->width * job->par.num / job->par.den;
[fDisplayWidthField setIntValue: display_width];
[fPreviewController setTitle:title];
@@ -676,15 +675,15 @@ static void *HBPictureControllerContext = &HBPictureControllerContext;
if (sender == fParWidthField || sender == fParHeightField)
{
- job->anamorphic.par_width = [fParWidthField intValue];
- job->anamorphic.par_height = [fParHeightField intValue];
+ job->par.num = [fParWidthField intValue];
+ job->par.den = [fParHeightField intValue];
}
if (sender == fDisplayWidthField)
{
dar_updated = 1;
- job->anamorphic.dar_width = [fDisplayWidthField intValue];
- job->anamorphic.dar_height = [fHeightStepper intValue];
+ job->par.num = [fDisplayWidthField intValue];
+ job->par.den = [fWidthField intValue];
}
if (sender == fCropMatrix)
@@ -721,35 +720,35 @@ static void *HBPictureControllerContext = &HBPictureControllerContext;
{
job->crop[0] = [fCropTopStepper intValue];
[fCropTopField setIntValue: job->crop[0]];
- [fHeightStepper setMaxValue: fTitle->height - job->crop[0] - job->crop[1]];
+ [fHeightStepper setMaxValue: fTitle->geometry.height - job->crop[0] - job->crop[1]];
}
if (sender == fCropBottomStepper)
{
job->crop[1] = [fCropBottomStepper intValue];
[fCropBottomField setIntValue: job->crop[1]];
- [fHeightStepper setMaxValue: fTitle->height - job->crop[0] - job->crop[1]];
+ [fHeightStepper setMaxValue: fTitle->geometry.height - job->crop[0] - job->crop[1]];
}
if (sender == fCropLeftStepper)
{
job->crop[2] = [fCropLeftStepper intValue];
[fCropLeftField setIntValue: job->crop[2]];
- [fWidthStepper setMaxValue: fTitle->width - job->crop[2] - job->crop[3]];
+ [fWidthStepper setMaxValue: fTitle->geometry.width - job->crop[2] - job->crop[3]];
}
if (sender == fCropRightStepper)
{
job->crop[3] = [fCropRightStepper intValue];
[fCropRightField setIntValue: job->crop[3]];
- [fWidthStepper setMaxValue: fTitle->width - job->crop[2] - job->crop[3]];
+ [fWidthStepper setMaxValue: fTitle->geometry.width - job->crop[2] - job->crop[3]];
}
if (sender == fCropTopField)
{
int cropValue = [fCropTopField intValue];
- if (cropValue >= 0 && (cropValue <= fTitle->height/2-2))
+ if (cropValue >= 0 && (cropValue <= fTitle->geometry.height/2-2))
{
job->crop[0] = cropValue;
[fCropTopStepper setIntValue:cropValue];
- [fHeightStepper setMaxValue: fTitle->height - job->crop[0] - job->crop[1]];
+ [fHeightStepper setMaxValue: fTitle->geometry.height - job->crop[0] - job->crop[1]];
}
else
{
@@ -759,11 +758,11 @@ static void *HBPictureControllerContext = &HBPictureControllerContext;
else if (sender == fCropBottomField)
{
int cropValue = [fCropBottomField intValue];
- if (cropValue >= 0 && (cropValue <= fTitle->height/2-2))
+ if (cropValue >= 0 && (cropValue <= fTitle->geometry.height/2-2))
{
job->crop[1] = cropValue;
[fCropBottomStepper setIntValue:cropValue];
- [fHeightStepper setMaxValue: fTitle->height - job->crop[0] - job->crop[1]];
+ [fHeightStepper setMaxValue: fTitle->geometry.height - job->crop[0] - job->crop[1]];
}
else
{
@@ -773,11 +772,11 @@ static void *HBPictureControllerContext = &HBPictureControllerContext;
else if (sender == fCropLeftField)
{
int cropValue = [fCropLeftField intValue];
- if (cropValue >= 0 && (cropValue <= fTitle->width/2-2))
+ if (cropValue >= 0 && (cropValue <= fTitle->geometry.width/2-2))
{
job->crop[2] = cropValue;
[fCropLeftStepper setIntValue:cropValue];
- [fWidthStepper setMaxValue: fTitle->width - job->crop[2] - job->crop[3]];
+ [fWidthStepper setMaxValue: fTitle->geometry.width - job->crop[2] - job->crop[3]];
}
else
{
@@ -787,11 +786,11 @@ static void *HBPictureControllerContext = &HBPictureControllerContext;
else if (sender == fCropRightField)
{
int cropValue = [fCropRightField intValue];
- if (cropValue >= 0 && (cropValue <= fTitle->width/2-2))
+ if (cropValue >= 0 && (cropValue <= fTitle->geometry.width/2-2))
{
job->crop[3] = cropValue;
[fCropRightStepper setIntValue:cropValue];
- [fWidthStepper setMaxValue: fTitle->width - job->crop[2] - job->crop[3]];
+ [fWidthStepper setMaxValue: fTitle->geometry.width - job->crop[2] - job->crop[3]];
}
else
{
@@ -802,40 +801,35 @@ static void *HBPictureControllerContext = &HBPictureControllerContext;
keep |= !!job->anamorphic.keep_display_aspect * HB_KEEP_DISPLAY_ASPECT;
hb_geometry_t srcGeo, resultGeo;
- hb_ui_geometry_t uiGeo;
+ hb_geometry_settings_t uiGeo;
- srcGeo.width = fTitle->width;
- srcGeo.height = fTitle->height;
- srcGeo.par.num = fTitle->pixel_aspect_width;
- srcGeo.par.den = fTitle->pixel_aspect_height;
+ srcGeo.width = fTitle->geometry.width;
+ srcGeo.height = fTitle->geometry.height;
+ srcGeo.par = fTitle->geometry.par;
uiGeo.mode = job->anamorphic.mode;
uiGeo.keep = keep;
uiGeo.itu_par = 0;
uiGeo.modulus = job->modulus;
memcpy(uiGeo.crop, job->crop, sizeof(int[4]));
- uiGeo.width = job->width;
- uiGeo.height = job->height;
+ uiGeo.geometry.width = job->width;
+ uiGeo.geometry.height = job->height;
/* Modulus added to maxWidth/maxHeight to allow a small amount of
* upscaling to the next mod boundary.
*/
- uiGeo.maxWidth = fTitle->width - job->crop[2] - job->crop[3] + job->modulus - 1;
- uiGeo.maxHeight = fTitle->height - job->crop[0] - job->crop[1] + job->modulus - 1;
- uiGeo.par.num = job->anamorphic.par_width;
- uiGeo.par.den = job->anamorphic.par_height;
- uiGeo.dar.num = 0;
- uiGeo.dar.den = 0;
+ uiGeo.maxWidth = fTitle->geometry.width - job->crop[2] - job->crop[3] + job->modulus - 1;
+ uiGeo.maxHeight = fTitle->geometry.height - job->crop[0] - job->crop[1] + job->modulus - 1;
+ uiGeo.geometry.par = job->par;
if (job->anamorphic.mode == HB_ANAMORPHIC_CUSTOM && dar_updated)
{
- uiGeo.dar.num = job->anamorphic.dar_width;
- uiGeo.dar.den = job->anamorphic.dar_height;
+ uiGeo.geometry.par.num = [fDisplayWidthField intValue];
+ uiGeo.geometry.par.den = uiGeo.geometry.width;
}
hb_set_anamorphic_size2(&srcGeo, &uiGeo, &resultGeo);
job->width = resultGeo.width;
job->height = resultGeo.height;
- job->anamorphic.par_width = resultGeo.par.num;
- job->anamorphic.par_height = resultGeo.par.den;
+ job->par = resultGeo.par;
int display_width;
display_width = resultGeo.width * resultGeo.par.num / resultGeo.par.den;
diff --git a/test/test.c b/test/test.c
index f4cee2c50..65708378b 100644
--- a/test/test.c
+++ b/test/test.c
@@ -479,11 +479,10 @@ static void PrintTitleInfo( hb_title_t * title, int feature )
fprintf( stderr, " + duration: %02d:%02d:%02d\n",
title->hours, title->minutes, title->seconds );
fprintf( stderr, " + size: %dx%d, pixel aspect: %d/%d, display aspect: %.2f, %.3f fps\n",
- title->width, title->height,
- title->pixel_aspect_width,
- title->pixel_aspect_height,
- (float) title->aspect,
- (float) title->rate / title->rate_base );
+ title->geometry.width, title->geometry.height,
+ title->geometry.par.num, title->geometry.par.den,
+ (float)title->dar.num / title->dar.den,
+ (float)title->vrate.num / title->vrate.num );
fprintf( stderr, " + autocrop: %d/%d/%d/%d\n", title->crop[0],
title->crop[1], title->crop[2], title->crop[3] );
@@ -647,7 +646,8 @@ static int HandleEvents( hb_handle_t * h )
hb_state_t s;
const hb_encoder_t *encoder;
int tmp_num_audio_tracks;
- int filter_cfr, filter_vrate, filter_vrate_base;
+ int filter_cfr;
+ hb_rational_t filter_vrate;
hb_get_state( h, &s );
switch( s.state )
@@ -762,7 +762,6 @@ static int HandleEvents( hb_handle_t * h )
job = hb_job_init(title);
filter_cfr = job->cfr;
filter_vrate = job->vrate;
- filter_vrate_base = job->vrate_base;
if( chapter_start && chapter_end && !stop_at_pts && !start_at_preview && !stop_at_frame && !start_at_pts && !start_at_frame )
@@ -792,7 +791,7 @@ static int HandleEvents( hb_handle_t * h )
}
vcodec = HB_VCODEC_X264;
job->vquality = 20.0;
- filter_vrate_base = 900000;
+ filter_vrate.den = 900000;
filter_cfr = 2;
if( !atracks )
{
@@ -862,7 +861,7 @@ static int HandleEvents( hb_handle_t * h )
job->ipod_atom = 1;
vcodec = HB_VCODEC_X264;
job->vquality = 22.0;
- filter_vrate_base = 900000;
+ filter_vrate.den = 900000;
filter_cfr = 2;
if( !atracks )
{
@@ -928,7 +927,7 @@ static int HandleEvents( hb_handle_t * h )
job->largeFileSize = 1;
vcodec = HB_VCODEC_X264;
job->vquality = 22.0;
- filter_vrate_base = 900000;
+ filter_vrate.den = 900000;
filter_cfr = 2;
if( !atracks )
{
@@ -998,7 +997,7 @@ static int HandleEvents( hb_handle_t * h )
job->largeFileSize = 1;
vcodec = HB_VCODEC_X264;
job->vquality = 20.0;
- filter_vrate_base = 900000;
+ filter_vrate.den = 900000;
filter_cfr = 2;
if( !atracks )
{
@@ -1068,7 +1067,7 @@ static int HandleEvents( hb_handle_t * h )
job->largeFileSize = 1;
vcodec = HB_VCODEC_X264;
job->vquality = 20.0;
- filter_vrate_base = 900000;
+ filter_vrate.den = 900000;
filter_cfr = 2;
if( !atracks )
{
@@ -1142,7 +1141,7 @@ static int HandleEvents( hb_handle_t * h )
job->largeFileSize = 1;
vcodec = HB_VCODEC_X264;
job->vquality = 20.0;
- filter_vrate_base = 900000;
+ filter_vrate.den = 900000;
filter_cfr = 2;
if( !atracks )
{
@@ -1212,7 +1211,7 @@ static int HandleEvents( hb_handle_t * h )
job->largeFileSize = 1;
vcodec = HB_VCODEC_X264;
job->vquality = 20.0;
- filter_vrate_base = 900000;
+ filter_vrate.den = 900000;
filter_cfr = 2;
if( !atracks )
{
@@ -1283,7 +1282,7 @@ static int HandleEvents( hb_handle_t * h )
}
vcodec = HB_VCODEC_X264;
job->vquality = 22.0;
- filter_vrate_base = 900000;
+ filter_vrate.den = 900000;
filter_cfr = 2;
if( !atracks )
{
@@ -1351,7 +1350,7 @@ static int HandleEvents( hb_handle_t * h )
}
vcodec = HB_VCODEC_X264;
job->vquality = 22.0;
- filter_vrate_base = 900000;
+ filter_vrate.den = 900000;
filter_cfr = 2;
if( !atracks )
{
@@ -1419,7 +1418,7 @@ static int HandleEvents( hb_handle_t * h )
}
vcodec = HB_VCODEC_X264;
job->vquality = 22.0;
- filter_vrate_base = 900000;
+ filter_vrate.den = 900000;
filter_cfr = 2;
if( !atracks )
{
@@ -1668,14 +1667,15 @@ static int HandleEvents( hb_handle_t * h )
memcpy(crop, title->crop, sizeof(int[4]));
}
- if( loose_crop >= 0 )
+ if (loose_crop >= 0)
{
int mod = modulus > 0 ? modulus : 2;
- apply_loose_crop(title->height, &crop[0], &crop[1], mod, loose_crop);
- apply_loose_crop(title->width, &crop[2], &crop[3], mod, loose_crop);
+ apply_loose_crop(title->geometry.height,
+ &crop[0], &crop[1], mod, loose_crop);
+ apply_loose_crop(title->geometry.width,
+ &crop[2], &crop[3], mod, loose_crop);
}
- job->deinterlace = deinterlace;
job->grayscale = grayscale;
hb_filter_object_t * filter;
@@ -1726,15 +1726,14 @@ static int HandleEvents( hb_handle_t * h )
}
hb_geometry_t srcGeo, resultGeo;
- hb_ui_geometry_t uiGeo;
+ hb_geometry_settings_t uiGeo;
- srcGeo.width = title->width;
- srcGeo.height = title->height;
- srcGeo.par.num = title->pixel_aspect_width;
- srcGeo.par.den = title->pixel_aspect_height;
+ srcGeo.width = title->geometry.width;
+ srcGeo.height = title->geometry.height;
+ srcGeo.par = title->geometry.par;
keep_display_aspect |= anamorphic_mode != HB_ANAMORPHIC_CUSTOM;
- uiGeo.mode = job->anamorphic.mode = anamorphic_mode;
+ uiGeo.mode = anamorphic_mode;
if (width != 0 && height != 0)
{
if (anamorphic_mode == HB_ANAMORPHIC_NONE)
@@ -1746,37 +1745,34 @@ static int HandleEvents( hb_handle_t * h )
uiGeo.mode = HB_ANAMORPHIC_CUSTOM;
}
}
- job->anamorphic.keep_display_aspect = keep_display_aspect;
uiGeo.keep = !!keep_display_aspect * HB_KEEP_DISPLAY_ASPECT;
- uiGeo.itu_par = job->anamorphic.itu_par = itu_par;
- uiGeo.modulus = job->modulus = modulus;
+ uiGeo.itu_par = itu_par;
+ uiGeo.modulus = modulus;
memcpy(uiGeo.crop, crop, sizeof(int[4]));
if (width == 0)
{
- uiGeo.width = title->width - crop[2] - crop[3];
+ uiGeo.geometry.width = title->geometry.width - crop[2] - crop[3];
}
else
{
uiGeo.keep |= HB_KEEP_WIDTH;
- uiGeo.width = width;
+ uiGeo.geometry.width = width;
}
if (height == 0)
{
- uiGeo.height = title->height - crop[0] - crop[1];
+ uiGeo.geometry.height = title->geometry.height - crop[0] - crop[1];
}
else
{
uiGeo.keep |= HB_KEEP_HEIGHT;
- uiGeo.height = height;
+ uiGeo.geometry.height = height;
}
uiGeo.maxWidth = maxWidth;
uiGeo.maxHeight = maxHeight;
- uiGeo.dar.num = 0;
- uiGeo.dar.den = 0;
if( par_width && par_height )
{
- uiGeo.par.num = par_width;
- uiGeo.par.den = par_height;
+ uiGeo.geometry.par.num = par_width;
+ uiGeo.geometry.par.den = par_height;
}
else if (display_width != 0 && width != 0)
{
@@ -1784,30 +1780,27 @@ static int HandleEvents( hb_handle_t * h )
{
fprintf(stderr, "display_width (%d), width (%d), and height (%d) can not all be specified, ignoring height", display_width, width, height);
}
- uiGeo.par.num = display_width;
- uiGeo.par.den = width;
+ uiGeo.geometry.par.num = display_width;
+ uiGeo.geometry.par.den = width;
}
else if (display_width != 0)
{
- uiGeo.dar.num = display_width;
- uiGeo.dar.den = uiGeo.height;
+ uiGeo.geometry.par.num = display_width;
+ uiGeo.geometry.par.den = uiGeo.geometry.width;
}
else
{
- uiGeo.par = srcGeo.par;
+ uiGeo.geometry.par = srcGeo.par;
}
hb_set_anamorphic_size2(&srcGeo, &uiGeo, &resultGeo);
- job->width = resultGeo.width;
- job->height = resultGeo.height;
- job->anamorphic.par_width = resultGeo.par.num;
- job->anamorphic.par_height = resultGeo.par.den;
- memcpy(job->crop, crop, sizeof(int[4]));
+ job->par = resultGeo.par;
// Add filter that does cropping and scaling
char * filter_str;
filter_str = hb_strdup_printf("%d:%d:%d:%d:%d:%d",
- job->width, job->height, crop[0], crop[1], crop[2], crop[3] );
+ resultGeo.width, resultGeo.height,
+ crop[0], crop[1], crop[2], crop[3] );
filter = hb_filter_init( HB_FILTER_CROP_SCALE );
hb_add_filter( job, filter, filter_str );
@@ -1816,21 +1809,20 @@ static int HandleEvents( hb_handle_t * h )
// Add framerate shaping filter
if (vrate)
{
- filter_cfr = cfr;
- filter_vrate = 27000000;
- filter_vrate_base = vrate;
+ filter_cfr = cfr;
+ filter_vrate.num = 27000000;
+ filter_vrate.den = vrate;
}
else if (cfr)
{
// cfr or pfr flag with no rate specified implies
// use the title rate.
filter_cfr = cfr;
- filter_vrate = title->rate;
- filter_vrate_base = title->rate_base;
+ filter_vrate = title->vrate;
}
filter = hb_filter_init(HB_FILTER_VFR);
- filter_str = hb_strdup_printf("%d:%d:%d", filter_cfr, filter_vrate,
- filter_vrate_base);
+ filter_str = hb_strdup_printf("%d:%d:%d", filter_cfr,
+ filter_vrate.num, filter_vrate.den);
hb_add_filter(job, filter, filter_str);
free(filter_str);
@@ -2798,11 +2790,6 @@ static int HandleEvents( hb_handle_t * h )
hb_job_set_encoder_profile(job, h264_profile);
hb_job_set_encoder_level (job, h264_level);
- if (maxWidth)
- job->maxWidth = maxWidth;
- if (maxHeight)
- job->maxHeight = maxHeight;
-
if( start_at_preview )
{
job->start_at_preview = start_at_preview - 1;