summaryrefslogtreecommitdiffstats
path: root/win/C#/Parsing/Parser.cs
blob: 3dd2fdeb4121dccf255ddc3753db3837987120c1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/*  Parser.cs $
    This file is part of the HandBrake source code.
    Homepage: <http://handbrake.fr>.
    It may be used under the terms of the GNU General Public License. */

namespace Handbrake.Parsing
{
    using System;
    using System.Globalization;
    using System.IO;
    using System.Text;
    using System.Text.RegularExpressions;

    /// <summary>
    /// A delegate to handle custom events regarding data being parsed from the buffer
    /// </summary>
    /// <param name="sender">The object which raised this delegate</param>
    /// <param name="data">The data parsed from the stream</param>
    public delegate void DataReadEventHandler(object sender, string data);

    /// <summary>
    /// A delegate to handle events regarding progress during DVD scanning
    /// </summary>
    /// <param name="sender">The object who's raising the event</param>
    /// <param name="currentTitle">The title number currently being processed</param>
    /// <param name="titleCount">The total number of titiles to be processed</param>
    public delegate void ScanProgressEventHandler(object sender, int currentTitle, int titleCount);

    /// <summary>
    /// A delegate to handle encode progress updates // EXPERIMENTAL
    /// </summary>
    /// <param name="sender">The object which raised the event</param>
    /// <param name="currentTask">The current task being processed from the queue</param>
    /// <param name="taskCount">The total number of tasks in queue</param>
    /// <param name="percentComplete">The percentage this task is complete</param>
    /// <param name="currentFps">The current encoding fps</param>
    /// <param name="averageFps">The average encoding fps for this task</param>
    /// <param name="timeRemaining">The estimated time remaining for this task to complete</param>
    public delegate void EncodeProgressEventHandler(object sender, int currentTask, int taskCount, float percentComplete, float currentFps, float averageFps, TimeSpan timeRemaining);


    /// <summary>
    /// A simple wrapper around a StreamReader to keep track of the entire output from a cli process
    /// </summary>
    internal class Parser : StreamReader
    {
        /// <summary>
        /// The Buffer StringBuilder
        /// </summary>
        private StringBuilder buffer = new StringBuilder(string.Empty);

        /// <summary>
        /// Initializes a new instance of the <see cref="Parser"/> class. 
        /// Default constructor for this object
        /// </summary>
        /// <param name="baseStream">
        /// The stream to parse from
        /// </param>
        public Parser(Stream baseStream) : base(baseStream)
        {
        }

        /// <summary>
        /// Raised upon a new line being read from stdout/stderr
        /// </summary>
        public event DataReadEventHandler OnReadLine;

        /// <summary>
        /// Raised upon the entire stdout/stderr stream being read in a single call
        /// </summary>
        public event DataReadEventHandler OnReadToEnd;

        /// <summary>
        /// Raised upon the catching of a "Scanning title # of #..." in the stream
        /// </summary>
        public event ScanProgressEventHandler OnScanProgress;

        /// <summary>
        /// Raised upon the catching of a "Scanning title # of #..." in the stream
        /// </summary>
        public event EncodeProgressEventHandler OnEncodeProgress;

        /// <summary>
        /// Gets the buffer of data that came from the CLI standard input/error
        /// </summary>
        public string Buffer
        {
            get { return buffer.ToString(); }
        }

        /// <summary>
        /// Read a line from standard in/err
        /// </summary>
        /// <returns>
        /// The read line
        /// </returns>
        public override string ReadLine()
        {
            string tmp = base.ReadLine();

            buffer.Append(tmp + Environment.NewLine);

            Match m = null;
            if (tmp.Contains("Scanning title"))
                m = Regex.Match(tmp, "^Scanning title ([0-9]*) of ([0-9]*)");

            if (OnReadLine != null)
                OnReadLine(this, tmp);

            if (m != null)
                if (m.Success && OnScanProgress != null)
                    OnScanProgress(this, int.Parse(m.Groups[1].Value), int.Parse(m.Groups[2].Value));

            return tmp;
        }

        /// <summary>
        /// Read to the end of the input stream
        /// </summary>
        /// <returns>
        /// A string of the input data
        /// </returns>
        public override string ReadToEnd()
        {
            string tmp = base.ReadToEnd();

            buffer.Append(tmp + Environment.NewLine);

            if (OnReadToEnd != null)
                OnReadToEnd(this, tmp);

            return tmp;
        }

        /// <summary>
        /// Pase the CLI status output (from standard output)
        /// </summary>
        public void ReadEncodeStatus()
        {
            CultureInfo culture = CultureInfo.CreateSpecificCulture("en-US");
            string tmp = base.ReadLine();

            Match m = Regex.Match(tmp, @"^Encoding: task ([0-9]*) of ([0-9]*), ([0-9]*\.[0-9]*) %( \(([0-9]*\.[0-9]*) fps, avg ([0-9]*\.[0-9]*) fps, ETA ([0-9]{2})h([0-9]{2})m([0-9]{2})s\))?");
            if (m.Success && OnEncodeProgress != null)
            {
                int currentTask = int.Parse(m.Groups[1].Value);
                int totalTasks = int.Parse(m.Groups[2].Value);
                float percent = float.Parse(m.Groups[3].Value, culture);
                float currentFps = m.Groups[5].Value == string.Empty ? 0.0F : float.Parse(m.Groups[5].Value, culture);
                float avgFps = m.Groups[6].Value == string.Empty ? 0.0F : float.Parse(m.Groups[6].Value, culture);
                TimeSpan remaining = TimeSpan.Zero;
                if (m.Groups[7].Value != string.Empty)
                {
                    remaining = TimeSpan.Parse(m.Groups[7].Value + ":" + m.Groups[8].Value + ":" + m.Groups[9].Value);
                }
                OnEncodeProgress(this, currentTask, totalTasks, percent, currentFps, avgFps, remaining);
            }
        }
    }
}