当前位置: 首页 > 面试题库 >

如何通过编程将图像编码为Java中的视频文件?

东郭弘方
2023-03-14
问题内容

我正在尝试使用将具有相同分辨率的一些图像编码到视频文件中,为此,我尝试:

编解码器

  • jcodec ..example

但这非常耗时,并且不是编码大量图像的合适工具,并且创建时间快速延长。

音频MPEG

  • FFMPEG ..example 描述

但是ffmpeg只能从图像文件创建视频。需要在物理系统上创建映像。

我听说Xuggler可以在Java程序中使用它的API创建视频文件,但是它的站点似乎坏了。我无法尝试。

有人知道如何将Java格式的图像编码成视频文件吗?请帮助!

提前致谢 !


问题答案:

Xuggler被 弃用
,用谦卑视频代替。它已经带有一些演示项目,包括如何获取屏幕截图并将其转换为视频文件:RecordAndEncodeVideo.java

/*******************************************************************************
 * Copyright (c) 2014, Art Clarke.  All rights reserved.
 * <p>
 * This file is part of Humble-Video.
 * <p>
 * Humble-Video is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * <p>
 * Humble-Video is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 * <p>
 * You should have received a copy of the GNU Affero General Public License
 * along with Humble-Video.  If not, see <http://www.gnu.org/licenses/>.
 *******************************************************************************/
package io.humble.video.demos;

import io.humble.video.*;
import io.humble.video.awt.MediaPictureConverter;
import io.humble.video.awt.MediaPictureConverterFactory;
import org.apache.commons.cli.*;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;

/**
 * Records the contents of your computer screen to a media file for the passed in duration.
 * This is meant as a demonstration program to teach the use of the Humble API.
 * <p>
 * Concepts introduced:
 * </p>
 * <ul>
 * <li>Muxer: A {@link Muxer} object is a container you can write media data to.</li>
 * <li>Encoders: An {@link Encoder} object lets you convert {@link MediaAudio} or {@link MediaPicture} objects into {@link MediaPacket} objects
 * so they can be written to {@link Muxer} objects.</li>
 * </ul>
 *
 * <p>
 * To run from maven, do:
 * </p>
 * <pre>
 * mvn install exec:java -Dexec.mainClass="io.humble.video.demos.RecordAndEncodeVideo" -Dexec.args="filename.mp4"
 * </pre>
 *
 * @author aclarke
 *
 */
public class RecordAndEncodeVideo
{
    /**
     * Records the screen
     */
    private static void recordScreen (String filename, String formatname, String codecname, int duration, int snapsPerSecond) throws AWTException, InterruptedException, IOException
    {
        /**
         * Set up the AWT infrastructure to take screenshots of the desktop.
         */
        final Robot robot = new Robot();
        final Toolkit toolkit = Toolkit.getDefaultToolkit();
        final Rectangle screenbounds = new Rectangle(toolkit.getScreenSize());

        final Rational framerate = Rational.make(1, snapsPerSecond);

        /** First we create a muxer using the passed in filename and formatname if given. */
        final Muxer muxer = Muxer.make(filename, null, formatname);

        /** Now, we need to decide what type of codec to use to encode video. Muxers
         * have limited sets of codecs they can use. We're going to pick the first one that
         * works, or if the user supplied a codec name, we're going to force-fit that
         * in instead.
         */
        final MuxerFormat format = muxer.getFormat();
        final Codec codec;
        if (codecname != null)
        {
            codec = Codec.findEncodingCodecByName(codecname);
        }
        else
        {
            codec = Codec.findEncodingCodec(format.getDefaultVideoCodecId());
        }

        /**
         * Now that we know what codec, we need to create an encoder
         */
        Encoder encoder = Encoder.make(codec);

        /**
         * Video encoders need to know at a minimum:
         *   width
         *   height
         *   pixel format
         * Some also need to know frame-rate (older codecs that had a fixed rate at which video files could
         * be written needed this). There are many other options you can set on an encoder, but we're
         * going to keep it simpler here.
         */
        encoder.setWidth(screenbounds.width);
        encoder.setHeight(screenbounds.height);
        // We are going to use 420P as the format because that's what most video formats these days use
        final PixelFormat.Type pixelformat = PixelFormat.Type.PIX_FMT_YUV420P;
        encoder.setPixelFormat(pixelformat);
        encoder.setTimeBase(framerate);

        /** An annoynace of some formats is that they need global (rather than per-stream) headers,
         * and in that case you have to tell the encoder. And since Encoders are decoupled from
         * Muxers, there is no easy way to know this beyond
         */
        if (format.getFlag(MuxerFormat.Flag.GLOBAL_HEADER))
        {
            encoder.setFlag(Encoder.Flag.FLAG_GLOBAL_HEADER, true);
        }

        /** Open the encoder. */
        encoder.open(null, null);


        /** Add this stream to the muxer. */
        muxer.addNewStream(encoder);

        /** And open the muxer for business. */
        muxer.open(null, null);

        /** Next, we need to make sure we have the right MediaPicture format objects
         * to encode data with. Java (and most on-screen graphics programs) use some
         * variant of Red-Green-Blue image encoding (a.k.a. RGB or BGR). Most video
         * codecs use some variant of YCrCb formatting. So we're going to have to
         * convert. To do that, we'll introduce a MediaPictureConverter object later. object.
         */
        MediaPictureConverter converter = null;
        final MediaPicture picture = MediaPicture.make(encoder.getWidth(), encoder.getHeight(), pixelformat);
        picture.setTimeBase(framerate);

        /** Now begin our main loop of taking screen snaps.
         * We're going to encode and then write out any resulting packets. */
        final MediaPacket packet = MediaPacket.make();
        for (int i = 0; i < duration / framerate.getDouble(); i++)
        {
            /** Make the screen capture && convert image to TYPE_3BYTE_BGR */
            final BufferedImage screen = convertToType(robot.createScreenCapture(screenbounds), BufferedImage.TYPE_3BYTE_BGR);

            /** This is LIKELY not in YUV420P format, so we're going to convert it using some handy utilities. */
            if (converter == null)
            {
                converter = MediaPictureConverterFactory.createConverter(screen, picture);
            }
            converter.toPicture(picture, screen, i);

            do
            {
                encoder.encode(packet, picture);
                if (packet.isComplete())
                {
                    muxer.write(packet, false);
                }
            } while (packet.isComplete());

            /** now we'll sleep until it's time to take the next snapshot. */
            Thread.sleep((long) (1000 * framerate.getDouble()));
        }

        /** Encoders, like decoders, sometimes cache pictures so it can do the right key-frame optimizations.
         * So, they need to be flushed as well. As with the decoders, the convention is to pass in a null
         * input until the output is not complete.
         */
        do
        {
            encoder.encode(packet, null);
            if (packet.isComplete())
            {
                muxer.write(packet, false);
            }
        } while (packet.isComplete());

        /** Finally, let's clean up after ourselves. */
        muxer.close();
    }

    @SuppressWarnings("static-access")
    public static void main (String[] args) throws InterruptedException, IOException, AWTException
    {
        final Options options = new Options();
        options.addOption("h", "help", false, "displays help");
        options.addOption("v", "version", false, "version of this library");
        options.addOption(OptionBuilder.withArgName("format").withLongOpt("format").hasArg().
                withDescription("muxer format to use. If unspecified, we will guess from filename").create("f"));
        options.addOption(OptionBuilder.withArgName("codec")
                .withLongOpt("codec")
                .hasArg()
                .withDescription("codec to use when encoding video; If unspecified, we will guess from format")
                .create("c"));
        options.addOption(OptionBuilder.withArgName("duration")
                .withLongOpt("duration")
                .hasArg()
                .withDescription("number of seconds of screenshot to record; defaults to 10.")
                .create("d"));
        options.addOption(OptionBuilder.withArgName("snaps per second")
                .withLongOpt("snaps")
                .hasArg()
                .withDescription("number of pictures to take per second (i.e. the frame rate); defaults to 5")
                .create("s"));

        final CommandLineParser parser = new org.apache.commons.cli.BasicParser();
        try
        {
            final CommandLine cmd = parser.parse(options, args);
            final String[] parsedArgs = cmd.getArgs();
            if (cmd.hasOption("version"))
            {
                // let's find what version of the library we're running
                final String version = io.humble.video_native.Version.getVersionInfo();
                System.out.println("Humble Version: " + version);
            }
            else if (cmd.hasOption("help") || parsedArgs.length != 1)
            {
                final HelpFormatter formatter = new HelpFormatter();
                formatter.printHelp(RecordAndEncodeVideo.class.getCanonicalName() + " <filename>", options);
            }
            else
            {
                /**
                 * Read in some option values and their defaults.
                 */
                final int duration = Integer.parseInt(cmd.getOptionValue("duration", "10"));
                if (duration <= 0)
                {
                    throw new IllegalArgumentException("duration must be > 0");
                }
                final int snaps = Integer.parseInt(cmd.getOptionValue("snaps", "5"));
                if (snaps <= 0)
                {
                    throw new IllegalArgumentException("snaps must be > 0");
                }
                final String codecname = cmd.getOptionValue("codec");
                final String formatname = cmd.getOptionValue("format");
                final String filename = cmd.getArgs()[0];

                recordScreen(filename, formatname, codecname, duration, snaps);
            }
        } catch (ParseException e)
        {
            System.err.println("Exception parsing command line: " + e.getLocalizedMessage());
        }
    }

    /**
     * Convert a {@link BufferedImage} of any type, to {@link BufferedImage} of a
     * specified type. If the source image is the same type as the target type,
     * then original image is returned, otherwise new image of the correct type is
     * created and the content of the source image is copied into the new image.
     *
     * @param sourceImage
     *          the image to be converted
     * @param targetType
     *          the desired BufferedImage type
     *
     * @return a BufferedImage of the specifed target type.
     *
     * @see BufferedImage
     */
    public static BufferedImage convertToType (BufferedImage sourceImage, int targetType)
    {
        BufferedImage image;

        // if the source image is already the target type, return the source image

        if (sourceImage.getType() == targetType)
        {
            image = sourceImage;
        }

        // otherwise create a new image of the target type and draw the new
        // image

        else
        {
            image = new BufferedImage(sourceImage.getWidth(), sourceImage.getHeight(), targetType);
            image.getGraphics().drawImage(sourceImage, 0, 0, null);
        }

        return image;
    }
}

也查看其他演示:humble-video-demos

我正在Webapp上实时使用它。

如果要实时流式传输,则需要RTSP服务器。您可以使用Red
5 Server
,Wowza Streaming
Engine之
类的大型框架,也可以使用Netty构建您自己的服务器,Netty自3.2版以来具有内置的RTSP编解码器。



 类似资料:
  • 问题内容: 您能否指导我如何将图像从URL转换为base64编码? 问题答案: 我认为应该是:

  • 问题内容: 我有一些JavaScript代码可将图像上传到服务器。下面是可以正常工作的ajax调用。 我现在需要将图像上传为base64编码,例如 但这是行不通的,即服务器无法识别我发送和抱怨的数据。 有谁知道在AJAX调用中发送base64编码数据的正确格式是什么? 问题答案: 感谢所有帮助我前进的答案。 我也已在 https://social.msdn.microsoft.com/Forums

  • 我有一个编码为base64的SVG文件,我想用ImageView显示图像。这是我尝试过的: 但是decodedByte总是返回null。 附注: 此代码适用于jpeg图像。 如果Bas64字符串包含Bas64前缀("data: Image/svg xml; Bas64,"或"data: Image/jpeg; Bas64,),则decdedByte也总是返回null Bas64字符串是正确的(它在

  • 我正在使用一个在线服务,它需要一个Base64中的映像。我已经完成了一个简单的表单,我可以上传一个图像,然后我的php将图像编码为base 64,如下所示: base64_encode(file_get_contents(_FILES图像]tmp_name); 然后,我将其传递到一个json数组中,另一个页面尝试用我的数据显示图像,但失败了(缺少图像图标),在Chrome控制台中出现错误: img

  • 我想把base64编码的字符串转换成位图,这样我就可以把它放在图像视图中,但是得到的错误像