Wednesday, October 17, 2018

How to get frame rate (FPS) and number of frames programmatically from a video in Android

17th of October, 2018.

Yesterday I was assigned to get metadata (width, height, frame rate and no of frames)  of a video recorded by camera. I have gone through many articles and stackoverflow answers, but none of them have fully covered what I want. After playing with android framework I manged to complete my assignment. I will show you what I  have learned.

What I need was either number of frames or frame rate. If I have one then I can calculate other because I have the video length.
 First I tried to use MediaPlayer class. There were 2 promising methods in this class.

 val mediaPlayer: MediaPlayer = MediaPlayer.create(context, uri)  
 val frames = mediaPlayer.metrics.get(MediaPlayer.MetricsConstants.FRAMES)  

However this method requires api level 28. My minimum api level was 21 so this was not going to work. There was also another method call,

 val frameRate = mediaPlayer.syncParams.frameRate  

However this always returns null for me. I wasn't eager to chase this around because I had another promising class which named MediaMetadataRetriever.

 val retriever = MediaMetadataRetriever()  
 val frameRate = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_CAPTURE_FRAMERATE)  

However this method also requires android api level 23 and also it returns me null.

Finally I found MediaExtractor class which is compatible with android api level 16 and gives me what I want.

 private fun getVideoMetaData(uri: Uri) : VideoMetaData{  
     val mediaExtractor = MediaExtractor()  
     mediaExtractor.setDataSource(uri.path)  
     val format = mediaExtractor.getTrackFormat(0)  
     mediaExtractor.release()  
     return if(format.containsKey(MediaFormat.KEY_FRAME_RATE)){  
       val frameRate = format.getInteger(MediaFormat.KEY_FRAME_RATE)  
       val frames = frameRate * (format.getLong(MediaFormat.KEY_DURATION)/ 1000000)  
       VideoMetaData(format.getInteger(MediaFormat.KEY_WIDTH).toString(),  
           format.getInteger(MediaFormat.KEY_HEIGHT).toString(),  
           frames.toString(),  
           frameRate.toString())  
     }else {  
       VideoMetaData(format.getInteger(MediaFormat.KEY_WIDTH).toString(), format.getInteger(MediaFormat.KEY_HEIGHT).toString())  
     }  
   }  

** VideoMetaData is a simple data class

So that's it. Hope this will be a help for someone.
:-)