Beschreibung:
Eine C# Implementierung des Timecode welcher bei der Videobearbeitung verwendet wird.
Methoden:
public struct MediaTimeCode {
public int Hours { get; set; }
public int Minutes { get; set; }
public int Seconds { get; set; }
public int Frames { get; set; }
public static MediaTimeCode FromMilliseconds(long milliseconds, int framesPerSecond) {
TimeSpan timespan = TimeSpan.FromMilliseconds(milliseconds);
return FromTimeSpan(timespan, framesPerSecond);
}
public static MediaTimeCode FromTimeSpan(TimeSpan timespan, int framesPerSecond) {
double framesPerMillisecond = (double)framesPerSecond / (double)1000;
int frames = (int)(timespan.Milliseconds * framesPerMillisecond);
return new MediaTimeCode() {
Hours = timespan.Hours,
Minutes = timespan.Minutes,
Seconds = timespan.Seconds,
Frames = frames
};
}
public static MediaTimeCode CalculateDuration(MediaTimeCode tcIn, MediaTimeCode tcOut, int fps) {
double fpm = 60 * fps;
double fph = 60 * fpm;
double frameHours = tcIn.Hours * fph;
double frameMinutes = tcIn.Minutes * fpm;
double frameSeconds = tcIn.Seconds * fps;
double tcInFrames = frameHours + frameMinutes + frameSeconds + tcIn.Frames;
frameHours = tcOut.Hours * fph;
frameMinutes = tcOut.Minutes * fpm;
frameSeconds = tcOut.Seconds * fps;
double tcOutFrames = frameHours + frameMinutes + frameSeconds + tcOut.Frames;
double durationInFrames = tcOutFrames - tcInFrames;
int fRest = (int)durationInFrames % (int)fps;
int frames = (int)durationInFrames - fRest;
int s = frames / (int)fps;
int sRest = s % 60;
int minutes = ((s - sRest) / 60) % 60;
int hours = (100 - minutes) / 60;
return new MediaTimeCode() {
Hours = hours,
Minutes = minutes,
Seconds = sRest,
Frames = fRest
};
}
public override string ToString() {
return string.Format("{0:00}:{1:00}:{2:00}:{3:00}",
Hours,
Minutes,
Seconds,
Frames);
}
public static MediaTimeCode Parse(string tcString) {
string[] tcParts = tcString.Split(':');
int hours = int.Parse(tcParts[0]);
int minutes = int.Parse(tcParts[1]);
int seconds = int.Parse(tcParts[2]);
int frames = int.Parse(tcParts[3]);
return new MediaTimeCode() {
Hours = hours,
Minutes = minutes,
Seconds = seconds,
Frames = frames
};
}
}
Schlagwörter: Video Timecode, TcIn, TcOut, Struct
Hi jaensen,
erstmal Danke für deine Timecode Komponente. Die hat mir ein gutes Stück Arbeit abgenommen. Mir ist nur aufgefallen, dass die Duration Berechnung nicht ganz korrekt hinhaut.
Beispielsweise bei einem Input von
tcIn = 01:00:00:00
tcOut = 01:00:33:00
FrameBase = 24
Erhalte ich ein Output von 01:00:33:00
Würde aber ein Output von 00:00:33:00 erwarten
Da ich deine Berechnung nicht ganz nachvollziehen kann und sehr schnell ein Ergebnis brauchte, habe ich zu einer Quick & Dirty Lösung gegriffen.
Dazu habe ich die durationInFrames in Millisekunden umgerechnet. Bei einer FrameBase von 24 dauert ein Frame 41.666666667 ms. Also habe ich folgendes berechnet:
TimeSpan t = TimeSpan.FromMilliseconds(durationInFrames * 41.666666667);
dann habe ich einfach aus der TimeSpan wieder den TimeCode herausgezogen:
return new MediaTimeCode()
{
Hours = t.Hours,
Minutes = t.Minutes,
Seconds = t.Seconds,
Frames = (int)Math.Round(t.Milliseconds / 41.666666667, MidpointRounding.AwayFromZero)
};
Wie sauber dies nun in jedem erdenklichen Fall funktioniert, das kann ich auf die schnelle nicht sagen (Stichwort eventuelle Rundungsfehler). Die Berechnung meiner Timeline konnte ich damit aber bisher fehlerfrei umsetzen.
Hallo,
ich denke mal, der Abschnitt
int s = frames / (int)fps;
int sRest = s % 60;
int minutes = ((s - sRest) / 60) % 60;
int hours = (100 - minutes) / 60;
in der Funktion CalculateDuration müsste eher wie folgt lauten:
int s = frames / (int)fps;
int sRest = s % 60;
int minutes = (s / 60) % 60;
int hours = s / 3600;
Grüße
Maik
Wieso denn immer das Rad neu erfinden statt einfachd as bestehende zu erweitern:
using System;
public static class MediaTimeCode
{
public static int TotalFrames(this TimeSpan TimeCode, int FPS)
{
return (int)((FPS / 1000D) * TimeCode.TotalMilliseconds);
}
public static int Frame(this TimeSpan TimeCode, int FPS)
{
return (int)((FPS / 1000D) * TimeCode.Milliseconds);
}
public static String ToMediaTimeCode(this TimeSpan TimeCode, int FPS)
{
return String.Format("{0:T}:{1}", TimeCode, TimeCode.Frame(FPS));
}
}
das fügt dem TimeSpan struct einafch eine Frame methode hin zu und sollte ziemlich denselben effekt wie dein struct haben 😃
außerdem lässt sich so weiter mit TimeSpans arbeiten die in manchen hinsichten besser sind
Gruß Alexander Schill