summaryrefslogtreecommitdiffstats
path: root/gst/avi/gstavidemux.c
diff options
context:
space:
mode:
Diffstat (limited to 'gst/avi/gstavidemux.c')
-rw-r--r--gst/avi/gstavidemux.c164
1 files changed, 163 insertions, 1 deletions
diff --git a/gst/avi/gstavidemux.c b/gst/avi/gstavidemux.c
index 38211be1..a48ceee4 100644
--- a/gst/avi/gstavidemux.c
+++ b/gst/avi/gstavidemux.c
@@ -1197,6 +1197,127 @@ gst_avi_demux_read_subindexes_pull (GstAviDemux * avi,
}
/*
+ * gst_avi_demux_riff_parse_vprp:
+ * @element: caller element (used for debugging/error).
+ * @buf: input data to be used for parsing, stripped from header.
+ * @vprp: a pointer (returned by this function) to a filled-in vprp
+ * structure. Caller should free it.
+ *
+ * Parses a video stream“s vprp. This function takes ownership of @buf.
+ *
+ * Returns: TRUE if parsing succeeded, otherwise FALSE. The stream
+ * should be skipped on error, but it is not fatal.
+ */
+static gboolean
+gst_avi_demux_riff_parse_vprp (GstElement * element,
+ GstBuffer * buf, gst_riff_vprp ** _vprp)
+{
+ gst_riff_vprp *vprp;
+ gint k;
+
+ g_return_val_if_fail (buf != NULL, FALSE);
+ g_return_val_if_fail (_vprp != NULL, FALSE);
+
+ if (GST_BUFFER_SIZE (buf) < G_STRUCT_OFFSET (gst_riff_vprp, field_info))
+ goto too_small;
+
+ vprp = g_memdup (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
+
+#if (G_BYTE_ORDER == G_BIG_ENDIAN)
+ vprp->format_token = GUINT32_FROM_LE (vprp->format_token);
+ vprp->standard = GUINT32_FROM_LE (vprp->standard);
+ vprp->vert_rate = GUINT32_FROM_LE (vprp->vert_rate);
+ vprp->hor_t_total = GUINT32_FROM_LE (vprp->hor_t_total);
+ vprp->vert_lines = GUINT32_FROM_LE (vprp->vert_lines);
+ vprp->aspect = GUINT32_FROM_LE (vprp->aspect);
+ vprp->width = GUINT32_FROM_LE (vprp->width);
+ vprp->height = GUINT32_FROM_LE (vprp->height);
+ vprp->fields = GUINT32_FROM_LE (vprp->fields);
+#endif
+
+ /* size checking */
+ /* calculate fields based on size */
+ k = (GST_BUFFER_SIZE (buf) - G_STRUCT_OFFSET (gst_riff_vprp, field_info)) /
+ vprp->fields;
+ if (vprp->fields > k) {
+ GST_WARNING_OBJECT (element,
+ "vprp header indicated %d fields, only %d available", vprp->fields, k);
+ vprp->fields = k;
+ }
+ if (vprp->fields > GST_RIFF_VPRP_VIDEO_FIELDS) {
+ GST_WARNING_OBJECT (element,
+ "vprp header indicated %d fields, at most %d supported", vprp->fields,
+ GST_RIFF_VPRP_VIDEO_FIELDS);
+ vprp->fields = GST_RIFF_VPRP_VIDEO_FIELDS;
+ }
+#if (G_BYTE_ORDER == G_BIG_ENDIAN)
+ for (k = 0; k < vprp->fields; k++) {
+ gst_riff_vprp_video_field_desc *fd;
+
+ fd = &(vidpad->vprp.field_info[k]);
+ fd->compressed_bm_height = GUINT32_FROM_LE (fd->compressed_bm_height);
+ fd->compressed_bm_width = GUINT32_FROM_LE (fd->compressed_bm_width);
+ fd->valid_bm_height = GUINT32_FROM_LE (fd->valid_bm_height);
+ fd->valid_bm_width = GUINT16_FROM_LE (fd->valid_bm_width);
+ fd->valid_bm_x_offset = GUINT16_FROM_LE (fd->valid_bm_x_offset);
+ fd->valid_bm_y_offset = GUINT32_FROM_LE (fd->valid_bm_y_offset);
+ fd->video_x_t_offset = GUINT32_FROM_LE (fd->video_x_t_offset);
+ fd->video_y_start = GUINT32_FROM_LE (fd->video_y_start);
+ }
+#endif
+
+ /* debug */
+ GST_INFO_OBJECT (element, "vprp tag found in context vids:");
+ GST_INFO_OBJECT (element, " format_token %d", vprp->format_token);
+ GST_INFO_OBJECT (element, " standard %d", vprp->standard);
+ GST_INFO_OBJECT (element, " vert_rate %d", vprp->vert_rate);
+ GST_INFO_OBJECT (element, " hor_t_total %d", vprp->hor_t_total);
+ GST_INFO_OBJECT (element, " vert_lines %d", vprp->vert_lines);
+ GST_INFO_OBJECT (element, " aspect %d:%d", vprp->aspect >> 16,
+ vprp->aspect & 0xffff);
+ GST_INFO_OBJECT (element, " width %d", vprp->width);
+ GST_INFO_OBJECT (element, " height %d", vprp->height);
+ GST_INFO_OBJECT (element, " fields %d", vprp->fields);
+ for (k = 0; k < vprp->fields; k++) {
+ gst_riff_vprp_video_field_desc *fd;
+
+ fd = &(vprp->field_info[k]);
+ GST_INFO_OBJECT (element, " field %u description:", k);
+ GST_INFO_OBJECT (element, " compressed_bm_height %d",
+ fd->compressed_bm_height);
+ GST_INFO_OBJECT (element, " compressed_bm_width %d",
+ fd->compressed_bm_width);
+ GST_INFO_OBJECT (element, " valid_bm_height %d",
+ fd->valid_bm_height);
+ GST_INFO_OBJECT (element, " valid_bm_width %d", fd->valid_bm_width);
+ GST_INFO_OBJECT (element, " valid_bm_x_offset %d",
+ fd->valid_bm_x_offset);
+ GST_INFO_OBJECT (element, " valid_bm_y_offset %d",
+ fd->valid_bm_y_offset);
+ GST_INFO_OBJECT (element, " video_x_t_offset %d",
+ fd->video_x_t_offset);
+ GST_INFO_OBJECT (element, " video_y_start %d", fd->video_y_start);
+ }
+
+ gst_buffer_unref (buf);
+
+ *_vprp = vprp;
+
+ return TRUE;
+
+ /* ERRORS */
+too_small:
+ {
+ GST_ERROR_OBJECT (element,
+ "Too small vprp (%d available, at least %d needed)",
+ GST_BUFFER_SIZE (buf),
+ (int) G_STRUCT_OFFSET (gst_riff_vprp, field_info));
+ gst_buffer_unref (buf);
+ return FALSE;
+ }
+}
+
+/*
* gst_avi_demux_parse_stream:
* @avi: calling element (used for debugging/errors).
* @buf: input buffer used to parse the stream.
@@ -1223,7 +1344,8 @@ gst_avi_demux_parse_stream (GstAviDemux * avi, GstBuffer * buf)
GstCaps *caps = NULL;
GstPad *pad;
GstElement *element;
- gboolean got_strh = FALSE, got_strf = FALSE;
+ gboolean got_strh = FALSE, got_strf = FALSE, got_vprp = FALSE;
+ gst_riff_vprp *vprp = NULL;
element = GST_ELEMENT_CAST (avi);
@@ -1294,6 +1416,30 @@ gst_avi_demux_parse_stream (GstAviDemux * avi, GstBuffer * buf)
got_strf = TRUE;
break;
}
+ case GST_RIFF_TAG_vprp:
+ {
+ if (got_vprp) {
+ GST_WARNING_OBJECT (avi, "Ignoring additional vprp chunk");
+ break;
+ }
+ if (!got_strh) {
+ GST_ERROR_OBJECT (avi, "Found vprp chunk before strh chunk");
+ goto fail;
+ }
+ if (!got_strf) {
+ GST_ERROR_OBJECT (avi, "Found vprp chunk before strf chunk");
+ goto fail;
+ }
+
+ if (!gst_avi_demux_riff_parse_vprp (element, sub, &vprp)) {
+ GST_WARNING_OBJECT (avi, "Failed to parse vprp chunk");
+ /* not considered fatal */
+ g_free (vprp);
+ vprp = NULL;
+ } else
+ got_vprp = TRUE;
+ break;
+ }
case GST_RIFF_TAG_strd:
if (stream->initdata)
gst_buffer_unref (stream->initdata);
@@ -1362,6 +1508,21 @@ gst_avi_demux_parse_stream (GstAviDemux * avi, GstBuffer * buf)
if (!caps) {
caps = gst_caps_new_simple ("video/x-avi-unknown", "fourcc",
GST_TYPE_FOURCC, fourcc, NULL);
+ } else if (got_vprp && vprp) {
+ guint32 aspect_n, aspect_d;
+ gint n, d;
+
+ aspect_n = vprp->aspect >> 16;
+ aspect_d = vprp->aspect & 0xffff;
+ /* calculate the pixel aspect ratio using w/h and aspect ratio */
+ n = aspect_n * stream->strf.vids->height;
+ d = aspect_d * stream->strf.vids->width;
+ if (n && d)
+ gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
+ n, d, NULL);
+ /* very local, not needed elsewhere */
+ g_free (vprp);
+ vprp = NULL;
}
tag_name = GST_TAG_VIDEO_CODEC;
avi->num_v_streams++;
@@ -1483,6 +1644,7 @@ fail:
gst_buffer_unref (buf);
if (sub)
gst_buffer_unref (sub);
+ g_free (vprp);
g_free (codec_name);
g_free (stream->strh);
g_free (stream->strf.data);