QT - WebSockets

QT - WebSockets,第1张

WebSocket 是基于Web的协议,旨在在客户端应用程序和远程主机之间实现双向通信。如果初始握手成功,它将使两个实体来回发送数据。 WebSocket 是应用程序通过较少的网络延迟和最少的数据交换来获取实时数据源的解决方案。

Qt WebSockets 模块提供了C ++和QML接口,这些接口使Qt应用程序充当可以处理 WebSocket 请求的服务器,可以充当从服务器接收的数据的客户端的客户端,或者两者都可以。

要包括模块类的定义,请使用以下指令:

要将QML类型导入到您的应用程序中,请在.qml文件中使用以下import语句:

要链接该模块,请将以下行添加到您的qmake .pro文件中:

Qt WebSockets 使您能够构建支持 WebSocket 的应用程序。它提供了 WebSocket 协议的实现,该协议由IETF(Internet工程任务组)提供,是使用现有Web基础结构进行双向通信的更好替代方案。

从历史上看,需要双向通信或推送通知的Web应用程序必须使用可用的基于HTTP的解决方案。这些解决方案采用了诸如轮询,长轮询和流传输之类的不同技术来克服HTTP协议的局限性,这些协议并非针对此类用例而设计。这导致高网络延迟,不必要的数据交换以及陈旧或旧数据。IETF 的 WebSocket 产品有助于在很大程度上克服这些问题。

如您在图片表示中所看到的,基于 WebSocket 的解决方案由客户端和服务器端组成。大多数流行的Web浏览器(例如Google Chrome,Internet Explorer,Safari等)都提供对 WebSocket 的本地客户端支持。 WebSocket 的服务器端支持使其成为完整的解决方案,从而实现了双向通信。任何具有本地 WebSocket 支持的浏览器都应允许您使用HTML5 WebSocket API 运行基于HTML和JavaScript的简单客户端应用程序。

网页套接字WebSocket 连接开始于初始HTTP兼容握手,这保证向后兼容性,使得 WebSocket 连接可以共享默认HTTP(80)和HTTPS(443)端口。成功握手后,连接将打开以进行数据交换,直到两个实体之一结束连接。

网页套接字WebSocket 协议使用 ws :和 wss :URL方案分别代表不安全和安全的 WebSocket 请求。在初始握手期间,如果检测到代理服务器,则协议会通过向 HTTP CONNECT 代理发布一条语句来尝试建立隧道。尽管已证明在安全连接中使用TLS(传输层安全性)可以更好地工作,但无论请求类型如何,都使用隧道方法来处理代理。

WebSocket 最适合以下情况:

我们努力使用传统方法来实现这些目标的一些示例应用程序例如:即时消息传递,在线游戏,在线股票交易等。

Qt WebSockets 模块提供API,以开发基于 WebSocket 的服务器和客户端应用程序。可以使用这些API的示例是提供股票数据的服务器应用程序,以及当少数股票价格发生变化时注册推送通知的客户端应用程序。

该模块提供API的C ++和QML版本,因此您可以选择适合您需要的替代方法。

客户端应用程序通常依赖于外部服务来获取数据。这些服务提供商中的大多数还不支持 WebSocket ,因此最终需要开发可 可感知WebSocket(WebSocket-aware) 的服务器应用程序以弥合差距。您可以在企业 WebSocket 网关服务(例如云服务)上运行服务器,从而避免了维护承载此类服务所需的必要基础结构的麻烦。

大多数云服务都提供平台即服务(PaaS)后端,该后端可在云上部署和运行服务器应用程序的实例。客户端应用程序可以使用 WebSocket URL 连接到正在运行的服务器并接收数据。

支持

qt客户端实时播放rtsp音频流demo并且无杂音

推流工具使用EasyDarwin

推流直接使用ffmpeg 推流到 EasyDarwin 服务器,音频流取自电脑拾音器,ffmepg指令为:

ffmpeg -f dshow -i audio=“麦克风 (Realtek® Audio)” -codec:a aac -ac 2 -ar 16000 -f rtsp rtsp://10.1.3.170:554/3_a.sdp

至于怎么推流自行百度呀

客户端采用FFMPEG 取流,解析出PCM 音频裸流,在一个线程中接收rtsp流并解析出音频数据,具体代码如下PlayVoicePlayer.c:

#include "playvoiceplayer.h"

#include <QDebug>

PlayVoicePlayer::PlayVoicePlayer(QObject *parent) : QThread(parent)

{

}

void PlayVoicePlayer::startPlay(QString url)

{

qDebug() <<"Video2PCM::startPlay()"

playUrl = url

unGetStream = true

this->start()

}

void PlayVoicePlayer::run()

{

qDebug() <<"Video2PCM::run():"<<playUrl

isStart = true

AVFormatContext *pFormatCtx = NULL

AVCodecContext *pCodecCtx = NULL

AVCodec *pCodec = NULL

AVPacket packet

AVFrame *pAudioFrame = NULL

uint8_t *buffer = NULL

struct SwrContext *audio_convert_ctx = NULL

int got_picture

int audioIndex

int out_buffer_size

av_register_all()

if (avformat_open_input(&pFormatCtx, playUrl.toStdString().data(), NULL, NULL) != 0)

{

emit getPcmStreamStop()

qDebug()<<" Video2PCM Couldn't open an input stream."

return

}

pFormatCtx->probesize = 5 *1024 //使用1000*1024 延时大概是2秒开始开始播放1920*1080使用这个参数暂时没发新崩溃的情况

pFormatCtx->max_analyze_duration = 1 * AV_TIME_BASE

if (avformat_find_stream_info(pFormatCtx, NULL) <0)

{

emit getPcmStreamStop()

qDebug()<<"Video2PCM Couldn't find stream information."

return

}

audioIndex = -1

for (int i = 0i <pFormatCtx->nb_streamsi++)

{

if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)

{

audioIndex = i

break

}

}

if (audioIndex == -1)

{

emit getPcmStreamStop()

qDebug()<<"Video2PCM Couldn't find a audio stream."

return

}

pCodecCtx = pFormatCtx->streams[audioIndex]->codec

pCodec = avcodec_find_decoder(pCodecCtx->codec_id)

if (pCodec == NULL) printf("Codec not found.\n")

if (avcodec_open2(pCodecCtx, pCodec, NULL) <0)

{

emit getPcmStreamStop()

qDebug()<<"Video2PCM Could not open codec."

return

}

pAudioFrame = av_frame_alloc()

if (pAudioFrame == NULL)

{

emit getPcmStreamStop()

qDebug()<<"Video2PCM Could not alloc AVFrame"

return

}

//音频输出参数

uint64_t out_channel_layout = AV_CH_LAYOUT_STEREO//声道格式

AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S32//采样格式

int out_nb_samples = pCodecCtx->frame_size//nb_samples: AAC-1024 MP3-1152

// int out_sample_rate = 44100//采样率

int out_sample_rate = 16000//采样率

int out_nb_channels = av_get_channel_layout_nb_channels(out_channel_layout)//根据声道格式返回声道个数

out_buffer_size = av_samples_get_buffer_size(NULL, out_nb_channels, out_nb_samples, out_sample_fmt, 1)

buffer = (uint8_t *)av_malloc(MAX_AUDIO_FRAME_SIZE)

audio_convert_ctx = swr_alloc()

if (audio_convert_ctx == NULL)

{

{

emit getPcmStreamStop()

qDebug()<<" Video2PCM Could not allocate SwrContext"

return

}

}

swr_alloc_set_opts(audio_convert_ctx, out_channel_layout, out_sample_fmt,out_sample_rate,

pCodecCtx->channel_layout, pCodecCtx->sample_fmt, pCodecCtx->sample_rate, 0, NULL)

swr_init(audio_convert_ctx)

int index = 0//计数器

while (isStart)

{

if(av_read_frame(pFormatCtx, &packet)<0)

{

emit getPcmStreamStop()

break

}

if (packet.stream_index == audioIndex) {

if (avcodec_decode_audio4(pCodecCtx, pAudioFrame, &got_picture, &packet) <0) {

qDebug() <<("Error in decoding audio frame.\n")

emit getPcmStreamStop()

break

}

if (got_picture) {

// int dst_nb_samples = av_rescale_rnd(swr_get_delay(audio_convert_ctx, pAudioFrame->sample_rate) + pAudioFrame->nb_samples, pAudioFrame->sample_rate, pAudioFrame->sample_rate, AVRounding(1))

swr_convert(audio_convert_ctx, &buffer, MAX_AUDIO_FRAME_SIZE, (const uint8_t **)pAudioFrame->data, pAudioFrame->nb_samples)

if(unGetStream == true)

{

qDebug() <<"Video2PCM unGetStream"

unGetStream =false

emit getAudioStream()

}

//printf("index:%5d\t pts:%lld\t packet size:%d\n", index, packet.pts, packet.size)

//Write PCM

//fwrite(buffer, 1, out_buffer_size, fp_pcm)

emit decodePCM(packet.pts, QByteArray((char*)buffer, out_buffer_size))

index++

}

}

av_free_packet(&packet)

}

qDebug() <<"Video2PCM close1"

swr_free(&audio_convert_ctx)

av_free(buffer)

av_frame_free(&pAudioFrame)

avcodec_close(pCodecCtx)

avformat_close_input(&pFormatCtx)

isStart= false

对应的PlayVoicePlayer.h文件如下:

#ifndef PLAYVOICEPLAYER_H

#define PLAYVOICEPLAYER_H

#include <QObject>

#include <QThread>

#ifdef _WINDOWS

extern "C"

{

#include "libavcodec\avcodec.h"

#include "libavformat\avformat.h"

#include "libswresample\swresample.h"

}

#else

extern "C"

{

#include "libavcodec/avcodec.h"

#include "libavformat/avformat.h"

#include "libswresample/swresample.h"

}

#endif

#include <QAudioFormat>

#include <QAudioOutput>

#define MAX_AUDIO_FRAME_SIZE 192000

class PlayVoicePlayer : public QThread

{

Q_OBJECT

public:

explicit PlayVoicePlayer(QObject *parent = nullptr)

void startPlay(QString url)

private:

bool isStart = true

QString playUrl

bool unGetStream

signals:

void getPcmStreamStop()

void getAudioStream()

void decodePCM(qint64 pts, const QByteArray&pcm)

protected:

void run()

}

#endif // PLAYVOICEPLAYER_H

首先你需要使用到以下几个类:

class QNetworkAccessManager;// http网络处理对象

class QNetworkReply;    // http返回应答处理的

calss QNetworkRequest; // 发送http协议请求的

简单举个例子

    用户名和密码添加post内容中

    QString strUserInfo = QString("uname=%1&pwd=%2").arg(editUser->text()).arg(editPassword->text())

    QByteArray  content =  strUserInfo.toUtf8()

    int contentLength = content.length()

    

    QNetworkRequest netReq

    netReq.setUrl(QUrl("you http server addr"))

    netReq.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded")

    netReq.setHeader(QNetworkRequest::ContentLengthHeader, contentLength)

    // 将用户名和密码发送至web服务器进行验证

    QNetworkAccessManager *m_manager = new QNetworkAccessManager(this)

    // 发送参数

    m_manager->post(netReq, content)

    connect(m_manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(SltLoginReplay(QNetworkReply*)))


欢迎分享,转载请注明来源:夏雨云

原文地址:https://www.xiayuyun.com/zonghe/363606.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-11
下一篇2023-05-11

发表评论

登录后才能评论

评论列表(0条)

    保存