Ported gstreamer camera backend from camerabin to camerabin2.
Change-Id: Ieb08df492e7b9cbfe35e93a056685cfdac6e704e Reviewed-on: http://codereview.qt.nokia.com/2994 Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com> Reviewed-by: Michael Goddard <michael.goddard@nokia.com>
This commit is contained in:
committed by
Qt by Nokia
parent
abee3a6548
commit
da9b436cd1
@@ -14,7 +14,8 @@ PKGCONFIG += \
|
||||
gstreamer-base-0.10 \
|
||||
gstreamer-interfaces-0.10 \
|
||||
gstreamer-audio-0.10 \
|
||||
gstreamer-video-0.10
|
||||
gstreamer-video-0.10 \
|
||||
gstreamer-pbutils-0.10
|
||||
|
||||
LIBS += -lgstphotography-0.10
|
||||
|
||||
|
||||
@@ -43,6 +43,8 @@
|
||||
|
||||
#include <gst/interfaces/photography.h>
|
||||
#include <gst/interfaces/photography-enumtypes.h>
|
||||
#include <gst/pbutils/pbutils.h>
|
||||
#include <gst/pbutils/encoding-profile.h>
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
|
||||
@@ -41,68 +41,14 @@
|
||||
|
||||
#include "camerabinaudioencoder.h"
|
||||
#include "camerabincontainer.h"
|
||||
#include "qgstcodecsinfo.h"
|
||||
|
||||
#include <QtCore/qdebug.h>
|
||||
|
||||
CameraBinAudioEncoder::CameraBinAudioEncoder(QObject *parent)
|
||||
:QAudioEncoderControl(parent)
|
||||
:QAudioEncoderControl(parent),
|
||||
m_codecs(QGstCodecsInfo::AudioEncoder)
|
||||
{
|
||||
QList<QByteArray> codecCandidates;
|
||||
|
||||
#if defined(Q_WS_MAEMO_6)
|
||||
codecCandidates << "audio/AAC" << "audio/PCM" << "audio/AMR" << "audio/AMR-WB" << "audio/speex"
|
||||
<< "audio/ADPCM" << "audio/iLBC" << "audio/vorbis" << "audio/mpeg" << "audio/FLAC";
|
||||
|
||||
m_elementNames["audio/AAC"] = "nokiaaacenc";
|
||||
m_elementNames["audio/speex"] = "speexenc";
|
||||
m_elementNames["audio/PCM"] = "audioresample";
|
||||
m_elementNames["audio/AMR"] = "nokiaamrnbenc";
|
||||
m_elementNames["audio/AMR-WB"] = "nokiaamrwbenc";
|
||||
m_elementNames["audio/ADPCM"] = "nokiaadpcmenc";
|
||||
m_elementNames["audio/iLBC"] = "nokiailbcenc";
|
||||
m_elementNames["audio/vorbis"] = "vorbisenc";
|
||||
m_elementNames["audio/FLAC"] = "flacenc";
|
||||
m_elementNames["audio/mpeg"] = "ffenc_mp2";
|
||||
#else
|
||||
codecCandidates << "audio/mpeg" << "audio/vorbis" << "audio/speex" << "audio/GSM"
|
||||
<< "audio/PCM" << "audio/AMR" << "audio/AMR-WB";
|
||||
|
||||
m_elementNames["audio/mpeg"] = "lamemp3enc";
|
||||
m_elementNames["audio/vorbis"] = "vorbisenc";
|
||||
m_elementNames["audio/speex"] = "speexenc";
|
||||
m_elementNames["audio/GSM"] = "gsmenc";
|
||||
m_elementNames["audio/PCM"] = "audioresample";
|
||||
m_elementNames["audio/AMR"] = "amrnbenc";
|
||||
m_elementNames["audio/AMR-WB"] = "amrwbenc";
|
||||
|
||||
m_codecOptions["audio/vorbis"] = QStringList() << "min-bitrate" << "max-bitrate";
|
||||
m_codecOptions["audio/mpeg"] = QStringList() << "mode";
|
||||
m_codecOptions["audio/speex"] = QStringList() << "mode" << "vbr" << "vad" << "dtx";
|
||||
m_codecOptions["audio/GSM"] = QStringList();
|
||||
m_codecOptions["audio/PCM"] = QStringList();
|
||||
m_codecOptions["audio/AMR"] = QStringList();
|
||||
m_codecOptions["audio/AMR-WB"] = QStringList();
|
||||
#endif
|
||||
|
||||
foreach( const QByteArray& codecName, codecCandidates ) {
|
||||
QByteArray elementName = m_elementNames[codecName];
|
||||
GstElementFactory *factory = gst_element_factory_find(elementName.constData());
|
||||
|
||||
if (factory) {
|
||||
m_codecs.append(codecName);
|
||||
const gchar *descr = gst_element_factory_get_description(factory);
|
||||
|
||||
if (codecName == QByteArray("audio/PCM"))
|
||||
m_codecDescriptions.insert(codecName, tr("Raw PCM audio"));
|
||||
else
|
||||
m_codecDescriptions.insert(codecName, QString::fromUtf8(descr));
|
||||
|
||||
m_streamTypes.insert(codecName,
|
||||
CameraBinContainer::supportedStreamTypes(factory, GST_PAD_SRC));
|
||||
|
||||
gst_object_unref(GST_OBJECT(factory));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CameraBinAudioEncoder::~CameraBinAudioEncoder()
|
||||
@@ -111,12 +57,12 @@ CameraBinAudioEncoder::~CameraBinAudioEncoder()
|
||||
|
||||
QStringList CameraBinAudioEncoder::supportedAudioCodecs() const
|
||||
{
|
||||
return m_codecs;
|
||||
return m_codecs.supportedCodecs();
|
||||
}
|
||||
|
||||
QString CameraBinAudioEncoder::codecDescription(const QString &codecName) const
|
||||
{
|
||||
return m_codecDescriptions.value(codecName);
|
||||
return m_codecs.codecDescription(codecName);
|
||||
}
|
||||
|
||||
QStringList CameraBinAudioEncoder::supportedEncodingOptions(const QString &codec) const
|
||||
@@ -165,129 +111,19 @@ void CameraBinAudioEncoder::resetActualSettings()
|
||||
m_audioSettings = m_userSettings;
|
||||
}
|
||||
|
||||
GstElement *CameraBinAudioEncoder::createEncoder()
|
||||
GstEncodingProfile *CameraBinAudioEncoder::createProfile()
|
||||
{
|
||||
QString codec = m_audioSettings.codec();
|
||||
QByteArray encoderElementName = m_elementNames.value(codec);
|
||||
GstElement *encoderElement = gst_element_factory_make(encoderElementName.constData(), NULL);
|
||||
if (!encoderElement)
|
||||
return 0;
|
||||
GstCaps *caps;
|
||||
|
||||
GstBin * encoderBin = GST_BIN(gst_bin_new("audio-encoder-bin"));
|
||||
GstElement *capsFilter = gst_element_factory_make("capsfilter", NULL);
|
||||
if (codec.isEmpty())
|
||||
caps = gst_caps_new_any();
|
||||
else
|
||||
caps = gst_caps_from_string(codec.toLatin1());
|
||||
|
||||
gst_bin_add(encoderBin, capsFilter);
|
||||
gst_bin_add(encoderBin, encoderElement);
|
||||
gst_element_link(capsFilter, encoderElement);
|
||||
|
||||
// add ghostpads
|
||||
GstPad *pad = gst_element_get_static_pad(capsFilter, "sink");
|
||||
gst_element_add_pad(GST_ELEMENT(encoderBin), gst_ghost_pad_new("sink", pad));
|
||||
gst_object_unref(GST_OBJECT(pad));
|
||||
|
||||
pad = gst_element_get_static_pad(encoderElement, "src");
|
||||
gst_element_add_pad(GST_ELEMENT(encoderBin), gst_ghost_pad_new("src", pad));
|
||||
gst_object_unref(GST_OBJECT(pad));
|
||||
|
||||
if (m_audioSettings.sampleRate() > 0 || m_audioSettings.channelCount() > 0) {
|
||||
GstCaps *caps = gst_caps_new_empty();
|
||||
GstStructure *structure = gst_structure_new("audio/x-raw-int", NULL);
|
||||
|
||||
if (m_audioSettings.sampleRate() > 0)
|
||||
gst_structure_set(structure, "rate", G_TYPE_INT, m_audioSettings.sampleRate(), NULL );
|
||||
|
||||
if (m_audioSettings.channelCount() > 0)
|
||||
gst_structure_set(structure, "channels", G_TYPE_INT, m_audioSettings.channelCount(), NULL );
|
||||
|
||||
gst_caps_append_structure(caps,structure);
|
||||
|
||||
g_object_set(G_OBJECT(capsFilter), "caps", caps, NULL);
|
||||
}
|
||||
|
||||
if (encoderElement) {
|
||||
if (m_audioSettings.encodingMode() == QtMultimediaKit::ConstantQualityEncoding) {
|
||||
QtMultimediaKit::EncodingQuality qualityValue = m_audioSettings.quality();
|
||||
|
||||
if (encoderElementName == "lamemp3enc") {
|
||||
g_object_set(G_OBJECT(encoderElement), "target", 0, NULL); //constant quality mode
|
||||
qreal quality[] = {
|
||||
10.0, //VeryLow
|
||||
6.0, //Low
|
||||
4.0, //Normal
|
||||
2.0, //High
|
||||
0.0 //VeryHigh
|
||||
};
|
||||
g_object_set(G_OBJECT(encoderElement), "quality", quality[qualityValue], NULL);
|
||||
} else if (encoderElementName == "ffenc_mp2") {
|
||||
int quality[] = {
|
||||
8000, //VeryLow
|
||||
64000, //Low
|
||||
128000, //Normal
|
||||
192000, //High
|
||||
320000 //VeryHigh
|
||||
};
|
||||
g_object_set(G_OBJECT(encoderElement), "bitrate", quality[qualityValue], NULL);
|
||||
} else if (codec == QLatin1String("audio/speex")) {
|
||||
//0-10 range with default 8
|
||||
double qualityTable[] = {
|
||||
2, //VeryLow
|
||||
5, //Low
|
||||
8, //Normal
|
||||
9, //High
|
||||
10 //VeryHigh
|
||||
};
|
||||
g_object_set(G_OBJECT(encoderElement), "quality", qualityTable[qualityValue], NULL);
|
||||
} else if (codec.startsWith("audio/AMR")) {
|
||||
int band[] = {
|
||||
0, //VeryLow
|
||||
2, //Low
|
||||
4, //Normal
|
||||
6, //High
|
||||
7 //VeryHigh
|
||||
};
|
||||
|
||||
g_object_set(G_OBJECT(encoderElement), "band-mode", band[qualityValue], NULL);
|
||||
}
|
||||
} else {
|
||||
int bitrate = m_audioSettings.bitRate();
|
||||
if (bitrate > 0) {
|
||||
g_object_set(G_OBJECT(encoderElement), "bitrate", bitrate, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
QMap<QString, QVariant> options = m_options.value(codec);
|
||||
QMapIterator<QString,QVariant> it(options);
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
QString option = it.key();
|
||||
QVariant value = it.value();
|
||||
|
||||
switch (value.type()) {
|
||||
case QVariant::Int:
|
||||
g_object_set(G_OBJECT(encoderElement), option.toAscii(), value.toInt(), NULL);
|
||||
break;
|
||||
case QVariant::Bool:
|
||||
g_object_set(G_OBJECT(encoderElement), option.toAscii(), value.toBool(), NULL);
|
||||
break;
|
||||
case QVariant::Double:
|
||||
g_object_set(G_OBJECT(encoderElement), option.toAscii(), value.toDouble(), NULL);
|
||||
break;
|
||||
case QVariant::String:
|
||||
g_object_set(G_OBJECT(encoderElement), option.toAscii(), value.toString().toUtf8().constData(), NULL);
|
||||
break;
|
||||
default:
|
||||
qWarning() << "unsupported option type:" << option << value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return GST_ELEMENT(encoderBin);
|
||||
|
||||
}
|
||||
|
||||
|
||||
QSet<QString> CameraBinAudioEncoder::supportedStreamTypes(const QString &codecName) const
|
||||
{
|
||||
return m_streamTypes.value(codecName);
|
||||
return (GstEncodingProfile *)gst_encoding_audio_profile_new(
|
||||
caps,
|
||||
NULL, //preset
|
||||
NULL, //restriction
|
||||
0); //presence
|
||||
}
|
||||
|
||||
@@ -50,8 +50,11 @@ class CameraBinSession;
|
||||
#include <QtCore/qset.h>
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/pbutils/pbutils.h>
|
||||
#include <gst/pbutils/encoding-profile.h>
|
||||
|
||||
#include <qaudioformat.h>
|
||||
#include "qgstcodecsinfo.h"
|
||||
|
||||
QT_USE_NAMESPACE
|
||||
|
||||
@@ -77,27 +80,19 @@ public:
|
||||
QAudioEncoderSettings audioSettings() const;
|
||||
void setAudioSettings(const QAudioEncoderSettings&);
|
||||
|
||||
|
||||
GstElement *createEncoder();
|
||||
|
||||
QSet<QString> supportedStreamTypes(const QString &codecName) const;
|
||||
|
||||
void setActualAudioSettings(const QAudioEncoderSettings&);
|
||||
void resetActualSettings();
|
||||
|
||||
GstEncodingProfile *createProfile();
|
||||
|
||||
Q_SIGNALS:
|
||||
void settingsChanged();
|
||||
|
||||
private:
|
||||
QStringList m_codecs;
|
||||
QMap<QString,QByteArray> m_elementNames;
|
||||
QMap<QString,QString> m_codecDescriptions;
|
||||
QGstCodecsInfo m_codecs;
|
||||
QMap<QString,QStringList> m_codecOptions;
|
||||
|
||||
QMap<QString, QMap<QString, QVariant> > m_options;
|
||||
|
||||
QMap<QString, QSet<QString> > m_streamTypes;
|
||||
|
||||
QAudioEncoderSettings m_audioSettings;
|
||||
QAudioEncoderSettings m_userSettings;
|
||||
};
|
||||
|
||||
@@ -40,83 +40,90 @@
|
||||
****************************************************************************/
|
||||
|
||||
#include "camerabincontainer.h"
|
||||
|
||||
#include <QtCore/qregexp.h>
|
||||
|
||||
#include <QtCore/qdebug.h>
|
||||
|
||||
CameraBinContainer::CameraBinContainer(QObject *parent)
|
||||
:QMediaContainerControl(parent)
|
||||
:QMediaContainerControl(parent),
|
||||
m_supportedContainers(QGstCodecsInfo::Muxer)
|
||||
{
|
||||
QList<QByteArray> formatCandidates;
|
||||
formatCandidates << "mp4" << "ogg" << "wav" << "amr" << "mkv"
|
||||
<< "avi" << "3gp" << "3gp2" << "webm" << "mjpeg" << "asf" << "mov";
|
||||
|
||||
QMap<QString,QByteArray> elementNames;
|
||||
|
||||
elementNames.insertMulti("mp4", "ffmux_mp4");
|
||||
elementNames.insertMulti("mp4", "hantromp4mux");
|
||||
elementNames.insertMulti("mp4", "mp4mux");
|
||||
elementNames.insert("ogg", "oggmux");
|
||||
elementNames["wav"] = "wavenc";
|
||||
elementNames["amr"] = "ffmux_amr";
|
||||
elementNames["mkv"] = "matroskamux";
|
||||
elementNames["avi"] = "avimux";
|
||||
elementNames["3gp"] = "ffmux_3gp";
|
||||
elementNames["3gp2"] = "ffmux_3g2";
|
||||
elementNames["webm"] = "webmmux";
|
||||
elementNames["mjpeg"] = "ffmux_mjpeg";
|
||||
elementNames["asf"] = "ffmux_asf";
|
||||
elementNames["mov"] = "qtmux";
|
||||
|
||||
QSet<QString> allTypes;
|
||||
|
||||
foreach(const QByteArray &formatName, formatCandidates) {
|
||||
foreach(const QByteArray &elementName, elementNames.values(formatName)) {
|
||||
GstElementFactory *factory = gst_element_factory_find(elementName.constData());
|
||||
if (factory) {
|
||||
m_supportedContainers.append(formatName);
|
||||
const gchar *descr = gst_element_factory_get_description(factory);
|
||||
m_containerDescriptions.insert(formatName, QString::fromUtf8(descr));
|
||||
|
||||
|
||||
if (formatName == QByteArray("raw")) {
|
||||
m_streamTypes.insert(formatName, allTypes);
|
||||
} else {
|
||||
QSet<QString> types = supportedStreamTypes(factory, GST_PAD_SINK);
|
||||
m_streamTypes.insert(formatName, types);
|
||||
allTypes.unite(types);
|
||||
//extension for containers hard to guess from mimetype
|
||||
m_fileExtensions["video/x-matroska"] = "mkv";
|
||||
m_fileExtensions["video/quicktime"] = "mov";
|
||||
m_fileExtensions["video/x-msvideo"] = "avi";
|
||||
m_fileExtensions["video/msvideo"] = "avi";
|
||||
m_fileExtensions["audio/mpeg"] = "mp3";
|
||||
m_fileExtensions["application/x-shockwave-flash"] = "swf";
|
||||
m_fileExtensions["application/x-pn-realmedia"] = "rm";
|
||||
}
|
||||
|
||||
gst_object_unref(GST_OBJECT(factory));
|
||||
|
||||
m_elementNames.insert(formatName, elementName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QSet<QString> CameraBinContainer::supportedStreamTypes(GstElementFactory *factory, GstPadDirection direction)
|
||||
QStringList CameraBinContainer::supportedContainers() const
|
||||
{
|
||||
QSet<QString> types;
|
||||
const GList *pads = gst_element_factory_get_static_pad_templates(factory);
|
||||
for (const GList *pad = pads; pad; pad = g_list_next(pad)) {
|
||||
GstStaticPadTemplate *templ = (GstStaticPadTemplate*)pad->data;
|
||||
if (templ->direction == direction) {
|
||||
GstCaps *caps = gst_static_caps_get(&templ->static_caps);
|
||||
for (uint i=0; i<gst_caps_get_size(caps); i++) {
|
||||
GstStructure *structure = gst_caps_get_structure(caps, i);
|
||||
types.insert( QString::fromUtf8(gst_structure_get_name(structure)) );
|
||||
}
|
||||
gst_caps_unref(caps);
|
||||
}
|
||||
return m_supportedContainers.supportedCodecs();
|
||||
}
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
|
||||
QSet<QString> CameraBinContainer::supportedStreamTypes(const QString &container) const
|
||||
QString CameraBinContainer::containerDescription(const QString &formatMimeType) const
|
||||
{
|
||||
return m_streamTypes.value(container);
|
||||
return m_supportedContainers.codecDescription(formatMimeType);
|
||||
}
|
||||
|
||||
QString CameraBinContainer::containerMimeType() const
|
||||
{
|
||||
return m_format;
|
||||
}
|
||||
|
||||
void CameraBinContainer::setContainerMimeType(const QString &formatMimeType)
|
||||
{
|
||||
m_format = formatMimeType;
|
||||
|
||||
if (m_userFormat != formatMimeType) {
|
||||
m_userFormat = formatMimeType;
|
||||
emit settingsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void CameraBinContainer::setActualContainer(const QString &formatMimeType)
|
||||
{
|
||||
m_format = formatMimeType;
|
||||
}
|
||||
|
||||
void CameraBinContainer::resetActualContainer()
|
||||
{
|
||||
m_format = m_userFormat;
|
||||
}
|
||||
|
||||
GstEncodingContainerProfile *CameraBinContainer::createProfile()
|
||||
{
|
||||
GstCaps *caps;
|
||||
|
||||
if (m_format.isEmpty())
|
||||
caps = gst_caps_new_any();
|
||||
else
|
||||
caps = gst_caps_from_string(m_format.toLatin1());
|
||||
|
||||
return (GstEncodingContainerProfile *)gst_encoding_container_profile_new(
|
||||
"camerabin2_profile",
|
||||
(gchar *)"custom camera profile",
|
||||
caps,
|
||||
NULL); //preset
|
||||
}
|
||||
|
||||
/*!
|
||||
Suggest file extension for current container mimetype.
|
||||
*/
|
||||
QString CameraBinContainer::suggestedFileExtension() const
|
||||
{
|
||||
QString format = m_format.left(m_format.indexOf(','));
|
||||
QString extension = m_fileExtensions.value(format);
|
||||
|
||||
if (!extension.isEmpty() || format.isEmpty())
|
||||
return extension;
|
||||
|
||||
QRegExp rx("[-/]([\\w]+)$");
|
||||
|
||||
if (rx.indexIn(format) != -1)
|
||||
extension = rx.cap(1);
|
||||
|
||||
return extension;
|
||||
}
|
||||
|
||||
@@ -48,6 +48,10 @@
|
||||
#include <QtCore/qset.h>
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/pbutils/pbutils.h>
|
||||
#include <gst/pbutils/encoding-profile.h>
|
||||
|
||||
#include "qgstcodecsinfo.h"
|
||||
|
||||
QT_USE_NAMESPACE
|
||||
|
||||
@@ -58,35 +62,18 @@ public:
|
||||
CameraBinContainer(QObject *parent);
|
||||
virtual ~CameraBinContainer() {}
|
||||
|
||||
virtual QStringList supportedContainers() const { return m_supportedContainers; }
|
||||
virtual QString containerMimeType() const { return m_format; }
|
||||
virtual void setContainerMimeType(const QString &formatMimeType)
|
||||
{
|
||||
m_format = formatMimeType;
|
||||
virtual QStringList supportedContainers() const;
|
||||
virtual QString containerDescription(const QString &formatMimeType) const;
|
||||
|
||||
if (m_userFormat != formatMimeType) {
|
||||
m_userFormat = formatMimeType;
|
||||
emit settingsChanged();
|
||||
}
|
||||
}
|
||||
virtual QString containerMimeType() const;
|
||||
virtual void setContainerMimeType(const QString &formatMimeType);
|
||||
|
||||
void setActualContainer(const QString &formatMimeType)
|
||||
{
|
||||
m_format = formatMimeType;
|
||||
}
|
||||
void setActualContainer(const QString &formatMimeType);
|
||||
void resetActualContainer();
|
||||
|
||||
void resetActualContainer()
|
||||
{
|
||||
m_format = m_userFormat;
|
||||
}
|
||||
QString suggestedFileExtension() const;
|
||||
|
||||
virtual QString containerDescription(const QString &formatMimeType) const { return m_containerDescriptions.value(formatMimeType); }
|
||||
|
||||
QByteArray formatElementName() const { return m_elementNames.value(containerMimeType()); }
|
||||
|
||||
QSet<QString> supportedStreamTypes(const QString &container) const;
|
||||
|
||||
static QSet<QString> supportedStreamTypes(GstElementFactory *factory, GstPadDirection direction);
|
||||
GstEncodingContainerProfile *createProfile();
|
||||
|
||||
Q_SIGNALS:
|
||||
void settingsChanged();
|
||||
@@ -94,10 +81,9 @@ Q_SIGNALS:
|
||||
private:
|
||||
QString m_format; // backend selected format, using m_userFormat
|
||||
QString m_userFormat;
|
||||
QStringList m_supportedContainers;
|
||||
QMap<QString,QByteArray> m_elementNames;
|
||||
QMap<QString, QString> m_containerDescriptions;
|
||||
QMap<QString, QSet<QString> > m_streamTypes;
|
||||
QMap<QString, QString> m_fileExtensions;
|
||||
|
||||
QGstCodecsInfo m_supportedContainers;
|
||||
};
|
||||
|
||||
#endif // CAMERABINMEDIACONTAINERCONTROL_H
|
||||
|
||||
@@ -75,14 +75,6 @@ CameraBinControl::CameraBinControl(CameraBinSession *session)
|
||||
connect(m_session, SIGNAL(stateChanged(QCamera::State)),
|
||||
this, SLOT(updateStatus()));
|
||||
|
||||
connect(m_session->audioEncodeControl(), SIGNAL(settingsChanged()),
|
||||
SLOT(reloadLater()));
|
||||
connect(m_session->videoEncodeControl(), SIGNAL(settingsChanged()),
|
||||
SLOT(reloadLater()));
|
||||
connect(m_session->mediaContainerControl(), SIGNAL(settingsChanged()),
|
||||
SLOT(reloadLater()));
|
||||
connect(m_session->imageEncodeControl(), SIGNAL(settingsChanged()),
|
||||
SLOT(reloadLater()));
|
||||
connect(m_session, SIGNAL(viewfinderChanged()),
|
||||
SLOT(reloadLater()));
|
||||
connect(m_session, SIGNAL(readyChanged(bool)),
|
||||
@@ -115,7 +107,6 @@ void CameraBinControl::setCaptureMode(QCamera::CaptureMode mode)
|
||||
{
|
||||
if (m_session->captureMode() != mode) {
|
||||
m_session->setCaptureMode(mode);
|
||||
reloadLater();
|
||||
|
||||
if (m_state == QCamera::ActiveState) {
|
||||
m_resourcePolicy->setResourceSet(
|
||||
|
||||
@@ -48,7 +48,8 @@
|
||||
#include <QtCore/qmetaobject.h>
|
||||
|
||||
//#define CAMERABIN_DEBUG 1
|
||||
#define ENUM_NAME(c,e,v) (c::staticMetaObject.enumerator(c::staticMetaObject.indexOfEnumerator(e)).valueToKey((v)))
|
||||
#define ZOOM_PROPERTY "zoom"
|
||||
#define MAX_ZOOM_PROPERTY "max-zoom"
|
||||
|
||||
CameraBinFocus::CameraBinFocus(CameraBinSession *session)
|
||||
:QCameraFocusControl(session),
|
||||
@@ -59,8 +60,6 @@ CameraBinFocus::CameraBinFocus(CameraBinSession *session)
|
||||
{
|
||||
connect(m_session, SIGNAL(stateChanged(QCamera::State)),
|
||||
this, SLOT(_q_handleCameraStateChange(QCamera::State)));
|
||||
connect(m_session, SIGNAL(imageCaptured(int,QImage)),
|
||||
this, SLOT(_q_handleCapturedImage()));
|
||||
}
|
||||
|
||||
CameraBinFocus::~CameraBinFocus()
|
||||
@@ -91,7 +90,9 @@ qreal CameraBinFocus::maximumOpticalZoom() const
|
||||
|
||||
qreal CameraBinFocus::maximumDigitalZoom() const
|
||||
{
|
||||
return 10;
|
||||
gfloat zoomFactor = 1.0;
|
||||
g_object_get(GST_BIN(m_session->cameraBin()), MAX_ZOOM_PROPERTY, &zoomFactor, NULL);
|
||||
return zoomFactor;
|
||||
}
|
||||
|
||||
qreal CameraBinFocus::opticalZoom() const
|
||||
@@ -102,15 +103,15 @@ qreal CameraBinFocus::opticalZoom() const
|
||||
qreal CameraBinFocus::digitalZoom() const
|
||||
{
|
||||
gfloat zoomFactor = 1.0;
|
||||
g_object_get(GST_BIN(m_session->cameraBin()), "zoom", &zoomFactor, NULL);
|
||||
g_object_get(GST_BIN(m_session->cameraBin()), ZOOM_PROPERTY, &zoomFactor, NULL);
|
||||
return zoomFactor;
|
||||
}
|
||||
|
||||
void CameraBinFocus::zoomTo(qreal optical, qreal digital)
|
||||
{
|
||||
Q_UNUSED(optical);
|
||||
digital = qBound(qreal(1.0), digital, qreal(10.0));
|
||||
g_object_set(GST_BIN(m_session->cameraBin()), "zoom", digital, NULL);
|
||||
digital = qBound(qreal(1.0), digital, maximumDigitalZoom());
|
||||
g_object_set(GST_BIN(m_session->cameraBin()), ZOOM_PROPERTY, digital, NULL);
|
||||
emit digitalZoomChanged(digital);
|
||||
}
|
||||
|
||||
@@ -184,9 +185,9 @@ void CameraBinFocus::_q_setFocusStatus(QCamera::LockStatus status, QCamera::Lock
|
||||
{
|
||||
#ifdef CAMERABIN_DEBUG
|
||||
qDebug() << Q_FUNC_INFO << "Current:"
|
||||
<< ENUM_NAME(QCamera, "LockStatus", m_focusStatus)
|
||||
<< m_focusStatus
|
||||
<< "New:"
|
||||
<< ENUM_NAME(QCamera, "LockStatus", status) << ENUM_NAME(QCamera, "LockChangeReason", reason);
|
||||
<< status << reason;
|
||||
#endif
|
||||
|
||||
if (m_focusStatus != status) {
|
||||
@@ -211,10 +212,6 @@ void CameraBinFocus::_q_handleCameraStateChange(QCamera::State state)
|
||||
_q_setFocusStatus(QCamera::Unlocked, QCamera::LockLost);
|
||||
}
|
||||
|
||||
void CameraBinFocus::_q_handleCapturedImage()
|
||||
{
|
||||
}
|
||||
|
||||
void CameraBinFocus::_q_startFocusing()
|
||||
{
|
||||
_q_setFocusStatus(QCamera::Searching, QCamera::UserRequest);
|
||||
|
||||
@@ -92,7 +92,6 @@ public Q_SLOTS:
|
||||
private Q_SLOTS:
|
||||
void _q_setFocusStatus(QCamera::LockStatus status, QCamera::LockChangeReason reason);
|
||||
void _q_handleCameraStateChange(QCamera::State state);
|
||||
void _q_handleCapturedImage();
|
||||
|
||||
private:
|
||||
CameraBinSession *m_session;
|
||||
|
||||
@@ -84,7 +84,6 @@ CameraBinImageCapture::CameraBinImageCapture(CameraBinSession *session)
|
||||
connect(m_session, SIGNAL(imageCaptured(int,QImage)), this, SIGNAL(imageCaptured(int,QImage)));
|
||||
|
||||
m_session->bus()->installMessageFilter(this);
|
||||
g_signal_connect(G_OBJECT(m_session->cameraBin()), IMAGE_DONE_SIGNAL, G_CALLBACK(handleImageSaved), this);
|
||||
}
|
||||
|
||||
CameraBinImageCapture::~CameraBinImageCapture()
|
||||
@@ -127,39 +126,9 @@ void CameraBinImageCapture::updateState()
|
||||
}
|
||||
}
|
||||
|
||||
gboolean CameraBinImageCapture::handleImageSaved(GstElement *camera,
|
||||
const gchar *filename,
|
||||
CameraBinImageCapture *self)
|
||||
{
|
||||
#ifdef DEBUG_CAPTURE
|
||||
qDebug() << "Image saved" << filename;
|
||||
#endif
|
||||
|
||||
Q_UNUSED(camera);
|
||||
|
||||
if (self->m_session->captureDestinationControl()->captureDestination() & QCameraImageCapture::CaptureToFile) {
|
||||
QMetaObject::invokeMethod(self, "imageSaved",
|
||||
Qt::QueuedConnection,
|
||||
Q_ARG(int, self->m_requestId),
|
||||
Q_ARG(QString, QString::fromUtf8(filename)));
|
||||
} else {
|
||||
#ifdef DEBUG_CAPTURE
|
||||
qDebug() << Q_FUNC_INFO << "Dropped saving file" << filename;
|
||||
#endif
|
||||
//camerabin creates an empty file when captured buffer is dropped,
|
||||
//let's remove it
|
||||
QFileInfo info(QString::fromUtf8(filename));
|
||||
if (info.isFile() &&
|
||||
info.filePath().startsWith("/home") &&
|
||||
info.size() == 0) {
|
||||
QFile(info.absoluteFilePath()).remove();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
gboolean CameraBinImageCapture::metadataEventProbe(GstPad *pad, GstEvent *event, CameraBinImageCapture *self)
|
||||
{
|
||||
Q_UNUSED(pad);
|
||||
|
||||
if (GST_EVENT_TYPE(event) == GST_EVENT_TAG) {
|
||||
GstTagList *gstTags;
|
||||
@@ -338,7 +307,33 @@ bool CameraBinImageCapture::processBusMessage(const QGstreamerMessage &message)
|
||||
gst_object_unref(srcpad);
|
||||
}
|
||||
}
|
||||
} else if (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_ELEMENT) {
|
||||
if (GST_MESSAGE_SRC(gm) == (GstObject *)m_session->cameraBin()) {
|
||||
const GstStructure *structure = gst_message_get_structure(gm);
|
||||
|
||||
if (gst_structure_has_name (structure, "image-done")) {
|
||||
const gchar *fileName = gst_structure_get_string (structure, "filename");
|
||||
#ifdef DEBUG_CAPTURE
|
||||
qDebug() << "Image saved" << fileName;
|
||||
#endif
|
||||
|
||||
if (m_session->captureDestinationControl()->captureDestination() & QCameraImageCapture::CaptureToFile) {
|
||||
emit imageSaved(m_requestId, QString::fromUtf8(fileName));
|
||||
} else {
|
||||
#ifdef DEBUG_CAPTURE
|
||||
qDebug() << Q_FUNC_INFO << "Dropped saving file" << fileName;
|
||||
#endif
|
||||
//camerabin creates an empty file when captured buffer is dropped,
|
||||
//let's remove it
|
||||
QFileInfo info(QString::fromUtf8(fileName));
|
||||
if (info.exists() && info.isFile() && info.size() == 0) {
|
||||
QFile(info.absoluteFilePath()).remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,6 @@ private:
|
||||
static gboolean metadataEventProbe(GstPad *pad, GstEvent *event, CameraBinImageCapture *);
|
||||
static gboolean uncompressedBufferProbe(GstPad *pad, GstBuffer *buffer, CameraBinImageCapture *);
|
||||
static gboolean jpegBufferProbe(GstPad *pad, GstBuffer *buffer, CameraBinImageCapture *);
|
||||
static gboolean handleImageSaved(GstElement *camera, const gchar *filename, CameraBinImageCapture *);
|
||||
|
||||
CameraBinSession *m_session;
|
||||
bool m_ready;
|
||||
|
||||
@@ -45,6 +45,8 @@
|
||||
#include "camerabincontainer.h"
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
#include <gst/pbutils/encoding-profile.h>
|
||||
|
||||
CameraBinRecorder::CameraBinRecorder(CameraBinSession *session)
|
||||
:QMediaRecorderControl(session),
|
||||
m_session(session),
|
||||
@@ -92,9 +94,6 @@ qint64 CameraBinRecorder::duration() const
|
||||
void CameraBinRecorder::record()
|
||||
{
|
||||
if (m_session->state() == QCamera::ActiveState) {
|
||||
if (m_state == QMediaRecorder::PausedState)
|
||||
m_session->resumeVideoRecording();
|
||||
else
|
||||
m_session->recordVideo();
|
||||
emit stateChanged(m_state = QMediaRecorder::RecordingState);
|
||||
} else
|
||||
@@ -103,11 +102,7 @@ void CameraBinRecorder::record()
|
||||
|
||||
void CameraBinRecorder::pause()
|
||||
{
|
||||
if (m_session->state() == QCamera::ActiveState) {
|
||||
m_session->pauseVideoRecording();
|
||||
emit stateChanged(m_state = QMediaRecorder::PausedState);
|
||||
} else
|
||||
emit error(QMediaRecorder::ResourceError, tr("Service has not been started"));
|
||||
emit error(QMediaRecorder::ResourceError, tr("QMediaRecorder::pause() is not supported by camerabin2."));
|
||||
}
|
||||
|
||||
void CameraBinRecorder::stop()
|
||||
@@ -118,100 +113,19 @@ void CameraBinRecorder::stop()
|
||||
}
|
||||
}
|
||||
|
||||
bool CameraBinRecorder::findCodecs()
|
||||
{
|
||||
//Check the codecs are compatible with container,
|
||||
//and choose the compatible codecs/container if omitted
|
||||
CameraBinAudioEncoder *audioEncodeControl = m_session->audioEncodeControl();
|
||||
CameraBinVideoEncoder *videoEncodeControl = m_session->videoEncodeControl();
|
||||
CameraBinContainer *mediaContainerControl = m_session->mediaContainerControl();
|
||||
|
||||
audioEncodeControl->resetActualSettings();
|
||||
videoEncodeControl->resetActualSettings();
|
||||
mediaContainerControl->resetActualContainer();
|
||||
|
||||
QStringList containerCandidates;
|
||||
if (mediaContainerControl->containerMimeType().isEmpty())
|
||||
containerCandidates = mediaContainerControl->supportedContainers();
|
||||
else
|
||||
containerCandidates << mediaContainerControl->containerMimeType();
|
||||
|
||||
|
||||
QStringList audioCandidates;
|
||||
QAudioEncoderSettings audioSettings = audioEncodeControl->audioSettings();
|
||||
if (audioSettings.codec().isEmpty())
|
||||
audioCandidates = audioEncodeControl->supportedAudioCodecs();
|
||||
else
|
||||
audioCandidates << audioSettings.codec();
|
||||
|
||||
QStringList videoCandidates;
|
||||
QVideoEncoderSettings videoSettings = videoEncodeControl->videoSettings();
|
||||
if (videoSettings.codec().isEmpty())
|
||||
videoCandidates = videoEncodeControl->supportedVideoCodecs();
|
||||
else
|
||||
videoCandidates << videoSettings.codec();
|
||||
|
||||
QString container;
|
||||
QString audioCodec;
|
||||
QString videoCodec;
|
||||
|
||||
foreach (const QString &containerCandidate, containerCandidates) {
|
||||
QSet<QString> supportedTypes = mediaContainerControl->supportedStreamTypes(containerCandidate);
|
||||
|
||||
audioCodec.clear();
|
||||
videoCodec.clear();
|
||||
|
||||
bool found = false;
|
||||
foreach (const QString &audioCandidate, audioCandidates) {
|
||||
QSet<QString> audioTypes = audioEncodeControl->supportedStreamTypes(audioCandidate);
|
||||
if (!audioTypes.intersect(supportedTypes).isEmpty()) {
|
||||
found = true;
|
||||
audioCodec = audioCandidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
continue;
|
||||
|
||||
found = false;
|
||||
foreach (const QString &videoCandidate, videoCandidates) {
|
||||
QSet<QString> videoTypes = videoEncodeControl->supportedStreamTypes(videoCandidate);
|
||||
if (!videoTypes.intersect(supportedTypes).isEmpty()) {
|
||||
found = true;
|
||||
videoCodec = videoCandidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
continue;
|
||||
|
||||
|
||||
container = containerCandidate;
|
||||
break;
|
||||
}
|
||||
|
||||
if (container.isEmpty()) {
|
||||
qWarning() << "Camera error: Not compatible codecs and container format.";
|
||||
emit error(QMediaRecorder::FormatError, tr("Not compatible codecs and container format."));
|
||||
return false;
|
||||
} else {
|
||||
mediaContainerControl->setActualContainer(container);
|
||||
|
||||
QAudioEncoderSettings audioSettings = audioEncodeControl->audioSettings();
|
||||
audioSettings.setCodec(audioCodec);
|
||||
audioEncodeControl->setActualAudioSettings(audioSettings);
|
||||
|
||||
QVideoEncoderSettings videoSettings = videoEncodeControl->videoSettings();
|
||||
videoSettings.setCodec(videoCodec);
|
||||
videoEncodeControl->setActualVideoSettings(videoSettings);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CameraBinRecorder::applySettings()
|
||||
{
|
||||
findCodecs();
|
||||
GstEncodingContainerProfile *containerProfile = m_session->mediaContainerControl()->createProfile();
|
||||
|
||||
if (containerProfile) {
|
||||
GstEncodingProfile *audioProfile = m_session->audioEncodeControl()->createProfile();
|
||||
GstEncodingProfile *videoProfile = m_session->videoEncodeControl()->createProfile();
|
||||
|
||||
gst_encoding_container_profile_add_profile(containerProfile, audioProfile);
|
||||
gst_encoding_container_profile_add_profile(containerProfile, videoProfile);
|
||||
}
|
||||
|
||||
g_object_set (G_OBJECT(m_session->cameraBin()), "video-profile", containerProfile, NULL);
|
||||
}
|
||||
|
||||
bool CameraBinRecorder::isMuted() const
|
||||
|
||||
@@ -64,8 +64,6 @@ public:
|
||||
|
||||
bool isMuted() const;
|
||||
|
||||
bool findCodecs();
|
||||
|
||||
void applySettings();
|
||||
|
||||
public slots:
|
||||
|
||||
@@ -237,7 +237,7 @@ void CameraBinService::releaseControl(QMediaControl *control)
|
||||
|
||||
bool CameraBinService::isCameraBinAvailable()
|
||||
{
|
||||
GstElementFactory *factory = gst_element_factory_find("camerabin");
|
||||
GstElementFactory *factory = gst_element_factory_find("camerabin2");
|
||||
if (factory) {
|
||||
gst_object_unref(GST_OBJECT(factory));
|
||||
return true;
|
||||
|
||||
@@ -66,34 +66,30 @@
|
||||
#include <QtGui/qimage.h>
|
||||
|
||||
//#define CAMERABIN_DEBUG 1
|
||||
//#define CAMERABIN_DEBUG_DUMP_BIN 1
|
||||
#define ENUM_NAME(c,e,v) (c::staticMetaObject.enumerator(c::staticMetaObject.indexOfEnumerator(e)).valueToKey((v)))
|
||||
|
||||
#define FILENAME_PROPERTY "filename"
|
||||
#define FILENAME_PROPERTY "location"
|
||||
#define MODE_PROPERTY "mode"
|
||||
#define MUTE_PROPERTY "mute"
|
||||
#define ZOOM_PROPERTY "zoom"
|
||||
#define IMAGE_PP_PROPERTY "image-post-processing"
|
||||
#define IMAGE_ENCODER_PROPERTY "image-encoder"
|
||||
#define VIDEO_PP_PROPERTY "video-post-processing"
|
||||
#define VIDEO_ENCODER_PROPERTY "video-encoder"
|
||||
#define AUDIO_ENCODER_PROPERTY "audio-encoder"
|
||||
#define VIDEO_MUXER_PROPERTY "video-muxer"
|
||||
#define VIEWFINDER_SINK_PROPERTY "viewfinder-sink"
|
||||
#define VIDEO_SOURCE_PROPERTY "video-source"
|
||||
#define CAMERA_SOURCE_PROPERTY "camera-source"
|
||||
#define AUDIO_SOURCE_PROPERTY "audio-source"
|
||||
#define VIDEO_SOURCE_CAPS_PROPERTY "video-source-caps"
|
||||
#define SUPPORTED_IMAGE_CAPTURE_CAPS_PROPERTY "image-capture-supported-caps"
|
||||
#define SUPPORTED_VIDEO_CAPTURE_CAPS_PROPERTY "video-capture-supported-caps"
|
||||
#define FILTER_CAPS_PROPERTY "filter-caps"
|
||||
#define PREVIEW_CAPS_PROPERTY "preview-caps"
|
||||
|
||||
#define IMAGE_DONE_SIGNAL "image-done"
|
||||
#define CAPTURE_START "capture-start"
|
||||
#define CAPTURE_STOP "capture-stop"
|
||||
#define CAPTURE_PAUSE "capture-pause"
|
||||
#define CAPTURE_START "start-capture"
|
||||
#define CAPTURE_STOP "stop-capture"
|
||||
#define SET_VIDEO_RESOLUTION_FPS "set-video-resolution-fps"
|
||||
#define SET_IMAGE_RESOLUTION "set-image-resolution"
|
||||
|
||||
#define CAMERABIN_IMAGE_MODE 0
|
||||
#define CAMERABIN_VIDEO_MODE 1
|
||||
#define CAMERABIN_IMAGE_MODE 1
|
||||
#define CAMERABIN_VIDEO_MODE 2
|
||||
|
||||
#define gstRef(element) { gst_object_ref(GST_OBJECT(element)); gst_object_sink(GST_OBJECT(element)); }
|
||||
#define gstUnref(element) { if (element) { gst_object_unref(GST_OBJECT(element)); element = 0; } }
|
||||
@@ -106,16 +102,16 @@
|
||||
#define VIEWFINDER_RESOLUTION_16x9 QSize(800, 450)
|
||||
|
||||
//using GST_STATE_READY for QCamera::LoadedState
|
||||
//doesn't work reliably at least with some webcams.
|
||||
#if defined(Q_WS_MAEMO_6)
|
||||
#define USE_READY_STATE_ON_LOADED
|
||||
#endif
|
||||
//may not work reliably at least with some webcams.
|
||||
|
||||
//#define USE_READY_STATE_ON_LOADED
|
||||
|
||||
|
||||
CameraBinSession::CameraBinSession(QObject *parent)
|
||||
:QObject(parent),
|
||||
m_recordingActive(false),
|
||||
m_state(QCamera::UnloadedState),
|
||||
m_pendingState(QCamera::UnloadedState),
|
||||
m_recordingActive(false),
|
||||
m_pendingResolutionUpdate(false),
|
||||
m_muted(false),
|
||||
m_busy(false),
|
||||
@@ -124,12 +120,10 @@ CameraBinSession::CameraBinSession(QObject *parent)
|
||||
m_videoInputFactory(0),
|
||||
m_viewfinder(0),
|
||||
m_viewfinderInterface(0),
|
||||
m_pipeline(0),
|
||||
m_videoSrc(0),
|
||||
m_viewfinderElement(0),
|
||||
m_viewfinderHasChanged(true),
|
||||
m_videoInputHasChanged(true),
|
||||
m_sourceCaps(0),
|
||||
m_audioSrc(0),
|
||||
m_audioConvert(0),
|
||||
m_capsFilter(0),
|
||||
@@ -137,12 +131,11 @@ CameraBinSession::CameraBinSession(QObject *parent)
|
||||
m_audioEncoder(0),
|
||||
m_muxer(0)
|
||||
{
|
||||
m_pipeline = gst_element_factory_make("camerabin", "camerabin");
|
||||
g_signal_connect(G_OBJECT(m_pipeline), "notify::idle", G_CALLBACK(updateBusyStatus), this);
|
||||
m_camerabin = gst_element_factory_make("camerabin2", "camerabin2");
|
||||
g_signal_connect(G_OBJECT(m_camerabin), "notify::idle", G_CALLBACK(updateBusyStatus), this);
|
||||
gstRef(m_camerabin);
|
||||
|
||||
gstRef(m_pipeline);
|
||||
|
||||
m_bus = gst_element_get_bus(m_pipeline);
|
||||
m_bus = gst_element_get_bus(m_camerabin);
|
||||
|
||||
m_busHelper = new QGstreamerBusHelper(m_bus, this);
|
||||
m_busHelper->installMessageFilter(this);
|
||||
@@ -159,36 +152,40 @@ CameraBinSession::CameraBinSession(QObject *parent)
|
||||
m_cameraLocksControl = new CameraBinLocks(this);
|
||||
m_captureDestinationControl = new CameraBinCaptureDestination(this);
|
||||
m_captureBufferFormatControl = new CameraBinCaptureBufferFormat(this);
|
||||
|
||||
//post image preview in RGB format
|
||||
GstCaps *previewCaps = gst_caps_from_string("video/x-raw-rgb");
|
||||
g_object_set(G_OBJECT(m_camerabin), PREVIEW_CAPS_PROPERTY, previewCaps, NULL);
|
||||
gst_caps_unref(previewCaps);
|
||||
}
|
||||
|
||||
CameraBinSession::~CameraBinSession()
|
||||
{
|
||||
if (m_pipeline) {
|
||||
if (m_camerabin) {
|
||||
if (m_viewfinderInterface)
|
||||
m_viewfinderInterface->stopRenderer();
|
||||
|
||||
gst_element_set_state(m_pipeline, GST_STATE_NULL);
|
||||
gst_element_get_state(m_pipeline, NULL, NULL, GST_CLOCK_TIME_NONE);
|
||||
gstUnref(m_pipeline);
|
||||
gst_element_set_state(m_camerabin, GST_STATE_NULL);
|
||||
gst_element_get_state(m_camerabin, NULL, NULL, GST_CLOCK_TIME_NONE);
|
||||
gstUnref(m_camerabin);
|
||||
gstUnref(m_viewfinderElement);
|
||||
}
|
||||
}
|
||||
|
||||
GstPhotography *CameraBinSession::photography()
|
||||
{
|
||||
if (GST_IS_PHOTOGRAPHY(m_pipeline)) {
|
||||
return GST_PHOTOGRAPHY(m_pipeline);
|
||||
if (GST_IS_PHOTOGRAPHY(m_camerabin)) {
|
||||
return GST_PHOTOGRAPHY(m_camerabin);
|
||||
}
|
||||
|
||||
if (!m_videoSrc) {
|
||||
m_videoSrc = buildVideoSrc();
|
||||
m_videoSrc = buildCameraSource();
|
||||
|
||||
if (m_videoSrc)
|
||||
g_object_set(m_pipeline, VIDEO_SOURCE_PROPERTY, m_videoSrc, NULL);
|
||||
g_object_set(m_camerabin, CAMERA_SOURCE_PROPERTY, m_videoSrc, NULL);
|
||||
else
|
||||
g_object_get(m_pipeline, VIDEO_SOURCE_PROPERTY, &m_videoSrc, NULL);
|
||||
g_object_get(m_camerabin, CAMERA_SOURCE_PROPERTY, &m_videoSrc, NULL);
|
||||
|
||||
updateVideoSourceCaps();
|
||||
m_videoInputHasChanged = false;
|
||||
}
|
||||
|
||||
@@ -203,33 +200,19 @@ CameraBinSession::CameraRole CameraBinSession::cameraRole() const
|
||||
return BackCamera;
|
||||
}
|
||||
|
||||
/*
|
||||
Configure camera during Loaded->Active states stansition.
|
||||
*/
|
||||
bool CameraBinSession::setupCameraBin()
|
||||
{
|
||||
if (m_captureMode == QCamera::CaptureStillImage) {
|
||||
g_object_set(m_pipeline, MODE_PROPERTY, CAMERABIN_IMAGE_MODE, NULL);
|
||||
}
|
||||
|
||||
if (m_captureMode == QCamera::CaptureVideo) {
|
||||
g_object_set(m_pipeline, MODE_PROPERTY, CAMERABIN_VIDEO_MODE, NULL);
|
||||
|
||||
if (!m_recorderControl->findCodecs())
|
||||
return false;
|
||||
|
||||
g_object_set(m_pipeline, VIDEO_ENCODER_PROPERTY, m_videoEncodeControl->createEncoder(), NULL);
|
||||
g_object_set(m_pipeline, AUDIO_ENCODER_PROPERTY, m_audioEncodeControl->createEncoder(), NULL);
|
||||
g_object_set(m_pipeline, VIDEO_MUXER_PROPERTY,
|
||||
gst_element_factory_make(m_mediaContainerControl->formatElementName().constData(), NULL), NULL);
|
||||
}
|
||||
|
||||
if (m_videoInputHasChanged) {
|
||||
m_videoSrc = buildVideoSrc();
|
||||
m_videoSrc = buildCameraSource();
|
||||
|
||||
if (m_videoSrc)
|
||||
g_object_set(m_pipeline, VIDEO_SOURCE_PROPERTY, m_videoSrc, NULL);
|
||||
g_object_set(m_camerabin, CAMERA_SOURCE_PROPERTY, m_videoSrc, NULL);
|
||||
else
|
||||
g_object_get(m_pipeline, VIDEO_SOURCE_PROPERTY, &m_videoSrc, NULL);
|
||||
g_object_get(m_camerabin, CAMERA_SOURCE_PROPERTY, &m_videoSrc, NULL);
|
||||
|
||||
updateVideoSourceCaps();
|
||||
m_videoInputHasChanged = false;
|
||||
}
|
||||
|
||||
@@ -248,25 +231,41 @@ bool CameraBinSession::setupCameraBin()
|
||||
m_viewfinderElement = gst_element_factory_make("fakesink", NULL);
|
||||
}
|
||||
gst_object_ref(GST_OBJECT(m_viewfinderElement));
|
||||
gst_element_set_state(m_pipeline, GST_STATE_NULL);
|
||||
g_object_set(G_OBJECT(m_pipeline), VIEWFINDER_SINK_PROPERTY, m_viewfinderElement, NULL);
|
||||
gst_element_set_state(m_camerabin, GST_STATE_NULL);
|
||||
g_object_set(G_OBJECT(m_camerabin), VIEWFINDER_SINK_PROPERTY, m_viewfinderElement, NULL);
|
||||
}
|
||||
|
||||
GstCaps *previewCaps = gst_caps_from_string(PREVIEW_CAPS_4_3);
|
||||
g_object_set(G_OBJECT(m_pipeline), PREVIEW_CAPS_PROPERTY, previewCaps, NULL);
|
||||
gst_caps_unref(previewCaps);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CameraBinSession::updateVideoSourceCaps()
|
||||
static GstCaps *resolutionToCaps(const QSize &resolution,
|
||||
const QPair<int, int> &rate = qMakePair<int,int>(0,0))
|
||||
{
|
||||
if (m_sourceCaps) {
|
||||
gst_caps_unref(m_sourceCaps);
|
||||
m_sourceCaps = 0;
|
||||
}
|
||||
if (resolution.isEmpty())
|
||||
return gst_caps_new_any();
|
||||
|
||||
g_object_get(G_OBJECT(m_pipeline), VIDEO_SOURCE_CAPS_PROPERTY, &m_sourceCaps, NULL);
|
||||
GstCaps *caps = 0;
|
||||
if (rate.second > 0) {
|
||||
caps = gst_caps_new_full(gst_structure_new("video/x-raw-yuv",
|
||||
"width", G_TYPE_INT, resolution.width(),
|
||||
"height", G_TYPE_INT, resolution.height(),
|
||||
"framerate", GST_TYPE_FRACTION, rate.first, rate.second,
|
||||
NULL),
|
||||
gst_structure_new("video/x-raw-rgb",
|
||||
"width", G_TYPE_INT, resolution.width(),
|
||||
"height", G_TYPE_INT, resolution.height(),
|
||||
"framerate", GST_TYPE_FRACTION, rate.first, rate.second,
|
||||
NULL), NULL);
|
||||
} else {
|
||||
caps = gst_caps_new_full (gst_structure_new ("video/x-raw-yuv",
|
||||
"width", G_TYPE_INT, resolution.width(),
|
||||
"height", G_TYPE_INT, resolution.height(),
|
||||
NULL),
|
||||
gst_structure_new ("video/x-raw-rgb",
|
||||
"width", G_TYPE_INT, resolution.width(),
|
||||
"height", G_TYPE_INT, resolution.height(), NULL), NULL);
|
||||
}
|
||||
return caps;
|
||||
}
|
||||
|
||||
void CameraBinSession::setupCaptureResolution()
|
||||
@@ -276,7 +275,6 @@ void CameraBinSession::setupCaptureResolution()
|
||||
|
||||
//by default select the maximum supported resolution
|
||||
if (resolution.isEmpty()) {
|
||||
updateVideoSourceCaps();
|
||||
bool continuous = false;
|
||||
QList<QSize> resolutions = supportedResolutions(qMakePair<int,int>(0,0),
|
||||
&continuous,
|
||||
@@ -285,17 +283,15 @@ void CameraBinSession::setupCaptureResolution()
|
||||
resolution = resolutions.last();
|
||||
}
|
||||
|
||||
QString previewCapsString = PREVIEW_CAPS_4_3;
|
||||
QSize viewfinderResolution = VIEWFINDER_RESOLUTION_4x3;
|
||||
|
||||
if (!resolution.isEmpty()) {
|
||||
GstCaps *caps = resolutionToCaps(resolution);
|
||||
#if CAMERABIN_DEBUG
|
||||
qDebug() << Q_FUNC_INFO << "set image resolution" << resolution;
|
||||
qDebug() << Q_FUNC_INFO << "set image resolution" << resolution << gst_caps_to_string(caps);
|
||||
#endif
|
||||
g_signal_emit_by_name(G_OBJECT(m_pipeline), SET_IMAGE_RESOLUTION, resolution.width(), resolution.height(), NULL);
|
||||
|
||||
previewCapsString = QString("video/x-raw-rgb, width = (int) %1, height = (int) 480")
|
||||
.arg(resolution.width()*480/resolution.height());
|
||||
g_object_set(m_camerabin, "image-capture-caps", caps, NULL);
|
||||
gst_caps_unref(caps);
|
||||
|
||||
if (!resolution.isEmpty()) {
|
||||
qreal aspectRatio = qreal(resolution.width()) / resolution.height();
|
||||
@@ -308,35 +304,25 @@ void CameraBinSession::setupCaptureResolution()
|
||||
}
|
||||
}
|
||||
|
||||
GstCaps *previewCaps = gst_caps_from_string(previewCapsString.toLatin1());
|
||||
g_object_set(G_OBJECT(m_pipeline), PREVIEW_CAPS_PROPERTY, previewCaps, NULL);
|
||||
gst_caps_unref(previewCaps);
|
||||
|
||||
//on low res cameras the viewfinder resolution should not be bigger
|
||||
//then capture resolution
|
||||
if (viewfinderResolution.width() > resolution.width())
|
||||
if (viewfinderResolution.width() > resolution.width() && !resolution.isEmpty())
|
||||
viewfinderResolution = resolution;
|
||||
|
||||
GstCaps *viewfinderCaps = resolutionToCaps(viewfinderResolution);
|
||||
#if CAMERABIN_DEBUG
|
||||
qDebug() << Q_FUNC_INFO << "set viewfinder resolution" << viewfinderResolution;
|
||||
qDebug() << "Set viewfinder resolution" << viewfinderResolution <<gst_caps_to_string(viewfinderCaps);
|
||||
#endif
|
||||
g_signal_emit_by_name(G_OBJECT(m_pipeline),
|
||||
SET_VIDEO_RESOLUTION_FPS,
|
||||
viewfinderResolution.width(),
|
||||
viewfinderResolution.height(),
|
||||
0, // maximum framerate
|
||||
1, // framerate denom
|
||||
NULL);
|
||||
g_object_set(m_camerabin, "viewfinder-caps", viewfinderCaps, NULL);
|
||||
gst_caps_unref(viewfinderCaps);
|
||||
}
|
||||
|
||||
if (m_captureMode == QCamera::CaptureVideo) {
|
||||
QSize resolution = m_videoEncodeControl->videoSettings().resolution();
|
||||
qreal framerate = m_videoEncodeControl->videoSettings().frameRate();
|
||||
//qreal framerate = m_videoEncodeControl->videoSettings().frameRate();
|
||||
|
||||
if (resolution.isEmpty()) {
|
||||
//select the hightest supported resolution
|
||||
|
||||
updateVideoSourceCaps();
|
||||
bool continuous = false;
|
||||
QList<QSize> resolutions = supportedResolutions(qMakePair<int,int>(0,0),
|
||||
&continuous,
|
||||
@@ -345,32 +331,27 @@ void CameraBinSession::setupCaptureResolution()
|
||||
resolution = resolutions.last();
|
||||
}
|
||||
|
||||
if (!resolution.isEmpty() || framerate > 0) {
|
||||
GstCaps *caps = resolutionToCaps(resolution /*, framerate*/); //convert to rational
|
||||
#if CAMERABIN_DEBUG
|
||||
qDebug() << Q_FUNC_INFO << "set video resolution" << resolution;
|
||||
qDebug() << Q_FUNC_INFO << "set video resolution" << resolution << gst_caps_to_string(caps);
|
||||
#endif
|
||||
g_signal_emit_by_name(G_OBJECT(m_pipeline),
|
||||
SET_VIDEO_RESOLUTION_FPS,
|
||||
resolution.width(),
|
||||
resolution.height(),
|
||||
0, //framerate nom == max rate
|
||||
1, // framerate denom == max rate
|
||||
NULL);
|
||||
}
|
||||
|
||||
g_object_set(m_camerabin, "video-capture-caps", caps, NULL);
|
||||
gst_caps_unref(caps);
|
||||
}
|
||||
}
|
||||
|
||||
GstElement *CameraBinSession::buildVideoSrc()
|
||||
GstElement *CameraBinSession::buildCameraSource()
|
||||
{
|
||||
#if CAMERABIN_DEBUG
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
#endif
|
||||
GstElement *videoSrc = 0;
|
||||
if (m_videoInputFactory) {
|
||||
videoSrc = m_videoInputFactory->buildElement();
|
||||
} else {
|
||||
QList<QByteArray> candidates;
|
||||
candidates << "subdevsrc"
|
||||
<< "v4l2camsrc"
|
||||
<< "v4l2src"
|
||||
<< "autovideosrc";
|
||||
candidates << "wrappercamerabinsrc";
|
||||
QByteArray sourceElementName;
|
||||
|
||||
foreach(sourceElementName, candidates) {
|
||||
@@ -389,7 +370,11 @@ GstElement *CameraBinSession::buildVideoSrc()
|
||||
else
|
||||
g_object_set(G_OBJECT(videoSrc), "camera-device", 0, NULL);
|
||||
} else {
|
||||
g_object_set(G_OBJECT(videoSrc), "device", m_inputDevice.toLocal8Bit().constData(), NULL);
|
||||
if (g_object_class_find_property(G_OBJECT_GET_CLASS(videoSrc), "device"))
|
||||
g_object_set(G_OBJECT(videoSrc),
|
||||
"device",
|
||||
m_inputDevice.toLocal8Bit().constData(),
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -405,9 +390,13 @@ void CameraBinSession::captureImage(int requestId, const QString &fileName)
|
||||
|
||||
m_requestId = requestId;
|
||||
|
||||
g_object_set(G_OBJECT(m_pipeline), FILENAME_PROPERTY, actualFileName.toLocal8Bit().constData(), NULL);
|
||||
#if CAMERABIN_DEBUG
|
||||
qDebug() << Q_FUNC_INFO << m_requestId << fileName << "actual file name:" << actualFileName;
|
||||
#endif
|
||||
|
||||
g_signal_emit_by_name(G_OBJECT(m_pipeline), CAPTURE_START, NULL);
|
||||
g_object_set(G_OBJECT(m_camerabin), FILENAME_PROPERTY, actualFileName.toLocal8Bit().constData(), NULL);
|
||||
|
||||
g_signal_emit_by_name(G_OBJECT(m_camerabin), CAPTURE_START, NULL);
|
||||
|
||||
m_imageFileName = actualFileName;
|
||||
}
|
||||
@@ -418,10 +407,10 @@ void CameraBinSession::setCaptureMode(QCamera::CaptureMode mode)
|
||||
|
||||
switch (m_captureMode) {
|
||||
case QCamera::CaptureStillImage:
|
||||
g_object_set(m_pipeline, MODE_PROPERTY, CAMERABIN_IMAGE_MODE, NULL);
|
||||
g_object_set(m_camerabin, MODE_PROPERTY, CAMERABIN_IMAGE_MODE, NULL);
|
||||
break;
|
||||
case QCamera::CaptureVideo:
|
||||
g_object_set(m_pipeline, MODE_PROPERTY, CAMERABIN_VIDEO_MODE, NULL);
|
||||
g_object_set(m_camerabin, MODE_PROPERTY, CAMERABIN_VIDEO_MODE, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -577,7 +566,7 @@ void CameraBinSession::setState(QCamera::State newState)
|
||||
m_pendingState = newState;
|
||||
|
||||
#if CAMERABIN_DEBUG
|
||||
qDebug() << Q_FUNC_INFO << ENUM_NAME(QCamera, "State", newState);
|
||||
qDebug() << Q_FUNC_INFO << newState;
|
||||
#endif
|
||||
|
||||
switch (newState) {
|
||||
@@ -588,7 +577,7 @@ void CameraBinSession::setState(QCamera::State newState)
|
||||
if (m_viewfinderInterface)
|
||||
m_viewfinderInterface->stopRenderer();
|
||||
|
||||
gst_element_set_state(m_pipeline, GST_STATE_NULL);
|
||||
gst_element_set_state(m_camerabin, GST_STATE_NULL);
|
||||
m_state = newState;
|
||||
if (m_busy)
|
||||
emit busyChanged(m_busy = false);
|
||||
@@ -603,19 +592,18 @@ void CameraBinSession::setState(QCamera::State newState)
|
||||
if (m_viewfinderInterface)
|
||||
m_viewfinderInterface->stopRenderer();
|
||||
|
||||
gst_element_set_state(m_pipeline, GST_STATE_NULL);
|
||||
m_videoSrc = buildVideoSrc();
|
||||
g_object_set(m_pipeline, VIDEO_SOURCE_PROPERTY, m_videoSrc, NULL);
|
||||
updateVideoSourceCaps();
|
||||
gst_element_set_state(m_camerabin, GST_STATE_NULL);
|
||||
m_videoSrc = buildCameraSource();
|
||||
g_object_set(m_camerabin, CAMERA_SOURCE_PROPERTY, m_videoSrc, NULL);
|
||||
m_videoInputHasChanged = false;
|
||||
}
|
||||
#ifdef USE_READY_STATE_ON_LOADED
|
||||
gst_element_set_state(m_pipeline, GST_STATE_READY);
|
||||
gst_element_set_state(m_camerabin, GST_STATE_READY);
|
||||
#else
|
||||
m_state = QCamera::LoadedState;
|
||||
if (m_viewfinderInterface)
|
||||
m_viewfinderInterface->stopRenderer();
|
||||
gst_element_set_state(m_pipeline, GST_STATE_NULL);
|
||||
gst_element_set_state(m_camerabin, GST_STATE_NULL);
|
||||
emit stateChanged(m_state);
|
||||
#endif
|
||||
break;
|
||||
@@ -623,15 +611,15 @@ void CameraBinSession::setState(QCamera::State newState)
|
||||
if (setupCameraBin()) {
|
||||
GstState binState = GST_STATE_NULL;
|
||||
GstState pending = GST_STATE_NULL;
|
||||
gst_element_get_state(m_pipeline, &binState, &pending, 0);
|
||||
gst_element_get_state(m_camerabin, &binState, &pending, 0);
|
||||
|
||||
if (pending == GST_STATE_VOID_PENDING && binState == GST_STATE_READY) {
|
||||
m_pendingResolutionUpdate = false;
|
||||
setupCaptureResolution();
|
||||
gst_element_set_state(m_pipeline, GST_STATE_PLAYING);
|
||||
gst_element_set_state(m_camerabin, GST_STATE_PLAYING);
|
||||
} else {
|
||||
m_pendingResolutionUpdate = true;
|
||||
gst_element_set_state(m_pipeline, GST_STATE_READY);
|
||||
gst_element_set_state(m_camerabin, GST_STATE_READY);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -664,7 +652,7 @@ qint64 CameraBinSession::duration() const
|
||||
GstFormat format = GST_FORMAT_TIME;
|
||||
gint64 duration = 0;
|
||||
|
||||
if ( m_pipeline && gst_element_query_position(m_pipeline, &format, &duration))
|
||||
if ( m_camerabin && gst_element_query_position(m_camerabin, &format, &duration))
|
||||
return duration / 1000000;
|
||||
else
|
||||
return 0;
|
||||
@@ -680,8 +668,8 @@ void CameraBinSession::setMuted(bool muted)
|
||||
if (m_muted != muted) {
|
||||
m_muted = muted;
|
||||
|
||||
if (m_pipeline)
|
||||
g_object_set(G_OBJECT(m_pipeline), MUTE_PROPERTY, m_muted, NULL);
|
||||
if (m_camerabin)
|
||||
g_object_set(G_OBJECT(m_camerabin), MUTE_PROPERTY, m_muted, NULL);
|
||||
emit mutedChanged(m_muted);
|
||||
}
|
||||
}
|
||||
@@ -695,8 +683,8 @@ void CameraBinSession::setMetaData(const QMap<QByteArray, QVariant> &data)
|
||||
{
|
||||
m_metaData = data;
|
||||
|
||||
if (m_pipeline) {
|
||||
GstIterator *elements = gst_bin_iterate_all_by_interface(GST_BIN(m_pipeline), GST_TYPE_TAG_SETTER);
|
||||
if (m_camerabin) {
|
||||
GstIterator *elements = gst_bin_iterate_all_by_interface(GST_BIN(m_camerabin), GST_TYPE_TAG_SETTER);
|
||||
GstElement *element = 0;
|
||||
while (gst_iterator_next(elements, (void**)&element) == GST_ITERATOR_OK) {
|
||||
QMapIterator<QByteArray, QVariant> it(data);
|
||||
@@ -747,6 +735,7 @@ bool CameraBinSession::processSyncMessage(const QGstreamerMessage &message)
|
||||
if (m_captureMode == QCamera::CaptureStillImage &&
|
||||
gst_structure_has_name(gm->structure, "preview-image")) {
|
||||
st = gst_message_get_structure(gm);
|
||||
|
||||
if (gst_structure_has_field_typed(st, "buffer", GST_TYPE_BUFFER)) {
|
||||
image = gst_structure_get_value(st, "buffer");
|
||||
if (image) {
|
||||
@@ -759,6 +748,9 @@ bool CameraBinSession::processSyncMessage(const QGstreamerMessage &message)
|
||||
GstStructure *structure = gst_caps_get_structure(caps, 0);
|
||||
gint width = 0;
|
||||
gint height = 0;
|
||||
#if CAMERABIN_DEBUG
|
||||
qDebug() << "Preview caps:" << gst_structure_to_string(structure);
|
||||
#endif
|
||||
|
||||
if (structure &&
|
||||
gst_structure_get_int(structure, "width", &width) &&
|
||||
@@ -824,13 +816,20 @@ bool CameraBinSession::processBusMessage(const QGstreamerMessage &message)
|
||||
}
|
||||
|
||||
//only report error messager from camerabin
|
||||
if (GST_MESSAGE_SRC(gm) == GST_OBJECT_CAST(m_pipeline)) {
|
||||
if (GST_MESSAGE_SRC(gm) == GST_OBJECT_CAST(m_camerabin)) {
|
||||
if (message.isEmpty())
|
||||
message = tr("Camera error");
|
||||
|
||||
emit error(int(QMediaRecorder::ResourceError), message);
|
||||
}
|
||||
|
||||
#ifdef CAMERABIN_DEBUG_DUMP_BIN
|
||||
_gst_debug_bin_to_dot_file_with_ts(GST_BIN(m_camerabin),
|
||||
GstDebugGraphDetails(GST_DEBUG_GRAPH_SHOW_ALL /* GST_DEBUG_GRAPH_SHOW_MEDIA_TYPE | GST_DEBUG_GRAPH_SHOW_NON_DEFAULT_PARAMS | GST_DEBUG_GRAPH_SHOW_STATES*/),
|
||||
"camerabin_error");
|
||||
#endif
|
||||
|
||||
|
||||
if (err)
|
||||
g_error_free (err);
|
||||
|
||||
@@ -852,7 +851,7 @@ bool CameraBinSession::processBusMessage(const QGstreamerMessage &message)
|
||||
g_free (debug);
|
||||
}
|
||||
|
||||
if (GST_MESSAGE_SRC(gm) == GST_OBJECT_CAST(m_pipeline)) {
|
||||
if (GST_MESSAGE_SRC(gm) == GST_OBJECT_CAST(m_camerabin)) {
|
||||
switch (GST_MESSAGE_TYPE(gm)) {
|
||||
case GST_MESSAGE_DURATION:
|
||||
break;
|
||||
@@ -878,6 +877,12 @@ bool CameraBinSession::processBusMessage(const QGstreamerMessage &message)
|
||||
.arg(states[pending]);
|
||||
#endif
|
||||
|
||||
#ifdef CAMERABIN_DEBUG_DUMP_BIN
|
||||
_gst_debug_bin_to_dot_file_with_ts(GST_BIN(m_camerabin),
|
||||
GstDebugGraphDetails(GST_DEBUG_GRAPH_SHOW_ALL /*GST_DEBUG_GRAPH_SHOW_MEDIA_TYPE | GST_DEBUG_GRAPH_SHOW_NON_DEFAULT_PARAMS | GST_DEBUG_GRAPH_SHOW_STATES*/),
|
||||
"camerabin");
|
||||
#endif
|
||||
|
||||
switch (newState) {
|
||||
case GST_STATE_VOID_PENDING:
|
||||
case GST_STATE_NULL:
|
||||
@@ -888,7 +893,7 @@ bool CameraBinSession::processBusMessage(const QGstreamerMessage &message)
|
||||
if (m_pendingResolutionUpdate) {
|
||||
m_pendingResolutionUpdate = false;
|
||||
setupCaptureResolution();
|
||||
gst_element_set_state(m_pipeline, GST_STATE_PLAYING);
|
||||
gst_element_set_state(m_camerabin, GST_STATE_PLAYING);
|
||||
}
|
||||
if (m_state != QCamera::LoadedState)
|
||||
emit stateChanged(m_state = QCamera::LoadedState);
|
||||
@@ -915,31 +920,19 @@ void CameraBinSession::recordVideo()
|
||||
m_recordingActive = true;
|
||||
m_actualSink = m_sink;
|
||||
if (m_actualSink.isEmpty()) {
|
||||
QString ext = m_mediaContainerControl->containerMimeType();
|
||||
QString ext = m_mediaContainerControl->suggestedFileExtension();
|
||||
m_actualSink = generateFileName("clip_", defaultDir(QCamera::CaptureVideo), ext);
|
||||
}
|
||||
|
||||
g_object_set(G_OBJECT(m_pipeline), FILENAME_PROPERTY, m_actualSink.toEncoded().constData(), NULL);
|
||||
g_object_set(G_OBJECT(m_camerabin), FILENAME_PROPERTY, m_actualSink.toEncoded().constData(), NULL);
|
||||
|
||||
g_signal_emit_by_name(G_OBJECT(m_pipeline), CAPTURE_START, NULL);
|
||||
}
|
||||
|
||||
void CameraBinSession::resumeVideoRecording()
|
||||
{
|
||||
m_recordingActive = true;
|
||||
g_signal_emit_by_name(G_OBJECT(m_pipeline), CAPTURE_START, NULL);
|
||||
}
|
||||
|
||||
|
||||
void CameraBinSession::pauseVideoRecording()
|
||||
{
|
||||
g_signal_emit_by_name(G_OBJECT(m_pipeline), CAPTURE_PAUSE, NULL);
|
||||
g_signal_emit_by_name(G_OBJECT(m_camerabin), CAPTURE_START, NULL);
|
||||
}
|
||||
|
||||
void CameraBinSession::stopVideoRecording()
|
||||
{
|
||||
m_recordingActive = false;
|
||||
g_signal_emit_by_name(G_OBJECT(m_pipeline), CAPTURE_STOP, NULL);
|
||||
g_signal_emit_by_name(G_OBJECT(m_camerabin), CAPTURE_STOP, NULL);
|
||||
}
|
||||
|
||||
//internal, only used by CameraBinSession::supportedFrameRates.
|
||||
@@ -976,13 +969,18 @@ QList< QPair<int,int> > CameraBinSession::supportedFrameRates(const QSize &frame
|
||||
{
|
||||
QList< QPair<int,int> > res;
|
||||
|
||||
if (!m_sourceCaps)
|
||||
GstCaps *supportedCaps = 0;
|
||||
g_object_get(G_OBJECT(m_camerabin),
|
||||
SUPPORTED_VIDEO_CAPTURE_CAPS_PROPERTY,
|
||||
&supportedCaps, NULL);
|
||||
|
||||
if (!supportedCaps)
|
||||
return res;
|
||||
|
||||
GstCaps *caps = 0;
|
||||
|
||||
if (frameSize.isEmpty()) {
|
||||
caps = gst_caps_copy(m_sourceCaps);
|
||||
caps = gst_caps_copy(supportedCaps);
|
||||
} else {
|
||||
GstCaps *filter = gst_caps_new_full(
|
||||
gst_structure_new(
|
||||
@@ -999,12 +997,13 @@ QList< QPair<int,int> > CameraBinSession::supportedFrameRates(const QSize &frame
|
||||
"height" , G_TYPE_INT, frameSize.height(), NULL),
|
||||
NULL);
|
||||
|
||||
caps = gst_caps_intersect(m_sourceCaps, filter);
|
||||
caps = gst_caps_intersect(supportedCaps, filter);
|
||||
gst_caps_unref(filter);
|
||||
}
|
||||
gst_caps_unref(supportedCaps);
|
||||
|
||||
//simplify to the list of rates only:
|
||||
gst_caps_make_writable(caps);
|
||||
caps = gst_caps_make_writable(caps);
|
||||
for (uint i=0; i<gst_caps_get_size(caps); i++) {
|
||||
GstStructure *structure = gst_caps_get_structure(caps, i);
|
||||
gst_structure_set_name(structure, "video/x-raw-yuv");
|
||||
@@ -1081,18 +1080,24 @@ QList<QSize> CameraBinSession::supportedResolutions(QPair<int,int> rate,
|
||||
if (continuous)
|
||||
*continuous = false;
|
||||
|
||||
if (!m_sourceCaps)
|
||||
GstCaps *supportedCaps = 0;
|
||||
g_object_get(G_OBJECT(m_camerabin),
|
||||
(mode == QCamera::CaptureStillImage) ?
|
||||
SUPPORTED_IMAGE_CAPTURE_CAPS_PROPERTY : SUPPORTED_VIDEO_CAPTURE_CAPS_PROPERTY,
|
||||
&supportedCaps, NULL);
|
||||
|
||||
if (!supportedCaps)
|
||||
return res;
|
||||
|
||||
#if CAMERABIN_DEBUG
|
||||
qDebug() << "Source caps:" << gst_caps_to_string(m_sourceCaps);
|
||||
qDebug() << "Source caps:" << gst_caps_to_string(supportedCaps);
|
||||
#endif
|
||||
|
||||
GstCaps *caps = 0;
|
||||
bool isContinuous = false;
|
||||
|
||||
if (rate.first <= 0 || rate.second <= 0) {
|
||||
caps = gst_caps_copy(m_sourceCaps);
|
||||
caps = gst_caps_copy(supportedCaps);
|
||||
} else {
|
||||
GstCaps *filter = gst_caps_new_full(
|
||||
gst_structure_new(
|
||||
@@ -1106,12 +1111,13 @@ QList<QSize> CameraBinSession::supportedResolutions(QPair<int,int> rate,
|
||||
"framerate" , GST_TYPE_FRACTION , rate.first, rate.second, NULL),
|
||||
NULL);
|
||||
|
||||
caps = gst_caps_intersect(m_sourceCaps, filter);
|
||||
caps = gst_caps_intersect(supportedCaps, filter);
|
||||
gst_caps_unref(filter);
|
||||
}
|
||||
gst_caps_unref(supportedCaps);
|
||||
|
||||
//simplify to the list of resolutions only:
|
||||
gst_caps_make_writable(caps);
|
||||
caps = gst_caps_make_writable(caps);
|
||||
for (uint i=0; i<gst_caps_get_size(caps); i++) {
|
||||
GstStructure *structure = gst_caps_get_structure(caps, i);
|
||||
gst_structure_set_name(structure, "video/x-raw-yuv");
|
||||
@@ -1175,16 +1181,6 @@ QList<QSize> CameraBinSession::supportedResolutions(QPair<int,int> rate,
|
||||
<< QSize(2580, 1936);
|
||||
QSize minSize = res.first();
|
||||
QSize maxSize = res.last();
|
||||
|
||||
#if defined(Q_WS_MAEMO_6)
|
||||
if (cameraRole() == FrontCamera && maxSize.width() > 640)
|
||||
maxSize = QSize(640, 480);
|
||||
else if (mode == QCamera::CaptureVideo && maxSize.width() > 1280)
|
||||
maxSize = QSize(1280, 720);
|
||||
#else
|
||||
Q_UNUSED(mode);
|
||||
#endif
|
||||
|
||||
res.clear();
|
||||
|
||||
foreach (const QSize &candidate, commonSizes) {
|
||||
|
||||
@@ -93,7 +93,7 @@ public:
|
||||
~CameraBinSession();
|
||||
|
||||
GstPhotography *photography();
|
||||
GstElement *cameraBin() { return m_pipeline; }
|
||||
GstElement *cameraBin() { return m_camerabin; }
|
||||
QGstreamerBusHelper *bus() { return m_busHelper; }
|
||||
|
||||
CameraRole cameraRole() const;
|
||||
@@ -143,8 +143,6 @@ public:
|
||||
qint64 duration() const;
|
||||
|
||||
void recordVideo();
|
||||
void pauseVideoRecording();
|
||||
void resumeVideoRecording();
|
||||
void stopVideoRecording();
|
||||
|
||||
bool isMuted() const;
|
||||
@@ -176,8 +174,7 @@ private slots:
|
||||
private:
|
||||
bool setupCameraBin();
|
||||
void setupCaptureResolution();
|
||||
void updateVideoSourceCaps();
|
||||
GstElement *buildVideoSrc();
|
||||
GstElement *buildCameraSource();
|
||||
static void updateBusyStatus(GObject *o, GParamSpec *p, gpointer d);
|
||||
|
||||
QUrl m_sink;
|
||||
@@ -214,14 +211,12 @@ private:
|
||||
|
||||
QGstreamerBusHelper *m_busHelper;
|
||||
GstBus* m_bus;
|
||||
GstElement *m_pipeline;
|
||||
GstElement *m_camerabin;
|
||||
GstElement *m_videoSrc;
|
||||
GstElement *m_viewfinderElement;
|
||||
bool m_viewfinderHasChanged;
|
||||
bool m_videoInputHasChanged;
|
||||
|
||||
GstCaps *m_sourceCaps;
|
||||
|
||||
GstElement *m_audioSrc;
|
||||
GstElement *m_audioConvert;
|
||||
GstElement *m_capsFilter;
|
||||
|
||||
@@ -46,58 +46,10 @@
|
||||
#include <QtCore/qdebug.h>
|
||||
|
||||
CameraBinVideoEncoder::CameraBinVideoEncoder(CameraBinSession *session)
|
||||
:QVideoEncoderControl(session), m_session(session)
|
||||
:QVideoEncoderControl(session),
|
||||
m_session(session),
|
||||
m_codecs(QGstCodecsInfo::VideoEncoder)
|
||||
{
|
||||
QList<QByteArray> codecCandidates;
|
||||
#if defined(Q_WS_MAEMO_6)
|
||||
codecCandidates << "video/mpeg4" << "video/h264" << "video/h263";
|
||||
|
||||
m_elementNames["video/h264"] = "dsph264enc";
|
||||
m_elementNames["video/mpeg4"] = "dsphdmp4venc";
|
||||
m_elementNames["video/h263"] = "dsph263enc";
|
||||
|
||||
QStringList options = QStringList() << "mode" << "keyframe-interval" << "max-bitrate" << "intra-refresh";
|
||||
m_codecOptions["video/h264"] = options;
|
||||
m_codecOptions["video/mpeg4"] = options;
|
||||
m_codecOptions["video/h263"] = options;
|
||||
#else
|
||||
codecCandidates << "video/h264" << "video/xvid" << "video/mpeg4"
|
||||
<< "video/mpeg1" << "video/mpeg2" << "video/theora"
|
||||
<< "video/VP8" << "video/h261" << "video/mjpeg";
|
||||
|
||||
m_elementNames["video/h264"] = "x264enc";
|
||||
m_elementNames["video/xvid"] = "xvidenc";
|
||||
m_elementNames["video/mpeg4"] = "ffenc_mpeg4";
|
||||
m_elementNames["video/mpeg1"] = "ffenc_mpeg1video";
|
||||
m_elementNames["video/mpeg2"] = "ffenc_mpeg2video";
|
||||
m_elementNames["video/theora"] = "theoraenc";
|
||||
m_elementNames["video/mjpeg"] = "ffenc_mjpeg";
|
||||
m_elementNames["video/VP8"] = "vp8enc";
|
||||
m_elementNames["video/h261"] = "ffenc_h261";
|
||||
|
||||
m_codecOptions["video/h264"] = QStringList() << "quantizer";
|
||||
m_codecOptions["video/xvid"] = QStringList() << "quantizer" << "profile";
|
||||
m_codecOptions["video/mpeg4"] = QStringList() << "quantizer";
|
||||
m_codecOptions["video/mpeg1"] = QStringList() << "quantizer";
|
||||
m_codecOptions["video/mpeg2"] = QStringList() << "quantizer";
|
||||
m_codecOptions["video/theora"] = QStringList();
|
||||
|
||||
#endif
|
||||
|
||||
foreach( const QByteArray& codecName, codecCandidates ) {
|
||||
QByteArray elementName = m_elementNames[codecName];
|
||||
GstElementFactory *factory = gst_element_factory_find(elementName.constData());
|
||||
if (factory) {
|
||||
m_codecs.append(codecName);
|
||||
const gchar *descr = gst_element_factory_get_description(factory);
|
||||
m_codecDescriptions.insert(codecName, QString::fromUtf8(descr));
|
||||
|
||||
m_streamTypes.insert(codecName,
|
||||
CameraBinContainer::supportedStreamTypes(factory, GST_PAD_SRC));
|
||||
|
||||
gst_object_unref(GST_OBJECT(factory));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CameraBinVideoEncoder::~CameraBinVideoEncoder()
|
||||
@@ -134,12 +86,12 @@ QList< qreal > CameraBinVideoEncoder::supportedFrameRates(const QVideoEncoderSet
|
||||
|
||||
QStringList CameraBinVideoEncoder::supportedVideoCodecs() const
|
||||
{
|
||||
return m_codecs;
|
||||
return m_codecs.supportedCodecs();
|
||||
}
|
||||
|
||||
QString CameraBinVideoEncoder::videoCodecDescription(const QString &codecName) const
|
||||
{
|
||||
return m_codecDescriptions.value(codecName);
|
||||
return m_codecs.codecDescription(codecName);
|
||||
}
|
||||
|
||||
QStringList CameraBinVideoEncoder::supportedEncodingOptions(const QString &codec) const
|
||||
@@ -180,118 +132,6 @@ void CameraBinVideoEncoder::resetActualSettings()
|
||||
m_videoSettings = m_userSettings;
|
||||
}
|
||||
|
||||
GstElement *CameraBinVideoEncoder::createEncoder()
|
||||
{
|
||||
QString codec = m_videoSettings.codec();
|
||||
QByteArray elementName = m_elementNames.value(codec);
|
||||
|
||||
GstElement *encoderElement = gst_element_factory_make( elementName.constData(), "video-encoder");
|
||||
|
||||
if (encoderElement) {
|
||||
if (m_videoSettings.encodingMode() == QtMultimediaKit::ConstantQualityEncoding) {
|
||||
QtMultimediaKit::EncodingQuality qualityValue = m_videoSettings.quality();
|
||||
|
||||
if (elementName == "x264enc") {
|
||||
//constant quantizer mode
|
||||
g_object_set(G_OBJECT(encoderElement), "pass", 4, NULL);
|
||||
int qualityTable[] = {
|
||||
50, //VeryLow
|
||||
35, //Low
|
||||
21, //Normal
|
||||
15, //High
|
||||
8 //VeryHigh
|
||||
};
|
||||
g_object_set(G_OBJECT(encoderElement), "quantizer", qualityTable[qualityValue], NULL);
|
||||
} else if (elementName == "xvidenc") {
|
||||
//constant quantizer mode
|
||||
g_object_set(G_OBJECT(encoderElement), "pass", 3, NULL);
|
||||
int qualityTable[] = {
|
||||
32, //VeryLow
|
||||
12, //Low
|
||||
5, //Normal
|
||||
3, //High
|
||||
2 //VeryHigh
|
||||
};
|
||||
int quant = qualityTable[qualityValue];
|
||||
g_object_set(G_OBJECT(encoderElement), "quantizer", quant, NULL);
|
||||
} else if (elementName == "ffenc_mpeg4" ||
|
||||
elementName == "ffenc_mpeg1video" ||
|
||||
elementName == "ffenc_mpeg2video" ) {
|
||||
//constant quantizer mode
|
||||
g_object_set(G_OBJECT(encoderElement), "pass", 2, NULL);
|
||||
//quant from 1 to 30, default ~3
|
||||
double qualityTable[] = {
|
||||
20, //VeryLow
|
||||
8.0, //Low
|
||||
3.0, //Normal
|
||||
2.5, //High
|
||||
2.0 //VeryHigh
|
||||
};
|
||||
double quant = qualityTable[qualityValue];
|
||||
g_object_set(G_OBJECT(encoderElement), "quantizer", quant, NULL);
|
||||
} else if (elementName == "theoraenc") {
|
||||
int qualityTable[] = {
|
||||
8, //VeryLow
|
||||
16, //Low
|
||||
32, //Normal
|
||||
45, //High
|
||||
60 //VeryHigh
|
||||
};
|
||||
//quality from 0 to 63
|
||||
int quality = qualityTable[qualityValue];
|
||||
g_object_set(G_OBJECT(encoderElement), "quality", quality, NULL);
|
||||
} else if (elementName == "dsph264enc" ||
|
||||
elementName == "dspmp4venc" ||
|
||||
elementName == "dsphdmp4venc" ||
|
||||
elementName == "dsph263enc") {
|
||||
//only bitrate parameter is supported
|
||||
int qualityTable[] = {
|
||||
1000000, //VeryLow
|
||||
2000000, //Low
|
||||
4000000, //Normal
|
||||
8000000, //High
|
||||
16000000 //VeryHigh
|
||||
};
|
||||
int bitrate = qualityTable[qualityValue];
|
||||
g_object_set(G_OBJECT(encoderElement), "bitrate", bitrate, NULL);
|
||||
}
|
||||
} else {
|
||||
int bitrate = m_videoSettings.bitRate();
|
||||
if (bitrate > 0) {
|
||||
g_object_set(G_OBJECT(encoderElement), "bitrate", bitrate, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
QMap<QString,QVariant> options = m_options.value(codec);
|
||||
QMapIterator<QString,QVariant> it(options);
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
QString option = it.key();
|
||||
QVariant value = it.value();
|
||||
|
||||
switch (value.type()) {
|
||||
case QVariant::Int:
|
||||
g_object_set(G_OBJECT(encoderElement), option.toAscii(), value.toInt(), NULL);
|
||||
break;
|
||||
case QVariant::Bool:
|
||||
g_object_set(G_OBJECT(encoderElement), option.toAscii(), value.toBool(), NULL);
|
||||
break;
|
||||
case QVariant::Double:
|
||||
g_object_set(G_OBJECT(encoderElement), option.toAscii(), value.toDouble(), NULL);
|
||||
break;
|
||||
case QVariant::String:
|
||||
g_object_set(G_OBJECT(encoderElement), option.toAscii(), value.toString().toUtf8().constData(), NULL);
|
||||
break;
|
||||
default:
|
||||
qWarning() << "unsupported option type:" << option << value;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return encoderElement;
|
||||
}
|
||||
|
||||
QPair<int,int> CameraBinVideoEncoder::rateAsRational(qreal frameRate) const
|
||||
{
|
||||
@@ -324,8 +164,19 @@ QPair<int,int> CameraBinVideoEncoder::rateAsRational(qreal frameRate) const
|
||||
return QPair<int,int>();
|
||||
}
|
||||
|
||||
|
||||
QSet<QString> CameraBinVideoEncoder::supportedStreamTypes(const QString &codecName) const
|
||||
GstEncodingProfile *CameraBinVideoEncoder::createProfile()
|
||||
{
|
||||
return m_streamTypes.value(codecName);
|
||||
QString codec = m_videoSettings.codec();
|
||||
GstCaps *caps;
|
||||
|
||||
if (codec.isEmpty())
|
||||
caps = gst_caps_new_any();
|
||||
else
|
||||
caps = gst_caps_from_string(codec.toLatin1());
|
||||
|
||||
return (GstEncodingProfile *)gst_encoding_video_profile_new(
|
||||
caps,
|
||||
NULL, //preset
|
||||
NULL, //restriction
|
||||
0); //presence
|
||||
}
|
||||
|
||||
@@ -50,6 +50,9 @@ class CameraBinSession;
|
||||
#include <QtCore/qset.h>
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/pbutils/pbutils.h>
|
||||
#include <gst/pbutils/encoding-profile.h>
|
||||
#include "qgstcodecsinfo.h"
|
||||
|
||||
QT_USE_NAMESPACE
|
||||
|
||||
@@ -78,29 +81,23 @@ public:
|
||||
QVariant encodingOption(const QString &codec, const QString &name) const;
|
||||
void setEncodingOption(const QString &codec, const QString &name, const QVariant &value);
|
||||
|
||||
GstElement *createEncoder();
|
||||
|
||||
QSet<QString> supportedStreamTypes(const QString &codecName) const;
|
||||
|
||||
void setActualVideoSettings(const QVideoEncoderSettings&);
|
||||
void resetActualSettings();
|
||||
|
||||
GstEncodingProfile *createProfile();
|
||||
|
||||
Q_SIGNALS:
|
||||
void settingsChanged();
|
||||
|
||||
private:
|
||||
CameraBinSession *m_session;
|
||||
|
||||
QStringList m_codecs;
|
||||
QMap<QString,QString> m_codecDescriptions;
|
||||
QMap<QString,QByteArray> m_elementNames;
|
||||
QGstCodecsInfo m_codecs;
|
||||
QMap<QString,QStringList> m_codecOptions;
|
||||
QMap<QString, QMap<QString, QVariant> > m_options;
|
||||
|
||||
QVideoEncoderSettings m_videoSettings; // backend selected settings, using m_userSettings
|
||||
QVideoEncoderSettings m_userSettings;
|
||||
|
||||
QMap<QString, QMap<QString, QVariant> > m_options;
|
||||
QMap<QString, QSet<QString> > m_streamTypes;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -21,7 +21,8 @@ PKGCONFIG += \
|
||||
gstreamer-base-0.10 \
|
||||
gstreamer-interfaces-0.10 \
|
||||
gstreamer-audio-0.10 \
|
||||
gstreamer-video-0.10
|
||||
gstreamer-video-0.10 \
|
||||
gstreamer-pbutils-0.10
|
||||
|
||||
maemo*:PKGCONFIG +=gstreamer-plugins-bad-0.10
|
||||
contains(config_test_gstreamer_appsrc, yes): PKGCONFIG += gstreamer-app-0.10
|
||||
@@ -53,6 +54,7 @@ HEADERS += \
|
||||
qgstreamervideoinputdevicecontrol.h \
|
||||
gstvideoconnector.h \
|
||||
qabstractgstbufferpool.h \
|
||||
qgstcodecsinfo.h \
|
||||
qgstutils.h
|
||||
|
||||
SOURCES += \
|
||||
@@ -65,6 +67,7 @@ SOURCES += \
|
||||
qgstvideobuffer.cpp \
|
||||
qvideosurfacegstsink.cpp \
|
||||
qgstreamervideoinputdevicecontrol.cpp \
|
||||
qgstcodecsinfo.cpp \
|
||||
gstvideoconnector.c \
|
||||
qgstutils.cpp
|
||||
|
||||
|
||||
182
src/plugins/gstreamer/qgstcodecsinfo.cpp
Normal file
182
src/plugins/gstreamer/qgstcodecsinfo.cpp
Normal file
@@ -0,0 +1,182 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** GNU Lesser General Public License Usage
|
||||
** 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.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU General
|
||||
** Public License version 3.0 as published by the Free Software Foundation
|
||||
** and appearing in the file LICENSE.GPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU General
|
||||
** Public License version 3.0 requirements will be met:
|
||||
** http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** Other Usage
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qgstcodecsinfo.h"
|
||||
|
||||
#include <QtCore/qset.h>
|
||||
|
||||
#ifdef QMEDIA_GSTREAMER_CAMERABIN
|
||||
#include <gst/pbutils/pbutils.h>
|
||||
#include <gst/pbutils/encoding-profile.h>
|
||||
#endif
|
||||
|
||||
|
||||
QGstCodecsInfo::QGstCodecsInfo(QGstCodecsInfo::ElementType elementType)
|
||||
{
|
||||
|
||||
#if GST_CHECK_VERSION(0,10,31)
|
||||
|
||||
GstElementFactoryListType gstElementType = 0;
|
||||
switch (elementType) {
|
||||
case AudioEncoder:
|
||||
gstElementType = GST_ELEMENT_FACTORY_TYPE_AUDIO_ENCODER;
|
||||
break;
|
||||
case VideoEncoder:
|
||||
gstElementType = GST_ELEMENT_FACTORY_TYPE_VIDEO_ENCODER;
|
||||
break;
|
||||
case Muxer:
|
||||
gstElementType = GST_ELEMENT_FACTORY_TYPE_MUXER;
|
||||
break;
|
||||
}
|
||||
|
||||
GstCaps *allCaps = supportedElementCaps(gstElementType);
|
||||
GstCaps *caps = gst_caps_new_empty();
|
||||
|
||||
uint codecsCount = gst_caps_get_size(allCaps);
|
||||
for (uint i=0; i<codecsCount; i++) {
|
||||
gst_caps_append_structure(caps, gst_caps_steal_structure(allCaps, 0));
|
||||
gchar * capsString = gst_caps_to_string(caps);
|
||||
|
||||
QString codec = QLatin1String(capsString);
|
||||
m_codecs.append(codec);
|
||||
|
||||
#ifdef QMEDIA_GSTREAMER_CAMERABIN
|
||||
gchar *description = gst_pb_utils_get_codec_description(caps);
|
||||
m_codecDescriptions.insert(codec, QString::fromUtf8(description));
|
||||
|
||||
if (description)
|
||||
g_free(description);
|
||||
#else
|
||||
m_codecDescriptions.insert(codec, codec);
|
||||
#endif
|
||||
|
||||
if (capsString)
|
||||
g_free(capsString);
|
||||
|
||||
gst_caps_remove_structure(caps, 0);
|
||||
}
|
||||
|
||||
#endif // GST_CHECK_VERSION(0,10,31)
|
||||
}
|
||||
|
||||
QStringList QGstCodecsInfo::supportedCodecs() const
|
||||
{
|
||||
return m_codecs;
|
||||
}
|
||||
|
||||
QString QGstCodecsInfo::codecDescription(const QString &codec) const
|
||||
{
|
||||
return m_codecDescriptions.value(codec);
|
||||
}
|
||||
|
||||
#if GST_CHECK_VERSION(0,10,31)
|
||||
|
||||
/*!
|
||||
List all supported caps for all installed elements of type \a elementType.
|
||||
|
||||
Caps are simplified to mime type and a few field necessary to distinguish
|
||||
different codecs like mpegversion or layer.
|
||||
*/
|
||||
GstCaps* QGstCodecsInfo::supportedElementCaps(GstElementFactoryListType elementType,
|
||||
GstRank minimumRank,
|
||||
GstPadDirection padDirection)
|
||||
{
|
||||
GList *elements = gst_element_factory_list_get_elements(elementType, minimumRank);
|
||||
GstCaps *res = gst_caps_new_empty();
|
||||
|
||||
QSet<QByteArray> fakeEncoderMimeTypes;
|
||||
fakeEncoderMimeTypes << "unknown/unknown"
|
||||
<< "audio/x-raw-int" << "audio/x-raw-float"
|
||||
<< "video/x-raw-yuv" << "video/x-raw-rgb";
|
||||
|
||||
QSet<QByteArray> fieldsToAdd;
|
||||
fieldsToAdd << "mpegversion" << "layer" << "layout" << "raversion"
|
||||
<< "wmaversion" << "wmvversion" << "variant";
|
||||
|
||||
GList *element = elements;
|
||||
while (element) {
|
||||
GstElementFactory *factory = (GstElementFactory *)element->data;
|
||||
element = element->next;
|
||||
|
||||
const GList *padTemplates = gst_element_factory_get_static_pad_templates(factory);
|
||||
while (padTemplates) {
|
||||
GstStaticPadTemplate *padTemplate = (GstStaticPadTemplate *)padTemplates->data;
|
||||
padTemplates = padTemplates->next;
|
||||
|
||||
if (padTemplate->direction == padDirection) {
|
||||
const GstCaps *caps = gst_static_caps_get(&padTemplate->static_caps);
|
||||
for (uint i=0; i<gst_caps_get_size(caps); i++) {
|
||||
const GstStructure *structure = gst_caps_get_structure(caps, i);
|
||||
|
||||
//skip "fake" encoders
|
||||
if (fakeEncoderMimeTypes.contains(gst_structure_get_name(structure)))
|
||||
continue;
|
||||
|
||||
GstStructure *newStructure = gst_structure_new(gst_structure_get_name(structure), NULL);
|
||||
|
||||
//add structure fields to distinguish between formats with similar mime types,
|
||||
//like audio/mpeg
|
||||
for (int j=0; j<gst_structure_n_fields(structure); j++) {
|
||||
const gchar* fieldName = gst_structure_nth_field_name(structure, j);
|
||||
if (fieldsToAdd.contains(fieldName)) {
|
||||
const GValue *value = gst_structure_get_value(structure, fieldName);
|
||||
GType valueType = G_VALUE_TYPE(value);
|
||||
|
||||
//don't add values of range type,
|
||||
//gst_pb_utils_get_codec_description complains about not fixed caps
|
||||
|
||||
if (valueType != GST_TYPE_INT_RANGE && valueType != GST_TYPE_DOUBLE_RANGE &&
|
||||
valueType != GST_TYPE_FRACTION_RANGE && valueType != GST_TYPE_LIST &&
|
||||
valueType != GST_TYPE_ARRAY)
|
||||
gst_structure_set_value(newStructure, fieldName, value);
|
||||
}
|
||||
}
|
||||
|
||||
gst_caps_merge_structure(res, newStructure);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
gst_plugin_feature_list_free(elements);
|
||||
|
||||
return res;
|
||||
}
|
||||
#endif //GST_CHECK_VERSION(0,10,31)
|
||||
72
src/plugins/gstreamer/qgstcodecsinfo.h
Normal file
72
src/plugins/gstreamer/qgstcodecsinfo.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** GNU Lesser General Public License Usage
|
||||
** 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.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU General
|
||||
** Public License version 3.0 as published by the Free Software Foundation
|
||||
** and appearing in the file LICENSE.GPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU General
|
||||
** Public License version 3.0 requirements will be met:
|
||||
** http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** Other Usage
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QGSTCODECSINFO_H
|
||||
#define QGSTCODECSINFO_H
|
||||
|
||||
#include <QtCore/qmap.h>
|
||||
#include <QtCore/qstringlist.h>
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
class QGstCodecsInfo
|
||||
{
|
||||
public:
|
||||
enum ElementType { AudioEncoder, VideoEncoder, Muxer };
|
||||
|
||||
QGstCodecsInfo(ElementType elementType);
|
||||
|
||||
QStringList supportedCodecs() const;
|
||||
QString codecDescription(const QString &codec) const;
|
||||
|
||||
#if GST_CHECK_VERSION(0,10,31)
|
||||
static GstCaps* supportedElementCaps(GstElementFactoryListType elementType,
|
||||
GstRank minimumRank = GST_RANK_MARGINAL,
|
||||
GstPadDirection padDirection = GST_PAD_SRC);
|
||||
#endif
|
||||
|
||||
private:
|
||||
QStringList m_codecs;
|
||||
QMap<QString,QString> m_codecDescriptions;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user