java图片和视频上传_Java实现视频网站的视频上传、视频转码、视频关键帧抽图, 及视频播放功能(转)...

本文介绍了如何使用Java实现视频网站的视频上传、转码为FLV格式、视频关键帧抽图及播放功能。利用FFmpeg进行视频处理,包括视频格式转换和截图,并展示了相关数据库设计、表单提交、业务接口定义和DAO实现。最后,通过Servlet控制器处理上传请求,使用Flash播放器播放视频。
摘要由CSDN通过智能技术生成

视频网站中提供的在线视频播放功能,播放的都是FLV格式的文件,它是Flash动画文件,可通过Flash制作的播放器来播放该文件.项目中用制作的player.swf播放器.

多媒体视频处理工具FFmpeg有非常强大的功能包括视频采集功能、视频格式转换、视频抓图、给视频加水印等。

ffmpeg视频采集功能非常强大,不仅可以采集视频采集卡或USB摄像头的图像,还可以进行屏幕录制,同时还支持以RTP方式将视频流传送给支持RTSP的流媒体服务器,支持直播应用。

1.能支持的格式

ffmpeg能解析的格式:(asx,asf,mpg,wmv,3gp,mp4,mov,avi,flv等)

2.不能支持的格式

对ffmpeg无法解析的文件格式(wmv9,rm,rmvb等),可以先用别的工具(mencoder)转换为avi(ffmpeg能解析的)格式.

实例是将上传视频转码为flv格式,该格式ffmpeg支持,所以我们实例中需要ffmpeg视频处理工具.

数据库MySQL5.5

实例所需要的数据库脚本

ab0593580b8a23ca29465519f193803b.pngdrop database if existsdb_mediaplayer;create databasedb_mediaplayer;usedb_mediaplayer;create tabletb_media(

idint not null primary key auto_increment comment '主键',

titlevarchar(50) not null comment '视频名称',

srcvarchar(200) not null comment '视频存放地址',

picturevarchar(200) not null comment '视频截图',

descriptvarchar(400) comment '视频描述',

uptimevarchar(40) comment '上传时间');desc tb_media;

f59b18f01a79f60e4b6d01ed1f20899f.png

项目结构图:

ee9f0ec6f239241e40db650f60a4dc16.png

上传视频界面设计

在上传文件时,Form表单中 enctype属性值必须为"multipart/form-data".模块界面设计如下图:

8240deb2bf34ec4741bbc9b7951b83d3.png

enctype属性值说明

application/x-www-form-urlencoded

表单数据被编码为名称/值对,这是标准的编码格式

multipart/form-data

表单数据被编码为一条消息,页面上每个控件对应消息中的一部分

text/plain

表单数据以纯文本形式进行编码,其中不含任何控件格式的字符

业务接口定义

面向接口编程,接口中定义系统功能模块.这样方便理清业务,同时接口的对象必须由实现了该接口的对象来创建.这样就避免编码中的某些业务遗漏等,同时扩展性也增强了.

6355004e709baac893b2265c9eccfefa.pngpackagecom.webapp.dao;importjava.util.List;importcom.webapp.entity.Media;/***

* MediaDao.java

*

*@version: 1.1

*

*@author: 苏若年 发送邮件

*

*@since: 1.0 创建时间: 2013-2-07 上午10:19:54

*

* TODO : interface MediaDao.java is used for ...

**/public interfaceMediaDao {/*** 视频转码

*@paramffmpegPath 转码工具的存放路径

*@paramupFilePath 用于指定要转换格式的文件,要截图的视频源文件

*@paramcodcFilePath 格式转换后的的文件保存路径

*@parammediaPicPath 截图保存路径

*@return*@throwsException*/public boolean executeCodecs(String ffmpegPath,String upFilePath, String codcFilePath, String mediaPicPath)throwsException;/*** 保存文件

*@parammedia

*@return*@throwsException*/public boolean saveMedia(Media media)throwsException;/*** 查询本地库中所有记录的数目

*@return*@throwsException*/public int getAllMediaCount()throwsException;/*** 带分页的查询

*@paramfirstResult

*@parammaxResult

*@return*/public List queryALlMedia(int firstResult, int maxResult)throwsException;/*** 根据Id查询视频

*@paramid

*@return*@throwsException*/public Media queryMediaById(int id)throwsException;

}

af8624c9cabe4cf383249dd717d77254.png

接口的实现,这里列出ffmpeg视频转码与截图模块

6440e09c525dfd3086bf2052def2f371.png/*** 视频转码

*@paramffmpegPath 转码工具的存放路径

*@paramupFilePath 用于指定要转换格式的文件,要截图的视频源文件

*@paramcodcFilePath 格式转换后的的文件保存路径

*@parammediaPicPath 截图保存路径

*@return*@throwsException*/public booleanexecuteCodecs(String ffmpegPath, String upFilePath, String codcFilePath,

String mediaPicPath)throwsException {//创建一个List集合来保存转换视频文件为flv格式的命令

List convert = new ArrayList();

convert.add(ffmpegPath);//添加转换工具路径

convert.add("-i"); //添加参数"-i",该参数指定要转换的文件

convert.add(upFilePath); //添加要转换格式的视频文件的路径

convert.add("-qscale"); //指定转换的质量

convert.add("6");

convert.add("-ab"); //设置音频码率

convert.add("64");

convert.add("-ac"); //设置声道数

convert.add("2");

convert.add("-ar"); //设置声音的采样频率

convert.add("22050");

convert.add("-r"); //设置帧频

convert.add("24");

convert.add("-y"); //添加参数"-y",该参数指定将覆盖已存在的文件convert.add(codcFilePath);//创建一个List集合来保存从视频中截取图片的命令

List cutpic = new ArrayList();

cutpic.add(ffmpegPath);

cutpic.add("-i");

cutpic.add(upFilePath);//同上(指定的文件即可以是转换为flv格式之前的文件,也可以是转换的flv文件)

cutpic.add("-y");

cutpic.add("-f");

cutpic.add("image2");

cutpic.add("-ss"); //添加参数"-ss",该参数指定截取的起始时间

cutpic.add("17"); //添加起始时间为第17秒

cutpic.add("-t"); //添加参数"-t",该参数指定持续时间

cutpic.add("0.001"); //添加持续时间为1毫秒

cutpic.add("-s"); //添加参数"-s",该参数指定截取的图片大小

cutpic.add("800*280"); //添加截取的图片大小为350*240

cutpic.add(mediaPicPath); //添加截取的图片的保存路径boolean mark = true;

ProcessBuilder builder= newProcessBuilder();try{

builder.command(convert);

builder.redirectErrorStream(true);

builder.start();

builder.command(cutpic);

builder.redirectErrorStream(true);//如果此属性为 true,则任何由通过此对象的 start() 方法启动的后续子进程生成的错误输出都将与标准输出合并,//因此两者均可使用 Process.getInputStream() 方法读取。这使得关联错误消息和相应的输出变得更容易builder.start();

}catch(Exception e) {

mark= false;

System.out.println(e);

e.printStackTrace();

}returnmark;

}

50cee23cee86835c3a5ef24030ed1f6f.png

系统中可能存在多个模块,这些模块的业务DAO可以通过工厂来管理,需要的时候直接提供即可.

因为如果对象new太多,会不必要的浪费资源.所以工厂,采用单例模式,私有构造,提供对外可访问的方法即可.

f383736f3a60daa39137c2ca55459f75.pngpackagecom.webapp.dao;importcom.webapp.dao.impl.MediaDaoImpl;/***

* DaoFactory.java

*

*@version: 1.1

*

*@author: 苏若年 发送邮件

*

*@since: 1.0 创建时间: 2013-2-07 下午02:18:51

*

* TODO : class DaoFactory.java is used for ...

**/public class DaoFactory { //工厂模式,生产Dao对象,面向接口编程,返回实现业务接口定义的对象private static DaoFactory daoFactory = newDaoFactory();//单例设计模式, 私有构造,对外提供获取创建的对象的唯一接口,privateDaoFactory(){

}public staticDaoFactory getInstance(){returndaoFactory;

}public staticMediaDao getMediaDao(){return newMediaDaoImpl();

}

}

3a043a39df6aa129a6f067a7418bc271.png

视图提交请求,给控制器,控制器分析请求参数,进行相应的业务调用处理.servlet控制器相关代码如下

81d8183b500b16a5ef86880ef647ea12.pngpackagecom.webapp.service;importjava.io.File;importjava.io.IOException;importjava.io.PrintWriter;importjava.util.List;importjavax.servlet.ServletContext;importjavax.servlet.ServletException;importjavax.servlet.http.HttpServlet;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importorg.apache.commons.fileupload.FileItem;importorg.apache.commons.fileupload.disk.DiskFileItemFactory;importorg.apache.commons.fileupload.servlet.ServletFileUpload;importcom.webapp.dao.DaoFactory;importcom.webapp.dao.MediaDao;importcom.webapp.entity.Media;importcom.webapp.util.DateTimeUtil;/***

* MediaService.java

*

*@version: 1.1

*

*@author: 苏若年 发送邮件

*

*@since: 1.0 创建时间: 2013-2-08 下午02:24:47

*

* TODO : class MediaService.java is used for ...

**/public class MediaService extendsHttpServlet {public voiddoGet(HttpServletRequest request, HttpServletResponse response)throwsServletException, IOException {

doPost(request, response);

}public voiddoPost(HttpServletRequest request, HttpServletResponse response)throwsServletException, IOException {

PrintWriter out=response.getWriter();

MediaDao mediaDao=DaoFactory.getMediaDao();

String message= "";

String uri=request.getRequestURI();

String path= uri.substring(uri.lastIndexOf("/"), uri.lastIndexOf("."));if("/uploadFile".equals(path)){//提供解析时的一些缺省配置

DiskFileItemFactory factory = newDiskFileItemFactory();//创建一个解析器,分析InputStream,该解析器会将分析的结果封装成一个FileItem对象的集合//一个FileItem对象对应一个表单域

ServletFileUpload sfu = newServletFileUpload(factory);try{

Media media= newMedia();

List items =sfu.parseRequest(request);boolean flag = false; //转码成功与否的标记for(int i=0; i

FileItem item=items.get(i);//要区分是上传文件还是普通的表单域if(item.isFormField()){//isFormField()为true,表示这不是文件上传表单域//普通表单域

String paramName =item.getFieldName();/*String paramValue = item.getString();

System.out.println("参数名称为:" + paramName + ", 对应的参数值为: " + paramValue);*/if(paramName.equals("title")){

media.setTitle(new String(item.getString().getBytes("ISO8859-1"),"UTF-8"));

}if(paramName.equals("descript")){

media.setDescript(new String(item.getString().getBytes("ISO8859-1"),"UTF-8"));

}

}else{//上传文件//System.out.println("上传文件" + item.getName());

ServletContext sctx = this.getServletContext();//获得保存文件的路径

String basePath = sctx.getRealPath("videos");//获得文件名

String fileUrl=item.getName();//在某些操作系统上,item.getName()方法会返回文件的完整名称,即包括路径

String fileType = fileUrl.substring(fileUrl.lastIndexOf(".")); //截取文件格式//自定义方式产生文件名

String serialName =String.valueOf(System.currentTimeMillis());//待转码的文件

File uploadFile = new File(basePath+"/temp/"+serialName +fileType);

item.write(uploadFile);if(item.getSize()>500*1024*1024){

message= "

上传失败!您上传的文件太大,系统允许最大文件500M";

}

String codcFilePath= basePath + "/" + serialName + ".flv"; //设置转换为flv格式后文件的保存路径

String mediaPicPath = basePath + "/images" +File.separator+ serialName + ".jpg"; //设置上传视频截图的保存路径//获取配置的转换工具(ffmpeg.exe)的存放路径

String ffmpegPath = getServletContext().getRealPath("/tools/ffmpeg.exe");

media.setSrc("videos/" + serialName + ".flv");

media.setPicture("videos/images/" +serialName + ".jpg");

media.setUptime(DateTimeUtil.getYMDHMSFormat());//转码flag=mediaDao.executeCodecs(ffmpegPath, uploadFile.getAbsolutePath(), codcFilePath, mediaPicPath);

}

}if(flag){//转码成功,向数据表中添加该视频信息mediaDao.saveMedia(media);

message= "

上传成功!";

}

request.setAttribute("message", message);

request.getRequestDispatcher("media_upload.jsp").forward(request,response);

}catch(Exception e) {

e.printStackTrace();throw newServletException(e);

}

}if("/queryAll".equals(path)){

ListmediaList;try{

mediaList= mediaDao.queryALlMedia(0,5);

request.setAttribute("mediaList", mediaList);

request.getRequestDispatcher("media_list.jsp").forward(request, response);

}catch(Exception e) {

e.printStackTrace();

}

}if("/play".equals(path)){

String idstr= request.getParameter("id");int mediaId = -1;

Media media= null;if(null!=idstr){

mediaId=Integer.parseInt(idstr);

}try{

media=mediaDao.queryMediaById(mediaId);

}catch(Exception e) {

e.printStackTrace();

}

request.setAttribute("media", media);

request.getRequestDispatcher("media_player.jsp").forward(request, response);

}

}

}

4a334ceec7cedf08b190e7e70dedf5ed.png

可以通过分页查找,显示最新top5,展示到首页.相应特效可以使用JS实现.

c7329dae17d05a86bafa340a0ab4afd4.png

相关代码如下:

66de2680dedc9d3e64ce20712e644f7c.png

String basePath= request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%>

视频列表

var sWidth= $("#focus").width(); //获取焦点图的宽度(显示面积)

var len = $("#focus ul li").length; //获取焦点图个数

var index = 0;

var picTimer;//以下代码添加数字按钮和按钮后的半透明条,还有上一页、下一页两个按钮

var btn = "

";for(var i=0; i < len; i++) {

btn+= "";

}

btn+= "

";

$("#focus").append(btn);

$("#focus .btnBg").css("opacity",0.5);//为小按钮添加鼠标滑入事件,以显示相应的内容

$("#focus .btn span").css("opacity",0.4).mouseenter(function() {

index= $("#focus .btn span").index(this);

showPics(index);

}).eq(0).trigger("mouseenter");//上一页、下一页按钮透明度处理

$("#focus .preNext").css("opacity",0.2).hover(function() {

$(this).stop(true,false).animate({"opacity":"0.5"},300);

},function() {

$(this).stop(true,false).animate({"opacity":"0.2"},300);

});//上一页按钮

$("#focus .pre").click(function() {

index-= 1;if(index == -1) {index = len - 1;}

showPics(index);

});//下一页按钮

$("#focus .next").click(function() {

index+= 1;if(index == len) {index = 0;}

showPics(index);

});//本例为左右滚动,即所有li元素都是在同一排向左浮动,所以这里需要计算出外围ul元素的宽度

$("#focus ul").css("width",sWidth *(len));//鼠标滑上焦点图时停止自动播放,滑出时开始自动播放

$("#focus").hover(function() {

clearInterval(picTimer);

},function() {

picTimer=setInterval(function() {

showPics(index);

index++;if(index == len) {index = 0;}

},4000); //此4000代表自动播放的间隔,单位:毫秒

}).trigger("mouseleave");//显示图片函数,根据接收的index值显示相应的内容

function showPics(index) { //普通切换

var nowLeft = -index*sWidth; //根据index值计算ul元素的left值

$("#focus ul").stop(true,false).animate({"left":nowLeft},300); //通过animate()调整ul元素滚动到计算出的position//$("#focus .btn span").removeClass("on").eq(index).addClass("on");//为当前的按钮切换到选中的效果

$("#focus .btn span").stop(true,false).animate({"opacity":"0.4"},300).eq(index).stop(true,false).animate({"opacity":"1"},300); //为当前的按钮切换到选中的效果}

});

最新视频

mediaList = (List)request.getAttribute("mediaList");if(mediaList.size()>0&&mediaList!=null){for(int i=0; i

Media media=mediaList.get(i);%>

}else{%>

没有记录

2196f3a4888529443d41d2b1927fb876.png

首页展示的图片都是带ID的链接请求.图片为视频转码过程中拉取到的图片.点击图片即可发送播放视频请求,

视频播放页面效果如下图所示.

f1872474022611888bb9e6e7bc3f25bb.png

0267ef710ed13e7d8ca3a677a711f651.png

视频播放页面需要在页面中嵌入Flash播放器

代码如下:

a1889f5a8c242989dc70afa779b68051.png

src="tools/player.swf?fileName="width="98%" height="90%">

9558e84fa5866353bf555d9ae3456414.png

相关说明:

元素,加载ActiveX控件,classid属性则指定了浏览器使用的ActiveX空间.因为使用Flash制作的播放器来播放视频文件,所以classid的值必须为”clsid:D27CDB6E-AE6D-11cf-96B8-444553540000”

元素,value属性指定被加载的视频文件.实例中用的是flash制作的视频播放器.在value属性值中向player.swf播放器传递了一个file参数.该参数指定了要播放的视频的路径.

元素,src属性也是用来加载影片,与标记的value属性值具体相同的功能.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值