音頻數(shù)據(jù)經(jīng)過(guò)解碼后會(huì)被保存為,pcm數(shù)據(jù)格式。而對(duì)應(yīng)的處理流程如下所示。
avcodec_find_encoder()?
/**
* 查找具有匹配編解碼器ID的已注冊(cè)編碼器.
*
* @param id AVCodecID of the requested encoder
* @return An encoder if one was found, NULL otherwise.
*/
const AVCodec *avcodec_find_encoder(enum AVCodecID id);
avcodec_find_encoder_by_name()?
/**
* 查找具有指定名稱的已注冊(cè)編碼器.
*
* @param name name of the requested encoder
* @return An encoder if one was found, NULL otherwise.
*/
const AVCodec *avcodec_find_encoder_by_name(const char *name);
avcodec_alloc_context3()?
/**
分配AVCodecContext并將其字段設(shè)置為默認(rèn)值。該應(yīng)使用avcodec_free_context()釋放結(jié)果結(jié)構(gòu)。
*
* @param codec if non-NULL, allocate private data and initialize defaults
* for the given codec. It is illegal to then call avcodec_open2()
* with a different codec.
* If NULL, then the codec-specific defaults won't be initialized,
* which may result in suboptimal default settings (this is
* important mainly for encoders, e.g. libx264).
*
* @return An AVCodecContext filled with default values or NULL on failure.
*/
AVCodecContext *avcodec_alloc_context3(const AVCodec *codec);
?設(shè)置對(duì)應(yīng)音頻編碼的數(shù)據(jù)類型
codec_ctx->sample_fmt = AV_SAMPLE_FMT_S16; //輸入音頻的采樣大小
codec_ctx->channel_layout = AV_CH_LAYOUT_STEREO; //輸入音頻的channel layout
codec_ctx->channels = 2; //輸入音頻 channel 個(gè)數(shù)
codec_ctx->sample_rate = 44100; //輸入音頻的采樣率
codec_ctx->bit_rate = 0; //AAC_LC: 128K, AAC HE: 64K, AAC HE V2: 32K
codec_ctx->profile = FF_PROFILE_AAC_HE_V2; //閱讀 ffmpeg 代碼
設(shè)置編碼的frame的相關(guān)參數(shù)文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-593288.html
//set parameters
frame->nb_samples = 512; //單通道一個(gè)音頻幀的采樣數(shù)
frame->format = AV_SAMPLE_FMT_S16; //每個(gè)采樣的大小
frame->channel_layout = AV_CH_LAYOUT_STEREO; //channel layout
整個(gè)代碼:文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-593288.html
#include <stdint.h>
#include <stdio.h>
#include <stdlib.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){
AVChannelLayout src = (AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO;
return av_channel_layout_copy(dst,&src);
}
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(int argc, char **argv)
{
// 對(duì)應(yīng)文件的編碼數(shù)據(jù)
const char *filename;
// 編碼器
const AVCodec *codec;
// 編碼器上下文
AVCodecContext *c= NULL;
// 保存未曾解碼的數(shù)據(jù)
AVFrame *frame;
// 對(duì)應(yīng)的保存數(shù)據(jù)
AVPacket *pkt;
int i, j, k, ret;
FILE *f;
uint16_t *samples;
float t, tincr;
if (argc <= 1) {
fprintf(stderr, "Usage: %s <output file>\n", argv[0]);
return 0;
}
// 獲得輸出文件
filename = argv[1];
// 找到對(duì)應(yīng)的編碼器
codec = avcodec_find_encoder(AV_CODEC_ID_MP2);
if (!codec) {
fprintf(stderr, "Codec not found\n");
exit(1);
}
// 使用默認(rèn)值設(shè)置編碼器的內(nèi)容數(shù)據(jù)
c = avcodec_alloc_context3(codec);
if (!c) {
fprintf(stderr, "Could not allocate audio codec context\n");
exit(1);
}
// 設(shè)置編碼器的相關(guān)信息
// 設(shè)置編碼器的比特率
c->bit_rate = 64000;
// /采樣的數(shù)據(jù)類型
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);
}
// 對(duì)應(yīng)的采樣頻率
c->sample_rate = select_sample_rate(codec);
// 設(shè)置對(duì)應(yīng)布局
ret = select_channel_layout(codec, &c->ch_layout);
if (ret < 0)
exit(1);
// 打開對(duì)應(yīng)的編碼器
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);
}
// 設(shè)置單通道數(shù)據(jù)采樣大小
frame->nb_samples = c->frame_size;
// 數(shù)據(jù)采樣的大小
frame->format = c->sample_fmt;
// 設(shè)置對(duì)用的通道大小
ret = av_channel_layout_copy(&frame->ch_layout, &c->ch_layout);
if (ret < 0)
exit(1);
/* 設(shè)置對(duì)應(yīng)數(shù)據(jù)的緩沖區(qū) */
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 */
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;
}
到了這里,關(guān)于ffmpeg學(xué)習(xí)之音頻解碼數(shù)據(jù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!