Skip to content

Instantly share code, notes, and snippets.

@weiancheng
Last active September 22, 2019 02:37
Show Gist options
  • Save weiancheng/c547732e8405db2d0c5ea9f049973bfb to your computer and use it in GitHub Desktop.
Save weiancheng/c547732e8405db2d0c5ea9f049973bfb to your computer and use it in GitHub Desktop.
[export frame to jpeg] #kotlin #android #media #video
// the path of output folder
private val EXPORT_FOLDER = "/your/folder/path/"
// this is a trigger for enabling/disabling the function
private var exportFrameToJpeg = false
// a counter which acculating the number of video frame
private var nbFrame = 0
// the prepare function of decoder
private fun prepare() {
// do other things for video decoder
// if we want to export frames, decoder won't export the frames to surface
if (exportFrameToJpeg)
codec!!.configure(inputFormat, null, null, 0)
else
codec!!.configure(inputFormat, Surface(surfaceTexture), null, 0)
// ...
}
private fun decode() {
// dealing the buffers of decoder
when (val index = codec!!.dequeueOutputBuffer(bufferInfo, WAIT_TIME)) {
MediaCodec.INFO_OUTPUT_FORMAT_CHANGED -> Log.i(TAG, "INFO_OUTPUT_FORMAT_CHANGED")
MediaCodec.INFO_TRY_AGAIN_LATER -> Log.i(TAG, "INFO_TRY_AGAIN_LATER")
MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED -> Log.i(TAG, "INFO_OUTPUT_BUFFERS_CHANGED")
else -> {
if (exportFrameToJpeg)
saveBitmap(index)
// do something for the frames
// release buffer
if (exportFrameToJpeg)
codec!!.releaseOutputBuffer(index, false) // don't rend the frames
else
codec!!.releaseOutputBuffer(index, true) // we want it to be rendered if it is true
}
}
}
private fun saveBitmap(index: Int) {
val image = codec!!.getOutputImage(index)
try {
val path = Environment.getExternalStorageDirectory().toString() + EXPORT_FOLDER
val testFile = File(path)
if (!testFile.exists())
testFile.mkdir()
var imgName = nbFrame.toString()
when {
nbFrame < 10 -> imgName = "000$nbFrame"
nbFrame < 100 -> imgName = "00$nbFrame"
nbFrame < 1000 -> imgName = "0$nbFrame"
}
val fileName = "Img_$imgName.jpg"
val file = File(path, fileName)
val out = FileOutputStream(file)
val yuvImage = YuvImage(yuv420TONv21(image!!),
ImageFormat.NV21,
getWidth(),
getHeight(),
null)
yuvImage.compressToJpeg(Rect(0, 0, getWidth(), getHeight()), 80, out)
++nbFrame
} catch (e: java.lang.Exception) {
e.printStackTrace()
}
}
private fun yuv420ToNv21(image: Image): ByteArray {
val yBuffer = image.planes[0].buffer
val uBuffer = image.planes[1].buffer
val vBuffer = image.planes[2].buffer
val ySize = yBuffer.remaining()
val uSize = uBuffer.remaining()
val vSize = vBuffer.remaining()
val nv21 = ByteArray(ySize + uSize + vSize)
// U and V are swapped
yBuffer.get(nv21, 0, ySize)
vBuffer.get(nv21, ySize, vSize)
uBuffer.get(nv21, ySize + vSize, uSize)
return nv21
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment