java - Xuggler 的 java 视频解码错误

标签 java xuggler

我正在按照 tutorial 中的代码学习 Xuggler(一个支持 Java 视频流的库)教学how to decode and play video .

我以为这段代码是可靠的,但是当我想播放在我的窗口上读取的视频时,我收到错误提示

线程“main”中的异常 java.lang.RuntimeException:解码视频错误:C:/Users/swnmlab/1.mp4

执行此行时发生此错误

int bytesDecoded = videoCoder.decodeVideo(picture, packet,offset);

我用debugger step into发现xuggle-xuggler.jar没有源码附件,有没有人遇到过这个问题?

import java.awt.image.BufferedImage;

import com.xuggle.xuggler.ICodec.Type;
import com.xuggle.xuggler.IContainer;
import com.xuggle.xuggler.IPacket;
import com.xuggle.xuggler.IPixelFormat;
import com.xuggle.xuggler.IStream;
import com.xuggle.xuggler.IStreamCoder;
import com.xuggle.xuggler.IVideoPicture;
import com.xuggle.xuggler.IVideoResampler;
import com.xuggle.xuggler.Utils;
import com.xuggle.xuggler.demos.VideoImage;

public class DecodeAndPlayVideo {
    public static void main(String[] args) {
        String filename = "C:/Users/swnmlab/1.mp4";

        // Create a Xuggler container object
        IContainer container = IContainer.make();

        // Open up the container
        if (container.open(filename, IContainer.Type.READ, null) < 0)
            throw new IllegalArgumentException("could not open file: "
                    + filename);

        // query how many streams the call to open found
        int numStreams = container.getNumStreams();

        // and iterate through the streams to find the first video stream
        int videoStreamId = -1;
        IStreamCoder videoCoder = null;
        for (int i = 0; i < numStreams; i++) {
            // Find the stream object
            IStream stream = container.getStream(i);
            // Get the pre-configured decoder that can decode this stream;
            IStreamCoder coder = stream.getStreamCoder();

            if (coder.getCodecType() == Type.CODEC_TYPE_VIDEO) {
                videoStreamId = i;
                videoCoder = coder;
                break;
            }
        }
        if (videoStreamId == -1)
            throw new RuntimeException(
                    "could not find video stream in container: " + filename);

        if (videoCoder.acquire() < 0)
            throw new RuntimeException(
                    "could not open video decoder for container: " + filename);

        IVideoResampler resampler = null;
        if (videoCoder.getPixelType() != IPixelFormat.Type.BGR24) {
            // if this stream is not in BGR24, we're going to need to
            // convert it. The VideoResampler does that for us.
            resampler = IVideoResampler.make(videoCoder.getWidth(),
                    videoCoder.getHeight(), IPixelFormat.Type.BGR24,
                    videoCoder.getWidth(), videoCoder.getHeight(),
                    videoCoder.getPixelType());
            if (resampler == null)
                throw new RuntimeException("could not create color space "
                        + "resampler for: " + filename);
        }

        /*
         * And once we have that, we draw a window on screen
         */
        openJavaWindow();

        IPacket packet = IPacket.make();
        while (container.readNextPacket(packet) >= 0) {
            /*
             * Now we have a packet, let's see if it belongs to our video stream
             */
            if (packet.getStreamIndex() == videoStreamId) {
                IVideoPicture picture = IVideoPicture.make(
                        videoCoder.getPixelType(), videoCoder.getWidth(),
                        videoCoder.getHeight());

                int offset = 0;
                while (offset < packet.getSize()) {
                    /*
                     * Now, we decode the video, checking for any errors.
                     */
                    int bytesDecoded = videoCoder.decodeVideo(picture, packet,
                            offset);
                    if (bytesDecoded < 0)
                        throw new RuntimeException(
                                "got error decoding video in: " + filename);
                    offset += bytesDecoded;

                    /*
                     * Some decoders will consume data in a packet, but will not
                     * be able to construct a full video picture yet. Therefore
                     * you should always check if you got a complete picture
                     * from the decoder
                     */
                    if (picture.isComplete()) {
                        IVideoPicture newPic = picture;
                        /*
                         * If the resampler is not null, that means we didn't
                         * get the video in BGR24 format and need to convert it
                         * into BGR24 format.
                         */
                        if (resampler != null) {
                            // we must resample
                            newPic = IVideoPicture.make(
                                    resampler.getOutputPixelFormat(),
                                    picture.getWidth(), picture.getHeight());
                            if (resampler.resample(newPic, picture) < 0)
                                throw new RuntimeException(
                                        "could not resample video from: "
                                                + filename);
                        }
                        if (newPic.getPixelType() != IPixelFormat.Type.BGR24)
                            throw new RuntimeException("could not decode video"
                                    + " as BGR 24 bit data in: " + filename);


                        @SuppressWarnings("deprecation")
                        BufferedImage javaImage = Utils.videoPictureToImage(newPic);

                        // and display it on the Java Swing window
                        updateJavaWindow(javaImage);    
                    }

                }
            } else {
                /*
                 * This packet isn't part of our video stream, so we just silently drop it.
                 */
                do {
                } while (false);
            }
        }

        closeJavaWindow();

    }

    private static VideoImage mScreen = null;
    private static void updateJavaWindow(BufferedImage javaImage) {
        mScreen.setImage(javaImage);
    }

    private static void openJavaWindow() {
        mScreen = new VideoImage();
    }

    private static void closeJavaWindow() {
        System.exit(0);
    }
}

附言如果你想试用这个库,你可以找到安装文件 here ,然后按照 this page 上的步骤操作在 Windows 上完成此库的安装。


我发现错误发生是因为我修改了原始代码

        if (videoCoder.open() < 0)
            throw new RuntimeException(
                    "could not open video decoder for container: " + filename);

        if (videoCoder.acquire() < 0)
            throw new RuntimeException(
                    "could not open video decoder for container: " + filename);

由于open()方法会导致deprecation warning,所以我用auto complete找了一个类似open()的方法,然后改成了acquire()。我认为这没问题,因为没有抛出“无法打开容器的视频解码器:”异常。所以只需按照示例代码操作即可。

最佳答案

open() 方法已弃用,您应该改用 open(null,null)

if (videoCoder.open(null,null) < 0)
throw new RuntimeException(
        "could not open video decoder for container: "
                + filename);

关于java - Xuggler 的 java 视频解码错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15452333/

相关文章:

java - 如何防止 Ant 在命令窗口中显示 [java]?

java - 无法将一系列 JPEG 图像编码为 MPEG 视频

java - 使用 Spring Annotation 有条件地导入类

java - 如何使用 Java MouseEvent 数据

java - 使用hibernate保存父表时在外键中插入Null

java - 在java中将yuv帧编码为视频文件

java - Xuggle Xuggler 在 JFrame 上播放视频速度太快

Xuggler 编译失败。

java - Xuggler MediaWriter 操作不允许问题

java - Retrofit2 - 将图像上传到服务器,在 android studio 中给出内部服务器错误作为响应