Qt 오디오 및 비디오 개발 23- 일반 비디오 제어

I. 소개

기존의 영상 감시 시스템에서는 사용자의 요구에 따라 다양한 영상 감시 커널이 만들어졌습니다. ffmpeg 커널, vlc 커널, mpv 커널, Haikang sdk 커널 등을 범용화하기 위해 다른 커널의 기능은 전환이 매우 편리합니다. 예를 들어 pro는 DEFINE의 변수 이름을 직접 변경하므로 다양한 커널을 동일한 인터페이스로 사용하여 매우 깔끔하게 보이도록 만들어야하므로 나중에 범용으로 특별히 다듬습니다. 비디오 제어.이 제어는 특정 비디오 재생 제어 기능이 없습니다. 다른 코어에 따라 특정 메소드를 호출하여 구현해야합니다. 나중에 Dahua SDK 또는 기타 타사 제조업체의 계약을 추가해야하는 경우이 일반 비디오 제어를 직접 적용 할 수 있습니다. , 향후 새로운 모니터링 커널을 추가하면 많은 작업을 절약 할 수 있습니다. 기본적으로 커널 분석 만하면되고 나머지 공통 인터페이스와 드로잉 이미지는 공통 비디오 컨트롤에 직접 전달됩니다.

일반 비디오 제어 기능 :

  1. 테두리 크기를 설정할 수 있습니다.
  2. 테두리 색상을 설정할 수 있습니다.
  3. 두 개의 OSD 레이블을 설정할 수 있습니다.
  4. OSD 라벨 그리기 여부를 설정할 수 있습니다.
  5. 레이블 텍스트 또는 그림을 설정할 수 있습니다.
  6. OSD 위치를 설정할 수 있습니다. 왼쪽 상단 모서리 + 왼쪽 하단 모서리 + 오른쪽 상단 모서리 + 오른쪽 하단 모서리
  7. OSD 스타일 텍스트 + 날짜 + 시간 + 날짜 및 시간 + 사진 설정 가능
  8. 사용자 정의 반투명 플로팅 양식, 버튼 행
  9. 플로팅 버튼은 배경색 + 누름 색상을 포함하여 사용자 정의 할 수 있습니다.
  10. 플로팅 버튼이 클릭되었음을 알립니다.
  11. 드래그 된 파일을 식별하고 URL을 알릴 수 있습니다.
  12. 열기 닫기 일시 중지와 같은 인터페이스 제공

2. 특징

  1. 1 + 4 + 6 + 8 + 9 + 13 + 16 + 25 + 36 + 64 화면 전환을 포함하여 다중 화면 전환, 전체 화면 전환 등을 지원합니다.
  2. 지원 alt + enter full screen, esc exit full screen.
  3. 사용자 지정 정보 상자 + 오류 상자 + 문의 상자 + 오른쪽 하단의 프롬프트 상자 (여러 형식 포함).
  4. 17 가지 스킨 스타일 세트를 마음대로 변경할 수 있으며 메뉴를 포함한 모든 스타일이 통합됩니다.
  5. 짐벌 대시 보드에서 마우스를 움직여 강조 표시하면 8 개의 방향이 정확하게 식별됩니다.
  6. 하단 화면 도구 모음 (화면 분할 스위치 + 스크린 샷 사운드 및 기타 설정)이 위로 이동하고 강조 표시됩니다.
  7. 로고 + 중국어 소프트웨어 이름 + 영어 소프트웨어 이름은 구성 파일에서 변경할 수 있습니다.
  8. Baidu지도,보기 전환, 모션 트랙, 장치 위치 및 마우스 클릭을 캡슐화하여 위도 및 경도 등을 가져옵니다.
  9. 지원 사진지도, 장치 버튼을 사진지도에서 자유롭게 드래그하여 위치 정보를 자동으로 저장할 수 있습니다.
  10. Baidu지도 및 사진지도에서 비디오를 두 번 클릭하여 카메라 실시간 비디오를 미리 봅니다.
  11. 스택 창, 각 창은 별도의 qwidget이며 자신의 코드를 작성하는 데 편리합니다.
  12. 상단 마우스의 오른쪽 클릭 메뉴는 CPU + 왼쪽 상단 패널 + 왼쪽 하단 패널 + 오른쪽 상단 패널 + 오른쪽 하단 패널의 시간 표시 및 숨기기를 동적으로 제어 할 수 있으며 기본 레이아웃 복원을 지원합니다.
  13. 도구 모음은 여러 개의 작은 아이콘을 배치하고 아이콘을 닫을 수 있습니다.
  14. 왼쪽과 오른쪽을 드래그하여 늘릴 수 있으며 너비와 높이 위치가 자동으로 기억되며 다시 시작하면 복원됩니다.
  15. 자동으로 비디오를 재생하려면 카메라 노드를 두 번 클릭하고, 순서대로 비디오를 자동으로 추가하려면 노드를 두 번 클릭하면 자동으로 다음 항목으로 건너 뜁니다. 상위 노드를 두 번 클릭하면 노드 아래에 모든 비디오가 자동으로 추가됩니다.
  16. 카메라 노드를 해당 창으로 드래그하여 비디오를 재생하고 로컬 파일은 직접 재생을 지원합니다.
  17. 비디오 프레임은 드래그 및 스왑을 지원하며 즉시 응답합니다.
  18. 노드를 두 번 클릭하고 노드를 드래그하고 양식을 드래그하여 위치를 바꾸면 url.txt가 자동으로 업데이트됩니다.
  19. url.txt에서 채널 비디오 재생 로딩을 지원하고, 마지막 채널에 해당하는 비디오를 자동으로 기억하고, 소프트웨어가 시작된 후 자동으로 열고 재생합니다.
  20. 오른쪽 하단 모서리에있는 볼륨 막대 컨트롤은 포커스를 잃으면 자동으로 숨겨지며 볼륨 막대에는 음소거 아이콘이 있습니다.
  21. 통합 Baidu 온라인지도 및 오프라인지도, 장치의 해당 위치를 추가하고 자동으로지도를 생성하고 확대 / 축소를 지원하고 오버레이를 추가 할 수 있습니다.
  22. 비디오를 채널 창 밖으로 드래그하면 자동으로 비디오가 삭제됩니다.
  23. 마우스 오른쪽 버튼으로 현재 + 모든 비디오를 삭제하고 현재 + 모든 비디오를 스크린 샷 할 수 있습니다.
  24. 레코더 관리, 카메라 관리, 인쇄 정보 추가, 삭제, 수정, 가져 오기 및 내보내기가 가능하며, 새 장치 정보를 즉시 적용하여 다시 시작하지 않고도 트리 목록을 생성 할 수 있습니다.
  25. pro 파일에서 맵로드 여부를 자유롭게 설정할 수 있습니다.
  26. 비디오 재생을 위해 두 종류의 커널을 자유롭게 전환 할 수 있습니다. vlc + ffmpeg, 둘 다 pro에서 설정할 수 있습니다.
  27. 1 + 4 + 9 + 16 화면 폴링 설정 가능, 폴링 간격 및 폴링 스트림 유형 설정 가능, 메인 인터페이스 하단의 툴바 오른쪽에있는 폴링 시작 버튼을 클릭 한 다음 다시 클릭하여 폴링을 중지합니다. .
  28. 기본적으로 마우스 포인터는 10 초 이상 작동하지 않고 자동으로 숨겨집니다.
  29. onvif 검색 장비 지원, Haikang Dahuayu Shitiandi Weiye Huawei 등을 포함하되 이에 국한되지 않는 모든 onvif 카메라 지원
  30. onvif PTZ 제어를 지원하고 재설정 및 초점 조정을 포함하여 PTZ 카메라를 위, 아래, 왼쪽 및 오른쪽으로 이동할 수 있습니다.
  31. 동시에 sqlite, mysql 및 postsql과 같은 데이터베이스를 지원합니다.
  32. 비디오를 저장할 수 있으며 타이밍 저장 또는 단일 파일 저장은 선택 사항이며 저장 간격은 선택 사항입니다.
  33. 비디오 스트림 통신 방법 tcp + udp를 설정할 수 있으며 비디오 디코딩을 속도 우선, 품질 우선, 이퀄라이제이션 등으로 설정할 수 있습니다.
  34. 하드 디코딩 유형을 설정하고 qsv, dxva2, d3d11va 등을 지원할 수 있습니다.
  35. 기본적으로 OpenGL은 CPU 리소스 소비가 매우 적고 yuyv 및 nv12 형식 그리기를 지원하는 비디오를 그리는 데 사용됩니다.
  36. 고도로 사용자 정의 할 수있는 사용자는 Linux 및 Mac 시스템을 지원하여이를 기반으로 자신의 기능을 쉽게 파생 할 수 있습니다.

세, 렌더링

여기에 사진 설명 삽입

네, 관련 사이트

  1. 국내 사이트 : https://gitee.com/feiyangqingyun/QWidgetDemo
  2. 국제 사이트 : https://github.com/feiyangqingyun/QWidgetDemo
  3. 개인 홈페이지 : https://blog.csdn.net/feiyangqingyun
  4. Zhihu 홈페이지 : https://www.zhihu.com/people/feiyangqingyun/
  5. 체험 주소 : https://blog.csdn.net/feiyangqingyun/article/details/97565652

다섯, 핵심 코드

void VideoWidget::paintEvent(QPaintEvent *)
{
    //如果不需要绘制
    if (!drawImage) {
        return;
    }

    //qDebug() << TIMEMS << "paintEvent" << objectName();
    QPainter painter(this);
    painter.setRenderHints(QPainter::Antialiasing);

    //绘制边框
    drawBorder(&painter);
    if (!image.isNull()) {
        //绘制背景图片
        drawImg(&painter, image);
        //绘制标签
        drawOSD(&painter, osd1Visible, osd1FontSize, osd1Text, osd1Color, osd1Image, osd1Format, osd1Position);
        drawOSD(&painter, osd2Visible, osd2FontSize, osd2Text, osd2Color, osd2Image, osd2Format, osd2Position);
    } else {
        //绘制背景
        drawBg(&painter);
    }
}

void VideoWidget::drawBorder(QPainter *painter)
{
    if (borderWidth == 0) {
        return;
    }

    painter->save();
    QPen pen;
    pen.setWidth(borderWidth);
    pen.setColor(hasFocus() ? focusColor : borderColor);
    painter->setPen(pen);
    painter->drawRect(rect());
    painter->restore();
}

void VideoWidget::drawBg(QPainter *painter)
{
    painter->save();

    //背景图片为空则绘制文字,否则绘制背景图片
    if (bgImage.isNull()) {
        painter->setFont(this->font());
        painter->setPen(palette().foreground().color());
        painter->drawText(rect(), Qt::AlignCenter, bgText);
    } else {
        //居中绘制
        int pixX = rect().center().x() - bgImage.width() / 2;
        int pixY = rect().center().y() - bgImage.height() / 2;
        QPoint point(pixX, pixY);
        painter->drawImage(point, bgImage);
    }

    painter->restore();
}

void VideoWidget::drawImg(QPainter *painter, QImage img)
{
    painter->save();

    int offset = borderWidth * 1 + 0;
    if (fillImage) {
        QRect rect(offset / 2, offset / 2, width() - offset, height() - offset);
        painter->drawImage(rect, img);
    } else {
        //按照比例自动居中绘制
        img = img.scaled(width() - offset, height() - offset, Qt::KeepAspectRatio);
        int pixX = rect().center().x() - img.width() / 2;
        int pixY = rect().center().y() - img.height() / 2;
        QPoint point(pixX, pixY);
        painter->drawImage(point, img);
    }

    painter->restore();
}

void VideoWidget::drawOSD(QPainter *painter,
                          bool osdVisible,
                          int osdFontSize,
                          const QString &osdText,
                          const QColor &osdColor,
                          const QImage &osdImage,
                          const VideoWidget::OSDFormat &osdFormat,
                          const VideoWidget::OSDPosition &osdPosition)
{
    if (!osdVisible) {
        return;
    }

    painter->save();

    //标签位置尽量偏移多一点避免遮挡
    QRect osdRect(rect().x() + (borderWidth * 2), rect().y() + (borderWidth * 2), width() - (borderWidth * 5), height() - (borderWidth * 5));
    int flag = Qt::AlignLeft | Qt::AlignTop;
    QPoint point = QPoint(osdRect.x(), osdRect.y());

    if (osdPosition == OSDPosition_Left_Top) {
        flag = Qt::AlignLeft | Qt::AlignTop;
        point = QPoint(osdRect.x(), osdRect.y());
    } else if (osdPosition == OSDPosition_Left_Bottom) {
        flag = Qt::AlignLeft | Qt::AlignBottom;
        point = QPoint(osdRect.x(), osdRect.height() - osdImage.height());
    } else if (osdPosition == OSDPosition_Right_Top) {
        flag = Qt::AlignRight | Qt::AlignTop;
        point = QPoint(osdRect.width() - osdImage.width(), osdRect.y());
    } else if (osdPosition == OSDPosition_Right_Bottom) {
        flag = Qt::AlignRight | Qt::AlignBottom;
        point = QPoint(osdRect.width() - osdImage.width(), osdRect.height() - osdImage.height());
    }

    if (osdFormat == OSDFormat_Image) {
        painter->drawImage(point, osdImage);
    } else {
        QDateTime now = QDateTime::currentDateTime();
        QString text = osdText;
        if (osdFormat == OSDFormat_Date) {
            text = now.toString("yyyy-MM-dd");
        } else if (osdFormat == OSDFormat_Time) {
            text = now.toString("HH:mm:ss");
        } else if (osdFormat == OSDFormat_DateTime) {
            text = now.toString("yyyy-MM-dd HH:mm:ss");
        }

        //设置颜色及字号
        QFont font;
        font.setPixelSize(osdFontSize);
        painter->setPen(osdColor);
        painter->setFont(font);

        painter->drawText(osdRect, flag, text);
    }

    painter->restore();
}

추천

출처blog.csdn.net/feiyangqingyun/article/details/108355000