ffmpeg音频编码
#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; }