This commit is contained in:
kdxcxs 2026-05-23 19:50:10 +02:00 committed by GitHub
commit 97a93a9828
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 50 additions and 31 deletions

View File

@ -196,9 +196,9 @@ export class H264Context {
} }
if (parser.profileIdc !== null) { if (parser.profileIdc !== null) {
self._profileIdc = parser.profileIdc; this._profileIdc = parser.profileIdc;
self._constraintSet = parser.constraintSet; this._constraintSet = parser.constraintSet;
self._levelIdc = parser.levelIdc; this._levelIdc = parser.levelIdc;
} }
if (this._decoder === null || this._decoder.state !== 'configured') { if (this._decoder === null || this._decoder.state !== 'configured') {
@ -206,12 +206,12 @@ export class H264Context {
Log.Warn("Missing key frame. Can't decode until one arrives"); Log.Warn("Missing key frame. Can't decode until one arrives");
continue; continue;
} }
if (self._profileIdc === null) { if (this._profileIdc === null) {
Log.Warn('Cannot config decoder. Have not received SPS and PPS yet.'); Log.Warn('Cannot config decoder. Have not received SPS and PPS yet.');
continue; continue;
} }
this._configureDecoder(self._profileIdc, self._constraintSet, this._configureDecoder(this._profileIdc, this._constraintSet,
self._levelIdc); this._levelIdc);
} }
result = this._preparePendingFrame(timestamp); result = this._preparePendingFrame(timestamp);

View File

@ -16,6 +16,7 @@ export default class Display {
this._renderQ = []; // queue drawing actions for in-order rendering this._renderQ = []; // queue drawing actions for in-order rendering
this._flushPromise = null; this._flushPromise = null;
this._pendingFrames = []; // video frames awaiting decoder output
// the full frame buffer (logical canvas) size // the full frame buffer (logical canvas) size
this._fbWidth = 0; this._fbWidth = 0;
@ -479,6 +480,22 @@ export default class Display {
} }
} }
_drawVideoFrame(pendingFrame, rect) {
let frame = pendingFrame.frame;
if (!frame) {
return;
}
if (frame.codedWidth < rect.width || frame.codedHeight < rect.height) {
Log.Warn("Decoded video frame does not cover its full rectangle area. Expecting at least " +
rect.width + "x" + rect.height + " but got " +
frame.codedWidth + "x" + frame.codedHeight);
}
this.drawImage(frame,
0, 0, rect.width, rect.height,
rect.x, rect.y, rect.width, rect.height);
frame.close();
}
_renderQPush(action) { _renderQPush(action) {
this._renderQ.push(action); this._renderQ.push(action);
if (this._renderQ.length === 1) { if (this._renderQ.length === 1) {
@ -501,7 +518,21 @@ export default class Display {
const a = this._renderQ[0]; const a = this._renderQ[0];
switch (a.type) { switch (a.type) {
case 'flip': case 'flip':
this.flip(true); if (this._pendingFrames.length > 0) {
// Wait for all pending video frames to be
// decoded before flipping, so they are
// visible on screen.
let display = this;
let frames = this._pendingFrames;
this._pendingFrames = [];
Promise.all(frames.map(f => f.promise)).then(() => {
display.flip(true);
display._scanRenderQ();
});
ready = false;
} else {
this.flip(true);
}
break; break;
case 'copy': case 'copy':
this.copyImage(a.oldX, a.oldY, a.x, a.y, a.width, a.height, true); this.copyImage(a.oldX, a.oldY, a.x, a.y, a.width, a.height, true);
@ -533,32 +564,20 @@ export default class Display {
} }
break; break;
case 'frame': case 'frame':
if (a.frame.ready) { if (!a.frame.ready) {
// The encoded frame may be larger than the rect due to // Don't block the queue — the video decoder
// limitations of the encoder, so we need to crop the // pipeline needs continued input to produce
// frame. // output. Register a callback to draw later,
let frame = a.frame.frame; // and let the queue keep feeding the decoder.
if (frame.codedWidth < a.width || frame.codedHeight < a.height) {
Log.Warn("Decoded video frame does not cover its full rectangle area. Expecting at least " +
a.width + "x" + a.height + " but got " +
frame.codedWidth + "x" + frame.codedHeight);
}
const sx = 0;
const sy = 0;
const sw = a.width;
const sh = a.height;
const dx = a.x;
const dy = a.y;
const dw = sw;
const dh = sh;
this.drawImage(frame, sx, sy, sw, sh, dx, dy, dw, dh);
frame.close();
} else {
let display = this; let display = this;
a.frame.promise.then(() => { let pendingFrame = a.frame;
display._scanRenderQ(); let rect = { x: a.x, y: a.y, width: a.width, height: a.height };
pendingFrame.promise.then(() => {
display._drawVideoFrame(pendingFrame, rect);
}); });
ready = false; this._pendingFrames.push(pendingFrame);
} else {
this._drawVideoFrame(a.frame, a);
} }
break; break;
} }