jsp 上传转码_Java实现视频网站的视频上传、视频转码、视频关键帧抽图, 及视频播放功能...
視頻網站中提供的在線視頻播放功能,播放的都是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
實例所需要的數據庫腳本
drop 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;
項目結構圖:
上傳視頻界面設計
在上傳文件時,Form表單中?enctype屬性值必須為"multipart/form-data".模塊界面設計如下圖:
enctype屬性值說明
application/x-www-form-urlencoded
表單數據被編碼為名稱/值對,這是標準的編碼格式
multipart/form-data
表單數據被編碼為一條消息,頁面上每個控件對應消息中的一部分
text/plain
表單數據以純文本形式進行編碼,其中不含任何控件格式的字符
業務接口定義
面向接口編程,接口中定義系統功能模塊.這樣方便理清業務,同時接口的對象必須由實現了該接口的對象來創建.這樣就避免編碼中的某些業務遺漏等,同時擴展性也增強了.
packagecom.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;
}
接口的實現,這里列出ffmpeg視頻轉碼與截圖模塊
/*** 視頻轉碼
*@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;
}
系統中可能存在多個模塊,這些模塊的業務DAO可以通過工廠來管理,需要的時候直接提供即可.
因為如果對象new太多,會不必要的浪費資源.所以工廠,采用單例模式,私有構造,提供對外可訪問的方法即可.
packagecom.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();
}
}
視圖提交請求,給控制器,控制器分析請求參數,進行相應的業務調用處理.servlet控制器相關代碼如下
packagecom.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);
}
}
}
可以通過分頁查找,顯示最新top5,展示到首頁.相應特效可以使用JS實現.
相關代碼如下:
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{%>
沒有記錄
首頁展示的圖片都是帶ID的鏈接請求.圖片為視頻轉碼過程中拉取到的圖片.點擊圖片即可發送播放視頻請求,
視頻播放頁面效果如下圖所示.
視頻播放頁面需要在頁面中嵌入Flash播放器
代碼如下:
src="tools/player.swf?fileName="width="98%" height="90%">
相關說明:
元素,加載ActiveX控件,classid屬性則指定了瀏覽器使用的ActiveX空間.因為使用Flash制作的播放器來播放視頻文件,所以classid的值必須為”clsid:D27CDB6E-AE6D-11cf-96B8-444553540000”
元素,value屬性指定被加載的視頻文件.實例中用的是flash制作的視頻播放器.在value屬性值中向player.swf播放器傳遞了一個file參數.該參數指定了要播放的視頻的路徑.
元素,src屬性也是用來加載影片,與標記的value屬性值具體相同的功能.
總結
以上是生活随笔為你收集整理的jsp 上传转码_Java实现视频网站的视频上传、视频转码、视频关键帧抽图, 及视频播放功能...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python实现xmind转excel_
- 下一篇: 系统状态下的洞察力