2009-05-15 5 views

Répondre

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; 

Vous devez copier la routine DIVMOD de l'unité SysUtils, et également l'unité SysUtils quelle que soit implémente cette fonction.

+1

+1, mais l'OMI la chaîne de format devrait être '% .2d:% 2d:% 2d% 2d....' - enlever les trois premiers les chiffres parce qu'ils ne sont pas nécessaires, et en ajoutant le dernier parce que sinon les images à un chiffre dans une seconde ne sont pas formatées correctement. – mghie

+0

Corrigé, À l'origine, j'avais laissé le dernier chiffre ouvert pour le formatage afin de pouvoir traiter des images de plus grande taille, ce qui, rétrospectivement, est peu probable. – skamradt

+0

NTSC Drop Frame Le timecode est de 29,97 ips, mais votre code n'accepte que fps comme entier, donc je ne pense pas que ce soit correct. –

2

Il est bien connu solution classique pour ce problème ...

  • le cadre de comptage d'entrée nr est par rapport à la vraie framerate, qui est AllWays 30000/1001 ~ = 29.97 images par seconde pour NTSC
  • le résultat de trame nr calculée est à la fréquence d'images de 30 images par seconde nominal (et sera présent à chaque minute plein saut de a +, à moins que la minute est divisible par 10

(bien sûr vous pouvez utiliser un plus petit type int si vous connaissez votre plage de valeurs est limitée)

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" 

De la résultante « drop » frameNumber, vous pouvez calculer les composants comme d'habitude, en utilisant le framerate de 30fps nominal. ..

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

et ainsi de suite ...

+0

Je devrais ajouter ... ce code est C/C++ '%' est modulo (reste) '/' est une division intégrale (tronquée) 'Lldiv' calcule à la fois le quotient et le reste. – Ichthyo

+0

Ce n'est toujours pas correct. Deux problèmes ne sont pas résolus: 1) Dans les drop frames à 30fps, vous n'avez PAS 30 frames dans chaque seconde. Certaines secondes n'ont que 28 images, et celles qui sont ignorées sont les images 0 et 1. 2) Pour cette raison, il est possible que les images perdues augmentent le nombre de secondes, minutes ou même heures (si le nombre est assez grand) . Il semble que tout le monde fait cette erreur subtile. –

+0

Voici un peu plus: Je travaille actuellement exactement sur le même problème (en convertissant le nombre de frames en smpte time avec drop frames). Va poster mon algorithme une fois que je suis sûr que c'est correct. –