2012-08-03 15 views

Odpowiedz

5

wierzę poprawną odpowiedzią jest http://code.google.com/p/mp4parser/

isoparser API może czytać i pisać strukturę plików MP4. Jest to narzędzie o niskim poziomie, zajmujące się tak zwanymi skrzynkami, ale ma również strukturę, taką jak ścieżki i filmy.

Nicea API i sposoby znacznie szybciej niż ffmpeg Behemoth

+0

tak, ale isoparser nie zawiera dekodera/kodera do utworzenia bitmapy z sekcji mdatów skrzynek – Nativ

9

Aby uzyskać eleganckie rozwiązanie, wydaje się, że do osiągnięcia tego celu konieczne jest użycie narzędzia ffmpeg dla systemu Android. Ktoś inny wypróbował to w ten sposób: How to get the frame from video file in android; i zasugerowano, aby użyć ffmpeg.

Sprawdziłem Reference Manual, ale mogliśmy znaleźć tylko sposób, aby uzyskać samą klatkę (bez znacznika czasu) w stosunku do danej pozycji w czasie korzystania z MediaMetadataRetriever() Jak wyjaśniono tutaj: http://developer.android.com/reference/android/media/MediaMetadataRetriever.html#extractMetadata%28int%29

Jeśli don” t chcą wykorzystać ffmpeg można spróbować wykonać następujące czynności:

private ArrayList<int> getKeyFrameTimestamps(String filename) { 
    ArrayList<int> timeStamps = new ArrayList<int>(); 

    try { 
    MediaMetadataRetriever mRetriever = new MediaMetadataRetriever(); 
    mRetriever.setDataSource(getDataSource(filename)); 
    mRetriever.getFrameAtTime(i, MediaMetadataRetriever.OPTION_CLOSEST_SYNC); 

    Bitmap lastFame = mRetriever.getFrameAtTime(0, MediaMetadataRetriever.OPTION_NEXT_SYNC); 
    result.add(0); 

    for(int time=1; frame ; ++time) { 
     Bitmap frame = mRetriever.getFrameAtTime(time, MediaMetadataRetriever.OPTION_PREVIOUS_SYNC); 
     if (frame && !frame.sameAs(lastFrame)) { 
     result.add(time); 
     lastFrame = frame; 
     } 
    } 
    } catch (Exception e) { /* TODO: HANDLE THIS */ } 

    return timeStamps; 
} 

to oczywiście niezbyt eleganckie, ale prawdopodobnie działa bez kłopotów zainstalować ffmpeg ... to chyba też dość powolne (nie wiem) . Ale może właśnie tego potrzebujesz.

PS: AN ffmpeg tutorial, który pasuje do Twojego problemu można znaleźć tutaj: http://dranger.com/ffmpeg/tutorial07.html

+1

Cześć Stefan, Dzięki za starania, ale ja już próbował tego rozwiązania i działa cholernie powolny i wykonuje dziwne wyniki. Zbadam dalej (np. Ffmpeg/ffprobe) i aktualizuję ten wątek. –

+0

To jest to, czego się spodziewałem. Pomysł, aby trochę przyspieszyć to próba 'time + = lastdistance;' Gdzie używasz zestawu 'lastdistance = lastFrameTime - time;' jeśli zostanie znaleziona klatka kluczowa, sprawdź, czy 'lastFrameTime + lastdistance - 1' jest nadal ostatnią ramką. Jeśli tak, to przejdź dalej ... w przeciwnym razie użyj "powolnego wyszukiwania", aby znaleźć następną ramkę: – SDwarfs

+1

Krzyża kompilacji ffmpeg na Androida. użyj komendy ffprobe z opcją -show_frames, aby uzyskać listę obrazów I. To powinno działać we wszystkich rodzajach filmów i jest dość szybkie. Najpierw sprawdź to na komputerze. [Jeśli zainstalowałeś ffmpeg, powinieneś również mieć ffprobe]. Otrzymasz wszystkie potrzebne informacje. Jest tam -show_packets, który jest jeszcze szybszy i może okazać się wystarczający, jeśli wszystko, co chcesz wiedzieć, to referencyjne a niereferencyjne. – av501

0

4.1+ - szybciej niż mp4parser ponieważ odbywa się pod spodem i rodzimy kod jest czystsze

mp4parser trzeba obliczyć timestampów od getsyncsamples + isampledurations, które również są denerwujące i nie pasują do ffprobe. to dostaje dokładne wyniki

MediaExtractor extractor = new MediaExtractor(); 
extractor.setDataSource(getVideoPath()); 

int trackindex = MediaExtractorUtil.selectVideoTrack(extractor); 
extractor.selectTrack(trackindex); 

while (extractor.getSampleTime() != -1) { 
    long sampleTime = extractor.getSampleTime(); 

    // check not really necessary but JIC 
    if ((extractor.getSampleFlags() & MediaExtractor.SAMPLE_FLAG_SYNC) > 0) { 
     mKeyframeTimestampsMS.add(sampleTime/1000); 
    } 

    extractor.seekTo(sampleTime + 1, MediaExtractor.SEEK_TO_NEXT_SYNC); 
} 
+0

dzięki za odpowiedź, sprawdzę to, gdy tylko wrócę do tego projektu –

0

Korzystanie MediaExtractor, można mieć wszystkie kluczowe (sync) ramki razy i/lub żadnej konkretnej klatki kluczowej w dowolnym czasie. + trochę więcej przydatnych danych.

Następnie przez MediaMetadataRetriever -> getFrameAtTime można uzyskać ramki bitmap.

tutaj jest przykładowy kod używać MediaExtractor:

mediaExtractor = new MediaExtractor() ; 
    mediaExtractor.setDataSource(mediaPath); 
    int numTracks = mediaExtractor.getTrackCount(); 
    for (int i = 0; i < numTracks; ++i) { 
     MediaFormat format = mediaExtractor.getTrackFormat(i); 
     String mime = format.getString(MediaFormat.KEY_MIME); 
     if (mime.startsWith("video")) { 
      mediaExtractor.selectTrack(i); 
     } 
     Log.i("LOG_Extractor" , "track "+i+" "+mime); 
    } 

    currentTime = mediaPlayer.getCurrentPosition(); 
    mediaExtractor.seekTo((long)currentTime*1000 , MediaExtractor.SEEK_TO_PREVIOUS_SYNC); 
    previousKeyFrameTimeMilis = mediaExtractor.getSampleTime() /1000 ; 
Powiązane problemy