ffmpegソースコードプロファイル(六)符号化-av_write_frame(),av_write_trailer()
7669 ワード
1.av_write_frame()
av_write_frame()は、libavformatavformatにあると宣言するフレームオーディオデータを出力するために使用される.h,以下に示す.
int av_write_frame(AVFormatContext *s, AVPacket *pkt);
:
s: AVFormatContext。
pkt: AVPacket。
0。
av_write_frame()の定義はlibavformatmuxにある.c,以下に示す.
int av_write_frame(AVFormatContext *s, AVPacket *pkt)
{
int ret;
ret = check_packet(s, pkt);
if (ret < 0)
return ret;
//Packet NULL,Flush Encoder
if (!pkt) {
if (s->oformat->flags & AVFMT_ALLOW_FLUSH) {
ret = s->oformat->write_packet(s, NULL);
if (s->flush_packets && s->pb && s->pb->error >= 0 && s->flags & AVFMT_FLAG_FLUSH_PACKETS)
avio_flush(s->pb);
if (ret >= 0 && s->pb && s->pb->error < 0)
ret = s->pb->error;
return ret;
}
return 1;
}
ret = compute_pkt_fields2(s, s->streams[pkt->stream_index], pkt);
if (ret < 0 && !(s->oformat->flags & AVFMT_NOTIMESTAMPS))
return ret;
//
ret = write_packet(s, pkt);
if (ret >= 0 && s->pb && s->pb->error < 0)
ret = s->pb->error;
if (ret >= 0)
s->streams[pkt->stream_index]->nb_frames++;
return ret;
}
ソースコードからav_write_frame()は主に以下のステップを完了しました:(1)check_を呼び出すpacket()簡単な検出(2)呼び出しcompute_pkt_Fields 2()AVPacketのいくつかの属性値を設定(3)write_を呼び出すpacket()書き込みデータ
これらの関数機能をそれぞれ見てみましょう.check_packet() check_packet()定義はlibavformatmuxにあります.c,以下に示す.
static int check_packet(AVFormatContext *s, AVPacket *pkt)
{
if (!pkt)
return 0;
if (pkt->stream_index < 0 || pkt->stream_index >= s->nb_streams) {
av_log(s, AV_LOG_ERROR, "Invalid packet stream index: %d
",
pkt->stream_index);
return AVERROR(EINVAL);
}
if (s->streams[pkt->stream_index]->codec->codec_type == AVMEDIA_TYPE_ATTACHMENT) {
av_log(s, AV_LOG_ERROR, "Received a packet for an attachment stream.
");
return AVERROR(EINVAL);
}
return 0;
}
コードから分かるようにcheck_packet()の機能は簡単です.まず、入力したAVPacketが空であるかどうかをチェックし、空であれば直接戻ります.そしてAVPacketのstream_をチェックindex(このAVPacketが属するAVStreamがマークされている)の設定が正常かどうかは、負またはAVStreamより大きい個数であればエラーメッセージを返します.
compute_pkt_fields2() compute_pkt_Fields 2()には主に2つの機能がある:一方、AVPacketのduration、dtsなどの情報を計算するために使用される.一方、pts、dtsのこれらのパラメータの妥当性(例えば、PTSがDTSよりも大きいかどうか)を調べるために使用される.
AVOutputFormat->write_packet() write_Packet()関数の最も重要な点は、AVOutputFormatにデータを書き込む方法を呼び出すことです.AVPacketのflagタグにAV_が含まれている場合PKT_FLAG_UNCODED_FRAMEは、AVOutputFormatのwrite_を呼び出しますuncoded_frame()関数;そのタグが含まれていなければwrite_が呼び出されますpacket()関数.write_packet()は実際には関数ポインタであり,特定のAVOutputFormatにおける実装関数を指す.
2.av_write_trailer()
av_write_trailer()はファイルの末尾を出力するために使用され、その宣言はlibavformatavformatにある.h,以下に示す.
int av_write_trailer(AVFormatContext *s);
出力用のAVFormatContextというパラメータを指定するだけです.関数が正常に実行されると、戻り値は0になります.av_write_trailer()の定義はlibavformatmuxにあります.c,以下に示す.
int av_write_trailer(AVFormatContext *s)
{
int ret, i;
for (;; ) {
AVPacket pkt;
ret = interleave_packet(s, &pkt, NULL, 1);
if (ret < 0)
goto fail;
if (!ret)
break;
// AVPacket
ret = write_packet(s, &pkt);
if (ret >= 0)
s->streams[pkt.stream_index]->nb_frames++;
av_free_packet(&pkt);
if (ret < 0)
goto fail;
if(s->pb && s->pb->error)
goto fail;
}
fail:
//
if (s->oformat->write_trailer)
if (ret >= 0) {
ret = s->oformat->write_trailer(s);
} else {
s->oformat->write_trailer(s);
}
if (s->pb)
avio_flush(s->pb);
if (ret == 0)
ret = s->pb ? s->pb->error : 0;
for (i = 0; i < s->nb_streams; i++) {
av_freep(&s->streams[i]->priv_data);
av_freep(&s->streams[i]->index_entries);
}
if (s->oformat->priv_class)
av_opt_free(s->priv_data);
av_freep(&s->priv_data);
return ret;
}
ソースコードからav_がわかりますwrite_trailer()は主に以下の2つのステップを完了しました.
(1)ループコールinterleave_packet()およびwrite_Packet()は、まだ出力されていないAVPacketを出力します.
(2)AVOutputFormatを呼び出すwrite_trailer()は、ファイルの末尾を出力します.
AVOutputFormat->write_trailer()AVOutputFormatのwrite_trailer()は、特定のAVOutputFormatの実装関数を指す関数ポインタです.