使用mp4parser,我如何处理从Uri和ContentResolver中获取的视频?

and*_*per 16 android filechannel inputstream android-contentresolver mp4parser

背景

我们希望让用户从任何应用中选择视频,然后将视频剪裁为最多5秒.

问题

为了让Uri被选中,我们让它工作正常(这里有解决方案).

至于修剪本身,我们找不到任何具有许可许可的好图书馆,除了一个名为"k4l-video-trimmer"的图书馆.例如,库"FFmpeg"被认为是非许可,因为它使用GPLv3,这要求使用它的应用程序也是开源的.此外,正如我所读,它需要相当多(约9MB).

可悲的是,这个库(k4l-video-trimmer)很老了,多年没有更新了,所以我不得不把它(这里)分叉,以便很好地处理它.它使用一个名为"mp4parser"的开源库来进行修剪.

问题是,这个库似乎只能处理文件,而不是一个Uri或者InputStream,所以即使样本在选择像普通文件一样无法访问的项目时也会崩溃,甚至还有无法处理的路径.我知道在很多情况下可以获得文件的路径,但在许多其他情况下,它不是,我也知道可以只复制文件(这里),但这不是一个好的解决方案,因为文件可能很大并占用大量空间,即使它已经可以访问.

我试过的

库有两个地方使用文件:

  1. 在"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)
  2. 在"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.

问题

  1. 有办法克服这个问题吗?

也许实现FileChannel和模拟一个真实的文件,使用ContentResolverUri?我想这可能是有可能的,即使这意味着在需要时重新打开InputStream ......

为了看看我的工作原理,你可以在这里克隆项目.只知道它没有做任何修剪,因为"K4LVideoTrimmer"文件中的代码被注释:

//TODO handle trimming using Uri
//TrimVideoUtils.startTrim(file, getDestinationPath(), mStartPosition, mEndPosition, mOnTrimVideoListener);
Run Code Online (Sandbox Code Playgroud)
  1. 是否有更好的替代这个修剪库,这也是允许的(例如Apache2/MIT许可证的意思)?一个没有这个问题?或者甚至可能是Android框架本身的某些东西?我认为MediaMuxer类可以帮助(如写在这里),但我认为这可能需要26 API,而我们需要处理的API 21以上......

编辑:

我以为我找到了一个解决方案,通过使用不同的解决方案来修剪自己,并在这里写了一下,但遗憾的是它无法处理一些输入视频,而mp4parser库可以处理它们.

请告诉我是否可以修改mp4parser处理此类输入视频,即使它来自Uri而不是文件(没有复制到视频文件的解决方法).

dr_*_*r_g 4

首先需要注意的是:我不熟悉 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 次

最近记录:

6 年,9 月 前