18
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

AndroidのMediaCodecとMediaExtractorあたりで動画のフレームスキップなどをしてみる

Last updated at Posted at 2017-02-20

AndroidのMediaPlayerだとフレーム単位で制御するAPIがなく早送りや任意にフレームスキップさせることは困難である。
しかし、MediaCodecMediaExtractorを使えばフレーム単位での制御が可能である。

ここでは自分で調べた結果をまとめておく。
動画再生に関しては素人なので間違ったことを書いてるかも。

実装サンプル

mafshin/MediaCodecDemo: Android MediaCodec API Demo with Seek and MediaController
実装としては上記のコードがわかりやすい。
MediaExtractorで動画ファイルから動画データを読み(音声データは無視)、MediaCodecで動画データをデコードしてSurfaceに対して描画している。

ちなみに、MediaCodecのgetInputBuffers()あたりはdeprecatedなので以下のように置き換える。

// 変更前
ByteBuffer[] inputBuffers = decoder.getInputBuffers();
...
ByteBuffer buffer = inputBuffers[inIndex];

// 変更後
ByteBuffer buffer = decoder.getInputBuffer(inIndex);

フレームスキップ

動画のキーフレーム以外のフレームではキーフレームからの差分のデータしか持っていないため、MediaCodecにはキーフレームからのデータを与え続ける必要がある。
上記リンク先の質問のようにMediaExtractorでキーフレームを無視してキーフレーム以外の動画データをMediaCodecに渡してもデコードは上手くいかない。

MediaExtractorのseekTo()ではキーフレームにしか移動できないがここらへんが関係していそう。

基本的にはMediaCodecにはキーフレームからのデータを与え続けてエンコードさせreleaseOutputBuffer()でrenderフラグをfalseにして描画をしないことでフレームスキップする。

早送り/スローモーション再生

上記のサンプルに対して以下のようにすることで早送りやスローモーション再生ができたりする。
が、上記のフレームスキップやサンプルのようにsleepで待つ方が良い?

  • 2倍速早送り再生
decoder.queueInputBuffer(inIndex, 0, sampleSize, extractor.getSampleTime() / 2, 0);
  • 2倍速スローモーション再生
decoder.queueInputBuffer(inIndex, 0, sampleSize, extractor.getSampleTime() * 2, 0);

動画と音声の同期

提示されているコードはよくわかってないけど、音声再生ベースにして動画再生をフレームスキップや待ったりして同期かければ良いのかなという感じ。

18
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?