G726编解码处理(ffmpeg,rtsp)

目录

G.726简介

FFMpeg编解码G.726

rtsp传输G.726

VLC播放G.726音频有问题


G.726简介

维基百科:https://en.wikipedia.org/wiki/G.726

以下内容,摘抄于维基百科

G.726ITU-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以上的调制解调器

  • 采样频率8 kHz
  • 提供16 kbit / s,24 kbit / s,32 kbit / s,40 kbit / s比特率
  • 生成一个比特流,因此帧长度由下式确定分组时间(通常为80个采样为10  毫秒的帧大小)
  • 典型算法延迟为0.125 ms,无提前延迟
  • G.726是使用自适应差分脉冲编码调制(ADPCM)的波形语音编码器

 

FFMpeg编解码G.726

参考:https://blog.csdn.net/byxdaz/article/details/78430453

由维基百科中我们得知,G.726包括了little endian和big endian(RFC3551),即小端和大端

对应ffmpeg中的AV_CODEC_ID_ADPCM_G726LEAV_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没有兼容好的问题

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值