0
    import javax.imageio.ImageIO;

    import org.bytedeco.javacv.FFmpegFrameGrabber;

    public class FrameData 
    {   
int count = 0;
int picWidth;
int picHeight;

BufferedImage img = null;

//GET FRAME COUNT
public int gf_count(int numofFrames, BufferedImage[] frameArray, String fileLocationsent, String videoNamesent) throws IOException
{        
    String fileLocation = fileLocationsent;
    String videoName = videoNamesent;

    int frameNums = numofFrames;
    int totFrames = 0;

            FFmpegFrameGrabber grab = new FFmpegFrameGrabber(fileLocation + videoName);

        try {   grab.start(); } 
        catch (Exception e) {   System.out.println("Unable to grab frames");  }

                    for(int i = 0 ; i < frameNums  ; i++) 
        {
            try 
            {                   
                frameArray[i]= grab.grab().getBufferedImage();
                totFrames = i;  
                File outputfile = new File(fileLocation + "GrayScaledImage" + i + ".jpg");
                ImageIO.write(frameArray[i], "jpg", outputfile);
            } 
            catch (Exception e) {   /*e.printStackTrace();*/    }
        }//END for

                return totFrames;

    }//END METHOD long getFrameCount()

Hope someone can explain this to me... I am just learning java so here goes... I wrote this code to count the number of frames in a .mov file and to test my buffered image array I generated files of the images. As the code is, it works as planned... The problem is immediately after the capturing, if I send the bufferedimages out as files, they all seem to be just the first image. see example below...

    for(int i = 0 ; i < frameNums  ; i++) 
        {
            try 
            {                   
                frameArray[i]= grab.grab().getBufferedImage();
                totFrames = i;  
                File outputfile = new File(fileLocation + "GrayScaledImage" + i + ".jpg");
                ImageIO.write(frameArray[i], "jpg", outputfile);
            } 
            catch (Exception e) {   /*e.printStackTrace();*/    }
        }//END for

And now if I change that to...

    for(int i = 0 ; i < frameNums  ; i++) 
        {
            try 
            {                   
                frameArray[i]= grab.grab().getBufferedImage();
                totFrames = i;  catch (Exception e) {   /*e.printStackTrace();*/    }}
    for(int j = 0; j < frameNums; j++)
    {
    File outputfile = new File(fileLocation + "GrayScaledImage" + j + ".jpg");
                ImageIO.write(frameArray[j], "jpg", outputfile);
    }

I don't understand why I am getting the same image repeatedly. If further information Is required, just lemme know, this is my first programming question online... Usually find what I am looking for that others have asked. Couldn't find this one. Thanks for your time Ken

ken
  • 3
  • 3
  • Just realized the last code block came out poorly formatted, my apologies. So you know both for loops are closed correctly... It's the data in the array that I am confused about. Thanks again – ken Mar 25 '16 at 20:37
  • it could be the names of the files it could be the framegrabber: print out fileLocation,videoName and fileLocation + videoName: doesnt this need some kind of / or \ ? I hope you video doesnt contain one image! – gpasch Mar 25 '16 at 20:55
  • @-gpasch No, as I said, depending on where I place the two lines of code, either as it grabs the frames or after... I get completely different results... If I save to files as it grabs the frames, I see the different pictures... but if I move it just outside the for loop where it grabs the frames it just saves the same picture over and over. File location and filename are formatted properly... Thanks for the ideas! – ken Mar 26 '16 at 14:26

1 Answers1

0

The problem is that the grab().getBufferedImage() does its work in the same buffer every time. When you assign a reference to that buffer in your loop, you are assigning a reference to the same buffer numofFrames times. What you are writing then is not the first frame, but the last frame. In order to fix this you need to do a "deep copy" of the BufferedImage. See code below:

public class FrameData {
    BufferedImage img;
    Graphics2D g2; 
    // GET FRAME COUNT
    public int gf_count(int numFrames, BufferedImage[] frameArray, String fileLocation, String videoName) throws Exception, IOException {
        Java2DFrameConverter converter = new Java2DFrameConverter();
        int totFrames = 0;

        img = new BufferedImage(100, 50, BufferedImage.TYPE_INT_ARGB);
        g2 = img.createGraphics();

        FFmpegFrameGrabber grab = new FFmpegFrameGrabber(fileLocation + videoName);
        grab.start();
        for (int i = 0; i < numFrames; i++) {
            frameArray[i] = deepCopy(converter.convert(grab.grab()));
            totFrames = i;
        }
        for (int j = 0; j < totFrames; j++) {
            File outputfile = new File(fileLocation + "TImage" + j + ".jpg");
            ImageIO.write(frameArray[j], "jpg", outputfile);
        }
        return totFrames;
    }// END METHOD long getFrameCount()

    BufferedImage deepCopy(BufferedImage bi) {
        ColorModel cm = bi.getColorModel();
        boolean isAlphaPremultiplied = cm.isAlphaPremultiplied();
        WritableRaster raster = bi.copyData(null);
        return new BufferedImage(cm, raster, isAlphaPremultiplied, null);
    }
    // This does what the converter.convert seems to do, which
    // is decode an image into the same place over and over.
    // if you don't copy the result every time, then you end up
    // with an array of references to the same last frame.
    BufferedImage draw() {
        g2.setColor(new Color(-1));
        g2.fillRect(0, 0, 100, 50);
        g2.setColor(new Color(0));
        g2.drawLine(0, 0, (int)(Math.random()*100.0), (int)(Math.random()*50.0));        
        return img;
    }

    public static void main(String... args) throws Exception, IOException {
        new FrameData().run();        
    }
    private void run() throws Exception, IOException {
        BufferedImage images[] = new BufferedImage[50];
        gf_count(50, images, "C:/Users/karl/Videos/", "dance.mpg");
    }
}

I have included a draw() method that shows by example how work is done in the same BufferedImage repeatedly, in case you want to replicate the problem.

There are certainly other ways to do a deep copy and there may be issues with the one shown. Reference: How do you clone a BufferedImage.

PS> I updated the code to use the 1.1 version of the bytedeco library.

Community
  • 1
  • 1
K.Nicholas
  • 10,956
  • 4
  • 46
  • 66