avimux: support raw BGR

https://bugzilla.gnome.org/show_bug.cgi?id=695543
This commit is contained in:
Dirk Van Haerenborgh 2013-03-10 09:10:18 +01:00 committed by Sebastian Dröge
parent d7743cf7c6
commit 065bdf5925

View file

@ -93,7 +93,7 @@ static GstStaticPadTemplate video_sink_factory =
GST_PAD_SINK,
GST_PAD_REQUEST,
GST_STATIC_CAPS ("video/x-raw, "
"format = (string) { YUY2, I420, GRAY8 }, "
"format = (string) { YUY2, I420, GRAY8, BGR, BGRx, BGRA }, "
"width = (int) [ 16, 4096 ], "
"height = (int) [ 16, 4096 ], "
"framerate = (fraction) [ 0, MAX ]; "
@ -395,6 +395,7 @@ gst_avi_mux_vidsink_set_caps (GstPad * pad, GstCaps * vscaps)
gint width, height;
gint par_n, par_d;
gboolean codec_data_in_headers = TRUE;
gboolean valid_caps = TRUE;
avimux = GST_AVI_MUX (gst_pad_get_parent (pad));
@ -480,7 +481,17 @@ gst_avi_mux_vidsink_set_caps (GstPad * pad, GstCaps * vscaps)
avipad->vids.compression = GST_MAKE_FOURCC ('Y', '8', '0', '0');
avipad->vids.bit_cnt = 8;
break;
case GST_VIDEO_FORMAT_BGR:
avipad->vids.compression = GST_MAKE_FOURCC (0x00, 0x00, 0x00, 0x00);
avipad->vids.bit_cnt = 24;
break;
case GST_VIDEO_FORMAT_BGRx:
case GST_VIDEO_FORMAT_BGRA:
avipad->vids.compression = GST_MAKE_FOURCC (0x00, 0x00, 0x00, 0x00);
avipad->vids.bit_cnt = 32;
break;
default:
valid_caps = FALSE;
break;
}
} else {
@ -506,6 +517,8 @@ gst_avi_mux_vidsink_set_caps (GstPad * pad, GstCaps * vscaps)
case 5:
avipad->vids.compression = GST_MAKE_FOURCC ('D', 'X', '5', '0');
break;
default:
valid_caps = FALSE;
}
} else if (gst_structure_has_name (structure, "video/x-msmpeg")) {
gint msmpegversion;
@ -571,6 +584,7 @@ gst_avi_mux_vidsink_set_caps (GstPad * pad, GstCaps * vscaps)
case 3:
avipad->vids.compression = GST_MAKE_FOURCC ('W', 'M', 'V', '3');
default:
valid_caps = FALSE;
break;
}
}
@ -578,9 +592,11 @@ gst_avi_mux_vidsink_set_caps (GstPad * pad, GstCaps * vscaps)
avipad->vids.compression = GST_MAKE_FOURCC ('M', 'J', '2', 'C');
} else if (!strcmp (mimetype, "video/x-vp8")) {
avipad->vids.compression = GST_MAKE_FOURCC ('V', 'P', '8', '0');
} else {
valid_caps = FALSE;
}
if (!avipad->vids.compression)
if (!valid_caps)
goto refuse_caps;
}
@ -1910,6 +1926,68 @@ gst_avi_mux_send_pad_data (GstAviMux * avimux, gulong num_bytes)
return gst_pad_push (avimux->srcpad, buffer);
}
#define gst_avi_mux_is_uncompressed(fourcc) \
(fourcc == GST_RIFF_DIB || \
fourcc == GST_RIFF_rgb || \
fourcc == GST_RIFF_RGB || fourcc == GST_RIFF_RAW)
/*
* Helper for gst_avi_demux_invert()
*/
static inline void
swap_line (guint8 * d1, guint8 * d2, guint8 * tmp, gint bytes)
{
memcpy (tmp, d1, bytes);
memcpy (d1, d2, bytes);
memcpy (d2, tmp, bytes);
}
/*
* Invert DIB buffers... Takes existing buffer and
* returns either the buffer or a new one (with old
* one dereferenced).
* FFMPEG does this by simply negating the height in the header. Should we?
* FIXME: can't we preallocate tmp? and remember stride, bpp?
* this could be done in do_one_buffer() I suppose
*/
static GstBuffer *
gst_avi_mux_invert (GstAviPad * avipad, GstBuffer * buf)
{
gint y, w, h;
gint bpp, stride;
guint8 *tmp = NULL;
GstMapInfo map;
GstAviVideoPad *vidpad = (GstAviVideoPad *) avipad;
h = vidpad->vids.height;
w = vidpad->vids.width;
bpp = vidpad->vids.bit_cnt ? vidpad->vids.bit_cnt : 8;
stride = GST_ROUND_UP_4 (w * (bpp / 8));
buf = gst_buffer_make_writable (buf);
gst_buffer_map (buf, &map, GST_MAP_READWRITE);
if (map.size < (stride * h)) {
GST_WARNING ("Buffer is smaller than reported Width x Height x Depth");
gst_buffer_unmap (buf, &map);
return buf;
}
tmp = g_malloc (stride);
for (y = 0; y < h / 2; y++) {
swap_line (map.data + stride * y, map.data + stride * (h - 1 - y), tmp,
stride);
}
g_free (tmp);
gst_buffer_unmap (buf, &map);
return buf;
}
/* do buffer */
static GstFlowReturn
gst_avi_mux_do_buffer (GstAviMux * avimux, GstAviPad * avipad)
@ -1941,6 +2019,11 @@ gst_avi_mux_do_buffer (GstAviMux * avimux, GstAviPad * avipad)
data = newdata;
vidpad->prepend_buffer = NULL;
}
/* DIB buffers are stored topdown (I don't know why) */
if (gst_avi_mux_is_uncompressed (avipad->hdr.fcc_handler)) {
data = gst_avi_mux_invert (avipad, data);
}
}
if (avimux->restart) {
@ -2048,9 +2131,6 @@ gst_avi_mux_do_one_buffer (GstAviMux * avimux)
if (!avipad->collect)
continue;
if (!avipad->hdr.fcc_handler)
goto not_negotiated;
buffer = gst_collect_pads_peek (avimux->collect, avipad->collect);
if (!buffer)
continue;
@ -2093,13 +2173,6 @@ gst_avi_mux_do_one_buffer (GstAviMux * avimux)
return GST_FLOW_EOS;
}
/* ERRORS */
not_negotiated:
{
GST_ELEMENT_ERROR (avimux, CORE, NEGOTIATION, (NULL),
("pad %s not negotiated", GST_PAD_NAME (avipad->collect->pad)));
return GST_FLOW_NOT_NEGOTIATED;
}
}
static GstFlowReturn