Reputation: 140
I am working on a project to get thumbnails from a video and then display them in the home page.
The thumbnails are correctly generated in the folder uploads but they are not displayed in the home page. I am getting not found error 404.
Bellow is a code JeutrollServiceImp used to get thumbnails from a video In the html, I am using a hard coding name of the image for test's purprose.
import com.jeutroll.dao.UserRepository;
import com.jeutroll.dao.VideoRepository;
import com.jeutroll.entities.Video;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
@Service
@Transactional
public class JeutrollServiceImp implements JeutrollService
{
public static String uploadDirectory= System.getProperty("user.home") + "/uploads";
@Autowired
private UserRepository userRepository;
@Autowired
private VideoRepository videoRepository;
@Override
public Page<Video> browseVideos(String aInCategory, int page, int size)
{
return videoRepository.listVideos(aInCategory, new PageRequest(page, size));
}
@Override
public Video browseVideo(String aTitle)
{
return null;
}
@Override
public void uploadVideo(Video aInVideo)
{
}
@Override
public com.jeutroll.entities.User findUserByEmail(String email)
{
return userRepository.findByEmail(email);
}
@Override
public String retriveThumbnailFromVideo(String videoPath)
{
String thumbnailPath;
File lImgFile = null;
FFmpegFrameGrabber g = new FFmpegFrameGrabber(videoPath);
try
{
g.start();
// on fait défiler les 10 premières frame
for (int i = 0; i < 100; i++)
{
g.grab();
}
Frame lFrame = g.grabImage();
BufferedImage lBufferedImage = new Java2DFrameConverter().convert(lFrame);
// on enregistre la 101ième
Path path = Paths.get(uploadDirectory,"life_" + System.currentTimeMillis() + ".png" );
//lImgFile = new File("/resources/static/life_" + System.currentTimeMillis() + ".png");
lImgFile = new File(path.toString());
ImageIO.write(lBufferedImage, "png", lImgFile);
// récupération de la durée de la vidéo
float duration = (float) g.getLengthInTime() / 1000000;
g.stop();
}
catch (Exception e)
{
// TODO Auto-generated catch block
System.err
.println("La création de la miniature n'a pas pu être effectuée!");
e.printStackTrace();
}
return lImgFile.getName();
}
@Override
public void uploadVideos(String aInFilePath)
{
// storageService.store(file);
}
}
WebConfigurer Class
package com.jeutroll.configuration;
import com.jeutroll.service.JeutrollServiceImp;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
public class WebConfigurer extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/uploads/**").addResourceLocations("file:/" + JeutrollServiceImp.uploadDirectory);
}
}
Here I am using a video that already existing in external folder on the disk.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorator="template1.html">
<head>
<meta charset="UTF-8">
<title>Jeutroll</title>
</head>
<body>
<div layout:fragment="content">
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2 text-center">
<h2 class="section-title uppercase"> Projets Réalisés</h2>
</div>
</div>
<section class="row" th:if="${videos}">
<div class="col-xs-12 col-sm-3 col-md-4 col-lg-4" th:each="v:${videos}">
<a href="#" class="thumbnail"><img src="/uploads/life_1549107645227.png" alt="Image 2" width="500px " >
<div class="caption">
<span class="cat-link">categorie</span>
<span class="separator">|</span>
<span class="pub-date">6 janvier 2019</span>
<span class="glyphicon glyphicon-comment"></span>
</div>
<div class="rating">
</div>
</a>
</div>
</section>
</div>
</div>
</body>
</html>
Upvotes: 1
Views: 2332
Reputation: 2479
I would suggest you take a look at Spring Content. This community project allows you to associate content (i.e. unstructured data like videos) with Spring Data Entities using the same programming model.
It is pretty simple to add to your existing project and it will give you the same easy programming model as Spring Data, an abstraction over your storage (so it could be store in any Storage Spring Content supports) and a bunch of other features OOTB like the REST endpoint that support video streaming.
In case you are interested here is how I think you could do it (assuming Spring Boot).
Add the dependencies to your project:-
pom.xml
<!-- Java API -->
<dependency>
<groupId>com.github.paulcwarren</groupId>
<artifactId>spring-content-fs-boot-starter</artifactId>
<version>0.5.0</version>
</dependency>
<!-- REST API -->
<dependency>
<groupId>com.github.paulcwarren</groupId>
<artifactId>spring-content-rest-boot-starter</artifactId>
<version>0.5.0</version>
</dependency>
Configure your file storage:
StoreConfig.java
@Configuration
@EnableFilesystemStores
public class EnableFilesystemStoresConfig {
@Bean
File filesystemRoot() {
try {
return new File(JeutrollServiceImp.uploadDirectory);
} catch (IOException ioe) {}
return null;
}
@Bean
FileSystemResourceLoader fileSystemResourceLoader() {
return new FileSystemResourceLoader(filesystemRoot().getAbsolutePath());
}
}
Associate content with your entity:
@Entity
public class Video {
@Id @GeneratedValue
private Long id;
... other Spring Data fields ...
// associate the video
@ContentId
private UUID contentId;
@ContentLength
private Long contentLength;
@Mimetype
private String mimeType;
// associate thumbnails
private Thumbnail thumbnail;
...
}
@Entity
public class Thumbnail {
@ContentId
private UUID contentId;
@ContentLength
private Long contentLength;
@MimeType
private String mimeType;
}
Create a video store and a thumbnail store:
VideoStore.java/ThumbnailStore.java
@StoreRestResource(path="videoContent")
public interface VideoStore extends ContentStore<Video,UUID> {
}
public interface ThumbnailStore extends ContentStore<Thumbnail,UUID> {
}
The spring-content-fs-boot-starter
dependency will cause Spring Content to inject filesystem-based implementations so you don't need to worry about implementing these yourself. Moreover, the spring-content-rest
dependency will cause Spring Content to also inject implementations of @Controller
that forward HTTP requests onto the methods of the VideoStore
and ThumbnailStore
respectively.
So you will now have a fully functional (POST, PUT, GET, DELETE) REST-based video service at /videoContent
that will use your VideoStore
to retrieve (and store) videos in JeutrollServiceImp.uploadDirectory
on your server.
So:
POST /videoContent/ -F "image=@/some/path/to/a/video.mp4"
will upload video.mp4
and add it to your uploads directory.
GET /videoContent/{videoId}
will get it again and store rest endpoints support Range requests so HTML5 video controls will work appropriately.
For the thumbnails you can add the processing to generate and store the thumbnail in an annotated store event handler:-
@Configuration
public class ThumbnailConfig {
@Bean
public StoreEventHandler thumbnailEventHandler() {
return new ThumbnailEventHandler();
}
@StoreEventHandler
public static class ThumbnailEventHandler {
@Autowired
VideoRepository videoRepository;
@Autowired
VideoStore videoStore;
@Autowired
ThumbnailStore thumnailStore;
@HandleAfterSetContent
public void handleAfterSetContent(Video video) {
BufferedImage img = // use modfied retrieveThumbnailFromVideo(videoStore.getContent(video));
Thumbnail thumbnail = new Thumbnail();
thumbnail.setMimeType("png")
thumbnail.setContent(thumbnail, toInputStream(img))
video.setThumbnail(thumbnail)
videoRepository.save(video);
}
}
}
After each video is store its thumbnail will then be available via:
GET /videoContent/{videoId}/thumbnail
or:
GET /videoContent/{videoId}/thumbnail/{contentId}
As we store the mimetype these URLs will be usable as the src
in a standard on your HTML.
So:
Becomes:
HTH
Upvotes: 0
Reputation: 140
After being stuck for hours on this problem, I finally figured it out. The main problem is that I did not added @EnableWebMvc in the class WebConfigurer. The second is the image directory was not correct. I am executing my project on Windows OS and I used System.getProperty("user.home") + "/uploads"; instead of System.getProperty("user.home") + "\uploads";
Because it is a recurrent subject. I have decided to write an example for this case. I home it will help. http://mkaroune.e-monsite.com/pages/spring/get-images-from-external-folder-on-disk.html
@Ahmed Yes the method is returning the correct image path.
Upvotes: 1