GStreamer - Sample Plugin - plugins

I am a newbie in gstreamer and trying to develop a sample plugin for captions decoding.
I have downloaded the gStreamer Plugin template: based on this information.
When I launched the plugin from command line, it is working fine.
I wrote a sample application to verify the plugin. But now, I am facing a problem in setting pipeline state to PLAYING. Below is the code snippet
Any inputs would be of great help.
Thanks in advance,
Kranti
gst_init(NULL, NULL);
loop = g_main_loop_new (NULL, TRUE);
g_print("\n Gstreamer is Initialized and Created the loop ");
pipeline = gst_pipeline_new ("pipeline");
source = gst_element_factory_make ("filesrc", "source");
filter = gst_element_factory_make ("myfilter", "testfilter");
sink = gst_element_factory_make ("fakesink", "sink");
if((NULL != pipeline) && (NULL != source) && (NULL != filter) && (NULL != sink))
{
g_print("\n Successfully created the factory elements ");
g_object_set(G_OBJECT (source), "location", fileName, NULL);
g_print("\n Set the file name \n");
g_object_set(G_OBJECT (filter), "silent", 1, NULL);
g_print("\n Set the silent type \n");
/* we add a message handler */
bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
bus_watch_id = gst_bus_add_watch (bus, bus_call, loop);
gst_object_unref (bus);
g_print("\n Created bus and a monitor to watch it");
gst_bin_add_many(GST_BIN(pipeline), source, filter, sink, NULL);
gst_element_link_many(source, filter, sink);
g_print("\n Added and Linked the factory elements");
g_signal_connect (filter, "pad-added", G_CALLBACK (on_pad_added), filter);
g_print ("Now reading: %s\n", "test.txt");
g_print ("Setting the pipeline state to PLAYING ");
ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
if(ret == GST_STATE_CHANGE_FAILURE)
{
g_print("\n Failure in setting pipeline state to PLAYING \n");
}
else
{
g_print("\n Successfully set the pipeline state to playing \n");
}
}
else
{
g_print("\n Failure in creating factory elements");
}

After trying with few examples on gstreamer elements, found the problem.
Apart from filesrc, filter, fakesink:: If I add 'decoder' element also to the pipeline, then I am able to change the state to PLAYING
But why is that required - I am still trying to figure it out
And sometimes, the name used to create pipeline is also causing problems: Better to use some unique name rather than pipeline in gst_pipeline_new ("pipeline");

Related

Gstreamer splitmuxsink callback when a new file is created

I have a gst pipeline for recording video with splitmuxsink set to create new file every hour. I would like to have some callback when the new file is created.
I have tried
GstElement *sink = gst_element_factory_make ("splitmuxsink", "sink");
g_object_set (sink, "max-size-bytes", 4294967295, NULL);
g_object_set (sink, "max-size-time", 3600000000000, NULL); // 3600000000000 - 1 hour
g_signal_connect (sink, "split-now",G_CALLBACK(split_now_callback_test), &data);
However i found out, that "split-now" is signal which I can pass to the splitmuxsink and not the other way around. Is there a relatively easy way to have some callback a new target file is created?
There is a message that is emitted by the splitmuxsink element when it opens or closes a new fragment: "splitmuxsink-fragment-opened" or "splitmuxsink-fragment-closed". I found these messages in the splitmuxsink source code (search for the gst_element_post_message function call to see where the message is sent).
Here's an SO question about of listening for element messages (from the multifilesink element, which is very similar to the splitmuxsink element). In particular, see this gist from the OP on that question for an example of how to implement this in C.
I didn't validate that the approach above works in C, as I used this splitmuxsink message in a Rust implementation of the pipeline, but I think the general idea, translated to C, is something like this (adapted from GStreamer basic tutorial #3):
/* Listen to the bus */
bus = gst_element_get_bus (data.pipeline);
do {
msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE,
GST_MESSAGE_ELEMENT | GST_MESSAGE_ERROR | GST_MESSAGE_EOS);
/* Parse message */
if (msg != NULL) {
GError *err;
gchar *debug_info;
switch (GST_MESSAGE_TYPE (msg)) {
case GST_MESSAGE_ERROR:
gst_message_parse_error (msg, &err, &debug_info);
g_printerr ("Error received from element %s: %s\n", GST_OBJECT_NAME (msg->src), err->message);
g_printerr ("Debugging information: %s\n", debug_info ? debug_info : "none");
g_clear_error (&err);
g_free (debug_info);
terminate = TRUE;
break;
case GST_MESSAGE_EOS:
g_print ("End-Of-Stream reached.\n");
terminate = TRUE;
break;
case GST_MESSAGE_ELEMENT:
/* Handle element-specific message here */
break;
default:
/* We should not reach here */
g_printerr ("Unexpected message received.\n");
break;
}
gst_message_unref (msg);
}
} while (!terminate);
For more info on element messages and the GstBus, see this page of the GStreamer docs

BizTalk custom pipeline parsing POP3 PDF attachment error

I have a BizTalk custom pipeline component where I'm parsing a PDF attachment using itexsharp into a custom model. The pipeline is bound to a POP3 receiving port.
In the new created message if I return the attachment stream (outputMessage.GetPart("Body").Data = ms), then this is looking good in the BizTalk administration console. I have been able to save the message from here manually and this was parsed correctly using the same parsing method as in the pipeline.
When parsing the PDF directly in the pipeline, then I'm getting the following error: Rebuild failed: trailer not found.; Original message: xref subsection not found at file pointer 1620729
If I remove the default XMLDisassembler component from pipeline, then the parsing error disappeared, but in the console the message Body is empty, although the AttachmentSizeInBytes=1788
public IBaseMessage Execute(IPipelineContext pContext, IBaseMessage pInMsg)
{
return ExtractMessagePartToMessage(pContext, pInMsg);
}
private IBaseMessage ExtractMessagePartToMessage(IPipelineContext pContext, IBaseMessage pInMsg)
{
if (pInMsg.PartCount <= 1)
{
throw new InvalidOperationException("The email had no attachment, apparently.");
}
string partName;
IBaseMessagePart attachmentPart = pInMsg.GetPartByIndex(1, out partName);
Stream attachmentPartStream = attachmentPart.GetOriginalDataStream();
IBaseMessage outputMessage;
outputMessage = pContext.GetMessageFactory().CreateMessage();
outputMessage.AddPart("Body", pContext.GetMessageFactory().CreateMessagePart(), true);
outputMessage.Context = pInMsg.Context;
var ms = new MemoryStream();
attachmentPartStream.CopyTo(ms);
ms.Seek(0L, SeekOrigin.Begin);
Stream orderStream = PdfFormParser.Parse(ms);
outputMessage.GetPart("Body").Data = orderStream;
outputMessage.Context.Write("AttachmentName", "http://schemas.microsoft.com/BizTalk/2003/file-properties", partName);
outputMessage.Context.Write("AttachmentSizeInBytes", "http://schemas.microsoft.com/BizTalk/2003/file-properties", orderStream.Length.ToString());
pContext.ResourceTracker.AddResource(ms);
pContext.ResourceTracker.AddResource(orderStream);
return outputMessage;
}
public static Stream Parse(Stream pdfDocument)
{
using (var reader = new PdfReader(pdfDocument))
{
var outputStream = new MemoryStream();
var pdfForm = ParseInternal(reader);
var xmlDocument = new XmlDocument();
xmlDocument.LoadXml(pdfForm.Serialize());
xmlDocument.Save(outputStream);
return outputStream;
}
In pipelines when you read or write a Stream, you have to rewind the stream back to the beginning if something else is going to use it (especially the final message that you expect BizTalk to process).

Eclipse plugin - getting the IStackframe object from a selection in DebugView

So, this is the problem I am stuck at for a few weeks.
I am developing an Eclipse plugin which fills in a View with custom values depending on a particular StackFrame selection in the Debug View.
In particular, I want to listen to the stackframe selected and would like to get the underlying IStackFrame object.
However, I have tried more than a dozen things and all of them have failed. So I tried adding DebugContextListener to get the DebugContextEvent and finally the selection. However, the main issue is that ISelection doesn't return the underlying IStackFrame object. It instead returns an object of type AbstractDMVMNode.DMVMContext. I tried getting an adapter but that didn't work out too. I posted this question sometime back also:
Eclipse Plugin Dev- Extracting IStackFrame object from selection in Debug View
Since then, I have tried out many different approaches. I tried adding IDebugEventSetListener (but this failed as it cannot identify stack frame selection in the debug view).
I tried adding an object contribution action but this too was pointless as it ultimately returned me an ISelection which is useless as it only returns me an object of class AbstractDMVMNode.DMVMContext and not IStackframe.
Moreover, I checked out the implementation of the VariablesView source code itself in the org.eclipse.debug.ui plugin. It looks like a few versions back (VariablesView source code in version 3.2), the underlying logic was to use the ISelection and get the IStackFrame. All the other resources on the internet also advocate the same. However, now, this scheme no longer works as ISelection doesn't return you an IStackFrame. Also, the source code for the latest eclipse Debug plugin (which doesn't use this scheme) was not very intuitive for me.
Can anyone tell how I should proceed ? Is hacking the latest Eclipse source code for VariablesView my only option ? This doesn't look like a good design practice and I believe there should be a much more elegant way of doing this.
PS: I have tried all the techniques and all of them return an ISelection. So, if your approach too return the same thing, then it is most likely incorrect.
Edit (Code snippet for trying to adapt the ISelection):
// Following is the listener implemnetation
IDebugContextListener flistener = new IDebugContextListener() {
#Override
public void debugContextChanged(DebugContextEvent event) {
if ((event.getFlags() & DebugContextEvent.ACTIVATED) > 0) {
contextActivated(event.getContext());
}
};
};
// Few things I tried in the contextActivated Method
//Attempt 1 (Getting the Adapter):
private void contextActivated(ISelection context) {
if (context instanceof StructuredSelection) {
Object data = ((StructuredSelection) context).getFirstElement();
if( data instanceof IAdaptable){
System.out.println("check1");
IStackFrame model = (IStackFrame)((IAdaptable)data).getAdapter(IStackFrame.class);
if(model != null){
System.out.println("success" + model.getName());
}
}
}
}
// Attemp2 (Directly getting it from ISelection):
private void contextActivated(ISelection context) {
if (context instanceof StructuredSelection) {
System.out.println("a");
Object data = ((StructuredSelection) context).getFirstElement();
if (data instanceof IStackFrame) {
System.out.println("yes");
} else {
System.out.println("no" + data.getClass().getName());
}
}
// This always execute the else and it prints: org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMNode.DMVMContext
}
// Attemp3 (Trying to obtain it from the viewer (similiar to object action binding in some ways):
private void contextActivated(ISelection context) {
VariablesView variablesView = (VariablesView) PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().findView(IDebugUIConstants.ID_VARIABLE_VIEW);
if (variablesView != null) {
Object input = ((TreeViewer) variablesView.getViewer()).getInput();
if(input != null) System.out.println(input.getClass().getName());
if (input instanceof IStackFrame) {
System.out.println("success");
} else if (input instanceof IThread) {
System.out.println("success");
try {
IStackFrame[] stackFrames = ((IThread) input).getStackFrames();
for (IStackFrame iStackFrame : stackFrames) {
printVariables(iStackFrame);
}
} catch (DebugException e) {
e.printStackTrace();
}
}
}
}
While I am building this view to work with both JDT & CDT, I am testing it out on the C project. So, this might be the reason why I always get the returned object type as AbstractDMVMNode.DMVMContext. Should my implementation be different to handle both these cases ? I believe I should be building a generic view. Also, if AbstractDMVMNode.DMVMContext is CDT specific, I should I go about implementing it for the CDT case?

Eclipse plugin - how to run external class

I want to make a plugin for Eclipse. The thing is that I looked into the API, and examples, and I managed to make a button on main bar, with a specific icon, and when I click it, open up an InputDialog.
The hard part, is that I want to start an aplication from this button, but not with Runtime as it was a new process. I simply want to start a class inside plugin, which will log in to a server and get some output from it. I want it to be opened in a console, like launching a normal application, or a separate console.
The best example of this kind is a Tomcat plugin which starts Tomcat, and then outputs the console to the Eclipse console. I want to do that too. I've looked at the Tomcat source plugin, but I got stuck there too. They use their own launcher.
I am not sure what you mean by "I want to simply start a class". I assume there is a command line tool that you want to execute and redirect its output to the console window.
To be able to do that without spawning a new process, you have to be able to control the output stream of the tool. If it cannot be controlled, then you have no choice but to start a new process to properly capture the tool's output.
It is technically possible to call System.setOut instead, but it will redirect output from all threads to your console which is not what you want.
Nevertheless you start by creating a console:
// function findConsole copied from:
// http://wiki.eclipse.org/FAQ_How_do_I_write_to_the_console_from_a_plug-in%3F
private MessageConsole findConsole(String name) {
ConsolePlugin plugin = ConsolePlugin.getDefault();
IConsoleManager conMan = plugin.getConsoleManager();
IConsole[] existing = conMan.getConsoles();
for (int i = 0; i < existing.length; i++)
if (name.equals(existing[i].getName()))
return (MessageConsole) existing[i];
//No console found, so create a new one.
MessageConsole myConsole = new MessageConsole(name, null);
conMan.addConsoles(new IConsole[]{myConsole});
return myConsole;
}
// Find my console
MessageConsole cons = findConsole("MyTool Console");
MessageConsoleStream out = cons.newMessageStream();
// Optionally get it's input stream so user can interact with my tool
IOConsoleInputStream in = cons.getInputStream();
// Optionally make a differently coloured error stream
MessageConsoleStream err = cons.newMessageStream();
err.setColor(display.getSystemColor(SWT.COLOR_RED));
// Display the console.
// Obtain the active page. See: http://wiki.eclipse.org/FAQ_How_do_I_find_the_active_workbench_page%3F
IWorkbenchPage page = ...;
String id = IConsoleConstants.ID_CONSOLE_VIEW;
IConsoleView view = (IConsoleView) page.showView(id);
view.display(cons);
Then set the input and output streams of my tool and start processing in a different thread so the UI will not block.
// Create my tool and redirect its output
final MyTool myTool = new MyTool();
myTool.setOutputStream(out);
myTool.setErrorStream(err);
myTool.setInputStream(in);
// Start it in another thread
Thread t = new Thread(new Runnable() {
public void run() {
myTool.startExecuting();
}
});
t.start();
If your tool does not support I/O redirection, you have no choice but to start it in another process with the ProcessBuilder and use a number of threads to move data between console and process streams See: Process.getInputStream(), Process.getOutputStream() and Process.getErrorStream().
The following links have additional useful details:
Executing a Java application in a separate process
FAQ How do I write to the console from a plug-in?
FAQ How do I find the active workbench page?
This is the code for running a new console with controls, like stop delete, and deleteAll! This is what I asked for in the beginning, but the message console is good to know!
ILaunchConfigurationType launchType = DebugPlugin.getDefault().getLaunchManager().getLaunchConfigurationType("org.eclipse.jdt.launching.localJavaApplication");
ILaunchConfigurationWorkingCopy config = null;
try {
config = launchType.newInstance(null, "My Plugin working");
} catch (CoreException e) {
System.err.println(e.getMessage());
}
config.setAttribute(ILaunchConfiguration.ATTR_SOURCE_LOCATOR_ID, "org.eclipse.jdt.launching.sourceLocator.JavaSourceLookupDirector");
String[] classpath = new String[] { "C:\\Users\\Administrator\\Documents\\myjr.jar" };
ArrayList classpathMementos = new ArrayList();
for (int i = 0; i < classpath.length; i++) {
IRuntimeClasspathEntry cpEntry = JavaRuntime.newArchiveRuntimeClasspathEntry(new Path(classpath[i]));
cpEntry.setClasspathProperty(IRuntimeClasspathEntry.USER_CLASSES);
try {
classpathMementos.add(cpEntry.getMemento());
} catch (CoreException e) {
System.err.println(e.getMessage());
}
}
config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_DEFAULT_CLASSPATH, false);
config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_CLASSPATH, classpathMementos);
config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, "collectorlog.handlers.MyClass");
try {
ILAUNCH = config.launch(ILaunchManager.RUN_MODE, null);
} catch (CoreException e) {
System.err.println(e.getMessage());
}

Eclipse RCP p2 update not working

I have a personal Eclipse RCP product (com.example.product) based on one personal feature (com.example.feature) which is composed of one personal plugin (com.example.plugin) and a bunch of others from Eclipse Helios (3.6). I want the app to check for updates and update itself if necessary from a p2 site. I want it to be headless, ie the user does not interact in the update process, but may see progress in a dialog.
I based my implementation for the updates on the RCP Mail application. I changed the P2Util.checkForUpdates method a bit to include some logging so I can see what, if anything, is going wrong there:
static IStatus checkForUpdates(IProvisioningAgent agent,
IProgressMonitor monitor) throws OperationCanceledException,
InvocationTargetException {
ProvisioningSession session = new ProvisioningSession(agent);
UpdateOperation operation = new UpdateOperation(session);
SubMonitor sub = SubMonitor.convert(monitor,
"Checking for application updates...", 200);
IStatus status = operation.resolveModal(sub.newChild(100));
if (status.getCode() == UpdateOperation.STATUS_NOTHING_TO_UPDATE) {
return status;
}
if (status.getSeverity() == IStatus.CANCEL)
throw new OperationCanceledException();
if (status.getSeverity() != IStatus.ERROR) {
try {
logger.info( "Status is " + status );
Update[] updates = operation.getPossibleUpdates();
for( Update u : updates){
logger.info( "Update is " + u );
}
ProvisioningJob job = operation.getProvisioningJob(null);
if( job == null ){
logger.error( "Provisioning Job is null" );
}
status = job.runModal(sub.newChild(100));
if (status.getSeverity() == IStatus.CANCEL) {
throw new OperationCanceledException();
}
} catch ( Exception e ){
logger.error( "Exception while trying to get updates", e);
}
}
return status;
}
I have a p2.inf file in my feature at the same level as my example.product file. It contains:
org.eclipse.equinox.p2.touchpoint.eclipse.addRepository":
instructions.configure=\
org.eclipse.equinox.p2.touchpoint.eclipse.addRepository(type:0,location:file${#58}/C${#58}/workspace/updatesite/);\
org.eclipse.equinox.p2.touchpoint.eclipse.addRepository(type:1,location:file${#58}/C${#58}/workspace/updatesite/);
I build the product with plugin, feature and product IDs set to 1.0.0.
I can export and run my product from eclipse using the product export wizard. I tick generate metadata repository when I do this.
I create my update site using the Create an Update Site Project option in the Feature Manfiest Editor. I add my `com.example.feature' and build it. Just to see if it works I try browsing it via eclipse IDE Install New Software option and I can see the feature there.
I build the update site with all 3 IDs changed to 1.0.1. When I start the app it says there are no updates to install, there are no errors in the logs.
I don't know why it doesn't update from the update site, but things that have crossed my mind are:
1) I may need more info in the p2.inf file, but I'm not sure what, maybe something like namespace, name and range, but I can't find a good practical example.
2) In the checkForUpdates method I may need to do something with profiles to change what installable units are being updated. Again, I only found comments hinting at this and not any example code that shows how.
Any hints or ideas are much appreciated here, this is eating a lot of time.
Look at this code. Rebuild your product with a new product version and try to setup a http server. It didnt work with file repo for me. Just publishing the feature will not work.
final IRunnableWithProgress runnable = new IRunnableWithProgress() {
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
sub = SubMonitor.convert(monitor, Messages.getString("UpdateManager.searchforupdates"), 200); //$NON-NLS-1$
final Update update = getUpdate(profile, provisioningContext, engine, context);
status = operation.resolveModal(sub.newChild(100));
LogHelper.log(status);
if (status.getCode() == UpdateOperation.STATUS_NOTHING_TO_UPDATE) {
status = null;
return;
}
if (status.getSeverity() == IStatus.CANCEL)
throw new OperationCanceledException();
if (status.getSeverity() != IStatus.ERROR) {
log(IStatus.INFO, "Checking for available update matches", null); //$NON-NLS-1$
Update[] selected = new Update[1];
operation.setSelectedUpdates(new Update[0]);
for (Update available : operation.getPossibleUpdates()) {
if (available.equals(update)) {
log(IStatus.INFO, "Update matches available: " + update, null); //$NON-NLS-1$
selected[0] = available;
operation.setSelectedUpdates(selected);
}
}
if (selected[0] == null) {
status = null;
monitor.setCanceled(true);
log(IStatus.WARNING, "No Update matches selected", null); //$NON-NLS-1$
return;
}
ProvisioningJob job = operation.getProvisioningJob(monitor);
if (job != null) {
status = job.runModal(sub.newChild(100));
if (status.getSeverity() != IStatus.ERROR) {
prefStore.setValue(JUSTUPDATED, true);
Display.getDefault().syncExec(new Runnable() {
public void run() {
PlatformUI.getWorkbench().restart();
}
});
} else {
LogHelper.log(status);
}
} else {
log(IStatus.INFO, "getJob returned null", null); //$NON-NLS-1$
status = null;
}
if (status != null && status.getSeverity() == IStatus.CANCEL)
throw new OperationCanceledException();
}
}
};
Display.getDefault().asyncExec(new Runnable() {
public void run() {
try {
new ProgressMonitorDialog(null).run(true, true, runnable);
} catch (InvocationTargetException x) {
log(IStatus.ERROR, "Runnable failure", x); //$NON-NLS-1$
} catch (InterruptedException e) {
}
}
});
#user473284's answer had some suggestions that I used but I don't know if they were definite requirements
1) using a local web server instead of trying to point to a file
2) Incrementing the product version and using the update repository generated by the export product wizard.
I never did find the implementation for the getUpdate method referenced from the code sample so I couldn't make use of the snippet.
After the above changes I was still left with the app detecting no updates on startup. Debugging showed that my repository was not showing up in the session. I had to explicitly add the update url in the code, despite having it in the p2.inf and in set in the feature manifest editor form field. Here's the code for this:
public static void addUpdateSite(IProvisioningAgent provisioningAgent)
throws InvocationTargetException {
// Load repository manager
IMetadataRepositoryManager metadataManager = (IMetadataRepositoryManager) provisioningAgent
.getService(IMetadataRepositoryManager.SERVICE_NAME);
if (metadataManager == null) {
logger.error( "Metadata manager was null");
Throwable throwable = new
Throwable("Could not load Metadata Repository Manager");
throwable.fillInStackTrace();
throw new InvocationTargetException(throwable);
}
// Load artifact manager
IArtifactRepositoryManager artifactManager = (IArtifactRepositoryManager) provisioningAgent
.getService(IArtifactRepositoryManager.SERVICE_NAME);
if (artifactManager == null) {
logger.error( "Artifact manager was null");
Throwable throwable = new Throwable(
"Could not load Artifact Repository Manager");
throwable.fillInStackTrace();
throw new InvocationTargetException(throwable);
}
// Load repo
try {
URI repoLocation = new URI("http://localhost/respository");
logger.info( "Adding repository " + repoLocation );
metadataManager.loadRepository(repoLocation, null);
artifactManager.loadRepository(repoLocation, null);
} catch (ProvisionException pe) {
logger.error( "Caught provisioning exception " + pe.getMessage(), pe);
throw new InvocationTargetException(pe);
} catch (URISyntaxException e) {
logger.error( "Caught URI syntax exception " + e.getMessage(), e);
throw new InvocationTargetException(e);
}
}
I now call this first thing in the checkForUpdates method from the original question. After this change my app at least now sees the update and attempts to install it. I'm still having problem but that deserves a separate question of its own which I've created at https://stackoverflow.com/questions/3944953/error-during-p2-eclipse-rcp-app-headless-update
Web server is not mandatory, you can get updates with file location.
It is mandatory to change product version too.
You can't update those features with Update Site Project build which are exported with product, however you can do that with some hacking in exported product.
If you add some other features with (Install New Softwares) option then you can update these features with Update Site Project build.
Hopefully this will be helpful. If you need more clarification you can ask.