FFmpegでPCMをAACにする


ffmpeg-3.4 libライブラリとヘッダファイルをコンパイルするプロファイルは、config.shは主に--enable-encoders--enable-swresample
#!/bin/bash

export PREFIX=./../ffmpeg

./configure \
    --disable-yasm \
    --disable-ffplay \
    --disable-ffprobe \
    --disable-ffserver \
    --disable-debug \
    --disable-zlib \
    --disable-bzlib \
    --disable-static \
    --disable-stripping \
    --enable-ffmpeg \
    --enable-shared \
    --enable-gpl \
    --enable-small \
    --target-os=linux \
    --arch=arm \
    --enable-cross-compile \
    --cross-prefix=arm-linux- \
    --cc=arm-linux-gcc \
    --prefix=$PREFIX \
    --enable-encoders \
    --enable-decoders \
    --enable-muxers \
    --enable-demuxers \
    --enable-parsers \
    --enable-bsfs \
    --enable-protocols \
    --disable-filters \
    --disable-avfilter \
    --disable-swscale \
    --enable-swresample \
    --disable-devices \
    --disable-postproc \
    --enable-network \
    --enable-indev=v4l2


Pcm2Aac.h参考までに、詳しくは注釈を参照
#ifdef __cplusplus
extern "C"
{
#endif
    #include "libavcodec/avcodec.h"
    #include "libavformat/avformat.h"
    #include "libswresample/swresample.h"
#ifdef __cplusplus
};
#endif

class Pcm2AAC
{
public:
    Pcm2AAC();
    ~Pcm2AAC();

    bool Init(int i_nPcmSampleRate, AVSampleFormat i_ePcmSampleFmt, int i_nPcmChannels);
    void AddData(char *i_pData, int i_nSize);
    void FlushData(void);
    bool GetData(char *&o_pData, int &o_nSize);

private:
    void AddADTS(int i_nPktLen);

    int m_nPcmSize;
    int m_nPcmChannel;
    int m_nPcmSampleRate;
    AVSampleFormat m_ePcmFormat;
    char *m_aPcmPointer[AV_NUM_DATA_POINTERS];
    char *m_pPcmData;
    char *m_pOutData;
    AVPacket *m_pPacket;
    AVFrame *m_pFrame;
    AVCodec *m_pCodec;
    AVCodecContext *m_pCodecCtx;
    SwrContext *m_pSwrCtx;
    int64_t m_s64Pts;
    int m_nFrameSize;
    int m_nFrameCnt;
};

Pcm2Aac.cppは参照用のみで、詳細はコメントを参照してください.
#include "Pcm2AAC.h"

// refer to ffmpeg/libavformat/adtsenc.c
#define ADTS_HEADER_SIZE 7
#define ADTS_MAX_FRAME_BYTES ((1 << 13) - 1) // 8K

Pcm2AAC::Pcm2AAC()
{
    m_nPcmSize = 0;
    m_pPacket = NULL;
    m_pFrame = NULL;
    m_pCodec = NULL;
    m_pCodecCtx = NULL;
    m_pSwrCtx = NULL;
    m_s64Pts = 0;
    m_nFrameSize = 0;
    m_nFrameCnt = 0;

    for(int i = 0; i < AV_NUM_DATA_POINTERS; i++)
    {
        m_aPcmPointer[i] = new char[1024 * 10];
    }
    m_pPcmData = new char[1024 * 10];
    m_pOutData = new char[1024 * 10];
    memset(m_pPcmData, 0, 1024 * 10);
    memset(m_pOutData, 0, 1024 * 10);
}

Pcm2AAC::~Pcm2AAC()
{
    // just for test
    // 1        
    int nFramesPerSecond = m_nPcmSampleRate / m_nFrameSize; // 44100/1024=43
    printf("nFramesPerSecond = %d
"
, nFramesPerSecond); // 1 ( ) double fFrameTime = 1000.00 / nFramesPerSecond; // 1000/43=23.26ms printf("fFrameTime = %.2fms
"
, fFrameTime); // = * 1 float fDuration = m_nFrameCnt * fFrameTime / 1000; // 2628*23.25=61.12s printf("This AAC total frames = %d, duration = %.2fs
"
, m_nFrameCnt, fDuration); if(m_pPacket != NULL) { av_packet_free(&m_pPacket); } if(m_pFrame != NULL) { av_frame_free(&m_pFrame); } if(m_pCodecCtx != NULL) { avcodec_free_context(&m_pCodecCtx); } if(m_pSwrCtx != NULL) { swr_free(&m_pSwrCtx); } for(int i = 0; i < AV_NUM_DATA_POINTERS; i++) { if(m_aPcmPointer[i] != NULL) { delete[] m_aPcmPointer[i]; } } if(m_pPcmData != NULL) { delete[] m_pPcmData; } if(m_pOutData != NULL) { delete[] m_pOutData; } } bool Pcm2AAC::Init(int i_nPcmSampleRate, AVSampleFormat i_ePcmSampleFmt, int i_nPcmChannels) { m_nPcmSampleRate = i_nPcmSampleRate; m_ePcmFormat = i_ePcmSampleFmt; m_nPcmChannel = i_nPcmChannels; avcodec_register_all(); // AAC m_pCodec = avcodec_find_encoder(AV_CODEC_ID_AAC); if(m_pCodec == NULL) { fprintf(stderr, "Codec not found
"
); return false; } // , , , m_pCodecCtx = avcodec_alloc_context3(m_pCodec); if(m_pCodecCtx == NULL) { fprintf(stderr, "Could not allocate audio codec context
"
); return false; } m_pCodecCtx->channels = m_nPcmChannel; m_pCodecCtx->channel_layout = av_get_default_channel_layout(m_nPcmChannel); m_pCodecCtx->sample_rate = m_nPcmSampleRate; // FFmpeg, AV_SAMPLE_FMT_FLTP AAC m_pCodecCtx->sample_fmt = AV_SAMPLE_FMT_FLTP; m_pCodecCtx->bit_rate = 64000; // Allow the use of the experimental AAC encoder m_pCodecCtx->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL; // if(avcodec_open2(m_pCodecCtx, m_pCodec, NULL) < 0) { fprintf(stderr, "Could not open codec
"
); return false; } // frame_size , frame_size , m_pFrame->nb_samples // : more samples than frame size (avcodec_encode_audio2) printf("m_pCodecCtx->frame_size = %d
"
, m_pCodecCtx->frame_size); m_nFrameSize = m_pCodecCtx->frame_size; // av_packet_alloc() NULL m_pPacket = av_packet_alloc(); if(m_pPacket == NULL) { return false; } m_pFrame = av_frame_alloc(); if(m_pFrame == NULL) { return false; } // m_pSwrCtx = swr_alloc_set_opts(NULL, m_pCodecCtx->channel_layout, m_pCodecCtx->sample_fmt, m_pCodecCtx->sample_rate, m_pCodecCtx->channel_layout, m_ePcmFormat, m_nPcmSampleRate, 0, NULL); if(m_pSwrCtx == NULL) { fprintf(stderr, "Could not allocate resample context
"
); return false; } if(swr_init(m_pSwrCtx) < 0) { fprintf(stderr, "Could not open resample context
"
); return false; } return true; } void Pcm2AAC::AddData(char *i_pData, int i_nSize) { int ret = 0; int nSampleSize = 0; memcpy(m_pPcmData + m_nPcmSize, i_pData, i_nSize); m_nPcmSize += i_nSize; nSampleSize = av_get_bytes_per_sample(m_ePcmFormat); if(m_nPcmSize <= (nSampleSize * m_nFrameSize * m_nPcmChannel)) { return; } memcpy(m_aPcmPointer[0], m_pPcmData, nSampleSize * m_nFrameSize * m_nPcmChannel); m_nPcmSize -= (nSampleSize * m_nFrameSize * m_nPcmChannel); memcpy(m_pPcmData, m_pPcmData + nSampleSize * m_nFrameSize * m_nPcmChannel, m_nPcmSize); m_pFrame->pts = m_s64Pts; m_s64Pts += m_nFrameSize; // fixme m_pFrame->nb_samples = m_nFrameSize; m_pFrame->format = m_pCodecCtx->sample_fmt; m_pFrame->channel_layout = m_pCodecCtx->channel_layout; m_pFrame->sample_rate = m_pCodecCtx->sample_rate; if(av_frame_get_buffer(m_pFrame, 0) < 0) { fprintf(stderr, "Could not allocate audio data buffers
"
); return ; } // if(swr_convert(m_pSwrCtx, m_pFrame->extended_data, m_pFrame->nb_samples, (const uint8_t**)m_aPcmPointer, m_pFrame->nb_samples) < 0) { fprintf(stderr, "Could not convert input samples (error )
"
); if(m_pFrame != NULL) { av_frame_unref(m_pFrame); } return ; } // ret = avcodec_send_frame(m_pCodecCtx, m_pFrame); if(ret < 0) { fprintf(stderr, "Error sending the frame to the encoder
"
); if(m_pFrame != NULL) { av_frame_unref(m_pFrame); } return; } if(m_pFrame != NULL) { av_frame_unref(m_pFrame); } } void Pcm2AAC::FlushData(void) { // NULL packet, avcodec_send_frame(m_pCodecCtx, NULL); } bool Pcm2AAC::GetData(char *&o_pData, int &o_nSize) { // int ret = avcodec_receive_packet(m_pCodecCtx, m_pPacket); if(ret < 0) { return false; } // AAC ADTS , , ADTS // AAC 7 ADTS AddADTS(m_pPacket->size + ADTS_HEADER_SIZE); m_nFrameCnt++; memcpy(m_pOutData + ADTS_HEADER_SIZE, m_pPacket->data, m_pPacket->size); o_nSize = m_pPacket->size + ADTS_HEADER_SIZE; o_pData = m_pOutData; av_packet_unref(m_pPacket); return true; } // ADTS (Audio Data Transport Stream), AAC void Pcm2AAC::AddADTS(int i_nPktLen) { int nProfile = 1; // AAC LC, int nFreqIdx = 4; // default 44.1kHz int nChanCfg = m_nPcmChannel; if(i_nPktLen > ADTS_MAX_FRAME_BYTES) { fprintf(stderr, "ADTS frame size too large: %d (max %d)
"
, i_nPktLen, ADTS_MAX_FRAME_BYTES); return; } switch(m_nPcmSampleRate) { case 96000: nFreqIdx = 0; break; case 88200: nFreqIdx = 1; break; case 64000: nFreqIdx = 2; break; case 48000: nFreqIdx = 3; break; case 44100: nFreqIdx = 4; break; case 32000: nFreqIdx = 5; break; case 24000: nFreqIdx = 6; break; case 22050: nFreqIdx = 7; break; case 16000: nFreqIdx = 8; break; case 12000: nFreqIdx = 9; break; case 11025: nFreqIdx = 10; break; case 8000: nFreqIdx = 11; break; case 7350: nFreqIdx = 12; break; default: break; } // Fill in ADTS header, 7 bytes m_pOutData[0] = 0xFF; m_pOutData[1] = 0xF1; m_pOutData[2] = ((nProfile) << 6) + (nFreqIdx << 2) + (nChanCfg >> 2); m_pOutData[3] = (((nChanCfg & 3) << 6) + (i_nPktLen >> 11)); m_pOutData[4] = ((i_nPktLen & 0x7FF) >> 3); m_pOutData[5] = (((i_nPktLen & 7) << 5) + 0x1F); m_pOutData[6] = 0xFC; }

main.cppは参照用のみで、詳細はコメントを参照してください.
#include 
#include "Pcm2AAC.h"

int main(int argc, char *argv[])
{
    //    PCM  
    FILE *pInFile = fopen("./in.pcm", "rb");
    //    AAC  
    FILE *pOutFile = fopen("./out.aac", "ab");
    char aFrameBuf[1024] = {0}; // AVCodecContext->frame_size = 1024
    char *pOutData = NULL;
    int nReadSize = 0;
    int nOutSize = 0;
    Pcm2AAC objPcm2AAC;
    bool bEOF = false;

    //      PCM AV_SAMPLE_FMT_S16  (    16 ),    44100,     
    if(!(objPcm2AAC.Init(44100, AV_SAMPLE_FMT_S16, 2)))
    {
        printf("objPcm2AAC Init error
"
); return -1; } printf("converting start
"
); while(true) { nReadSize = fread(aFrameBuf, 1, sizeof(aFrameBuf), pInFile); if(nReadSize > 0) { // PCM objPcm2AAC.AddData(aFrameBuf, nReadSize); } else { // , PCM objPcm2AAC.FlushData(); bEOF = true; } while(true) { // AAC if(!(objPcm2AAC.GetData(pOutData, nOutSize))) { break; } fwrite(pOutData, 1, nOutSize, pOutFile); } if(bEOF) { break; } } printf("converting end
"
); fclose(pOutFile); fclose(pInFile); return 0; }

arm-linux-g++-std=c++11 mainをコンパイルする.cpp Pcm2Aac.cpp -o pcm2aac -I/ffmpeg/include -I./-L/ffmpeg/lib -lpthread -lavdevice -lavformat -lavcodec -lavutil -lswresample
運転~#./pcm2aac m_pCodecCtx->frame_size = 1024 converting start converting end nFramesPerSecond = 43 fFrameTime = 23.26ms This AAC total frames = 2628, duration = 61.12s [aac @ 0xf33350] Qavg: 678.742
得られたaacファイルはPCで再生できます
in.pcmはここで取りに行けますhttps://download.csdn.net/download/cfl927096306/12584097
リファレンスhttps://blog.csdn.net/g0415shenw/article/details/81606813