diff options
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; |