diff options
Diffstat (limited to 'ext/xvid/gstxviddec.c')
-rw-r--r-- | ext/xvid/gstxviddec.c | 260 |
1 files changed, 129 insertions, 131 deletions
diff --git a/ext/xvid/gstxviddec.c b/ext/xvid/gstxviddec.c index 84af838d..37abbed5 100644 --- a/ext/xvid/gstxviddec.c +++ b/ext/xvid/gstxviddec.c @@ -22,14 +22,16 @@ #endif #include <string.h> -#include "gstxviddec.h" +#include <xvid.h> + #include <gst/video/video.h> +#include "gstxviddec.h" /* elementfactory information */ GstElementDetails gst_xviddec_details = { "Xvid decoder", "Codec/Video/Decoder", - "Xvid decoder based on xviddecore", + "Xvid decoder based on xvidcore", "Ronald Bultje <rbultje@ronald.bitfreak.net>", }; @@ -53,7 +55,11 @@ GST_STATIC_PAD_TEMPLATE ( GST_PAD_ALWAYS, GST_STATIC_CAPS ( GST_VIDEO_YUV_PAD_TEMPLATE_CAPS ("{ I420, YUY2, YV12, YVYU, UYVY }") "; " - GST_VIDEO_RGB_PAD_TEMPLATE_CAPS_24_32 "; " + RGB_24_32_STATIC_CAPS (32, 0x00ff0000, 0x0000ff00, 0x000000ff) "; " + RGB_24_32_STATIC_CAPS (32, 0xff000000, 0x00ff0000, 0x0000ff00) "; " + RGB_24_32_STATIC_CAPS (32, 0x0000ff00, 0x00ff0000, 0xff000000) "; " + RGB_24_32_STATIC_CAPS (32, 0x000000ff, 0x0000ff00, 0x00ff0000) "; " + RGB_24_32_STATIC_CAPS (24, 0x0000ff, 0x00ff00, 0xff0000) "; " GST_VIDEO_RGB_PAD_TEMPLATE_CAPS_15_16 ) ); @@ -70,15 +76,20 @@ enum { /* FILL ME */ }; -static void gst_xviddec_base_init (gpointer g_class); -static void gst_xviddec_class_init (GstXvidDecClass *klass); -static void gst_xviddec_init (GstXvidDec *xviddec); -static void gst_xviddec_dispose (GObject *object); -static void gst_xviddec_chain (GstPad *pad, - GstData *data); -static GstPadLinkReturn gst_xviddec_link (GstPad *pad, - const GstCaps *vscapslist); -static GstPadLinkReturn gst_xviddec_negotiate (GstXvidDec *xviddec); +static void gst_xviddec_base_init (gpointer g_class); +static void gst_xviddec_class_init (GstXvidDecClass *klass); +static void gst_xviddec_init (GstXvidDec *xviddec); +static void gst_xviddec_chain (GstPad *pad, + GstData *data); +static GstPadLinkReturn + gst_xviddec_sink_link (GstPad *pad, + const GstCaps *vscapslist); +static GstPadLinkReturn + gst_xviddec_src_link (GstPad *pad, + const GstCaps *vscapslist); +static GstElementStateReturn + gst_xviddec_change_state (GstElement *element); + static GstElementClass *parent_class = NULL; /* static guint gst_xviddec_signals[LAST_SIGNAL] = { 0 }; */ @@ -125,19 +136,19 @@ gst_xviddec_base_init (gpointer g_class) static void gst_xviddec_class_init (GstXvidDecClass *klass) { - GObjectClass *gobject_class = (GObjectClass *) klass; - - gst_xvid_init(); + GstElementClass *gstelement_class = (GstElementClass *) klass; parent_class = g_type_class_ref(GST_TYPE_ELEMENT); - gobject_class->dispose = gst_xviddec_dispose; + gstelement_class->change_state = gst_xviddec_change_state; } static void gst_xviddec_init (GstXvidDec *xviddec) { + gst_xvid_init(); + /* create the sink pad */ xviddec->sinkpad = gst_pad_new_from_template( gst_static_pad_template_get (&sink_template), @@ -145,7 +156,7 @@ gst_xviddec_init (GstXvidDec *xviddec) gst_element_add_pad(GST_ELEMENT(xviddec), xviddec->sinkpad); gst_pad_set_chain_function(xviddec->sinkpad, gst_xviddec_chain); - gst_pad_set_link_function(xviddec->sinkpad, gst_xviddec_link); + gst_pad_set_link_function(xviddec->sinkpad, gst_xviddec_sink_link); /* create the src pad */ xviddec->srcpad = gst_pad_new_from_template( @@ -153,7 +164,9 @@ gst_xviddec_init (GstXvidDec *xviddec) "src"); gst_element_add_pad(GST_ELEMENT(xviddec), xviddec->srcpad); - /* bitrate, etc. */ + gst_pad_set_link_function(xviddec->srcpad, gst_xviddec_src_link); + + /* size, etc. */ xviddec->width = xviddec->height = xviddec->csp = -1; /* set xvid handle to NULL */ @@ -173,16 +186,17 @@ gst_xviddec_unset (GstXvidDec *xviddec) static gboolean gst_xviddec_setup (GstXvidDec *xviddec) { - XVID_DEC_PARAM xdec; + xvid_dec_create_t xdec; int ret; /* initialise parameters, see xvid documentation */ - memset(&xdec, 0, sizeof(XVID_DEC_PARAM)); + gst_xvid_init_struct (xdec); xdec.width = xviddec->width; xdec.height = xviddec->height; + xdec.handle = NULL; if ((ret = xvid_decore(NULL, XVID_DEC_CREATE, - &xdec, NULL)) != XVID_ERR_OK) { + &xdec, NULL)) < 0) { gst_element_error(GST_ELEMENT(xviddec), "Setting parameters %dx%d@%d failed: %s (%d)", xviddec->width, xviddec->height, xviddec->csp, @@ -197,60 +211,59 @@ gst_xviddec_setup (GstXvidDec *xviddec) static void -gst_xviddec_dispose (GObject *object) -{ - GstXvidDec *xviddec = GST_XVIDDEC(object); - - gst_xviddec_unset(xviddec); -} - - -static void gst_xviddec_chain (GstPad *pad, GstData *_data) { GstBuffer *buf = GST_BUFFER (_data); - GstXvidDec *xviddec; + GstXvidDec *xviddec = GST_XVIDDEC(GST_OBJECT_PARENT(pad)); GstBuffer *outbuf; - XVID_DEC_FRAME xframe; + xvid_dec_frame_t xframe; int ret; g_return_if_fail(pad != NULL); g_return_if_fail(GST_IS_PAD(pad)); - g_return_if_fail(buf != NULL); - - xviddec = GST_XVIDDEC(GST_OBJECT_PARENT(pad)); if (!xviddec->handle) { - if (!gst_xviddec_negotiate(xviddec)) { - gst_element_error(GST_ELEMENT(xviddec), - "No format set - aborting"); - gst_buffer_unref(buf); - return; - } + gst_element_error(GST_ELEMENT(xviddec), + "No format set - aborting"); + gst_buffer_unref(buf); + return; } outbuf = gst_buffer_new_and_alloc(xviddec->width * xviddec->height * xviddec->bpp / 8); GST_BUFFER_TIMESTAMP(outbuf) = GST_BUFFER_TIMESTAMP(buf); + GST_BUFFER_DURATION(outbuf) = GST_BUFFER_DURATION(buf); GST_BUFFER_SIZE(outbuf) = xviddec->width * xviddec->height * xviddec->bpp / 8; - /* encode and so ... */ + /* decode and so ... */ + gst_xvid_init_struct (xframe); + xframe.general = 0; xframe.bitstream = (void *) GST_BUFFER_DATA(buf); - xframe.image = (void *) GST_BUFFER_DATA(outbuf); xframe.length = GST_BUFFER_SIZE(buf); - xframe.stride = 0; /*xviddec->width * xviddec->bpp / 8;*/ - xframe.colorspace = xviddec->csp; + xframe.output.csp = xviddec->csp; + if (xviddec->width == xviddec->stride) { + xframe.output.plane[0] = GST_BUFFER_DATA(outbuf); + xframe.output.plane[1] = xframe.output.plane[0] + (xviddec->width * xviddec->height); + xframe.output.plane[2] = xframe.output.plane[1] + (xviddec->width * xviddec->height / 4); + xframe.output.stride[0] = xviddec->width; + xframe.output.stride[1] = xviddec->width / 2; + xframe.output.stride[2] = xviddec->width / 2; + } else { + xframe.output.plane[0] = GST_BUFFER_DATA(outbuf); + xframe.output.stride[0] = xviddec->stride; + } if ((ret = xvid_decore(xviddec->handle, XVID_DEC_DECODE, - &xframe, NULL))) { + &xframe, NULL)) < 0) { gst_element_error(GST_ELEMENT(xviddec), "Error decoding xvid frame: %s (%d)\n", gst_xvid_error(ret), ret); gst_buffer_unref(buf); + gst_buffer_unref(outbuf); return; } @@ -258,112 +271,97 @@ gst_xviddec_chain (GstPad *pad, gst_buffer_unref(buf); } +/* + * This function allows multiple structures because it + * can be called from sink_link(). + */ static GstPadLinkReturn -gst_xviddec_negotiate (GstXvidDec *xviddec) +gst_xviddec_src_link (GstPad *pad, + const GstCaps *vscaps) { - GstPadLinkReturn ret; - GstCaps *caps; - struct { - guint32 fourcc; - gint depth, bpp; - gint csp; - } fmt_list[] = { - { GST_MAKE_FOURCC('Y','U','Y','V'), 16, 16, XVID_CSP_YUY2 }, - { GST_MAKE_FOURCC('U','Y','V','Y'), 16, 16, XVID_CSP_UYVY }, - { GST_MAKE_FOURCC('Y','V','Y','U'), 16, 16, XVID_CSP_YVYU }, - { GST_MAKE_FOURCC('Y','V','1','2'), 12, 12, XVID_CSP_YV12 }, - { GST_MAKE_FOURCC('I','4','2','0'), 12, 12, XVID_CSP_I420 }, - { GST_MAKE_FOURCC('R','G','B',' '), 32, 32, XVID_CSP_RGB32 }, - { GST_MAKE_FOURCC('R','G','B',' '), 24, 24, XVID_CSP_RGB24 }, - { GST_MAKE_FOURCC('R','G','B',' '), 16, 16, XVID_CSP_RGB555 }, - { GST_MAKE_FOURCC('R','G','B',' '), 15, 16, XVID_CSP_RGB565 }, - { 0, 0, 0 } - }; - gint i; - - for (i = 0; fmt_list[i].fourcc != 0; i++) { - xviddec->csp = fmt_list[i].csp; - - /* try making a caps to set on the other side */ - if (fmt_list[i].fourcc == GST_MAKE_FOURCC('R','G','B',' ')) { - guint32 r_mask = 0, b_mask = 0, g_mask = 0; - gint endianness = 0; - switch (fmt_list[i].depth) { - case 15: - endianness = G_BYTE_ORDER; - r_mask = 0xf800; g_mask = 0x07c0; b_mask = 0x003e; - break; - case 16: - endianness = G_BYTE_ORDER; - r_mask = R_MASK_16_INT; g_mask = G_MASK_16_INT; b_mask = B_MASK_16_INT; - break; - case 24: - endianness = G_BIG_ENDIAN; - r_mask = R_MASK_24_INT; g_mask = G_MASK_24_INT; b_mask = B_MASK_24_INT; - break; - case 32: - endianness = G_BIG_ENDIAN; - r_mask = R_MASK_32_INT; g_mask = G_MASK_32_INT; b_mask = B_MASK_32_INT; - break; - } - caps = gst_caps_new_simple ( - "video/x-raw-rgb", - "width", G_TYPE_INT, xviddec->width, - "height", G_TYPE_INT, xviddec->height, - "depth", G_TYPE_INT, fmt_list[i].depth, - "bpp", G_TYPE_INT, fmt_list[i].bpp, - "endianness", G_TYPE_INT, endianness, - "red_mask", G_TYPE_INT, r_mask, - "green_mask", G_TYPE_INT, g_mask, - "blue_mask", G_TYPE_INT, b_mask, - "framerate", G_TYPE_DOUBLE, xviddec->fps, - NULL); - } else { - caps = gst_caps_new_simple ( - "video/x-raw-yuv", - "width", G_TYPE_INT, xviddec->width, - "height", G_TYPE_INT, xviddec->height, - "format", GST_TYPE_FOURCC, fmt_list[i].fourcc, - "framerate", G_TYPE_DOUBLE, xviddec->fps, - NULL); - } + GstXvidDec *xviddec = GST_XVIDDEC(gst_pad_get_parent (pad)); + GstStructure *structure = gst_caps_get_structure (vscaps, 0); - if ((ret = gst_pad_try_set_caps(xviddec->srcpad, caps)) > 0) { - xviddec->csp = fmt_list[i].csp; - xviddec->bpp = fmt_list[i].bpp; - if (gst_xviddec_setup(xviddec)) - return GST_PAD_LINK_OK; - } else if (ret == GST_PAD_LINK_DELAYED) { - return ret; /* don't try further (yet) */ - } + if (!GST_PAD_CAPS (xviddec->sinkpad)) + return GST_PAD_LINK_DELAYED; + + /* if there's something old around, remove it */ + if (xviddec->handle) { + gst_xviddec_unset(xviddec); } - /* if we got here - it's not good */ - return GST_PAD_LINK_REFUSED; -} + xviddec->csp = gst_xvid_structure_to_csp (structure, xviddec->width, + &xviddec->stride, + &xviddec->bpp); + + if (xviddec->csp < 0) + return GST_PAD_LINK_REFUSED; + if (!gst_xviddec_setup(xviddec)) + return GST_PAD_LINK_REFUSED;; + + return GST_PAD_LINK_OK; +} static GstPadLinkReturn -gst_xviddec_link (GstPad *pad, - const GstCaps *vscaps) +gst_xviddec_sink_link (GstPad *pad, + const GstCaps *vscaps) { - GstXvidDec *xviddec; + GstXvidDec *xviddec = GST_XVIDDEC(gst_pad_get_parent (pad)); GstStructure *structure; - xviddec = GST_XVIDDEC(gst_pad_get_parent (pad)); - /* if there's something old around, remove it */ if (xviddec->handle) { gst_xviddec_unset(xviddec); } /* if we get here, we know the input is xvid. we - * only need to bother with the output colorspace */ + * only need to bother with the output colorspace, + * which the src_link function takes care of. */ structure = gst_caps_get_structure (vscaps, 0); gst_structure_get_int(structure, "width", &xviddec->width); gst_structure_get_int(structure, "height", &xviddec->height); gst_structure_get_double(structure, "framerate", &xviddec->fps); - return gst_xviddec_negotiate(xviddec); + /* re-nego? or just await src nego? */ + if (GST_PAD_CAPS(xviddec->srcpad)) { + GstPadLinkReturn ret; + GstCaps *vscaps = gst_pad_get_caps (GST_PAD_PEER (xviddec->srcpad)), *new; + gint i, csp; + + for (i = 0; i < gst_caps_get_size (vscaps); i++) { + csp = gst_xvid_structure_to_csp (gst_caps_get_structure (vscaps, i), + 0, NULL, NULL); + new = gst_xvid_csp_to_caps (csp, xviddec->width, xviddec->height, xviddec->fps); + ret = gst_pad_try_set_caps(xviddec->srcpad, new); + if (ret != GST_PAD_LINK_REFUSED) + return ret; + } + + return GST_PAD_LINK_REFUSED; + } + + return GST_PAD_LINK_OK; +} + +static GstElementStateReturn +gst_xviddec_change_state (GstElement *element) +{ + GstXvidDec *xviddec = GST_XVIDDEC (element); + + switch (GST_STATE_PENDING (element)) { + case GST_STATE_PAUSED_TO_READY: + if (xviddec->handle) { + gst_xviddec_unset (xviddec); + } + break; + default: + break; + } + + if (parent_class->change_state) + return parent_class->change_state (element); + + return GST_STATE_SUCCESS; } |