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.
:-)





2 comments:

  1. Thanks for the post ... This is very helpful.

    ReplyDelete
  2. Using the mediaExtractor method, We might be getting the FPS value with which the stream got encoded. But, what if we want the FPS while playing the stream?

    ReplyDelete