MediaCodec を使用して、(カメラまたはデコーダーによって) フレームをビデオにエンコードしようとしています。dequeueOutputBuffer() によってエンコーダー出力を処理するとき、戻りインデックス = MediaCodec.INFO_OUTPUT_FORMAT_CHANGED を受け取ることが期待されるため、getOutputFormat() を呼び出して、現在使用されている ffmpeg マルチプレクサーの入力としてエンコーダー出力形式を取得できます。
Android バージョン 4.1 ~ 4.3 でいくつかのパッド/電話デバイスをテストしました。それらはすべて、少なくとも 1 つのハードウェア ビデオ AVC エンコーダーを備えており、テストで使用されます。バージョン 4.3 のデバイスでは、エンコーダーはエンコードされたデータを期待どおりに書き込む前に MediaCodec.INFO_OUTPUT_FORMAT_CHANGED を提供し、getOutputFormat() から返された出力形式をマルチプレクサーで正しく使用できます。4.2.2 以前のデバイスでは、エンコーダーは MediaCodec.INFO_OUTPUT_FORMAT_CHANGED を提供しませんが、エンコードされたエレメンタリー ストリームを出力できますが、マルチプレクサは正確な出力形式を認識できません。
次の質問をしたいです。
- エンコーダーの動作 (エンコードされたデータを出力する前に MediaCodec.INFO_OUTPUT_FORMAT_CHANGED を与えるかどうか) は、Android API レベルまたは個々のデバイスのチップに依存しますか?
- MediaCodec.INFO_OUTPUT_FORMAT_CHANGED が表示される前にエンコーダーがデータを書き込む場合、エンコードされたデータの出力形式を取得する方法はありますか?
- エンコーダーは、エンコードされたデータの前に、デバイスのコーデック構成データ (フラグ MediaCodec.BUFFER_FLAG_CODEC_CONFIG を使用) を引き続き出力します。主にデコーダーの構成に使用されますが、コーデック構成データから出力形式を導き出すことはできますか?
出力形式を取得するためにこれらのソリューションを試しましたが、失敗しました:
- エンコード プロセス全体で頻繁に getOutputFormat() を呼び出します。ただし、それらはすべて、MediaCodec.INFO_OUTPUT_FORMAT_CHANGED を表示せずに IllegalStateException をスローします。
例のように、最初の MediaFormat の使用を使用して、最初にエンコーダーを構成します。
m_init_encode_format = MediaFormat.createVideoFormat(m_encode_video_mime, m_frame_width, m_frame_height); int encode_bit_rate = 3000000; int encode_frame_rate = 15; int encode_iframe_interval = 2; m_init_encode_format.setInteger(MediaFormat.KEY_COLOR_FORMAT, m_encode_color_format); m_init_encode_format.setInteger(MediaFormat.KEY_BIT_RATE, encode_bit_rate); m_init_encode_format.setInteger(MediaFormat.KEY_FRAME_RATE, encode_frame_rate); m_init_encode_format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, encode_iframe_interval); m_encoder = MediaCodec.createByCodecName(m_video_encoder_codec_info.getName()); m_encoder.configure(m_init_encode_format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); // Assume m_init_encode_format is the output format of the encoder
ただし、エンコーダーの出力形式がまだ最初のものから「変更」されているため、失敗します。
エンコーダーの動作を理解するのを手伝ってください。必要な MediaCodec.INFO_OUTPUT_FORMAT_CHANGED が欠落している場合、出力形式を照会する解決策があれば教えてください。
出力形式とコーデック構成データを比較すると、欠落しているフィールドは csd-0、csd-1、および値 = 1869968451 の「what」フィールドです。 (「what」フィールドはわかりません。定数であり、必須ではありません. 誰かがその意味について教えてもらえますか?)
コーデック構成データを csd-1 フィールド (最後の 8 バイト) および csd-0 フィールド (残りのバイト) として解析すると、マルチプレクサは正しく動作し、すべてのテスト デバイスで再生可能なビデオを出力できるようです。(しかし、私は質問したい: この 8 バイトの仮定は正しいですか、それともデータを解析するためのより信頼できる方法はありますか?)
しかし、もう一度 Android MediaCodec でビデオをデコードすると、dequeueOutputBuffer() で取得される BufferInfo.presentationTimeUs の値が、デコードされたフレームのほとんどで 0 になるという別の問題が発生しました。最後の数フレームだけが正しい時間です。MediaExtractor.getSampleTime() で取得したサンプル時間は正しく、エンコーダー/マルチプレクサーに設定した値とまったく同じですが、デコードされたフレーム時間は異なります。この問題は、4.2.2 以前のデバイスでのみ発生します。
フレーム時間が正しくないのは奇妙ですが、ビデオはデバイスで正しい速度で再生できます。(私がテストした 4.2.2 以前のほとんどのデバイスには、ビデオ AVC デコーダーが 1 つしかありません。) プレゼンテーション時間に影響を与える可能性のある他のフィールドを設定する必要がありますか?