Catch preview image from a video / listFiles () does not work

4

I'm having two issues with a super simple project I'm developing in which I have not found a solution in the Forum or Google, the project is a Video Management.

I'll leave the Github link below for those who are curious, want to refine the project or would like a simple example to study.

Github: link

Problems

  • How to get the Preview image (thumbnail) of a video of any format ?! I've already looked it up on Google but I've only seen tutorials on how to generate a thumbnail of the video using xuggler , but that's going to cause me to have to store it somewhere and it's not something I wanted to do because I have to handle it later .

  • I have a folder where listFiles() does not work, the read and write permissions are all Ok and nothing. It just returns null , does anyone have any idea what it can be?

  • asked by anonymous 03.11.2015 / 03:04

    3 answers

    4

    Decoding videos

    Regarding the problem # 1 , there is no magic solution for reading images from any video format.

    Each video format needs a specific algorithm to interpret it and hardly a single implementation will cover all formats.

    Even though some libraries (or group libraries) can read several common formats, there are always some proprietary formats or variations that end up causing problems.

    Approaches

    Two basic solutions for thumbnails would be:

    Pre-store thumbnails

    Store the thumbnails together with the video files.

    If you have some control over how video files are generated or included in the directory, this would be the best solution.

    Use any command line tool to generate the thumbnail and make your Java program simple and fast.

    Generate thumbnail on demand

    This is the approach possible when you have no control over the videos.

    Decoding the video from your program may be convenient on the one hand, but keep in mind that it will greatly increase the complexity of the program and potentially affect performance in a very negative way. Consider rendering 500 videos from any folder.

    It may be necessary to create a queue to process the videos and work with different threads to not lock the program and allow the cancellation in case the user does not want to wait for the operation to finish.

    Xuggler

    I did not understand the problem with keeping the libraries used by xuggler . Many programs and tools come with different libraries.

    The argument of "having to control this later" does not make sense because any dependencies added to your project will have to be managed.

    What exactly is the difficulty in controlling this if you put the libraries together with your program when you distribute?

    From what I read in documentation , xuggler is a wrapper for native FFMPEG libraries, used in several projects. The advantage of using these libraries is that they are mature and trusted.

    JCodec

    Another alternative would be JCodec , a purely Java implementation.

    The first page already shows an example of how to extract a frame from the video to an image:

    int frameNumber = 150;
    BufferedImage frame = FrameGrab.getFrame(new File("arquivo.mp4"), frameNumber);
    ImageIO.write(frame, "png", new File("frame_150.png"));
    

    However, as one would expect from a less-used library, it supports few formats: AVC, H.264 in MP4, ISO BMF, and Quicktime. I suppose it also has less adherence to variations of these formats.

    Although there are recent updates to this library, updates to new or even existing formats are likely to be few or more time-consuming, as there does not seem to be much involvement in the project.

    Problem with listFiles()

    The problem with listFiles can be caused if the Java process does not have permissions to read from the folder.

    It may also be that the directory you have passed is invalid. For example, I did a test passing ~ (user directory) and did not work. However, passing the absolute path did work.

    I would also use the newer Java API. Example:

    //extensões aceitas
    PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:*.{txt,log}");
    //diretório de busca
    Path diretorio = Paths.get("/my/dir");
    //permite links simbólicos
    EnumSet<FileVisitOption> options = EnumSet.of(FileVisitOption.FOLLOW_LINKS);
    //navega no diretório
    Files.walkFileTree(diretorio, options, 1,
            new SimpleFileVisitor<Path>() {
                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                    //verifica se não é um diretório e se tem uma das extensões esperadas
                    if (!attrs.isDirectory() && matcher.matches(file.getFileName())) {
                        System.out.println(file.toString());
                    }
                    return super.visitFile(file, attrs);
                }
            });
    

    See the relevant documentation on walkFileTree and < a href="https://docs.oracle.com/javase/tutorial/essential/io/find.html"> PathMatcher .

    Considerations

    Define the best approach for your case and remember that any of them will have their strengths and weaknesses.

        
    05.11.2015 / 04:29
    3

    On Xuggler and taking into account @utluiz's settings, it works perfectly, tailored to my needs, it's perfect (which is very similar to what you're doing) #:

    import javax.imageio.ImageIO;
    
    import java.io.File;
    
    import java.awt.image.BufferedImage;
    
    import com.xuggle.mediatool.IMediaReader;
    import com.xuggle.mediatool.MediaListenerAdapter;
    import com.xuggle.mediatool.ToolFactory;
    import com.xuggle.mediatool.event.IVideoPictureEvent;
    import com.xuggle.xuggler.Global;
    
    /**
     *  * @author aclarke
     *    @author trebor
     */
    
    public class DecodeAndCaptureFrames extends MediaListenerAdapter
    {
      private int mVideoStreamIndex = -1;
      private boolean gotFirst = false;
      private String saveFile;
      private Exception e;
      /** Construct a DecodeAndCaptureFrames which reads and captures
       * frames from a video file.
       * 
       * @param filename the name of the media file to read
       */
    
      public DecodeAndCaptureFrames(String videoFile, String saveFile)throws Exception
      {
        // create a media reader for processing video
        this.saveFile = saveFile;
        this.e = null;
         IMediaReader reader = ToolFactory.makeReader(videoFile);
    
        // stipulate that we want BufferedImages created in BGR 24bit color space
        reader.setBufferedImageTypeToGenerate(BufferedImage.TYPE_3BYTE_BGR);
    
    
        // note that DecodeAndCaptureFrames is derived from
        // MediaReader.ListenerAdapter and thus may be added as a listener
        // to the MediaReader. DecodeAndCaptureFrames implements
        // onVideoPicture().
    
        reader.addListener(this);
    
        // read out the contents of the media file, note that nothing else
        // happens here.  action happens in the onVideoPicture() method
        // which is called when complete video pictures are extracted from
        // the media source
    
          while (reader.readPacket() == null && !gotFirst);
    
          if (e != null)
              throw e;
      }
    
    
    
      /** 
       * Called after a video frame has been decoded from a media stream.
       * Optionally a BufferedImage version of the frame may be passed
       * if the calling {@link IMediaReader} instance was configured to
       * create BufferedImages.
       * 
       * This method blocks, so return quickly.
       */
    
      public void onVideoPicture(IVideoPictureEvent event)
      {
        try
        {
          // if the stream index does not match the selected stream index,
          // then have a closer look
    
          if (event.getStreamIndex() != mVideoStreamIndex)
          {
            // if the selected video stream id is not yet set, go ahead an
            // select this lucky video stream
    
            if (-1 == mVideoStreamIndex)
              mVideoStreamIndex = event.getStreamIndex();
    
            // otherwise return, no need to show frames from this video stream
    
            else
              return;
          }
    
          ImageIO.write(event.getImage(), "jpg", new File(saveFile));
          gotFirst = true;
    
        }
        catch (Exception e)
        {
          this.e = e;
        }
      }
    }
    
        
    06.11.2015 / 02:08
    1
  • In the case of Windows (most commonly used system), it creates thumbnails in a Thumbs.db file. If you can access it you can grab those thumbnails. The bad thing about this approach is relying on operating system resources (which is not recommended).

  • If you can already generate the thumbnails without problems you can create a hidden folder (or not) along with the videos in question. With a default path and standard nomenclatures you know that the thumbnails will always be there (you can check whether they are or not and create).

  • 05.11.2015 / 13:00