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/3001(s)
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的事情,视频转换和视频修改:)