1. ffmpeg 视频解码一
2. ffmpeg 视频解码二
3. ffmpeg 音频解码一
4. ffmpeg 音频解码二
5. ffmpeg 音视频解码
6. ffmpeg 视频编码一
7. ffmpeg 视频编码一(精简版)
8. ffmpeg 视频编码二(基于 libswscale 转换视频)
9. ffmpeg 过滤器libavfilter的使用
10. ffmpeg 视频编码三(基于 libavfilter 转换视频)

前言

这是ffmpeg的音频解码的第二篇,这篇主要实现一下使用ffmpeg的API实现解码,不使用和上篇的解析器做解析。

音频的基本信息这里不概述,具体可以参照 ffmpeg 音频解码一

流程图


代码流程即如流程图所示,下面讲解一下当中部分函数的作用)。

  1. avformat_open_input
    打开输入文件,并读取文件头相关信息
  2. avformat_find_stream_info
    读取媒体文件信息。
  3. av_find_best_stream
    获取音频流序号(因为文件当中可能既有音频也有视频,字幕等流,我们这里使用这个函数获取视频流的序号)。
  4. avcodec_find_decoder
    获取解码器
  5. avcodec_parameters_to_context
    我们自己构建的解码器并没有设置一些解码相关的参数,此时我们拷贝音频流的参数到里面即可。
  6. av_read_frame
    从视频当中读取数据(一帧),不用和上篇一样,还需要我们使用解析器解析成一帧。
  7. avcodec_send_packet
    发送我们刚刚得到的解析数据到解码器做解码。
  8. avcodec_receive_frame
    获取解码之后的数据。

源码


#pragma once
#define __STDC_CONSTANT_MACROS
#define _CRT_SECURE_NO_WARNINGSextern "C"
{#include <libavformat/avformat.h>
#include "libavcodec/avcodec.h"
}using namespace std;#define INPUT_FILE_NAME "lh_online.aac"
#define OUTPUT_FILE_NAME "lh_online.pcm"static int get_format_from_sample_fmt(const char** fmt,enum AVSampleFormat sample_fmt)
{int i;struct sample_fmt_entry {enum AVSampleFormat sample_fmt; const char* fmt_be, * fmt_le;} sample_fmt_entries[] = {{ AV_SAMPLE_FMT_U8,  "u8",    "u8"    },{ AV_SAMPLE_FMT_S16, "s16be", "s16le" },{ AV_SAMPLE_FMT_S32, "s32be", "s32le" },{ AV_SAMPLE_FMT_FLT, "f32be", "f32le" },{ AV_SAMPLE_FMT_DBL, "f64be", "f64le" },};*fmt = NULL;for (i = 0; i < FF_ARRAY_ELEMS(sample_fmt_entries); i++) {struct sample_fmt_entry* entry = &sample_fmt_entries[i];if (sample_fmt == entry->sample_fmt) {*fmt = AV_NE(entry->fmt_be, entry->fmt_le);return 0;}}av_log(NULL, AV_LOG_ERROR, "sample format %s is not supported as output format\n", av_get_sample_fmt_name(sample_fmt));return -1;
}static void decode(AVCodecContext* dec_ctx, AVFrame* frame, AVPacket* pkt,FILE* ofile)
{int i, ch;int ret, data_size;ret = avcodec_send_packet(dec_ctx, pkt);if (ret < 0) {av_log(NULL, AV_LOG_ERROR, "Error sending a packet for decoding。\n");exit(1);}while (ret >= 0) {ret = avcodec_receive_frame(dec_ctx, frame);if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)return;else if (ret < 0) {av_log(NULL, AV_LOG_ERROR, "Error receive a frame for decoding.\n");exit(1);}printf("frame_number: %d \n", dec_ctx->frame_number);//获取每个采样点当中每个声道的大小data_size = av_get_bytes_per_sample(dec_ctx->sample_fmt);if (data_size < 0) {av_log(NULL, AV_LOG_ERROR, "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, ofile);}}}
}int main(int argc, char* argv[])
{const AVCodec* codec;AVFormatContext* fmt_ctx = NULL;AVCodecContext* c = NULL;AVStream* st;AVFrame* frame;AVPacket* pkt;int ret;int stream_index;FILE* ofile;enum AVSampleFormat sfmt;const char* fmt;//打开输入文件,并为fmt_ctx分配空间if (avformat_open_input(&fmt_ctx, INPUT_FILE_NAME, NULL, NULL)) {av_log(NULL, AV_LOG_ERROR, "Codec not open source file.\n");exit(1);}//获取流信息if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {av_log(NULL, AV_LOG_ERROR, "Could not find stream information.\n");exit(1);}//获取视频流序号(这里我们明确要解码的是视频,也只处理音频)stream_index = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);if (stream_index < 0) {av_log(NULL, AV_LOG_ERROR, "Cannot find stream index\n");exit(1);}//获取文件流st = fmt_ctx->streams[stream_index];//获取解码器(这里不需要我们显示的指定了)codec = avcodec_find_decoder(st->codecpar->codec_id);if (!codec) {av_log(NULL, AV_LOG_ERROR, "Codec not found.\n");exit(1);}//分配解析器上下文c = avcodec_alloc_context3(codec);if (!c) {av_log(NULL, AV_LOG_ERROR, "Could not allocate video codec context.\n");exit(1);}//把输入流的编解码参数复制到我们的解码器上if (avcodec_parameters_to_context(c, st->codecpar) < 0) {av_log(NULL, AV_LOG_ERROR, "Failed to copy %s codec parameters to decoder context\n");exit(1);}//打开解码器if (avcodec_open2(c, codec, NULL) < 0) {av_log(NULL, AV_LOG_ERROR, "Could not open codec.\n");exit(1);}//分配AVPacketpkt = av_packet_alloc();if (!pkt) {exit(1);}//分配AVFrameframe = av_frame_alloc();if (!frame) {exit(1);}//打开输出文件ofile = fopen(OUTPUT_FILE_NAME, "wb+");if (!ofile) {av_log(NULL, AV_LOG_ERROR, "Could not open \s.\n", OUTPUT_FILE_NAME);exit(1);}//从文件读取帧while (av_read_frame(fmt_ctx, pkt) >= 0) {//只处理音频流if (pkt->stream_index == stream_index) {decode(c, frame, pkt, ofile);}av_packet_unref(pkt);}//flush 解码器decode(c, frame, NULL, ofile);//此时就已经解码完了,我们稍后使用ffplay播放下音频//解码出来的pcm数据是没有这些基础数据的,我们需要从元数据获取//打印下基本信息//声道数printf("channels: %d \n", c->channels);//采样率printf("sample_rate: %d  \n", c->sample_rate);//一帧音频所占字节代销printf("buffer: %d  \n", av_samples_get_buffer_size(NULL, c->channels, c->frame_size, c->sample_fmt, 1));//采样格式sfmt = c->sample_fmt;printf("sample_fmt: %s  \n", av_get_sample_fmt_name(sfmt));//如果为planar,转换为packed格式if (av_sample_fmt_is_planar(sfmt)) {const char* packed = av_get_sample_fmt_name(sfmt);sfmt = av_get_packed_sample_fmt(sfmt);}if (get_format_from_sample_fmt(&fmt, sfmt) < 0) {av_log(NULL, AV_LOG_ERROR, "Could not get forma \s.\n", av_get_sample_fmt_name(sfmt));exit(1);}//打印播放命令printf("Play the output audio file with the command:\n""ffplay -f %s -ac %d -ar %d %s\n",fmt, c->channels, c->sample_rate, OUTPUT_FILE_NAME);//资源释放fclose(ofile);avcodec_free_context(&c);av_frame_free(&frame);av_packet_free(&pkt);return 0;
}

执行过程中的一些信息如下:

可见待解码文件是一个 有2个声道,采样率为44100HZ,采样格式为fltp的文件,共有1478帧。
到此,我们的音频就解码完成了。
接下来使用命令播放我们解码出来的音频试试:

ffplay -f f32le -ac 2 -ar 44100 lh_online.pcm

结果:

此时你应该听到和aac音频文件一样的声音。
到此,音频解码的部分就结束了。
接下来将写 从一个包含音视频的文件拆分音频和视频到单独的文件中,之后是重采样,编码,音视频推流等。

ffmpeg 音频解码二相关推荐

  1. ffmpeg 音频解码一

    1. ffmpeg 视频解码一 2. ffmpeg 视频解码二 3. ffmpeg 音频解码一 4. ffmpeg 音频解码二 5. ffmpeg 音视频解码 6. ffmpeg 视频编码一 7. f ...

  2. FFmpeg音频解码流程详解及简单demo参考

    本文主要讲解FFmpeg的音频解码具体流程,API使用.最后再以一个非常简单的demo演示将一个mp3格式的音频文件解码为原始数据pcm文件. 本文主要基于FFmpeg音频解码新接口. 一.FFmpe ...

  3. 深入浅出:FFmpeg 音频解码与处理AVFrame全解析

    深入浅出:FFmpeg 音频解码与处理全解析 一.FFmpeg 简介 1.1 FFmpeg 的历史与发展 1.2 FFmpeg 的主要组成部分 二.音频编解码基础 (Basics of Audio E ...

  4. ffmpeg中音频解码方法(附代码)+ffmpeg音频解码播放速度快的问题(随手笔记,以供查阅)

    最近在做一款取名为变速不变调播放器的时候,解码音频遇到了些问题(ffmpeg音频解码播放速度快的问题),网络上的方法对绝大多数的音视频文件有效,但是对于某些音频会有问题,比如某些ADPCM编码的WAV ...

  5. FFMPEG音频解码浅析

    结合各种资料和自己的理解,估计有些浅显. FFMPEG解码流程: 1. 注册所有容器格式和CODEC: av_register_all() 2. 打开文件: av_open_input_file() ...

  6. FFmpeg音频解码-音频可视化

    最近在做一个音频可视化的业务,网上有Java层的实现方法,但是业务需要用C实现,从原理出发其实很简单,先对音频进行解码,再计算分贝.这比把大象放进冰箱还简单.本文从音频可视化的业务为依托,以FFmpe ...

  7. Android NDK开发之旅31 FFmpeg音频解码

    ###前言 #####基于Android NDK开发之旅30--FFmpeg视频播放这篇文章,我们已经学会视频解码基本过程.这篇文章就对音频解码进行分析. #####音频解码和视频解码的套路基本是一样 ...

  8. FFmpeg - 音频解码过程

    1. 注册所有解码器  av_register_all(); 2. Codec & CodecContext AVCodec* codec = avcodec_find_decoder(COD ...

  9. ffmpeg音频解码重采样(立体声转成单声道)

    https://blog.csdn.net/qq_37003193/article/details/93870141 PCM双声道分离为单声道 https://blog.csdn.net/chinab ...

最新文章

  1. input的readonly属性与TextBox的ReadOnly和Enabled属性区别
  2. C++实现各种选择排序(简单选择排序,堆排序)
  3. set trans 必须是事务处理的第一个语句_MySQL中特别实用的几种SQL语句送给大家
  4. android 豆瓣客户端 视频
  5. python grid函数_(转)Python Tkinter Grid布局管理器详解
  6. python3程序运行中会跳过注释行,Python: 读取文件时如何忽略#条注释行
  7. 【英语学习】【Daily English】U15 Culture L04 When in Rome, do as the Romans Do
  8. IP地址基础和子网规划之其一
  9. Arcgis 重装 的 license 问题
  10. vant-ui的list
  11. 考研数据结构代码总结
  12. snownlp 原理_使用snownlp进行情感分析
  13. 新唐MS51FB9AE串口烧录程序
  14. OSChina 周六乱弹 —— 生命诚可贵,啤酒价更高
  15. Application Server was not connected before run configuration stop, reason: javax.management.Instanc
  16. 单片机60秒秒表c语言,基于51单片机的60秒,秒表计时器
  17. JS_将汉字转换成汉语拼音JS版
  18. Vue之点击收藏与取消收藏
  19. vlookup使用步骤_vlookup怎么用详细步骤 vlookup函数的使用步骤 vlookup教程
  20. 计算机存储器件中运行速度最快,选择题:下列存储器中,存取速度最快的是()...

热门文章

  1. Python---python3.7.0---如何安装PIL
  2. oracle高效设计阅读心得体会_Oracle高效设计_IT教程网
  3. Mysql 安装,及其闪退的问题解决
  4. jQuery-file-upload插件的使用(小实例)
  5. 2022-4-4 基于单片机的MQ2烟雾报警(风吹摇铃 奔赴星海)
  6. 一键安装ghost轻博客
  7. 助力老旧小区安防智能化升级
  8. 修改注册表将日文键盘改成中文键盘
  9. 实用!!服务器监测邮箱报警
  10. 事件10001,10016,10037