以MLT自带的Melt命令行工具源码为例
去掉一些不重要的代码
melt.c
cpp
int main(int argc, char **argv)
{
int i;
mlt_consumer consumer = NULL;
FILE *store = NULL;
char *name = NULL;
mlt_profile profile = NULL;
int is_progress = 0;
int is_silent = 0;
int is_abort = 0;
int is_getc = 0;
int error = 0;
mlt_profile backup_profile;
mlt_repository repo = NULL;
const char *repo_path = NULL;
int is_consumer_explicit = 0;
int is_setlocale = 0;
// Handle abnormal exit situations.
signal(SIGSEGV, abnormal_exit_handler);
signal(SIGILL, abnormal_exit_handler);
signal(SIGABRT, abnormal_exit_handler);
// 设置地区,不设置默认是中国
// 在程序中,区域是影响程序语言处理方式的环境变量,比如日期,时间,货币,数字和字符串的格式等。
for (i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-setlocale")) {
is_setlocale = 1;
break;
}
}
for (i = 1; i < argc; i++) {
// Check for serialisation switch
if (!strcmp(argv[i], "-serialise")) {
name = argv[++i];
if (name != NULL && strstr(name, ".melt"))
store = fopen(name, "w");
else {
if (name == NULL || name[0] == '-')
store = stdout;
name = NULL;
}
}
// Look for the profile option
else if (!strcmp(argv[i], "-profile")) {
// Construct the factory
if (!repo)
repo = setup_factory(repo_path, is_setlocale);
const char *pname = argv[++i];
if (pname && pname[0] != '-')
profile = mlt_profile_init(pname);
} else if (!strcmp(argv[i], "-progress")) {
is_progress = 1;
} else if (!strcmp(argv[i], "-progress2")) {
is_progress = 2;
}
// 查找,会打印对应的service种类和信息
// Look for the query option
else if (!strcmp(argv[i], "-query")) {
// Construct the factory
if (!repo)
repo = setup_factory(repo_path, is_setlocale);
const char *pname = argv[++i];
if (pname && pname[0] != '-') {
if (!strcmp(pname, "consumers") || !strcmp(pname, "consumer"))
query_services(repo, mlt_service_consumer_type);
else if (!strcmp(pname, "filters") || !strcmp(pname, "filter"))
query_services(repo, mlt_service_filter_type);
else if (!strcmp(pname, "links") || !strcmp(pname, "link"))
query_services(repo, mlt_service_link_type);
else if (!strcmp(pname, "producers") || !strcmp(pname, "producer"))
query_services(repo, mlt_service_producer_type);
else if (!strcmp(pname, "transitions") || !strcmp(pname, "transition"))
query_services(repo, mlt_service_transition_type);
else if (!strcmp(pname, "profiles") || !strcmp(pname, "profile"))
query_profiles();
else if (!strcmp(pname, "presets") || !strcmp(pname, "preset"))
query_presets();
else if (!strncmp(pname, "format", 6))
query_formats();
else if (!strncmp(pname, "acodec", 6) || !strcmp(pname, "audio_codecs"))
query_acodecs();
else if (!strncmp(pname, "vcodec", 6) || !strcmp(pname, "video_codecs"))
query_vcodecs();
else if (!strncmp(pname, "consumer=", 9))
query_metadata(repo,
mlt_service_consumer_type,
"consumer",
strchr(pname, '=') + 1);
else if (!strncmp(pname, "filter=", 7))
query_metadata(repo, mlt_service_filter_type, "filter", strchr(pname, '=') + 1);
else if (!strncmp(pname, "link=", 5))
query_metadata(repo, mlt_service_link_type, "link", strchr(pname, '=') + 1);
else if (!strncmp(pname, "producer=", 9))
query_metadata(repo,
mlt_service_producer_type,
"producer",
strchr(pname, '=') + 1);
else if (!strncmp(pname, "transition=", 11))
query_metadata(repo,
mlt_service_transition_type,
"transition",
strchr(pname, '=') + 1);
else if (!strncmp(pname, "profile=", 8))
query_profile(strchr(pname, '=') + 1);
else if (!strncmp(pname, "preset=", 7))
query_preset(strchr(pname, '=') + 1);
else
goto query_all;
} else {
query_all:
query_services(repo, mlt_service_consumer_type);
query_services(repo, mlt_service_filter_type);
query_services(repo, mlt_service_link_type);
query_services(repo, mlt_service_producer_type);
query_services(repo, mlt_service_transition_type);
fprintf(stdout,
"# You can query the metadata for a specific service using:\n"
"# -query <type>=<identifier>\n"
"# where <type> is one of: consumer, filter, producer, or transition.\n");
}
goto exit_factory;
} else if (!strcmp(argv[i], "-silent")) {
is_silent = 1;
} else if (!strcmp(argv[i], "-quiet")) {
is_silent = 1;
mlt_log_set_level(MLT_LOG_QUIET);
} else if (!strcmp(argv[i], "-verbose")) {
mlt_log_set_level(MLT_LOG_VERBOSE);
} else if (!strcmp(argv[i], "-timings")) {
mlt_log_set_level(MLT_LOG_TIMINGS);
} else if (!strcmp(argv[i], "-version") || !strcmp(argv[i], "--version")) {
fprintf(stdout,
"%s " VERSION "\n"
"Copyright (C) 2002-2023 Meltytech, LLC\n"
"<https://www.mltframework.org/>\n"
"This is free software; see the source for copying conditions. There is NO\n"
"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
basename(argv[0]));
goto exit_factory;
} else if (!strcmp(argv[i], "-debug")) {
mlt_log_set_level(MLT_LOG_DEBUG);
} else if (!strcmp(argv[i], "-abort")) {
is_abort = 1;
} else if (!strcmp(argv[i], "-getc")) {
is_getc = 1;
} else if (!repo && !strcmp(argv[i], "-repository")) {
if (i + 1 < argc && argv[i + 1][0] != '-')
repo_path = argv[++i];
} else if (!strcmp(argv[i], "-consumer")) {
is_consumer_explicit = 1;
}
}
if (!is_silent && !isatty(STDIN_FILENO) && !is_progress)
is_progress = 1;
// Construct the factory
if (!repo)
repo = setup_factory(repo_path, is_setlocale);
// Create profile if not set explicitly
if (getenv("MLT_PROFILE"))
// 根据环境变量去找到对应的profile
profile = mlt_profile_init(NULL);
if (profile == NULL)
profile = mlt_profile_init(NULL);
else
profile->is_explicit = 1;
// 备份profile,然后加载consumer,如果profile在加载consumer的时候发生了改变,则表明这时候的profile信息是精确的
// Look for the consumer option to load profile settings from consumer properties
backup_profile = mlt_profile_clone(profile);
if (load_consumer(&consumer, profile, argc, argv) != EXIT_SUCCESS)
goto exit_factory;
// If the consumer changed the profile, then it is explicit.
if (backup_profile && !profile->is_explicit
&& (profile->width != backup_profile->width || profile->height != backup_profile->height
|| profile->sample_aspect_num != backup_profile->sample_aspect_num
|| profile->sample_aspect_den != backup_profile->sample_aspect_den
|| profile->frame_rate_den != backup_profile->frame_rate_den
|| profile->frame_rate_num != backup_profile->frame_rate_num
|| profile->colorspace != backup_profile->colorspace))
profile->is_explicit = 1;
mlt_profile_close(backup_profile);
backup_profile = NULL;
// 除了第一个参数,把后面的参数都传递到factory中,用于生产producer
// Get melt producer
if (argc > 1)
melt = mlt_factory_producer(profile, "melt", &argv[1]);
if (melt) {
// Generate an automatic profile if needed.
if (!profile->is_explicit) {
mlt_producer first_producer = mlt_properties_get_data(MLT_PRODUCER_PROPERTIES(melt),
"first_producer",
NULL);
mlt_profile_from_producer(profile, first_producer);
mlt_consumer melt_consumer = MLT_CONSUMER(
mlt_service_consumer(MLT_PRODUCER_SERVICE(melt)));
if (melt_consumer)
mlt_consumer_connect(melt_consumer, NULL);
mlt_producer_close(melt);
melt = mlt_factory_producer(profile, "melt", &argv[1]);
}
double scale = mlt_properties_get_double(MLT_CONSUMER_PROPERTIES(consumer), "scale");
if (scale > 0.0) {
// 设置缩放
set_preview_scale(&profile, &backup_profile, scale);
}
// Reload the consumer with the fully qualified profile.
// The producer or auto-profile could have changed the profile.
load_consumer(&consumer, profile, argc, argv);
// See if producer has consumer already attached
if (!store && !consumer) {
consumer = MLT_CONSUMER(mlt_service_consumer(MLT_PRODUCER_SERVICE(melt)));
if (consumer) {
// 增加引用计数
mlt_properties_inc_ref(
MLT_CONSUMER_PROPERTIES(consumer)); // because we explicitly close it
// 设置传输回调函数
mlt_properties_set_data(MLT_CONSUMER_PROPERTIES(consumer),
"transport_callback",
transport_action,
0,
NULL,
NULL);
}
}
// If we have no consumer, default to sdl
if (store == NULL && consumer == NULL)
consumer = create_consumer(profile, NULL);
}
// Set transport properties on consumer and produder
if (consumer != NULL && melt != NULL) {
mlt_properties_set_data(MLT_CONSUMER_PROPERTIES(consumer),
"transport_producer",
melt,
0,
NULL,
NULL);
mlt_properties_set_data(MLT_PRODUCER_PROPERTIES(melt),
"transport_consumer",
consumer,
0,
NULL,
NULL);
if (is_progress)
mlt_properties_set_int(MLT_CONSUMER_PROPERTIES(consumer), "progress", is_progress);
if (is_silent)
mlt_properties_set_int(MLT_CONSUMER_PROPERTIES(consumer), "silent", is_silent);
if (is_getc)
mlt_properties_set_int(MLT_CONSUMER_PROPERTIES(consumer), "melt_getc", is_getc);
}
if (argc > 1 && melt != NULL && mlt_producer_get_length(melt) > 0) {
// Parse the arguments
for (i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-jack") && consumer) {
setup_jack_transport(consumer, profile);
} else if (!strcmp(argv[i], "-serialise")) {
if (store != stdout)
i++;
} else {
if (store != NULL)
fprintf(store, "%s\n", argv[i]);
i++;
while (argv[i] != NULL && argv[i][0] != '-') {
if (store != NULL)
fprintf(store, "%s\n", argv[i]);
i += 1;
}
i--;
}
}
if (consumer != NULL && store == NULL) {
// Get melt's properties
mlt_properties melt_props = MLT_PRODUCER_PROPERTIES(melt);
mlt_properties properties = MLT_CONSUMER_PROPERTIES(consumer);
if (is_consumer_explicit) {
// Apply group settings
mlt_properties group = mlt_properties_get_data(melt_props, "group", 0);
// properties继承
mlt_properties_inherit(properties, group);
}
int in = mlt_properties_get_int(properties, "in");
int out = mlt_properties_get_int(properties, "out");
if (in > 0 || out > 0) {
if (out == 0) {
out = mlt_producer_get_length(melt) - 1;
}
mlt_producer_set_in_and_out(melt, in, out);
mlt_producer_seek(melt, 0);
}
// Connect consumer to melt
mlt_consumer_connect(consumer, MLT_PRODUCER_SERVICE(melt));
// Start the consumer
mlt_events_listen(properties,
consumer,
"consumer-fatal-error",
(mlt_listener) on_fatal_error);
if (mlt_consumer_start(consumer) == 0) {
// Try to exit gracefully upon these signals
signal(SIGINT, stop_handler);
signal(SIGTERM, stop_handler);
#ifndef _WIN32
signal(SIGHUP, stop_handler);
signal(SIGPIPE, stop_handler);
#endif
// Transport functionality
transport(melt, consumer);
// Stop the consumer
mlt_consumer_stop(consumer);
}
} else if (store != NULL && store != stdout && name != NULL) {
fprintf(stderr, "Project saved as %s.\n", name);
fclose(store);
}
} else {
show_usage(argv[0]);
}
// Disconnect producer from consumer to prevent ref cycles from closing services
if (consumer) {
error = mlt_properties_get_int(MLT_CONSUMER_PROPERTIES(consumer), "melt_error");
mlt_consumer_connect(consumer, NULL);
if (!is_abort)
mlt_events_fire(MLT_CONSUMER_PROPERTIES(consumer),
"consumer-cleanup",
mlt_event_data_none());
}
if (is_abort)
return error;
// Close the producer
if (melt != NULL)
mlt_producer_close(melt);
// Close the consumer
if (consumer != NULL)
mlt_consumer_close(consumer);
// Close the factory
mlt_profile_close(profile);
mlt_profile_close(backup_profile);
exit_factory:
// Workaround qmelt on OS X from crashing at exit.
#if !defined(__MACH__) || !defined(QT_GUI_LIB)
mlt_factory_close();
#endif
return error;
}