Подтвердить что ты не робот

Как вернуть видео с помощью Spring MVC, чтобы его можно было перемещать с помощью тега html5 <video>?

Если у меня есть файл на веб-сервере (Tomcat) и создайте тег, я могу посмотреть видео, приостановить его, перемещаться по нему и перезапустить его после его завершения.

Но если я создаю интерфейс REST, который отправляет видеофайл по запросу и добавляет его URL-адрес в тег, я могу играть и приостанавливать. Нет перемотки, нет быстрой перемотки вперед, нет навигации, ничего.

Итак, есть ли способ исправления этого? Я чего-то не хватает?

Видеофайлы находятся на том же сервере, что и интерфейс REST, и интерфейс REST только проверяет сеанс и отправляет видео после выяснения, какой из них он должен отправить.

Это те методы, которые я пробовал до сих пор. Все они работают, но ни один из них не позволяет выполнять навигацию.

Способ 1, ResponseEntity:

/*
 * This will actually load the whole video file in a byte array in memory,
 * so it not recommended.
 */
@RequestMapping(value = "/{id}/preview", method = RequestMethod.GET)
@ResponseBody public ResponseEntity<byte[]> getPreview1(@PathVariable("id") String id, HttpServletResponse response) {
    ResponseEntity<byte[]> result = null;
    try {
        String path = repositoryService.findVideoLocationById(id);
        Path path = Paths.get(pathString);
        byte[] image = Files.readAllBytes(path);

        response.setStatus(HttpStatus.OK.value());
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        headers.setContentLength(image.length);
        result = new ResponseEntity<byte[]>(image, headers, HttpStatus.OK);
    } catch (java.nio.file.NoSuchFileException e) {
        response.setStatus(HttpStatus.NOT_FOUND.value());
    } catch (Exception e) {
        response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
    }
    return result;
}

Способ 2, копия потока:

/*
 * IOUtils is available in Apache commons io
 */
@RequestMapping(value = "/{id}/preview2", method = RequestMethod.GET)
@ResponseBody public void getPreview2(@PathVariable("id") String id, HttpServletResponse response) {
    try {
        String path = repositoryService.findVideoLocationById(id);
        File file = new File(path)
        response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
        response.setHeader("Content-Disposition", "attachment; filename="+file.getName().replace(" ", "_"));
        InputStream iStream = new FileInputStream(file);
        IOUtils.copy(iStream, response.getOutputStream());
        response.flushBuffer();
    } catch (java.nio.file.NoSuchFileException e) {
        response.setStatus(HttpStatus.NOT_FOUND.value());
    } catch (Exception e) {
        response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
    }
}

Способ 3, FileSystemResource:

@RequestMapping(value = "/{id}/preview3", method = RequestMethod.GET)
@ResponseBody public FileSystemResource getPreview3(@PathVariable("id") String id, HttpServletResponse response) {
    String path = repositoryService.findVideoLocationById(id);
    return new FileSystemResource(path);
}
4b9b3361

Ответ 1

Функция загрузки резюме HTTP может быть вашим другом. Раньше у меня была такая же проблема. После внедрения диапазона HTTP появилась возможность навигации по видео:

http://balusc.blogspot.com/2009/02/fileservlet-supporting-resume-and.html

Ответ 2

Простое решение для обработки нестатических ресурсов:

@SpringBootApplication
public class DemoApplication {

    private final static File MP4_FILE = new File("/home/ego/bbb_sunflower_1080p_60fps_normal.mp4");

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Controller
    final static class MyController {

        @Autowired
        private MyResourceHttpRequestHandler handler;

        // supports byte-range requests
        @GetMapping("/")
        public void home(
                HttpServletRequest request,
                HttpServletResponse response
        ) throws ServletException, IOException {

            request.setAttribute(MyResourceHttpRequestHandler.ATTR_FILE, MP4_FILE);
            handler.handleRequest(request, response);
        }

        // does not support byte-range requests
        @GetMapping(path = "/plain", produces = "video/mp4")
        public FileSystemResource plain() {

            return new FileSystemResource(MP4_FILE);
        }
    }

    @Component
    final static class MyResourceHttpRequestHandler extends ResourceHttpRequestHandler {

        private final static String ATTR_FILE = MyResourceHttpRequestHandler.class.getName() + ".file";

        @Override
        protected Resource getResource(HttpServletRequest request) throws IOException {

            final File file = (File) request.getAttribute(ATTR_FILE);
            return new FileSystemResource(file);
        }
    }
}

(вдохновленный Spring Boots LogFileMvcEndpoint и более или менее равный Пол-Уорренсу (@paul-warren) StoreByteRangeHttpRequestHandler, который я нашел позже).

Надеюсь, это то, что Spring будет поддерживать в ближайшем будущем, см. https://jira.spring.io/browse/SPR-13834 (проголосуйте за него).

Ответ 3

Я знаю, что это старый пост, но в случае, если он полезен кому-то еще, задавая одинаковые/похожие вопросы.

В настоящее время существуют такие проекты, как Spring Контент, который поддерживает потоковое видео. Весь код, который вам понадобится для простейшей реализации, будет: -

@StoreRestResource(path="videos")
public interface VideoStore extends Store<String> {}

И этого было бы достаточно, чтобы создать Java API и набор конечных точек REST, которые позволят вам потоки PUT/POST, GET и DELETE видео. GET поддерживает диапазоны байтов и будет правильно воспроизводиться в видеоплеере HTML5 и т.п.

Ответ 4

Фактически, передняя часть показывает элементы управления видео для <video> тег.

Каждый браузер для специального видеоформата имеет панель управления по умолчанию.

Вы можете использовать html и css для создания собственного элемента управления с медиа-API. Media api

От Div в HTML5 [По умолчанию, <video> элемент не будет выставлять какие-либо элементы управления проигрывателем. Вы можете создавать свои собственные элементы управления с помощью простого старого HTML, CSS и JavaScript. <video> элемент имеет такие методы, как play() и pause(), и свойство read/write, называемое currentTime. Есть также объем чтения/записи и отключенные свойства. Таким образом, у вас действительно есть все необходимое для создания собственного интерфейса.]