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 ]; "
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));
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 {
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;
case 3:
avipad->vids.compression = GST_MAKE_FOURCC ('W', 'M', 'V', '3');
default:
+ valid_caps = FALSE;
break;
}
}
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;
}
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)
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) {
if (!avipad->collect)
continue;
- if (!avipad->hdr.fcc_handler)
- goto not_negotiated;
-
buffer = gst_collect_pads_peek (avimux->collect, avipad->collect);
if (!buffer)
continue;
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