mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-09-27 02:43:48 +02:00
Transparent video read/write support (#145)
* Add support for reading transparent Matroska and implement alpha side data & decode * Few fixes * Implement alpha encoding * Gracefully handle inability to acquire WebGL context, properly clean up WebGL contexts * Improve touch device detection * Test test * Test test #2 * Test test 3 * Test test 4 * Test test 5 * Test test 6 * Test test 7 * Test test 8 * Test test 9 * Test test 10 * Test test 11 * Test test 12 * Test test 13 * Test test 14 * Test test 15 * Test test 16 * Test test 17 * Test test 18 * Test test 19 * Test test 20 * Fix type errors, improve MetadataTags docs * Do a bunch of docs work * Test test? * "Unexpected only modifier 🤓" * Add InputVideoTrack.canBeTransparent() * Some clean-up * Adjust CI to be less spammy in PRs * Fix broken license headers
This commit is contained in:
@@ -35,7 +35,7 @@ const fullscreenButton = document.querySelector('#fullscreen-button') as HTMLBut
|
||||
const errorElement = document.querySelector('#error-element') as HTMLDivElement;
|
||||
const warningElement = document.querySelector('#warning-element') as HTMLDivElement;
|
||||
|
||||
const context = canvas.getContext('2d', { alpha: false, desynchronized: true })!;
|
||||
const context = canvas.getContext('2d')!;
|
||||
|
||||
let audioContext: AudioContext | null = null;
|
||||
let gainNode: GainNode | null = null;
|
||||
@@ -149,11 +149,18 @@ const initMediaPlayer = async (resource: File | string) => {
|
||||
gainNode.connect(audioContext.destination);
|
||||
updateVolume();
|
||||
|
||||
const videoCanBeTransparent = videoTrack
|
||||
? await videoTrack.canBeTransparent()
|
||||
: false;
|
||||
|
||||
playerContainer.style.background = videoCanBeTransparent ? 'transparent' : '';
|
||||
|
||||
// For video, let's use a CanvasSink as it handles rotation and closing video samples for us.
|
||||
// Pool size of 2: We'll only ever have the current and the next frame around, so we only need two canvases.
|
||||
videoSink = videoTrack && new CanvasSink(videoTrack, {
|
||||
poolSize: 2,
|
||||
fit: 'contain', // In case the video changes dimensions over time
|
||||
alpha: videoCanBeTransparent,
|
||||
});
|
||||
// For audio, we'll use an AudioBufferSink to directly retrieve AudioBuffers compatible with the Web Audio API
|
||||
audioSink = audioTrack && new AudioBufferSink(audioTrack);
|
||||
@@ -226,6 +233,7 @@ const startVideoIterator = async () => {
|
||||
|
||||
if (firstFrame) {
|
||||
// Draw the first frame
|
||||
context.clearRect(0, 0, canvas.width, canvas.height);
|
||||
context.drawImage(firstFrame.canvas, 0, 0);
|
||||
}
|
||||
};
|
||||
@@ -242,6 +250,7 @@ const render = (requestFrame = true) => {
|
||||
|
||||
// Check if the current playback time has caught up to the next frame
|
||||
if (nextFrame && nextFrame.timestamp <= playbackTime) {
|
||||
context.clearRect(0, 0, canvas.width, canvas.height);
|
||||
context.drawImage(nextFrame.canvas, 0, 0);
|
||||
nextFrame = null;
|
||||
|
||||
@@ -281,6 +290,7 @@ const updateNextFrame = async () => {
|
||||
const playbackTime = getPlaybackTime();
|
||||
if (newNextFrame.timestamp <= playbackTime) {
|
||||
// Draw it immediately
|
||||
context.clearRect(0, 0, canvas.width, canvas.height);
|
||||
context.drawImage(newNextFrame.canvas, 0, 0);
|
||||
} else {
|
||||
// Save it for later
|
||||
@@ -594,9 +604,7 @@ fullscreenButton.addEventListener('click', () => {
|
||||
|
||||
// I'm sorry for this
|
||||
const isTouchDevice = () => {
|
||||
return (('ontouchstart' in window)
|
||||
|| (navigator.maxTouchPoints > 0)
|
||||
|| ('msMaxTouchPoints' in navigator && (navigator.msMaxTouchPoints as number) > 0));
|
||||
return 'ontouchstart' in window;
|
||||
};
|
||||
|
||||
playerContainer.addEventListener('click', () => {
|
||||
|
||||
@@ -55,6 +55,7 @@ const extractMetadata = (resource: File | string) => {
|
||||
'Coded width': `${track.codedWidth} pixels`,
|
||||
'Coded height': `${track.codedHeight} pixels`,
|
||||
'Rotation': `${track.rotation}° clockwise`,
|
||||
'Transparency': track.canBeTransparent(),
|
||||
}
|
||||
: track.isAudioTrack()
|
||||
? {
|
||||
|
||||
Reference in New Issue
Block a user