diff --git a/doc/muxers.texi b/doc/muxers.texi index 86976f4f61..813b4678f4 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}). +@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} 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;