使用FFmpeg为android编写自定义编解码器

时间:2013-06-20 15:33:47

标签: android ffmpeg

我正在为Android做一个视频压缩项目,我正在考虑通过设计一个新的视频编解码器来实现它(我已经设计了算法)。我已经阅读了视频压缩的基础知识,相关的相关算法和编解码器基础知识。我还发现 FFmpeg 可以作为Android上非常好的解决方案。

现在我的问题来了:

  1. 如何在FFmpeg中编写 视频编解码器?我仍然是编写编解码器的初学者,但是 我该如何开始?我有一个粗略的想法,你必须首先编写至少一个解复用器,然后是特定的编码器和解码器等。 (请在这里索取参考资料。)

  2. 由于我的编解码器不能简单地调整视频属性,如fps,分辨率,比特率等。 在官方Android SDK中阅读 MediaCodec API和MediaPlayer API是否足以编写新的编解码器? (因为上次我看到它只支持MPEG-4 SP,H.263和H.264。我无法找到你是否可以直接编写自己的类和函数。)

  3. 谢谢。

3 个答案:

答案 0 :(得分:2)

您可以在Android上使用ffmpeg作为工具或ffmpeg库集(libavcodec,libaviformat,...)。您可以以跨平台方式添加或更改ffmpeg编解码器,因为此项目非常强调平台独立性。您可以改用MediaCodec API。 但是没有办法扩展MediaCodec API 更新可以扩展MediaCodec,它记录在http://source.android.com/devices/media.html#codecs)并且没有简单的方法让ffmpeg使用此API。

答案 1 :(得分:2)

如果你是一个新手并且“只想在SW中做”,那就不要在SW中做了。我假设您的算法不需要是实时的,并且可以动态压缩视频数据,或者您需要使用HW编解码器。

这是Android MediaCodec Reference

 MediaCodec codec = MediaCodec.createDecoderByType(type);
 codec.configure(format, ...);
 codec.start();
 ByteBuffer[] inputBuffers = codec.getInputBuffers();
 ByteBuffer[] outputBuffers = codec.getOutputBuffers();
 for (;;) {
   int inputBufferIndex = codec.dequeueInputBuffer(timeoutUs);
   if (inputBufferIndex >= 0) {
     // fill inputBuffers[inputBufferIndex] with valid data
     ...
     codec.queueInputBuffer(inputBufferIndex, ...);
   }

   int outputBufferIndex = codec.dequeueOutputBuffer(timeoutUs);
   if (outputBufferIndex >= 0) {
     // outputBuffer is ready to be processed or rendered.
     ...
     codec.releaseOutputBuffer(outputBufferIndex, ...);
   } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
     outputBuffers = codec.getOutputBuffers();
   } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
     // Subsequent data will conform to new format.
     MediaFormat format = codec.getOutputFormat();
     ...
   }
 }
 codec.stop();
 codec.release();
 codec = null;

在读取“// outputBuffer已准备好处理或呈现”的行上应用您的编解码器。

那是你的第一帧将是outputBuffers [0]到outputBuffers [outputBufferIndex]。保存outputBufferIndex,即outputBufferIndex_old = outputBufferIndex;那么你的下一帧将是outputbuffers [outputBufferIndex_old]到outputbuffers [outputBufferIndex]。但这是一个循环缓冲区,所以在for循环中...啊啊啊

类似的东西:

//init
int old = 0;
int len = codec.BufferInfo().size,buff_len=outputBuffers.size;
Byte[] processBuffer = new Byte[len];

... // outputBuffer ready
for (int i=old; i<old+len; i++){
   processBuffer[i-old] = outputBuffers[i%buff_len];
}
old = outputBufferIndex;

Here就是一个很好的例子。您可能需要查看MediaMetadataRetriever以获取有关输入视频的信息。高度和宽度等。每个像素的字节大小,如果您希望编码器对不同类型的视频具有鲁棒性。无论如何,这应该让你开始。

我强烈建议使用Matlab(或GNU Octave)进行视频编解码器的原型设计。它将为您节省大量时间。这意味着在尝试在几乎不可能的系统上实现它之前,您应该确保您的预期编解码算法有效,以便像Android一样进行调试。

希望这有帮助。

答案 2 :(得分:0)

如果有人偶然发现这个老问题,答案是:

  1. 编写您的程序。
  2. 你想要&#34; Codec&#34;简单地添加一个空编解码器&#39; (将输入复制到输出)。
  3. 测试您的程序是否仍然有效,并且您可以阅读(所谓的)编码文件。
  4. 将您的编解码器添加到&#39; null编解码器&#39;是(调用函数以避免对工作文件进行大量编辑)。
  5. 重新测试您的程序以确保它仍然有效并阅读输出以确保它是正确的。
  6. 就是这样。 ;)

    需要考虑的事项:

    • A&#34;视频播放器&#34;可以丢帧,一个&#34;录像机&#34;最好不要 丢帧。
    • A&#39;软件编解码器&#39; (没有硬件辅助)会很慢, 如果可用的话,在不同的Core上运行它。
    • 硬件编解码器(从软件调用)将是必要的,除非您只是制作一个 演示。
    • 将您的程序拆分为可以单独运行的部分,以便它可以被线程化,并且可以将这些线程分配给不同的核心。您需要检测核心数量并评估其速度,以便在运行时动态进行一些分区。
    • 使用NDK和汇编语言编程是必要的,以获得足够的速度以所需的帧速率压缩体面的视频(IE:你不希望你完成的程序只支持320x176 @ 5 FPS视频)。压缩器必须运行得比输入到达的速度快。
    • 设计自己的编解码器以击败现有的编解码器(x265)需要数年时间(没有帮助)。
    • 如果您是Java,C和ARM程序集(以及软件工程师)的Wiz,则需要花费几个月的时间;所以提交或退出。尝试找一些开源作为开始的基础。