使用 xuggler 从文件中读取视频时抛出“EXCEPTION_ACCESS_VIOLATION”

jjo*_*n91 5 java xuggle xuggler

我正在编写 java 代码以接收 mp4 格式的视频文件,对其应用效果,然后将其保存到一个新文件中。代码应该将给定的视频拆分为其帧并将它们存储在一个数组中,以便每个帧都可以用于构建效果。这部分代码由xuggler处理,所以我很难确定哪里出了问题。

问题是,甚至在阅读视频的一张图片之前,错误就会被抛出,我不知道它指的是什么,广泛的谷歌搜索告诉我它与内存访问错误有关。

更奇怪的部分是它只发生在一些 mp4 文件上,即使它们都是 mp4 格式并且都应该以相同的方式运行。

我已经尝试了许多来自不同来源的不同 mp4 文件,其中一些有效,一些无效,似乎是随机的。我对应用效果最感兴趣的 mp4 是不起作用的 mp4 之一。

在下面的代码中,我在各个点使用打印语句进行了识别,导致错误的代码部分位于具有变量名称 media 的 IMediaListener 中的某处。侦听器本身由while(reader.readPacket()==null);ActionListener 内部的行调用,特别是在按“子”按钮触发的部分中。这是唯一被称为它的地方。

我应该注意,所有与 xuggler 相关的代码都不是我自己的,因为我在网上的代码演示中找到了它。我不会假装了解 xuggler 的工作原理。

import java.util.*;
import java.util.concurrent.*;
import java.awt.*;
import javax.swing.*;
import javax.swing.filechooser.*;
import java.awt.image.*;
import com.xuggle.xuggler.*;
import com.xuggle.mediatool.*;
import com.xuggle.mediatool.event.*;
import java.awt.event.*;
public class mainClass {
    static JFrame win=new JFrame();
    static JPanel dis=new JPanel();
    static JButton sub=new JButton("Submit"),b1=new JButton("Browse"),b2=new JButton("Browse");
    static JTextField input=new JTextField(),output=new JTextField();
    static String savePath="",sourcePath="";
    static JLabel l1=new JLabel("Input:"),l2=new JLabel("Output:");
    static BufferedImage[] images=new BufferedImage[0];
    static Set<Long> timestamps=new HashSet<Long>();
    static int ind=0;
    public static void main(String[]args) {
        win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        win.setResizable(false);
        win.setVisible(true);
        win.add(dis);
        win.setLocation(100,300);
        dis.setPreferredSize(new Dimension(850,80));
        dis.setLayout(null);
        win.pack();
        dis.add(input).setBounds(100,0,550,40);
        dis.add(output).setBounds(100,40,550,40);
        dis.add(sub).setBounds(750,0,100,80);
        dis.add(b1).setBounds(650,0,100,40);
        dis.add(b2).setBounds(650,40,100,40);
        dis.add(l1).setBounds(0,0,100,40);
        dis.add(l2).setBounds(0,40,100,40);
        input.setFocusable(false);
        input.setFont(new Font(Font.SANS_SERIF,Font.PLAIN,22));
        output.setFocusable(false);
        output.setFont(input.getFont());
        sub.setFocusable(false);
        sub.addActionListener(action);
        b1.setFocusable(false);
        b1.addActionListener(action);
        b2.setFocusable(false);
        b2.addActionListener(action);
        l1.setFont(input.getFont());
        l1.setHorizontalAlignment(SwingConstants.CENTER);
        l2.setFont(input.getFont());
        l2.setHorizontalAlignment(SwingConstants.CENTER);
    }
    static IMediaListener media=new MediaListenerAdapter() {
        public void onVideoPicture(IVideoPictureEvent e) {
            timestamps.add(e.getTimeStamp(TimeUnit.MICROSECONDS));
            BufferedImage image=e.getImage();
            BufferedImage[] copy=images;
            images=new BufferedImage[copy.length+1];
            for(int i=0;i<copy.length;i++) {
                images[i]=copy[i];
            }
            images[images.length-1]=image;
        }
    };
    static ActionListener action=new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            if(e.getSource()==sub) {
                if(input.getText().length()>0&output.getText().length()>0) {
                    IMediaReader reader=ToolFactory.makeReader(input.getText());
                    reader.setBufferedImageTypeToGenerate(BufferedImage.TYPE_3BYTE_BGR);
                    reader.addListener(media);
                    while(reader.readPacket()==null);
                    BufferedImage[] pics=images;
                    Long[] times=new Long[timestamps.size()];
                    times=timestamps.toArray(times);
                    for(int i=0;i<pics.length;i++) {
                        int min=i;
                        for(int j=i;j<pics.length;j++) {
                            if(times[j]<times[min]) {
                                min=j;
                            }
                        }
                        Long f1=times[i];
                        times[i]=times[min];
                        times[min]=f1;
                    }
                    timestamps=new HashSet<Long>();
                    long frameSep=(long)(times[times.length-1]/times.length);
                    IMediaWriter writer=ToolFactory.makeWriter(output.getText()+"\\video1.mp4");
                    writer.addVideoStream(0,0,ICodec.ID.CODEC_ID_MPEG4,pics[0].getWidth(),pics[0].getHeight());
                    for(int i=0;i<pics.length+pics[0].getHeight()-1;i++) {
                        BufferedImage image=pics[0];
                        for(int j=0;j<i;j++) {
                            int ind=i-j,ind2=image.getHeight()-j-1;
                            if(ind>=pics.length) {
                                ind=pics.length-1;
                            }
                            if(ind2<0) {
                                ind2=0;
                            }
                            int[] rgbArray=new int[image.getWidth()];
                            pics[ind].getRGB(0, ind2, image.getWidth(), 1, rgbArray, 0, image.getWidth());
                            image.setRGB(0, ind2, image.getWidth(), 1, rgbArray, 0, image.getWidth());
                        }
                        writer.encodeVideo(0, image, frameSep*i, TimeUnit.MICROSECONDS);
                        if(i%((pics.length+pics[0].getHeight()-1)/100)==0) {
                            System.out.println(Double.toString(i/(pics.length+pics[0].getHeight()-1)*100)+" %");
                        }
                    }
                    System.out.println("finished");
                    writer.close();
                }
            }
            if(e.getSource()==b1) {
                JFileChooser fc=new JFileChooser();
                fc.setMultiSelectionEnabled(false);
                fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
                fc.setFileFilter(new FileNameExtensionFilter("mp4 file","mp4"));
                fc.setAcceptAllFileFilterUsed(false);
                if(fc.showOpenDialog(sub)==JFileChooser.APPROVE_OPTION)input.setText(fc.getSelectedFile().getAbsolutePath());
            }
            if(e.getSource()==b2) {
                JFileChooser fc=new JFileChooser();
                fc.setMultiSelectionEnabled(false);
                fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
                if(fc.showOpenDialog(sub)==JFileChooser.APPROVE_OPTION)output.setText(fc.getSelectedFile().getAbsolutePath());
            }
        }
    };
}
Run Code Online (Sandbox Code Playgroud)

对于工作的给定 mp4,代码将完成应用效果,然后打印“完成”,以便我知道去检查输出文件夹,可以在最初出现的 GUI 中指定。

对于不工作的给定 mp4,控制台会打印以下错误消息,如下所示:

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x000000006ee76520, pid=2176, tid=0x00000000000000c0
#
# JRE version: Java(TM) SE Runtime Environment (8.0_211-b12) (build 1.8.0_211-b12)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.211-b12 mixed mode windows-amd64 compressed oops)
# Problematic frame:
# C  [xuggle1222138188201648765.dll+0x736520]
#
# Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
#
# An error report file with more information is saved as:
# C:\Users\John\eclipse-workspace\Video effects\hs_err_pid2176.log
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
Run Code Online (Sandbox Code Playgroud)

它所指的日志文件包含大量我无法理解的复杂信息,谈论寄存器位置和虚拟机等。我不会假装理解。

非常感谢任何帮助!

小智 1

我希望你能解决这个问题,因为两年后我才谈到这个问题,但是......

当我使用xuggle导入视频时,我遇到了同样的错误。我知道这是特定文件的问题,因为我使用不同的视频进行了测试,但没有收到错误。我通过使用VLC Media Player将视频转换为相同的文件类型来修复此问题 - 仍然是具有相同质量的相同视频,但看起来阻止 Java 使用该文件的任何内容都在该转换中丢失了。