HTML5 VIDEO 스트리밍(STREAMING) 서버 프로그래밍 - JAVA
2. HTTP REQUEST 헤더의 RANGE
우선 HTML의 VIDEO 태그 사용 방법은 아실거라 생각 하고 패스 합니다.
- StreamingResponse.java
import java.io.File; import java.io.IOException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class StreamingResponse { public static final int DEFAULT_BUFFER_SIZE = 204800; private static final String CONTENT_TYPE = "video/mp4"; private static final long DEFAULT_EXPIRE_TIME = 604800000L; public Range write(File file, HttpServletRequest request, HttpServletResponse response) throws IOException { Range range = null; String rangeStr = request.getHeader("range"); if (rangeStr != null) { if (rangeStr.endsWith("-")) { rangeStr = rangeStr + (file.length() - 1); } int idxm = rangeStr.trim().indexOf("-"); range = new Range(Long.parseLong(rangeStr.substring(6, idxm)), Long.parseLong(rangeStr.substring(idxm + 1)), file.length()); if (range.start > 0) { range.isPart = true; } } else { range = new Range(0, file.length() - 1, file.length()); } range.partSize = range.end - range.start + 1; if (range.end == 0) { range.end = range.start + DEFAULT_BUFFER_SIZE - 1; } if (range.end > file.length() - 1) { range.end = file.length() - 1; } String eTag = file.getName() + "_" + range.length + "_" + file.lastModified(); response.reset(); response.setStatus(range.isPart ? HttpServletResponse.SC_PARTIAL_CONTENT : HttpServletResponse.SC_OK); response.setContentType(CONTENT_TYPE); response.setHeader("Content-Range", "bytes " + range.start + "-" + range.end + "/" + range.total); response.setHeader("Accept-Ranges", "bytes"); response.setHeader("Content-Length", "" + range.partSize); response.setBufferSize(DEFAULT_BUFFER_SIZE); response.setHeader("Content-Disposition", "inline;filename=\"" + file.getName() + "\""); response.setHeader("ETag", eTag); response.setDateHeader("Last-Modified", file.lastModified()); response.setDateHeader("Expires", System.currentTimeMillis() + DEFAULT_EXPIRE_TIME); return range; } } |
위 소스코드에서 중요한 포인트는 HTTP REQUEST 헤더에서 RANGE 속성을 찾아 요청된 START, END 값을 찾습니다.
RANGE 속성의 값이 있다면 PARTIAL 콘텐츠 요청이라고 판단 하여 동영상의 일부를 보내야 합니다.
- StreamingUtil.java
import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.io.RandomAccessFile; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.io.IOUtils; public class StreamingUtil { public void streaming(File file, HttpServletRequest request, HttpServletResponse response, OutputStream out) throws IOException { StreamingResponse streamingResponse = new StreamingResponse(); Range range = streamingResponse.write(file, request, response); copyStreaming(file, out, range); } private void copyStreaming(File file, OutputStream output, Range range) { RandomAccessFile randomFile = null; try { long partSize = range.partSize; randomFile = new RandomAccessFile(file, "r"); randomFile.seek(range.start); byte[] buf = new byte[StreamingResponse.DEFAULT_BUFFER_SIZE]; do { int block = partSize > StreamingResponse.DEFAULT_BUFFER_SIZE ? StreamingResponse.DEFAULT_BUFFER_SIZE : (int) partSize; int len = randomFile.read(buf, 0, block); output.write(buf, 0, len); output.flush(); partSize -= block; } while (partSize > 0); } catch (Exception e) { //log.info("User canceled streaming request"); } finally { IOUtils.closeQuietly(randomFile); } } } |
찾아낸 RANGE 속성 만큼 부분 영상 데이터를 보내게 됩니다.
브라우저에서 개발자 도구(F12) 네트워크를 통해 확인을 하게 되면 영상이 실제로 부분 데이터가 전송 되는 것을 확인 할 수 있습니다.
또한 영상 스킵도 가능하고, 빠르게 재생 됨을 확인 할 수 있습니다.
기타 궁금한 사항은 댓글을 달아주세요.
'JAVA' 카테고리의 다른 글
메이븐(MAVEN) RPM 플러그인으로 RPM 생성하기 (0) | 2018.09.07 |
---|---|
Linux에서 자바 어플리케이션 서버 실행 쉘(Shell) 스크립트 (0) | 2018.08.07 |
Spring 스케쥴러를 이용한 파일 삭제 (수정한 날짜 기준 데이터 삭제) (0) | 2018.03.07 |
Open API 연동 Controller 로직 공유 합니다. (0) | 2017.10.23 |
Open API 개발 가이드 - java (0) | 2017.10.23 |