ffmpeg api-alac-text.c

这篇具有很好参考价值的文章主要介绍了ffmpeg api-alac-text.c。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

generate_raw_frame

这个函数接受一个 frame_data 数组作为参数,用于存储音频数据。i 参数表示当前帧的索引,sample_rate 是采样率,channels 是声道数,frame_size 是帧大小。函数使用一个简单的算法生成音频数据,然后将其存储在 frame_data 数组中。

具体来说,它遍历帧中的每个采样点,根据公式 10000 * ((j / 10 * i) % 2) 生成音频数据的第一个声道,并根据声道数生成其他声道的数据。最后,它将生成的音频数据存储在 frame_data 数组中,并返回 0 表示成功生成音频帧。

假设我们调用 generate_raw_frame 函数来生成一个采样率为 44100Hz,双声道(立体声)的音频帧,帧大小为 1024 个采样点:

uint16_t frame_data[1024 * 2]; // 1024 个采样点,每个采样点包含双声道数据

generate_raw_frame(frame_data, 0, 44100, 2, 1024); // 生成第一帧的音频数据

此时,frame_data 数组中将包含 1024 个采样点的音频数据,每个采样点包含左右两个声道的数据。


首先,我们声明一个 uint16_t 类型的数组 frame_data,用来存储生成的音频帧数据。这个数组的大小为 1024 * 2,因为我们有 1024 个采样点,每个采样点包含左右两个声道的数据。

然后,我们调用 generate_raw_frame 函数,并传入以下参数:

frame_data:指向要填充的音频帧数据的指针,即我们声明的 frame_data 数组的首地址。
0:当前帧的索引。在这个例子中,我们传入 0,表示生成的是第一帧的音频数据。
44100:采样率为 44100Hz。
2:声道数为 2,表示双声道(立体声)。
1024:帧大小为 1024 个采样点。
generate_raw_frame 函数开始执行。它使用一个嵌套的循环来填充音频帧数据:

外层循环 for (j = 0; j < frame_size; j++) 遍历每个采样点。
内层循环 for (k = 1; k < channels; k++) 遍历每个声道(从第二个声道开始)。
在每个采样点内部,首先计算了第一个声道的采样值 frame_data[channels * j] = 10000 * ((j / 10 * i) % 2)。这里的计算方式是一个简单的模式,用来生成音频波形数据。采样值的范围是 0 到 10000。
然后,对于其他声道,它们的采样值是第一个声道采样值的倍数,frame_data[channels * j + k] = frame_data[channels * j] * (k + 1)。
generate_raw_frame 函数执行完毕后,frame_data 数组中将包含 1024 个采样点的音频数据,每个采样点包含左右两个声道的数据,可以用来表示一帧音频数据。

/**
 * 生成原始音频帧
 * @param frame_data 存储音频数据的数组
 * @param i 当前帧的索引
 * @param sample_rate 采样率
 * @param channels 声道数
 * @param frame_size 帧大小
 * @return 成功返回 0,失败返回其他值
 */
static int generate_raw_frame(uint16_t *frame_data, int i, int sample_rate,
                              int channels, int frame_size)
{
    int j, k;

    for (j = 0; j < frame_size; j++) {
        // 根据公式生成音频数据
        frame_data[channels * j] = 10000 * ((j / 10 * i) % 2);
        for (k = 1; k < channels; k++)
            frame_data[channels * j + k] = frame_data[channels * j] * (k + 1);
    }
    return 0; // 成功生成音频帧
}

init_encoder

这个函数接受一个编码器 enc、一个指向编码器上下文指针的指针 enc_ctx、声道布局 ch_layout 和采样率 sample_rate 作为参数。
它首先使用 av_get_channel_layout_string 函数获取声道布局的字符串表示形式,并打印声道布局和采样率的信息。
然后,它使用 avcodec_alloc_context3 函数为编码器分配上下文内存,并设置上下文的参数。最后,它使用 avcodec_open2 函数打开编码器。

函数返回 0 表示成功初始化编码器,并将分配的编码器上下文存储在传入的指针 enc_ctx 中。如果内存分配失败或打开编码器失败,
函数将返回相应的错误代码。

void av_get_channel_layout_string(char *buf, int buf_size, int nb_channels, uint64_t channel_layout)
参数说明:

buf:指向存储结果的缓冲区的指针。
buf_size:缓冲区的大小。
nb_channels:声道数量。
channel_layout:声道布局。
这个函数会根据传入的 channel_layout 参数生成对应的声道布局字符串,并将结果存储在 buf 缓冲区中。例如,如果我们要获取立体声(左右声道)的声道布局字符串,可以这样使用:

char layout_str[256]; // 声道布局字符串存储缓冲区
uint64_t layout = AV_CH_LAYOUT_STEREO; // 立体声声道布局

av_get_channel_layout_string(layout_str, sizeof(layout_str), 0, layout);

printf("Channel layout: %s\n", layout_str);

Channel layout: stereo

这里 AV_CH_LAYOUT_STEREO 是一个宏,表示立体声声道布局,对应的字符串为 "stereo"/*
*
 * 初始化编码器
 * @param enc 编码器
 * @param enc_ctx 指向编码器上下文指针的指针,将分配的编码器上下文存储在这里
 * @param ch_layout 声道布局
 * @param sample_rate 采样率
 * @return 成功返回 0,失败返回错误代码
 */
static int init_encoder(AVCodec *enc, AVCodecContext **enc_ctx,
                        int64_t ch_layout, int sample_rate)
{
    AVCodecContext *ctx;
    int result;
    char name_buff[NAME_BUFF_SIZE]; // 用于存储声道布局字符串的缓冲区

    // 获取声道布局的字符串表示形式
    av_get_channel_layout_string(name_buff, NAME_BUFF_SIZE, 0, ch_layout);
    // 打印声道布局和采样率信息
    av_log(NULL, AV_LOG_INFO, "channel layout: %s, sample rate: %i\n", name_buff, sample_rate);

    // 为编码器分配上下文内存
    ctx = avcodec_alloc_context3(enc);
    if (!ctx) {
        av_log(NULL, AV_LOG_ERROR, "Can't allocate encoder context\n");
        return AVERROR(ENOMEM); // 内存分配失败
    }

    // 设置编码器上下文的参数
    ctx->sample_fmt = AV_SAMPLE_FMT_S16; // 采样格式为 16 位整数
    ctx->sample_rate = sample_rate; // 设置采样率
    ctx->channel_layout = ch_layout; // 设置声道布局

    // 打开编码器
    result = avcodec_open2(ctx, enc, NULL);
    if (result < 0) {
        av_log(ctx, AV_LOG_ERROR, "Can't open encoder\n");
        return result; // 打开编码器失败,返回错误代码
    }

    // 将分配的编码器上下文存储在传入的指针中
    *enc_ctx = ctx;
    return 0; // 初始化编码器成功
}

init_decoder

这个函数接受一个解码器 dec、一个指向解码器上下文指针的指针 dec_ctx 和声道布局 ch_layout 作为参数。
它首先使用 avcodec_alloc_context3 函数为解码器分配上下文内存,并设置上下文的参数。然后,它使用 a
vcodec_open2 函数打开解码器。
函数返回 0 表示成功初始化解码器,并将分配的解码器上下文存储在传入的指针 dec_ctx 中。如果内存分配失
败或打开解码器失败,函数将返回相应的错误代码。
/**
 * 初始化解码器
 * @param dec 解码器
 * @param dec_ctx 指向解码器上下文指针的指针,将分配的解码器上下文存储在这里
 * @param ch_layout 声道布局
 * @return 成功返回 0,失败返回错误代码
 */
static int init_decoder(AVCodec *dec, AVCodecContext **dec_ctx,
                        int64_t ch_layout)
{
    AVCodecContext *ctx;
    int result;

    // 为解码器分配上下文内存
    ctx = avcodec_alloc_context3(dec);
    if (!ctx) {
        av_log(NULL, AV_LOG_ERROR , "Can't allocate decoder context\n");
        return AVERROR(ENOMEM); // 内存分配失败
    }

    // 设置解码器上下文的参数
    ctx->request_sample_fmt = AV_SAMPLE_FMT_S16; // 请求采样格式为 16 位整数
    /* XXX: FLAC ignores it for some reason */
    ctx->request_channel_layout = ch_layout; // 请求声道布局
    ctx->channel_layout = ch_layout; // 设置解码器的声道布局

    // 打开解码器
    result = avcodec_open2(ctx, dec, NULL);
    if (result < 0) {
        av_log(ctx, AV_LOG_ERROR, "Can't open decoder\n");
        return result; // 打开解码器失败,返回错误代码
    }

    // 将分配的解码器上下文存储在传入的指针中
    *dec_ctx = ctx;
    return 0; // 初始化解码器成功
}

run_test

用于执行编码器和解码器的测试的主要函数。它包括对音频数据进行编码和解码,然后比较编码前后的数据是否一致。
这个函数的主要功能是生成原始音频数据,然后将其编码为 FLAC 格式,再解码回原始数据,并比较解码后的数据
与原始数据是否一致。函数首先分配输入和输出音频帧的内存,然后循环进行编码和解码的测试。在每一次循环中,
它使用 generate_raw_frame 函数生成原始音频数据,并将其拷贝到输入原始音频数据缓冲区。接着,它调用 avcodec_encode_audio2 函数对音频帧进行编码,并使用 avcodec_decode_audio4 函数对编码后的数据进行解码。
解码后,它比较解码前后的音频数据是否一致。最后,它释放分配的内存,并返回测试结果。文章来源地址https://www.toymoban.com/news/detail-784398.html

/**
 * 执行编码器和解码器的测试
 * @param enc 编码器
 * @param dec 解码器
 * @param enc_ctx 编码器上下文
 * @param dec_ctx 解码器上下文
 * @return 成功返回 0,失败返回错误代码
 */
static int run_test(AVCodec *enc, AVCodec *dec, AVCodecContext *enc_ctx,
                    AVCodecContext *dec_ctx)
{
    AVPacket enc_pkt; // 编码后的数据包
    AVFrame *in_frame, *out_frame; // 输入和输出的音频帧
    uint8_t *raw_in = NULL, *raw_out = NULL; // 输入和输出的原始音频数据
    int in_offset = 0, out_offset = 0; // 输入和输出数据的偏移量
    int result = 0; // 返回结果
    int got_output = 0; // 是否得到输出的标志
    int i = 0; // 循环计数器
    int in_frame_bytes, out_frame_bytes; // 输入和输出音频帧的字节数

    // 分配输入音频帧内存
    in_frame = av_frame_alloc();
    if (!in_frame) {
        av_log(NULL, AV_LOG_ERROR, "Can't allocate input frame\n");
        return AVERROR(ENOMEM); // 分配内存失败
    }

    // 设置输入音频帧的参数
    in_frame->nb_samples = enc_ctx->frame_size;
    in_frame->format = enc_ctx->sample_fmt;
    in_frame->channel_layout = enc_ctx->channel_layout;
    if (av_frame_get_buffer(in_frame, 32) != 0) {
        av_log(NULL, AV_LOG_ERROR, "Can't allocate a buffer for input frame\n");
        return AVERROR(ENOMEM); // 分配内存失败
    }

    // 分配输出音频帧内存
    out_frame = av_frame_alloc();
    if (!out_frame) {
        av_log(NULL, AV_LOG_ERROR, "Can't allocate output frame\n");
        return AVERROR(ENOMEM); // 分配内存失败
    }

    // 分配输入和输出的原始音频数据内存
    raw_in = av_malloc(in_frame->linesize[0] * NUMBER_OF_FRAMES);
    if (!raw_in) {
        av_log(NULL, AV_LOG_ERROR, "Can't allocate memory for raw_in\n");
        return AVERROR(ENOMEM); // 分配内存失败
    }

    raw_out = av_malloc(in_frame->linesize[0] * NUMBER_OF_FRAMES);
    if (!raw_out) {
        av_log(NULL, AV_LOG_ERROR, "Can't allocate memory for raw_out\n");
        return AVERROR(ENOMEM); // 分配内存失败
    }

    // 循环进行编码和解码的测试
    for (i = 0; i < NUMBER_OF_FRAMES; i++) {
        av_init_packet(&enc_pkt); // 初始化编码后的数据包
        enc_pkt.data = NULL;
        enc_pkt.size = 0;

        // 生成原始音频帧
        generate_raw_frame((uint16_t*)(in_frame->data[0]), i, enc_ctx->sample_rate,
                           enc_ctx->channels, enc_ctx->frame_size);
        in_frame_bytes = in_frame->nb_samples * in_frame->channels * sizeof(uint16_t);
        if (in_frame_bytes > in_frame->linesize[0]) {
            av_log(NULL, AV_LOG_ERROR, "Incorrect value of input frame linesize\n");
            return 1; // 输入帧的数据不正确
        }
        // 将原始音频数据拷贝到输入原始音频数据缓冲区
        memcpy(raw_in + in_offset, in_frame->data[0], in_frame_bytes);
        in_offset += in_frame_bytes;

        // 编码音频帧
        result = avcodec_encode_audio2(enc_ctx, &enc_pkt, in_frame, &got_output);
        if (result < 0) {
            av_log(NULL, AV_LOG_ERROR, "Error encoding audio frame\n");
            return result; // 编码失败,返回错误代码
        }

        // 如果有编码输出,进行解码
        if (got_output) {
            // 解码音频包
            result = avcodec_decode_audio4(dec_ctx, out_frame, &got_output, &enc_pkt);
            if (result < 0) {
                av_log(NULL, AV_LOG_ERROR, "Error decoding audio packet\n");
                return result; // 解码失败,返回错误代码
            }

            if (got_output) {
                // 检查解码后的音频帧参数
                if (in_frame->nb_samples != out_frame->nb_samples) {
                    av_log(NULL, AV_LOG_ERROR, "Error frames before and after decoding has different number of samples\n");
                    return AVERROR_UNKNOWN; // 解码后的音频帧参数不正确
                }
                if (in_frame->channel_layout != out_frame->channel_layout) {
                    av_log(NULL, AV_LOG_ERROR, "Error frames before and after decoding has different channel layout\n");
                    return AVERROR_UNKNOWN; // 解码后的音频帧参数不正确
                }
                if (in_frame->format != out_frame->format) {
                    av_log(NULL, AV_LOG_ERROR, "Error frames before and after decoding has different sample format\n");
                    return AVERROR_UNKNOWN; // 解码后的音频帧参数不正确
                }
                // 将解码后的音频数据拷贝到输出原始音频数据缓冲区
                out_frame_bytes = out_frame->nb_samples * out_frame->channels * sizeof(uint16_t);
                if (out_frame_bytes > out_frame->linesize[0]) {
                    av_log(NULL, AV_LOG_ERROR, "Incorrect value of output frame linesize\n");
                    return 1; // 输出帧的数据不正确
                }
                memcpy(raw_out + out_offset, out_frame->data[0], out_frame_bytes);
                out_offset += out_frame_bytes;
            }
        }
        av_packet_unref(&enc_pkt); // 释放编码后的数据包
    }

    // 比较编码前后的音频数据是否一致
    if (memcmp(raw_in, raw_out, out_frame_bytes * NUMBER_OF_FRAMES) != 0) {
        av_log(NULL, AV_LOG_ERROR, "Output differs\n");
        return 1; // 编码后的数据与解码前的数据不一致
    }

    av_log(NULL, AV_LOG_INFO, "OK\n"); // 测试通过

	//保存生成的音频文件
    char layout_name_buff[NAME_BUFF_SIZE];
    av_get_channel_layout_string(layout_name_buff, NAME_BUFF_SIZE, 0, enc_ctx->channel_layout);

    char filename[100];
    snprintf(filename, sizeof(filename), "output_%s.raw", layout_name_buff);
    FILE* outfile = fopen(filename, "wb");
    if (!outfile) {
        av_log(NULL, AV_LOG_ERROR, "Can't open output file\n");
        return 1;
    }

    fwrite(raw_out, 1, out_offset, outfile);
    fclose(outfile);



    // 释放分配的内存
    av_freep(&raw_in);
    av_freep(&raw_out);
    av_frame_free(&in_frame);
    av_frame_free(&out_frame);
    return 0; // 测试成功
}

main

/**
 * 程序入口点,执行编码器和解码器的测试
 * @return 成功返回 0,失败返回错误代码

AV_CH_LAYOUT_STEREO: 这表示立体声音频通道布局,即左右两个声道。在这种布局下,左声道通常用于表示音频的左侧声音,右声道用于表示
右侧声音。这是最常见的音频通道布局之一。

AV_CH_LAYOUT_5POINT1_BACK: 这是一个 5.1 声道的音频通道布局,也称为“5.1 后置声道布局”。它包括一个中置声道(Center)、
两个前置声道(Front Left 和 Front Right)、两个环绕声道(Surround Left 和 Surround Right)、一个低频增强声道(LFE)。
此外,还有两个后置环绕声道(Back Left 和 Back Right),用于在 7.1 系统中提供额外的环绕效果。

AV_CH_LAYOUT_SURROUND: 这表示环绕声道布局,通常包括一个中心声道(Center)、一个低频增强声道(LFE)、两个前置声道
(Front Left 和 Front Right)、两个环绕声道(Surround Left 和 Surround Right)。这是一个常见的环绕声道布局。

AV_CH_LAYOUT_STEREO_DOWNMIX: 这是一个混合的立体声音频通道布局,通常用于表示将多声道音频(如 5.1 或 7.1 声道)混合为立
体声的输出。在这种布局下,可能会进行混音、平衡和降噪等处理,以适应立体声播放环境。
 */
int main(void)
{
    AVCodec *enc = NULL, *dec = NULL; // 编码器和解码器
    AVCodecContext *enc_ctx = NULL, *dec_ctx = NULL; // 编码器和解码器上下文
    uint64_t channel_layouts[] = {AV_CH_LAYOUT_STEREO, AV_CH_LAYOUT_5POINT1_BACK, AV_CH_LAYOUT_SURROUND, AV_CH_LAYOUT_STEREO_DOWNMIX}; // 声道布局数组
    int sample_rates[] = {8000, 44100, 48000, 192000}; // 采样率数组
    int cl, sr; // 循环计数器

    // 查找 FLAC 编码器
    enc = avcodec_find_encoder(AV_CODEC_ID_FLAC);
    if (!enc) {
        av_log(NULL, AV_LOG_ERROR, "Can't find encoder\n");
        return 1; // 找不到编码器,返回错误代码
    }

    // 查找 FLAC 解码器
    dec = avcodec_find_decoder(AV_CODEC_ID_FLAC);
    if (!dec) {
        av_log(NULL, AV_LOG_ERROR, "Can't find decoder\n");
        return 1; // 找不到解码器,返回错误代码
    }

    // 循环遍历声道布局和采样率数组,进行编码器和解码器的测试
    for (cl = 0; cl < FF_ARRAY_ELEMS(channel_layouts); cl++) {
        for (sr = 0; sr < FF_ARRAY_ELEMS(sample_rates); sr++) {
            // 初始化编码器上下文
            if (init_encoder(enc, &enc_ctx, channel_layouts[cl], sample_rates[sr]) != 0)
                return 1; // 初始化编码器上下文失败,返回错误代码

            // 初始化解码器上下文
            if (init_decoder(dec, &dec_ctx, channel_layouts[cl]) != 0)
                return 1; // 初始化解码器上下文失败,返回错误代码

            // 执行编码器和解码器的测试
            if (run_test(enc, dec, enc_ctx, dec_ctx) != 0)
                return 1; // 执行测试失败,返回错误代码

            // 关闭编码器和解码器
            close_encoder(&enc_ctx);
            close_decoder(&dec_ctx);
        }
    }

    return 0; // 所有测试执行成功,返回 0
}

到了这里,关于ffmpeg api-alac-text.c的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【音视频处理】转编码H264 to H265,FFmpeg,代码分享讲解

    大家好,欢迎来到停止重构的频道。 本期我们讨论音视频文件 转编码 ,如将视频H264转H265等。 内容中所提及的 代码都会放在GitHub ,感兴趣的小伙伴可以到GitHub下载。 我们按这样的顺序展开讨论:​ 1、  编码的作用  2、  转编码的工作原理 3、  编解码器安装  4、  示

    2024年02月11日
    浏览(53)
  • 【JaveWeb教程】(14) SpringBootWeb之请求与Postman详细代码示例讲解

    在上一次的课程中,我们开发了springbootweb的入门程序。 基于SpringBoot的方式开发一个web应用,浏览器发起请求 /hello 后 ,给浏览器返回字符串 “Hello World ~”。 其实呢,是我们在浏览器发起请求,请求了我们的后端web服务器(也就是内置的Tomcat)。而我们在开发web程序时呢,定

    2024年02月01日
    浏览(47)
  • stable diffusion API 调用,超级详细代码示例和说明

    本文主要介绍 stable diffusion API 调用,准确来说是对 stable diffusion webui 的 API 调用。接口文档可以查看: http://sd-webui.test.cn/docs 这里的 sd-webui.test.cn 是自己的 sd webui Endpoint。 文生图是: /sdapi/v1/txt2img 这个 POST 接口。 图生图是: /sdapi/v1/img2img 这个 POST 接口。 本文主要介绍文生

    2024年02月12日
    浏览(47)
  • python实战应用讲解-【numpy数组篇】常用函数(八)(附python示例代码)

    目录 Python Numpy MaskedArray.cumprod()函数 Python Numpy MaskedArray.cumsum()函数 Python Numpy MaskedArray.default_fill_value()函数 Python Numpy MaskedArray.flatten()函数 Python Numpy MaskedArray.masked_equal()函数 numpy.MaskedArray.cumprod() 返回在给定轴上被屏蔽的数组元素的累积乘积。在计算过程中,被屏蔽的值在内部

    2024年02月02日
    浏览(58)
  • 义乌购关键字搜索API接口技术详解与代码示例

    义乌购搜索API接口技术详解与代码示例 在电子商务蓬勃发展的今天,义乌购作为国内知名的批发市场平台,为广大商家和消费者提供了丰富的商品资源。为了方便开发者快速接入义乌购平台,实现商品信息的搜索与获取,义乌购开放了搜索API接口。本文将详细介

    2024年03月17日
    浏览(58)
  • python实战应用讲解-【numpy数组篇】实用小技巧(五)(附python示例代码)

    目录   查找两个NumPy数组的并集 查找NumPy数组中的唯一行 扁平化 一个NumPy数组的列表 使用NumPy在Python中扁平化一个矩阵 从元素上获取NumPy数组值的幂 为了找到两个一维数组的联合,我们可以使用Python Numpy库的函数numpy.union1d()。它返回唯一的、经过排序的数组,其值在两个输

    2023年04月14日
    浏览(45)
  • python实战应用讲解-【numpy数组篇】实用小技巧(八)(附python示例代码)

    目录   如何在NumPy数组上映射一个函数 方法一:numpy.vectorize()方法 方法2:使用lambda函数 方法3:用一个数组作为函数的参数来映射一个NumPy数组 如何使用给定的索引位置重新排列二维NumPy数组的列 如何用NumPy删除只包含0的数组行 如何删除Numpy数组中包含非数字值的列

    2024年02月01日
    浏览(49)
  • 【JaveWeb教程】(26) Mybatis基础操作(新增、修改、查询、删除) 详细代码示例讲解(最全面)

    学习完mybatis入门后,我们继续学习mybatis基础操作。 需求说明: 根据资料中提供的《tlias智能学习辅助系统》页面原型及需求,完成员工管理的需求开发。 通过分析以上的页面原型和需求,我们确定了功能列表: 查询 根据主键ID查询 条件查询 新增 更新 删除 根据主键ID删除

    2024年01月17日
    浏览(53)
  • 多语言对接电商平台api接口获取京东商品评论数据代码展示示例

    商品评论接口的意义: 确认消费者关注与产品卖点是否一致; 洞察用户对价格、促销、直播的敏感度;发现产品质量、客服、物流等方面的问题;找到品牌宣称与用户预期、实际场景之间差异化;挖掘消费者偏好的差异性,进行用户分群偏好研究;还原客户故事,分析其购

    2024年02月11日
    浏览(41)
  • GDAL OGR C++ API 学习之路 (5)OGRLayer篇 代码示例

    virtual  OGRStyleTable * GetStyleTable   ( ) 返回图层样式表 返回:  指向不应由调用方修改或释放的样式表的指针 virtual  void  SetStyleTableDirect (OGRStyleTable *poStyleTable  ) 设置图层样式表 参数: poStyleTable  -- 指向要设置的样式表的指针 Virtual  OGRErr  StartTransaction ( ) 对于支持事务的数

    2024年02月14日
    浏览(52)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包