yl-backend/src/main/java/com/guwan/backend/controller/VideoStreamController.java

66 lines
2.5 KiB
Java

package com.guwan.backend.controller;
import com.guwan.backend.entity.Video;
import com.guwan.backend.service.HdfsStorageService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.ResourceRegion;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
import java.io.InputStream;
@Slf4j
@RestController
@RequestMapping("/api/stream")
@RequiredArgsConstructor
public class VideoStreamController {
private final HdfsStorageService hdfsStorageService;
private static final long CHUNK_SIZE = 1024 * 1024; // 1MB chunks
@GetMapping("/video/{id}")
public ResponseEntity<ResourceRegion> streamVideo(
@PathVariable Long id,
@RequestHeader(value = "Range", required = false) String rangeHeader) {
try {
// 获取视频路径
Video video = videoMapper.selectById(id);
if (video == null) {
return ResponseEntity.notFound().build();
}
// 获取视频流
InputStream videoStream = hdfsStorageService.getVideoStream(video.getUrl());
InputStreamResource resource = new InputStreamResource(videoStream);
// 获取视频元数据
VideoMetadata metadata = hdfsStorageService.getVideoMetadata(video.getUrl());
long contentLength = metadata.getSize();
// 处理Range请求
HttpRange range = rangeHeader == null ? null : HttpRange.parseRanges(rangeHeader).get(0);
ResourceRegion region;
if (range != null) {
long start = range.getRangeStart(contentLength);
long end = range.getRangeEnd(contentLength);
long rangeLength = Math.min(CHUNK_SIZE, end - start + 1);
region = new ResourceRegion(resource, start, rangeLength);
} else {
long rangeLength = Math.min(CHUNK_SIZE, contentLength);
region = new ResourceRegion(resource, 0, rangeLength);
}
return ResponseEntity.status(HttpStatus.PARTIAL_CONTENT)
.contentType(MediaTypeFactory.getMediaType(resource).orElse(MediaType.APPLICATION_OCTET_STREAM))
.body(region);
} catch (IOException e) {
log.error("视频流处理失败", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
}