용테크

[HTML5] Video Tag를 사용한 video 동적 출력 본문

Web/HTML5

[HTML5] Video Tag를 사용한 video 동적 출력

YongT 2020. 10. 26. 13:15

Client(Javascript)

  1. div태그로 video player가 삽입될 공간을 만들어준다.
  2. 호출하는 url에 따라 호출할 비지니스 로직 및 파라미터 설정.
  3. 1. 에서 생성한 div의 attr값에 매핑.
var a = $('div[ux-name="videoPlayer"]');    
a.html('<input type="hidden" id="video" value=""/><video id="videoPlay" width="100%" height="100%" controls controlsList="nodownload" autoplay></video>');    

var oplSrc = '';

if (window.location.href.includes('#')) { 
	oplSrc  =  window.location.href.slice(0, -1) + "do?r=StreamingResponse&file_id=" + fileID + "&file_name=" + fileName + "&userId=cc&token=dd&file_path=" + filePath;
} else { 
	oplSrc  =  window.location.href + "do?r=StreamingResponse&file_id=" + fileID + "&file_name=" + fileName + "&userId=cc&token=dd&file_path=" + filePath;
}


$("#videoPlay").attr("src", oplSrc);

 

Server(Java)

public class StreamingResponse extends DatasetRule {

	
	@Override
    public void doEvent() throws Throwable {
		
		IMessage msg = this.getMessage().get();
		HttpSession session = msg.getSession();
		
		HttpServletRequest request = session.getRequest();
		HttpServletResponse response = session.getResponse();

		
		String file_id = session.getParameter("file_id");
		//String file_name = session.getParameter("file_name");
		String file_path = session.getParameter("file_path");
	
	    //progressbar 에서 특정 위치를 클릭하거나 해서 임의 위치의 내용을 요청할 수 있으므로
	    //파일의 임의의 위치에서 읽어오기 위해 RandomAccessFile 클래스를 사용한다.
	    //해당 파일이 없을 경우 예외 발생
	    RandomAccessFile randomFile = new RandomAccessFile(new File(file_path+"//"+file_id), "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;
	       //logger.debug("accepted range: {}",rangeStart+"-"+rangeEnd+"/"+partSize+" isPart:"+isPart);
	
	       //전송시작
	       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);
	       
	       
	       //logger.debug("sent " + movieName + " " + rangeStart + "-" + rangeEnd);
	   }catch(IOException e){
		   
	       //전송 중에 브라우저를 닫거나, 화면을 전환한 경우 종료해야 하므로 전송취소.
	       // progressBar를 클릭한 경우에는 클릭한 위치값으로 재요청이 들어오므로 전송 취소.
	       //logger.debug("전송이 취소 되었음" );
		   Log.error(StreamingResponse.class, "", e);
		   Logger.debug("Error => " + e.getMessage());
		   e.printStackTrace();
		   
	   }finally{
	       randomFile.close();
	   }
	}
}
Comments