在RTP包中用FFmpeg解码AAC

在RTP包中用FFmpeg解码AAC,c,ffmpeg,rtp,aac,C,Ffmpeg,Rtp,Aac,我正在尝试用FFmpeg解码RTP包中的AAC。根据RTP,有效载荷直接映射为音频像素。我尝试删除RTP头并将剩余字节读取到AVPacket struct,但avcodec_decode_audio4()返回错误-1094995529。代码如下: #include "stdafx.h" #include "stdio.h" #include "conio.h" extern "C" { #ifndef __STDC_CONSTANT_MACROS #define __STDC_CONSTA

我正在尝试用FFmpeg解码RTP包中的AAC。根据RTP,有效载荷直接映射为音频像素。我尝试删除RTP头并将剩余字节读取到AVPacket struct,但avcodec_decode_audio4()返回错误-1094995529。代码如下:

#include "stdafx.h"
#include "stdio.h"
#include "conio.h"


extern "C" 
{
#ifndef __STDC_CONSTANT_MACROS
#define __STDC_CONSTANT_MACROS
#endif
#include <libavcodec\avcodec.h>
#include <libavformat\avformat.h>
}


// compatibility with newer API
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1)
#define av_frame_alloc avcodec_alloc_frame
#define av_frame_free avcodec_free_frame
#endif

#define AUDIO_INBUF_SIZE 20480
#define AUDIO_REFILL_THRESH 4096
#define SAMPLE_RATE 44100
#define CHANNEL_NUM 2

static void decode_packet();

int main(int argc, char *argv[]) {
    decode_packet();
    getch();
    return 0;
}



static void decode_packet()
{
    const char *filename = "D:\\NoRTP_AACPacket.dat";
    const char *outfilename = "D:\\test2.pcm";

    AVCodec *codec;
    AVFormatContext   *pFormatCtx = NULL;
    AVCodecContext * pCodecCtx= NULL;
    int len;
    FILE *f, *outfile;
    uint8_t inbuf[AUDIO_INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
    AVPacket avpkt;
    AVFrame *decoded_frame = NULL;

    av_register_all();

    av_init_packet(&avpkt);

    printf("Decode audio file %s to %s\n", filename, outfilename);

    // Find the decoder for the audio stream
    codec=avcodec_find_decoder(AV_CODEC_ID_AAC_LATM);
    if(codec==NULL) {
        fprintf(stderr, "Codec not found\n");
        return; // Codec not found
    }

    pCodecCtx = avcodec_alloc_context3(codec);
    if (!pCodecCtx) {
        fprintf(stderr, "Could not allocate audio codec context\n");
        return;
    }

    pCodecCtx->sample_rate = SAMPLE_RATE;
    pCodecCtx->channels = CHANNEL_NUM;


    /* open it */
    if (avcodec_open2(pCodecCtx, codec, NULL) < 0) {
        fprintf(stderr, "Could not open codec\n");
        return;
    }

    f = fopen(filename, "rb");
    if (!f) {
        fprintf(stderr, "Could not open %s\n", filename);
        return;
    }
    outfile = fopen(outfilename, "wb");
    if (!outfile) {
        av_free(pCodecCtx);
        return;
    }

    avpkt.data = inbuf;
    avpkt.size = fread(inbuf, 1, AUDIO_INBUF_SIZE, f);
    // supposed to do this but don't have AVFormatContext
    // int frReadStt = av_read_frame(pFormatCtx, &avpkt);   

     /* decode until eof */
    while (avpkt.size > 0) {
        int i, ch;
        int got_frame = 0;

        if (!decoded_frame) {
            if (!(decoded_frame = av_frame_alloc())) {
                fprintf(stderr, "Could not allocate audio frame\n");
                return;
            }
        }

        len = avcodec_decode_audio4(pCodecCtx, decoded_frame, &got_frame, &avpkt);
        if (len < 0) {
            fprintf(stderr, "Error while decoding. len = %d \n",len);
            return;
        }
        if (got_frame) {
            /* if a frame has been decoded, output it */
            int data_size = av_get_bytes_per_sample(pCodecCtx->sample_fmt);
            if (data_size < 0) {
                /* This should not occur, checking just for paranoia */
                fprintf(stderr, "Failed to calculate data size\n");
                return;
            }
            for (i=0; i < decoded_frame->nb_samples; i++)
                for (ch=0; ch < pCodecCtx->channels; ch++)
                    fwrite(decoded_frame->data[ch] + data_size*i, 1, data_size, outfile);
        }

        avpkt.size -= len;
        avpkt.data += len;

        avpkt.dts =
        avpkt.pts = AV_NOPTS_VALUE;
        // frReadStt = av_read_frame(pFormatCtx, &avpkt);

        if (avpkt.size < AUDIO_REFILL_THRESH) {
            /* Refill the input buffer, to avoid trying to decode
             * incomplete frames. Instead of this, one could also use
             * a parser, or use a proper container format through
             * libavformat. */
            memmove(inbuf, avpkt.data, avpkt.size);
            avpkt.data = inbuf;
            len = fread(avpkt.data + avpkt.size, 1,
                        AUDIO_INBUF_SIZE - avpkt.size, f);
            if (len > 0)
                avpkt.size += len;
        }
    }

    fclose(outfile);
    fclose(f);

    avcodec_close(pCodecCtx);
    av_free(pCodecCtx);
    av_frame_free(&decoded_frame);

    printf("Finish decode audio file %s to %s\n", filename, outfilename);
}
#包括“stdafx.h”
#包括“stdio.h”
#包括“conio.h”
外部“C”
{
#ifndef uu STDC u常量u宏
#定义\uu STDC\u常量\u宏
#恩迪夫
#包括
#包括
}
//与较新API的兼容性
#如果LIBAVCODEC_VERSION_INT采样率=采样率;
pCodecCtx->channels=CHANNEL\u NUM;
/*打开它*/
if(avcodec_open2(pCodecCtx,codec,NULL)<0){
fprintf(stderr,“无法打开编解码器”\n);
返回;
}
f=fopen(文件名,“rb”);
如果(!f){
fprintf(stderr,“无法打开%s\n”,文件名);
返回;
}
outfile=fopen(outfilename,“wb”);
如果(!outfile){
无av_(PCODECTX);
返回;
}
avpkt.data=inbuf;
avpkt.size=fread(inbuf,1,AUDIO_inbuf_size,f);
//应该这样做,但没有上下文
//int frReadStt=av_读取_帧(pFormatCtx和avpkt);
/*解码到eof*/
而(avpkt.size>0){
int i,ch;
int got_frame=0;
如果(!解码帧){
如果(!(解码帧=av帧匹配()){
fprintf(stderr,“无法分配音频帧”\n);
返回;
}
}
len=avcodec\U decode\U audio4(PCODECTX、解码的\U帧、获取的\U帧和avpkt);
if(len<0){
fprintf(stderr,“解码时出错。len=%d\n”,len);
返回;
}
如果(得到了框架){
/*如果一帧已解码,则将其输出*/
int data_size=av_get_bytes_/样本(pCodecCtx->sample_fmt);
如果(数据大小<0){
/*这不应该发生,只检查偏执狂*/
fprintf(stderr,“无法计算数据大小\n”);
返回;
}
对于(i=0;inb_samples;i++)
对于(ch=0;chchannels;ch++)
fwrite(解码帧->数据[ch]+数据大小*i,1,数据大小,输出文件);
}
avpkt.size-=len;
avpkt.data+=len;
avpkt.dts=
avpkt.pts=AV_NOPTS_值;
//frReadStt=av_读取_帧(pFormatCtx和avpkt);
if(avpkt.size<音频\重新填充\阈值){
/*重新填充输入缓冲区,以避免尝试解码
*不完整的框架。除此之外,还可以使用
*解析器,或通过
*libav格式*/
memmove(inbuf,avpkt.data,avpkt.size);
avpkt.data=inbuf;
len=fread(avpkt.data+avpkt.size,1,
音频尺寸-avpkt.SIZE,f);
如果(len>0)
avpkt.size+=len;
}
}
fclose(输出文件);
fclose(f);
avcodec_关闭(PCODECTX);
无av_(PCODECTX);
无av_帧(&解码_帧);
printf(“完成将音频文件%s解码为%s\n”,文件名,输出文件名);
}

我从中学到我应该使用av_read_frame()而不是fread,但我只有RTP有效负载,而不是整个文件。直接将rtp有效负载映射到AVPacket结构是否正确?如果没有,那么我应该如何解码RTP有效负载

我最终使用了编解码器AV_codec_ID_AAC而不是AV_codec_ID_AAC_LATM。在深入研究rfc和ISO文档后,我发现数据包是LATM格式的,但AAC解码器的输入数据包必须在ADTS中格式化,因此这里必须编写一些解析器。我不能发布代码,但写一个也不难

我最终使用了编解码器AV_codec_ID_AAC而不是AV_codec_ID_AAC_LATM。在深入研究rfc和ISO文档后,我发现数据包是LATM格式的,但AAC解码器的输入数据包必须在ADTS中格式化,因此这里必须编写一些解析器。我不能发布代码,但写一个也不难