Last active
September 22, 2019 02:37
-
-
Save weiancheng/c547732e8405db2d0c5ea9f049973bfb to your computer and use it in GitHub Desktop.
[export frame to jpeg] #kotlin #android #media #video
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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