概述

本文基于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编解码示例相关推荐

  1. ASN.1编解码:asn1c-ORAN-E2AP编解码示例

    ASN.1编解码:asn1c-ORAN-E2AP编解码示例 荣涛 2021年9月2日 整体代码:https://gitee.com/rtoax/test/tree/master/ASN.1/asn1c ...

  2. FFmpeg音视频编解码示例

    FFmpeg示例程序集:https://www3.nd.edu/~sjiang1/docio/ffmpeg_doc/globals_eval.html FFmpeg音视频编解码示例:https://w ...

  3. MapBox 矢量数据规格(MVT) C++ 编解码示例

    开发准备: 1)开发环境: CLion 2022.3 2)MapBox 矢量数据规格定义可参见 github MapBox官网 . 开发步骤: 第一步:根据文件 vector_tile.proto 生 ...

  4. G711(PCM/PCMA/PCMU),G721,G723,G729等 音频编解码

    G711,G721,G723音频编解码,G729音频库,Android G711(PCMA/PCMU).G726.PCM音频转码到AAC,ffmpeg接收g723音频流,Android G726语音编 ...

  5. 音频编解码之G711

    <音视频应用开发系列文章目录> G711规定了如何将128kbps的raw pcm信号转为64kbps的g711u/g711a音频信号.本文在前人的基础上封装了G711的编解码算法,有两种 ...

  6. 解码base64_linux C++ Base64编解码

    Base64的由来 目前Base64已经成为网络上常见的传输8Bit字节代码的编码方式之一.在做支付系统时,系统之间的报文交互都需要使用Base64对明文进行转码,然后再进行签名或加密,之后再进行(或 ...

  7. Notepad++插件Base64编解码

    我们平常进行Base64编码需要自己写代码转换, 或者使用其他人编写的小工具程序, 也可以使用在线base64编码工具, 现在我们还可以使用Notepad++自带的插件, 进行Base64编码和解码, ...

  8. g723编解码之自我总结

    其实,很多关于编解码的音视频例子,都是通过文件来进行操作的. 自己做过的(ffmpeg视频编解码.g726编解码.g723编解码)都是从网上找的例子来进行修改的.其中,最难的地方就是在于把文件读取改为 ...

  9. 实验三 LZW编解码算法实现与分析

    LZW简述 本部分参考wiki https://en.wikipedia.org/wiki/Lempel%E2%80%93Ziv%E2%80%93Welch LZW压缩算法在1978年提出,由 Abr ...

最新文章

  1. 分布式一致性(共识)算法(Paxos,raft,ZAB)的一些总结
  2. 总线的数据传输类型(微机接口技术)
  3. “深度学习不能拿来乱用”,Nature论文引发激烈争论
  4. Java 垃圾回收机制,你知多少??
  5. 基于Bootstrap Ace模板+bootstrap.addtabs.js的菜单
  6. android 自定义菜单栏,GitHub - earthWo/AndroidBottomNavigation: android 底部菜单栏,自定义样式,自定义菜单数量,添加滚动动画和水波纹动画...
  7. LeetCode —— 365. 水壶问题(Python3)
  8. ajax中json响应
  9. c语言标准函数模板,c – 标准库容器的通用函数模板
  10. load initialize
  11. 华为认证云服务工程师(HCIA-Cloud Service)-- 练习题1
  12. ESXi Arm Edition version 1.11更新,及安装Win11 Arm版
  13. html页面字体缩小模糊怎么解决,如何解决网页字体模糊的问题
  14. 对给定的10个国家名,按其字母的顺序输出。C++
  15. 盘点人工智能重点技术领域
  16. FileReader 和 FileWriter(Second)
  17. 光纤分类——多模和单模
  18. 32位系统加载不了64位的dll。。。是不是没有为此架构安装?
  19. goland中出现declared but not used 如何解决
  20. 右下角图标不见了的解决办法

热门文章

  1. 产险精算GLM-GAM案例
  2. CountDownLatch - 关于门闩的一个面试题
  3. 2020-04-13起码仗剑走天涯
  4. Aegisub 打K值视频教程+相关插件
  5. 利用MSP430F5529定时器捕获功能,实现信号周期或频率的测量
  6. 集成ShareSDK
  7. 组合逻辑电路——半加器
  8. PHP爬虫音乐,PHP 爬虫———爬取网易云音乐歌单
  9. java动画代码_利用Java制作字符动画实例代码
  10. 二叉树的前、中、后、层次非递归遍历(js)