artclarke / humble-video

Humble Video: Demuxing, Decoding, Filtering, Encoding and Muxing of 100's of video and audio formats and Codecs from the JVM
GNU Affero General Public License v3.0
557 stars 115 forks source link

PAL8 video decoding #143

Open kkolyan opened 4 years ago

kkolyan commented 4 years ago

I have a set of SMK files with PAL8 pixel format.

ffmpeg command line utility successfully converts it to MP4/h264 and I easily play this MP4 files in java using humble or xuggler.
I'd like to play these files from java directly without use of ffmpeg CLI, but both xuggler and humble fails (to play or transcode from my SMK files) with very similar error (it refuses to convert PAL8 to BGR)

Xuggler:

Exception in thread "main" java.lang.UnsupportedOperationException: Converter class com.xuggle.xuggler.video.BgrConverter constructor failed with: java.lang.RuntimeException: 2 Could not create could resampler to translate from BGR24 to PAL8

Humble:

Converter class io.humble.video.awt.BgrConverter constructor failed with: java.lang.RuntimeException: could not allocate an image rescaler

I see, they both try to convert format in Java code and there is no converter implemented for such pair of formats. But it's a pity, because ffmpeg can do it. Why do not expose a possibility to transcode by ffmpeg natively? (at least just do something like ffmpeg -i somefile.smk somefile.mp4 command do).

file example: https://drive.google.com/file/d/1cH_HxygvIV2FoRwoM7YO_A6SZGHadLSQ/view?usp=sharing

kkolyan commented 4 years ago

Workaround:

package io.humble.video.demos;

import io.humble.video.MediaPicture;
import io.humble.video.PixelFormat;
import io.humble.video.awt.MediaPictureConverter;

import java.awt.image.BufferedImage;
import java.nio.ByteBuffer;

public class Pal8Converter implements MediaPictureConverter {
    public static final int IMAGE_TYPE = BufferedImage.TYPE_3BYTE_BGR;

    public Pal8Converter(PixelFormat.Type pictureType, int pictureWidth,
                         int pictureHeight, int imageWidth, int imageHeight) {
    }

    public PixelFormat.Type getPictureType() {
        return PixelFormat.Type.PIX_FMT_PAL8;
    }

    public int getImageType() {
        return IMAGE_TYPE;
    }

    public boolean willResample() {
        return false;
    }

    public MediaPicture toPicture(final MediaPicture output, final BufferedImage input, final long timestamp) {
        throw new UnsupportedOperationException();
    }

    public BufferedImage toImage(final BufferedImage output, final MediaPicture input) {
        final BufferedImage image;
        if (output == null) {
            int w = input.getWidth();
            int h = input.getHeight();
            image = new BufferedImage(w, h, IMAGE_TYPE);
        } else {
            image = output;
        }

        ByteBuffer pixels = input.getData(0).getByteBuffer(0, input.getDataPlaneSize(0));
        ByteBuffer palette = input.getData(1).getByteBuffer(0, input.getDataPlaneSize(1));

        for (int y = 0; y < input.getHeight(); y++) {
            for (int x = 0; x < input.getWidth(); x++) {
                int index = x + y * input.getLineSize(0);
                int pixel = pixels.get(index) & 0xFF;
                int r = palette.get(pixel * 4) & 0xFF;
                int g = palette.get(pixel * 4 + 1) & 0xFF;
                int b = palette.get(pixel * 4 + 2) & 0xFF;
                image.setRGB(x, y, b << 16 | g << 8 | r);
            }
        }

        return image;
    }

    public String getDescription() {
        return "PAL8-BGR24";
    }

    public void delete() {
        throw new UnsupportedOperationException();
    }
}

        MediaPictureConverterFactory.registerConverter(new MediaPictureConverterFactory.Type("PAL8", Pal8Converter.class,
            PixelFormat.Type.PIX_FMT_PAL8, Pal8Converter.IMAGE_TYPE));