summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjstebbins <[email protected]>2014-12-16 16:50:50 +0000
committerjstebbins <[email protected]>2014-12-16 16:50:50 +0000
commitf56efd7b52c89da8cac55b4d4a187f2c87fdfee6 (patch)
tree24eacb856704fa8e4b8b8f0edc76568916f70255
parentd0a975e42dcab93e1d2eead350fb1ba3951d977c (diff)
json: add json APIs
There are several changes to job and title structs that break current windows interop code. The interop code should be changed such that it only uses json APIs. So if there is any missing features (or bugs) in these APIs, please let me know. git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@6602 b64f7644-9d1e-0410-96f1-a4d463321fa5
-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;