目录
G.726简介
维基百科:https://en.wikipedia.org/wiki/G.726
以下内容,摘抄于维基百科
G.726是ITU-T ADPCM 语音编解码器标准,涵盖以16、24、32和40 kbit / s的速率传输语音 。它被引入以取代以32 kbit / s的速率覆盖ADPCM的G.721和以24和40 kbit / s的速率描述ADPCM的G.723。G.726还引入了新的16 kbit / s速率。与G.726相关的四个比特率通常由样本的比特大小来指代,分别为2、3、4和5位。基于相同技术的相应宽带编解码器为G.722。
最常用的模式是32 kbit / s,通过使用G.711速率的一半将可用网络容量增加一倍。它主要用于电话网络中的国际中继线上,并且是DECT无线电话系统中使用的标准编解码器。24和16 kbit / s通道的主要应用是用于在数字电路乘法设备(DCME)中承载语音的过载通道。40 kbit / s通道的主要应用是在DCME中传送数据调制解调器信号,尤其是对于工作于4800 bit / s以上的调制解调器。
FFMpeg编解码G.726
参考:https://blog.csdn.net/byxdaz/article/details/78430453
由维基百科中我们得知,G.726包括了little endian和big endian(RFC3551),即小端和大端
对应ffmpeg中的AV_CODEC_ID_ADPCM_G726LE和AV_CODEC_ID_ADPCM_G726
g726文件解码成PCM
/*
* 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 "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavutil/frame.h"
#include "libswscale/swscale.h"
#include "libavutil/imgutils.h"
#define AUDIO_INBUF_SIZE 20480
#define AUDIO_REFILL_THRESH 4096
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 < 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)
{
if(argc != 3)
{
printf("usage:./demo input_file output_file\n");
return 0;
}
AVCodec *codec;
AVCodecContext *c= NULL;
AVPacket avpkt;
AVFrame *decoded_frame = NULL;
avcodec_register_all();
av_init_packet(&avpkt);
/* find the mpeg audio decoder */
codec = avcodec_find_decoder(AV_CODEC_ID_ADPCM_G726LE);
if (!codec)
{
fprintf(stderr, "codec not found\n");
return;
}
c = avcodec_alloc_context3(codec);
//采样率= 8000 每个采样用的bit数= 16 通道数= 1
c->bits_per_coded_sample = 2; //g726 比特率/采样率 = 16Kbit/8KHz = 2
c->channels = 1;
c->sample_fmt = AV_SAMPLE_FMT_S16;
c->sample_rate = 8000;
c->codec_type = AVMEDIA_TYPE_AUDIO;
int iRet = avcodec_open2(c, codec,NULL);
if ( iRet < 0 )
{
fprintf(stderr, "could not open codec\n");
return;
}
char szData[100] = {0};
char szOutData[320] = {0};
int nDataLen = c->bits_per_coded_sample * 20;
int nOutDataLen = 320;
int nReadedSize = 0;
FILE *fp_in = fopen(argv[1],"r");
FILE *fp_out = fopen(argv[2],"w");
while(1)
{
nDataLen = 40;
nReadedSize = fread(szData,sizeof(char),nDataLen,fp_in);
if(nReadedSize < nDataLen)
{
break;
}
avpkt.data = (uint8_t *)szData;
avpkt.size = nDataLen;
int got_frame = 0;
if (!decoded_frame)
{
if (!(decoded_frame = av_frame_alloc()))
{
return;
}
}
else
{
av_frame_unref(decoded_frame);
}
int len = avcodec_decode_audio4(c, decoded_frame, &got_frame, &avpkt);
if (len < 0)
{
return;
}
if (got_frame)
{
/* if a frame has been decoded, output it */
int data_size = av_samples_get_buffer_size(NULL, c->channels,
decoded_frame->nb_samples,
c->sample_fmt, 1);
fwrite(decoded_frame->data[0], 1, data_size, fp_out);
}
}
fclose(fp_in);
fclose(fp_out);
return 0;
}
解码G726 RTP流或者包含G726的avi文件
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavdevice/avdevice.h>
#include <libswresample/swresample.h>
#include <signal.h>
#define MAX_AUDIO_FRAME_SIZE 192000
const char *out_file = "./test.pcm";
static int g_run = 1;
void int_handle(int sig)
{
printf("quit!\n");
g_run = 0;
}
int main()
{
int i = 0;
int ret = 0;
AVFormatContext *fmt_ctx = NULL;
AVCodecContext *dec_ctx = NULL;
AVCodec *dec = NULL;
const char url[64] = "rtsp://admin:ms123456@192.168.2.138:554/main";
// const char url[256] = "rtsp://admin:support2019@192.168.9.205:554/ISAPI/streaming/channels/101";
// const char url[64] = "./g726.avi";
signal(SIGINT,int_handle);
//分配一个avformat
fmt_ctx = avformat_alloc_context();
if (fmt_ctx == NULL)
{
printf("alloc fail");
exit(1);
}
//打开文件,解封装
if (avformat_open_input(&fmt_ctx, url, NULL, NULL) != 0)
{
printf("open fail");
exit(1);
}
//查找文件的相关流信息
if (avformat_find_stream_info(fmt_ctx, NULL) < 0)
{
printf("find stream fail");
exit(1);
}
//输出格式信息
av_dump_format(fmt_ctx, 0, url, 0);
//查找解码信息
int stream_index = -1;
for (i = 0; i < fmt_ctx->nb_streams; i++)
if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
stream_index = i;
printf("audio index------------------%d,codec_id:%d\n",i,fmt_ctx->streams[stream_index]->codecpar->codec_id);
break;
}
if (stream_index == -1)
printf("find stream fail");
printf("AV_CODEC_ID_ADPCM_G726:%d\n",AV_CODEC_ID_ADPCM_G726);
printf("AV_CODEC_ID_ADPCM_G726LE:%d\n",AV_CODEC_ID_ADPCM_G726LE);
printf("AV_CODEC_ID_ADPCM_G722:%d\n",AV_CODEC_ID_ADPCM_G722);
//保存解码器
dec = avcodec_find_decoder(fmt_ctx->streams[stream_index]->codecpar->codec_id);
if (dec == NULL)
printf("find codec fail");
/* create decoding context */
dec_ctx = avcodec_alloc_context3(dec);
if (!dec_ctx)
printf("avcodec_alloc_context3 failed\n");
avcodec_parameters_to_context(dec_ctx, fmt_ctx->streams[stream_index]->codecpar);
//采样率= 8000 每个采样用的bit数= 16 通道数= 1
dec_ctx->bits_per_coded_sample = 2; //g726压缩比为8:1 编码前采样用bit数为那么编码后应该占/8 = 2
dec_ctx->channels = 1;
dec_ctx->sample_fmt = AV_SAMPLE_FMT_S16;
dec_ctx->sample_rate = 8000;
dec_ctx->codec_type = AVMEDIA_TYPE_AUDIO;
if (avcodec_open2(dec_ctx, dec, NULL) < 0)
printf("can't open codec");
FILE *out_fb = NULL;
out_fb = fopen(out_file, "wb");
//创建packet,用于存储解码前的数据
AVPacket *packet = av_packet_alloc();;
av_init_packet(packet);
//设置转码后输出相关参数
int buffer_size = 0;
//注意要用av_malloc
uint8_t *buffer = (uint8_t *)av_malloc(MAX_AUDIO_FRAME_SIZE * 2);
//创建Frame,用于存储解码后的数据
AVFrame *frame = av_frame_alloc();
AVFrame *decoded_frame = NULL;
//while循环,每次读取一帧
while (av_read_frame(fmt_ctx, packet) >= 0 && g_run) {
if (packet->stream_index == stream_index) {
int got_frame = 0;
if (!decoded_frame)
{
if (!(decoded_frame = av_frame_alloc()))
{
return;
}
}
else
{
av_frame_unref(decoded_frame);
}
int len = avcodec_decode_audio4(dec_ctx, decoded_frame, &got_frame, packet);
if (len < 0)
{
return;
}
if (got_frame)
{
/* if a frame has been decoded, output it */
int data_size = av_samples_get_buffer_size(NULL, dec_ctx->channels,
decoded_frame->nb_samples,
dec_ctx->sample_fmt, 1);
printf("nb_samples:%d----------------data_size:%d\n",decoded_frame->nb_samples,data_size);
fwrite(decoded_frame->data[0], 1, data_size, out_fb);
}
}
//release resource
av_packet_unref(packet);
}
av_frame_free(&frame);
av_packet_free(&packet);
fclose(out_fb);
return 0;
}
解码后的PCM可以使用Audacity进行播放
rtsp传输G.726
由该图可知道,当使用比特率为16kbit时,rtpmap为G726-16/8000,以下为抓包结果
VLC播放G.726音频有问题
ffmpeg已经支持G.726大端和小端,但是VLC只支持rtpmap为G726,但是使用标准的G726小端,在VLC中播放声音有问题。将G726编码改为大端后,rtpmap仍然使用小端,这时候播放正常。这应该是VLC没有兼容好的问题