비디오 스트리밍
그냥 스트리밍하는 것은 이미지를 스트리밍하는 것과 같다.
http://whiteduck.tistory.com/117
비디오에 위과 같이 적용해보니 죄우로 선택할 수가 없었다.
그래서 검색중에 스트링에서 비디오스트리밍하는 것을 찾았다.
http://aodis.egloos.com/5962812
위의 참조한 것을 내 위주로 수정하였다.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** @reference : http://aodis.egloos.com/5962812 | |
* @modified : whiteduck | |
*/ | |
@RequestMapping(value="/contents/{content_id}/medias/video/{video_name:.+}", method= RequestMethod.GET) | |
public String getContentMediaVideo(@PathVariable("content_id")String content_id, @PathVariable("video_name")String video_name,HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException, IOException { | |
// 확장자 확인 // | |
String[] filename_seperate = video_name.split("\\."); | |
String exp = ""; | |
if( filename_seperate.length <= 1 ) { | |
// 확장자 에러 // | |
String resultMsg = new MessageMaker().getErrorMessage("Wrong file name. You need to include expand file name"); | |
response.getOutputStream().write(resultMsg.getBytes(SystemInfo.ENCODING)); | |
response.getOutputStream().flush(); | |
return null; | |
} | |
else { | |
exp = filename_seperate[1]; | |
} | |
//progressbar 에서 특정 위치를 클릭하거나 해서 임의 위치의 내용을 요청할 수 있으므로 | |
//파일의 임의의 위치에서 읽어오기 위해 RandomAccessFile 클래스를 사용한다. | |
//해당 파일이 없을 경우 예외 발생 | |
File file = new File("/home/"+content_id+"/medias/video/"+ video_name); | |
if( ! file.exists() ) throws new FileNotFoundException(); | |
RandomAccessFile randomFile = new RandomAccessFile(file, "r"); | |
long rangeStart = 0; //요청 범위의 시작 위치 | |
long rangeEnd = 0; //요청 범위의 끝 위치 | |
boolean isPart=false; //부분 요청일 경우 true, 전체 요청의 경우 false | |
//randomFile 을 클로즈 하기 위하여 try~finally 사용 | |
try{ | |
//동영상 파일 크기 | |
long movieSize = randomFile.length(); | |
//스트림 요청 범위, request의 헤더에서 range를 읽는다. | |
String range = request.getHeader("range"); | |
//브라우저에 따라 range 형식이 다른데, 기본 형식은 "bytes={start}-{end}" 형식이다. | |
//range가 null이거나, reqStart가 0이고 end가 없을 경우 전체 요청이다. | |
//요청 범위를 구한다. | |
if(range!=null) { | |
//처리의 편의를 위해 요청 range에 end 값이 없을 경우 넣어줌 | |
if(range.endsWith("-")){ | |
range = range+(movieSize - 1); | |
} | |
int idxm = range.trim().indexOf("-"); //"-" 위치 | |
rangeStart = Long.parseLong(range.substring(6,idxm)); | |
rangeEnd = Long.parseLong(range.substring(idxm+1)); | |
if(rangeStart > 0){ | |
isPart = true; | |
} | |
}else{ //range가 null인 경우 동영상 전체 크기로 초기값을 넣어줌. 0부터 시작하므로 -1 | |
rangeStart = 0; | |
rangeEnd = movieSize - 1; | |
} | |
//전송 파일 크기 | |
long partSize = rangeEnd - rangeStart + 1; | |
//전송시작 | |
response.reset(); | |
//전체 요청일 경우 200, 부분 요청일 경우 206을 반환상태 코드로 지정 | |
response.setStatus(isPart ? 206 : 200); | |
//mime type 지정 | |
response.setContentType("video/mp4"); | |
//전송 내용을 헤드에 넣어준다. 마지막에 파일 전체 크기를 넣는다. | |
response.setHeader("Content-Range", "bytes "+rangeStart+"-"+rangeEnd+"/"+movieSize); | |
response.setHeader("Accept-Ranges", "bytes"); | |
response.setHeader("Content-Length", ""+partSize); | |
OutputStream out = response.getOutputStream(); | |
//동영상 파일의 전송시작 위치 지정 | |
randomFile.seek(rangeStart); | |
//파일 전송... java io는 1회 전송 byte수가 int로 지정됨 | |
//동영상 파일의 경우 int형으로는 처리 안되는 크기의 파일이 있으므로 | |
//8kb로 잘라서 파일의 크기가 크더라도 문제가 되지 않도록 구현 | |
int bufferSize = 8*1024; | |
byte[] buf = new byte[bufferSize]; | |
do{ | |
int block = partSize > bufferSize ? bufferSize : (int)partSize; | |
int len = randomFile.read(buf, 0, block); | |
out.write(buf, 0, len); | |
partSize -= block; | |
}while(partSize > 0); | |
}catch(IOException e){ | |
//전송 중에 브라우저를 닫거나, 화면을 전환한 경우 종료해야 하므로 전송취소. | |
// progressBar를 클릭한 경우에는 클릭한 위치값으로 재요청이 들어오므로 전송 취소. | |
}finally{ | |
randomFile.close(); | |
} | |
return null; | |
} |
해보니
좌우로 움직이긴 한다. 버퍼링도 있고 ( 크롬 )
반응형
'Java Story' 카테고리의 다른 글
[ SPRING ] GPS 수신 하기 (3) | 2017.04.21 |
---|---|
[ Spring ] image resource (0) | 2016.10.13 |
[ Eclipse Short cut ] getter setter (0) | 2016.09.07 |
[이클립스] 프로젝트 패키지별로 보기 (1) | 2016.08.29 |
[ 서버 ] Ubuntu 14.04-server 기반 tomcat서버 세팅 (0) | 2016.08.26 |
[JAVA] 이클립스 비트버켓(bitbucket연동) link (0) | 2016.08.22 |
[ JAVA ] 성능을 업그레이드?? (링크) (0) | 2016.06.01 |
[ Spring ] @ModelAttribute와 @SessionAttributes의 이해와 한계 (링크) (0) | 2016.05.23 |