ffmpeg相关的测试命令
#从mp4文件中提取pcm
ffmpeg -i input.mp4 -ar 44100 -ac 2 -f f32le output.pcm
#播放音频pcm
ffplay -ar 44100 -ac 2 -f f32le output.pcm
#ffmpeg将pcm转aac
ffmpeg -ar 44100 -ac 2 -f f32le -i output.pcm -c:a aac -b:a 192k output.aac
c语言实现将pcm_f32le编码为aac
#include<stdio.h>
#include<stdlib.h>
#include <libavcodec/codec.h>
#include <libavcodec/avcodec.h>
#define ADTS_HEADER_LEN 7
static const int sampling_frequency_map[] = {
96000,
88200,
64000,
48000,
44100,
32000,
24000,
22050,
16000,
12000,
11025,
8000,
7350,
};
static int fill_adts_header(char * const adts_header_buf, const int data_length,
const int profile, const int sample_rate,
const int nb_channels)
{
int sampling_frequency_index = 3;
int adts_len = data_length + 7;
int sampling_frequency_size = sizeof(sampling_frequency_map) / sizeof(sampling_frequency_map[0]);
int i = 0;
for(i = 0; i < sampling_frequency_size; i++)
{
if(sampling_frequency_map[i] == sample_rate)
{
sampling_frequency_index = i;
break;
}
}
if(i >= sampling_frequency_size)
{
fprintf(stderr, "The sampling frequency of %d Hz is not supported.\n", sample_rate);
return -1;
}
adts_header_buf[0] = 0xff;
adts_header_buf[1] = 0xf0;
adts_header_buf[1] |= (0 << 3);
adts_header_buf[1] |= (0 << 1);
adts_header_buf[1] |= 1;
adts_header_buf[2] = (profile)<<6;
adts_header_buf[2] |= (sampling_frequency_index & 0x0f)<<2;
adts_header_buf[2] |= (0 << 1);
adts_header_buf[2] |= (nb_channels & 0x04)>>2;
adts_header_buf[3] = (nb_channels & 0x03)<<6;
adts_header_buf[3] |= (0 << 5);
adts_header_buf[3] |= (0 << 4);
adts_header_buf[3] |= (0 << 3);
adts_header_buf[3] |= (0 << 2);
adts_header_buf[3] |= ((adts_len & 0x1800) >> 11);
adts_header_buf[4] = (uint8_t)((adts_len & 0x7f8) >> 3);
adts_header_buf[5] = (uint8_t)((adts_len & 0x7) << 5);
adts_header_buf[5] |= 0x1f;
adts_header_buf[6] = 0xfc;
return 0;
}
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;
}
static int encode(AVCodecContext *ctx, AVFrame *frame, AVPacket *pkt,
FILE *output)
{
int ret;
ret = avcodec_send_frame(ctx, frame);
if (ret < 0) {
fprintf(stderr, "Error sending the frame to the encoder\n");
return -1;
}
while (ret >= 0) {
ret = avcodec_receive_packet(ctx, pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
return 0;
else if (ret < 0) {
fprintf(stderr, "Error encoding audio frame\n");
return -1;
}
char adts_header_buf[ADTS_HEADER_LEN] = {0};
fill_adts_header(adts_header_buf,
pkt->size,
ctx->profile,
ctx->sample_rate,
ctx->ch_layout.nb_channels);
fwrite(adts_header_buf, 1, ADTS_HEADER_LEN, output);
fwrite(pkt->data, 1, pkt->size, output);
av_packet_unref(pkt);
}
return 0;
}
int pcm_to_aac(const char * const pcm_file_path, const char * const aac_file_path,
const int sample_rate, const int nb_channels, const int bit_rate)
{
const AVCodec *codec = NULL;
AVCodecContext *ctx = NULL;
AVFrame *frame = NULL;
AVPacket *pkt = NULL;
int ret;
FILE *pcm_file = fopen(pcm_file_path, "rb");
if (!pcm_file) {
perror("open pcm file failed");
ret = -1;
goto end;
}
FILE *aac_file = fopen(aac_file_path, "wb");
if (!aac_file) {
perror("open aac file failed");
ret = -1;
goto end;
}
codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
if (!codec) {
fprintf(stderr, "AV_CODEC_ID_AAC codec not found\n");
ret = -1;
goto end;
}
ctx = avcodec_alloc_context3(codec);
if (!ctx) {
fprintf(stderr, "Could not allocate audio codec context\n");
ret = -1;
goto end;
}
ctx->bit_rate = bit_rate;
ctx->sample_rate = sample_rate;
ctx->sample_fmt = AV_SAMPLE_FMT_FLTP;
if (!check_sample_fmt(codec, ctx->sample_fmt)) {
fprintf(stderr, "Encoder does not support sample format %s",
av_get_sample_fmt_name(ctx->sample_fmt));
ret = -1;
goto end;
}
AVChannelLayout *ch_layout = NULL;
if (nb_channels == 1) {
ch_layout = &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO;
} else if (nb_channels == 2)
{
ch_layout = &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO;
} else {
fprintf(stderr, "nb_channels %d not support!", nb_channels);
ret = -1;
goto end;
}
ret = av_channel_layout_copy(&ctx->ch_layout, ch_layout);
if (ret < 0) {
fprintf(stderr, "av_channel_layout_copy() error!");
ret = -1;
goto end;
}
ret = avcodec_open2(ctx, codec, NULL);
if (ret < 0) {
fprintf(stderr, "Could not open codec\n");
ret = -1;
goto end;
}
pkt = av_packet_alloc();
if (!pkt) {
fprintf(stderr, "Could not allocate the packet\n");
ret = -1;
goto end;
}
frame = av_frame_alloc();
if (!frame) {
fprintf(stderr, "Could not allocate audio frame\n");
ret = -1;
goto end;
}
frame->nb_samples = ctx->frame_size;
frame->format = ctx->sample_fmt;
ret = av_channel_layout_copy(&frame->ch_layout, &ctx->ch_layout);
if (ret < 0) {
fprintf(stderr, "av_channel_layout_copy() error!");
ret = -1;
goto end;
}
ret = av_frame_get_buffer(frame, 0);
if (ret < 0) {
fprintf(stderr, "Could not allocate audio data buffers\n");
ret = -1;
goto end;
}
int bytes_frame = sizeof(float) * ctx->ch_layout.nb_channels * ctx->frame_size;
printf("frame_size: %d\n", ctx->frame_size);
printf("sample_fmt: %d, name: %s\n", ctx->sample_fmt, av_get_sample_fmt_name(ctx->sample_fmt));
printf("ch_layout.nb_channels: %d\n", ctx->ch_layout.nb_channels);
printf("bit_rate: %lld\n", ctx->bit_rate);
printf("bytes_frame: %d\n", bytes_frame);
float *tmp_buffer = (float*) malloc(bytes_frame);
if (!tmp_buffer) {
fprintf(stderr, "Could not allocate tmp_buffer\n");
goto end;
}
printf("sizeof(tmp_buffer): %ld\n", sizeof(tmp_buffer));
int bytes_read;
int count;
long long pcm_file_size = 0;
while((bytes_read = fread(tmp_buffer, 1, bytes_frame, pcm_file)) > 0) {
pcm_file_size += bytes_read;
count++;
if(count % 100 == 0) {
printf("count: %d, bytes_read: %d\n", count, bytes_read);
}
for (int ch = 0; ch < ctx->ch_layout.nb_channels; ch++) {
float *data = (float*) frame->data[ch];
for (int i = 0; i < ctx->frame_size; i++) {
data[i] = tmp_buffer[ctx->ch_layout.nb_channels * i + ch];
}
}
ret = encode(ctx, frame, pkt, aac_file);
if (ret < 0) {
fprintf(stderr, "encode failed!\n");
ret = -1;
goto end;
}
}
printf("count: %d, bytes_read: %d, pcm_file_size: %lld\n", count, bytes_read, pcm_file_size);
ret = encode(ctx, NULL, pkt, aac_file);
if (ret < 0) {
fprintf(stderr, "flush the encoder failed!\n");
ret = -1;
goto end;
}
ret = 0;
end:
if (pcm_file) {
fclose(pcm_file);
}
if (aac_file) {
fclose(aac_file);
}
if (ctx) {
avcodec_free_context(&ctx);
}
if (frame) {
av_frame_free(&frame);
}
if (pkt) {
av_packet_free(&pkt);
}
if (tmp_buffer) {
free(tmp_buffer);
tmp_buffer = NULL;
}
return ret;
}
int main(int argc, char** argv)
{
char *pcm_file_path = "../output.pcm";
char *aac_file_path = "../output.aac";
int sample_rate = 44100;
int nb_channels = 2;
int bit_rate = 128000;
int ret = pcm_to_aac(pcm_file_path, aac_file_path, sample_rate, nb_channels, bit_rate);
printf("main ret: %d\n", ret);
return 0;
}