ffmpeg获取rtmp音频

1. 命令行获取rtmp音频并且存储为16K16BIT PCM格式音频

    ./ffmpeg -i "rtmp://live.hkstv.hk.lxdns.com/live/hks" -ar 16000 -ac 1 a.wav

   说明:

   -i  输入

   -ar 采样率

   -ac 声道。 1为单声道,2为双声道。

2. 代码获取

#include 
#include 
#include 
#include 
#include 

// ffmpeg需要相关定义
#define __STDC_CONSTANT_MACROS
#define __STDC_FORMAT_MACROS

#ifndef INT64_C
#define INT64_C(c)  (c ## LL)
#define UINT64_C(c) (c ## ULL)
#endif

#ifdef __cplusplus
extern "C"
{
#endif
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#ifdef __cplusplus
};
#endif

using namespace std;

// rtmp 测试地址,公网可用
static string rtmp_url = "rtmp://live.hkstv.hk.lxdns.com/live/hks";

// 保存音频
void WriteData(int id, const char *data, int data_len)
{
	ostringstream str("");
	str << id << ".pcm";
	FILE *fp = fopen(str.str().c_str(), "ab+");
	if (fp == NULL)
	{
		printf("Open file error!\n");
		return;
	}
	fwrite(data, 1, data_len, fp);
	fclose(fp);
}

int GetVoice(int id)
{
	AVFormatContext *pFormatCtx = NULL;
	AVOutputFormat *fmt = NULL;
	AVStream *audio_st = NULL;
	AVCodecContext *pCodecCtx = NULL;
	AVCodec *pCodec = NULL;

	uint8_t *frame_buf = NULL;
	AVFrame *pFrame = NULL;
	AVPacket pkt;

	int got_frame = 0;
	int ret = 0;
	int size = 0;

	// 打开流
	if ((ret = avformat_open_input(&pFormatCtx, rtmp_url.c_str(), NULL, NULL)) < 0)
	{
		printf("avformat_open_input error!  [ret:%d]\n", ret);
		return -1;
	}

	// 获取音视频信息
	if ((ret = avformat_find_stream_info(pFormatCtx, NULL)) < 0)
	{
		printf("avformat_find_stream_info error! [ret:%d]\n", ret);
		avformat_close_input(&pFormatCtx);
		return -1;
	}

	// 获取音频通道ID
	int audio_index = -1;
	for (int i = 0; i < pFormatCtx->nb_streams; ++i)
	{
		if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
		{
			audio_index = i;
			break;
		}
	}

	if (audio_index == -1)
	{
		printf("Can't find audio_index!\n");
		avformat_close_input(&pFormatCtx);
		return -1;
	}

	//av_dump_format(pFormatCtx, 0, rtmp_url.c_str(), 0);

	pCodecCtx = pFormatCtx->streams[audio_index]->codec;
	// 获取解码器
	pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
	if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
	{
		printf("Codec cannot be found\n");
		avformat_close_input(&pFormatCtx);
		return -1;
	}

	pFrame = av_frame_alloc();
	if (pFrame == NULL)
	{
		printf("av_frame_alloc failed! \n");
		avformat_close_input(&pFormatCtx);
		return -1;
	}

	pFrame->format = pCodecCtx->sample_fmt;
	pFrame->channel_layout = pCodecCtx->channel_layout;
	pFrame->nb_samples = pCodecCtx->frame_size * 2;

	int64_t src_ch_layout = pCodecCtx->channel_layout, dst_ch_layout = AV_CH_LAYOUT_MONO;
	int src_rate = pCodecCtx->sample_rate, dst_rate = 16000, src_nb_channels = 0, dst_nb_channels = 0, dst_linesize;
	int src_nb_samples = pCodecCtx->frame_size, dst_nb_samples, max_dst_nb_samples, dst_bufsize = 0;
	enum AVSampleFormat dst_sample_fmt = AV_SAMPLE_FMT_S16;
	uint8_t ** dst_data = NULL;

	struct SwrContext *swr_ctx = swr_alloc();
	if (swr_ctx == NULL)
	{
		printf("swc_ctx error!");
		avformat_close_input(&pFormatCtx);
		return -1;
	}

	// 设置音频重采样参数
	av_opt_set_int(swr_ctx, "in_channel_layout", src_ch_layout, 0);
	av_opt_set_int(swr_ctx, "in_sample_rate", src_rate, 0);
	av_opt_set_int(swr_ctx, "in_sample_fmt", pCodecCtx->sample_fmt, 0);

	av_opt_set_int(swr_ctx, "out_channel_layout", dst_ch_layout, 0);
	av_opt_set_int(swr_ctx, "out_sample_rate", dst_rate, 0);
	av_opt_set_int(swr_ctx, "out_sample_fmt", dst_sample_fmt, 0);

	if ((ret = swr_init(swr_ctx)) < 0)
	{
		printf("swr_init error!\n");
		swr_free(&swr_ctx);
		avformat_close_input(&pFormatCtx);
		return -1;
	}

	max_dst_nb_samples = dst_nb_samples = av_rescale_rnd(pCodecCtx->channel_layout, dst_rate,
			pCodecCtx->sample_rate, AV_ROUND_UP);
	dst_nb_channels = av_get_channel_layout_nb_channels(dst_ch_layout);
	ret = av_samples_alloc_array_and_samples(&dst_data, &dst_linesize, dst_nb_channels, dst_nb_samples,
			dst_sample_fmt, 0);
	if (ret < 0)
	{
		printf("av_samples_alloc_array_and_samples error! [ret:%d]\n", ret);
		swr_free(&swr_ctx);
		avformat_close_input(&pFormatCtx);
		return -1;
	}

	int count = 0;
	// 获取音频
	while (count < 200)
	{
		if ((ret = av_read_frame(pFormatCtx, &pkt)) < 0)
			break;
		if (pkt.stream_index == audio_index)
		{
			int out_size = 0;
			// 解码
			int len = avcodec_decode_audio4(pCodecCtx, pFrame, &out_size, &pkt);
			if (len < 0)
			{
				printf("decodec error! [len:%d]\n", len);
				av_free_packet(&pkt);
				continue;
			}
			dst_nb_samples = av_rescale_rnd(swr_get_delay(swr_ctx, pCodecCtx->sample_rate) + \
						pCodecCtx->frame_size, dst_rate, pCodecCtx->sample_rate, AV_ROUND_UP);
			if (dst_nb_samples > max_dst_nb_samples)
			{
				av_freep(&dst_data[0]);
				ret = av_samples_alloc(dst_data, &dst_linesize, dst_nb_samples, dst_nb_samples, dst_sample_fmt, 1);
				if (ret < 0)
				{
					av_freep(&dst_data[0]);
					av_free_packet(&pkt);
					swr_free(&swr_ctx);
					av_frame_free(&pFrame);
					avformat_close_input(&pFormatCtx);
					return -1;
				}
				max_dst_nb_samples = dst_nb_samples;
			}
			// 转码
			ret = swr_convert(swr_ctx, dst_data, dst_nb_samples, (const uint8_t **)pFrame->data, pFrame->nb_samples);
			if (ret < 0)
			{
				av_freep(&dst_data[0]);
				av_free_packet(&pkt);
				swr_free(&swr_ctx);
				av_frame_free(&pFrame);
				avformat_close_input(&pFormatCtx);
				return -1;
			}
			dst_bufsize = av_samples_get_buffer_size(&dst_linesize, dst_nb_channels, ret, dst_sample_fmt, 1);
			if (dst_bufsize < 0)
			{
				av_freep(&dst_data[0]);
				av_free_packet(&pkt);
				swr_free(&swr_ctx);
				av_frame_free(&pFrame);
				avformat_close_input(&pFormatCtx);
				return -1;
			}
			WriteData(id, (char *)dst_data[0], dst_bufsize);
			++count;
		}
		av_free_packet(&pkt);
	}
	av_freep(&dst_data[0]);
	av_frame_free(&pFrame);
	swr_free(&swr_ctx);
	avformat_close_input(&pFormatCtx);
	return 0;
}

int main()
{
	// ffmpeg注册, 进程开始时使用
	av_register_all();
	avcodec_register_all();
	avformat_network_init();

	GetVoice(1);
	return 0;
}

示例使用ffmpeg版本为:3.4.2。

完整示例详见:https://download.csdn.net/download/pengwchen/10513929。

你可能感兴趣的:(ffmpeg)