Xuggler tutorial 1 使用xuggle进行视频操作(译+修改)

Fri 13 December 2013 by XiaomengZhao
原文网址:http://www.javacodegeeks.com/2011/02/introduction-xuggler-video-manipulation.html

随着互联网视频数量的爆发,开发者需要在他们的应用中非常频繁地操作视频数据。Xuggle为Java开发者提供的开源的库,能够解压,处理和压缩存储的视频数据和实时的现场直播的视频数据。Xuggle使用了非常强有力的FFmpeg媒体操作库,是FFPEG的Java Wrapper,使得开发能够使用Java更好的解压,修改媒体文件。

FFmpeg是一个完整的,跨平台的用来记录,转换,流式化音频和视频文件,支持多种格式。可能您不清楚你在使用它,但是其实你已经在使用了。但是,Xuggle不仅仅是提供给你使用复杂的FFmpeg的简单方法。Xuggle dev团队还在帮助优化FFmpeg。

然后我们需要安装FFmpeg。注意Xuggle自带了FFmpeg(优化过的)来避免错误的配置,所以你不需要自己手动的获取FFmpeg。但是在这个教程中,我们在使用Xuggle之前,需要使用FFmpeg测试一些操作,所以我们需要先分开安装FFmpeg。

FFmpeg下载页下载。Linux可以下载源代码然后编译(注:Linux其实也有编译好的包)。而Windows的话,可以下载编译好的二进制包,然后可以找到ffmpeg.exe执行程序。将它拷贝到特定目录,并将这个目录加到windows的环境变量中。

为了检查FFmpeg是否正常工作,我们可以直接输入FFmpeg。你可以看到类似的输出:

ffmpeg version 2.1.1-tessus Copyright (c) 2000-2013 the FFmpeg developers
built on Nov 21 2013 13:33:40 with llvm-gcc 4.2.1 (LLVM build 2336.1.00)
configuration: -- prefix=/Users/tessus/data/ext/ffmpeg/sw --as=yasm --extra-version=tessus --disable-shared --enable-static --disable-ffplay --enable-gpl --enable-pthreads --enable-postproc --enable-libmp3lame --enable-libtheora --enable-libvorbis --enable-libx264 --enable-libxvid --enable-libspeex --enable-bzlib --enable-zlib --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libxavs --enable-version3 --enable-libvo-aacenc --enable-libvo-amrwbenc --enable-libvpx --enable-libgsm --enable-libopus --enable-fontconfig --enable-libfreetype --enable-libass --enable-libbluray --enable-filters --enable-runtime-cpudetect
libavutil      52. 48.101 / 52. 48.101
libavcodec     55. 39.101 / 55. 39.101
libavformat    55. 19.104 / 55. 19.104
libavdevice    55.  5.100 / 55.  5.100
libavfilter     3. 90.100 /  3. 90.100
libswscale      2.  5.101 /  2.  5.101
libswresample   0. 17.104 /  0. 17.104
libpostproc    52.  3.100 / 52.  3.100
Hyper fast Audio and Video encoder
usage: ffmpeg [options] [[infile options] -i infile]... {[outfile options] outfile}...

Use -h to get full help or, even better, run 'man ffmpeg'

首先转化你的第一个视频。我的输入是MP4格式,想要转化成Flash,显然会降低质量。完成这项任务的命令式: ffmpeg -i test.mp4 test.flv。 然后这篇文章说明怎么配置xuggle。过去xuggle需要安装,但是现在只需要新建一个maven工程,并在其中添加:

<repositories>
  <repository>
   <id>xuggle repo</id>
   <url>http://xuggle.googlecode.com/svn/trunk/repo/share/java/</url>
  </repository>
</repositories>

<dependencies>
 <dependency>
  <groupId>xuggle</groupId>
  <artifactId>xuggle-xuggler</artifactId>
  <version>5.2</version>
 </dependency>
</dependencies>

下面写我们的第一个Xuggle程序:

package edu.bupt.videodatacenter.try_xuggle;
import com.xuggle.xuggler.ICodec;
import com.xuggle.xuggler.IContainer;
import com.xuggle.xuggler.IStream;
import com.xuggle.xuggler.IStreamCoder;

public class VideoInfo {

    private static final String filename = "/Users/zhaoxm/InBUPT/test_videos/te2.avi";

    public static void main(String[] args) {

        // first we create a Xuggler container object
        IContainer container = IContainer.make();

        // we attempt to open up the container
        int result = container.open(filename, IContainer.Type.READ, null);

        // check if the operation was successful
        if (result<0)
            throw new RuntimeException("Failed to open media file");

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

        // query for the total duration
        long duration = container.getDuration();

        // query for the file size
        long fileSize = container.getFileSize();

        // query for the bit rate
        long bitRate = container.getBitRate();

        System.out.println("Number of streams: " + numStreams);
        System.out.println("Duration (ms): " + duration);
        System.out.println("File Size (bytes): " + fileSize);
        System.out.println("Bit Rate: " + bitRate);

        // iterate through the streams to print their meta data
        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();

            System.out.println("*** Start of Stream Info ***");

            System.out.printf("stream %d: ", i);
            System.out.printf("type: %s; ", coder.getCodecType());
            System.out.printf("codec: %s; ", coder.getCodecID());
            System.out.printf("duration: %s; ", stream.getDuration());
            System.out.printf("start time: %s; ", container.getStartTime());
            System.out.printf("timebase: %d/%d; ",
                 stream.getTimeBase().getNumerator(),
                 stream.getTimeBase().getDenominator());
            System.out.printf("coder tb: %d/%d; ",
                 coder.getTimeBase().getNumerator(),
                 coder.getTimeBase().getDenominator());
            System.out.println();

            if (coder.getCodecType() == ICodec.Type.CODEC_TYPE_AUDIO) {
                System.out.printf("sample rate: %d; ", coder.getSampleRate());
                System.out.printf("channels: %d; ", coder.getChannels());
                System.out.printf("format: %s", coder.getSampleFormat());
            } 
            else if (coder.getCodecType() == ICodec.Type.CODEC_TYPE_VIDEO) {
                System.out.printf("width: %d; ", coder.getWidth());
                System.out.printf("height: %d; ", coder.getHeight());
                System.out.printf("format: %s; ", coder.getPixelType());
                System.out.printf("frame-rate: %5.2f; ", coder.getFrameRate().getDouble());
            }

            System.out.println();
            System.out.println("*** End of Stream Info ***");         
        }   
    }
}
输出是:
Number of streams: 1
Duration (ms): 92055565
File Size (bytes): 19711174
Bit Rate: 1712980
*** Start of Stream Info ***
stream 0: type: CODEC_TYPE_VIDEO; codec: CODEC_ID_H264; duration: 2759; start   time: 0; timebase: 1001/30001; coder tb: 1/48; 
width: 720; height: 480; format: YUV420P; frame-rate: 29.97; 
*** End of Stream Info ***

我们先创建一个IContainer实例,它包含了一个或者多个音频流或数据流,然后我们用它打开一个媒体文件。如果操作成功,我们能得到Container中有多少流Stream,还有持续时间,文件大小和比特率。

以上这些信息都是关于Container的。但是,我们能够获得关于每个流的元数据。我们可以使用getStream方法来获取每个流的引用,然后ISreamCoder是一个解码器能够解码特定的流。对于这个获得的解码器,我们能够知道流的codec type(如CODEC_TYPE_VIDEO), codec ID(如CODEC_ID_H264)和其他一些信息。

最终,我们能够区分音频和视频流。对于音频流,我们能够找到采样频率,频道数目,音频的采样格式。同时,对于视频流,我们能够得到维度信心(高度和宽度),像素格式和频率。

其中一些函数的作用:

public long getDuration()

Return the duration, in getTimeBase() units, of this stream, or Global.NO_PTS if unknown.
Returns:
The duration (in getTimeBase units) of this stream, if known
TimeBase为单位返回视频的持续时间。
以我们的示例视频为例:
真正的持续时间是1:32s = 92s
getDuration返回:2759 getTimebase返回:1001/3001s
2759*(1001/3001) = 92s

public IRational getFrameRate()

Get the (sometimes estimated) frame rate of this container. an approimation. Better to use getTimeBase(). For contant frame-rate containers, this will be 1 ( getTimeBase() )
一般都是近似值,最好用getTimeBase()
Returns:
The frame-rate of this container.

后面的教程会使用Xuggler和FFmpeg来做一些很Cool的事情,视频转换和视频修改:)


Comments

Fork me on GitHub