android获取视频⼤⼩,Android获取视频缩略图(获取视频每帧
数据)的优化⽅案
速度对⽐
左边的图⽚是通过⽅式1
右边的图⽚是通过⽅式2
speed.gif
速度优化,效果拔群。
在缩⼩2倍的Bitmap输出情况下
使⽤MediaMetadataRetriever 抽帧的速度,每帧稳定在 300ms左右。
使⽤MediaCodec+ImageReader 第⼀次抽帧。⼤概是200ms ,后续每帧则是50ms左右。
注意:如果不缩⼩图⽚的话,建议还是使⽤MediaMetadataRetriever。
使⽤当前库的话,调⽤metadataRetriever.forceFallBack(true);
⽅案
1. 通过MediaMetaRetrivier来进⾏获取
代码较为简单,就是⼀个循环
MediaMetadataRetriever metadataRetriever = new MediaMetadataRetriever();
metadataRetriever.tDataSource(fileName);
String duration = actMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
Log.d(TAG, "duration = " + duration);
int durationMs = Integer.parInt(duration);
//每秒取⼀次
for (int i = 0; i < durationMs; i += 1000) {
清明有感long start = System.nanoTime();
Log.d(TAG, "getFrameAtTime time = " + i);
//这⾥传⼊的是ms
Bitmap frameAtIndex = FrameAtTime(i * 1000);
Bitmap ateScaledBitmap(Width()/Height()/8,fal); le();
long end = System.nanoTime();
long cost = end - start;
Log.d(TAG, "cost time in millis = " + (cost * 1f / 1000000));
if (callBack != null) {
}
}
2. 通过MediaCodec和ImageReader进⾏获取
就是通过通过Surface,⽤MediaExtrator,将MediaCodec解码后的数据,传递给ImageReader。来进⾏显⽰。MediaExtractor extractor = null;
MediaCodec codec = null;
try {
extractor = new MediaExtractor();
extractor.tDataSource(fileName);
int trackCount = TrackCount();
MediaFormat videoFormat = null;
for (int i = 0; i < trackCount; i++) {
MediaFormat trackFormat = TrackFormat(i);
if (String(MediaFormat.KEY_MIME).contains("video")) {
videoFormat = trackFormat;
extractor.lectTrack(i);
朗读稿
break;
}
}
if (videoFormat == null) {
Log.d(TAG, "Can not get video format");
return;
}
int imageFormat = ImageFormat.YUV_420_888;
int colorFormat = COLOR_FormatYUV420Flexible;
videoFormat.tInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat);
videoFormat.tInteger(MediaFormat.KEY_WIDTH, Integer(MediaFormat.KEY_WIDTH) / 4); videoFormat.tInteger(MediaFormat.KEY_HEIGHT, Integer(MediaFormat.KEY_HEIGHT) / 4); long duration = Long(MediaFormat.KEY_DURATION);
codec = String(MediaFormat.KEY_MIME));
ImageReader imageReader = ImageReader豆豉酱
.newInstance(
imageFormat,
3);
final ImageReaderHandlerThread imageReaderHandlerThread = new ImageReaderHandlerThread();
imageReader.tOnImageAvailableListener(new MyOnImageAvailableListener(callBack), Handler());
codec.start();
心灵救赎MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
long timeOut = 5 * 1000;//10ms
boolean inputDone = fal;
boolean outputDone = fal;
ByteBuffer[] inputBuffers = null;
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.LOLLIPOP) { inputBuffers = InputBuffers();
}
//开始进⾏解码。
int count = 1;
while (!outputDone) {
if (requestStop) {
有口无心return;
济南特色
}
if (!inputDone) {
//feed data
int inputBufferIndex = codec.dequeueInputBuffer(timeOut);
if (inputBufferIndex >= 0) {
ByteBuffer inputBuffer;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { inputBuffer = InputBuffer(inputBufferIndex);
} el {
inputBuffer = inputBuffers[inputBufferIndex];
}
int sampleData = adSampleData(inputBuffer, 0);
long sampleTime = SampleTime();
codec.queueInputBuffer(inputBufferIndex, 0, sampleData, sampleTime, 0);
//继续
if (interval == 0) {
extractor.advance();
} el {
extractor.ekTo(count * interval * 1000, MediaExtractor.SEEK_TO_PREVIOUS_SYNC);
count++;
// extractor.advance();
}
lol卡特琳娜} el {
//⼩于0,说明读完了
codec.queueInputBuffer(inputBufferIndex, 0, 0, 0L, MediaCodec.BUFFER_FLAG_END_OF_STREAM); inputDone = true;
Log.d(TAG, "end of stream");
}
}
}
if (!outputDone) {
//get data
int status = codec.dequeueOutputBuffer(bufferInfo, timeOut);
if (status ==
MediaCodec.INFO_TRY_AGAIN_LATER) {
//继续
} el if (status == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
//开始进⾏解码
} el if (status == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
//同样啥都不做
} el {
//在这⾥判断,当前编码器的状态
if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
Log.d(TAG, "output EOS");
outputDone = true;
boolean doRender = (bufferInfo.size != 0);
long prentationTimeUs = bufferInfo.prentationTimeUs;
if (lastPrentationTimeUs == 0) {
lastPrentationTimeUs = prentationTimeUs;
} el {
long diff = prentationTimeUs - lastPrentationTimeUs;
if (interval != 0) {
if (diff < interval * 1000) {
doRender = fal;
} el {
lastPrentationTimeUs = prentationTimeUs;
}
Log.d(TAG,
"diff time in ms =" + diff / 1000);
}
}
//有数据了.因为会直接传递给Surface,所以说明都不做好了
澳大利亚的英语Log.d(TAG, "surface decoder given buffer " + status +
" (size=" + bufferInfo.size + ")" + ",doRender = " + doRender + ", prentationTimeUs=" + prentationTimeUs); //直接送显就可以了
}
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (codec != null) {
codec.stop();
}
if (extractor != null) {