2

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

现在我的问题来了:

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

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

谢谢 。

4

3 回答 3

2

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

这是来自Android MediaCodec 参考

 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 循环中... ahhhhh

像这样的东西:

//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;

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

我强烈推荐使用 Matlab(或 GNU Octave)来制作视频编解码器的原型。它将为您节省大量时间。这意味着您应该确保您的预期编解码器算法有效,然后再尝试在几乎不可能的系统上实现它以进行调试,例如 Android。

希望这可以帮助。

于 2013-09-19T19:16:00.553 回答
2

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

于 2013-06-22T18:18:43.430 回答
0

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

  1. 编写你的程序。
  2. 您希望“编解码器”去的地方只需添加一个“空编解码器”(将输入复制到输出)。
  3. 测试您的程序是否仍然有效并且您可以读取(所谓的)编码文件。
  4. 在“空编解码器”所在的位置添加您的编解码器(调用函数以避免对工作文件进行大编辑)。
  5. 重新测试您的程序以确保它仍然有效并阅读输出以确保它是正确的。

就这些。;)

需要考虑的事项:

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