1 Star 0 Fork 0

张文超/qtaod-example

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
m3u8parser.h 7.91 KB
一键复制 编辑 原始数据 按行查看 历史
张文超 提交于 2024-10-25 16:58 . 基于qt6的简单播放器
#ifndef M3U8PARSER_H
#define M3U8PARSER_H
#include <QString>
#include <QList>
#include <QVector>
#include <QDebug>
#include <QDir>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>
#include <QtNetwork/QNetworkRequest>
#include <QObject>
enum class NodeStatu {
UNDOWNLOAD = 0,
DOWNLOADING,
DOWNLOADED
};
struct M3u8Node {
int piece_idx; // 分片序号
NodeStatu download_statu;//是否完成下载
QString url; // 分片请求URL
QString path; // 已下载分片的存放路径
float duration; // 分片时长
float stime;
int offset; //播放偏移量,只有在seek跳转的时候才有用
bool is_seek;
M3u8Node():piece_idx(-1){}
M3u8Node(int idx, NodeStatu statu, const QString &u, const QString &p, float d, float s)
: piece_idx(idx)
, download_statu(statu)
, url(u)
, path(p)
, duration(d)
, stime(s)
, offset(0)
, is_seek(false){
qDebug() << "分片: idx=" << idx << "; url=" << u << "; path=" << p << "; duration=" << d << "stime=" << s << "; statu: " << (int)statu;
}
};
class M3u8Parser : public QObject
{
Q_OBJECT
public:
M3u8Parser(const QString &store_path)
:_is_m3u8(false)
,_total_duration(0)
,_piece_count(0)
,_base_store_path(store_path){
createDir(_base_store_path);
}
int duration() {
return _total_duration;
}
int pieceCount() {
return _piece_count;
}
bool piece(int idx, M3u8Node& piece) {
if (idx >= _piece_count) {
qDebug() << "请求的分片ID大于分片总数!" << idx;
return false;
}
piece = _pieces[idx];
return true;
}
void reset() {
_is_m3u8 = false;
_total_duration = 0;
_piece_count = 0;
_version = "";
_pieces.clear();
}
bool hlsRequest(const QString &url){
reset();
qDebug() << "开始请求HLS网络视频:" << url ;
QNetworkRequest request;
request.setUrl(QUrl(url));
QNetworkReply *reply = manager.get(request);
connect(reply, &QNetworkReply::finished, this, [=](){
if (reply->error() != QNetworkReply::NoError) {
qDebug() << "HLS请求失败: " << reply->errorString();
emit hlsRequestFailedSignal(reply->errorString());
return reply->deleteLater();
}
QString res = QString::fromUtf8(reply->readAll());
bool ret = this->parse(res);
if (ret == false) {
emit hlsRequestFailedSignal("请求到的文件非M3U8配置文件!");
return reply->deleteLater();
}
qDebug() << "请求到的M3U8配置文件解析完毕,发送HLS请求成功信号";
emit hlsRequestSuccessSignal();
return reply->deleteLater();
});
return true;
}
bool downloadPiece(int idx) {
if (idx < 0 || idx >= _piece_count) {
qDebug() << "请求下载的分片ID不合法!" << idx;
emit pieceDownloadFailSignal(idx, "视频分片下载失败:分片ID不合法");
return false;
}
if (_pieces[idx].download_statu == NodeStatu::DOWNLOADING) {
qDebug() << "分片正在下载中!" << idx;
return true;
} else if (_pieces[idx].download_statu == NodeStatu::DOWNLOADED) {
qDebug() << "分片已经下载过了!" << idx;
emit pieceDownloadSuccessSignal(idx);
return true;
}
qDebug() << "开始请求下载分片: " << idx;
_pieces[idx].download_statu = NodeStatu::DOWNLOADING;
QNetworkRequest request;
request.setUrl(QUrl(_pieces[idx].url));
QNetworkReply *reply = manager.get(request);
connect(reply, &QNetworkReply::finished, this, [=](){
if (reply->error() != QNetworkReply::NoError) {
qDebug() << "视频分片下载失败: " << reply->errorString();
emit pieceDownloadFailSignal(idx, "视频分片下载失败");
return reply->deleteLater();
}
QFile file(_pieces[idx].path);
if (file.open(QIODevice::WriteOnly) == false){
qDebug() << "打开分片文件失败: " << _pieces[idx].path;
emit pieceDownloadFailSignal(idx, "视频分片存储失败");
return reply->deleteLater();
}
file.write(reply->readAll());
file.close();
qDebug() << "分片下载成功:" << idx;
_pieces[idx].download_statu = NodeStatu::DOWNLOADED;
emit pieceDownloadSuccessSignal(idx);
return reply->deleteLater();
});
return true;
}
bool seek(int pos, M3u8Node &piece) {
if (pos > _total_duration) {
qDebug() << "请求位置大于总时长!";
return false;
}
float tp = pos;
for (int i = 0; i < _pieces.size(); i++) {
if (tp - _pieces[i].duration < 0) {
this->piece(i, piece);
piece.offset = tp;
piece.is_seek = true;
break;
}
tp -= _pieces[i].duration;
}
qDebug() << "跳转位置: pos=" << pos << "; index=" << piece.piece_idx << "; stime=" << piece.stime << "; offset=" << piece.offset;
return true;
}
private:
bool parse(const QString &data){
qDebug() << "开始解析m3u8配置文件!";
createDir(_base_store_path);
const QString m3u8type_filed = "#EXTM3U"; //表示这是个m3u8文件
const QString version_filed = "#EXT-X-VERSION:";
const QString piece_filed = "#EXTINF:"; //指定媒体段的时长
int pos;
QList<QString> list = data.split("\n");
for (int i = 0; i < list.size(); i++) {
QString str = list[i];
if (str == m3u8type_filed) {
_is_m3u8 = true;
} else if ((pos = str.indexOf(version_filed)) != -1) {
_version = str.mid(pos + version_filed.size());
}else if ((pos = str.indexOf(piece_filed)) != -1) {
QString duration = str.mid(pos + piece_filed.size());
if (duration.back() == ',') duration.removeLast();
QString piece_url = list[++i];
QString store_path = _base_store_path + getName(piece_url);
NodeStatu complated = NodeStatu::UNDOWNLOAD;
if (exists(store_path)) complated = NodeStatu::DOWNLOADED;
float fd = duration.toFloat();
M3u8Node node(_piece_count++, complated, piece_url, store_path, fd, _total_duration);
_pieces.push_back(node);
_total_duration += fd;
}
}
qDebug() << "视频总时长:" << _total_duration;
return _is_m3u8;
}
QString getPath(const QString &filename) {
int pos = filename.lastIndexOf('/');
return filename.mid(0, pos);
}
QString getName(const QString &filename) {
int pos = filename.lastIndexOf('/');
if (pos == -1) {
return filename;
}
return filename.mid(pos + 1);
}
bool exists(const QString &filename) {
QFile file(filename);
return file.exists();
}
void createDir(const QString &path) {
QDir dir(path);
if (!dir.exists()) {
dir.mkdir(path);
}
}
signals:
void hlsRequestSuccessSignal();
void hlsRequestFailedSignal(const QString msg);
void pieceDownloadSuccessSignal(int idx);
void pieceDownloadFailSignal(int idx, const QString &msg);
private slots:
private:
QNetworkAccessManager manager;
bool _is_m3u8;
float _total_duration;
int _piece_count;
QString _version;
QString _base_store_path;
QVector<M3u8Node> _pieces;
};
#endif // M3U8PARSER_H
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/qigezi/qtaod-example.git
git@gitee.com:qigezi/qtaod-example.git
qigezi
qtaod-example
qtaod-example
master

搜索帮助

0d507c66 1850385 C8b1a773 1850385