GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-raw-yuv, "
- "format = (fourcc) I420, "
+ "format = (fourcc) { I420, YUY2, Y444 }, "
"framerate = (fraction) [0/1, MAX], "
"width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
);
case GST_FORMAT_BYTES:
switch (*dest_format) {
case GST_FORMAT_DEFAULT:
- *dest_value = gst_util_uint64_scale_int (src_value, 2,
- dec->info.height * dec->info.width * 3);
+ *dest_value = gst_util_uint64_scale_int (src_value, 8,
+ dec->info.height * dec->info.width * dec->output_bpp);
break;
case GST_FORMAT_TIME:
/* seems like a rather silly conversion, implement me if you like */
case GST_FORMAT_TIME:
switch (*dest_format) {
case GST_FORMAT_BYTES:
- scale = 3 * (dec->info.width * dec->info.height) / 2;
+ scale = dec->output_bpp * (dec->info.width * dec->info.height) / 8;
case GST_FORMAT_DEFAULT:
*dest_value = scale * gst_util_uint64_scale (src_value,
dec->info.fps_numerator, dec->info.fps_denominator * GST_SECOND);
break;
case GST_FORMAT_BYTES:
*dest_value = gst_util_uint64_scale_int (src_value,
- 3 * dec->info.width * dec->info.height, 2);
+ dec->output_bpp * dec->info.width * dec->info.height, 8);
break;
default:
res = FALSE;
GstFlowReturn ret = GST_FLOW_OK;
guint32 bitstream_version;
GList *walk;
+ guint32 fourcc;
GST_DEBUG_OBJECT (dec, "fps %d/%d, PAR %d/%d",
dec->info.fps_numerator, dec->info.fps_denominator,
GST_DEBUG_OBJECT (dec, "frame dimension %dx%d, offset %d:%d",
dec->info.frame_width, dec->info.frame_height,
dec->info.offset_x, dec->info.offset_y);
- if (dec->info.pixelformat != OC_PF_420) {
- GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
- (NULL), ("pixel formats other than 4:2:0 not yet supported"));
+ if (dec->info.pixelformat == OC_PF_420) {
+ dec->output_bpp = 12; /* Average bits per pixel. */
+ fourcc = GST_MAKE_FOURCC ('I', '4', '2', '0');
+ } else if (dec->info.pixelformat == OC_PF_422) {
+ dec->output_bpp = 16;
+ fourcc = GST_MAKE_FOURCC ('Y', 'U', 'Y', '2');
+ } else if (dec->info.pixelformat == OC_PF_444) {
+ dec->output_bpp = 24;
+ fourcc = GST_MAKE_FOURCC ('Y', '4', '4', '4');
+ } else {
+ GST_ERROR_OBJECT (dec, "Invalid pixel format %d", dec->info.pixelformat);
return GST_FLOW_ERROR;
}
theora_decode_init (&dec->state, &dec->info);
caps = gst_caps_new_simple ("video/x-raw-yuv",
- "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'),
+ "format", GST_TYPE_FOURCC, fourcc,
"framerate", GST_TYPE_FRACTION,
dec->info.fps_numerator, dec->info.fps_denominator,
"pixel-aspect-ratio", GST_TYPE_FRACTION, par_num, par_den,
}
static GstFlowReturn
-theora_handle_data_packet (GstTheoraDec * dec, ogg_packet * packet,
- GstClockTime outtime)
+theora_handle_420_image (GstTheoraDec * dec, yuv_buffer * yuv, GstBuffer ** out)
{
- /* normal data packet */
- yuv_buffer yuv;
- GstBuffer *out;
- guint i;
- gboolean keyframe;
+ gint width = dec->width;
+ gint height = dec->height;
+ gint cwidth = width / 2;
+ gint cheight = height / 2;
gint out_size;
gint stride_y, stride_uv;
- gint width, height;
- gint cwidth, cheight;
GstFlowReturn result;
-
- if (G_UNLIKELY (!dec->have_header))
- goto not_initialized;
-
- /* the second most significant bit of the first data byte is cleared
- * for keyframes. We can only check it if it's not a zero-length packet. */
- keyframe = packet->bytes && ((packet->packet[0] & 0x40) == 0);
- if (G_UNLIKELY (keyframe)) {
- GST_DEBUG_OBJECT (dec, "we have a keyframe");
- dec->need_keyframe = FALSE;
- } else if (G_UNLIKELY (dec->need_keyframe)) {
- goto dropping;
- }
-
- GST_DEBUG_OBJECT (dec, "parsing data packet");
-
- /* this does the decoding */
- if (G_UNLIKELY (theora_decode_packetin (&dec->state, packet)))
- goto decode_error;
-
- if (outtime != -1) {
- gboolean need_skip;
- GstClockTime qostime;
-
- /* qos needs to be done on running time */
- qostime = gst_segment_to_running_time (&dec->segment, GST_FORMAT_TIME,
- outtime);
-
- GST_OBJECT_LOCK (dec);
- /* check for QoS, don't perform the last steps of getting and
- * pushing the buffers that are known to be late. */
- /* FIXME, we can also entirely skip decoding if the next valid buffer is
- * known to be after a keyframe (using the granule_shift) */
- need_skip = dec->earliest_time != -1 && qostime <= dec->earliest_time;
- GST_OBJECT_UNLOCK (dec);
-
- if (need_skip)
- goto dropping_qos;
- }
-
- /* this does postprocessing and set up the decoded frame
- * pointers in our yuv variable */
- if (G_UNLIKELY (theora_decode_YUVout (&dec->state, &yuv) < 0))
- goto no_yuv;
-
- if (G_UNLIKELY ((yuv.y_width != dec->info.width)
- || (yuv.y_height != dec->info.height)))
- goto wrong_dimensions;
-
- width = dec->width;
- height = dec->height;
- cwidth = width / 2;
- cheight = height / 2;
+ int i;
/* should get the stride from the caps, for now we round up to the nearest
* multiple of 4 because some element needs it. chroma needs special
* frame_width, frame_height */
result =
gst_pad_alloc_buffer_and_set_caps (dec->srcpad, GST_BUFFER_OFFSET_NONE,
- out_size, GST_PAD_CAPS (dec->srcpad), &out);
+ out_size, GST_PAD_CAPS (dec->srcpad), out);
if (G_UNLIKELY (result != GST_FLOW_OK))
goto no_buffer;
guchar *dest_v, *src_v;
gint offset;
- dest_y = GST_BUFFER_DATA (out);
+ dest_y = GST_BUFFER_DATA (*out);
dest_u = dest_y + stride_y * GST_ROUND_UP_2 (height);
dest_v = dest_u + stride_uv * GST_ROUND_UP_2 (height) / 2;
GST_LOG_OBJECT (dec, "plane 1, offset %d", dest_u - dest_y);
GST_LOG_OBJECT (dec, "plane 2, offset %d", dest_v - dest_y);
- src_y = yuv.y + dec->offset_x + dec->offset_y * yuv.y_stride;
+ src_y = yuv->y + dec->offset_x + dec->offset_y * yuv->y_stride;
for (i = 0; i < height; i++) {
memcpy (dest_y, src_y, width);
dest_y += stride_y;
- src_y += yuv.y_stride;
+ src_y += yuv->y_stride;
}
- offset = dec->offset_x / 2 + dec->offset_y / 2 * yuv.uv_stride;
+ offset = dec->offset_x / 2 + dec->offset_y / 2 * yuv->uv_stride;
- src_u = yuv.u + offset;
- src_v = yuv.v + offset;
+ src_u = yuv->u + offset;
+ src_v = yuv->v + offset;
for (i = 0; i < cheight; i++) {
memcpy (dest_u, src_u, cwidth);
memcpy (dest_v, src_v, cwidth);
dest_u += stride_uv;
- src_u += yuv.uv_stride;
+ src_u += yuv->uv_stride;
dest_v += stride_uv;
- src_v += yuv.uv_stride;
+ src_v += yuv->uv_stride;
}
}
+no_buffer:
+ {
+ GST_DEBUG_OBJECT (dec, "could not get buffer, reason: %s",
+ gst_flow_get_name (result));
+ return result;
+ }
+}
+
+static GstFlowReturn
+theora_handle_data_packet (GstTheoraDec * dec, ogg_packet * packet,
+ GstClockTime outtime)
+{
+ /* normal data packet */
+ yuv_buffer yuv;
+ GstBuffer *out;
+ gboolean keyframe;
+ GstFlowReturn result;
+
+ if (G_UNLIKELY (!dec->have_header))
+ goto not_initialized;
+
+ /* the second most significant bit of the first data byte is cleared
+ * for keyframes. We can only check it if it's not a zero-length packet. */
+ keyframe = packet->bytes && ((packet->packet[0] & 0x40) == 0);
+ if (G_UNLIKELY (keyframe)) {
+ GST_DEBUG_OBJECT (dec, "we have a keyframe");
+ dec->need_keyframe = FALSE;
+ } else if (G_UNLIKELY (dec->need_keyframe)) {
+ goto dropping;
+ }
+
+ GST_DEBUG_OBJECT (dec, "parsing data packet");
+
+ /* this does the decoding */
+ if (G_UNLIKELY (theora_decode_packetin (&dec->state, packet)))
+ goto decode_error;
+
+ if (outtime != -1) {
+ gboolean need_skip;
+ GstClockTime qostime;
+
+ /* qos needs to be done on running time */
+ qostime = gst_segment_to_running_time (&dec->segment, GST_FORMAT_TIME,
+ outtime);
+
+ GST_OBJECT_LOCK (dec);
+ /* check for QoS, don't perform the last steps of getting and
+ * pushing the buffers that are known to be late. */
+ /* FIXME, we can also entirely skip decoding if the next valid buffer is
+ * known to be after a keyframe (using the granule_shift) */
+ need_skip = dec->earliest_time != -1 && qostime <= dec->earliest_time;
+ GST_OBJECT_UNLOCK (dec);
+
+ if (need_skip)
+ goto dropping_qos;
+ }
+
+ /* this does postprocessing and set up the decoded frame
+ * pointers in our yuv variable */
+ if (G_UNLIKELY (theora_decode_YUVout (&dec->state, &yuv) < 0))
+ goto no_yuv;
+
+ if (G_UNLIKELY ((yuv.y_width != dec->info.width)
+ || (yuv.y_height != dec->info.height)))
+ goto wrong_dimensions;
+
+ if (dec->info.pixelformat == OC_PF_420) {
+ result = theora_handle_420_image (dec, &yuv, &out);
+#if 0
+ } else if (dec->info.pixelformat == OC_PF_422) {
+ result = theora_handle_422_image (dec, &yuv, &out);
+ } else if (dec->info.pixelformat == OC_PF_444) {
+ result = theora_handle_444_image (dec, &yuv, &out);
+ } else {
+ g_assert_not_reached ();
+#endif
+ }
+
+ if (result != GST_FLOW_OK)
+ return result;
GST_BUFFER_OFFSET (out) = dec->frame_nr;
if (dec->frame_nr != -1)
(NULL), ("dimensions of image do not match header"));
return GST_FLOW_ERROR;
}
-no_buffer:
- {
- GST_DEBUG_OBJECT (dec, "could not get buffer, reason: %s",
- gst_flow_get_name (result));
- return result;
- }
}
static GstFlowReturn