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。