mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-09-28 03:13:51 +02:00
Add custom quality factors and quantizer bitrate mode (#448)
* Add custom quality factors and quantizer bitrate mode (closes #327) * Fix quantizer mode fallback and per-frame quantizer edge cases * Clean up quantizer mode tests * Quantizer implementation * Add quality tests * Improve conversion codec error message, make test more lenient * Add quantizer support blog post --------- Co-authored-by: Vanilagy <[email protected]>
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
import {
|
||||
Input,
|
||||
ALL_FORMATS,
|
||||
BlobSource,
|
||||
UrlSource,
|
||||
Output,
|
||||
BufferTarget,
|
||||
Mp4OutputFormat,
|
||||
Conversion,
|
||||
QUALITY_VERY_LOW,
|
||||
Input,
|
||||
Mp4OutputFormat,
|
||||
Output,
|
||||
Quality,
|
||||
UrlSource,
|
||||
} from 'mediabunny';
|
||||
import { registerAc3Decoder } from '@mediabunny/ac3';
|
||||
import { registerProresDecoder } from '@mediabunny/prores';
|
||||
@@ -72,11 +72,11 @@ const compressFile = async (resource: File | string) => {
|
||||
tracks: 'primary', // Keep only one track per type
|
||||
video: {
|
||||
width: 320, // Height will be deduced automatically to retain aspect ratio
|
||||
bitrate: QUALITY_VERY_LOW,
|
||||
quality: new Quality('very-low'),
|
||||
},
|
||||
audio: {
|
||||
codec: 'opus',
|
||||
bitrate: QUALITY_VERY_LOW,
|
||||
quality: new Quality('very-low'),
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
import {
|
||||
Input,
|
||||
ALL_FORMATS,
|
||||
BlobSource,
|
||||
UrlSource,
|
||||
BufferTarget,
|
||||
Conversion,
|
||||
HlsOutputFormat,
|
||||
Input,
|
||||
MpegTsOutputFormat,
|
||||
Output,
|
||||
PathedTarget,
|
||||
BufferTarget,
|
||||
HlsOutputFormat,
|
||||
MpegTsOutputFormat,
|
||||
Conversion,
|
||||
QUALITY_VERY_HIGH,
|
||||
QUALITY_HIGH,
|
||||
QUALITY_MEDIUM,
|
||||
QUALITY_LOW,
|
||||
QUALITY_VERY_LOW,
|
||||
Quality,
|
||||
UrlSource,
|
||||
} from 'mediabunny';
|
||||
import { registerAc3Decoder } from '@mediabunny/ac3';
|
||||
import { registerProresDecoder } from '@mediabunny/prores';
|
||||
@@ -101,14 +97,14 @@ const convertToHls = async (resource: File | string) => {
|
||||
output,
|
||||
tracks: 'primary', // Use only the primary video and audio tracks of the input
|
||||
video: [
|
||||
{ codec: 'avc', height: 1080, bitrate: QUALITY_VERY_HIGH },
|
||||
{ codec: 'avc', height: 720, bitrate: QUALITY_HIGH },
|
||||
{ codec: 'avc', height: 480, bitrate: QUALITY_MEDIUM },
|
||||
{ codec: 'avc', height: 360, bitrate: QUALITY_LOW },
|
||||
{ codec: 'avc', height: 240, bitrate: QUALITY_VERY_LOW },
|
||||
{ codec: 'avc', height: 1080, quality: new Quality('very-high') },
|
||||
{ codec: 'avc', height: 720, quality: new Quality('high') },
|
||||
{ codec: 'avc', height: 480, quality: new Quality('medium') },
|
||||
{ codec: 'avc', height: 360, quality: new Quality('low') },
|
||||
{ codec: 'avc', height: 240, quality: new Quality('very-low') },
|
||||
],
|
||||
audio: [
|
||||
{ codec: 'aac', bitrate: QUALITY_HIGH },
|
||||
{ codec: 'aac', quality: new Quality('high') },
|
||||
],
|
||||
});
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
MediaStreamAudioTrackSource,
|
||||
Mp4OutputFormat,
|
||||
Output,
|
||||
QUALITY_MEDIUM,
|
||||
Quality,
|
||||
StreamTarget,
|
||||
} from 'mediabunny';
|
||||
|
||||
@@ -48,7 +48,7 @@ const startRecording = async () => {
|
||||
context.fillRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
const audioIsEncodable = await canEncodeAudio('opus', {
|
||||
bitrate: QUALITY_MEDIUM,
|
||||
quality: new Quality('medium'),
|
||||
});
|
||||
|
||||
let audioTrack: MediaStreamAudioTrack | null = null;
|
||||
@@ -99,7 +99,7 @@ const startRecording = async () => {
|
||||
// Add the video track, with the canvas as the source
|
||||
videoSource = new CanvasSource(canvas, {
|
||||
codec: 'avc',
|
||||
bitrate: QUALITY_MEDIUM,
|
||||
quality: new Quality('medium'),
|
||||
keyFrameInterval: 0.5,
|
||||
latencyMode: 'realtime', // Allow the encoder to skip frames to keep up with real-time constraints
|
||||
});
|
||||
@@ -109,7 +109,7 @@ const startRecording = async () => {
|
||||
// Add the audio track, with the media stream track as the source
|
||||
const audioSource = new MediaStreamAudioTrackSource(audioTrack, {
|
||||
codec: 'opus',
|
||||
bitrate: QUALITY_MEDIUM,
|
||||
quality: new Quality('medium'),
|
||||
});
|
||||
audioSource.errorPromise.catch(cancelRecording); // Make sure errors are bubbled up
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import {
|
||||
Output,
|
||||
BufferTarget,
|
||||
Mp4OutputFormat,
|
||||
CanvasSource,
|
||||
AudioBufferSource,
|
||||
QUALITY_HIGH,
|
||||
BufferTarget,
|
||||
CanvasSource,
|
||||
getFirstEncodableAudioCodec,
|
||||
getFirstEncodableVideoCodec,
|
||||
Mp4OutputFormat,
|
||||
Output,
|
||||
OutputFormat,
|
||||
Quality,
|
||||
} from 'mediabunny';
|
||||
|
||||
const durationSlider = document.querySelector('#duration-slider') as HTMLInputElement;
|
||||
@@ -102,7 +102,7 @@ const generateVideo = async () => {
|
||||
// For video, we use a CanvasSource for convenience, as we're rendering to a canvas
|
||||
const canvasSource = new CanvasSource(renderCanvas, {
|
||||
codec: videoCodec,
|
||||
bitrate: QUALITY_HIGH,
|
||||
quality: new Quality('high'),
|
||||
});
|
||||
output.addVideoTrack(canvasSource, { frameRate });
|
||||
|
||||
@@ -117,7 +117,7 @@ const generateVideo = async () => {
|
||||
if (audioCodec) {
|
||||
audioBufferSource = new AudioBufferSource({
|
||||
codec: audioCodec,
|
||||
bitrate: QUALITY_HIGH,
|
||||
quality: new Quality('high'),
|
||||
});
|
||||
output.addAudioTrack(audioBufferSource);
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user