2009-05-15 5 views

Antwort

2
function FramesToNTSCDropFrameCode(Frames:Integer;FramesPerSecond:Double):string; 
var 
    iTH, iTM, iTS, iTF : word; 
    MinCount, MFrameCount : word; 
begin 
    DivMod(Frames, Trunc(SecsPerMin * FramesPerSecond), MinCount, MFrameCount); 
    DivMod(MinCount, MinsPerHour, iTH, iTM); 
    DivMod(MFrameCount, Trunc(FramesPerSecond), ITS, ITF); 
    Result := Format('%.2d:%.2d:%.2d.%.2d',[iTH,iTM,iTS,iTF]); 
end; 

Sie müssen die divmod Routine von der Unit SysUtils kopieren, und auch die Unit SysUtils in welcher diese Funktion implementiert.

+1

+1, aber IMO sollte das Format String '% .2d:% 2d:% 2d% 2d....' - Entfernen der ersten drei Ziffern, weil sie nicht notwendig sind, und das Hinzufügen der letzten, weil ansonsten Einzelbilder in einer Sekunde nicht korrekt formatiert sind. – mghie

+0

Korrigiert, Ursprünglich hatte ich die letzte Ziffer für die Formatierung offen gelassen, um größere Frames in der Sekunde verarbeiten zu können ... was im Nachhinein unwahrscheinlich ist. – skamradt

+0

NTSC Drop Frame Timecode ist 29,97 fps, aber Sie Code akzeptiert nur fps als Integer, also glaube ich nicht, dass es richtig ist. –

2

Es gibt eine gut bekannt ist klassische Lösung für dieses Problem ...

  • der Eingangsrahmen-Zählung nr der realen Bildrate relativ ist, die Allways 30000/1001 ~ = 29,97 ist Frames pro Sekunde für NTSC
  • die berechnete Ergebnis Rahmen-nr auf die Nennbildrate von 30 Bildern pro Sekunde ist (und wird ein + jump 2frames zu jeder vollen Minute aufweist, es sei denn, die Minute, um 10
aufteilbar ist 0

(natürlich können Sie einen kleineren int-Typen verwenden, wenn Sie Ihren Wertebereich begrenzt ist weiß)

const uint FRAMES_PER_10min = 10*60 * 30000/1001; 
const uint FRAMES_PER_1min = 1*60 * 30000/1001; 
const uint DISCREPANCY  = (1*60 * 30) - FRAMES_PER_1min; 


/** reverse the drop-frame calculation 
* @param frameNr raw frame number in 30000/1001 = 29.97fps 
* @return frame number using NTSC drop-frame encoding, nominally 30fps 
*/ 
int64_t 
calculate_drop_frame_number (int64_t frameNr) 
{ 
    // partition into 10 minute segments 
    lldiv_t tenMinFrames = lldiv (frameNr, FRAMES_PER_10min); 

    // ensure the drop-frame incidents happen at full minutes; 
    // at start of each 10-minute segment *no* drop incident happens, 
    // thus we need to correct discrepancy between nominal/real framerate once: 
    int64_t remainingMinutes = (tenMinFrames.rem - DISCREPANCY)/FRAMES_PER_1min; 

    int64_t dropIncidents = (10-1) * tenMinFrames.quot + remainingMinutes; 
    return frameNr + 2*dropIncidents; 
}     // perform "drop" 

Aus dem resultierenden „drop“ framenumber, können Sie die Komponenten wie üblich berechnen, die nominal 30 fps Framerate verwenden. ..

frames = frameNumber % 30 
seconds = (frameNumber/30) % 60 

und so weiter ...

+0

Ich sollte hinzufügen ... dieser Code ist C/C++ '%' ist Modulo (Rest) '/' ist Integral Division (Abschneiden) 'lldiv' berechnet sowohl Quotienten als auch Rest – Ichthyo

+0

Das ist immer noch nicht richtig. Es gibt zwei Probleme, die nicht behoben werden: 1) In Drop-Frames mit 30 Bildern pro Sekunde haben Sie KEINE 30 Bilder pro Sekunde. Einige Sekunden haben nur 28 Frames, und diejenigen, die übersprungen werden, sind die Frames 0 und 1. 2) Aus diesem Grund ist es möglich, dass ausgelassene Frames die Anzahl von Sekunden, Minuten oder sogar Stunden erhöhen (wenn die Anzahl groß genug ist). . Es scheint, dass JEDER diesen subtilen Fehler macht. –

+0

Hier ist ein bisschen mehr: Ich arbeite gerade an genau dem gleichen Problem (Konvertieren der Frame-Anzahl in Smpte-Zeit mit Drop-Frames). Wird meinen Algorithmus veröffentlichen, sobald ich sicher bin, dass er korrekt ist. –