obs-ffmpeg: Refactor media source properties

Reactors a bit of code related to starting up FFmpeg and makes it so the
initial view for the media source's properties displays the most
commonly desired settings.

Instead of the media source properties showing the URL mode by default
along with a whole bunch of properties that are confusing to most users,
starts on file mode and changes defaults to be a bit more sensible
related to file input.

Also, as a temporary measure for fixing color format issues (some video
files would display their color information incorrectly), forced format
conversion is now enabled by default, and has been moved to advanced
settings.  Ideally, the actual bug causing color format issues in either
media-io or libff should be fixed at some point.
master
jp9000 2016-01-23 02:31:45 -08:00
parent df4f0c4142
commit 419d6b1a22
1 changed files with 108 additions and 70 deletions

View File

@ -45,6 +45,14 @@ struct ffmpeg_source {
uint8_t *sws_data; uint8_t *sws_data;
int sws_linesize; int sws_linesize;
obs_source_t *source; obs_source_t *source;
char *input;
char *input_format;
enum AVDiscard frame_drop;
int audio_buffer_size;
int video_buffer_size;
bool is_advanced;
bool is_looping;
bool is_forcing_scale; bool is_forcing_scale;
bool is_hw_decoding; bool is_hw_decoding;
bool is_clear_on_media_end; bool is_clear_on_media_end;
@ -303,9 +311,11 @@ static bool is_advanced_modified(obs_properties_t *props,
UNUSED_PARAMETER(prop); UNUSED_PARAMETER(prop);
bool enabled = obs_data_get_bool(settings, "advanced"); bool enabled = obs_data_get_bool(settings, "advanced");
obs_property_t *fscale = obs_properties_get(props, "force_scale");
obs_property_t *abuf = obs_properties_get(props, "audio_buffer_size"); obs_property_t *abuf = obs_properties_get(props, "audio_buffer_size");
obs_property_t *vbuf = obs_properties_get(props, "video_buffer_size"); obs_property_t *vbuf = obs_properties_get(props, "video_buffer_size");
obs_property_t *frame_drop = obs_properties_get(props, "frame_drop"); obs_property_t *frame_drop = obs_properties_get(props, "frame_drop");
obs_property_set_visible(fscale, enabled);
obs_property_set_visible(abuf, enabled); obs_property_set_visible(abuf, enabled);
obs_property_set_visible(vbuf, enabled); obs_property_set_visible(vbuf, enabled);
obs_property_set_visible(frame_drop, enabled); obs_property_set_visible(frame_drop, enabled);
@ -313,6 +323,17 @@ static bool is_advanced_modified(obs_properties_t *props,
return true; return true;
} }
static void ffmpeg_source_defaults(obs_data_t *settings)
{
obs_data_set_default_bool(settings, "is_local_file", true);
obs_data_set_default_bool(settings, "looping", false);
obs_data_set_default_bool(settings, "clear_on_media_end", true);
obs_data_set_default_bool(settings, "force_scale", true);
#if defined(_WIN32) || defined(__APPLE__)
obs_data_set_default_bool(settings, "hw_decode", true);
#endif
}
static const char *media_filter = static const char *media_filter =
" (*.mp4 *.ts *.mov *.flv *.mkv *.avi *.mp3 *.ogg *.aac *.wav *.gif *.webm);;"; " (*.mp4 *.ts *.mov *.flv *.mkv *.avi *.mp3 *.ogg *.aac *.wav *.gif *.webm);;";
static const char *video_filter = static const char *video_filter =
@ -358,9 +379,6 @@ static obs_properties_t *ffmpeg_source_getproperties(void *data)
obs_properties_add_text(props, "input_format", obs_properties_add_text(props, "input_format",
obs_module_text("InputFormat"), OBS_TEXT_DEFAULT); obs_module_text("InputFormat"), OBS_TEXT_DEFAULT);
obs_properties_add_bool(props, "force_scale",
obs_module_text("ForceFormat"));
obs_properties_add_bool(props, "hw_decode", obs_properties_add_bool(props, "hw_decode",
obs_module_text("HardwareDecode")); obs_module_text("HardwareDecode"));
@ -372,6 +390,9 @@ static obs_properties_t *ffmpeg_source_getproperties(void *data)
obs_property_set_modified_callback(prop, is_advanced_modified); obs_property_set_modified_callback(prop, is_advanced_modified);
obs_properties_add_bool(props, "force_scale",
obs_module_text("ForceFormat"));
prop = obs_properties_add_int(props, "audio_buffer_size", prop = obs_properties_add_int(props, "audio_buffer_size",
obs_module_text("AudioBufferSize"), 1, 9999, 1); obs_module_text("AudioBufferSize"), 1, 9999, 1);
@ -440,7 +461,7 @@ static void dump_source_info(struct ffmpeg_source *s, const char *input,
"\tis_clear_on_media_end: %s", "\tis_clear_on_media_end: %s",
input ? input : "(null)", input ? input : "(null)",
input_format ? input_format : "(null)", input_format ? input_format : "(null)",
s->demuxer->options.is_looping ? "yes" : "no", s->is_looping ? "yes" : "no",
s->is_forcing_scale ? "yes" : "no", s->is_forcing_scale ? "yes" : "no",
s->is_hw_decoding ? "yes" : "no", s->is_hw_decoding ? "yes" : "no",
s->is_clear_on_media_end ? "yes" : "no"); s->is_clear_on_media_end ? "yes" : "no");
@ -453,74 +474,19 @@ static void dump_source_info(struct ffmpeg_source *s, const char *input,
"\taudio_buffer_size: %d\n" "\taudio_buffer_size: %d\n"
"\tvideo_buffer_size: %d\n" "\tvideo_buffer_size: %d\n"
"\tframe_drop: %s", "\tframe_drop: %s",
s->demuxer->options.audio_frame_queue_size, s->audio_buffer_size,
s->demuxer->options.video_frame_queue_size, s->video_buffer_size,
frame_drop_to_str(s->demuxer->options.frame_drop)); frame_drop_to_str(s->frame_drop));
} }
static void ffmpeg_source_update(void *data, obs_data_t *settings) static void ffmpeg_source_start(struct ffmpeg_source *s)
{ {
struct ffmpeg_source *s = data;
bool is_local_file = obs_data_get_bool(settings, "is_local_file");
bool is_advanced = obs_data_get_bool(settings, "advanced");
bool is_looping;
char *input;
char *input_format;
if (is_local_file) {
input = (char *)obs_data_get_string(settings, "local_file");
input_format = NULL;
is_looping = obs_data_get_bool(settings, "looping");
} else {
input = (char *)obs_data_get_string(settings, "input");
input_format = (char *)obs_data_get_string(settings,
"input_format");
is_looping = false;
}
s->is_forcing_scale = obs_data_get_bool(settings, "force_scale");
s->is_hw_decoding = obs_data_get_bool(settings, "hw_decode");
s->is_clear_on_media_end = obs_data_get_bool(settings,
"clear_on_media_end");
if (s->demuxer != NULL) if (s->demuxer != NULL)
ff_demuxer_free(s->demuxer); ff_demuxer_free(s->demuxer);
s->demuxer = ff_demuxer_init(); s->demuxer = ff_demuxer_init();
s->demuxer->options.is_hw_decoding = s->is_hw_decoding; s->demuxer->options.is_hw_decoding = s->is_hw_decoding;
s->demuxer->options.is_looping = is_looping; s->demuxer->options.is_looping = s->is_looping;
if (is_advanced) {
int audio_buffer_size = (int)obs_data_get_int(settings,
"audio_buffer_size");
int video_buffer_size = (int)obs_data_get_int(settings,
"video_buffer_size");
enum AVDiscard frame_drop =
(enum AVDiscard)obs_data_get_int(settings,
"frame_drop");
if (audio_buffer_size < 1) {
audio_buffer_size = 1;
FF_BLOG(LOG_WARNING, "invalid audio_buffer_size %d",
audio_buffer_size);
}
if (video_buffer_size < 1) {
video_buffer_size = 1;
FF_BLOG(LOG_WARNING, "invalid audio_buffer_size %d",
audio_buffer_size);
}
s->demuxer->options.audio_frame_queue_size = audio_buffer_size;
s->demuxer->options.video_frame_queue_size = video_buffer_size;
if (frame_drop < AVDISCARD_NONE || frame_drop > AVDISCARD_ALL) {
frame_drop = AVDISCARD_NONE;
FF_BLOG(LOG_WARNING, "invalid frame_drop %d",
frame_drop);
}
s->demuxer->options.frame_drop = frame_drop;
}
ff_demuxer_set_callbacks(&s->demuxer->video_callbacks, ff_demuxer_set_callbacks(&s->demuxer->video_callbacks,
video_frame, NULL, video_frame, NULL,
@ -530,11 +496,81 @@ static void ffmpeg_source_update(void *data, obs_data_t *settings)
audio_frame, NULL, audio_frame, NULL,
NULL, NULL, NULL, s); NULL, NULL, NULL, s);
dump_source_info(s, input, input_format, is_advanced); if (s->is_advanced) {
s->demuxer->options.audio_frame_queue_size =
s->audio_buffer_size;
s->demuxer->options.video_frame_queue_size =
s->video_buffer_size;
s->demuxer->options.frame_drop = s->frame_drop;
}
ff_demuxer_open(s->demuxer, input, input_format); ff_demuxer_open(s->demuxer, s->input, s->input_format);
} }
static void ffmpeg_source_update(void *data, obs_data_t *settings)
{
struct ffmpeg_source *s = data;
bool is_local_file = obs_data_get_bool(settings, "is_local_file");
bool is_advanced = obs_data_get_bool(settings, "advanced");
char *input;
char *input_format;
bfree(s->input);
bfree(s->input_format);
if (is_local_file) {
input = (char *)obs_data_get_string(settings, "local_file");
input_format = NULL;
s->is_looping = obs_data_get_bool(settings, "looping");
} else {
input = (char *)obs_data_get_string(settings, "input");
input_format = (char *)obs_data_get_string(settings,
"input_format");
s->is_looping = false;
}
s->input = input ? bstrdup(input) : NULL;
s->input_format = input_format ? bstrdup(input_format) : NULL;
s->is_advanced = is_advanced;
s->is_hw_decoding = obs_data_get_bool(settings, "hw_decode");
s->is_clear_on_media_end = obs_data_get_bool(settings,
"clear_on_media_end");
s->is_forcing_scale = true;
if (is_advanced) {
s->audio_buffer_size = (int)obs_data_get_int(settings,
"audio_buffer_size");
s->video_buffer_size = (int)obs_data_get_int(settings,
"video_buffer_size");
s->frame_drop = (enum AVDiscard)obs_data_get_int(settings,
"frame_drop");
s->is_forcing_scale = obs_data_get_bool(settings,
"force_scale");
if (s->audio_buffer_size < 1) {
s->audio_buffer_size = 1;
FF_BLOG(LOG_WARNING, "invalid audio_buffer_size %d",
s->audio_buffer_size);
}
if (s->video_buffer_size < 1) {
s->video_buffer_size = 1;
FF_BLOG(LOG_WARNING, "invalid audio_buffer_size %d",
s->audio_buffer_size);
}
if (s->frame_drop < AVDISCARD_NONE ||
s->frame_drop > AVDISCARD_ALL) {
s->frame_drop = AVDISCARD_DEFAULT;
FF_BLOG(LOG_WARNING, "invalid frame_drop %d",
s->frame_drop);
}
}
dump_source_info(s, input, input_format, is_advanced);
ffmpeg_source_start(s);
}
static const char *ffmpeg_source_getname(void *unused) static const char *ffmpeg_source_getname(void *unused)
{ {
@ -557,13 +593,14 @@ static void ffmpeg_source_destroy(void *data)
{ {
struct ffmpeg_source *s = data; struct ffmpeg_source *s = data;
ff_demuxer_free(s->demuxer); if (s->demuxer)
ff_demuxer_free(s->demuxer);
if (s->sws_ctx != NULL) if (s->sws_ctx != NULL)
sws_freeContext(s->sws_ctx); sws_freeContext(s->sws_ctx);
if (s->sws_data != NULL) bfree(s->sws_data);
bfree(s->sws_data); bfree(s->input);
bfree(s->input_format);
bfree(s); bfree(s);
} }
@ -574,6 +611,7 @@ struct obs_source_info ffmpeg_source = {
.get_name = ffmpeg_source_getname, .get_name = ffmpeg_source_getname,
.create = ffmpeg_source_create, .create = ffmpeg_source_create,
.destroy = ffmpeg_source_destroy, .destroy = ffmpeg_source_destroy,
.get_defaults = ffmpeg_source_defaults,
.get_properties = ffmpeg_source_getproperties, .get_properties = ffmpeg_source_getproperties,
.update = ffmpeg_source_update .update = ffmpeg_source_update
}; };