ffmpeg音频编码

发布时间 2023-10-30 14:55:58作者: 邗影
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern "C" {

#include <libavcodec/avcodec.h>
#include <libavutil/channel_layout.h>
#include <libavutil/common.h>
#include <libavutil/frame.h>
#include <libavutil/samplefmt.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;
    int best_nb_channels = 0;

    if (!codec->ch_layouts)
        return AV_CH_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,
    FILE* output)
{
    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);
        av_packet_unref(pkt);
    }
}

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

  
    filename = "D://Emscripten/cmaketest/outMP2.mp3";
    filename_in = "C://User//zho_44100HZ_2channel_16bitwidth.pcm";

    /* find the MP2 encoder */
    codec = avcodec_find_encoder(AV_CODEC_ID_MP2);
    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_S16;
    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);
    }

    /* 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);

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

    f = fopen(filename, "wb");
    if (!f) {
        fprintf(stderr, "Could not open %s\n", filename);
        exit(1);
    }

    /* 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);
    }

    /* encode a single tone sound */
    FILE* fpin = fopen(filename_in,"rb+");
    if (!fpin)
    {
        fprintf(stderr, "Could not open in file\n");
        exit(1);
    }
   //这里注意,由于PCM是双声道,16位宽,所以每次编码需要的字节数:frame_size*4;=通道采样点数*通道数*每个采样点的字节数
//这个是左右声道交叉存储的package模式,不是planner模式;
auto ret1
= av_frame_make_writable(frame); if (ret1 < 0) exit(1); samples = (uint16_t*)frame->data[0]; ret = fread(samples, 2, c->frame_size*2, fpin);//frame_size音频帧中每个通道的采样数 while(ret == c->frame_size*2 ){ encode(c, frame, pkt, f); ret1 = av_frame_make_writable(frame); if (ret1 < 0) exit(1); samples = (uint16_t*)frame->data[0]; ret = fread(samples,2, c->frame_size*2 , fpin); } //t = 0; //tincr = 2 * M_PI * 440.0 / c->sample_rate; //for (i = 0; i < 200; i++) { // /* make sure the frame is writable -- makes a copy if the encoder // * kept a reference internally */ // ret = av_frame_make_writable(frame); // if (ret < 0) // exit(1); // samples = (uint16_t*)frame->data[0]; // for (j = 0; j < c->frame_size; j++) { // samples[2 * j] = (int)(sin(t) * 10000); // for (k = 1; k < c->ch_layout.nb_channels; k++) // samples[2 * j + k] = samples[2 * j]; // t += tincr; // } // encode(c, frame, pkt, f); //} /* flush the encoder */ encode(c, NULL, pkt, f); fclose(f); av_frame_free(&frame); av_packet_free(&pkt); avcodec_free_context(&c); return 0; }