#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;
}