MLT媒体程序框架02:源码剖析

以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;
}
相关推荐
EasyGBS1 天前
国标GB28181公网直播EasyGBS国标GB28181软件管理解决方案
大数据·网络·音视频·媒体·视频监控·gb28181
dingzd952 天前
Web3对社交媒体的影响:重新定义用户互动方式
web3·去中心化·区块链·媒体
X档案库5 天前
【Windows】X-DOC:无需NAS使用Windows也能安装Jellyfin玩私人影音媒体平台
媒体
大舍传媒5 天前
大舍传媒:海外发稿的卓越选择——老挝新闻网报道及海外媒体发布服务
人工智能·传媒·媒体
tusik686 天前
冷钱包与热钱包的差异 | 加密货币存储的安全方案
社交电子·娱乐·传媒·媒体
ZVAyIVqt0UFji7 天前
流媒体网关媒体源管理
网络·ffmpeg·媒体
m0_523674217 天前
物价上涨为何会削弱我们的幸福感?
笔记·媒体·零售
130252015128 天前
企业新闻及产品宣传稿怎么写?有哪些商业财经类报纸杂志或媒体发布?
媒体
meizisay8 天前
工作软件推荐
经验分享·传媒·媒体
繁华落尽,寻一世真情12 天前
2023IKCEST第五届“一带一路”国际大数据竞赛--社交网络中多模态虚假 媒体内容核查top11
媒体