###2016.09.04
- この文書を参照しdecoding時のそれぞれの役割のもっと明瞭な説明を追加しました。
- ソースを更新しました。
##Decoding Functions
-
引数
- AVCodecContext* avctx - デコーダーするコデックのコンテキスト。
- AVPacket* avpkt - 解除されたデータを持つべきのコンテーナ。nullの場合はコンテキストのでコーディングデータを全てドーレイン(クリア)します。
-
役割
- それぞれのストリームのpacketをAVCodecContextの内部バーファ保存します。普通は1フレーム程度の大きさになりそうです。
- もし、内部バーファが籠った場合、**AVERROR(EAGAIN)**のエラーを返還します。この場合、avcodec_receive_frameでデータを読まなければなりません。
- stream読みが終わった場合、avpkt引数にNULLを渡って、drain modeを実行させます。
- **流れ** 1. コデックコンテキストが開いているか、またはデコーダー用のコンテキストなのかを検討する。条件に当たらない場合い、この段階でAVERROR(EINVAL)を返還します。 2. コンテキストがドーレインされてる場合、**AVERROR_EOF**変換します。 3. avpktがnull、またはavpkt->sizeが0の場合、コンテキストにドレインすることを指示する。コデックのcapabilities(avctx->codec->capabilities)がAV_CODEC_CAP_DELAYである場合、0を返還します。 4. コンテキストが持つコデックにsend_packet関数がある場合、avpktをsend_packet関数に渡し、結果を返還します。avpktがない場合はそのままnullを渡して結果を返還します。 5. 普通は4番までの順番で終わりですがコデックが新しいapiを対応してない場合、以前のapiをエミュレーションします。詳細はまあ面倒くさいです。笑。
-
引数
- AVCodecContext* avctx - デコーダーするコデックのコンテキスト。
- AVFrame* frame
-
役割
- AVCodecContextの内部バーファーのpacketをdecodeしてAVFrameに渡します。
- AVERROR(EAGAIN)が変換されるまで、繰り返して、関数を呼び出す必要があります。
- decodingが終わって、コンテキストがdrain modeに入った場合、AVERROR_EOFが変換されるまでこの関数を呼び出してください。
-
流れ
- frameの持つデータをクリンします。av_frame_unrefをframeポインターについに使っています。 注意する処ですね。
- コデックコンテキストが開いているか、またはデコーダー用のコンテキストなのかを検討する。条件に当たらない場合い、この段階でAVERROR(EINVAL)を返還します。
- コンテキストが持つコデックにreceive_frame関数がある場合、コンテキストがドレイン中ならAVERROR_EOFを返還します。その以外は、receive_frameにframeポインターを渡して結果を返還します。
- 普通は3番までの順番で終わりですがコデックが新しいapiを対応してない場合、以前のapiをエミュレーションします。
###使用法(出所はこちらから)
defer {
avcodec_send_packet(avctx, NULL)
while true {
if AVERROR_EOF == avcodec_receive_packet(avctx, frame) {
break
}
}
}
while 0 <= av_read_frame(avctx, packet) {
// avcodec_decode_video2[audio4](...)を下のコードに変更します。
// もっと簡単に出来ると思いますが。サイドーイフェックトを避けるためほとんど変更しないままで適用してみました。
...
var ret = avcodec_send_packet(avctx, packet)
// retがAVERROR(EAGAIN)の場合, receive_frameでAVERROR_EOFが返還されるまで、packet繰り返して送ります。
if 0 > ret && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF {
if 0 > ret { // error
break
}
continue
}
ret = avcodec_receive_frame(avctx, frame)
if 0 > ret && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF {
if 0 > ret {
break
}
}
// success to get frame
...
}