【问题标题】:Is it possible to record video from webcam to file using Xuggle Xuggler only?是否可以仅使用 Xuggle Xuggler 将网络摄像头中的视频录制到文件中?
【发布时间】:2015-11-06 12:26:58
【问题描述】:

我在过去 2 周尝试从网络摄像头记录到文件,但我无法让网络摄像头捕获 API 在我的 Raspberry Pi 型号 B+ 上工作。

应用程序启动,但在最后冻结,没有任何控制台错误。

Java source code 从网络摄像头记录,但在结束时冻结并留下 100% 的 CPU 使用率,直到使用 ctrl+c 终止。

Xuggle Xuggler 似乎工作正常,但是否可以仅使用 Xuggle Xuggler 录制视频?

我找到了 Xuggle Xuggler 的演示,但没有一个来自网络摄像头的记录文件

Xuggle Xuggler java demos

那么是否可以使用 xuggle xuggler 和 java 库来录制视频,还是只是再次浪费时间?

【问题讨论】:

    标签: java raspberry-pi webcam video-capture


    【解决方案1】:

    看来这不仅仅是浪费时间……

    下面的源代码将仅使用 Xuggle Xuggler 和 Java 库将视频捕获到文件中。仅使用 320x240 或更高的分辨率时,源代码将起作用,这是因为 xuggle xugglers lousy webcam support

    我仍在等待更好更快的解决方案,以便我的原始问题被接受为答案。

    package webcam;
    
    import com.xuggle.mediatool.IMediaWriter;
    import com.xuggle.mediatool.ToolFactory;
    import com.xuggle.xuggler.ICodec;
    import com.xuggle.xuggler.IContainer;
    import com.xuggle.xuggler.IContainerFormat;
    import com.xuggle.xuggler.IError;
    import com.xuggle.xuggler.IMetaData;
    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.video.ConverterFactory;
    import com.xuggle.xuggler.video.IConverter;
    import java.awt.image.BufferedImage;
    import java.io.File;
    
    
    public class Uusi {
    
        @SuppressWarnings("deprecation")
        public static void main(String[] args) throws Throwable {
    
            File file = new File("output.h264");
            IMediaWriter writer = ToolFactory.makeWriter(file.getName());
    
            writer.addVideoStream(0, 0, ICodec.ID.CODEC_ID_H264, 320, 240);
    
            String driverName = "vfwcap";
            String deviceName = "0";
    
            // Let's make sure that we can actually convert video pixel formats.
            if (!IVideoResampler.isSupported(IVideoResampler.Feature.FEATURE_COLORSPACECONVERSION)) {
                throw new RuntimeException("you must install the GPL version of Xuggler (with IVideoResampler support) for this demo to work");
            }
    
            // Create a Xuggler container object
            IContainer container = IContainer.make();
    
            // Tell Xuggler about the device format
            IContainerFormat format = IContainerFormat.make();
            if (format.setInputFormat(driverName) < 0) {
                throw new IllegalArgumentException("couldn't open webcam device: " + driverName);
            }
    
            // devices, unlike most files, need to have parameters set in order
            // for Xuggler to know how to configure them, for a webcam, these
            // parameters make sense
            IMetaData params = IMetaData.make();
    
            params.setValue("framerate", "30/1");
            params.setValue("video_size", "320x240");
    
    
            // Open up the container
            int retval = container.open(deviceName, IContainer.Type.READ, format,
                    false, true, params, null);
            if (retval < 0) {
                // This little trick converts the non friendly integer return value into
                // a slightly more friendly object to get a human-readable error name
                IError error = IError.make(retval);
                throw new IllegalArgumentException("could not open file: " + deviceName + "; Error: " + error.getDescription());
            }
    
            // 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() == ICodec.Type.CODEC_TYPE_VIDEO) {
                    videoStreamId = i;
                    videoCoder = coder;
                    break;
                }
            }
            if (videoStreamId == -1) {
                throw new RuntimeException("could not find video stream in container: " + deviceName);
            }
    
            /*
             * Now we have found the video stream in this file.  Let's open up our decoder so it can
             * do work.
             */
            if (videoCoder.open() < 0) {
                throw new RuntimeException("could not open video decoder for container: " + deviceName);
            }
    
            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: " + deviceName);
                }
            }
    
    
            /*
             * Now, we start walking through the container looking at each packet.
             */
            IPacket packet = IPacket.make();
    
            long start = System.currentTimeMillis();
            int i = 0;
            while (container.readNextPacket(packet) >= 0 && i < 100) {
                /*
                 * Now we have a packet, let's see if it belongs to our video stream
                 */
                if (packet.getStreamIndex() == videoStreamId) {
                    /*
                     * We allocate a new picture to get the data out of Xuggler
                     */
                    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: " + deviceName);
                        }
                        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: " + deviceName);
                                }
                            }
                            if (newPic.getPixelType() != IPixelFormat.Type.BGR24) {
                                throw new RuntimeException("could not decode video as BGR 24 bit data in: " + deviceName);
                            }
    
                            // Convert the BGR24 to an Java buffered image
                            BufferedImage javaImage = Utils.videoPictureToImage(newPic);   
    
                            System.out.println("Capture frame " + i);
    
                            BufferedImage image = ConverterFactory.convertToType(javaImage, BufferedImage.TYPE_3BYTE_BGR);
                            IConverter converter = ConverterFactory.createConverter(image, IPixelFormat.Type.YUV420P);
    
                            IVideoPicture frame = converter.toPicture(image, (System.currentTimeMillis() - start) * 1000);
                            frame.setKeyFrame(i == 0);
                            frame.setQuality(0);
    
                            writer.encodeVideo(0, frame);          
    
                            i++;
                        }
    
                    }
    
                } else {
                    /*
                     * This packet isn't part of our video stream, so we just silently drop it.
                     */
                    do {
                    } while (false);
                }
    
            }
    
            writer.close();
    
            System.out.println("Video recorded in file: " + file.getAbsolutePath());
        }
    }
    

    更新:在 Raspberry Pi Model B+ 上测试上述代码时,它会录制视频,但在观看录制的视频时,它似乎处于“fast-fordward”模式。所以代码不好,因为 raspberry 在编码视频时比功能强大的笔记本电脑(Windows 8.1)花费更多的时间。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-09-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多