【问题标题】:Smooth playback of consecutive mp4 video sequences on Android在 Android 上流畅播放连续的 mp4 视频序列
【发布时间】:2014-01-14 08:16:18
【问题描述】:

我想在我的 Android 设备上流畅地播放(渲染到表面)两个或多个连续的 mp4 视频序列(每个都存储在我设备上的单独文件中,并且可能在启动时不存在)(没有停顿、闪烁等) 。) 方式。因此,观众可能会得到只观看一个连续视频的印象。第一步,仅对我的 Nexus 7 平板电脑就足够了。 为了只显示一个视频,我一直在使用 MediaCodec API,其方式与http://dpsm.wordpress.com/2012/07/28/android-mediacodec-decoded/ 类似,而且效果很好。通过仅在第一个序列完成后创建(和配置)第二个解码器(decoder.stop 和第一个解码器的 decoder.release 被调用),可以看到混合。为了在两个不同的视频序列之间平滑淡入淡出,我正在考虑使用 init 功能,其中第二个视频已经通过 decoder.configure(format, surface, null, 0) 在第一个播放过程中。此外,第一帧也通过 decoder.queueInputBuffer 排队。 但是这样做会导致以下错误:

01-13 16:20:37.182: E/BufferQueue(183): [SurfaceView] connect: already connected (cur=3, req=3)
01-13 16:20:37.182: E/MediaCodec(9148): native_window_api_connect returned an error: Invalid argument (-22)
01-13 16:20:37.182: E/Decoder Init(9148): Exception decoder.configure: java.lang.IllegalStateException

在我看来,一个表面只能由一个解码器同时使用。那么,还有其他可能吗?也许使用 OpenGL?

最好, 亚历克斯。

【问题讨论】:

    标签: android video android-mediacodec


    【解决方案1】:

    您使用MediaCodec 的多个实例所描述的内容将起作用,但您一次只能将一个“生产者”连接到 Surface。你需要先拆掉第一个,然后才能继续第二个,我不确定你能得到多近的时间。

    您可以改为解码为SurfaceTexture,然后在 SurfaceView 上绘制(如您所想,使用 OpenGL)。

    您可以在 ExtractMpegFramesTest 示例中看到将 MP4 文件渲染为 SurfaceTexture 的示例。从那里你只需要将纹理渲染到你的表面(SurfaceView?TextureView?),使用类似于CameraToMpegTest 中的STextureRender 类。

    Grafika 中还有一些其他示例,尽管那里的视频播放器更接近您已有的(解码器输出到 TextureView)。

    顺便说一句,您需要计算在影片 N 的最后一帧和影片 N+1 的第一帧之间放置多少延迟。如果录制是以固定帧速率拍摄的,这很容易,但某些来源(例如screenrecord)不会以这种方式录制。

    更新:如果您可以保证您的影片剪辑具有相同的特征(大小、编码类型——基本上是MediaFormat 中的所有内容),那么有一个更简单的方法。当您到达流尾并开始输入下一个文件时,您可以flush() 解码器。我用它在 Grafika 视频播放器中循环播放视频(请参阅 MoviePlayer#doExtract())。

    【讨论】:

    • 感谢您的示例 (ExtractMpegFramesTest) 对 SurfaceTexture 的解码效果很好!现在我面临将纹理渲染到表面的问题。据我所知,CameraToMpegTest 也在存储视频而不显示,对吧?我对 SurfaceView 和 TextureView 都很好,但根据developer.android.com/training/graphics/opengl/environment.html,选择 TextureView 可能更容易。 Ps.:是的,保证影片剪辑具有相同的特征和固定的帧率。
    • bigflake 样本不显示任何内容。 ExtractMpegFramesTest 创建一个 SurfaceTexture,并将 MediaCodec 输出定向到它。要在 TextureView 上显示输出,您需要更改代码以便它使用来自 TextureView#getSurfaceTexture() 的 SurfaceTexture。然后,TextureView 类将负责锁定缓冲区并将其渲染到屏幕上。 (如果您使用 SurfaceView,则必须自己进行渲染。)
    • 我根据你的建议做了一些修改;我创建了一个 TextureView 并通过mTextureView.setSurfaceTextureListener(this) 设置了一个监听器。我将 SurfaceTexture 转发到 CodecOutputSurface 并使用它而不是创建一个新的。但是当我尝试通过mSurfaceTexture.attachToGLContext(mTextureRender.getTextureId()) 将其附加到 GL 上下文时,我收到以下错误:“E/GLConsumer: [unnamed-11969-0] attachToContext: GLConsumer is already attach to a context”。甚至有必要附加它吗?如何从这里开始?
    • 您不想弄乱从SurfaceView 获得的SurfaceTexture 的EGL 上下文。它归 UI 线程所有。看看 Grafika 中的 TextureViewGLActivity (github.com/google/grafika)。在Renderer#run() 中,它创建一个新的EGL 上下文并使用TextureViewSurfaceTexture 作为表面。诀窍在于,您不是在利用TextureViewEGLSurface,而是在利用它的Surface……这些是完全不同的东西。您在映射到纹理的Surface 上绘制,然后TextureView 将其渲染到EGLSurface
    【解决方案2】:

    疯狂的想法。试试margin the two videos to one。它们都在您的设备上,因此不会花费很长时间。并且可以自己实现淡入淡出效果。

    【讨论】:

    • 总的来说,这肯定是一种很有前途的方法,但可能是当第一个视频序列开始播放时,并非所有视频序列都已存储在我的设备上,我必须同时下载它们.因此“连接”不是我的选择。
    • @A.Wolf 比流媒体怎么样?
    • 当然,它“感觉”类似于流式传输,但我们没有连续的帧流。每个视频序列都是帧的组合,比如大约 2 秒的视频。
    • @A.Wolf 所以不要使用 MP4。只播放图像。这样听起来更容易
    • 我也在考虑每帧提取 mp4 输入文件的帧并分别渲染它们。有没有办法将 YUV 帧直接显示到表面?我相信转换它们会花费太多时间。
    猜你喜欢
    • 2020-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-06
    • 1970-01-01
    • 2012-10-12
    • 1970-01-01
    • 2016-05-09
    相关资源
    最近更新 更多