Skip to content

ES MX 5 Codecs

J-RAP edited this page Nov 7, 2026 · 3 revisions

5. CÓDECS

Warning

Experimental: decode, reader, sniff y encoder pueden cambiar en cualquier actualización, así que no los uses en tus mods todavía (mira paquetes públicos e internos).

Note

Configurable: codecs.maxImageSourceSize, codecs.png.failOnCorruptedData, codecs.png.useBKGDChunk, codecs.svg.maxSize y codecs.vp8.brokenTokens. Mira sus comentarios en config/watermedia.toml.

CodecsAPI entrega un decodificador (ImageReader) y un codificador (Encoder). Las imágenes usan nuestros códecs en Java puro, sin arranque ni FFmpeg; el video pasa por FFmpeg.

5.1 DECODIFICADORES

Imágenes fijas

PNG, JPEG, WebP, SVG y Netpbm.

ImageData image = CodecsAPI.decode(bytes);                   // A byte[], A ByteBuffer OR AN InputStream
ByteBuffer pixels = image.frames()[0];                       // TIGHTLY PACKED; JPEG AND WEBP COME ROTATED TO THEIR EXIF ORIENTATION
PixelFormat format = image.format();                         // BGRA (GRAY FOR GRAYSCALE JPEGS)
int width = image.width();
int height = image.height();

ImageData rgba = CodecsAPI.decode(bytes, PixelFormat.RGBA);  // ASK FOR BGRA, RGBA OR GRAY AND IT CONVERTS

Imágenes animadas

GIF, APNG y WebP animado. Un lector recorre los cuadros uno por uno en lugar de tenerlos todos en memoria.

try (ImageReader reader = CodecsAPI.reader(buffer)) {        // DON'T CHANGE buffer UNTIL THE READER CLOSES
    int frames = reader.frameCount();
    boolean forever = reader.repeat() == ImageData.REPEAT_FOREVER;
    reader.addFilter(new DownscaleFilter(0.5f));             // OPTIONAL: SHRINKS EVERY FRAME, NEVER ENLARGES

    while (reader.hasNext()) {
        ByteBuffer frame = reader.next();                    // REUSED ON THE NEXT CALL: COPY IT TO KEEP IT
        long delayMs = reader.delay();                       // HOW LONG THIS FRAME STAYS ON SCREEN
    }
    boolean rewound = reader.reset();                        // BACK TO THE FIRST FRAME; false WHEN IT CAN'T
    ImageData all = reader.readAll();                        // OR EVERY FRAME LEFT AT ONCE, AS COPIES
}

Cualquier imagen

MediaType type = CodecsAPI.sniff(buffer);                    // IMAGE, VIDEO, AUDIO... FROM THE FIRST BYTES
ImageMetadata info = reader.metadata();                      // ON AN OPEN READER: title(), authors()... AND value(CodecsAPI.METAKEY_EXIF)

try {
    ImageData image = CodecsAPI.decode(bytes);
} catch (UnsupportedFormatException unsupported) {
    // A VALID FILE USING A FEATURE THE DECODER LACKS: FALL BACK TO ANOTHER DECODER
} catch (CodecException broken) {
    // A BROKEN OR OVERSIZED FILE
}

Algunos formatos que sniff reconoce como imágenes (BMP, TIFF, AVIF...) todavía no tienen decodificador. Para tus propios motores, new BcReader(buffer) lee los bloques comprimidos BC1, BC3 y BC7 de una textura DDS; los motores integrados todavía no los dibujan.

Video

El video y el audio se decodifican dentro de los reproductores: crea uno con PlayerAPI.player (mira reproducción multimedia).

5.2 CODIFICADORES

Set<VideoCodec> videoCodecs = Container.MP4.video();         // WHAT EACH CONTAINER ACCEPTS; A TRACK THAT
Set<AudioCodec> audioCodecs = Container.MP4.audio();         // DOESN'T FIT IS REFUSED BEFORE THE FILE IS TOUCHED

Cada codificador recibe un cuadro por llamada, en el formato de Encoder.Video, con timestamps en microsegundos que siempre van en aumento; cada cuadro dura hasta el siguiente. Alimenta cada codificador desde un solo hilo.

Imágenes fijas y animadas

PNG (escrito como APNG cuando recibe más de un cuadro) y GIF, sin FFmpeg. Aceptan cuadros RGBA, BGRA, RGB o GRAY.

// STATIC: ONE FRAME AND NO AUDIO TRACK
Encoder.Video png = new Encoder.Video(VideoCodec.PNG, 512, 512, PixelFormat.RGBA, 1);
try (Encoder encoder = CodecsAPI.encoder(Container.PNG, Path.of("logo.png"), png, null)) {
    encoder.video(pixels, 0);
}

// ANIMATED: MORE FRAMES; THE FULL CONSTRUCTOR ADDS QUALITY (0 TO 100, 50 BY DEFAULT) AND PLAYS (0 LOOPS FOREVER)
Encoder.Video gif = new Encoder.Video(VideoCodec.GIF, 320, 240, PixelFormat.BGRA, 30, 80, 0);
try (Encoder encoder = CodecsAPI.encoder(Container.GIF, Path.of("clip.gif"), gif, null)) {
    for (int i = 0; i < frames.length; i++) encoder.video(frames[i], i * 33_333L);
}

Archivos de video

MP4, MOV, MKV y WebM con FFmpeg, más Ogg sólo para audio. Aceptan cualquier PixelFormat sin comprimir.

Encoder.Video video = new Encoder.Video(VideoCodec.H264, 1280, 720, PixelFormat.BGRA, 60); // THE FULL CONSTRUCTOR SETS QUALITY, LIKE ON IMAGES
Encoder.Audio audio = new Encoder.Audio(AudioCodec.AAC, 48_000, 2, SampleType.S16);
try (Encoder encoder = CodecsAPI.encoder(Container.MP4, Path.of("clip.mp4"), video, audio)) { // IOException WITHOUT FFMPEG
    encoder.video(frame, ptsUs);                             // EXACTLY video.frameBytes() BYTES
    encoder.audio(pcm);                                      // INTERLEAVED SAMPLES FROM TIME ZERO: PAD A LATE START WITH SILENCE
}                                                            // close() FINISHES THE FILE, WRITTEN AS <file>.part UNTIL THEN

Clone this wiki locally