【记一个错误】使用Javacv通过视频url生成网络视频封面报错:FrameGrabber$Exception: avformat_open_input() e

674 阅读1分钟

一、报错详情:

2022-12-06 15:06:53.243 [main] [] ERROR com.zzdx.util.FileUtils [fetchFrame,190] - 错误:
org.bytedeco.javacv.FrameGrabber$Exception: avformat_open_input() error -2: Could not open input "java.io.BufferedInputStream@2254127a". (Has setFormat() been called?)
	at org.bytedeco.javacv.FFmpegFrameGrabber.startUnsafe(FFmpegFrameGrabber.java:861)
	at org.bytedeco.javacv.FFmpegFrameGrabber.start(FFmpegFrameGrabber.java:790)
	at org.bytedeco.javacv.FFmpegFrameGrabber.start(FFmpegFrameGrabber.java:785)
	at com.zzdx.util.FileUtils.fetchFrame(FileUtils.java:150)
	at com.zzdx.Test.main(Test.java:64)
Error on InputStream.reset() or skip(): org.apache.http.ConnectionClosedException: Premature end of Content-Length delimited message body (expected: 20,398,927; received: 7,860)
[mov,mp4,m4a,3gp,3g2,mj2 @ 0000027846357440] moov atom not found

二、报错原因:

先看代码:

public static InputStream sendPostByHttps(String url, Map<String, String> body, String token) {
    CloseableHttpResponse response = null;
    // 处理请求路径
    url = UriComponentsBuilder.fromHttpUrl(url)
            .toUriString();
    //创建httpclient对象
    CloseableHttpClient client = null;
    try {
        client = HttpClients.custom()
                .setSSLSocketFactory(new SSLConnectionSocketFactory(SSLContexts.custom()
                        //忽略掉对服务器端证书的校验
                        .loadTrustMaterial(null, new TrustSelfSignedStrategy())
                        .build(), NoopHostnameVerifier.INSTANCE))
                .build();
        //创建post方式请求对象
        HttpGet httpPost = new HttpGet(url);
        // 请求头设置
        httpPost.setHeader("Accept", "*/*");
        httpPost.setHeader("connection", "Keep-Alive");
        httpPost.setHeader("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
        httpPost.setHeader("Content-type", "application/json;charset=utf-8");
        //执行请求操作,并拿到结果
        response = client.execute(httpPost);
        return response.getEntity().getContent();
    } catch (Exception e) {
    } finally {
        try {
            if (client != null) {
                client.close();
            }
            if (response != null) {
                response.close();
            }
        } catch (IOException e) {
        }
    }
    return null;
}

由于通过Javacv生成视频封面需要获取文件流,所以需要先访问视频url获取输入流。

而在sendPostByHttps()中,finally块关闭了httpClient和CloseableHttpResponse导致输入流被停止了,进而导致FFmpegFrameGrabber在读取输入流时出错。

所以,httpClient和CloseableHttpResponse的关闭必须在FFmpegFrameGrabber生成视频封面结束之后。