[FFmpeg-devel] [PATCH] avformat/riffenc: indicate storage of flipped RGB bitmaps

Gyan Doshi ffmpeg at gyani.pro
Tue Jul 14 10:59:42 EEST 2020


Plan to push in 24h.

On 08-07-2020 06:21 pm, Gyan Doshi wrote:
> Some legacy applications such as AVI2MVE expect raw RGB bitmaps
> to be stored bottom-up, whereas our RIFF BITMAPINFOHEADER assumes
> they are always stored top-down and thus write a negative value
> for height. This can prevent reading of these files.
>
> Option flipped_raw_rgb added to AVI and Matroska muxers
> which will write positive value for height when enabled.
>
> Note that the user has to flip the bitmaps beforehand using other
> means such as the vflip filter.
> ---
>   doc/muxers.texi           | 13 +++++++++++++
>   libavformat/asfenc.c      |  2 +-
>   libavformat/avienc.c      |  4 +++-
>   libavformat/matroskaenc.c |  5 ++++-
>   libavformat/riff.h        |  2 +-
>   libavformat/riffenc.c     |  7 ++++---
>   libavformat/wtvenc.c      |  2 +-
>   7 files changed, 27 insertions(+), 8 deletions(-)
>
> diff --git a/doc/muxers.texi b/doc/muxers.texi
> index b1389a3227..2f26494bfa 100644
> --- a/doc/muxers.texi
> +++ b/doc/muxers.texi
> @@ -89,6 +89,12 @@ specific scenarios, e.g. when merging multiple audio streams into one for
>   compatibility with software that only supports a single audio stream in AVI
>   (see @ref{amerge,,the "amerge" section in the ffmpeg-filters manual,ffmpeg-filters}).
>   
> + at item flipped_raw_rgb
> +If set to true, store positive height for raw RGB bitmaps, which indicates
> +bitmap is stored bottom-up. Note that this option does not flip the bitmap
> +which has to be done manually beforehand, e.g. by using the vflip filter.
> +Default is @var{false} and indicates bitmap is stored top down.
> +
>   @end table
>   
>   @anchor{chromaprint}
> @@ -1409,6 +1415,13 @@ disposition default exists, no subtitle track will be marked as default.
>   In this mode the FlagDefault is set if and only if the AV_DISPOSITION_DEFAULT
>   flag is set in the disposition of the corresponding stream.
>   @end table
> +
> + at item flipped_raw_rgb
> +If set to true, store positive height for raw RGB bitmaps, which indicates
> +bitmap is stored bottom-up. Note that this option does not flip the bitmap
> +which has to be done manually beforehand, e.g. by using the vflip filter.
> +Default is @var{false} and indicates bitmap is stored top down.
> +
>   @end table
>   
>   @anchor{md5}
> diff --git a/libavformat/asfenc.c b/libavformat/asfenc.c
> index 73afb13200..8b24264c94 100644
> --- a/libavformat/asfenc.c
> +++ b/libavformat/asfenc.c
> @@ -682,7 +682,7 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size,
>               avio_wl16(pb, 40 + par->extradata_size); /* size */
>   
>               /* BITMAPINFOHEADER header */
> -            ff_put_bmp_header(pb, par, 1, 0);
> +            ff_put_bmp_header(pb, par, 1, 0, 0);
>           }
>           end_header(pb, hpos);
>       }
> diff --git a/libavformat/avienc.c b/libavformat/avienc.c
> index 297d5b8964..1b2cb529b9 100644
> --- a/libavformat/avienc.c
> +++ b/libavformat/avienc.c
> @@ -72,6 +72,7 @@ typedef struct AVIContext {
>       int reserve_index_space;
>       int master_index_max_size;
>       int write_channel_mask;
> +    int flipped_raw_rgb;
>   } AVIContext;
>   
>   typedef struct AVIStream {
> @@ -449,7 +450,7 @@ static int avi_write_header(AVFormatContext *s)
>                       && par->bits_per_coded_sample == 15)
>                       par->bits_per_coded_sample = 16;
>                   avist->pal_offset = avio_tell(pb) + 40;
> -                ff_put_bmp_header(pb, par, 0, 0);
> +                ff_put_bmp_header(pb, par, 0, 0, avi->flipped_raw_rgb);
>                   pix_fmt = avpriv_find_pix_fmt(avpriv_pix_fmt_bps_avi,
>                                                 par->bits_per_coded_sample);
>                   if (   !par->codec_tag
> @@ -993,6 +994,7 @@ static void avi_deinit(AVFormatContext *s)
>   static const AVOption options[] = {
>       { "reserve_index_space", "reserve space (in bytes) at the beginning of the file for each stream index", OFFSET(reserve_index_space), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, ENC },
>       { "write_channel_mask", "write channel mask into wave format header", OFFSET(write_channel_mask), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, ENC },
> +    { "flipped_raw_rgb", "Raw RGB bitmaps are stored bottom-up", OFFSET(flipped_raw_rgb), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, ENC },
>       { NULL },
>   };
>   
> diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c
> index 105ed5197e..233c472b8f 100644
> --- a/libavformat/matroskaenc.c
> +++ b/libavformat/matroskaenc.c
> @@ -154,6 +154,7 @@ typedef struct MatroskaMuxContext {
>       int                 is_dash;
>       int                 dash_track_number;
>       int                 allow_raw_vfw;
> +    int                 flipped_raw_rgb;
>       int                 default_mode;
>   
>       uint32_t            segment_uid[4];
> @@ -764,6 +765,7 @@ static int mkv_write_codecprivate(AVFormatContext *s, AVIOContext *pb,
>                                     int native_id, int qt_id)
>   {
>       AVIOContext *dyn_cp;
> +    MatroskaMuxContext *mkv = s->priv_data;
>       uint8_t *codecpriv;
>       int ret, codecpriv_size;
>   
> @@ -802,7 +804,7 @@ static int mkv_write_codecprivate(AVFormatContext *s, AVIOContext *pb,
>                   ret = AVERROR(EINVAL);
>               }
>   
> -            ff_put_bmp_header(dyn_cp, par, 0, 0);
> +            ff_put_bmp_header(dyn_cp, par, 0, 0, mkv->flipped_raw_rgb);
>           }
>       } else if (par->codec_type == AVMEDIA_TYPE_AUDIO) {
>           unsigned int tag;
> @@ -2787,6 +2789,7 @@ static const AVOption options[] = {
>       { "dash_track_number", "Track number for the DASH stream", OFFSET(dash_track_number), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, INT_MAX, FLAGS },
>       { "live", "Write files assuming it is a live stream.", OFFSET(is_live), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS },
>       { "allow_raw_vfw", "allow RAW VFW mode", OFFSET(allow_raw_vfw), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS },
> +    { "flipped_raw_rgb", "Raw RGB bitmaps in VFW mode are stored bottom-up", OFFSET(flipped_raw_rgb), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS },
>       { "write_crc32", "write a CRC32 element inside every Level 1 element", OFFSET(write_crc), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, FLAGS },
>       { "default_mode", "Controls how a track's FlagDefault is inferred", OFFSET(default_mode), AV_OPT_TYPE_INT, { .i64 = DEFAULT_MODE_INFER }, DEFAULT_MODE_INFER, DEFAULT_MODE_PASSTHROUGH, FLAGS, "default_mode" },
>       { "infer", "For each track type, mark the first track of disposition default as default; if none exists, mark the first track as default.", 0, AV_OPT_TYPE_CONST, { .i64 = DEFAULT_MODE_INFER }, 0, 0, FLAGS, "default_mode" },
> diff --git a/libavformat/riff.h b/libavformat/riff.h
> index 21078b77c8..127138d2bc 100644
> --- a/libavformat/riff.h
> +++ b/libavformat/riff.h
> @@ -46,7 +46,7 @@ void ff_end_tag(AVIOContext *pb, int64_t start);
>    */
>   int ff_get_bmp_header(AVIOContext *pb, AVStream *st, uint32_t *size);
>   
> -void ff_put_bmp_header(AVIOContext *pb, AVCodecParameters *par, int for_asf, int ignore_extradata);
> +void ff_put_bmp_header(AVIOContext *pb, AVCodecParameters *par, int for_asf, int ignore_extradata, int rgb_frame_is_flipped);
>   
>   /**
>    * Tell ff_put_wav_header() to use WAVEFORMATEX even for PCM codecs.
> diff --git a/libavformat/riffenc.c b/libavformat/riffenc.c
> index c04d55c423..d0ee98bfcc 100644
> --- a/libavformat/riffenc.c
> +++ b/libavformat/riffenc.c
> @@ -207,10 +207,11 @@ int ff_put_wav_header(AVFormatContext *s, AVIOContext *pb,
>   
>   /* BITMAPINFOHEADER header */
>   void ff_put_bmp_header(AVIOContext *pb, AVCodecParameters *par,
> -                       int for_asf, int ignore_extradata)
> +                       int for_asf, int ignore_extradata, int rgb_frame_is_flipped)
>   {
> -    int keep_height = par->extradata_size >= 9 &&
> -                      !memcmp(par->extradata + par->extradata_size - 9, "BottomUp", 9);
> +    int keep_height = (par->extradata_size >= 9 &&
> +                      !memcmp(par->extradata + par->extradata_size - 9, "BottomUp", 9)) ||
> +                      rgb_frame_is_flipped;
>       int extradata_size = par->extradata_size - 9*keep_height;
>       enum AVPixelFormat pix_fmt = par->format;
>       int pal_avi;
> diff --git a/libavformat/wtvenc.c b/libavformat/wtvenc.c
> index 498bc64019..b53fdf9048 100644
> --- a/libavformat/wtvenc.c
> +++ b/libavformat/wtvenc.c
> @@ -241,7 +241,7 @@ static void put_videoinfoheader2(AVIOContext *pb, AVStream *st)
>       avio_wl32(pb, 0);
>       avio_wl32(pb, 0);
>   
> -    ff_put_bmp_header(pb, st->codecpar, 0, 1);
> +    ff_put_bmp_header(pb, st->codecpar, 0, 1, 0);
>   
>       if (st->codecpar->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
>           int padding = (st->codecpar->extradata_size & 3) ? 4 - (st->codecpar->extradata_size & 3) : 0;



More information about the ffmpeg-devel mailing list