⾳频解码过程

FFmpeg对应流程

关键函数说明:

avcodec_find_decoder:根据指定的AVCodecID查找注册的解码器。

av_parser_init:初始化AVCodecParserContext。

avcodec_alloc_context3:为AVCodecContext分配内存。

avcodec_open2:打开解码器。

av_parser_parse2:解析获得⼀个Packet。

avcodec_send_packet:将AVPacket压缩数据给解码器。

avcodec_receive_frame:获取到解码后的AVFrame数据。

av_get_bytes_per_sample: 获取每个sample中的字节数。

关键数据结构

VCodecParser:⽤于解析输⼊的数据流并把它分成⼀帧⼀帧的压缩编码数据。⽐较形象 的说法就是把⻓⻓的⼀段连续的数据“切割”成⼀段段的数据。

⽐如AAC aac_parser

 从AVCodecParser结构的实例化我们可以看出来,不同编码类型的parser是和CODE_ID进⾏绑定的。所 以也就可以解释

可以通过CODE_ID查找到对应的码流 parser。

avcodec编解码API介绍

FFmpeg提供了两组函数,分别⽤于编码和解码:

解码:avcodec_send_packet()、avcodec_receive_frame()。

编码:avcodec_send_frame()、avcodec_receive_packet()。

代码如下 注释很详细

#include <stdio.h>
#include <stdlib.h>
#include <string.h>#include <libavutil/frame.h>
#include <libavutil/mem.h>#include <libavcodec/avcodec.h>#define AUDIO_INBUF_SIZE 20480
#define AUDIO_REFILL_THRESH 4096static char err_buf[128] = {0};
static char* av_get_err(int errnum)
{av_strerror(errnum, err_buf, 128);return err_buf;
}static void print_sample_format(const AVFrame *frame)
{printf("ar-samplerate: %uHz\n", frame->sample_rate);printf("ac-channel: %u\n", frame->channels);printf("f-format: %u\n", frame->format);// 格式需要注意,实际存储到本地文件时已经改成交错模式
}static void decode(AVCodecContext *dec_ctx, AVPacket *pkt, AVFrame *frame,FILE *outfile)
{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 == AVERROR(EAGAIN)){fprintf(stderr, "Receive_frame and send_packet both returned EAGAIN, which is an API violation.\n");}else if (ret < 0){fprintf(stderr, "Error submitting the packet to the decoder, err:%s, pkt_size:%d\n",av_get_err(ret), pkt->size);
//        exit(1);return;}/* read all the output frames (infile general there may be any number of them */while (ret >= 0){// 对于frame, avcodec_receive_frame内部每次都先调用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);}static int s_print_format = 0;if(s_print_format == 0){s_print_format = 1;print_sample_format(frame);}/**P表示Planar(平面),其数据格式排列方式为 :LLLLLLRRRRRRLLLLLLRRRRRRLLLLLLRRRRRRL...(每个LLLLLLRRRRRR为一个音频帧)而不带P的数据格式(即交错排列)排列方式为:LRLRLRLRLRLRLRLRLRLRLRLRLRLRLRLRLRLRL...(每个LR为一个音频样本)播放范例:   ffplay -ar 48000 -ac 2 -f f32le believe.pcm*/for (i = 0; i < frame->nb_samples; i++){for (ch = 0; ch < dec_ctx->channels; ch++)  // 交错的方式写入, 大部分float的格式输出fwrite(frame->data[ch] + data_size*i, 1, data_size, outfile);}}
}
// 播放范例:   ffplay -ar 48000 -ac 2 -f f32le believe.pcm
int main(int argc, char **argv)
{const char *outfilename;const char *filename;const AVCodec *codec;AVCodecContext *codec_ctx= NULL;AVCodecParserContext *parser = NULL;int len = 0;int ret = 0;FILE *infile = NULL;FILE *outfile = NULL;uint8_t inbuf[AUDIO_INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];uint8_t *data = NULL;size_t   data_size = 0;AVPacket *pkt = NULL;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();enum AVCodecID audio_codec_id = AV_CODEC_ID_AAC;if(strstr(filename, "aac") != NULL){audio_codec_id = AV_CODEC_ID_AAC;}else if(strstr(filename, "mp3") != NULL){audio_codec_id = AV_CODEC_ID_MP3;}else{printf("default codec id:%d\n", audio_codec_id);}// 查找解码器codec = avcodec_find_decoder(audio_codec_id);  // AV_CODEC_ID_AACif (!codec) {fprintf(stderr, "Codec not found\n");exit(1);}// 获取裸流的解析器 AVCodecParserContext(数据)  +  AVCodecParser(方法)parser = av_parser_init(codec->id);if (!parser) {fprintf(stderr, "Parser not found\n");exit(1);}// 分配codec上下文codec_ctx = avcodec_alloc_context3(codec);if (!codec_ctx) {fprintf(stderr, "Could not allocate audio codec context\n");exit(1);}// 将解码器和解码器上下文进行关联if (avcodec_open2(codec_ctx, codec, NULL) < 0) {fprintf(stderr, "Could not open codec\n");exit(1);}// 打开输入文件infile = fopen(filename, "rb");if (!infile) {fprintf(stderr, "Could not open %s\n", filename);exit(1);}// 打开输出文件outfile = fopen(outfilename, "wb");if (!outfile) {av_free(codec_ctx);exit(1);}// 读取文件进行解码data      = inbuf;data_size = fread(inbuf, 1, AUDIO_INBUF_SIZE, infile);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, codec_ctx, &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(codec_ctx, pkt, decoded_frame, outfile);if (data_size < AUDIO_REFILL_THRESH)    // 如果数据少了则再次读取{memmove(inbuf, data, data_size);    // 把之前剩的数据拷贝到buffer的起始位置data = inbuf;// 读取数据 长度: AUDIO_INBUF_SIZE - data_sizelen = fread(data + data_size, 1, AUDIO_INBUF_SIZE - data_size, infile);if (len > 0)data_size += len;}}/* 冲刷解码器 */pkt->data = NULL;   // 让其进入drain modepkt->size = 0;decode(codec_ctx, pkt, decoded_frame, outfile);fclose(outfile);fclose(infile);avcodec_free_context(&codec_ctx);av_parser_close(parser);av_frame_free(&decoded_frame);av_packet_free(&pkt);printf("main finish, please enter Enter and exit\n");return 0;
}

ffmpeg 解码本地无封装裸音频流 AAC MP3 复制代码就可以运行相关推荐

  1. android全平台基于ffmpeg解码本地MP4视频推流到RTMP服务器

    音视频实践学习 android全平台编译ffmpeg以及x264与fdk-aac实践 ubuntu下使用nginx和nginx-rtmp-module配置直播推流服务器 android全平台编译ffm ...

  2. ffmpeg 解码本地裸视频流

    解码本地视频流基本和解码音频流一致 视频解码过程 FFmpeg流程 关键函数啥的就不多说了 直接看我之前解码音频的文章 代码如下 #include <stdio.h> #include & ...

  3. 【Qt+FFmpeg】FFmpeg解码本地视频流程

    目录 一.视频播放器的实现框架 1.解封装(Demuxing) 2.解码(Decode) 3.音视频同步 二.FFmpeg解码视频流程 1.FFmpeg解码视频流程图 2. 代码实现 一.视频播放器的 ...

  4. android推流局域网,android全平台基于ffmpeg解码本地MP4视频推流到RTMP服务器

    音视频实践学习 本文目录 概述 还是先从最简单的搞起来,先从最基本的视频推流开始,要知道在电脑上使用ffmpeg完成推流,简直不要太简单,直接使用ffmpeg的推流命令即可,今天想在android平台 ...

  5. NDK--利用OpenSL ES实现播放FFmpeg解码后的音频流

    OpenSL ES全称为Open Sound Library for Embedded Systems.OpenSL ES是无授权费.跨平台.针对嵌入式系统 精心优化的硬件音频加速API.当然安卓也使 ...

  6. 【Qt学习】 FFmpeg 解码播放本地视频

    目录 一:效果展示 二:源码分享 一:效果展示 二:源码分享 videodecode.h .cpp [解码线程的封装] #ifndef VIDEODECODE_H #define VIDEODECOD ...

  7. ffmpeg 解码音频(aac、mp3)输出pcm文件

    ffmpeg 解码音频(aac.mp3)输出pcm文件 播放pcm可以参考: ffplay -ar 48000 -ac 2 -f f32le out.pcm main.c #include <s ...

  8. 最简单的基于FFMPEG 4.2的封装格式转换器(无编解码MP4转FLV)

    文章目录 最简单的基于FFMPEG 4.2的封装格式转换器(无编解码) 配置 代码 结果 关键函数说明 avformat_open_input avformat_find_stream_info av ...

  9. FFmpeg 解码 AAC 格式的音频

    FFmpeg 默认是可以解码 AAC 格式的音频,但是如果需要获取 PCM16 此类数据则需要经过音频转码.首先要打开解码器,然后向解码器发送 AAC 音频帧(不带 ADTS),然后从解码器获取解码后 ...

最新文章

  1. linux检测网卡步骤,linux网卡检测命令
  2. 更新Android Studio 3.1.1碰到的问题
  3. Ubuntu16.04 修改主机名
  4. About os.path
  5. Android之 FLAG_ACTIVITY_CLEAR_TASK
  6. 一次Nginx负载均衡的安装与配置
  7. mysql启动找不见socket
  8. arp 已知mac找ip_ARP协议修订版
  9. MCU新趋势—Cortex M0/M3/M4 行业应用主题研讨会
  10. python接口自动化 -参数关联(一)
  11. 高效管理之团队梯度建设
  12. Oracle第二财季业绩表现抢眼 | 搜狗推出“唇语识别”技术 | FF宣布完成超10亿美元A轮融资
  13. Codeforces Round #439 (Div. 2) E. The Untended Antiquity
  14. 酒店管理系统-毕业设计
  15. Elasticsearch7.x证书过期简单解决方法
  16. 正负数在计算机中的存储方式
  17. java工程师的薪资真的有那么高吗?
  18. CAS单点登录(十一)——单点退出
  19. 三菱Q系列QJ71C24N模块 MODBUS通信(含完整步骤+源代码)
  20. openwrt用WEB刷固件型号不对问题强行处理

热门文章

  1. 为什么二级菜单会被挡住_多级下来菜单被select挡住的有关问题
  2. 《爱你就像爱生命》读后
  3. 为什么说CRM对B2B企业很重要?
  4. 数据库第十四次作业 电子商城项目
  5. Router Password Kracker(路由器密码破解工具)
  6. 27-TCP 协议(快重传与快恢复)
  7. Boost读写锁:shared_mutex
  8. 使用HTML制作简单的新闻页面
  9. 机器学习读书笔记:半监督学习
  10. [转]IE、FireFox、Chrome浏览器中关于URL传参中文乱码,解决兼容性问题!