macOS上使用qt creator编译调试ffmpeg.c

1 前言

    上文macOS上将ffmpeg.c编译成Framework介绍了使用xocde将ffmpeg.c编译成Framework的方法,这里列举另外一种办法,就是用qt creator来完成这件事情。

    编译环境如下:

  • qt creator 9.0.2;
  • ffmpeg release/6.1;

2 编译ffmpeg.c

    大致思路如下:

  • 将ffmpeg.c编译成动态库dylib;
  • 在qt creator的app工程里使用该动态库;

    值得一提的是,用qt creator新建工程,必须是Plain C Application,不能是C++的工程。因为ffmpeg.c相关头文件的变量名用到了c++的关键字,比如class等,这会导致在c++项目里无法编译成功。 

2.1 新建qt工程

    新建一个Plain C Application工程,并选择使用cmake来构建项目:

    代码目录结构如下图:

2.2 改写ffmpeg.c接口

    在ffmpeg.h文件中将main方法名改为ffmpeg:

#将main方法名改为ffmpeg
int ffmpeg(int argc, char* argv[]);

    在ffmpeg.c文件中将main方法名改为ffmpeg:

#将main方法名改为ffmpeg
int ffmpeg(int argc, char **argv)
{
    int ret, err_rate_exceeded;
    BenchmarkTimeStamps ti;

    init_dynload();

    setvbuf(stderr,NULL,_IONBF,0); /* win32 runtime needs this */

    av_log_set_flags(AV_LOG_SKIP_REPEATED);
    parse_loglevel(argc, argv, options);

#if CONFIG_AVDEVICE
    avdevice_register_all();
#endif
    avformat_network_init();

    show_banner(argc, argv, options);

    /* parse options and open all input/output files */
    ret = ffmpeg_parse_options(argc, argv);
    if (ret < 0)
        goto finish;

    if (nb_output_files <= 0 && nb_input_files == 0) {
        show_usage();
        av_log(NULL, AV_LOG_WARNING, "Use -h to get full help or, even better, run 'man %s'\n", program_name);
        ret = 1;
        goto finish;
    }

    if (nb_output_files <= 0) {
        av_log(NULL, AV_LOG_FATAL, "At least one output file must be specified\n");
        ret = 1;
        goto finish;
    }

    current_time = ti = get_benchmark_time_stamps();
    ret = transcode(&err_rate_exceeded);
    if (ret >= 0 && do_benchmark) {
        int64_t utime, stime, rtime;
        current_time = get_benchmark_time_stamps();
        utime = current_time.user_usec - ti.user_usec;
        stime = current_time.sys_usec  - ti.sys_usec;
        rtime = current_time.real_usec - ti.real_usec;
        av_log(NULL, AV_LOG_INFO,
               "bench: utime=%0.3fs stime=%0.3fs rtime=%0.3fs\n",
               utime / 1000000.0, stime / 1000000.0, rtime / 1000000.0);
    }

    ret = received_nb_signals ? 255 :
          err_rate_exceeded   ?  69 : ret;

finish:
    if (ret == AVERROR_EXIT)
        ret = 0;

    ffmpeg_cleanup(ret);
    return ret;
}

2.3 编写CMakeLists.txt

    用qt creator编译ffmpeg.c,关键在于cmake脚本的编写,这里贴出所写的cmake编译脚本:

cmake_minimum_required(VERSION 3.5)

project(qt-ffmpegc LANGUAGES C)

#ffmpeg源码根目录
set(FFMPEG_SRC_ROOT_PATH ${PROJECT_SOURCE_DIR}/../)
#fftools源码目录
set(FFMPEG_SRC_TOOL_PATH ${FFMPEG_SRC_ROOT_PATH}/fftools)
#列出要参与编译的ffmpeg.c相关源码
set(FFMPEG_SRC
    ${FFMPEG_SRC_TOOL_PATH}/cmdutils.c ${FFMPEG_SRC_TOOL_PATH}/cmdutils.h
    ${FFMPEG_SRC_TOOL_PATH}/ffmpeg_dec.c ${FFMPEG_SRC_TOOL_PATH}/ffmpeg_demux.c
    ${FFMPEG_SRC_TOOL_PATH}/ffmpeg_enc.c ${FFMPEG_SRC_TOOL_PATH}/ffmpeg_filter.c
    ${FFMPEG_SRC_TOOL_PATH}/ffmpeg_hw.c ${FFMPEG_SRC_TOOL_PATH}/ffmpeg_mux_init.c
    ${FFMPEG_SRC_TOOL_PATH}/ffmpeg_mux.c ${FFMPEG_SRC_TOOL_PATH}/ffmpeg_mux.h
    ${FFMPEG_SRC_TOOL_PATH}/ffmpeg_opt.c ${FFMPEG_SRC_TOOL_PATH}/ffmpeg.c
    ${FFMPEG_SRC_TOOL_PATH}/ffmpeg.h
    ${FFMPEG_SRC_TOOL_PATH}/opt_common.c ${FFMPEG_SRC_TOOL_PATH}/opt_common.h
    ${FFMPEG_SRC_TOOL_PATH}/sync_queue.c ${FFMPEG_SRC_TOOL_PATH}/sync_queue.h
    ${FFMPEG_SRC_TOOL_PATH}/thread_queue.c ${FFMPEG_SRC_TOOL_PATH}/thread_queue.h
    ${FFMPEG_SRC_TOOL_PATH}/objpool.c ${FFMPEG_SRC_TOOL_PATH}/objpool.h)

#ffmpeg的头文件、lib文件及相关基础库根目录
set(FFMPEG_BUILD_ROOT_PATH ${FFMPEG_SRC_ROOT_PATH}/mac_build)
#ffmpeg几个库的include文件路径
set(FFMPEG_INCLUDE_PATH ${FFMPEG_BUILD_ROOT_PATH}/include)
#全部的依赖库所在目录
set(FFMPEG_LIB_PATH ${FFMPEG_BUILD_ROOT_PATH}/lib)

#系统基础库
set(SYS_BASE_LIB iconv z bz2)
#ffmpeg几个.a库
set(LINK_FFMPEG_LIBS
    ${FFMPEG_LIB_PATH}/libavformat.a
    ${FFMPEG_LIB_PATH}/libavutil.a
    ${FFMPEG_LIB_PATH}/libavcodec.a
    ${FFMPEG_LIB_PATH}/libavfilter.a
    ${FFMPEG_LIB_PATH}/libswscale.a
    ${FFMPEG_LIB_PATH}/libswresample.a
    ${FFMPEG_LIB_PATH}/libavdevice.a)
#其他依赖库
set(OTHER_3RDPARTY_LIBS
    ${FFMPEG_LIB_PATH}/libxcb.a
    ${FFMPEG_LIB_PATH}/libxcb-xfixes.a
    ${FFMPEG_LIB_PATH}/libxcb-shm.a
    ${FFMPEG_LIB_PATH}/libxcb-shape.a
    ${FFMPEG_LIB_PATH}/libXdmcp.a
    ${FFMPEG_LIB_PATH}/libXau.a
    ${FFMPEG_LIB_PATH}/libX11.a
    ${FFMPEG_LIB_PATH}/libX11-xcb.a
    ${FFMPEG_LIB_PATH}/libSDL2.dylib)

#将ffmpeg.c打成动态库
add_library(ffmpegc SHARED ${FFMPEG_SRC})
#指定ffmpegc动态库相关依赖库
target_link_libraries(ffmpegc PRIVATE ${LINK_FFMPEG_LIBS} ${OTHER_3RDPARTY_LIBS} ${SYS_BASE_LIB})
#ffmpeg所依赖的macOS的Framework
list(APPEND DEPENDCY_LIB_LIST
    Foundation AudioToolbox CoreAudio AVFoundation CoreVideo CoreMedia CoreGraphics OpenGL Metal VideoToolbox CoreImage AppKit CoreFoundation CoreServices Security)
foreach(var IN LISTS DEPENDCY_LIB_LIST)
    target_link_libraries(ffmpegc PRIVATE "-framework ${var}")
endforeach()
# 设置ffmpeg.c动态库的输出路径
set_target_properties(ffmpegc PROPERTIES
    LIBRARY_OUTPUT_DIRECTORY ${FFMPEG_LIB_PATH}
    ARCHIVE_OUTPUT_DIRECTORY ${FFMPEG_LIB_PATH}
)

add_executable(qt-ffmpegc main.c)

include_directories(${FFMPEG_SRC_ROOT_PATH})
include_directories(${FFMPEG_SRC_TOOL_PATH})
include_directories(${FFMPEG_INCLUDE_PATH})

#指定qt-ffmpegc app工程所依赖的库,与ffmpeg.c一致
target_link_libraries(qt-ffmpegc PRIVATE ${LINK_FFMPEG_LIBS} ${OTHER_3RDPARTY_LIBS} ${SYS_BASE_LIB})
#qt-ffmpegc依赖ffmpegc动态库
target_link_libraries(qt-ffmpegc PRIVATE ${FFMPEG_LIB_PATH}/libffmpegc.dylib)
#qt-ffmpegc依赖macOS的各framwork
foreach(var IN LISTS DEPENDCY_LIB_LIST)
    message(STATUS ${var})
    target_link_libraries(qt-ffmpegc PRIVATE "-framework ${var}")
endforeach()

install(TARGETS qt-ffmpegc
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})

    值得一提的是,cmake脚本里指定对macOS系统Framework的依赖脚本如下,列出范例代码:

target_link_libraries(qt-ffmpegc PRIVATE "-framework Foundation")

    好了,cmake脚本编写完成,现在可以编译ffmpeg.c动态库和qt-ffmpegc可执行文件了。

3 使用ffmpeg.c动态库

    列出qt-ffmpegc工程main.c的调用代码:

#include <stdio.h>

#include "libavformat/avformat.h"
#include "ffmpeg.h"

static void test_ffmpeg() {
    AVFormatContext* ifmt = NULL;
    const char* filename = "";
    int ret = avformat_open_input(&ifmt, filename, NULL, NULL);
    if (ret < 0) {
        av_log(ifmt, AV_LOG_INFO, "avformat_open_input failed\n");
    }
    ret = avformat_find_stream_info(ifmt, NULL);
    if (ret < 0) {

    }

    AVPacket pkt;
    av_init_packet(&pkt);
    while (1) {
        ret = av_read_frame(ifmt, &pkt);
        if (pkt.stream_index == 1 &&  pkt.flags & AV_PKT_FLAG_KEY) {
            av_log(ifmt, AV_LOG_INFO, "keyframe\n");
        }
    }
}

static void test_ffmpeg_cmd(int argc, const char* argv[]) {
    ffmpeg(argc, argv);
}

int main()
{
    printf("Hello World!\n");
    test_ffmpeg();
    const char* args[3] = { "ffmpeg", "-h", "filter=overlay" };
    test_ffmpeg_cmd(3, args);
    return 0;
}

    然后编译调试,执行ffmpeg -h filter=overlay范例命令:

  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值