测试代码来源于:http://ffmpeg.org/doxygen/trunk/decode_audio_8c-example.html

/*
* Copyright (c) 2001 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
 
/**
* @file
* audio decoding with libavcodec API example
*
* @example decode_audio.c
*/
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#include <libavutil/mem.h>
 
 
#define AUDIO_INBUF_SIZE 20480
#define AUDIO_REFILL_THRESH 4096
 
{
  int i, ch;
  int ret, data_size;
 
  /* send the packet with the compressed data to the decoder */
  ret = avcodec_send_packet(dec_ctx, pkt);
  if (ret < 0) {
  fprintf(stderr, "Error submitting the packet to the decoder\n");
  exit(1);
  }
 
  /* read all the output frames (in general there may be any number of them */
  while (ret >= 0) {
    ret = avcodec_receive_frame(dec_ctx, frame);
    if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
      return;
    else if (ret < 0) {
      fprintf(stderr, "Error during decoding\n");
      exit(1);
    }
    data_size = av_get_bytes_per_sample(dec_ctx->sample_fmt);
    if (data_size < 0) {
      /* This should not occur, checking just for paranoia */
      fprintf(stderr, "Failed to calculate data size\n");
      exit(1);
    }
    for (i = 0; i < frame->nb_samples; i++)
      for (ch = 0; ch < dec_ctx->channels; ch++)
        fwrite(frame->data[ch] + data_size*i, 1, data_size, outfile);
  }
}
 
int main(int argc, char **argv)
{
  const char *outfilename, *filename;
  const AVCodec *codec;
  AVCodecParserContext *parser = NULL;
  int len, ret;
  FILE *f, *outfile;
  size_t data_size;
  AVFrame *decoded_frame = NULL;
 
  if (argc <= 2) {
    fprintf(stderr, "Usage: %s <input file> <output file>\n", argv[0]);
    exit(0);
  }  
  filename = argv[1];
  outfilename = argv[2];
 
  pkt = av_packet_alloc();
 
  /* find the MPEG audio decoder */
  if (!codec) {
    fprintf(stderr, "Codec not found\n");
    exit(1);
  }
 
  parser = av_parser_init(codec->id);
  if (!parser) {
    fprintf(stderr, "Parser not found\n");
    exit(1);
  }
 
  c = avcodec_alloc_context3(codec);
  if (!c) {
    fprintf(stderr, "Could not allocate audio codec context\n");
    exit(1);
  }
 
  /* open it */
  if (avcodec_open2(c, codec, NULL) < 0) {
    fprintf(stderr, "Could not open codec\n");
    exit(1);
  }
 
  f = fopen(filename, "rb");
  if (!f) {
    fprintf(stderr, "Could not open %s\n", filename);
    exit(1);
  }
  outfile = fopen(outfilename, "wb");
  if (!outfile) {
    av_free(c);
    exit(1);
  }
 
  /* decode until eof */
  data = inbuf;
  data_size = fread(inbuf, 1, AUDIO_INBUF_SIZE, f);
 
  while (data_size > 0) {
    if (!decoded_frame) {
      if (!(decoded_frame = av_frame_alloc())) {
        fprintf(stderr, "Could not allocate audio frame\n");
        exit(1);
      }
    }
 
    ret = av_parser_parse2(parser, c, &pkt->data, &pkt->size,data, data_size,
        AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
    if (ret < 0) {
      fprintf(stderr, "Error while parsing\n");
      exit(1);
    }
    data += ret;
    data_size -= ret;
 
    if (pkt->size)
    decode(c, pkt, decoded_frame, outfile);
 
    if (data_size < AUDIO_REFILL_THRESH) {
      memmove(inbuf, data, data_size);
      data = inbuf;
      len = fread(data + data_size, 1,AUDIO_INBUF_SIZE - data_size, f);
      if (len > 0)
        data_size += len;
    }
  }
 
  /* flush the decoder */
  pkt->data = NULL;
  pkt->size = 0;
  decode(c, pkt, decoded_frame, outfile);
 
  fclose(outfile);
  fclose(f);
 
  av_parser_close(parser);
  av_frame_free(&decoded_frame);
  av_packet_free(&pkt);
 
  return 0;
}
 
 
 
 

需要在sample code加一行avcodec_register_all()

Makefile如下:

export CC=gcc
FFMPEGPATH=/mnt/hgfs/share/ffmpeg-3.3.3/ffmpeg-3.3.3/output
SOURCE=decode_audio.c
INCLUDE=-I$(FFMPEGPATH)/include
LINK=-L$(FFMPEGPATH)/lib/ -lavcodec -lavformat -lavutil -lswresample
LINK+=-lpthread -lm -ldl
TARGET=adecoder
all:
  $(CC) $(SOURCE) $(INCLUDE) $(LINK) -o $(TARGET)

主要函数介绍:

AVPacket *av_packet_alloc(void)

分配并初始化AVPacket结构体,AVPacket是存储压缩编码数据相关信息的结构体。free AVPacket的函数为av_packet_free().

av_packet_alloc只allocate AVPacket本身,并不分配内部data buffer. data buffer 使用其他方式allocate,比如av_new_packet.

AVCodec * avcodec_find_decoder(enum AVCodecID  id)

使用codec ID在已经注册的decoders中查找相应的decoder,如果ffmpeg有注册了相应的decoder,则返回AVCodec结构体,否则返回NULL.AVCodec是存储编解码器信息的结构体.

AVCodecParserContex *av_parser_init(int codec_id)

根据codec id,在已经注册的parser中查找,是否有相关codec的parser,如果存在该codec的parser,则分配AVCodecParserContex结构体。parser用于从raw data中parse出packet.AVCodecParserContex存储parser contex相关信息的结构体,包含AVCodecParser结构体和frame_offset,next_frame_offset等,AVCodecParser存储parser相关信息。

AVCodecContext *avcodec_alloc_context3(const AVCodec *codec)

allocate AVCodecContext 结构体,对AVCodecContext 设置一些default值。AVCodecContext 存储codec contex信息,包含AVCodec结构。

int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options)

使用AVCodec对AVCodecContex进行初始化。

 AVFrame *av_frame_alloc(void)

allocate AVFrame 结构体,并对AVFrame 的Filed设置default值。AVFrame存储解码后的数据。av_frame_alloc只allocate AVFrame本身,并不分配内部data buffer. data buffer 使用其他方式allocate,比如av_frame_get_buffer().

 int av_parser_parse2(AVCodecParserContext *s, AVCodecContext *avctx, uint8_t **poutbuf, int *poutbuf_size,const uint8_t *buf, int buf_size, int64_t pts, int64_t dts, int64_t pos)

调用codec的parser的parser_parse函数从输入的数据buf中 parse一个packet出来。packet的data放到poutbuf, size为poutbuf_size.

int attribute_align_arg avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt)

将parser parse出的raw packet作为输入数据给到decoder解码。如果decoder有send_packet函数则调用该函数,如果没有,则调用avcodec_decode_audio4()进行解码,将解码出来的AVFrame结构保存在avctx->internal->buffer_frame。

如果返回0表示该函数成功返回。如果返回负数AVERROR(EAGAIN),decoder当前状态不接收input数据,用户必须调用avcodec_recieve_frame来读走output数据,一旦output数据被读走,resent packet后就不会返回这样的错误。

int attribute_align_arg avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame)

如果decoder有recieve_frame函数则调用该函数,如果没有该函数,则check avctx->internal->buffer_frame是否有数据,如果有则返回avctx->internal->buffer_frame,没有数据这调用avcodec_decode_audio4()进行解码,将解码出来的AVFrame结构保存在avctx->internal->buffer_frame,并返回AVFrame。

对于video,一个avpkt对应一个video frame,但对于某些audio codec,一个avpkt有多个audio frame.如果有多个audio frame,需要在调用avcodec_send_packet后调用多次avcodec_recieve_frame直到packet完全被消耗,才能send new packet.

 int attribute_align_arg avcodec_decode_audio4(AVCodecContext *avctx,AVFrame *frame,int *got_frame_ptr,const AVPacket *avpkt)

从输入的avpcket解码出audio frame.返回值为负值表示decoder出现error,否则返回消耗avpkt的byte数。

对于一个AVPacket包含多个audio frame的情况,第一调用avcodec_decode_audio4只解码出第一个frame,返回值小于avpkt->size.再call一次avcodec_decode_audio4解码出第二个frame.....即使函数不返回frame,也要将packet送到decoder直至消耗完或返回error.

某些decoder在input 和output有delay,这表示一些packet并不是立即经由decoder解码输出,而需要decoding结束时flush,从而获得所有的解码数据。对于没有delay的decoder,flush也是安全的。flush是通过调用该函数,并将avpkt->data=NULL, avpkt->size=0.

ffmpeg-- audio decoder的更多相关文章

  1. (转)Integrating Intel® Media SDK with FFmpeg for mux/demuxing and audio encode/decode usages 1

    Download Article and Source Code Download Integrating Intel® Media SDK with FFmpeg for mux/demuxing ...

  2. [ffmpeg]deocde audio(v3.3.2)

    /* * Copyright (c) 2001 Fabrice Bellard * * Permission is hereby granted, free of charge, to any per ...

  3. Linux下编译带x264的ffmpeg的配置方法,包含SDL2

    一.环境准备 ffmpeg下载:http://www.ffmpeg.org/download.html x264下载:http://download.videolan.org/x264/snapsho ...

  4. 基于ffmpeg的简单音视频编解码的例子

    近日需要做一个视频转码服务器,对我这样一个在该领域的新手来说却是够我折腾一番,在别人的建议下开始研究开源ffmpeg项目,下面是在代码中看到的一 段例子代码,对我的学习非常有帮助.该例子代码包含音频的 ...

  5. FFmpeg源代码简单分析:configure

    ===================================================== FFmpeg的库函数源代码分析文章列表: [架构图] FFmpeg源代码结构图 - 解码 F ...

  6. 最简单的基于FFMPEG+SDL的音频播放器 ver2 (采用SDL2.0)

    ===================================================== 最简单的基于FFmpeg的音频播放器系列文章列表: <最简单的基于FFMPEG+SDL ...

  7. FFmpeg(9)-解码器解码代码演示(FFmpeg调用MediaCodec实现硬解码、多线程解码、及音视频解码性能测试)

    一.AVFrame 用来存放解码后的数据. [相关函数] AVFrame *frame = av_frame_alloc();                       // 空间分配,分配一个空间 ...

  8. Qt与FFmpeg联合开发指南(一)——解码(1):功能实现

    前言:对于从未接触过音视频编解码的同学来说,使用FFmpeg的学习曲线恐怕略显陡峭.本人由于工作需要,正好需要在项目中使用.因此特地将开发过程总结下来.只当提供给有兴趣的同学参考和学习. 由于FFmp ...

  9. ffmpeg h264+ts +udp传输

    http://bbs.csdn.net/topics/370246456 http://1229363.blog.163.com/blog/static/19743427201001244711137 ...

  10. 最简单的基于FFMPEG+SDL的音频播放器 ver2 (採用SDL2.0)

    ===================================================== 最简单的基于FFmpeg的音频播放器系列文章列表: <最简单的基于FFMPEG+SDL ...

随机推荐

  1. PAT (Advanced Level) Practice 1035 Password (20 分)

    To prepare for PAT, the judge sometimes has to generate random passwords for the users. The problem ...

  2. 【算法】用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。

    public class Solution { Stack<Integer> stack1 = new Stack<Integer>(); Stack<Integer&g ...

  3. 题解 P5712 【【深基3.例4】Apples】

    题目传送门 思路 仔细读题后,我们可以发现,输出可以分成\(2\)种情况,apple加s与apple不加s,所以我们可以使用if/else来实现. 接着,我们读入n. int n; cin>&g ...

  4. Python获取时间范围

    import datetime def dateRange(beginDate, endDate): dates = [] dt = datetime.datetime.strptime(beginD ...

  5. pyecharts包学习笔记

    目录 pyecharts包简介 特性 or 优点 版本 pyecharts包简介 精巧的图表设计.原作者说,当数据分析遇到数据可视化的时候github,该包就诞生了. 可以批量,直观的输出可视化图标吧 ...

  6. 初识压缩感知Compressive Sensing

    压缩感知是近年来极为热门的研究前沿,在若干应用领域中都引起瞩目.最近粗浅地看了这方面一些研究,对于Compressive Sensing有了初步理解,在此分享一些资料与精华.本文针对陶哲轩和Emman ...

  7. [shell脚本] mysql服务启动脚本

    服务启动脚本(初始化.启动.登录) #!/bin/bash export PID=/usr/local/nestdb_master/bin/mysqld export PASSWORD=123456 ...

  8. Wannafly Camp 2020 Day 6M 自闭 - 模拟

    按题意模拟,又乱又烦,没什么可说的 #include <bits/stdc++.h> using namespace std; #define int long long int n,m, ...

  9. 题解 CF409A 【The Great Game】

    题目传送门. 思路: 首先我们定义\(2\)个字符串,分别存放 TEAM 1 与 TEAM 2 的出招顺序.接着再定义\(2\)个变量,存放 TEAM 1 与 TEAM 2 的分数. string s ...

  10. C++中多态实现的关键——虚函数

    1.多态的作用 在面向对象程序设计中,使用多态能够增强代码的可扩充性,,即程序需要增加或修改部分功能时,只需修改少量代码就能够达到目的,此外多态也能起到精简代码的作用. 而实现多态的关键点,就是虚函数 ...