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;
}
相关推荐
卜锦元6 小时前
音视频媒体服务领域中三种架构方式的定义与区别(Mesh、MCU、SFU)
架构·音视频·媒体
蚁巡信息巡查系统1 天前
自媒体内容安全审核指引怎么写,有哪些内容?
安全·信息可视化·媒体·内容运营
卜锦元2 天前
Mediasoup的SFU媒体服务转发中心详解(与传统SFU的区别)
音视频·webrtc·媒体
flex88885 天前
一款专为媒体爱好者设计的跨平台客户端软件,整合 Jellyfin、Emby、CMS 、webdav和IPTV媒体服务
媒体
Swift社区6 天前
iOS 基于 Foundation Model 构建媒体流
ios·iphone·swift·媒体
我希望的一路生花6 天前
告别文件混乱!Adobe Bridge 2026 全媒体可视化管理,让设计流程更顺畅
adobe·媒体
点金石游戏出海8 天前
每周资讯 | 印度数字媒体与娱乐市场在2025财年达93亿美;《崩坏:星穹铁道》新版本登顶iOS畅销榜首
游戏·娱乐·媒体·游戏资讯·崩坏星穹铁道
yingxiao8888 天前
挖掘百亿“数字热土”!解读印度游戏与媒体娱乐的高速增长
游戏·娱乐·媒体
十五年专注C++开发11 天前
Qt-VLC: 一个集成VLC的开源跨平台媒体播放库
开发语言·qt·媒体·libvlc·vlc-qt
present122714 天前
一段音频/视频分离成人声与伴奏,Windows + Anaconda 快速跑通 Spleeter(离线可用)
windows·职场和发展·ffmpeg·音视频·娱乐·媒体