return hb_autopassthru_get_encoder(in_codec, copy_mask, fallback, mux);
}
- gint ii;
// Sanitize fallback
- for (ii = 0; ii < hb_audio_encoders_count; ii++)
+ const hb_encoder_t *enc;
+ for (enc = hb_audio_encoder_get_next(NULL); enc != NULL;
+ enc = hb_audio_encoder_get_next(enc))
{
- if (hb_audio_encoders[ii].encoder == fallback &&
- !(hb_audio_encoders[ii].muxers & mux))
+ if (enc->codec == fallback &&
+ !(enc->muxers & mux))
{
if ( mux == HB_MUX_MKV )
fallback = HB_ACODEC_LAME;
{
return fallback;
}
- for (ii = 0; ii < hb_audio_encoders_count; ii++)
+ for (enc = hb_audio_encoder_get_next(NULL); enc != NULL;
+ enc = hb_audio_encoder_get_next(enc))
{
- if (hb_audio_encoders[ii].encoder == acodec &&
- !(hb_audio_encoders[ii].muxers & mux))
+ if (enc->codec == acodec &&
+ !(enc->muxers & mux))
{
return fallback;
}
{
if (mix == 0)
mix = ghb_get_best_mix( aconfig, select_acodec, 0);
- bitrate = hb_get_best_audio_bitrate(select_acodec, bitrate, sr, mix);
+ bitrate = hb_audio_bitrate_get_best(select_acodec, bitrate, sr, mix);
ghb_settings_set_string(asettings, "AudioMixdown",
ghb_lookup_combo_string("AudioMixdown", ghb_int_value(mix)));
}
ghb_lookup_combo_string("AudioBitrate", ghb_int_value(bitrate)));
ghb_settings_take_value(asettings, "AudioEncoderActual",
- ghb_lookup_acodec_value(select_acodec));
+ ghb_lookup_audio_encoder_value(select_acodec));
}
void
{
if (mix == 0)
mix = ghb_get_best_mix( aconfig, select_acodec, 0);
- bitrate = hb_get_best_audio_bitrate(select_acodec, bitrate, sr, mix);
+ bitrate = hb_audio_bitrate_get_best(select_acodec, bitrate, sr, mix);
ghb_ui_update(ud, "AudioMixdown", ghb_int64_value(mix));
}
if (!codec_defined_bitrate)
{
int low, high;
mix = ghb_get_best_mix( aconfig, select_acodec, mix);
- hb_get_audio_bitrate_limits(select_acodec, sr, mix, &low, &high);
+ hb_audio_bitrate_get_limits(select_acodec, sr, mix, &low, &high);
ghb_set_bitrate_opts (ud->builder, low, high, -1);
}
ghb_ui_update(ud, "AudioBitrate", ghb_int64_value(bitrate));
ghb_settings_take_value(ud->settings, "AudioEncoderActual",
- ghb_lookup_acodec_value(select_acodec));
+ ghb_lookup_audio_encoder_value(select_acodec));
GValue *asettings = get_selected_asettings(ud);
if (asettings)
{
ghb_settings_take_value(asettings, "AudioEncoderActual",
- ghb_lookup_acodec_value(select_acodec));
+ ghb_lookup_audio_encoder_value(select_acodec));
}
ghb_audio_list_refresh_selected(ud);
ghb_check_dependency(ud, NULL, "AudioEncoderActual");
ghb_settings_set_string(asettings, "AudioEncoder",
ghb_lookup_combo_string("AudioEncoder", ghb_int_value(acodec)));
ghb_settings_set_value(asettings, "AudioEncoderActual",
- ghb_lookup_acodec_value(select_acodec));
+ ghb_lookup_audio_encoder_value(select_acodec));
ghb_settings_set_value(asettings, "AudioTrackQualityEnable", enable_qual);
ghb_settings_set_double(asettings, "AudioTrackQuality", quality);
track = ghb_settings_combo_int(ud->settings, "AudioTrack");
if (sr)
{
- sr = ghb_find_closest_audio_rate(sr);
+ sr = ghb_find_closest_audio_samplerate(sr);
}
ghb_ui_update(ud, "AudioSamplerate", ghb_int64_value(sr));
sr = aconfig ? aconfig->in.samplerate : 48000;
}
mix_code = ghb_get_best_mix( aconfig, acodec_code, mix_code);
- br = hb_get_best_audio_bitrate(acodec_code, br, sr, mix_code);
+ br = hb_audio_bitrate_get_best(acodec_code, br, sr, mix_code);
ghb_ui_update(ud, "AudioBitrate", ghb_int64_value(br));
ghb_ui_update(ud, "AudioMixdown", ghb_int64_value(mix_code));
float low, high, gran, defval;
int dir;
- hb_get_audio_quality_limits(acodec_code, &low, &high, &gran, &dir);
- defval = hb_get_default_audio_quality(acodec_code);
+ hb_audio_quality_get_limits(acodec_code, &low, &high, &gran, &dir);
+ defval = hb_audio_quality_get_default(acodec_code);
GtkScaleButton *sb;
GtkAdjustment *adj;
sb = GTK_SCALE_BUTTON(GHB_WIDGET(ud->builder, "AudioTrackQuality"));
{
float low, high, gran;
int dir;
- hb_get_audio_quality_limits(codec, &low, &high, &gran, &dir);
+ hb_audio_quality_get_limits(codec, &low, &high, &gran, &dir);
int digits = 0;
float tmp = gran;
float low, high, gran;
int dir;
int codec = ghb_settings_combo_int(ud->settings, "AudioEncoderActual");
- hb_get_audio_quality_limits(codec, &low, &high, &gran, &dir);
+ hb_audio_quality_get_limits(codec, &low, &high, &gran, &dir);
if (dir)
{
// Quality values are inverted
d_vqual_granularity_opts
};
-static options_map_t d_container_opts[] =
-{
- {"MKV", "mkv", HB_MUX_MKV, "mkv"},
- {"MP4", "mp4", HB_MUX_MP4, "mp4"},
-};
-combo_opts_t container_opts =
-{
- sizeof(d_container_opts)/sizeof(options_map_t),
- d_container_opts
-};
-
static options_map_t d_detel_opts[] =
{
{"Off", "off", 0, ""},
{"LogLongevity", &log_longevity_opts},
{"check_updates", &appcast_update_opts},
{"VideoQualityGranularity", &vqual_granularity_opts},
- {"FileFormat", &container_opts},
{"PictureDeinterlace", &deint_opts},
{"PictureDecomb", &decomb_opts},
{"PictureDetelecine", &detel_opts},
return result;
}
-static gint
-lookup_mix_int(const GValue *mix)
+static const hb_mixdown_t *
+lookup_mixdown_by_int(int imix)
{
- gint ii;
- gint result = 0;
-
-
- if (G_VALUE_TYPE(mix) == G_TYPE_STRING)
+ const hb_mixdown_t *mix;
+ for (mix = hb_mixdown_get_next(NULL); mix != NULL;
+ mix = hb_mixdown_get_next(mix))
{
- gchar * str = ghb_value_string(mix);
- for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
+ if (mix->amixdown == imix)
{
- if (strcmp(hb_audio_mixdowns[ii].short_name, str) == 0)
- {
- result = hb_audio_mixdowns[ii].amixdown;
- break;
- }
- }
- g_free(str);
- }
- else if (G_VALUE_TYPE(mix) == G_TYPE_INT ||
- G_VALUE_TYPE(mix) == G_TYPE_INT64 ||
- G_VALUE_TYPE(mix) == G_TYPE_DOUBLE)
- {
- gint val = ghb_value_int(mix);
- for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
- {
- if (hb_audio_mixdowns[ii].amixdown == val)
- {
- result = hb_audio_mixdowns[ii].amixdown;
- break;
- }
+ return mix;
}
}
- return result;
+ return NULL;
}
-static const gchar*
-lookup_mix_option(const GValue *mix)
+static const hb_mixdown_t *
+lookup_mixdown(const GValue *gmix)
{
- gint ii;
- const gchar *result = "None";
+ const hb_mixdown_t *mix;
-
- if (G_VALUE_TYPE(mix) == G_TYPE_STRING)
+ if (G_VALUE_TYPE(gmix) == G_TYPE_STRING)
{
- gchar *str = ghb_value_string(mix);
- for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
+ gchar * str = ghb_value_string(gmix);
+ for (mix = hb_mixdown_get_next(NULL); mix != NULL;
+ mix = hb_mixdown_get_next(mix))
{
- if (strcmp(hb_audio_mixdowns[ii].short_name, str) == 0)
+ if (strcmp(mix->short_name, str) == 0)
{
- result = hb_audio_mixdowns[ii].human_readable_name;
- break;
+ g_free(str);
+ return mix;
}
}
g_free(str);
}
- else if (G_VALUE_TYPE(mix) == G_TYPE_INT ||
- G_VALUE_TYPE(mix) == G_TYPE_INT64 ||
- G_VALUE_TYPE(mix) == G_TYPE_DOUBLE)
+ else if (G_VALUE_TYPE(gmix) == G_TYPE_INT ||
+ G_VALUE_TYPE(gmix) == G_TYPE_INT64 ||
+ G_VALUE_TYPE(gmix) == G_TYPE_DOUBLE)
{
- gint val = ghb_value_int(mix);
- for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
- {
- if (hb_audio_mixdowns[ii].amixdown == val)
- {
- result = hb_audio_mixdowns[ii].human_readable_name;
- break;
- }
- }
+ return lookup_mixdown_by_int(ghb_value_int(gmix));
}
- return result;
+ return NULL;
}
-static const gchar*
-lookup_mix_string(const GValue *mix)
+static gint
+lookup_mixdown_int(const GValue *gmix)
{
- gint ii;
- const gchar *result = "none";
+ const hb_mixdown_t *mix = lookup_mixdown(gmix);
+ if (mix != NULL)
+ return mix->amixdown;
+ return 0;
+}
+static const gchar*
+lookup_mixdown_option(const GValue *gmix)
+{
+ const hb_mixdown_t *mix = lookup_mixdown(gmix);
+ if (mix != NULL)
+ return mix->name;
+ return "None";
+}
- if (G_VALUE_TYPE(mix) == G_TYPE_STRING)
- {
- gchar *str = ghb_value_string(mix);
- for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
- {
- if (strcmp(hb_audio_mixdowns[ii].short_name, str) == 0)
- {
- result = hb_audio_mixdowns[ii].short_name;
- break;
- }
- }
- g_free(str);
- }
- else if (G_VALUE_TYPE(mix) == G_TYPE_INT ||
- G_VALUE_TYPE(mix) == G_TYPE_INT64 ||
- G_VALUE_TYPE(mix) == G_TYPE_DOUBLE)
- {
- gint val = ghb_value_int(mix);
- for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
- {
- if (hb_audio_mixdowns[ii].amixdown == val)
- {
- result = hb_audio_mixdowns[ii].short_name;
- break;
- }
- }
- }
- return result;
+static const gchar*
+lookup_mixdown_string(const GValue *gmix)
+{
+ const hb_mixdown_t *mix = lookup_mixdown(gmix);
+ if (mix != NULL)
+ return mix->short_name;
+ return "none";
}
-static gint
-lookup_video_rate_int(const GValue *vrate)
+static const hb_rate_t *
+lookup_video_framerate(const GValue *grate)
{
- gint ii;
gchar *str;
- gint result = 0;
+ const hb_rate_t *rate;
- str = ghb_value_string(vrate);
- for (ii = 0; ii < hb_video_rates_count; ii++)
+ str = ghb_value_string(grate);
+ for (rate = hb_video_framerate_get_next(NULL); rate != NULL;
+ rate = hb_video_framerate_get_next(rate))
{
- if (strcmp(hb_video_rates[ii].string, str) == 0)
+ if (strcmp(rate->name, str) == 0)
{
- result = hb_video_rates[ii].rate;
- break;
+ g_free(str);
+ return rate;
}
}
g_free(str);
// Default to "same as source"
- return result;
+ return NULL;
}
-static const gchar*
-lookup_video_rate_option(const GValue *vrate)
+static gint
+lookup_video_framerate_int(const GValue *grate)
{
- gint ii;
- gchar *str;
- const gchar *result = "Same as source";
+ const hb_rate_t *rate = lookup_video_framerate(grate);
+ if (rate != NULL)
+ return rate->rate;
+ return 0;
+}
- str = ghb_value_string(vrate);
- for (ii = 0; ii < hb_video_rates_count; ii++)
- {
- if (strcmp(hb_video_rates[ii].string, str) == 0)
- {
- result = hb_video_rates[ii].string;
- break;
- }
- }
- g_free(str);
- // Default to "same as source"
- return result;
+static const gchar*
+lookup_video_framerate_option(const GValue *grate)
+{
+ const hb_rate_t *rate = lookup_video_framerate(grate);
+ if (rate != NULL)
+ return rate->name;
+ return "Same as source";
}
-static gint
-lookup_audio_rate_int(const GValue *rate)
+static const hb_rate_t *
+lookup_audio_samplerate(const GValue *grate)
{
- gint ii;
- gint result = 0;
+ const hb_rate_t *rate;
- if (G_VALUE_TYPE(rate) == G_TYPE_STRING)
+ if (G_VALUE_TYPE(grate) == G_TYPE_STRING)
{
// Coincidentally, the string "source" will return 0
// which is our flag to use "same as source"
- gchar * str = ghb_value_string(rate);
- for (ii = 0; ii < hb_audio_rates_count; ii++)
+ gchar * str = ghb_value_string(grate);
+ for (rate = hb_audio_samplerate_get_next(NULL); rate != NULL;
+ rate = hb_audio_samplerate_get_next(rate))
{
- if (strcmp(hb_audio_rates[ii].string, str) == 0)
+ if (strcmp(rate->name, str) == 0)
{
- result = hb_audio_rates[ii].rate;
- break;
+ g_free(str);
+ return rate;
}
}
g_free(str);
}
- else if (G_VALUE_TYPE(rate) == G_TYPE_INT ||
- G_VALUE_TYPE(rate) == G_TYPE_INT64 ||
- G_VALUE_TYPE(rate) == G_TYPE_DOUBLE)
+ else if (G_VALUE_TYPE(grate) == G_TYPE_INT ||
+ G_VALUE_TYPE(grate) == G_TYPE_INT64 ||
+ G_VALUE_TYPE(grate) == G_TYPE_DOUBLE)
{
- for (ii = 0; ii < hb_audio_rates_count; ii++)
+ gint val = ghb_value_int(grate);
+ for (rate = hb_audio_samplerate_get_next(NULL); rate != NULL;
+ rate = hb_audio_samplerate_get_next(rate))
{
- gint val = ghb_value_int(rate);
- if (val == hb_audio_rates[ii].rate)
+ if (val == rate->rate)
{
- result = hb_audio_rates[ii].rate;
- break;
+ return rate;
}
}
}
- return result;
+ return NULL;
+}
+
+static gint
+lookup_audio_samplerate_int(const GValue *grate)
+{
+ const hb_rate_t *rate = lookup_audio_samplerate(grate);
+ if (rate != NULL)
+ return rate->rate;
+ return 0;
}
static const gchar*
-lookup_audio_rate(const GValue *rate, const char *def)
+lookup_audio_samplerate_def(const GValue *grate, const char *def)
{
- gint ii;
const gchar *result = def;
-
- if (G_VALUE_TYPE(rate) == G_TYPE_STRING)
- {
- // Coincidentally, the string "source" will return 0
- // which is our flag to use "same as source"
- gchar *str = ghb_value_string(rate);
- for (ii = 0; ii < hb_audio_rates_count; ii++)
- {
- if (strcmp(hb_audio_rates[ii].string, str) == 0)
- {
- result = hb_audio_rates[ii].string;
- break;
- }
- }
- g_free(str);
- }
- else if (G_VALUE_TYPE(rate) == G_TYPE_INT ||
- G_VALUE_TYPE(rate) == G_TYPE_INT64 ||
- G_VALUE_TYPE(rate) == G_TYPE_DOUBLE)
- {
- for (ii = 0; ii < hb_audio_rates_count; ii++)
- {
- gint val = ghb_value_int(rate);
- if (val == hb_audio_rates[ii].rate)
- {
- result = hb_audio_rates[ii].string;
- break;
- }
- }
- }
+ const hb_rate_t *rate = lookup_audio_samplerate(grate);
+ if (rate != NULL)
+ return rate->name;
return result;
}
static const gchar*
-lookup_audio_rate_option(const GValue *rate)
+lookup_audio_samplerate_option(const GValue *grate)
{
- return lookup_audio_rate(rate, "Same as Source");
+ return lookup_audio_samplerate_def(grate, "Same as Source");
}
static const gchar*
-lookup_audio_rate_string(const GValue *rate)
+lookup_audio_samplerate_string(const GValue *grate)
{
- return lookup_audio_rate(rate, "source");
+ return lookup_audio_samplerate_def(grate, "source");
}
gint
-ghb_find_closest_audio_rate(gint rate)
+ghb_find_closest_audio_samplerate(gint irate)
{
- gint ii;
gint result;
+ const hb_rate_t *rate;
result = 0;
- for (ii = 0; ii < hb_audio_rates_count; ii++)
+ for (rate = hb_audio_samplerate_get_next(NULL); rate != NULL;
+ rate = hb_audio_samplerate_get_next(rate))
{
- if (rate <= hb_audio_rates[ii].rate)
+ if (irate <= rate->rate)
{
- result = hb_audio_rates[ii].rate;
+ result = rate->rate;
break;
}
}
return result;
}
-hb_rate_t *ghb_audio_bitrates;
-int ghb_audio_bitrates_count;
+hb_rate_t *ghb_audio_bitrates = NULL;
+int ghb_audio_bitrates_count = 0;
+int ghb_abr_count = 0;
-static gint
-lookup_audio_bitrate_int(const GValue *rate)
+static const hb_rate_t *
+lookup_audio_bitrate(const GValue *grate)
{
gint ii;
- gint result = 160;
+ const hb_rate_t *result = NULL;
- if (G_VALUE_TYPE(rate) == G_TYPE_STRING)
+ if (G_VALUE_TYPE(grate) == G_TYPE_STRING)
{
// Coincidentally, the string "source" will return 0
// which is our flag to use "same as source"
- gchar *str = ghb_value_string(rate);
+ gchar *str = ghb_value_string(grate);
for (ii = 0; ii < ghb_audio_bitrates_count; ii++)
{
- if (strcmp(ghb_audio_bitrates[ii].string, str) == 0)
+ if (strcmp(ghb_audio_bitrates[ii].name, str) == 0)
{
- result = ghb_audio_bitrates[ii].rate;
- break;
+ g_free(str);
+ return &ghb_audio_bitrates[ii];
}
}
g_free(str);
}
- else if (G_VALUE_TYPE(rate) == G_TYPE_INT ||
- G_VALUE_TYPE(rate) == G_TYPE_INT64 ||
- G_VALUE_TYPE(rate) == G_TYPE_DOUBLE)
+ else if (G_VALUE_TYPE(grate) == G_TYPE_INT ||
+ G_VALUE_TYPE(grate) == G_TYPE_INT64 ||
+ G_VALUE_TYPE(grate) == G_TYPE_DOUBLE)
{
- gint val = ghb_value_int(rate);
+ gint val = ghb_value_int(grate);
for (ii = 0; ii < ghb_audio_bitrates_count; ii++)
{
if (ghb_audio_bitrates[ii].rate == val)
{
- result = ghb_audio_bitrates[ii].rate;
- break;
+ return &ghb_audio_bitrates[ii];
}
}
}
return result;
}
+static gint
+lookup_audio_bitrate_int(const GValue *grate)
+{
+ const hb_rate_t *rate = lookup_audio_bitrate(grate);
+ if (rate != NULL)
+ return rate->rate;
+ return 160;
+}
+
static const gchar*
-lookup_audio_bitrate_option(const GValue *rate)
+lookup_audio_bitrate_option(const GValue *grate)
{
- gint ii;
- const gchar *result = "160";
+ const hb_rate_t *rate = lookup_audio_bitrate(grate);
+ if (rate != NULL)
+ return rate->name;
+ return "160";
+}
- if (G_VALUE_TYPE(rate) == G_TYPE_STRING)
- {
- // Coincidentally, the string "source" will return 0
- // which is our flag to use "same as source"
- gchar *str = ghb_value_string(rate);
- for (ii = 0; ii < ghb_audio_bitrates_count; ii++)
- {
- if (strcmp(ghb_audio_bitrates[ii].string, str) == 0)
- {
- result = ghb_audio_bitrates[ii].string;
- break;
- }
- }
- g_free(str);
- }
- else if (G_VALUE_TYPE(rate) == G_TYPE_INT ||
- G_VALUE_TYPE(rate) == G_TYPE_INT64 ||
- G_VALUE_TYPE(rate) == G_TYPE_DOUBLE)
+static const hb_encoder_t *
+lookup_audio_encoder_by_int(int ienc)
+{
+ const hb_encoder_t *enc;
+ for (enc = hb_audio_encoder_get_next(NULL); enc != NULL;
+ enc = hb_audio_encoder_get_next(enc))
{
- gint val = ghb_value_int(rate);
- for (ii = 0; ii < ghb_audio_bitrates_count; ii++)
+ if (enc->codec == ienc)
{
- if (ghb_audio_bitrates[ii].rate == val)
- {
- result = ghb_audio_bitrates[ii].string;
- break;
- }
+ return enc;
}
}
- return result;
+ return NULL;
}
-static gint
-lookup_hb_encoder_int(const GValue *enc, hb_encoder_t *encoders, int len)
+static const hb_encoder_t *
+lookup_audio_encoder(const GValue *genc)
{
- gint ii;
+ const hb_encoder_t *enc;
- if (G_VALUE_TYPE(enc) == G_TYPE_STRING)
+ if (G_VALUE_TYPE(genc) == G_TYPE_STRING)
{
- gchar *str = ghb_value_string(enc);
- for (ii = 0; ii < len; ii++)
+ gchar *str = ghb_value_string(genc);
+ for (enc = hb_audio_encoder_get_next(NULL); enc != NULL;
+ enc = hb_audio_encoder_get_next(enc))
{
- if (strcmp(encoders[ii].human_readable_name, str) == 0 ||
- strcmp(encoders[ii].short_name, str) == 0)
+ if (strcmp(enc->name, str) == 0 ||
+ strcmp(enc->short_name, str) == 0)
{
g_free(str);
- return encoders[ii].encoder;
+ return enc;
}
}
g_free(str);
}
- else if (G_VALUE_TYPE(enc) == G_TYPE_INT ||
- G_VALUE_TYPE(enc) == G_TYPE_INT64 ||
- G_VALUE_TYPE(enc) == G_TYPE_DOUBLE)
+ else if (G_VALUE_TYPE(genc) == G_TYPE_INT ||
+ G_VALUE_TYPE(genc) == G_TYPE_INT64 ||
+ G_VALUE_TYPE(genc) == G_TYPE_DOUBLE)
{
- int val = ghb_value_int(enc);
- for (ii = 0; ii < len; ii++)
- {
- if (encoders[ii].encoder == val)
- {
- return encoders[ii].encoder;
- }
- }
+ return lookup_audio_encoder_by_int(ghb_value_int(genc));
}
- return 0;
+ return NULL;
}
-static const gchar*
-lookup_hb_encoder_option(const GValue *enc, hb_encoder_t *encoders, int len)
+static const hb_encoder_t *
+lookup_video_encoder_by_int(int ienc)
{
- gint ii;
-
- if (G_VALUE_TYPE(enc) == G_TYPE_STRING)
+ const hb_encoder_t *enc;
+ for (enc = hb_video_encoder_get_next(NULL); enc != NULL;
+ enc = hb_video_encoder_get_next(enc))
{
- gchar *str = ghb_value_string(enc);
- for (ii = 0; ii < len; ii++)
+ if (enc->codec == ienc)
{
- if (strcmp(encoders[ii].human_readable_name, str) == 0 ||
- strcmp(encoders[ii].short_name, str) == 0)
- {
- g_free(str);
- return encoders[ii].human_readable_name;
- }
+ return enc;
}
- g_free(str);
}
- else if (G_VALUE_TYPE(enc) == G_TYPE_INT ||
- G_VALUE_TYPE(enc) == G_TYPE_INT64 ||
- G_VALUE_TYPE(enc) == G_TYPE_DOUBLE)
- {
- int val = ghb_value_int(enc);
- for (ii = 0; ii < len; ii++)
- {
- if (encoders[ii].encoder == val)
- {
- return encoders[ii].human_readable_name;
- }
- }
- }
- return 0;
+ return NULL;
}
-static const gchar*
-lookup_hb_encoder_string(const GValue *enc, hb_encoder_t *encoders, int len)
+static const hb_encoder_t *
+lookup_video_encoder(const GValue *genc)
{
- gint ii;
+ const hb_encoder_t *enc;
- if (G_VALUE_TYPE(enc) == G_TYPE_STRING)
+ if (G_VALUE_TYPE(genc) == G_TYPE_STRING)
{
- gchar *str = ghb_value_string(enc);
- for (ii = 0; ii < len; ii++)
+ gchar *str = ghb_value_string(genc);
+ for (enc = hb_video_encoder_get_next(NULL); enc != NULL;
+ enc = hb_video_encoder_get_next(enc))
{
- if (strcmp(encoders[ii].human_readable_name, str) == 0 ||
- strcmp(encoders[ii].short_name, str) == 0)
+ if (strcmp(enc->name, str) == 0 ||
+ strcmp(enc->short_name, str) == 0)
{
g_free(str);
- return encoders[ii].short_name;
+ return enc;
}
}
g_free(str);
}
- else if (G_VALUE_TYPE(enc) == G_TYPE_INT ||
- G_VALUE_TYPE(enc) == G_TYPE_INT64 ||
- G_VALUE_TYPE(enc) == G_TYPE_DOUBLE)
+ else if (G_VALUE_TYPE(genc) == G_TYPE_INT ||
+ G_VALUE_TYPE(genc) == G_TYPE_INT64 ||
+ G_VALUE_TYPE(genc) == G_TYPE_DOUBLE)
{
- int val = ghb_value_int(enc);
- for (ii = 0; ii < len; ii++)
- {
- if (encoders[ii].encoder == val)
- {
- return encoders[ii].short_name;
- }
- }
+ return lookup_video_encoder_by_int(ghb_value_int(genc));
}
+ return NULL;
+}
+
+static gint
+lookup_audio_encoder_int(const GValue *genc)
+{
+ const hb_encoder_t *enc = lookup_audio_encoder(genc);
+ if (enc != NULL)
+ return enc->codec;
return 0;
}
static gint
-lookup_audio_lang_int(const GValue *rate)
+lookup_video_encoder_int(const GValue *genc)
+{
+ const hb_encoder_t *enc = lookup_video_encoder(genc);
+ if (enc != NULL)
+ return enc->codec;
+ return 0;
+}
+
+static const gchar*
+lookup_audio_encoder_option(const GValue *genc)
+{
+ const hb_encoder_t *enc = lookup_audio_encoder(genc);
+ if (enc != NULL)
+ return enc->name;
+ return NULL;
+}
+
+static const gchar*
+lookup_video_encoder_option(const GValue *genc)
+{
+ const hb_encoder_t *enc = lookup_video_encoder(genc);
+ if (enc != NULL)
+ return enc->name;
+ return NULL;
+}
+
+static const gchar*
+lookup_audio_encoder_string(const GValue *genc)
+{
+ const hb_encoder_t *enc = lookup_audio_encoder(genc);
+ if (enc != NULL)
+ return enc->short_name;
+ return NULL;
+}
+
+static const gchar*
+lookup_video_encoder_string(const GValue *genc)
+{
+ const hb_encoder_t *enc = lookup_video_encoder(genc);
+ if (enc != NULL)
+ return enc->short_name;
+ return NULL;
+}
+
+static int
+lookup_audio_lang(const GValue *glang)
{
gint ii;
gchar *str;
- gint result = 0;
- // Coincidentally, the string "source" will return 0
- // which is our flag to use "same as source"
- str = ghb_value_string(rate);
+ str = ghb_value_string(glang);
for (ii = 0; ii < LANG_TABLE_SIZE; ii++)
{
if (strcmp(ghb_language_table[ii].iso639_2, str) == 0)
{
- result = ii;
- break;
+ g_free(str);
+ return ii;
}
}
g_free(str);
- return result;
+ return -1;
}
-static const gchar*
-lookup_audio_lang_option(const GValue *rate)
+static int
+lookup_audio_lang_int(const GValue *glang)
{
- gint ii;
- gchar *str;
- const gchar *result = "Same as source";
+ gint ii = lookup_audio_lang(glang);
+ if (ii >= 0)
+ return ii;
+ return 0;
+}
- // Coincidentally, the string "source" will return 0
- // which is our flag to use "same as source"
- str = ghb_value_string(rate);
- for (ii = 0; ii < LANG_TABLE_SIZE; ii++)
+static const gchar*
+lookup_audio_lang_option(const GValue *glang)
+{
+ gint ii = lookup_audio_lang(glang);
+ if (ii >= 0)
{
- if (strcmp(ghb_language_table[ii].iso639_2, str) == 0)
- {
- if (ghb_language_table[ii].native_name[0] != 0)
- result = ghb_language_table[ii].native_name;
- else
- result = ghb_language_table[ii].eng_name;
- break;
- }
+ if (ghb_language_table[ii].native_name[0] != 0)
+ return ghb_language_table[ii].native_name;
+ else
+ return ghb_language_table[ii].eng_name;
}
- g_free(str);
- return result;
+ return "Same as source";
}
GValue*
-ghb_lookup_acodec_value(gint val)
+ghb_lookup_audio_encoder_value(gint ienc)
{
- GValue *value = NULL;
- gint ii;
+ const hb_encoder_t *enc = lookup_audio_encoder_by_int(ienc);
+ if (enc != NULL)
+ return ghb_string_value_new(enc->short_name);
+ return ghb_string_value_new("copy");
+}
- for (ii = 0; ii < hb_audio_encoders_count; ii++)
+static GValue*
+lookup_mixdown_value(gint imix)
+{
+ const hb_mixdown_t *mix = lookup_mixdown_by_int(imix);
+ if (mix != NULL)
+ return ghb_string_value_new(mix->short_name);
+ return NULL;
+}
+static const hb_container_t *
+lookup_container_by_int(int imux)
+{
+ const hb_container_t *mux;
+ for (mux = hb_container_get_next(NULL); mux != NULL;
+ mux = hb_container_get_next(mux))
{
- if ((int)hb_audio_encoders[ii].encoder == val)
+ if (mux->format == imux)
{
- value = ghb_string_value_new(hb_audio_encoders[ii].short_name);
- return value;
+ return mux;
}
}
- value = ghb_string_value_new("copy");
- return value;
+ return NULL;
}
-static GValue*
-get_amix_value(gint val)
+static const hb_container_t *
+lookup_container(const GValue *gmux)
{
- GValue *value = NULL;
- gint ii;
+ const hb_container_t *mux;
- for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
+ if (G_VALUE_TYPE(gmux) == G_TYPE_STRING)
{
- if (hb_audio_mixdowns[ii].amixdown == val)
+ gchar *str = ghb_value_string(gmux);
+ for (mux = hb_container_get_next(NULL); mux != NULL;
+ mux = hb_container_get_next(mux))
{
- value = ghb_string_value_new(hb_audio_mixdowns[ii].short_name);
- break;
+ if (strcmp(mux->name, str) == 0 ||
+ strcmp(mux->short_name, str) == 0)
+ {
+ g_free(str);
+ return mux;
+ }
}
+ g_free(str);
+ }
+ else if (G_VALUE_TYPE(gmux) == G_TYPE_INT ||
+ G_VALUE_TYPE(gmux) == G_TYPE_INT64 ||
+ G_VALUE_TYPE(gmux) == G_TYPE_DOUBLE)
+ {
+ return lookup_container_by_int(ghb_value_int(gmux));
}
- return value;
+ return NULL;
+}
+
+static gint
+lookup_container_int(const GValue *gmux)
+{
+ const hb_container_t *mux = lookup_container(gmux);
+ if (mux != NULL)
+ return mux->format;
+ return 0;
+}
+
+static const gchar*
+lookup_container_option(const GValue *gmux)
+{
+ const hb_container_t *mux = lookup_container(gmux);
+ if (mux != NULL)
+ return mux->name;
+ return 0;
+}
+
+static const gchar*
+lookup_container_string(const GValue *gmux)
+{
+ const hb_container_t *mux = lookup_container(gmux);
+ if (mux != NULL)
+ return mux->short_name;
+ return 0;
}
// Handle for libhb. Gets set by ghb_backend_init()
static void
grey_mix_opts(signal_user_data_t *ud, gint acodec, gint64 layout)
{
- gint ii;
-
g_debug("grey_mix_opts()\n");
- for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
+
+ const hb_mixdown_t *mix;
+ for (mix = hb_mixdown_get_next(NULL); mix != NULL;
+ mix = hb_mixdown_get_next(mix))
{
- grey_combo_box_item(ud->builder, "AudioMixdown",
- hb_audio_mixdowns[ii].amixdown,
- !hb_mixdown_is_supported(hb_audio_mixdowns[ii].amixdown,
- acodec, layout));
+ grey_combo_box_item(ud->builder, "AudioMixdown", mix->amixdown,
+ !hb_mixdown_is_supported(mix->amixdown, acodec, layout));
}
}
gint mux, track, titleindex, acodec, fallback;
hb_audio_config_t *aconfig = NULL;
GValue *gval;
- int ii;
widget = GHB_WIDGET (ud->builder, "title");
gval = ghb_widget_value(widget);
ghb_value_free(gval);
grey_combo_box_item(ud->builder, "x264_analyse", 4, TRUE);
- for (ii = 0; ii < hb_audio_encoders_count; ii++)
+
+ const hb_encoder_t *enc;
+ for (enc = hb_audio_encoder_get_next(NULL); enc != NULL;
+ enc = hb_audio_encoder_get_next(enc))
{
- if (!(mux & hb_audio_encoders[ii].muxers))
+ if (!(mux & enc->muxers))
{
grey_combo_box_item(ud->builder, "AudioEncoder",
- hb_audio_encoders[ii].encoder, TRUE);
+ enc->codec, TRUE);
grey_combo_box_item(ud->builder, "AudioEncoderFallback",
- hb_audio_encoders[ii].encoder, TRUE);
+ enc->codec, TRUE);
}
else
{
grey_combo_box_item(ud->builder, "AudioEncoder",
- hb_audio_encoders[ii].encoder, FALSE);
+ enc->codec, FALSE);
grey_combo_box_item(ud->builder, "AudioEncoderFallback",
- hb_audio_encoders[ii].encoder, FALSE);
+ enc->codec, FALSE);
}
}
- for (ii = 0; ii < hb_video_encoders_count; ii++)
+ for (enc = hb_video_encoder_get_next(NULL); enc != NULL;
+ enc = hb_video_encoder_get_next(enc))
{
- if (!(mux & hb_video_encoders[ii].muxers))
+ if (!(mux & enc->muxers))
{
grey_combo_box_item(ud->builder, "VideoEncoder",
- hb_video_encoders[ii].encoder, TRUE);
+ enc->codec, TRUE);
}
else
{
grey_combo_box_item(ud->builder, "VideoEncoder",
- hb_video_encoders[ii].encoder, FALSE);
+ enc->codec, FALSE);
}
}
layout = aconfig ? aconfig->in.channel_layout : AV_CH_LAYOUT_5POINT1;
if (mix == HB_AMIXDOWN_NONE)
- mix = hb_audio_mixdowns[hb_audio_mixdowns_count-1].amixdown;
+ mix = HB_INVALID_AMIXDOWN;
- return hb_get_best_mixdown( acodec, layout, mix );
+ return hb_mixdown_get_best( acodec, layout, mix );
}
// Set up the model for the combo box
}
static void
-audio_samplerate_opts_set(GtkBuilder *builder, const gchar *name, hb_rate_t *rates, gint count)
+audio_samplerate_opts_set(GtkBuilder *builder, const gchar *name)
{
GtkTreeIter iter;
GtkListStore *store;
- gint ii;
gchar *str;
g_debug("audio_samplerate_opts_set ()\n");
3, 0.0,
4, "source",
-1);
- for (ii = 0; ii < count; ii++)
+
+ const hb_rate_t *rate;
+ for (rate = hb_audio_samplerate_get_next(NULL); rate != NULL;
+ rate = hb_audio_samplerate_get_next(rate))
{
gtk_list_store_append(store, &iter);
- str = g_strdup_printf("<small>%s</small>", rates[ii].string);
+ str = g_strdup_printf("<small>%s</small>", rate->name);
gtk_list_store_set(store, &iter,
0, str,
1, TRUE,
- 2, rates[ii].string,
- 3, (gdouble)rates[ii].rate,
- 4, rates[ii].string,
+ 2, rate->name,
+ 3, (gdouble)rate->rate,
+ 4, rate->name,
-1);
g_free(str);
}
}
static void
-video_rate_opts_set(GtkBuilder *builder, const gchar *name, hb_rate_t *rates, gint count)
+video_framerate_opts_set(GtkBuilder *builder, const gchar *name)
{
GtkTreeIter iter;
GtkListStore *store;
- gint ii;
- g_debug("video_rate_opts_set ()\n");
+ g_debug("video_framerate_opts_set ()\n");
store = get_combo_box_store(builder, name);
gtk_list_store_clear(store);
// Add an item for "Same As Source"
3, 0.0,
4, "source",
-1);
- for (ii = 0; ii < count; ii++)
+
+ const hb_rate_t *rate;
+ for (rate = hb_video_framerate_get_next(NULL); rate != NULL;
+ rate = hb_video_framerate_get_next(rate))
{
gchar *desc = "";
gchar *option;
- if (strcmp(rates[ii].string, "23.976") == 0)
+ if (strcmp(rate->name, "23.976") == 0)
{
desc = "(NTSC Film)";
}
- else if (strcmp(rates[ii].string, "25") == 0)
+ else if (strcmp(rate->name, "25") == 0)
{
desc = "(PAL Film/Video)";
}
- else if (strcmp(rates[ii].string, "29.97") == 0)
+ else if (strcmp(rate->name, "29.97") == 0)
{
desc = "(NTSC Video)";
}
- option = g_strdup_printf ("%s %s", rates[ii].string, desc);
+ option = g_strdup_printf ("%s %s", rate->name, desc);
gtk_list_store_append(store, &iter);
gtk_list_store_set(store, &iter,
0, option,
1, TRUE,
- 2, rates[ii].string,
- 3, (gdouble)rates[ii].rate,
- 4, rates[ii].string,
+ 2, rate->name,
+ 3, (gdouble)rate->rate,
+ 4, rate->name,
-1);
g_free(option);
}
}
static void
-hb_encoder_opts_set_with_mask(
+video_encoder_opts_set(
+ GtkBuilder *builder,
+ const gchar *name)
+{
+ GtkTreeIter iter;
+ GtkListStore *store;
+ gchar *str;
+
+ g_debug("video_encoder_opts_set ()\n");
+ store = get_combo_box_store(builder, name);
+ gtk_list_store_clear(store);
+
+ const hb_encoder_t *enc;
+ for (enc = hb_video_encoder_get_next(NULL); enc != NULL;
+ enc = hb_video_encoder_get_next(enc))
+ {
+ gtk_list_store_append(store, &iter);
+ str = g_strdup_printf("<small>%s</small>", enc->name);
+ gtk_list_store_set(store, &iter,
+ 0, str,
+ 1, TRUE,
+ 2, enc->short_name,
+ 3, (gdouble)enc->codec,
+ 4, enc->short_name,
+ -1);
+ g_free(str);
+ }
+}
+
+static void
+audio_encoder_opts_set_with_mask(
GtkBuilder *builder,
const gchar *name,
- hb_encoder_t *encoders,
- int len,
int mask,
int neg_mask)
{
GtkTreeIter iter;
GtkListStore *store;
- gint ii;
gchar *str;
- g_debug("hb_encoder_opts_set ()\n");
+ g_debug("audio_encoder_opts_set ()\n");
store = get_combo_box_store(builder, name);
gtk_list_store_clear(store);
- for (ii = 0; ii < len; ii++)
+
+ const hb_encoder_t *enc;
+ for (enc = hb_audio_encoder_get_next(NULL); enc != NULL;
+ enc = hb_audio_encoder_get_next(enc))
{
- if ((mask & encoders[ii].encoder) &&
- !(neg_mask & encoders[ii].encoder))
+ if ((mask & enc->codec) && !(neg_mask & enc->codec))
{
gtk_list_store_append(store, &iter);
- str = g_strdup_printf("<small>%s</small>",
- encoders[ii].human_readable_name);
+ str = g_strdup_printf("<small>%s</small>", enc->name);
gtk_list_store_set(store, &iter,
0, str,
1, TRUE,
- 2, encoders[ii].short_name,
- 3, (gdouble)encoders[ii].encoder,
- 4, encoders[ii].short_name,
+ 2, enc->short_name,
+ 3, (gdouble)enc->codec,
+ 4, enc->short_name,
-1);
g_free(str);
}
}
static void
-hb_encoder_opts_set(
+audio_encoder_opts_set(
GtkBuilder *builder,
- const gchar *name,
- hb_encoder_t *encoders,
- int len)
+ const gchar *name)
{
- hb_encoder_opts_set_with_mask(builder, name, encoders, len, ~0, 0);
+ audio_encoder_opts_set_with_mask(builder, name, ~0, 0);
}
static void
acodec_fallback_opts_set(GtkBuilder *builder, const gchar *name)
{
- hb_encoder_opts_set_with_mask(builder, name, hb_audio_encoders,
- hb_audio_encoders_count, ~0, HB_ACODEC_PASS_FLAG);
+ audio_encoder_opts_set_with_mask(builder, name, ~0, HB_ACODEC_PASS_FLAG);
}
static void
{
GtkTreeIter iter;
GtkListStore *store;
- gint ii;
gchar *str;
g_debug("mix_opts_set ()\n");
store = get_combo_box_store(builder, name);
gtk_list_store_clear(store);
- for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
+
+ const hb_mixdown_t *mix;
+ for (mix = hb_mixdown_get_next(NULL); mix != NULL;
+ mix = hb_mixdown_get_next(mix))
{
gtk_list_store_append(store, &iter);
- str = g_strdup_printf("<small>%s</small>",
- hb_audio_mixdowns[ii].human_readable_name);
+ str = g_strdup_printf("<small>%s</small>", mix->name);
gtk_list_store_set(store, &iter,
0, str,
1, TRUE,
- 2, hb_audio_mixdowns[ii].short_name,
- 3, (gdouble)hb_audio_mixdowns[ii].amixdown,
- 4, hb_audio_mixdowns[ii].internal_name,
+ 2, mix->short_name,
+ 3, (gdouble)mix->amixdown,
+ 4, mix->internal_name,
+ -1);
+ g_free(str);
+ }
+}
+
+static void
+container_opts_set(
+ GtkBuilder *builder,
+ const gchar *name)
+{
+ GtkTreeIter iter;
+ GtkListStore *store;
+ gchar *str;
+
+ g_debug("hb_container_opts_set ()\n");
+ store = get_combo_box_store(builder, name);
+ gtk_list_store_clear(store);
+
+ const hb_container_t *mux;
+ for (mux = hb_container_get_next(NULL); mux != NULL;
+ mux = hb_container_get_next(mux))
+ {
+ gtk_list_store_append(store, &iter);
+ str = g_strdup_printf("<small>%s</small>", mux->name);
+ gtk_list_store_set(store, &iter,
+ 0, str,
+ 1, TRUE,
+ 2, mux->short_name,
+ 3, (gdouble)mux->format,
+ 4, mux->short_name,
-1);
g_free(str);
}
if (strcmp(name, "AudioBitrate") == 0)
return lookup_audio_bitrate_int(gval);
else if (strcmp(name, "AudioSamplerate") == 0)
- return lookup_audio_rate_int(gval);
+ return lookup_audio_samplerate_int(gval);
else if (strcmp(name, "VideoFramerate") == 0)
- return lookup_video_rate_int(gval);
+ return lookup_video_framerate_int(gval);
else if (strcmp(name, "AudioMixdown") == 0)
- return lookup_mix_int(gval);
+ return lookup_mixdown_int(gval);
else if (strcmp(name, "SrtLanguage") == 0)
return lookup_audio_lang_int(gval);
else if (strcmp(name, "PreferredLanguage") == 0)
return lookup_audio_lang_int(gval);
else if (strcmp(name, "VideoEncoder") == 0)
- return lookup_hb_encoder_int(gval, hb_video_encoders, hb_video_encoders_count);
+ return lookup_video_encoder_int(gval);
else if (strcmp(name, "AudioEncoder") == 0)
- return lookup_hb_encoder_int(gval, hb_audio_encoders, hb_audio_encoders_count);
+ return lookup_audio_encoder_int(gval);
else if (strcmp(name, "AudioEncoderFallback") == 0)
- return lookup_hb_encoder_int(gval, hb_audio_encoders, hb_audio_encoders_count);
+ return lookup_audio_encoder_int(gval);
else if (strcmp(name, "AudioEncoderActual") == 0)
- return lookup_hb_encoder_int(gval, hb_audio_encoders, hb_audio_encoders_count);
+ return lookup_audio_encoder_int(gval);
+ else if (strcmp(name, "FileFormat") == 0)
+ return lookup_container_int(gval);
else
{
return lookup_generic_int(find_combo_table(name), gval);
if (strcmp(name, "AudioBitrate") == 0)
return lookup_audio_bitrate_int(gval);
else if (strcmp(name, "AudioSamplerate") == 0)
- return lookup_audio_rate_int(gval);
+ return lookup_audio_samplerate_int(gval);
else if (strcmp(name, "VideoFramerate") == 0)
- return lookup_video_rate_int(gval);
+ return lookup_video_framerate_int(gval);
else if (strcmp(name, "AudioMixdown") == 0)
- return lookup_mix_int(gval);
+ return lookup_mixdown_int(gval);
else if (strcmp(name, "SrtLanguage") == 0)
return lookup_audio_lang_int(gval);
else if (strcmp(name, "PreferredLanguage") == 0)
return lookup_audio_lang_int(gval);
else if (strcmp(name, "VideoEncoder") == 0)
- return lookup_hb_encoder_int(gval, hb_video_encoders, hb_video_encoders_count);
+ return lookup_video_encoder_int(gval);
else if (strcmp(name, "AudioEncoder") == 0)
- return lookup_hb_encoder_int(gval, hb_audio_encoders, hb_audio_encoders_count);
+ return lookup_audio_encoder_int(gval);
else if (strcmp(name, "AudioEncoderFallback") == 0)
- return lookup_hb_encoder_int(gval, hb_audio_encoders, hb_audio_encoders_count);
+ return lookup_audio_encoder_int(gval);
else if (strcmp(name, "AudioEncoderActual") == 0)
- return lookup_hb_encoder_int(gval, hb_audio_encoders, hb_audio_encoders_count);
+ return lookup_audio_encoder_int(gval);
+ else if (strcmp(name, "FileFormat") == 0)
+ return lookup_container_int(gval);
else
{
return lookup_generic_double(find_combo_table(name), gval);
if (strcmp(name, "AudioBitrate") == 0)
return lookup_audio_bitrate_option(gval);
else if (strcmp(name, "AudioSamplerate") == 0)
- return lookup_audio_rate_option(gval);
+ return lookup_audio_samplerate_option(gval);
else if (strcmp(name, "VideoFramerate") == 0)
- return lookup_video_rate_option(gval);
+ return lookup_video_framerate_option(gval);
else if (strcmp(name, "AudioMixdown") == 0)
- return lookup_mix_option(gval);
+ return lookup_mixdown_option(gval);
else if (strcmp(name, "SrtLanguage") == 0)
return lookup_audio_lang_option(gval);
else if (strcmp(name, "PreferredLanguage") == 0)
return lookup_audio_lang_option(gval);
else if (strcmp(name, "VideoEncoder") == 0)
- return lookup_hb_encoder_option(gval, hb_video_encoders, hb_video_encoders_count);
+ return lookup_video_encoder_option(gval);
else if (strcmp(name, "AudioEncoder") == 0)
- return lookup_hb_encoder_option(gval, hb_audio_encoders, hb_audio_encoders_count);
+ return lookup_audio_encoder_option(gval);
else if (strcmp(name, "AudioEncoderFallback") == 0)
- return lookup_hb_encoder_option(gval, hb_audio_encoders, hb_audio_encoders_count);
+ return lookup_audio_encoder_option(gval);
else if (strcmp(name, "AudioEncoderActual") == 0)
- return lookup_hb_encoder_option(gval, hb_audio_encoders, hb_audio_encoders_count);
+ return lookup_audio_encoder_option(gval);
+ else if (strcmp(name, "FileFormat") == 0)
+ return lookup_container_option(gval);
else
{
return lookup_generic_option(find_combo_table(name), gval);
if (strcmp(name, "AudioBitrate") == 0)
return lookup_audio_bitrate_option(gval);
else if (strcmp(name, "AudioSamplerate") == 0)
- return lookup_audio_rate_string(gval);
+ return lookup_audio_samplerate_string(gval);
else if (strcmp(name, "VideoFramerate") == 0)
- return lookup_video_rate_option(gval);
+ return lookup_video_framerate_option(gval);
else if (strcmp(name, "AudioMixdown") == 0)
- return lookup_mix_string(gval);
+ return lookup_mixdown_string(gval);
else if (strcmp(name, "SrtLanguage") == 0)
return lookup_audio_lang_option(gval);
else if (strcmp(name, "PreferredLanguage") == 0)
return lookup_audio_lang_option(gval);
else if (strcmp(name, "VideoEncoder") == 0)
- return lookup_hb_encoder_string(gval, hb_video_encoders, hb_video_encoders_count);
+ return lookup_video_encoder_string(gval);
else if (strcmp(name, "AudioEncoder") == 0)
- return lookup_hb_encoder_string(gval, hb_audio_encoders, hb_audio_encoders_count);
+ return lookup_audio_encoder_string(gval);
else if (strcmp(name, "AudioEncoderFallback") == 0)
- return lookup_hb_encoder_string(gval, hb_audio_encoders, hb_audio_encoders_count);
+ return lookup_audio_encoder_string(gval);
else if (strcmp(name, "AudioEncoderActual") == 0)
- return lookup_hb_encoder_string(gval, hb_audio_encoders, hb_audio_encoders_count);
+ return lookup_audio_encoder_string(gval);
+ else if (strcmp(name, "FileFormat") == 0)
+ return lookup_container_string(gval);
else
{
return lookup_generic_string(find_combo_table(name), gval);
if (all)
{
audio_bitrate_opts_set(ud->builder, "AudioBitrate");
- audio_samplerate_opts_set(ud->builder, "AudioSamplerate", hb_audio_rates, hb_audio_rates_count);
- video_rate_opts_set(ud->builder, "VideoFramerate", hb_video_rates, hb_video_rates_count);
+ audio_samplerate_opts_set(ud->builder, "AudioSamplerate");
+ video_framerate_opts_set(ud->builder, "VideoFramerate");
mix_opts_set(ud->builder, "AudioMixdown");
- hb_encoder_opts_set(ud->builder, "VideoEncoder", hb_video_encoders, hb_video_encoders_count);
- hb_encoder_opts_set(ud->builder, "AudioEncoder", hb_audio_encoders, hb_audio_encoders_count);
+ video_encoder_opts_set(ud->builder, "VideoEncoder");
+ audio_encoder_opts_set(ud->builder, "AudioEncoder");
acodec_fallback_opts_set(ud->builder, "AudioEncoderFallback");
language_opts_set(ud->builder, "SrtLanguage");
language_opts_set(ud->builder, "PreferredLanguage");
generic_opts_set(ud->builder, "LoggingLevel", &logging_opts);
generic_opts_set(ud->builder, "LogLongevity", &log_longevity_opts);
generic_opts_set(ud->builder, "check_updates", &appcast_update_opts);
- generic_opts_set(ud->builder, "FileFormat", &container_opts);
generic_opts_set(ud->builder, "PictureDeinterlace", &deint_opts);
generic_opts_set(ud->builder, "PictureDetelecine", &detel_opts);
generic_opts_set(ud->builder, "PictureDecomb", &decomb_opts);
x264_tune_opts_set(ud->builder, "x264Tune");
h264_profile_opts_set(ud->builder, "h264Profile");
h264_level_opts_set(ud->builder, "h264Level");
+ container_opts_set(ud->builder, "FileFormat");
}
else
{
if (strcmp(name, "AudioBitrate") == 0)
audio_bitrate_opts_set(ud->builder, "AudioBitrate");
else if (strcmp(name, "AudioSamplerate") == 0)
- audio_samplerate_opts_set(ud->builder, "AudioSamplerate", hb_audio_rates, hb_audio_rates_count);
+ audio_samplerate_opts_set(ud->builder, "AudioSamplerate");
else if (strcmp(name, "VideoFramerate") == 0)
- video_rate_opts_set(ud->builder, "VideoFramerate", hb_video_rates, hb_video_rates_count);
+ video_framerate_opts_set(ud->builder, "VideoFramerate");
else if (strcmp(name, "AudioMixdown") == 0)
mix_opts_set(ud->builder, "AudioMixdown");
else if (strcmp(name, "VideoEncoder") == 0)
- hb_encoder_opts_set(ud->builder, "VideoEncoder", hb_video_encoders, hb_video_encoders_count);
+ video_encoder_opts_set(ud->builder, "VideoEncoder");
else if (strcmp(name, "AudioEncoder") == 0)
- hb_encoder_opts_set(ud->builder, "AudioEncoder", hb_audio_encoders, hb_audio_encoders_count);
+ audio_encoder_opts_set(ud->builder, "AudioEncoder");
else if (strcmp(name, "AudioEncoderFallback") == 0)
acodec_fallback_opts_set(ud->builder, "AudioEncoderFallback");
else if (strcmp(name, "SrtLanguage") == 0)
h264_profile_opts_set(ud->builder, "h264Profile");
else if (strcmp(name, "h264Level") == 0)
h264_level_opts_set(ud->builder, "h264Level");
+ else if (strcmp(name, "FileFormat") == 0)
+ container_opts_set(ud->builder, "FileFormat");
else
generic_opts_set(ud->builder, name, find_combo_table(name));
}
init_combo_box(builder, "x264Tune");
init_combo_box(builder, "h264Profile");
init_combo_box(builder, "h264Level");
+ init_combo_box(builder, "FileFormat");
for (ii = 0; combo_name_map[ii].name != NULL; ii++)
{
init_combo_box(builder, combo_name_map[ii].name);
if (rate >= 0 && rate < 8) return;
- if (ghb_audio_bitrates[hb_audio_bitrates_count].string)
+ if (ghb_audio_bitrates[ghb_abr_count].name)
{
- g_free((char*)ghb_audio_bitrates[hb_audio_bitrates_count].string);
+ g_free((char*)ghb_audio_bitrates[ghb_abr_count].name);
}
- ghb_audio_bitrates[hb_audio_bitrates_count].rate = rate;
+ ghb_audio_bitrates[ghb_abr_count].rate = rate;
if (rate < 0)
{
- ghb_audio_bitrates[hb_audio_bitrates_count].string =
- g_strdup_printf("N/A");
+ ghb_audio_bitrates[ghb_abr_count].name = g_strdup_printf("N/A");
}
else
{
- ghb_audio_bitrates[hb_audio_bitrates_count].string =
- g_strdup_printf("%d", rate);
+ ghb_audio_bitrates[ghb_abr_count].name = g_strdup_printf("%d", rate);
}
- ghb_audio_bitrates_count = hb_audio_bitrates_count + 1;
+ ghb_audio_bitrates_count = ghb_abr_count + 1;
store = get_combo_box_store(builder, name);
if (!find_combo_item_by_int(GTK_TREE_MODEL(store), rate, &iter))
{
str = g_strdup_printf ("<small>%s</small>",
- ghb_audio_bitrates[hb_audio_bitrates_count].string);
+ ghb_audio_bitrates[ghb_abr_count].name);
gtk_list_store_append(store, &iter);
gtk_list_store_set(store, &iter,
0, str,
1, TRUE,
- 2, ghb_audio_bitrates[hb_audio_bitrates_count].string,
+ 2, ghb_audio_bitrates[ghb_abr_count].name,
3, (gdouble)rate,
- 4, ghb_audio_bitrates[hb_audio_bitrates_count].string,
+ 4, ghb_audio_bitrates[ghb_abr_count].name,
-1);
g_free(str);
}
guint last = (guint)last_rate;
guint first = (guint)first_rate;
- ghb_audio_bitrates_count = hb_audio_bitrates_count;
+ ghb_audio_bitrates_count = ghb_abr_count;
g_debug("audio_bitrate_opts_clean ()\n");
store = get_combo_box_store(builder, name);
{
GtkTreeIter iter;
GtkListStore *store;
- gint ii;
+ gint count = 0;
gchar *str;
+ int ii;
- ghb_audio_bitrates_count = hb_audio_bitrates_count;
- ghb_audio_bitrates = calloc(hb_audio_bitrates_count+1, sizeof(hb_rate_t));
+ const hb_rate_t *rate;
- for (ii = 0; ii < hb_audio_bitrates_count; ii++)
+ if (ghb_audio_bitrates == NULL)
{
- ghb_audio_bitrates[ii] = hb_audio_bitrates[ii];
+ // Count rates
+ for (rate = hb_audio_bitrate_get_next(NULL); rate != NULL;
+ rate = hb_audio_bitrate_get_next(rate))
+ {
+ count++;
+ }
+
+ ghb_audio_bitrates_count = ghb_abr_count = count;
+ ghb_audio_bitrates = calloc(count+1, sizeof(hb_rate_t));
+
+ for (ii = 0, rate = hb_audio_bitrate_get_next(NULL); rate != NULL;
+ ii++, rate = hb_audio_bitrate_get_next(rate))
+ {
+ ghb_audio_bitrates[ii] = *rate;
+ }
}
g_debug("audio_bitrate_opts_set ()\n");
{
gtk_list_store_append(store, &iter);
str = g_strdup_printf ("<small>%s</small>",
- ghb_audio_bitrates[ii].string);
+ ghb_audio_bitrates[ii].name);
gtk_list_store_set(store, &iter,
0, str,
1, TRUE,
- 2, ghb_audio_bitrates[ii].string,
+ 2, ghb_audio_bitrates[ii].name,
3, (gdouble)ghb_audio_bitrates[ii].rate,
- 4, ghb_audio_bitrates[ii].string,
+ 4, ghb_audio_bitrates[ii].name,
-1);
g_free(str);
}
{
codec = HB_ACODEC_FAAC;
}
- value = ghb_lookup_acodec_value(codec);
+ value = ghb_lookup_audio_encoder_value(codec);
ghb_settings_take_value(asettings, "AudioEncoder", value);
}
gchar *a_unsup = NULL;
return FALSE;
}
g_free(message);
- value = ghb_lookup_acodec_value(codec);
+ value = ghb_lookup_audio_encoder_value(codec);
ghb_settings_take_value(asettings, "AudioEncoder", value);
}
gint mix = ghb_settings_combo_int (asettings, "AudioMixdown");
- gint jj;
const gchar *mix_unsup = NULL;
if (!hb_mixdown_is_supported(mix, codec, aconfig->in.channel_layout))
{
- for (jj = 0; jj < hb_audio_mixdowns_count; jj++)
- {
- if (mix == hb_audio_mixdowns[jj].amixdown)
- {
- {
- mix_unsup = hb_audio_mixdowns[jj].human_readable_name;
- }
- }
- }
+ const hb_mixdown_t *hb_mix = lookup_mixdown_by_int(mix);
+ if (hb_mix != NULL)
+ mix_unsup = hb_mix->name;
}
if (mix_unsup)
{
}
g_free(message);
mix = ghb_get_best_mix(aconfig, codec, mix);
- value = get_amix_value(mix);
+ value = lookup_mixdown_value(mix);
ghb_settings_take_value(asettings, "AudioMixdown", value);
}
}
audio.out.bitrate =
ghb_settings_combo_int(asettings, "AudioBitrate");
- audio.out.bitrate = hb_get_best_audio_bitrate(
+ audio.out.bitrate = hb_audio_bitrate_get_best(
audio.out.codec, audio.out.bitrate,
audio.out.samplerate, audio.out.mixdown);
}
const gchar* ghb_lookup_combo_option(const gchar *name, const GValue *gval);
const gchar* ghb_lookup_combo_string(const gchar *name, const GValue *gval);
gchar* ghb_get_tmp_dir();
-gint ghb_find_closest_audio_rate(gint rate);
-GValue* ghb_lookup_acodec_value(gint val);
+gint ghb_find_closest_audio_samplerate(gint rate);
+GValue* ghb_lookup_audio_encoder_value(gint val);
#endif // _HBBACKEND_H_
static value_map_t *acodec_xlat;
-static value_map_t * create_encoder_xlat_tbl(value_map_t *compat, hb_encoder_t *enc, int size)
+static value_map_t * create_video_encoder_xlat_tbl(value_map_t *compat)
{
value_map_t *out;
- int cc, ii;
+ int cc, ii, size = 0;
for (cc = 0; compat[cc].mac_val != NULL; cc++);
+ const hb_encoder_t *enc;
+ for (enc = hb_video_encoder_get_next(NULL); enc != NULL;
+ enc = hb_video_encoder_get_next(enc))
+ {
+ size++;
+ }
out = calloc(cc + size + 1, sizeof(value_map_t));
- for (ii = 0; ii < size; ii++)
+ for (ii = 0, enc = hb_video_encoder_get_next(NULL); enc != NULL;
+ ii++, enc = hb_video_encoder_get_next(enc))
{
- out[ii].mac_val = enc[ii].human_readable_name;
- out[ii].lin_val = enc[ii].short_name;
+ out[ii].mac_val = enc->name;
+ out[ii].lin_val = enc->short_name;
}
for (ii = 0; ii < cc; ii++)
return out;
}
-static value_map_t * create_mix_xlat_tbl(value_map_t *compat, hb_mixdown_t * mix, int size)
+static value_map_t * create_audio_encoder_xlat_tbl(value_map_t *compat)
{
value_map_t *out;
- int cc, ii;
+ int cc, ii, size = 0;
for (cc = 0; compat[cc].mac_val != NULL; cc++);
-
+
+ const hb_encoder_t *enc;
+ for (enc = hb_audio_encoder_get_next(NULL); enc != NULL;
+ enc = hb_audio_encoder_get_next(enc))
+ {
+ size++;
+ }
out = calloc(cc + size + 1, sizeof(value_map_t));
- for (ii = 0; ii < size; ii++)
+ for (ii = 0, enc = hb_audio_encoder_get_next(NULL); enc != NULL;
+ ii++, enc = hb_audio_encoder_get_next(enc))
{
- out[ii].mac_val = mix[ii].human_readable_name;
- out[ii].lin_val = mix[ii].short_name;
+ out[ii].mac_val = enc->name;
+ out[ii].lin_val = enc->short_name;
}
for (ii = 0; ii < cc; ii++)
return out;
}
-value_map_t container_xlat[] =
+static value_map_t * create_mix_xlat_tbl(value_map_t *compat)
{
- {"MP4 file", "mp4"},
- {"M4V file", "mp4"},
- {"MKV file", "mkv"},
- {"AVI file", "mkv"},
- {"OGM file", "mkv"},
- {NULL, NULL}
-};
+ value_map_t *out;
+ int cc, ii, size = 0;;
+
+ for (cc = 0; compat[cc].mac_val != NULL; cc++);
+
+ const hb_mixdown_t *mix;
+ for (mix = hb_mixdown_get_next(NULL); mix != NULL;
+ mix = hb_mixdown_get_next(mix))
+ {
+ size++;
+ }
+ out = calloc(cc + size + 1, sizeof(value_map_t));
+
+ for (ii = 0, mix = hb_mixdown_get_next(NULL); mix != NULL;
+ ii++, mix = hb_mixdown_get_next(mix))
+ {
+ out[ii].mac_val = mix->name;
+ out[ii].lin_val = mix->short_name;
+ }
+
+ for (ii = 0; ii < cc; ii++)
+ out[ii+size] = compat[ii];
+
+ return out;
+}
value_map_t framerate_xlat[] =
{
return NULL;
}
+static GValue*
+export_value_xlat_container(GValue *lin_val)
+{
+ GValue *sval = NULL;
+ gchar *str;
+ const gchar *mux;
+ int imux;
+
+ str = ghb_value_string(lin_val);
+ imux = hb_container_get_from_name(str);
+ g_free(str);
+ mux = hb_container_get_name(imux);
+ if (mux != NULL)
+ sval = ghb_string_value_new(mux);
+
+ return sval;
+}
+
static void
export_value_xlat(GValue *dict)
{
ghb_dict_insert(dict, g_strdup(key), gval);
key = "FileFormat";
lin_val = ghb_dict_lookup(dict, key);
- gval = export_value_xlat2(container_xlat, lin_val, G_TYPE_STRING);
+ gval = export_value_xlat_container(lin_val);
if (gval)
ghb_dict_insert(dict, g_strdup(key), gval);
key = "VideoFramerate";
return NULL;
}
+static GValue*
+import_value_xlat_container(GValue *mac_val)
+{
+ GValue *sval = NULL;
+ gchar *str;
+ const gchar *mux;
+ int imux;
+
+ str = ghb_value_string(mac_val);
+ mux = hb_container_sanitize_name(str);
+ g_free(str);
+
+ if (mux == NULL)
+ {
+ imux = hb_container_get_from_extension("mp4");
+ }
+ else
+ {
+ imux = hb_container_get_from_name(mux);
+ }
+ mux = hb_container_get_short_name(imux);
+
+ if (mux != NULL)
+ sval = ghb_string_value_new(mux);
+
+ return sval;
+}
+
static void
import_value_xlat(GValue *dict)
{
ghb_dict_insert(dict, g_strdup(key), gval);
key = "FileFormat";
mac_val = ghb_dict_lookup(dict, key);
- gval = import_value_xlat2(defaults, container_xlat, key, mac_val);
+ gval = import_value_xlat_container(mac_val);
if (gval)
ghb_dict_insert(dict, g_strdup(key), gval);
key = "VideoFramerate";
ghb_presets_load(signal_user_data_t *ud)
{
// Create translation tables from libhb tables
- mix_xlat = create_mix_xlat_tbl(mix_xlat_compat, hb_audio_mixdowns, hb_audio_mixdowns_count);
- acodec_xlat = create_encoder_xlat_tbl(acodec_xlat_compat, hb_audio_encoders, hb_audio_encoders_count);
- vcodec_xlat = create_encoder_xlat_tbl(vcodec_xlat_compat, hb_video_encoders, hb_video_encoders_count);
+ mix_xlat = create_mix_xlat_tbl(mix_xlat_compat);
+ acodec_xlat = create_audio_encoder_xlat_tbl(acodec_xlat_compat);
+ vcodec_xlat = create_video_encoder_xlat_tbl(vcodec_xlat_compat);
presetsPlist = load_plist("presets");
if (presetsPlist == NULL)
/**********************************************************************
* Global variables
*********************************************************************/
+static hb_error_handler_t *error_handler = NULL;
+
hb_rate_t hb_video_rates[] =
{
{ "5", 5400000 },
};
int hb_audio_bitrates_count = sizeof(hb_audio_bitrates) / sizeof(hb_rate_t);
-static hb_error_handler_t *error_handler = NULL;
-
hb_dither_t hb_audio_dithers[] =
{
{ "default", "auto", AV_RESAMPLE_DITHER_NONE - 1, },
hb_encoder_t hb_video_encoders[] =
{
- { "H.264 (x264)", "x264", HB_VCODEC_X264, HB_MUX_MP4|HB_MUX_MKV },
+ { "H.264 (x264)", "x264", HB_VCODEC_X264, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV },
#ifdef USE_QSV
- { "H.264 (Intel QSV)", "qsv_h264", HB_VCODEC_QSV_H264, HB_MUX_MP4|HB_MUX_MKV },
+ { "H.264 (Intel QSV)", "qsv_h264", HB_VCODEC_QSV_H264, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV },
#endif
- { "MPEG-4 (FFmpeg)", "ffmpeg4", HB_VCODEC_FFMPEG_MPEG4, HB_MUX_MP4|HB_MUX_MKV },
- { "MPEG-2 (FFmpeg)", "ffmpeg2", HB_VCODEC_FFMPEG_MPEG2, HB_MUX_MP4|HB_MUX_MKV },
- { "VP3 (Theora)", "theora", HB_VCODEC_THEORA, HB_MUX_MKV },
+ { "MPEG-4 (FFmpeg)", "ffmpeg4", HB_VCODEC_FFMPEG_MPEG4, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV },
+ { "MPEG-2 (FFmpeg)", "ffmpeg2", HB_VCODEC_FFMPEG_MPEG2, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV },
+ { "VP3 (Theora)", "theora", HB_VCODEC_THEORA, HB_MUX_MASK_MKV },
};
int hb_video_encoders_count = sizeof(hb_video_encoders) / sizeof(hb_encoder_t);
hb_encoder_t hb_audio_encoders[] =
{
#ifdef __APPLE__
- { "AAC (CoreAudio)", "ca_aac", HB_ACODEC_CA_AAC, HB_MUX_MP4|HB_MUX_MKV },
- { "HE-AAC (CoreAudio)", "ca_haac", HB_ACODEC_CA_HAAC, HB_MUX_MP4|HB_MUX_MKV },
+ { "AAC (CoreAudio)", "ca_aac", HB_ACODEC_CA_AAC, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV },
+ { "HE-AAC (CoreAudio)", "ca_haac", HB_ACODEC_CA_HAAC, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV },
#endif
- { "AAC (faac)", "faac", HB_ACODEC_FAAC, HB_MUX_MP4|HB_MUX_MKV },
+ { "AAC (faac)", "faac", HB_ACODEC_FAAC, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV },
#ifdef USE_FDK_AAC
- { "AAC (FDK)", "fdk_aac", HB_ACODEC_FDK_AAC, HB_MUX_MP4|HB_MUX_MKV },
- { "HE-AAC (FDK)", "fdk_haac", HB_ACODEC_FDK_HAAC, HB_MUX_MP4|HB_MUX_MKV },
+ { "AAC (FDK)", "fdk_aac", HB_ACODEC_FDK_AAC, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV },
+ { "HE-AAC (FDK)", "fdk_haac", HB_ACODEC_FDK_HAAC, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV },
#endif
- { "AAC (ffmpeg)", "ffaac", HB_ACODEC_FFAAC, HB_MUX_MP4|HB_MUX_MKV },
- { "AAC Passthru", "copy:aac", HB_ACODEC_AAC_PASS, HB_MUX_MP4|HB_MUX_MKV },
- { "AC3 (ffmpeg)", "ffac3", HB_ACODEC_AC3, HB_MUX_MP4|HB_MUX_MKV },
- { "AC3 Passthru", "copy:ac3", HB_ACODEC_AC3_PASS, HB_MUX_MP4|HB_MUX_MKV },
- { "DTS Passthru", "copy:dts", HB_ACODEC_DCA_PASS, HB_MUX_MP4|HB_MUX_MKV },
- { "DTS-HD Passthru", "copy:dtshd", HB_ACODEC_DCA_HD_PASS, HB_MUX_MP4|HB_MUX_MKV },
- { "MP3 (lame)", "lame", HB_ACODEC_LAME, HB_MUX_MP4|HB_MUX_MKV },
- { "MP3 Passthru", "copy:mp3", HB_ACODEC_MP3_PASS, HB_MUX_MP4|HB_MUX_MKV },
- { "Vorbis (vorbis)", "vorbis", HB_ACODEC_VORBIS, HB_MUX_MKV },
- { "FLAC (ffmpeg)", "ffflac", HB_ACODEC_FFFLAC, HB_MUX_MKV },
- { "FLAC (24-bit)", "ffflac24", HB_ACODEC_FFFLAC24, HB_MUX_MKV },
- { "Auto Passthru", "copy", HB_ACODEC_AUTO_PASS, HB_MUX_MP4|HB_MUX_MKV },
+ { "AAC (ffmpeg)", "ffaac", HB_ACODEC_FFAAC, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV },
+ { "AAC Passthru", "copy:aac", HB_ACODEC_AAC_PASS, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV },
+ { "AC3 (ffmpeg)", "ffac3", HB_ACODEC_AC3, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV },
+ { "AC3 Passthru", "copy:ac3", HB_ACODEC_AC3_PASS, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV },
+ { "DTS Passthru", "copy:dts", HB_ACODEC_DCA_PASS, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV },
+ { "DTS-HD Passthru", "copy:dtshd", HB_ACODEC_DCA_HD_PASS, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV },
+ { "MP3 (lame)", "lame", HB_ACODEC_LAME, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV },
+ { "MP3 Passthru", "copy:mp3", HB_ACODEC_MP3_PASS, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV },
+ { "Vorbis (vorbis)", "vorbis", HB_ACODEC_VORBIS, HB_MUX_MASK_MKV },
+ { "FLAC (ffmpeg)", "ffflac", HB_ACODEC_FFFLAC, HB_MUX_MASK_MKV },
+ { "FLAC (24-bit)", "ffflac24", HB_ACODEC_FFFLAC24, HB_MUX_MASK_MKV },
+ { "Auto Passthru", "copy", HB_ACODEC_AUTO_PASS, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV },
};
int hb_audio_encoders_count = sizeof(hb_audio_encoders) / sizeof(hb_encoder_t);
-/* Expose values for PInvoke */
-hb_rate_t* hb_get_video_rates() { return hb_video_rates; }
-int hb_get_video_rates_count() { return hb_video_rates_count; }
-hb_rate_t* hb_get_audio_rates() { return hb_audio_rates; }
-int hb_get_audio_rates_count() { return hb_audio_rates_count; }
-hb_rate_t* hb_get_audio_bitrates() { return hb_audio_bitrates; }
-int hb_get_audio_bitrates_count() { return hb_audio_bitrates_count; }
-hb_dither_t* hb_get_audio_dithers() { return hb_audio_dithers; }
-int hb_get_audio_dithers_count() { return hb_audio_dithers_count; }
-hb_mixdown_t* hb_get_audio_mixdowns() { return hb_audio_mixdowns; }
-int hb_get_audio_mixdowns_count() { return hb_audio_mixdowns_count; }
-hb_encoder_t* hb_get_video_encoders() { return hb_video_encoders; }
-int hb_get_video_encoders_count() { return hb_video_encoders_count; }
-hb_encoder_t* hb_get_audio_encoders() { return hb_audio_encoders; }
-int hb_get_audio_encoders_count() { return hb_audio_encoders_count; }
+// note: for each container, the muxer nearer the top is the default
+hb_container_t hb_containers[] =
+{
+ { "MPEG-4 (mp4v2)", "mp4v2", "mp4", HB_MUX_MP4V2, },
+ { "Matroska (libmkv)", "libmkv", "mkv", HB_MUX_LIBMKV, },
+};
+int hb_containers_count = sizeof(hb_containers) / sizeof(hb_container_t);
-int hb_audio_dither_get_default()
+int hb_video_framerate_get_from_name(const char *name)
{
- // "auto"
- return hb_audio_dithers[0].method;
-}
+ if (name == NULL || *name == '\0')
+ goto fail;
-int hb_audio_dither_get_default_method()
+ // TODO: implement something more flexible
+ if (!strcasecmp(name, "23.976 (NTSC Film)"))
{
- /*
- * input could be s16 (possibly already dithered) converted to flt, so
- * let's use a "low-risk" dither algorithm (standard triangular).
- */
- return AV_RESAMPLE_DITHER_TRIANGULAR;
+ return 1126125;
}
-
-int hb_audio_dither_is_supported(uint32_t codec)
+ if (!strcasecmp(name, "25 (PAL Film/Video)"))
{
- // encoder's input sample format must be s16(p)
- switch (codec)
+ return 1080000;
+ }
+ if (!strcasecmp(name, "29.97 (NTSC Video)"))
{
- case HB_ACODEC_FFFLAC:
- case HB_ACODEC_FDK_AAC:
- case HB_ACODEC_FDK_HAAC:
- return 1;
- default:
- return 0;
+ return 900900;
}
-}
-const char* hb_audio_dither_get_description(int method)
-{
int i;
- for (i = 0; i < hb_audio_dithers_count; i++)
+ for (i = 0; i < hb_video_rates_count; i++)
{
- if (hb_audio_dithers[i].method == method)
+ if (!strcasecmp(hb_video_rates[i].name, name))
{
- return hb_audio_dithers[i].description;
+ return hb_video_rates[i].rate;
}
}
- return "";
-}
-
-int hb_mixdown_is_supported(int mixdown, uint32_t codec, uint64_t layout)
-{
- return (hb_mixdown_has_codec_support(mixdown, codec) &&
- hb_mixdown_has_remix_support(mixdown, layout));
+fail:
+ return -1;
}
-int hb_mixdown_has_codec_support(int mixdown, uint32_t codec)
+const char* hb_video_framerate_get_name(int framerate)
{
- // Passthru, only "None" mixdown is supported
- if (codec & HB_ACODEC_PASS_FLAG)
- return (mixdown == HB_AMIXDOWN_NONE);
-
- // Not passthru, "None" mixdown never supported
- if (mixdown == HB_AMIXDOWN_NONE)
- return 0;
+ if (framerate > hb_video_rates[0].rate ||
+ framerate < hb_video_rates[hb_video_rates_count - 1].rate)
+ goto fail;
- switch (codec)
+ int i;
+ for (i = 0; i < hb_video_rates_count; i++)
{
- case HB_ACODEC_VORBIS:
- case HB_ACODEC_FFFLAC:
- case HB_ACODEC_FFFLAC24:
- return (mixdown <= HB_AMIXDOWN_7POINT1);
-
- case HB_ACODEC_LAME:
- case HB_ACODEC_FFAAC:
- return (mixdown <= HB_AMIXDOWN_DOLBYPLII);
-
- case HB_ACODEC_FAAC:
- case HB_ACODEC_CA_AAC:
- case HB_ACODEC_CA_HAAC:
- return ((mixdown <= HB_AMIXDOWN_5POINT1) ||
- (mixdown == HB_AMIXDOWN_5_2_LFE));
-
- default:
- return (mixdown <= HB_AMIXDOWN_5POINT1);
- }
-}
-
-int hb_mixdown_has_remix_support(int mixdown, uint64_t layout)
+ if (hb_video_rates[i].rate == framerate)
{
- switch (mixdown)
- {
- // stereo + front left/right of center
- case HB_AMIXDOWN_5_2_LFE:
- return ((layout & AV_CH_FRONT_LEFT_OF_CENTER) &&
- (layout & AV_CH_FRONT_RIGHT_OF_CENTER) &&
- (layout & AV_CH_LAYOUT_STEREO) == AV_CH_LAYOUT_STEREO);
-
- // 7.0 or better
- case HB_AMIXDOWN_7POINT1:
- return ((layout & AV_CH_LAYOUT_7POINT0) == AV_CH_LAYOUT_7POINT0);
-
- // 6.0 or better
- case HB_AMIXDOWN_6POINT1:
- return ((layout & AV_CH_LAYOUT_7POINT0) == AV_CH_LAYOUT_7POINT0 ||
- (layout & AV_CH_LAYOUT_6POINT0) == AV_CH_LAYOUT_6POINT0 ||
- (layout & AV_CH_LAYOUT_HEXAGONAL) == AV_CH_LAYOUT_HEXAGONAL);
-
- // stereo + either of front center, side or back left/right, back center
- case HB_AMIXDOWN_5POINT1:
- return ((layout & AV_CH_LAYOUT_2_1) == AV_CH_LAYOUT_2_1 ||
- (layout & AV_CH_LAYOUT_2_2) == AV_CH_LAYOUT_2_2 ||
- (layout & AV_CH_LAYOUT_QUAD) == AV_CH_LAYOUT_QUAD ||
- (layout & AV_CH_LAYOUT_SURROUND) == AV_CH_LAYOUT_SURROUND);
-
- // stereo + either of side or back left/right, back center
- // also, allow Dolby Surrounbd output if the input is already Dolby
- case HB_AMIXDOWN_DOLBY:
- case HB_AMIXDOWN_DOLBYPLII:
- return ((layout & AV_CH_LAYOUT_2_1) == AV_CH_LAYOUT_2_1 ||
- (layout & AV_CH_LAYOUT_2_2) == AV_CH_LAYOUT_2_2 ||
- (layout & AV_CH_LAYOUT_QUAD) == AV_CH_LAYOUT_QUAD ||
- (layout == AV_CH_LAYOUT_STEREO_DOWNMIX &&
- mixdown == HB_AMIXDOWN_DOLBY));
-
- // more than 1 channel
- case HB_AMIXDOWN_STEREO:
- return (av_get_channel_layout_nb_channels(layout) > 1);
-
- // regular stereo (not Dolby)
- case HB_AMIXDOWN_LEFT:
- case HB_AMIXDOWN_RIGHT:
- return (layout == AV_CH_LAYOUT_STEREO);
-
- // mono remix always supported
- // HB_AMIXDOWN_NONE always supported (for Passthru)
- case HB_AMIXDOWN_MONO:
- case HB_AMIXDOWN_NONE:
- return 1;
-
- // unknown mixdown, should never happen
- default:
- return 0;
+ return hb_video_rates[i].name;
}
}
-int hb_mixdown_get_discrete_channel_count(int amixdown)
-{
- switch (amixdown)
- {
- case HB_AMIXDOWN_5_2_LFE:
- case HB_AMIXDOWN_7POINT1:
- return 8;
-
- case HB_AMIXDOWN_6POINT1:
- return 7;
-
- case HB_AMIXDOWN_5POINT1:
- return 6;
-
- case HB_AMIXDOWN_MONO:
- case HB_AMIXDOWN_LEFT:
- case HB_AMIXDOWN_RIGHT:
- return 1;
-
- case HB_AMIXDOWN_NONE:
- return 0;
-
- default:
- return 2;
+fail:
+ return NULL;
}
-}
-int hb_mixdown_get_low_freq_channel_count(int amixdown)
+const char* hb_video_framerate_sanitize_name(const char *name)
{
- switch (amixdown)
- {
- case HB_AMIXDOWN_5POINT1:
- case HB_AMIXDOWN_6POINT1:
- case HB_AMIXDOWN_7POINT1:
- case HB_AMIXDOWN_5_2_LFE:
- return 1;
-
- default:
- return 0;
+ return hb_video_framerate_get_name(hb_video_framerate_get_from_name(name));
}
-}
-int hb_mixdown_get_mixdown_from_short_name(const char *short_name)
+const hb_rate_t* hb_video_framerate_get_next(const hb_rate_t *last)
{
- int i;
- for (i = 0; i < hb_audio_mixdowns_count; i++)
+ if (last == NULL)
{
- if (!strcmp(hb_audio_mixdowns[i].short_name, short_name))
- {
- return hb_audio_mixdowns[i].amixdown;
+ return &hb_video_rates[0];
}
- }
- return 0;
-}
-
-const char* hb_mixdown_get_short_name_from_mixdown(int amixdown)
+ if (last < &hb_video_rates[0] ||
+ last >= &hb_video_rates[hb_video_rates_count - 1])
{
- int i;
- for (i = 0; i < hb_audio_mixdowns_count; i++)
- {
- if (hb_audio_mixdowns[i].amixdown == amixdown)
- {
- return hb_audio_mixdowns[i].short_name;
+ return NULL;
}
+ return last + 1;
}
- return "";
-}
-void hb_autopassthru_apply_settings( hb_job_t * job )
+int hb_audio_samplerate_get_best(uint32_t codec, int samplerate, int *sr_shift)
{
- int i, j, already_printed;
- hb_audio_t * audio;
- for( i = 0, already_printed = 0; i < hb_list_count( job->list_audio ); )
+ int ii, best_samplerate, samplerate_shift;
+ if ((samplerate < 32000) &&
+ (codec == HB_ACODEC_CA_HAAC || codec == HB_ACODEC_AC3))
{
- audio = hb_list_item( job->list_audio, i );
- if( audio->config.out.codec == HB_ACODEC_AUTO_PASS )
- {
- if( !already_printed )
- hb_autopassthru_print_settings( job );
- already_printed = 1;
- audio->config.out.codec = hb_autopassthru_get_encoder( audio->config.in.codec,
- job->acodec_copy_mask,
- job->acodec_fallback,
- job->mux );
- if( !( audio->config.out.codec & HB_ACODEC_PASS_FLAG ) &&
- !( audio->config.out.codec & HB_ACODEC_MASK ) )
- {
- hb_log( "Auto Passthru: passthru not possible and no valid fallback specified, dropping track %d",
- audio->config.out.track );
- hb_list_rem( job->list_audio, audio );
- hb_audio_close( &audio );
- continue;
+ // ca_haac can't do samplerates < 32 kHz
+ // AC-3 < 32 kHz suffers from poor hardware compatibility
+ best_samplerate = 32000;
+ samplerate_shift = 0;
}
- audio->config.out.samplerate = audio->config.in.samplerate;
- if( !( audio->config.out.codec & HB_ACODEC_PASS_FLAG ) )
+ else if (samplerate < 16000 && codec == HB_ACODEC_FDK_HAAC)
{
- if( audio->config.out.codec == job->acodec_fallback )
- {
- hb_log( "Auto Passthru: passthru not possible for track %d, using fallback",
- audio->config.out.track );
+ // fdk_haac can't do samplerates < 16 kHz
+ best_samplerate = 16000;
+ samplerate_shift = 1;
}
else
{
- hb_log( "Auto Passthru: passthru and fallback not possible for track %d, using default encoder",
- audio->config.out.track );
- }
- audio->config.out.mixdown = hb_get_default_mixdown( audio->config.out.codec,
- audio->config.in.channel_layout );
- audio->config.out.bitrate = hb_get_default_audio_bitrate( audio->config.out.codec,
- audio->config.out.samplerate,
- audio->config.out.mixdown );
- audio->config.out.compression_level = hb_get_default_audio_compression( audio->config.out.codec );
- }
- else
+ best_samplerate = samplerate;
+ for (ii = hb_audio_rates_count - 1; ii >= 0; ii--)
{
- for( j = 0; j < hb_audio_encoders_count; j++ )
+ // valid samplerate
+ if (best_samplerate == hb_audio_rates[ii].rate)
+ break;
+
+ // samplerate is higher than the next valid samplerate,
+ // or lower than the lowest valid samplerate
+ if (best_samplerate > hb_audio_rates[ii].rate || ii == 0)
{
- if( hb_audio_encoders[j].encoder == audio->config.out.codec )
- {
- hb_log( "Auto Passthru: using %s for track %d",
- hb_audio_encoders[j].human_readable_name,
- audio->config.out.track );
+ best_samplerate = hb_audio_rates[ii].rate;
break;
}
}
+ /* sr_shift: 0 -> 48000, 44100, 32000 Hz
+ * 1 -> 24000, 22050, 16000 Hz
+ * 2 -> 12000, 11025, 8000 Hz
+ *
+ * also, since samplerates are sanitized downwards:
+ *
+ * (samplerate < 32000) implies (samplerate <= 24000)
+ */
+ samplerate_shift = ((best_samplerate < 16000) ? 2 :
+ (best_samplerate < 32000) ? 1 : 0);
}
+ if (sr_shift != NULL)
+ {
+ *sr_shift = samplerate_shift;
}
- /* Adjust output track number, in case we removed one.
- * Output tracks sadly still need to be in sequential order.
- * Note: out.track starts at 1, i starts at 0 */
- audio->config.out.track = ++i;
+ return best_samplerate;
}
-}
-void hb_autopassthru_print_settings( hb_job_t * job )
+int hb_audio_samplerate_get_from_name(const char *name)
{
- int i, codec_len;
- char *mask = NULL, *tmp;
- const char *fallback = NULL;
- for( i = 0; i < hb_audio_encoders_count; i++ )
+ if (name == NULL || *name == '\0')
+ goto fail;
+
+ // TODO: implement something more flexible
+ int i = atoi(name);
+ if (i >= hb_audio_rates[0].rate &&
+ i <= hb_audio_rates[hb_audio_rates_count - 1].rate)
{
- if( ( hb_audio_encoders[i].encoder & HB_ACODEC_PASS_FLAG ) &&
- ( hb_audio_encoders[i].encoder != HB_ACODEC_AUTO_PASS ) &&
- ( hb_audio_encoders[i].encoder & job->acodec_copy_mask ) )
- {
- if( mask )
- {
- tmp = hb_strncat_dup( mask, ", ", 2 );
- if( tmp )
- {
- free( mask );
- mask = tmp;
+ return i;
}
- }
- // passthru name without " Passthru"
- codec_len = strlen( hb_audio_encoders[i].human_readable_name ) - 9;
- tmp = hb_strncat_dup( mask, hb_audio_encoders[i].human_readable_name, codec_len );
- if( tmp )
+
+ for (i = 0; i < hb_audio_rates_count; i++)
{
- free( mask );
- mask = tmp;
- }
- }
- else if( !( hb_audio_encoders[i].encoder & HB_ACODEC_PASS_FLAG ) &&
- ( hb_audio_encoders[i].encoder == job->acodec_fallback ) )
+ if (!strcasecmp(hb_audio_rates[i].name, name))
{
- fallback = hb_audio_encoders[i].human_readable_name;
+ return hb_audio_rates[i].rate;
}
}
- if( !mask )
- hb_log( "Auto Passthru: no codecs allowed" );
- else
- hb_log( "Auto Passthru: allowed codecs are %s", mask );
- if( !fallback )
- hb_log( "Auto Passthru: no valid fallback specified" );
- else
- hb_log( "Auto Passthru: fallback is %s", fallback );
+
+fail:
+ return -1;
}
-int hb_autopassthru_get_encoder( int in_codec, int copy_mask, int fallback, int muxer )
+const char* hb_audio_samplerate_get_name(int samplerate)
{
+ if (samplerate < hb_audio_rates[0].rate ||
+ samplerate > hb_audio_rates[hb_audio_rates_count - 1].rate)
+ goto fail;
+
int i;
- int out_codec = ( copy_mask & in_codec ) | HB_ACODEC_PASS_FLAG;
- // sanitize fallback encoder and selected passthru
- // note: invalid fallbacks are caught in hb_autopassthru_apply_settings
- for( i = 0; i < hb_audio_encoders_count; i++ )
+ for (i = 0; i < hb_audio_rates_count; i++)
{
- if( ( hb_audio_encoders[i].encoder == fallback ) &&
- !( hb_audio_encoders[i].muxers & muxer ) )
+ if (hb_audio_rates[i].rate == samplerate)
{
- // fallback not possible with current muxer
- // use the default audio encoder instead
- fallback = hb_get_default_audio_encoder(muxer);
- break;
+ return hb_audio_rates[i].name;
}
}
- for( i = 0; i < hb_audio_encoders_count; i++ )
- {
- if( ( hb_audio_encoders[i].encoder == out_codec ) &&
- !( hb_audio_encoders[i].muxers & muxer ) )
- {
- // selected passthru not possible with current muxer
- out_codec = fallback;
- break;
+
+fail:
+ return NULL;
}
- }
- if( !( out_codec & HB_ACODEC_PASS_MASK ) )
- return fallback;
- return out_codec;
-}
-int hb_get_default_audio_encoder(int muxer)
+const hb_rate_t* hb_audio_samplerate_get_next(const hb_rate_t *last)
{
-#ifndef __APPLE__
- if (muxer == HB_MUX_MKV)
+ if (last == NULL)
{
- return HB_ACODEC_LAME;
+ return &hb_audio_rates[0];
}
-#endif
- return hb_audio_encoders[0].encoder;
+ if (last < &hb_audio_rates[0] ||
+ last >= &hb_audio_rates[hb_audio_rates_count - 1])
+ {
+ return NULL;
+}
+ return last + 1;
}
// Given an input bitrate, find closest match in the set of allowed bitrates
-int hb_find_closest_audio_bitrate(int bitrate)
+static int hb_audio_bitrate_find_closest(int bitrate)
{
// Check if bitrate mode was disabled
if (bitrate <= 0)
return bitrate;
- int ii, result;
// result is highest rate if none found during search.
// rate returned will always be <= rate asked for.
- result = hb_audio_bitrates[0].rate;
- for (ii = hb_audio_bitrates_count - 1; ii > 0; ii--)
+ int i, result = hb_audio_bitrates[0].rate;
+ for (i = hb_audio_bitrates_count - 1; i > 0; i--)
{
- if (bitrate >= hb_audio_bitrates[ii].rate)
+ if (bitrate >= hb_audio_bitrates[i].rate)
{
- result = hb_audio_bitrates[ii].rate;
+ result = hb_audio_bitrates[i].rate;
break;
}
}
return result;
}
-/* Get the bitrate low and high limits for a codec/samplerate/mixdown triplet.
-
-Encoder 1.0 channel 2.0 channels 5.1 channels 6.1 channels 7.1 channels
---------------------------------------------------------------------------------------
-
-faac
-----
-supported samplerates: 8 - 48 kHz
-libfaac/util.c defines the bitrate limits:
-MinBitrate() -> 8000 bps (per channel, incl. LFE).
-MaxBitrate() -> (6144 * samplerate / 1024) bps (per channel, incl. LFE).
-But output bitrates don't go as high as the theoretical maximums:
-12 kHz 43 (72) 87 (144) 260 (432) 303 (504) 342 (576)
-24 kHz 87 (144) 174 (288) 514 (864) 595 (1008) 669 (1152)
-48 kHz 174 (288) 347 (576) 970 (1728) 1138 (2016) 1287 (2304)
-Also, faac isn't a great encoder, so you don't want to allow too low a bitrate.
-Limits: minimum of 32 Kbps per channel
- maximum of 192 Kbps per channel at 32-48 kHz, adjusted for sr_shift
-
-
-ffaac
------
-supported samplerates: 8 - 48 kHz
-libavcodec/aacenc.c defines a maximum bitrate:
--> 6144 * samplerate / 1024 bps (per channel, incl. LFE).
-But output bitrates don't go as high as the theoretical maximums:
-12 kHz 61 (72) 123 (144)
-24 kHz 121 (144) 242 (288)
-48 kHz 236 (288) 472 (576)
-Also, ffaac isn't a great encoder, so you don't want to allow too low a bitrate.
-Limits: minimum of 32 Kbps per channel
- maximum of 192 Kbps per channel at 32 kHz, adjusted for sr_shift
- maximum of 256 Kbps per channel at 44.1-48 kHz, adjusted for sr_shift
-
-vorbis
-------
-supported samplerates: 8 - 48 kHz
-lib/modes/setup_*.h provides a range of allowed bitrates for various configurations.
-for each samplerate, the highest minimums and lowest maximums are:
- 8 kHz Minimum 8 Kbps, maximum 32 Kbps (per channel, incl. LFE).
-12 kHz Minimum 14 Kbps, maximum 44 Kbps (per channel, incl. LFE).
-16 kHz Minimum 16 Kbps, maximum 86 Kbps (per channel, incl. LFE).
-24 kHz Minimum 22 Kbps, maximum 86 Kbps (per channel, incl. LFE).
-32 kHz Minimum 26 Kbps, maximum 190 Kbps (per channel, incl. LFE).
-48 kHz Minimum 28 Kbps, maximum 240 Kbps (per channel, incl. LFE).
-Limits: minimum of 14/22/28 Kbps per channel (8-12, 16-24, 32-48 kHz)
- maximum of 32/86/190/240 Kbps per channel (8-12, 16-24, 32, 44.1-48 kHz)
-
-lame
-----
-supported samplerates: 8 - 48 kHz
-lame_init_params() allows the following bitrates:
-12 kHz Minimum 8 Kbps, maximum 64 Kbps
-24 kHz Minimum 8 Kbps, maximum 160 Kbps
-48 kHz Minimum 32 Kbps, maximum 320 Kbps
-Limits: minimum of 8/8/32 Kbps (8-12, 16-24, 32-48 kHz)
- maximum of 64/160/320 Kbps (8-12, 16-24, 32-48 kHz)
-
-ffac3
------
-supported samplerates: 32 - 48 kHz (< 32 kHz disabled for compatibility reasons)
-Dolby's encoder has a min. of 224 Kbps for 5 full-bandwidth channels (5.0, 5.1)
-The maximum AC3 bitrate is 640 Kbps
-Limits: minimum of 224/5 Kbps per full-bandwidth channel, maximum of 640 Kbps
-
-ca_aac
-------
-supported samplerates: 8 - 48 kHz
-Core Audio API provides a range of allowed bitrates:
- 8 kHz 8 - 24 16 - 48 40 - 112 48 - 144 56 - 160
-12 kHz 12 - 32 24 - 64 64 - 160 72 - 192 96 - 224
-16 kHz 12 - 48 24 - 96 64 - 224 72 - 288 96 - 320
-24 kHz 16 - 64 32 - 128 80 - 320 96 - 384 112 - 448
-32 kHz 24 - 96 48 - 192 128 - 448 144 - 576 192 - 640
-48 kHz 32 - 256 64 - 320 160 - 768 192 - 960 224 - 960
-Limits:
- 8 kHz -> minimum of 8 Kbps and maximum of 24 Kbps per full-bandwidth channel
-12 kHz -> minimum of 12 Kbps and maximum of 32 Kbps per full-bandwidth channel
-16 kHz -> minimum of 12 Kbps and maximum of 48 Kbps per full-bandwidth channel
-24 kHz -> minimum of 16 Kbps and maximum of 64 Kbps per full-bandwidth channel
-32 kHz -> minimum of 24 Kbps and maximum of 96 Kbps per full-bandwidth channel
-48 kHz -> minimum of 32 Kbps and maximum of 160 Kbps per full-bandwidth channel
-48 kHz -> maximum of +96 Kbps for Mono
-Note: encCoreAudioInit() will sanitize any mistake made here.
-
-ca_haac
--------
-supported samplerates: 32 - 48 kHz
-Core Audio API provides a range of allowed bitrates:
-32 kHz 12 - 40 24 - 80 64 - 192 N/A 96 - 256
-48 kHz 16 - 40 32 - 80 80 - 192 N/A 112 - 256
-Limits: minimum of 12 Kbps per full-bandwidth channel (<= 32 kHz)
- minimum of 16 Kbps per full-bandwidth channel ( > 32 kHz)
- maximum of 40 Kbps per full-bandwidth channel
-Note: encCoreAudioInit() will sanitize any mistake made here.
-
-fdk_aac
--------
-supported samplerates: 8 - 48 kHz
-libfdk limits the bitrate to the following values:
- 8 kHz 48 96 240
-12 kHz 72 144 360
-16 kHz 96 192 480
-24 kHz 144 288 720
-32 kHz 192 384 960
-48 kHz 288 576 1440
-Limits: minimum of samplerate * 2/3 Kbps per full-bandwidth channel (see ca_aac)
- maximum of samplerate * 6.0 Kbps per full-bandwidth channel
-
-fdk_haac
---------
-supported samplerates: 16 - 48 kHz
-libfdk limits the bitrate to the following values:
-16 kHz 8 - 48 16 - 96 45 - 199
-24 kHz 8 - 63 16 - 127 45 - 266
-32 kHz 8 - 63 16 - 127 45 - 266
-48 kHz 12 - 63 16 - 127 50 - 266
-Limits: minimum of 12 Kbps per full-bandwidth channel (<= 32 kHz) (see ca_haac)
- minimum of 16 Kbps per full-bandwidth channel ( > 32 kHz) (see ca_haac)
- maximum of 48, 96 or 192 Kbps (1.0, 2.0, 5.1) (<= 16 kHz)
- maximum of 64, 128 or 256 Kbps (1.0, 2.0, 5.1) ( > 16 kHz)
-*/
+// Given an input bitrate, sanitize it.
+// Check low and high limits and make sure it is in the set of allowed bitrates.
+int hb_audio_bitrate_get_best(uint32_t codec, int bitrate, int samplerate,
+ int mixdown)
+{
+ int low, high;
+ hb_audio_bitrate_get_limits(codec, samplerate, mixdown, &low, &high);
+ if (bitrate > high)
+ bitrate = high;
+ if (bitrate < low)
+ bitrate = low;
+ return hb_audio_bitrate_find_closest(bitrate);
+}
-void hb_get_audio_bitrate_limits(uint32_t codec, int samplerate, int mixdown,
- int *low, int *high)
+// Get the default bitrate for a given codec/samplerate/mixdown triplet.
+int hb_audio_bitrate_get_default(uint32_t codec, int samplerate, int mixdown)
{
- if (codec & HB_ACODEC_PASS_FLAG)
+ if ((codec & HB_ACODEC_PASS_FLAG) || !(codec & HB_ACODEC_MASK))
+ goto fail;
+
+ int bitrate, nchannels, sr_shift;
+ /* full-bandwidth channels, sr_shift */
+ nchannels = (hb_mixdown_get_discrete_channel_count(mixdown) -
+ hb_mixdown_get_low_freq_channel_count(mixdown));
+ hb_audio_samplerate_get_best(codec, samplerate, &sr_shift);
+
+ switch (codec)
{
- // Bitrates don't apply to passthrough audio, but may apply if we
- // fallback to an encoder when the source can't be passed through.
- *low = hb_audio_bitrates[0].rate;
- *high = hb_audio_bitrates[hb_audio_bitrates_count-1].rate;
- return;
+ case HB_ACODEC_FFFLAC:
+ case HB_ACODEC_FFFLAC24:
+ goto fail;
+
+ // 96, 224, 640 Kbps
+ case HB_ACODEC_AC3:
+ bitrate = (nchannels * 128) - (32 * (nchannels < 5));
+ break;
+
+ case HB_ACODEC_CA_HAAC:
+ case HB_ACODEC_FDK_HAAC:
+ bitrate = nchannels * 32;
+ break;
+
+ default:
+ bitrate = nchannels * 80;
+ break;
}
+ // sample_rate adjustment
+ bitrate >>= sr_shift;
+ return hb_audio_bitrate_get_best(codec, bitrate, samplerate, mixdown);
+fail:
+ return -1;
+}
+
+/* Get the bitrate low and high limits for a codec/samplerate/mixdown triplet.
+ *
+ * Encoder 1.0 channel 2.0 channels 5.1 channels 6.1 channels 7.1 channels
+ * --------------------------------------------------------------------------------------
+ *
+ * faac
+ * ----
+ * supported samplerates: 8 - 48 kHz
+ * libfaac/util.c defines the bitrate limits:
+ * MinBitrate() -> 8000 bps (per channel, incl. LFE).
+ * MaxBitrate() -> (6144 * samplerate / 1024) bps (per channel, incl. LFE).
+ * But output bitrates don't go as high as the theoretical maximums:
+ * 12 kHz 43 (72) 87 (144) 260 (432) 303 (504) 342 (576)
+ * 24 kHz 87 (144) 174 (288) 514 (864) 595 (1008) 669 (1152)
+ * 48 kHz 174 (288) 347 (576) 970 (1728) 1138 (2016) 1287 (2304)
+ * Also, faac isn't a great encoder, so you don't want to allow too low a bitrate.
+ * Limits: minimum of 32 Kbps per channel
+ * maximum of 192 Kbps per channel at 32-48 kHz, adjusted for sr_shift
+ *
+ *
+ * ffaac
+ * -----
+ * supported samplerates: 8 - 48 kHz
+ * libavcodec/aacenc.c defines a maximum bitrate:
+ * -> 6144 * samplerate / 1024 bps (per channel, incl. LFE).
+ * But output bitrates don't go as high as the theoretical maximums:
+ * 12 kHz 61 (72) 123 (144)
+ * 24 kHz 121 (144) 242 (288)
+ * 48 kHz 236 (288) 472 (576)
+ * Also, ffaac isn't a great encoder, so you don't want to allow too low a bitrate.
+ * Limits: minimum of 32 Kbps per channel
+ * maximum of 192 Kbps per channel at 32 kHz, adjusted for sr_shift
+ * maximum of 256 Kbps per channel at 44.1-48 kHz, adjusted for sr_shift
+ *
+ * vorbis
+ * ------
+ * supported samplerates: 8 - 48 kHz
+ * lib/modes/setup_*.h provides a range of allowed bitrates for various configurations.
+ * for each samplerate, the highest minimums and lowest maximums are:
+ * 8 kHz Minimum 8 Kbps, maximum 32 Kbps (per channel, incl. LFE).
+ * 12 kHz Minimum 14 Kbps, maximum 44 Kbps (per channel, incl. LFE).
+ * 16 kHz Minimum 16 Kbps, maximum 86 Kbps (per channel, incl. LFE).
+ * 24 kHz Minimum 22 Kbps, maximum 86 Kbps (per channel, incl. LFE).
+ * 32 kHz Minimum 26 Kbps, maximum 190 Kbps (per channel, incl. LFE).
+ * 48 kHz Minimum 28 Kbps, maximum 240 Kbps (per channel, incl. LFE).
+ * Limits: minimum of 14/22/28 Kbps per channel (8-12, 16-24, 32-48 kHz)
+ * maximum of 32/86/190/240 Kbps per channel (8-12, 16-24, 32, 44.1-48 kHz)
+ *
+ * lame
+ * ----
+ * supported samplerates: 8 - 48 kHz
+ * lame_init_params() allows the following bitrates:
+ * 12 kHz Minimum 8 Kbps, maximum 64 Kbps
+ * 24 kHz Minimum 8 Kbps, maximum 160 Kbps
+ * 48 kHz Minimum 32 Kbps, maximum 320 Kbps
+ * Limits: minimum of 8/8/32 Kbps (8-12, 16-24, 32-48 kHz)
+ * maximum of 64/160/320 Kbps (8-12, 16-24, 32-48 kHz)
+ *
+ * ffac3
+ * -----
+ * supported samplerates: 32 - 48 kHz (< 32 kHz disabled for compatibility reasons)
+ * Dolby's encoder has a min. of 224 Kbps for 5 full-bandwidth channels (5.0, 5.1)
+ * The maximum AC3 bitrate is 640 Kbps
+ * Limits: minimum of 224/5 Kbps per full-bandwidth channel, maximum of 640 Kbps
+ *
+ * ca_aac
+ * ------
+ * supported samplerates: 8 - 48 kHz
+ * Core Audio API provides a range of allowed bitrates:
+ * 8 kHz 8 - 24 16 - 48 40 - 112 48 - 144 56 - 160
+ * 12 kHz 12 - 32 24 - 64 64 - 160 72 - 192 96 - 224
+ * 16 kHz 12 - 48 24 - 96 64 - 224 72 - 288 96 - 320
+ * 24 kHz 16 - 64 32 - 128 80 - 320 96 - 384 112 - 448
+ * 32 kHz 24 - 96 48 - 192 128 - 448 144 - 576 192 - 640
+ * 48 kHz 32 - 256 64 - 320 160 - 768 192 - 960 224 - 960
+ * Limits:
+ * 8 kHz -> minimum of 8 Kbps and maximum of 24 Kbps per full-bandwidth channel
+ * 12 kHz -> minimum of 12 Kbps and maximum of 32 Kbps per full-bandwidth channel
+ * 16 kHz -> minimum of 12 Kbps and maximum of 48 Kbps per full-bandwidth channel
+ * 24 kHz -> minimum of 16 Kbps and maximum of 64 Kbps per full-bandwidth channel
+ * 32 kHz -> minimum of 24 Kbps and maximum of 96 Kbps per full-bandwidth channel
+ * 48 kHz -> minimum of 32 Kbps and maximum of 160 Kbps per full-bandwidth channel
+ * 48 kHz -> maximum of +96 Kbps for Mono
+ * Note: encCoreAudioInit() will sanitize any mistake made here.
+ *
+ * ca_haac
+ * -------
+ * supported samplerates: 32 - 48 kHz
+ * Core Audio API provides a range of allowed bitrates:
+ * 32 kHz 12 - 40 24 - 80 64 - 192 N/A 96 - 256
+ * 48 kHz 16 - 40 32 - 80 80 - 192 N/A 112 - 256
+ * Limits: minimum of 12 Kbps per full-bandwidth channel (<= 32 kHz)
+ * minimum of 16 Kbps per full-bandwidth channel ( > 32 kHz)
+ * maximum of 40 Kbps per full-bandwidth channel
+ * Note: encCoreAudioInit() will sanitize any mistake made here.
+ *
+ * fdk_aac
+ * -------
+ * supported samplerates: 8 - 48 kHz
+ * libfdk limits the bitrate to the following values:
+ * 8 kHz 48 96 240
+ * 12 kHz 72 144 360
+ * 16 kHz 96 192 480
+ * 24 kHz 144 288 720
+ * 32 kHz 192 384 960
+ * 48 kHz 288 576 1440
+ * Limits: minimum of samplerate * 2/3 Kbps per full-bandwidth channel (see ca_aac)
+ * maximum of samplerate * 6.0 Kbps per full-bandwidth channel
+ *
+ * fdk_haac
+ * --------
+ * supported samplerates: 16 - 48 kHz
+ * libfdk limits the bitrate to the following values:
+ * 16 kHz 8 - 48 16 - 96 45 - 199
+ * 24 kHz 8 - 63 16 - 127 45 - 266
+ * 32 kHz 8 - 63 16 - 127 45 - 266
+ * 48 kHz 12 - 63 16 - 127 50 - 266
+ * Limits: minimum of 12 Kbps per full-bandwidth channel (<= 32 kHz) (see ca_haac)
+ * minimum of 16 Kbps per full-bandwidth channel ( > 32 kHz) (see ca_haac)
+ * maximum of 48, 96 or 192 Kbps (1.0, 2.0, 5.1) (<= 16 kHz)
+ * maximum of 64, 128 or 256 Kbps (1.0, 2.0, 5.1) ( > 16 kHz)
+*/
+void hb_audio_bitrate_get_limits(uint32_t codec, int samplerate, int mixdown,
+ int *low, int *high)
+{
/* samplerate, sr_shift */
int sr_shift;
- samplerate = hb_get_best_samplerate(codec, samplerate, &sr_shift);
+ samplerate = hb_audio_samplerate_get_best(codec, samplerate, &sr_shift);
/* LFE, full-bandwidth channels */
int lfe_count, nchannels;
*low = nchannels * 8;
*high = nchannels * 24;
break;
+
case 11025:
case 12000:
*low = nchannels * 12;
*high = nchannels * 32;
break;
+
case 16000:
*low = nchannels * 12;
*high = nchannels * 48;
break;
+
case 22050:
case 24000:
*low = nchannels * 16;
*high = nchannels * 64;
break;
+
case 32000:
*low = nchannels * 24;
*high = nchannels * 96;
break;
+
case 44100:
case 48000:
default:
*low = nchannels * 32;
*high = nchannels * (160 + (96 * (nchannels == 1)));
break;
+ } break;
}
- } break;
case HB_ACODEC_CA_HAAC:
*low = nchannels * (12 + (4 * (samplerate >= 44100)));
( 50 * (samplerate >= 44100)));
break;
+ // Bitrates don't apply to passthrough audio, but may apply if we
+ // fall back to an encoder when the source can't be passed through.
default:
*low = hb_audio_bitrates[0].rate;
*high = hb_audio_bitrates[hb_audio_bitrates_count-1].rate;
break;
}
+
// sanitize max. bitrate
if (*high < hb_audio_bitrates[0].rate)
*high = hb_audio_bitrates[0].rate;
*high = hb_audio_bitrates[hb_audio_bitrates_count-1].rate;
}
-// Given an input bitrate, sanitize it.
-// Check low and high limits and make sure it is in the set of allowed bitrates.
-int hb_get_best_audio_bitrate(uint32_t codec, int bitrate, int samplerate,
- int mixdown)
+const hb_rate_t* hb_audio_bitrate_get_next(const hb_rate_t *last)
{
- int low, high;
- hb_get_audio_bitrate_limits(codec, samplerate, mixdown, &low, &high);
- if (bitrate > high)
- bitrate = high;
- if (bitrate < low)
- bitrate = low;
- return hb_find_closest_audio_bitrate(bitrate);
-}
-
-// Get the default bitrate for a given codec/samplerate/mixdown triplet.
-int hb_get_default_audio_bitrate(uint32_t codec, int samplerate, int mixdown)
+ if (last == NULL)
{
- if (codec & HB_ACODEC_PASS_FLAG)
- {
- return -1;
+ return &hb_audio_bitrates[0];
}
-
- int bitrate, nchannels, sr_shift;
- /* full-bandwidth channels, sr_shift */
- nchannels = (hb_mixdown_get_discrete_channel_count(mixdown) -
- hb_mixdown_get_low_freq_channel_count(mixdown));
- hb_get_best_samplerate(codec, samplerate, &sr_shift);
-
- switch (codec)
+ if (last < &hb_audio_bitrates[0] ||
+ last >= &hb_audio_bitrates[hb_audio_bitrates_count - 1])
{
- case HB_ACODEC_FFFLAC:
- case HB_ACODEC_FFFLAC24:
- return -1;
-
- // 96, 224, 640 Kbps
- case HB_ACODEC_AC3:
- bitrate = (nchannels * 128) - (32 * (nchannels < 5));
- break;
-
- case HB_ACODEC_CA_HAAC:
- case HB_ACODEC_FDK_HAAC:
- bitrate = nchannels * 32;
- break;
-
- default:
- bitrate = nchannels * 80;
- break;
+ return NULL;
}
- // sample_rate adjustment
- bitrate >>= sr_shift;
- return hb_get_best_audio_bitrate(codec, bitrate, samplerate, mixdown);
+ return last + 1;
}
// Get limits and hints for the UIs.
//
// direction says whether 'low' limit is highest or lowest
// quality (direction 0 == lowest value is worst quality)
-void hb_get_audio_quality_limits(uint32_t codec, float *low, float *high,
+void hb_audio_quality_get_limits(uint32_t codec, float *low, float *high,
float *granularity, int *direction)
{
switch (codec)
*direction = 1;
*granularity = 0.5;
*low = 0.;
- *high = 10.0;
+ *high = 10.;
break;
case HB_ACODEC_VORBIS:
*direction = 0;
*granularity = 0.5;
- *low = -2.0;
- *high = 10.0;
+ *low = -2.;
+ *high = 10.;
break;
case HB_ACODEC_CA_AAC:
*direction = 0;
- *granularity = 9;
+ *granularity = 9.;
*low = 1.;
- *high = 127.0;
+ *high = 127.;
break;
default:
*direction = 0;
- *granularity = 1;
+ *granularity = 1.;
*low = *high = HB_INVALID_AUDIO_QUALITY;
break;
}
}
-float hb_get_best_audio_quality(uint32_t codec, float quality)
+float hb_audio_quality_get_best(uint32_t codec, float quality)
{
- float low, high, granularity;
int direction;
- hb_get_audio_quality_limits(codec, &low, &high, &granularity, &direction);
+ float low, high, granularity;
+ hb_audio_quality_get_limits(codec, &low, &high, &granularity, &direction);
if (quality > high)
quality = high;
if (quality < low)
return quality;
}
-float hb_get_default_audio_quality( uint32_t codec )
+float hb_audio_quality_get_default(uint32_t codec)
{
- float quality;
switch( codec )
{
case HB_ACODEC_LAME:
- quality = 2.;
- break;
+ return 2.;
case HB_ACODEC_VORBIS:
- quality = 5.;
- break;
+ return 5.;
case HB_ACODEC_CA_AAC:
- quality = 91.;
- break;
+ return 91.;
default:
- quality = HB_INVALID_AUDIO_QUALITY;
- break;
+ return HB_INVALID_AUDIO_QUALITY;
}
- return quality;
}
// Get limits and hints for the UIs.
//
// direction says whether 'low' limit is highest or lowest
// compression level (direction 0 == lowest value is worst compression level)
-void hb_get_audio_compression_limits(uint32_t codec, float *low, float *high,
+void hb_audio_compression_get_limits(uint32_t codec, float *low, float *high,
float *granularity, int *direction)
{
switch (codec)
case HB_ACODEC_FFFLAC:
case HB_ACODEC_FFFLAC24:
*direction = 0;
- *granularity = 1;
- *high = 12;
- *low = 0;
+ *granularity = 1.;
+ *high = 12.;
+ *low = 0.;
break;
case HB_ACODEC_LAME:
*direction = 1;
- *granularity = 1;
- *high = 9;
- *low = 0;
+ *granularity = 1.;
+ *high = 9.;
+ *low = 0.;
break;
default:
*direction = 0;
- *granularity = 1;
- *low = *high = -1;
+ *granularity = 1.;
+ *low = *high = -1.;
break;
}
}
-float hb_get_best_audio_compression(uint32_t codec, float compression)
+float hb_audio_compression_get_best(uint32_t codec, float compression)
{
- float low, high, granularity;
int direction;
- hb_get_audio_compression_limits(codec, &low, &high, &granularity, &direction);
+ float low, high, granularity;
+ hb_audio_compression_get_limits(codec, &low, &high, &granularity, &direction);
if( compression > high )
compression = high;
if( compression < low )
return compression;
}
-float hb_get_default_audio_compression(uint32_t codec)
+float hb_audio_compression_get_default(uint32_t codec)
{
switch (codec)
{
}
}
-int hb_get_best_mixdown(uint32_t codec, uint64_t layout, int mixdown)
+int hb_audio_dither_get_default()
{
- // Passthru, only "None" mixdown is supported
- if (codec & HB_ACODEC_PASS_FLAG)
- return HB_AMIXDOWN_NONE;
-
- // caller requested the best available mixdown
- if (mixdown == HB_INVALID_AMIXDOWN)
- mixdown = hb_audio_mixdowns[hb_audio_mixdowns_count - 1].amixdown;
+ // "auto"
+ return hb_audio_dithers[0].method;
+}
- int ii;
- // test all mixdowns until an authorized, supported mixdown is found
- // stop before we reach the "worst" non-None mixdown (index == 1)
- for (ii = hb_audio_mixdowns_count - 1; ii > 1; ii--)
- if (hb_audio_mixdowns[ii].amixdown <= mixdown &&
- hb_mixdown_is_supported(hb_audio_mixdowns[ii].amixdown, codec, layout))
- break;
- return hb_audio_mixdowns[ii].amixdown;
+int hb_audio_dither_get_default_method()
+{
+ /*
+ * input could be s16 (possibly already dithered) converted to flt, so
+ * let's use a "low-risk" dither algorithm (standard triangular).
+ */
+ return AV_RESAMPLE_DITHER_TRIANGULAR;
}
-int hb_get_default_mixdown(uint32_t codec, uint64_t layout)
+int hb_audio_dither_is_supported(uint32_t codec)
{
- int mixdown;
+ // encoder's input sample format must be s16(p)
switch (codec)
{
- // the FLAC encoder defaults to the best mixdown up to 7.1
case HB_ACODEC_FFFLAC:
- case HB_ACODEC_FFFLAC24:
- mixdown = HB_AMIXDOWN_7POINT1;
- break;
- // the AC3 encoder defaults to the best mixdown up to 5.1
- case HB_ACODEC_AC3:
- mixdown = HB_AMIXDOWN_5POINT1;
- break;
- // other encoders default to the best mixdown up to DPLII
+ case HB_ACODEC_FDK_AAC:
+ case HB_ACODEC_FDK_HAAC:
+ return 1;
+
default:
- mixdown = HB_AMIXDOWN_DOLBYPLII;
- break;
+ return 0;
}
- // return the best available mixdown up to the selected default
- return hb_get_best_mixdown(codec, layout, mixdown);
}
-int hb_get_best_samplerate(uint32_t codec, int samplerate, int *sr_shift)
+int hb_audio_dither_get_from_name(const char *name)
{
- int ii, best_samplerate, samplerate_shift;
- if ((samplerate < 32000) &&
- (codec == HB_ACODEC_CA_HAAC || codec == HB_ACODEC_AC3))
- {
- // ca_haac can't do samplerates < 32 kHz
- // AC-3 < 32 kHz suffers from poor hardware compatibility
- best_samplerate = 32000;
- samplerate_shift = 0;
- }
- else if (samplerate < 16000 && codec == HB_ACODEC_FDK_HAAC)
+ if (name == NULL || *name == '\0')
+ goto fail;
+
+ int i;
+ for ( i = 0; i < hb_audio_dithers_count; i++)
{
- // fdk_haac can't do samplerates < 16 kHz
- best_samplerate = 16000;
- samplerate_shift = 1;
+ if (!strcasecmp(hb_audio_dithers[i].short_name, name))
+ {
+ return hb_audio_dithers[i].method;
+ }
}
- else
+
+fail:
+ return hb_audio_dither_get_default();
+}
+
+const char* hb_audio_dither_get_description(int method)
+{
+ if (method < hb_audio_dithers[0].method ||
+ method > hb_audio_dithers[hb_audio_dithers_count - 1].method)
+ goto fail;
+
+ int i;
+ for (i = 0; i < hb_audio_dithers_count; i++)
{
- best_samplerate = samplerate;
- for (ii = hb_audio_rates_count - 1; ii >= 0; ii--)
+ if (hb_audio_dithers[i].method == method)
{
- // valid samplerate
- if (best_samplerate == hb_audio_rates[ii].rate)
- break;
-
- // samplerate is higher than the next valid samplerate,
- // or lower than the lowest valid samplerate
- if (best_samplerate > hb_audio_rates[ii].rate || ii == 0)
- {
- best_samplerate = hb_audio_rates[ii].rate;
- break;
- }
+ return hb_audio_dithers[i].description;
}
- /* sr_shift: 0 -> 48000, 44100, 32000 Hz
- * 1 -> 24000, 22050, 16000 Hz
- * 2 -> 12000, 11025, 8000 Hz
- *
- * also, since samplerates are sanitized downwards:
- *
- * (samplerate < 32000) implies (samplerate <= 24000)
- */
- samplerate_shift = ((best_samplerate < 16000) ? 2 :
- (best_samplerate < 32000) ? 1 : 0);
}
- if (sr_shift != NULL)
+
+fail:
+ return NULL;
+}
+
+const hb_dither_t* hb_audio_dither_get_next(const hb_dither_t *last)
+{
+ if (last == NULL)
{
- *sr_shift = samplerate_shift;
+ return &hb_audio_dithers[0];
}
- return best_samplerate;
+ if (last < &hb_audio_dithers[0] ||
+ last >= &hb_audio_dithers[hb_audio_dithers_count - 1])
+ {
+ return NULL;
+ }
+ return last + 1;
+}
+
+int hb_mixdown_is_supported(int mixdown, uint32_t codec, uint64_t layout)
+{
+ return (hb_mixdown_has_codec_support(mixdown, codec) &&
+ hb_mixdown_has_remix_support(mixdown, layout));
+}
+
+int hb_mixdown_has_codec_support(int mixdown, uint32_t codec)
+{
+ // Passthru, only "None" mixdown is supported
+ if (codec & HB_ACODEC_PASS_FLAG)
+ return (mixdown == HB_AMIXDOWN_NONE);
+
+ // Not passthru, "None" mixdown never supported
+ if (mixdown == HB_AMIXDOWN_NONE)
+ return 0;
+
+ switch (codec)
+ {
+ case HB_ACODEC_VORBIS:
+ case HB_ACODEC_FFFLAC:
+ case HB_ACODEC_FFFLAC24:
+ return (mixdown <= HB_AMIXDOWN_7POINT1);
+
+ case HB_ACODEC_LAME:
+ case HB_ACODEC_FFAAC:
+ return (mixdown <= HB_AMIXDOWN_DOLBYPLII);
+
+ case HB_ACODEC_FAAC:
+ case HB_ACODEC_CA_AAC:
+ case HB_ACODEC_CA_HAAC:
+ return ((mixdown <= HB_AMIXDOWN_5POINT1) ||
+ (mixdown == HB_AMIXDOWN_5_2_LFE));
+
+ default:
+ return (mixdown <= HB_AMIXDOWN_5POINT1);
+ }
+}
+
+int hb_mixdown_has_remix_support(int mixdown, uint64_t layout)
+{
+ switch (mixdown)
+ {
+ // stereo + front left/right of center
+ case HB_AMIXDOWN_5_2_LFE:
+ return ((layout & AV_CH_FRONT_LEFT_OF_CENTER) &&
+ (layout & AV_CH_FRONT_RIGHT_OF_CENTER) &&
+ (layout & AV_CH_LAYOUT_STEREO) == AV_CH_LAYOUT_STEREO);
+
+ // 7.0 or better
+ case HB_AMIXDOWN_7POINT1:
+ return ((layout & AV_CH_LAYOUT_7POINT0) == AV_CH_LAYOUT_7POINT0);
+
+ // 6.0 or better
+ case HB_AMIXDOWN_6POINT1:
+ return ((layout & AV_CH_LAYOUT_7POINT0) == AV_CH_LAYOUT_7POINT0 ||
+ (layout & AV_CH_LAYOUT_6POINT0) == AV_CH_LAYOUT_6POINT0 ||
+ (layout & AV_CH_LAYOUT_HEXAGONAL) == AV_CH_LAYOUT_HEXAGONAL);
+
+ // stereo + either of front center, side or back left/right, back center
+ case HB_AMIXDOWN_5POINT1:
+ return ((layout & AV_CH_LAYOUT_2_1) == AV_CH_LAYOUT_2_1 ||
+ (layout & AV_CH_LAYOUT_2_2) == AV_CH_LAYOUT_2_2 ||
+ (layout & AV_CH_LAYOUT_QUAD) == AV_CH_LAYOUT_QUAD ||
+ (layout & AV_CH_LAYOUT_SURROUND) == AV_CH_LAYOUT_SURROUND);
+
+ // stereo + either of side or back left/right, back center
+ // also, allow Dolby Surrounbd output if the input is already Dolby
+ case HB_AMIXDOWN_DOLBY:
+ case HB_AMIXDOWN_DOLBYPLII:
+ return ((layout & AV_CH_LAYOUT_2_1) == AV_CH_LAYOUT_2_1 ||
+ (layout & AV_CH_LAYOUT_2_2) == AV_CH_LAYOUT_2_2 ||
+ (layout & AV_CH_LAYOUT_QUAD) == AV_CH_LAYOUT_QUAD ||
+ (layout == AV_CH_LAYOUT_STEREO_DOWNMIX &&
+ mixdown == HB_AMIXDOWN_DOLBY));
+
+ // more than 1 channel
+ case HB_AMIXDOWN_STEREO:
+ return (av_get_channel_layout_nb_channels(layout) > 1);
+
+ // regular stereo (not Dolby)
+ case HB_AMIXDOWN_LEFT:
+ case HB_AMIXDOWN_RIGHT:
+ return (layout == AV_CH_LAYOUT_STEREO);
+
+ // mono remix always supported
+ // HB_AMIXDOWN_NONE always supported (for Passthru)
+ case HB_AMIXDOWN_MONO:
+ case HB_AMIXDOWN_NONE:
+ return 1;
+
+ // unknown mixdown, should never happen
+ default:
+ return 0;
+ }
+}
+
+int hb_mixdown_get_discrete_channel_count(int amixdown)
+{
+ switch (amixdown)
+ {
+ case HB_AMIXDOWN_5_2_LFE:
+ case HB_AMIXDOWN_7POINT1:
+ return 8;
+
+ case HB_AMIXDOWN_6POINT1:
+ return 7;
+
+ case HB_AMIXDOWN_5POINT1:
+ return 6;
+
+ case HB_AMIXDOWN_MONO:
+ case HB_AMIXDOWN_LEFT:
+ case HB_AMIXDOWN_RIGHT:
+ return 1;
+
+ case HB_AMIXDOWN_NONE:
+ return 0;
+
+ default:
+ return 2;
+ }
+}
+
+int hb_mixdown_get_low_freq_channel_count(int amixdown)
+{
+ switch (amixdown)
+ {
+ case HB_AMIXDOWN_5POINT1:
+ case HB_AMIXDOWN_6POINT1:
+ case HB_AMIXDOWN_7POINT1:
+ case HB_AMIXDOWN_5_2_LFE:
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+int hb_mixdown_get_best(uint32_t codec, uint64_t layout, int mixdown)
+{
+ // Passthru, only "None" mixdown is supported
+ if (codec & HB_ACODEC_PASS_FLAG)
+ return HB_AMIXDOWN_NONE;
+
+ // caller requested the best available mixdown
+ if (mixdown == HB_INVALID_AMIXDOWN)
+ mixdown = hb_audio_mixdowns[hb_audio_mixdowns_count - 1].amixdown;
+
+ // test all mixdowns until an authorized, supported mixdown is found
+ // stop before we reach the "worst" non-None mixdown (index == 1)
+ int i;
+ for (i = hb_audio_mixdowns_count - 1; i > 1; i--)
+ if (hb_audio_mixdowns[i].amixdown <= mixdown &&
+ hb_mixdown_is_supported(hb_audio_mixdowns[i].amixdown, codec, layout))
+ break;
+ return hb_audio_mixdowns[i].amixdown;
+}
+
+int hb_mixdown_get_default(uint32_t codec, uint64_t layout)
+{
+ int mixdown;
+ switch (codec)
+ {
+ // the FLAC encoder defaults to the best mixdown up to 7.1
+ case HB_ACODEC_FFFLAC:
+ case HB_ACODEC_FFFLAC24:
+ mixdown = HB_AMIXDOWN_7POINT1;
+ break;
+
+ // the AC3 encoder defaults to the best mixdown up to 5.1
+ case HB_ACODEC_AC3:
+ mixdown = HB_AMIXDOWN_5POINT1;
+ break;
+
+ // other encoders default to the best mixdown up to DPLII
+ default:
+ mixdown = HB_AMIXDOWN_DOLBYPLII;
+ break;
+ }
+
+ // return the best available mixdown up to the selected default
+ return hb_mixdown_get_best(codec, layout, mixdown);
+}
+
+int hb_mixdown_get_from_name(const char *name)
+{
+ if (name == NULL || *name == '\0')
+ goto fail;
+
+ // TODO: implement something more flexible
+ if (!strcasecmp(name, "AC3 Passthru") ||
+ !strcasecmp(name, "DTS Passthru") ||
+ !strcasecmp(name, "DTS-HD Passthru"))
+ {
+ return HB_AMIXDOWN_NONE;
+ }
+ if (!strcasecmp(name, "6-channel discrete"))
+ {
+ return HB_AMIXDOWN_5POINT1;
+ }
+
+ int i;
+ for (i = 0; i < hb_audio_mixdowns_count; i++)
+ {
+ if (!strcasecmp(hb_audio_mixdowns[i].name, name) ||
+ !strcasecmp(hb_audio_mixdowns[i].short_name, name))
+ {
+ return hb_audio_mixdowns[i].amixdown;
+ }
+ }
+
+fail:
+ return -1;
+}
+
+const char* hb_mixdown_get_name(int mixdown)
+{
+ if (mixdown < hb_audio_mixdowns[0].amixdown ||
+ mixdown > hb_audio_mixdowns[hb_audio_mixdowns_count - 1].amixdown)
+ goto fail;
+
+ int i;
+ for (i = 0; i < hb_audio_mixdowns_count; i++)
+ {
+ if (hb_audio_mixdowns[i].amixdown == mixdown)
+ {
+ return hb_audio_mixdowns[i].name;
+ }
+ }
+
+fail:
+ return NULL;
+}
+
+const char* hb_mixdown_get_short_name(int mixdown)
+{
+ if (mixdown < hb_audio_mixdowns[0].amixdown ||
+ mixdown > hb_audio_mixdowns[hb_audio_mixdowns_count - 1].amixdown)
+ goto fail;
+
+ int i;
+ for (i = 0; i < hb_audio_mixdowns_count; i++)
+ {
+ if (hb_audio_mixdowns[i].amixdown == mixdown)
+ {
+ return hb_audio_mixdowns[i].short_name;
+ }
+ }
+
+fail:
+ return NULL;
+}
+
+const char* hb_mixdown_sanitize_name(const char *name)
+{
+ return hb_mixdown_get_name(hb_mixdown_get_from_name(name));
+}
+
+const hb_mixdown_t* hb_mixdown_get_next(const hb_mixdown_t *last)
+{
+ if (last == NULL)
+ {
+ return &hb_audio_mixdowns[0];
+ }
+ if (last < &hb_audio_mixdowns[0] ||
+ last >= &hb_audio_mixdowns[hb_audio_mixdowns_count - 1])
+ {
+ return NULL;
+ }
+ return last + 1;
+}
+
+int hb_video_encoder_get_default(int muxer)
+{
+ if (!(muxer & HB_MUX_MASK))
+ goto fail;
+
+ int i;
+ for (i = 0; i < hb_video_encoders_count; i++)
+ {
+ if (hb_video_encoders[i].muxers & muxer)
+ {
+ return hb_video_encoders[i].codec;
+ }
+ }
+
+fail:
+ return -1;
+}
+
+int hb_video_encoder_get_from_name(const char *name)
+{
+ if (name == NULL || *name == '\0')
+ goto fail;
+
+ // TODO: implement something more flexible
+ if (!strcasecmp(name, "XviD") ||
+ !strcasecmp(name, "FFmpeg"))
+ {
+ return HB_VCODEC_FFMPEG_MPEG4;
+ }
+
+ int i;
+ for (i = 0; i < hb_video_encoders_count; i++)
+ {
+ if (!strcasecmp(hb_video_encoders[i].name, name) ||
+ !strcasecmp(hb_video_encoders[i].short_name, name))
+ {
+ return hb_video_encoders[i].codec;
+ }
+ }
+
+fail:
+ return -1;
+}
+
+const char* hb_video_encoder_get_name(int encoder)
+{
+ if (!(encoder & HB_VCODEC_MASK))
+ goto fail;
+
+ int i;
+ for (i = 0; i < hb_video_encoders_count; i++)
+ {
+ if (hb_video_encoders[i].codec == encoder)
+ {
+ return hb_video_encoders[i].name;
+ }
+ }
+
+fail:
+ return NULL;
+}
+
+const char* hb_video_encoder_get_short_name(int encoder)
+{
+ if (!(encoder & HB_VCODEC_MASK))
+ goto fail;
+
+ int i;
+ for (i = 0; i < hb_video_encoders_count; i++)
+ {
+ if (hb_video_encoders[i].codec == encoder)
+ {
+ return hb_video_encoders[i].short_name;
+ }
+ }
+
+fail:
+ return NULL;
+}
+
+const char* hb_video_encoder_sanitize_name(const char *name)
+{
+ return hb_video_encoder_get_name(hb_video_encoder_get_from_name(name));
+}
+
+const hb_encoder_t* hb_video_encoder_get_next(const hb_encoder_t *last)
+{
+ if (last == NULL)
+ {
+ return &hb_video_encoders[0];
+ }
+ if (last < &hb_video_encoders[0] ||
+ last >= &hb_video_encoders[hb_video_encoders_count - 1])
+ {
+ return NULL;
+ }
+ return last + 1;
+}
+
+// for a valid passthru, return the matching encoder for that codec (if any),
+// else return -1 (i.e. drop the track)
+int hb_audio_encoder_get_fallback_for_passthru(int passthru)
+{
+ // TODO: implement something more flexible
+ switch (passthru)
+ {
+ case HB_ACODEC_AAC_PASS:
+#ifdef __APPLE__
+ return HB_ACODEC_CA_AAC;
+#else
+ return HB_ACODEC_FAAC;
+#endif
+
+ case HB_ACODEC_AC3_PASS:
+ return HB_ACODEC_AC3;
+
+ case HB_ACODEC_MP3_PASS:
+ return HB_ACODEC_LAME;
+
+ // passthru tracks are often the second audio from the same source track
+ // if we don't have an encoder matching the passthru codec, return -1
+ // dropping the track, as well as ensuring that there is at least one
+ // audio track in the output is then up to the UIs
+ default:
+ return -1;
+ }
+}
+
+int hb_audio_encoder_get_default(int muxer)
+{
+ if (!(muxer & HB_MUX_MASK))
+ goto fail;
+
+#ifndef __APPLE__
+ if (muxer == HB_MUX_MKV)
+ {
+ return HB_ACODEC_LAME;
+ }
+#endif
+
+ int i;
+ for (i = 0; i < hb_audio_encoders_count; i++)
+ {
+ // default encoder should not be passthru
+ if ((hb_audio_encoders[i].muxers & muxer) &&
+ (hb_audio_encoders[i].codec & HB_ACODEC_PASS_FLAG) == 0)
+ {
+ return hb_audio_encoders[i].codec;
+ }
+ }
+
+fail:
+ return -1;
+}
+
+int hb_audio_encoder_get_from_name(const char *name)
+{
+ if (name == NULL || *name == '\0')
+ goto fail;
+
+ // TODO: implement something more flexible
+ if (!strcasecmp(name, "AC3"))
+ {
+ return HB_ACODEC_AC3;
+ }
+ // libfdk fallback, use Core Audio if available, else FAAC
+#ifndef USE_FDK_AAC
+#ifdef __APPLE__
+#define AAC_ENC HB_ACODEC_CA_AAC
+#define HAAC_ENC HB_ACODEC_CA_HAAC
+#else
+#define AAC_ENC HB_ACODEC_FAAC
+#define HAAC_ENC HB_ACODEC_FAAC
+#endif
+ if (!strcasecmp(name, "AAC (FDK)") || !strcasecmp(name, "fdk_aac"))
+ {
+ return AAC_ENC;
+ }
+ if (!strcasecmp(name, "HE-AAC (FDK)") || !strcasecmp(name, "fdk_haac"))
+ {
+ return HAAC_ENC;
+ }
+#undef AAC_ENC
+#undef HAAC_ENC
+#endif
+
+ int i;
+ for (i = 0; i < hb_audio_encoders_count; i++)
+ {
+ if (!strcasecmp(hb_audio_encoders[i].name, name) ||
+ !strcasecmp(hb_audio_encoders[i].short_name, name))
+ {
+ return hb_audio_encoders[i].codec;
+ }
+ }
+
+fail:
+ return -1;
+}
+
+const char* hb_audio_encoder_get_name(int encoder)
+{
+ if (!(encoder & HB_ACODEC_ANY))
+ goto fail;
+
+ int i;
+ for (i = 0; i < hb_audio_encoders_count; i++)
+ {
+ if (hb_audio_encoders[i].codec == encoder)
+ {
+ return hb_audio_encoders[i].name;
+ }
+ }
+
+fail:
+ return NULL;
+}
+
+const char* hb_audio_encoder_get_short_name(int encoder)
+{
+ if (!(encoder & HB_ACODEC_ANY))
+ goto fail;
+
+ int i;
+ for (i = 0; i < hb_audio_encoders_count; i++)
+ {
+ if (hb_audio_encoders[i].codec == encoder)
+ {
+ return hb_audio_encoders[i].short_name;
+ }
+ }
+
+fail:
+ return NULL;
+}
+
+const char* hb_audio_encoder_sanitize_name(const char *name)
+{
+ return hb_audio_encoder_get_name(hb_audio_encoder_get_from_name(name));
+}
+
+const hb_encoder_t* hb_audio_encoder_get_next(const hb_encoder_t *last)
+{
+ if (last == NULL)
+ {
+ return &hb_audio_encoders[0];
+ }
+ if (last < &hb_audio_encoders[0] ||
+ last >= &hb_audio_encoders[hb_audio_encoders_count - 1])
+ {
+ return NULL;
+ }
+ return last + 1;
+}
+
+void hb_autopassthru_apply_settings(hb_job_t *job)
+{
+ hb_audio_t *audio;
+ int i, already_printed;
+ for (i = already_printed = 0; i < hb_list_count(job->list_audio);)
+ {
+ audio = hb_list_item(job->list_audio, i);
+ if (audio->config.out.codec == HB_ACODEC_AUTO_PASS)
+ {
+ if (!already_printed)
+ hb_autopassthru_print_settings(job);
+ already_printed = 1;
+ audio->config.out.codec = hb_autopassthru_get_encoder(audio->config.in.codec,
+ job->acodec_copy_mask,
+ job->acodec_fallback,
+ job->mux);
+ if (!(audio->config.out.codec & HB_ACODEC_PASS_FLAG) &&
+ !(audio->config.out.codec & HB_ACODEC_MASK))
+ {
+ hb_log("Auto Passthru: passthru not possible and no valid fallback specified, dropping track %d",
+ audio->config.out.track );
+ hb_list_rem(job->list_audio, audio);
+ hb_audio_close(&audio);
+ continue;
+ }
+ audio->config.out.samplerate = audio->config.in.samplerate;
+ if (!(audio->config.out.codec & HB_ACODEC_PASS_FLAG))
+ {
+ if (audio->config.out.codec == job->acodec_fallback)
+ {
+ hb_log("Auto Passthru: passthru not possible for track %d, using fallback",
+ audio->config.out.track);
+ }
+ else
+ {
+ hb_log("Auto Passthru: passthru and fallback not possible for track %d, using default encoder",
+ audio->config.out.track);
+ }
+ audio->config.out.mixdown =
+ hb_mixdown_get_default(audio->config.out.codec,
+ audio->config.in.channel_layout);
+ audio->config.out.bitrate =
+ hb_audio_bitrate_get_default(audio->config.out.codec,
+ audio->config.out.samplerate,
+ audio->config.out.mixdown );
+ audio->config.out.compression_level =
+ hb_audio_compression_get_default(audio->config.out.codec);
+ }
+ else
+ {
+ const hb_encoder_t *audio_encoder = NULL;
+ while ((audio_encoder = hb_audio_encoder_get_next(audio_encoder)) != NULL)
+ {
+ if (audio_encoder->codec == audio->config.out.codec)
+ {
+ hb_log("Auto Passthru: using %s for track %d",
+ audio_encoder->name,
+ audio->config.out.track);
+ break;
+ }
+ }
+ }
+ }
+ /* Adjust output track number, in case we removed one.
+ * Output tracks sadly still need to be in sequential order.
+ * Note: out.track starts at 1, i starts at 0 */
+ audio->config.out.track = ++i;
+ }
+}
+
+void hb_autopassthru_print_settings(hb_job_t *job)
+ {
+ char *mask = NULL, *tmp;
+ const char *fallback = NULL;
+ const hb_encoder_t *audio_encoder = NULL;
+ while ((audio_encoder = hb_audio_encoder_get_next(audio_encoder)) != NULL)
+ {
+ if ((audio_encoder->codec & HB_ACODEC_PASS_FLAG) &&
+ (audio_encoder->codec != HB_ACODEC_AUTO_PASS) &&
+ (audio_encoder->codec & job->acodec_copy_mask))
+ {
+ if (mask != NULL)
+ {
+ tmp = hb_strncat_dup(mask, ", ", 2);
+ if (tmp != NULL)
+ {
+ free(mask);
+ mask = tmp;
+ }
+ }
+ // passthru name without " Passthru"
+ tmp = hb_strncat_dup(mask, audio_encoder->name,
+ strlen(audio_encoder->name) - 9);
+ if (tmp != NULL)
+ {
+ free(mask);
+ mask = tmp;
+ }
+ }
+ else if ((audio_encoder->codec & HB_ACODEC_PASS_FLAG) == 0 &&
+ (audio_encoder->codec == job->acodec_fallback))
+ {
+ fallback = audio_encoder->name;
+ }
+ }
+ if (mask == NULL)
+ hb_log("Auto Passthru: no codecs allowed");
+ else
+ hb_log("Auto Passthru: allowed codecs are %s", mask);
+ if (fallback == NULL)
+ hb_log("Auto Passthru: no valid fallback specified");
+ else
+ hb_log("Auto Passthru: fallback is %s", fallback);
+}
+
+int hb_autopassthru_get_encoder(int in_codec, int copy_mask, int fallback,
+ int muxer)
+{
+ int i = 0;
+ const hb_encoder_t *audio_encoder = NULL;
+ int out_codec = (copy_mask & in_codec) | HB_ACODEC_PASS_FLAG;
+ // sanitize fallback encoder and selected passthru
+ // note: invalid fallbacks are caught in hb_autopassthru_apply_settings
+ while ((audio_encoder = hb_audio_encoder_get_next(audio_encoder)) != NULL)
+ {
+ if (audio_encoder->codec == out_codec)
+ {
+ i++;
+ if (!(audio_encoder->muxers & muxer))
+ out_codec = 0;
+ }
+ else if (audio_encoder->codec == fallback)
+ {
+ i++;
+ if (!(audio_encoder->muxers & muxer))
+ fallback = hb_audio_encoder_get_default(muxer);
+ }
+ if (i > 1)
+ {
+ break;
+ }
+ }
+ return (out_codec & HB_ACODEC_PASS_MASK) ? out_codec : fallback;
+ }
+
+int hb_container_get_from_name(const char *name)
+ {
+ if (name == NULL || *name == '\0')
+ goto fail;
+
+ // TODO: implement something more flexible
+ if (!strcasecmp(name, "m4v"))
+ {
+ // old CLI alternate short name for "mp4"
+ return HB_MUX_MP4;
+ }
+ if (!strcasecmp(name, "MP4 file"))
+ {
+ return HB_MUX_MP4;
+}
+ if (!strcasecmp(name, "MKV file"))
+ {
+ return HB_MUX_MKV;
+ }
+
+ int i;
+ for (i = 0; i < hb_containers_count; i++)
+ {
+ if (!strcasecmp(hb_containers[i].name, name) ||
+ !strcasecmp(hb_containers[i].short_name, name) ||
+ !strcasecmp(hb_containers[i].default_extension, name))
+ {
+ return hb_containers[i].format;
+ }
+ }
+
+fail:
+ return -1;
+}
+
+int hb_container_get_from_extension(const char *extension)
+{
+ if (extension == NULL || *extension == '\0')
+ goto fail;
+
+ // TODO: implement something more flexible
+ if (!strcasecmp(extension, "m4v"))
+ {
+ return HB_MUX_MP4;
+ }
+
+ int i;
+ for (i = 0; i < hb_containers_count; i++)
+ {
+ if (!strcasecmp(hb_containers[i].default_extension, extension))
+ {
+ return hb_containers[i].format;
+ }
+ }
+
+fail:
+ return -1;
+}
+
+const char* hb_container_get_name(int format)
+{
+ if (!(format & HB_MUX_MASK))
+ goto fail;
+
+ int i;
+ for (i = 0; i < hb_containers_count; i++)
+ {
+ if (hb_containers[i].format == format)
+ {
+ return hb_containers[i].name;
+ }
+
+ }
+
+fail:
+ return NULL;
+}
+
+const char* hb_container_get_short_name(int format)
+{
+ if (!(format & HB_MUX_MASK))
+ goto fail;
+
+ int i;
+ for (i = 0; i < hb_containers_count; i++)
+ {
+ if (hb_containers[i].format == format)
+ {
+ return hb_containers[i].short_name;
+ }
+ }
+
+fail:
+ return NULL;
+}
+
+const char* hb_container_get_default_extension(int format)
+{
+ if (!(format & HB_MUX_MASK))
+ goto fail;
+
+ int i;
+ for (i = 0; i < hb_containers_count; i++)
+ {
+ if (hb_containers[i].format == format)
+ {
+ return hb_containers[i].default_extension;
+ }
+ }
+
+fail:
+ return NULL;
+}
+
+const char* hb_container_sanitize_name(const char *name)
+{
+ return hb_container_get_name(hb_container_get_from_name(name));
+}
+
+const hb_container_t* hb_container_get_next(const hb_container_t *last)
+{
+ if (last == NULL)
+ {
+ return &hb_containers[0];
+ }
+ if (last < &hb_containers[0] ||
+ last >= &hb_containers[hb_containers_count - 1])
+ {
+ return NULL;
+ }
+ return last + 1;
}
/**********************************************************************
/* Initalize some sensible defaults */
audiocfg->in.track = audiocfg->out.track = 0;
- audiocfg->out.codec = hb_audio_encoders[0].encoder;
+ audiocfg->out.codec = hb_audio_encoders[0].codec;
audiocfg->out.samplerate = -1;
audiocfg->out.samples_per_frame = -1;
audiocfg->out.bitrate = -1;
typedef struct hb_dither_s hb_dither_t;
typedef struct hb_mixdown_s hb_mixdown_t;
typedef struct hb_encoder_s hb_encoder_t;
+typedef struct hb_container_s hb_container_t;
typedef struct hb_job_s hb_job_t;
typedef struct hb_title_set_s hb_title_set_t;
typedef struct hb_title_s hb_title_t;
struct hb_rate_s
{
- const char *string;
+ const char *name;
int rate;
};
struct hb_mixdown_s
{
- const char *human_readable_name;
+ const char *name;
const char *internal_name;
const char *short_name;
int amixdown;
struct hb_encoder_s
{
- const char *human_readable_name; // note: used in presets
- const char *short_name; // note: used in CLI
- int encoder; // HB_*CODEC_* define
- int muxers; // supported muxers
+ const char *name; // note: used in presets
+ const char *short_name; // note: used in CLI
+ int codec; // HB_*CODEC_* define
+ int muxers; // supported muxers
+};
+
+struct hb_container_s
+{
+ const char *name;
+ const char *short_name;
+ const char *default_extension;
+ int format;
};
struct hb_subtitle_config_s
int64_t offset;
};
-#define HB_VIDEO_RATE_BASE 27000000
-
-extern hb_rate_t hb_video_rates[];
-extern int hb_video_rates_count;
-extern hb_rate_t hb_audio_rates[];
-extern int hb_audio_rates_count;
-extern int hb_audio_rates_default;
-extern hb_rate_t hb_audio_bitrates[];
-extern int hb_audio_bitrates_count;
-extern hb_dither_t hb_audio_dithers[];
-extern int hb_audio_dithers_count;
-extern hb_mixdown_t hb_audio_mixdowns[];
-extern int hb_audio_mixdowns_count;
-extern hb_encoder_t hb_video_encoders[];
-extern int hb_video_encoders_count;
-extern hb_encoder_t hb_audio_encoders[];
-extern int hb_audio_encoders_count;
-
-/* Expose values for PInvoke */
-hb_rate_t* hb_get_video_rates();
-int hb_get_video_rates_count();
-hb_rate_t* hb_get_audio_rates();
-int hb_get_audio_rates_count();
-int hb_get_audio_rates_default();
-hb_rate_t* hb_get_audio_bitrates();
-int hb_get_audio_bitrates_count();
-hb_dither_t* hb_get_audio_dithers();
-int hb_get_audio_dithers_count();
-hb_mixdown_t* hb_get_audio_mixdowns();
-int hb_get_audio_mixdowns_count();
-hb_encoder_t* hb_get_video_encoders();
-int hb_get_video_encoders_count();
-hb_encoder_t* hb_get_audio_encoders();
-int hb_get_audio_encoders_count();
-
-int hb_audio_dither_get_default();
-int hb_audio_dither_get_default_method();
-int hb_audio_dither_is_supported(uint32_t codec);
-const char* hb_audio_dither_get_description(int method);
-
-int hb_mixdown_is_supported(int mixdown, uint32_t codec, uint64_t layout);
-int hb_mixdown_has_codec_support(int mixdown, uint32_t codec);
-int hb_mixdown_has_remix_support(int mixdown, uint64_t layout);
-int hb_mixdown_get_discrete_channel_count(int amixdown);
-int hb_mixdown_get_low_freq_channel_count(int amixdown);
-int hb_mixdown_get_mixdown_from_short_name(const char *short_name);
-const char* hb_mixdown_get_short_name_from_mixdown(int amixdown);
+/*******************************************************************************
+ * Lists of rates, mixdowns, encoders etc.
+ *******************************************************************************
+ *
+ * Use hb_*_get_next() to get the next list item (use NULL to get the first).
+ *
+ * Use hb_*_get_from_name() to get the value corresponding to a name.
+ * The name can be either the short or full name.
+ * Legacy names are sanitized to currently-supported values whenever possible.
+ * Returns -1 if no value could be found.
+ *
+ * Use hb_*_get_name() and hb_*_get_short_name() to get the corresponding value.
+ * Returns NULL if the value is invalid.
+ *
+ * hb_*_sanitize_name() are convenience functions for use when dealing
+ * with full names (e.g. to translate legacy values while loading a preset).
+ *
+ * Names are case-insensitive; libhb will ensure that the lists do not contain
+ * more than one entry with the same name.
+ *
+ * Use hb_*_get_limits() to get the minimum/maximum for lists with numerically
+ * ordered values.
+ *
+ * Use hb_*_get_best() to sanitize a value based on other relevant parameters.
+ *
+ * Use hb_*_get_default() to get the default based on other relevant parameters.
+ *
+ */
+
+int hb_video_framerate_get_from_name(const char *name);
+const char* hb_video_framerate_get_name(int framerate);
+const char* hb_video_framerate_sanitize_name(const char *name);
+const hb_rate_t* hb_video_framerate_get_next(const hb_rate_t *last);
+
+int hb_audio_samplerate_get_best(uint32_t codec, int samplerate, int *sr_shift);
+int hb_audio_samplerate_get_from_name(const char *name);
+const char* hb_audio_samplerate_get_name(int samplerate);
+const hb_rate_t* hb_audio_samplerate_get_next(const hb_rate_t *last);
+
+int hb_audio_bitrate_get_best(uint32_t codec, int bitrate, int samplerate, int mixdown);
+int hb_audio_bitrate_get_default(uint32_t codec, int samplerate, int mixdown);
+void hb_audio_bitrate_get_limits(uint32_t codec, int samplerate, int mixdown, int *low, int *high);
+const hb_rate_t* hb_audio_bitrate_get_next(const hb_rate_t *last);
+
+void hb_audio_quality_get_limits(uint32_t codec, float *low, float *high, float *granularity, int *direction);
+float hb_audio_quality_get_best(uint32_t codec, float quality);
+float hb_audio_quality_get_default(uint32_t codec);
+
+void hb_audio_compression_get_limits(uint32_t codec, float *low, float *high, float *granularity, int *direction);
+float hb_audio_compression_get_best(uint32_t codec, float compression);
+float hb_audio_compression_get_default(uint32_t codec);
+
+int hb_audio_dither_get_default();
+int hb_audio_dither_get_default_method(); // default method, if enabled && supported
+int hb_audio_dither_is_supported(uint32_t codec);
+int hb_audio_dither_get_from_name(const char *name);
+const char* hb_audio_dither_get_description(int method);
+const hb_dither_t* hb_audio_dither_get_next(const hb_dither_t *last);
+
+int hb_mixdown_is_supported(int mixdown, uint32_t codec, uint64_t layout);
+int hb_mixdown_has_codec_support(int mixdown, uint32_t codec);
+int hb_mixdown_has_remix_support(int mixdown, uint64_t layout);
+int hb_mixdown_get_discrete_channel_count(int mixdown);
+int hb_mixdown_get_low_freq_channel_count(int mixdown);
+int hb_mixdown_get_best(uint32_t codec, uint64_t layout, int mixdown);
+int hb_mixdown_get_default(uint32_t codec, uint64_t layout);
+int hb_mixdown_get_from_name(const char *name);
+const char* hb_mixdown_get_name(int mixdown);
+const char* hb_mixdown_get_short_name(int mixdown);
+const char* hb_mixdown_sanitize_name(const char *name);
+const hb_mixdown_t* hb_mixdown_get_next(const hb_mixdown_t *last);
+
+int hb_video_encoder_get_default(int muxer);
+int hb_video_encoder_get_from_name(const char *name);
+const char* hb_video_encoder_get_name(int encoder);
+const char* hb_video_encoder_get_short_name(int encoder);
+const char* hb_video_encoder_sanitize_name(const char *name);
+const hb_encoder_t* hb_video_encoder_get_next(const hb_encoder_t *last);
+
+/*
+ * hb_audio_encoder_get_fallback_for_passthru() will sanitize a passthru codec
+ * to the matching audio encoder (if any is available).
+ *
+ * hb_audio_encoder_get_from_name(), hb_audio_encoder_sanitize_name() will
+ * sanitize legacy encoder names, but won't convert passthru to an encoder.
+ */
+int hb_audio_encoder_get_fallback_for_passthru(int passthru);
+int hb_audio_encoder_get_default(int muxer);
+int hb_audio_encoder_get_from_name(const char *name);
+const char* hb_audio_encoder_get_name(int encoder);
+const char* hb_audio_encoder_get_short_name(int encoder);
+const char* hb_audio_encoder_sanitize_name(const char *name);
+const hb_encoder_t* hb_audio_encoder_get_next(const hb_encoder_t *last);
+/*
+ * Not typically used by the UIs
+ * (set hb_job_t.acodec_copy_mask, hb_job_t.acodec_fallback instead).
+ */
void hb_autopassthru_apply_settings(hb_job_t *job);
void hb_autopassthru_print_settings(hb_job_t *job);
int hb_autopassthru_get_encoder(int in_codec, int copy_mask, int fallback, int muxer);
-int hb_get_default_audio_encoder(int muxer);
-
-int hb_get_best_mixdown(uint32_t codec, uint64_t layout, int mixdown);
-int hb_get_default_mixdown(uint32_t codec, uint64_t layout);
-
-int hb_get_best_samplerate(uint32_t codec, int samplerate, int *sr_shift);
-
-int hb_find_closest_audio_bitrate(int bitrate);
-void hb_get_audio_bitrate_limits(uint32_t codec, int samplerate, int mixdown, int *low, int *high);
-int hb_get_best_audio_bitrate(uint32_t codec, int bitrate, int samplerate, int mixdown);
-int hb_get_default_audio_bitrate(uint32_t codec, int samplerate, int mixdown);
-
-void hb_get_audio_quality_limits(uint32_t codec, float *low, float *high, float *granularity, int *direction);
-float hb_get_best_audio_quality(uint32_t codec, float quality);
-float hb_get_default_audio_quality(uint32_t codec);
-
-void hb_get_audio_compression_limits(uint32_t codec, float *low, float *high, float *granularity, int *direction);
-float hb_get_best_audio_compression(uint32_t codec, float compression);
-float hb_get_default_audio_compression(uint32_t codec);
+int hb_container_get_from_name(const char *name);
+int hb_container_get_from_extension(const char *extension); // not really a container name
+const char* hb_container_get_name(int format);
+const char* hb_container_get_short_name(int format);
+const char* hb_container_get_default_extension(int format);
+const char* hb_container_sanitize_name(const char *name);
+const hb_container_t* hb_container_get_next(const hb_container_t *last);
struct hb_title_set_s
{
int vcodec;
float vquality;
int vbitrate;
- int pfr_vrate;
- int pfr_vrate_base;
int vrate;
int vrate_base;
int cfr;
hb_metadata_t * metadata;
- /* Muxer settings
- mux: output file format
- file: file path */
-#define HB_MUX_MASK 0xFF0000
-#define HB_MUX_MP4 0x010000
-#define HB_MUX_MKV 0x200000
+ /*
+ * Muxer settings
+ * mux: output file format
+ * file: file path
+ */
+#define HB_MUX_MASK 0xFF0000
+#define HB_MUX_MP4V2 0x010000
+#define HB_MUX_MASK_MP4 0x0F0000
+#define HB_MUX_LIBMKV 0x100000
+#define HB_MUX_MASK_MKV 0xF00000
+// default MP4 and MKV muxers
+#define HB_MUX_MP4 HB_MUX_MP4V2
+#define HB_MUX_MKV HB_MUX_LIBMKV
int mux;
char * file;
int crop[4];
int vrate_base;
int vrate;
- int pfr_vrate_base;
- int pfr_vrate;
int cfr;
} hb_filter_init_t;
pv->pix_fmt_out = init->pix_fmt;
pv->width_in = init->width;
pv->height_in = init->height;
- pv->width_out = init->width;
- pv->height_out = init->height;
+ pv->width_out = init->width - (init->crop[2] + init->crop[3]);
+ pv->height_out = init->height - (init->crop[0] + init->crop[1]);
memcpy( pv->crop, init->crop, sizeof( int[4] ) );
if( filter->settings )
{
// to fps.den.
if (fps.num == 27000000)
{
- int ii;
- for (ii = 0; ii < hb_video_rates_count; ii++)
+ const hb_rate_t *video_framerate = NULL;
+ while ((video_framerate = hb_video_framerate_get_next(video_framerate)) != NULL)
{
- if (abs(fps.den - hb_video_rates[ii].rate) < 10)
+ if (abs(fps.den - video_framerate->rate) < 10)
{
- fps.den = hb_video_rates[ii].rate;
+ fps.den = video_framerate->rate;
break;
}
}
// 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)
- for( i = 0; i < hb_video_rates_count; i++ )
+ 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, hb_video_rates[i].rate, 100 ) )
+ if (is_close_to(vid_info.rate_base, video_framerate->rate, 100))
{
- vid_info.rate_base = hb_video_rates[i].rate;
+ vid_info.rate_base = video_framerate->rate;
break;
}
}
}
}
-static int hb_vfr_init( hb_filter_object_t * filter,
- hb_filter_init_t * init )
+static int hb_vfr_init(hb_filter_object_t *filter, hb_filter_init_t *init)
{
- filter->private_data = calloc( 1, sizeof(struct hb_filter_private_s) );
- hb_filter_private_t * pv = filter->private_data;
+ filter->private_data = calloc(1, sizeof(struct hb_filter_private_s));
+ hb_filter_private_t *pv = filter->private_data;
+ build_gamma_lut(pv);
- build_gamma_lut( pv );
- pv->cfr = init->cfr;
+ pv->cfr = init->cfr;
pv->input_vrate = pv->vrate = init->vrate;
pv->input_vrate_base = pv->vrate_base = init->vrate_base;
- if( filter->settings )
+ if (filter->settings != NULL)
{
- sscanf( filter->settings, "%d:%d:%d",
- &pv->cfr, &pv->vrate, &pv->vrate_base );
+ sscanf(filter->settings, "%d:%d:%d",
+ &pv->cfr, &pv->vrate, &pv->vrate_base);
}
pv->job = init->job;
pv->lost_time[0] = 0; pv->lost_time[1] = 0; pv->lost_time[2] = 0; pv->lost_time[3] = 0;
pv->frame_metric = 1000; // Force first frame
- if ( pv->cfr == 0 )
- {
- /* Ensure we're using "Same as source" FPS */
- pv->vrate_base = init->vrate_base;
- pv->vrate = init->vrate;
- }
- else if ( pv->cfr == 2 )
+ 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.
+ // 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;
- if ( source_fps > peak_fps )
+ if (source_fps > peak_fps)
{
- // peak framerate is lower than source framerate. so signal
- // that the nominal framerate will be changed.
+ // 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;
}
- init->pfr_vrate = pv->vrate;
- init->pfr_vrate_base = pv->vrate_base;
}
else
{
- // Constant framerate. Signal the framerate we are using.
init->vrate = pv->vrate;
init->vrate_base = pv->vrate_base;
}
- init->cfr = pv->cfr;
- pv->frame_rate = (double)pv->vrate_base * 90000. / pv->vrate;
+ pv->frame_rate = (double)pv->vrate_base * 90000. / pv->vrate;
+ init->cfr = pv->cfr;
return 0;
}
return 1;
memset( info, 0, sizeof( hb_filter_info_t ) );
- info->out.vrate_base = pv->vrate_base;
- info->out.vrate = pv->vrate;
+ 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;
+ 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 )
{
* Displays job parameters in the debug log.
* @param job Handle work hb_job_t.
*/
-void hb_display_job_info( hb_job_t * job )
+void hb_display_job_info(hb_job_t *job)
{
- hb_title_t * title = job->title;
- hb_audio_t * audio;
- hb_subtitle_t * subtitle;
- int i, j;
+ int i;
+ hb_title_t *title = job->title;
+ hb_audio_t *audio;
+ hb_subtitle_t *subtitle;
hb_log("job configuration:");
hb_log( " * source");
sec_stop = (float)stop / 90000.0 - min_stop * 60;
min_stop %= 60;
- hb_log( " + title %d, start %d:%d:%.2f stop %d:%d:%.2f", title->index,
- hr_start, min_start, sec_start,
- hr_stop, min_stop, sec_stop);
+ hb_log(" + title %d, start %02d:%02d:%02.2f stop %02d:%02d:%02.2f",
+ title->index,
+ hr_start, min_start, sec_start,
+ hr_stop, min_stop, sec_stop);
}
else if( job->frame_to_start || job->frame_to_stop )
{
hb_log( " + %s", job->file );
- switch( job->mux )
+ hb_log(" + container: %s", hb_container_get_name(job->mux));
+ switch (job->mux)
{
- case HB_MUX_MP4:
- hb_log(" + container: MPEG-4 (.mp4 and .m4v)");
-
- if( job->ipod_atom )
- hb_log( " + compatibility atom for iPod 5G");
-
- if( job->largeFileSize )
- hb_log( " + 64-bit formatting");
-
- if( job->mp4_optimize )
- hb_log( " + optimized for progressive web downloads");
-
- if( job->color_matrix_code )
- hb_log( " + custom color matrix: %s", job->color_matrix_code == 1 ? "ITU Bt.601 (SD)" : job->color_matrix_code == 2 ? "ITU Bt.709 (HD)" : "Custom" );
+ case HB_MUX_MP4V2:
+ if (job->largeFileSize)
+ hb_log(" + 64-bit chunk offsets");
+ if (job->mp4_optimize)
+ hb_log(" + optimized for HTTP streaming (fast start)");
+ if (job->ipod_atom)
+ hb_log(" + compatibility atom for iPod 5G");
break;
- case HB_MUX_MKV:
- hb_log(" + container: Matroska (.mkv)");
+ default:
break;
}
hb_log( " + bitrate %d kbps", title->video_bitrate / 1000 );
}
- if( job->cfr == 0 )
- {
- hb_log( " + frame rate: same as source (around %.3f fps)",
- (float) title->rate / (float) title->rate_base );
- }
- else if( job->cfr == 1 )
- {
- hb_log( " + frame rate: %.3f fps -> constant %.3f fps",
- (float) title->rate / (float) title->rate_base,
- (float) job->vrate / (float) job->vrate_base );
- }
- else if( job->cfr == 2 )
- {
- hb_log( " + frame rate: %.3f fps -> peak rate limited to %.3f fps",
- (float) title->rate / (float) title->rate_base,
- (float) job->pfr_vrate / (float) job->pfr_vrate_base );
- }
-
// Filters can modify dimensions. So show them first.
if( hb_list_count( job->list_filter ) )
{
if( !job->indepth_scan )
{
/* Video encoder */
- for( i = 0; i < hb_video_encoders_count; i++ )
- {
- if( hb_video_encoders[i].encoder == job->vcodec )
- {
- hb_log( " + encoder: %s", hb_video_encoders[i].human_readable_name );
- break;
- }
- }
+ hb_log(" + encoder: %s", hb_video_encoder_get_name(job->vcodec));
if( job->x264_preset && *job->x264_preset &&
job->vcodec == HB_VCODEC_X264 )
hb_log( " subq=2 (if originally greater than 2, else subq unchanged)" );
}
}
+
+ if (job->color_matrix_code && (job->vcodec == HB_VCODEC_X264 ||
+ job->mux == HB_MUX_MP4V2))
+ {
+ // color matrix is set:
+ // 1) at the stream level (x264 only),
+ // 2) at the container level (mp4v2 only)
+ hb_log(" + custom color matrix: %s",
+ job->color_matrix_code == 1 ? "ITU Bt.601 (NTSC)" :
+ job->color_matrix_code == 2 ? "ITU Bt.601 (PAL)" :
+ job->color_matrix_code == 3 ? "ITU Bt.709 (HD)" : "Custom");
+ }
}
if( job->indepth_scan )
if( audio->config.out.codec & HB_ACODEC_PASS_FLAG )
{
- for( j = 0; j < hb_audio_encoders_count; j++ )
- {
- if( hb_audio_encoders[j].encoder == audio->config.out.codec )
- {
- hb_log( " + %s", hb_audio_encoders[j].human_readable_name );
- break;
- }
- }
+ hb_log(" + %s",
+ hb_audio_encoder_get_name(audio->config.out.codec));
}
else
{
- for( j = 0; j < hb_audio_mixdowns_count; j++ )
- {
- if( hb_audio_mixdowns[j].amixdown == audio->config.out.mixdown )
- {
- hb_log( " + mixdown: %s", hb_audio_mixdowns[j].human_readable_name );
- break;
- }
- }
+ hb_log(" + mixdown: %s",
+ hb_mixdown_get_name(audio->config.out.mixdown));
if( audio->config.out.normalize_mix_level != 0 )
{
hb_log( " + normalized mixing levels" );
hb_log(" + dither: %s",
hb_audio_dither_get_description(audio->config.out.dither_method));
}
- for( j = 0; j < hb_audio_encoders_count; j++ )
+ hb_log(" + encoder: %s",
+ hb_audio_encoder_get_name(audio->config.out.codec));
+ if (audio->config.out.bitrate > 0)
{
- if( hb_audio_encoders[j].encoder == audio->config.out.codec )
- {
- hb_log( " + encoder: %s", hb_audio_encoders[j].human_readable_name );
- if( audio->config.out.bitrate > 0 )
- hb_log( " + bitrate: %d kbps, samplerate: %d Hz", audio->config.out.bitrate, audio->config.out.samplerate );
- else if( audio->config.out.quality != HB_INVALID_AUDIO_QUALITY )
- hb_log( " + quality: %.2f, samplerate: %d Hz", audio->config.out.quality, audio->config.out.samplerate );
- else if( audio->config.out.samplerate > 0 )
- hb_log( " + samplerate: %d Hz", audio->config.out.samplerate );
- if( audio->config.out.compression_level >= 0 )
- hb_log( " + compression level: %.2f",
- audio->config.out.compression_level );
- break;
- }
+ hb_log(" + bitrate: %d kbps, samplerate: %d Hz",
+ audio->config.out.bitrate, audio->config.out.samplerate);
+ }
+ else if (audio->config.out.quality != HB_INVALID_AUDIO_QUALITY)
+ {
+ hb_log(" + quality: %.2f, samplerate: %d Hz",
+ audio->config.out.quality, audio->config.out.samplerate);
+ }
+ else if (audio->config.out.samplerate > 0)
+ {
+ hb_log(" + samplerate: %d Hz",
+ audio->config.out.samplerate);
+ }
+ if (audio->config.out.compression_level >= 0)
+ {
+ hb_log(" + compression level: %.2f",
+ audio->config.out.compression_level);
}
}
}
* Closes threads and frees fifos.
* @param job Handle work hb_job_t.
*/
-static void do_job( hb_job_t * job )
+static void do_job(hb_job_t *job)
{
- hb_title_t * title;
- int i, j;
- hb_work_object_t * w;
- hb_work_object_t * sync;
- hb_work_object_t * muxer;
+ int i;
+ hb_title_t *title;
+ hb_interjob_t *interjob;
+ hb_work_object_t *w;
+ hb_work_object_t *sync;
+ hb_work_object_t *muxer;
hb_work_object_t *reader = hb_get_work(WORK_READER);
- hb_interjob_t * interjob;
-
- hb_audio_t * audio;
- hb_subtitle_t * subtitle;
- unsigned int subtitle_highest = 0;
- unsigned int subtitle_lowest = 0;
- unsigned int subtitle_lowest_id = 0;
- unsigned int subtitle_forced_id = 0;
+
+ hb_audio_t *audio;
+ hb_subtitle_t *subtitle;
+ unsigned int subtitle_highest = 0;
+ unsigned int subtitle_lowest = 0;
+ unsigned int subtitle_lowest_id = 0;
+ unsigned int subtitle_forced_id = 0;
unsigned int subtitle_forced_hits = 0;
- unsigned int subtitle_hit = 0;
+ unsigned int subtitle_hit = 0;
title = job->title;
interjob = hb_interjob_get( job->h );
init.height = title->height;
init.par_width = job->anamorphic.par_width;
init.par_height = job->anamorphic.par_height;
- memcpy(init.crop, job->crop, sizeof(int[4]));
- init.vrate_base = job->vrate_base;
- init.vrate = job->vrate;
- init.pfr_vrate_base = job->pfr_vrate_base;
- init.pfr_vrate = job->pfr_vrate;
+ memcpy(init.crop, title->crop, sizeof(int[4]));
+ init.vrate_base = title->rate_base;
+ init.vrate = title->rate;
init.cfr = 0;
int is_vpp_interlace = 0;
memcpy(job->crop, init.crop, sizeof(int[4]));
job->vrate_base = init.vrate_base;
job->vrate = init.vrate;
- job->pfr_vrate_base = init.pfr_vrate_base;
- job->pfr_vrate = init.pfr_vrate;
job->cfr = init.cfr;
}
audio->config.out.samplerate = audio->config.in.samplerate;
}
best_samplerate =
- hb_get_best_samplerate(audio->config.out.codec,
- audio->config.out.samplerate, NULL);
+ hb_audio_samplerate_get_best(audio->config.out.codec,
+ audio->config.out.samplerate,
+ NULL);
if (best_samplerate != audio->config.out.samplerate)
{
- int ii;
- for (ii = 0; ii < hb_audio_rates_count; ii++)
- {
- if (best_samplerate == hb_audio_rates[ii].rate)
- {
- hb_log("work: sanitizing track %d unsupported samplerate %d Hz to %s kHz",
- audio->config.out.track, audio->config.out.samplerate,
- hb_audio_rates[ii].string);
- break;
- }
- }
+ hb_log("work: sanitizing track %d unsupported samplerate %d Hz to %s kHz",
+ audio->config.out.track, audio->config.out.samplerate,
+ hb_audio_samplerate_get_name(best_samplerate));
audio->config.out.samplerate = best_samplerate;
}
{
/* Mixdown not specified, set the default mixdown */
audio->config.out.mixdown =
- hb_get_default_mixdown(audio->config.out.codec,
+ hb_mixdown_get_default(audio->config.out.codec,
audio->config.in.channel_layout);
- for (j = 0; j < hb_audio_mixdowns_count; j++)
- {
- if (hb_audio_mixdowns[j].amixdown == audio->config.out.mixdown)
- {
- hb_log("work: mixdown not specified, track %d setting mixdown %s",
- audio->config.out.track,
- hb_audio_mixdowns[j].human_readable_name);
- break;
- }
- }
+ hb_log("work: mixdown not specified, track %d setting mixdown %s",
+ audio->config.out.track,
+ hb_mixdown_get_name(audio->config.out.mixdown));
}
else
{
best_mixdown =
- hb_get_best_mixdown(audio->config.out.codec,
+ hb_mixdown_get_best(audio->config.out.codec,
audio->config.in.channel_layout,
audio->config.out.mixdown);
if (audio->config.out.mixdown != best_mixdown)
{
- int prev_mix_idx = 0, best_mix_idx = 0;
- for (j = 0; j < hb_audio_mixdowns_count; j++)
- {
- if (hb_audio_mixdowns[j].amixdown == audio->config.out.mixdown)
- {
- prev_mix_idx = j;
- }
- else if (hb_audio_mixdowns[j].amixdown == best_mixdown)
- {
- best_mix_idx = j;
- }
- }
/* log the output mixdown */
hb_log("work: sanitizing track %d mixdown %s to %s",
audio->config.out.track,
- hb_audio_mixdowns[prev_mix_idx].human_readable_name,
- hb_audio_mixdowns[best_mix_idx].human_readable_name);
+ hb_mixdown_get_name(audio->config.out.mixdown),
+ hb_mixdown_get_name(best_mixdown));
audio->config.out.mixdown = best_mixdown;
}
}
if (audio->config.out.compression_level < 0)
{
audio->config.out.compression_level =
- hb_get_default_audio_compression(audio->config.out.codec);
+ hb_audio_compression_get_default(audio->config.out.codec);
if (audio->config.out.compression_level >= 0)
{
hb_log("work: compression level not specified, track %d setting compression level %.2f",
else
{
float best_compression =
- hb_get_best_audio_compression(audio->config.out.codec,
+ hb_audio_compression_get_best(audio->config.out.codec,
audio->config.out.compression_level);
if (best_compression != audio->config.out.compression_level)
{
if (audio->config.out.quality != HB_INVALID_AUDIO_QUALITY)
{
float best_quality =
- hb_get_best_audio_quality(audio->config.out.codec,
+ hb_audio_quality_get_best(audio->config.out.codec,
audio->config.out.quality);
if (best_quality != audio->config.out.quality)
{
{
/* Bitrate not specified, set the default bitrate */
audio->config.out.bitrate =
- hb_get_default_audio_bitrate(audio->config.out.codec,
+ hb_audio_bitrate_get_default(audio->config.out.codec,
audio->config.out.samplerate,
audio->config.out.mixdown);
if (audio->config.out.bitrate > 0)
else
{
best_bitrate =
- hb_get_best_audio_bitrate(audio->config.out.codec,
+ hb_audio_bitrate_get_best(audio->config.out.codec,
audio->config.out.bitrate,
audio->config.out.samplerate,
audio->config.out.mixdown);
/* Destination box*/
NSMenuItem *menuItem;
[fDstFormatPopUp removeAllItems];
- // MP4 file
- menuItem = [[fDstFormatPopUp menu] addItemWithTitle:@"MP4 file" action: NULL keyEquivalent: @""];
- [menuItem setTag: HB_MUX_MP4];
- // MKV file
- menuItem = [[fDstFormatPopUp menu] addItemWithTitle:@"MKV file" action: NULL keyEquivalent: @""];
- [menuItem setTag: HB_MUX_MKV];
-
- [fDstFormatPopUp selectItemAtIndex: 0];
-
+ for (const hb_container_t *container = hb_container_get_next(NULL);
+ container != NULL;
+ container = hb_container_get_next(container))
+ {
+ menuItem = [[fDstFormatPopUp menu] addItemWithTitle:[NSString stringWithUTF8String:container->name]
+ action:nil
+ keyEquivalent:@""];
+ [menuItem setTag:container->format];
+ }
+ // select the first container
+ [fDstFormatPopUp selectItemAtIndex:0];
[self formatPopUpChanged:nil];
+
+ // enable/disable chapter markers as necessary
+ if ([fCreateChapterMarkers isEnabled] &&
+ [[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultChapterMarkers"])
+ {
+ [fCreateChapterMarkers setState:NSOnState];
+ }
+ else
+ {
+ [fCreateChapterMarkers setState:NSOffState];
+ }
- /* We enable the create chapters checkbox here since we are .mp4 */
- [fCreateChapterMarkers setEnabled: YES];
- if ([fDstFormatPopUp indexOfSelectedItem] == 0 && [[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultChapterMarkers"] > 0)
- {
- [fCreateChapterMarkers setState: NSOnState];
- }
-
-
-
-
- [fDstFile2Field setStringValue: [NSString stringWithFormat:
- @"%@/Desktop/Movie.mp4", NSHomeDirectory()]];
+ [fDstFile2Field setStringValue:[NSString
+ stringWithFormat:@"%@/Desktop/Movie.mp4",
+ NSHomeDirectory()]];
/* Video encoder */
[fVidEncoderPopUp removeAllItems];
/* Video framerate */
[fVidRatePopUp removeAllItems];
- [fVidRatePopUp addItemWithTitle: NSLocalizedString( @"Same as source", @"" )];
- for( int i = 0; i < hb_video_rates_count; i++ )
+ menuItem = [[fVidRatePopUp menu] addItemWithTitle:@"Same as source"
+ action:nil
+ keyEquivalent:@""];
+ [menuItem setTag:-1]; // hb_video_framerate_get_from_name(NULL)
+ for (const hb_rate_t *video_framerate = hb_video_framerate_get_next(NULL);
+ video_framerate != NULL;
+ video_framerate = hb_video_framerate_get_next(video_framerate))
{
- if ([[NSString stringWithUTF8String: hb_video_rates[i].string] isEqualToString: [NSString stringWithFormat: @"%.3f",23.976]])
- {
- [fVidRatePopUp addItemWithTitle:[NSString stringWithFormat: @"%@%@",
- [NSString stringWithUTF8String: hb_video_rates[i].string], @" (NTSC Film)"]];
- }
- else if ([[NSString stringWithUTF8String: hb_video_rates[i].string] isEqualToString: [NSString stringWithFormat: @"%d",25]])
- {
- [fVidRatePopUp addItemWithTitle:[NSString stringWithFormat: @"%@%@",
- [NSString stringWithUTF8String: hb_video_rates[i].string], @" (PAL Film/Video)"]];
- }
- else if ([[NSString stringWithUTF8String: hb_video_rates[i].string] isEqualToString: [NSString stringWithFormat: @"%.2f",29.97]])
- {
- [fVidRatePopUp addItemWithTitle:[NSString stringWithFormat: @"%@%@",
- [NSString stringWithUTF8String: hb_video_rates[i].string], @" (NTSC Video)"]];
- }
- else
- {
- [fVidRatePopUp addItemWithTitle:
- [NSString stringWithUTF8String: hb_video_rates[i].string]];
- }
+ NSString *itemTitle;
+ if (!strcmp(video_framerate->name, "23.976"))
+ {
+ itemTitle = @"23.976 (NTSC Film)";
+ }
+ else if (!strcmp(video_framerate->name, "25"))
+ {
+ itemTitle = @"25 (PAL Film/Video)";
+ }
+ else if (!strcmp(video_framerate->name, "29.97"))
+ {
+ itemTitle = @"29.97 (NTSC Video)";
+ }
+ else
+ {
+ itemTitle = [NSString stringWithUTF8String:video_framerate->name];
+ }
+ menuItem = [[fVidRatePopUp menu] addItemWithTitle:itemTitle
+ action:nil
+ keyEquivalent:@""];
+ [menuItem setTag:video_framerate->rate];
}
- [fVidRatePopUp selectItemAtIndex: 0];
+ [fVidRatePopUp selectItemAtIndex:0];
/* Set Auto Crop to On at launch */
[fPictureController setAutoCrop:YES];
[fSrcDVD2Field setStringValue:browsedSourceDisplayName];
// use the correct extension based on the container
- int format = [fDstFormatPopUp indexOfSelectedItem];
- char *ext = "mp4";
- if (format == 1)
- {
- ext = "mkv";
- }
+ int videoContainer = [[fDstFormatPopUp selectedItem] tag];
+ const char *ext = hb_container_get_default_extension(videoContainer);
/* If its a queue rescan for edit, get the queue item output path */
/* if not, its a new source scan. */
}
// set m4v extension if necessary - do not override user-specified .mp4 extension
- if (format == 0 && applyQueueToScan != YES)
+ if ((videoContainer & HB_MUX_MASK_MP4) && (applyQueueToScan != YES))
{
- [self autoSetM4vExtension: sender];
+ [self autoSetM4vExtension:sender];
}
/* See if this is the main feature according to libhb */
/* Framerate */
[queueFileJob setObject:[NSNumber numberWithInt:[fVidRatePopUp indexOfSelectedItem]] forKey:@"JobIndexVideoFramerate"];
- [queueFileJob setObject:[NSNumber numberWithInt:title->rate] forKey:@"JobVrate"];
- [queueFileJob setObject:[NSNumber numberWithInt:title->rate_base] forKey:@"JobVrateBase"];
+ [queueFileJob setObject:[NSNumber numberWithInt:title->rate] forKey:@"JobVrate"];
+ [queueFileJob setObject:[NSNumber numberWithInt:title->rate_base] forKey:@"JobVrateBase"];
/* Picture Sizing */
/* Use Max Picture settings for whatever the dvd is.*/
}
/* Video settings */
-
+ int fps_mode, fps_num, fps_den;
if( [fVidRatePopUp indexOfSelectedItem] > 0 )
{
/* a specific framerate has been chosen */
- job->vrate = 27000000;
- job->vrate_base = hb_video_rates[[fVidRatePopUp indexOfSelectedItem]-1].rate;
+ fps_num = 27000000;
+ fps_den = [[fVidRatePopUp selectedItem] tag];
if ([fFramerateMatrix selectedRow] == 1)
{
// CFR
- job->cfr = 1;
+ fps_mode = 1;
}
else
{
// PFR
- job->cfr = 2;
+ fps_mode = 2;
}
}
else
{
/* same as source */
- job->vrate = title->rate;
- job->vrate_base = title->rate_base;
+ fps_num = title->rate;
+ fps_den = title->rate_base;
if ([fFramerateMatrix selectedRow] == 1)
{
// CFR
- job->cfr = 1;
+ fps_mode = 1;
}
else
{
// VFR
- job->cfr = 0;
+ fps_mode = 0;
}
}
job->crop[2], job->crop[3]] UTF8String] );
/* Add framerate shaping filter */
- filter = hb_filter_init( HB_FILTER_VFR );
- hb_add_filter( job, filter, [[NSString stringWithFormat:@"%d:%d:%d",
- job->cfr, job->vrate, job->vrate_base] UTF8String] );
+ filter = hb_filter_init(HB_FILTER_VFR);
+ hb_add_filter(job, filter, [[NSString stringWithFormat:@"%d:%d:%d",
+ fps_mode, fps_num, fps_den] UTF8String]);
}
/* Video settings */
/* Framerate */
-
- if( [[queueToApply objectForKey:@"JobIndexVideoFramerate"] intValue] > 0 )
+ int fps_mode, fps_num, fps_den;
+ if ([[queueToApply objectForKey:@"JobIndexVideoFramerate"] intValue] > 0)
{
/* a specific framerate has been chosen */
- job->vrate = 27000000;
- job->vrate_base = hb_video_rates[[[queueToApply objectForKey:@"JobIndexVideoFramerate"] intValue]-1].rate;
+ fps_num = 27000000;
+ fps_den = [[fVidRatePopUp itemAtIndex:[[queueToApply objectForKey:@"JobIndexVideoFramerate"] intValue]] tag];
if ([[queueToApply objectForKey:@"VideoFramerateMode"] isEqualToString:@"cfr"])
{
// CFR
- job->cfr = 1;
+ fps_mode = 1;
}
else
{
// PFR
- job->cfr = 2;
+ fps_mode = 2;
}
}
else
{
/* same as source */
- job->vrate = [[queueToApply objectForKey:@"JobVrate"] intValue];
- job->vrate_base = [[queueToApply objectForKey:@"JobVrateBase"] intValue];
+ fps_num = [[queueToApply objectForKey:@"JobVrate"] intValue];
+ fps_den = [[queueToApply objectForKey:@"JobVrateBase"] intValue];
if ([[queueToApply objectForKey:@"VideoFramerateMode"] isEqualToString:@"cfr"])
{
// CFR
- job->cfr = 1;
+ fps_mode = 1;
}
else
{
// VFR
- job->cfr = 0;
+ fps_mode = 0;
}
}
/* We go ahead and assign values to our audio->out.<properties> */
audio->out.track = audio->in.track;
audio->out.codec = [[queueToApply objectForKey:[jobPrefix stringByAppendingString:@"Encoder"]] intValue];
- audio->out.compression_level = hb_get_default_audio_compression(audio->out.codec);
+ audio->out.compression_level = hb_audio_compression_get_default(audio->out.codec);
audio->out.mixdown = [[queueToApply objectForKey:[jobPrefix stringByAppendingString:@"Mixdown"]] intValue];
audio->out.normalize_mix_level = 0;
audio->out.bitrate = [[queueToApply objectForKey:[jobPrefix stringByAppendingString:@"Bitrate"]] intValue];
job->crop[2], job->crop[3]] UTF8String] );
/* Add framerate shaping filter */
- filter = hb_filter_init( HB_FILTER_VFR );
- hb_add_filter( job, filter, [[NSString stringWithFormat:@"%d:%d:%d",
- job->cfr, job->vrate, job->vrate_base] UTF8String] );
+ filter = hb_filter_init(HB_FILTER_VFR);
+ hb_add_filter(job, filter, [[NSString stringWithFormat:@"%d:%d:%d",
+ fps_mode, fps_num, fps_den] UTF8String]);
[self writeToActivityLog: "prepareJob exiting"];
}
- (IBAction) formatPopUpChanged: (id) sender
{
- NSString * string = [fDstFile2Field stringValue];
- int format = [fDstFormatPopUp indexOfSelectedItem];
- char * ext = NULL;
+ NSString *string = [fDstFile2Field stringValue];
+ int videoContainer = [[fDstFormatPopUp selectedItem] tag];
+ const char *ext = NULL;
NSMenuItem *menuItem;
- int i;
- /* Initially set the large file (64 bit formatting) output checkbox to hidden */
- [fDstMp4LargeFileCheck setHidden: YES];
- [fDstMp4HttpOptFileCheck setHidden: YES];
- [fDstMp4iPodFileCheck setHidden: YES];
+ /* Initially set the large file (64 bit formatting) output checkbox to hidden */
+ [fDstMp4LargeFileCheck setHidden:YES];
+ [fDstMp4HttpOptFileCheck setHidden:YES];
+ [fDstMp4iPodFileCheck setHidden:YES];
/* Update the Video Codec Popup */
/* lets get the tag of the currently selected item first so we might reset it later */
- int selectedVidEncoderTag;
- selectedVidEncoderTag = [[fVidEncoderPopUp selectedItem] tag];
+ int selectedVidEncoderTag = [[fVidEncoderPopUp selectedItem] tag];
/* Note: we now store the video encoder int values from common.c in the tags of each popup for easy retrieval later */
[fVidEncoderPopUp removeAllItems];
- for( i = 0; i < hb_video_encoders_count; i++ )
+ for (const hb_encoder_t *video_encoder = hb_video_encoder_get_next(NULL);
+ video_encoder != NULL;
+ video_encoder = hb_video_encoder_get_next(video_encoder))
{
- if( ( ( format == 0 ) && ( hb_video_encoders[i].muxers & HB_MUX_MP4 ) ) ||
- ( ( format == 1 ) && ( hb_video_encoders[i].muxers & HB_MUX_MKV ) ) )
+ if (video_encoder->muxers & videoContainer)
{
- menuItem = [[fVidEncoderPopUp menu] addItemWithTitle: [NSString stringWithUTF8String: hb_video_encoders[i].human_readable_name]
- action: NULL keyEquivalent: @""];
- [menuItem setTag: hb_video_encoders[i].encoder];
+ menuItem = [[fVidEncoderPopUp menu] addItemWithTitle:[NSString stringWithUTF8String:video_encoder->name]
+ action:nil
+ keyEquivalent:@""];
+ [menuItem setTag:video_encoder->codec];
}
}
/* Update the Auto Passtgru Fallback Codec Popup */
/* lets get the tag of the currently selected item first so we might reset it later */
- int selectedAutoPassthruFallbackEncoderTag;
- selectedAutoPassthruFallbackEncoderTag = [[fAudioFallbackPopUp selectedItem] tag];
+ int selectedAutoPassthruFallbackEncoderTag = [[fAudioFallbackPopUp selectedItem] tag];
[fAudioFallbackPopUp removeAllItems];
- for( i = 0; i < hb_audio_encoders_count; i++ )
+ for (const hb_encoder_t *audio_encoder = hb_audio_encoder_get_next(NULL);
+ audio_encoder != NULL;
+ audio_encoder = hb_audio_encoder_get_next(audio_encoder))
{
- if( !( hb_audio_encoders[i].encoder & HB_ACODEC_PASS_FLAG ) &&
- ( ( ( format == 0 ) && ( hb_audio_encoders[i].muxers & HB_MUX_MP4 ) ) ||
- ( ( format == 1 ) && ( hb_audio_encoders[i].muxers & HB_MUX_MKV ) ) ) )
+ if ((audio_encoder->codec & HB_ACODEC_PASS_FLAG) == 0 &&
+ (audio_encoder->muxers & videoContainer))
{
- menuItem = [[fAudioFallbackPopUp menu] addItemWithTitle: [NSString stringWithUTF8String: hb_audio_encoders[i].human_readable_name]
- action: NULL keyEquivalent: @""];
- [menuItem setTag: hb_audio_encoders[i].encoder];
+ menuItem = [[fAudioFallbackPopUp menu] addItemWithTitle:[NSString stringWithUTF8String:audio_encoder->name]
+ action:nil
+ keyEquivalent:@""];
+ [menuItem setTag:audio_encoder->codec];
}
}
/* if we have a previously selected auto passthru fallback encoder tag, then try to select it */
if (selectedAutoPassthruFallbackEncoderTag)
{
- selectedAutoPassthruFallbackEncoderTag = [fAudioFallbackPopUp selectItemWithTag: selectedAutoPassthruFallbackEncoderTag];
+ selectedAutoPassthruFallbackEncoderTag = [fAudioFallbackPopUp selectItemWithTag:selectedAutoPassthruFallbackEncoderTag];
}
/* if we had no previous fallback selected OR if selection failed
* select the default fallback encoder (AC3) */
if (!selectedAutoPassthruFallbackEncoderTag)
{
- [fAudioFallbackPopUp selectItemWithTag: HB_ACODEC_AC3];
+ [fAudioFallbackPopUp selectItemWithTag:HB_ACODEC_AC3];
}
- switch( format )
+ // enable chapter markers and hide muxer-specific options
+ [fCreateChapterMarkers setEnabled:YES];
+ [fDstMp4LargeFileCheck setHidden:YES];
+ [fDstMp4HttpOptFileCheck setHidden:YES];
+ [fDstMp4iPodFileCheck setHidden:YES];
+ switch (videoContainer)
{
- case 0:
- [self autoSetM4vExtension: nil];
- /* We show the mp4 option checkboxes here since we are mp4 */
- [fCreateChapterMarkers setEnabled: YES];
- [fDstMp4LargeFileCheck setHidden: NO];
- [fDstMp4HttpOptFileCheck setHidden: NO];
- [fDstMp4iPodFileCheck setHidden: NO];
+ case HB_MUX_MP4V2:
+ [fDstMp4LargeFileCheck setHidden:NO];
+ [fDstMp4HttpOptFileCheck setHidden:NO];
+ [fDstMp4iPodFileCheck setHidden:NO];
break;
-
- case 1:
- ext = "mkv";
- /* We enable the create chapters checkbox here */
- [fCreateChapterMarkers setEnabled: YES];
- break;
-
+ default:
+ break;
+ }
+ // set the file extension
+ ext = hb_container_get_default_extension(videoContainer);
+ [fDstFile2Field setStringValue:[NSString stringWithFormat:@"%@.%s",
+ [string stringByDeletingPathExtension],
+ ext]];
+ if (videoContainer & HB_MUX_MASK_MP4)
+ {
+ [self autoSetM4vExtension:sender];
}
- /* tell fSubtitlesDelegate we have a new video container */
- [fSubtitlesDelegate containerChanged:[[fDstFormatPopUp selectedItem] tag]];
+ /* tell fSubtitlesDelegate we have a new video container */
+ [fSubtitlesDelegate containerChanged:videoContainer];
[fSubtitlesTable reloadData];
- /* post a notification for any interested observers to indicate that our video container has changed */
- [[NSNotificationCenter defaultCenter] postNotification:
- [NSNotification notificationWithName: HBContainerChangedNotification
- object: self
- userInfo: [NSDictionary dictionaryWithObjectsAndKeys:
- [NSNumber numberWithInt: [[fDstFormatPopUp selectedItem] tag]], keyContainerTag,
- nil]]];
-
- if( format == 0 )
- [self autoSetM4vExtension: sender];
- else
- [fDstFile2Field setStringValue: [NSString stringWithFormat:@"%@.%s", [string stringByDeletingPathExtension], ext]];
+ /* post a notification for any interested observers to indicate that our video container has changed */
+ [[NSNotificationCenter defaultCenter] postNotification:
+ [NSNotification notificationWithName:HBContainerChangedNotification
+ object:self
+ userInfo:[NSDictionary dictionaryWithObjectsAndKeys:
+ [NSNumber numberWithInt:videoContainer], keyContainerTag,
+ nil]]];
if (SuccessfulScan)
{
- (IBAction) videoEncoderPopUpChanged: (id) sender
{
+ /* if no valid encoder is selected, use the first one */
+ if ([fVidEncoderPopUp selectedItem] == nil)
+ {
+ [fVidEncoderPopUp selectItemAtIndex:0];
+ }
+
int videoEncoder = [[fVidEncoderPopUp selectedItem] tag];
[fAdvancedOptions setHidden:YES];
- (IBAction ) videoFrameRateChanged: (id) sender
{
+ /* if no valid framerate is selected, use "Same as source" */
+ if ([fVidRatePopUp selectedItem] == nil)
+ {
+ [fVidRatePopUp selectItemAtIndex:0];
+ }
+
/* Hide and set the PFR Checkbox to OFF if we are set to Same as Source */
/* Depending on whether or not Same as source is selected modify the title for
* fFramerateVfrPfrCell*/
- (NSString*) muxerOptionsSummary
{
NSMutableString *summary = [NSMutableString stringWithString:@""];
- if (([fDstFormatPopUp selectedItem]) &&
- [[fDstFormatPopUp selectedItem] tag] == HB_MUX_MP4)
+ if ([fDstMp4LargeFileCheck isHidden] == NO &&
+ [fDstMp4LargeFileCheck isEnabled] == YES &&
+ [fDstMp4LargeFileCheck state] == NSOnState)
{
- if ([fDstMp4LargeFileCheck state])
- {
- [summary appendString:@" - Large file size"];
- }
- if ([fDstMp4HttpOptFileCheck state])
- {
- [summary appendString:@" - Web optimized"];
- }
- if ([fDstMp4iPodFileCheck state])
- {
- [summary appendString:@" - iPod 5G support"];
- }
+ [summary appendString:@" - Large file size"];
+ }
+ if ([fDstMp4HttpOptFileCheck isHidden] == NO &&
+ [fDstMp4HttpOptFileCheck isEnabled] == YES &&
+ [fDstMp4HttpOptFileCheck state] == NSOnState)
+ {
+ [summary appendString:@" - Web optimized"];
+ }
+ if ([fDstMp4iPodFileCheck isHidden] == NO &&
+ [fDstMp4iPodFileCheck isEnabled] == YES &&
+ [fDstMp4iPodFileCheck state] == NSOnState)
+ {
+ [summary appendString:@" - iPod 5G support"];
}
if ([summary hasPrefix:@" - "])
{
- (IBAction)selectPreset:(id)sender
{
-
if (YES == [self hasValidPresetSelected])
{
+ // for mapping names via libhb
+ int intValue;
+ const char *strValue;
chosenPreset = [self selectedPreset];
[fPresetSelectedDisplay setStringValue:[chosenPreset objectForKey:@"PresetName"]];
}
/* File Format */
- [fDstFormatPopUp selectItemWithTitle:[chosenPreset objectForKey:@"FileFormat"]];
+ /* map legacy container names via libhb */
+ strValue = hb_container_sanitize_name([[chosenPreset objectForKey:@"FileFormat"] UTF8String]);
+ [fDstFormatPopUp selectItemWithTitle:[NSString stringWithFormat:@"%s", strValue]];
[self formatPopUpChanged:nil];
/* Chapter Markers*/
[fDstMp4HttpOptFileCheck setState:[[chosenPreset objectForKey:@"Mp4HttpOptimize"] intValue]];
/* Video encoder */
- [fVidEncoderPopUp selectItemWithTitle:[chosenPreset objectForKey:@"VideoEncoder"]];
+ /* map legacy encoder names via libhb */
+ strValue = hb_video_encoder_sanitize_name([[chosenPreset objectForKey:@"VideoEncoder"] UTF8String]);
+ [fVidEncoderPopUp selectItemWithTitle:[NSString stringWithFormat:@"%s", strValue]];
[self videoEncoderPopUpChanged:nil];
- if ([[chosenPreset objectForKey:@"VideoEncoder"] isEqualToString:@"H.264 (x264)"])
+ if ([[fVidEncoderPopUp selectedItem] tag] == HB_VCODEC_X264)
{
if (![chosenPreset objectForKey:@"x264UseAdvancedOptions"] ||
[[chosenPreset objectForKey:@"x264UseAdvancedOptions"] intValue])
[fFramerateMatrix selectCellAtRow:1 column:0]; // we want cfr
}
}
- [fVidRatePopUp selectItemWithTitle:[chosenPreset objectForKey:@"VideoFramerate"]];
+ /* map legacy names via libhb */
+ intValue = hb_video_framerate_get_from_name([[chosenPreset objectForKey:@"VideoFramerate"] UTF8String]);
+ [fVidRatePopUp selectItemWithTag:intValue];
[self videoFrameRateChanged:nil];
/* 2 Pass Encoding */
}
if ((tempObject = [chosenPreset objectForKey:@"AudioEncoderFallback"]) != nil)
{
- [fAudioFallbackPopUp selectItemWithTitle:tempObject];
+ /* map legacy encoder names via libhb */
+ strValue = hb_audio_encoder_sanitize_name([tempObject UTF8String]);
+ [fAudioFallbackPopUp selectItemWithTitle:[NSString stringWithFormat:@"%s", strValue]];
}
else
{
- [fAudioFallbackPopUp selectItemWithTitle:@"AC3 (ffmpeg)"];
+ [fAudioFallbackPopUp selectItemWithTag:HB_ACODEC_AC3];
}
/* Audio */
[preset setObject:[fVidBitrateField stringValue] forKey:@"VideoAvgBitrate"];
[preset setObject:[NSNumber numberWithFloat:[fVidQualityRFField floatValue]] forKey:@"VideoQualitySlider"];
- /* Video framerate */
- /* Set the Video Frame Rate Mode */
+ /* Video framerate and framerate mode */
if ([fFramerateMatrix selectedRow] == 1)
{
[preset setObject:@"cfr" forKey:@"VideoFramerateMode"];
}
- /* Set the actual framerate from popup overriding the cfr setting as needed */
if ([fVidRatePopUp indexOfSelectedItem] == 0) // Same as source is selected
{
[preset setObject:@"Same as source" forKey:@"VideoFramerate"];
[preset setObject:@"vfr" forKey:@"VideoFramerateMode"];
}
}
- else // we can record the actual titleOfSelectedItem
+ else // translate the rate (selected item's tag) to the official libhb name
{
- [preset setObject:[fVidRatePopUp titleOfSelectedItem] forKey:@"VideoFramerate"];
+ [preset setObject:[NSString stringWithFormat:@"%s",
+ hb_video_framerate_get_name([[fVidRatePopUp selectedItem] tag])]
+ forKey:@"VideoFramerate"];
if ([fFramerateMatrix selectedRow] == 0)
{
#import "hb.h"
NSString *keyAudioCodecName = @"keyAudioCodecName";
-NSString *keyAudioMP4 = @"keyAudioMP4";
-NSString *keyAudioMKV = @"keyAudioMKV";
+NSString *keyAudioSupportedMuxers = @"keyAudioSupportedMuxers";
NSString *keyAudioSampleRateName = @"keyAudioSampleRateName";
NSString *keyAudioBitrateName = @"keyAudioBitrateName";
NSString *keyAudioMustMatchTrack = @"keyAudioMustMatchTrack";
{
if ([HBAudio class] == self)
{
- int i, audioMustMatch;
- BOOL muxMKV, muxMP4;
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- NSDictionary *dict;
-
masterCodecArray = [[NSMutableArray alloc] init]; // knowingly leaked
- for (i = 0; i < hb_audio_encoders_count; i++)
+ for (const hb_encoder_t *audio_encoder = hb_audio_encoder_get_next(NULL);
+ audio_encoder != NULL;
+ audio_encoder = hb_audio_encoder_get_next(audio_encoder))
{
- if ((hb_audio_encoders[i].encoder & HB_ACODEC_PASS_FLAG) &&
- (hb_audio_encoders[i].encoder != HB_ACODEC_AUTO_PASS))
+ id audioMustMatchTrack;
+ if ((audio_encoder->codec & HB_ACODEC_PASS_FLAG) &&
+ (audio_encoder->codec != HB_ACODEC_AUTO_PASS))
{
- audioMustMatch = (hb_audio_encoders[i].encoder & ~HB_ACODEC_PASS_FLAG);
+ audioMustMatchTrack = [NSNumber
+ numberWithInt:(audio_encoder->codec &
+ ~HB_ACODEC_PASS_FLAG)];
}
else
{
- audioMustMatch = 0;
- }
- muxMKV = (hb_audio_encoders[i].muxers & HB_MUX_MKV) ? YES : NO;
- muxMP4 = (hb_audio_encoders[i].muxers & HB_MUX_MP4) ? YES : NO;
- if (audioMustMatch)
- {
- [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys:
- [NSString stringWithUTF8String: hb_audio_encoders[i].human_readable_name], keyAudioCodecName,
- [NSNumber numberWithInt: hb_audio_encoders[i].encoder], keyAudioCodec,
- [NSNumber numberWithBool: muxMP4], keyAudioMP4,
- [NSNumber numberWithBool: muxMKV], keyAudioMKV,
- [NSNumber numberWithInt: audioMustMatch], keyAudioMustMatchTrack,
- nil]];
- }
- else
- {
- [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys:
- [NSString stringWithUTF8String: hb_audio_encoders[i].human_readable_name], keyAudioCodecName,
- [NSNumber numberWithInt: hb_audio_encoders[i].encoder], keyAudioCodec,
- [NSNumber numberWithBool: muxMP4], keyAudioMP4,
- [NSNumber numberWithBool: muxMKV], keyAudioMKV,
- [NSNumber numberWithBool: NO], keyAudioMustMatchTrack,
- nil]];
+ audioMustMatchTrack = [NSNumber numberWithBool:NO];
}
+ [masterCodecArray addObject:[NSDictionary dictionaryWithObjectsAndKeys:
+ [NSString stringWithUTF8String:audio_encoder->name], keyAudioCodecName,
+ [NSNumber numberWithInt:audio_encoder->codec], keyAudioCodec,
+ [NSNumber numberWithInt:audio_encoder->muxers], keyAudioSupportedMuxers,
+ audioMustMatchTrack, keyAudioMustMatchTrack,
+ nil]];
}
masterMixdownArray = [[NSMutableArray alloc] init]; // knowingly leaked
- for (i = 0; i < hb_audio_mixdowns_count; i++)
+ for (const hb_mixdown_t *mixdown = hb_mixdown_get_next(NULL);
+ mixdown != NULL;
+ mixdown = hb_mixdown_get_next(mixdown))
{
- [masterMixdownArray addObject: [NSDictionary dictionaryWithObjectsAndKeys:
- [NSString stringWithUTF8String: hb_audio_mixdowns[i].human_readable_name], keyAudioMixdownName,
- [NSNumber numberWithInt: hb_audio_mixdowns[i].amixdown], keyAudioMixdown,
- nil]];
+ [masterMixdownArray addObject:[NSDictionary dictionaryWithObjectsAndKeys:
+ [NSString stringWithUTF8String:mixdown->name], keyAudioMixdownName,
+ [NSNumber numberWithInt:mixdown->amixdown], keyAudioMixdown,
+ nil]];
}
// Note that for the Auto value we use 0 for the sample rate because our controller will give back the track's
// input sample rate when it finds this 0 value as the selected sample rate. We do this because the input
// sample rate depends on the track, which means it depends on the title, so cannot be nicely set up here.
masterSampleRateArray = [[NSMutableArray alloc] init]; // knowingly leaked
- [masterSampleRateArray addObject: [NSDictionary dictionaryWithObjectsAndKeys:
- NSLocalizedString(@"Auto", @"Auto"), keyAudioSampleRateName,
- [NSNumber numberWithInt: 0], keyAudioSamplerate,
- nil]];
- for (i = 0; i < hb_audio_rates_count; i++)
+ [masterSampleRateArray addObject:[NSDictionary dictionaryWithObjectsAndKeys:
+ [NSString stringWithString:@"Auto"], keyAudioSampleRateName,
+ [NSNumber numberWithInt:0], keyAudioSamplerate,
+ nil]];
+ for (const hb_rate_t *audio_samplerate = hb_audio_samplerate_get_next(NULL);
+ audio_samplerate != NULL;
+ audio_samplerate = hb_audio_samplerate_get_next(audio_samplerate))
{
- [masterSampleRateArray addObject: [NSDictionary dictionaryWithObjectsAndKeys:
- [NSString stringWithUTF8String: hb_audio_rates[i].string], keyAudioSampleRateName,
- [NSNumber numberWithInt: hb_audio_rates[i].rate], keyAudioSamplerate,
- nil]];
+ [masterSampleRateArray addObject:[NSDictionary dictionaryWithObjectsAndKeys:
+ [NSString stringWithUTF8String:audio_samplerate->name], keyAudioSampleRateName,
+ [NSNumber numberWithInt:audio_samplerate->rate], keyAudioSamplerate,
+ nil]];
}
masterBitRateArray = [[NSMutableArray alloc] init]; // knowingly leaked
- for (i = 0; i < hb_audio_bitrates_count; i++)
+ for (const hb_rate_t *audio_bitrate = hb_audio_bitrate_get_next(NULL);
+ audio_bitrate != NULL;
+ audio_bitrate = hb_audio_bitrate_get_next(audio_bitrate))
{
- dict = [NSDictionary dictionaryWithObjectsAndKeys:
- [NSString stringWithUTF8String: hb_audio_bitrates[i].string], keyAudioBitrateName,
- [NSNumber numberWithInt: hb_audio_bitrates[i].rate], keyAudioBitrate,
- nil];
- [masterBitRateArray addObject: dict];
+ [masterBitRateArray addObject:[NSDictionary dictionaryWithObjectsAndKeys:
+ [NSString stringWithUTF8String:audio_bitrate->name], keyAudioBitrateName,
+ [NSNumber numberWithInt:audio_bitrate->rate], keyAudioBitrate,
+ nil]];
}
-
- [pool release];
}
}
NSMutableArray *permittedCodecs = [NSMutableArray array];
unsigned int count = [masterCodecArray count];
NSDictionary *dict;
- NSString *keyThatAllows = nil;
-
- // Determine which key we use to see which codecs are permitted
- switch ([videoContainerTag intValue])
- {
- case HB_MUX_MP4:
- keyThatAllows = keyAudioMP4;
- break;
- case HB_MUX_MKV:
- keyThatAllows = keyAudioMKV;
- break;
- default:
- keyThatAllows = @"error condition";
- break;
- }
// First get a list of the permitted codecs based on the internal rules
if (nil != track && [self enabled])
dict = [masterCodecArray objectAtIndex: i];
// First make sure only codecs permitted by the container are here
- goodToAdd = [[dict objectForKey: keyThatAllows] boolValue];
+ goodToAdd = !!([[dict objectForKey:keyAudioSupportedMuxers] intValue] &
+ [videoContainerTag intValue]);
// Now we make sure if DTS or AC3 is not available in the track it is not put in the codec list, but in a general way
if ([[dict objectForKey: keyAudioMustMatchTrack] boolValue])
int currentMixdown;
unsigned long long channelLayout = [[track objectForKey: keyAudioInputChannelLayout] unsignedLongLongValue];
- unsigned int count = [masterMixdownArray count];
- int codecCodec = [[codec objectForKey: keyAudioCodec] intValue];
- int theDefaultMixdown = hb_get_default_mixdown(codecCodec, channelLayout);
+ unsigned int count = [masterMixdownArray count];
+ int codecCodec = [[codec objectForKey: keyAudioCodec] intValue];
+ int theDefaultMixdown = hb_mixdown_get_default(codecCodec, channelLayout);
for (unsigned int i = 0; i < count; i++)
{
theSampleRate = [[[self track] objectForKey: keyAudioInputSampleRate] intValue];
}
- int ourCodec = [[codec objectForKey: keyAudioCodec] intValue];
- int ourMixdown = [[[self mixdown] objectForKey: keyAudioMixdown] intValue];
- hb_get_audio_bitrate_limits(ourCodec, theSampleRate, ourMixdown, &minBitRate, &maxBitRate);
- int theDefaultBitRate = hb_get_default_audio_bitrate(ourCodec, theSampleRate, ourMixdown);
+ int ourCodec = [[codec objectForKey:keyAudioCodec] intValue];
+ int ourMixdown = [[[self mixdown] objectForKey:keyAudioMixdown] intValue];
+ int theDefaultBitRate = hb_audio_bitrate_get_default(ourCodec, theSampleRate, ourMixdown);
+ hb_audio_bitrate_get_limits(ourCodec, theSampleRate, ourMixdown, &minBitRate, &maxBitRate);
BOOL codecIsPassthru = ([[codec objectForKey: keyAudioCodec] intValue] & HB_ACODEC_PASS_FLAG) ? YES : NO;
BOOL codecIsLossless = (theDefaultBitRate == -1) ? YES : NO;
if (retval)
{
- int myCodecCodec = [[[self codec] objectForKey: keyAudioCodec] intValue];
- int myCodecDefaultBitrate = hb_get_default_audio_bitrate(myCodecCodec, 0, 0);
+ int myCodecCodec = [[[self codec] objectForKey:keyAudioCodec] intValue];
+ int myCodecDefaultBitrate = hb_audio_bitrate_get_default(myCodecCodec, 0, 0);
if (myCodecDefaultBitrate < 0)
{
retval = NO;
/* We go ahead and assign values to our audio->out.<properties> */
audio->out.track = audio->in.track;
audio->out.codec = [[[anAudio codec] objectForKey:keyAudioCodec] intValue];
- audio->out.compression_level = hb_get_default_audio_compression(audio->out.codec);
+ audio->out.compression_level = hb_audio_compression_get_default(audio->out.codec);
audio->out.mixdown = [[[anAudio mixdown] objectForKey:keyAudioMixdown] intValue];
audio->out.normalize_mix_level = 0;
audio->out.bitrate = [[[anAudio bitRate] objectForKey:keyAudioBitrate] intValue];
[newAudio setVideoContainerTag: [self videoContainerTag]];
[newAudio setTrackFromIndex: trackIndex];
- key = [dict objectForKey: @"AudioEncoder"];
-
// map faac to ca_aac for built-in presets (can be disabled in preferences)
if (0 == aType &&
- [[NSUserDefaults standardUserDefaults] boolForKey: @"UseCoreAudio"] &&
- [key isEqualToString: @"AAC (faac)"])
+ [[NSUserDefaults standardUserDefaults] boolForKey:@"UseCoreAudio"] &&
+ [[dict objectForKey:@"AudioEncoder"] isEqualToString:@"AAC (faac)"])
{
- [dict setObject: @"AAC (CoreAudio)" forKey: @"AudioEncoder"];
+ key = @"AAC (CoreAudio)";
}
-
- // passthru fallbacks
- if ([key isEqualToString: @"AAC Passthru"])
+ else
{
- if (![newAudio setCodecFromName: key])
- {
- [dict setObject: @"AAC (CoreAudio)" forKey: @"AudioEncoder"];
- fallenBack = YES;
- }
+ key = [dict objectForKey:@"AudioEncoder"];
}
- else if ([key isEqualToString: @"AC3 Passthru"])
+
+ // map legacy encoder names via libhb
+ if (key != nil)
{
- if (![newAudio setCodecFromName: key])
+ const char *name;
+ // passthru fallbacks
+ if ([key hasSuffix:@"Passthru"] &&
+ ![newAudio setCodecFromName:key])
{
- [dict setObject: @"AC3 (ffmpeg)" forKey: @"AudioEncoder"];
+ int passthru, fallback;
fallenBack = YES;
+ passthru = hb_audio_encoder_get_from_name([key UTF8String]);
+ fallback = hb_audio_encoder_get_fallback_for_passthru(passthru);
+ name = hb_audio_encoder_get_name(fallback);
}
- }
- else if ([key isEqualToString: @"MP3 Passthru"])
- {
- if (![newAudio setCodecFromName: key])
+ else
{
- [dict setObject: @"MP3 (lame)" forKey: @"AudioEncoder"];
- fallenBack = YES;
+ name = hb_audio_encoder_sanitize_name([key UTF8String]);
}
- }
-
- // map legacy encoder names
- if ([key isEqualToString: @"AC3"])
- {
- [dict setObject: @"AC3 (ffmpeg)" forKey: @"AudioEncoder"];
+ [dict setObject:[NSString stringWithFormat:@"%s", name]
+ forKey:@"AudioEncoder"];
}
// If our preset does not contain a drc or gain value set it to a default of 0.0
[dict setObject:[NSNumber numberWithFloat:0.0] forKey:@"AudioTrackGainSlider"];
}
- // map legacy mixdowns
+ // map legacy mixdowns via libhb
key = [dict objectForKey: @"AudioMixdown"];
- if ([key isEqualToString: @"AC3 Passthru"] ||
- [key isEqualToString: @"DTS Passthru"] ||
- [key isEqualToString: @"DTS-HD Passthru"])
- {
- [dict setObject: @"None" forKey: @"AudioMixdown"];
- }
- else if ([key isEqualToString: @"6-channel discrete"])
+ if (key != nil)
{
- [dict setObject: @"5.1 Channels" forKey: @"AudioMixdown"];
+ [dict setObject:[NSString stringWithFormat:@"%s",
+ hb_mixdown_sanitize_name([key UTF8String])]
+ forKey:@"AudioMixdown"];
}
// If our preset wants us to support a codec that the track does not support, instead
}
/* Destination file. We set this to our preview directory
* changing the extension appropriately.*/
- if (fTitle->job->mux == HB_MUX_MP4) // MP4 file
+ if (fTitle->job->mux & HB_MUX_MASK_MP4) // MP4 file
{
/* we use .m4v for our mp4 files so that ac3 and chapters in mp4 will play properly */
fPreviewMoviePath = [PreviewDirectory stringByAppendingString:@"/preview_temp.m4v"];
}
- else if (fTitle->job->mux == HB_MUX_MKV) // MKV file
+ else if (fTitle->job->mux & HB_MUX_MASK_MKV) // MKV file
{
fPreviewMoviePath = [PreviewDirectory stringByAppendingString:@"/preview_temp.mkv"];
}
* by default to avoid massive confusion and anarchy. However we also want to guard against multiple burned in subtitle tracks
* as libhb would ignore all but the first one anyway. Plus it would probably be stupid.
*/
- if (container == HB_MUX_MP4 && [anObject intValue] != 0)
+ if ((container & HB_MUX_MASK_MP4) && ([anObject intValue] != 0))
{
if ([[[subtitleArray objectAtIndex:rowIndex] objectForKey:@"subtitleSourceTrackType"] intValue] == VOBSUB)
{
(cd $(STAGE.out.src/)raring && dput handbrake-snapshots handbrake_$(HB.version)ppa1~raring1_source.changes )
(cd $(STAGE.out.src/)quantal && dput handbrake-snapshots handbrake_$(HB.version)ppa1~quantal1_source.changes )
(cd $(STAGE.out.src/)precise && dput handbrake-snapshots handbrake_$(HB.version)ppa1~precise1_source.changes )
- (cd $(STAGE.out.src/)oneiric && dput handbrake-snapshots handbrake_$(HB.version)ppa1~oneiric1_source.changes )
$(PKG.src.deb.stamp): GNUmakefile
-$(RM.exe) -rf $(STAGE.out.src/)
echo " -- John Stebbins <jstebbins.hb@gmail.com> Sun, 11 Apr 2010 9:51:07 -0800" >> $(STAGE.out.src/)precise/$(PKG.deb.basename)/debian/changelog
$(TAR.exe) czf $(STAGE.out.src/)precise/$(PKG.src.deb.tar) -C $(STAGE.out.src/)precise $(PKG.deb.basename)
(cd $(STAGE.out.src/)precise/$(PKG.deb.basename) && debuild -S -kjstebbins.hb)
- svn co -r$(HB.repo.rev) $(HB.repo.url) $(STAGE.out.src/)oneiric/$(PKG.deb.basename)
- $(CP.exe) -a $(SRC/)download $(STAGE.out.src/)oneiric/$(PKG.deb.basename)
- cp -a $(PWD)/$(PKG.debian) $(STAGE.out.src/)oneiric/$(PKG.deb.basename)
- $(CP.exe) $(STAGE.out.src/)oneiric/$(PKG.deb.basename)/debian/control.oneiric $(STAGE.out.src/)oneiric/$(PKG.deb.basename)/debian/control
- $(CP.exe) $(STAGE.out.src/)oneiric/$(PKG.deb.basename)/debian/rules.oneiric $(STAGE.out.src/)oneiric/$(PKG.deb.basename)/debian/rules
- echo "handbrake ($(HB.version)ppa1~oneiric1) oneiric; urgency=low" > $(STAGE.out.src/)oneiric/$(PKG.deb.basename)/debian/changelog
- echo " * Snapshot" >> $(STAGE.out.src/)oneiric/$(PKG.deb.basename)/debian/changelog
- echo " - See timeline at http://trac.handbrake.fr/timeline" >> $(STAGE.out.src/)oneiric/$(PKG.deb.basename)/debian/changelog
- echo "" >> $(STAGE.out.src/)oneiric/$(PKG.deb.basename)/debian/changelog
- echo " -- John Stebbins <jstebbins.hb@gmail.com> Sun, 11 Apr 2010 9:51:07 -0800" >> $(STAGE.out.src/)oneiric/$(PKG.deb.basename)/debian/changelog
- $(TAR.exe) czf $(STAGE.out.src/)oneiric/$(PKG.src.deb.tar) -C $(STAGE.out.src/)oneiric $(PKG.deb.basename)
- (cd $(STAGE.out.src/)oneiric/$(PKG.deb.basename) && debuild -S -kjstebbins.hb)
#Filename suffix
case hash["FileFormat"]
- when /MP4/
+ when /MPEG-4/, /MP4/
commandString << "mp4 "
- when /MKV/
+ when /Matroska/, /MKV/
commandString << "mkv "
end
#Container
commandString << " -f "
case hash["FileFormat"]
+ when "MPEG-4 (mp4v2)"
+ commandString << "mp4v2"
when /MP4/
commandString << "mp4"
+ when "Matroska (libmkv)"
+ commandString << "libmkv"
when /MKV/
commandString << "mkv"
end
#Container
commandString << " -f "
case hash["FileFormat"]
+ when "MPEG-4 (mp4v2)"
+ commandString << "mp4v2"
when /MP4/
commandString << "mp4"
+ when "Matroska (libmkv)"
+ commandString << "libmkv"
when /MKV/
commandString << "mkv"
end
commandString = "if (!strcasecmp(preset_name, \"" << hash["PresetName"] << "\"))\n{\n "
- #Filename suffix
+ #Container
commandString << "if( !mux )\n "
commandString << "{\n "
case hash["FileFormat"]
+ when "MPEG-4 (mp4v2)"
+ commandString << " mux = " << "HB_MUX_MP4V2;\n "
when /MP4/
commandString << " mux = " << "HB_MUX_MP4;\n "
+ when "Matroska (libmkv)"
+ commandString << " mux = " << "HB_MUX_LIBMKV;\n "
when /MKV/
commandString << " mux = " << "HB_MUX_MKV;\n "
end
#FPS
if hash["VideoFramerate"] != "Same as source"
if hash["VideoFramerate"] == "23.976 (NTSC Film)"
- commandString << "job->vrate_base = " << "1126125;\n "
+ commandString << "filter_vrate_base = " << "1126125;\n "
elsif hash["VideoFramerate"] == "29.97 (NTSC Video)"
- commandString << "job->vrate_base = " << "900900;\n "
+ commandString << "filter_vrate_base = " << "900900;\n "
elsif hash["VideoFramerate"] == "25 (PAL Film/Video)"
- commandString << "job->vrate_base = " << "1080000;\n "
+ commandString << "filter_vrate_base = " << "1080000;\n "
else
- commandString << "job->vrate_base = " << (27000000 / hash["VideoFramerate"].to_i).to_s << ";\n "
+ commandString << "filter_vrate_base = " << (27000000 / hash["VideoFramerate"].to_i).to_s << ";\n "
end
# not same as source: pfr, else default (cfr)
if hash["VideoFramerateMode"] == "pfr"
- commandString << "job->cfr = 2;\n "
+ commandString << "filter_cfr = 2;\n "
else
- commandString << "job->cfr = 1;\n "
+ commandString << "filter_cfr = 1;\n "
end
# same as source: cfr, else default (vfr)
elsif hash["VideoFramerateMode"] == "cfr"
- commandString << "job->cfr = 1;\n "
+ commandString << "filter_cfr = 1;\n "
end
#Audio tracks
#Container
commandString << " -f "
case hash["FileFormat"]
+ when "MPEG-4 (mp4v2)"
+ commandString << "mp4v2"
when /MP4/
commandString << "mp4"
+ when "Matroska (libmkv)"
+ commandString << "libmkv"
when /MKV/
commandString << "mkv"
end
static int CheckOptions( int argc, char ** argv );
static int HandleEvents( hb_handle_t * h );
-static int get_dither_for_string(const char *dither);
-static int get_acodec_for_string(const char *codec);
-static const char* get_string_for_acodec(int acodec);
-
-static int is_sample_rate_valid(int rate);
static void str_vfree( char **strv );
static char** str_split( char *str, char delem );
{
hb_state_t s;
int tmp_num_audio_tracks;
+ int filter_cfr, filter_vrate, filter_vrate_base;
hb_get_state( h, &s );
switch( s.state )
PrintTitleInfo( title, title_set->feature );
/* Set job settings */
- job = hb_job_init( title );
+ 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 )
}
vcodec = HB_VCODEC_X264;
job->vquality = 20.0;
- job->vrate_base = 900000;
- job->cfr = 2;
+ filter_vrate_base = 900000;
+ filter_cfr = 2;
if( !atracks )
{
atracks = strdup("1,1");
job->ipod_atom = 1;
vcodec = HB_VCODEC_X264;
job->vquality = 22.0;
- job->vrate_base = 900000;
- job->cfr = 2;
+ filter_vrate_base = 900000;
+ filter_cfr = 2;
if( !atracks )
{
atracks = strdup("1");
job->largeFileSize = 1;
vcodec = HB_VCODEC_X264;
job->vquality = 22.0;
- job->vrate_base = 900000;
- job->cfr = 2;
+ filter_vrate_base = 900000;
+ filter_cfr = 2;
if( !atracks )
{
atracks = strdup("1");
job->largeFileSize = 1;
vcodec = HB_VCODEC_X264;
job->vquality = 20.0;
- job->vrate_base = 900000;
- job->cfr = 2;
+ filter_vrate_base = 900000;
+ filter_cfr = 2;
if( !atracks )
{
atracks = strdup("1");
job->largeFileSize = 1;
vcodec = HB_VCODEC_X264;
job->vquality = 20.0;
- job->vrate_base = 900000;
- job->cfr = 2;
+ filter_vrate_base = 900000;
+ filter_cfr = 2;
if( !atracks )
{
atracks = strdup("1,1");
job->largeFileSize = 1;
vcodec = HB_VCODEC_X264;
job->vquality = 20.0;
- job->vrate_base = 900000;
- job->cfr = 2;
+ filter_vrate_base = 900000;
+ filter_cfr = 2;
if( !atracks )
{
atracks = strdup("1,1");
job->largeFileSize = 1;
vcodec = HB_VCODEC_X264;
job->vquality = 20.0;
- job->vrate_base = 900000;
- job->cfr = 2;
+ filter_vrate_base = 900000;
+ filter_cfr = 2;
if( !atracks )
{
atracks = strdup("1,1");
}
vcodec = HB_VCODEC_X264;
job->vquality = 22.0;
- job->vrate_base = 900000;
- job->cfr = 2;
+ filter_vrate_base = 900000;
+ filter_cfr = 2;
if( !atracks )
{
atracks = strdup("1");
}
vcodec = HB_VCODEC_X264;
job->vquality = 22.0;
- job->vrate_base = 900000;
- job->cfr = 2;
+ filter_vrate_base = 900000;
+ filter_cfr = 2;
if( !atracks )
{
atracks = strdup("1");
// Add framerate shaping filter
- if( vrate )
+ if (vrate)
{
- job->cfr = cfr;
- job->vrate = 27000000;
- job->vrate_base = vrate;
+ filter_cfr = cfr;
+ filter_vrate = 27000000;
+ filter_vrate_base = vrate;
}
- else if ( cfr )
+ else if (cfr)
{
// cfr or pfr flag with no rate specified implies
// use the title rate.
- job->cfr = cfr;
- job->vrate = title->rate;
- job->vrate_base = title->rate_base;
+ filter_cfr = cfr;
+ filter_vrate = title->rate;
+ filter_vrate_base = title->rate_base;
}
- filter_str = hb_strdup_printf("%d:%d:%d",
- job->cfr, job->vrate, job->vrate_base );
- filter = hb_filter_init( HB_FILTER_VFR );
- hb_add_filter( job, filter, filter_str );
- free( filter_str );
+ filter = hb_filter_init(HB_FILTER_VFR);
+ filter_str = hb_strdup_printf("%d:%d:%d", filter_cfr, filter_vrate,
+ filter_vrate_base);
+ hb_add_filter(job, filter, filter_str);
+ free(filter_str);
if(vcodec == HB_VCODEC_QSV_H264)
{
token = acodecs;
while ( token != NULL )
{
- if ((acodec = get_acodec_for_string(token)) == -1)
+ if ((acodec = hb_audio_encoder_get_from_name(token)) == -1)
{
fprintf(stderr, "Invalid codec %s, using default for container.\n", token);
- acodec = hb_get_default_audio_encoder(job->mux);
+ acodec = hb_audio_encoder_get_default(job->mux);
}
if( i < num_audio_tracks )
{
* then use that codec instead.
*/
if (i != 1)
- acodec = hb_get_default_audio_encoder(job->mux);
+ acodec = hb_audio_encoder_get_default(job->mux);
for ( ; i < num_audio_tracks; i++)
{
audio = hb_list_audio_config_item(job->list_audio, i);
token = arates;
while ( token != NULL )
{
- arate = atoi(token);
audio = hb_list_audio_config_item(job->list_audio, i);
- int j;
-
- for( j = 0; j < hb_audio_rates_count; j++ )
- {
- if( !strcmp( token, hb_audio_rates[j].string ) )
- {
- arate = hb_audio_rates[j].rate;
- break;
- }
- }
if( audio != NULL )
{
arate = audio->in.samplerate;
auto_sample_rate = 1;
}
- if (!is_sample_rate_valid(arate))
+ else
+ {
+ arate = hb_audio_samplerate_get_from_name(token);
+ }
+ if (arate == -1)
{
- fprintf(stderr, "Invalid sample rate %d, using input rate %d\n", arate, audio->in.samplerate);
+ fprintf(stderr,
+ "Invalid sample rate %s, using input rate %d\n",
+ token, audio->in.samplerate);
arate = audio->in.samplerate;
}
token = mixdowns;
while ( token != NULL )
{
- mixdown = hb_mixdown_get_mixdown_from_short_name(token);
- audio = hb_list_audio_config_item(job->list_audio, i);
+ mixdown = hb_mixdown_get_from_name(token);
+ audio = hb_list_audio_config_item(job->list_audio, i);
if( audio != NULL )
{
audio->out.mixdown = mixdown;
int dither_method = hb_audio_dither_get_default();
for (i = 0; audio_dither[i] != NULL; i++)
{
- dither_method = get_dither_for_string(audio_dither[i]);
- audio = hb_list_audio_config_item(job->list_audio, i);
+ dither_method = hb_audio_dither_get_from_name(audio_dither[i]);
+ audio = hb_list_audio_config_item(job->list_audio, i);
if (audio != NULL)
{
if (hb_audio_dither_is_supported(audio->out.codec))
{
// Auto Passthru
job->acodec_copy_mask = allowed_audio_copy == -1 ? HB_ACODEC_PASS_MASK : allowed_audio_copy;
- job->acodec_fallback = acodec_fallback ? get_acodec_for_string( acodec_fallback ) : 0;
+ job->acodec_fallback = hb_audio_encoder_get_from_name(acodec_fallback);
// sanitize the fallback; -1 isn't a valid HB_ACODEC_* value
- if( job->acodec_fallback == -1 )
- job->acodec_fallback = 0;
+ if (job->acodec_fallback == -1)
+ job->acodec_fallback = 0;
}
else if( ( audio->out.codec & HB_ACODEC_PASS_FLAG ) &&
!( audio->out.codec & audio->in.codec & HB_ACODEC_PASS_MASK ) )
{
- if( audio->out.codec == HB_ACODEC_AAC_PASS )
- {
- fprintf( stderr, "AAC Passthru requested and input codec is not AAC for track %d, using AAC encoder\n",
- audio->out.track );
- audio->out.codec = hb_audio_encoders[0].encoder;
- }
- else if( audio->out.codec == HB_ACODEC_AC3_PASS )
- {
- fprintf( stderr, "AC3 Passthru requested and input codec is not AC3 for track %d, using AC3 encoder\n",
- audio->out.track );
- audio->out.codec = HB_ACODEC_AC3;
- }
- else if( audio->out.codec == HB_ACODEC_MP3_PASS )
- {
- fprintf( stderr, "MP3 Passthru requested and input codec is not MP3 for track %d, using MP3 encoder\n",
- audio->out.track );
- audio->out.codec = HB_ACODEC_LAME;
- }
- else
+ // passthru fallbacks
+ int requested_passthru = audio->out.codec;
+ audio->out.codec =
+ hb_audio_encoder_get_fallback_for_passthru(requested_passthru);
+ if (!(audio->out.codec & HB_ACODEC_MASK))
{
// Passthru not possible, drop audio.
- fprintf( stderr, "Passthru requested and input codec is not the same as output codec for track %d, dropping track\n",
- audio->out.track );
- hb_audio_t * item = hb_list_item( job->list_audio, i );
- hb_list_rem( job->list_audio, item );
+ fprintf(stderr,
+ "Passthru requested and input codec is not the same as output codec for track %d, dropping track\n",
+ audio->out.track);
+ hb_audio_t *item = hb_list_item(job->list_audio, i);
+ hb_list_rem(job->list_audio, item);
+ hb_audio_close(&item);
continue;
}
+ fprintf(stderr,
+ "%s requested and input codec is not compatible for track %d, using %s encoder\n",
+ hb_audio_encoder_get_name(requested_passthru), audio->out.track,
+ hb_audio_encoder_get_name(audio->out.codec));
// we didn't drop the track, set the mixdown and bitrate from libhb defaults
- audio->out.mixdown = hb_get_default_mixdown( audio->out.codec, audio->in.channel_layout );
- audio->out.bitrate = hb_get_default_audio_bitrate( audio->out.codec, audio->out.samplerate,
- audio->out.mixdown );
+ audio->out.mixdown =
+ hb_mixdown_get_default(audio->out.codec,
+ audio->in.channel_layout);
+ audio->out.bitrate =
+ hb_audio_bitrate_get_default(audio->out.codec,
+ audio->out.samplerate,
+ audio->out.mixdown);
}
// we didn't drop the track
i++;
****************************************************************************/
static void ShowHelp()
{
- int i, j, len;
+ int i, len;
+ const char *name;
+ const hb_rate_t *rate;
+ const hb_dither_t *dither;
+ const hb_mixdown_t *mixdown;
+ const hb_encoder_t *encoder;
+ const hb_container_t *container;
FILE* const out = stdout;
const char * const *x264_opts;
char tmp[80];
"### Destination Options------------------------------------------------------\n\n"
" -o, --output <string> Set output file name\n"
- " -f, --format <string> Set output format (mp4/mkv, default:\n"
- " autodetected from file name)\n"
+ " -f, --format <string> Set output container format (");
+ container = NULL;
+ while ((container = hb_container_get_next(container)) != NULL)
+ {
+ fprintf(out, "%s", container->short_name);
+ if (hb_container_get_next(container) != NULL)
+ {
+ fprintf(out, "/");
+ }
+ else
+ {
+ fprintf(out, ")\n");
+ }
+ }
+ fprintf(out,
+ " (default: autodetected from file name)\n"
" -m, --markers Add chapter markers\n"
" -4, --large-file Create 64-bit mp4 files that can hold more than 4 GB\n"
" of data. Note: breaks pre-iOS iPod compatibility.\n"
"### Video Options------------------------------------------------------------\n\n"
" -e, --encoder <string> Set video library encoder\n"
" Options: " );
- for( i = 0; i < hb_video_encoders_count; i++ )
+ encoder = NULL;
+ while ((encoder = hb_video_encoder_get_next(encoder)) != NULL)
{
- fprintf( out, "%s", hb_video_encoders[i].short_name );
-
- if( i != hb_video_encoders_count - 1 )
- fprintf( out, "/" );
+ fprintf(out, "%s", encoder->short_name);
+ if (hb_video_encoder_get_next(encoder) != NULL)
+ {
+ fprintf(out, "/");
+ }
else
- fprintf( out, "\n" );
- }
- for( i = 0; i < hb_video_encoders_count; i++ )
- {
- if( hb_video_encoders[i].encoder == vcodec )
{
- fprintf( out, " (default: %s)\n",
- hb_video_encoders[i].short_name );
- break;
+ fprintf(out, "\n");
+ }
+ if (encoder->codec == vcodec)
+ {
+ name = encoder->short_name;
}
}
+ fprintf(out, " (default: %s)\n", name);
fprintf( out,
" --x264-preset When using x264, selects the x264 preset:\n"
" <string> ");
" -T, --turbo When using 2-pass use \"turbo\" options on the\n"
" 1st pass to improve speed (only works with x264)\n"
" -r, --rate Set video framerate (" );
- for( i = 0; i < hb_video_rates_count; i++ )
+ rate = NULL;
+ while ((rate = hb_video_framerate_get_next(rate)) != NULL)
{
- fprintf( out, "%s", hb_video_rates[i].string );
- if( i != hb_video_rates_count - 1 )
- fprintf( out, "/" );
+ fprintf(out, "%s", rate->name);
+ if (hb_video_framerate_get_next(rate) != NULL)
+ {
+ fprintf(out, "/");
+ }
}
fprintf( out, ")\n"
" Be aware that not specifying a framerate lets\n"
" tracks, default: first one).\n"
" Multiple output tracks can be used for one input.\n"
" -E, --aencoder <string> Audio encoder(s):\n" );
- for (i = 0; i < hb_audio_encoders_count; i++)
+ encoder = NULL;
+ while ((encoder = hb_audio_encoder_get_next(encoder)) != NULL)
{
fprintf(out, " %s\n",
- hb_audio_encoders[i].short_name);
+ encoder->short_name);
}
fprintf(out,
" copy:* will passthrough the corresponding\n"
" audio unmodified to the muxer if it is a\n"
" supported passthrough audio type.\n"
" Separated by commas for more than one audio track.\n"
- " (default: %s for mp4, %s for mkv)\n",
- get_string_for_acodec(hb_get_default_audio_encoder(HB_MUX_MP4)),
- get_string_for_acodec(hb_get_default_audio_encoder(HB_MUX_MKV)));
+ " Defaults:\n");
+ container = NULL;
+ while ((container = hb_container_get_next(container)) != NULL)
+ {
+ int audio_encoder = hb_audio_encoder_get_default(container->format);
+ fprintf(out, " %-8s %s\n",
+ container->short_name,
+ hb_audio_encoder_get_short_name(audio_encoder));
+ }
fprintf(out,
" --audio-copy-mask Set audio codecs that are permitted when the\n"
" <string> \"copy\" audio encoder option is specified\n"
" (" );
- for (i = j = 0; i < hb_audio_encoders_count; i++)
+ i = 0;
+ encoder = NULL;
+ while ((encoder = hb_audio_encoder_get_next(encoder)) != NULL)
{
- if ((hb_audio_encoders[i].encoder & HB_ACODEC_PASS_FLAG) &&
- (hb_audio_encoders[i].encoder != HB_ACODEC_AUTO_PASS))
+ if ((encoder->codec & HB_ACODEC_PASS_FLAG) &&
+ (encoder->codec != HB_ACODEC_AUTO_PASS))
{
- if (j)
+ if (i)
+ {
fprintf(out, "/");
+ }
+ i = 1;
// skip "copy:"
- fprintf(out, "%s", hb_audio_encoders[i].short_name + 5);
- j = 1;
+ fprintf(out, "%s", encoder->short_name + 5);
}
}
fprintf(out, ", default: all).\n"
" Separated by commas for more than one audio track.\n"
" -6, --mixdown <string> Format(s) for audio downmixing/upmixing:\n");
// skip HB_AMIXDOWN_NONE
- for (i = 1; i < hb_audio_mixdowns_count; i++)
+ mixdown = hb_mixdown_get_next(NULL);
+ while((mixdown = hb_mixdown_get_next(mixdown)) != NULL)
{
fprintf(out, " %s\n",
- hb_audio_mixdowns[i].short_name);
+ mixdown->short_name);
}
fprintf(out,
" Separated by commas for more than one audio track.\n"
" Defaults:\n");
- for (i = 0; i < hb_audio_encoders_count; i++)
+ encoder = NULL;
+ while((encoder = hb_audio_encoder_get_next(encoder)) != NULL)
{
- if (!(hb_audio_encoders[i].encoder & HB_ACODEC_PASS_FLAG))
+ if (!(encoder->codec & HB_ACODEC_PASS_FLAG))
{
// layout: UINT64_MAX (all channels) should work with any mixdown
- int mixdown = hb_get_default_mixdown(hb_audio_encoders[i].encoder,
- UINT64_MAX);
+ int mixdown = hb_mixdown_get_default(encoder->codec, UINT64_MAX);
// assumes that the encoder short name is <= 16 characters long
fprintf(out, " %-16s up to %s\n",
- hb_audio_encoders[i].short_name,
- hb_mixdown_get_short_name_from_mixdown(mixdown));
+ encoder->short_name, hb_mixdown_get_short_name(mixdown));
}
}
fprintf(out,
" 0 = Disable Normalization (default)\n"
" 1 = Enable Normalization\n"
" -R, --arate Set audio samplerate(s) (" );
- for( i = 0; i < hb_audio_rates_count; i++ )
+ rate = NULL;
+ while ((rate = hb_audio_samplerate_get_next(rate)) != NULL)
{
- fprintf( out, "%s", hb_audio_rates[i].string );
- if( i != hb_audio_rates_count - 1 )
- fprintf( out, "/" );
+ fprintf(out, "%s", rate->name);
+ if (hb_audio_samplerate_get_next(rate) != NULL)
+ {
+ fprintf(out, "/");
+ }
}
fprintf( out, " kHz)\n"
" Separated by commas for more than one audio track.\n"
" --adither <string> Apply dithering to the audio before encoding.\n"
" Separated by commas for more than one audio track.\n"
" Only supported by some encoders (");
- for (i = j = 0; i < hb_audio_encoders_count; i++)
+ i = 0;
+ encoder = NULL;
+ while ((encoder = hb_audio_encoder_get_next(encoder)) != NULL)
{
- if (hb_audio_dither_is_supported(hb_audio_encoders[i].encoder))
+ if (hb_audio_dither_is_supported(encoder->codec))
{
- if (j)
+ if (i)
+ {
fprintf(out, "/");
- fprintf(out, "%s", hb_audio_encoders[i].short_name);
- j = 1;
+ }
+ i = 1;
+ fprintf(out, "%s", encoder->short_name);
}
}
fprintf(out, ").\n");
fprintf(out,
" Options:\n");
- for (i = 0; i < hb_audio_dithers_count; i++)
+ dither = NULL;
+ while ((dither = hb_audio_dither_get_next(dither)) != NULL)
{
- if (hb_audio_dithers[i].method == hb_audio_dither_get_default())
+ if (dither->method == hb_audio_dither_get_default())
{
fprintf(out, " %s (default)\n",
- hb_audio_dithers[i].short_name);
+ dither->short_name);
}
else
{
fprintf(out, " %s\n",
- hb_audio_dithers[i].short_name);
+ dither->short_name);
}
}
fprintf(out,
break;
case 'e':
{
- int i;
- for( i = 0, vcodec = 0; i < hb_video_encoders_count; i++ )
+ vcodec = hb_video_encoder_get_from_name(optarg);
+ if (vcodec <= 0)
{
- if( !strcasecmp( hb_video_encoders[i].short_name, optarg ) )
- {
- vcodec = hb_video_encoders[i].encoder;
- break;
- }
- }
- if( !vcodec )
- {
- fprintf( stderr, "invalid codec (%s)\n", optarg );
+ fprintf(stderr, "invalid codec (%s)\n", optarg);
return -1;
}
break;
break;
case 'r':
{
- int i;
- vrate = 0;
- for( i = 0; i < hb_video_rates_count; i++ )
+ vrate = hb_video_framerate_get_from_name(optarg);
+ if (vrate <= 0)
{
- if( !strcmp( optarg, hb_video_rates[i].string ) )
- {
- vrate = hb_video_rates[i].rate;
- break;
- }
+ vrate = 0;
+ fprintf(stderr, "invalid framerate %s\n", optarg);
}
- if( !vrate )
- {
- fprintf( stderr, "invalid framerate %s\n", optarg );
- }
- else if ( cfr == 0 )
+ else if (!cfr)
{
cfr = 1;
}
}
case ALLOWED_AUDIO_COPY:
{
- int i, j;
- char **allowed = str_split( optarg, ',' );
+ allowed_audio_copy = 0;
+ const hb_encoder_t *audio_encoder = NULL;
+ char **allowed = str_split(optarg, ',');
- allowed_audio_copy = 0;
- for( i = 0; allowed[i]; i++ )
+ while ((audio_encoder = hb_audio_encoder_get_next(audio_encoder)) != NULL)
{
- for( j = 0; j < hb_audio_encoders_count; j++ )
+ if ((audio_encoder->codec & HB_ACODEC_PASS_FLAG) &&
+ (audio_encoder->codec != HB_ACODEC_AUTO_PASS))
{
- const char *encoder = hb_audio_encoders[j].short_name;
- // skip "copy:"
- if( strlen( encoder ) > 5 )
- encoder += 5;
- if( !strcmp( allowed[i], encoder ) )
+ int i = -1;
+ while(allowed[++i] != NULL)
{
- allowed_audio_copy |= hb_audio_encoders[j].encoder;
- break;
+ // skip "copy:"
+ if (!strcasecmp(allowed[i],
+ audio_encoder->short_name + 5))
+ {
+ allowed_audio_copy |= audio_encoder->codec;
+ break;
+ }
}
}
}
+
allowed_audio_copy &= HB_ACODEC_PASS_MASK;
- str_vfree( allowed );
- } break;
+ str_vfree(allowed);
+ break;
+ }
case AUDIO_FALLBACK:
acodec_fallback = strdup( optarg );
break;
return 1;
}
- if( !format )
+ if (format == NULL)
{
- char * p = strrchr( output, '.' );
-
/* autodetect */
- if( p && ( !strcasecmp( p, ".mp4" ) ||
- !strcasecmp( p, ".m4v" ) ) )
- {
- mux = HB_MUX_MP4;
- }
- else if( p && !strcasecmp(p, ".mkv" ) )
+ const char *extension = strrchr(output, '.');
+ if (extension != NULL)
{
- mux = HB_MUX_MKV;
+ // skip '.'
+ mux = hb_container_get_from_extension(extension + 1);
}
- else
+ if (mux <= 0)
{
- fprintf( stderr, "Output format couldn't be guessed "
- "from file name, using default.\n" );
+ fprintf(stderr,
+ "Output format can't be guessed from file name (%s), "
+ "using default.\n", output);
+ // reset the muxer (use default)
+ mux = 0;
return 0;
}
}
- else if( !strcasecmp( format, "mp4" ) ||
- !strcasecmp( format, "m4v" ) )
- {
- mux = HB_MUX_MP4;
- }
- else if( !strcasecmp( format, "mkv" ) )
- {
- mux = HB_MUX_MKV;
- }
else
{
- fprintf( stderr, "Invalid output format (%s). Possible "
- "choices are mp4, m4v and mkv\n.", format );
- return 1;
- }
- }
-
- return 0;
-}
-
-static int get_dither_for_string(const char *dither)
-{
- int i;
- for (i = 0; i < hb_audio_dithers_count; i++)
- {
- if (!strcasecmp(hb_audio_dithers[i].short_name, dither))
- {
- return hb_audio_dithers[i].method;
- }
- }
- return hb_audio_dither_get_default();
-}
-
-static int get_acodec_for_string(const char *codec)
-{
- int i;
- for (i = 0; i < hb_audio_encoders_count; i++)
- {
- if (!strcasecmp(hb_audio_encoders[i].short_name, codec))
- {
- return hb_audio_encoders[i].encoder;
- }
- }
- return -1;
-}
-
-static const char* get_string_for_acodec(int acodec)
-{
- int i;
- for (i = 0; i < hb_audio_encoders_count; i++)
- {
- if (hb_audio_encoders[i].encoder == acodec)
- {
- return hb_audio_encoders[i].short_name;
+ mux = hb_container_get_from_name(format);
+ if (mux <= 0)
+ {
+ fprintf(stderr, "Invalid output format (%s).", format);
+ fprintf(stderr, "Possible choices are: ");
+ const hb_container_t *container = NULL;
+ while ((container = hb_container_get_next(container)) != NULL)
+ {
+ fprintf(stderr, "%s", container->short_name);
+ if (hb_container_get_next(container) != NULL)
+ {
+ fprintf(stderr, ", ");
+ }
+ else
+ {
+ fprintf(stderr, "\n");
+ }
+ }
+ return 1;
+ }
}
}
- return NULL;
-}
-static int is_sample_rate_valid(int rate)
-{
- int i;
- for( i = 0; i < hb_audio_rates_count; i++ )
- {
- if (rate == hb_audio_rates[i].rate)
- return 1;
- }
return 0;
}
/// </summary>\r
public const string Verbosity = "Verbosity";\r
\r
- /// <summary>\r
- /// When Complete Action\r
- /// </summary>\r
- public const string WhenCompleteAction = "WhenCompleteAction";\r
-\r
/// <summary>\r
/// Process Priority\r
/// </summary>\r
public const string ProcessPriority = "ProcessPriority";\r
\r
- /// <summary>\r
- /// Prevent Sleep\r
- /// </summary>\r
- public const string PreventSleep = "PreventSleep";\r
-\r
/// <summary>\r
/// Save Log Directory\r
/// </summary>\r
/// </summary>\r
public const string DisableLibDvdNav = "DisableLibDvdNav";\r
\r
- /// <summary>\r
- /// Send file enabled.\r
- /// </summary>\r
- public const string SendFile = "SendFile";\r
-\r
- /// <summary>\r
- /// Send file to application path\r
- /// </summary>\r
- public const string SendFileTo = "SendFileTo";\r
-\r
- /// <summary>\r
- /// Send file to arguments\r
- /// </summary>\r
- public const string SendFileToArgs = "SendFileToArgs";\r
-\r
/// <summary>\r
/// Min Title Scan Duration\r
/// </summary>\r
using System;\r
using System.Runtime.Serialization;\r
\r
+ using HandBrake.ApplicationServices.Model;\r
+\r
/// <summary>\r
/// Encode Progress Event Args\r
/// </summary>\r
/// <param name="errorInformation">\r
/// The error information.\r
/// </param>\r
- public EncodeCompletedEventArgs(bool sucessful, Exception exception, string errorInformation)\r
+ /// <param name="filename">\r
+ /// The filename.\r
+ /// </param>\r
+ public EncodeCompletedEventArgs(bool sucessful, Exception exception, string errorInformation, string filename)\r
{\r
this.Successful = sucessful;\r
this.Exception = exception;\r
this.ErrorInformation = errorInformation;\r
+ this.FileName = filename;\r
}\r
\r
+ /// <summary>\r
+ /// Gets or sets the file name.\r
+ /// </summary>\r
+ [DataMember]\r
+ public string FileName { get; set; }\r
+\r
/// <summary>\r
/// Gets or sets a value indicating whether Successful.\r
/// </summary>\r
this.H264Level = task.H264Level;\r
this.FastDecode = task.FastDecode;\r
this.ExtraAdvancedArguments = task.ExtraAdvancedArguments;\r
+ \r
\r
this.PreviewStartAt = task.PreviewStartAt;\r
this.PreviewDuration = task.PreviewDuration;\r
+\r
+ this.ShowAdvancedTab = task.ShowAdvancedTab;\r
}\r
\r
#region Source\r
None = 0,\r
[Display(Name = "Custom")]\r
Custom = 1,\r
- [Display(Name = "Source Maximum")]\r
+ [Display(Name = "Current Source Max Size")]\r
SourceMaximum = 2,\r
}\r
}
\ No newline at end of file
/// </summary>\r
public string LanguageCode { get; set; }\r
\r
+ /// <summary>\r
+ /// Gets the language code clean.\r
+ /// TODO Remove this after fixing language code.\r
+ /// </summary>\r
+ public string LanguageCodeClean\r
+ {\r
+ get\r
+ {\r
+ if (this.LanguageCode != null)\r
+ {\r
+ return this.LanguageCode.Replace("iso639-2: ", string.Empty).Trim();\r
+ }\r
+ return string.Empty;\r
+ }\r
+ }\r
+\r
/// <summary>\r
/// Gets or sets the Subtitle Type\r
/// </summary>\r
using System.IO;\r
using System.Windows.Forms;\r
\r
- using Caliburn.Micro;\r
-\r
using HandBrake.ApplicationServices.EventArgs;\r
+ using HandBrake.ApplicationServices.Exceptions;\r
using HandBrake.ApplicationServices.Model;\r
using HandBrake.ApplicationServices.Services.Base;\r
using HandBrake.ApplicationServices.Services.Interfaces;\r
{\r
if (this.IsEncoding)\r
{\r
- throw new Exception("HandBrake is already encodeing.");\r
+ throw new GeneralApplicationException("HandBrake is already encodeing.", "Please try again in a minute", null);\r
}\r
\r
this.IsEncoding = true;\r
-\r
this.currentTask = encodeQueueTask;\r
\r
if (enableLogging)\r
}\r
}\r
\r
- if (this.userSettingService.GetUserSetting<bool>(ASUserSettingConstants.PreventSleep))\r
- {\r
- Win32.PreventSleep();\r
- }\r
-\r
// Make sure the path exists, attempt to create it if it doesn't\r
this.VerifyEncodeDestinationPath(currentTask);\r
\r
catch (Exception exc)\r
{\r
encodeQueueTask.Status = QueueItemStatus.Error;\r
+ this.IsEncoding = false;\r
this.InvokeEncodeCompleted(\r
new EncodeCompletedEventArgs(\r
- false, null, "An Error occured when trying to encode this source. "));\r
+ false, exc, "An Error occured when trying to encode this source. ", this.currentTask.Task.Destination));\r
throw;\r
}\r
}\r
// This exception doesn't warrent user interaction, but it should be logged (TODO)\r
}\r
\r
- Execute.OnUIThread(() =>\r
- {\r
- if (this.userSettingService.GetUserSetting<bool>(ASUserSettingConstants.PreventSleep))\r
- {\r
- Win32.AllowSleep();\r
- }\r
- });\r
-\r
this.currentTask.Status = QueueItemStatus.Completed;\r
this.IsEncoding = false;\r
- this.InvokeEncodeCompleted(new EncodeCompletedEventArgs(true, null, string.Empty));\r
+ this.InvokeEncodeCompleted(new EncodeCompletedEventArgs(true, null, string.Empty, this.currentTask.Task.Destination));\r
}\r
\r
/// <summary>\r
{\r
using System;\r
using System.Diagnostics;\r
- using System.Globalization;\r
\r
using HandBrake.ApplicationServices.Model;\r
using HandBrake.ApplicationServices.Services.Base;\r
/// </summary>\r
private bool loggingEnabled;\r
\r
+ /// <summary>\r
+ /// The Current Task\r
+ /// </summary>\r
+ private QueueTask currentTask;\r
+\r
#endregion\r
\r
/// <summary>\r
{\r
this.startTime = DateTime.Now;\r
this.loggingEnabled = enableLogging;\r
+ this.currentTask = job;\r
\r
try\r
{\r
}\r
}\r
\r
- // Prvent the system from sleeping if the user asks\r
- if (this.userSettingService.GetUserSetting<bool>(ASUserSettingConstants.PreventSleep) )\r
- {\r
- Win32.PreventSleep();\r
- }\r
-\r
// Verify the Destination Path Exists, and if not, create it.\r
this.VerifyEncodeDestinationPath(job);\r
\r
}\r
catch (Exception exc)\r
{\r
- this.InvokeEncodeCompleted(new EncodeCompletedEventArgs(false, exc, "An Error has occured."));\r
+ this.InvokeEncodeCompleted(new EncodeCompletedEventArgs(false, exc, "An Error has occured.", this.currentTask.Task.Destination));\r
}\r
}\r
\r
\r
this.InvokeEncodeCompleted(\r
e.Error\r
- ? new EncodeCompletedEventArgs(false, null, string.Empty)\r
- : new EncodeCompletedEventArgs(true, null, string.Empty));\r
-\r
- if (this.userSettingService.GetUserSetting<bool>(ASUserSettingConstants.PreventSleep))\r
- {\r
- Win32.AllowSleep();\r
- }\r
+ ? new EncodeCompletedEventArgs(false, null, string.Empty, this.currentTask.Task.Destination)\r
+ : new EncodeCompletedEventArgs(true, null, string.Empty, this.currentTask.Task.Destination));\r
\r
this.ShutdownFileWriter();\r
}\r
Task = QueryParserUtility.Parse(presetName[2])\r
};\r
\r
+ if (newPreset.Name == "iPod")\r
+ {\r
+ newPreset.Task.KeepDisplayAspect = true;\r
+ }\r
+\r
newPreset.Task.AllowedPassthruOptions = new AllowedPassthru(true); // We don't want to override the built-in preset\r
\r
if (newPreset.Name == "Normal")\r
using System;\r
using System.Collections.Generic;\r
using System.ComponentModel;\r
- using System.Diagnostics;\r
using System.IO;\r
using System.Linq;\r
- using System.Windows.Forms;\r
using System.Xml.Serialization;\r
\r
using Caliburn.Micro;\r
/// </summary>\r
private string queueFile;\r
\r
+ /// <summary>\r
+ /// The is paused.\r
+ /// </summary>\r
+ private bool isPaused;\r
+\r
#endregion\r
\r
#region Constructors and Destructors\r
{\r
Execute.OnUIThread(\r
() =>\r
+ {\r
+ List<QueueTask> deleteList =\r
+ this.queue.Where(task => task.Status == QueueItemStatus.Completed).ToList();\r
+ foreach (QueueTask item in deleteList)\r
{\r
- List<QueueTask> deleteList =\r
- this.queue.Where(task => task.Status == QueueItemStatus.Completed).ToList();\r
- foreach (QueueTask item in deleteList)\r
- {\r
- this.queue.Remove(item);\r
- }\r
- this.InvokeQueueChanged(EventArgs.Empty);\r
- });\r
+ this.queue.Remove(item);\r
+ }\r
+ this.InvokeQueueChanged(EventArgs.Empty);\r
+ });\r
}\r
\r
/// <summary>\r
catch (Exception exc)\r
{\r
throw new GeneralApplicationException(\r
- "Unable to restore queue file.", \r
- "The file may be corrupted or from an older incompatible version of HandBrake", \r
+ "Unable to restore queue file.",\r
+ "The file may be corrupted or from an older incompatible version of HandBrake",\r
exc);\r
}\r
\r
{\r
this.InvokeQueuePaused(EventArgs.Empty);\r
this.IsProcessing = false;\r
+ this.isPaused = true;\r
}\r
\r
/// <summary>\r
throw new Exception("Already Processing the Queue");\r
}\r
\r
- this.IsProcessing = true;\r
+ this.EncodeService.EncodeCompleted -= this.EncodeServiceEncodeCompleted;\r
this.EncodeService.EncodeCompleted += this.EncodeServiceEncodeCompleted;\r
- this.ProcessNextJob();\r
+\r
+ if (!this.EncodeService.IsEncoding)\r
+ {\r
+ this.ProcessNextJob();\r
+ }\r
+\r
+ this.IsProcessing = true;\r
+ this.isPaused = false;\r
}\r
\r
#endregion\r
// Handling Log Data \r
this.EncodeService.ProcessLogs(this.LastProcessedJob.Task.Destination);\r
\r
- // Post-Processing\r
- if (e.Successful)\r
- {\r
- this.SendToApplication(this.LastProcessedJob.Task.Destination);\r
- }\r
-\r
// Move onto the next job.\r
if (this.IsProcessing)\r
{\r
}\r
}\r
\r
- /// <summary>\r
- /// Perform an action after an encode. e.g a shutdown, standby, restart etc.\r
- /// </summary>\r
- private void Finish()\r
- {\r
- // Do something whent he encode ends.\r
- switch (this.userSettingService.GetUserSetting<string>(ASUserSettingConstants.WhenCompleteAction))\r
- {\r
- case "Shutdown":\r
- Process.Start("Shutdown", "-s -t 60");\r
- break;\r
- case "Log off":\r
- Win32.ExitWindowsEx(0, 0);\r
- break;\r
- case "Suspend":\r
- Application.SetSuspendState(PowerState.Suspend, true, true);\r
- break;\r
- case "Hibernate":\r
- Application.SetSuspendState(PowerState.Hibernate, true, true);\r
- break;\r
- case "Lock System":\r
- Win32.LockWorkStation();\r
- break;\r
- case "Quit HandBrake":\r
- Execute.OnUIThread(Application.Exit);\r
- break;\r
- }\r
- }\r
-\r
/// <summary>\r
/// Invoke the JobProcessingStarted event\r
/// </summary>\r
\r
// Fire the event to tell connected services.\r
this.InvokeQueueCompleted(EventArgs.Empty);\r
-\r
- // Run the After encode completeion work\r
- this.Finish();\r
- }\r
- }\r
-\r
- /// <summary>\r
- /// Send a file to a 3rd party application after encoding has completed.\r
- /// </summary>\r
- /// <param name="file">\r
- /// The file path\r
- /// </param>\r
- private void SendToApplication(string file)\r
- {\r
- if (this.userSettingService.GetUserSetting<bool>(ASUserSettingConstants.SendFile) &&\r
- !string.IsNullOrEmpty(this.userSettingService.GetUserSetting<string>(ASUserSettingConstants.SendFileTo)))\r
- {\r
- string args = string.Format(\r
- "{0} \"{1}\"", \r
- this.userSettingService.GetUserSetting<string>(ASUserSettingConstants.SendFileToArgs), \r
- file);\r
- var vlc =\r
- new ProcessStartInfo(\r
- this.userSettingService.GetUserSetting<string>(ASUserSettingConstants.SendFileTo), args);\r
- Process.Start(vlc);\r
}\r
}\r
\r
case "ffaac":\r
return "AAC (ffmpeg)";\r
case "ffflac":\r
- return "Flac (ffmpeg)";\r
+ return "FLAC (ffmpeg)";\r
+ case "ffflac24":\r
+ return "FLAC (24-bit)";\r
case "copy":\r
return "Auto Passthru";\r
default:\r
return AudioEncoder.Ac3;\r
case "ffflac":\r
return AudioEncoder.ffflac;\r
+ case "ffflac24":\r
+ return AudioEncoder.ffflac24;\r
case "copy:ac3":\r
return AudioEncoder.Ac3Passthrough;\r
case "copy:dts":\r
return AudioEncoder.AacPassthru;\r
case "MP3 Passthru":\r
return AudioEncoder.Mp3Passthru;\r
- case "Flac (ffmpeg)":\r
+ case "FLAC (ffmpeg)":\r
return AudioEncoder.ffflac;\r
+ case "FLAC (24-bit)":\r
+ return AudioEncoder.ffflac24;\r
case "Auto Passthru":\r
return AudioEncoder.Passthrough;\r
default:\r
return "faac";\r
case AudioEncoder.ffaac:\r
return "ffaac";\r
+\r
case AudioEncoder.Lame:\r
return "lame";\r
case AudioEncoder.Vorbis:\r
return "copy";\r
case AudioEncoder.ffflac:\r
return "ffflac";\r
+ case AudioEncoder.ffflac24:\r
+ return "ffflac24";\r
default:\r
return "faac";\r
}\r
// Delete old and excessivly large files (> ~50MB).\r
foreach (FileInfo file in logFiles)\r
{\r
- if (file.LastWriteTime < DateTime.Now.AddDays(-daysToKeep))\r
+ try\r
{\r
- File.Delete(file.FullName);\r
+ if (file.LastWriteTime < DateTime.Now.AddDays(-daysToKeep))\r
+ {\r
+ File.Delete(file.FullName);\r
+ }\r
+ else if (file.Length > 50000000)\r
+ {\r
+ File.Delete(file.FullName);\r
+ }\r
}\r
- else if (file.Length > 50000000)\r
+ catch (Exception)\r
{\r
- File.Delete(file.FullName);\r
+ // Silently ignore files we can't delete. They are probably being used by the app right now.\r
}\r
}\r
}\r
namespace HandBrake.ApplicationServices.Utilities\r
{\r
using System.Collections.Generic;\r
+ using System.Collections.Specialized;\r
\r
/// <summary>\r
/// Language Utilities\r
/// </summary>\r
public class LanguageUtilities\r
{\r
+ /// <summary>\r
+ /// The language map.\r
+ /// </summary>\r
+ private static IDictionary<string, string> languageMap;\r
+\r
/// <summary>\r
/// Map languages and their iso639_2 value into a IDictionary\r
/// </summary>\r
/// <returns>A Dictionary containing the language and iso code</returns>\r
public static IDictionary<string, string> MapLanguages()\r
{\r
- IDictionary<string, string> languageMap = new Dictionary<string, string>\r
+ if (languageMap != null)\r
+ {\r
+ return languageMap;\r
+ }\r
+\r
+ languageMap = new Dictionary<string, string>\r
{\r
{"(Any)", "und"}, \r
{"Afar", "aar"}, \r
};\r
return languageMap;\r
}\r
+\r
+ /// <summary>\r
+ /// The get language codes.\r
+ /// </summary>\r
+ /// <param name="userLanguages">\r
+ /// The user languages.\r
+ /// </param>\r
+ /// <returns>\r
+ /// The <see cref="IList"/>.\r
+ /// </returns>\r
+ public static List<string> GetLanguageCodes(StringCollection userLanguages)\r
+ {\r
+ // Translate to Iso Codes\r
+ List<string> iso6392Codes = new List<string>();\r
+ foreach (var item in userLanguages)\r
+ {\r
+ string isoCode;\r
+ if (LanguageUtilities.MapLanguages().TryGetValue(item, out isoCode))\r
+ {\r
+ iso6392Codes.Add(isoCode);\r
+ }\r
+ }\r
+\r
+ return iso6392Codes;\r
+ } \r
}\r
}\r
tune = tune == "none" ? "fastdecode" : tune + ",fastdecode";\r
}\r
AddEncodeElement(xmlWriter, "x264Tune", "string", tune);\r
+ AddEncodeElement(xmlWriter, "x264UseAdvancedOptions", "integer", parsed.ShowAdvancedTab ? "1" : "0");\r
+ \r
\r
int videoQualityType = 0;\r
if (parsed.VideoBitrate != null) videoQualityType = 1;\r
[Display(Name = "Vorbis (vorbis)")]\r
Vorbis,\r
\r
- [Display(Name = "Flac (ffmpeg)")]\r
+ [Display(Name = "FLAC (ffmpeg)")]\r
ffflac,\r
+\r
+ [Display(Name = "FLAC (24-bit)")]\r
+ ffflac24,\r
}\r
}\r
namespace HandBrake.Server\r
{\r
- using System;\r
using System.Linq;\r
\r
using HandBrake.ApplicationServices.Services;\r
{\r
if (args.Count() != 1)\r
{\r
- //Console.WriteLine("Invalid Arguments");\r
- //Console.ReadLine();\r
-\r
IServerService server = new ServerService();\r
server.Start("8001");\r
}\r
--- /dev/null
+// --------------------------------------------------------------------------------------------------------------------\r
+// <copyright file="DriveMenu.cs" company="HandBrake Project (http://handbrake.fr)">\r
+// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License.\r
+// </copyright>\r
+// <summary>\r
+// The drive menu.\r
+// </summary>\r
+// --------------------------------------------------------------------------------------------------------------------\r
+\r
+namespace HandBrakeWPF.AttachedProperties\r
+{\r
+ using System;\r
+ using System.Collections.Generic;\r
+ using System.Linq;\r
+ using System.Windows;\r
+ using System.Windows.Controls;\r
+ using System.Windows.Media.Imaging;\r
+\r
+ using HandBrake.ApplicationServices.Utilities;\r
+\r
+ using HandBrakeWPF.Commands;\r
+ using HandBrakeWPF.Model;\r
+ using HandBrakeWPF.ViewModels;\r
+\r
+ /// <summary>\r
+ /// The drive menu.\r
+ /// </summary>\r
+ public class DriveMenu\r
+ {\r
+ /// <summary>\r
+ /// The show available drives property.\r
+ /// </summary>\r
+ public static readonly DependencyProperty ShowAvailableDrivesProperty = DependencyProperty.RegisterAttached(\r
+ "ShowAvailableDrives",\r
+ typeof(Boolean),\r
+ typeof(DriveMenu),\r
+ new PropertyMetadata(false, OnShowAvailableDrivesChanged));\r
+\r
+ /// <summary>\r
+ /// The get show available drives.\r
+ /// </summary>\r
+ /// <param name="element">\r
+ /// The element.\r
+ /// </param>\r
+ /// <returns>\r
+ /// The <see cref="bool"/>.\r
+ /// </returns>\r
+ public static Boolean GetShowAvailableDrives(MenuItem element)\r
+ {\r
+ bool result;\r
+ return bool.TryParse(element.GetValue(ShowAvailableDrivesProperty).ToString(), out result) && result;\r
+ }\r
+\r
+ /// <summary>\r
+ /// The set show available drives.\r
+ /// </summary>\r
+ /// <param name="element">\r
+ /// The element.\r
+ /// </param>\r
+ /// <param name="value">\r
+ /// The value.\r
+ /// </param>\r
+ public static void SetShowAvailableDrives(MenuItem element, Boolean value)\r
+ {\r
+ element.SetValue(ShowAvailableDrivesProperty, value);\r
+ }\r
+\r
+ /// <summary>\r
+ /// The on show available drives changed.\r
+ /// </summary>\r
+ /// <param name="d">\r
+ /// The d.\r
+ /// </param>\r
+ /// <param name="e">\r
+ /// The e.\r
+ /// </param>\r
+ private static void OnShowAvailableDrivesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)\r
+ {\r
+ Menu menu = d as Menu;\r
+ if (menu != null)\r
+ {\r
+ menu.PreviewMouseDown -= MenuMouseDown;\r
+ menu.PreviewMouseDown += MenuMouseDown;\r
+ }\r
+ }\r
+\r
+ /// <summary>\r
+ /// The menu_ mouse down.\r
+ /// </summary>\r
+ /// <param name="sender">\r
+ /// The sender.\r
+ /// </param>\r
+ /// <param name="e">\r
+ /// The e.\r
+ /// </param>\r
+ private static void MenuMouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)\r
+ {\r
+ Menu menu = sender as Menu;\r
+ if (menu != null)\r
+ {\r
+ MainViewModel mvm = menu.DataContext as MainViewModel;\r
+ if (mvm != null)\r
+ {\r
+ List<SourceMenuItem> remove = mvm.SourceMenu.Where(s => s.IsDrive).ToList();\r
+ foreach (var item in remove)\r
+ {\r
+ mvm.SourceMenu.Remove(item);\r
+ }\r
+\r
+ foreach (SourceMenuItem menuItem in from item in GeneralUtilities.GetDrives()\r
+ let driveInformation = item\r
+ select new SourceMenuItem\r
+ {\r
+ Image = new Image { Source = new BitmapImage(new Uri("pack://application:,,,/HandBrake;component/Views/Images/disc_small.png")), Width = 16, Height = 16 },\r
+ Text = string.Format("{0} ({1})", item.RootDirectory, item.VolumeLabel),\r
+ Command = new SourceMenuCommand(() => mvm.ProcessDrive(driveInformation)),\r
+ Tag = item,\r
+ IsDrive = true\r
+ })\r
+ {\r
+ mvm.SourceMenu.Add(menuItem);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+}\r
/// The appcast 32.\r
/// </summary>\r
public const string Appcast32 = "http://handbrake.fr/appcast.i386.xml";\r
+\r
+ /// <summary>\r
+ /// The any.\r
+ /// </summary>\r
+ public const string Any = "(Any)";\r
+\r
+ /// <summary>\r
+ /// The chapters.\r
+ /// </summary>\r
+ public const string Chapters = "{chapters}";\r
+\r
+ /// <summary>\r
+ /// The title.\r
+ /// </summary>\r
+ public const string Title = "{title}";\r
}\r
}\r
--- /dev/null
+// --------------------------------------------------------------------------------------------------------------------\r
+// <copyright file="DropButton.cs" company="HandBrake Project (http://handbrake.fr)">\r
+// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License.\r
+// </copyright>\r
+// <summary>\r
+// Defines the DropDownButton type.\r
+// </summary>\r
+// --------------------------------------------------------------------------------------------------------------------\r
+\r
+namespace HandBrakeWPF.Controls.DropButton\r
+{\r
+ using System.Windows;\r
+ using System.Windows.Controls;\r
+ using System.Windows.Controls.Primitives;\r
+ using System.Windows.Data;\r
+\r
+ /// <summary>\r
+ /// The drop down button.\r
+ /// </summary>\r
+ public class DropButton : ToggleButton\r
+ {\r
+ /// <summary>\r
+ /// The drop down property.\r
+ /// </summary>\r
+ public static readonly DependencyProperty DropDownProperty =\r
+ DependencyProperty.Register("DropDown",\r
+ typeof(ContextMenu),\r
+ typeof(DropButton),\r
+ new UIPropertyMetadata(null));\r
+\r
+ /// <summary>\r
+ /// Initializes a new instance of the <see cref="DropButton"/> class.\r
+ /// </summary>\r
+ public DropButton()\r
+ {\r
+ // Bind the ToogleButton.IsChecked property to the drop-down's IsOpen property \r
+ Binding binding = new Binding("DropDown.IsOpen") { Source = this };\r
+ this.SetBinding(IsCheckedProperty, binding);\r
+ }\r
+\r
+ /// <summary>\r
+ /// Gets or sets the drop down.\r
+ /// </summary>\r
+ public ContextMenu DropDown\r
+ {\r
+ get { return (ContextMenu)this.GetValue(DropDownProperty); }\r
+ set { this.SetValue(DropDownProperty, value); }\r
+ }\r
+\r
+ /// <summary>\r
+ /// Handle the users click on the button.\r
+ /// </summary>\r
+ protected override void OnClick()\r
+ {\r
+ if (this.DropDown != null)\r
+ {\r
+ // If there is a drop-down assigned to this button, then position and display it \r
+\r
+ this.DropDown.PlacementTarget = this;\r
+ this.DropDown.Placement = PlacementMode.Bottom;\r
+ this.DropDown.IsOpen = true;\r
+ }\r
+ }\r
+ }\r
+}\r
{\r
encoders.Remove(AudioEncoder.Vorbis);\r
encoders.Remove(AudioEncoder.ffflac);\r
+ encoders.Remove(AudioEncoder.ffflac24);\r
}\r
\r
if (parameter != null && parameter.ToString() == "True")\r
<Generator>MSBuild:Compile</Generator>\r
<SubType>Designer</SubType>\r
</ApplicationDefinition>\r
+ <Compile Include="AttachedProperties\DriveMenu.cs" />\r
<Compile Include="AttachedProperties\MenuItemExtensions.cs" />\r
<Compile Include="Commands\CancelScanCommand.cs" />\r
<Compile Include="Commands\Interfaces\IAdvancedEncoderOptionsCommand.cs" />\r
<Compile Include="Commands\SourceMenuCommand.cs" />\r
<Compile Include="Commands\AdvancedEncoderOptionsCommand.cs" />\r
<Compile Include="Constants.cs" />\r
+ <Compile Include="Controls\DropButton\DropButton.cs" />\r
<Compile Include="Controls\TimeSpanBox.xaml.cs">\r
<DependentUpon>TimeSpanBox.xaml</DependentUpon>\r
</Compile>\r
<Compile Include="Helpers\GrowlCommunicator.cs" />\r
<Compile Include="Model\OptionsTab.cs" />\r
<Compile Include="Model\SelectionTitle.cs" />\r
- <Compile Include="Services\DriveDetectService.cs" />\r
<Compile Include="Services\EncodeServiceWrapper.cs" />\r
- <Compile Include="Services\Interfaces\IDriveDetectService.cs" />\r
<Compile Include="Model\ShellWindow.cs" />\r
<Compile Include="Model\SourceMenuItem.cs" />\r
<Compile Include="Model\UpdateCheckInformation.cs" />\r
<Compile Include="Model\DownloadStatus.cs" />\r
<Compile Include="Services\Interfaces\INotificationService.cs" />\r
<Compile Include="Services\Interfaces\IUpdateService.cs" />\r
+ <Compile Include="Services\Interfaces\IPrePostActionService.cs" />\r
<Compile Include="Services\NotificationService.cs" />\r
<Compile Include="Services\ScanServiceWrapper.cs" />\r
<Compile Include="Services\UpdateService.cs" />\r
+ <Compile Include="Services\PrePostActionService.cs" />\r
<Compile Include="ViewModels\AdvancedViewModel.cs" />\r
<Compile Include="ViewModels\EncoderOptionsViewModel.cs" />\r
<Compile Include="ViewModels\Interfaces\IEncoderOptionsViewModel.cs" />\r
<EmbeddedResource Include="Properties\Resources.resx">\r
<Generator>PublicResXFileCodeGenerator</Generator>\r
<LastGenOutput>Resources.Designer.cs</LastGenOutput>\r
+ <SubType>Designer</SubType>\r
</EmbeddedResource>\r
<None Include="app.config" />\r
<None Include="Installer\Installer.nsi" />\r
{\r
destinationFilename = userSettingService.GetUserSetting<string>(UserSettingConstants.AutoNameFormat);\r
destinationFilename = destinationFilename.Replace("{source}", sourceName)\r
- .Replace("{title}", dvdTitle)\r
- .Replace("{chapters}", combinedChapterTag)\r
+ .Replace(Constants.Title, dvdTitle)\r
+ .Replace(Constants.Chapters, combinedChapterTag)\r
.Replace("{date}", DateTime.Now.Date.ToShortDateString().Replace('/', '-'));\r
}\r
else\r
using System.IO;\r
using System.Security.Cryptography;\r
using System.Text.RegularExpressions;\r
+ using System.Windows.Forms;\r
\r
using Caliburn.Micro;\r
\r
\r
// Get the SHA1 Hash of HandBrakeCLI\r
byte[] hash;\r
- using (Stream stream = File.OpenRead("HandBrakeCLI.exe"))\r
+ using (Stream stream = File.OpenRead(Path.Combine(Application.StartupPath, "HandBrakeCLI.exe")))\r
{\r
hash = SHA1.Create().ComputeHash(stream);\r
}\r
\r
// It's not the same, so start the CLI to get it's version data.\r
Process cliProcess = new Process();\r
- ProcessStartInfo handBrakeCli = new ProcessStartInfo("HandBrakeCLI.exe", " -u -v0")\r
+ ProcessStartInfo handBrakeCli = new ProcessStartInfo(Path.Combine(Application.StartupPath, "HandBrakeCLI.exe"), " -u -v0")\r
{\r
UseShellExecute = false,\r
RedirectStandardError = true,\r
\r
; HM NIS Edit Wizard helper defines\r
!define PRODUCT_NAME "HandBrake"\r
-!define PRODUCT_VERSION "0.9.9"\r
-!define PRODUCT_VERSION_NUMBER "0.9.9"\r
+!define PRODUCT_VERSION "0.9.9.1"\r
+!define PRODUCT_VERSION_NUMBER "0.9.9.1"\r
!define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\Handbrake.exe"\r
!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"\r
!define PRODUCT_UNINST_ROOT_KEY "HKLM"\r
\r
; HM NIS Edit Wizard helper defines\r
!define PRODUCT_NAME "HandBrake"\r
-!define PRODUCT_VERSION "0.9.9"\r
-!define PRODUCT_VERSION_NUMBER "0.9.9"\r
+!define PRODUCT_VERSION "0.9.9.1"\r
+!define PRODUCT_VERSION_NUMBER "0.9.9.1"\r
!define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\Handbrake.exe"\r
!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"\r
!define PRODUCT_UNINST_ROOT_KEY "HKLM"\r
/// </summary>\r
public ObservableCollection<SourceMenuItem> Children { get; set; }\r
\r
+ /// <summary>\r
+ /// Gets or sets a value indicating whether is drive.\r
+ /// </summary>\r
+ public bool IsDrive { get; set; }\r
+\r
/// <summary>\r
/// Gets or sets the tag.\r
/// </summary>\r
//------------------------------------------------------------------------------\r
// <auto-generated>\r
// This code was generated by a tool.\r
-// Runtime Version:4.0.30319.296\r
+// Runtime Version:4.0.30319.18047\r
//\r
// Changes to this file may cause incorrect behavior and will be lost if\r
// the code is regenerated.\r
}\r
\r
/// <summary>\r
- /// Looks up a localized string similar to You can optionally store a maximum resolution for encodes that use this preset. There are 3 modes:\r
+ /// Looks up a localized string similar to You can optionally store a maximum resolution for encodes that use this preset. There are 4 modes:\r
///\r
- ///None: There is no maximum resolution for encodes using this preset. They will always use the source resolution minus any cropping that may be applied.\r
+ ///None: There is no maximum resolution for encodes using this preset. When the preset is loaded, the current width, height and aspect ratio that you currently have set will be reloaded.\r
///\r
- ///Custom: You can optionally set a Maximum width and height. When doing this an encode will be less than or equal to these values.\r
+ ///Custom: You can optionally set a Maximum width and Height. When doing this an encode will be less than or equal to these values. Keep Aspect Ratio will be automatically turned on.\r
///\r
- ///Source Maximum: Similar to custom, but the resolution of your current source is used as the Max width and Height values in [rest of string was truncated]";.\r
+ ///Source Maximum: Similar to custom, but [rest of string was truncated]";.\r
/// </summary>\r
public static string AddPreset_PictureSizeMode {\r
get {\r
}\r
}\r
\r
+ /// <summary>\r
+ /// Looks up a localized resource of type System.Drawing.Bitmap.\r
+ /// </summary>\r
public static System.Drawing.Bitmap logo64 {\r
get {\r
object obj = ResourceManager.GetObject("logo64", resourceCulture);\r
}\r
}\r
\r
+ /// <summary>\r
+ /// Looks up a localized string similar to WARNING: You do not have automatic file naming turned on. Please enable this in options..\r
+ /// </summary>\r
+ public static string QueueSelection_AutoNameWarning {\r
+ get {\r
+ return ResourceManager.GetString("QueueSelection_AutoNameWarning", resourceCulture);\r
+ }\r
+ }\r
+ \r
+ /// <summary>\r
+ /// Looks up a localized string similar to WARNING: You do not currently have automatic audio and subtitle track selection setup. You can setup the default track selection behaviour in options..\r
+ /// </summary>\r
+ public static string QueueSelection_AutoTrackSelectionWarning {\r
+ get {\r
+ return ResourceManager.GetString("QueueSelection_AutoTrackSelectionWarning", resourceCulture);\r
+ }\r
+ }\r
+ \r
/// <summary>\r
/// Looks up a localized string similar to Warning: RF 0 is Lossless!.\r
/// </summary>\r
Suggested values are: 18 to 20 for Standard Definition and 20 to 23 for High Definition.</value>\r
</data>\r
<data name="AddPreset_PictureSizeMode" xml:space="preserve">\r
- <value>You can optionally store a maximum resolution for encodes that use this preset. There are 3 modes:\r
+ <value>You can optionally store a maximum resolution for encodes that use this preset. There are 4 modes:\r
\r
-None: There is no maximum resolution for encodes using this preset. They will always use the source resolution minus any cropping that may be applied.\r
+None: There is no maximum resolution for encodes using this preset. When the preset is loaded, the current width, height and aspect ratio that you currently have set will be reloaded.\r
\r
-Custom: You can optionally set a Maximum width and height. When doing this an encode will be less than or equal to these values.\r
+Custom: You can optionally set a Maximum width and Height. When doing this an encode will be less than or equal to these values. Keep Aspect Ratio will be automatically turned on.\r
\r
-Source Maximum: Similar to custom, but the resolution of your current source is used as the Max width and Height values instead.</value>\r
+Source Maximum: Similar to custom, but the resolution of your current source is used as the Max width and Height values instead. Keep Aspect Ratio will be automatically turned on.\r
+\r
+No Limit: Always use the full source resolution for all sources keeping aspect ratio. This is the default behaviour.</value>\r
</data>\r
<data name="Advanced_EncoderOptions" xml:space="preserve">\r
<value>The options passed to the x264 encoder. \r
\r
If you do not use this tab, it can be hidden from: Tools Menu > Options > Advanced.</value>\r
</data>\r
+ <data name="QueueSelection_AutoNameWarning" xml:space="preserve">\r
+ <value>WARNING: You do not have automatic file naming turned on. Please enable this in options.</value>\r
+ </data>\r
+ <data name="QueueSelection_AutoTrackSelectionWarning" xml:space="preserve">\r
+ <value>WARNING: You do not currently have automatic audio and subtitle track selection setup. You can setup the default track selection behaviour in options.</value>\r
+ </data>\r
</root>
\ No newline at end of file
+++ /dev/null
-// --------------------------------------------------------------------------------------------------------------------\r
-// <copyright file="DriveDetectService.cs" company="HandBrake Project (http://handbrake.fr)">\r
-// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License.\r
-// </copyright>\r
-// <summary>\r
-// Drive Detection Helper.\r
-// </summary>\r
-// --------------------------------------------------------------------------------------------------------------------\r
-\r
-namespace HandBrakeWPF.Services\r
-{\r
- using System;\r
- using System.Management;\r
- using System.Threading;\r
-\r
- using HandBrakeWPF.Services.Interfaces;\r
-\r
- /// <summary>\r
- /// Drive Detection Helper.\r
- /// </summary>\r
- public class DriveDetectService : IDriveDetectService\r
- {\r
- /// <summary>\r
- /// The watcher.\r
- /// </summary>\r
- private ManagementEventWatcher watcher;\r
-\r
- /// <summary>\r
- /// The detection action.\r
- /// </summary>\r
- private Action detectionAction;\r
-\r
- /// <summary>\r
- /// The start detection.\r
- /// </summary>\r
- /// <param name="action">\r
- /// The detection Action.\r
- /// </param>\r
- public void StartDetection(Action action)\r
- {\r
- ThreadPool.QueueUserWorkItem(\r
- delegate\r
- {\r
- this.detectionAction = action;\r
-\r
- var options = new ConnectionOptions { EnablePrivileges = true };\r
- var scope = new ManagementScope(@"root\CIMV2", options);\r
-\r
- try\r
- {\r
- var query = new WqlEventQuery\r
- {\r
- EventClassName = "__InstanceModificationEvent",\r
- WithinInterval = TimeSpan.FromSeconds(1),\r
- Condition = @"TargetInstance ISA 'Win32_LogicalDisk' and TargetInstance.DriveType = 5" // DriveType - 5: CDROM\r
- };\r
-\r
- this.watcher = new ManagementEventWatcher(scope, query);\r
- this.watcher.EventArrived += this.WatcherEventArrived;\r
- this.watcher.Start();\r
- }\r
- catch (Exception e)\r
- {\r
- Console.WriteLine(e.Message);\r
- }\r
- });\r
- }\r
-\r
- /// <summary>\r
- /// The close.\r
- /// </summary>\r
- public void Close()\r
- {\r
- if (watcher != null)\r
- {\r
- this.watcher.Stop();\r
- }\r
- }\r
-\r
- /// <summary>\r
- /// The watcher_ event arrived.\r
- /// </summary>\r
- /// <param name="sender">\r
- /// The sender.\r
- /// </param>\r
- /// <param name="e">\r
- /// The EventArrivedEventArgs.\r
- /// </param>\r
- private void WatcherEventArrived(object sender, EventArrivedEventArgs e)\r
- {\r
- if (this.detectionAction != null)\r
- {\r
- this.detectionAction();\r
- }\r
- }\r
- }\r
-}\r
+++ /dev/null
-// --------------------------------------------------------------------------------------------------------------------\r
-// <copyright file="IDriveDetectService.cs" company="HandBrake Project (http://handbrake.fr)">\r
-// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License.\r
-// </copyright>\r
-// <summary>\r
-// Defines the IDriveDetectService type.\r
-// </summary>\r
-// --------------------------------------------------------------------------------------------------------------------\r
-\r
-namespace HandBrakeWPF.Services.Interfaces\r
-{\r
- using System;\r
-\r
- /// <summary>\r
- /// The DriveDetectService interface.\r
- /// </summary>\r
- public interface IDriveDetectService\r
- {\r
- /// <summary>\r
- /// The start detection.\r
- /// </summary>\r
- /// <param name="action">\r
- /// The detection Action.\r
- /// </param>\r
- void StartDetection(Action action);\r
-\r
- /// <summary>\r
- /// Stop the watcher. Must be done before the app shuts down.\r
- /// </summary>\r
- void Close();\r
- }\r
-}
\ No newline at end of file
-namespace HandBrakeWPF.Services.Interfaces\r
+// --------------------------------------------------------------------------------------------------------------------\r
+// <copyright file="INotificationService.cs" company="HandBrake Project (http://handbrake.fr)">\r
+// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License.\r
+// </copyright>\r
+// <summary>\r
+// Defines the INotificationService type.\r
+// </summary>\r
+// --------------------------------------------------------------------------------------------------------------------\r
+\r
+namespace HandBrakeWPF.Services.Interfaces\r
{\r
+ /// <summary>\r
+ /// The NotificationService interface.\r
+ /// </summary>\r
public interface INotificationService\r
{\r
}\r
--- /dev/null
+// --------------------------------------------------------------------------------------------------------------------\r
+// <copyright file="IPrePostActionService.cs" company="HandBrake Project (http://handbrake.fr)">\r
+// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License.\r
+// </copyright>\r
+// <summary>\r
+// Defines the IPrePostActionService type.\r
+// </summary>\r
+// --------------------------------------------------------------------------------------------------------------------\r
+\r
+namespace HandBrakeWPF.Services.Interfaces\r
+{\r
+ /// <summary>\r
+ /// The WhenDoneService interface.\r
+ /// </summary>\r
+ public interface IPrePostActionService\r
+ {\r
+ }\r
+}\r
--- /dev/null
+// --------------------------------------------------------------------------------------------------------------------\r
+// <copyright file="WhenDoneService.cs" company="HandBrake Project (http://handbrake.fr)">\r
+// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License.\r
+// </copyright>\r
+// <summary>\r
+// Defines the WhenDoneService type.\r
+// </summary>\r
+// --------------------------------------------------------------------------------------------------------------------\r
+\r
+namespace HandBrakeWPF.Services\r
+{\r
+ using System.Diagnostics;\r
+ using System.Windows.Forms;\r
+\r
+ using Caliburn.Micro;\r
+\r
+ using HandBrake.ApplicationServices.Services.Interfaces;\r
+ using HandBrake.ApplicationServices.Utilities;\r
+\r
+ using HandBrakeWPF.Services.Interfaces;\r
+\r
+ using Application = System.Windows.Application;\r
+\r
+ /// <summary>\r
+ /// The when done service.\r
+ /// </summary>\r
+ public class PrePostActionService : IPrePostActionService\r
+ {\r
+ /// <summary>\r
+ /// The queue processor.\r
+ /// </summary>\r
+ private readonly IQueueProcessor queueProcessor;\r
+\r
+ /// <summary>\r
+ /// The user setting service.\r
+ /// </summary>\r
+ private readonly IUserSettingService userSettingService;\r
+\r
+ /// <summary>\r
+ /// Initializes a new instance of the <see cref="PrePostActionService"/> class.\r
+ /// </summary>\r
+ /// <param name="queueProcessor">\r
+ /// The queue processor.\r
+ /// </param>\r
+ /// <param name="userSettingService">\r
+ /// The user Setting Service.\r
+ /// </param>\r
+ public PrePostActionService(IQueueProcessor queueProcessor, IUserSettingService userSettingService)\r
+ {\r
+ this.queueProcessor = queueProcessor;\r
+ this.userSettingService = userSettingService;\r
+\r
+ this.queueProcessor.QueueCompleted += QueueProcessorQueueCompleted;\r
+ this.queueProcessor.EncodeService.EncodeCompleted += EncodeService_EncodeCompleted;\r
+ this.queueProcessor.EncodeService.EncodeStarted += EncodeService_EncodeStarted;\r
+ }\r
+\r
+ /// <summary>\r
+ /// The encode service_ encode started.\r
+ /// </summary>\r
+ /// <param name="sender">\r
+ /// The sender.\r
+ /// </param>\r
+ /// <param name="e">\r
+ /// The e.\r
+ /// </param>\r
+ private void EncodeService_EncodeStarted(object sender, System.EventArgs e)\r
+ {\r
+ if (this.userSettingService.GetUserSetting<bool>(UserSettingConstants.PreventSleep))\r
+ {\r
+ Win32.PreventSleep();\r
+ }\r
+ }\r
+\r
+ /// <summary>\r
+ /// The encode service_ encode completed.\r
+ /// </summary>\r
+ /// <param name="sender">\r
+ /// The sender.\r
+ /// </param>\r
+ /// <param name="e">\r
+ /// The EncodeCompletedEventArgs.\r
+ /// </param>\r
+ private void EncodeService_EncodeCompleted(object sender, HandBrake.ApplicationServices.EventArgs.EncodeCompletedEventArgs e)\r
+ {\r
+ // Send the file to the users requested applicaiton\r
+ if (e.Successful)\r
+ {\r
+ this.SendToApplication(e.FileName);\r
+ }\r
+\r
+ // Allow the system to sleep again.\r
+ Execute.OnUIThread(() =>\r
+ {\r
+ if (this.userSettingService.GetUserSetting<bool>(UserSettingConstants.PreventSleep))\r
+ {\r
+ Win32.AllowSleep();\r
+ }\r
+ });\r
+ }\r
+\r
+ /// <summary>\r
+ /// The queue processor queue completed event handler.\r
+ /// </summary>\r
+ /// <param name="sender">\r
+ /// The sender.\r
+ /// </param>\r
+ /// <param name="e">\r
+ /// The e.\r
+ /// </param>\r
+ private void QueueProcessorQueueCompleted(object sender, System.EventArgs e)\r
+ {\r
+ // Do something whent he encode ends.\r
+ switch (this.userSettingService.GetUserSetting<string>(UserSettingConstants.WhenCompleteAction))\r
+ {\r
+ case "Shutdown":\r
+ Process.Start("Shutdown", "-s -t 60");\r
+ break;\r
+ case "Log off":\r
+ Win32.ExitWindowsEx(0, 0);\r
+ break;\r
+ case "Suspend":\r
+ System.Windows.Forms.Application.SetSuspendState(PowerState.Suspend, true, true);\r
+ break;\r
+ case "Hibernate":\r
+ System.Windows.Forms.Application.SetSuspendState(PowerState.Hibernate, true, true);\r
+ break;\r
+ case "Lock System":\r
+ Win32.LockWorkStation();\r
+ break;\r
+ case "Quit HandBrake":\r
+ Execute.OnUIThread(() => Application.Current.Shutdown());\r
+ break;\r
+ }\r
+ }\r
+\r
+ /// <summary>\r
+ /// Send a file to a 3rd party application after encoding has completed.\r
+ /// </summary>\r
+ /// <param name="file">\r
+ /// The file path\r
+ /// </param>\r
+ private void SendToApplication(string file)\r
+ {\r
+ if (this.userSettingService.GetUserSetting<bool>(UserSettingConstants.SendFile) &&\r
+ !string.IsNullOrEmpty(this.userSettingService.GetUserSetting<string>(UserSettingConstants.SendFileTo)))\r
+ {\r
+ string args = string.Format(\r
+ "{0} \"{1}\"",\r
+ this.userSettingService.GetUserSetting<string>(UserSettingConstants.SendFileToArgs),\r
+ file);\r
+ var vlc =\r
+ new ProcessStartInfo(\r
+ this.userSettingService.GetUserSetting<string>(UserSettingConstants.SendFileTo), args);\r
+ Process.Start(vlc);\r
+ }\r
+ }\r
+ }\r
+}\r
\r
// Services\r
this.windsorContainer.Register(Component.For<IUpdateService>().ImplementedBy<UpdateService>().LifeStyle.Is(LifestyleType.Singleton));\r
- this.windsorContainer.Register(Component.For<IDriveDetectService>().ImplementedBy<DriveDetectService>().LifeStyle.Is(LifestyleType.Singleton));\r
this.windsorContainer.Register(Component.For<IScanServiceWrapper>().ImplementedBy<ScanServiceWrapper>().LifeStyle.Is(LifestyleType.Singleton));\r
this.windsorContainer.Register(Component.For<IEncodeServiceWrapper>().ImplementedBy<EncodeServiceWrapper>().LifeStyle.Is(LifestyleType.Singleton));\r
this.windsorContainer.Register(Component.For<INotificationService>().ImplementedBy<NotificationService>().LifeStyle.Is(LifestyleType.Singleton));\r
+ this.windsorContainer.Register(Component.For<IPrePostActionService>().ImplementedBy<PrePostActionService>().LifeStyle.Is(LifestyleType.Singleton));\r
\r
// Commands\r
this.windsorContainer.Register(Component.For<IAdvancedEncoderOptionsCommand>().ImplementedBy<AdvancedEncoderOptionsCommand>().LifeStyle.Is(LifestyleType.Singleton));\r
/// Disable LibHb Features\r
/// </summary>\r
public const string DisableLibHbFeatures = "DisableLibHbFeatures";\r
+ \r
+ /// <summary>\r
+ /// When Complete Action\r
+ /// </summary>\r
+ public const string WhenCompleteAction = "WhenCompleteAction";\r
+\r
+ /// <summary>\r
+ /// Send file enabled.\r
+ /// </summary>\r
+ public const string SendFile = "SendFile";\r
+\r
+ /// <summary>\r
+ /// Send file to application path\r
+ /// </summary>\r
+ public const string SendFileTo = "SendFileTo";\r
+\r
+ /// <summary>\r
+ /// Send file to arguments\r
+ /// </summary>\r
+ public const string SendFileToArgs = "SendFileToArgs";\r
+\r
+ /// <summary>\r
+ /// Prevent Sleep\r
+ /// </summary>\r
+ public const string PreventSleep = "PreventSleep";\r
\r
#endregion\r
}\r
using System.Windows;\r
\r
using HandBrake.ApplicationServices.Model;\r
+ using HandBrake.ApplicationServices.Parsing;\r
using HandBrake.ApplicationServices.Services;\r
using HandBrake.ApplicationServices.Services.Interfaces;\r
using HandBrake.ApplicationServices.Utilities;\r
/// </summary>\r
public class AddPresetViewModel : ViewModelBase, IAddPresetViewModel\r
{\r
- /* TODO this window is up for redesign. Quite a few nippy edge cases that can cause odd behaviour with importing presets. */\r
-\r
/// <summary>\r
/// Backing field for the Preset Service\r
/// </summary>\r
/// </summary>\r
private bool showCustomInputs;\r
\r
+ /// <summary>\r
+ /// The source.\r
+ /// </summary>\r
+ private Title selectedTitle;\r
+\r
/// <summary>\r
/// Initializes a new instance of the <see cref="AddPresetViewModel"/> class.\r
/// </summary>\r
/// <param name="task">\r
/// The Encode Task.\r
/// </param>\r
- public void Setup(EncodeTask task)\r
+ public void Setup(EncodeTask task, Title title)\r
{\r
this.Preset.Task = new EncodeTask(task);\r
+ this.selectedTitle = title;\r
}\r
\r
/// <summary>\r
}\r
}\r
\r
- if (this.SelectedPictureSettingMode == PresetPictureSettingsMode.SourceMaximum && (this.Preset.Task.Width == null || this.Preset.Task.Width == 0))\r
+ if (this.SelectedPictureSettingMode == PresetPictureSettingsMode.SourceMaximum && this.selectedTitle == null)\r
{\r
this.errorService.ShowMessageBox("You must first scan a source to use the 'Source Maximum' Option.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);\r
return;\r
\r
if (this.SelectedPictureSettingMode == PresetPictureSettingsMode.SourceMaximum)\r
{\r
- this.Preset.Task.MaxWidth = this.Preset.Task.Width;\r
- this.Preset.Task.MaxHeight = this.Preset.Task.Height;\r
+ this.Preset.Task.MaxWidth = selectedTitle.Resolution.Width;\r
+ this.Preset.Task.MaxHeight = selectedTitle.Resolution.Height;\r
}\r
\r
// Add the Preset\r
/// </summary>\r
private IEnumerable<Audio> sourceTracks;\r
\r
+ /// <summary>\r
+ /// The current preset.\r
+ /// </summary>\r
private Preset currentPreset;\r
\r
#region Constructors and Destructors\r
private IEnumerable<Audio> GetSelectedLanguagesTracks()\r
{\r
List<Audio> trackList = new List<Audio>();\r
- foreach (string language in this.UserSettingService.GetUserSetting<StringCollection>(UserSettingConstants.SelectedLanguages))\r
+\r
+\r
+ List<string> isoCodes =\r
+ LanguageUtilities.GetLanguageCodes(\r
+ this.UserSettingService.GetUserSetting<StringCollection>(UserSettingConstants.SelectedLanguages));\r
+\r
+ foreach (string code in isoCodes)\r
{\r
- trackList.AddRange(this.SourceTracks.Where(source => source.Language.Trim() == language));\r
+ trackList.AddRange(this.SourceTracks.Where(source => source.LanguageCode.Trim() == code));\r
}\r
\r
return trackList;\r
namespace HandBrakeWPF.ViewModels.Interfaces\r
{\r
using HandBrake.ApplicationServices.Model;\r
+ using HandBrake.ApplicationServices.Parsing;\r
\r
/// <summary>\r
/// The Add Preset View Model\r
/// <param name="task">\r
/// The Encode Task.\r
/// </param>\r
- void Setup(EncodeTask task);\r
+ /// <param name="title">\r
+ /// The title.\r
+ /// </param>\r
+ void Setup(EncodeTask task, Title title);\r
}\r
}\r
\r
namespace HandBrakeWPF.ViewModels.Interfaces\r
{\r
+ using System;\r
using System.Collections.Generic;\r
using System.ComponentModel;\r
\r
/// <param name="sourceName">\r
/// The source Name.\r
/// </param>\r
- void Setup(Source scannedSource, string sourceName);\r
+ /// <param name="addAction">\r
+ /// The add To Queue action\r
+ /// </param>\r
+ void Setup(Source scannedSource, string sourceName, Action<IEnumerable<SelectionTitle>> addAction);\r
}\r
}\r
{\r
using System;\r
using System.Collections.Generic;\r
+ using System.ComponentModel;\r
using System.Diagnostics;\r
using System.Globalization;\r
using System.IO;\r
/// </summary>\r
private readonly IUpdateService updateService;\r
\r
- /// <summary>\r
- /// The drive detect service.\r
- /// </summary>\r
- private readonly IDriveDetectService driveDetectService;\r
-\r
/// <summary>\r
/// Backing field for the user setting service.\r
/// </summary>\r
/// <summary>\r
/// The Source Menu Backing Field\r
/// </summary>\r
- private IEnumerable<SourceMenuItem> sourceMenu;\r
+ private BindingList<SourceMenuItem> sourceMenu;\r
\r
/// <summary>\r
/// The last percentage complete value.\r
/// <param name="updateService">\r
/// The update Service.\r
/// </param>\r
- /// <param name="driveDetectService">\r
- /// The drive Detect Service.\r
- /// </param>\r
/// <param name="notificationService">\r
/// The notification Service.\r
- /// *** Leave in Constructor. *** TODO find out why?\r
+ /// *** Leave in Constructor. *** \r
+ /// </param>\r
+ /// <param name="whenDoneService">\r
+ /// The when Done Service.\r
+ /// *** Leave in Constructor. *** \r
/// </param>\r
public MainViewModel(IUserSettingService userSettingService, IScanServiceWrapper scanService, IEncodeServiceWrapper encodeService, IPresetService presetService,\r
- IErrorService errorService, IShellViewModel shellViewModel, IUpdateService updateService, IDriveDetectService driveDetectService, INotificationService notificationService)\r
+ IErrorService errorService, IShellViewModel shellViewModel, IUpdateService updateService, INotificationService notificationService,\r
+ IPrePostActionService whenDoneService)\r
{\r
this.scanService = scanService;\r
this.encodeService = encodeService;\r
this.errorService = errorService;\r
this.shellViewModel = shellViewModel;\r
this.updateService = updateService;\r
- this.driveDetectService = driveDetectService;\r
this.userSettingService = userSettingService;\r
this.queueProcessor = IoC.Get<IQueueProcessor>();\r
\r
/// <summary>\r
/// Gets or sets the source menu.\r
/// </summary>\r
- public IEnumerable<SourceMenuItem> SourceMenu\r
+ public BindingList<SourceMenuItem> SourceMenu\r
{\r
get\r
{\r
\r
if (this.UserSettingService.GetUserSetting<bool>(UserSettingConstants.AutoNaming))\r
{\r
- this.Destination = AutoNameHelper.AutoName(this.CurrentTask, this.SourceName);\r
+ if (this.userSettingService.GetUserSetting<string>(UserSettingConstants.AutoNameFormat) != null )\r
+ {\r
+ this.Destination = AutoNameHelper.AutoName(this.CurrentTask, this.SourceName);\r
+ }\r
}\r
this.NotifyOfPropertyChange(() => this.CurrentTask);\r
\r
\r
if (this.UserSettingService.GetUserSetting<bool>(UserSettingConstants.AutoNaming) && this.ScannedSource.ScanPath != null)\r
{\r
- this.Destination = AutoNameHelper.AutoName(this.CurrentTask, this.SourceName);\r
+ if (this.SelectedPointToPoint == PointToPointMode.Chapters && this.userSettingService.GetUserSetting<string>(UserSettingConstants.AutoNameFormat) != null &&\r
+ this.userSettingService.GetUserSetting<string>(UserSettingConstants.AutoNameFormat).Contains(Constants.Chapters))\r
+ {\r
+ this.Destination = AutoNameHelper.AutoName(this.CurrentTask, this.SourceName);\r
+ }\r
+ }\r
+\r
+ if (this.SelectedStartPoint > this.SelectedEndPoint)\r
+ {\r
+ this.SelectedEndPoint = this.SelectedStartPoint;\r
}\r
}\r
}\r
this.NotifyOfPropertyChange(() => this.SelectedEndPoint);\r
this.Duration = this.DurationCalculation();\r
\r
- if (this.UserSettingService.GetUserSetting<bool>(UserSettingConstants.AutoNaming) && this.ScannedSource.ScanPath != null)\r
+ if (this.SelectedPointToPoint == PointToPointMode.Chapters && this.userSettingService.GetUserSetting<string>(UserSettingConstants.AutoNameFormat) != null &&\r
+ this.userSettingService.GetUserSetting<string>(UserSettingConstants.AutoNameFormat).Contains(Constants.Chapters))\r
{\r
this.Destination = AutoNameHelper.AutoName(this.CurrentTask, this.SourceName);\r
}\r
+\r
+ if (this.SelectedStartPoint > this.SelectedEndPoint && this.SelectedPointToPoint == PointToPointMode.Chapters)\r
+ {\r
+ this.SelectedStartPoint = this.SelectedEndPoint;\r
+ }\r
}\r
}\r
\r
\r
\r
this.SelectedStartPoint = 1;\r
- this.SelectedEndPoint = selectedTitle.Chapters.Last().ChapterNumber;\r
- } \r
+ this.SelectedEndPoint = selectedTitle.Chapters != null && selectedTitle.Chapters.Count > 0 ? selectedTitle.Chapters.Last().ChapterNumber : 1;\r
+ }\r
else if (value == PointToPointMode.Seconds)\r
{\r
if (this.selectedTitle == null)\r
// Setup the presets.\r
if (this.presetService.CheckIfPresetsAreOutOfDate())\r
if (!this.userSettingService.GetUserSetting<bool>(UserSettingConstants.PresetNotification))\r
- this.errorService.ShowMessageBox("HandBrake has determined your built-in presets are out of date... These presets will now be updated.",\r
+ this.errorService.ShowMessageBox("HandBrake has determined your built-in presets are out of date... These presets will now be updated." + Environment.NewLine +\r
+ "Your custom presets have not been updated so you may have to re-create these by deleting and re-adding them.",\r
"Preset Update", MessageBoxButton.OK, MessageBoxImage.Information);\r
\r
// Queue Recovery\r
this.SelectedPreset = this.presetService.DefaultPreset;\r
\r
// Populate the Source menu with drives.\r
- this.SourceMenu = this.GenerateSourceMenu();\r
-\r
- this.driveDetectService.StartDetection(this.DriveTrayChanged);\r
+ this.SourceMenu = new BindingList<SourceMenuItem>(this.GenerateSourceMenu());\r
\r
// Log Cleaning\r
if (userSettingService.GetUserSetting<bool>(UserSettingConstants.ClearOldLogs))\r
public void Shutdown()\r
{\r
// Shutdown Service\r
- this.driveDetectService.Close();\r
-\r
this.scanService.Shutdown();\r
this.encodeService.Shutdown();\r
\r
Window window = Application.Current.Windows.Cast<Window>().FirstOrDefault(x => x.GetType() == typeof(QueueSelectionViewModel));\r
IQueueSelectionViewModel viewModel = IoC.Get<IQueueSelectionViewModel>();\r
\r
- viewModel.Setup(this.ScannedSource, this.SourceName);\r
+ viewModel.Setup(this.ScannedSource, this.SourceName, (tasks) =>\r
+ {\r
+ foreach (SelectionTitle title in tasks)\r
+ {\r
+ this.SelectedTitle = title.Title;\r
+ this.AddToQueue();\r
+ }\r
+ });\r
\r
if (window != null)\r
{\r
public void PresetAdd()\r
{\r
IAddPresetViewModel presetViewModel = IoC.Get<IAddPresetViewModel>();\r
- presetViewModel.Setup(this.CurrentTask);\r
+ presetViewModel.Setup(this.CurrentTask, this.SelectedTitle);\r
this.WindowManager.ShowWindow(presetViewModel);\r
}\r
\r
}\r
else\r
{\r
- this.SourceLabel = "Scan Failed... See Activity Log for details."; this.StatusLabel = "Scan Failed... See Activity Log for details.";\r
+ this.SourceLabel = "Scan Failed... See Activity Log for details."; this.StatusLabel = "Scan Failed... See Activity Log for details.";\r
}\r
});\r
}\r
Execute.OnUIThread(\r
() =>\r
{\r
- if (this.IsEncoding)\r
+ if (this.queueProcessor.EncodeService.IsEncoding)\r
{\r
this.ProgramStatusLabel =\r
string.Format(\r
\r
lastEncodePercentage = percent;\r
}\r
+ else\r
+ {\r
+ this.ProgramStatusLabel = "Queue Finished";\r
+ this.IsEncoding = false;\r
+\r
+ if (this.windowsSeven.IsWindowsSeven)\r
+ {\r
+ this.windowsSeven.SetTaskBarProgressToNoProgress();\r
+ }\r
+ }\r
});\r
}\r
\r
/// <param name="item">\r
/// The item.\r
/// </param>\r
- private void ProcessDrive(object item)\r
+ public void ProcessDrive(object item)\r
{\r
if (item != null)\r
{\r
/// <returns>\r
/// The System.Collections.Generic.IEnumerable`1[T -> HandBrakeWPF.Model.SourceMenuItem].\r
/// </returns>\r
- private IEnumerable<SourceMenuItem> GenerateSourceMenu()\r
+ private IList<SourceMenuItem> GenerateSourceMenu()\r
{\r
List<SourceMenuItem> menuItems = new List<SourceMenuItem>();\r
\r
{\r
Image = new Image { Source = new BitmapImage(new Uri("pack://application:,,,/HandBrake;component/Views/Images/folder.png")), Width = 16, Height = 16 },\r
Text = "Open Folder",\r
- Command = new SourceMenuCommand(this.FolderScan)\r
+ Command = new SourceMenuCommand(this.FolderScan),\r
+ IsDrive = false\r
};\r
SourceMenuItem fileScan = new SourceMenuItem\r
{\r
Image = new Image { Source = new BitmapImage(new Uri("pack://application:,,,/HandBrake;component/Views/Images/Movies.png")), Width = 16, Height = 16 },\r
Text = "Open File",\r
- Command = new SourceMenuCommand(this.FileScan)\r
+ Command = new SourceMenuCommand(this.FileScan),\r
+ IsDrive = false\r
};\r
\r
SourceMenuItem titleSpecific = new SourceMenuItem { Text = "Title Specific Scan" };\r
{\r
Image = new Image { Source = new BitmapImage(new Uri("pack://application:,,,/HandBrake;component/Views/Images/folder.png")), Width = 16, Height = 16 },\r
Text = "Open Folder",\r
- Command = new SourceMenuCommand(this.FolderScanTitleSpecific)\r
+ Command = new SourceMenuCommand(this.FolderScanTitleSpecific),\r
+ IsDrive = false\r
};\r
SourceMenuItem fileScanTitle = new SourceMenuItem\r
{\r
Image = new Image { Source = new BitmapImage(new Uri("pack://application:,,,/HandBrake;component/Views/Images/Movies.png")), Width = 16, Height = 16 },\r
Text = "Open File",\r
- Command = new SourceMenuCommand(this.FileScanTitleSpecific)\r
+ Command = new SourceMenuCommand(this.FileScanTitleSpecific),\r
+ IsDrive = false\r
};\r
titleSpecific.Children.Add(folderScanTitle);\r
titleSpecific.Children.Add(fileScanTitle);\r
Image = new Image { Source = new BitmapImage(new Uri("pack://application:,,,/HandBrake;component/Views/Images/disc_small.png")), Width = 16, Height = 16 },\r
Text = string.Format("{0} ({1})", item.RootDirectory, item.VolumeLabel),\r
Command = new SourceMenuCommand(() => this.ProcessDrive(driveInformation)),\r
- Tag = item\r
+ Tag = item,\r
+ IsDrive = true\r
});\r
\r
return menuItems;\r
}\r
\r
- /// <summary>\r
- /// The drive tray changed.\r
- /// </summary>\r
- private void DriveTrayChanged()\r
- {\r
- Caliburn.Micro.Execute.OnUIThread(() => this.SourceMenu = this.GenerateSourceMenu());\r
- }\r
-\r
/// <summary>\r
/// Allows the main window to respond to setting changes.\r
/// </summary>\r
/// </param>\r
private void CurrentTask_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)\r
{\r
- if (e.PropertyName == UserSettingConstants.ShowAdvancedTab)\r
- {\r
- this.NotifyOfPropertyChange(() => this.ShowAdvancedTab);\r
- }\r
+ if (e.PropertyName == UserSettingConstants.ShowAdvancedTab)\r
+ {\r
+ this.NotifyOfPropertyChange(() => this.ShowAdvancedTab);\r
+ }\r
}\r
\r
#endregion\r
using System.Linq;\r
using System.Windows;\r
\r
+ using Caliburn.Micro;\r
+\r
using HandBrake.ApplicationServices;\r
using HandBrake.ApplicationServices.Services.Interfaces;\r
using HandBrake.ApplicationServices.Utilities;\r
/// <param name="updateService">\r
/// The update Service.\r
/// </param>\r
- public OptionsViewModel(IUserSettingService userSettingService, IShellViewModel shellViewModel, IUpdateService updateService )\r
+ public OptionsViewModel(IUserSettingService userSettingService, IShellViewModel shellViewModel, IUpdateService updateService)\r
{\r
this.Title = "Options";\r
this.userSettingService = userSettingService;\r
this.whenDoneOptions.Add("Hibernate");\r
this.whenDoneOptions.Add("Lock System");\r
this.whenDoneOptions.Add("Log off");\r
- // this.whenDoneOptions.Add("Quit HandBrake");\r
+ this.whenDoneOptions.Add("Quit HandBrake");\r
this.WhenDone = userSettingService.GetUserSetting<string>("WhenCompleteAction");\r
\r
this.GrowlAfterEncode = userSettingService.GetUserSetting<bool>(UserSettingConstants.GrowlEncode);\r
this.GrowlAfterQueue = userSettingService.GetUserSetting<bool>(UserSettingConstants.GrowlQueue);\r
- this.SendFileAfterEncode = this.userSettingService.GetUserSetting<bool>(ASUserSettingConstants.SendFile);\r
- this.SendFileTo = Path.GetFileNameWithoutExtension(this.userSettingService.GetUserSetting<string>(ASUserSettingConstants.SendFileTo)) ?? string.Empty;\r
- this.SendFileToPath = this.userSettingService.GetUserSetting<string>(ASUserSettingConstants.SendFileTo) ?? string.Empty;\r
- this.Arguments = this.userSettingService.GetUserSetting<string>(ASUserSettingConstants.SendFileToArgs) ?? string.Empty;\r
+ this.SendFileAfterEncode = this.userSettingService.GetUserSetting<bool>(UserSettingConstants.SendFile);\r
+ this.SendFileTo = Path.GetFileNameWithoutExtension(this.userSettingService.GetUserSetting<string>(UserSettingConstants.SendFileTo)) ?? string.Empty;\r
+ this.SendFileToPath = this.userSettingService.GetUserSetting<string>(UserSettingConstants.SendFileTo) ?? string.Empty;\r
+ this.Arguments = this.userSettingService.GetUserSetting<string>(UserSettingConstants.SendFileToArgs) ?? string.Empty;\r
\r
// #############################\r
// Output Settings\r
this.preferredLanguages.Add(item);\r
\r
// In the available languages should be no "Any" and no selected language.\r
- if ((item != "(Any)") && (!this.userSettingService.GetUserSetting<StringCollection>(UserSettingConstants.SelectedLanguages).Contains(item)))\r
+ if ((item != Constants.Any) && (!this.userSettingService.GetUserSetting<StringCollection>(UserSettingConstants.SelectedLanguages).Contains(item)))\r
{\r
this.availableLanguages.Add(item);\r
}\r
this.priorityLevelOptions.Add("Low");\r
this.SelectedPriority = userSettingService.GetUserSetting<string>(ASUserSettingConstants.ProcessPriority);\r
\r
- this.PreventSleep = userSettingService.GetUserSetting<bool>(ASUserSettingConstants.PreventSleep);\r
+ this.PreventSleep = userSettingService.GetUserSetting<bool>(UserSettingConstants.PreventSleep);\r
\r
// Log Verbosity Level\r
this.logVerbosityOptions.Clear();\r
/* General */\r
this.userSettingService.SetUserSetting(UserSettingConstants.UpdateStatus, this.CheckForUpdates);\r
this.userSettingService.SetUserSetting(UserSettingConstants.DaysBetweenUpdateCheck, this.CheckForUpdatesFrequency);\r
- this.userSettingService.SetUserSetting(ASUserSettingConstants.WhenCompleteAction, this.WhenDone);\r
+ this.userSettingService.SetUserSetting(UserSettingConstants.WhenCompleteAction, this.WhenDone);\r
this.userSettingService.SetUserSetting(UserSettingConstants.GrowlQueue, this.GrowlAfterQueue);\r
this.userSettingService.SetUserSetting(UserSettingConstants.GrowlEncode, this.GrowlAfterEncode);\r
- this.userSettingService.SetUserSetting(ASUserSettingConstants.SendFileTo, this.SendFileToPath);\r
- this.userSettingService.SetUserSetting(ASUserSettingConstants.SendFile, this.SendFileAfterEncode);\r
- this.userSettingService.SetUserSetting(ASUserSettingConstants.SendFileToArgs, this.Arguments);\r
+ this.userSettingService.SetUserSetting(UserSettingConstants.SendFileTo, this.SendFileToPath);\r
+ this.userSettingService.SetUserSetting(UserSettingConstants.SendFile, this.SendFileAfterEncode);\r
+ this.userSettingService.SetUserSetting(UserSettingConstants.SendFileToArgs, this.Arguments);\r
\r
/* Output Files */\r
this.userSettingService.SetUserSetting(UserSettingConstants.AutoNaming, this.AutomaticallyNameFiles);\r
\r
/* System and Logging */\r
userSettingService.SetUserSetting(ASUserSettingConstants.ProcessPriority, this.SelectedPriority);\r
- userSettingService.SetUserSetting(ASUserSettingConstants.PreventSleep, this.PreventSleep);\r
+ userSettingService.SetUserSetting(UserSettingConstants.PreventSleep, this.PreventSleep);\r
userSettingService.SetUserSetting(ASUserSettingConstants.Verbosity, this.SelectedVerbosity);\r
userSettingService.SetUserSetting(ASUserSettingConstants.SaveLogWithVideo, this.CopyLogToEncodeDirectory);\r
userSettingService.SetUserSetting(ASUserSettingConstants.SaveLogToCopyDirectory, this.CopyLogToSepcficedLocation);\r
userSettingService.SetUserSetting(UserSettingConstants.ServerPort, this.ServerPort.ToString());\r
userSettingService.SetUserSetting(UserSettingConstants.EnableDebugFeatures, this.EnableDebugFeatures);\r
userSettingService.SetUserSetting(UserSettingConstants.DisableLibHbFeatures, this.DisableLibHbFeatures);\r
+ userSettingService.SetUserSetting(UserSettingConstants.EnableLibHb, this.EnableLibHb);\r
}\r
\r
/// <summary>\r
{\r
this.UpdateMessage = "A New Update is Available!";\r
this.UpdateAvailable = true;\r
- } \r
+ }\r
else\r
{\r
this.UpdateMessage = "There are no new updates at this time.";\r
this.UpdateMessage = info.WasSuccessful ? "Update Downloaded" : "Update Failed. You can try downloading the update from http://handbrake.fr";\r
\r
Process.Start(Path.Combine(Path.GetTempPath(), "handbrake-setup.exe"));\r
- Application.Current.Shutdown();\r
+ Execute.OnUIThread(() => Application.Current.Shutdown());\r
}\r
\r
/// <summary>\r
{\r
this.Task = task;\r
\r
- // TODO: These all need to be handled correctly.\r
- this.SelectedAnamorphicMode = preset.Task.Anamorphic;\r
-\r
- // Set the limits on the UI Controls.\r
- this.MaxWidth = preset.Task.MaxWidth ?? this.sourceResolution.Width;\r
- this.MaxHeight = preset.Task.MaxHeight ?? this.sourceResolution.Height;\r
- this.Task.MaxWidth = preset.Task.MaxWidth;\r
- this.Task.MaxHeight = preset.Task.MaxHeight;\r
-\r
- // Setup the Width\r
- if (preset.Task.MaxWidth.HasValue)\r
+ // Handle built-in presets.\r
+ if (preset.IsBuildIn)\r
{\r
- if (this.Width > preset.Task.MaxWidth)\r
- {\r
- // Limit the Width to the Max Width\r
- this.Width = preset.Task.MaxWidth.Value; \r
- }\r
- else\r
- {\r
- // Figure out the best width based on the preset and source\r
- this.Width = preset.Task.Width ?? this.GetModulusValue(this.getRes((this.sourceResolution.Width - this.CropLeft - this.CropRight), preset.Task.MaxWidth.Value));\r
- }\r
+ preset.PictureSettingsMode = PresetPictureSettingsMode.Custom;\r
}\r
- else\r
+\r
+ // Setup the Picture Sizes\r
+ switch (preset.PictureSettingsMode)\r
{\r
- this.Width = preset.Task.Width ?? this.GetModulusValue((this.sourceResolution.Width - this.CropLeft - this.CropRight));\r
- }\r
+ default:\r
+ case PresetPictureSettingsMode.Custom:\r
+ case PresetPictureSettingsMode.SourceMaximum:\r
\r
- // Set the Maintain Aspect ratio. This will calculate Height for us now.\r
- this.MaintainAspectRatio = preset.Task.Anamorphic == Anamorphic.None || preset.Task.KeepDisplayAspect;\r
+ // Anamorphic Mode\r
+ this.SelectedAnamorphicMode = preset.Task.Anamorphic;\r
\r
- // Set Height, but only if necessary.\r
- if (preset.Task.MaxHeight.HasValue)\r
- {\r
- if (this.Height > preset.Task.MaxHeight)\r
- {\r
- // Limit the Height to the Max Height of the preset. Setting this will recalculate the width.\r
- this.Height = preset.Task.MaxHeight.Value;\r
- }\r
- else\r
- {\r
- // Only calculate height if Maintain Aspect ratio is off.\r
- if (!this.MaintainAspectRatio)\r
+ // Modulus\r
+ if (preset.Task.Modulus.HasValue)\r
{\r
- this.Height = preset.Task.Height ??\r
- this.getRes(\r
- (this.sourceResolution.Height - this.CropTop - this.CropBottom),\r
- preset.Task.MaxHeight.Value);\r
+ this.SelectedModulus = preset.Task.Modulus;\r
}\r
- }\r
+\r
+ // Set the Maintain Aspect ratio.\r
+ this.MaintainAspectRatio = preset.Task.KeepDisplayAspect;\r
+\r
+ // Set the width, then check the height doesn't breach the max height and correct if necessary.\r
+ int width = this.GetModulusValue(this.getRes((this.sourceResolution.Width - this.CropLeft - this.CropRight), preset.Task.MaxWidth));\r
+ this.Width = width;\r
+\r
+ // If we have a max height, make sure we havn't breached it.\r
+ int height = this.GetModulusValue(this.getRes((this.sourceResolution.Height - this.CropTop - this.CropBottom), preset.Task.MaxHeight));\r
+ if (preset.Task.MaxHeight.HasValue && this.Height > preset.Task.MaxHeight.Value)\r
+ {\r
+ this.Height = height;\r
+ }\r
+\r
+ this.MaxWidth = width;\r
+ this.MaxHeight = height;\r
+ break;\r
+ case PresetPictureSettingsMode.None:\r
+ // Do Nothing except reset the Max Width/Height\r
+ this.MaxWidth = this.sourceResolution.Width;\r
+ this.MaxHeight = this.sourceResolution.Height;\r
+ break;\r
}\r
\r
- // Anamorphic\r
+ // Custom Anamorphic\r
if (preset.Task.Anamorphic == Anamorphic.Custom)\r
{\r
this.DisplayWidth = preset.Task.DisplayWidth != null ? int.Parse(preset.Task.DisplayWidth.ToString()) : 0;\r
this.ParHeight = preset.Task.PixelAspectY;\r
}\r
\r
- // Modulus\r
- if (preset.Task.Modulus.HasValue)\r
- {\r
- this.SelectedModulus = preset.Task.Modulus;\r
- }\r
-\r
// Cropping\r
if (preset.Task.HasCropping)\r
{\r
this.sourceParValues = title.ParVal;\r
this.sourceResolution = title.Resolution;\r
\r
- // Set the Max Width / Height available to the user controls\r
- if (this.sourceResolution.Width < this.MaxWidth)\r
+ if (preset.PictureSettingsMode == PresetPictureSettingsMode.None)\r
{\r
- this.MaxWidth = this.sourceResolution.Width;\r
+ // We have no instructions, so simply set it to the source.\r
+ this.Width = this.GetModulusValue(this.sourceResolution.Width - this.CropLeft - this.CropRight);\r
+ this.MaintainAspectRatio = true;\r
}\r
- else if (this.sourceResolution.Width > this.MaxWidth)\r
+ else\r
{\r
- this.MaxWidth = preset.Task.MaxWidth ?? this.sourceResolution.Width;\r
- }\r
+ // Set the Max Width / Height available to the user controls\r
+ if (this.sourceResolution.Width < this.MaxWidth)\r
+ {\r
+ this.MaxWidth = this.sourceResolution.Width;\r
+ }\r
+ else if (this.sourceResolution.Width > this.MaxWidth)\r
+ {\r
+ this.MaxWidth = preset.Task.MaxWidth ?? this.sourceResolution.Width;\r
+ }\r
\r
- if (this.sourceResolution.Height < this.MaxHeight)\r
- {\r
- this.MaxHeight = this.sourceResolution.Height;\r
- }\r
- else if (this.sourceResolution.Height > this.MaxHeight)\r
- {\r
- this.MaxHeight = preset.Task.MaxHeight ?? this.sourceResolution.Height;\r
+ if (this.sourceResolution.Height < this.MaxHeight)\r
+ {\r
+ this.MaxHeight = this.sourceResolution.Height;\r
+ }\r
+ else if (this.sourceResolution.Height > this.MaxHeight)\r
+ {\r
+ this.MaxHeight = preset.Task.MaxHeight ?? this.sourceResolution.Height;\r
+ }\r
+\r
+ // Update the cropping values, preffering those in the presets.\r
+ if (!preset.Task.HasCropping)\r
+ {\r
+ this.CropTop = title.AutoCropDimensions.Top;\r
+ this.CropBottom = title.AutoCropDimensions.Bottom;\r
+ this.CropLeft = title.AutoCropDimensions.Left;\r
+ this.CropRight = title.AutoCropDimensions.Right;\r
+ this.IsCustomCrop = false;\r
+ }\r
+ else\r
+ {\r
+ this.CropLeft = preset.Task.Cropping.Left;\r
+ this.CropRight = preset.Task.Cropping.Right;\r
+ this.CropTop = preset.Task.Cropping.Top;\r
+ this.CropBottom = preset.Task.Cropping.Bottom;\r
+ this.IsCustomCrop = true;\r
+ }\r
+\r
+ // Set the Width, and Maintain Aspect ratio. That should calc the Height for us.\r
+ this.Width = preset.Task.Width ?? this.MaxWidth; // Note: This will be auto-corrected in the property if it's too large.\r
+\r
+ // If our height is too large, let it downscale the width for us by setting the height to the lower value.\r
+ if (!this.MaintainAspectRatio && this.Height > this.MaxHeight)\r
+ {\r
+ this.Height = this.MaxHeight;\r
+ }\r
+\r
+ if (this.SelectedAnamorphicMode == Anamorphic.Custom)\r
+ {\r
+ this.AnamorphicAdjust(); // Refresh the values\r
+ }\r
}\r
\r
// Set Screen Controls\r
title.Resolution.Width,\r
title.Resolution.Height,\r
title.AspectRatio);\r
-\r
- if (!preset.Task.HasCropping)\r
- {\r
- this.CropTop = title.AutoCropDimensions.Top;\r
- this.CropBottom = title.AutoCropDimensions.Bottom;\r
- this.CropLeft = title.AutoCropDimensions.Left;\r
- this.CropRight = title.AutoCropDimensions.Right;\r
- this.IsCustomCrop = false;\r
- }\r
- else\r
- {\r
- this.CropLeft = preset.Task.Cropping.Left;\r
- this.CropRight = preset.Task.Cropping.Right;\r
- this.CropTop = preset.Task.Cropping.Top;\r
- this.CropBottom = preset.Task.Cropping.Bottom;\r
- this.IsCustomCrop = true;\r
- }\r
-\r
- // Set the Width, and Maintain Aspect ratio. That should calc the Height for us.\r
- this.Width = this.MaxWidth;\r
- this.MaintainAspectRatio = true;\r
-\r
- // If our height is too large, let it downscale the width for us by setting the height to the lower value.\r
- if (this.Height > this.MaxHeight)\r
- {\r
- this.Height = this.MaxHeight;\r
- }\r
- \r
- if (this.SelectedAnamorphicMode == Anamorphic.Custom)\r
- {\r
- this.AnamorphicAdjust(); // Refresh the values\r
- }\r
}\r
\r
this.NotifyOfPropertyChange(() => this.Task);\r
this.ShowDisplaySize = false;\r
this.ShowKeepAR = true;\r
this.SelectedModulus = 16; // Reset\r
- this.Width = this.sourceResolution.Width;\r
+ if (this.Width == 0)\r
+ {\r
+ this.Width = this.GetModulusValue(this.sourceResolution.Width - this.CropLeft - this.CropRight);\r
+ }\r
+\r
+ if (!this.MaintainAspectRatio && this.Height == 0)\r
+ {\r
+ this.Height = this.GetModulusValue(this.sourceResolution.Height - this.CropTop - this.CropBottom);\r
+ }\r
+\r
this.SetDisplaySize();\r
break;\r
case Anamorphic.Strict:\r
this.HeightControlEnabled = false;\r
this.ShowCustomAnamorphicControls = false;\r
this.ShowModulus = true;\r
- this.Width = this.sourceResolution.Width;\r
+ if (this.Width == 0)\r
+ {\r
+ this.Width = this.sourceResolution.Width;\r
+ }\r
this.Height = 0;\r
this.ShowKeepAR = false;\r
\r
/// <returns>\r
/// An Int\r
/// </returns>\r
- private int getRes(int value, int max)\r
+ private int getRes(int value, int? max)\r
{\r
- return value > max ? max : value;\r
+ return max.HasValue ? (value > max.Value ? max.Value : value) : value;\r
}\r
\r
#endregion\r
/// </summary>\r
private bool orderedByTitle;\r
\r
+ /// <summary>\r
+ /// The add to queue.\r
+ /// </summary>\r
+ private Action<IEnumerable<SelectionTitle>> addToQueue;\r
+\r
/// <summary>\r
/// Initializes a new instance of the <see cref="QueueSelectionViewModel"/> class. \r
/// </summary>\r
}\r
}\r
\r
+ /// <summary>\r
+ /// Gets a value indicating whether is auto naming enabled.\r
+ /// </summary>\r
+ public bool IsAutoNamingEnabled\r
+ {\r
+ get\r
+ {\r
+ return this.UserSettingService.GetUserSetting<bool>(UserSettingConstants.AutoNaming);\r
+ }\r
+ }\r
+\r
+ /// <summary>\r
+ /// Gets a value indicating whether is automatic track selection enabled.\r
+ /// </summary>\r
+ public bool IsAutomaticTrackSelectionEnabled\r
+ {\r
+ get\r
+ {\r
+ // TODO decide what is the minimal requirement to hide the warning message.\r
+ if (this.UserSettingService.GetUserSetting<string>(UserSettingConstants.NativeLanguage) != Constants.Any ||\r
+ this.UserSettingService.GetUserSetting<string>(UserSettingConstants.NativeLanguageForSubtitles) !=\r
+ Constants.Any)\r
+ {\r
+ return true;\r
+ }\r
+\r
+ return false;\r
+ }\r
+ }\r
+\r
/// <summary>\r
/// The order by title.\r
/// </summary>\r
/// </summary>\r
public void Add()\r
{\r
+ this.addToQueue(this.TitleList.Where(c => c.IsSelected));\r
this.Close();\r
}\r
\r
/// <param name="srcName">\r
/// The src Name.\r
/// </param>\r
- public void Setup(Source scannedSource, string srcName)\r
+ /// <param name="addAction">\r
+ /// The add Action.\r
+ /// </param>\r
+ public void Setup(Source scannedSource, string srcName, Action<IEnumerable<SelectionTitle>> addAction)\r
{\r
this.TitleList.Clear();\r
+ this.addToQueue = addAction;\r
\r
if (scannedSource != null)\r
{\r
-\r
IEnumerable<Title> titles = orderedByTitle\r
? scannedSource.Titles\r
: scannedSource.Titles.OrderByDescending(o => o.Duration).ToList();\r
\r
foreach (Title item in titles)\r
{\r
- SelectionTitle title = new SelectionTitle(item, srcName);\r
+ SelectionTitle title = new SelectionTitle(item, srcName) { IsSelected = true };\r
TitleList.Add(title);\r
}\r
}\r
+\r
+ this.NotifyOfPropertyChange(() => this.IsAutoNamingEnabled);\r
+ this.NotifyOfPropertyChange(() => this.IsAutomaticTrackSelectionEnabled);\r
}\r
}\r
}\r
namespace HandBrakeWPF.ViewModels\r
{\r
using System;\r
- using System.Collections.ObjectModel;\r
using System.ComponentModel;\r
using System.Windows;\r
\r
using Caliburn.Micro;\r
\r
- using HandBrake.ApplicationServices;\r
using HandBrake.ApplicationServices.EventArgs;\r
using HandBrake.ApplicationServices.Model;\r
using HandBrake.ApplicationServices.Services.Interfaces;\r
/// </summary>\r
public class QueueViewModel : ViewModelBase, IQueueViewModel\r
{\r
- /*\r
- \r
- * TODO FIX THE DRAP/DROP ADORNER!\r
- */\r
-\r
-\r
-\r
#region Constants and Fields\r
\r
/// <summary>\r
/// <summary>\r
/// Initializes a new instance of the <see cref="QueueViewModel"/> class.\r
/// </summary>\r
- /// <param name="windowManager">\r
- /// The window manager.\r
- /// </param>\r
/// <param name="userSettingService">\r
/// The user Setting Service.\r
/// </param>\r
/// <param name="errorService">\r
/// The Error Service \r
/// </param>\r
- public QueueViewModel(IWindowManager windowManager, IUserSettingService userSettingService, IQueueProcessor queueProcessor, IErrorService errorService)\r
+ public QueueViewModel(IUserSettingService userSettingService, IQueueProcessor queueProcessor, IErrorService errorService)\r
{\r
this.userSettingService = userSettingService;\r
this.queueProcessor = queueProcessor;\r
public void WhenDone(string action)\r
{\r
this.WhenDoneAction = action;\r
- this.userSettingService.SetUserSetting(ASUserSettingConstants.WhenCompleteAction, action);\r
+ this.userSettingService.SetUserSetting(UserSettingConstants.WhenCompleteAction, action);\r
}\r
\r
/// <summary>\r
public void PauseEncode()\r
{\r
this.queueProcessor.Pause();\r
+\r
+ this.JobStatus = "Queue Paused";\r
+ this.JobsPending = string.Format("{0} jobs pending", this.queueProcessor.Count);\r
+ this.IsEncoding = false;\r
+\r
+ MessageBox.Show("The Queue has been pasued. The currently running job will run to completion and no further jobs will start.", "Queue",\r
+ MessageBoxButton.OK, MessageBoxImage.Information);\r
}\r
\r
/// <summary>\r
return;\r
}\r
\r
+ this.JobStatus = "Queue Started";\r
+ this.JobsPending = string.Format("{0} jobs pending", this.queueProcessor.Count);\r
+ this.IsEncoding = true;\r
+\r
this.queueProcessor.Start();\r
}\r
\r
{\r
this.Load();\r
\r
- this.WhenDoneAction = this.userSettingService.GetUserSetting<string>(ASUserSettingConstants.WhenCompleteAction);\r
+ this.WhenDoneAction = this.userSettingService.GetUserSetting<string>(UserSettingConstants.WhenCompleteAction);\r
\r
- this.queueProcessor.JobProcessingStarted += this.queueProcessor_JobProcessingStarted;\r
this.queueProcessor.QueueCompleted += this.queueProcessor_QueueCompleted;\r
- this.queueProcessor.QueuePaused += this.queueProcessor_QueuePaused;\r
this.queueProcessor.QueueChanged += this.QueueManager_QueueChanged;\r
this.queueProcessor.EncodeService.EncodeStatusChanged += this.EncodeService_EncodeStatusChanged;\r
+ this.queueProcessor.EncodeService.EncodeCompleted += EncodeService_EncodeCompleted;\r
+ this.queueProcessor.JobProcessingStarted += this.QueueProcessorJobProcessingStarted;\r
+\r
+ this.JobsPending = string.Format("{0} jobs pending", this.queueProcessor.Count);\r
+ this.JobStatus = "Queue Ready";\r
\r
base.OnActivate();\r
}\r
/// </param>\r
protected override void OnDeactivate(bool close)\r
{\r
- this.queueProcessor.JobProcessingStarted -= this.queueProcessor_JobProcessingStarted;\r
this.queueProcessor.QueueCompleted -= this.queueProcessor_QueueCompleted;\r
- this.queueProcessor.QueuePaused -= this.queueProcessor_QueuePaused;\r
this.queueProcessor.QueueChanged -= this.QueueManager_QueueChanged;\r
this.queueProcessor.EncodeService.EncodeStatusChanged -= this.EncodeService_EncodeStatusChanged;\r
+ this.queueProcessor.EncodeService.EncodeCompleted -= EncodeService_EncodeCompleted;\r
+ this.queueProcessor.JobProcessingStarted -= this.QueueProcessorJobProcessingStarted;\r
\r
base.OnDeactivate(close);\r
}\r
{\r
Caliburn.Micro.Execute.OnUIThread(() =>\r
{\r
- if (this.IsEncoding)\r
- {\r
- this.JobStatus =\r
- string.Format(\r
- "Encoding: Pass {0} of {1}, {2:00.00}%, FPS: {3:000.0}, Avg FPS: {4:000.0}, Time Remaining: {5}, Elapsed: {6:hh\\:mm\\:ss}",\r
- e.Task,\r
- e.TaskCount,\r
- e.PercentComplete,\r
- e.CurrentFrameRate,\r
- e.AverageFrameRate,\r
- e.EstimatedTimeLeft,\r
- e.ElapsedTime);\r
- }\r
\r
+\r
+ this.JobStatus =\r
+ string.Format(\r
+ "Encoding: Pass {0} of {1}, {2:00.00}%, FPS: {3:000.0}, Avg FPS: {4:000.0}, Time Remaining: {5}, Elapsed: {6:hh\\:mm\\:ss}",\r
+ e.Task,\r
+ e.TaskCount,\r
+ e.PercentComplete,\r
+ e.CurrentFrameRate,\r
+ e.AverageFrameRate,\r
+ e.EstimatedTimeLeft,\r
+ e.ElapsedTime);\r
});\r
}\r
\r
private void QueueManager_QueueChanged(object sender, EventArgs e)\r
{\r
this.JobsPending = string.Format("{0} jobs pending", this.queueProcessor.Count);\r
+\r
+ if (!queueProcessor.IsProcessing)\r
+ {\r
+ this.JobStatus = "Queue Not Running";\r
+ }\r
}\r
\r
/// <summary>\r
- /// Handle teh Job Processing Started Event\r
+ /// Handle the Queue Completed Event\r
/// </summary>\r
/// <param name="sender">\r
/// The sender.\r
/// </param>\r
/// <param name="e">\r
- /// The QueueProgressEventArgs.\r
+ /// The EventArgs.\r
/// </param>\r
- private void queueProcessor_JobProcessingStarted(\r
- object sender, QueueProgressEventArgs e)\r
+ private void queueProcessor_QueueCompleted(object sender, EventArgs e)\r
{\r
- this.JobStatus = "Queue Started";\r
+ this.JobStatus = "Queue Completed";\r
this.JobsPending = string.Format("{0} jobs pending", this.queueProcessor.Count);\r
- this.IsEncoding = true;\r
+ this.IsEncoding = false;\r
}\r
\r
/// <summary>\r
- /// Handle the Queue Completed Event\r
+ /// The encode service_ encode completed.\r
/// </summary>\r
/// <param name="sender">\r
/// The sender.\r
/// </param>\r
/// <param name="e">\r
- /// The EventArgs.\r
+ /// The e.\r
/// </param>\r
- private void queueProcessor_QueueCompleted(object sender, EventArgs e)\r
+ private void EncodeService_EncodeCompleted(object sender, EncodeCompletedEventArgs e)\r
{\r
- this.JobStatus = "Queue Completed";\r
- this.JobsPending = string.Format("{0} jobs pending", this.queueProcessor.Count);\r
- this.IsEncoding = false;\r
+ if (!this.queueProcessor.IsProcessing)\r
+ {\r
+ this.JobStatus = "Last Queued Job Finished";\r
+ }\r
}\r
\r
/// <summary>\r
- /// Handle the Queue Paused Event\r
+ /// The queue processor job processing started.\r
/// </summary>\r
/// <param name="sender">\r
/// The sender.\r
/// </param>\r
/// <param name="e">\r
- /// The EventArgs.\r
+ /// The QueueProgressEventArgs.\r
/// </param>\r
- private void queueProcessor_QueuePaused(object sender, EventArgs e)\r
+ private void QueueProcessorJobProcessingStarted(object sender, QueueProgressEventArgs e)\r
{\r
- this.JobStatus = "Queue Paused";\r
+ this.JobStatus = "Queue Started";\r
this.JobsPending = string.Format("{0} jobs pending", this.queueProcessor.Count);\r
- this.IsEncoding = false;\r
+ this.IsEncoding = true;\r
}\r
\r
#endregion\r
/// </summary>\r
public void AddAllClosedCaptions()\r
{\r
-\r
foreach (Subtitle subtitle in this.SourceTitlesSubset(null).Where(s => s.SubtitleType == SubtitleType.CC))\r
{\r
this.Add(subtitle);\r
public void AddAllRemainingForSelectedLanguages()\r
{\r
// Get a list of subtitle tracks that match the users lanaguages\r
- StringCollection userSelectedLanguages =\r
- this.UserSettingService.GetUserSetting<StringCollection>(UserSettingConstants.SelectedLanguages);\r
- userSelectedLanguages.Add(\r
- this.UserSettingService.GetUserSetting<string>(UserSettingConstants.NativeLanguageForSubtitles));\r
+ StringCollection userSelectedLanguages = this.UserSettingService.GetUserSetting<StringCollection>(UserSettingConstants.SelectedLanguages);\r
+ userSelectedLanguages.Add(this.UserSettingService.GetUserSetting<string>(UserSettingConstants.NativeLanguageForSubtitles));\r
+\r
+ // Translate to Iso Codes\r
+ List<string> iso6392Codes = LanguageUtilities.GetLanguageCodes(userSelectedLanguages);\r
+\r
List<Subtitle> availableTracks =\r
- this.SourceTracks.Where(subtitle => userSelectedLanguages.Contains(subtitle.Language)).ToList();\r
+ this.SourceTracks.Where(subtitle => iso6392Codes.Contains(subtitle.LanguageCodeClean)).ToList();\r
\r
foreach (Subtitle subtitle in this.SourceTitlesSubset(availableTracks))\r
{\r
{\r
get\r
{\r
- return 51.Equals(this.RF) && this.SelectedVideoEncoder == VideoEncoder.X264;\r
+ return 0.0.Equals(this.DisplayRF) && this.SelectedVideoEncoder == VideoEncoder.X264;\r
}\r
}\r
\r
Grid.Column="0"\r
Style="{StaticResource LongToolTipHolder}"\r
ToolTip="{x:Static Properties:Resources.AddPreset_PictureSizeMode}"\r
- Text="Picture Size:" />\r
+ Text="Max Picture Size:" />\r
<ComboBox Grid.Row="2"\r
Grid.Column="1"\r
Width="125"\r
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"\r
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"\r
xmlns:NumericUpDown="clr-namespace:EagleBoost.Wpf.Presentation.Controls.NumericUpDown;assembly=EagleBoost.Wpf.Presentation"\r
- xmlns:controls="clr-namespace:HandBrakeWPF.Controls"\r
+ xmlns:dropButton="clr-namespace:HandBrakeWPF.Controls.DropButton"\r
d:DesignHeight="170"\r
d:DesignWidth="616"\r
mc:Ignorable="d">\r
<ColumnDefinition Width="*" />\r
<ColumnDefinition Width="Auto" />\r
</Grid.ColumnDefinitions>\r
- <Button Grid.Column="0"\r
- MaxWidth="95"\r
+ \r
+ <StackPanel Orientation="Horizontal" Grid.Row="0">\r
+ <dropButton:DropButton Content="Add Track" FontWeight="Bold" Margin="0,0,10,0" Style="{StaticResource DropButtonStyle}">\r
+ <dropButton:DropButton.DropDown>\r
+ <ContextMenu>\r
+ <MenuItem Header="Add New Track" cal:Message.Attach="[Event Click] = [Action Add]" />\r
+ <MenuItem Header="Add All Remaining Tracks" cal:Message.Attach="[Event Click] = [Action AddAllRemaining]" />\r
+ <MenuItem Header="Add All Remaining Selected Languages" cal:Message.Attach="[Event Click] = [Action AddAllRemainingForSelectedLanguages]" />\r
+ </ContextMenu>\r
+ </dropButton:DropButton.DropDown>\r
+ </dropButton:DropButton>\r
+ \r
+ <Button MinWidth="65"\r
Margin="0,0,10,0"\r
- cal:Message.Attach="[Event Click] = [Action Add]"\r
- Content="Add Track" />\r
+ cal:Message.Attach="[Event Click] = [Action Clear]"\r
+ Content="Clear" />\r
+\r
+\r
+ </StackPanel>\r
\r
<StackPanel Grid.Column="2"\r
Orientation="Horizontal"\r
xmlns:Converters="clr-namespace:HandBrakeWPF.Converters"\r
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"\r
xmlns:Micro="clr-namespace:Caliburn.Micro;assembly=Caliburn.Micro"\r
- AllowDrop="True"\r
+ xmlns:attachedProperties="clr-namespace:HandBrakeWPF.AttachedProperties"\r
+ AllowDrop="True"\r
Background="#FFF0F0F0"\r
FontSize="11"\r
Micro:Message.Attach="[Event Loaded] = [Action Load]"\r
ToolBar.OverflowMode="Never"\r
ToolBarTray.IsLocked="True"\r
>\r
- <Menu Background="Transparent">\r
+ <Menu Background="Transparent" attachedProperties:DriveMenu.ShowAvailableDrives="true">\r
<MenuItem ItemsSource="{Binding SourceMenu}">\r
<MenuItem.Header>\r
<StackPanel Orientation="Horizontal">\r
</StackPanel>\r
</MenuItem.Header>\r
<MenuItem Header="Add All" Micro:Message.Attach="[Event Click] = [Action AddAllToQueue]" />\r
- <!--<MenuItem Header="Add Selection" Micro:Message.Attach="[Event Click] = [Action AddSelectionToQueue]" />-->\r
+ <MenuItem Header="Add Selection" Micro:Message.Attach="[Event Click] = [Action AddSelectionToQueue]" />\r
</MenuItem>\r
</Menu>\r
\r
xmlns:cal="http://www.caliburnproject.org"\r
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"\r
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"\r
+ xmlns:Conveters="clr-namespace:HandBrakeWPF.Converters"\r
+ xmlns:Properties="clr-namespace:HandBrakeWPF.Properties"\r
Title="{Binding Title}"\r
Width="450"\r
MaxHeight="450"\r
<Setter Property="ToolTipService.ShowDuration" Value="20000" />\r
<Setter Property="Margin" Value="0,2,0,2" />\r
</Style>\r
+ \r
+ <Conveters:BooleanToVisibilityConverter x:Key="boolToVisConverter" />\r
</Window.Resources>\r
\r
<Grid HorizontalAlignment="Stretch"\r
\r
<!-- Header -->\r
<StackPanel Grid.Row="0"\r
- Height="30"\r
+ Height="36"\r
Margin="0,0,0,10"\r
Background="White"\r
Orientation="Horizontal">\r
- <Image Width="24"\r
- Height="24"\r
+ <Image Width="32"\r
+ Height="32"\r
Margin="10,0,5,0"\r
VerticalAlignment="Center"\r
Source="Images/AddToQueue_small.png" />\r
<StackPanel VerticalAlignment="Center" Orientation="Vertical">\r
- <TextBlock FontWeight="Bold" Text="Queue Multiple Items" />\r
+ <TextBlock FontWeight="Bold" Text="Add to Queue" />\r
+ <TextBlock Text="*** Experimental ***" />\r
</StackPanel>\r
</StackPanel>\r
\r
<ListBox.ContextMenu>\r
<ContextMenu>\r
<MenuItem Header="Select All" cal:Message.Attach="[Event Click] = [Action SelectAll]" />\r
- <MenuItem Header="Select All" cal:Message.Attach="[Event Click] = [Action UnSelectAll]" />\r
+ <MenuItem Header="Deselect All" cal:Message.Attach="[Event Click] = [Action UnSelectAll]" />\r
<Separator />\r
<MenuItem Header="Order by Title" IsChecked="{Binding OrderedByTitle}" cal:Message.Attach="[Event Click] = [Action OrderByTitle]" />\r
<MenuItem Header="Order by Duration" IsChecked="{Binding OrderedByDuration}" cal:Message.Attach="[Event Click] = [Action OrderByDuration]" />\r
\r
<!-- Checlist -->\r
<StackPanel Orientation="Vertical" Grid.Row="3" Margin="10,10,10,0">\r
- <TextBlock Text="Checklist " />\r
+ <TextBlock Text="{x:Static Properties:Resources.QueueSelection_AutoTrackSelectionWarning}"\r
+ TextWrapping="Wrap" Visibility="{Binding IsAutomaticTrackSelectionEnabled, Converter={StaticResource boolToVisConverter}, ConverterParameter=true}" \r
+ Margin="0,0,0,10"/>\r
+\r
+ <TextBlock Text="{x:Static Properties:Resources.QueueSelection_AutoNameWarning}"\r
+ TextWrapping="Wrap" Visibility="{Binding IsAutoNamingEnabled, Converter={StaticResource boolToVisConverter}, ConverterParameter=true}"/>\r
</StackPanel>\r
\r
<!-- Controls -->\r
xmlns:YourNamespace="clr-namespace:HandBrakeWPF.AttachedProperties"\r
xmlns:Audio="clr-namespace:HandBrakeWPF.Converters.Audio"\r
xmlns:Subtitles="clr-namespace:HandBrakeWPF.Converters.Subtitles" Title="{Binding Title}"\r
- Width="600"\r
- Height="400"\r
- MinWidth="600"\r
- MinHeight="400"\r
- MaxWidth="600"\r
+ Width="700"\r
+ Height="500"\r
+ MinWidth="200"\r
+ MinHeight="200"\r
Background="#FFF0F0F0"\r
WindowStartupLocation="CenterScreen"\r
TextOptions.TextFormattingMode="Display"\r
<Converters:QueueStatusToVisibilityConverter x:Key="queueStatusVisConverter" />\r
<Audio:AudioQueueDisplayConverter x:Key="audioTrackDisplayConverter" />\r
<Subtitles:SubtitlesQueueDisplayConverter x:Key="subtitleTrackDisplayConverter" />\r
+\r
+\r
+ <Style x:Key="LongToolTipHolder" TargetType="FrameworkElement">\r
+ <Setter Property="ToolTipService.ShowDuration" Value="10000" />\r
+ </Style>\r
+\r
</Window.Resources>\r
\r
<Grid>\r
YourNamespace:MenuItemExtensions.GroupName="whenDone" />\r
<MenuItem x:Name="lock"\r
cal:Message.Attach="[Event Click] = [Action WhenDone(lock.Header)]"\r
- Header="Lock system"\r
+ Header="Lock System"\r
IsCheckable="True"\r
YourNamespace:MenuItemExtensions.GroupName="whenDone" />\r
<MenuItem x:Name="logoff"\r
<TextBlock Text="{Binding JobsPending}" />\r
<TextBlock Text="{Binding JobStatus}" />\r
</StackPanel>\r
- \r
+\r
<ListBox Grid.Row="2"\r
Margin="10,0,10,10"\r
Background="LightGray"\r
<Setter Property="Margin" Value="0,0,0,1" />\r
<Setter Property="ToolTip">\r
<Setter.Value>\r
- <StackPanel Grid.Column="1"\r
- Margin="0,5,0,5"\r
- HorizontalAlignment="Stretch">\r
- <StackPanel Orientation="Horizontal">\r
- <TextBlock FontWeight="Bold" Text="Video" />\r
- <TextBlock Text=": " />\r
- <TextBlock Text="{Binding Task.VideoEncoder, Converter={StaticResource enumComboConverter}}" />\r
- <TextBlock Margin="10,0,0,0" FontWeight="Bold" Text="Audio: " />\r
- <TextBlock Text="{Binding Task.AudioTracks, Converter={StaticResource audioTrackDisplayConverter}}" />\r
- </StackPanel>\r
-\r
- <StackPanel Orientation="Horizontal">\r
- <TextBlock FontWeight="Bold" Text="Subtitles: " />\r
- <TextBlock Text="{Binding Task.SubtitleTracks, Converter={StaticResource subtitleTrackDisplayConverter}}" />\r
- </StackPanel>\r
-\r
- <StackPanel Orientation="Horizontal">\r
- <TextBlock FontWeight="Bold" Text="Advanced: " />\r
- <TextBlock Text="{Binding Task.AdvancedEncoderOptions}" />\r
- </StackPanel>\r
+ <Grid MaxWidth="650" Margin="0,5,0,5" Style="{StaticResource LongToolTipHolder}">\r
+ <Grid.Resources>\r
+ <Style TargetType="TextBlock">\r
+ <Setter Property="Margin" Value="0,5,0,5" />\r
+ </Style>\r
+ </Grid.Resources>\r
+\r
+ <Grid.RowDefinitions>\r
+ <RowDefinition Height="Auto" />\r
+ <RowDefinition Height="Auto" />\r
+ <RowDefinition Height="Auto" />\r
+ <RowDefinition Height="Auto" />\r
+ <RowDefinition Height="Auto" />\r
+ <RowDefinition Height="Auto" />\r
+ </Grid.RowDefinitions>\r
+\r
+ <Grid.ColumnDefinitions>\r
+ <ColumnDefinition Width="90" />\r
+ <ColumnDefinition Width="*" />\r
+ </Grid.ColumnDefinitions>\r
+\r
+ <TextBlock FontWeight="Bold" Text="Source:" VerticalAlignment="Top" Grid.Row="0" Grid.Column="0" />\r
+ <TextBlock Text="{Binding Task.Source}" TextWrapping="Wrap" Grid.Row="0" Grid.Column="1" />\r
+\r
+ <TextBlock FontWeight="Bold" Text="Destination:" VerticalAlignment="Top" Grid.Row="1" Grid.Column="0" />\r
+ <TextBlock Text="{Binding Task.Destination}" TextWrapping="Wrap" Grid.Row="1" Grid.Column="1" />\r
+\r
+ <TextBlock FontWeight="Bold" Text="Video:" Grid.Row="2" Grid.Column="0" />\r
+ <TextBlock Text="{Binding Task.VideoEncoder, Converter={StaticResource enumComboConverter}}"\r
+ Grid.Row="2" Grid.Column="1" />\r
+\r
+ <TextBlock FontWeight="Bold" Text="Audio: " Grid.Row="3" Grid.Column="0"/>\r
+ <TextBlock Text="{Binding Task.AudioTracks, Converter={StaticResource audioTrackDisplayConverter}}"\r
+ Grid.Row="3" Grid.Column="1"/>\r
+\r
+ <TextBlock FontWeight="Bold" VerticalAlignment="Top" Text="Subtitles: " Grid.Row="4" Grid.Column="0" />\r
+ <TextBlock Text="{Binding Task.SubtitleTracks, Converter={StaticResource subtitleTrackDisplayConverter}}"\r
+ Grid.Row="4" Grid.Column="1" />\r
+\r
+\r
+ <TextBlock FontWeight="Bold" VerticalAlignment="Top" Grid.Row="5" Grid.Column="0" Text="Advanced: " />\r
+ <TextBlock Text="{Binding Task.AdvancedEncoderOptions}" Grid.Row="5" Grid.Column="1" />\r
+ </Grid>\r
\r
- </StackPanel>\r
</Setter.Value>\r
</Setter>\r
</Style>\r
\r
<Style x:Key="{x:Type StatusBar}" TargetType="{x:Type StatusBar}">\r
<Setter Property="SnapsToDevicePixels" Value="True"/>\r
- <Setter Property="OverridesDefaultStyle" Value="true"/>\r
<Setter Property="Template">\r
<Setter.Value>\r
<ControlTemplate TargetType="{x:Type StatusBar}">\r
\r
<SolidColorBrush x:Key="GlyphBrush" Color="#444"/>\r
\r
+ <Style x:Key="DropButtonStyle" TargetType="ToggleButton" >\r
+ <Setter Property="Padding" Value="2,2" />\r
+ <Setter Property="ContentTemplate">\r
+ <Setter.Value>\r
+ <DataTemplate>\r
+ <Grid VerticalAlignment="Stretch">\r
+ <Grid.ColumnDefinitions>\r
+ <ColumnDefinition Width="*" />\r
+ <ColumnDefinition Width="Auto" />\r
+ <ColumnDefinition Width="Auto" />\r
+ </Grid.ColumnDefinitions>\r
+\r
+ <TextBlock Text="{TemplateBinding Content}" Margin="4,0,0,0" Grid.Column="0" />\r
+\r
+ <!--<Rectangle Grid.Column="1" Width="1" Fill="Black" Opacity="0.4" Margin="6,2,0,2"/>-->\r
+\r
+ <Path Data="M 0,0 L 8,0 L 4,4 Z" Fill="Black" Grid.Column="2" Margin="4,0,4,0" VerticalAlignment="Center"/>\r
+ </Grid>\r
+ </DataTemplate>\r
+ </Setter.Value>\r
+ </Setter>\r
+ </Style>\r
+\r
</ResourceDictionary>
\ No newline at end of file
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"\r
xmlns:NumericUpDown="clr-namespace:EagleBoost.Wpf.Presentation.Controls.NumericUpDown;assembly=EagleBoost.Wpf.Presentation"\r
xmlns:controls="clr-namespace:HandBrakeWPF.Controls"\r
+ xmlns:dropButton="clr-namespace:HandBrakeWPF.Controls.DropButton"\r
d:DesignHeight="153"\r
d:DesignWidth="319"\r
mc:Ignorable="d">\r
FontWeight="Bold"\r
Text="Subtitles" />\r
\r
- <Grid Grid.Row="1" Margin="10,5,10,0">\r
- <Grid.ColumnDefinitions>\r
- <ColumnDefinition Width="Auto" />\r
- <ColumnDefinition Width="Auto" />\r
- <ColumnDefinition Width="Auto" />\r
- </Grid.ColumnDefinitions>\r
- <Button Name="AddTrack"\r
- Grid.Column="0"\r
- Width="75"\r
- Margin="0,0,10,0"\r
- cal:Message.Attach="[Event Click] = [Action Add]"\r
- Content="Add" />\r
- <Button Grid.Column="2"\r
- MaxWidth="100"\r
+ <StackPanel Grid.Row="1" Margin="10,5,10,0" Orientation="Horizontal">\r
+ <dropButton:DropButton Content="Add Track" FontWeight="Bold" Margin="0,0,10,0" Style="{StaticResource DropButtonStyle}">\r
+ <dropButton:DropButton.DropDown>\r
+ <ContextMenu>\r
+ <MenuItem Header="Add New Track" cal:Message.Attach="[Event Click] = [Action Add]" />\r
+ <MenuItem Header="Add All Remaining Tracks" cal:Message.Attach="[Event Click] = [Action AddAllRemaining]" />\r
+ <MenuItem Header="Add All Remaining Closed Captions" cal:Message.Attach="[Event Click] = [Action AddAllClosedCaptions]" />\r
+ <MenuItem Header="Add All Remaining Selected Languages" cal:Message.Attach="[Event Click] = [Action AddAllRemainingForSelectedLanguages]" />\r
+ </ContextMenu>\r
+ </dropButton:DropButton.DropDown>\r
+ </dropButton:DropButton>\r
+\r
+ <Button MinWidth="75"\r
cal:Message.Attach="[Event Click] = [Action Import]"\r
- Content="Import SRT" />\r
- </Grid>\r
+ Content="Import SRT"\r
+ Margin="0,0,10,0"/>\r
+ <Button MinWidth="65"\r
+ Grid.Column="3"\r
+ Margin="0,0,10,0"\r
+ cal:Message.Attach="[Event Click] = [Action Clear]"\r
+ Content="Clear" />\r
+ </StackPanel>\r
\r
<ListBox Grid.Row="2"\r
Margin="10,10,10,10"\r
\r
<StackPanel Orientation="Horizontal" Margin="0,0,0,10" >\r
<RadioButton Content="Constant Quality:" IsChecked="{Binding IsConstantQuantity}" Margin="0,0,10,0"/>\r
- <TextBlock Text="{Binding DisplayRF}" Width="25" />\r
- <TextBlock Text="{Binding Rfqp}" FontWeight="Bold" />\r
+ <TextBlock Text="{Binding DisplayRF}" MinWidth="30" />\r
+ <TextBlock Text="{Binding Rfqp}" FontWeight="Bold" Margin="5,0,0,0" />\r
\r
<TextBlock Text="{x:Static Properties:Resources.Video_LosslessWarning}" Visibility="{Binding IsLossless, Converter={StaticResource boolToVisConverter}}" \r
Margin="10,0,0,0" ToolTip="{x:Static Properties:Resources.Video_LosslessWarningTooltip}" FontWeight="Bold" />\r
<string>ShowAdvancedTab</string>\r
</key>\r
<value>\r
- <anyType xmlns:q1="http://www.w3.org/2001/XMLSchema" d4p1:type="q1:boolean" xmlns:d4p1="http://www.w3.org/2001/XMLSchema-instance">true</anyType>\r
+ <anyType xmlns:q1="http://www.w3.org/2001/XMLSchema" d4p1:type="q1:boolean" xmlns:d4p1="http://www.w3.org/2001/XMLSchema-instance">false</anyType>\r
</value>\r
</item>\r
<item>\r