Code Repo    |     RSS
MD's Technical Sharing



Tuesday, August 26, 2008

Scaling SRT subtitle timestamps

Sometimes the downloaded SRT subtitle is faster or slower than the actual movie.

The timestamps are either upscaled/downscaled by a constant K and not by an offset. The following code attempts to adjust the subtitle timestamps to fit the movie.


Const K As Double = 0.95905 'scale constant
Const timeFormat As String = "HH:mm:ss,fff" 'format of timestamps

'get the total number of miliseconds in a datetime. Ignore the date component
Public Function GetTotalMSeconds(ByVal dt As DateTime) As Double
Return dt.Hour * 3600000 + dt.Minute * 60000 + dt.Second * 1000 + dt.Millisecond
End Function

'convert the specified amount of miliseconds to datetime. Ignore the date component
Public Function GetDateTimeFromMSeconds(ByVal msecs As Double) As DateTime
Dim hour As Integer = CInt(Math.Floor(msecs / 3600000))
Dim minute As Integer = CInt(Math.Floor((msecs - hour * 3600000) / 60000))
Dim seconds As Integer = CInt(Math.Floor((msecs - hour * 3600000 - minute * 60000) / 1000))
Dim milisec As Integer = CInt(Math.Floor(msecs - hour * 3600000 - minute * 60000 - seconds * 1000))
Return New DateTime(Now.Year, Now.Month, Now.Day, hour, minute, seconds, milisec)
End Function

Sub Main()

'SRT file will look like
'1:
'00:00:03,203 --> 00:00:05,194
'[Music playing]
'[Music playing line 2]

'2:
'00:00:14,381 --> 00:00:17,350
'[Tapping, spring rattling]

'3:
'00:00:17,384 --> 00:00:19,716
'[Scrapes]
'For simplicity, assume all 2nd lines after a blank line contains the timestamp. Only modify these lines

Dim sr As StreamReader = File.OpenText("c:\temp\test.srt")
Dim sw As StreamWriter = File.CreateText("c:\temp\Finding Nemo (2003).srt")
Dim waitCount As Integer = 0
While Not sr.EndOfStream
Dim st As String = sr.ReadLine()
waitCount += 1

'find the timestamp line
If waitCount = 2 Then
Debug.WriteLine("Old value: " + st)

'scale the timestamp
'e.g
'old value: 01:39:56,324 --> 01:39:57,951
'new value: 01:35:50,774 --> 01:35:52,334
If st.Length > 0 Then
Dim splitArr As String() = st.Split(New String() {"-->"}, StringSplitOptions.None)
Dim timeStart As DateTime = DateTime.ParseExact(splitArr(0).Trim, timeFormat, System.Globalization.CultureInfo.CurrentCulture)
Dim timeEnd As DateTime = DateTime.ParseExact(splitArr(1).Trim, timeFormat, System.Globalization.CultureInfo.CurrentCulture)

Dim timeStartNew As DateTime = New DateTime(CLng(timeStart.Ticks * K))
Dim timeStartEnd As DateTime = New DateTime(CLng(timeStart.Ticks * K))

Dim stNew As String = GetDateTimeFromMSeconds(GetTotalMSeconds(timeStart) * K).ToString(timeFormat) + "-->" + GetDateTimeFromMSeconds(GetTotalMSeconds(timeEnd) * K).ToString(timeFormat)
Debug.WriteLine("New value: " + stNew)

'change the string
st = stNew
End If
End If

'encounter an empty line, new timestamp will be encountered
If st.Length = 0 Then
waitCount = 0
End If

sw.WriteLine(st)
End While

'close the file
sr.Close()
sw.Close()
End Sub


Most of the code is straightforward. Notice the following:


Dim timeEnd As DateTime = DateTime.ParseExact(splitArr(1).Trim, timeFormat, System.Globalization.CultureInfo.CurrentCulture)


This converts the timestamp string into a DateTime value. Had we not used DateTime.ParseExact, but Convert.ToDateTime, the miliseconds part of the original timestamp would have been lost! DateTime.ParseExact allows us to specify a custom format string as well as keeping the miliseconds part.


To scale a timestamp, multiply the Time part by a constant K. This is done by converting the DateTime value into seconds, multiplying the seconds by K, and finally converting it back to DateTime. Multiplying the Ticks property would not work, as this would take into account the Date part of the DateTime value.

Read More »

Thursday, August 21, 2008

Relaxed Delegates in VB.NET 2008

Reference: http://msdn.microsoft.com/en-gb/library/ms364068(VS.80).aspx

In VS2005 the following code cannot compile and gives an error saying that testSub does not have the signature required by the Activated event. However, in VS2008 this compiles successfully without any error!


Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
AddHandler
MyBase.Activated, AddressOf testSub
End Sub

Private Sub testSub()
End Sub


This is a new feature in VB 2008 called "Relaxed Delegates"; since it's safe for a delegate with parameters to point at a method with zero parameters, we now allow this to compile. (This is called a "zero-argument relaxation").


The following is also allowed:


Module Module1
Delegate Sub MyDelegate(ByVal x As Short)
Sub Foo(ByVal x As Integer)
MsgBox(x)
End Sub

Sub Main()
Dim d As MyDelegate = AddressOf Foo
d.Invoke(4)
End Sub
End Module


We've pointed MyDelegate at a method that does not have an exact signature match. This is completely safe though because when we invoke the delegate, it can only take something that can fit inside a Short variable; since Short always widens to Integer, this is completely safe and guaranteed to work at runtime.


Now if we try it the other way around (make MyDelegate of type Integer and Foo take a parameter of type Short) it'll only work with Option Strict Off (since this conversion could fail at runtime).

However, this is not possible in C#:


private void Form1_Load(object sender, EventArgs e)
{
this.textBox1.TextChanged += new EventHandler(textBox1_TextChanged);
}
void textBox1_TextChanged(){}


This gives: "error CS0123: No overload for 'textBox1_TextChanged' matches delegate 'System.EventHandler"


Similiarly the following won't work although Int16 can always widen to In32


public delegate void SimpleDelegate(Int16 x);
public static void MyFunc(Int32 x){}

private void Form1_Load(object sender, EventArgs e)
{
SimpleDelegate simpleDelegate
= new SimpleDelegate(MyFunc);
simpleDelegate
.Invoke(9); //or simpleDelegate(9);
}


This again gives a similiar error message:


"No overload for 'WindowsFormsApplication2.Form1.MyFunc(int)' matches delegate 'WindowsFormsApplication2.Form1.SimpleDelegate'"


Relaxed delagates is not supported in C#. However, both C# and VB have another 'version' of relaxed delegates - you can use type 'object' for any of the parameters

Read More »

Saturday, August 16, 2008

RGB Values for Common Colors

const COLORREF colAliceBlue = RGB(240,248,255);
const COLORREF colAntiqueWhite = RGB(250,235,215);
const COLORREF colAqua = RGB( 0,255,255);
const COLORREF colAquamarine = RGB(127,255,212);
const COLORREF colAzure = RGB(240,255,255);
const COLORREF colBeige = RGB(245,245,220);
const COLORREF colBisque = RGB(255,228,196);
const COLORREF colBlack = RGB( 0, 0, 0);
const COLORREF colBlanchedAlmond = RGB(255,255,205);
const COLORREF colBlue = RGB( 0, 0,255);
const COLORREF colBlueViolet = RGB(138, 43,226);
const COLORREF colBrown = RGB(165, 42, 42);
const COLORREF colBurlywood = RGB(222,184,135);
const COLORREF colCadetBlue = RGB( 95,158,160);
const COLORREF colChartreuse = RGB(127,255, 0);
const COLORREF colChocolate = RGB(210,105, 30);
const COLORREF colCoral = RGB(255,127, 80);
const COLORREF colCornflowerBlue = RGB(100,149,237);
const COLORREF colCornsilk = RGB(255,248,220);
const COLORREF colCrimson = RGB(220, 20, 60);
const COLORREF colCyan = RGB( 0,255,255);
const COLORREF colDarkBlue = RGB( 0, 0,139);
const COLORREF colDarkCyan = RGB( 0,139,139);
const COLORREF colDarkGoldenRod = RGB(184,134, 11);
const COLORREF colDarkGray = RGB(169,169,169);
const COLORREF colDarkGreen = RGB( 0,100, 0);
const COLORREF colDarkKhaki = RGB(189,183,107);
const COLORREF colDarkMagenta = RGB(139, 0,139);
const COLORREF colDarkOliveGreen = RGB( 85,107, 47);
const COLORREF colDarkOrange = RGB(255,140, 0);
const COLORREF colDarkOrchid = RGB(153, 50,204);
const COLORREF colDarkRed = RGB(139, 0, 0);
const COLORREF colDarkSalmon = RGB(233,150,122);
const COLORREF colDarkSeaGreen = RGB(143,188,143);
const COLORREF colDarkSlateBlue = RGB( 72, 61,139);
const COLORREF colDarkSlateGray = RGB( 47, 79, 79);
const COLORREF colDarkTurquoise = RGB( 0,206,209);
const COLORREF colDarkViolet = RGB(148, 0,211);
const COLORREF colDeepPink = RGB(255, 20,147);
const COLORREF colDeepSkyBlue = RGB( 0,191,255);
const COLORREF colDimGray = RGB(105,105,105);
const COLORREF colDodgerBlue = RGB( 30,144,255);
const COLORREF colFireBrick = RGB(178, 34, 34);
const COLORREF colFloralWhite = RGB(255,250,240);
const COLORREF colForestGreen = RGB( 34,139, 34);
const COLORREF colFuchsia = RGB(255, 0,255);
const COLORREF colGainsboro = RGB(220,220,220);
const COLORREF colGhostWhite = RGB(248,248,255);
const COLORREF colGold = RGB(255,215, 0);
const COLORREF colGoldenRod = RGB(218,165, 32);
const COLORREF colGray = RGB(127,127,127);
const COLORREF colGreen = RGB( 0,128, 0);
const COLORREF colGreenYellow = RGB(173,255, 47);
const COLORREF colHoneyDew = RGB(240,255,240);
const COLORREF colHotPink = RGB(255,105,180);
const COLORREF colIndianRed = RGB(205, 92, 92);
const COLORREF colIndigo = RGB( 75, 0,130);
const COLORREF colIvory = RGB(255,255,240);
const COLORREF colKhaki = RGB(240,230,140);
const COLORREF colLavender = RGB(230,230,250);
const COLORREF colLavenderBlush = RGB(255,240,245);
const COLORREF colLawngreen = RGB(124,252, 0);
const COLORREF colLemonChiffon = RGB(255,250,205);
const COLORREF colLightBlue = RGB(173,216,230);
const COLORREF colLightCoral = RGB(240,128,128);
const COLORREF colLightCyan = RGB(224,255,255);
const COLORREF colLightGoldenRodYellow = RGB(250,250,210);
const COLORREF colLightGreen = RGB(144,238,144);
const COLORREF colLightGrey = RGB(211,211,211);
const COLORREF colLightPink = RGB(255,182,193);
const COLORREF colLightSalmon = RGB(255,160,122);
const COLORREF colLightSeaGreen = RGB( 32,178,170);
const COLORREF colLightSkyBlue = RGB(135,206,250);
const COLORREF colLightSlateGray = RGB(119,136,153);
const COLORREF colLightSteelBlue = RGB(176,196,222);
const COLORREF colLightYellow = RGB(255,255,224);
const COLORREF colLime = RGB( 0,255, 0);
const COLORREF colLimeGreen = RGB( 50,205, 50);
const COLORREF colLinen = RGB(250,240,230);
const COLORREF colMagenta = RGB(255, 0,255);
const COLORREF colMaroon = RGB(128, 0, 0);
const COLORREF colMediumAquamarine = RGB(102,205,170);
const COLORREF colMediumBlue = RGB( 0, 0,205);
const COLORREF colMediumOrchid = RGB(186, 85,211);
const COLORREF colMediumPurple = RGB(147,112,219);
const COLORREF colMediumSeaGreen = RGB( 60,179,113);
const COLORREF colMediumSlateBlue = RGB(123,104,238);
const COLORREF colMediumSpringGreen = RGB( 0,250,154);
const COLORREF colMediumTurquoise = RGB( 72,209,204);
const COLORREF colMediumVioletRed = RGB(199, 21,133);
const COLORREF colMidnightBlue = RGB( 25, 25,112);
const COLORREF colMintCream = RGB(245,255,250);
const COLORREF colMistyRose = RGB(255,228,225);
const COLORREF colMoccasin = RGB(255,228,181);
const COLORREF colNavajoWhite = RGB(255,222,173);
const COLORREF colNavy = RGB( 0, 0,128);
const COLORREF colNavyblue = RGB(159,175,223);
const COLORREF colOldLace = RGB(253,245,230);
const COLORREF colOlive = RGB(128,128, 0);
const COLORREF colOliveDrab = RGB(107,142, 35);
const COLORREF colOrange = RGB(255,165, 0);
const COLORREF colOrangeRed = RGB(255, 69, 0);
const COLORREF colOrchid = RGB(218,112,214);
const COLORREF colPaleGoldenRod = RGB(238,232,170);
const COLORREF colPaleGreen = RGB(152,251,152);
const COLORREF colPaleTurquoise = RGB(175,238,238);
const COLORREF colPaleVioletRed = RGB(219,112,147);
const COLORREF colPapayaWhip = RGB(255,239,213);
const COLORREF colPeachPuff = RGB(255,218,185);
const COLORREF colPeru = RGB(205,133, 63);
const COLORREF colPink = RGB(255,192,203);
const COLORREF colPlum = RGB(221,160,221);
const COLORREF colPowderBlue = RGB(176,224,230);
const COLORREF colPurple = RGB(128, 0,128);
const COLORREF colRed = RGB(255, 0, 0);
const COLORREF colRosyBrown = RGB(188,143,143);
const COLORREF colRoyalBlue = RGB( 65,105,225);
const COLORREF colSaddleBrown = RGB(139, 69, 19);
const COLORREF colSalmon = RGB(250,128,114);
const COLORREF colSandyBrown = RGB(244,164, 96);
const COLORREF colSeaGreen = RGB( 46,139, 87);
const COLORREF colSeaShell = RGB(255,245,238);
const COLORREF colSienna = RGB(160, 82, 45);
const COLORREF colSilver = RGB(192,192,192);
const COLORREF colSkyBlue = RGB(135,206,235);
const COLORREF colSlateBlue = RGB(106, 90,205);
const COLORREF colSlateGray = RGB(112,128,144);
const COLORREF colSnow = RGB(255,250,250);
const COLORREF colSpringGreen = RGB( 0,255,127);
const COLORREF colSteelBlue = RGB( 70,130,180);
const COLORREF colTan = RGB(210,180,140);
const COLORREF colTeal = RGB( 0,128,128);
const COLORREF colThistle = RGB(216,191,216);
const COLORREF colTomato = RGB(255, 99, 71);
const COLORREF colTurquoise = RGB( 64,224,208);
const COLORREF colViolet = RGB(238,130,238);
const COLORREF colWheat = RGB(245,222,179);
const COLORREF colWhite = RGB(255,255,255);
const COLORREF colWhiteSmoke = RGB(245,245,245);
const COLORREF colYellow = RGB(255,255, 0);
const COLORREF colYellowGreen = RGB(139,205, 50);

Read More »