国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

音視頻開(kāi)發(fā)系列(10):基于qt的音頻推流

這篇具有很好參考價(jià)值的文章主要介紹了音視頻開(kāi)發(fā)系列(10):基于qt的音頻推流。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

今天分享一下利用qt錄制音頻,然后再利用ffmpeg推流到nginx服務(wù)器,最后再利用vlc進(jìn)行拉流的demo。

首先介紹一下如何利用qt來(lái)進(jìn)行音頻的錄制,qt的音頻錄制主要利用qt的QAudioFormat先進(jìn)行音頻信息的配置。主要需要配置以下的信息:

QAudioFormat fmt;
	fmt.setSampleRate(sampleRate);// 采樣率, 一秒采集音頻樣本數(shù)量,常設(shè)置為44100
	fmt.setChannelCount(channels);  // 音頻通道數(shù)
	fmt.setSampleSize(16); //一個(gè)音頻數(shù)據(jù)大小
	fmt.setCodec("audio/pcm"); //編碼方式,大多聲卡只支持pcm,也可以通過(guò)獲取參數(shù)得到聲卡支持參數(shù)
	fmt.setByteOrder(QAudioFormat::LittleEndian); // 小端 存儲(chǔ)還是大端存儲(chǔ)
	fmt.setSampleType(QAudioFormat::UnSignedInt); // 數(shù)據(jù)類型,對(duì)應(yīng)的是16位

然后使用QAudioDeviceInfo來(lái)獲取是否支持改設(shè)置信息,如果不支持的話就取其最近的配置。

	QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice();
	if (!info.isFormatSupported(fmt))
	{
		cout << "Audio format not support!" << endl;
		fmt = info.nearestFormat(fmt);
	}

然后再利用QIODevice開(kāi)始錄制音頻,具體的讀取方式如下所示。

		//一次讀取一幀音頻 由于這種方式讀取不準(zhǔn)確,所以僅用來(lái)進(jìn)行判斷
		if (input->bytesReady() < readSize)
		{
			QThread::msleep(1);
			continue;
		}

        int size = 0;
		while (size != readSize)
		{
			int len = io->read(buf + size, readSize - size);
			if (len < 0)break;
			size += len;
		}
		if (size != readSize)continue;

到這里利用qt進(jìn)行音頻的錄制就完成了,接下來(lái)是利用ffmpeg進(jìn)行推流,推流的調(diào)用的函數(shù)和之前視頻推流調(diào)用的api一致,只是一些參數(shù)的配置進(jìn)行了改變。

由于推流時(shí)音頻的格式是AV_SAMPLE_FMT_FLTP,與qt采集到的格式AV_SAMPLE_FMT_S16不一致,所以需要對(duì)采集到的音頻進(jìn)行重采樣。

這邊利用的是ffmpeg的api函數(shù)來(lái)進(jìn)行重采樣,首先需要初始化重采樣的上下文,主要利用

swr_alloc_set_opts()函數(shù),設(shè)置參數(shù)如下:

	SwrContext *asc = NULL;
	asc = swr_alloc_set_opts(asc,
		    av_get_default_channel_layout(channels), AV_SAMPLE_FMT_FLTP, sampleRate,               //輸出格式
		av_get_default_channel_layout(channels), AV_SAMPLE_FMT_S16, sampleRate,//輸入格式	
		0,0);
	if (!asc)
	{	
		cout << "swr_alloc_set_opts failed!"<<endl;
		getchar();
		return -1;
	}

主要是配置輸出和輸入的參數(shù),接著利用swr_init()初始化該上下文。

然后分配好音頻重采樣的輸出空間,配置信息如下:

	AVFrame *pcm = av_frame_alloc();
	pcm->format = outSampleFmt;
	pcm->channels = channels;
	pcm->channel_layout = av_get_default_channel_layout(channels);
	pcm->nb_samples = 1024;//一幀音頻一通道的采樣數(shù)量
	ret = av_frame_get_buffer(pcm, 0); //給pcm分配存儲(chǔ)空間
	if (ret != 0)
	{
		char err[1024] = { 0 };
		av_strerror(ret, err, sizeof(err) - 1);
		cout << err << endl;
		getchar();
		return -1;
	}

然后利用swr_convert()函數(shù)進(jìn)行轉(zhuǎn)化將轉(zhuǎn)化后的數(shù)據(jù)放入pcm中。

接下來(lái)需要對(duì)音頻的pts進(jìn)行運(yùn)算,主要運(yùn)算如下:

		//pts運(yùn)算
		//nb_sample/sample_rate =一幀音頻的秒數(shù) 
		//time_base pts=sec * timebase.den 
		pcm->pts = apts;
		apts += av_rescale_q(pcm->nb_samples, {1,sampleRate},ac->time_base);

接下來(lái)就是對(duì)重采樣后的音頻進(jìn)行推流,這邊與之前視頻推流的一致,具體的參數(shù)配置可以參考我下面分享的代碼:

#include <QtCore/QCoreApplication>
#include <QAudioInput>
#include <QThread>
#include <iostream>
extern "C"
{
#include "libswresample/swresample.h"
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
}
#pragma comment(lib,"avformat.lib")
#pragma comment(lib,"swresample.lib")
#pragma comment(lib,"avutil.lib")
#pragma comment(lib, "avcodec.lib")
using namespace std;
int main(int argc, char *argv[])
{
	QCoreApplication a(argc, argv);

	//注冊(cè)所有的編解碼器
	avcodec_register_all();
	//注冊(cè)所有的封裝器
	av_register_all();
	//注冊(cè)所有的網(wǎng)絡(luò)協(xié)議
	avformat_network_init();
	char *outUrl = "rtmp://192.168.198.128/live";
	int sampleRate = 44100;
	int channels = 2;
	int sampleByte = 2;
	AVSampleFormat inSampleFmt = AV_SAMPLE_FMT_S16;
	AVSampleFormat outSampleFmt = AV_SAMPLE_FMT_FLTP;
	///1 qt音頻開(kāi)始錄制 
	QAudioFormat fmt;
	//采樣頻率
	fmt.setSampleRate(sampleRate);
	//通道數(shù)量
	fmt.setChannelCount(channels);
	//樣本大小
	fmt.setSampleSize(sampleByte *8);
	//格式
	fmt.setCodec("audio/pcm");
	//字節(jié)序
	fmt.setByteOrder(QAudioFormat::LittleEndian);
	fmt.setSampleType(QAudioFormat::UnSignedInt);
	QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice();
	if (!info.isFormatSupported(fmt))
	{
		cout << "Audio format not support!" << endl;
		fmt = info.nearestFormat(fmt);
	}
	cout << "Audio format success" << endl;

	QAudioInput *input = new QAudioInput(fmt);
	//開(kāi)始錄制音頻
	QIODevice *io= input->start();

	///2 音頻重采樣
	SwrContext *asc = NULL;
	asc = swr_alloc_set_opts(asc,
		    av_get_default_channel_layout(channels), AV_SAMPLE_FMT_FLTP, sampleRate,               //輸出格式
		av_get_default_channel_layout(channels), AV_SAMPLE_FMT_S16, sampleRate,//輸入格式	
		0,0);
	if (!asc)
	{	
		cout << "swr_alloc_set_opts failed!"<<endl;
		getchar();
		return -1;
	}
	int ret = swr_init(asc);
	if (ret != 0)
	{
		char err[1024] = { 0 };
		av_strerror(ret, err, sizeof(err) - 1);
		cout << err << endl;
		getchar();
		return -1;
	}
	cout << "音頻重采樣 上下文初始化成功" << endl;

	///3 音頻重采樣輸出空間分配
	AVFrame *pcm = av_frame_alloc();
	pcm->format = outSampleFmt;
	pcm->channels = channels;
	pcm->channel_layout = av_get_default_channel_layout(channels);
	pcm->nb_samples = 1024;//一幀音頻一通道的采樣數(shù)量
	ret = av_frame_get_buffer(pcm, 0); //給pcm分配存儲(chǔ)空間
	if (ret != 0)
	{
		char err[1024] = { 0 };
		av_strerror(ret, err, sizeof(err) - 1);
		cout << err << endl;
		getchar();
		return -1;
	}

	///4 初始化音頻編碼器
	AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
	if (!codec)
	{
		cout << "avcodec_find_encoder failed!" << endl;
		getchar();
		return -1;
	}
	//音頻編碼器上下文
	AVCodecContext *ac = avcodec_alloc_context3(codec);
	if (!ac)
	{
		cout << "avcodec_alloc_context3 failed!" << endl;
		getchar();
		return -1;
	}
	cout << "avcodec_alloc_context3 success!" << endl;
	
	ac->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
	ac->thread_count = 8;

	//音頻的參數(shù)
	ac->bit_rate = 40000;
	ac->sample_rate = sampleRate;
	ac->sample_fmt = AV_SAMPLE_FMT_FLTP;
	ac->channels = channels;
	ac->channel_layout = av_get_default_channel_layout(channels);
	//打開(kāi)編碼器
	ret = avcodec_open2(ac, 0, 0);
	if (ret != 0)
	{
		char err[1024] = { 0 };
		av_strerror(ret, err, sizeof(err) - 1);
		cout << err << endl;
		getchar();
		return -1;
	}
	cout << "avcodec_open2 success!" << endl;

	///5 封裝器和音頻流配置
	//a.創(chuàng)建輸出封裝器上下文
	AVFormatContext *ic = NULL;

	ret = avformat_alloc_output_context2(&ic, 0, "flv", outUrl);
	if (ret != 0)
	{
		char buf[1024] = { 0 };
		av_strerror(ret, buf, sizeof(buf) - 1);
		cout << buf << endl;
		getchar();
		return -1;
	}
	cout << "avformat_alloc_output_context2 success!" << endl;
	//b.添加音頻流
	AVStream *as = avformat_new_stream(ic, NULL);
	if (!as)
	{
		throw exception("avformat_new_stream failed!");
	}
	cout << "avformat_new_stream success!" << endl;
	as->codecpar->codec_tag = 0;
	//從編碼器復(fù)制參數(shù)
	avcodec_parameters_from_context(as->codecpar, ac);
	av_dump_format(ic, 0, outUrl, 1);

	///6 打開(kāi)rtmp的網(wǎng)絡(luò)輸出io
	ret = avio_open(&ic->pb, outUrl, AVIO_FLAG_WRITE);
	if (ret != 0)
	{
		char buf[1024] = { 0 };
		av_strerror(ret, buf, sizeof(buf) - 1);
		cout << buf << endl;
		getchar();
		return -1;
	}
	//寫入封裝頭
	ret = avformat_write_header(ic, NULL);
	if (ret != 0)
	{
		char buf[1024] = { 0 };
		av_strerror(ret, buf, sizeof(buf) - 1);
		cout << buf << endl;
		getchar();
		return -1;
	}
	cout << "avformat_write_header success!" << endl;

	//一次讀取一幀音頻的字節(jié)數(shù)
	int readSize = pcm->nb_samples*channels*sampleByte;
	char *buf = new char[readSize];
	int apts = 0;
	AVPacket pkt = {0};
	for (;;)
	{
		//一次讀取一幀音頻
		if (input->bytesReady() < readSize)
		{
			QThread::msleep(1);
			continue;
		}
		int size = 0;
		while (size != readSize)
		{
			int len = io->read(buf + size, readSize - size);
			if (len < 0)break;
			size += len;
		}
		if (size != readSize)continue;

		const uint8_t *indata[AV_NUM_DATA_POINTERS] = { 0 };
		indata[0] = (uint8_t *)buf;
		//已經(jīng)讀取一幀源數(shù)據(jù)
		//重采樣數(shù)據(jù)
		int len = swr_convert(asc, pcm->data, pcm->nb_samples,//輸出參數(shù),輸出存儲(chǔ)地址,樣本數(shù)
			indata, pcm->nb_samples
			);

		//pts運(yùn)算
		//nb_sample/sample_rate =一幀音頻的秒數(shù) 
		//time_base pts=sec * timebase.den 
		pcm->pts = apts;
		apts += av_rescale_q(pcm->nb_samples, {1,sampleRate},ac->time_base);

		int ret = avcodec_send_frame(ac, pcm);
		if (ret != 0)continue;

		av_packet_unref(&pkt);
		ret = avcodec_receive_packet(ac, &pkt);
		cout << "avcodec_receive_packet   " << ret << endl;
		if (ret != 0)continue;
		cout << pkt.size << " " << flush;

		//推流
		pkt.pts = av_rescale_q(pkt.pts, ac->time_base, as->time_base);
		pkt.dts = av_rescale_q(pkt.dts, ac->time_base, as->time_base);
		pkt.duration= av_rescale_q(pkt.duration, ac->time_base, as->time_base);
		ret = av_interleaved_write_frame(ic, &pkt);
		if (ret == 0)
		{
			cout << "#" << flush;
		}
	}
	delete buf;
	getchar();
	return a.exec();
}

然后在這邊做個(gè)分享,由于我在第一次在函數(shù)?avcodec_receive_packe()沒(méi)有接收返回值,所以導(dǎo)致出現(xiàn)dump的情況,根據(jù)下面的打印可以發(fā)現(xiàn)第一次接收數(shù)據(jù)的時(shí)候返回的是-11,說(shuō)明從緩存區(qū)獲取到的數(shù)據(jù)是有問(wèn)題的,下面還對(duì)其進(jìn)行推流就會(huì)出現(xiàn)錯(cuò)誤的情況,具體的情況分析可以參考這篇文章關(guān)于FFmpeg編碼時(shí),avcodec_receive_packet返回-11的解決辦法_小小菜鳥(niǎo)少少煩惱的博客-CSDN博客_avcodec_receive_packet

音視頻開(kāi)發(fā)系列(10):基于qt的音頻推流

?文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-433942.html

到了這里,關(guān)于音視頻開(kāi)發(fā)系列(10):基于qt的音頻推流的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 音視頻開(kāi)發(fā):音頻編碼原理+采集+編碼實(shí)戰(zhàn)

    音視頻開(kāi)發(fā):音頻編碼原理+采集+編碼實(shí)戰(zhàn)

    消除冗余信息,壓縮量最大,也叫有損壓縮 剔除人耳聽(tīng)覺(jué)范圍外的音頻信號(hào)20Hz以下和20000Hz以上; 去除被掩蔽的音頻信號(hào),信號(hào)的遮蔽可以分為頻域遮蔽和時(shí)域遮蔽; 頻域遮蔽效應(yīng) 屏蔽70分貝以下,20HZ以下,20000HZ以上 屏蔽分貝小,頻率小的聲音 兩個(gè)頻率相近發(fā)出的聲音,

    2024年02月05日
    瀏覽(19)
  • Android 音視頻開(kāi)發(fā)—MediaPlayer音頻與視頻的播放介紹

    Android 音視頻開(kāi)發(fā)—MediaPlayer音頻與視頻的播放介紹

    Android多媒體中的——MediaPlayer,我們可以通過(guò)這個(gè)API來(lái)播放音頻和視頻該類是Androd多媒體框架中的一個(gè)重要組件,通過(guò)該類,我們可以以最小的步驟來(lái)獲取,解碼和播放音視頻。 它支持三種不同的媒體來(lái)源: 本地資源 內(nèi)部的URI,比如你可以通過(guò)ContentResolver來(lái)獲取 外部URL(流

    2024年02月10日
    瀏覽(27)
  • Qt音視頻開(kāi)發(fā)45-音視頻類結(jié)構(gòu)體參數(shù)的設(shè)計(jì)

    Qt音視頻開(kāi)發(fā)45-音視頻類結(jié)構(gòu)體參數(shù)的設(shè)計(jì)

    視頻監(jiān)控內(nèi)核組件重構(gòu)和完善花了一年多時(shí)間,整個(gè)組件個(gè)人認(rèn)為設(shè)計(jì)的最好的部分就是各種結(jié)構(gòu)體參數(shù)的設(shè)計(jì),而且分門別類,有枚舉值,也有窗體相關(guān)的結(jié)構(gòu)體參數(shù),解碼相關(guān)的結(jié)構(gòu)體參數(shù),同時(shí)將部分常用的結(jié)構(gòu)體參數(shù)的獲取和設(shè)置單獨(dú)提供了函數(shù),參閱??荡笕A等大

    2024年02月05日
    瀏覽(29)
  • 安卓音視頻開(kāi)發(fā)(3)—— AudioTrack兩種方式播放pcm音頻

    前言 之前學(xué)習(xí)了AudioRecord錄制pcm音頻,與之對(duì)應(yīng)的就是AudioTrack播放pcm音頻(MediaPlayer、SoundPool有其他應(yīng)用場(chǎng)景),它有兩種數(shù)據(jù)加載模式(MODE_STATIC、MODE_STREAM)。 模式 MODE_STATIC :這種模式下,一次將所有的數(shù)據(jù)放入一個(gè)固定的buffer,然后寫入到AudioTrack中,后續(xù)就不用繼續(xù)

    2023年04月22日
    瀏覽(25)
  • Qt/C++音視頻開(kāi)發(fā)46-音視頻同步保存到MP4

    用ffmpeg單獨(dú)做視頻保存不難,單獨(dú)做音頻保存也不難,難的是音視頻同步保存到MP4中,重點(diǎn)是音視頻要同步,其實(shí)這也不難,只要播放那邊音視頻同步后的數(shù)據(jù),寫入到文件即可。最難的是在播放過(guò)程中不斷隨機(jī)的切換播放進(jìn)度,而且還會(huì)暫停播放、暫停錄制的情況出現(xiàn),這

    2024年02月17日
    瀏覽(38)
  • Qt之基于QMediaPlayer的音視頻播放器(支持常見(jiàn)音視頻格式)

    Qt之基于QMediaPlayer的音視頻播放器(支持常見(jiàn)音視頻格式)

    Qt自帶了一個(gè)Media Player的例子,如下圖所示: 但是運(yùn)行這個(gè)例子機(jī)會(huì)發(fā)現(xiàn),連最基本的MP4格式視頻都播放不了。因?yàn)镼MediaPlayer是個(gè)殼(也可以叫框架),依賴本地解碼器,視頻這塊默認(rèn)基本上就播放個(gè)MP4,甚至連MP4都不能播放,如果要支持其他格式需要下載k-lite或者LAVFilter

    2024年02月02日
    瀏覽(30)
  • Qt音視頻開(kāi)發(fā)38-ffmpeg視頻暫停錄制的設(shè)計(jì)

    Qt音視頻開(kāi)發(fā)38-ffmpeg視頻暫停錄制的設(shè)計(jì)

    基本上各種播放器提供的錄制視頻接口,都是只有開(kāi)始錄制和結(jié)束錄制兩個(gè),當(dāng)然一般用的最多的也是這兩個(gè)接口,但是實(shí)際使用過(guò)程中,還有一種可能需要中途暫停錄制,暫停以后再次繼續(xù)錄制,將中間部分視頻不需要錄制,跳過(guò)這部分不需要的視頻,而且錄制的視頻文件

    2023年04月20日
    瀏覽(25)
  • 音視頻開(kāi)發(fā)之旅——音頻基礎(chǔ)概念、交叉編譯原理和實(shí)踐(LAME的交叉編譯)(Android)

    音視頻開(kāi)發(fā)之旅——音頻基礎(chǔ)概念、交叉編譯原理和實(shí)踐(LAME的交叉編譯)(Android)

    本文章已授權(quán)微信公眾號(hào)郭霖(guolin_blog)轉(zhuǎn)載。 本文主要講解的是 音頻基礎(chǔ)概念 、 交叉編譯原理和實(shí)踐(LAME的交叉編譯) ,是基于 Android平臺(tái) ,示例代碼如下所示: AndroidAudioDemo 另外, iOS平臺(tái) 也有相關(guān)的文章,如下所示: 音視頻開(kāi)發(fā)之旅——音頻基礎(chǔ)概念、交叉編譯

    2024年04月25日
    瀏覽(34)
  • FFMpeg-3、基于QT實(shí)現(xiàn)音視頻播放顯示

    FFMpeg-3、基于QT實(shí)現(xiàn)音視頻播放顯示

    1、音視頻播放的基礎(chǔ)知識(shí) 內(nèi)容來(lái)自雷神博客 1、在Windows平臺(tái)下的視頻播放技術(shù)主要有以下三種:GDI,Direct3D和OpenGL;音頻播放技術(shù)主要是DirectSound。 SDL本身并不具有播放顯示的功能,它只是封裝了底層播放顯示的代碼 記錄三種視頻顯示技術(shù):GDI,Direct3D,OpenGL。其中Direct3D包

    2024年02月03日
    瀏覽(36)
  • 音視頻開(kāi)發(fā)-ffmpeg介紹-系列一

    音視頻開(kāi)發(fā)-ffmpeg介紹-系列一

    目錄 一.簡(jiǎn)介 FFmpeg框架的基本組成包含: 二.?FFmpeg框架梳理音視頻的流程?編輯 基本概念: 三.ffmpeg、ffplay、ffprobe區(qū)別 ? ? ?4.1 ffmpeg是用于轉(zhuǎn)碼的應(yīng)用程序? 4.2?fffplay是用于播放的應(yīng)用程序? ? ? ?4.3?ffprobe是用于查看文件格式的應(yīng)用程序 ? ? ?4.4?ffmpeg是用于轉(zhuǎn)碼的應(yīng)用程

    2024年02月16日
    瀏覽(30)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包