Directshow GMFBridge saving multiple clips to a single file - vb.net

Here is the main body of code that I am using with GMFBridge. I have an sg (sourcegraph) and rg (rendergraph) object that keeps the filtergraph, mediaseeking, etc., in the one place so I can release them.
When I run this it renders the clips to the screen perfectly. Seeking to each clip and playing properly. I get the right sequence of event codes in the "Bridge End of Segment" that I expect (i.e. one BEOS message per clip).
However, When I try to write the clips out to an AVI file, I only ever get the first clip. I also only ever get one "Bridge End of Segment" message. The code that is commented out in the "with rg" section is what I use to write to an AVI file. If I check the graphs in GraphEdit they are connected properly.
I have also added the code for the "Bridge End of Segment" message at the bottom.
This is driving me crazy. I must be missing something really simple. Any help appreciated.
' Get the source media file...
If openfile.ShowDialog = Windows.Forms.DialogResult.OK Then
If Bridge Is Nothing Then
Bridge = New GMFBridgeController
Bridge.AddStream(True, eFormatType.eAny, True)
'Bridge.AddStream(False, eFormatType.eMuxInputs, False)
Bridge.SetBufferMinimum(200)
End If
With sg
' Create graph to use.
.graph = New FilterGraph
' Create other interfaces. Don't need them all but am
' experimenting.
.mediacontrol = DirectCast(.graph, IMediaControl)
.mediaseeking = DirectCast(sg.graph, IMediaSeeking)
.mediaeventex = DirectCast(.graph, IMediaEventEx)
.mediaeventex.SetNotifyWindow(Me.Handle, WM_GRAPHNOTIFY, Nothing)
' Create the graphedit entry so I can see what I've made.
.rotentry = New DsROTEntry(.graph)
' If not using bridge comment out this line.
sg.filter = Bridge.CreateSourceGraph(openfile.FileName, sg.graph)
End With
With rg
.graph = DirectCast(New FilterGraph, IFilterGraph2)
.capgraph = New CaptureGraphBuilder2
.capgraph.SetFiltergraph(.graph)
''''' CODE THAT I USE TO WRITE TO AN AVI FILE
'''''Dim aviDest As IBaseFilter = New AviDest()
'''''.graph.AddFilter(aviDest, "AVI Mux")
'''''Dim writer As IBaseFilter = New FileWriter
'''''.graph.AddFilter(writer, "File Writer")
'''''Dim filewriter As IFileSinkFilter2 = DirectCast(writer, IFileSinkFilter2)
'''''filewriter.SetFileName(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\StatsManager\Videos\momtest.avi", Nothing)
' Create the render graph ...
.filter = Bridge.CreateRenderGraph(sg.filter, .graph)
' Ancillary control interfaces...
.mediaseeking = DirectCast(.graph, IMediaSeeking)
.mediacontrol = DirectCast(.graph, IMediaControl)
' Let me see the graph in GraphEdit.
.rotentry = New DsROTEntry(.graph)
End With
' Add my list of offsets...
For Each obj As Object In listOffsets.Items
clipoffsets.Add(Val(obj.ToString))
Next
' How long to play the clips for...
clipplaytime = Val(txtClipTime.Text)
' Just so I know what video I chose.
Me.Text = "Video:" + Path.GetFileName(openfile.FileName)
End If
This is the code that handles the "End of Segment" message.....
Public Sub Bridge_OnEndOfSegment() Handles Bridge.OnEndOfSegment
Try
log("BEOS")
clipindex = clipindex + 1
If clipindex = clipoffsets.Count Then ' this is the proper version :)
log("End of clips")
clipindex = 0
If chkLoop.Checked = False Then
sg.mediacontrol.Stop()
rg.mediacontrol.Stop()
Else
log("....looping")
SeekToClip(clipoffsets(clipindex))
End If
Else
log("Moving to clip:" + clipoffsets(clipindex).ToString)
SeekToClip(clipoffsets(clipindex))
End If
Catch ex As Exception
log("ERROR in EOS :" + ex.Message)
End Try
End Sub

Related

File is in Use VB.NET

I am using VB.NET (VS-2012), I use to scan documents in my applicant software. When i scan document i resize the scanned image and save it over the original file. When the user scan all the required documents then the use click the save button. After clicking the save button the application upload the images to database and try to delete the locally created files but stuck with the error that the file is in use.
I am using the following code...
Tw.Init(Me.Handle)
If (Not msgfilter) Then
Me.Enabled = False
msgfilter = True
Application.AddMessageFilter(Me)
End If
If SelectScanner Then
Tw.Select()
SelectScanner = False
End If
Tw.Acquire(chkScanner.Checked)
This function listens the event triggered by tw.acquire()
Public Function PreFilterMessage(ByRef m As Message) As Boolean Implements IMessageFilter.PreFilterMessage
Try
Dim cmd As TwainCommand = Tw.PassMessage(m)
If (cmd = TwainCommand.Not) Then
Return False
End If
Select Case cmd
Case TwainCommand.CloseRequest
EndingScan()
Tw.CloseSrc()
Case TwainCommand.CloseOk
EndingScan()
Tw.CloseSrc()
Case TwainCommand.DeviceEvent
Case TwainCommand.TransferReady
Dim pics As ArrayList = Tw.TransferPictures()
EndingScan()
Tw.CloseSrc()
For i = 0 To pics.Count - 1 Step 1
flName = TempPath & "\" & GetNextFileName(TempPath, lstDocType.Items(cboDocTypes.SelectedIndex).ToString)
Dim img As IntPtr = CType(pics(i), IntPtr)
SaveImage(img)
lstDocuments.Items.Add(flName)
lstDocType.Items.Add(GetDocType(cboDocTypes.SelectedIndex))
SetItemData(lstDocuments, lstDocuments.Items.Count - 1, GetItemData(lstApplicants, lstApplicants.SelectedIndex))
Try
lstDocuments.SelectedIndex = lstDocuments.Items.Count - 1
Catch ex As Exception
End Try
Dim Original As Image = Image.FromFile(flName)
Dim Resized As Image = ResizeImage(Original, New Size(1024, 1407), False)
Original.Dispose()
Resized.Save(flName, ImageFormat.Jpeg)
Resized.Dispose()
img = Nothing
pics = Nothing
Next
Tw.Dispose()
Case 0
Return False
End Select
Return True
Catch ex As Exception
Return False
MsgBox(ex.Message)
End Try
End Function
In this given function you can see that the image is resized and the original image is replaced with the resized one. And then the resize object is disposed but when the software try to delete the image after uploading it to database, an error occurs.
I don't know whats the problem.

Setting AutoCAD ActiveSpace to ModelSpace VB.NET

I am trying to ensure that I am addressing entities in ModelSpace, but I get an exception that gives no hint at what the problem is because it's a COM object I guess. Does anyone know what I might be doing wrong? If I take out that line (and the zoom extents line) the remaining code works just fine, so I know my document object is being set correctly.
Dim acDWG As AutoCAD.AcadDocument
' open the drawing
acDWG = acApp.Documents.Open(dgvr.Cells("FullName").Value.ToString)
' ensure the drawing has the modelspace tab activated (doesnt work)
acDWG.ActiveSpace = AutoCAD.AcActiveSpace.acModelSpace
' zoom to extents (sometimes works, sometimes not) '
acApp.ZoomExtents()
' build a selectionset of all blocks named 'Solid1' and then delete them all
Dim ss As AutoCAD.AcadSelectionSet = acDWG.SelectionSets.Add("DELETE")
Dim gpCode(1) As Int16
Dim dataValue(1) As Object
gpCode(0) = 0 : dataValue(0) = "Insert"
gpCode(1) = 2 : dataValue(1) = "Solid1"
ss.Select(AutoCAD.AcSelect.acSelectionSetAll,,, gpCode, dataValue)
ss.Erase()
ss.Delete()
ss = Nothing
Update: I discovered why I am getting the error. The code is correct, but the problem is that the drawing has not completed opening yet. If I put a "wait for 5 seconds" line of code directly after the Open line, it works just fine. So it seems my question is how to open the drawing and have VB.Net wait for a signal from the COM object that it is "ready to continue"? (not sure how to word it)
Use a combination of Do...Loop and a Try...Catch block to "wait" like this:
Dim acDWG As AutoCAD.AcadDocument
acDWG = acApp.Documents.Open(dgvr.Cells("FullName").Value.ToString)
Dim bOpen As Boolean = False
Do Until bOpen = True
Try
acDWG.ActiveSpace = AutoCAD.AcActiveSpace.acModelSpace
bOpen = True
Catch ex As Exception
' ignore the error and try again until it is open
End Try
Loop

Printing an external PDF document in VB.net

I know this question has been asked before, but my situation is a bit wonky.
Basically, I'm trying to print a PDF file that I've generated using a previous Windows Form. I can find the file no problem, and I used the following code which I found off MSDN's help forums:
Dim p As New System.Diagnostics.ProcessStartInfo()
p.Verb = "print"
p.WindowStyle = ProcessWindowStyle.Hidden
p.FileName = "C:\534679.pdf" 'This is the file name
p.UseShellExecute = True
System.Diagnostics.Process.Start(p)
So far so good, but everytime I press the button to run this code, it keeps asking me to save it as a PDF file instead, as shown below:
I've also tried adding a PrintDialog to the Windows Form, getting it to pop up, and I can select the printer I want to use from there, but even after selecting the printer it still asks me to print to PDF Document instead.
What am I doing wrong?
To print massive PDF documents with VB.Net you can use LVBPrint and run it via command line:
http://www.lvbprint.de/html/gsbatchprint1.html
For Example:
C:\temp\gsbatchprint64\gsbatchprintc.exe -P \\server\printer -N A3 -O Port -F C:\temp\gsbatchprint64\Test*.pdf -I Tray3
I use the following function in my application:
' print a pdf with lvbrint
Private Function UseLvbPrint(ByVal oPrinter As tb_Printer, fileName As String, portrait As Boolean, sTray As String) As String
Dim lvbArguments As String
Dim lvbProcessInfo As ProcessStartInfo
Dim lvbProcess As Process
Try
Dim sPrinterName As String
If portrait Then
lvbArguments = String.Format(" -P ""{0}"" -O Port -N A4 -F ""{1}"" -I ""{2}"" ", sPrinterName, fileName, sTray)
Else
lvbArguments = String.Format(" -P ""{0}"" -O Land -N A4 -F ""{1}"" -I ""{2}"" ", sPrinterName, fileName, sTray)
End If
lvbProcessInfo = New ProcessStartInfo()
lvbProcessInfo.WindowStyle = ProcessWindowStyle.Hidden
' location of gsbatchprintc.exe
lvbProcessInfo.FileName = LvbLocation
lvbProcessInfo.Arguments = lvbArguments
lvbProcessInfo.UseShellExecute = False
lvbProcessInfo.RedirectStandardOutput = True
lvbProcessInfo.RedirectStandardError = True
lvbProcessInfo.CreateNoWindow = False
lvbProcess = Process.Start(lvbProcessInfo)
'
' Read in all the text from the process with the StreamReader.
'
Using reader As StreamReader = lvbProcess.StandardOutput
Dim result As String = reader.ReadToEnd()
WriteLog(result)
End Using
Using readerErr As StreamReader = lvbProcess.StandardError
Dim resultErr As String = readerErr.ReadToEnd()
If resultErr.Trim() > "" Then
WriteLog(resultErr)
lvbProcess.Close()
Return resultErr
End If
End Using
If lvbProcess.HasExited = False Then
lvbProcess.WaitForExit(3000)
End If
lvbProcess.Close()
Return ""
Catch ex As Exception
Return ex.Message
End Try
End Function
I discourage on using AcrRd32.exe as it doesn't work with massive printings.
First, to be able to select a Printer, you'll have to use a PrintDialog and PrintDocument to send graphics to print to the selected printer.
Imports System.Drawing.Printing
Private WithEvents p_Document As PrintDocument = Nothing
Private Sub SelectPrinterThenPrint()
Dim PrintersDialog As New PrintDialog()
If PrintersDialog.ShowDialog(Me) = System.Windows.Forms.DialogResult.OK Then
Try
p_Document = New PrintDocument()
PrintersDialog.Document = p_Document
AddHandler p_Document.PrintPage, AddressOf HandleOnPrintPage
Catch CurrentException As Exception
End Try
End If
End Sub
Private Sub HandleOnPrintPage(ByVal sender As Object, ByVal e As PrintPageEventArgs) Handles p_Document.PrintPage
Dim MorePagesPending As Boolean = False
'e.Graphics.Draw...(....)
'e.Graphics.DrawString(....)
' Draw everything...
If MorePagesPending Then
e.HasMorePages = True
Else
e.HasMorePages = False
End If
End Sub
That's what I'm doing since I usually have custom objects to print.
But to print PDF Files, you must understand that PDF means absolutely nothing to dotNet. Unlike common images like Bitmaps (.bmp) or Ping images (.png) the dotNet doesn't seem to have any inbuilt parser/decoder for reading, displaying and printing PDF files.
So you must use a third party application, thrid party library or your own custom PDF parser/layout generator in order to be able to send pages to print to your printer.
That's why you can't launch a hidden (not visible) process of Acrobat Reader with the command "print". You won't be able to select a printer but will direct to the default one instead !
You can however launch the Acrobat Reader process just to open the file, and do the printing manipulations (select a printer) inside Acrobat Reader (you're outside dotNet coding now)
A workaround for your may aslo to select another default printer by opening Acrobat Reader, and print one blank page on an actual working printer. This should deselect your FoxIt thing in favour of an actual printer..
This code will help you to print in a specific printer.
The sample print a file using a ProcessStartInfo and a specific printer you can change the printer to use in the process.
If the print process is not finished after 10 seconds we kill the print process.
'Declare a printerSettings
Dim defaultPrinterSetting As System.Drawing.Printing.PrinterSettings = Nothing
Private Sub cmdPrint_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdPrint.Click
Try
dim fileName As String = "C:\534679.pdf"
'Get de the default printer in the system
defaultPrinterSetting = DocumentPrinter.GetDefaultPrinterSetting
'uncomment if you want to change the default printer before print
'DocumentPrinter.ChangePrinterSettings(defaultPrinterSetting)
'print your file
If PrintFile(fileName, defaultPrinterSetting) then
msgbox ("your print file success message")
else
msgbox ("your print file failed message")
end if
Catch ex As Exception
mssbox(ex.Message.toString)
End Try
End Sub
Public NotInheritable Class DocumentPrinter
Shared Sub New()
End Sub
Public Shared Function PrintFile(ByVal fileName As String, printerSetting As System.Drawing.Printing.PrinterSettings) As Boolean
Dim printProcess As System.Diagnostics.Process = Nothing
Dim printed As Boolean = False
Try
If PrinterSetting IsNot Nothing Then
Dim startInfo As New ProcessStartInfo()
startInfo.Verb = "Print"
startInfo.Arguments = defaultPrinterSetting.PrinterName ' <----printer to use----
startInfo.FileName = fileName
startInfo.UseShellExecute = True
startInfo.CreateNoWindow = True
startInfo.WindowStyle = ProcessWindowStyle.Hidden
Using print As System.Diagnostics.Process = Process.Start(startInfo)
'Close the application after X milliseconds with WaitForExit(X)
print.WaitForExit(10000)
If print.HasExited = False Then
If print.CloseMainWindow() Then
printed = True
Else
printed = True
End If
Else
printed = True
End If
print.Close()
End Using
Else
Throw New Exception("Printers not found in the system...")
End If
Catch ex As Exception
Throw
End Try
Return printed
End Function
''' <summary>
''' Change the default printer using a print dialog Box
''' </summary>
''' <param name="defaultPrinterSetting"></param>
''' <remarks></remarks>
Public Shared Sub ChangePrinterSettings(ByRef defaultPrinterSetting As System.Drawing.Printing.PrinterSettings)
Dim printDialogBox As New PrintDialog
If printDialogBox.ShowDialog = Windows.Forms.DialogResult.OK Then
If printDialogBox.PrinterSettings.IsValid Then
defaultPrinterSetting = printDialogBox.PrinterSettings
End If
End If
End Sub
''' <summary>
''' Get the default printer settings in the system
''' </summary>
''' <returns></returns>
''' <remarks></remarks>
Public Shared Function GetDefaultPrinterSetting() As System.Drawing.Printing.PrinterSettings
Dim defaultPrinterSetting As System.Drawing.Printing.PrinterSettings = Nothing
For Each printer As String In System.Drawing.Printing.PrinterSettings.InstalledPrinters
defaultPrinterSetting = New System.Drawing.Printing.PrinterSettings
defaultPrinterSetting.PrinterName = printer
If defaultPrinterSetting.IsDefaultPrinter Then
Return defaultPrinterSetting
End If
Next
Return defaultPrinterSetting
End Function
End Class
I used this code to print my PDF files on VB NET:
Dim PrintPDF As New ProcessStartInfo
PrintPDF.UseShellExecute = True
PrintPDF.Verb = "print"
PrintPDF.WindowStyle = ProcessWindowStyle.Hidden
PrintPDF.FileName = dirName & fileName 'fileName is a string parameter
Process.Start(PrintPDF)
When you do this, process remains open with a adobe reader window that users have to close manually. I wanted to avoid user's interaction, just want them to get their documents. So, I added a few code lines to kill process:
Private Sub killProcess(ByVal processName As String)
Dim procesos As Process()
procesos = Process.GetProcessesByName(processName) 'I used "AcroRd32" as parameter
If procesos.Length > 0 Then
For i = procesos.Length - 1 To 0 Step -1
procesos(i).Kill()
Next
End If
End Sub
If you put the kill process method right after the print method you won't get your document printed (I guess this is because process is killed before it is sent to printer). So, between these 2 methods, I added this line:
Threading.Thread.Sleep(10000) ' 10000 is the milisecs after the next code line is executed
And with this my code worked as I wanted. Hope it helps you!

IO.File.Delete Random UnauthorizedAccessException

I'm using My.Computer.Filesystem.WriteAllBytes to write out an executable stored in my application's resources to it's startup directory. After running the executable, I then delete it. Everything works fine; however, I'll randomly get an UnauthorizedAccessException for no reason. After getting the exception, I can manually delete the file with no problem. Here's the full code:
' Convert MP3
' First, copy out converter
Dim Path = New IO.FileInfo(SoundPath)
Try
My.Computer.FileSystem.WriteAllBytes(Application.StartupPath + "\converter.exe", My.Resources.madplay, False)
Catch ex As Exception
MessageBox.Show(ex.ToString, "Report", MessageBoxButtons.OK)
Exit Sub
End Try
' Set up process
Dim MAD As New Process
' Set process info
Dim output As String = IO.Path.GetFileNameWithoutExtension(Path.FullName) + ".wav"
Dim input As String = Path.FullName
Dim adjust As String = barVolumeAdjust.Value.ToString
Dim hz As String = "15000"
With (MAD.StartInfo)
.FileName = Application.StartupPath + "\converter.exe"
.Arguments = "-v -a " + adjust + " -R " + hz + " -o """ + output + """ """ + input + """"
.UseShellExecute = False
.RedirectStandardInput = True
.RedirectStandardError = True
.RedirectStandardOutput = True
.CreateNoWindow = True
End With
' Start
MAD.Start()
' Update title with output
Dim Line As String = MAD.StandardError.ReadLine
While Not Line Is Nothing
Me.Text = Line
Line = MAD.StandardError.ReadLine
End While
' Stop
MAD.Close()
' Delete MAD
Try
IO.File.Delete(Application.StartupPath + "\converter.exe")
Catch ex As Exception
MessageBox.Show(ex.ToString, "Report", MessageBoxButtons.OK)
End Try
What perplexes me is that I literally just wrote out the executable, and nothing else could possibly be using it. I've checked the file attributes and it's not read-only. My application is also running as an administrator. What could be the problem?
You do not wait for the process to exit, so it is still running when you attempt to delete the file. See Process.WaitForExit
It looks like your using a separate process to write out the file - perhaps this is still using the file when you try to delete.
I suggest catching and handling the exception to get around the problem.

images vb.net file used by another process error

I'm writing a little program where I select a picture through an open file dialogue. When I selected a picture I want it to overwrite the current picture and display the new image. Now I don't have any problems with picking an image with a different extension. So when I currently have a .png I can select a .jpg but when I choose an image with the same extension as the current image I get an error:
The process cannot access the file 'C:\Users....\woontypeimages\chalet_foto.jpg' because it is being used by another process.
If ofd.ShowDialog() = Windows.Forms.DialogResult.OK Then
Dim sFilename As String = cboWoningtypesWoningtype.SelectedItem.ToString & "_foto" & System.IO.Path.GetExtension(ofd.FileName)
System.IO.File.Copy(ofd.FileName, Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & "\Camping Relaxx\woontypeimages\" & sFilename, True)
txtWoningtypesFoto.Text = sFilename
updateImages()
End If
Private Sub updateImages()
Try
picFoto.Image = Nothing
txtWoningtypesFoto.BackColor = clrReadonly
txtWoningtypesFoto.ForeColor = Color.Black
picFoto.Image = System.Drawing.Image.FromFile(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & "\Camping Relaxx\woontypeimages\" & txtWoningtypesFoto.Text)
Catch ex As Exception
txtWoningtypesFoto.BackColor = clrError
txtWoningtypesFoto.ForeColor = Color.White
End Try
Try
picGrondplan.Image = Nothing
txtWoningtypesGrondplan.BackColor = clrReadonly
txtWoningtypesGrondplan.ForeColor = Color.Black
picGrondplan.Image = System.Drawing.Image.FromFile(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & "\Camping Relaxx\woontypeimages\" & txtWoningtypesGrondplan.Text)
Catch ex As Exception
txtWoningtypesGrondplan.BackColor = clrError
txtWoningtypesGrondplan.ForeColor = Color.White
End Try
End Sub
If anyone could help me I would be pleased
Thanks in advance
Instead of worrying about Dispose() you can instead use the Load(string) method of the PictureBox which won't lock the file.
Me.PictureBox1.Load("C:\test.png")
Use these :
picFoto.Image.Dispose()
picGrondplan.Image.Dispose()
instead of :
picFoto.Image = Nothing
picGrondplan.Image = Nothing
The Image.FromFile method maintains a lock on the source file until the image has been disposed. Setting an object to nothing does not immediately dispose it - the garbage collector will take care of that in its own time (which might well not be until you've closed the form with the picture box on). Dispose is required to immediately free the file handle.