I am using surface view to render frames after extracted from video, the problem is that there is a flickering effect while rendering, the origin video was smooth, I play the frames in ImageViewer and hold on press NEXT key to switch next and next it was smooth too, only flicker after render them in SurfaceView.
the problem is I have a period between frames drawing, because I want to control the playing frame rate, make it slower or faster via user's choice, once I give up the delay drawing the problem gone, but that's no my intention, I need to make them delay.
I understand that this is due to double/triple buffering problem, even though I went through many posts, including turn to use GLSurfaceView to render, also drawBitmap twice intent to keep front-buffer and back-buffer align, it doesn't help to fix this problem.
I found this Flickering while using surface view post, and try all the solution-like mention inside, but it's not work, the accepted answer mention about dirty rect, remind me to update every pixels if call lockCanvas()
without rect specified, but I think I already draw the whole bitmap in the next, imply I updated every pixels, so I get not idea of this.
below are the code and the problem's gif, please take a look at my code and help me get this fixed.
class CustomView(
context: Context, attrs: AttributeSet?
) : SurfaceView(context, attrs), Runnable {
private var animationThread: Thread? = null
@Volatile private var running = false
private var frameList: List<BitmapFrame1>? = null
private var index = 0
fun start(frameList: List<BitmapFrame1>) {
if (running) return
running = true
index = 0
this.frameList = frameList
animationThread = Thread(this).apply {
start()
}
}
override fun run() {
val surHolder = holder
var nextFrameTimeMs = 0L
while (running) {
if (!surHolder.surface.isValid) continue
if (SystemClock.uptimeMillis() >= nextFrameTimeMs) {
val currentFrame = frameList!!.getOrNull(++index)
if (currentFrame == null) {
running = false
} else {
val canvas = surHolder.lockCanvas()
canvas.drawBitmap(currentFrame.bitmap, 0f, 0f, Paint())
val drawTimestamp = SystemClock.uptimeMillis()
surHolder.unlockCanvasAndPost(canvas)
nextFrameTimeMs = drawTimestamp + currentFrame.delayMs
}
} else {
// have tried to draw the current frame again before delay time's up,
// but not effect
val currentFrame = frameList!![index]
val canvas = surHolder.lockCanvas()
canvas.drawBitmap(currentFrame.bitmap, 0f, 0f, Paint())
surHolder.unlockCanvasAndPost(canvas)
}
}
}
}