Thema: Zeitcode

Einzelnen Beitrag anzeigen

samso

Registriert seit: 29. Mär 2009
439 Beiträge
 
#32

AW: Zeitcode

  Alt 27. Jul 2018, 07:49
Um Rundungsfehler zu vermeiden, würde ich mit Sekunden und Frames rechnen. Wenn die maximale Anzahl der FPS überschritten wird, muss der Übertrag berücksichtigt werden.
Diese Lösung sollte mit allen Timecodes funktionieren die ganzzahlige fps haben (also z.B. nicht 23.976fps). Man muss lediglich die Konstante fps anpassen.
Delphi-Quellcode:
program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  Types, SysUtils, Math, StrUtils;

type
  TCDTimecode = record
    h, m, s, f: Word;
    neg: Boolean;
    function GetSeconds: Integer; // h, m, s => seconds
    procedure SetSeconds(Seconds: Integer);
    procedure Add(const t: TCDTimecode);
    function GetAsString: String;
    procedure SetAsString(const tc: String);
  end;

{ TCDTimecode }

procedure TCDTimecode.Add(const t: TCDTimecode);
const
  fps = 75;
var
  s: Integer;
  f: Integer;
begin
  s := Self.GetSeconds + t.GetSeconds;
  f := Self.f;
  if Self.neg
  then
    f := -f;
  if t.neg
  then
    dec(f, t.f)
  else
    inc(f, t.f);
  if f<0
  then begin
    inc(f, fps);
    dec(s); // Carry
  end
  else
  if f>=fps
  then begin
    dec(f, fps);
    inc(s); // Carry
  end;
  SetSeconds(s);
  Self.f := Word(f);
end;

function TCDTimecode.GetAsString: String;
const
  sign: array [Boolean] of String = ('+', '-');
begin
  Result := Format('%s%.2d:%.2d:%.2d:%.2d', [sign[neg], h, m, s, f])
end;

function TCDTimecode.GetSeconds: Integer;
begin
  Result := h * SecsPerHour + m * SecsPerMin + s;
  if neg
  then
    Result := -Result;
end;

procedure TCDTimecode.SetAsString(const tc: String);
var
  List: TStringDynArray;
  t: Integer;
begin
  List := SplitString(tc, ':');
  if length(List) = 4
  then begin
    t := StrToInt(List[0]);
    neg := t<0;
    h := abs(t);
    m := StrToInt(List[1]);
    s := StrToInt(List[2]);
    f := StrToInt(List[3]);
  end
  else
    raise Exception.CreateFmt('invalid timecode "%s"', [tc]);
end;

procedure TCDTimecode.SetSeconds(Seconds: Integer);
begin
  neg := Seconds<0;
  divmod(Cardinal(abs(Seconds)), SecsPerHour, h, m);
  divmod(Cardinal(m), SecsPerMin, m, s);
end;

var
  t1, t2: TCDTimecode;

begin
  try
    t1.SetAsString('03:00:00:12');
    t2.SetAsString('-01:00:00:12');
    t1.Add(t2);
    writeln(t1.GetAsString);
    t1.SetAsString('03:00:00:12');
    t2.SetAsString('-01:00:00:13');
    t1.Add(t2);
    writeln(t1.GetAsString);
    readln;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.
Ausgabe
+02:00:00:00
+01:59:59:74

Geändert von samso (27. Jul 2018 um 08:03 Uhr) Grund: Einschränkung auf ganzzahlige Frameraten
  Mit Zitat antworten Zitat