Xuggler对Java视频解码出错

时间:2013-03-16 17:28:00

标签: java xuggler

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

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

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

此行执行时会发生此错误

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

我使用调试器进入并发现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);
    }
}

P.S。如果您想尝试使用此库,可以找到安装文件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()方法导致弃用警告,所以我使用auto complete来查找看起来像open()的方法,然后改为acquire()。我认为没关系,因为没有“无法打开容器的视频解码器:”异常被抛出。所以只需按照示例代码。

3 个答案:

答案 0 :(得分:4)

不推荐使用

open()方法,你应该使用open(null,null)代替

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

答案 1 :(得分:2)

我查看了您的代码,发现您获得了videoCoder,但在播放之前您没有open。也许这就是为什么你无法解码它。你能试一试吗?

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

答案 2 :(得分: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;
  }

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

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