音频文件转码期间出现编码异常
Posted
技术标签:
【中文标题】音频文件转码期间出现编码异常【英文标题】:Encoding Exception during Transcode with audio files 【发布时间】:2016-04-18 01:09:11 【问题描述】:我正在尝试使用 Eclipse 4.50 在 Mac OSX 10.11.3 上使用名为 JAVE 的 FFMPEG 包装库进行转码
我的 Converter.java 类看起来像这样:
package matador;
import it.sauronsoftware.jave.AudioAttributes;
import it.sauronsoftware.jave.EncodingAttributes;
import it.sauronsoftware.jave.EncoderException;
import it.sauronsoftware.jave.InputFormatException;
import it.sauronsoftware.jave.Encoder;
import java.io.*;
public class Converter
public static void main(String[] args) throws InputFormatException, EncoderException
File source = new File("Classic.m4a");
File target = new File("target.mp3");
AudioAttributes audio = new AudioAttributes();
audio.setCodec("libmp3lame");
audio.setBitRate(new Integer(128000));
audio.setChannels(new Integer(2));
audio.setSamplingRate(new Integer(44100));
EncodingAttributes attrs = new EncodingAttributes();
attrs.setFormat("mp3");
attrs.setAudioAttributes(audio);
Encoder encoder = new Encoder(new MyFFMPEGExecutableLocator());
try
encoder.encode(source, target, attrs, null);
catch (IllegalArgumentException e)
e.printStackTrace();
catch (InputFormatException e)
e.printStackTrace();
catch (EncoderException e)
e.printStackTrace();
我遇到的问题是特定音频文件(无论格式如何)给我这个 EncoderException:
it.sauronsoftware.jave.EncoderException: Metadata:
at it.sauronsoftware.jave.Encoder.encode(Encoder.java:863)
at matador.Converter.main(Converter.java:32)
我查看了 Encoder.java,第 863 行的 EncoderException 是这个特定代码:
else if (!line.startsWith("Output #0"))
throw new EncoderException(line);
我一直无法弄清楚为什么会发生这种情况,但特定的音频文件(WAV/AAC/等)确实会编码,但大多数只是给出这个例外。
感谢您的帮助!
编辑:根据可能能够进一步帮助我的请求,这里是 Encoder.java 代码的全部内容:
package it.sauronsoftware.jave;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Encoder
private static final Pattern FORMAT_PATTERN = Pattern
.compile("^\\s*([D ])([E ])\\s+([\\w,]+)\\s+.+$");
private static final Pattern ENCODER_DECODER_PATTERN = Pattern.compile(
"^\\s*([D ])([E ])([AVS]).3\\s+(.+)$", Pattern.CASE_INSENSITIVE);
private static final Pattern PROGRESS_INFO_PATTERN = Pattern.compile(
"\\s*(\\w+)\\s*=\\s*(\\S+)\\s*", Pattern.CASE_INSENSITIVE);
private static final Pattern SIZE_PATTERN = Pattern.compile(
"(\\d+)x(\\d+)", Pattern.CASE_INSENSITIVE);
private static final Pattern FRAME_RATE_PATTERN = Pattern.compile(
"([\\d.]+)\\s+(?:fps|tb\\(r\\))", Pattern.CASE_INSENSITIVE);
private static final Pattern BIT_RATE_PATTERN = Pattern.compile(
"(\\d+)\\s+kb/s", Pattern.CASE_INSENSITIVE);
private static final Pattern SAMPLING_RATE_PATTERN = Pattern.compile(
"(\\d+)\\s+Hz", Pattern.CASE_INSENSITIVE);
private static final Pattern CHANNELS_PATTERN = Pattern.compile(
"(mono|stereo)", Pattern.CASE_INSENSITIVE);
private static final Pattern SUCCESS_PATTERN = Pattern.compile(
"^\\s*video\\:\\S+\\s+audio\\:\\S+\\s+global headers\\:\\S+.*$",
Pattern.CASE_INSENSITIVE);
private FFMPEGLocator locator;
public Encoder()
this.locator = new DefaultFFMPEGLocator();
public Encoder(FFMPEGLocator locator)
this.locator = locator;
public String[] getAudioDecoders() throws EncoderException
ArrayList res = new ArrayList();
FFMPEGExecutor ffmpeg = locator.createExecutor();
ffmpeg.addArgument("-formats");
try
ffmpeg.execute();
RBufferedReader reader = null;
reader = new RBufferedReader(new InputStreamReader(ffmpeg
.getInputStream()));
String line;
boolean evaluate = false;
while ((line = reader.readLine()) != null)
if (line.trim().length() == 0)
continue;
if (evaluate)
Matcher matcher = ENCODER_DECODER_PATTERN.matcher(line);
if (matcher.matches())
String decoderFlag = matcher.group(1);
String audioVideoFlag = matcher.group(3);
if ("D".equals(decoderFlag)
&& "A".equals(audioVideoFlag))
String name = matcher.group(4);
res.add(name);
else
break;
else if (line.trim().equals("Codecs:"))
evaluate = true;
catch (IOException e)
throw new EncoderException(e);
finally
ffmpeg.destroy();
int size = res.size();
String[] ret = new String[size];
for (int i = 0; i < size; i++)
ret[i] = (String) res.get(i);
return ret;
public String[] getAudioEncoders() throws EncoderException
ArrayList res = new ArrayList();
FFMPEGExecutor ffmpeg = locator.createExecutor();
ffmpeg.addArgument("-formats");
try
ffmpeg.execute();
RBufferedReader reader = null;
reader = new RBufferedReader(new InputStreamReader(ffmpeg
.getInputStream()));
String line;
boolean evaluate = false;
while ((line = reader.readLine()) != null)
if (line.trim().length() == 0)
continue;
if (evaluate)
Matcher matcher = ENCODER_DECODER_PATTERN.matcher(line);
if (matcher.matches())
String encoderFlag = matcher.group(2);
String audioVideoFlag = matcher.group(3);
if ("E".equals(encoderFlag)
&& "A".equals(audioVideoFlag))
String name = matcher.group(4);
res.add(name);
else
break;
else if (line.trim().equals("Codecs:"))
evaluate = true;
catch (IOException e)
throw new EncoderException(e);
finally
ffmpeg.destroy();
int size = res.size();
String[] ret = new String[size];
for (int i = 0; i < size; i++)
ret[i] = (String) res.get(i);
return ret;
public String[] getVideoDecoders() throws EncoderException
ArrayList res = new ArrayList();
FFMPEGExecutor ffmpeg = locator.createExecutor();
ffmpeg.addArgument("-formats");
try
ffmpeg.execute();
RBufferedReader reader = null;
reader = new RBufferedReader(new InputStreamReader(ffmpeg
.getInputStream()));
String line;
boolean evaluate = false;
while ((line = reader.readLine()) != null)
if (line.trim().length() == 0)
continue;
if (evaluate)
Matcher matcher = ENCODER_DECODER_PATTERN.matcher(line);
if (matcher.matches())
String decoderFlag = matcher.group(1);
String audioVideoFlag = matcher.group(3);
if ("D".equals(decoderFlag)
&& "V".equals(audioVideoFlag))
String name = matcher.group(4);
res.add(name);
else
break;
else if (line.trim().equals("Codecs:"))
evaluate = true;
catch (IOException e)
throw new EncoderException(e);
finally
ffmpeg.destroy();
int size = res.size();
String[] ret = new String[size];
for (int i = 0; i < size; i++)
ret[i] = (String) res.get(i);
return ret;
public String[] getVideoEncoders() throws EncoderException
ArrayList res = new ArrayList();
FFMPEGExecutor ffmpeg = locator.createExecutor();
ffmpeg.addArgument("-formats");
try
ffmpeg.execute();
RBufferedReader reader = null;
reader = new RBufferedReader(new InputStreamReader(ffmpeg
.getInputStream()));
String line;
boolean evaluate = false;
while ((line = reader.readLine()) != null)
if (line.trim().length() == 0)
continue;
if (evaluate)
Matcher matcher = ENCODER_DECODER_PATTERN.matcher(line);
if (matcher.matches())
String encoderFlag = matcher.group(2);
String audioVideoFlag = matcher.group(3);
if ("E".equals(encoderFlag)
&& "V".equals(audioVideoFlag))
String name = matcher.group(4);
res.add(name);
else
break;
else if (line.trim().equals("Codecs:"))
evaluate = true;
catch (IOException e)
throw new EncoderException(e);
finally
ffmpeg.destroy();
int size = res.size();
String[] ret = new String[size];
for (int i = 0; i < size; i++)
ret[i] = (String) res.get(i);
return ret;
public String[] getSupportedEncodingFormats() throws EncoderException
ArrayList res = new ArrayList();
FFMPEGExecutor ffmpeg = locator.createExecutor();
ffmpeg.addArgument("-formats");
try
ffmpeg.execute();
RBufferedReader reader = null;
reader = new RBufferedReader(new InputStreamReader(ffmpeg
.getInputStream()));
String line;
boolean evaluate = false;
while ((line = reader.readLine()) != null)
if (line.trim().length() == 0)
continue;
if (evaluate)
Matcher matcher = FORMAT_PATTERN.matcher(line);
if (matcher.matches())
String encoderFlag = matcher.group(2);
if ("E".equals(encoderFlag))
String aux = matcher.group(3);
StringTokenizer st = new StringTokenizer(aux, ",");
while (st.hasMoreTokens())
String token = st.nextToken().trim();
if (!res.contains(token))
res.add(token);
else
break;
else if (line.trim().equals("File formats:"))
evaluate = true;
catch (IOException e)
throw new EncoderException(e);
finally
ffmpeg.destroy();
int size = res.size();
String[] ret = new String[size];
for (int i = 0; i < size; i++)
ret[i] = (String) res.get(i);
return ret;
public String[] getSupportedDecodingFormats() throws EncoderException
ArrayList res = new ArrayList();
FFMPEGExecutor ffmpeg = locator.createExecutor();
ffmpeg.addArgument("-formats");
try
ffmpeg.execute();
RBufferedReader reader = null;
reader = new RBufferedReader(new InputStreamReader(ffmpeg
.getInputStream()));
String line;
boolean evaluate = false;
while ((line = reader.readLine()) != null)
if (line.trim().length() == 0)
continue;
if (evaluate)
Matcher matcher = FORMAT_PATTERN.matcher(line);
if (matcher.matches())
String decoderFlag = matcher.group(1);
if ("D".equals(decoderFlag))
String aux = matcher.group(3);
StringTokenizer st = new StringTokenizer(aux, ",");
while (st.hasMoreTokens())
String token = st.nextToken().trim();
if (!res.contains(token))
res.add(token);
else
break;
else if (line.trim().equals("File formats:"))
evaluate = true;
catch (IOException e)
throw new EncoderException(e);
finally
ffmpeg.destroy();
int size = res.size();
String[] ret = new String[size];
for (int i = 0; i < size; i++)
ret[i] = (String) res.get(i);
return ret;
public MultimediaInfo getInfo(File source) throws InputFormatException,
EncoderException
FFMPEGExecutor ffmpeg = locator.createExecutor();
ffmpeg.addArgument("-i");
ffmpeg.addArgument(source.getAbsolutePath());
try
ffmpeg.execute();
catch (IOException e)
throw new EncoderException(e);
try
RBufferedReader reader = null;
reader = new RBufferedReader(new InputStreamReader(ffmpeg
.getErrorStream()));
return parseMultimediaInfo(source, reader);
finally
ffmpeg.destroy();
private MultimediaInfo parseMultimediaInfo(File source,
RBufferedReader reader) throws InputFormatException,
EncoderException
Pattern p1 = Pattern.compile("^\\s*Input #0, (\\w+).+$\\s*",
Pattern.CASE_INSENSITIVE);
Pattern p2 = Pattern.compile(
"^\\s*Duration: (\\d\\d):(\\d\\d):(\\d\\d)\\.(\\d).*$",
Pattern.CASE_INSENSITIVE);
Pattern p3 = Pattern.compile(
"^\\s*Stream #\\S+: ((?:Audio)|(?:Video)|(?:Data)): (.*)\\s*$",
Pattern.CASE_INSENSITIVE);
MultimediaInfo info = null;
try
int step = 0;
while (true)
String line = reader.readLine();
if (line == null)
break;
if (step == 0)
String token = source.getAbsolutePath() + ": ";
if (line.startsWith(token))
String message = line.substring(token.length());
throw new InputFormatException(message);
Matcher m = p1.matcher(line);
if (m.matches())
String format = m.group(1);
info = new MultimediaInfo();
info.setFormat(format);
step++;
else if (step == 1)
Matcher m = p2.matcher(line);
if (m.matches())
long hours = Integer.parseInt(m.group(1));
long minutes = Integer.parseInt(m.group(2));
long seconds = Integer.parseInt(m.group(3));
long dec = Integer.parseInt(m.group(4));
long duration = (dec * 100L) + (seconds * 1000L)
+ (minutes * 60L * 1000L)
+ (hours * 60L * 60L * 1000L);
info.setDuration(duration);
step++;
else
step = 3;
else if (step == 2)
Matcher m = p3.matcher(line);
if (m.matches())
String type = m.group(1);
String specs = m.group(2);
if ("Video".equalsIgnoreCase(type))
VideoInfo video = new VideoInfo();
StringTokenizer st = new StringTokenizer(specs, ",");
for (int i = 0; st.hasMoreTokens(); i++)
String token = st.nextToken().trim();
if (i == 0)
video.setDecoder(token);
else
boolean parsed = false;
// Video size.
Matcher m2 = SIZE_PATTERN.matcher(token);
if (!parsed && m2.find())
int width = Integer.parseInt(m2
.group(1));
int height = Integer.parseInt(m2
.group(2));
video.setSize(new VideoSize(width,
height));
parsed = true;
// Frame rate.
m2 = FRAME_RATE_PATTERN.matcher(token);
if (!parsed && m2.find())
try
float frameRate = Float
.parseFloat(m2.group(1));
video.setFrameRate(frameRate);
catch (NumberFormatException e)
;
parsed = true;
// Bit rate.
m2 = BIT_RATE_PATTERN.matcher(token);
if (!parsed && m2.find())
int bitRate = Integer.parseInt(m2
.group(1));
video.setBitRate(bitRate);
parsed = true;
info.setVideo(video);
else if ("Audio".equalsIgnoreCase(type))
AudioInfo audio = new AudioInfo();
StringTokenizer st = new StringTokenizer(specs, ",");
for (int i = 0; st.hasMoreTokens(); i++)
String token = st.nextToken().trim();
if (i == 0)
audio.setDecoder(token);
else
boolean parsed = false;
// Sampling rate.
Matcher m2 = SAMPLING_RATE_PATTERN
.matcher(token);
if (!parsed && m2.find())
int samplingRate = Integer.parseInt(m2
.group(1));
audio.setSamplingRate(samplingRate);
parsed = true;
// Channels.
m2 = CHANNELS_PATTERN.matcher(token);
if (!parsed && m2.find())
String ms = m2.group(1);
if ("mono".equalsIgnoreCase(ms))
audio.setChannels(1);
else if ("stereo"
.equalsIgnoreCase(ms))
audio.setChannels(2);
parsed = true;
// Bit rate.
m2 = BIT_RATE_PATTERN.matcher(token);
if (!parsed && m2.find())
int bitRate = Integer.parseInt(m2
.group(1));
audio.setBitRate(bitRate);
parsed = true;
info.setAudio(audio);
else
step = 3;
if (step == 3)
reader.reinsertLine(line);
break;
catch (IOException e)
throw new EncoderException(e);
if (info == null)
throw new InputFormatException();
return info;
private Hashtable parseProgressInfoLine(String line)
Hashtable table = null;
Matcher m = PROGRESS_INFO_PATTERN.matcher(line);
while (m.find())
if (table == null)
table = new Hashtable();
String key = m.group(1);
String value = m.group(2);
table.put(key, value);
return table;
public void encode(File source, File target, EncodingAttributes attributes)
throws IllegalArgumentException, InputFormatException,
EncoderException
encode(source, target, attributes, null);
public void encode(File source, File target, EncodingAttributes attributes,
EncoderProgressListener listener) throws IllegalArgumentException,
InputFormatException, EncoderException
String formatAttribute = attributes.getFormat();
Float offsetAttribute = attributes.getOffset();
Float durationAttribute = attributes.getDuration();
AudioAttributes audioAttributes = attributes.getAudioAttributes();
VideoAttributes videoAttributes = attributes.getVideoAttributes();
if (audioAttributes == null && videoAttributes == null)
throw new IllegalArgumentException(
"Both audio and video attributes are null");
target = target.getAbsoluteFile();
target.getParentFile().mkdirs();
FFMPEGExecutor ffmpeg = locator.createExecutor();
if (offsetAttribute != null)
ffmpeg.addArgument("-ss");
ffmpeg.addArgument(String.valueOf(offsetAttribute.floatValue()));
ffmpeg.addArgument("-i");
ffmpeg.addArgument(source.getAbsolutePath());
if (durationAttribute != null)
ffmpeg.addArgument("-t");
ffmpeg.addArgument(String.valueOf(durationAttribute.floatValue()));
if (videoAttributes == null)
ffmpeg.addArgument("-vn");
else
String codec = videoAttributes.getCodec();
if (codec != null)
ffmpeg.addArgument("-vcodec");
ffmpeg.addArgument(codec);
String tag = videoAttributes.getTag();
if (tag != null)
ffmpeg.addArgument("-vtag");
ffmpeg.addArgument(tag);
Integer bitRate = videoAttributes.getBitRate();
if (bitRate != null)
ffmpeg.addArgument("-b");
ffmpeg.addArgument(String.valueOf(bitRate.intValue()));
Integer frameRate = videoAttributes.getFrameRate();
if (frameRate != null)
ffmpeg.addArgument("-r");
ffmpeg.addArgument(String.valueOf(frameRate.intValue()));
VideoSize size = videoAttributes.getSize();
if (size != null)
ffmpeg.addArgument("-s");
ffmpeg.addArgument(String.valueOf(size.getWidth()) + "x"
+ String.valueOf(size.getHeight()));
if (audioAttributes == null)
ffmpeg.addArgument("-an");
else
String codec = audioAttributes.getCodec();
if (codec != null)
ffmpeg.addArgument("-acodec");
ffmpeg.addArgument(codec);
Integer bitRate = audioAttributes.getBitRate();
if (bitRate != null)
ffmpeg.addArgument("-ab");
ffmpeg.addArgument(String.valueOf(bitRate.intValue()));
Integer channels = audioAttributes.getChannels();
if (channels != null)
ffmpeg.addArgument("-ac");
ffmpeg.addArgument(String.valueOf(channels.intValue()));
Integer samplingRate = audioAttributes.getSamplingRate();
if (samplingRate != null)
ffmpeg.addArgument("-ar");
ffmpeg.addArgument(String.valueOf(samplingRate.intValue()));
Integer volume = audioAttributes.getVolume();
if (volume != null)
ffmpeg.addArgument("-vol");
ffmpeg.addArgument(String.valueOf(volume.intValue()));
ffmpeg.addArgument("-f");
ffmpeg.addArgument(formatAttribute);
ffmpeg.addArgument("-y");
ffmpeg.addArgument(target.getAbsolutePath());
try
ffmpeg.execute();
catch (IOException e)
throw new EncoderException(e);
try
String lastWarning = null;
long duration;
long progress = 0;
RBufferedReader reader = null;
reader = new RBufferedReader(new InputStreamReader(ffmpeg
.getErrorStream()));
MultimediaInfo info = parseMultimediaInfo(source, reader);
if (durationAttribute != null)
duration = (long) Math
.round((durationAttribute.floatValue() * 1000L));
else
duration = info.getDuration();
if (offsetAttribute != null)
duration -= (long) Math
.round((offsetAttribute.floatValue() * 1000L));
if (listener != null)
listener.sourceInfo(info);
int step = 0;
String line;
while ((line = reader.readLine()) != null)
if (step == 0)
if (line.startsWith("WARNING: "))
if (listener != null)
listener.message(line);
else if (!line.startsWith("Output #0"))
throw new EncoderException(line);
else
step++;
else if (step == 1)
if (!line.startsWith(" "))
step++;
if (step == 2)
if (!line.startsWith("Stream mapping:"))
throw new EncoderException(line);
else
step++;
else if (step == 3)
if (!line.startsWith(" "))
step++;
if (step == 4)
line = line.trim();
if (line.length() > 0)
Hashtable table = parseProgressInfoLine(line);
if (table == null)
if (listener != null)
listener.message(line);
lastWarning = line;
else
if (listener != null)
String time = (String) table.get("time");
if (time != null)
int dot = time.indexOf('.');
if (dot > 0 && dot == time.length() - 2
&& duration > 0)
String p1 = time.substring(0, dot);
String p2 = time.substring(dot + 1);
try
long i1 = Long.parseLong(p1);
long i2 = Long.parseLong(p2);
progress = (i1 * 1000L)
+ (i2 * 100L);
int perm = (int) Math
.round((double) (progress * 1000L)
/ (double) duration);
if (perm > 1000)
perm = 1000;kMDItemAudioEncodingApplication = "Lavf57.26.100"
listener.progress(perm);
catch (NumberFormatException e)
;
lastWarning = null;
if (lastWarning != null)
if (!SUCCESS_PATTERN.matcher(lastWarning).matches())
throw new EncoderException(lastWarning);
catch (IOException e)
throw new EncoderException(e);
finally
ffmpeg.destroy();
【问题讨论】:
也许您可以发布整个 Encoder.java 或将其链接到某个地方 我继续为你做了那件事@gpasch 我没有看到很多关于 Jave 字符串的信息输出 #0 是 ffmpeg 操作期间的正常输出 - 也许有人会回答,但你应该直接从命令行使用 ffmpeg - 没有真正的麻烦 @gpasch 这是包装器的问题,我刚刚打开了整个库并编辑了几行以不包含该特定异常,并且每个文件现在都在无缝转换。我会留下这个,以防有人找到更好的方法来绕过这个 【参考方案1】:改变
Encoder encoder = new Encoder(new MyFFMPEGExecutableLocator());
try
encoder.encode(source, target, attrs, null);
catch (IllegalArgumentException e)
e.printStackTrace();
catch (InputFormatException e)
e.printStackTrace();
catch (EncoderException e)
e.printStackTrace();
到
Encoder encoder = new Encoder();
try
encoder.encode(source, target, attrs);
catch(Exception e)
System.out.println("Encoding Failed");
【讨论】:
为什么一个特定的 FFMPEG 定位器会导致这个 EncoderException?可能是因为 ffmpeg 命令参数版本?以上是关于音频文件转码期间出现编码异常的主要内容,如果未能解决你的问题,请参考以下文章
使用 IMFSourceReader 对来自麦克风的音频和视频流中的延迟进行编码时会出现噪音