Implement encoder settings in camerabin backend.
This is not comprehensive since different encoders have different names and representations for many settings, but it should cover bit rate for most encoders, and quality and encodingMode for a number of common encoders. Change-Id: I0ba4e70c2f234e0deaaa02bdecc0f5198122c1e9 Reviewed-by: Yoann Lopes <yoann.lopes@digia.com>
This commit is contained in:
committed by
Yoann Lopes
parent
9c020cd39a
commit
55ce8ed072
@@ -117,4 +117,28 @@ GstEncodingProfile *CameraBinAudioEncoder::createProfile()
|
|||||||
return profile;
|
return profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CameraBinAudioEncoder::applySettings(GstElement *encoder)
|
||||||
|
{
|
||||||
|
GObjectClass * const objectClass = G_OBJECT_GET_CLASS(encoder);
|
||||||
|
const char * const name = gst_plugin_feature_get_name(
|
||||||
|
GST_PLUGIN_FEATURE(gst_element_get_factory(encoder)));
|
||||||
|
|
||||||
|
const bool isVorbis = qstrcmp(name, "vorbisenc") == 0;
|
||||||
|
|
||||||
|
const int bitRate = m_actualAudioSettings.bitRate();
|
||||||
|
if (!isVorbis && bitRate == -1) {
|
||||||
|
// Bit rate is invalid, don't evaluate the remaining conditions unless the encoder is
|
||||||
|
// vorbisenc which is known to accept -1 as an unspecified bitrate.
|
||||||
|
} else if (g_object_class_find_property(objectClass, "bitrate")) {
|
||||||
|
g_object_set(G_OBJECT(encoder), "bitrate", bitRate, NULL);
|
||||||
|
} else if (g_object_class_find_property(objectClass, "target-bitrate")) {
|
||||||
|
g_object_set(G_OBJECT(encoder), "target-bitrate", bitRate, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isVorbis) {
|
||||||
|
static const double qualities[] = { 0.1, 0.3, 0.5, 0.7, 1.0 };
|
||||||
|
g_object_set(G_OBJECT(encoder), "quality", qualities[m_actualAudioSettings.quality()], NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|||||||
@@ -78,6 +78,8 @@ public:
|
|||||||
|
|
||||||
GstEncodingProfile *createProfile();
|
GstEncodingProfile *createProfile();
|
||||||
|
|
||||||
|
void applySettings(GstElement *element);
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void settingsChanged();
|
void settingsChanged();
|
||||||
|
|
||||||
|
|||||||
@@ -133,6 +133,7 @@ CameraBinSession::CameraBinSession(GstElementFactory *sourceFactory, QObject *pa
|
|||||||
m_capsFilter(0),
|
m_capsFilter(0),
|
||||||
m_fileSink(0),
|
m_fileSink(0),
|
||||||
m_audioEncoder(0),
|
m_audioEncoder(0),
|
||||||
|
m_videoEncoder(0),
|
||||||
m_muxer(0)
|
m_muxer(0)
|
||||||
{
|
{
|
||||||
if (m_sourceFactory)
|
if (m_sourceFactory)
|
||||||
@@ -140,6 +141,8 @@ CameraBinSession::CameraBinSession(GstElementFactory *sourceFactory, QObject *pa
|
|||||||
|
|
||||||
m_camerabin = gst_element_factory_make("camerabin2", "camerabin2");
|
m_camerabin = gst_element_factory_make("camerabin2", "camerabin2");
|
||||||
g_signal_connect(G_OBJECT(m_camerabin), "notify::idle", G_CALLBACK(updateBusyStatus), this);
|
g_signal_connect(G_OBJECT(m_camerabin), "notify::idle", G_CALLBACK(updateBusyStatus), this);
|
||||||
|
g_signal_connect(G_OBJECT(m_camerabin), "element-added", G_CALLBACK(elementAdded), this);
|
||||||
|
g_signal_connect(G_OBJECT(m_camerabin), "element-removed", G_CALLBACK(elementRemoved), this);
|
||||||
qt_gst_object_ref_sink(m_camerabin);
|
qt_gst_object_ref_sink(m_camerabin);
|
||||||
|
|
||||||
m_bus = gst_element_get_bus(m_camerabin);
|
m_bus = gst_element_get_bus(m_camerabin);
|
||||||
@@ -344,6 +347,9 @@ void CameraBinSession::setupCaptureResolution()
|
|||||||
} else {
|
} else {
|
||||||
g_object_set(m_camerabin, VIEWFINDER_CAPS_PROPERTY, NULL, NULL);
|
g_object_set(m_camerabin, VIEWFINDER_CAPS_PROPERTY, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_videoEncoder)
|
||||||
|
m_videoEncodeControl->applySettings(m_videoEncoder);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CameraBinSession::setAudioCaptureCaps()
|
void CameraBinSession::setAudioCaptureCaps()
|
||||||
@@ -370,6 +376,9 @@ void CameraBinSession::setAudioCaptureCaps()
|
|||||||
GstCaps *caps = gst_caps_new_full(structure, NULL);
|
GstCaps *caps = gst_caps_new_full(structure, NULL);
|
||||||
g_object_set(G_OBJECT(m_camerabin), AUDIO_CAPTURE_CAPS_PROPERTY, caps, NULL);
|
g_object_set(G_OBJECT(m_camerabin), AUDIO_CAPTURE_CAPS_PROPERTY, caps, NULL);
|
||||||
gst_caps_unref(caps);
|
gst_caps_unref(caps);
|
||||||
|
|
||||||
|
if (m_audioEncoder)
|
||||||
|
m_audioEncodeControl->applySettings(m_audioEncoder);
|
||||||
}
|
}
|
||||||
|
|
||||||
GstElement *CameraBinSession::buildCameraSource()
|
GstElement *CameraBinSession::buildCameraSource()
|
||||||
@@ -1293,4 +1302,32 @@ QList<QSize> CameraBinSession::supportedResolutions(QPair<int,int> rate,
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CameraBinSession::elementAdded(GstBin *, GstElement *element, CameraBinSession *session)
|
||||||
|
{
|
||||||
|
GstElementFactory *factory = gst_element_get_factory(element);
|
||||||
|
|
||||||
|
if (GST_IS_BIN(element)) {
|
||||||
|
g_signal_connect(G_OBJECT(element), "element-added", G_CALLBACK(elementAdded), session);
|
||||||
|
g_signal_connect(G_OBJECT(element), "element-removed", G_CALLBACK(elementRemoved), session);
|
||||||
|
} else if (!factory) {
|
||||||
|
// no-op
|
||||||
|
} else if (gst_element_factory_list_is_type(factory, GST_ELEMENT_FACTORY_TYPE_AUDIO_ENCODER)) {
|
||||||
|
session->m_audioEncoder = element;
|
||||||
|
|
||||||
|
session->m_audioEncodeControl->applySettings(element);
|
||||||
|
} else if (gst_element_factory_list_is_type(factory, GST_ELEMENT_FACTORY_TYPE_VIDEO_ENCODER)) {
|
||||||
|
session->m_videoEncoder = element;
|
||||||
|
|
||||||
|
session->m_videoEncodeControl->applySettings(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CameraBinSession::elementRemoved(GstBin *, GstElement *element, CameraBinSession *session)
|
||||||
|
{
|
||||||
|
if (element == session->m_audioEncoder)
|
||||||
|
session->m_audioEncoder = 0;
|
||||||
|
else if (element == session->m_videoEncoder)
|
||||||
|
session->m_videoEncoder = 0;
|
||||||
|
}
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|||||||
@@ -190,6 +190,9 @@ private:
|
|||||||
void setAudioCaptureCaps();
|
void setAudioCaptureCaps();
|
||||||
static void updateBusyStatus(GObject *o, GParamSpec *p, gpointer d);
|
static void updateBusyStatus(GObject *o, GParamSpec *p, gpointer d);
|
||||||
|
|
||||||
|
static void elementAdded(GstBin *bin, GstElement *element, CameraBinSession *session);
|
||||||
|
static void elementRemoved(GstBin *bin, GstElement *element, CameraBinSession *session);
|
||||||
|
|
||||||
QUrl m_sink;
|
QUrl m_sink;
|
||||||
QUrl m_actualSink;
|
QUrl m_actualSink;
|
||||||
bool m_recordingActive;
|
bool m_recordingActive;
|
||||||
@@ -241,6 +244,7 @@ private:
|
|||||||
GstElement *m_capsFilter;
|
GstElement *m_capsFilter;
|
||||||
GstElement *m_fileSink;
|
GstElement *m_fileSink;
|
||||||
GstElement *m_audioEncoder;
|
GstElement *m_audioEncoder;
|
||||||
|
GstElement *m_videoEncoder;
|
||||||
GstElement *m_muxer;
|
GstElement *m_muxer;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -175,4 +175,46 @@ GstEncodingProfile *CameraBinVideoEncoder::createProfile()
|
|||||||
return (GstEncodingProfile *)profile;
|
return (GstEncodingProfile *)profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CameraBinVideoEncoder::applySettings(GstElement *encoder)
|
||||||
|
{
|
||||||
|
GObjectClass * const objectClass = G_OBJECT_GET_CLASS(encoder);
|
||||||
|
const char * const name = gst_plugin_feature_get_name(
|
||||||
|
GST_PLUGIN_FEATURE(gst_element_get_factory(encoder)));
|
||||||
|
|
||||||
|
const int bitRate = m_actualVideoSettings.bitRate();
|
||||||
|
if (bitRate == -1) {
|
||||||
|
// Bit rate is invalid, don't evaluate the remaining conditions.
|
||||||
|
} else if (g_object_class_find_property(objectClass, "bitrate")) {
|
||||||
|
g_object_set(G_OBJECT(encoder), "bitrate", bitRate, NULL);
|
||||||
|
} else if (g_object_class_find_property(objectClass, "target-bitrate")) {
|
||||||
|
g_object_set(G_OBJECT(encoder), "target-bitrate", bitRate, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qstrcmp(name, "theoraenc") == 0) {
|
||||||
|
static const int qualities[] = { 8, 16, 32, 45, 60 };
|
||||||
|
g_object_set(G_OBJECT(encoder), "quality", qualities[m_actualVideoSettings.quality()], NULL);
|
||||||
|
} else if (qstrncmp(name, "avenc_", 6) == 0) {
|
||||||
|
if (g_object_class_find_property(objectClass, "pass")) {
|
||||||
|
static const int modes[] = { 0, 2, 512, 1024 };
|
||||||
|
g_object_set(G_OBJECT(encoder), "pass", modes[m_actualVideoSettings.encodingMode()], NULL);
|
||||||
|
}
|
||||||
|
if (g_object_class_find_property(objectClass, "quantizer")) {
|
||||||
|
static const double qualities[] = { 20, 8.0, 3.0, 2.5, 2.0 };
|
||||||
|
g_object_set(G_OBJECT(encoder), "quantizer", qualities[m_actualVideoSettings.quality()], NULL);
|
||||||
|
}
|
||||||
|
} else if (qstrncmp(name, "omx", 3) == 0) {
|
||||||
|
if (!g_object_class_find_property(objectClass, "control-rate")) {
|
||||||
|
} else switch (m_actualVideoSettings.encodingMode()) {
|
||||||
|
case QMultimedia::ConstantBitRateEncoding:
|
||||||
|
g_object_set(G_OBJECT(encoder), "control-rate", 2, NULL);
|
||||||
|
break;
|
||||||
|
case QMultimedia::AverageBitRateEncoding:
|
||||||
|
g_object_set(G_OBJECT(encoder), "control-rate", 1, NULL);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_object_set(G_OBJECT(encoder), "control-rate", 0, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|||||||
@@ -76,6 +76,8 @@ public:
|
|||||||
|
|
||||||
GstEncodingProfile *createProfile();
|
GstEncodingProfile *createProfile();
|
||||||
|
|
||||||
|
void applySettings(GstElement *encoder);
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void settingsChanged();
|
void settingsChanged();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user