2015-08-05 12 views
3

Я пытаюсь декодировать AAC с FFmpeg родным декодером и обнаружил ошибкуОшибка при расшифровывает AAC с avcodec_decode_audio4()

SSR is not implemeted. Update your FFmpeg version to newest from Git. If the  problem still occurs, it mean that your file has a feature which has not implemented. 

Функции avcodec_decode_audio4() возвращения -1163346256. Это из-за версии FFmpeg? Я загрузил общую и dev-версию с here. Это актуально?

Вот исходный код:

#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 


static void audio_decode_example(const char *outfilename, const char *filename); 


int main(int argc, char *argv[]) { 
    audio_decode_example("D:\\sample.pcm","D:\\sample.m4a"); 
    getch(); 
    return 0; 
} 


/* 
* Audio decoding. 
*/ 
static void audio_decode_example(const char *outfilename, const char *filename) 
{ 
    AVCodec *codec; 
    AVFormatContext *pFormatCtx = NULL; 
    AVCodecContext *pCodecCtxOrig = 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); 

    // Open file to get format context 
    if(avformat_open_input(&pFormatCtx, filename, NULL, NULL)!=0){ 
     printf("Couldn't open file"); 
     return; // Couldn't open file 
    } 

    // Retrieve stream information 
    if(avformat_find_stream_info(pFormatCtx, NULL)<0){ 
     printf("Couldn't find stream information"); 
     return; // Couldn't find stream information 
    } 

    // Dump information about file onto standard error 
    av_dump_format(pFormatCtx, 0, filename, 0); 

    // Find the first audio stream 
    int audioStream = -1; 
    int i =0; 
    for(i=0; i<pFormatCtx->nb_streams; i++) { 
     if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO) { 
      audioStream=i; 
      break; 
     } 
    } 

    if(audioStream==-1) { 
     printf("Didn't find a audio stream"); 
     return; // Didn't find a audio stream 
    } 

    // Get a pointer to the codec context for the audio stream 
    pCodecCtxOrig=pFormatCtx->streams[audioStream]->codec; 

    // Find the decoder for the audio stream 
    codec=avcodec_find_decoder(pCodecCtxOrig->codec_id); 
    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; 
    } 

    if(avcodec_copy_context(pCodecCtx, pCodecCtxOrig) != 0) { 
     fprintf(stderr, "Couldn't copy codec context"); 
     return; // Error copying codec context 
    } 


    /* 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; 
    } 

    /* decode until eof */ 
    avpkt.data = inbuf; 
    avpkt.size = fread(inbuf, 1, AUDIO_INBUF_SIZE, f); 

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

Я также прочитал этот вопрос: How to decode AAC using avcodec_decode_audio4? но не предусмотрено никакого решения.

+0

В вашем аудиовходном файле используется функция, которую декодер еще не поддерживает. Я бы рекомендовал открыть отчет об ошибке и загрузить образец вашего файла, чтобы он мог быть реализован (https://www.ffmpeg.org/bugreports.html). Откуда у вас этот файл/данные/поток? –

+0

Имеет ли SSR здесь значение AAC SSR? Я использовал кодировку файла с профилем AAC LC. Я не могу загрузить файл прямо сейчас, потому что он находится на другом компьютере. Я также пробую с помощью mp2 (получил возврат -1163346256) отсюда: http://www.squee.eclipse.co.uk/samples/ и некоторые mp3 на моем компьютере (отсутствует заголовок ошибки). Что-то не так с исходным кодом? –

ответ

2
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; 
} 

/* decode until eof */ 
avpkt.data = inbuf; 
avpkt.size = fread(inbuf, 1, AUDIO_INBUF_SIZE, f); 

while (avpkt.size > 0) { 
    int i, ch; 
    int got_frame = 0; 

Да, это не будет работать. Вы не можете выгружать необработанные байты из некоторого случайного формата мультиплексирования (потенциально mp4) в декодер и ожидать, что он будет работать. Используйте av_read_frame() для чтения отдельных аудиопакетов из формата мультиплексирования и подачи полученного AVPacket в декодер с помощью avcodec_decode_audio4(). См. dranger api tutorial. Я знаю, что api-example.c использует приведенный выше код, но, к сожалению, работает только в очень ограниченном подмножестве случаев. Также см. Подробное описание в API docs.

+0

Спасибо. Я попробую еще раз. –

+0

Спасибо, я заменил функцию fread на av_read_frame() и теперь это работает. У меня есть еще несколько вопросов, я был бы признателен, если бы вы могли дать мне несколько советов. Вход av_read_frame() - это AVFormatContext, и что, если у меня есть несколько потоков? Как я могу установить тип pcm (s16le, f32be и т. Д.) Для выходного файла .pcm. Я пытаюсь установить AVCodecContext-> sample_fmt, но он получил ошибку. –

+0

Каждый поток (AVStream) в том же файле (AVFormatContext) установит AVPacket.stream_index в индекс этого AVStream внутри массива AVFormatContext-> streams []. Вы не можете установить pcm_type, каждый родной декодер имеет один тип вывода, и это то, что вы получаете. Если вы хотите конвертировать из родного типа вывода в другое, используйте libswresample для преобразования формата (и сэмплирования и канала). –