G711/G726编解码示例
概述
本文基于ffmpeg,演示g711a,g711u,g726,g726le的编码以及编码后的文件如何播放测试。
g711本质还是pcm,不过是将16位带符号pcm数据压缩为8位pcm数据。g711a是取s16le格式的高13位;g711u则是取s16le格式的高14位。实际压缩比是2:1,具体压缩算法可参考如下博客:https://blog.csdn.net/q2519008/article/details/80900838。
编码代码
encode_audio.c :
/*** func: g711a/g711u/g726/g726le encoder.* author: Francis Fan*/#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>#include <libavcodec/avcodec.h>#include <libavutil/channel_layout.h>
#include <libavutil/common.h>
#include <libavutil/frame.h>
#include <libavutil/samplefmt.h>/* check that a given sample format is supported by the encoder */
static int check_sample_fmt(const AVCodec *codec, enum AVSampleFormat sample_fmt)
{const enum AVSampleFormat *p = codec->sample_fmts;while (*p != AV_SAMPLE_FMT_NONE) {if (*p == sample_fmt)return 1;p++;}return 0;
}static void encode(AVCodecContext *ctx, AVFrame *frame, AVPacket *pkt,FILE *output)
{int ret;/* send the frame for encoding */ret = avcodec_send_frame(ctx, frame);if (ret < 0) {fprintf(stderr, "Error sending the frame to the encoder\n");exit(1);}/* read all the available output packets (in general there may be any* number of them */while (ret >= 0) {ret = avcodec_receive_packet(ctx, pkt);if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)return;else if (ret < 0) {fprintf(stderr, "Error encoding audio frame\n");exit(1);}fwrite(pkt->data, 1, pkt->size, output);av_packet_unref(pkt);}
}static char optstr[] = "?i:o:c:r:f:b:t:";static void print_usage(char *name)
{fprintf(stderr, "Usage: \n");fprintf(stderr, "\t%s -i <infile> -o <outfile> -c <channel>"" -r <samplerate> -f <formate> -b <bitrate>""-t <encodertype>\n", name);fprintf(stderr, "Notice: encoder type:\n");fprintf(stderr, "\t[alaw ]:1\n");fprintf(stderr, "\t[mulaw ]:2\n");fprintf(stderr, "\t[g726 ]:3\n");fprintf(stderr, "\t[g726le]:4\n");
}int main(int argc, char **argv)
{const char *outfilename = NULL;const char *infilename = NULL;const AVCodec *codec;AVCodecContext *c= NULL;AVFrame *frame;AVPacket *pkt;int readsize, perframesize;int ret, opt;FILE *fin, *fout;char *inbuff;int bitrate = 64000;int channel = 2;int samplerate = 44100;int sampleformat = AV_SAMPLE_FMT_S16; //s16leint encodertype = 0;opterr = 1;while ((opt = getopt(argc, argv, optstr)) != -1) {switch (opt) {case 'i':infilename = optarg;fprintf(stderr, "input file path: %s\n", infilename);break;case 'o':outfilename = optarg;fprintf(stderr, "output file path: %s\n", outfilename);break;case 'c':channel = atoi(optarg);fprintf(stderr, "input channel: %d\n", channel);break;case 'r':samplerate = atoi(optarg);fprintf(stderr, "input samplerate: %d\n", samplerate);break;case 'f':sampleformat = atoi(optarg);fprintf(stderr, "input sampleformat: %d\n", sampleformat);break;case 'b':bitrate = atoi(optarg);fprintf(stderr, "input bitrate: %d\n", bitrate);break;case 't':encodertype = atoi(optarg);fprintf(stderr, "input encodertype: %d\n", encodertype);break;case '?':default:print_usage(argv[0]);exit(0);}}/* Arguments check */if (!infilename || !outfilename || !encodertype) {print_usage(argv[0]);exit(1);}if ((sampleformat < 1) || (sampleformat > 4)) {fprintf(stderr, "ERROR: invalid encoder type:%d\n", encodertype);print_usage(argv[0]);exit(1);}if (sampleformat != AV_SAMPLE_FMT_S16) {fprintf(stderr, "ERROR: Sample format must be AV_SAMPLE_FMT_S16 for this test!\n");exit(1);}if (((encodertype == 3) || (encodertype == 4)) &&((samplerate > 8000) || (channel != 1) || (bitrate != 16000))) {fprintf(stderr, "ERROR: [G726 or G726LE] input file should be:""channel:1, samplerate:8000, bitrate:16000\n");exit(1);}/* Create encoder */if (encodertype == 1) {fprintf(stderr, "# creating alaw encoder...\n");codec = avcodec_find_encoder(AV_CODEC_ID_PCM_ALAW);} else if (encodertype == 2) {fprintf(stderr, "# creating mulaw encoder...\n");codec = avcodec_find_encoder(AV_CODEC_ID_PCM_MULAW);} else if (encodertype == 3) {fprintf(stderr, "# creating g726 encoder...\n");codec = avcodec_find_encoder(AV_CODEC_ID_ADPCM_G726);} else if (encodertype == 4) {fprintf(stderr, "# creating g726le encoder...\n");codec = avcodec_find_encoder(AV_CODEC_ID_ADPCM_G726LE);}if (!codec) {fprintf(stderr, "ERROR: Codec not found!\n");exit(1);}c = avcodec_alloc_context3(codec);if (!c) {fprintf(stderr, "ERROR: Could not allocate audio codec context\n");exit(1);}/* put sample parameters */c->bit_rate = bitrate;/* check that the encoder supports s16 pcm input */c->sample_fmt = AV_SAMPLE_FMT_S16;if (!check_sample_fmt(codec, c->sample_fmt)) {fprintf(stderr, "ERROR: Encoder does not support sample format %s",av_get_sample_fmt_name(c->sample_fmt));exit(1);}c->sample_rate = samplerate;c->channels = channel;if (channel == 1)c->channel_layout = AV_CH_LAYOUT_MONO;else if (channel == 2)c->channel_layout = AV_CH_LAYOUT_STEREO;#if 0if ((encodertype == 3) || (encodertype == 4))c->bits_per_coded_sample = 2;
#endiffprintf(stderr, "### INFO: sample_rate:%d\n", c->sample_rate);fprintf(stderr, "### INFO: channels:%d\n", c->channels);/* open it */if (avcodec_open2(c, codec, NULL) < 0) {fprintf(stderr, "Could not open codec\n");exit(1);}fprintf(stderr, "### INFO: frame_size:%d\n", c->frame_size);fprintf(stderr, "### INFO: bits_per_coded_sample:%d\n", c->bits_per_coded_sample);fin = fopen(infilename, "rb");if (!fin) {fprintf(stderr, "Could not open input: %s\n", infilename);exit(1);}fout = fopen(outfilename, "wb");if (!fout) {fprintf(stderr, "Could not open output: %s\n", outfilename);exit(1);}/* packet for holding encoded output */pkt = av_packet_alloc();if (!pkt) {fprintf(stderr, "could not allocate the packet\n");exit(1);}/* frame containing input raw audio */frame = av_frame_alloc();if (!frame) {fprintf(stderr, "Could not allocate audio frame\n");exit(1);}if (c->frame_size == 0) {fprintf(stderr, "# Codec has no default frame_size, set 1024 default\n");c->frame_size = 1024;}perframesize = c->channels * av_get_bytes_per_sample(c->sample_fmt);fprintf(stderr, "### INFO: perframesize:%d\n", perframesize);inbuff = (char *)malloc(c->frame_size * perframesize);if (!inbuff) {fprintf(stderr, "ERROR: no space left!\n");exit(1);}printf("+++ FLC-DBG: readsize:%d\n", c->frame_size * perframesize);while (1) {readsize = fread(inbuff, 1, c->frame_size * perframesize, fin);if (readsize <= 0) {fprintf(stderr, "# Get the end of file! error:%s\n", strerror(errno));break;}fprintf(stderr, "# encoder %d size...\n", readsize);frame->nb_samples = readsize / perframesize;ret = avcodec_fill_audio_frame(frame, c->channels, c->sample_fmt, (unsigned char *)inbuff, readsize, 1);if (ret < 0) {fprintf(stderr, "ERROR: fill audio frame failed!\n");break;}encode(c, frame, pkt, fout);}/* flush the encoder */encode(c, NULL, pkt, fout);free(inbuff);fclose(fin);fclose(fout);av_frame_free(&frame);av_packet_free(&pkt);avcodec_free_context(&c);return 0;
}
编码演示
使用说明:
g711a
编码:
encode_audio -i test8000.pcm -r 8000 -c 1 -o test.alaw -t 1
播放:
ffplay -ar 8000 -channels 1 -f alaw -i test.alaw -nod isp
g711u
编码:encode_audio -i test8000.pcm -r 8000 -c 1 -o test.ulaw -t 2
播放:
ffplay -ar 8000 -channels 1 -f mulaw -i test.ulaw -nod isp
g726
encode_audio -i test8000.pcm -r 8000 -c 1 -o test.g726 -t 3
播放:
由于ffplay播放码率为32kbps,编码器要求的编码码率只能为16kbps,因此使用ffplay播放失败。可使用下面章节的解码程序对test.g726进行解码然后再进行pcm的播放。注意:
g726要求必须是采样率:8k,单通道,16kbps的音频数据。本文使用S16LE格式进行测试,其他格式是否支持尚未深究。
解码代码
decode_audio.c: 仅支持G726解码。
/*** func: Only decode G726 file.* author: Francis Fan*/#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 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 < 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;AVCodecContext *c= NULL;AVCodecParserContext *parser = NULL;int len, ret;FILE *f, *outfile;uint8_t inbuf[AUDIO_INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];uint8_t *data;size_t data_size;AVPacket *pkt;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 */codec = avcodec_find_decoder(AV_CODEC_ID_ADPCM_G726);if (!codec) {fprintf(stderr, "Codec not found\n");exit(1);}c = avcodec_alloc_context3(codec);if (!c) {fprintf(stderr, "Could not allocate audio codec context\n");exit(1);}c->bits_per_coded_sample = 2; //g726压缩比为8:1 编码前采样用bit数为那么编码后应该占/8 = 2c->channels = 1;c->sample_fmt = AV_SAMPLE_FMT_S16;c->sample_rate = 8000;c->codec_type = AVMEDIA_TYPE_AUDIO;c->bit_rate = 16000;/* 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);}while (1) {if (!decoded_frame) {if (!(decoded_frame = av_frame_alloc())) {fprintf(stderr, "Could not allocate audio frame\n");exit(1);}}data = inbuf;data_size = fread(inbuf, 1, AUDIO_INBUF_SIZE, f);if (data_size <= 0) {printf("INFO: Get end of the file\n");break;}pkt->data = (uint8_t *)inbuf;pkt->size = data_size;if (pkt->size)decode(c, pkt, decoded_frame, outfile);}/* flush the decoder */pkt->data = NULL;pkt->size = 0;decode(c, pkt, decoded_frame, outfile);fclose(outfile);fclose(f);avcodec_free_context(&c);av_frame_free(&decoded_frame);av_packet_free(&pkt);return 0;
}
解码演示
decode_audio test.g726 g726.pcm
注:有些设备不支持mono pcm,可使用ffplay播放或者pull出源文件,使用Audacity播放。
G711/G726编解码示例相关推荐
- ASN.1编解码:asn1c-ORAN-E2AP编解码示例
ASN.1编解码:asn1c-ORAN-E2AP编解码示例 荣涛 2021年9月2日 整体代码:https://gitee.com/rtoax/test/tree/master/ASN.1/asn1c ...
- FFmpeg音视频编解码示例
FFmpeg示例程序集:https://www3.nd.edu/~sjiang1/docio/ffmpeg_doc/globals_eval.html FFmpeg音视频编解码示例:https://w ...
- MapBox 矢量数据规格(MVT) C++ 编解码示例
开发准备: 1)开发环境: CLion 2022.3 2)MapBox 矢量数据规格定义可参见 github MapBox官网 . 开发步骤: 第一步:根据文件 vector_tile.proto 生 ...
- G711(PCM/PCMA/PCMU),G721,G723,G729等 音频编解码
G711,G721,G723音频编解码,G729音频库,Android G711(PCMA/PCMU).G726.PCM音频转码到AAC,ffmpeg接收g723音频流,Android G726语音编 ...
- 音频编解码之G711
<音视频应用开发系列文章目录> G711规定了如何将128kbps的raw pcm信号转为64kbps的g711u/g711a音频信号.本文在前人的基础上封装了G711的编解码算法,有两种 ...
- 解码base64_linux C++ Base64编解码
Base64的由来 目前Base64已经成为网络上常见的传输8Bit字节代码的编码方式之一.在做支付系统时,系统之间的报文交互都需要使用Base64对明文进行转码,然后再进行签名或加密,之后再进行(或 ...
- Notepad++插件Base64编解码
我们平常进行Base64编码需要自己写代码转换, 或者使用其他人编写的小工具程序, 也可以使用在线base64编码工具, 现在我们还可以使用Notepad++自带的插件, 进行Base64编码和解码, ...
- g723编解码之自我总结
其实,很多关于编解码的音视频例子,都是通过文件来进行操作的. 自己做过的(ffmpeg视频编解码.g726编解码.g723编解码)都是从网上找的例子来进行修改的.其中,最难的地方就是在于把文件读取改为 ...
- 实验三 LZW编解码算法实现与分析
LZW简述 本部分参考wiki https://en.wikipedia.org/wiki/Lempel%E2%80%93Ziv%E2%80%93Welch LZW压缩算法在1978年提出,由 Abr ...
最新文章
- 分布式一致性(共识)算法(Paxos,raft,ZAB)的一些总结
- 总线的数据传输类型(微机接口技术)
- “深度学习不能拿来乱用”,Nature论文引发激烈争论
- Java 垃圾回收机制,你知多少??
- 基于Bootstrap Ace模板+bootstrap.addtabs.js的菜单
- android 自定义菜单栏,GitHub - earthWo/AndroidBottomNavigation: android 底部菜单栏,自定义样式,自定义菜单数量,添加滚动动画和水波纹动画...
- LeetCode —— 365. 水壶问题(Python3)
- ajax中json响应
- c语言标准函数模板,c – 标准库容器的通用函数模板
- load initialize
- 华为认证云服务工程师(HCIA-Cloud Service)-- 练习题1
- ESXi Arm Edition version 1.11更新,及安装Win11 Arm版
- html页面字体缩小模糊怎么解决,如何解决网页字体模糊的问题
- 对给定的10个国家名,按其字母的顺序输出。C++
- 盘点人工智能重点技术领域
- FileReader 和 FileWriter(Second)
- 光纤分类——多模和单模
- 32位系统加载不了64位的dll。。。是不是没有为此架构安装?
- goland中出现declared but not used 如何解决
- 右下角图标不见了的解决办法