diff options
author | Lorn Potter <lorn.potter@nokia.com> | 2010-06-15 13:28:45 +1000 |
---|---|---|
committer | Lorn Potter <lorn.potter@nokia.com> | 2010-06-15 13:28:45 +1000 |
commit | d8898b8dfefd7f3736d94eee43dd3dd9beaf1f90 (patch) | |
tree | 2d1f28571543959b1ebfe3f86c213d89c1eb3cce /examples | |
parent | 5989ac32ea37311b29e7d45efdfe956e4d4ffc2c (diff) | |
parent | 24843e428b0c5095e31f6c994388050cb4d31292 (diff) |
Merge branch '1.0' of ../qtmobility into 1.0
Conflicts:
.gitignore
Diffstat (limited to 'examples')
48 files changed, 3584 insertions, 140 deletions
diff --git a/examples/audiodevices/audiodevices.cpp b/examples/audiodevices/audiodevices.cpp new file mode 100644 index 0000000000..3b0919b144 --- /dev/null +++ b/examples/audiodevices/audiodevices.cpp @@ -0,0 +1,313 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <qaudiodeviceinfo.h> + +#include "audiodevices.h" + +// Utility functions for converting QAudioFormat fields into text + +QString toString(QAudioFormat::SampleType sampleType) +{ + QString result("Unknown"); + switch (sampleType) { + case QAudioFormat::SignedInt: + result = "SignedInt"; + break; + case QAudioFormat::UnSignedInt: + result = "UnSignedInt"; + break; + case QAudioFormat::Float: + result = "Float"; + break; + } + return result; +} + +QString toString(QAudioFormat::Endian endian) +{ + QString result("Unknown"); + switch (endian) { + case QAudioFormat::LittleEndian: + result = "LittleEndian"; + break; + case QAudioFormat::BigEndian: + result = "BigEndian"; + break; + } + return result; +} + + +AudioDevicesBase::AudioDevicesBase(QWidget *parent, Qt::WFlags f) + : QMainWindow(parent, f) +{ + setupUi(this); +} + +AudioDevicesBase::~AudioDevicesBase() {} + + +AudioTest::AudioTest(QWidget *parent, Qt::WFlags f) + : AudioDevicesBase(parent, f) +{ + mode = QAudio::AudioOutput; + + connect(testButton, SIGNAL(clicked()), SLOT(test())); + connect(modeBox, SIGNAL(activated(int)), SLOT(modeChanged(int))); + connect(deviceBox, SIGNAL(activated(int)), SLOT(deviceChanged(int))); + connect(frequencyBox, SIGNAL(activated(int)), SLOT(freqChanged(int))); + connect(channelsBox, SIGNAL(activated(int)), SLOT(channelChanged(int))); + connect(codecsBox, SIGNAL(activated(int)), SLOT(codecChanged(int))); + connect(sampleSizesBox, SIGNAL(activated(int)), SLOT(sampleSizeChanged(int))); + connect(sampleTypesBox, SIGNAL(activated(int)), SLOT(sampleTypeChanged(int))); + connect(endianBox, SIGNAL(activated(int)), SLOT(endianChanged(int))); + connect(populateTableButton, SIGNAL(clicked()), SLOT(populateTable())); + + modeBox->setCurrentIndex(0); + modeChanged(0); + deviceBox->setCurrentIndex(0); + deviceChanged(0); +} + +AudioTest::~AudioTest() +{ +} + +void AudioTest::test() +{ + // tries to set all the settings picked. + testResult->clear(); + + if (!deviceInfo.isNull()) { + if (deviceInfo.isFormatSupported(settings)) { + testResult->setText(tr("Success")); + nearestFreq->setText(""); + nearestChannel->setText(""); + nearestCodec->setText(""); + nearestSampleSize->setText(""); + nearestSampleType->setText(""); + nearestEndian->setText(""); + } else { + QAudioFormat nearest = deviceInfo.nearestFormat(settings); + testResult->setText(tr("Failed")); + nearestFreq->setText(QString("%1").arg(nearest.frequency())); + nearestChannel->setText(QString("%1").arg(nearest.channels())); + nearestCodec->setText(nearest.codec()); + nearestSampleSize->setText(QString("%1").arg(nearest.sampleSize())); + nearestSampleType->setText(toString(nearest.sampleType())); + nearestEndian->setText(toString(nearest.byteOrder())); + } + } + else + testResult->setText(tr("No Device")); +} + +void AudioTest::modeChanged(int idx) +{ + testResult->clear(); + + // mode has changed + if (idx == 0) + mode = QAudio::AudioInput; + else + mode = QAudio::AudioOutput; + + deviceBox->clear(); + foreach (const QAudioDeviceInfo &deviceInfo, QAudioDeviceInfo::availableDevices(mode)) + deviceBox->addItem(deviceInfo.deviceName(), qVariantFromValue(deviceInfo)); + + deviceBox->setCurrentIndex(0); + deviceChanged(0); +} + +void AudioTest::deviceChanged(int idx) +{ + testResult->clear(); + + if (deviceBox->count() == 0) + return; + + // device has changed + deviceInfo = deviceBox->itemData(idx).value<QAudioDeviceInfo>(); + + frequencyBox->clear(); + QList<int> freqz = deviceInfo.supportedFrequencies(); + for(int i = 0; i < freqz.size(); ++i) + frequencyBox->addItem(QString("%1").arg(freqz.at(i))); + if(freqz.size()) + settings.setFrequency(freqz.at(0)); + + channelsBox->clear(); + QList<int> chz = deviceInfo.supportedChannels(); + for(int i = 0; i < chz.size(); ++i) + channelsBox->addItem(QString("%1").arg(chz.at(i))); + if(chz.size()) + settings.setChannels(chz.at(0)); + + codecsBox->clear(); + QStringList codecz = deviceInfo.supportedCodecs(); + for (int i = 0; i < codecz.size(); ++i) + codecsBox->addItem(QString("%1").arg(codecz.at(i))); + if (codecz.size()) + settings.setCodec(codecz.at(0)); + // Add false to create failed condition! + codecsBox->addItem("audio/test"); + + sampleSizesBox->clear(); + QList<int> sampleSizez = deviceInfo.supportedSampleSizes(); + for (int i = 0; i < sampleSizez.size(); ++i) + sampleSizesBox->addItem(QString("%1").arg(sampleSizez.at(i))); + if (sampleSizez.size()) + settings.setSampleSize(sampleSizez.at(0)); + + sampleTypesBox->clear(); + QList<QAudioFormat::SampleType> sampleTypez = deviceInfo.supportedSampleTypes(); + + for (int i = 0; i < sampleTypez.size(); ++i) + sampleTypesBox->addItem(toString(sampleTypez.at(i))); + if (sampleTypez.size()) + settings.setSampleType(sampleTypez.at(0)); + + endianBox->clear(); + QList<QAudioFormat::Endian> endianz = deviceInfo.supportedByteOrders(); + for (int i = 0; i < endianz.size(); ++i) + endianBox->addItem(toString(endianz.at(i))); + if (endianz.size()) + settings.setByteOrder(endianz.at(0)); + + allFormatsTable->clearContents(); +} + +void AudioTest::populateTable() +{ + int row = 0; + + QAudioFormat format; + foreach (QString codec, deviceInfo.supportedCodecs()) { + format.setCodec(codec); + foreach (int frequency, deviceInfo.supportedFrequencies()) { + format.setFrequency(frequency); + foreach (int channels, deviceInfo.supportedChannels()) { + format.setChannels(channels); + foreach (QAudioFormat::SampleType sampleType, deviceInfo.supportedSampleTypes()) { + format.setSampleType(sampleType); + foreach (int sampleSize, deviceInfo.supportedSampleSizes()) { + format.setSampleSize(sampleSize); + foreach (QAudioFormat::Endian endian, deviceInfo.supportedByteOrders()) { + format.setByteOrder(endian); + if (deviceInfo.isFormatSupported(format)) { + allFormatsTable->setRowCount(row + 1); + + QTableWidgetItem *codecItem = new QTableWidgetItem(format.codec()); + allFormatsTable->setItem(row, 0, codecItem); + + QTableWidgetItem *frequencyItem = new QTableWidgetItem(QString("%1").arg(format.frequency())); + allFormatsTable->setItem(row, 1, frequencyItem); + + QTableWidgetItem *channelsItem = new QTableWidgetItem(QString("%1").arg(format.channels())); + allFormatsTable->setItem(row, 2, channelsItem); + + QTableWidgetItem *sampleTypeItem = new QTableWidgetItem(toString(format.sampleType())); + allFormatsTable->setItem(row, 3, sampleTypeItem); + + QTableWidgetItem *sampleSizeItem = new QTableWidgetItem(QString("%1").arg(format.sampleSize())); + allFormatsTable->setItem(row, 4, sampleSizeItem); + + QTableWidgetItem *byteOrderItem = new QTableWidgetItem(toString(format.byteOrder())); + allFormatsTable->setItem(row, 5, byteOrderItem); + + ++row; + } + } + } + } + } + } + } +} + +void AudioTest::freqChanged(int idx) +{ + // freq has changed + settings.setFrequency(frequencyBox->itemText(idx).toInt()); +} + +void AudioTest::channelChanged(int idx) +{ + settings.setChannels(channelsBox->itemText(idx).toInt()); +} + +void AudioTest::codecChanged(int idx) +{ + settings.setCodec(codecsBox->itemText(idx)); +} + +void AudioTest::sampleSizeChanged(int idx) +{ + settings.setSampleSize(sampleSizesBox->itemText(idx).toInt()); +} + +void AudioTest::sampleTypeChanged(int idx) +{ + switch (sampleTypesBox->itemText(idx).toInt()) { + case QAudioFormat::SignedInt: + settings.setSampleType(QAudioFormat::SignedInt); + break; + case QAudioFormat::UnSignedInt: + settings.setSampleType(QAudioFormat::UnSignedInt); + break; + case QAudioFormat::Float: + settings.setSampleType(QAudioFormat::Float); + } +} + +void AudioTest::endianChanged(int idx) +{ + switch (endianBox->itemText(idx).toInt()) { + case QAudioFormat::LittleEndian: + settings.setByteOrder(QAudioFormat::LittleEndian); + break; + case QAudioFormat::BigEndian: + settings.setByteOrder(QAudioFormat::BigEndian); + } +} diff --git a/examples/audiodevices/audiodevices.h b/examples/audiodevices/audiodevices.h new file mode 100644 index 0000000000..2725debcc6 --- /dev/null +++ b/examples/audiodevices/audiodevices.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QObject> +#include <QMainWindow> +#include <qaudiodeviceinfo.h> + +#include "ui_audiodevicesbase.h" + +class AudioDevicesBase : public QMainWindow, public Ui::AudioDevicesBase +{ +public: + AudioDevicesBase(QWidget *parent = 0, Qt::WFlags f = 0); + virtual ~AudioDevicesBase(); +}; + +class AudioTest : public AudioDevicesBase +{ + Q_OBJECT +public: + AudioTest(QWidget *parent = 0, Qt::WFlags f = 0); + virtual ~AudioTest(); + + QAudioDeviceInfo deviceInfo; + QAudioFormat settings; + QAudio::Mode mode; + +private slots: + void modeChanged(int idx); + void deviceChanged(int idx); + void freqChanged(int idx); + void channelChanged(int idx); + void codecChanged(int idx); + void sampleSizeChanged(int idx); + void sampleTypeChanged(int idx); + void endianChanged(int idx); + void test(); + void populateTable(); + +}; + diff --git a/examples/audiodevices/audiodevices.pro b/examples/audiodevices/audiodevices.pro new file mode 100644 index 0000000000..9018624629 --- /dev/null +++ b/examples/audiodevices/audiodevices.pro @@ -0,0 +1,21 @@ +TEMPLATE = app +CONFIG += example + +INCLUDEPATH += ../../src/multimedia ../../src/multimedia/audio +include(../examples.pri) + +CONFIG += mobility +MOBILITY = multimedia + +QMAKE_RPATHDIR += $$DESTDIR + +HEADERS = audiodevices.h + +SOURCES = audiodevices.cpp \ + main.cpp + +FORMS += audiodevicesbase.ui + +symbian { + TARGET.CAPABILITY = UserEnvironment WriteDeviceData ReadDeviceData +} diff --git a/examples/audiodevices/audiodevicesbase.ui b/examples/audiodevices/audiodevicesbase.ui new file mode 100644 index 0000000000..23b45d7366 --- /dev/null +++ b/examples/audiodevices/audiodevicesbase.ui @@ -0,0 +1,399 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>AudioDevicesBase</class> + <widget class="QMainWindow" name="AudioDevicesBase"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>679</width> + <height>598</height> + </rect> + </property> + <property name="windowTitle"> + <string>Audio Devices</string> + </property> + <widget class="QWidget" name="centralwidget"> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QScrollArea" name="scrollArea"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="widgetResizable"> + <bool>true</bool> + </property> + <widget class="QWidget" name="scrollAreaWidgetContents"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>659</width> + <height>558</height> + </rect> + </property> + <layout class="QGridLayout" name="gridLayout_4"> + <item row="0" column="0"> + <layout class="QGridLayout" name="gridLayout_2"> + <item row="0" column="0"> + <widget class="QLabel" name="modeLabel"> + <property name="text"> + <string>Mode</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLabel" name="deviceLabel"> + <property name="text"> + <string>Device</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QComboBox" name="modeBox"> + <item> + <property name="text"> + <string>Input</string> + </property> + </item> + <item> + <property name="text"> + <string>Output</string> + </property> + </item> + </widget> + </item> + <item row="1" column="1"> + <widget class="QComboBox" name="deviceBox"/> + </item> + <item row="2" column="0" colspan="2"> + <widget class="QTabWidget" name="tabWidget"> + <property name="currentIndex"> + <number>0</number> + </property> + <widget class="QWidget" name="testFormatTab"> + <attribute name="title"> + <string>Test format</string> + </attribute> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="1"> + <widget class="QLabel" name="actualLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> + </property> + <property name="text"> + <string><i>Actual Settings</i></string> + </property> + <property name="textFormat"> + <enum>Qt::RichText</enum> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + <item row="0" column="2"> + <widget class="QLabel" name="nearestLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> + </property> + <property name="text"> + <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:italic;">Nearest Settings</span></p></body></html></string> + </property> + <property name="textFormat"> + <enum>Qt::RichText</enum> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QComboBox" name="frequencyBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + <item row="3" column="2"> + <widget class="QLineEdit" name="nearestFreq"> + <property name="enabled"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="5" column="1"> + <widget class="QComboBox" name="channelsBox"/> + </item> + <item row="5" column="2"> + <widget class="QLineEdit" name="nearestChannel"> + <property name="enabled"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="9" column="1"> + <widget class="QComboBox" name="sampleSizesBox"/> + </item> + <item row="9" column="2"> + <widget class="QLineEdit" name="nearestSampleSize"> + <property name="enabled"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="14" column="1"> + <widget class="QComboBox" name="endianBox"/> + </item> + <item row="14" column="2"> + <widget class="QLineEdit" name="nearestEndian"> + <property name="enabled"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="15" column="1"> + <widget class="QPushButton" name="testButton"> + <property name="text"> + <string>Test</string> + </property> + </widget> + </item> + <item row="15" column="2"> + <widget class="QLabel" name="testResult"> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="actualFreqLabel"> + <property name="text"> + <string>Frequency (Hz)</string> + </property> + </widget> + </item> + <item row="5" column="0"> + <widget class="QLabel" name="actualChannelLabel"> + <property name="text"> + <string>Channels</string> + </property> + </widget> + </item> + <item row="9" column="0"> + <widget class="QLabel" name="actualSampleSizeLabel"> + <property name="text"> + <string>Sample size (bits)</string> + </property> + </widget> + </item> + <item row="14" column="0"> + <widget class="QLabel" name="actualEndianLabel"> + <property name="text"> + <string>Endianess</string> + </property> + </widget> + </item> + <item row="16" column="0" colspan="3"> + <widget class="QLabel" name="label"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Note: an invalid codec 'audio/test' exists in order to allow an invalid format to be constructed, and therefore to trigger a 'nearest format' calculation.</string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="actualCodecLabel"> + <property name="text"> + <string>Codec</string> + </property> + </widget> + </item> + <item row="2" column="2"> + <widget class="QLineEdit" name="nearestCodec"> + <property name="enabled"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QComboBox" name="codecsBox"/> + </item> + <item row="6" column="0"> + <widget class="QLabel" name="actualSampleTypeLabel"> + <property name="text"> + <string>SampleType</string> + </property> + </widget> + </item> + <item row="6" column="1"> + <widget class="QComboBox" name="sampleTypesBox"/> + </item> + <item row="6" column="2"> + <widget class="QLineEdit" name="nearestSampleType"> + <property name="enabled"> + <bool>false</bool> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="tab"> + <attribute name="title"> + <string>All formats</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QPushButton" name="populateTableButton"> + <property name="text"> + <string>Populate table</string> + </property> + </widget> + </item> + <item> + <widget class="QTableWidget" name="allFormatsTable"> + <property name="editTriggers"> + <set>QAbstractItemView::NoEditTriggers</set> + </property> + <property name="dragDropOverwriteMode"> + <bool>false</bool> + </property> + <property name="selectionMode"> + <enum>QAbstractItemView::NoSelection</enum> + </property> + <property name="selectionBehavior"> + <enum>QAbstractItemView::SelectItems</enum> + </property> + <property name="textElideMode"> + <enum>Qt::ElideNone</enum> + </property> + <property name="sortingEnabled"> + <bool>false</bool> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + <property name="cornerButtonEnabled"> + <bool>false</bool> + </property> + <attribute name="horizontalHeaderHighlightSections"> + <bool>false</bool> + </attribute> + <attribute name="verticalHeaderVisible"> + <bool>false</bool> + </attribute> + <attribute name="verticalHeaderHighlightSections"> + <bool>false</bool> + </attribute> + <attribute name="verticalHeaderVisible"> + <bool>false</bool> + </attribute> + <attribute name="horizontalHeaderHighlightSections"> + <bool>false</bool> + </attribute> + <attribute name="verticalHeaderHighlightSections"> + <bool>false</bool> + </attribute> + <column> + <property name="text"> + <string>Codec</string> + </property> + <property name="textAlignment"> + <set>AlignHCenter|AlignVCenter|AlignCenter</set> + </property> + </column> + <column> + <property name="text"> + <string>Frequency (Hz)</string> + </property> + <property name="textAlignment"> + <set>AlignHCenter|AlignVCenter|AlignCenter</set> + </property> + </column> + <column> + <property name="text"> + <string>Channels</string> + </property> + <property name="textAlignment"> + <set>AlignHCenter|AlignVCenter|AlignCenter</set> + </property> + </column> + <column> + <property name="text"> + <string>Sample type</string> + </property> + <property name="textAlignment"> + <set>AlignHCenter|AlignVCenter|AlignCenter</set> + </property> + </column> + <column> + <property name="text"> + <string>Sample size (bits)</string> + </property> + <property name="textAlignment"> + <set>AlignHCenter|AlignVCenter|AlignCenter</set> + </property> + </column> + <column> + <property name="text"> + <string>Endianness</string> + </property> + <property name="textAlignment"> + <set>AlignHCenter|AlignVCenter|AlignCenter</set> + </property> + </column> + </widget> + </item> + </layout> + </widget> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </widget> + </item> + </layout> + </widget> + <widget class="QStatusBar" name="statusbar"/> + </widget> + <resources/> + <connections/> +</ui> diff --git a/examples/audiodevices/main.cpp b/examples/audiodevices/main.cpp new file mode 100644 index 0000000000..8ca4932509 --- /dev/null +++ b/examples/audiodevices/main.cpp @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtGui> + +#include "audiodevices.h" + +int main(int argv, char **args) +{ + QApplication app(argv, args); + app.setApplicationName("Audio Device Test"); + + AudioTest audio; +#ifdef Q_OS_SYMBIAN + audio.showMaximized(); +#else + audio.show(); +#endif + + return app.exec(); +} diff --git a/examples/audioinput/audioinput.cpp b/examples/audioinput/audioinput.cpp new file mode 100644 index 0000000000..1b101fa3cd --- /dev/null +++ b/examples/audioinput/audioinput.cpp @@ -0,0 +1,375 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <stdlib.h> +#include <math.h> + +#include <QDebug> +#include <QPainter> +#include <QVBoxLayout> + +#include <qaudiodeviceinfo.h> +#include <qaudioinput.h> + +#include <QtCore/qendian.h> + +#include "audioinput.h" + +const QString InputTest::PushModeLabel(tr("Enable push mode")); +const QString InputTest::PullModeLabel(tr("Enable pull mode")); +const QString InputTest::SuspendLabel(tr("Suspend recording")); +const QString InputTest::ResumeLabel(tr("Resume recording")); + +const int BufferSize = 4096; + +AudioInfo::AudioInfo(const QAudioFormat &format, QObject *parent) + : QIODevice(parent) + , m_format(format) + , m_maxAmplitude(0) + , m_level(0.0) + +{ + switch (m_format.sampleSize()) { + case 8: + switch (m_format.sampleType()) { + case QAudioFormat::UnSignedInt: + m_maxAmplitude = 255; + break; + case QAudioFormat::SignedInt: + m_maxAmplitude = 127; + break; + default: + break; + } + break; + case 16: + switch (m_format.sampleType()) { + case QAudioFormat::UnSignedInt: + m_maxAmplitude = 65535; + break; + case QAudioFormat::SignedInt: + m_maxAmplitude = 32767; + break; + default: + break; + } + break; + default: + break; + } +} + +AudioInfo::~AudioInfo() +{ +} + +void AudioInfo::start() +{ + open(QIODevice::WriteOnly); +} + +void AudioInfo::stop() +{ + close(); +} + +qint64 AudioInfo::readData(char *data, qint64 maxlen) +{ + Q_UNUSED(data) + Q_UNUSED(maxlen) + + return 0; +} + +qint64 AudioInfo::writeData(const char *data, qint64 len) +{ + if (m_maxAmplitude) { + Q_ASSERT(m_format.sampleSize() % 8 == 0); + const int channelBytes = m_format.sampleSize() / 8; + const int sampleBytes = m_format.channels() * channelBytes; + Q_ASSERT(len % sampleBytes == 0); + const int numSamples = len / sampleBytes; + + quint16 maxValue = 0; + const unsigned char *ptr = reinterpret_cast<const unsigned char *>(data); + + for (int i = 0; i < numSamples; ++i) { + for(int j = 0; j < m_format.channels(); ++j) { + quint16 value = 0; + + if (m_format.sampleSize() == 8 && m_format.sampleType() == QAudioFormat::UnSignedInt) { + value = *reinterpret_cast<const quint8*>(ptr); + } else if (m_format.sampleSize() == 8 && m_format.sampleType() == QAudioFormat::SignedInt) { + value = qAbs(*reinterpret_cast<const qint8*>(ptr)); + } else if (m_format.sampleSize() == 16 && m_format.sampleType() == QAudioFormat::UnSignedInt) { + if (m_format.byteOrder() == QAudioFormat::LittleEndian) + value = qFromLittleEndian<quint16>(ptr); + else + value = qFromBigEndian<quint16>(ptr); + } else if (m_format.sampleSize() == 16 && m_format.sampleType() == QAudioFormat::SignedInt) { + if (m_format.byteOrder() == QAudioFormat::LittleEndian) + value = qAbs(qFromLittleEndian<qint16>(ptr)); + else + value = qAbs(qFromBigEndian<qint16>(ptr)); + } + + maxValue = qMax(value, maxValue); + ptr += channelBytes; + } + } + + maxValue = qMin(maxValue, m_maxAmplitude); + m_level = qreal(maxValue) / m_maxAmplitude; + } + + emit update(); + return len; +} + +RenderArea::RenderArea(QWidget *parent) + : QWidget(parent) +{ + setBackgroundRole(QPalette::Base); + setAutoFillBackground(true); + + m_level = 0; + setMinimumHeight(30); + setMinimumWidth(200); +} + +void RenderArea::paintEvent(QPaintEvent * /* event */) +{ + QPainter painter(this); + + painter.setPen(Qt::black); + painter.drawRect(QRect(painter.viewport().left()+10, + painter.viewport().top()+10, + painter.viewport().right()-20, + painter.viewport().bottom()-20)); + if (m_level == 0.0) + return; + + painter.setPen(Qt::red); + + int pos = ((painter.viewport().right()-20)-(painter.viewport().left()+11))*m_level; + for (int i = 0; i < 10; ++i) { + int x1 = painter.viewport().left()+11; + int y1 = painter.viewport().top()+10+i; + int x2 = painter.viewport().left()+20+pos; + int y2 = painter.viewport().top()+10+i; + if (x2 < painter.viewport().left()+10) + x2 = painter.viewport().left()+10; + + painter.drawLine(QPoint(x1, y1),QPoint(x2, y2)); + } +} + +void RenderArea::setLevel(qreal value) +{ + m_level = value; + repaint(); +} + + +InputTest::InputTest() + : m_canvas(0) + , m_modeButton(0) + , m_suspendResumeButton(0) + , m_deviceBox(0) + , m_device(QAudioDeviceInfo::defaultInputDevice()) + , m_audioInfo(0) + , m_audioInput(0) + , m_input(0) + , m_pullMode(false) + , m_buffer(BufferSize, 0) +{ + initializeWindow(); + initializeAudio(); +} + +InputTest::~InputTest() {} + +void InputTest::initializeWindow() +{ + QScopedPointer<QWidget> window(new QWidget); + QScopedPointer<QVBoxLayout> layout(new QVBoxLayout); + + m_canvas = new RenderArea(this); + layout->addWidget(m_canvas); + + m_deviceBox = new QComboBox(this); + QList<QAudioDeviceInfo> devices = QAudioDeviceInfo::availableDevices(QAudio::AudioInput); + for(int i = 0; i < devices.size(); ++i) + m_deviceBox->addItem(devices.at(i).deviceName(), qVariantFromValue(devices.at(i))); + + connect(m_deviceBox, SIGNAL(activated(int)), SLOT(deviceChanged(int))); + layout->addWidget(m_deviceBox); + + m_modeButton = new QPushButton(this); + m_modeButton->setText(PushModeLabel); + connect(m_modeButton, SIGNAL(clicked()), SLOT(toggleMode())); + layout->addWidget(m_modeButton); + + m_suspendResumeButton = new QPushButton(this); + m_suspendResumeButton->setText(SuspendLabel); + connect(m_suspendResumeButton, SIGNAL(clicked()), SLOT(toggleSuspend())); + layout->addWidget(m_suspendResumeButton); + + window->setLayout(layout.data()); + layout.take(); // ownership transferred + + setCentralWidget(window.data()); + QWidget *const windowPtr = window.take(); // ownership transferred + windowPtr->show(); +} + +void InputTest::initializeAudio() +{ + m_pullMode = true; + + m_format.setFrequency(8000); + m_format.setChannels(1); + m_format.setSampleSize(16); + m_format.setSampleType(QAudioFormat::SignedInt); + m_format.setByteOrder(QAudioFormat::LittleEndian); + m_format.setCodec("audio/pcm"); + + QAudioDeviceInfo info(QAudioDeviceInfo::defaultInputDevice()); + if (!info.isFormatSupported(m_format)) { + qWarning() << "Default format not supported - trying to use nearest"; + m_format = info.nearestFormat(m_format); + } + + m_audioInfo = new AudioInfo(m_format, this); + connect(m_audioInfo, SIGNAL(update()), SLOT(refreshDisplay())); + + createAudioInput(); +} + +void InputTest::createAudioInput() +{ + m_audioInput = new QAudioInput(m_device, m_format, this); + connect(m_audioInput, SIGNAL(notify()), SLOT(notified())); + connect(m_audioInput, SIGNAL(stateChanged(QAudio::State)), SLOT(stateChanged(QAudio::State))); + m_audioInfo->start(); + m_audioInput->start(m_audioInfo); +} + +void InputTest::notified() +{ + qWarning() << "bytesReady = " << m_audioInput->bytesReady() + << ", " << "elapsedUSecs = " <<m_audioInput->elapsedUSecs() + << ", " << "processedUSecs = "<<m_audioInput->processedUSecs(); +} + +void InputTest::readMore() +{ + if(!m_audioInput) + return; + qint64 len = m_audioInput->bytesReady(); + if(len > 4096) + len = 4096; + qint64 l = m_input->read(m_buffer.data(), len); + if(l > 0) { + m_audioInfo->write(m_buffer.constData(), l); + } +} + +void InputTest::toggleMode() +{ + // Change bewteen pull and push modes + m_audioInput->stop(); + + if (m_pullMode) { + m_modeButton->setText(PullModeLabel); + m_input = m_audioInput->start(); + connect(m_input, SIGNAL(readyRead()), SLOT(readMore())); + m_pullMode = false; + } else { + m_modeButton->setText(PushModeLabel); + m_pullMode = true; + m_audioInput->start(m_audioInfo); + } + + m_suspendResumeButton->setText(SuspendLabel); +} + +void InputTest::toggleSuspend() +{ + // toggle suspend/resume + if(m_audioInput->state() == QAudio::SuspendedState) { + qWarning() << "status: Suspended, resume()"; + m_audioInput->resume(); + m_suspendResumeButton->setText(SuspendLabel); + } else if (m_audioInput->state() == QAudio::ActiveState) { + qWarning() << "status: Active, suspend()"; + m_audioInput->suspend(); + m_suspendResumeButton->setText(ResumeLabel); + } else if (m_audioInput->state() == QAudio::StoppedState) { + qWarning() << "status: Stopped, resume()"; + m_audioInput->resume(); + m_suspendResumeButton->setText(SuspendLabel); + } else if (m_audioInput->state() == QAudio::IdleState) { + qWarning() << "status: IdleState"; + } +} + +void InputTest::stateChanged(QAudio::State state) +{ + qWarning() << "state = " << state; +} + +void InputTest::refreshDisplay() +{ + m_canvas->setLevel(m_audioInfo->level()); + m_canvas->repaint(); +} + +void InputTest::deviceChanged(int index) +{ + m_audioInfo->stop(); + m_audioInput->stop(); + m_audioInput->disconnect(this); + delete m_audioInput; + + m_device = m_deviceBox->itemData(index).value<QAudioDeviceInfo>(); + createAudioInput(); +} diff --git a/examples/audioinput/audioinput.h b/examples/audioinput/audioinput.h new file mode 100644 index 0000000000..be721de3d8 --- /dev/null +++ b/examples/audioinput/audioinput.h @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QPixmap> +#include <QWidget> +#include <QObject> +#include <QMainWindow> +#include <QPushButton> +#include <QComboBox> +#include <QByteArray> + +#include <qaudioinput.h> + +class AudioInfo : public QIODevice +{ + Q_OBJECT +public: + AudioInfo(const QAudioFormat &format, QObject *parent); + ~AudioInfo(); + + void start(); + void stop(); + + qreal level() const { return m_level; } + + qint64 readData(char *data, qint64 maxlen); + qint64 writeData(const char *data, qint64 len); + +private: + const QAudioFormat m_format; + quint16 m_maxAmplitude; + qreal m_level; // 0.0 <= m_level <= 1.0 + +signals: + void update(); +}; + + +class RenderArea : public QWidget +{ + Q_OBJECT + +public: + RenderArea(QWidget *parent = 0); + + void setLevel(qreal value); + +protected: + void paintEvent(QPaintEvent *event); + +private: + qreal m_level; + QPixmap m_pixmap; +}; + +class InputTest : public QMainWindow +{ + Q_OBJECT +public: + InputTest(); + ~InputTest(); + +private: + void initializeWindow(); + void initializeAudio(); + void createAudioInput(); + +private slots: + void refreshDisplay(); + void notified(); + void readMore(); + void toggleMode(); + void toggleSuspend(); + void stateChanged(QAudio::State state); + void deviceChanged(int index); + +private: + // Owned by layout + RenderArea *m_canvas; + QPushButton *m_modeButton; + QPushButton *m_suspendResumeButton; + QComboBox *m_deviceBox; + + QAudioDeviceInfo m_device; + AudioInfo *m_audioInfo; + QAudioFormat m_format; + QAudioInput *m_audioInput; + QIODevice *m_input; + bool m_pullMode; + QByteArray m_buffer; + + static const QString PushModeLabel; + static const QString PullModeLabel; + static const QString SuspendLabel; + static const QString ResumeLabel; +}; + diff --git a/examples/audioinput/audioinput.pro b/examples/audioinput/audioinput.pro new file mode 100644 index 0000000000..ed2b88bdf4 --- /dev/null +++ b/examples/audioinput/audioinput.pro @@ -0,0 +1,16 @@ +TEMPLATE = app +CONFIG += example + +INCLUDEPATH += ../../src/multimedia ../../src/multimedia/audio +include(../examples.pri) + +CONFIG += mobility +MOBILITY = multimedia + +QMAKE_RPATHDIR += $$DESTDIR + +HEADERS = audioinput.h + +SOURCES = audioinput.cpp \ + main.cpp + diff --git a/examples/audioinput/main.cpp b/examples/audioinput/main.cpp new file mode 100644 index 0000000000..42104cffd7 --- /dev/null +++ b/examples/audioinput/main.cpp @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtGui> + +#include "audioinput.h" + +int main(int argv, char **args) +{ + QApplication app(argv, args); + app.setApplicationName("Audio Input Test"); + + InputTest input; + input.show(); + + return app.exec(); +} diff --git a/examples/audiooutput/audiooutput.cpp b/examples/audiooutput/audiooutput.cpp new file mode 100644 index 0000000000..c4f767179e --- /dev/null +++ b/examples/audiooutput/audiooutput.cpp @@ -0,0 +1,315 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QDebug> +#include <QVBoxLayout> + +#include <qaudiooutput.h> +#include <qaudiodeviceinfo.h> +#include <QtCore/qmath.h> +#include <QtCore/qendian.h> +#include "audiooutput.h" + +const QString AudioTest::PushModeLabel(tr("Enable push mode")); +const QString AudioTest::PullModeLabel(tr("Enable pull mode")); +const QString AudioTest::SuspendLabel(tr("Suspend playback")); +const QString AudioTest::ResumeLabel(tr("Resume playback")); + +const int DurationSeconds = 1; +const int ToneFrequencyHz = 600; +const int DataFrequencyHz = 44100; +const int BufferSize = 32768; + + +Generator::Generator(const QAudioFormat &format, + qint64 durationUs, + int frequency, + QObject *parent) + : QIODevice(parent) + , m_pos(0) +{ + generateData(format, durationUs, frequency); +} + +Generator::~Generator() +{ + +} + +void Generator::start() +{ + open(QIODevice::ReadOnly); +} + +void Generator::stop() +{ + m_pos = 0; + close(); +} + +void Generator::generateData(const QAudioFormat &format, qint64 durationUs, int frequency) +{ + const int channelBytes = format.sampleSize() / 8; + const int sampleBytes = format.channels() * channelBytes; + + qint64 length = (format.frequency() * format.channels() * (format.sampleSize() / 8)) + * durationUs / 100000; + + Q_ASSERT(length % sampleBytes == 0); + Q_UNUSED(sampleBytes) // suppress warning in release builds + + m_buffer.resize(length); + unsigned char *ptr = reinterpret_cast<unsigned char *>(m_buffer.data()); + int sampleIndex = 0; + + while (length) { + const qreal x = qSin(2 * M_PI * frequency * qreal(sampleIndex % format.frequency()) / format.frequency()); + for (int i=0; i<format.channels(); ++i) { + if (format.sampleSize() == 8 && format.sampleType() == QAudioFormat::UnSignedInt) { + const quint8 value = static_cast<quint8>((1.0 + x) / 2 * 255); + *reinterpret_cast<quint8*>(ptr) = value; + } else if (format.sampleSize() == 8 && format.sampleType() == QAudioFormat::SignedInt) { + const qint8 value = static_cast<qint8>(x * 127); + *reinterpret_cast<quint8*>(ptr) = value; + } else if (format.sampleSize() == 16 && format.sampleType() == QAudioFormat::UnSignedInt) { + quint16 value = static_cast<quint16>((1.0 + x) / 2 * 65535); + if (format.byteOrder() == QAudioFormat::LittleEndian) + qToLittleEndian<quint16>(value, ptr); + else + qToBigEndian<quint16>(value, ptr); + } else if (format.sampleSize() == 16 && format.sampleType() == QAudioFormat::SignedInt) { + qint16 value = static_cast<qint16>(x * 32767); + if (format.byteOrder() == QAudioFormat::LittleEndian) + qToLittleEndian<qint16>(value, ptr); + else + qToBigEndian<qint16>(value, ptr); + } + + ptr += channelBytes; + length -= channelBytes; + } + ++sampleIndex; + } +} + +qint64 Generator::readData(char *data, qint64 len) +{ + qint64 total = 0; + while (len - total) { + const qint64 chunk = qMin((m_buffer.size() - m_pos), len - total); + memcpy(data, m_buffer.constData() + m_pos, chunk); + m_pos = (m_pos + chunk) % m_buffer.size(); + total += chunk; + } + return total; +} + +qint64 Generator::writeData(const char *data, qint64 len) +{ + Q_UNUSED(data); + Q_UNUSED(len); + + return 0; +} + +qint64 Generator::bytesAvailable() const +{ + return m_buffer.size() + QIODevice::bytesAvailable(); +} + +AudioTest::AudioTest() + : m_pullTimer(new QTimer(this)) + , m_modeButton(0) + , m_suspendResumeButton(0) + , m_deviceBox(0) + , m_device(QAudioDeviceInfo::defaultOutputDevice()) + , m_generator(0) + , m_audioOutput(0) + , m_output(0) + , m_buffer(BufferSize, 0) +{ + initializeWindow(); + initializeAudio(); +} + +void AudioTest::initializeWindow() +{ + QScopedPointer<QWidget> window(new QWidget); + QScopedPointer<QVBoxLayout> layout(new QVBoxLayout); + + m_deviceBox = new QComboBox(this); + foreach (const QAudioDeviceInfo &deviceInfo, QAudioDeviceInfo::availableDevices(QAudio::AudioOutput)) + m_deviceBox->addItem(deviceInfo.deviceName(), qVariantFromValue(deviceInfo)); + connect(m_deviceBox,SIGNAL(activated(int)),SLOT(deviceChanged(int))); + layout->addWidget(m_deviceBox); + + m_modeButton = new QPushButton(this); + m_modeButton->setText(PushModeLabel); + connect(m_modeButton, SIGNAL(clicked()), SLOT(toggleMode())); + layout->addWidget(m_modeButton); + + m_suspendResumeButton = new QPushButton(this); + m_suspendResumeButton->setText(SuspendLabel); + connect(m_suspendResumeButton, SIGNAL(clicked()), SLOT(toggleSuspendResume())); + layout->addWidget(m_suspendResumeButton); + + window->setLayout(layout.data()); + layout.take(); // ownership transferred + + setCentralWidget(window.data()); + QWidget *const windowPtr = window.take(); // ownership transferred + windowPtr->show(); +} + +void AudioTest::initializeAudio() +{ + connect(m_pullTimer, SIGNAL(timeout()), SLOT(pullTimerExpired())); + + m_pullMode = true; + + m_format.setFrequency(DataFrequencyHz); + m_format.setChannels(1); + m_format.setSampleSize(16); + m_format.setCodec("audio/pcm"); + m_format.setByteOrder(QAudioFormat::LittleEndian); + m_format.setSampleType(QAudioFormat::SignedInt); + + QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice()); + if (!info.isFormatSupported(m_format)) { + qWarning() << "Default format not supported - trying to use nearest"; + m_format = info.nearestFormat(m_format); + } + + m_generator = new Generator(m_format, DurationSeconds*1000000, ToneFrequencyHz, this); + + createAudioOutput(); +} + +void AudioTest::createAudioOutput() +{ + delete m_audioOutput; + m_audioOutput = 0; + m_audioOutput = new QAudioOutput(m_device, m_format, this); + connect(m_audioOutput, SIGNAL(notify()), SLOT(notified())); + connect(m_audioOutput, SIGNAL(stateChanged(QAudio::State)), SLOT(stateChanged(QAudio::State))); + m_generator->start(); + m_audioOutput->start(m_generator); +} + +AudioTest::~AudioTest() +{ + +} + +void AudioTest::deviceChanged(int index) +{ + m_pullTimer->stop(); + m_generator->stop(); + m_audioOutput->stop(); + m_audioOutput->disconnect(this); + m_device = m_deviceBox->itemData(index).value<QAudioDeviceInfo>(); + createAudioOutput(); +} + +void AudioTest::notified() +{ + qWarning() << "bytesFree = " << m_audioOutput->bytesFree() + << ", " << "elapsedUSecs = " << m_audioOutput->elapsedUSecs() + << ", " << "processedUSecs = " << m_audioOutput->processedUSecs(); +} + +void AudioTest::pullTimerExpired() +{ + if (m_audioOutput && m_audioOutput->state() != QAudio::StoppedState) { + int chunks = m_audioOutput->bytesFree()/m_audioOutput->periodSize(); + while (chunks) { + const qint64 len = m_generator->read(m_buffer.data(), m_audioOutput->periodSize()); + if (len) + m_output->write(m_buffer.data(), len); + if (len != m_audioOutput->periodSize()) + break; + --chunks; + } + } +} + +void AudioTest::toggleMode() +{ + m_pullTimer->stop(); + m_audioOutput->stop(); + + if (m_pullMode) { + m_modeButton->setText(PullModeLabel); + m_output = m_audioOutput->start(); + m_pullMode = false; + m_pullTimer->start(20); + } else { + m_modeButton->setText(PushModeLabel); + m_pullMode = true; + m_audioOutput->start(m_generator); + } + + m_suspendResumeButton->setText(SuspendLabel); +} + +void AudioTest::toggleSuspendResume() +{ + if (m_audioOutput->state() == QAudio::SuspendedState) { + qWarning() << "status: Suspended, resume()"; + m_audioOutput->resume(); + m_suspendResumeButton->setText(SuspendLabel); + } else if (m_audioOutput->state() == QAudio::ActiveState) { + qWarning() << "status: Active, suspend()"; + m_audioOutput->suspend(); + m_suspendResumeButton->setText(ResumeLabel); + } else if (m_audioOutput->state() == QAudio::StoppedState) { + qWarning() << "status: Stopped, resume()"; + m_audioOutput->resume(); + m_suspendResumeButton->setText(SuspendLabel); + } else if (m_audioOutput->state() == QAudio::IdleState) { + qWarning() << "status: IdleState"; + } +} + +void AudioTest::stateChanged(QAudio::State state) +{ + qWarning() << "state = " << state; +} diff --git a/examples/audiooutput/audiooutput.h b/examples/audiooutput/audiooutput.h new file mode 100644 index 0000000000..05f9c38555 --- /dev/null +++ b/examples/audiooutput/audiooutput.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <math.h> + +#include <QObject> +#include <QMainWindow> +#include <QIODevice> +#include <QTimer> +#include <QPushButton> +#include <QComboBox> +#include <QByteArray> + +#include <qaudiooutput.h> + +class Generator : public QIODevice +{ + Q_OBJECT +public: + Generator(const QAudioFormat &format, qint64 durationUs, int frequency, QObject *parent); + ~Generator(); + + void start(); + void stop(); + + qint64 readData(char *data, qint64 maxlen); + qint64 writeData(const char *data, qint64 len); + qint64 bytesAvailable() const; + +private: + void generateData(const QAudioFormat &format, qint64 durationUs, int frequency); + +private: + qint64 m_pos; + QByteArray m_buffer; +}; + +class AudioTest : public QMainWindow +{ + Q_OBJECT +public: + AudioTest(); + ~AudioTest(); + +private: + void initializeWindow(); + void initializeAudio(); + void createAudioOutput(); + +private: + QTimer* m_pullTimer; + + // Owned by layout + QPushButton* m_modeButton; + QPushButton* m_suspendResumeButton; + QComboBox* m_deviceBox; + + QAudioDeviceInfo m_device; + Generator* m_generator; + QAudioOutput* m_audioOutput; + QIODevice* m_output; // not owned + QAudioFormat m_format; + + bool m_pullMode; + QByteArray m_buffer; + + static const QString PushModeLabel; + static const QString PullModeLabel; + static const QString SuspendLabel; + static const QString ResumeLabel; + +private slots: + void notified(); + void pullTimerExpired(); + void toggleMode(); + void toggleSuspendResume(); + void stateChanged(QAudio::State state); + void deviceChanged(int index); +}; + diff --git a/examples/audiooutput/audiooutput.pro b/examples/audiooutput/audiooutput.pro new file mode 100644 index 0000000000..85de866027 --- /dev/null +++ b/examples/audiooutput/audiooutput.pro @@ -0,0 +1,15 @@ +TEMPLATE = app +CONFIG += example + +INCLUDEPATH += ../../src/multimedia ../../src/multimedia/audio +include(../examples.pri) + +CONFIG += mobility +MOBILITY = multimedia + +QMAKE_RPATHDIR += $$DESTDIR + +HEADERS = audiooutput.h + +SOURCES = audiooutput.cpp \ + main.cpp diff --git a/examples/audiooutput/main.cpp b/examples/audiooutput/main.cpp new file mode 100644 index 0000000000..b2b3a068a2 --- /dev/null +++ b/examples/audiooutput/main.cpp @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtGui> + +#include "audiooutput.h" + +int main(int argv, char **args) +{ + QApplication app(argv, args); + app.setApplicationName("Audio Output Test"); + + AudioTest audio; + audio.show(); + + return app.exec(); +} diff --git a/examples/audiorecorder/audiorecorder.cpp b/examples/audiorecorder/audiorecorder.cpp index 8011bdcd24..63a6ddacdd 100644 --- a/examples/audiorecorder/audiorecorder.cpp +++ b/examples/audiorecorder/audiorecorder.cpp @@ -45,7 +45,7 @@ #include <qmediaservice.h> #include <qaudioencodercontrol.h> -#include <QtMultimedia/qaudioformat.h> +#include <qaudioformat.h> #include "audiorecorder.h" @@ -54,18 +54,9 @@ AudioRecorder::AudioRecorder() audiosource = new QAudioCaptureSource; capture = new QMediaRecorder(audiosource); - if (capture->supportedAudioCodecs().size() > 0) { - QAudioEncoderSettings audioSettings; - audioSettings.setQuality(QtMediaServices::LowQuality); - audioSettings.setEncodingMode(QtMediaServices::ConstantQualityEncoding); - audioSettings.setCodec(capture->supportedAudioCodecs().first()); - capture->setEncodingSettings(audioSettings,QVideoEncoderSettings(), - capture->supportedContainers().first()); - } - // set a default file #ifdef Q_OS_SYMBIAN - capture->setOutputLocation(recordPathAudio(QUrl())); + capture->setOutputLocation(recordPathAudio(QUrl())); #else capture->setOutputLocation(QUrl("test.raw")); #endif @@ -82,6 +73,12 @@ AudioRecorder::AudioRecorder() deviceBox->setSizePolicy(QSizePolicy::MinimumExpanding,QSizePolicy::Fixed); deviceBox->setMinimumSize(200,10); + QLabel* encmodeLabel = new QLabel; + encmodeLabel->setText(tr("Encode Mode")); + encModeBox = new QComboBox(this); + encModeBox->setSizePolicy(QSizePolicy::MinimumExpanding,QSizePolicy::Fixed); + encModeBox->setMinimumSize(200,10); + QLabel* containerLabel = new QLabel; containerLabel->setText(tr("File Container")); containersBox = new QComboBox(this); @@ -92,20 +89,20 @@ AudioRecorder::AudioRecorder() codecLabel->setText(tr("Audio Codec")); codecsBox = new QComboBox(this); codecsBox->setSizePolicy(QSizePolicy::MinimumExpanding,QSizePolicy::Fixed); - codecsBox->setMinimumSize(200,10); - + codecsBox->setMinimumSize(200,10); + QLabel* sampleRateLabel = new QLabel; sampleRateLabel->setText(tr("Sample Rate")); sampleRateBox = new QComboBox(this); sampleRateBox->setSizePolicy(QSizePolicy::MinimumExpanding,QSizePolicy::Fixed); sampleRateBox->setMinimumSize(200,10); - + QLabel* channelLabel = new QLabel; channelLabel->setText(tr("Channel count")); channelBox = new QComboBox(this); channelBox->setSizePolicy(QSizePolicy::MinimumExpanding,QSizePolicy::Fixed); channelBox->setMinimumSize(200,10); - + QLabel* qualityLabel = new QLabel; qualityLabel->setText(tr("Audio Quality")); qualityBox = new QComboBox(this); @@ -116,7 +113,14 @@ AudioRecorder::AudioRecorder() for(int i = 0; i < inputs.size(); i++) deviceBox->addItem(inputs.at(i)); + QList<QString> encmodes; + encmodes <<"ConstantQuality"<<"ConstantBitRate"; + for(int i = 0; i < encmodes.size(); i++) + encModeBox->addItem(encmodes.at(i)); + QStringList codecs = capture->supportedAudioCodecs(); + if (codecs.count() == 2) + swap(codecs[0], codecs[1]); for(int i = 0; i < codecs.count(); i++) codecsBox->addItem(codecs.at(i)); @@ -124,19 +128,19 @@ AudioRecorder::AudioRecorder() for(int i = 0; i < containers.count(); i++) containersBox->addItem(containers.at(i)); - QList<int> samplerates = capture->supportedAudioSampleRates(); - for(int i = 0; i < samplerates.count(); i++) { + QList<int> samplerates = capture->supportedAudioSampleRates(); + for(int i = 0; i < samplerates.count(); i++) { QString rateString = QString("%1").arg(samplerates.at(i)); - sampleRateBox->addItem(rateString, QVariant(samplerates.at(i))); + sampleRateBox->addItem(rateString, QVariant(samplerates.at(i))); } - + QList<int> channels; - channels <<1<<2; - for(int i = 0; i < channels.count(); i++) { + channels <<1<<2; + for(int i = 0; i < channels.count(); i++) { QString channelString = QString("%1").arg(channels.at(i)); - channelBox->addItem(channelString, QVariant(channels.at(i))); + channelBox->addItem(channelString, QVariant(channels.at(i))); } - + qualityBox->addItem(tr("Low")); qualityBox->addItem(tr("Medium")); qualityBox->addItem(tr("High")); @@ -145,59 +149,72 @@ AudioRecorder::AudioRecorder() connect(capture, SIGNAL(stateChanged(QMediaRecorder::State)), this, SLOT(stateChanged(QMediaRecorder::State))); connect(capture, SIGNAL(error(QMediaRecorder::Error)), this, SLOT(errorChanged(QMediaRecorder::Error))); + if (codecs.count() > 0) { + QAudioEncoderSettings audioSettings; + audioSettings.setQuality(QtMultimediaKit::LowQuality); + audioSettings.setEncodingMode(QtMultimediaKit::ConstantQualityEncoding); + audioSettings.setCodec(codecs.first()); + capture->setEncodingSettings(audioSettings,QVideoEncoderSettings(), + containers.first()); + } + layout->addWidget(deviceLabel,0,0,Qt::AlignHCenter); connect(deviceBox,SIGNAL(activated(int)),SLOT(deviceChanged(int))); layout->addWidget(deviceBox,0,1,1,3,Qt::AlignLeft); - layout->addWidget(containerLabel,1,0,Qt::AlignHCenter); + layout->addWidget(encmodeLabel,1,0,Qt::AlignHCenter); + connect(encModeBox,SIGNAL(activated(int)),SLOT(encmodeChanged(int))); + layout->addWidget(encModeBox,1,1,1,3,Qt::AlignLeft); + + layout->addWidget(containerLabel,2,0,Qt::AlignHCenter); connect(containersBox,SIGNAL(activated(int)),SLOT(containerChanged(int))); - layout->addWidget(containersBox,1,1,1,3,Qt::AlignLeft); + layout->addWidget(containersBox,2,1,1,3,Qt::AlignLeft); - layout->addWidget(codecLabel,2,0,Qt::AlignHCenter); + layout->addWidget(codecLabel,3,0,Qt::AlignHCenter); connect(codecsBox,SIGNAL(activated(int)),SLOT(codecChanged(int))); - layout->addWidget(codecsBox,2,1,1,3,Qt::AlignLeft); - - layout->addWidget(sampleRateLabel,3,0,Qt::AlignHCenter); + layout->addWidget(codecsBox,3,1,1,3,Qt::AlignLeft); + + layout->addWidget(sampleRateLabel,4,0,Qt::AlignHCenter); connect(sampleRateBox,SIGNAL(activated(int)),SLOT(sampleRateChanged(int))); - layout->addWidget(sampleRateBox,3,1,1,3,Qt::AlignLeft); - - layout->addWidget(channelLabel,4,0,Qt::AlignHCenter); + layout->addWidget(sampleRateBox,4,1,1,3,Qt::AlignLeft); + + layout->addWidget(channelLabel,5,0,Qt::AlignHCenter); connect(channelBox,SIGNAL(activated(int)),SLOT(channelCountChanged(int))); - layout->addWidget(channelBox,4,1,1,3,Qt::AlignLeft); - - layout->addWidget(qualityLabel,5,0,Qt::AlignHCenter); + layout->addWidget(channelBox,5,1,1,3,Qt::AlignLeft); + + layout->addWidget(qualityLabel,6,0,Qt::AlignHCenter); connect(qualityBox,SIGNAL(activated(int)),SLOT(qualityChanged(int))); - layout->addWidget(qualityBox,5,1,1,3,Qt::AlignLeft); + layout->addWidget(qualityBox,6,1,1,3,Qt::AlignLeft); fileButton = new QPushButton(this); - fileButton->setText(tr("Output File")); + fileButton->setText(tr("Output File")); connect(fileButton,SIGNAL(clicked()),SLOT(selectOutputFile())); - layout->addWidget(fileButton,6,0,Qt::AlignHCenter); - - pauseButton = new QPushButton(this); + layout->addWidget(fileButton,7,0,Qt::AlignHCenter); + + pauseButton = new QPushButton(this); pauseButton->setText(tr("Pause")); connect(pauseButton,SIGNAL(clicked()),SLOT(togglePause())); - layout->addWidget(pauseButton,6,1,Qt::AlignHCenter); + layout->addWidget(pauseButton,7,1,Qt::AlignHCenter); button = new QPushButton(this); button->setText(tr("Record")); connect(button,SIGNAL(clicked()),SLOT(toggleRecord())); - layout->addWidget(button,6,2,Qt::AlignHCenter); + layout->addWidget(button,7,2,Qt::AlignHCenter); statusLabel = new QLabel; statusLabel->setSizePolicy(QSizePolicy::MinimumExpanding,QSizePolicy::Fixed); statusLabel->setMinimumSize(130,10); statusLabel->setFrameStyle(QFrame::Panel | QFrame::Sunken); statusLabel->setLineWidth(1); - layout->addWidget(statusLabel,7,0,Qt::AlignHCenter); - + layout->addWidget(statusLabel,8,0,Qt::AlignHCenter); + QLabel* durationLabel = new QLabel; durationLabel->setText(tr("Duration")); - layout->addWidget(durationLabel,7,1,Qt::AlignRight); + layout->addWidget(durationLabel,8,1,Qt::AlignRight); recTime = new QLabel; - layout->addWidget(recTime,7,2,Qt::AlignLeft); - + layout->addWidget(recTime,8,2,Qt::AlignLeft); + window->setLayout(layout); setCentralWidget(window); window->show(); @@ -207,21 +224,21 @@ AudioRecorder::AudioRecorder() } QUrl AudioRecorder::recordPathAudio(QUrl filePath) -{ +{ if (!filePath.isEmpty()) - return filePath; - + return filePath; + QDir outputDir(QDir::rootPath()); - - int lastImage = 0; + + int lastImage = 0; int fileCount = 0; - foreach(QString fileName, outputDir.entryList(QStringList() << "testclip_*")) { + foreach(QString fileName, outputDir.entryList(QStringList() << "testclip_*")) { int imgNumber = fileName.mid(5, fileName.size()-9).toInt(); lastImage = qMax(lastImage, imgNumber); - if (outputDir.exists(fileName)) - fileCount+=1; - } - lastImage+=fileCount; + if (outputDir.exists(fileName)) + fileCount+=1; + } + lastImage+=fileCount; QUrl location(QDir::toNativeSeparators(outputDir.canonicalPath()+QString("/testclip_%1").arg(lastImage+1,4,10,QLatin1Char('0')))); return location; } @@ -285,32 +302,49 @@ void AudioRecorder::codecChanged(int idx) } void AudioRecorder::sampleRateChanged(int idx) -{ +{ QAudioEncoderSettings settings = capture->audioSettings(); settings.setSampleRate((sampleRateBox->itemData(idx).toInt())); capture->setEncodingSettings(settings); } void AudioRecorder::channelCountChanged(int idx) -{ +{ QAudioEncoderSettings settings = capture->audioSettings(); settings.setChannelCount((channelBox->itemData(idx).toInt())); capture->setEncodingSettings(settings); } void AudioRecorder::qualityChanged(int idx) -{ - QAudioEncoderSettings settings = capture->audioSettings(); - +{ + QAudioEncoderSettings settings = capture->audioSettings(); + + switch(idx) { + case 0: + settings.setQuality(QtMultimediaKit::LowQuality); + break; + case 1: + settings.setQuality(QtMultimediaKit::NormalQuality); + break; + default: + settings.setQuality(QtMultimediaKit::HighQuality); + } + capture->setEncodingSettings(settings); +} + +void AudioRecorder::encmodeChanged(int idx) +{ + QAudioEncoderSettings settings = capture->audioSettings(); + switch(idx) { case 0: - settings.setQuality(QtMediaServices::LowQuality); + settings.setEncodingMode(QtMultimediaKit::ConstantQualityEncoding); break; case 1: - settings.setQuality(QtMediaServices::NormalQuality); + settings.setEncodingMode(QtMultimediaKit::ConstantBitRateEncoding); break; default: - settings.setQuality(QtMediaServices::HighQuality); + settings.setEncodingMode(QtMultimediaKit::ConstantQualityEncoding); } capture->setEncodingSettings(settings); } @@ -322,22 +356,23 @@ void AudioRecorder::toggleRecord() recTime->setText("0"); currentTime = 0; } -#ifdef Q_OS_SYMBIAN - capture->setOutputLocation(recordPathAudio(destination)); +#ifdef Q_OS_SYMBIAN + if (!paused) + capture->setOutputLocation(recordPathAudio(destination)); #endif - capture->record(); + capture->record(); active = true; paused = false; } else { - capture->stop(); + capture->stop(); active = false; } } void AudioRecorder::togglePause() { - if(active && !paused) { - capture->pause(); + if(active && !paused) { + capture->pause(); active = false; paused = true; } @@ -356,10 +391,10 @@ void AudioRecorder::selectOutputFile() if(fileNames.size() > 0) #ifdef Q_OS_SYMBIAN destination = QUrl(fileNames.first()); -#else +#else capture->setOutputLocation(QUrl(fileNames.first())); - -#endif + +#endif } void AudioRecorder::errorChanged(QMediaRecorder::Error err) @@ -373,18 +408,27 @@ void AudioRecorder::updateSamplerates(int idx) { QAudioEncoderSettings settings; settings.setCodec(codecsBox->itemText(idx)); - + QList<int> supportedSampleRates = capture->supportedAudioSampleRates(settings); - sampleRateBox->clear(); - for(int i = 0; i < supportedSampleRates.count(); i++) { + sampleRateBox->clear(); + for(int i = 0; i < supportedSampleRates.count(); i++) { QString rateString = QString("%1").arg(supportedSampleRates.at(i)); - sampleRateBox->addItem(rateString, QVariant(supportedSampleRates.at(i))); - } + sampleRateBox->addItem(rateString, QVariant(supportedSampleRates.at(i))); + } } void AudioRecorder::updateChannelCount(int idx) -{ - QAudioEncoderControl *audioEncoder = qobject_cast<QAudioEncoderControl*>(capture->service()->control(QAudioEncoderControl_iid)); +{ + QMediaControl *control = audiosource->service()->requestControl(QAudioEncoderControl_iid); + if (!control) + return; + + QAudioEncoderControl *audioEncoder = qobject_cast<QAudioEncoderControl*>(control); + if (!audioEncoder) { + audiosource->service()->releaseControl(control); + return; + } + channelBox->clear(); QStringList list = audioEncoder->supportedEncodingOptions(codecsBox->itemText(idx)); QList<int> channels; @@ -392,15 +436,24 @@ void AudioRecorder::updateChannelCount(int idx) channels <<1<<2; else channels <<1; - for(int i = 0; i < channels.count(); i++) { + for(int i = 0; i < channels.count(); i++) { QString channelString = QString("%1").arg(channels.at(i)); - channelBox->addItem(channelString, QVariant(channels.at(i))); - } + channelBox->addItem(channelString, QVariant(channels.at(i))); + } } void AudioRecorder::updateQuality(int idx) -{ - QAudioEncoderControl *audioEncoder = qobject_cast<QAudioEncoderControl*>(capture->service()->control(QAudioEncoderControl_iid)); +{ + QMediaControl *control = audiosource->service()->requestControl(QAudioEncoderControl_iid); + if (!control) + return; + + QAudioEncoderControl *audioEncoder = qobject_cast<QAudioEncoderControl*>(control); + if (!audioEncoder) { + audiosource->service()->releaseControl(control); + return; + } + qualityBox->clear(); QStringList list = audioEncoder->supportedEncodingOptions(codecsBox->itemText(idx)); QList<int> channels; @@ -410,5 +463,5 @@ void AudioRecorder::updateQuality(int idx) qualityBox->addItem(tr("High")); }else { qualityBox->addItem(tr("Low")); - } + } } diff --git a/examples/audiorecorder/audiorecorder.h b/examples/audiorecorder/audiorecorder.h index 090d3d0e22..d57b6a1b56 100644 --- a/examples/audiorecorder/audiorecorder.h +++ b/examples/audiorecorder/audiorecorder.h @@ -67,6 +67,7 @@ private: void updateSamplerates(int idx); void updateChannelCount(int idx); void updateQuality(int idx); + static inline void swap(QString& a, QString& b){qSwap(a,b);} private slots: void deviceChanged(int idx); @@ -75,6 +76,7 @@ private slots: void qualityChanged(int idx); void sampleRateChanged(int idx); void channelCountChanged(int idx); + void encmodeChanged(int idx); void selectOutputFile(); void togglePause(); void toggleRecord(); @@ -92,6 +94,7 @@ private: QComboBox* qualityBox; QComboBox* sampleRateBox; QComboBox* channelBox; + QComboBox* encModeBox; QLabel* recTime; QLabel* statusLabel; QPushButton* button; diff --git a/examples/audiorecorder/audiorecorder.pro b/examples/audiorecorder/audiorecorder.pro index 324a44ffc5..5cf7403540 100644 --- a/examples/audiorecorder/audiorecorder.pro +++ b/examples/audiorecorder/audiorecorder.pro @@ -1,9 +1,7 @@ TEMPLATE = app CONFIG += example -contains(QT_CONFIG, multimedia): QT += multimedia - -INCLUDEPATH += ../../src/multimedia +INCLUDEPATH += ../../src/multimedia ../../src/multimedia/audio include(../examples.pri) CONFIG += mobility @@ -19,5 +17,5 @@ SOURCES = \ audiorecorder.cpp symbian: { - TARGET.CAPABILITY = UserEnvironment ReadDeviceData + TARGET.CAPABILITY = UserEnvironment ReadDeviceData WriteDeviceData } diff --git a/examples/battery-charge/battery-subscriber/battery-subscriber.qml b/examples/battery-charge/battery-subscriber/battery-subscriber.qml index 805eafcc66..f706ca609d 100644 --- a/examples/battery-charge/battery-subscriber/battery-subscriber.qml +++ b/examples/battery-charge/battery-subscriber/battery-subscriber.qml @@ -39,7 +39,9 @@ ****************************************************************************/ import Qt 4.7 +//! [4] import QtMobility.publishsubscribe 1.0 +//! [4] import Qt.labs.particles 1.0 import "content" diff --git a/examples/bearermonitor/bearermonitor.cpp b/examples/bearermonitor/bearermonitor.cpp index 699ab32875..d05e75d091 100644 --- a/examples/bearermonitor/bearermonitor.cpp +++ b/examples/bearermonitor/bearermonitor.cpp @@ -80,7 +80,7 @@ BearerMonitor::BearerMonitor(QWidget *parent) break; } } - + connect(&manager, SIGNAL(onlineStateChanged(bool)), this ,SLOT(onlineStateChanged(bool))); connect(&manager, SIGNAL(configurationAdded(const QNetworkConfiguration&)), this, SLOT(configurationAdded(const QNetworkConfiguration&))); connect(&manager, SIGNAL(configurationRemoved(const QNetworkConfiguration&)), @@ -88,7 +88,6 @@ BearerMonitor::BearerMonitor(QWidget *parent) connect(&manager, SIGNAL(configurationChanged(const QNetworkConfiguration&)), this, SLOT(configurationChanged(const QNetworkConfiguration))); connect(&manager, SIGNAL(updateCompleted()), this, SLOT(updateConfigurations())); - connect(&manager, SIGNAL(onlineStateChanged(bool)), this ,SLOT(onlineStateChanged(bool))); #ifdef Q_OS_WIN connect(registerButton, SIGNAL(clicked()), this, SLOT(registerNetwork())); @@ -111,6 +110,10 @@ BearerMonitor::BearerMonitor(QWidget *parent) #endif connect(scanButton, SIGNAL(clicked()), this, SLOT(performScan())); + + // Just in case update all configurations so that all + // configurations are up to date. + manager.updateConfigurations(); } BearerMonitor::~BearerMonitor() @@ -209,6 +212,10 @@ void BearerMonitor::updateConfigurations() progressBar->hide(); scanButton->show(); + // Just in case update online state, on Symbian platform + // WLAN scan needs to be triggered initially to have their true state. + onlineStateChanged(manager.isOnline()); + QList<QTreeWidgetItem *> items = treeWidget->findItems(QLatin1String("*"), Qt::MatchWildcard); QMap<QString, QTreeWidgetItem *> itemMap; while (!items.isEmpty()) { diff --git a/examples/bearermonitor/bearermonitor_240_320.ui b/examples/bearermonitor/bearermonitor_240_320.ui index ce9c2d1d12..93cfc5e0e3 100644 --- a/examples/bearermonitor/bearermonitor_240_320.ui +++ b/examples/bearermonitor/bearermonitor_240_320.ui @@ -11,7 +11,7 @@ </rect> </property> <property name="windowTitle"> - <string>Form</string> + <string>BearerMonitor</string> </property> <layout class="QVBoxLayout" name="verticalLayout_5"> <item> diff --git a/examples/bearermonitor/bearermonitor_640_480.ui b/examples/bearermonitor/bearermonitor_640_480.ui index 941eaa0282..52866bc9cd 100644 --- a/examples/bearermonitor/bearermonitor_640_480.ui +++ b/examples/bearermonitor/bearermonitor_640_480.ui @@ -11,7 +11,7 @@ </rect> </property> <property name="windowTitle"> - <string>Form</string> + <string>BearerMonitor</string> </property> <layout class="QGridLayout" name="gridLayout"> <item row="0" column="0"> diff --git a/examples/bearermonitor/bearermonitor_maemo.ui b/examples/bearermonitor/bearermonitor_maemo.ui index 5f17e7da74..a7940c6fe9 100644 --- a/examples/bearermonitor/bearermonitor_maemo.ui +++ b/examples/bearermonitor/bearermonitor_maemo.ui @@ -11,7 +11,7 @@ </rect> </property> <property name="windowTitle"> - <string>Form</string> + <string>BearerMonitor</string> </property> <layout class="QHBoxLayout" name="horizontalLayout_3"> <item> diff --git a/examples/bearermonitor/sessionwidget.ui b/examples/bearermonitor/sessionwidget.ui index 5bbae4fdd7..4e607ee8d2 100644 --- a/examples/bearermonitor/sessionwidget.ui +++ b/examples/bearermonitor/sessionwidget.ui @@ -11,7 +11,7 @@ </rect> </property> <property name="windowTitle"> - <string>Form</string> + <string>Session Details</string> </property> <layout class="QVBoxLayout" name="verticalLayout_2"> <item> diff --git a/examples/bearermonitor/sessionwidget_maemo.ui b/examples/bearermonitor/sessionwidget_maemo.ui index 86f915c973..ca682463e7 100644 --- a/examples/bearermonitor/sessionwidget_maemo.ui +++ b/examples/bearermonitor/sessionwidget_maemo.ui @@ -11,7 +11,7 @@ </rect> </property> <property name="windowTitle"> - <string>Form</string> + <string>Session Details</string> </property> <layout class="QHBoxLayout" name="horizontalLayout"> <item> diff --git a/examples/examples.pro b/examples/examples.pro index 167b57f977..fa4fc2f601 100644 --- a/examples/examples.pro +++ b/examples/examples.pro @@ -69,7 +69,12 @@ contains(mobility_modules,multimedia) { radio \ player \ slideshow \ - audiorecorder + audiorecorder \ + audiodevices \ + audioinput \ + audiooutput \ + videographicsitem \ + videowidget } diff --git a/examples/player/main.cpp b/examples/player/main.cpp index 8d5abe9335..ed8186809b 100644 --- a/examples/player/main.cpp +++ b/examples/player/main.cpp @@ -48,6 +48,8 @@ int main(int argc, char *argv[]) #ifdef Q_OS_SYMBIAN QMainWindow window; + window.setContentsMargins(10, 10, 10, 10); // workaround for issue where UI is not drawn in older SDKs + // this line can be removed when bug QTBUG-8697 is fixed Player *player = new Player(&window); window.setCentralWidget(player); window.showMaximized(); diff --git a/examples/player/player.cpp b/examples/player/player.cpp index 54d7f280cb..b69b9422e6 100644 --- a/examples/player/player.cpp +++ b/examples/player/player.cpp @@ -65,23 +65,22 @@ Player::Player(QWidget *parent) , videoWidget(0) , coverLabel(0) , slider(0) + , audioEndpointSelector(0) #ifdef Q_OS_SYMBIAN , mediaKeysObserver(0) , playlistDialog(0) , toggleAspectRatio(0) , showYoutubeDialog(0) , youtubeDialog(0) - , audioEndpointSelector(0) #else , colorDialog(0) #endif { //! [create-objs] player = new QMediaPlayer(this); - // owned by PlaylistModel playlist = new QMediaPlaylist(); - playlist->setMediaObject(player); + player->setPlaylist(playlist); //! [create-objs] connect(player, SIGNAL(durationChanged(qint64)), SLOT(durationChanged(qint64))); @@ -95,7 +94,7 @@ Player::Player(QWidget *parent) //! [2] videoWidget = new VideoWidget(this); - videoWidget->setMediaObject(player); + player->setVideoOutput(videoWidget); playlistModel = new PlaylistModel(this); playlistModel->setPlaylist(playlist); @@ -112,8 +111,19 @@ Player::Player(QWidget *parent) connect(slider, SIGNAL(sliderMoved(int)), this, SLOT(seek(int))); - audioEndpointSelector = qobject_cast<QAudioEndpointSelector*>(player->service()->control(QAudioEndpointSelector_iid)); - connect(audioEndpointSelector, SIGNAL(activeEndpointChanged(const QString&)), this, SLOT(handleAudioOutputChangedSignal(const QString&))); + QMediaService *service = player->service(); + if (service) { + QMediaControl *control = service->requestControl(QAudioEndpointSelector_iid); + if (control) { + audioEndpointSelector = qobject_cast<QAudioEndpointSelector*>(control); + if (audioEndpointSelector) { + connect(audioEndpointSelector, SIGNAL(activeEndpointChanged(const QString&)), + this, SLOT(handleAudioOutputChangedSignal(const QString&))); + } else { + service->releaseControl(control); + } + } + } #ifndef Q_OS_SYMBIAN QPushButton *openButton = new QPushButton(tr("Open"), this); @@ -231,13 +241,22 @@ Player::Player(QWidget *parent) metaDataChanged(); - QStringList fileNames = qApp->arguments(); - fileNames.removeAt(0); - foreach (QString const &fileName, fileNames) { - if (fileName.startsWith(QLatin1String("http://"))) - playlist->addMedia(QUrl(fileName)); - else if (QFileInfo(fileName).exists()) - playlist->addMedia(QUrl::fromLocalFile(fileName)); + QStringList arguments = qApp->arguments(); + arguments.removeAt(0); + foreach (QString const &argument, arguments) { + QFileInfo fileInfo(argument); + if (fileInfo.exists()) { + QUrl url = QUrl::fromLocalFile(fileInfo.absoluteFilePath()); + if (fileInfo.suffix().toLower() == QLatin1String("m3u")) { + playlist->load(url); + } else + playlist->addMedia(url); + } else { + QUrl url(argument); + if (url.isValid()) { + playlist->addMedia(url); + } + } } } @@ -271,15 +290,15 @@ void Player::metaDataChanged() setTrackInfo(QString("(%1/%2) %3 - %4") .arg(playlist->currentIndex()+1) .arg(playlist->mediaCount()) - .arg(player->metaData(QtMediaServices::AlbumArtist).toString()) - .arg(player->metaData(QtMediaServices::Title).toString())); + .arg(player->metaData(QtMultimediaKit::AlbumArtist).toString()) + .arg(player->metaData(QtMultimediaKit::Title).toString())); if (!player->isVideoAvailable()) { - QUrl uri = player->metaData(QtMediaServices::CoverArtUrlLarge).value<QUrl>(); + QUrl uri = player->metaData(QtMultimediaKit::CoverArtUrlLarge).value<QUrl>(); QPixmap pixmap = NULL; - if (uri.isEmpty()) { - QVariant picture = player->extendedMetaData("attachedpicture"); + if (uri.isEmpty()) { + QVariant picture = player->metaData(QtMultimediaKit::CoverArtImage); // Load picture from metadata if (!picture.isNull() && picture.canConvert<QByteArray>()) pixmap.loadFromData(picture.value<QByteArray>()); @@ -305,20 +324,22 @@ void Player::metaDataChanged() // Load picture from file pointed by uri } else pixmap.load(uri.toString()); - + coverLabel->setPixmap((!pixmap.isNull())?pixmap:QPixmap()); + coverLabel->setAlignment(Qt::AlignCenter); + coverLabel->setScaledContents(true); } hideOrShowCoverArt(); } #else - //qDebug() << "update metadata" << player->metaData(QtMediaServices::Title).toString(); + //qDebug() << "update metadata" << player->metaData(QtMultimediaKit::Title).toString(); if (player->isMetaDataAvailable()) { setTrackInfo(QString("%1 - %2") - .arg(player->metaData(QtMediaServices::AlbumArtist).toString()) - .arg(player->metaData(QtMediaServices::Title).toString())); + .arg(player->metaData(QtMultimediaKit::AlbumArtist).toString()) + .arg(player->metaData(QtMultimediaKit::Title).toString())); if (coverLabel) { - QUrl url = player->metaData(QtMediaServices::CoverArtUrlLarge).value<QUrl>(); + QUrl url = player->metaData(QtMultimediaKit::CoverArtUrlLarge).value<QUrl>(); coverLabel->setPixmap(!url.isEmpty() ? QPixmap(url.toString()) @@ -594,8 +615,9 @@ void Player::hideOrShowCoverArt() videoWidget->show(); videoWidget->repaint(); } else { - coverLabel->show(); videoWidget->hide(); + QApplication::setActiveWindow(this); + coverLabel->show(); } } diff --git a/examples/player/player.h b/examples/player/player.h index f32794f8a2..0b2b2145d7 100644 --- a/examples/player/player.h +++ b/examples/player/player.h @@ -133,11 +133,11 @@ private: QVideoWidget *videoWidget; QLabel *coverLabel; QSlider *slider; + QAudioEndpointSelector *audioEndpointSelector; PlaylistModel *playlistModel; QAbstractItemView *playlistView; QString trackInfo; QString statusInfo; - QAudioEndpointSelector *audioEndpointSelector; #ifdef Q_OS_SYMBIAN MediaKeysObserver *mediaKeysObserver; QDialog *playlistDialog; diff --git a/examples/player/player.pro b/examples/player/player.pro index c94f04b087..3c9b783e4c 100644 --- a/examples/player/player.pro +++ b/examples/player/player.pro @@ -3,7 +3,7 @@ TARGET = player QT += network \ xml -INCLUDEPATH += ../../src/multimedia +INCLUDEPATH += ../../src/multimedia ../../src/multimedia/audio include(../examples.pri) CONFIG += mobility diff --git a/examples/qmlcontacts/qmlcontacts.pro b/examples/qmlcontacts/qmlcontacts.pro index 713049ddcc..74d495d0cd 100644 --- a/examples/qmlcontacts/qmlcontacts.pro +++ b/examples/qmlcontacts/qmlcontacts.pro @@ -26,8 +26,5 @@ OTHER_FILES += example.qml \ contents/MediaButton.qml \ ScrollBar.qml symbian::TARGET.CAPABILITY = ReadUserData \ - WriteUserData \ - ReadDeviceData \ - WriteDeviceData \ - SwEvent + WriteUserData include(../examples.pri) diff --git a/examples/radio/radio.cpp b/examples/radio/radio.cpp index 4bb954d81c..7aab46f64b 100644 --- a/examples/radio/radio.cpp +++ b/examples/radio/radio.cpp @@ -71,13 +71,15 @@ Radio::Radio() else signal->setText(tr("No radio found")); topBar->addWidget(signal); - +#if defined Q_WS_MAEMO_5 + QSpacerItem *spacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum); + topBar->addItem(spacer); + volumeSlider = new QSlider(Qt::Horizontal,this); +#else volumeSlider = new QSlider(Qt::Vertical,this); - volumeSlider->setRange(0,100); -#if defined Q_OS_SYMBIAN - volumeSlider->setRange(0,10); #endif - volumeSlider->setValue(radio->volume()); + volumeSlider->setRange(0,100); + volumeSlider->setValue(50); connect(volumeSlider,SIGNAL(valueChanged(int)),this,SLOT(updateVolume(int))); topBar->addWidget(volumeSlider); diff --git a/examples/radio/radio.pro b/examples/radio/radio.pro index 36894c584c..7709cfcda2 100644 --- a/examples/radio/radio.pro +++ b/examples/radio/radio.pro @@ -16,3 +16,6 @@ SOURCES = \ main.cpp \ radio.cpp +symbian: { + TARGET.CAPABILITY = UserEnvironment WriteDeviceData ReadDeviceData SwEvent +} diff --git a/examples/samplephonebook/phonebook.cpp b/examples/samplephonebook/phonebook.cpp index 219ce2a1bd..16bca1494e 100644 --- a/examples/samplephonebook/phonebook.cpp +++ b/examples/samplephonebook/phonebook.cpp @@ -81,7 +81,9 @@ PhoneBook::~PhoneBook() void PhoneBook::activateEditor(QContactLocalId contactId) { +#if !(defined(Q_OS_SYMBIAN) || defined(Q_WS_MAEMO_5)) menuBar()->setVisible(false); +#endif m_editorPage->setCurrentContact(m_manager, contactId); m_stackedWidget->setCurrentIndex(1); // list = 0, editor = 1, find = 2. } @@ -106,7 +108,9 @@ void PhoneBook::activateList() void PhoneBook::activateFind() { +#if !(defined(Q_OS_SYMBIAN) || defined(Q_WS_MAEMO_5)) menuBar()->setVisible(false); +#endif m_stackedWidget->setCurrentIndex(2); // list = 0, editor = 1, find = 2. } diff --git a/examples/samplephonebook/samplephonebook.pro b/examples/samplephonebook/samplephonebook.pro index df266f1cae..e086aba3a0 100644 --- a/examples/samplephonebook/samplephonebook.pro +++ b/examples/samplephonebook/samplephonebook.pro @@ -35,8 +35,5 @@ HEADERS += phonebook.h \ symbian: { TARGET.CAPABILITY = ReadUserData \ - WriteUserData \ - ReadDeviceData \ - WriteDeviceData \ - SwEvent + WriteUserData } diff --git a/examples/slideshow/slideshow.cpp b/examples/slideshow/slideshow.cpp index f7bc47c52d..bdbfab3adb 100644 --- a/examples/slideshow/slideshow.cpp +++ b/examples/slideshow/slideshow.cpp @@ -65,13 +65,24 @@ SlideShow::SlideShow(QWidget *parent) connect(imageViewer, SIGNAL(elapsedTimeChanged(int)), this, SLOT(elapsedTimeChanged(int))); playlist = new QMediaPlaylist; - playlist->setMediaObject(imageViewer); + imageViewer->bind(playlist); + + connect(playlist, SIGNAL(loaded()), this, SLOT(playlistLoaded())); + connect(playlist, SIGNAL(loadFailed()), this, SLOT(playlistLoadFailed())); connect(playlist, SIGNAL(loaded()), this, SLOT(playlistLoaded())); connect(playlist, SIGNAL(loadFailed()), this, SLOT(playlistLoadFailed())); QVideoWidget *videoWidget = new QVideoWidget; - videoWidget->setMediaObject(imageViewer); + imageViewer->bind(videoWidget); + + statusLabel = new QLabel(tr("%1 Images").arg(0)); + statusLabel->setAlignment(Qt::AlignCenter); + + viewerLayout = new QStackedLayout; + viewerLayout->setStackingMode(QStackedLayout::StackAll); + viewerLayout->addWidget(videoWidget); + viewerLayout->addWidget(statusLabel); statusLabel = new QLabel(tr("%1 Images").arg(0)); statusLabel->setAlignment(Qt::AlignCenter); diff --git a/examples/videographicsitem/main.cpp b/examples/videographicsitem/main.cpp new file mode 100644 index 0000000000..4031010630 --- /dev/null +++ b/examples/videographicsitem/main.cpp @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "videoplayer.h" + +#include <QtGui/QApplication> + +int main(int argc, char **argv) +{ + QApplication app(argc, argv); + + VideoPlayer player; + player.show(); + + return app.exec(); +} + diff --git a/examples/videographicsitem/videographicsitem.pro b/examples/videographicsitem/videographicsitem.pro new file mode 100644 index 0000000000..51497936d8 --- /dev/null +++ b/examples/videographicsitem/videographicsitem.pro @@ -0,0 +1,19 @@ +TEMPLATE = app +CONFIG += example + +INCLUDEPATH += ../../src/multimedia ../../src/multimedia/video +include(../examples.pri) + +CONFIG += mobility +MOBILITY = multimedia + +QMAKE_RPATHDIR += $$DESTDIR + +contains(QT_CONFIG, opengl): QT += opengl + +HEADERS += videoplayer.h \ + videoitem.h + +SOURCES += main.cpp \ + videoplayer.cpp \ + videoitem.cpp diff --git a/examples/videographicsitem/videoitem.cpp b/examples/videographicsitem/videoitem.cpp new file mode 100644 index 0000000000..55b75f87c8 --- /dev/null +++ b/examples/videographicsitem/videoitem.cpp @@ -0,0 +1,145 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "videoitem.h" + +#include <QtGui> +#include <qvideosurfaceformat.h> + +VideoItem::VideoItem(QGraphicsItem *parent) + : QGraphicsItem(parent) + , imageFormat(QImage::Format_Invalid) + , framePainted(false) +{ +} + +VideoItem::~VideoItem() +{ +} + +QRectF VideoItem::boundingRect() const +{ + return QRectF(QPointF(0,0), surfaceFormat().sizeHint()); +} + +void VideoItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + + if (currentFrame.map(QAbstractVideoBuffer::ReadOnly)) { + const QTransform oldTransform = painter->transform(); + + if (surfaceFormat().scanLineDirection() == QVideoSurfaceFormat::BottomToTop) { + painter->scale(1, -1); + painter->translate(0, -boundingRect().height()); + } + + painter->drawImage(boundingRect(), QImage( + currentFrame.bits(), + imageSize.width(), + imageSize.height(), + imageFormat)); + + painter->setTransform(oldTransform); + + framePainted = true; + + currentFrame.unmap(); + } +} + +QList<QVideoFrame::PixelFormat> VideoItem::supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const +{ + if (handleType == QAbstractVideoBuffer::NoHandle) { + return QList<QVideoFrame::PixelFormat>() + << QVideoFrame::Format_RGB32 + << QVideoFrame::Format_ARGB32 + << QVideoFrame::Format_ARGB32_Premultiplied + << QVideoFrame::Format_RGB565 + << QVideoFrame::Format_RGB555; + } else { + return QList<QVideoFrame::PixelFormat>(); + } +} + +bool VideoItem::start(const QVideoSurfaceFormat &format) +{ + if (isFormatSupported(format)) { + imageFormat = QVideoFrame::imageFormatFromPixelFormat(format.pixelFormat()); + imageSize = format.frameSize(); + framePainted = true; + + QAbstractVideoSurface::start(format); + + prepareGeometryChange(); + + return true; + } else { + return false; + } +} + +void VideoItem::stop() +{ + currentFrame = QVideoFrame(); + framePainted = false; + + QAbstractVideoSurface::stop(); +} + +bool VideoItem::present(const QVideoFrame &frame) +{ + if (!framePainted) { + if (!QAbstractVideoSurface::isActive()) + setError(StoppedError); + + return false; + } else { + currentFrame = frame; + framePainted = false; + + update(); + + return true; + } +} diff --git a/examples/videographicsitem/videoitem.h b/examples/videographicsitem/videoitem.h new file mode 100644 index 0000000000..659edad18c --- /dev/null +++ b/examples/videographicsitem/videoitem.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef VIDEOITEM_H +#define VIDEOITEM_H + +#include <qabstractvideosurface.h> +#include <QtGui/QGraphicsItem> + +class VideoItem + : public QAbstractVideoSurface, + public QGraphicsItem +{ + Q_OBJECT + Q_INTERFACES(QGraphicsItem) +public: + explicit VideoItem(QGraphicsItem *parentItem = 0); + ~VideoItem(); + + QRectF boundingRect() const; + void paint( + QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + + //video surface + QList<QVideoFrame::PixelFormat> supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const; + + bool start(const QVideoSurfaceFormat &format); + void stop(); + bool present(const QVideoFrame &frame); + +private: + QImage::Format imageFormat; + QSize imageSize; + + QVideoFrame currentFrame; + bool framePainted; +}; + +#endif + diff --git a/examples/videographicsitem/videoplayer.cpp b/examples/videographicsitem/videoplayer.cpp new file mode 100644 index 0000000000..958252eb67 --- /dev/null +++ b/examples/videographicsitem/videoplayer.cpp @@ -0,0 +1,210 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "videoplayer.h" +#include "videoitem.h" + +#include <QtGui> +#include <qvideosurfaceformat.h> + +#ifndef QT_NO_OPENGL +# include <QtOpenGL/QGLWidget> +#endif + +VideoPlayer::VideoPlayer(QWidget *parent, Qt::WindowFlags flags) + : QWidget(parent, flags) + , videoItem(0) + , playButton(0) + , positionSlider(0) +{ + connect(&movie, SIGNAL(stateChanged(QMovie::MovieState)), + this, SLOT(movieStateChanged(QMovie::MovieState))); + connect(&movie, SIGNAL(frameChanged(int)), + this, SLOT(frameChanged(int))); + + videoItem = new VideoItem; + + QGraphicsScene *scene = new QGraphicsScene(this); + QGraphicsView *graphicsView = new QGraphicsView(scene); + +#ifndef QT_NO_OPENGL + graphicsView->setViewport(new QGLWidget); +#endif + + scene->addItem(videoItem); + + QSlider *rotateSlider = new QSlider(Qt::Horizontal); + rotateSlider->setRange(-180, 180); + rotateSlider->setValue(0); + + connect(rotateSlider, SIGNAL(valueChanged(int)), + this, SLOT(rotateVideo(int))); + + QAbstractButton *openButton = new QPushButton(tr("Open...")); + connect(openButton, SIGNAL(clicked()), this, SLOT(openFile())); + + playButton = new QPushButton; + playButton->setEnabled(false); + playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay)); + + connect(playButton, SIGNAL(clicked()), + this, SLOT(play())); + + positionSlider = new QSlider(Qt::Horizontal); + positionSlider->setRange(0, 0); + + connect(positionSlider, SIGNAL(sliderMoved(int)), + this, SLOT(setPosition(int))); + + connect(&movie, SIGNAL(frameChanged(int)), + positionSlider, SLOT(setValue(int))); + + QBoxLayout *controlLayout = new QHBoxLayout; + controlLayout->setMargin(0); + controlLayout->addWidget(openButton); + controlLayout->addWidget(playButton); + controlLayout->addWidget(positionSlider); + + QBoxLayout *layout = new QVBoxLayout; + layout->addWidget(graphicsView); + layout->addWidget(rotateSlider); + layout->addLayout(controlLayout); + + setLayout(layout); +} + +VideoPlayer::~VideoPlayer() +{ +} + +void VideoPlayer::openFile() +{ + QString fileName = QFileDialog::getOpenFileName(this, tr("Open Movie")); + + if (!fileName.isEmpty()) { + videoItem->stop(); + + movie.setFileName(fileName); + + playButton->setEnabled(true); + positionSlider->setMaximum(movie.frameCount()); + + movie.jumpToFrame(0); + } +} + +void VideoPlayer::play() +{ + switch(movie.state()) { + case QMovie::NotRunning: + movie.start(); + break; + case QMovie::Paused: + movie.setPaused(false); + break; + case QMovie::Running: + movie.setPaused(true); + break; + } +} + +void VideoPlayer::movieStateChanged(QMovie::MovieState state) +{ + switch(state) { + case QMovie::NotRunning: + case QMovie::Paused: + playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay)); + break; + case QMovie::Running: + playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPause)); + break; + } +} + +void VideoPlayer::frameChanged(int frame) +{ + if (!presentImage(movie.currentImage())) { + movie.stop(); + playButton->setEnabled(false); + positionSlider->setMaximum(0); + } else { + positionSlider->setValue(frame); + } +} + +void VideoPlayer::setPosition(int frame) +{ + movie.jumpToFrame(frame); +} + +void VideoPlayer::rotateVideo(int angle) +{ + //rotate around the center of video element + qreal x = videoItem->boundingRect().width() / 2.0; + qreal y = videoItem->boundingRect().height() / 2.0; + videoItem->setTransform(QTransform().translate(x, y).rotate(angle).translate(-x, -y)); +} + +bool VideoPlayer::presentImage(const QImage &image) +{ + QVideoFrame frame(image); + + if (!frame.isValid()) + return false; + + QVideoSurfaceFormat currentFormat = videoItem->surfaceFormat(); + + if (frame.pixelFormat() != currentFormat.pixelFormat() + || frame.size() != currentFormat.frameSize()) { + QVideoSurfaceFormat format(frame.size(), frame.pixelFormat()); + + if (!videoItem->start(format)) + return false; + } + + if (!videoItem->present(frame)) { + videoItem->stop(); + + return false; + } else { + return true; + } +} diff --git a/examples/videographicsitem/videoplayer.h b/examples/videographicsitem/videoplayer.h new file mode 100644 index 0000000000..ccb0a083eb --- /dev/null +++ b/examples/videographicsitem/videoplayer.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef VIDEOPLAYER_H +#define VIDEOPLAYER_H + +#include <QtGui/QMovie> +#include <QtGui/QWidget> + +QT_BEGIN_NAMESPACE +class QAbstractButton; +class QAbstractVideoSurface; +class QSlider; +QT_END_NAMESPACE + + +class VideoItem; + +class VideoPlayer : public QWidget +{ + Q_OBJECT +public: + VideoPlayer(QWidget *parent = 0, Qt::WindowFlags flags = 0); + ~VideoPlayer(); + + QSize sizeHint() const { return QSize(800, 600); } + +public slots: + void openFile(); + void play(); + +private slots: + void movieStateChanged(QMovie::MovieState state); + void frameChanged(int frame); + void setPosition(int frame); + void rotateVideo(int angle); + +private: + bool presentImage(const QImage &image); + + QMovie movie; + VideoItem *videoItem; + QAbstractButton *playButton; + QSlider *positionSlider; +}; + +#endif + diff --git a/examples/videowidget/main.cpp b/examples/videowidget/main.cpp new file mode 100644 index 0000000000..b32794904f --- /dev/null +++ b/examples/videowidget/main.cpp @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "videoplayer.h" + +#include <QtGui/QApplication> + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + + VideoPlayer player; + player.show(); + + return app.exec(); +} diff --git a/examples/videowidget/videoplayer.cpp b/examples/videowidget/videoplayer.cpp new file mode 100644 index 0000000000..00ef54490e --- /dev/null +++ b/examples/videowidget/videoplayer.cpp @@ -0,0 +1,183 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "videoplayer.h" + +#include "videowidget.h" + +#include <QtGui> +#include <qvideosurfaceformat.h> + +VideoPlayer::VideoPlayer(QWidget *parent) + : QWidget(parent) + , surface(0) + , playButton(0) + , positionSlider(0) +{ + connect(&movie, SIGNAL(stateChanged(QMovie::MovieState)), + this, SLOT(movieStateChanged(QMovie::MovieState))); + connect(&movie, SIGNAL(frameChanged(int)), + this, SLOT(frameChanged(int))); + + VideoWidget *videoWidget = new VideoWidget; + surface = videoWidget->videoSurface(); + + QAbstractButton *openButton = new QPushButton(tr("Open...")); + connect(openButton, SIGNAL(clicked()), this, SLOT(openFile())); + + playButton = new QPushButton; + playButton->setEnabled(false); + playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay)); + + connect(playButton, SIGNAL(clicked()), + this, SLOT(play())); + + positionSlider = new QSlider(Qt::Horizontal); + positionSlider->setRange(0, 0); + + connect(positionSlider, SIGNAL(sliderMoved(int)), + this, SLOT(setPosition(int))); + + connect(&movie, SIGNAL(frameChanged(int)), + positionSlider, SLOT(setValue(int))); + + QBoxLayout *controlLayout = new QHBoxLayout; + controlLayout->setMargin(0); + controlLayout->addWidget(openButton); + controlLayout->addWidget(playButton); + controlLayout->addWidget(positionSlider); + + QBoxLayout *layout = new QVBoxLayout; + layout->addWidget(videoWidget); + layout->addLayout(controlLayout); + + setLayout(layout); +} + +VideoPlayer::~VideoPlayer() +{ +} + +void VideoPlayer::openFile() +{ + QString fileName = QFileDialog::getOpenFileName(this, tr("Open Movie")); + + if (!fileName.isEmpty()) { + surface->stop(); + + movie.setFileName(fileName); + + playButton->setEnabled(true); + positionSlider->setMaximum(movie.frameCount()); + + movie.jumpToFrame(0); + } +} + +void VideoPlayer::play() +{ + switch(movie.state()) { + case QMovie::NotRunning: + movie.start(); + break; + case QMovie::Paused: + movie.setPaused(false); + break; + case QMovie::Running: + movie.setPaused(true); + break; + } +} + +void VideoPlayer::movieStateChanged(QMovie::MovieState state) +{ + switch(state) { + case QMovie::NotRunning: + case QMovie::Paused: + playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay)); + break; + case QMovie::Running: + playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPause)); + break; + } +} + +void VideoPlayer::frameChanged(int frame) +{ + if (!presentImage(movie.currentImage())) { + movie.stop(); + playButton->setEnabled(false); + positionSlider->setMaximum(0); + } else { + positionSlider->setValue(frame); + } +} + +void VideoPlayer::setPosition(int frame) +{ + movie.jumpToFrame(frame); +} + +bool VideoPlayer::presentImage(const QImage &image) +{ + QVideoFrame frame(image); + + if (!frame.isValid()) + return false; + + QVideoSurfaceFormat currentFormat = surface->surfaceFormat(); + + if (frame.pixelFormat() != currentFormat.pixelFormat() + || frame.size() != currentFormat.frameSize()) { + QVideoSurfaceFormat format(frame.size(), frame.pixelFormat()); + + if (!surface->start(format)) + return false; + } + + if (!surface->present(frame)) { + surface->stop(); + + return false; + } else { + return true; + } +} diff --git a/examples/videowidget/videoplayer.h b/examples/videowidget/videoplayer.h new file mode 100644 index 0000000000..69944599ff --- /dev/null +++ b/examples/videowidget/videoplayer.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef VIDEOPLAYER_H +#define VIDEOPLAYER_H + +#include <QtGui/QMovie> +#include <QtGui/QWidget> + +QT_BEGIN_NAMESPACE +class QAbstractButton; +class QAbstractVideoSurface; +class QSlider; +QT_END_NAMESPACE + +class VideoPlayer : public QWidget +{ + Q_OBJECT +public: + VideoPlayer(QWidget *parent = 0); + ~VideoPlayer(); + +public slots: + void openFile(); + void play(); + +private slots: + void movieStateChanged(QMovie::MovieState state); + void frameChanged(int frame); + void setPosition(int frame); + +private: + bool presentImage(const QImage &image); + + QMovie movie; + QAbstractVideoSurface *surface; + QAbstractButton *playButton; + QSlider *positionSlider; +}; + +#endif diff --git a/examples/videowidget/videowidget.cpp b/examples/videowidget/videowidget.cpp new file mode 100644 index 0000000000..fa34bca1ad --- /dev/null +++ b/examples/videowidget/videowidget.cpp @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "videowidget.h" + +#include "videowidgetsurface.h" + +#include <QtGui> +#include <qvideosurfaceformat.h> + +//! [0] +VideoWidget::VideoWidget(QWidget *parent) + : QWidget(parent) + , surface(0) +{ + setAutoFillBackground(false); + setAttribute(Qt::WA_NoSystemBackground, true); + setAttribute(Qt::WA_PaintOnScreen, true); + + QPalette palette = this->palette(); + palette.setColor(QPalette::Background, Qt::black); + setPalette(palette); + + setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); + + surface = new VideoWidgetSurface(this); +} +//! [0] + +//! [1] +VideoWidget::~VideoWidget() +{ + delete surface; +} +//! [1] + +//! [2] +QSize VideoWidget::sizeHint() const +{ + return surface->surfaceFormat().sizeHint(); +} +//! [2] + + +//! [3] +void VideoWidget::paintEvent(QPaintEvent *event) +{ + QPainter painter(this); + + if (surface->isActive()) { + const QRect videoRect = surface->videoRect(); + + if (!videoRect.contains(event->rect())) { + QRegion region = event->region(); + region.subtract(videoRect); + + QBrush brush = palette().background(); + + foreach (const QRect &rect, region.rects()) + painter.fillRect(rect, brush); + } + + surface->paint(&painter); + } else { + painter.fillRect(event->rect(), palette().background()); + } +} +//! [3] + +//! [4] +void VideoWidget::resizeEvent(QResizeEvent *event) +{ + QWidget::resizeEvent(event); + + surface->updateVideoRect(); +} +//! [4] diff --git a/examples/videowidget/videowidget.h b/examples/videowidget/videowidget.h new file mode 100644 index 0000000000..ba5f64167f --- /dev/null +++ b/examples/videowidget/videowidget.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef VIDEOWIDGET_H +#define VIDEOWIDGET_H + +#include "videowidgetsurface.h" + +#include <QtGui/QWidget> + +QT_BEGIN_NAMESPACE +class QAbstractVideoSurface; +QT_END_NAMESPACE + +class VideoWidgetSurface; + +//! [0] +class VideoWidget : public QWidget +{ + Q_OBJECT +public: + VideoWidget(QWidget *parent = 0); + ~VideoWidget(); + + QAbstractVideoSurface *videoSurface() const { return surface; } + + QSize sizeHint() const; + +protected: + void paintEvent(QPaintEvent *event); + void resizeEvent(QResizeEvent *event); + +private: + VideoWidgetSurface *surface; +}; +//! [0] + +#endif diff --git a/examples/videowidget/videowidget.pro b/examples/videowidget/videowidget.pro new file mode 100644 index 0000000000..992797794a --- /dev/null +++ b/examples/videowidget/videowidget.pro @@ -0,0 +1,22 @@ +TEMPLATE = app +CONFIG += example + +INCLUDEPATH += ../../src/multimedia ../../src/multimedia/video +include(../examples.pri) + +CONFIG += mobility +MOBILITY = multimedia + +QMAKE_RPATHDIR += $$DESTDIR + +HEADERS = \ + videoplayer.h \ + videowidget.h \ + videowidgetsurface.h + +SOURCES = \ + main.cpp \ + videoplayer.cpp \ + videowidget.cpp \ + videowidgetsurface.cpp + diff --git a/examples/videowidget/videowidgetsurface.cpp b/examples/videowidget/videowidgetsurface.cpp new file mode 100644 index 0000000000..9abdb8ecba --- /dev/null +++ b/examples/videowidget/videowidgetsurface.cpp @@ -0,0 +1,177 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "videowidgetsurface.h" + +#include <QtGui> +#include <qabstractvideosurface.h> +#include <qvideosurfaceformat.h> + +VideoWidgetSurface::VideoWidgetSurface(QWidget *widget, QObject *parent) + : QAbstractVideoSurface(parent) + , widget(widget) + , imageFormat(QImage::Format_Invalid) +{ +} + +//! [0] +QList<QVideoFrame::PixelFormat> VideoWidgetSurface::supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const +{ + if (handleType == QAbstractVideoBuffer::NoHandle) { + return QList<QVideoFrame::PixelFormat>() + << QVideoFrame::Format_RGB32 + << QVideoFrame::Format_ARGB32 + << QVideoFrame::Format_ARGB32_Premultiplied + << QVideoFrame::Format_RGB565 + << QVideoFrame::Format_RGB555; + } else { + return QList<QVideoFrame::PixelFormat>(); + } +} +//! [0] + +//! [1] +bool VideoWidgetSurface::isFormatSupported( + const QVideoSurfaceFormat &format, QVideoSurfaceFormat *similar) const +{ + Q_UNUSED(similar); + + const QImage::Format imageFormat = QVideoFrame::imageFormatFromPixelFormat(format.pixelFormat()); + const QSize size = format.frameSize(); + + return imageFormat != QImage::Format_Invalid + && !size.isEmpty() + && format.handleType() == QAbstractVideoBuffer::NoHandle; +} +//! [1] + +//! [2] +bool VideoWidgetSurface::start(const QVideoSurfaceFormat &format) +{ + const QImage::Format imageFormat = QVideoFrame::imageFormatFromPixelFormat(format.pixelFormat()); + const QSize size = format.frameSize(); + + if (imageFormat != QImage::Format_Invalid && !size.isEmpty()) { + this->imageFormat = imageFormat; + imageSize = size; + sourceRect = format.viewport(); + + QAbstractVideoSurface::start(format); + + widget->updateGeometry(); + updateVideoRect(); + + return true; + } else { + return false; + } +} +//! [2] + +//! [3] +void VideoWidgetSurface::stop() +{ + currentFrame = QVideoFrame(); + targetRect = QRect(); + + QAbstractVideoSurface::stop(); + + widget->update(); +} +//! [3] + +//! [4] +bool VideoWidgetSurface::present(const QVideoFrame &frame) +{ + if (surfaceFormat().pixelFormat() != frame.pixelFormat() + || surfaceFormat().frameSize() != frame.size()) { + setError(IncorrectFormatError); + stop(); + + return false; + } else { + currentFrame = frame; + + widget->repaint(targetRect); + + return true; + } +} +//! [4] + +//! [5] +void VideoWidgetSurface::updateVideoRect() +{ + QSize size = surfaceFormat().sizeHint(); + size.scale(widget->size().boundedTo(size), Qt::KeepAspectRatio); + + targetRect = QRect(QPoint(0, 0), size); + targetRect.moveCenter(widget->rect().center()); +} +//! [5] + +//! [6] +void VideoWidgetSurface::paint(QPainter *painter) +{ + if (currentFrame.map(QAbstractVideoBuffer::ReadOnly)) { + const QTransform oldTransform = painter->transform(); + + if (surfaceFormat().scanLineDirection() == QVideoSurfaceFormat::BottomToTop) { + painter->scale(1, -1); + painter->translate(0, -widget->height()); + } + + QImage image( + currentFrame.bits(), + currentFrame.width(), + currentFrame.height(), + currentFrame.bytesPerLine(), + imageFormat); + + painter->drawImage(targetRect, image, sourceRect); + + painter->setTransform(oldTransform); + + currentFrame.unmap(); + } +} +//! [6] diff --git a/examples/videowidget/videowidgetsurface.h b/examples/videowidget/videowidgetsurface.h new file mode 100644 index 0000000000..c75a81da7d --- /dev/null +++ b/examples/videowidget/videowidgetsurface.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef VIDEOWIDGETSURFACE_H +#define VIDEOWIDGETSURFACE_H + +#include <QtCore/QRect> +#include <QtGui/QImage> +#include <qabstractvideosurface.h> +#include <qvideoframe.h> + +//! [0] +class VideoWidgetSurface : public QAbstractVideoSurface +{ + Q_OBJECT +public: + VideoWidgetSurface(QWidget *widget, QObject *parent = 0); + + QList<QVideoFrame::PixelFormat> supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const; + bool isFormatSupported(const QVideoSurfaceFormat &format, QVideoSurfaceFormat *similar) const; + + bool start(const QVideoSurfaceFormat &format); + void stop(); + + bool present(const QVideoFrame &frame); + + QRect videoRect() const { return targetRect; } + void updateVideoRect(); + + void paint(QPainter *painter); + +private: + QWidget *widget; + QImage::Format imageFormat; + QRect targetRect; + QSize imageSize; + QRect sourceRect; + QVideoFrame currentFrame; +}; +//! [0] + +#endif |