diff mbox series

[FFmpeg-devel] avformat/yuv4mpegenc: simplify writing the header

Message ID 20200903185505.1865-1-jamrial@gmail.com
State Accepted
Commit f901d75bf18c866933f90c052fb990736aee7c47
Headers show
Series [FFmpeg-devel] avformat/yuv4mpegenc: simplify writing the header | expand

Checks

Context Check Description
andriy/default pending
andriy/make success Make finished
andriy/make_fate success Make fate finished

Commit Message

James Almer Sept. 3, 2020, 6:55 p.m. UTC
Actually write it in yuv4_write_header() instead of with the first
packet.

Signed-off-by: James Almer <jamrial@gmail.com>
---
 libavformat/yuv4mpegenc.c | 35 ++++++++++++++---------------------
 1 file changed, 14 insertions(+), 21 deletions(-)

Comments

Paul B Mahol Sept. 3, 2020, 7:16 p.m. UTC | #1
On 9/3/20, James Almer <jamrial@gmail.com> wrote:
> Actually write it in yuv4_write_header() instead of with the first
> packet.
>
> Signed-off-by: James Almer <jamrial@gmail.com>
> ---
>  libavformat/yuv4mpegenc.c | 35 ++++++++++++++---------------------
>  1 file changed, 14 insertions(+), 21 deletions(-)
>

Nice catch, LGTM

> diff --git a/libavformat/yuv4mpegenc.c b/libavformat/yuv4mpegenc.c
> index e84dbf9568..c4781042bd 100644
> --- a/libavformat/yuv4mpegenc.c
> +++ b/libavformat/yuv4mpegenc.c
> @@ -26,14 +26,16 @@
>
>  #define Y4M_LINE_MAX 256
>
> -static int yuv4_generate_header(AVFormatContext *s, char* buf)
> +static int yuv4_write_header(AVFormatContext *s)
>  {
>      AVStream *st;
> +    AVIOContext *pb = s->pb;
>      int width, height;
>      int raten, rated, aspectn, aspectd, n;
>      char inter;
>      const char *colorspace = "";
>      const char *colorrange = "";
> +    char buf[Y4M_LINE_MAX + 1];
>      int field_order;
>
>      st     = s->streams[0];
> @@ -173,7 +175,15 @@ static int yuv4_generate_header(AVFormatContext *s,
> char* buf)
>                   Y4M_MAGIC, width, height, raten, rated, inter,
>                   aspectn, aspectd, colorspace, colorrange);
>
> -    return n;
> +    if (n < 0) {
> +        av_log(s, AV_LOG_ERROR,
> +               "Error. YUV4MPEG stream header write failed.\n");
> +        return AVERROR(EIO);
> +    }
> +
> +    avio_write(pb, buf, strlen(buf));
> +
> +    return 0;
>  }
>
>
> @@ -182,26 +192,12 @@ static int yuv4_write_packet(AVFormatContext *s,
> AVPacket *pkt)
>      AVStream *st = s->streams[pkt->stream_index];
>      AVIOContext *pb = s->pb;
>      AVFrame *frame;
> -    int* first_pkt = s->priv_data;
>      int width, height, h_chroma_shift, v_chroma_shift;
>      int i;
> -    char buf2[Y4M_LINE_MAX + 1];
>      uint8_t *ptr, *ptr1, *ptr2;
>
>      frame = (AVFrame *)pkt->data;
>
> -    /* for the first packet we have to output the header as well */
> -    if (*first_pkt) {
> -        *first_pkt = 0;
> -        if (yuv4_generate_header(s, buf2) < 0) {
> -            av_log(s, AV_LOG_ERROR,
> -                   "Error. YUV4MPEG stream header write failed.\n");
> -            return AVERROR(EIO);
> -        } else {
> -            avio_write(pb, buf2, strlen(buf2));
> -        }
> -    }
> -
>      /* construct frame header */
>
>      avio_printf(s->pb, "%s\n", Y4M_FRAME_MAGIC);
> @@ -279,10 +275,8 @@ static int yuv4_write_packet(AVFormatContext *s,
> AVPacket *pkt)
>      return 0;
>  }
>
> -static int yuv4_write_header(AVFormatContext *s)
> +static int yuv4_init(AVFormatContext *s)
>  {
> -    int *first_pkt = s->priv_data;
> -
>      if (s->nb_streams != 1)
>          return AVERROR(EIO);
>
> @@ -347,7 +341,6 @@ static int yuv4_write_header(AVFormatContext *s)
>          return AVERROR(EIO);
>      }
>
> -    *first_pkt = 1;
>      return 0;
>  }
>
> @@ -355,9 +348,9 @@ AVOutputFormat ff_yuv4mpegpipe_muxer = {
>      .name              = "yuv4mpegpipe",
>      .long_name         = NULL_IF_CONFIG_SMALL("YUV4MPEG pipe"),
>      .extensions        = "y4m",
> -    .priv_data_size    = sizeof(int),
>      .audio_codec       = AV_CODEC_ID_NONE,
>      .video_codec       = AV_CODEC_ID_WRAPPED_AVFRAME,
> +    .init              = yuv4_init,
>      .write_header      = yuv4_write_header,
>      .write_packet      = yuv4_write_packet,
>  };
> --
> 2.27.0
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
James Almer Sept. 3, 2020, 8:10 p.m. UTC | #2
On 9/3/2020 4:16 PM, Paul B Mahol wrote:
> On 9/3/20, James Almer <jamrial@gmail.com> wrote:
>> Actually write it in yuv4_write_header() instead of with the first
>> packet.
>>
>> Signed-off-by: James Almer <jamrial@gmail.com>
>> ---
>>  libavformat/yuv4mpegenc.c | 35 ++++++++++++++---------------------
>>  1 file changed, 14 insertions(+), 21 deletions(-)
>>
> 
> Nice catch, LGTM

Pushed, thanks.
Michael Niedermayer Sept. 9, 2020, 10:54 p.m. UTC | #3
On Thu, Sep 03, 2020 at 03:55:04PM -0300, James Almer wrote:
> Actually write it in yuv4_write_header() instead of with the first
> packet.
> 
> Signed-off-by: James Almer <jamrial@gmail.com>
> ---
>  libavformat/yuv4mpegenc.c | 35 ++++++++++++++---------------------
>  1 file changed, 14 insertions(+), 21 deletions(-)

This changes the written header
for example:
./ffmpeg  -i ~/tickets/2190/clip.yuv -bitexact testbad.y4m

YUV4MPEG2 W720 H480 F30000:1001 Ip A10:11 C411 XYSCSS=411
vs
YUV4MPEG2 W720 H480 F30000:1001 Ib A10:11 C411 XYSCSS=411


[...]
James Almer Sept. 10, 2020, midnight UTC | #4
On 9/9/2020 7:54 PM, Michael Niedermayer wrote:
> On Thu, Sep 03, 2020 at 03:55:04PM -0300, James Almer wrote:
>> Actually write it in yuv4_write_header() instead of with the first
>> packet.
>>
>> Signed-off-by: James Almer <jamrial@gmail.com>
>> ---
>>  libavformat/yuv4mpegenc.c | 35 ++++++++++++++---------------------
>>  1 file changed, 14 insertions(+), 21 deletions(-)
> 
> This changes the written header
> for example:
> ./ffmpeg  -i ~/tickets/2190/clip.yuv -bitexact testbad.y4m
> 
> YUV4MPEG2 W720 H480 F30000:1001 Ip A10:11 C411 XYSCSS=411
> vs
> YUV4MPEG2 W720 H480 F30000:1001 Ib A10:11 C411 XYSCSS=411

If I'm reading this right, ffmpeg.c changes the output AVCodecParameters
struct (In this case, field_order) after calling avformat_write_header()
but before writing a packet, which is wrong.

We could revert this change (And the one by Andreas that came after it),
but perhaps ffmpeg.c should be fixed to not violate the API instead.
Jan Ekström Sept. 20, 2020, 7:23 p.m. UTC | #5
On Thu, Sep 10, 2020 at 3:00 AM James Almer <jamrial@gmail.com> wrote:
>
> On 9/9/2020 7:54 PM, Michael Niedermayer wrote:
> > On Thu, Sep 03, 2020 at 03:55:04PM -0300, James Almer wrote:
> >> Actually write it in yuv4_write_header() instead of with the first
> >> packet.
> >>
> >> Signed-off-by: James Almer <jamrial@gmail.com>
> >> ---
> >>  libavformat/yuv4mpegenc.c | 35 ++++++++++++++---------------------
> >>  1 file changed, 14 insertions(+), 21 deletions(-)
> >
> > This changes the written header
> > for example:
> > ./ffmpeg  -i ~/tickets/2190/clip.yuv -bitexact testbad.y4m
> >
> > YUV4MPEG2 W720 H480 F30000:1001 Ip A10:11 C411 XYSCSS=411
> > vs
> > YUV4MPEG2 W720 H480 F30000:1001 Ib A10:11 C411 XYSCSS=411
>
> If I'm reading this right, ffmpeg.c changes the output AVCodecParameters
> struct (In this case, field_order) after calling avformat_write_header()
> but before writing a packet, which is wrong.
>
> We could revert this change (And the one by Andreas that came after it),
> but perhaps ffmpeg.c should be fixed to not violate the API instead.

My patch set that moves the encoder initialization later actually
enables moving this logic to before the encoder or the stream are
initialized, and fixes this difference.

Unfortunately, the resulting values which are now available for
general usage in header writing lead to various differences in FATE
tests (mostly tt switching tb) a la:

diff --git a/tests/ref/fate/concat-demuxer-simple1-lavf-mxf_d10
b/tests/ref/fate/concat-demuxer-simple1-lavf-mxf_d10
index 79ce1e2306..8f3f2e5265 100644
--- a/tests/ref/fate/concat-demuxer-simple1-lavf-mxf_d10
+++ b/tests/ref/fate/concat-demuxer-simple1-lavf-mxf_d10
@@ -78,5 +78,5 @@
video|0|34|1.360000|34|1.360000|1|0.040000|N/A|N/A|150000|1924096|K_|1
 Strings Metadata
 audio|1|65280|1.360000|65280|1.360000|1920|0.040000|N/A|N/A|7680|2074624|K_|1
 Strings Metadata
-0|mpeg2video|0|video|1/25|[0][0][0][0]|0x0000|720|608|0|0|0|0|1:1|45:38|yuv422p|5|tv|unknown|unknown|unknown|topleft|tt|N/A|1|N/A|25/1|25/1|1/25|0|0.000000|N/A|N/A|30000000|N/A|N/A|N/A|N/A|35|0|0|0|0|0|0|0|0|0|0|0|0|0x060A2B340101010501010D001300000000000000000000000000000000000001
+0|mpeg2video|0|video|1/25|[0][0][0][0]|0x0000|720|608|0|0|0|0|1:1|45:38|yuv422p|5|tv|unknown|unknown|unknown|topleft|tb|N/A|1|N/A|25/1|25/1|1/25|0|0.000000|N/A|N/A|30000000|N/A|N/A|N/A|N/A|35|0|0|0|0|0|0|0|0|0|0|0|0|0x060A2B340101010501010D001300000000000000000000000000000000000001
 1|pcm_s16le|unknown|audio|1/48000|[0][0][0][0]|0x0000|s16|48000|2|unknown|16|N/A|0/0|0/0|1/48000|0|0.000000|N/A|N/A|1536000|N/A|N/A|N/A|N/A|35|0|0|0|0|0|0|0|0|0|0|0|0|0x060A2B340101010501010D001300000000000000000000000000000000000001


Patch to test on top of the late_encoder_init set follows (also
included as part of the WIP branch
https://github.com/jeeb/ffmpeg/commits/late_encoder_init_v5 ):

Jan

------->8------
diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index 8874da9268..0a3b998e7a 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -1114,7 +1114,6 @@ static void do_video_out(OutputFile *of,
     int ret, format_video_sync;
     AVPacket pkt;
     AVCodecContext *enc = ost->enc_ctx;
-    AVCodecParameters *mux_par = ost->st->codecpar;
     AVRational frame_rate;
     int nb_frames, nb0_frames, i;
     double delta, delta0;
@@ -1276,18 +1275,6 @@ static void do_video_out(OutputFile *of,
         if (!check_recording_time(ost))
             return;

-        if (enc->flags & (AV_CODEC_FLAG_INTERLACED_DCT |
AV_CODEC_FLAG_INTERLACED_ME) &&
-            ost->top_field_first >= 0)
-            in_picture->top_field_first = !!ost->top_field_first;
-
-        if (in_picture->interlaced_frame) {
-            if (enc->codec->id == AV_CODEC_ID_MJPEG)
-                mux_par->field_order = in_picture->top_field_first ?
AV_FIELD_TT:AV_FIELD_BB;
-            else
-                mux_par->field_order = in_picture->top_field_first ?
AV_FIELD_TB:AV_FIELD_BT;
-        } else
-            mux_par->field_order = AV_FIELD_PROGRESSIVE;
-
         in_picture->quality = enc->global_quality;
         in_picture->pict_type = 0;

@@ -3432,6 +3419,20 @@ static int
init_output_stream_encode(OutputStream *ost, AVFrame *frame)
             enc_ctx->field_order = AV_FIELD_TT;
         }

+        if (frame) {
+            if (enc_ctx->flags & (AV_CODEC_FLAG_INTERLACED_DCT |
AV_CODEC_FLAG_INTERLACED_ME) &&
+                ost->top_field_first >= 0)
+                frame->top_field_first = !!ost->top_field_first;
+
+            if (frame->interlaced_frame) {
+                if (enc_ctx->codec->id == AV_CODEC_ID_MJPEG)
+                    enc_ctx->field_order = frame->top_field_first ?
AV_FIELD_TT:AV_FIELD_BB;
+                else
+                    enc_ctx->field_order = frame->top_field_first ?
AV_FIELD_TB:AV_FIELD_BT;
+            } else
+                enc_ctx->field_order = AV_FIELD_PROGRESSIVE;
+        }
+
         if (ost->forced_keyframes) {
             if (!strncmp(ost->forced_keyframes, "expr:", 5)) {
                 ret = av_expr_parse(&ost->forced_keyframes_pexpr,
ost->forced_keyframes+5,
diff mbox series

Patch

diff --git a/libavformat/yuv4mpegenc.c b/libavformat/yuv4mpegenc.c
index e84dbf9568..c4781042bd 100644
--- a/libavformat/yuv4mpegenc.c
+++ b/libavformat/yuv4mpegenc.c
@@ -26,14 +26,16 @@ 
 
 #define Y4M_LINE_MAX 256
 
-static int yuv4_generate_header(AVFormatContext *s, char* buf)
+static int yuv4_write_header(AVFormatContext *s)
 {
     AVStream *st;
+    AVIOContext *pb = s->pb;
     int width, height;
     int raten, rated, aspectn, aspectd, n;
     char inter;
     const char *colorspace = "";
     const char *colorrange = "";
+    char buf[Y4M_LINE_MAX + 1];
     int field_order;
 
     st     = s->streams[0];
@@ -173,7 +175,15 @@  static int yuv4_generate_header(AVFormatContext *s, char* buf)
                  Y4M_MAGIC, width, height, raten, rated, inter,
                  aspectn, aspectd, colorspace, colorrange);
 
-    return n;
+    if (n < 0) {
+        av_log(s, AV_LOG_ERROR,
+               "Error. YUV4MPEG stream header write failed.\n");
+        return AVERROR(EIO);
+    }
+
+    avio_write(pb, buf, strlen(buf));
+
+    return 0;
 }
 
 
@@ -182,26 +192,12 @@  static int yuv4_write_packet(AVFormatContext *s, AVPacket *pkt)
     AVStream *st = s->streams[pkt->stream_index];
     AVIOContext *pb = s->pb;
     AVFrame *frame;
-    int* first_pkt = s->priv_data;
     int width, height, h_chroma_shift, v_chroma_shift;
     int i;
-    char buf2[Y4M_LINE_MAX + 1];
     uint8_t *ptr, *ptr1, *ptr2;
 
     frame = (AVFrame *)pkt->data;
 
-    /* for the first packet we have to output the header as well */
-    if (*first_pkt) {
-        *first_pkt = 0;
-        if (yuv4_generate_header(s, buf2) < 0) {
-            av_log(s, AV_LOG_ERROR,
-                   "Error. YUV4MPEG stream header write failed.\n");
-            return AVERROR(EIO);
-        } else {
-            avio_write(pb, buf2, strlen(buf2));
-        }
-    }
-
     /* construct frame header */
 
     avio_printf(s->pb, "%s\n", Y4M_FRAME_MAGIC);
@@ -279,10 +275,8 @@  static int yuv4_write_packet(AVFormatContext *s, AVPacket *pkt)
     return 0;
 }
 
-static int yuv4_write_header(AVFormatContext *s)
+static int yuv4_init(AVFormatContext *s)
 {
-    int *first_pkt = s->priv_data;
-
     if (s->nb_streams != 1)
         return AVERROR(EIO);
 
@@ -347,7 +341,6 @@  static int yuv4_write_header(AVFormatContext *s)
         return AVERROR(EIO);
     }
 
-    *first_pkt = 1;
     return 0;
 }
 
@@ -355,9 +348,9 @@  AVOutputFormat ff_yuv4mpegpipe_muxer = {
     .name              = "yuv4mpegpipe",
     .long_name         = NULL_IF_CONFIG_SMALL("YUV4MPEG pipe"),
     .extensions        = "y4m",
-    .priv_data_size    = sizeof(int),
     .audio_codec       = AV_CODEC_ID_NONE,
     .video_codec       = AV_CODEC_ID_WRAPPED_AVFRAME,
+    .init              = yuv4_init,
     .write_header      = yuv4_write_header,
     .write_packet      = yuv4_write_packet,
 };