pcm转aac

开发环境

操作系统:win10
IDE:VS2019
第三方库:ffmpeg5

代码

/*
 * Copyright (c) 2001 Fabrice Bellard
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

 /**
  * @file
  * audio encoding with libavcodec API example.
  *
  * @example encode_audio.c
  */

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/channel_layout.h>
#include <libavutil/common.h>
#include <libavutil/frame.h>
#include <libavutil/samplefmt.h>
#include <libswresample/swresample.h>

  /* check that a given sample format is supported by the encoder */
static int check_sample_fmt(const AVCodec* codec, enum AVSampleFormat sample_fmt)
{
    const enum AVSampleFormat* p = codec->sample_fmts;

    while (*p != AV_SAMPLE_FMT_NONE) {
        if (*p == sample_fmt)
            return 1;
        p++;
    }
    return 0;
}

/* just pick the highest supported samplerate */
static int select_sample_rate(const AVCodec* codec)
{
    const int* p;
    int best_samplerate = 0;

    if (!codec->supported_samplerates)
        return 44100;

    p = codec->supported_samplerates;
    while (*p) {
        if (!best_samplerate || abs(44100 - *p) < abs(44100 - best_samplerate))
            best_samplerate = *p;
        p++;
    }
    return best_samplerate;
}

/* select layout with the highest channel count */
static int select_channel_layout(const AVCodec* codec, AVChannelLayout* dst)
{
    const AVChannelLayout* p, * best_ch_layout = NULL;
    int best_nb_channels = 0;

    if (!codec->ch_layouts)
        return av_channel_layout_copy(dst, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO);

    p = codec->ch_layouts;
    while (p->nb_channels) {
        int nb_channels = p->nb_channels;

        if (nb_channels > best_nb_channels) {
            best_ch_layout = p;
            best_nb_channels = nb_channels;
        }
        p++;
    }
    return av_channel_layout_copy(dst, best_ch_layout);
}

static void encode(AVCodecContext* ctx, AVFrame* frame, AVPacket* pkt,
    AVFormatContext* avFormatContext)
{
    int ret;

    /* send the frame for encoding */
    ret = avcodec_send_frame(ctx, frame);
    if (ret < 0) {
        fprintf(stderr, "Error sending the frame to the encoder\n");
        exit(1);
    }

    /* read all the available output packets (in general there may be any
     * number of them */
    while (ret >= 0) {
        ret = avcodec_receive_packet(ctx, pkt);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
            return;
        else if (ret < 0) {
            fprintf(stderr, "Error encoding audio frame\n");
            exit(1);
        }

        //fwrite(pkt->data, 1, pkt->size, output);
        // 指定是音频流。 1为视频流
        pkt->stream_index = 0;
        // 解码时间、显示时间置为0
        pkt->dts = 0;
        pkt->pts = 0;
        // 编码后的写入ac文件 1.输出上下文
        av_interleaved_write_frame(avFormatContext, pkt);
        av_packet_unref(pkt);
    }
}

int main(int argc, char** argv)
{
    const char* filename;
    const AVCodec* codec;
    AVCodecContext* c = NULL;
    AVFrame* frame;
    AVFrame* aacFrame;
    AVPacket* pkt;
    int i, j, k, ret;
    FILE* f;
    uint16_t* samples;
    float t, tincr;
    struct SwrContext* swr_ctx;

    //if (argc <= 1) {
    //    fprintf(stderr, "Usage: %s <output file>\n", argv[0]);
    //    return 0;
    //}

    const char* inFileName = "../resources/output.pcm";

    filename = "output.aac";

    FILE* inFile;
    fopen_s(&inFile, inFileName, "rb");
    if (!inFile) {
        fprintf(stderr, "Could not open %s\n", inFileName);
        exit(1);
    }

    /* find the AAC encoder */
    codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
    if (!codec) {
        fprintf(stderr, "Codec not found\n");
        exit(1);
    }

    c = avcodec_alloc_context3(codec);
    if (!c) {
        fprintf(stderr, "Could not allocate audio codec context\n");
        exit(1);
    }

    /* put sample parameters */
    c->bit_rate = 64000;

    /* check that the encoder supports s16 pcm input */
    c->sample_fmt = AV_SAMPLE_FMT_FLTP;
    if (!check_sample_fmt(codec, c->sample_fmt)) {
        fprintf(stderr, "Encoder does not support sample format %s",
            av_get_sample_fmt_name(c->sample_fmt));
        exit(1);
    }
    c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;//音频帧设置头部

    c->channels = 2;
    
    /* select other audio parameters supported by the encoder */
    c->sample_rate = select_sample_rate(codec);
    ret = select_channel_layout(codec, &c->ch_layout);
    if (ret < 0)
        exit(1);

    c->channel_layout = AV_CH_LAYOUT_STEREO;

    /* create resampler context */
    swr_ctx = swr_alloc();
    if (!swr_ctx) {
        fprintf(stderr, "Could not allocate resampler context\n");
        ret = AVERROR(ENOMEM);
        exit(1);
    }
    ///* set options */
    av_opt_set_int(swr_ctx, "in_channel_layout", AV_CH_LAYOUT_STEREO, 0);
    av_opt_set_int(swr_ctx, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0);

    av_opt_set_int(swr_ctx, "in_sample_rate", c->sample_rate, 0);
    av_opt_set_sample_fmt(swr_ctx, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0);

    av_opt_set_int(swr_ctx, "out_sample_rate", c->sample_rate, 0);
    av_opt_set_sample_fmt(swr_ctx, "out_sample_fmt", AV_SAMPLE_FMT_FLTP, 0);

    /* initialize the resampling context */
    if ((ret = swr_init(swr_ctx)) < 0) {
        fprintf(stderr, "Failed to initialize the resampling context\n");
        exit(1);
    }

    /* open it */
    if (avcodec_open2(c, codec, NULL) < 0) {
        fprintf(stderr, "Could not open codec\n");
        exit(1);
    }

    // 创建输出的上下文
    AVFormatContext* avFormatContext = NULL;
    // 初始化
    avformat_alloc_output_context2(&avFormatContext, NULL, NULL, filename);
    if (!avFormatContext) {
        return -1;
    }
    // 创建音频流
    AVStream* st = avformat_new_stream(avFormatContext, NULL);
    // 音频流参数设置
    st->codecpar->codec_tag = 0;
    // 编码器参数复制到音频流上,省得再设置一遍
    avcodec_parameters_from_context(st->codecpar, c);
    // 第三个参数,0音频、1视频
    av_dump_format(avFormatContext, 0, filename, 1);

    // 打开输出文件
    ret = avio_open(&avFormatContext->pb, filename, AVIO_FLAG_WRITE);
    if (ret < 0) {
        return -1;
    }
    // 写头部信息,创建输出文件
    avformat_write_header(avFormatContext, NULL);

    /* packet for holding encoded output */
    pkt = av_packet_alloc();
    if (!pkt) {
        fprintf(stderr, "could not allocate the packet\n");
        exit(1);
    }

    /* frame containing input raw audio */
    frame = av_frame_alloc();
    if (!frame) {
        fprintf(stderr, "Could not allocate audio frame\n");
        exit(1);
    }

    frame->nb_samples = c->frame_size;
    frame->format = c->sample_fmt;
    ret = av_channel_layout_copy(&frame->ch_layout, &c->ch_layout);
    if (ret < 0)
        exit(1);

    /* allocate the data buffers */
    ret = av_frame_get_buffer(frame, 0);
    if (ret < 0) {
        fprintf(stderr, "Could not allocate audio data buffers\n");
        exit(1);
    }

    /* frame containing input raw audio */
    aacFrame = av_frame_alloc();
    if (!aacFrame) {
        fprintf(stderr, "Could not allocate audio frame\n");
        exit(1);
    }

    aacFrame->nb_samples = c->frame_size;
    aacFrame->format = AV_SAMPLE_FMT_FLTP;
    ret = av_channel_layout_copy(&aacFrame->ch_layout, &c->ch_layout);
    if (ret < 0)
        exit(1);

    /* allocate the data buffers */
    ret = av_frame_get_buffer(aacFrame, 0);
    if (ret < 0) {
        fprintf(stderr, "Could not allocate audio data buffers\n");
        exit(1);
    }

    // 准备缓存空间存放数据
    int readSize = frame->nb_samples * 2 * 2; //双声道,float
    char* pcms = (char*)malloc(readSize);

    int sum = 0;
    int index = 0;

    for (;;) {
        int len = fread(pcms, 1, readSize, inFile);
        if (len <= 0) {
            // 告诉解码器没有帧了
            avcodec_send_frame(c, NULL);
            while (avcodec_receive_packet(c, pkt) != AVERROR_EOF);
            break;
        }
        else {
            index++;
            sum += len;
            // 强制数据类型转换,重采样之前的数据
            const uint8_t* data[1];
            data[0] = (uint8_t*)pcms;
            // 重采样 1.重采样上下文 2.重采样后的数据 3.样本数量不变 4.重采样之前的数据
            len = swr_convert(swr_ctx, frame->data, frame->nb_samples, data, frame->nb_samples);
            if (len <= 0) {
                break;
            }
            encode(c, frame, pkt, avFormatContext);
        }
    }
    av_packet_free(&pkt);


    free(pcms);
    pcms = NULL;

    // 写入索引
    av_write_trailer(avFormatContext);

    fclose(inFile);
    avio_close(avFormatContext->pb);
    avcodec_close(c);
    swr_free(&swr_ctx);
    av_frame_free(&frame);
    av_frame_free(&aacFrame);
    av_packet_free(&pkt);
    avcodec_free_context(&c);
    avformat_free_context(avFormatContext);

    return 0;
}

注意
aac的编码器的音频数据格式(sample_fmt)需要设置为AV_SAMPLE_FMT_FLTP,而原始的pcm的sample_fmt是AV_SAMPLE_FMT_S16,因此需要做重采样。重采样使用libswresample库。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: Java是一种广泛应用于软件开发中的编程语言,而FAAC是一款常用的开源编码器,可以将PCM(脉冲编码调制)格式的音频换成AAC(高级音频编码)格式。下面是一种使用Java和FAAC库进行PCMAAC的简单示例。 首先,需要在Java项目中引入FAAC库的依赖。可以通过Maven等构建工具来添加FAAC库的依赖项。然后,在Java代码中调用FAAC库提供的方法来实现PCMAAC的功能。 ```java import com.googlecode.mp4parser.authoring.Sample; import java.io.FileInputStream; import java.io.FileOutputStream; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.ShortBuffer; import java.util.ArrayList; public class PCM2AACConverter { // PCMAAC的方法 public static void pcmToAac(String inputPath, String outputPath) { try { FileInputStream fis = new FileInputStream(inputPath); FileOutputStream fos = new FileOutputStream(outputPath); int channels = 2; // 音频通道数 int sampleRate = 44100; // 采样率 int bitRate = 128000; // 码率 // 创建FAAC编码器 com.googlecode.mp4parser.authoring.Sample sample = new com.googlecode.mp4parser.authoring.Sample(); sample.begin(channels, sampleRate, bitRate); byte[] data = new byte[1024]; int bytesRead = 0; while ((bytesRead = fis.read(data)) > 0) { // 将PCM数据换成short类型的数组 ShortBuffer shortBuffer = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer(); short[] pcmData = new short[shortBuffer.remaining()]; shortBuffer.get(pcmData); // 将PCM数据添加到FAAC编码器 sample.add(pcmData); } // 完成PCM数据添加操作 sample.end(); // 获取AAC编码后的数据 ArrayList<byte[]> aacData = sample.getAACData(); // 将AAC数据写入输出文件 for (byte[] aacFrame : aacData) { fos.write(aacFrame); } fis.close(); fos.close(); } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { String inputPath = "input.pcm"; // 输入PCM文件的路径 String outputPath = "output.aac"; // 输出AAC文件的路径 pcmToAac(inputPath, outputPath); } } ``` 上述代码使用了FAAC库提供的`Sample`类来进行PCMAAC操作。通过`pcmToAac`方法,将输入的PCM文件换成AAC格式并输出到指定路径。在此过程中,需要指定音频的通道数、采样率和码率等参数。 要使用上述方法,首先需要确保Java项目已经引入FAAC库的依赖,同时将输入的PCM文件和输出的AAC文件放置在正确的路径下。 以上是一个简单的示例,仅供参考。实际应用中,可能需要根据具体需求对代码进行修改和优化。 ### 回答2: Java FAAC PCMAAC可以通过使用FAAC库和Java编程语言来实现。以下是一个简单的示例代码来演示如何使用Java FAAC库将PCM音频文件换为AAC格式: ```java import com.googlecode.faac.Faac; import com.googlecode.faac.FaacConfig; import com.googlecode.faac.FaacConfigParams; import com.googlecode.faac.FaacInstance; public class PCMtoAACConverter { public static void main(String[] args) { String pcmFile = "input.pcm"; String aacFile = "output.aac"; // 初始化FAAC库 Faac faac = Faac.getInstance(); // 创建FAAC实例 FaacInstance faacInstance = faac.faacEncOpenDefault(48000, 2); // 设置FAAC配置参数 FaacConfig faacConfig = faac.faacEncGetCurrentConfiguration(faacInstance); FaacConfigParams configParams = new FaacConfigParams(); configParams.setBitrate(128000); configParams.setInputFormat(Faac.FAAC_INPUT_FORMAT_16BIT); faacConfig.setParams(configParams); faac.faacEncSetConfiguration(faacInstance, faacConfig); // 打开PCM文件和AAC文件 faac.faacEncOpenFile(faacInstance, pcmFile, aacFile); // 开始换 faac.faacEncEncode(faacInstance); // 关闭文件和FAAC实例 faac.faacEncClose(faacInstance); faac.faacEncCloseFile(faacInstance); System.out.println("PCMAAC完成!"); } } ``` 上述代码示例使用了FAAC库提供的相关函数来实现PCM文件换为AAC文件的功能。其中,需先准备好待换的PCM音频文件和指定的输出AAC文件路径。代码中的配置参数可根据需求进行调整,例如比特率、通道数等。 需要注意的是,使用FAAC库需要先下载并导入合适的FAAC库文件到项目中,并进行相关的配置。此外,FAAC库是一个开源的第三方库,使用时需了解其许可证限制和相关文档。 ### 回答3: 要使用Java将PCM音频文件换为AAC格式,可以使用FAAC库。FAAC是一个用于将音频文件编码为AAC格式的开源库。 首先,需要确保已经下载并安装了FAAC库。然后,可以在Java项目中使用JNI(Java Native Interface)来调用FAAC库的功能。 在Java中使用JNI调用FAAC库时,可以使用JNIWrapper库。这个库提供了一种方便的方式来与C/C++代码进行交互。 首先,需要编写一个调用FAAC的Java类。在这个类中,可以使用JNIWrapper库提供的函数来加载FAAC库和调用它的函数。可以编写一个Java方法来将PCM文件换为AAC文件。 示例代码如下: ```java import com.jniwrapper.*; import com.jniwrapper.win32.jni.*; import com.jniwrapper.util.*; public class FaacConverter { private static final String LIBRARY_NAME = "your_FAAC_library_name"; static { NativeLibraryLoader.loadLibrary(LIBRARY_NAME); } public static native int convertPcmToAac(String pcmFilePath, String aacFilePath); public static void main(String[] args) { String pcmFilePath = "/path/to/pcm/file.pcm"; String aacFilePath = "/path/to/aac/file.aac"; int result = convertPcmToAac(pcmFilePath, aacFilePath); if (result == 0) { System.out.println("PCM file converted to AAC successfully."); } else { System.out.println("Failed to convert PCM file to AAC."); } } } ``` 要使用这个示例代码,需要将FAAC库文件与Java项目一起编译,并将LIBRARY_NAME变量设置为FAAC库的名称。 编写完Java类后,可以使用Java编译器将其编译为可执行的Java程序。 然后,可以通过运行这个程序来将PCM文件换为AAC文件。在main方法中,可以设置PCM文件的路径和要生成的AAC文件的路径。 运行这个程序后,如果换成功,将会在控制台打印出"PCM file converted to AAC successfully."的消息,否则将会打印出"Failed to convert PCM file to AAC."的消息。 这就是使用Java将PCM音频文件换为AAC格式的基本步骤。希望对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

都市无名者

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

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

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

打赏作者

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

抵扣说明:

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

余额充值