java 音频解码_java视频音频解码-封装xuggle-实现多种视频编码格式解码扩展

本文介绍了一个Java项目中如何利用Xuggler库扩展支持多种视频编码格式的解码,包括avi、flv、mov等。通过封装Xuggler 5.4版本,实现了从JMF和OpenCV Jni的局限性中解脱,支持了更多的视频格式解码。文章提供了详细的代码示例,展示了如何读取、解码并处理视频帧。
摘要由CSDN通过智能技术生成

手头做一个视频相关项目,但是客户发来的测试视频(avi格式) 现有组件不能解码。现有

视频解码组件方案有基于JMF和opencv Jni调用。远远不能满足目前市面上玲琅满目的各种视频编码

标准。

进行检索 找到xuggler官方主页:http://www.xuggle.com/xuggler  对5.4版本进行简单封装,实现现有组件接口。需要slf4j包支持。实现了从现有组件只能支持摄像头和特定编码AVI文件到多种编码格式视频解码的支持。

经过测试至少支持 flv mov avi mpg wmv mp4 mkv 这些格式的视频解码。

实现代码如下:

package edu.zjut.framecollector;

import java.awt.image.BufferedImage;

import java.io.File;

import javax.media.ControllerEvent;

import javax.media.ControllerListener;

import javax.swing.JFileChooser;

import com.xuggle.xuggler.Global;

import com.xuggle.xuggler.ICodec;

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;

/**

* @author 田旭园 E-mail: tianxuyuan@yahoo.com.cn

* @version 1.0 创建时间:2012-8-14 下午07:11:02

* @说明 AVI视频采集 解码 可对多种格式音频视频进行解码编码 http://blog.xuggle.com/

* @说明 JMF和opencv对各种视频编码格式的 不给力 学习AVIFrameCollector.java,进行对xuggler简单封装使用

* @说明 不需要有安装JMF 但是需要导入xuggle-xuggler-5.4.jar 和 slf4j库

*/

public class AVIFrameCollectorOnXuggle extends FrameCollector implements

ControllerListener {

private int step = 1;

IContainer container = null;

IStreamCoder videoCoder = null;

IPacket packet;

long firstTimestampInStream = Global.NO_PTS;

long systemClockStartTime = 0;

int videoStreamId = -1;

String filename;

IVideoResampler resampler = null;

@Override

public void close() {

if (videoCoder != null) {

videoCoder.close();

videoCoder = null;

}

if (container != null) {

container.close();

container = null;

}

}

@Override

public BufferedImage getCurrentFrame() {

BufferedImage javaImage = null;

while (container.readNextPacket(packet) >= 0) {

/*

* 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: " + 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);

/**

* We could just display the images as quickly as we

* decode them, but it turns out we can decode a lot

* faster than you think.

*

* So instead, the following code does a poor-man's

* version of trying to match up the frame-rate

* requested for each IVideoPicture with the system

* clock time on your computer.

*

* Remember that all Xuggler IAudioSamples and

* IVideoPicture objects always give timestamps in

* Microseconds, relative to the first decoded item. If

* instead you used the packet timestamps, they can be

* in different units depending on your IContainer, and

* IStream and things can get hairy quickly.

*/

if (firstTimestampInStream == Global.NO_PTS) {

// This is our first time through

firstTimestampInStream = picture.getTimeStamp();

// get the starting clock time so we can hold up

// frames

// until the right time.

systemClockStartTime = System.currentTimeMillis();

} else {

long systemClockCurrentTime = System

.currentTimeMillis();

long millisecondsClockTimeSinceStartofVideo = systemClockCurrentTime

- systemClockStartTime;

// compute how long for this frame since the first

// frame in the

// stream.

// remember that IVideoPicture and IAudioSamples

// timestamps are

// always in MICROSECONDS,

// so we divide by 1000 to get milliseconds.

long millisecondsStreamTimeSinceStartOfVideo = (picture

.getTimeStamp() - firstTimestampInStream) / 1000;

final long millisecondsTolerance = 50; // and we

// give

// ourselfs

// 50 ms of

// tolerance

final long millisecondsToSleep = (millisecondsStreamTimeSinceStartOfVideo - (millisecondsClockTimeSinceStartofVideo + millisecondsTolerance));

if (millisecondsToSleep > 0) {

try {

Thread.sleep(millisecondsToSleep);

} catch (InterruptedException e) {

// we might get this when the user closes

// the dialog box, so

// just return from the method.

return null;

}

}

}

// And finally, convert the BGR24 to an Java buffered

// image

javaImage = Utils.videoPictureToImage(newPic);

return javaImage;

}

}

} else {

/*

* This packet isn't part of our video stream, so we just

* silently drop it.

*/

do {

} while (false);

}

}

return javaImage;

}

@Override

public FrameCollectorMode getMode() {

return FrameCollectorMode.AVI_FILE;

}

/**

*

* 使用用户定义的连接参数打开AVI视频文件。

*

*

* @param fileURL

* AVI视频文件的地址

* @param strStep

* 指定avi文件的播放速度,即每次跳帧的步进,调用时请注意给定的字符串要可以转换为整型。 1为正常速度,2为两倍速度,....

* @return true,如果成功打开,否则返回false

* @since 1.0

*/

@Override

public boolean open(String fileURL, String strStep) {

// fileURL="file:/F:/组件和项目/图像质量诊断工程/vedio/视频文件/亮度1.avi";

// 打开AVI视频文件

if (fileURL == null) {

return open();

}

if ((fileURL.substring(0, 6)).equals("file:/")) {

fileURL = fileURL.substring(6);

// System.out.println(" dfsfjasjf "+fileURL);

}

try {

step = Integer.parseInt(strStep);

} catch (NumberFormatException ex) {

step = 1;

}

return setupPlayer(fileURL);

}

/**

*

* 通过打开对话框打开指定AVI视频文件。

*

*

* @return true,如果成功打开,否则返回false

* @since 1.0

*/

@Override

public boolean open() {

// 从文件对话框中选择AVI文件

JFileChooser chooser = new JFileChooser();

chooser.setAcceptAllFileFilterUsed(false);

int result = chooser.showOpenDialog(null);

if (result == JFileChooser.CANCEL_OPTION) {

return false;

}

File file = chooser.getSelectedFile();

String fileURL = null;

try {

fileURL = file.getAbsolutePath();

System.out.println(fileURL);

} catch (Exception e) {

return false;

}

// 打开AVI视频文件

return setupPlayer(fileURL);

}

@Override

public void controllerUpdate(ControllerEvent arg0) {

// TODO Auto-generated method stub

}

/**

*

* Initialize the Player object.

*

*

* @param fileURL

* The selected file's URL

* @return true if set up the player successfully, false otherwise

*/

private boolean setupPlayer(String filename) {

this.filename = filename;

System.out.println(filename + " ==============");

// 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

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

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: " + filename);

/*

* 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: " + filename);

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);

}

/*

* Now, we start walking through the container looking at each packet.

*/

packet = IPacket.make();

return true;

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值