2015-04-03 11 views
7

Mam plik NSURL, który zawiera wideo i chcę nagrać klatkę tego filmu dziesięć razy co sekundę. Mam kod, który przechwyci obraz mojego odtwarzacza, ale mam problem z jego ustawieniem, aby przechwycić 10 klatek na sekundę. Próbuję czegoś takiego, ale zwraca on tę samą początkową klatkę wideo, odpowiednią liczbę razy? Oto, co mam:iOS Zrób kilka zrzutów ekranu

AVAsset *asset = [AVAsset assetWithURL:videoUrl]; 
CMTime vidLength = asset.duration; 
float seconds = CMTimeGetSeconds(vidLength); 
int frameCount = 0; 
for (float i = 0; i < seconds;) { 
    AVAssetImageGenerator *imageGenerator = [[AVAssetImageGenerator alloc]initWithAsset:asset]; 
    CMTime time = CMTimeMake(i, 10); 
    CGImageRef imageRef = [imageGenerator copyCGImageAtTime:time actualTime:NULL error:NULL]; 
    UIImage *thumbnail = [UIImage imageWithCGImage:imageRef]; 
           CGImageRelease(imageRef); 
NSString* filename = [NSString stringWithFormat:@"Documents/frame_%d.png", frameCount]; 
NSString* pngPath = [NSHomeDirectory() stringByAppendingPathComponent:filename]; 

[UIImagePNGRepresentation(thumbnail) writeToFile: pngPath atomically: YES]; 
frameCount++; 
i = i + 0.1; 
} 

Ale zamiast uzyskać ramkę w bieżącym czasie i wideo, mam tylko początkową klatkę?

Jak mogę uzyskać klatkę wideo 10 razy na sekundę?

Dzięki za pomoc :)

Odpowiedz

2

Z CMTimeMake(A, B) przechowywać liczbą wymierną, dokładny frakcja A/B sekund, a pierwszy parametr to funkcja przyjmuje wartość int. Przez 20 sekund wideo przechwycisz klatkę z czasem ((int) 19.9)/10 = 1.9 sekundy w ostatniej iteracji twojego cyklu. Użyj funkcji CMTimeMakeWithSeconds(i, NSEC_PER_SEC), aby naprawić ten problem czasu.

10

Otrzymujesz początkowy ramki, ponieważ starają się stworzyć CMTime przy pomocy wartości float:

CMTime time = CMTimeMake(i, 10); 

Od CMTimeMake funkcja przyjmuje int64_t wartość jako pierwszy parametr, swoją wartość pływak zostanie zaokrąglona do int, a otrzymasz nieprawidłowy wynik.

Pozwala zmienić kod nieco:

1) Na początku trzeba znaleźć całkowite ramy liczyć, że trzeba się z filmu. Napisałeś, że trzeba 10 klatek na sekundę, więc kod będzie:

int requiredFramesCount = seconds * 10; 

2) Następnie trzeba znaleźć wartość, która będzie się zwiększać swoją wartość CMTime na każdym kroku:

int64_t step = vidLength.value/requiredFramesCount; 

3) i wreszcie, trzeba ustawić requestedTimeToleranceBefore i requestedTimeToleranceAfter do kCMTimeZero, aby uzyskać ramkę na dokładnym czasie:

imageGenerator.requestedTimeToleranceAfter = kCMTimeZero; 
imageGenerator.requestedTimeToleranceBefore = kCMTimeZero; 

Oto jak kod będzie wyglądać następująco:

CMTime vidLength = asset.duration; 
float seconds = CMTimeGetSeconds(vidLength); 

int requiredFramesCount = seconds * 10; 
int64_t step = vidLength.value/requiredFramesCount; 

int value = 0; 

for (int i = 0; i < requiredFramesCount; i++) { 

    AVAssetImageGenerator *imageGenerator = [[AVAssetImageGenerator alloc]initWithAsset:asset]; 
    imageGenerator.requestedTimeToleranceAfter = kCMTimeZero; 
    imageGenerator.requestedTimeToleranceBefore = kCMTimeZero; 

    CMTime time = CMTimeMake(value, vidLength.timescale); 

    CGImageRef imageRef = [imageGenerator copyCGImageAtTime:time actualTime:NULL error:NULL]; 
    UIImage *thumbnail = [UIImage imageWithCGImage:imageRef]; 
    CGImageRelease(imageRef); 
    NSString* filename = [NSString stringWithFormat:@"Documents/frame_%d.png", i]; 
    NSString* pngPath = [NSHomeDirectory() stringByAppendingPathComponent:filename]; 

    [UIImagePNGRepresentation(thumbnail) writeToFile: pngPath atomically: YES]; 

    value += step; 
} 
+0

To samo pytanie używając Swift http://stackoverflow.com/questions/32286320/grab-frames-from-video-using-swift/32297251 – arpo