]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/ivfenc.c
configure: add -lvulkan to libglslang's lib flags
[ffmpeg] / libavformat / ivfenc.c
index adf72117e93436763cfe4b4ddbf7c8c0595b078a..5aa8bd12574f95d6e647af7ab6f3a24406527569 100644 (file)
 
 typedef struct IVFEncContext {
     unsigned frame_cnt;
-    uint64_t last_pts, sum_delta_pts;
+    uint64_t last_pts, sum_delta_pts, last_pkt_duration;
 } IVFEncContext;
 
-static int ivf_write_header(AVFormatContext *s)
+static int ivf_init(AVFormatContext *s)
 {
     AVCodecParameters *par;
-    AVIOContext *pb = s->pb;
 
     if (s->nb_streams != 1) {
         av_log(s, AV_LOG_ERROR, "Format supports only exactly one video stream\n");
@@ -43,6 +42,25 @@ static int ivf_write_header(AVFormatContext *s)
         av_log(s, AV_LOG_ERROR, "Currently only VP8, VP9 and AV1 are supported!\n");
         return AVERROR(EINVAL);
     }
+
+    if (par->codec_id == AV_CODEC_ID_VP9) {
+        int ret = ff_stream_add_bitstream_filter(s->streams[0], "vp9_superframe", NULL);
+        if (ret < 0)
+            return ret;
+    } else if (par->codec_id == AV_CODEC_ID_AV1) {
+        int ret = ff_stream_add_bitstream_filter(s->streams[0], "av1_metadata", "td=insert");
+        if (ret < 0)
+            return ret;
+    }
+
+    return 0;
+}
+
+static int ivf_write_header(AVFormatContext *s)
+{
+    AVCodecParameters *par = s->streams[0]->codecpar;
+    AVIOContext *pb = s->pb;
+
     avio_write(pb, "DKIF", 4);
     avio_wl16(pb, 0); // version
     avio_wl16(pb, 32); // header length
@@ -53,7 +71,7 @@ static int ivf_write_header(AVFormatContext *s)
     avio_wl16(pb, par->height);
     avio_wl32(pb, s->streams[0]->time_base.den);
     avio_wl32(pb, s->streams[0]->time_base.num);
-    avio_wl64(pb, 0xFFFFFFFFFFFFFFFFULL);
+    avio_wl64(pb, 0xFFFFFFFFFFFFFFFFULL); // length is overwritten at the end of muxing
 
     return 0;
 }
@@ -68,6 +86,7 @@ static int ivf_write_packet(AVFormatContext *s, AVPacket *pkt)
     avio_write(pb, pkt->data, pkt->size);
     if (ctx->frame_cnt)
         ctx->sum_delta_pts += pkt->pts - ctx->last_pts;
+    ctx->last_pkt_duration = pkt->duration;
     ctx->frame_cnt++;
     ctx->last_pts = pkt->pts;
 
@@ -79,30 +98,22 @@ static int ivf_write_trailer(AVFormatContext *s)
     AVIOContext *pb = s->pb;
     IVFEncContext *ctx = s->priv_data;
 
-    if ((pb->seekable & AVIO_SEEKABLE_NORMAL) && ctx->frame_cnt > 1) {
-        size_t end = avio_tell(pb);
+    if ((pb->seekable & AVIO_SEEKABLE_NORMAL) &&
+        (ctx->frame_cnt > 1 || (ctx->frame_cnt == 1 && ctx->last_pkt_duration))) {
+        int64_t end = avio_tell(pb);
 
         avio_seek(pb, 24, SEEK_SET);
-        avio_wl64(pb, ctx->frame_cnt * ctx->sum_delta_pts / (ctx->frame_cnt - 1));
+        // overwrite the "length" field (duration)
+        avio_wl32(pb, ctx->last_pkt_duration ?
+                  ctx->sum_delta_pts + ctx->last_pkt_duration :
+                  ctx->frame_cnt * ctx->sum_delta_pts / (ctx->frame_cnt - 1));
+        avio_wl32(pb, 0); // zero out unused bytes
         avio_seek(pb, end, SEEK_SET);
     }
 
     return 0;
 }
 
-static int ivf_check_bitstream(struct AVFormatContext *s, const AVPacket *pkt)
-{
-    int ret = 1;
-    AVStream *st = s->streams[pkt->stream_index];
-
-    if (st->codecpar->codec_id == AV_CODEC_ID_VP9)
-        ret = ff_stream_add_bitstream_filter(st, "vp9_superframe", NULL);
-    else if (st->codecpar->codec_id == AV_CODEC_ID_AV1)
-        ret = ff_stream_add_bitstream_filter(st, "av1_metadata", "td=insert");
-
-    return ret;
-}
-
 static const AVCodecTag codec_ivf_tags[] = {
     { AV_CODEC_ID_VP8,  MKTAG('V', 'P', '8', '0') },
     { AV_CODEC_ID_VP9,  MKTAG('V', 'P', '9', '0') },
@@ -110,16 +121,16 @@ static const AVCodecTag codec_ivf_tags[] = {
     { AV_CODEC_ID_NONE, 0 }
 };
 
-AVOutputFormat ff_ivf_muxer = {
+const AVOutputFormat ff_ivf_muxer = {
     .priv_data_size = sizeof(IVFEncContext),
     .name         = "ivf",
     .long_name    = NULL_IF_CONFIG_SMALL("On2 IVF"),
     .extensions   = "ivf",
     .audio_codec  = AV_CODEC_ID_NONE,
     .video_codec  = AV_CODEC_ID_VP8,
+    .init         = ivf_init,
     .write_header = ivf_write_header,
     .write_packet = ivf_write_packet,
     .write_trailer = ivf_write_trailer,
-    .check_bitstream = ivf_check_bitstream,
     .codec_tag    = (const AVCodecTag* const []){ codec_ivf_tags, 0 },
 };