[libav-devel] [PATCH] Add av_image_check_sar() and use it to validate SAR

Justin Ruggles justin.ruggles at gmail.com
Thu Jun 19 19:27:13 CEST 2014


---
 doc/APIchanges           |  3 +++
 libavcodec/dirac.c       |  2 ++
 libavcodec/dpx.c         |  2 ++
 libavcodec/dvdec.c       | 17 +++++++++--------
 libavcodec/exr.c         |  4 ++--
 libavcodec/ffv1dec.c     |  8 ++++++++
 libavcodec/h263dec.c     |  2 ++
 libavcodec/h264_slice.c  |  3 +--
 libavcodec/hevc.c        |  3 ++-
 libavcodec/internal.h    |  6 ++++++
 libavcodec/mjpegdec.c    |  1 +
 libavcodec/mpeg12dec.c   |  2 ++
 libavcodec/truemotion1.c |  2 ++
 libavcodec/utils.c       | 33 +++++++++++++++++++++++++++++++++
 libavcodec/vc1.c         |  1 +
 libavcodec/vp3.c         |  1 +
 libavutil/imgutils.c     | 23 +++++++++++++++++++++++
 libavutil/imgutils.h     | 15 +++++++++++++++
 libavutil/version.h      |  2 +-
 19 files changed, 116 insertions(+), 14 deletions(-)

diff --git a/doc/APIchanges b/doc/APIchanges
index 51a2ff5..1b32d0b 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -13,6 +13,9 @@ libavutil:     2013-12-xx
 
 API changes, most recent first:
 
+2014-06-xx - xxxxxxx - lavu 53.17.0 - imgutils.h
+  Add av_image_check_sar().
+
 2014-xx-xx - xxxxxxx - lavf 55.20.0 - avformat.h
   The proper way for providing a hint about the desired timebase to the muxers
   is now setting AVStream.time_base, instead of AVStream.codec.time_base as was
diff --git a/libavcodec/dirac.c b/libavcodec/dirac.c
index f0fb85d..ed0ea9f 100644
--- a/libavcodec/dirac.c
+++ b/libavcodec/dirac.c
@@ -316,6 +316,8 @@ int avpriv_dirac_parse_sequence_header(AVCodecContext *avctx, GetBitContext *gb,
     if (ret < 0)
         return ret;
 
+    ff_set_sar(avctx, avctx->sample_aspect_ratio);
+
     /* [DIRAC_STD] picture_coding_mode shall be 0 for fields and 1 for frames
      * currently only used to signal field coding */
     picture_coding_mode = svq3_get_ue_golomb(gb);
diff --git a/libavcodec/dpx.c b/libavcodec/dpx.c
index 0dfa538..c796387 100644
--- a/libavcodec/dpx.c
+++ b/libavcodec/dpx.c
@@ -150,6 +150,8 @@ static int decode_frame(AVCodecContext *avctx,
     if ((ret = ff_set_dimensions(avctx, w, h)) < 0)
         return ret;
 
+    ff_set_sar(avctx, avctx->sample_aspect_ratio);
+
     if ((ret = ff_get_buffer(avctx, p, 0)) < 0) {
         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
         return ret;
diff --git a/libavcodec/dvdec.c b/libavcodec/dvdec.c
index ef9ba4c..77f8473 100644
--- a/libavcodec/dvdec.c
+++ b/libavcodec/dvdec.c
@@ -36,6 +36,7 @@
  */
 
 #include "libavutil/internal.h"
+#include "libavutil/imgutils.h"
 #include "libavutil/pixdesc.h"
 #include "avcodec.h"
 #include "internal.h"
@@ -337,6 +338,14 @@ static int dvvideo_decode_frame(AVCodecContext *avctx,
     if (ret < 0)
         return ret;
 
+    /* Determine the codec's sample_aspect ratio from the packet */
+    vsc_pack = buf + 80*5 + 48 + 5;
+    if ( *vsc_pack == dv_video_control ) {
+        apt = buf[4] & 0x07;
+        is16_9 = (vsc_pack && ((vsc_pack[2] & 0x07) == 0x02 || (!apt && (vsc_pack[2] & 0x07) == 0x07)));
+        ff_set_sar(avctx, s->sys->sar[is16_9]);
+    }
+
     if (ff_get_buffer(avctx, s->frame, 0) < 0) {
         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
         return -1;
@@ -353,14 +362,6 @@ static int dvvideo_decode_frame(AVCodecContext *avctx,
     /* return image */
     *got_frame = 1;
 
-    /* Determine the codec's sample_aspect ratio from the packet */
-    vsc_pack = buf + 80*5 + 48 + 5;
-    if ( *vsc_pack == dv_video_control ) {
-        apt = buf[4] & 0x07;
-        is16_9 = (vsc_pack && ((vsc_pack[2] & 0x07) == 0x02 || (!apt && (vsc_pack[2] & 0x07) == 0x07)));
-        avctx->sample_aspect_ratio = s->sys->sar[is16_9];
-    }
-
     return s->sys->frame_size;
 }
 
diff --git a/libavcodec/exr.c b/libavcodec/exr.c
index 9f60cc6..37a31ce 100644
--- a/libavcodec/exr.c
+++ b/libavcodec/exr.c
@@ -1107,8 +1107,8 @@ static int decode_header(EXRContext *s)
             if (!var_size)
                 return AVERROR_INVALIDDATA;
 
-            s->avctx->sample_aspect_ratio =
-                av_d2q(av_int2float(bytestream2_get_le32(&s->gb)), 255);
+            ff_set_sar(s->avctx,
+                       av_d2q(av_int2float(bytestream2_get_le32(&s->gb)), 255));
 
             continue;
         } else if ((var_size = check_header_variable(s, "compression",
diff --git a/libavcodec/ffv1dec.c b/libavcodec/ffv1dec.c
index 8f7b2bf..703491e 100644
--- a/libavcodec/ffv1dec.c
+++ b/libavcodec/ffv1dec.c
@@ -328,6 +328,14 @@ static int decode_slice_header(FFV1Context *f, FFV1Context *fs)
     f->cur->sample_aspect_ratio.num = get_symbol(c, state, 0);
     f->cur->sample_aspect_ratio.den = get_symbol(c, state, 0);
 
+    if (av_image_check_sar(f->width, f->height,
+                           f->cur->sample_aspect_ratio) < 0) {
+        av_log(f->avctx, AV_LOG_WARNING, "ignoring invalid SAR: %u/%u\n",
+               f->cur->sample_aspect_ratio.num,
+               f->cur->sample_aspect_ratio.den);
+        f->cur->sample_aspect_ratio = (AVRational){ 0, 1 };
+    }
+
     return 0;
 }
 
diff --git a/libavcodec/h263dec.c b/libavcodec/h263dec.c
index f70feb9..b081e30 100644
--- a/libavcodec/h263dec.c
+++ b/libavcodec/h263dec.c
@@ -497,6 +497,8 @@ int ff_h263_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
         if (ret < 0)
             return ret;
 
+        ff_set_sar(avctx, avctx->sample_aspect_ratio);
+
         if ((ret = ff_MPV_common_frame_size_change(s)))
             return ret;
     }
diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c
index 25f0f4d..8e0e187 100644
--- a/libavcodec/h264_slice.c
+++ b/libavcodec/h264_slice.c
@@ -1067,8 +1067,7 @@ static int h264_slice_header_init(H264Context *h, int reinit)
                     h->avctx->thread_count : 1;
     int i, ret;
 
-    h->avctx->sample_aspect_ratio = h->sps.sar;
-    av_assert0(h->avctx->sample_aspect_ratio.den);
+    ff_set_sar(h->avctx, h->sps.sar);
     av_pix_fmt_get_chroma_sub_sample(h->avctx->pix_fmt,
                                      &h->chroma_x_shift, &h->chroma_y_shift);
 
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
index a4c495d..f66a49f 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
@@ -400,9 +400,10 @@ static int set_sps(HEVCContext *s, const HEVCSPS *sps)
     s->avctx->width               = sps->output_width;
     s->avctx->height              = sps->output_height;
     s->avctx->pix_fmt             = sps->pix_fmt;
-    s->avctx->sample_aspect_ratio = sps->vui.sar;
     s->avctx->has_b_frames        = sps->temporal_layer[sps->max_sub_layers - 1].num_reorder_pics;
 
+    ff_set_sar(s->avctx, sps->vui.sar);
+
     if (sps->vui.video_signal_type_present_flag)
         s->avctx->color_range = sps->vui.video_full_range_flag ? AVCOL_RANGE_JPEG
                                                                : AVCOL_RANGE_MPEG;
diff --git a/libavcodec/internal.h b/libavcodec/internal.h
index 6aaaf4c..3b2ae40 100644
--- a/libavcodec/internal.h
+++ b/libavcodec/internal.h
@@ -177,6 +177,12 @@ const uint8_t *avpriv_find_start_code(const uint8_t *restrict p,
 int ff_set_dimensions(AVCodecContext *s, int width, int height);
 
 /**
+ * Check that the provided sample aspect ratio is valid and set it on the codec
+ * context.
+ */
+int ff_set_sar(AVCodecContext *avctx, AVRational sar);
+
+/**
  * Add or update AV_FRAME_DATA_MATRIXENCODING side data.
  */
 int ff_side_data_update_matrix_encoding(AVFrame *frame,
diff --git a/libavcodec/mjpegdec.c b/libavcodec/mjpegdec.c
index cd1e292..adcab4f 100644
--- a/libavcodec/mjpegdec.c
+++ b/libavcodec/mjpegdec.c
@@ -1222,6 +1222,7 @@ static int mjpeg_decode_app(MJpegDecodeContext *s)
 
         s->avctx->sample_aspect_ratio.num = get_bits(&s->gb, 16);
         s->avctx->sample_aspect_ratio.den = get_bits(&s->gb, 16);
+        ff_set_sar(s->avctx, s->avctx->sample_aspect_ratio);
 
         if (s->avctx->debug & FF_DEBUG_PICT_INFO)
             av_log(s->avctx, AV_LOG_INFO,
diff --git a/libavcodec/mpeg12dec.c b/libavcodec/mpeg12dec.c
index 195f9f3..91f9343 100644
--- a/libavcodec/mpeg12dec.c
+++ b/libavcodec/mpeg12dec.c
@@ -1294,6 +1294,8 @@ static int mpeg_decode_postinit(AVCodecContext *avctx)
             }
         } // MPEG-2
 
+        ff_set_sar(s->avctx, s->avctx->sample_aspect_ratio);
+
         avctx->pix_fmt = mpeg_get_pixelformat(avctx);
         // until then pix_fmt may be changed right after codec init
 #if FF_API_XVMC
diff --git a/libavcodec/truemotion1.c b/libavcodec/truemotion1.c
index 270a030..5dffb4e 100644
--- a/libavcodec/truemotion1.c
+++ b/libavcodec/truemotion1.c
@@ -412,6 +412,8 @@ static int truemotion1_decode_header(TrueMotion1Context *s)
         if ((ret = ff_set_dimensions(s->avctx, s->w, s->h)) < 0)
             return ret;
 
+        ff_set_sar(s->avctx, s->avctx->sample_aspect_ratio);
+
         av_fast_malloc(&s->vert_pred, &s->vert_pred_size, s->avctx->width * sizeof(unsigned int));
     }
 
diff --git a/libavcodec/utils.c b/libavcodec/utils.c
index dff8419..33983f8 100644
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@ -153,6 +153,21 @@ int ff_set_dimensions(AVCodecContext *s, int width, int height)
     return ret;
 }
 
+int ff_set_sar(AVCodecContext *avctx, AVRational sar)
+{
+    int ret = av_image_check_sar(avctx->width, avctx->height, sar);
+
+    if (ret < 0) {
+        av_log(avctx, AV_LOG_WARNING, "ignoring invalid SAR: %u/%u\n",
+               sar.num, sar.den);
+        avctx->sample_aspect_ratio = (AVRational){ 0, 1 };
+        return ret;
+    } else {
+        avctx->sample_aspect_ratio = sar;
+    }
+    return 0;
+}
+
 int ff_side_data_update_matrix_encoding(AVFrame *frame,
                                         enum AVMatrixEncoding matrix_encoding)
 {
@@ -636,6 +651,14 @@ int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
         if (!frame->sample_aspect_ratio.num)
             frame->sample_aspect_ratio = avctx->sample_aspect_ratio;
 
+        if (av_image_check_sar(frame->width, frame->height,
+                               frame->sample_aspect_ratio) < 0) {
+            av_log(avctx, AV_LOG_WARNING, "ignoring invalid SAR: %u/%u\n",
+                   frame->sample_aspect_ratio.num,
+                   frame->sample_aspect_ratio.den);
+            frame->sample_aspect_ratio = (AVRational){ 0, 1 };
+        }
+
         if ((ret = av_image_check_size(avctx->width, avctx->height, 0, avctx)) < 0)
             return ret;
         break;
@@ -1071,6 +1094,16 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code
         ff_set_dimensions(avctx, 0, 0);
     }
 
+    if (avctx->width > 0 && avctx->height > 0) {
+        if (av_image_check_sar(avctx->width, avctx->height,
+                               avctx->sample_aspect_ratio) < 0) {
+            av_log(avctx, AV_LOG_WARNING, "ignoring invalid SAR: %u/%u\n",
+                   avctx->sample_aspect_ratio.num,
+                   avctx->sample_aspect_ratio.den);
+            avctx->sample_aspect_ratio = (AVRational){ 0, 1 };
+        }
+    }
+
     /* if the decoder init function was already called previously,
      * free the already allocated subtitle_header before overwriting it */
     if (av_codec_is_decoder(codec))
diff --git a/libavcodec/vc1.c b/libavcodec/vc1.c
index 81635b1..1978b08 100644
--- a/libavcodec/vc1.c
+++ b/libavcodec/vc1.c
@@ -478,6 +478,7 @@ static int decode_sequence_header_adv(VC1Context *v, GetBitContext *gb)
                       v->s.avctx->width * h,
                       1 << 30);
         }
+        ff_set_sar(v->s.avctx, v->s.avctx->sample_aspect_ratio);
         av_log(v->s.avctx, AV_LOG_DEBUG, "Aspect: %i:%i\n",
                v->s.avctx->sample_aspect_ratio.num,
                v->s.avctx->sample_aspect_ratio.den);
diff --git a/libavcodec/vp3.c b/libavcodec/vp3.c
index 2de3ebd..c215fbb 100644
--- a/libavcodec/vp3.c
+++ b/libavcodec/vp3.c
@@ -2243,6 +2243,7 @@ static int theora_decode_header(AVCodecContext *avctx, GetBitContext *gb)
         av_reduce(&avctx->sample_aspect_ratio.num,
                   &avctx->sample_aspect_ratio.den,
                   aspect.num, aspect.den, 1 << 30);
+        ff_set_sar(avctx, avctx->sample_aspect_ratio);
     }
 
     if (s->theora < 0x030200)
diff --git a/libavutil/imgutils.c b/libavutil/imgutils.c
index 813724b..fc367d9 100644
--- a/libavutil/imgutils.c
+++ b/libavutil/imgutils.c
@@ -25,7 +25,9 @@
 #include "imgutils.h"
 #include "internal.h"
 #include "log.h"
+#include "mathematics.h"
 #include "pixdesc.h"
+#include "rational.h"
 
 void av_image_fill_max_pixsteps(int max_pixsteps[4], int max_pixstep_comps[4],
                                 const AVPixFmtDescriptor *pixdesc)
@@ -228,6 +230,27 @@ int av_image_check_size(unsigned int w, unsigned int h, int log_offset, void *lo
     return AVERROR(EINVAL);
 }
 
+int av_image_check_sar(unsigned int w, unsigned int h, AVRational sar)
+{
+    int64_t scaled_dim;
+
+    if (!sar.den)
+        return AVERROR(EINVAL);
+
+    if (!sar.num || sar.num == sar.den)
+        return 0;
+
+    if (sar.num < sar.den)
+        scaled_dim = av_rescale_rnd(w, sar.num, sar.den, AV_ROUND_ZERO);
+    else
+        scaled_dim = av_rescale_rnd(h, sar.den, sar.num, AV_ROUND_ZERO);
+
+    if (scaled_dim > 0)
+        return 0;
+
+    return AVERROR(EINVAL);
+}
+
 void av_image_copy_plane(uint8_t       *dst, int dst_linesize,
                          const uint8_t *src, int src_linesize,
                          int bytewidth, int height)
diff --git a/libavutil/imgutils.h b/libavutil/imgutils.h
index 7151013..313037a 100644
--- a/libavutil/imgutils.h
+++ b/libavutil/imgutils.h
@@ -29,6 +29,7 @@
 
 #include "avutil.h"
 #include "pixdesc.h"
+#include "rational.h"
 
 /**
  * Compute the max pixel step for each plane of an image with a
@@ -128,6 +129,20 @@ void av_image_copy(uint8_t *dst_data[4], int dst_linesizes[4],
  */
 int av_image_check_size(unsigned int w, unsigned int h, int log_offset, void *log_ctx);
 
+/**
+ * Check if the given sample aspect ratio of an image is valid.
+ *
+ * It is considered invalid if the denominator is 0 or if applying the ratio
+ * to the image size would make the smaller dimension less than 1. If the
+ * sar numerator is 0, it is considered unknown and will return as valid.
+ *
+ * @param w width of the image
+ * @param h height of the image
+ * @param sar sample aspect ratio of the image
+ * @return 0 if valid, a negative AVERROR code otherwise
+ */
+int av_image_check_sar(unsigned int w, unsigned int h, AVRational sar);
+
 int avpriv_set_systematic_pal2(uint32_t pal[256], enum AVPixelFormat pix_fmt);
 
 /**
diff --git a/libavutil/version.h b/libavutil/version.h
index 427409f..a4384b3 100644
--- a/libavutil/version.h
+++ b/libavutil/version.h
@@ -54,7 +54,7 @@
  */
 
 #define LIBAVUTIL_VERSION_MAJOR 53
-#define LIBAVUTIL_VERSION_MINOR 16
+#define LIBAVUTIL_VERSION_MINOR 17
 #define LIBAVUTIL_VERSION_MICRO  0
 
 #define LIBAVUTIL_VERSION_INT   AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \
-- 
1.8.1.2



More information about the libav-devel mailing list