From: Michael Smith Date: Tue, 28 Apr 2009 04:01:51 +0000 (-0700) Subject: theoradec: rearrange code in preparation for 422 and 444 support. X-Git-Tag: 1.19.3~511^2~9717 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=a91b7f0857ff4933eecd147f441cc097344d00e9;p=platform%2Fupstream%2Fgstreamer.git theoradec: rearrange code in preparation for 422 and 444 support. --- diff --git a/ext/theora/gsttheoradec.h b/ext/theora/gsttheoradec.h index 30646ef..ed7b722 100644 --- a/ext/theora/gsttheoradec.h +++ b/ext/theora/gsttheoradec.h @@ -72,6 +72,7 @@ struct _GstTheoraDec gboolean need_keyframe; gint width, height; gint offset_x, offset_y; + gint output_bpp; gboolean crop; diff --git a/ext/theora/theoradec.c b/ext/theora/theoradec.c index 78b5e08..64b07fb 100644 --- a/ext/theora/theoradec.c +++ b/ext/theora/theoradec.c @@ -66,7 +66,7 @@ GST_STATIC_PAD_TEMPLATE ("src", 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 ]") ); @@ -346,8 +346,8 @@ theora_dec_src_convert (GstPad * pad, 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 */ @@ -358,7 +358,7 @@ theora_dec_src_convert (GstPad * pad, 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); @@ -375,7 +375,7 @@ theora_dec_src_convert (GstPad * pad, 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; @@ -853,6 +853,7 @@ theora_handle_type_packet (GstTheoraDec * dec, ogg_packet * packet) 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, @@ -888,10 +889,18 @@ theora_handle_type_packet (GstTheoraDec * dec, ogg_packet * packet) 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; } @@ -931,7 +940,7 @@ theora_handle_type_packet (GstTheoraDec * dec, ogg_packet * packet) 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, @@ -1107,72 +1116,16 @@ theora_dec_push_reverse (GstTheoraDec * dec, GstBuffer * buf) } 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 @@ -1187,7 +1140,7 @@ theora_handle_data_packet (GstTheoraDec * dec, ogg_packet * packet, * 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; @@ -1204,7 +1157,7 @@ theora_handle_data_packet (GstTheoraDec * dec, ogg_packet * packet, 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; @@ -1212,30 +1165,110 @@ theora_handle_data_packet (GstTheoraDec * dec, ogg_packet * packet, 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) @@ -1299,12 +1332,6 @@ wrong_dimensions: (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