개발환경

springboot mp4 streaming and download

toogari 2023. 9. 26. 10:21
  • mp4 같은 동영상을 스트리밍하는 경우와 다운로드를 동시에 처리하는 리소스가 없어서 이것저것 살펴보면서 작성함.
  • 스트리밍요청과 다운로드 요청을 구분하여 처리하는게 필요함.
  • 브라우저에서 여러번 요청을 받아서 처리해야 하므로 InputStreamResource 이 아닌 FileSystemResource 를 사용해야 함
@RequestMapping(value = "/api/file/download/{filepath}"
			, method = RequestMethod.GET
			, produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
	public ResponseEntity<ResourceRegion> getMp4StreamingAndDownload(@RequestHeader(value = "Range", required = false) String httpRangeList, @PathVariable String filepath, @PathVariable String value, @RequestHeader HttpHeaders headers)
			throws IOException {
            
         String fileFullPath = "";	// 스트리밍할 리소스 경로.

		Optional<HttpRange> httpRangeOptional = headers.getRange().stream().findFirst();
		if (httpRangeOptional.isPresent() == false) {
            // 다운로드 요청시에.
			Resource resource = new FileSystemResource(new File(fileFullPath));
			return ResponseEntity.ok()
					.contentType(MediaType.APPLICATION_OCTET_STREAM)
					.cacheControl(CacheControl.noCache())
					.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=video.mp4")
					.body(new ResourceRegion(resource, 0, resource.contentLength()));
		} else {
            // 스트리밍 요청시에...
			Resource resource = new FileSystemResource(new File(fileFullPath));
			long chunkSize = 1024 * 1024;
			long contentLength = resource.contentLength();
			ResourceRegion region = null;

			try {
				HttpRange httpRange = httpRangeOptional.get();
				long start = httpRange.getRangeStart(contentLength);
				long end = httpRange.getRangeEnd(contentLength);
				long rangeLength = Long.min(chunkSize, end - start + 1);
				region = new ResourceRegion(resource, start, rangeLength);

			} catch (Exception e) {
				long rangeLength = Long.min(chunkSize, contentLength);
				region = new ResourceRegion(resource, 0, rangeLength);
			}

			return ResponseEntity.status(HttpStatus.PARTIAL_CONTENT)
					.cacheControl(CacheControl.maxAge(10, TimeUnit.MINUTES))
					.contentType(MediaTypeFactory.getMediaType(resource).orElse(MediaType.APPLICATION_OCTET_STREAM))
					.header("Accept-Ranges", "bytes")
					.eTag(fileFullPath)
					.body(region);
}