]> git.sesse.net Git - ffmpeg/commitdiff
avformat/riffenc: indicate storage of flipped RGB bitmaps
authorGyan Doshi <ffmpeg@gyani.pro>
Wed, 8 Jul 2020 12:02:25 +0000 (17:32 +0530)
committerGyan Doshi <ffmpeg@gyani.pro>
Wed, 15 Jul 2020 15:22:01 +0000 (20:52 +0530)
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
libavformat/asfenc.c
libavformat/avienc.c
libavformat/matroskaenc.c
libavformat/riff.h
libavformat/riffenc.c
libavformat/wtvenc.c

index 86976f4f617e213ea95711409dde69b1bc13f567..813b4678f4098b45170055a2acf48939ec50061d 100644 (file)
@@ -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}).
 
+@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}
@@ -1413,6 +1419,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
+
+@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}
index 73afb13200b1a36e8e90dffbeb79ba4eaf22e15f..8b24264c9475904edc9bae9b2459d3c710e05735 100644 (file)
@@ -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);
     }
index 297d5b8964ae71e77a8c90d5780867cc679a9e04..1b2cb529b90b4a0cc32d4175ba59426891acc520 100644 (file)
@@ -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 },
 };
 
index 105ed5197edf6f5b360395b173b7fc700034e699..233c472b8f321da5590ade93bbc79eac6a4c1c29 100644 (file)
@@ -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" },
index 21078b77c8edf4a94a4f2686758f56c35e0a0940..127138d2bcabf2ccd6a2b36a18babe19e4b2cf72 100644 (file)
@@ -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.
index c04d55c4230dcc85889785b023da58fd707e64d3..d0ee98bfcccaf080ddf717ff93debbafd87abd82 100644 (file)
@@ -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;
index 498bc64019551ac210b7f883068c5b17c016d360..b53fdf904878fe1a52f8fe2532ab428d1d8ea27f 100644 (file)
@@ -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;