I have a legacy code which has been working for a long time until I received a complaint from a customer who is using a HUAWEI P30 Pro. The problem is when a video is played in app, only a black screen is shown. The resolution is set to 1028*720 and it is supported by the phone.The frame rate is also set to 30 and tested with 60 and still nothing.
Here is the code where the playback thread is done:
private void startPlaybackLoop(){
assert mc != null;
new Thread(() -> {
try {
MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
clear();
while (started) {
if(restart) {
targetFrame = -1;
clear();
me.seekTo(0,MediaExtractor.SEEK_TO_PREVIOUS_SYNC);
}
if (advance) {
Integer q = syncFrames.higher(currentFrame);
if(q != null) {
targetFrame = -1;
clear();
me.seekTo(renderTimestamp.get(q), MediaExtractor.SEEK_TO_CLOSEST_SYNC);
} else advance = false;
}
if(back) {
Integer q = syncFrames.lower(currentFrame);
if(q != null) q = syncFrames.lower(q);
if(q != null) {
targetFrame = -1;
clear();
me.seekTo(renderTimestamp.get(q), MediaExtractor.SEEK_TO_CLOSEST_SYNC);
} else back = false;
}
if(seekTo != -1){
if(seekTo == currentFrame){
seekTo = -1;
} else {
targetFrame = seekTo;
seekTo = -1;
if ((targetFrame < currentFrame || targetFrame > syncFrames.higher(currentFrame)) && targetFrame < renderTimestamp.size()) {
clear();
Long q = renderTimestamp.get(targetFrame);
if (q == null) q = 0L;
me.seekTo(q, MediaExtractor.SEEK_TO_PREVIOUS_SYNC);
}
}
}
if(flush){
flush = false;
mc.flush();
currentFrame = renderFrame.get(me.getSampleTime())-1;
}
//Always keep reading.
int ib = mc.dequeueInputBuffer(100);
if (ib >= 0) {
ByteBuffer ibuf = mc.getInputBuffer(ib);
if (ibuf != null) {
int sz = me.readSampleData(ibuf,0 );
if(sz > 0) me.advance();
if (sz > 0) {
mc.queueInputBuffer(ib, 0, sz, 0, 0);
}
else {
mc.queueInputBuffer(ib, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
break;
}
}
}
if (paused && !renderSingle) {
continue;
}
int ob = mc.dequeueOutputBuffer(info, 100);
if (ob >= 0) {
currentFrame++;
Frame f = frameData.get(currentFrame);
if(currentFrame < targetFrame || (frameData.size() > 3 && (f == null || !f.getCamera().isValid))){
mc.releaseOutputBuffer(ob, false);
continue;
} else if(targetFrame > 0) targetFrame = -1;
//This will be slightly below 30fps, but hopefully not significant.
if(displayTimeToFrame.size() > 10000){
displayTimeToFrame.clear();
}
long renderTime = System.nanoTime() + fps30;
displayTimeToFrame.append(renderTime, currentFrame);
mc.releaseOutputBuffer(ob, renderTime);
renderSingle = false;
if (sfv != null) {
sfv.requestRender();
try {
if (Playback.this.syncRender)
renderSem.tryAcquire(500, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
restart = true;
}
}
}
} catch( IllegalStateException e) {
Timber.d("Killing MC thread");
Timber.d(e);
}
}).start();
}
I have looked at many answers: here and here but no success.
Edit 1:
After trying different things I realised there is a function called clear() where it sets flush = true
and later on it flushes the MediaCodec. Clear()
is called right before the while loop in the very beginning.
In most phones it continues fine except in HUAWEI P30 Pro. Any idea?!!