Welcome to Doom9's Forum, THE in-place to be for everyone interested in DVD conversion.

Before you start posting please read the forum rules. By posting to this forum you agree to abide by the rules.

 

Go Back   Doom9's Forum > Programming and Hacking > Development
Register FAQ Calendar Today's Posts Search

Reply
 
Thread Tools Search this Thread Display Modes
Old 21st August 2010, 01:29   #1  |  Link
Metroidn1f
Registered User
 
Join Date: Aug 2010
Location: Hamilton, Ontario, Canada
Posts: 15
x264 Progress Bar

hey, I was just wondering if anyone could help me make a progress bar for x264 with vb10? I am sort of new to programing, but I still know some things. I am making a DVD and Blu Ray Ripper that encodes the videos to be compatible to be streamed to the 360. I have that all done, but I just want to add a progress bar to everything, The Demuxing, Audio Encoding, Video Encoding, and Muxing. Right now I just have a marquee progress bar that will keep active till a file is created after one of the procedures are done.

So does anyone know how to help me make a progress bar for these things? First on the list the x264 procedure.
Metroidn1f is offline   Reply With Quote
Old 21st August 2010, 01:43   #2  |  Link
LoRd_MuldeR
Software Developer
 
LoRd_MuldeR's Avatar
 
Join Date: Jun 2005
Location: Last House on Slunk Street
Posts: 13,248
What exactly is your problem/question ???
__________________
Go to https://standforukraine.com/ to find legitimate Ukrainian Charities 🇺🇦✊
LoRd_MuldeR is offline   Reply With Quote
Old 21st August 2010, 01:57   #3  |  Link
linyx
Un-Registered User
 
linyx's Avatar
 
Join Date: Mar 2008
Location: Audio Stream - 0x80
Posts: 341
Add a ProgressBar to your form, then you will have to capture the stdout of the program(s), parse it and update the progressbar.
For x264, it should be pretty easy (i.e., just round it's percentage to an integer and set ProgressBar1.Value = x264Percentage)
linyx is offline   Reply With Quote
Old 21st August 2010, 02:35   #4  |  Link
Metroidn1f
Registered User
 
Join Date: Aug 2010
Location: Hamilton, Ontario, Canada
Posts: 15
Quote:
Originally Posted by linyx View Post
Add a ProgressBar to your form, then you will have to capture the stdout of the program(s), parse it and update the progressbar.
For x264, it should be pretty easy (i.e., just round it's percentage to an integer and set ProgressBar1.Value = x264Percentage)
But exactly how do I do that? I have been searching on how to do this for along time. I posted a forum on MSDN, but no one could help me, they kept on telling me to do stuff like do it per byte or something like that, but I did not know how to do that. How do I get the persentage of x264? I tried outputting the encode results to a text file with this command in the command prompt, > "Output.txt" but that does not work. I thenfound something else that was really weird, it was like, tee | 2>1 "Output.txt" That did to the trick a little, but even if I changed the --progress to something else, it would output and make that whole file after the encode was done.

So could you tell me how I could do this?

Thanks.
Metroidn1f
Metroidn1f is offline   Reply With Quote
Old 21st August 2010, 03:50   #5  |  Link
Sharktooth
Mr. Sandman
 
Sharktooth's Avatar
 
Join Date: Sep 2003
Location: Haddonfield, IL
Posts: 11,768
http://msdn.microsoft.com/en-us/library/3x292kth.aspx
every program outputs console info to stdout and stderr (IIRC x264 outputs the progress percentage to stderr). you should parse them and get the info (percentage text) you need from that output, convert that into an int and set your progressbar.value property to that value.
obviously you need a continous or timed capture of the stdout/stderr.

Last edited by Sharktooth; 21st August 2010 at 04:06.
Sharktooth is offline   Reply With Quote
Old 21st August 2010, 04:10   #6  |  Link
linyx
Un-Registered User
 
linyx's Avatar
 
Join Date: Mar 2008
Location: Audio Stream - 0x80
Posts: 341
I honestly don't know how to capture stdout in realtime, my best suggestion would be to look into LoRd_MuldeR's Logger program.
linyx is offline   Reply With Quote
Old 21st August 2010, 04:14   #7  |  Link
Sharktooth
Mr. Sandman
 
Sharktooth's Avatar
 
Join Date: Sep 2003
Location: Haddonfield, IL
Posts: 11,768
look at ProcessStartInfo class and ProcessStartInfo.RedirectStandardOutput and ProcessStartInfo.RedirectStandardError properties
start here: http://msdn.microsoft.com/en-us/libr...v=VS.100).aspx then here: http://msdn.microsoft.com/en-us/libr...darderror.aspx and here: http://msdn.microsoft.com/en-us/libr...ardoutput.aspx
Sharktooth is offline   Reply With Quote
Old 21st August 2010, 06:31   #8  |  Link
Metroidn1f
Registered User
 
Join Date: Aug 2010
Location: Hamilton, Ontario, Canada
Posts: 15
Sorry for my lack of knoledge, but I for the first link, I don't see what a progress bar has to do with Internet Explorer.

If possible, could someone give me an example of how to do it with x264, I am making batch files with VB then starting them, will that interfeer with anything?

I learn better from examples no looking at some code that has nothing to do with or nothing to do with the same subject that I want to deal with. I know that might not make sence, but I am not good at expaining my self. To tell you the truth, this is my first application that I have attempted to make. If you need to know anything about my code, just ask me and I can provide it for you, or I can even give you the source to see how I have it programed. If you see it you will probably laugh on how I have it programed and set up.

Well here is the link to my source. It is just a little under
12MB, it is a rar, compressed at stored/Fastest. The only thing that will work is the media info. I did not inckude the tools, the file would have been over 100MB. If you want me to include the tools, just ask and I will.

http://download898.mediafire.com/5nt...r+-+Source.rar
Metroidn1f is offline   Reply With Quote
Old 21st August 2010, 13:04   #9  |  Link
LoRd_MuldeR
Software Developer
 
LoRd_MuldeR's Avatar
 
Join Date: Jun 2005
Location: Last House on Slunk Street
Posts: 13,248
Well, it's not written in VisualBasic but in Pascal/Delphi, however here is a class that I use to redirect the stdout/stderr in several of my projects:
http://code.google.com/p/mulder/sour...RunProcess.pas

This should be relatively easy to adapt for C/C++ or other languages (I often did it the other way around), as long as you are on the Windows platform (the code heavily uses Win32 API calls).

Another project of mine related to stdout/stderr redirection that might be interesting in this context:
http://code.google.com/p/mulder/sour...ger/logger.dpr

(Please remember to release your software under a GPL license, in case you decide to re-use any of the code from the above mentioned projects ^^)

See also:
http://support.microsoft.com/kb/190351
__________________
Go to https://standforukraine.com/ to find legitimate Ukrainian Charities 🇺🇦✊

Last edited by LoRd_MuldeR; 21st August 2010 at 13:09.
LoRd_MuldeR is offline   Reply With Quote
Old 21st August 2010, 13:24   #10  |  Link
stax76
Registered User
 
stax76's Avatar
 
Join Date: Jun 2002
Location: On thin ice
Posts: 6,837
Why not use StaxRip, RipBot264, HDConvertToX, Handbrake etc.?

Answer to your question:

http://forum.doom9.org/showthread.php?t=153580
stax76 is offline   Reply With Quote
Old 21st August 2010, 14:51   #11  |  Link
Sharktooth
Mr. Sandman
 
Sharktooth's Avatar
 
Join Date: Sep 2003
Location: Haddonfield, IL
Posts: 11,768
Quote:
Originally Posted by Metroidn1f View Post
Sorry for my lack of knoledge, but I for the first link, I don't see what a progress bar has to do with Internet Explorer.

If possible, could someone give me an example of how to do it with x264, I am making batch files with VB then starting them, will that interfeer with anything?

I learn better from examples no looking at some code that has nothing to do with or nothing to do with the same subject that I want to deal with. I know that might not make sence, but I am not good at expaining my self. To tell you the truth, this is my first application that I have attempted to make. If you need to know anything about my code, just ask me and I can provide it for you, or I can even give you the source to see how I have it programed. If you see it you will probably laugh on how I have it programed and set up.

Well here is the link to my source. It is just a little under
12MB, it is a rar, compressed at stored/Fastest. The only thing that will work is the media info. I did not inckude the tools, the file would have been over 100MB. If you want me to include the tools, just ask and I will.

http://download898.mediafire.com/5nt...r+-+Source.rar
The internet explorer code is an example on how to start a process. You need to start a process before capturing its standard streams...

Last edited by Sharktooth; 21st August 2010 at 15:04.
Sharktooth is offline   Reply With Quote
Old 21st August 2010, 15:48   #12  |  Link
JonE
Registered User
 
JonE's Avatar
 
Join Date: Sep 2008
Location: Birmingham (UK)
Posts: 69
@Metroidn1f

Heres a c# example - translation to vb should be straight forward.
First launch your process - x264 in your case

Code:
Process process = new Process();
process.StartInfo.FileName = <path to your x264.exe>;
process.StartInfo.Arguments = <command line args you want to pass>;
process.EnableRaisingEvents = false;
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = false;
process.StartInfo.RedirectStandardOutput = false;
process.StartInfo.RedirectStandardError = true;
bool ok = process.Start();
Note you have to set process' RedirectStandardOutput/Error as appropriate (if only I had a quid for each time I forgot that one ).

Now attach to the stream you want to read

Code:
using (StreamReader reader = process.StandardError)
{
   string line = reader.ReadLine();
   if( line == null )
      break;

   // Interpret the line as you see fit
}
Job done (give or take error handling!).

TTFN,
Jon
JonE is offline   Reply With Quote
Old 21st August 2010, 23:13   #13  |  Link
Metroidn1f
Registered User
 
Join Date: Aug 2010
Location: Hamilton, Ontario, Canada
Posts: 15
Quote:
Originally Posted by stax76 View Post
Why not use StaxRip, RipBot264, HDConvertToX, Handbrake etc.?

Answer to your question:

http://forum.doom9.org/showthread.php?t=153580
I don't know. I got inspired from the program Megui, so I just wanted to make my own. I like having my own programs that I can consider mine. It makes me feel good, lol.

@JonE
What are the arguments though? Are the arguments my command line?

This is what I have so far.

Code:
Dim process = New Process()
        process.StartInfo.FileName = "C:\Users\Metroidn1f\Desktop\Metroidn1f Encoder v4.2.38.3\Tools\x264\x264.exe"
        process.StartInfo.Arguments = "x264 --help> ""help.txt"""
        process.EnableRaisingEvents = False
        Process.StartInfo.UseShellExecute = False
        process.StartInfo.CreateNoWindow = False
        process.StartInfo.RedirectStandardOutput = False
        process.StartInfo.RedirectStandardError = True
        process.Start()

        Using IO.StreamReader(process.StandardError)

            String.line = reader.ReadLine()
            If (line = null) Then
                break()
            End If


        End Using
But the
Quote:
Using IO.StreamReader(process.StandardError)
has an error "StreamReader' is a type in 'IO' and cannot be used as an expression." What do I do?

Last edited by Metroidn1f; 21st August 2010 at 23:45.
Metroidn1f is offline   Reply With Quote
Old 22nd August 2010, 00:14   #14  |  Link
JonE
Registered User
 
JonE's Avatar
 
Join Date: Sep 2008
Location: Birmingham (UK)
Posts: 69
Yep, it is the command line args.

I've not used x264 in this scenario yet (used it with ffmpeg - nightmare!) but I guess the c# code would b something like

Code:
process.StartInfo.Arguments = "x264 --help \"help.txt\""
assuming x264 is expecting to see help.txt encased in quotes.

The "using" statement looks wrong. It should be along the lines of "using <type> name = ...." but you do not seem to be setting a name for the variable. Its not a "using" statement like a using statement at the head of a file - you aren't specifying a namespace that is being used - rather, the "using" statement is a way of wrapping certain types of variable such that it is released when it goes out of scope, be that normal loop exit, via a break statement or even an exception.

Try removing the "using" block and replacing it with

Code:
StreamReader reader = process.StandardError;

while( true)
{
   string line = reader.Readline();
   if( line == null )
      break;

   // Do stuff with 'line'
}
I need to go look up if you need to explicitly close "reader" once finished with.

TTFN,
Jon
JonE is offline   Reply With Quote
Old 31st August 2010, 23:32   #15  |  Link
Metroidn1f
Registered User
 
Join Date: Aug 2010
Location: Hamilton, Ontario, Canada
Posts: 15
Alright, I have the progress bar working now, but I have 2 problems now.

The first on is I can't get my form 3 to do anything. As soon as I click the encode button it will start encoding, but it will not display anything in the form 3. I think I might have to use a background worker, but I don't know how.

This is part of the code that I am using for the encode button.

Code:
If VideoMode = "ConstantQuality" Then
                Dim s = Sub()
                            Form3.Show()
                            Using p As New Process
                                AddHandler p.ErrorDataReceived,
                                  Sub(sendingProcess As Object,
                                    outLine As DataReceivedEventArgs)
                                      If outLine.Data <> "" Then BeginInvoke(Sub() Form3.Label1.Text = outLine.Data.Substring(1).Split("]")(0))
                                      If ProgressETACheck < 1 Then
                                          If outLine.Data <> "" Then BeginInvoke(Sub() ProgressETA = outLine.Data.Split(" ")(6))
                                          If ProgressETA = "kb/s," Then
                                              ProgressETACheck = ProgressETACheck + 1
                                          End If
                                      End If
                                      If ProgressETACheck = 1 Then
                                          If outLine.Data <> "" Then BeginInvoke(Sub() Form3.Label5.Text = "ETA:" & outLine.Data.Split(" ")(8))
                                          If outLine.Data <> "" Then BeginInvoke(Sub() Form3.Label4.Text = outLine.Data.Split(" ")(5) & " KB/s")
                                          If outLine.Data <> "" Then BeginInvoke(Sub() Form3.Label2.Text = outLine.Data.Split(" ")(1) & " Frames")
                                          If outLine.Data <> "" Then BeginInvoke(Sub() Form3.Label3.Text = outLine.Data.Split(" ")(3) & " fps")
                                      End If
                                  End Sub

                                p.StartInfo.FileName = WorkingDirectory & "\Tools\x264\x264.exe"
                                p.StartInfo.Arguments = "--quiet --profile " & VideoProfileDropDown.Invoke(New GetTextDelegate(AddressOf GetText), VideoProfileDropDown).ToString _
                                  & " --level " & VideoLevelDropDown.Invoke(New GetTextDelegate(AddressOf GetText), VideoLevelDropDown).ToString & _
                                  " --preset medium --no-dct-decimate --no-fast-pskip --crf " & _
                                  VideoCrfUpDown.Invoke(New GetTextDelegate(AddressOf GetText), VideoCrfUpDown).ToString & " " & Trellis & " " & SubME & " " & MeAlgorhithim & " " & _
                                  BAdapt & " --merange " & VideoMERangeUpDown.Text & " --fps " & fps & " --ref " _
                                  & VideoReferenceFramesUpDown.Invoke(New GetTextDelegate(AddressOf GetText), VideoReferenceFramesUpDown).ToString & " --bframes " _
                                  & VideoBFramesUpDown.Invoke(New GetTextDelegate(AddressOf GetText), VideoBFramesUpDown).ToString & " --deblock " _
                                  & VideoDeblockStrengthUpDown.Invoke(New GetTextDelegate(AddressOf GetText), VideoDeblockStrengthUpDown).ToString & ":" _
                                  & VideoDeblockThresholdUpDown.Invoke(New GetTextDelegate(AddressOf GetText), VideoDeblockThresholdUpDown).ToString & " --scenecut " _
                                  & VideoIFramesUpDown.Invoke(New GetTextDelegate(AddressOf GetText), VideoIFramesUpDown).ToString & " --slices " _
                                  & VideoSlicesUpDown.Invoke(New GetTextDelegate(AddressOf GetText), VideoSlicesUpDown).ToString & " --rc-lookahead " _
                                  & VideoLookaheadUpDown.Invoke(New GetTextDelegate(AddressOf GetText), VideoLookaheadUpDown).ToString & " --qpmin " _
                                  & VideoQuantinizersMinUpDown.Invoke(New GetTextDelegate(AddressOf GetText), VideoQuantinizersMinUpDown).ToString & " --qpmax " _
                                  & VideoQuantinizersMaxUpDown.Invoke(New GetTextDelegate(AddressOf GetText), VideoQuantinizersMaxUpDown).ToString & " --qpstep " _
                                  & VideoQuantinizersStepUpDown.Invoke(New GetTextDelegate(AddressOf GetText), VideoQuantinizersStepUpDown).ToString _
                                  & " --output """ & VideoOutputBox.Invoke(New GetTextDelegate(AddressOf GetText), VideoOutputBox).ToString & """ """ _
                                  & VideoInputBox.Invoke(New GetTextDelegate(AddressOf GetText), VideoInputBox).ToString & """"
                                p.StartInfo.UseShellExecute = False
                                p.StartInfo.RedirectStandardError = True
                                p.StartInfo.CreateNoWindow = False
                                p.Start()
                                p.BeginErrorReadLine()
                                p.WaitForExit()
                            End Using
                        End Sub
                s.BeginInvoke(Nothing, Nothing)
            End If
        End If
In the form 3 I just have the basic stuff that just converts the stdout to a percentage.

My second problem is I don't know how to end the process if one of the windows are closed. I tried using on form closing but it will not let me cancel or kill the task with the variable. I tried making it a public variable but it still did not work.

Can anyone help me out?
Metroidn1f is offline   Reply With Quote
Old 1st September 2010, 07:01   #16  |  Link
Snowknight26
Registered User
 
Join Date: Aug 2007
Posts: 1,430
You're right, your form won't be repainted unless you use a background worker or a thread. If you go the thread route, you could try something like this:
Code:
Imports System.Threading

Public Class Form1

    Public t As Thread = New Thread(AddressOf doWork)
    Public p As Process = New Process()

    Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
        If Not p.HasExited Then
            p.Close() 'or maybe p.Kill()
        End If
        If t.ThreadState = ThreadState.Running Then
            t.Abort()
        End If
    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        t.Start()
    End Sub

    Private Sub doWork()
        'code that interacts with x264
        'p.StartInfo = ...
        'p.Start()
        '...
    End Sub

End Class
If you don't go the thread route, well.. no example code from me. :P
Snowknight26 is offline   Reply With Quote
Old 1st September 2010, 17:53   #17  |  Link
Metroidn1f
Registered User
 
Join Date: Aug 2010
Location: Hamilton, Ontario, Canada
Posts: 15
What ever I try in the formclosing, the form will never close. I try e.Cancel = False, Me.Close(), End but the form will never close. It will only close if I do not have the p.Kill() there. I also tried what said to do if not p.hasexited. I did not bother putting the thread part because I got it to work. I don't know why, I had this problem before that I could not get the form to close if I had anything else in the formclosing but the end or stuff like that. I even tried closing the form 3 first then closing the main form, but it will not close.
Metroidn1f is offline   Reply With Quote
Old 1st September 2010, 22:05   #18  |  Link
JonE
Registered User
 
JonE's Avatar
 
Join Date: Sep 2008
Location: Birmingham (UK)
Posts: 69
I'm concerned that an attempt is being made to kill a process on which a subsequent thread may currently be working. Not necessarily wrong, but does ring alarm bells.

So the first step I'd take is to introduce two bools (there are better ways but this illustrates the process).

Initially set bool's A and B to false.

When you want to exit via form closing, you set A and then whilst B is false call System.Threading.Thread.Sleep(100). [Its good practice to include a timeout - say, try 10 times then give up and exit anyway - setting the thread's IsBackground to true is also a good idea as a backup plan)

Meanwhile, inside the thread itself, after processing each line, check if A is set and if so stop reading the process (exit the "while" loop), dispose of the reader, and only then try and kill the process. Then, regardless of how you get to the end of the thread function, set B to true.

This means that the process is terminated only after you stop trying to read it and is closed from within the thread that launched it (good practice if nothing else). Also there is no timing problems. for example
Quote:
Code:
        If t.ThreadState = ThreadState.Running Then
            t.Abort()
think what happens if thread just so happens to exit between the first line and the second line (albeit very unlikely, but typical of the every-now-an-again / only on certain machines / etc type errors that you see apps generate).

Another thing is that if I read correctly you are using some of form3's controls to supply parameters for the encoding process ? If so, note that Form3.Show() is modeless so returns immediately, so you'll only ever be using the default values of form3. Try Form3.ShowDialog(). Or, is Form3 showing the progress too?

Anyhow, if you are still learning then trying to use threads may be a bit of a big learning curve.

So, what you can do instead, is forget threads and maybe instead on your "encode" button run the inline code to launch process and read lines, but call DoEvents() for each line read as this will keep your UI updated (if a bit sluggish - depends on how frequently x264 outputs a new line of text).

Don't get me wrong, Snowknight26's suggestion to use threads is absolutely the right design choice (DoEvents() is the spawn of Satan), however at this stage to just get something working give DoEvents() a whirl, you should also then not have any cross-thread issues to worry about.

TTFN,
Jon
JonE is offline   Reply With Quote
Old 8th September 2010, 22:42   #19  |  Link
Metroidn1f
Registered User
 
Join Date: Aug 2010
Location: Hamilton, Ontario, Canada
Posts: 15
Well I can't figure out a way to do it. I have another problem on not getting the stdout from mkvextract and ffmpeg. I have not tried mp4box yet though. I am using the same code as I did before with the dim s = sub() but I am not getting anything. Do you know the cause of this? Also, is there a way that I can take out subtitles with avisynth without cropping the video to a smaller clip?
Metroidn1f is offline   Reply With Quote
Old 10th September 2010, 11:16   #20  |  Link
JonE
Registered User
 
JonE's Avatar
 
Join Date: Sep 2008
Location: Birmingham (UK)
Posts: 69
Well, attached is an example of a form that launches a command line (ffmsindex.exe in this instance) and retrieves progress information which it uses to update a progress bar. It also implements a cancel.

For reasons of file size, I've omitted ffms2.dll and ffmsindex.exe which are part of the avisynth add-in for FfmpegSource, but hopefully you wont need to run the code to see how it works. (If you want to run the code then add them them to the project directory.)

Example code to run the form :-

Code:
var form = new OpenFileDialog();
form.RestoreDirectory = true;
form.Filter = "Video file|*.avi;*.flv;*.mpg;*.vob;*.mp4|All Files|*.*";

if (form.ShowDialog() == DialogResult.OK)
{
    var form2 = new Synthedit.FfmpegSource.FormFfmpegSourceImport();
    form2.VideoFilename = form.FileName;

    MessageBox.Show(form2.ShowDialog().ToString(), "Result :", MessageBoxButtons.OK, MessageBoxIcon.None);
}
Some apps output text to StandardOutput. Some output to StandardError. You need to select the appropriate method when setting up the Process :-

Code:
...
proc.StartInfo.RedirectStandardError = false;
proc.StartInfo.RedirectStandardOutput = true;
...
...
using (StreamReader reader = proc.StandardOutput)
or if you reverse the above true/false pair :-
using (StreamReader reader = proc.StandardError)
...
Some apps may write to both - such as Ffmpeg. However IIRC ffmpeg uses StandardError to output progress info so thats the one you need to attach to. Warning : Ffmpeg can output all sorts of spurious info during file conversions - writing a general purpose interpreter for ffmpeg's output text is a major challenge ! That's why I used ffmsindex as an example instead. However it might be worth experimenting with ffmpeg's logging options, maybe you can remove / reduce the spurious bits.

Hope this helps.

TTFN,
Jon

PS : Ignore any bit where e.Result is set to something at the same time that e.Cancel is set to true. Micro$oft thought it a jolly good wheeze to make accessing e.Result impossible when a cancel occurs. Thanks Bill :-(
Attached Files
File Type: zip Synthedit.FfmpegSource.zip (8.3 KB, 64 views)
JonE is offline   Reply With Quote
Reply

Tags
how to, programing, progress bar, visual basic 2010, x264


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +1. The time now is 11:15.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.