I am new to Gstreamer. I have a question about change_state function for plugin.
As I read in this guide: http://gstreamer.freedesktop.org/data/doc/gstreamer/head/pwg/html/chapter-statemanage-states.html#section-statemanage-filters
static GstStateChangeReturn
gst_my_filter_change_state (GstElement *element, GstStateChange transition)
{
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
GstMyFilter *filter = GST_MY_FILTER (element);
switch (transition) {
**//Downwards state change;**
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
if (ret == GST_STATE_CHANGE_FAILURE)
return ret;
**//upward state change**
}
return ret;
}
I really don't know how we can use parent_class and call parent_class->change_state
Because in init function of this element:
gst_my_filter_class_init (GstMyFilterClass *klass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
element_class->change_state = gst_my_filter_change_state;**strong text**
}
element_class->change_state was assigned to gst_my_filter_change_state. Why can we still call element_class->change_state in gst_my_filter_change_state when element_class->change_state is assign to another function.
Thank you!
Change gst_my_filter_class_init (GstMyFilterClass *klass) to something like this:
gst_my_filter_class_init (GstMyFilterClass *klass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
parent_class = (GstXyzClass *) g_type_class_peek_parent (klass);
element_class->change_state = gst_my_filter_change_state;**strong text**
}
And add a static global variable GstXyzClass *parent_class; somewhere near the top of your plugin. Just GstXyzClass will be the type of the Element you are inheriting from, e.g. GstElementClass. Just look at other plugin sources for examples.
Thanks for your answer. Actually,this code I quoted from that guide can run normally.But the thing I can not understand is in header file we declare: GstMyFilterClass {GstElementClass parent_class;} It means GstElementClass is the father class of GstMyFilterClass
but why can we use parent_class in source file of this plugin(.c file)? Sorry for my lacking of knowledge in Gobject , but as I know GstMyFilterClass is a struct and(not class like C++) and the attribute parent_class can not be used in function of plugin(in C++ we can easily use attribute in method of class). And in the gst_my_filter_class_init :
gst_my_filter_class_init (GstMyFilterClass *klass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
element_class->change_state = gst_my_filter_change_state;//assign to function pointer state change
}
Does The statement:GstElementClass *element_class = GST_ELEMENT_CLASS (klass); mean we cast GST_ELEMENT_CLASS (klass) to get its parent class(GstElementClass parent_class)?
If it is true,so the change_state function pointer of parent_class is not Null. So In
gst_my_filter_change_state (GstElement *element, GstStateChange transition)
{
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
GstMyFilter *filter = GST_MY_FILTER (element);
switch (transition) {
**//Downwards state change;**
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
if (ret == GST_STATE_CHANGE_FAILURE)
return ret;
**//upward state change**
}
return ret;
}
what is GST_ELEMENT_CLASS (parent_class)->change_state (element, transition)?
As I know every GstElementClass has a default function change_state but in this situation function change_state has assigned to another pointer function(gst_my_filter_class_init do this assignment) Is it right? Hope to receive your answer soon. Thank you very much
Related
I'm trying to connect some widgets with the same user_function callback. In some cases, the signal has diferent signatures.
Searching i found gtk_signal_connect_full, I think.
My Code for example:
int MyObject::connect()
{
callback_object ....
// Create the callback
int ret = g_signal_connect(instance, "clicked", G_CALLBACK (connect_callback), callback_object);
int ret = g_signal_connect(instance, "button-release-event", G_CALLBACK (connect_callback), callback_object);
// Return handler id
return ret;
}
void MyObject::connect_callback(GObject *passedInstance, gpointer param1, gpointer param2)
{
// Return to st_callback
struct st_callback *callback_object = (struct st_callback *) param2;
if(sizeof(param1) == 0) {
callback_object = (struct st_callback *) param1;
}
}
Can i "abstract" user_function like that? and if I can, How to get extra parameters like GdkEvent or GdkEventButton, or gchar, ...
EDIT
- This question is a GTK+ issue, because in the first g_signal_connect, param1 is my struct. I'ts ok, I know my struct to cast back. In the second g_signal_connect, param1 is a GdkEventButton. It's OK too, becouse I know it's a GdkEventButton to cast back. BUT, how to do this, if I dont know param1 is my struct, if its a GdkEvent, GdkEventButton, gchar, or all others possibilities of sinal signatures?
EDIT 2
- I have found this info on Closures doc
Closures allow the callee to get the types of the callback parameters, which means that language bindings don't have to write individual glue for each callback type.
This seen perfect for what i'm looking for, but I don't found nothing more that it
EDIT 3
With ebassi ideia about, g_signal_query is what I need. I do this for abstract:
1 - query the params of signal with g_signal_query, set into my structure to pass with callback user_data
2 - connect with g_cclosure_new_swap and g_signal_connect_closure, this set gpointer user_data as first param
3 - created callback like this: connect_callback(gpointer user_data, ...), with variable parameter list
4 - inside callback, get back my struct with custom + g_signal_query result
5 - loop into param_types of GSignalQuery, verifying each fundamental types
6 - get va_arg with correct type
Complete code for call the callback
// Create gpoint param
struct st_callback *callback_object = (struct st_callback *)malloc(sizeof(struct st_callback));
memset(callback_object, 0, sizeof(struct st_callback));
callback_object->callback_name = callback_name;
callback_object->callback_params = callback_params;
// Get params of signal
GSignalQuery signal_info;
g_signal_query(g_signal_lookup (callback_signal, G_OBJECT_TYPE (instance)), &signal_info);
// Save
callback_object->signal_id = signal_info.signal_id;
callback_object->signal_name = signal_info.signal_name;
callback_object->itype = signal_info.itype;
callback_object->signal_flags = signal_info.signal_flags;
callback_object->return_type = signal_info.return_type;
callback_object->n_params = signal_info.n_params;
callback_object->param_types = signal_info.param_types;
GClosure *closure;
closure = g_cclosure_new_swap (G_CALLBACK (connect_callback), callback_object, NULL);
int ret = g_signal_connect_closure (instance, callback_event, closure, TRUE);
And the callback
static bool connect_callback(gpointer user_data, ...)
{
// Return to st_callback
struct st_callback *callback_object = (struct st_callback *) user_data;
// get parameters count
int param_count = callback_object->n_params;
va_list ap;
va_start(ap, param_count);
// loop paramters
for (int i=0; i<param_count; i++) {
switch (G_TYPE_FUNDAMENTAL(callback_object->param_types[i])) {
case G_TYPE_CHAR:
break;
case G_TYPE_UCHAR:
break;
case G_TYPE_STRING:
{
char *path = va_arg(ap, char *);
break;
}
case G_TYPE_OBJECT:
break;
case G_TYPE_POINTER:
break;
case G_TYPE_INTERFACE:
break;
case G_TYPE_PARAM:
break;
case G_TYPE_BOXED:
{
// Example, try to cast correct boxed
GdkEvent *e = va_arg(ap, GdkEvent *);
break;
}
}
}
va_end(ap);
}
Needs to correct return and boxed cast, but with this I can work fine
You should not use the same function for different types of callbacks. Some callbacks take different parameters, others have different return values — for instance, in your example, clicked does not return anything, whereas button-press-event returns a boolean value.
If you have common code that needs to be executed in different signal handlers, write a function and then call it from the various handlers.
I would like to implement a workaround to use a non-static class as a call-back function. I am working with Eclipse Paho MQTT code. The following type is implemented and used as callback:
typedef void MQTTAsync_onSuccess(void* context, MQTTAsync_successData* response);
MQTTAsync_onSuccess* onSuccess;
onSuccess = myStaticCallback;
void myStaticCallback (void* context, MQTTAsync_successData* response)
{
//...callback actions...
}
I want to wrap this C API (without modifying the existing MQTT C API) and implement non-static / non-centralized callback function that belongs to an object/class.
typedef void MQTTAsync_onSuccess(void* context, MQTTAsync_successData* response);
class myMQTTClass
{
private:
void myCallback (void* context, MQTTAsync_successData* response);
MQTTAsync_onSuccess* onSuccess;
public:
void foo (void)
{
this->onSuccess = this->myCallback;
}
}
As you might guess, the code above causes the error:
cannot convert myCallback from type 'void (myMQTTClass::) (void*, MQTTAsync_successData*)' to type 'void (*)(void*, MQTTAsync_successData*)'.
Any guidance as to how to address this issue or any workaround is greately appreciated. I would be willing to provide any possible missing information. Thanks in advance.
EDIT: Actual code with some omissions
namespace rover
{
typedef struct
{
char * clientID;
char * topic;
char * payload;
int qos; // 1
long int timeout; // Such as 10000L usec
} RoverMQTT_Configure_t;
class RoverPahoMQTT
{
public:
RoverPahoMQTT (char * host_name, int port, RoverMQTT_Configure_t MQTT_Configure);
private:
/**
* #brief Host name used for connecting to the Eclipse Paho MQTT server
*/
char * HOST_NAME;
/**
* #brief Port used for connecting to the Eclipse Paho MQTT server
*/
int PORT;
RoverMQTT_Configure_t rover_MQTT_configure;
/* Internal attributes */
MQTTAsync client;
/**
* #brief Connect options
*/
MQTTAsync_connectOptions conn_opts;
/**
* #brief Disconnect options
*/
MQTTAsync_disconnectOptions disc_opts;
//...
static void onPublisherConnect (void* context, MQTTAsync_successData* response);
void onPublisherConnect_ (MQTTAsync_successData* response);
//...
}
}
int rover::RoverPahoMQTT::publish (void)
{
this->flushFlags ();
this->conn_opts = MQTTAsync_connectOptions_initializer;
this->client = new MQTTAsync;
int rc;
char my_addr[20];
this->constructAddress (my_addr);
printf ("address: %s", my_addr);
MQTTAsync_create ( &(this->client),
my_addr,
this->rover_MQTT_configure.clientID,
MQTTCLIENT_PERSISTENCE_NONE,
NULL);
MQTTAsync_setCallbacks(this->client, NULL, onConnectionLost, NULL, NULL);
conn_opts.keepAliveInterval = 20;
conn_opts.cleansession = 1;
conn_opts.onSuccess = rover::RoverPahoMQTT::onPublisherConnect;
conn_opts.onFailure = onConnectFailure;
conn_opts.context = this->client;
if ((rc = MQTTAsync_connect(this->client, &(this->conn_opts))) != MQTTASYNC_SUCCESS)
{
printf("Failed to start connect, return code %d\n", rc);
return rc;
}
/*printf("Waiting for publication of %s\n"
"on topic %s for client with ClientID: %s\n",
PAYLOAD, TOPIC, CLIENTID);*/
while (!mqtt_finished)
usleep(this->rover_MQTT_configure.timeout);
MQTTAsync_destroy(&client);
return rc;
}
void rover::RoverPahoMQTT::onPublisherConnect_(MQTTAsync_successData* response)
{
MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer;
MQTTAsync_message pubmsg = MQTTAsync_message_initializer;
int rc;
printf("Successful connection\n");
opts.onSuccess = onPublisherSend;
opts.context = client;
pubmsg.payload = &default_MQTT_configure.payload;
pubmsg.payloadlen = strlen(default_MQTT_configure.payload);
pubmsg.qos = default_MQTT_configure.qos;
pubmsg.retained = 0;
deliveredtoken = 0;
if ((rc = MQTTAsync_sendMessage(client, default_MQTT_configure.topic, &pubmsg, &opts)) != MQTTASYNC_SUCCESS)
{
printf("Failed to start sendMessage, return code %d\n", rc);
exit(EXIT_FAILURE);
}
}
void rover::RoverPahoMQTT::onPublisherConnect (void* context, MQTTAsync_successData* response)
{
rover::RoverPahoMQTT* m = (rover::RoverPahoMQTT*) context;
m->onPublisherConnect_(response);
//((rover::RoverPahoMQTT*)context)->onPublisherConnect_(response);
// ^^^HERE IS THE SEGMENTATION FAULT
}
As clearly stated here, the callback has to be
registered with the client library by passing it as an argument in
MQTTAsync_responseOptions
and the context argument is a
pointer to the context value originally passed to
MQTTAsync_responseOptions, which contains any application-specific
context.
I suggest a common interface for your classes, which provides a static method that matches the callback prototype:
class myMQTTClass
{
public:
static void callback(void* context, MQTTAsync_successData* response)
{
myMQTTClass * m = (myMQTTClass*)context;
m->myCallback(response);
}
protected:
virtual void myCallback(MQTTAsync_successData* response) = 0;
};
You can now implement different behaviours in subclasses:
class myMQTTClassImpl : public myMQTTClass
{
protected:
void myCallback(MQTTAsync_successData *response)
{
std::cout << "success!!!" << std::endl;
}
};
Let's see how to use it:
int main()
{
myMQTTClass * m = new myMQTTClassImpl();
MQTTAsync_responseOptions options;
options.onSuccess = myMQTTClass::callback;
options.context = m;
}
Edit (refers to actual code posted):
In your publish method, this is right:
conn_opts.onSuccess = rover::RoverPahoMQTT::onPublisherConnect;
this is wrong:
conn_opts.context = this->client;
it should be:
conn_opts.context = this;
If you can use the context parameter to point to the object you want the callback to fire on you could simply make the callback function static and forward to an instance function. If the context parameter is needed for other data then I would use libffi to generate a closure and associate the object pointer with the closure's saved arguments.
There is no correct way to pass an actual instance function to that callback and be sure that it will work (even if you made the instance function be something like void MyCallback(MQTTAsync_successData*) and then forcibly cast that to the callback type you aren't guaranteed that the calling convention would match.
For the first (where you can use the context arg to point to 'this'):
class MyCallback
{
static void CallbackFunc(void * ptr, MQTTAsync_successData* data)
{
((MyCallback*)ptr)->RealCallback(data);
}
void RealCallback(MQTTAsync_successData*)
{}
};
You would then assign &MyCallback::CallbackFunc to the function pointer.
libffi is quite a bit more complicated.
I'm work on next version of v8-profiler and now I want to simplify it.
I see that my class (ProfileNode) don't needs hidden link to internal object (v8::CpuProfileNode), because my class don't uses internal object methods.
Can I delete getter methods and replace it like the example below?
Is it wrong realisation?
Is it hight memory usage?
Or it's OK?
(I'm novice in c++ and v8 library)
(Please ignore version uncompatibility - it's not a part of question)
This is a part of current profile_node.cc
Persistent<ObjectTemplate> ProfileNode::node_template_;
void ProfileNode::Initialize() {
Local<ObjectTemplate> tpl = NanNewLocal<ObjectTemplate>(ObjectTemplate::New());
NanAssignPersistent(ObjectTemplate, node_template_, tpl);
tpl->SetInternalFieldCount(1);
tpl->SetAccessor(String::New("functionName"), ProfileNode::GetFunctionName);
...
}
NAN_GETTER(ProfileNode::GetFunctionName) {
NanScope();
Local<Object> self = args.Holder();
void* ptr = NanGetInternalFieldPointer(self, 0);
Handle<String> fname = static_cast<CpuProfileNode*>(ptr)->GetFunctionName();
NanReturnValue(fname);
}
...
Handle<Value> ProfileNode::New(const CpuProfileNode* node) {
NanScope();
if (node_template_.IsEmpty()) {
ProfileNode::Initialize();
}
if(!node) {
return Undefined();
}
else {
Local<Object> obj = NanPersistentToLocal(node_template_)->NewInstance();
NanSetInternalFieldPointer(obj, 0, const_cast<CpuProfileNode*>(node));
return obj;
}
}
After refactoring
//ProfileNode::Initialize deleted
//ProfileNode::GetFunctionName deleted
Handle<Value> ProfileNode::New(const CpuProfileNode* node) {
NanScope();
if(!node) {
return NanUndefined();
}
else {
//Create new simplest object, instead of new instance of object template
Local<Object> obj = NanNew<Object>();
//Append the value to this object
obj->Set(String::New("functionName"), node->GetFunctionName());
//Delete internal link.
//NanSetInternalFieldPointer(obj, 0, const_cast<CpuProfileNode*>(node));
return obj;
}
}
I have a JNI problem which I hope someone can help me out with.
I'm trying to call on a constructor of a Java class called LUSOutputJNI from a native thread.
It keeps failing on FindClass(...) of this specific class.
Here is the code:
LOGE("1");
JNIEnv *env = NULL;
LOGE("2");
int res = -1;
res = g_vm->AttachCurrentThread(&env, NULL);
if(env == NULL)
{
LOGE("env is NULL, AttachCurrentThread failed");;
}
if(res >= 0)
LOGE("AttachCurrentThread was successful");
jclass clazz = NULL;
jmethodID cid;
jclass clazzESEngine;
jmethodID callbackid;
jobject jCoreOut;
static jfieldID fid_ActionState = NULL;
static jfieldID fid_nSpeed = NULL;
static jfieldID fid_nType = NULL;
static jfieldID fid_nInProcess = NULL;
static jfieldID fid_nX = NULL;
static jfieldID fid_nY = NULL;
LOGE("3");
static const char* const ECOClassName = "lus/android/sdk/LUSOutputJNI";
//static const char* const ECOClassName = "android/widget/TextView";
clazz = env->FindClass(ECOClassName);
if (clazz == NULL) {
LOGE("Can't find class LUSOutputJNI");
}
else
LOGE("lus/android/sdk/LUSOutputJNI was found, YEY!!");
LOGE("4");
cid = env->GetMethodID(clazz,"<init>", "()V");
LOGE("5");
jCoreOut = env->NewObject(clazz, cid);
LOGE("6");
Here is the logcat output from when it fails:
E/lusCore_JNI( 3040): 1
E/lusCore_JNI( 3040): 2
E/lusCore_JNI( 3040): AttachCurrentThread was successful
E/lusCore_JNI( 3040): 3
E/lusCore_JNI( 3040): Can't find class LUSOutputJNI
E/lusCore_JNI( 3040): 4
W/dalvikvm( 3040): JNI WARNING: JNI method called with exception raised
Observations:
I get a result from AttachCurrentThread which is 0, which means that this attachment was successful + the env pointer is no longer NULL.
I'm sure about the package name declaration of LUSOutputJNI (triple checked it...)
When I try to run FindClass(..) with a more popular class name such as android/widget/TextView , I get a positive match. It is there. Meaning the thread attachment and the env variables are ok. (Can I assume that?)
When I try to run the following code from a JNI method which has a JNI thread running it, it finds the LUSOutputJNI class without a problem.
What am I doing wrong?
Help will be much appreciated :)
Thanks for your time,
Ita
Found the answer \ work around in here. (Look for FAQ: "FindClass didn't find my class" in
JNI tips)
I basicaly saved a global ref to the needed jclass objects.
Did however had to overcome some evil JNI changes between C/JNI and C++/JNI in order for the code to compile.
This is how I got the NewGlobalRef to compile and work.
jclass localRefCls = env->FindClass(strLUSClassName);
if (localRefCls == NULL) {
LOGE("Can't find class %s",strLUSCoreClassName);
return result;
}
//cache the EyeSightCore ref as global
/* Create a global reference */
clazzLUSCore = (_jclass*)env->NewGlobalRef(localRefCls);
/* The local reference is no longer useful */
env->DeleteLocalRef(localRefCls);
/* Is the global reference created successfully? */
if (clazzLUSCore == NULL) {
LOGE("Error - clazzLUSCore is still null when it is suppose to be global");
return result; /* out of memory exception thrown */
}
I hope this helps anyone.
To get a bit more information about whats going wrong ( it will log to stderr, not LOGE, and I'm not sure how to change that) you can add some exception printing - you can change this:
//static const char* const ECOClassName = "android/widget/TextView";
clazz = env->FindClass(ECOClassName);
if (clazz == NULL) {
LOGE("Can't find class LUSOutputJNI");
}
else
LOGE("lus/android/sdk/LUSOutputJNI was found, YEY!!");
To this:
//static const char* const ECOClassName = "android/widget/TextView";
clazz = env->FindClass(ECOClassName);
if (clazz == NULL) {
LOGE("Can't find class LUSOutputJNI");
jthrowable exc = env->ExceptionOccurred();
if(exc)
{
env->ExceptionDescribe();
env->ExceptionClear();
}
}
else
LOGE("lus/android/sdk/LUSOutputJNI was found, YEY!!");
I want to implement port-forwarding using intel-upnp.
I got XML data like:
Device found at location: http://192.168.10.1:49152/gatedesc.xml
service urn:schemas-upnp-org:service:WANIPConnection:1
controlurl /upnp/control/WANIPConn1
eventsuburl : /upnp/control/WANIPConn1
scpdurl : /gateconnSCPD.xml
And now, I want to make upnp-action. But, I don't know how to make it.
If you know some code snippet or helpful URL in C, please tell me.
char actionxml[250];
IXML_Document *action = NULL;
strcpy(actionxml, "<u:GetConnectionTypeInfo xmlns:u=\"urn:schemas-upnp- org:service:WANCommonInterfaceConfig:1\">");
action = ixmlParseBuffer(actionxml);
int ret = UpnpSendActionAsync( g_handle,
"http:192.168.10.1:49152/upnp/control/WANCommonIFC1",
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
NULL,
action,
upnp_callback,
NULL);
I know this is an old question, but it can be kept for reference. You can take a look at the sample code in the libupnp library here: https://github.com/mrjimenez/pupnp/blob/master/upnp/sample/common/tv_ctrlpt.c
The relevant code is in the function TvCtrlPointSendAction():
int TvCtrlPointSendAction(
int service,
int devnum,
const char *actionname,
const char **param_name,
char **param_val,
int param_count)
{
struct TvDeviceNode *devnode;
IXML_Document *actionNode = NULL;
int rc = TV_SUCCESS;
int param;
ithread_mutex_lock(&DeviceListMutex);
rc = TvCtrlPointGetDevice(devnum, &devnode);
if (TV_SUCCESS == rc) {
if (0 == param_count) {
actionNode =
UpnpMakeAction(actionname, TvServiceType[service],
0, NULL);
} else {
for (param = 0; param < param_count; param++) {
if (UpnpAddToAction
(&actionNode, actionname,
TvServiceType[service], param_name[param],
param_val[param]) != UPNP_E_SUCCESS) {
SampleUtil_Print
("ERROR: TvCtrlPointSendAction: Trying to add action param\n");
/*return -1; // TBD - BAD! leaves mutex locked */
}
}
}
rc = UpnpSendActionAsync(ctrlpt_handle,
devnode->device.
TvService[service].ControlURL,
TvServiceType[service], NULL,
actionNode,
TvCtrlPointCallbackEventHandler, NULL);
if (rc != UPNP_E_SUCCESS) {
SampleUtil_Print("Error in UpnpSendActionAsync -- %d\n",
rc);
rc = TV_ERROR;
}
}
ithread_mutex_unlock(&DeviceListMutex);
if (actionNode)
ixmlDocument_free(actionNode);
return rc;
}
The explanation is that you should create the action with UpnpMakeAction() if you have no parameters or UpnpAddToAction() if you have parameters to create your action, and then send it either synchronously or asynchronously.