测试代码来源于: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. 数据结构与算法之比较排序【Java】

    比较排序与非比较排序的对比 常见的快速排序.归并排序.堆排序.冒泡排序等属于比较排序.在排序的最终结果里,元素之间的次序依赖于它们之间的比较.每个数都必须和其他数进行比较,才能确定自己的位置.在冒泡排 ...

  2. install multiple versions of CUDA

    https://www.pugetsystems.com/labs/hpc/How-To-Install-CUDA-10-together-with-9-2-on-Ubuntu-18-04-with- ...

  3. 论文阅读笔记(六)【TCSVT2018】:Semi-Supervised Cross-View Projection-Based Dictionary Learning for Video-Based Person Re-Identification

    Introduction (1)Motivation: ① 现实场景中,给所有视频进行标记是一项繁琐和高成本的工作,而且随着监控相机的记录,视频信息会快速增多,因此需要采用半监督学习的方式,只对一部分 ...

  4. Chrome Extension 记录

    传递选定元素到内容脚本 内容脚本不能直接访问当前选中的元素.但是,任何使用 inspectedWindow.eval 来执行的代码都可以在 DevTools 控制台和命令行的 API 中使用.例如,在 ...

  5. KC开发组官方网站

    KC开发组,简称KC,又叫KC Team,是Kong Che Team(空车开发组)的缩写 是由ordosyz(某乡村小学)的CSP2019退役OIer(信息学奥林匹克竞赛选手) 于2020年2月23 ...

  6. mysql 时间,时间戳,字符串之间相互转换

    时间转字符串 date_format(now(),'%Y-%m-%d') 时间转时间戳 unix_timestamp(now()) 字符串转时间 str_to_date('2020-01-19','% ...

  7. 变量 Variables

    是为了存储(store)程序(program)运算过程中的一些信息(informations),为了方便日后调用.操作和更改 变量名应该简明,见名识意,让读者和我们自己能更清晰的了解 如果我们把变量看 ...

  8. VMware安装centos7与配置网络

    自己想搭建个虚机学习下k8s,使用VMware安装centos7,上不了网,折腾了很久才连上.发现网上很多教程都是错误的或者不明确的,这边写下自己的配置记录 首先安装centos7系统就不赘述了,这边 ...

  9. mysql空数据的处理

    1.统计分析时,统计值为null则转为0 //统计婚姻接口调用次数select count ,(zsj/count) as pjdysjfrom(-- 实时调用量 评论返回时间差(取平均值)selec ...

  10. JNA 使用总结

    JNA 是基于 JNI(Java Native Interface) 技术的开源工具,能够实现单方向的 Java 调用本地方法(通常是 C/C++ 编写的动态链接库中的函数),在 Windows 中是 ...