使用MediaCodec、Media Extractor和Media Muxer在Android上进行视频剪辑
在我的Android应用程序中,我需要一个解决方案,当用户可以从内部存储中修剪视频时。我试图在不使用任何第三方库的情况下实现这一点。我引用的是谷歌的Gallery应用程序源代码。但我得到了以下错误: 视频曲目的时间戳66733<时间戳133467 关于时间戳的问题很少有这样的问题,但我真的没有弄明白,因为我对使用MediaCodec、MediaMuxer等还不熟悉。如果有任何问题可以帮助解决,那就太好了 这是我的密码:使用MediaCodec、Media Extractor和Media Muxer在Android上进行视频剪辑,android,video,android-mediacodec,mediamuxer,Android,Video,Android Mediacodec,Mediamuxer,在我的Android应用程序中,我需要一个解决方案,当用户可以从内部存储中修剪视频时。我试图在不使用任何第三方库的情况下实现这一点。我引用的是谷歌的Gallery应用程序源代码。但我得到了以下错误: 视频曲目的时间戳66733
// Set up MediaExtractor to read from the source.
MediaExtractor extractor = new MediaExtractor();
extractor.setDataSource(srcPath);
int trackCount = extractor.getTrackCount();
System.out.println("tracl" + trackCount);
// Set up MediaMuxer for the destination.
MediaMuxer muxer;
muxer = new MediaMuxer(dstPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
// Set up the tracks and retrieve the max buffer size for selected
// tracks.
HashMap<Integer, Integer> indexMap = new HashMap<>(trackCount);
int bufferSize = -1;
for (int i = 0; i < trackCount; i++) {
MediaFormat format = extractor.getTrackFormat(i);
String mime = format.getString(MediaFormat.KEY_MIME);
boolean selectCurrentTrack = false;
if (mime.startsWith("audio/") && useAudio) {
selectCurrentTrack = true;
} else if (mime.startsWith("video/") && useVideo) {
selectCurrentTrack = true;
}
if (selectCurrentTrack) {
extractor.selectTrack(i);
int dstIndex = muxer.addTrack(format);
System.out.println(format);
System.out.println("dstIndex" + dstIndex);
indexMap.put(i, dstIndex);
if (format.containsKey(MediaFormat.KEY_MAX_INPUT_SIZE)) {
int newSize = format.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE);
bufferSize = newSize > bufferSize ? newSize : bufferSize;
}
}
}
System.out.println(indexMap);
if (bufferSize < 0) {
bufferSize = DEFAULT_BUFFER_SIZE;
}
// Set up the orientation and starting time for extractor.
MediaMetadataRetriever retrieverSrc = new MediaMetadataRetriever();
retrieverSrc.setDataSource(srcPath);
String degreesString = retrieverSrc.extractMetadata(
MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION);
if (degreesString != null) {
int degrees = Integer.parseInt(degreesString);
if (degrees >= 0) {
muxer.setOrientationHint(degrees);
}
}
if (startMs > 0) {
extractor.seekTo(startMs * 1000, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
}
// System.out.println(extractor.);
// Copy the samples from MediaExtractor to MediaMuxer. We will loop
// for copying each sample and stop when we get to the end of the source
// file or exceed the end time of the trimming.
int offset = 0;
int trackIndex = -1;
ByteBuffer dstBuf = ByteBuffer.allocate(bufferSize);
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
try {
muxer.start();
while (true) {
System.out.println("copying");
bufferInfo.offset = offset;
bufferInfo.size = extractor.readSampleData(dstBuf, offset);
if (bufferInfo.size < 0 ) {
// InstabugSDKLogger.d(TAG, "Saw input EOS.");
System.out.println("Saw input EOS.");
bufferInfo.size = 0;
break;
} else {
/**
* The presentation timestamp in microseconds for the buffer.
* This is derived from the presentation timestamp passed in
* with the corresponding input buffer. This should be ignored for
* a 0-sized buffer.
*/
/**
* Returns the current sample's presentation time in microseconds.
* or -1 if no more samples are available.
*/
bufferInfo.presentationTimeUs = extractor.getSampleTime();
//1 sec = 1000000 micco sec
if (endMs > 0 && bufferInfo.presentationTimeUs > (endMs * 1000)) {
break;
} else {
bufferInfo.flags = extractor.getSampleFlags();
trackIndex = extractor.getSampleTrackIndex();
muxer.writeSampleData(indexMap.get(trackIndex), dstBuf, bufferInfo);
//System.out.println(muxer);
extractor.advance();
}
}
}
muxer.stop();
File file = new File(srcPath);
file.delete();
} catch (IllegalStateException e) {
System.out.println("The source video file is malformed");
} finally {
muxer.release();
}
//将MediaExtractor设置为从源代码读取。
MediaExtractor提取器=新的MediaExtractor();
setDataSource(srcPath);
int trackCount=extractor.getTrackCount();
System.out.println(“tracl”+trackCount);
//为目标设置MediaMuxer。
MediaMuxer-muxer;
muxer=newmediamuxer(dstPath,MediaMuxer.OutputFormat.muxer\u OUTPUT\u MPEG\u 4);
//设置磁道并检索选定磁道的最大缓冲区大小
//轨道。
HashMap indexMap=新的HashMap(trackCount);
int bufferSize=-1;
对于(int i=0;ibufferSize?newSize:bufferSize;
}
}
}
System.out.println(indexMap);
如果(缓冲区大小<0){
bufferSize=默认的缓冲区大小;
}
//设置提取器的方向和启动时间。
MediaMetadataRetriever retrieverSrc=新的MediaMetadataRetriever();
retrieverSrc.setDataSource(srcPath);
String degreesString=retrieverSrc.extractMetadata(
MediaMetadataRetriever.METADATA\u KEY\u VIDEO\u ROTATION);
if(degreesString!=null){
int度=整数.parseInt(degreesString);
如果(度>=0){
muxer.setOrientationHint(度);
}
}
如果(startMs>0){
提取器.seekTo(startMs*1000,MediaExtractor.SEEK\u至\u最近的\u同步);
}
//系统输出打印LN(提取器);
//将样本从MediaExtractor复制到MediaMuxer。我们将循环
//用于复制每个样本,并在到达源代码末尾时停止
//归档或超过修剪的结束时间。
整数偏移=0;
int trackIndex=-1;
ByteBuffer DSTBUFF=ByteBuffer.allocate(缓冲区大小);
MediaCodec.BufferInfo BufferInfo=新的MediaCodec.BufferInfo();
试一试{
muxer.start();
while(true){
系统输出打印项次(“复制”);
bufferInfo.offset=偏移量;
bufferInfo.size=提取器.readSampleData(dstBuf,偏移量);
如果(bufferInfo.size<0){
//InstabugSDKLogger.d(标签,“Saw输入EOS”);
System.out.println(“Saw输入EOS”);
bufferInfo.size=0;
打破
}否则{
/**
*缓冲区的表示时间戳(以微秒为单位)。
*这是从传入的表示时间戳派生的
*使用相应的输入缓冲区。对于
*0大小的缓冲区。
*/
/**
*返回当前样本的显示时间(以微秒为单位)。
*如果没有更多样本,则为-1。
*/
bufferInfo.presentationTimeUs=提取器.getSampleTime();
//1秒=1000000米秒
如果(endMs>0&&bufferInfo.presentationTimeUs>(endMs*1000)){
打破
}否则{
bufferInfo.flags=提取器.getSampleFlags();
trackIndex=extractor.getSampleTrackIndex();
muxer.writeSampleData(indexMap.get(trackIndex)、dstBuf、bufferInfo);
//系统输出打印LN(muxer);
提取器;
}
}
}
muxer.stop();
文件文件=新文件(srcPath);
delete();
}捕获(非法状态){
System.out.println(“源视频文件格式不正确”);
}最后{
muxer.release();
}
这可能是很多事情,但我看到时间戳后的第一个想法是,前3个视频样本中有2个出现了故障(就演示时间而言)。这对于某些格式来说是正常的,例如“H.264 main”。相反,这些样品是按合成时间排序的。由于MediaExtractor/Muxer
似乎不支持合成时间,这让我相信您只能使用更简单的格式,例如“H.264基线”。如果你想证明我的理论,只需编写一个例程来转储所有的输入演示时间,看看它们是否严格有序。嘿@greeble31刚刚检查过。演示时间不按顺序排列。当订单中断时,它就崩溃了顺便问一下,你在测试什么版本的android?MediaMuxer只支持牛轧糖后的B帧。您好,先生,android版本是6。您的视频中有B帧,这意味着pts可能不会单调递增,这是自android牛轧糖后才支持的。你有3个选择,使用安卓7或更高版本