and*_*per 16 android filechannel inputstream android-contentresolver mp4parser
我们希望让用户从任何应用中选择视频,然后将视频剪裁为最多5秒.
为了让Uri被选中,我们让它工作正常(这里有解决方案).
至于修剪本身,我们找不到任何具有许可许可的好图书馆,除了一个名为"k4l-video-trimmer"的图书馆.例如,库"FFmpeg"被认为是非许可,因为它使用GPLv3,这要求使用它的应用程序也是开源的.此外,正如我所读,它需要相当多(约9MB).
可悲的是,这个库(k4l-video-trimmer)很老了,多年没有更新了,所以我不得不把它(这里)分叉,以便很好地处理它.它使用一个名为"mp4parser"的开源库来进行修剪.
问题是,这个库似乎只能处理文件,而不是一个Uri或者InputStream,所以即使样本在选择像普通文件一样无法访问的项目时也会崩溃,甚至还有无法处理的路径.我知道在很多情况下可以获得文件的路径,但在许多其他情况下,它不是,我也知道可以只复制文件(这里),但这不是一个好的解决方案,因为文件可能很大并占用大量空间,即使它已经可以访问.
库有两个地方使用文件:
在"K4LVideoTrimmer"文件中,在"setVideoURI"函数中,它只是获取要显示的文件大小.根据Google的文档,这里的解决方案非常简单:
public void setVideoURI(final Uri videoURI) {
mSrc = videoURI;
if (mOriginSizeFile == 0) {
final Cursor cursor = getContext().getContentResolver().query(videoURI, null, null, null, null);
if (cursor != null) {
int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE);
cursor.moveToFirst();
mOriginSizeFile = cursor.getLong(sizeIndex);
cursor.close();
mTextSize.setText(Formatter.formatShortFileSize(getContext(), mOriginSizeFile));
}
}
...
Run Code Online (Sandbox Code Playgroud)在"TrimVideoUtils"文件中,在"startTrim"中调用"genVideoUsingMp4Parser"函数.在那里,它使用以下方法调用"mp4parser"库:
Movie movie = MovieCreator.build(new FileDataSourceViaHeapImpl(src.getAbsolutePath()));
Run Code Online (Sandbox Code Playgroud)
它说他们使用FileDataSourceViaHeapImpl(来自"mp4parser"库)来避免Android上的OOM,所以我决定继续使用它.
事实是,它有4个CTORS,都期望文件有一些变化:File,filePath,FileChannel,FileChannel + fileName.
也许实现FileChannel和模拟一个真实的文件,使用ContentResolver和Uri?我想这可能是有可能的,即使这意味着在需要时重新打开InputStream ......
为了看看我的工作原理,你可以在这里克隆项目.只知道它没有做任何修剪,因为"K4LVideoTrimmer"文件中的代码被注释:
//TODO handle trimming using Uri
//TrimVideoUtils.startTrim(file, getDestinationPath(), mStartPosition, mEndPosition, mOnTrimVideoListener);
Run Code Online (Sandbox Code Playgroud)
编辑:
我以为我找到了一个解决方案,通过使用不同的解决方案来修剪自己,并在这里写了一下,但遗憾的是它无法处理一些输入视频,而mp4parser库可以处理它们.
请告诉我是否可以修改mp4parser处理此类输入视频,即使它来自Uri而不是文件(没有复制到视频文件的解决方法).
首先需要注意的是:我不熟悉 mp4parser 库,但你的问题看起来很有趣,所以我看了一下。
我认为值得您查看代码注释中所说的“主要用于测试”的类之一。InMemRandomAccessSourceImpl。要从任何 URI 创建电影,代码如下:
try {
InputStream inputStream = getContentResolver().openInputStream(uri);
Log.e("InputStream Size","Size " + inputStream);
int bytesAvailable = inputStream.available();
int bufferSize = Math.min(bytesAvailable, MAX_BUFFER_SIZE);
final byte[] buffer = new byte[bufferSize];
int read = 0;
int total = 0;
while ((read = inputStream.read(buffer)) !=-1 ) {
total += read;
}
if( total < bytesAvailable ){
Log.e(TAG, "Read from input stream failed")
return;
}
//or try inputStream.readAllBytes() if using Java 9
inputStream.close();
ByteBuffer bb = ByteBuffer.wrap(buffer);
Movie m2 = MovieCreator.build(new ByteBufferByteChannel(bb),
new InMemRandomAccessSourceImpl(bb), "inmem");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Run Code Online (Sandbox Code Playgroud)
但我想说,您想要实现的目标与解析器采用的方法之间似乎存在一些冲突。它依靠本地文件来避免大量的内存开销,并且只有在整个数据集可用的情况下才能对字节进行随机访问,这与流式方法不同。
在解析器获得缓冲区之前,它需要一次性缓冲至少剪辑所需的数据量。如果您想要抓取较短的部分并且缓冲不太麻烦,这可能对您有用。如果读取出现问题,您可能会遇到 IO 异常等问题InputStream,特别是如果它是远程内容,而您确实不希望现代系统上的文件出现这种情况。
还需要MemoryFile考虑哪个提供了 ashmem 支持的类文件对象。我认为以某种方式可以解决这个问题。
| 归档时间: |
|
| 查看次数: |
587 次 |
| 最近记录: |