1

我正在按照教程中的代码学习 Xuggler(一个支持 Java 视频流的库),该教程教授如何解码和播放视频

我认为这段代码是可靠的,但是当我想播放在我的窗口上读取的视频时,我收到错误消息告诉我

Exception in thread "main" java.lang.RuntimeException: got error decoding video in: C:/Users/swnmlab/1.mp4

执行此行时发生此错误

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

我用debugger单步进去发现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);
    }
}

PS如果你想尝试这个库,你可以在这里找到安装文件,然后按照这个页面上的步骤在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() 方法会导致弃用警告,所以我使用自动完成来找到一个看起来像 open() 的方法,然后更改为 acquire()。我认为这没关系,因为没有“无法打开容器的视频解码器:”异常抛出。所以只需按照示例代码进行操作即可。

4

3 回答 3

4

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

if (videoCoder.open(null,null) < 0)
throw new RuntimeException(
        "could not open video decoder for container: "
                + filename);
于 2013-05-10T09:42:37.680 回答
2

我浏览了你的代码,发现你获得了一个,但你在玩之前videoCoder没有。open也许这就是你无法解码的原因。那你能试试吗?

if (videoCoder.open() < 0)
    throw new RuntimeException(
            "could not open video decoder for container: "
                    + filename);
IVideoResampler resampler = null;
于 2013-03-16T18:31:44.993 回答
1

我通过以下代码更改执行了相同的代码。这些更改是必需的,因为不推荐使用以下 API。

IMetaData params = IMetaData.make();
IContainerParameters params = IContainerParameters.make();

如图所示,我使用 videoCoder 来设置 timeBase、Height 和 Width。

  if (coder.getCodecType() == ICodec.Type.CODEC_TYPE_VIDEO)
  {
    videoStreamId = i;
    videoCoder = coder;

    // The timebase here is used as the camera frame rate    
    videoCoder.setTimeBase(IRational.make(30,1));

    // we need to tell the driver what video with and height to use
    videoCoder.setWidth(320);
    videoCoder.setHeight(240);

    break;
  }

但是,我面临一个不同的问题,即网络摄像头显示占据整个屏幕,而不是指定的宽度和高度。

设置高度和宽度的代码更改是否不正确?我们应该如何控制尺寸?

于 2014-06-25T08:21:32.210 回答