FFmpeg视频录制

FFmpeg 库组成

首先,FFmpeg 是一个模块化的多媒体框架,主要由以下几个库组成:

  • libavcodec:提供编解码器(编码/解码视频和音频)。
  • libavformat:处理多媒体容器格式(如 MP4、AVI)的封装和解封装。
  • libavdevice:提供输入输出设备支持(如摄像头、麦克风)。
  • libavutil:工具库,包含内存管理、数学运算、数据结构等辅助功能。
  • libswscale:用于图像格式转换、缩放、色彩空间转换。

我们的程序用到了所有这些库,下面按照代码执行顺序解释每个 API 的作用。

1. 初始化与设备注册

avdevice_register_all();
  • 作用:注册所有可用的输入输出设备。对于使用摄像头(v4l2)等设备,必须先调用此函数,否则无法找到设备格式。

2. 设置输入参数

AVDictionary* input_options = nullptr;
av_dict_set(&input_options, "video_size", "640x480", 0);
av_dict_set(&input_options, "framerate", "30", 0);
av_dict_set(&input_options, "pixel_format", "yuyv422", 0);
  • AVDictionary 是 FFmpeg 中用于传递键值对选项的通用结构。
  • av_dict_set 用于设置选项,比如我们希望摄像头输出 640x480 分辨率、30 帧/秒、yuyv422 像素格式。

3. 查找输入格式并打开设备

const AVInputFormat* input_format = av_find_input_format("v4l2");
  • av_find_input_format 根据名称(如 “v4l2”)查找对应的输入格式描述符,返回一个 AVInputFormat 指针,后续打开设备时需要用到。
AVFormatContext* input_ctx = nullptr;
int ret = avformat_open_input(&input_ctx, "/dev/video2", input_format, &input_options);
  • avformat_open_input 打开输入设备(或文件)。它根据提供的格式和设备路径,初始化 AVFormatContext。如果成功,input_ctx 将包含输入流的元信息。选项字典中的参数(如分辨率)在此阶段传递给设备驱动。

4. 获取流信息

avformat_find_stream_info(input_ctx, nullptr);
  • avformat_find_stream_info 从输入中读取一部分数据,探测并填充各个流的详细信息(如编解码器类型、参数等)。它会填充 input_ctx->streams 数组,每个元素代表一个流(视频、音频等)。

5. 查找视频流

for (...) {
    if (par->codec_type == AVMEDIA_TYPE_VIDEO) { ... }
}
  • 遍历所有流,找到类型为 AVMEDIA_TYPE_VIDEO 的流,记录其索引。后续操作将针对这个视频流。

6. 准备解码器

const AVCodec* decoder = avcodec_find_decoder(input_codecpar->codec_id);
  • avcodec_find_decoder 根据编码器 ID(如 AV_CODEC_ID_YUYV422)找到对应的解码器。摄像头输出的原始格式(yuyv422)在 FFmpeg 中也是一个编码器 ID,需要解码才能得到可处理的帧。
AVCodecContext* decoder_ctx = avcodec_alloc_context3(decoder);
avcodec_parameters_to_context(decoder_ctx, input_codecpar);
  • avcodec_alloc_context3 分配解码器上下文,用于保存解码过程中的参数和状态。
  • avcodec_parameters_to_context 将从流中获取的编解码参数(AVCodecParameters)复制到解码器上下文中。
avcodec_open2(decoder_ctx, decoder, nullptr);
  • avcodec_open2 真正打开解码器,初始化内部资源。之后就可以使用此上下文进行解码。

7. 设置输出(MP4 文件)

AVFormatContext* output_ctx = nullptr;
avformat_alloc_output_context2(&output_ctx, nullptr, nullptr, "output.mp4");
  • avformat_alloc_output_context2 创建输出上下文,根据文件名后缀自动推断输出格式(如 MP4)。output_ctx 将用于管理输出文件。

8. 准备编码器(H.264)

const AVCodec* encoder = avcodec_find_encoder_by_name("libx264");
  • avcodec_find_encoder_by_name 通过编码器名称(如 “libx264”)查找编码器。也可以使用 avcodec_find_encoder(AV_CODEC_ID_H264)
AVStream* output_stream = avformat_new_stream(output_ctx, encoder);
AVCodecContext* encoder_ctx = avcodec_alloc_context3(encoder);
  • avformat_new_stream 在输出上下文中创建一个新的流,并与指定的编码器关联。
  • avcodec_alloc_context3 为编码器分配上下文。
// 设置编码参数
encoder_ctx->height = decoder_ctx->height;
encoder_ctx->width = decoder_ctx->width;
encoder_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
encoder_ctx->time_base = (AVRational){1, 30};
encoder_ctx->framerate = (AVRational){30, 1};
encoder_ctx->bit_rate = 400000;
  • 设置编码器的参数:分辨率、像素格式、时间基、帧率、比特率等。时间基 time_base 用于表示时间戳的单位,这里设为 1/30 秒。
av_dict_set(&encoder_options, "preset", "ultrafast", 0);
av_dict_set(&encoder_options, "tune", "zerolatency", 0);
avcodec_open2(encoder_ctx, encoder, &encoder_options);
  • 使用字典设置编码器私有选项(如 x264 的 preset 和 tune),然后打开编码器。
avcodec_parameters_from_context(output_stream->codecpar, encoder_ctx);
output_stream->time_base = encoder_ctx->time_base;
  • 将编码器上下文的参数复制到输出流的 codecpar 中,这样输出文件才能正确描述视频流。
  • 设置输出流的时间基与编码器一致。

9. 打开输出文件

if (!(output_ctx->oformat->flags & AVFMT_NOFILE)) {
    avio_open(&output_ctx->pb, output_filename, AVIO_FLAG_WRITE);
}
  • 如果输出格式需要文件 IO(MP4 需要),则调用 avio_open 打开文件,准备写入。

10. 初始化图像转换(SWS)

SwsContext* sws_ctx = sws_getContext(
    decoder_ctx->width, decoder_ctx->height, decoder_ctx->pix_fmt,
    encoder_ctx->width, encoder_ctx->height, encoder_ctx->pix_fmt,
    SWS_BILINEAR, nullptr, nullptr, nullptr
);
  • sws_getContext 创建并初始化一个图像转换上下文。它描述了从输入格式(解码后的 yuyv422)到输出格式(编码器需要的 YUV420P)的转换参数。后续的 sws_scale 将使用这个上下文进行转换。

11. 分配帧缓冲区

AVFrame* yuv_frame = av_frame_alloc();
yuv_frame->format = encoder_ctx->pix_fmt;
yuv_frame->width = encoder_ctx->width;
yuv_frame->height = encoder_ctx->height;
av_frame_get_buffer(yuv_frame, 0);
  • av_frame_alloc 分配一个空的 AVFrame 结构体。
  • av_frame_get_buffer 为帧分配实际的数据缓冲区。这里我们为转换后的 YUV420P 帧分配内存。

12. 写入文件头

avformat_write_header(output_ctx, nullptr);
  • avformat_write_header 写入输出文件的头部信息(如 MP4 的 moov 等元数据)。必须在写入任何数据包之前调用。

13. 主循环:读取、解码、转换、编码、写入

读取数据包

av_read_frame(input_ctx, input_pkt);
  • av_read_frame 从输入中读取下一个数据包(AVPacket)。对于摄像头,每个包通常包含一帧图像数据(压缩或原始)。

解码

avcodec_send_packet(decoder_ctx, input_pkt);
avcodec_receive_frame(decoder_ctx, decoded_frame);
  • avcodec_send_packet 向解码器发送一个压缩数据包。
  • avcodec_receive_frame 从解码器接收解码后的原始帧。这两个函数是 FFmpeg 3.0 之后推荐的编解码 API,采用异步方式,可能需要多次调用才能获得所有输出帧。

图像格式转换

sws_scale(sws_ctx,
          decoded_frame->data, decoded_frame->linesize,
          0, decoder_ctx->height,
          yuv_frame->data, yuv_frame->linesize);
  • sws_scale 执行实际的图像转换。它将 decoded_frame 中的数据按照 sws_ctx 中定义的规则转换后填入 yuv_frame

编码

avcodec_send_frame(encoder_ctx, yuv_frame);
avcodec_receive_packet(encoder_ctx, output_pkt);
  • avcodec_send_frame 向编码器发送一帧原始图像。
  • avcodec_receive_packet 从编码器接收压缩后的数据包。同样需要循环直到返回 EAGAINEOF

写入文件

av_packet_rescale_ts(output_pkt, encoder_ctx->time_base, output_stream->time_base);
av_interleaved_write_frame(output_ctx, output_pkt);
  • av_packet_rescale_ts 将包的时间戳从编码器的时间基转换到输出流的时间基。
  • av_interleaved_write_frame 将数据包写入输出文件。它会负责交错(interleaving)不同流的数据包,确保文件格式正确。

14. 清理与收尾

当用户停止录制(收到信号)后,需要:

  • Flush 编码器:调用 avcodec_send_frame(encoder_ctx, nullptr) 并循环接收剩余包。
  • 写入文件尾av_write_trailer(output_ctx) 写入文件末尾的元数据(如 MP4 的索引信息),使文件完整可播。
  • 释放所有资源:使用对应的 free 函数:av_packet_freeav_frame_freesws_freeContextavcodec_free_contextavformat_close_inputavio_closep 等。

数据流总结

  1. 摄像头(V4L2)→ 原始包AVPacket,格式 yuyv422)
  2. 解码 → 原始帧AVFrame,格式 yuyv422)
  3. 图像转换 → 目标帧AVFrame,格式 yuv420p)
  4. 编码 → 压缩包AVPacket,H.264)
  5. 封装 → MP4 文件

进一步学习建议

  • 官方文档FFmpeg Doxygen 是最终的参考。
  • 示例代码:FFmpeg 源码的 doc/examples 目录下有大量示例,如 demuxing_decoding.cmuxing.c 等,非常值得阅读。
  • 书籍:《FFmpeg从入门到精通》或《FFmpeg Basics》可以帮助系统学习。
  • 实践:尝试修改代码,比如录制音频、调整编码参数、支持更多输入格式等。

demo

#include <stdio.h>
#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <atomic>

extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavdevice/avdevice.h>
#include <libavutil/avutil.h>
#include <libavutil/imgutils.h>
#include <libavutil/error.h>
#include <libswscale/swscale.h>
}

std::atomic<bool> is_recording(true);

void signal_handler(int sig) {
    if (sig == SIGINT) {
        std::cout << "\n收到停止信号,正在结束录制..." << std::endl;
        is_recording = false;
    }
}

int main() {
    // 注册信号处理
    signal(SIGINT, signal_handler);

    avdevice_register_all();

    const char* input_device = "/dev/video2";
    const char* input_format_name = "v4l2";

    AVDictionary* input_options = nullptr;
    av_dict_set(&input_options, "video_size", "640x480", 0);
    av_dict_set(&input_options, "framerate", "30", 0);
    av_dict_set(&input_options, "pixel_format", "yuyv422", 0);
    av_dict_set(&input_options, "noblock", "1", 0);  // 非阻塞模式

     AVInputFormat* input_format = av_find_input_format(input_format_name);
    if (!input_format) {
        std::cerr << "无法找到输入格式: " << input_format_name << std::endl;
        return -1;
    }

    AVFormatContext* input_ctx = nullptr;
    int ret = avformat_open_input(&input_ctx, input_device, input_format, &input_options);
    if (ret != 0) {
        char errbuf[128];
        av_strerror(ret, errbuf, sizeof(errbuf));
        std::cerr << "无法打开摄像头设备: " << input_device << ",错误: " << errbuf << std::endl;
        return -1;
    }

    ret = avformat_find_stream_info(input_ctx, nullptr);
    if (ret < 0) {
        char errbuf[128];
        av_strerror(ret, errbuf, sizeof(errbuf));
        std::cerr << "avformat_find_stream_info 失败: " << errbuf << std::endl;
        return -1;
    }

    std::cout << "成功获取流信息,共有 " << input_ctx->nb_streams << " 个流" << std::endl;

    int video_stream_index = -1;
    for (unsigned int i = 0; i < input_ctx->nb_streams; i++) {
        AVCodecParameters* par = input_ctx->streams[i]->codecpar;
        std::cout << "流 " << i << " 类型: " << av_get_media_type_string(par->codec_type) << std::endl;
        if (par->codec_type == AVMEDIA_TYPE_VIDEO) {
            video_stream_index = i;
            break;
        }
    }
    if (video_stream_index == -1) {
        std::cerr << "未找到视频流" << std::endl;
        return -1;
    }

    std::cout << "视频流索引: " << video_stream_index << std::endl;

    AVCodecParameters* input_codecpar = input_ctx->streams[video_stream_index]->codecpar;
    const AVCodec* decoder = avcodec_find_decoder(input_codecpar->codec_id);
    if (!decoder) {
        std::cerr << "找不到解码器,codec_id: " << input_codecpar->codec_id << std::endl;
        return -1;
    }

    AVCodecContext* decoder_ctx = avcodec_alloc_context3(decoder);
    avcodec_parameters_to_context(decoder_ctx, input_codecpar);
    ret = avcodec_open2(decoder_ctx, decoder, nullptr);
    if (ret < 0) {
        char errbuf[128];
        av_strerror(ret, errbuf, sizeof(errbuf));
        std::cerr << "无法打开解码器: " << errbuf << std::endl;
        return -1;
    }

    std::cout << "解码器打开成功,输入格式: " << av_get_pix_fmt_name(decoder_ctx->pix_fmt)
              << ",分辨率: " << decoder_ctx->width << "x" << decoder_ctx->height << std::endl;

    const char* output_filename = "output.mp4";
    AVFormatContext* output_ctx = nullptr;
    avformat_alloc_output_context2(&output_ctx, nullptr, nullptr, output_filename);
    if (!output_ctx) {
        std::cerr << "无法创建输出上下文" << std::endl;
        return -1;
    }

    const AVCodec* encoder = avcodec_find_encoder_by_name("libx264");
    if (!encoder) {
        std::cerr << "找不到 H.264 编码器 (libx264)" << std::endl;
        return -1;
    }

    AVStream* output_stream = avformat_new_stream(output_ctx, encoder);
    AVCodecContext* encoder_ctx = avcodec_alloc_context3(encoder);

    encoder_ctx->height = decoder_ctx->height;
    encoder_ctx->width = decoder_ctx->width;
    encoder_ctx->sample_aspect_ratio = decoder_ctx->sample_aspect_ratio;
    encoder_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
    encoder_ctx->time_base = (AVRational){1, 30};
    encoder_ctx->framerate = (AVRational){30, 1};
    encoder_ctx->bit_rate = 400000;

    AVDictionary* encoder_options = nullptr;
    av_dict_set(&encoder_options, "preset", "ultrafast", 0);
    av_dict_set(&encoder_options, "tune", "zerolatency", 0);

    ret = avcodec_open2(encoder_ctx, encoder, &encoder_options);
    if (ret < 0) {
        char errbuf[128];
        av_strerror(ret, errbuf, sizeof(errbuf));
        std::cerr << "无法打开编码器: " << errbuf << std::endl;
        return -1;
    }

    avcodec_parameters_from_context(output_stream->codecpar, encoder_ctx);
    output_stream->time_base = encoder_ctx->time_base;

    if (!(output_ctx->oformat->flags & AVFMT_NOFILE)) {
        ret = avio_open(&output_ctx->pb, output_filename, AVIO_FLAG_WRITE);
        if (ret < 0) {
            char errbuf[128];
            av_strerror(ret, errbuf, sizeof(errbuf));
            std::cerr << "无法打开输出文件: " << errbuf << std::endl;
            return -1;
        }
    }

    SwsContext* sws_ctx = sws_getContext(
        decoder_ctx->width, decoder_ctx->height, decoder_ctx->pix_fmt,
        encoder_ctx->width, encoder_ctx->height, encoder_ctx->pix_fmt,
        SWS_BILINEAR, nullptr, nullptr, nullptr
    );
    if (!sws_ctx) {
        std::cerr << "sws_getContext 失败" << std::endl;
        return -1;
    }

    AVFrame* yuv_frame = av_frame_alloc();
    yuv_frame->format = encoder_ctx->pix_fmt;
    yuv_frame->width = encoder_ctx->width;
    yuv_frame->height = encoder_ctx->height;
    ret = av_frame_get_buffer(yuv_frame, 0);
    if (ret < 0) {
        std::cerr << "无法分配帧缓冲区" << std::endl;
        return -1;
    }

    ret = avformat_write_header(output_ctx, nullptr);
    if (ret < 0) {
        char errbuf[128];
        av_strerror(ret, errbuf, sizeof(errbuf));
        std::cerr << "写入文件头失败: " << errbuf << std::endl;
        return -1;
    }

    std::cout << "开始录制,按 Ctrl+C 停止..." << std::endl;

    AVPacket* input_pkt = av_packet_alloc();
    AVPacket* output_pkt = av_packet_alloc();
    int64_t frame_counter = 0;
    int encoded_frame_count = 0;
    int loop_counter = 0;

    while (is_recording) {
        loop_counter++;
        if (loop_counter % 100 == 0) {
            std::cout << "循环 " << loop_counter << " 次" << std::endl;
        }

        ret = av_read_frame(input_ctx, input_pkt);
        if (ret < 0) {
            if (ret == AVERROR(EAGAIN)) {
                // 非阻塞模式下无数据,等待后继续
                usleep(10000); // 10ms
                continue;
            }
            char errbuf[128];
            av_strerror(ret, errbuf, sizeof(errbuf));
            std::cerr << "av_read_frame 失败: " << errbuf << std::endl;
            break;
        }

        if (input_pkt->stream_index == video_stream_index) {
            ret = avcodec_send_packet(decoder_ctx, input_pkt);
            if (ret < 0) {
                char errbuf[128];
                av_strerror(ret, errbuf, sizeof(errbuf));
                std::cerr << "avcodec_send_packet 失败: " << errbuf << std::endl;
                av_packet_unref(input_pkt);
                continue;
            }

            while (true) {
                AVFrame* decoded_frame = av_frame_alloc();
                ret = avcodec_receive_frame(decoder_ctx, decoded_frame);
                if (ret == AVERROR(EAGAIN)) {
                    av_frame_free(&decoded_frame);
                    break;
                } else if (ret == AVERROR_EOF) {
                    av_frame_free(&decoded_frame);
                    break;
                } else if (ret < 0) {
                    char errbuf[128];
                    av_strerror(ret, errbuf, sizeof(errbuf));
                    std::cerr << "avcodec_receive_frame 错误: " << errbuf << std::endl;
                    av_frame_free(&decoded_frame);
                    break;
                }

                decoded_frame->pts = frame_counter++;

                sws_scale(sws_ctx,
                          decoded_frame->data, decoded_frame->linesize,
                          0, decoder_ctx->height,
                          yuv_frame->data, yuv_frame->linesize);

                yuv_frame->pts = decoded_frame->pts;

                ret = avcodec_send_frame(encoder_ctx, yuv_frame);
                if (ret < 0) {
                    char errbuf[128];
                    av_strerror(ret, errbuf, sizeof(errbuf));
                    std::cerr << "avcodec_send_frame 失败: " << errbuf << std::endl;
                    av_frame_free(&decoded_frame);
                    break;
                }

                while (true) {
                    ret = avcodec_receive_packet(encoder_ctx, output_pkt);
                    if (ret == AVERROR(EAGAIN)) {
                        break;
                    } else if (ret == AVERROR_EOF) {
                        break;
                    } else if (ret < 0) {
                        char errbuf[128];
                        av_strerror(ret, errbuf, sizeof(errbuf));
                        std::cerr << "avcodec_receive_packet 错误: " << errbuf << std::endl;
                        break;
                    }

                    encoded_frame_count++;
                    std::cout << "写入包 #" << encoded_frame_count << ",大小: " << output_pkt->size << " 字节" << std::endl;

                    av_packet_rescale_ts(output_pkt, encoder_ctx->time_base, output_stream->time_base);
                    output_pkt->stream_index = output_stream->index;

                    ret = av_interleaved_write_frame(output_ctx, output_pkt);
                    if (ret < 0) {
                        char errbuf[128];
                        av_strerror(ret, errbuf, sizeof(errbuf));
                        std::cerr << "av_interleaved_write_frame 失败: " << errbuf << std::endl;
                    }
                    av_packet_unref(output_pkt);
                }

                av_frame_free(&decoded_frame);
            }
        }
        av_packet_unref(input_pkt);
    }

    std::cout << "录制结束,共编码 " << encoded_frame_count << " 帧" << std::endl;

    // Flush 编码器
    avcodec_send_frame(encoder_ctx, nullptr);
    while (true) {
        ret = avcodec_receive_packet(encoder_ctx, output_pkt);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
            break;
        }
        if (ret < 0) break;
        av_packet_rescale_ts(output_pkt, encoder_ctx->time_base, output_stream->time_base);
        output_pkt->stream_index = output_stream->index;
        av_interleaved_write_frame(output_ctx, output_pkt);
        av_packet_unref(output_pkt);
    }

    // 写入文件尾
    av_write_trailer(output_ctx);

    // 释放资源
    av_packet_free(&input_pkt);
    av_packet_free(&output_pkt);
    av_frame_free(&yuv_frame);
    sws_freeContext(sws_ctx);
    avcodec_free_context(&decoder_ctx);
    avcodec_free_context(&encoder_ctx);
    if (output_ctx && !(output_ctx->oformat->flags & AVFMT_NOFILE)) {
        avio_closep(&output_ctx->pb);
    }
    avformat_free_context(output_ctx);
    avformat_close_input(&input_ctx);

    std::cout << "完成!" << std::endl;
    return 0;
}

安装依赖:确保你的系统已经安装了 FFmpeg 开发库。

sudo apt update
sudo apt install ffmpeg libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev

编译代码:将上面的代码保存为 record_camera.cpp,然后使用以下命令编译。注意链接器需要找到所有 FFmpeg 的库。

g++ -o record_camera record_camera.cpp -lavcodec -lavformat -lavdevice -lavutil -lswscale

openssl:
    url: ${git_url}/thdpty/openssl.git
    branch: OpenSSL_1_1_1o
    dependencies:
    - arch_pattern: '*'
      dependencies: []
    commands:
      configure:
        # 核心修改1:按系统分支指定 command(Linux 用原逻辑,Windows 用 perl 调用)
        command:
          - arch_pattern: '*linux*'  # Linux 系统保留原命令
            command: ${PROJECT_SOURCE_DIR}/Configure
          - arch_pattern: '*x86_64-windows*'  # Windows 系统用 perl 调用 Configure
            command: perl
          - arch_pattern: '*'  # 兜底分支(非windows/linux用原命令)
            command: ${PROJECT_SOURCE_DIR}/Configure
        arguments:
        - arch_pattern: '*aarch64-linux*'
          arguments:
          - shared
          - --prefix=${IMOBUILDER_TARGET_OUTPUT}/3rdparty
          - --openssldir=${IMOBUILDER_TARGET_OUTPUT}/3rdparty/lib/ssl
          - linux-aarch64
          - '&&'
          - perl
          - configdata.pm
          - -d
        - arch_pattern: '*aarch64-qnx*'
          arguments:
          - shared
          - --prefix=${IMOBUILDER_TARGET_OUTPUT}/3rdparty
          - --openssldir=${IMOBUILDER_TARGET_OUTPUT}/3rdparty/lib/ssl
          - linux-aarch64
          - '&&'
          - perl
          - configdata.pm
          - -d
        - arch_pattern: '*x86_64-linux*'
          arguments:
          - shared
          - --prefix=${IMOBUILDER_TARGET_OUTPUT}/3rdparty
          - --openssldir=${IMOBUILDER_TARGET_OUTPUT}/3rdparty/lib/ssl
          - linux-x86_64
          - '&&'
          - perl
          - configdata.pm
          - -d
        # 核心修改2:修复缩进 + 正确配置 Windows 分支参数
        - arch_pattern: '*x86_64-windows*'
          arguments:
          - ${PROJECT_SOURCE_DIR}/Configure  # 传给 perl 的第一个参数(Configure 路径)
          - shared
          - --prefix=${IMOBUILDER_TARGET_OUTPUT}/3rdparty
          - --openssldir=${IMOBUILDER_TARGET_OUTPUT}/3rdparty/lib/ssl
          - VC-WIN64A  # Windows 64位编译目标
          - '&&'
          - perl
          - configdata.pm
          - -d
        - arch_pattern: '*'
          arguments:
          - shared
          - --prefix=${IMOBUILDER_TARGET_OUTPUT}/3rdparty
          - --openssldir=${IMOBUILDER_TARGET_OUTPUT}/3rdparty/lib/ssl
          - linux-x86_64
          - '&&'
          - perl
          - configdata.pm
          - -d
      build:
        # 核心修改3:build 命令按系统分支区分(Linux=make,Windows=nmake)
        command:
          - arch_pattern: '*linux*'
            command: make
          - arch_pattern: '*x86_64-windows*'
            command: nmake
          - arch_pattern: '*'
            command: make
        arguments:
        - arch_pattern: '*'
          arguments: []
      install:
        # 核心修改4:install 命令按系统分支区分
        command:
          - arch_pattern: '*linux*'
            command: make
          - arch_pattern: '*x86_64-windows*'
            command: nmake
          - arch_pattern: '*'
            command: make
        arguments:
        - arch_pattern: '*'
          arguments:
          - install
    package:
      manifest: null
      files:
      - ${IMOBUILDER_TARGET_OUTPUT}/3rdparty/lib/libcrypto*
      - ${IMOBUILDER_TARGET_OUTPUT}/3rdparty/lib/libssl*
      - ${IMOBUILDER_TARGET_OUTPUT}/3rdparty/lib/pkgconfig/openssl.pc
      - ${IMOBUILDER_TARGET_OUTPUT}/3rdparty/lib/pkgconfig/libcrypto.pc
      - ${IMOBUILDER_TARGET_OUTPUT}/3rdparty/lib/pkgconfig/libssl.pc
      - ${IMOBUILDER_TARGET_OUTPUT}/3rdparty/bin/openssl
      - ${IMOBUILDER_TARGET_OUTPUT}/3rdparty/bin/c_rehash
      directories:
      - ${IMOBUILDER_TARGET_OUTPUT}/3rdparty/lib/engines-1.1
      - ${IMOBUILDER_TARGET_OUTPUT}/3rdparty/lib/ssl
      - ${IMOBUILDER_TARGET_OUTPUT}/3rdparty/include/openssl
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tew_gogogo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值