#include "tools.h" #include "cfg.h" #include "globaldefine.h" #include "wProgramManager/pagelistitem.h" #include "base/x_uimsgboxok.h" #include #include #include #include #include extern "C"{ #include #include #include } void Tools::timerEvent(QTimerEvent *event) { if(timer_id==event->timerId()) emit sTick(); } Tools* Tools::getInstance() { static const auto ins = new Tools(qApp); return ins; } QRectF Tools::centerRect(qreal width, qreal height, int maxW, int maxH) { if(maxW < width || maxH < height) { auto rate = qMin(maxW / width, maxH / height); width *= rate; height *= rate; } return QRectF((maxW - width) / 2, (maxH - height) / 2, width, height); } QString Tools::addSufix(QString path) { int i = path.lastIndexOf('.'); QString prefix = path, sufix; if(i > 0 && i > path.lastIndexOf('/')+1 && i >= path.length()-9) { prefix = path.left(i); sufix = path.mid(i); } i = 1; while(QFileInfo::exists(path = prefix+QString::number(i)+sufix)) i++; return path; } QString Tools::videoInfo(QByteArray url, QImage &img, int64_t *dur, AVCodecID *codec_id) { AVFormatContext *fmt_ctx = avformat_alloc_context(); QString err; { if(avformat_open_input(&fmt_ctx, url.constData(), nullptr, nullptr) != 0) { err = "Couldn't open input stream"; goto free; } if(avformat_find_stream_info(fmt_ctx, nullptr) < 0) { err = "Couldn't find stream information"; goto free; } if(dur!=nullptr) *dur = fmt_ctx->duration; int vi_idx = -1; for(uint ss=0; ssnb_streams; ss++) if(fmt_ctx->streams[ss]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) vi_idx = ss; if(vi_idx == -1) { err = "Didn't find a Video Stream"; goto free; } auto codecpar = fmt_ctx->streams[vi_idx]->codecpar; if(codec_id!=nullptr) *codec_id = codecpar->codec_id; qDebug()<<"codec_id"<codec_id<codec_id); if(av_seek_frame(fmt_ctx, -1, 1000000, AVSEEK_FLAG_BACKWARD) < 0) { err = "av_seek_frame fail"; goto free; } const AVCodec *decoder = avcodec_find_decoder(codecpar->codec_id); if(decoder==nullptr) { err = "Could not found Video Decoder"; goto free; } auto vcCtx = avcodec_alloc_context3(decoder); avcodec_parameters_to_context(vcCtx, codecpar); if(avcodec_open2(vcCtx, decoder, nullptr) < 0) { err = "Could not open Video Codec Ctx"; avcodec_free_context(&vcCtx); goto free; } auto sws_ctx = sws_getContext(vcCtx->width, vcCtx->height, vcCtx->pix_fmt, vcCtx->width, vcCtx->height, AV_PIX_FMT_RGB32, SWS_FAST_BILINEAR, nullptr, nullptr, nullptr); auto packet = av_packet_alloc(); auto frm = av_frame_alloc(); while(1) { if(av_read_frame(fmt_ctx, packet) < 0) break; if(packet->stream_index != vi_idx) continue; int res = avcodec_send_packet(vcCtx, packet); if(res < 0) break; while((res = avcodec_receive_frame(vcCtx, frm)) != AVERROR(EAGAIN)) { if(res < 0) goto free2; img = QImage(vcCtx->width, vcCtx->height, QImage::Format_ARGB32); uint8_t *dst[4]{img.bits()}; int dstStride[4]{img.bytesPerLine()}; sws_scale(sws_ctx, frm->data, frm->linesize, 0, vcCtx->height, dst, dstStride); goto free2; } } free2: av_frame_free(&frm); av_packet_free(&packet); avcodec_free_context(&vcCtx); sws_freeContext(sws_ctx); } free: avformat_close_input(&fmt_ctx); return err; } QString trans(int sw, int sh, int dw, int dh, int cnt, QPointF pos, QByteArray file) { AVFormatContext *in_fmt = avformat_alloc_context(), *out_fmt = 0; AVCodecContext *de_ctx = 0, *en_ctx = 0; QString err; char buf[AV_ERROR_MAX_STRING_SIZE]; int ret; { if((ret = avformat_open_input(&in_fmt, file.constData(), nullptr, nullptr)) < 0) { err = QString("Couldn't open input stream. ")+av_strerror(ret, buf, AV_ERROR_MAX_STRING_SIZE); goto free; } if((ret = avformat_find_stream_info(in_fmt, nullptr)) < 0) { err = QString("Couldn't find stream information. ")+av_strerror(ret, buf, AV_ERROR_MAX_STRING_SIZE); goto free; } auto outfile = file+"-square.mp4"; if((ret = avformat_alloc_output_context2(&out_fmt, 0, "mp4", outfile.constData())) < 0) { err = QString("avformat_alloc_output_context2 fail. ")+av_strerror(ret, buf, AV_ERROR_MAX_STRING_SIZE); goto free; } int vi_idx = -1; for(int ss=0; ssnb_streams; ss++) { AVStream *stream = in_fmt->streams[ss]; AVStream *newStream = avformat_new_stream(out_fmt, 0); if((ret = avcodec_parameters_copy(newStream->codecpar, stream->codecpar)) < 0) { err = QString("avcodec_parameters_copy fail. ") + av_strerror(ret, buf, AV_ERROR_MAX_STRING_SIZE); goto free; } //LOGD("fourcc %s",av_fourcc2str(newStream->codecpar->codec_tag)); if(vi_idx == -1 && stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) vi_idx = ss; } if(vi_idx == -1) { err = "Didn't find a Video Stream"; goto free; } auto codecpar = in_fmt->streams[vi_idx]->codecpar; qDebug()<<"codec_id"<codec_id<codec_id); auto decoder = avcodec_find_decoder(codecpar->codec_id); if(decoder==0) { err = "Could not found Video Decoder"; goto free; } de_ctx = avcodec_alloc_context3(decoder); avcodec_parameters_to_context(de_ctx, codecpar); if(avcodec_open2(de_ctx, decoder, 0) < 0) { err = "Could not open Video Codec Ctx"; goto free; } auto sws_ctx = sws_getContext(de_ctx->width, de_ctx->height, de_ctx->pix_fmt, sw, sh, AV_PIX_FMT_ARGB, SWS_FAST_BILINEAR, 0, 0, 0); auto encoder = avcodec_find_encoder(AV_CODEC_ID_H264); if(encoder==0) { fprintf(stderr, "Codec not found\n"); goto free; } en_ctx = avcodec_alloc_context3(encoder); avcodec_parameters_to_context(en_ctx, codecpar); if(avcodec_open2(en_ctx, encoder, 0) < 0) { err = "Could not open Video Codec Ctx"; goto free; } en_ctx->pix_fmt = AV_PIX_FMT_ARGB; en_ctx->bit_rate = dw*dh/150000; //码率 清晰度有关 en_ctx->width = dw; en_ctx->height = dh; qDebug()<<"gop_size"<gop_size; qDebug()<<"max_b_frames"<max_b_frames; if (avcodec_open2(en_ctx, encoder, 0) < 0) { fprintf(stderr, "Could not open codec\n"); goto free; } avcodec_parameters_from_context(out_fmt->streams[vi_idx]->codecpar, en_ctx); if(out_fmt->flags & AVFMT_NOFILE) qDebug()<<"AVFMT_NOFILE"; else if((ret = avio_open(&out_fmt->pb, outfile.constData(), AVIO_FLAG_WRITE)) < 0) { err = QString("avio_open fail. ")+av_strerror(ret, buf, AV_ERROR_MAX_STRING_SIZE); goto free; } if((ret = avformat_write_header(out_fmt, 0)) < 0) { err = QString("avformat_write_header fail. ")+av_strerror(ret, buf, AV_ERROR_MAX_STRING_SIZE); goto free; } auto packet = av_packet_alloc(); auto frm = av_frame_alloc(); while(1) { if((ret = av_read_frame(in_fmt, packet)) < 0) { if(ret!=AVERROR_EOF) { err = QString("Read packet fail: ")+av_strerror(ret, buf, AV_ERROR_MAX_STRING_SIZE); break; } ret = avcodec_send_packet(de_ctx, 0); } else { if(packet->stream_index != vi_idx) { av_write_frame(out_fmt, packet); continue; } ret = avcodec_send_packet(de_ctx, packet); } if(ret < 0) break; while((ret = avcodec_receive_frame(de_ctx, frm)) != AVERROR(EAGAIN)) { if(ret < 0) { if(ret!=AVERROR_EOF) { err = QString("Receive frame fail: ")+av_strerror(ret, buf, AV_ERROR_MAX_STRING_SIZE); goto free2; } ret = avcodec_send_frame(en_ctx, 0); } else { QImage img(sw, sh, QImage::Format_ARGB32); uint8_t *dst[4]{img.bits()}; int dstStride[4]{img.bytesPerLine()}; sws_scale(sws_ctx, frm->data, frm->linesize, 0, de_ctx->height, dst, dstStride); auto out_frm = av_frame_alloc(); av_image_alloc(out_frm->data, out_frm->linesize, dw, dh, AV_PIX_FMT_ARGB, 8); av_frame_copy_props(out_frm, frm); out_frm->width = dw; out_frm->height = dh; out_frm->format = AV_PIX_FMT_ARGB; QImage out_img(out_frm->data[0], dw, dh, out_frm->linesize[0], QImage::Format_ARGB32); QPainter painter(&out_img); painter.drawImage(pos, img); for(int i=1; iduration; } free: avformat_close_input(&fmt_ctx); return err; } QString Tools::readErrStr(QImageReader::ImageReaderError err) { if(err==QImageReader::UnknownError) return "UnknownError"; if(err==QImageReader::FileNotFoundError) return "FileNotFoundError"; if(err==QImageReader::DeviceError) return "DeviceError"; if(err==QImageReader::UnsupportedFormatError) return "UnsupportedFormatError"; if(err==QImageReader::InvalidDataError) return "InvalidDataError"; return QString::number(err); } QString Tools::fileMd5(QString filePath) { QFile file(filePath); if(! file.open(QFile::ReadOnly)) return QString(); QCryptographicHash cryptoHash(QCryptographicHash::Md5); if(! cryptoHash.addData(&file)) { file.close(); return QString(); } file.close(); return QString::fromLatin1(cryptoHash.result().toHex()); } void Tools::mergeFormat(QTextEdit *textEdit, const QTextCharFormat &format) { QTextCursor cursor = textEdit->textCursor(); if(! cursor.hasSelection()) cursor.select(QTextCursor::WordUnderCursor); cursor.mergeCharFormat(format); textEdit->mergeCurrentCharFormat(format); } void Tools::saveImg(const QString& dir, const QFontMetrics& metric, const QFont& font, const QColor& color, QJsonObject& imgs, const QString& str, const QString& name) { if(str.isEmpty()) return; QImage img(metric.horizontalAdvance(str), metric.lineSpacing(), QImage::Format_ARGB32); img.fill(Qt::transparent); QPainter painter(&img); painter.setFont(font); painter.setPen(color); QTextOption opt(Qt::AlignCenter); opt.setWrapMode(QTextOption::NoWrap); painter.drawText(QRectF(0, 0, img.width(), img.height()), str, opt); QBuffer buf; if(! img.save(&buf, "PNG")) return; QCryptographicHash cryptoHash(QCryptographicHash::Md5); cryptoHash.addData(buf.data()); auto md5 = QString::fromLatin1(cryptoHash.result().toHex()); QFile file(dir+"/"+md5); if(! file.open(QFile::WriteOnly)) return; file.write(buf.data()); file.close(); imgs.insert(name, md5); } void Tools::saveImg2(const QString& dir, const QFontMetrics& metric, const QFont& font, const QColor& color, QJsonArray& imgs, const QString& str, const QString& name) { QJsonObject obj{ {"name", name}, {"mime", "image/png"} }; if(! str.isEmpty()) { QImage img(metric.horizontalAdvance(str), metric.lineSpacing(), QImage::Format_ARGB32); img.fill(Qt::transparent); QPainter painter(&img); painter.setFont(font); painter.setPen(color); QTextOption opt(Qt::AlignCenter); opt.setWrapMode(QTextOption::NoWrap); painter.drawText(QRectF(0, 0, img.width(), img.height()), str, opt); QBuffer buf; if(img.save(&buf, "PNG")) { obj.insert("picWidth", img.width()); obj.insert("picHeight", img.height()); QCryptographicHash cryptoHash(QCryptographicHash::Md5); cryptoHash.addData(buf.data()); auto md5 = QString::fromLatin1(cryptoHash.result().toHex()); QFile file(dir+"/"+md5); if(file.open(QFile::WriteOnly)) { file.write(buf.data()); file.close(); obj.insert("id", md5); } } } imgs.append(obj); } QBrush Tools::getBrush(const QColor& color) { return color.alpha()==0 ? Qt::NoBrush : QBrush(color); } int Tools::color2Int(const QColor& color) { int res = 0; res |= (color.red() & 0xFF) << 24; res |= (color.green() & 0xFF) << 16; res |= (color.blue() & 0xFF) << 8; res |= (color.alpha() & 0xFF); return res; } QColor Tools::int2Color(int value) { QColor res; res.setRed ((value >> 24) & 0xFF); res.setGreen((value >> 16) & 0xFF); res.setBlue ((value >> 8) & 0xFF); res.setAlpha((value ) & 0xFF); return res; } QString Tools::selectStr(bool f, const QString &s0, const QString &s1) { return f ? s0 : s1; } QString Tools::convertFileSize(const qint64 & bytes){ float num = bytes; QStringList list; list << "KB" << "MB" << "GB" << "TB"; QStringListIterator i(list); QString unit("bytes"); while(num >= 1024.0 && i.hasNext()) { unit = i.next(); num /= 1024.0; } return QString().setNum(num,'f',2)+" "+unit; } QString Tools::styleSheet() { QStringList qsses = QDir(":/qss").entryList(QStringList{"*.css"}); std::sort(qsses.begin(), qsses.end(), [](const QString &a, const QString &b) { return a < b; }); QString qss; foreach(QString qss_name, qsses) { QFile f(":/qss/" + qss_name); if(f.exists() && f.open(QFile::ReadOnly)) { qss += f.readAll(); f.close(); } } return qss; }