I am trying to initialize a gstreamer pipeline via the C API. The code looks similar to this:
[...]
pipeline = (GstPipeline*)gst_pipeline_new(nullptr);
if(!pipeline) {
//error
return;
}
[...]
sink = gst_element_factory_make("autoaudiosink", nullptr);
if(!sink) {
//error
return;
}
if(!gst_bin_add((GstBin*)pipeline, sink)) {
//error
return;
}
[...]
GstBus* bus = gst_pipeline_get_bus(pipeline);
gst_bus_add_watch(bus, (GstBusFunc)bus_callback, this);
gst_object_unref(bus);
GstStateChangeReturn state = gst_element_set_state((GstElement*)pipeline, GST_STATE_PLAYING);
if(!state) {
//error2
return;
}
[...]
Although errors appear in the cout I would like to retrieve the errors as a C string (or any format that I can process). How do I do that?
I have read that errors are posted to the bus of the pipeline, yet when calling gst_element_set_state my bus callback isn't called. Maybe because the glib main loop is not running yet?
Sorry, I am pretty new to the gstreamer/glib libraries and I couldn't find a clear answer in the (overwhelming) documentation.
One solution is to set a listener which receives messages and checks for errors. Example: http://gstreamer.freedesktop.org/data/doc/gstreamer/head/manual/html/chapter-helloworld.html. (GError is the data type used for errors.)
Related
I'm trying to use the Leadtools API version 21 for automatically scanning some documents and here is a sudo code of what I have done (it runs in a secondary thread and the unlock has been done in the main thread):
void CheckRetCode(int rc)
{
if (SUCCESS != rc)
{
L_TCHAR errMsg[1024];
memset(errMsg, 0, sizeof(errMsg));
L_GetFriendlyErrorMessage(rc, errMsg, 1024, L_FALSE);
throw TLeadException(errMsg, rc);
}
}
void OnThreadExecute(void)
{
HTWAINSESSION hSession = nullptr;
APPLICATIONDATA appData;
L_INT nRet;
L_TCHAR pszTwnSourceName[1024];
LTWAINSOURCE sInfo;
memset(&appData, 0, sizeof(APPLICATIONDATA));
appData.uStructSize = sizeof(APPLICATIONDATA);
appData.hWnd = hWnd;// hWnd is valid handle of my main window
appData.uLanguage = TWLG_ENGLISH_USA;
appData.uCountry = TWCY_USA;
wcscpy(appData.szManufacturerName, L"MyCompanyName");
wcscpy(appData.szAppProductFamily, L"MyProductName");
wcscpy(appData.szAppName, appData.szAppProductFamily);
wcscpy(appData.szVersionInfo, L"Version 0.1.0.1");
nRet = L_TwainInitSession2(&hSession, &appData, LTWAIN_INIT_MULTI_THREADED);
CheckRetCode(nRet);// the exception gets catched elsewhere but no error reported here
memset(pszTwnSourceName, 0, sizeof(pszTwnSourceName));
wcscpy(pszTwnSourceName, L"EPSON Artisan837/PX830"); // the name of the scanner is verifyed
sInfo.uStructSize = sizeof(LTWAINSOURCE);
sInfo.pszTwainSourceName = pszTwnSourceName;
CheckRetCode(L_TwainSelectSource(hSession, &sInfo)); // No error reported here
CheckRetCode(L_TwainStartCapsNeg(hSession)); // in here I get the return value -84 which is reported as "TWAIN DS or DSM reported error, app shouldn't (no need for your app to report the error)."
// the rest of the code but we cannot get there since above code reports error
}
Can anyone tell me what I'm doing wrong? Is there a step that I'm missing here?
EditThe function L_TwainSelectSource() make no effort to make sure the supplied source is valid and does not even return an error. As result, if you set the selected source to a garbage name, it will act as if it accepted it. From that point on if you try to Get/Set anything or try to acquire an image, every function returns -84.
Thank you
Sam
To test your code, I put the main window’s handle in a global variable:
globalhWnd = hWnd;
And modified your function to use that handle like this:
void OnThreadExecute(void *)
{
...
appData.hWnd = globalhWnd; // hWnd is valid handle of my main window
...
}
Then created a thread for it from the main program like this:
globalhWnd = hWnd;
_beginthread(OnThreadExecute, 0, 0);
I tried this with 5 different Twain sources: 2 virtual and 3 physical scanners (one of them an old Epson). All 5 drivers returned SUCCESS when calling L_TwainStartCapsNeg() from within the thread.
Two possibilities come to mind:
The problem might be caused by something else in your code other than the thread function.
Or the problem could be specific to your Twain driver.
To rule out the first possibility, I suggest creating a small test project that only creates a similar thread and does nothing else and trying it with different scanners. If it causes the same problem with all scanners, send that test project (not your full application) to support#leadtools.com and our support engineers with test it for you.
If the problem only happens with a specific Twain driver, try contacting the scanner’s vendor to see if they have an updated driver.
I am trying to build a DLL that reads Raw input, processes the data, and streams it to a client application that consumes this DLL. Both my DLL, and client application will be running in the background, or in the system tray. To achieve this behavior, I plan to use events. While I was trying to learn about the right approach to do this, I found conflicting guidance online and had trouble differentiating between these, and picking the right approach.
This article on event handling in native C++ suggests to setup an event source and event receiver using the event_source and event_receiver attributes. Though this approach might work in my situation, This documentation on event handling informs that event handling, though supported for native C++, is deprecated and will not be supported in future releases. This implies that I should not be using this approach. At the same time, This documentation on handling COM events looks like one potentially correct approach. I however am not able to fully understand the code here. Are there better examples or documentation that I could learn from?
Finally, This article on using C++ events in CLI discusses what I understand is a slightly different approach. The code below shows my approach for registering for input from a Precision Touchpad. I want to then override the WindowProc callback function to read input in the background. Finally, I want my DLL to raise my own events when a touch begins, is in progress, and ends. An application (running in the background) consuming this DLL should then be able to listen for the events I raise, and perform actions.
What is the right, and non-deprecated approach to fire events in a C++ DLL, and handle it in the client?
My Code
// skipping headers and error handeling for brevity.
static std::vector<RAWINPUTDEVICELIST> getRawInputDevices()
{
std::vector<RAWINPUTDEVICELIST> devices(64);
while (true) {
UINT numDevices = devices.size();
UINT ret = GetRawInputDeviceList(&devices[0], &numDevices, sizeof(RAWINPUTDEVICELIST));
if (ret != (UINT)-1) {
devices.resize(ret);
return devices;
}
else if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
devices.resize(numDevices);
}
else {
throw win32_error();
}
}
}
static RID_DEVICE_INFO getDeviceInfo(HANDLE HDevice)
{
RID_DEVICE_INFO info;
info.cbSize = sizeof(RID_DEVICE_INFO);
UINT deviceSize;
deviceSize = sizeof(RID_DEVICE_INFO);
if (GetRawInputDeviceInfo(HDevice, RIDI_DEVICEINFO, &info, &deviceSize) == -1)
{
throw win32_error();
}
return info;
}
bool isPrecisionTouchAvailable()
{
bool isDigitizerAvailable = false;
std::vector<RAWINPUTDEVICELIST> devices = getRawInputDevices();
for (std::size_t i = 0; i < devices.size(); ++i)
{
RID_DEVICE_INFO info = getDeviceInfo(devices[i].hDevice);
if (info.dwType == RIM_INPUT && info.hid.usUsagePage == HID_USAGE_PAGE_DIGITIZER && info.hid.usUsage == HID_USAGE_DIGITIZER_TOUCH_PAD)
{
isDigitizerAvailable = true;
break;
}
else {
isDigitizerAvailable = false;
}
}
return isDigitizerAvailable;
}
bool registerTouchpadForInput()
{
bool registrationStatus = false;
bool precisionTouchStatus = isPrecisionTouchAvailable();
if (isPrecisionTouchAvailable != 0)
{
return registrationStatus;
}
else {
RAWINPUTDEVICE rid[1]; //one for precision touch when application is in background. Array because I plan to register for more devices like keyboard once I get things working.
rid[0].usUsagePage = HID_USAGE_PAGE_DIGITIZER; // for touchpad
rid[0].usUsage = HID_USAGE_DIGITIZER_TOUCH_PAD; // usage ID for touchpad
rid[0].dwFlags = RIDEV_INPUTSINK; //to receive events even in the background.
if (RegisterRawInputDevices(rid, 1, sizeof(rid[0])) == false)
{
GetLastError();
//throw "error registering touchpad to get data.";
}
else { registrationStatus = true; }
}
return registrationStatus;
}
When my application launches, I want to call registerTouchpadForInput and let the user know that they will not be able to use my application if they do not have a Precision Touchpad on their device.
Even to develop a simple application, the existing examples in Openthread are complex to refer. Can anybody provide a list of steps to use Openthread "mdt/fdt library" and develop a simple application, from where a CoAP message can be sent or received ? Following is what I have written, but it is not running properly and crashing at times. I have linked "fdt, posix, mbedtls, libcrypto" etc libraries and able to build the application successfully.
instance = otInstanceInitSingle();
otError err = otIp6SetEnabled(instance, true);
if(err == OT_ERROR_NONE)
{
err = otCoapStart(instance, OT_DEFAULT_COAP_PORT);
pthread_t thread_id;
pthread_create(&thread_id, NULL, OTProcessThread, NULL); // To call otTaskletsProcess(instance);
return OK;
}
else{
std::cout << "Init Status: " << err << "\n";
}
The thread looks like the following. I this is a sample code, so I have not given any sleep/signal in the thread at present.
void *OTProcessThread(void *vargp)
{
printf("\nOTProcessThread started..");
while (true)
{
otTaskletsProcess(instance);
//otSysProcessDrivers(instance);
}
}
With this initialization process, I am trying to send a message as follows. But after that the application is crashing somewhere inside the Openthread code.
message = otCoapNewMessage(instance, NULL);
otCoapMessageInit(message, coapType, coapCode);
otCoapMessageGenerateToken(message, 8);
otCoapMessageAppendUriPathOptions(message, uri.c_str());
//otMessageAppend(message, NULL, 0);
otError status = otCoapSendRequest(instance, message, &messageInfo, &HandleResponse, this);
Can somebody please let me know, what exactly I am missing ?
While I can't speak to your specific issue without greater visibility, here are some resources you may find helpful:
https://github.com/openthread/ot-rtos
https://codelabs.developers.google.com/codelabs/openthread-apis/
https://www.nordicsemi.com/Software-and-tools/Software/nRF5-SDK-for-Thread-and-Zigbee
I'm implementing gstreamer media player with my own source of data using appsrc. Everything works fine except one thing:
When stream reaches it's end, callback emits "end-of-stream" signal. Signals sending fucntion g_signal_emit_by_name(appsrc, "end-of-stream", &ret) returns GstFlowReturn value GST_FLOW_OK. But then it calls need-data my callback again, so it returns "end-of-stream" signal again. And this time GstFlowReturn value is (-3) which is GST_FLOW UNEXPECTED. I assume that it does not expect "end-of-stream" signal when it already recieved one, but why it requests more data than? Maybe it is because I didn't set size value iof the steam?
Gstreamer version is 0.10.
Callback function code (appsrc type is seekable btw):
static void cb_need_data (GstElement *appsrc, guint size, gpointer user_data)
{
GstBuffer *buffer;
GstFlowReturn ret;
AppsrcData* data = static_cast<AppsrcData*>(user_data);
buffer = gst_buffer_new_and_alloc(size);
int read = fread(GST_BUFFER_DATA(buffer), 1, size, data->file);
GST_BUFFER_SIZE(buffer) = read;
g_signal_emit_by_name (appsrc, "push-buffer", buffer, &ret);
if (ret != GST_FLOW_OK) {
/* something wrong, stop pushing */
g_printerr("GST_FLOW != OK, return value is %d\n", ret);
g_main_loop_quit (data->loop);
}
if(feof(data->file) || read == 0)
{
g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
if (ret != GST_FLOW_OK) {
g_printerr("EOF reached, GST_FLOW != OK, return value is %d\nAborting...", ret);
g_main_loop_quit (data->loop);
}
}
}
You should provide some corrections to your code(if they are not there already) that should alleviate your issue and help the overall application:
Never try and send a buffer without first checking if it actually has data. So, simply check the buffer data and length to make sure that the data is not NULL and that the length is >0
You can flag that a stream is ended in your user_data. When you send your EOS, set an item in your userdata to indicate that it has been sent and if the appsrc requests more data, simply check if it has been sent and then do not send anything else to the buffer.
Listen for the EOS on your pipeline bus so that it can destroy the stream and close the loop when the EOS message is handled so that you can be sure that your mediasink has received the EOS and you can safely dispose of the pipeline and loop without losing any data.
Have you tried the method gst_app_src_end_of_stream()? I'm not sure what return code you should use after invoking it, but it should be either GST_FLOW_OK or GST_FLOW_UNEXPECTED.
In GStreamer 1.x you return GST_FLOW_EOS.
I am writing a GStreamer application (GStreamer uses DirectShow under the hood on Windows) that captures a computer's microphone and videocamera. It works fine, but requires me to specify the device names manually. I would like to have my program detect these automatically. Does anyone know how to do that?
It would surprise me if GStreamer doesn't have capabilities to enumerate devices, but DirectShow definitely has.
See the article on using the system device enumerator and use it with the correct filter categories - in your case CLSID_AudioInputDeviceCategory and CLSID_VideoInputDeviceCategory.
You should use GStreamer's probing interface which allows you to list all possible values for a given property, in your case 'device-name'.
Here is an example:
GList*
gst_camera_capturer_enum_devices(gchar* device_name)
{
GstElement* device;
GstPropertyProbe* probe;
GValueArray* va;
GList* list=NULL;
guint i=0;
device = gst_element_factory_make (device_name, "source");
gst_element_set_state(device, GST_STATE_READY);
gst_element_get_state(device, NULL, NULL, 5 * GST_SECOND);
if (!device || !GST_IS_PROPERTY_PROBE(device))
goto finish;
probe = GST_PROPERTY_PROBE (device);
va = gst_property_probe_get_values_name (probe, "device-name");
if (!va)
goto finish;
for(i=0; i < va->n_values; ++i) {
GValue* v = g_value_array_get_nth(va, i);
list = g_list_append(list, g_string_new(g_value_get_string(v)));
}
g_value_array_free(va);
finish:
{
gst_element_set_state (device, GST_STATE_NULL);
gst_object_unref(GST_OBJECT (device));
return list;
}
}
GList*
gst_camera_capturer_enum_video_devices(void)
{
return gst_camera_capturer_enum_devices("dshowvideosrc");
}
GList*
gst_camera_capturer_enum_audio_devices(void)
{
return gst_camera_capturer_enum_devices("dshowaudiosrc");
}