\documentclass[a4paper]{article} \input{../common-preamble} \input{../bmstu-preamble} \input{../fancy-listings-preamble} \numerationTop \begin{document} \fontsize{14pt}{14pt}\selectfont % Вполне очевидно, что мы хотим 14й шрифт, все его хотят \thispagestyle{empty} \makeBMSTUHeader \makeReportTitle{лабораторной}{3}{Разработка мультимедийного приложения}{Мультимедиа технологии}{}{Д.А. Видьманов} \newpage \pagestyle{fancy} \sloppy \section{Цель} Целью работы является приобретение навыков создания мультимедийных приложений. Создать мультимедийное приложение. \section{Задачи} \begin{enumerate} \item Установить среду разработки; \item Описать критерии создания приложения; \item Написать код и отладить работу приложения. \end{enumerate} \section{Выполнение работы} Для написания мультимедйного приложения был выбран Qt Framework версии 5.12, и язык C++. Разрабатываемое приложение - это единый мультимедийный просмотрщик файлов (офисные документы, pdf, видео). Для реализации мультимедийности были выбраны несколько компонентов и создан экран, основной частью которого является область просмотра. \begin{figure}[H] \centering \includegraphics[width=12cm]{03-mmt-lab-03-main.png} \caption{Основное окно приложения} \end{figure} \subsection{Функции. Открытие MPEG} \begin{figure}[H] \centering \includegraphics[width=12cm]{03-mmt-lab-03-video.png} \caption{Видео в приложении} \end{figure} Для открытия, воспроизведения и перемотки видеофайлов используются компоненты \code{QMediaPlayer} и \code{QVideoWidget}. Для работы с компонентами были описаны следующие слоты и функции: \begin{itemize} \item \code{void openMPEG(QString&)}. Достраивает в главном окне необходимые области, добавляет кнопки, инициализирует слайдеры, связывает слоты. \item \code{void closeMPEG()}. Отвязывает слоты, удаляет динамические объекты, очищает окно от элементов управления. \item \code{void playVideo()}. Начинает/продолжает проигрывание медиафайла. \item \code{void stopVideo()}. Завершает проигрывание файла. Позиция проигрывания перемещается в начало. Если после вызова этой функции вызвать \code{playVideo()}, то видео начнется сначала. \item \code{void pauseVideo()}. Приостанавливает проигрывание медиа. Позиция сохраняется. Если после вызова этой вызвать \code{playVideo()}, то видео продолжится с момента приостановки видео. \item \code{void changeVolume(int)}. Изменяет громкость звука. Слот вызывается сигналом \code{&QSlider::valueChanged} с передачей значения из компонента. \item \code{void changePosition()}. Принудительно перематывает видео ползунком. При вызове слота позиции видео присваивается значение с ползунка, отвечающего за перемотку видео. \item \code{void updatePosition(qint64)}. Слот реагирует на текущее положение курсора в проигрывателе и передает относительное положение ползунку перемотки видео, чтобы положение ползунка менялось в ходе проигрывания видео. \item \code{void updateDuration(qint64)}. При старте видеопотока общая продолжительность видео считается некоторое время, поэтому сразу идентифицировать не удастся. Слот привязан к сигналу о том, что для данного видеофайла изменилось (вычислилось) значение продолжительности. \item \code{void updateState(int)}. Справочный слот. Реагирует на Старт, Стоп и Паузу видео. Если необходимо в процессе работы выдавать еще какие-то команды - слот «узнаёт», в каком состоянии проигрывания медиафайл. \end{itemize} \subsection{Функции. Открытие офисных документов (XLSX, DOCX, PPTX)} Функции офиса используют компонент ActiveX и отображают содержимое, фактически открытое в приложениях офисного пакета. \begin{figure}[H] \centering \includegraphics[width=12cm]{03-mmt-lab-03-open.png} \caption{Окно открытия файла} \end{figure} \begin{itemize} \item \code{void openXLSX(QString&)}. Открывает XLSX файл и передает управление файлом приложению MS Excel. Отображение размещается внутри виджета. \item \code{void openDOCX(QString&)}. Открывает DOCX файл и передает управление файлом приложению MS Word. Отображение размещается внутри виджета. \item \code{void openPPTX(QString&)}. Открывает PPTX файл и передает управление файлом приложению MS PowerPoint. Отображение размещается внутри виджета. Дополнительно, здесь происходит подключение к слоту, вызывющему проигрывание в режиме презентации. \end{itemize} \subsection{Функции. Открытие документов PDF} \code{void openPDF(QString&)}. Открывает PDF файл и передает управление файлом приложению Adobe Acrobat. Отображение размещается внутри виджета. \begin{figure}[H] \centering \includegraphics[width=12cm]{03-mmt-lab-03-pdf.png} \caption{Просмотр PDF документа} \end{figure} \subsection{Закрытие документа} \code{void closeFile()} - Закрывает открытый документ. \section{Выводы} Для разработки мультимедийного приложения необходимо изучить разнообразный инструментарий, позволяющий манипулировать мультимедийными данными. Написание мультимедийнх приложений тесно связано с обработкой больших объёмов данных или использованием внешних библиотек и приложений. Мультимедийные приложения возможно написать для любых платформ и внедрить для любых категорий пользователей. \newpage \appendix \setcounter{secnumdepth}{0} \section{Приложения} \renewcommand{\thesubsection}{\Asbuk{subsection}} \subsection{Полный листинг главного окна приложения} \begin{lstlisting}[language=C++,style=CCodeStyle] #include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); QMenuBar *menuBar = new QMenuBar(); m_menuFile = menuBar->addMenu("&File"); m_openAction = new QAction("&Open"); m_openAction->setStatusTip(tr("Open a document")); m_menuFile->addAction(m_openAction); m_menuFile->addSeparator(); m_quitAction = new QAction("&Quit"); m_quitAction->setShortcut(tr("CTRL+Q")); m_quitAction->setStatusTip(tr("Quit application")); m_menuFile->addAction(m_quitAction); connect(this->m_openAction, &QAction::triggered, this, &MainWindow::slotOpenAction); connect(this->m_quitAction, &QAction::triggered, qApp, &QApplication::quit); this->setMenuBar(menuBar); this->resize(800, 600); show(); } MainWindow::~MainWindow() { delete ui; } void MainWindow::delay(int delay) { QTime dieTime= QTime::currentTime().addSecs(delay); while (QTime::currentTime() < dieTime) QCoreApplication::processEvents(QEventLoop::AllEvents, 100); } void MainWindow::slotOpenAction() { m_filename = QFileDialog::getOpenFileName( this, tr("Выберите файл"), "../", tr("MPEG (*.mpeg) ;; PDF (*.pdf) ;; DOCX (*.docx) ;; XLSX (*.xlsx) ;; PPTX (*.pptx)")); if (m_filename != "") { if (axObj) { qDebug() << "Close file!\n"; closeFile(); } if (m_videoWidget) { qDebug() << "Close MPEG!\n"; closeMPEG(); } if (m_filename.endsWith(".pdf")) { openPDF(m_filename); } else if (m_filename.endsWith(".pptx")) { openPPTX(m_filename); } else if (m_filename.endsWith(".docx")) { openDOCX(m_filename); } else if (m_filename.endsWith(".xlsx")) { openXLSX(m_filename); } else if (m_filename.endsWith(".mpeg")) { openMPEG(m_filename); } } } void MainWindow::closeFile() { if (axObj != nullptr) { QProcess process; QString strCmd; strCmd = "taskkill /im winword.exe /f"; process.execute(strCmd); strCmd = "taskkill /im EXCEL.exe /f"; process.execute(strCmd); strCmd = "taskkill /im POWERPNT.exe /f"; process.execute(strCmd); strCmd = "taskkill /im AcroRd32.exe /f"; process.execute(strCmd); process.close(); axObj->close(); axObj->clear(); delete axObj; axObj = nullptr; qDebug() << "file closed!"; } } void MainWindow::openPDF(QString &filename) { axObj = new QAxWidget(this); setCentralWidget(axObj); if(!axObj->setControl("Adobe PDF Reader")) QMessageBox::critical(this, "Error", "Make sure you have Adobe Reader (and its ActiveX) installed!"); axObj->dynamicCall("LoadFile(QString)", filename); } /* run slideshow */ void MainWindow::playPPTX() { // Open parameter QList param_list; axObj->setControl("PowerPoint.Application"); param_list.append(m_filename); param_list.append(1); param_list.append(1); param_list.append(0); // Open a template file QAxObject *presentations = axObj->querySubObject("Presentations"); QAxObject *presentation = presentations->querySubObject("Open(const QString&,int,int,int)", param_list); // Start the slides QAxObject *slideshow = presentation->querySubObject("SlideShowSettings"); slideshow->setProperty("RangeType", "ppShowAll"); slideshow->dynamicCall("run()"); } void MainWindow::openPPTX(QString &filename) { /* инициализация окна виджетом */ m_wideWidget = new QWidget; setCentralWidget(m_wideWidget); qDebug() << "1"; /* здесь будут элементы управления и окно проигрывателя (выравнивание по горизонтали) */ m_qvBoxLayout = new QVBoxLayout(m_wideWidget); axObj = new QAxWidget("PowerPoint.Application", m_wideWidget); m_btnPlay = new QPushButton("Начать презентацию"); qDebug() << "2"; m_qvBoxLayout->addWidget(axObj); m_qvBoxLayout->addWidget(m_btnPlay); if (axObj == nullptr) { return; } if (!axObj->setControl(filename)) { return; } axObj->dynamicCall("LoadFile(const QString&)", filename); axObj->dynamicCall("SetVisible (bool Visible)", "false"); axObj->setProperty("DisplayAlerts", false); axObj->setProperty("DisplayScrollBars", true); delay(1); axObj->show(); axObj->raise(); qDebug() << "3"; connect(this->m_btnPlay, &QPushButton::clicked, this, &MainWindow::playPPTX); } void MainWindow::openXLSX(QString &filename) { axObj = new QAxWidget("Excel.Application", this); setCentralWidget(axObj); if (axObj == nullptr) { return; } axObj->dynamicCall("SetVisible (bool Visible)", "false"); axObj->setProperty("DisplayAlerts", false); axObj->setProperty("DisplayScrollBars", true); // Show scroll bar axObj->setGeometry(this->geometry()); axObj->setControl(filename); axObj->show(); } void MainWindow::openDOCX(QString &filename) { axObj = new QAxWidget("Word.Application", this); setCentralWidget(axObj); if (axObj == nullptr) { return; } axObj->dynamicCall("SetVisible (bool Visible)", "false"); axObj->setFocusPolicy(Qt::StrongFocus); axObj->setProperty("DisplayAlerts", false); axObj->setProperty("DisplayHorizontalScrollBar", true); // Show scroll bar axObj->setGeometry(this->geometry()); axObj->setControl(filename); axObj->show(); } /* продолжить проигрывать видео */ void MainWindow::playVideo() { m_player->setPosition(m_position); m_player->play(); } /* остановка видео */ void MainWindow::stopVideo() { m_player->stop(); } /* пауза видео */ void MainWindow::pauseVideo() { m_player->pause(); } /* событие при изменении состояния видеопроигрывателя */ void MainWindow::updateState(int state) { switch (state) { case QMediaPlayer::PlayingState: /* media is played */ break; case QMediaPlayer::PausedState: /* media paused */ break; case QMediaPlayer::StoppedState: /* media is stopped */ break; } } /* принудительно изменить время проигрывания */ void MainWindow::changePosition() { m_position = m_sliderVideo->value(); m_player->setPosition(m_position); } /* принудительно изменить время проигрывания */ void MainWindow::updatePosition(qint64 position) { m_position = position; m_sliderVideo->setValue(m_position); } /* изменить величину звука */ void MainWindow::changeVolume(int volume) { m_player->setVolume(volume); } /* слот для иницализации значением слайдера видео */ void MainWindow::updateDuration(qint64 duration) { m_sliderVideo->setRange(0, m_player->duration()); m_sliderVideo->setEnabled(duration > 0); m_sliderVideo->setPageStep(duration / 10); } /* инициализация медиа файла */ void MainWindow::openMPEG(QString &filename) { /* инициализация окна виджетом */ m_wideWidget = new QWidget; setCentralWidget(m_wideWidget); /* здесь будут элементы управления и окно проигрывателя (выравнивание по горизонтали) */ m_qvBoxLayout = new QVBoxLayout(m_wideWidget); /* область для отображения видео */ m_videoWidget = new QVideoWidget; m_player = new QMediaPlayer(m_videoWidget); m_player->setVideoOutput(m_videoWidget); m_player->setMedia(QUrl::fromLocalFile(filename)); /* область размещения кнопок управления видео */ m_hBtnsLayout = new QHBoxLayout; m_play = new QPushButton("Play"); m_stop = new QPushButton("Stop"); m_pause = new QPushButton("Pause"); m_sliderVolume = new QSlider(Qt::Horizontal); m_sliderVolume->setRange(0, 100); // диапазон значений громкости m_sliderVolume->setValue(50); // текущая громкость 50% m_sliderVideo = new QSlider(Qt::Horizontal); m_hBtnsLayout->addWidget(m_play, 1); m_hBtnsLayout->addWidget(m_stop, 1); m_hBtnsLayout->addWidget(m_pause, 1); m_hBtnsLayout->addWidget(&m_labelVolume); m_hBtnsLayout->addWidget(m_sliderVolume, 1); m_hBtnsLayout->addWidget(&m_labelScroll); m_hBtnsLayout->addWidget(m_sliderVideo, 5); /* поместить настроенные объекты в центральный виджет */ m_qvBoxLayout->addWidget(m_videoWidget); m_qvBoxLayout->addLayout(m_hBtnsLayout); /* связать слоты */ connect(this->m_play, &QPushButton::clicked, this, &MainWindow::playVideo); connect(this->m_stop, &QPushButton::clicked, this, &MainWindow::stopVideo); connect(this->m_pause, &QPushButton::clicked, this, &MainWindow::pauseVideo); connect(this->m_sliderVolume, &QSlider::sliderMoved, this, &MainWindow::changeVolume); connect(this->m_sliderVideo, &QSlider::sliderMoved, this, &MainWindow::changePosition); connect(this->m_sliderVideo, &QSlider::valueChanged, this, &MainWindow::changePosition); connect(this->m_player, &QMediaPlayer::durationChanged, this, &MainWindow::updateDuration); connect(this->m_player, &QMediaPlayer::positionChanged, this, &MainWindow::updatePosition); connect(this->m_player, &QMediaPlayer::stateChanged, this, &MainWindow::updateState); /* начать проигрывать видео */ playVideo(); } void MainWindow::closeMPEG() { /* отключение всех слотов */ disconnect(this->m_play, &QPushButton::clicked, this, &MainWindow::playVideo); disconnect(this->m_stop, &QPushButton::clicked, this, &MainWindow::stopVideo); disconnect(this->m_pause, &QPushButton::clicked, this, &MainWindow::pauseVideo); disconnect(this->m_sliderVolume, &QSlider::sliderMoved, this, &MainWindow::changeVolume); disconnect(this->m_sliderVideo, &QSlider::sliderMoved, this, &MainWindow::changePosition); disconnect(this->m_sliderVideo, &QSlider::sliderPressed, this, &MainWindow::changePosition); disconnect(this->m_player, &QMediaPlayer::durationChanged, this, &MainWindow::updateDuration); disconnect(this->m_player, &QMediaPlayer::positionChanged, this, &MainWindow::updatePosition); disconnect(this->m_player, &QMediaPlayer::stateChanged, this, &MainWindow::updateState); /* удаление динамических объектов */ delete m_sliderVideo; delete m_sliderVolume; delete m_play; delete m_stop; delete m_pause; delete m_hBtnsLayout; delete m_player; delete m_videoWidget; delete m_qvBoxLayout; } \end{lstlisting} \end{document}