简体   繁体   English

在RTP数据包中使用FFmpeg解码AAC

[英]Decode AAC with FFmpeg in RTP packet

I'm trying to decode AAC in RTP packet with FFmpeg. 我正在尝试使用FFmpeg解码RTP数据包中的AAC。 According to rfc document the RTP payload is audioMuxElement mapped directly. 根据rfc文档 ,RTP有效负载直接是audioMuxElement映射的。 I try remove the RTP header and read the remaining bytes to AVPacket struct, but the avcodec_decode_audio4() returning error -1094995529. 我尝试删除RTP标头,并将其余字节读取到AVPacket结构,但是avcodec_decode_audio4()返回错误-1094995529。 Here is the code: 这是代码:

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

I learnt from this question that I should use av_read_frame() instead of fread but I only have RTP payload not a whole file. 我从这个问题中学到,我应该使用av_read_frame()而不是fread,但是我只有RTP有效负载,而不是整个文件。 Is it right to directly map rtp payload to AVPacket struct? 直接将rtp有效负载映射到AVPacket结构是否正确? If not then how should I decode the RTP payload? 如果没有,那么我应该如何解码RTP有效负载?

I ended up using codec AV_CODEC_ID_AAC instead of AV_CODEC_ID_AAC_LATM. 我最终使用了编解码器AV_CODEC_ID_AAC而不是AV_CODEC_ID_AAC_LATM。 After digging into rfc and ISO document, I figured out that the packet is format in LATM but the input packet for AAC Decoder have to be formatted in ADTS, so a bit of parser have to be written here. 在深入研究rfc和ISO文档之后,我发现该数据包是在LATM中格式化的,但是AAC解码器的输入数据包必须在ADTS中格式化,因此这里必须编写一些解析器。 I can't post the code but it's not too hard to write one. 我无法发布代码,但是编写代码并不难。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM