diff options
Diffstat (limited to 'ext')
-rw-r--r-- | ext/xvid/gstxvid.c | 225 | ||||
-rw-r--r-- | ext/xvid/gstxvid.h | 32 | ||||
-rw-r--r-- | ext/xvid/gstxviddec.c | 260 | ||||
-rw-r--r-- | ext/xvid/gstxviddec.h | 3 | ||||
-rw-r--r-- | ext/xvid/gstxvidenc.c | 320 | ||||
-rw-r--r-- | ext/xvid/gstxvidenc.h | 16 |
6 files changed, 567 insertions, 289 deletions
diff --git a/ext/xvid/gstxvid.c b/ext/xvid/gstxvid.c index 4ed5733c..64ab2f56 100644 --- a/ext/xvid/gstxvid.c +++ b/ext/xvid/gstxvid.c @@ -1,4 +1,4 @@ -/* GStreamer xvid decoder plugin +/* GStreamer xvid encoder/decoder plugin * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net> * * This library is free software; you can redistribute it and/or @@ -22,14 +22,16 @@ #endif #include <string.h> +#include <xvid.h> +#include <gst/video/video.h> #include "gstxviddec.h" #include "gstxvidenc.h" gboolean gst_xvid_init (void) { - XVID_INIT_PARAM xinit; + xvid_gbl_init_t xinit; gint ret; static gboolean is_init = FALSE; @@ -39,20 +41,18 @@ gst_xvid_init (void) } /* set up xvid initially (function pointers, CPU flags) */ - memset(&xinit, 0, sizeof(XVID_INIT_PARAM)); - xinit.cpu_flags = 0; - if ((ret = xvid_init(NULL, 0, &xinit, NULL)) != XVID_ERR_OK) { + gst_xvid_init_struct (xinit); + if ((ret = xvid_global(NULL, XVID_GBL_INIT, &xinit, NULL)) < 0) { g_warning("Failed to initialize XviD: %s (%d)", gst_xvid_error(ret), ret); return FALSE; } - - if (xinit.api_version != API_VERSION) { - g_warning("Xvid API version mismatch! %d.%d (that's us) != %d.%d (lib)", - (API_VERSION >> 8) & 0xff, API_VERSION & 0xff, - (xinit.api_version >> 8) & 0xff, xinit.api_version & 0xff); - return FALSE; - } + + GST_LOG ("Initted XviD version %d.%d.%d (API %d.%d)", + XVID_VERSION_MAJOR (XVID_VERSION), + XVID_VERSION_MINOR (XVID_VERSION), + XVID_VERSION_PATCH (XVID_VERSION), + XVID_API_MAJOR (XVID_API), XVID_API_MINOR (XVID_API)); is_init = TRUE; return TRUE; @@ -67,14 +67,17 @@ gst_xvid_error (int errorcode) case XVID_ERR_FAIL: error = "Operation failed"; break; - case XVID_ERR_OK: + case 0: error = "No error"; break; case XVID_ERR_MEMORY: - error = "Memory error"; + error = "Memory allocation error"; break; case XVID_ERR_FORMAT: - error = "Invalid format"; + error = "File format not supported"; + break; + case XVID_ERR_VERSION: + error = "Structure version not supported"; break; default: error = "Unknown error"; @@ -84,6 +87,193 @@ gst_xvid_error (int errorcode) return error; } +gint +gst_xvid_structure_to_csp (GstStructure *structure, + gint w, gint *_stride, gint *_bpp) +{ + const gchar *mime = gst_structure_get_name (structure); + gint xvid_cs = -1, stride = -1, bpp = -1; + + if (!strcmp (mime, "video/x-raw-yuv")) { + guint32 fourcc; + + gst_structure_get_fourcc (structure, "format", &fourcc); + switch (fourcc) { + case GST_MAKE_FOURCC('I','4','2','0'): + xvid_cs = XVID_CSP_I420; + stride = w; + bpp = 12; + break; + case GST_MAKE_FOURCC('Y','U','Y','2'): + xvid_cs = XVID_CSP_YUY2; + stride = w * 2; + bpp = 16; + break; + case GST_MAKE_FOURCC('Y','V','1','2'): + xvid_cs = XVID_CSP_YV12; + stride = w; + bpp = 12; + break; + case GST_MAKE_FOURCC('U','Y','V','Y'): + xvid_cs = XVID_CSP_UYVY; + stride = w * 2; + bpp = 16; + break; + case GST_MAKE_FOURCC('Y','V','Y','U'): + xvid_cs = XVID_CSP_YVYU; + stride = w * 2; + bpp = 16; + break; + } + } else { + gint depth, r_mask; + + gst_structure_get_int(structure, "depth", &depth); + gst_structure_get_int(structure, "bpp", &bpp); + gst_structure_get_int(structure, "red_mask", &r_mask); + + switch (depth) { + case 15: + xvid_cs = XVID_CSP_RGB555; + break; + case 16: + xvid_cs = XVID_CSP_RGB565; + break; + case 24: + if (bpp == 24) { + xvid_cs = XVID_CSP_BGR; + } else { + switch (r_mask) { + case 0xff000000: + xvid_cs = XVID_CSP_RGBA; + break; + case 0x00ff0000: + xvid_cs = XVID_CSP_ARGB; + break; + case 0x0000ff00: + xvid_cs = XVID_CSP_BGRA; + break; + case 0x000000ff: + xvid_cs = XVID_CSP_ABGR; + break; + } + } + break; + default: + break; + } + + stride = w * bpp / 8; + } + + if (_stride) + *_stride = stride; + if (_bpp) + *_bpp = bpp; + + return xvid_cs; +} + +GstCaps * +gst_xvid_csp_to_caps (gint csp, gint w, gint h, gdouble fps) +{ + GstCaps *caps = NULL; + + switch (csp) { + case XVID_CSP_RGB555: + case XVID_CSP_RGB565: + case XVID_CSP_BGR: + case XVID_CSP_ABGR: + case XVID_CSP_BGRA: + case XVID_CSP_ARGB: + case XVID_CSP_RGBA: { + gint r_mask = 0, b_mask = 0, g_mask = 0, + endianness = 0, bpp = 0, depth = 0; + + switch (csp) { + case XVID_CSP_RGB555: + r_mask = R_MASK_15_INT; g_mask = G_MASK_15_INT; b_mask = B_MASK_15_INT; + endianness = G_BYTE_ORDER; depth = 15; bpp = 16; + break; + case XVID_CSP_RGB565: + r_mask = R_MASK_16_INT; g_mask = G_MASK_16_INT; b_mask = B_MASK_16_INT; + endianness = G_BYTE_ORDER; depth = 16; bpp = 16; + break; + case XVID_CSP_BGR: + r_mask = 0x0000ff; g_mask = 0x00ff00; b_mask = 0xff0000; + endianness = G_BIG_ENDIAN; depth = 24; bpp = 24; + break; + case XVID_CSP_ABGR: + r_mask = 0x000000ff; g_mask = 0x0000ff00; b_mask = 0x00ff0000; + endianness = G_BIG_ENDIAN; depth = 24; bpp = 32; + break; + case XVID_CSP_BGRA: + r_mask = 0x0000ff00; g_mask = 0x00ff0000; b_mask = 0xff000000; + endianness = G_BIG_ENDIAN; depth = 24; bpp = 32; + break; + case XVID_CSP_ARGB: + r_mask = 0x00ff0000; g_mask = 0x0000ff00; b_mask = 0x000000ff; + endianness = G_BIG_ENDIAN; depth = 24; bpp = 32; + break; + case XVID_CSP_RGBA: + r_mask = 0xff000000; g_mask = 0x00ff0000; b_mask = 0x0000ff00; + endianness = G_BIG_ENDIAN; depth = 24; bpp = 32; + break; + } + + caps = gst_caps_new_simple ("video/x-raw-rgb", + "width", G_TYPE_INT, w, + "height", G_TYPE_INT, h, + "depth", G_TYPE_INT, depth, + "bpp", G_TYPE_INT, 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, fps, + NULL); + break; + } + + case XVID_CSP_YUY2: + case XVID_CSP_YVYU: + case XVID_CSP_UYVY: + case XVID_CSP_I420: + case XVID_CSP_YV12: { + guint32 fourcc = 0; + + switch (csp) { + case XVID_CSP_YUY2: + fourcc = GST_MAKE_FOURCC ('Y','U','Y','2'); + break; + case XVID_CSP_YVYU: + fourcc = GST_MAKE_FOURCC ('Y','V','Y','U'); + break; + case XVID_CSP_UYVY: + fourcc = GST_MAKE_FOURCC ('U','Y','V','Y'); + break; + case XVID_CSP_I420: + fourcc = GST_MAKE_FOURCC ('I','4','2','0'); + break; + case XVID_CSP_YV12: + fourcc = GST_MAKE_FOURCC ('Y','V','1','2'); + break; + } + + caps = gst_caps_new_simple ("video/x-raw-yuv", + "width", G_TYPE_INT, w, + "height", G_TYPE_INT, h, + "format", GST_TYPE_FOURCC, fourcc, + "framerate", G_TYPE_DOUBLE, fps, + NULL); + break; + } + } + + return caps; +} + + static gboolean plugin_init (GstPlugin *plugin) { @@ -97,9 +287,10 @@ GST_PLUGIN_DEFINE ( GST_VERSION_MAJOR, GST_VERSION_MINOR, "xvid", - "XVid plugin library", + "XviD plugin library", plugin_init, VERSION, "GPL", GST_PACKAGE, - GST_ORIGIN) + GST_ORIGIN +) diff --git a/ext/xvid/gstxvid.h b/ext/xvid/gstxvid.h index 6e444f5f..100f93b8 100644 --- a/ext/xvid/gstxvid.h +++ b/ext/xvid/gstxvid.h @@ -1,4 +1,4 @@ -/* GStreamer xvid decoder plugin +/* GStreamer xvid encoder/decoder plugin * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net> * * This library is free software; you can redistribute it and/or @@ -22,15 +22,33 @@ #include <gst/gst.h> -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ +G_BEGIN_DECLS + +#define gst_xvid_init_struct(s) \ + do { \ + memset (&s, 0, sizeof(s)); \ + s.version = XVID_VERSION; \ + } while (0); + +#define RGB_24_32_STATIC_CAPS(bpp, r_mask,g_mask,b_mask) \ + "video/x-raw-rgb, " \ + "width = (int) [ 0, MAX ], " \ + "height = (int) [ 0, MAX], " \ + "framerate = (double) [ 0.0, MAX], " \ + "depth = (int) 24, " \ + "bpp = (int) " G_STRINGIFY (bpp) ", " \ + "endianness = (int) BIG_ENDIAN, " \ + "red_mask = (int) " G_STRINGIFY (r_mask) ", " \ + "green_mask = (int) " G_STRINGIFY (g_mask) ", " \ + "blue_mask = (int) " G_STRINGIFY (b_mask) extern gchar * gst_xvid_error (int errorcode); extern gboolean gst_xvid_init (void); -#ifdef __cplusplus -} -#endif /* __cplusplus */ +extern gint gst_xvid_structure_to_csp (GstStructure *structure, + gint w, gint *stride, gint *bpp); +extern GstCaps *gst_xvid_csp_to_caps (gint csp, gint w, gint h, gdouble fps); + +G_END_DECLS #endif /* __GST_XVID_H__ */ 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; } diff --git a/ext/xvid/gstxviddec.h b/ext/xvid/gstxviddec.h index a614bd81..fa90d06a 100644 --- a/ext/xvid/gstxviddec.h +++ b/ext/xvid/gstxviddec.h @@ -21,7 +21,6 @@ #define __GST_XVIDDEC_H__ #include <gst/gst.h> -#include <xvid.h> #include "gstxvid.h" #ifdef __cplusplus @@ -53,7 +52,7 @@ struct _GstXvidDec { void *handle; /* video (output) settings */ - gint csp, bpp; + gint csp, bpp, stride; gint width, height; double fps; }; diff --git a/ext/xvid/gstxvidenc.c b/ext/xvid/gstxvidenc.c index ce2e71e9..72ec9d78 100644 --- a/ext/xvid/gstxvidenc.c +++ b/ext/xvid/gstxvidenc.c @@ -22,15 +22,17 @@ #endif #include <string.h> -#include "gstxvidenc.h" -#include <gst/video/video.h> + #include <xvid.h> +#include <gst/video/video.h> +#include "gstxvidenc.h" + /* elementfactory information */ GstElementDetails gst_xvidenc_details = { "Xvid encoder", "Codec/Video/Encoder", - "Xvid encoder based on xvidencore", + "Xvid encoder based on xvidcore", "Ronald Bultje <rbultje@ronald.bitfreak.net>", }; @@ -41,7 +43,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 ) ); @@ -68,32 +74,75 @@ enum { enum { ARG_0, + ARG_PROFILE, ARG_BITRATE, ARG_MAXKEYINTERVAL, ARG_BUFSIZE + /* FILL ME: + * - ME + * - VOP + * - VOL + * - PAR + * - max b frames + */ }; -static void gst_xvidenc_base_init (gpointer g_class); -static void gst_xvidenc_class_init (GstXvidEncClass *klass); -static void gst_xvidenc_init (GstXvidEnc *xvidenc); -static void gst_xvidenc_chain (GstPad *pad, - GstData *data); -static GstPadLinkReturn gst_xvidenc_link (GstPad *pad, - const GstCaps *vscapslist); +static void gst_xvidenc_base_init (gpointer g_class); +static void gst_xvidenc_class_init (GstXvidEncClass *klass); +static void gst_xvidenc_init (GstXvidEnc *xvidenc); +static void gst_xvidenc_chain (GstPad *pad, + GstData *data); +static GstPadLinkReturn + gst_xvidenc_link (GstPad *pad, + const GstCaps *vscapslist); /* properties */ -static void gst_xvidenc_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); -static void gst_xvidenc_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); +static void gst_xvidenc_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void gst_xvidenc_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static GstElementStateReturn + gst_xvidenc_change_state (GstElement *element); static GstElementClass *parent_class = NULL; static guint gst_xvidenc_signals[LAST_SIGNAL] = { 0 }; +#define GST_TYPE_XVIDENC_PROFILE (gst_xvidenc_profile_get_type ()) + +static GType +gst_xvidenc_profile_get_type (void) +{ + static GType xvidenc_profile_type = 0; + + if (!xvidenc_profile_type) { + static const GEnumValue xvidenc_profiles[] = { + { XVID_PROFILE_S_L0, "S_L0", "Simple profile, L0" }, + { XVID_PROFILE_S_L1, "S_L1", "Simple profile, L1" }, + { XVID_PROFILE_S_L2, "S_L2", "Simple profile, L2" }, + { XVID_PROFILE_S_L3, "S_L3", "Simple profile, L3" }, + { XVID_PROFILE_ARTS_L1, "ARTS_L1", "Advanced real-time simple profile, L1" }, + { XVID_PROFILE_ARTS_L2, "ARTS_L2", "Advanced real-time simple profile, L2" }, + { XVID_PROFILE_ARTS_L3, "ARTS_L3", "Advanced real-time simple profile, L3" }, + { XVID_PROFILE_ARTS_L4, "ARTS_L4", "Advanced real-time simple profile, L4" }, + { XVID_PROFILE_AS_L0, "AS_L0", "Advanced simple profile, L0" }, + { XVID_PROFILE_AS_L1, "AS_L1", "Advanced simple profile, L1" }, + { XVID_PROFILE_AS_L2, "AS_L2", "Advanced simple profile, L2" }, + { XVID_PROFILE_AS_L3, "AS_L3", "Advanced simple profile, L3" }, + { XVID_PROFILE_AS_L4, "AS_L4", "Advanced simple profile, L4" }, + { 0, NULL, NULL }, + }; + + xvidenc_profile_type = + g_enum_register_static ("GstXvidEncProfiles", + xvidenc_profiles); + } + + return xvidenc_profile_type; +} GType gst_xvidenc_get_type(void) @@ -125,8 +174,10 @@ gst_xvidenc_base_init (gpointer g_class) { GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&sink_template)); - gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&src_template)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&sink_template)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&src_template)); gst_element_class_set_details (element_class, &gst_xvidenc_details); } @@ -136,30 +187,37 @@ gst_xvidenc_class_init (GstXvidEncClass *klass) GstElementClass *gstelement_class; GObjectClass *gobject_class; - gst_xvid_init(); - gobject_class = (GObjectClass *) klass; gstelement_class = (GstElementClass *) klass; parent_class = g_type_class_ref(GST_TYPE_ELEMENT); - g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BITRATE, - g_param_spec_ulong("bitrate","Bitrate", - "Target video bitrate", - 0,G_MAXULONG,0,G_PARAM_READWRITE)); + /* encoding profile */ + g_object_class_install_property(gobject_class, ARG_PROFILE, + g_param_spec_enum("profile", "Profile", "XviD/MPEG-4 encoding profile", + GST_TYPE_XVIDENC_PROFILE, XVID_PROFILE_S_L0, + G_PARAM_READWRITE)); + + /* bitrate */ + g_object_class_install_property(gobject_class, ARG_BITRATE, + g_param_spec_int("bitrate","Bitrate", + "Target video bitrate (kbps)", + 0,G_MAXINT,512,G_PARAM_READWRITE)); - g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_MAXKEYINTERVAL, + /* keyframe interval */ + g_object_class_install_property(gobject_class, ARG_MAXKEYINTERVAL, g_param_spec_int("max_key_interval","Max. Key Interval", "Maximum number of frames between two keyframes", 0,G_MAXINT,0,G_PARAM_READWRITE)); - g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BUFSIZE, + g_object_class_install_property(gobject_class, ARG_BUFSIZE, g_param_spec_ulong("buffer_size", "Buffer Size", "Size of the video buffers", 0,G_MAXULONG,0,G_PARAM_READWRITE)); gobject_class->set_property = gst_xvidenc_set_property; gobject_class->get_property = gst_xvidenc_get_property; + gstelement_class->change_state = gst_xvidenc_change_state; gst_xvidenc_signals[FRAME_ENCODED] = g_signal_new ("frame_encoded", G_TYPE_FROM_CLASS(klass), @@ -173,6 +231,8 @@ gst_xvidenc_class_init (GstXvidEncClass *klass) static void gst_xvidenc_init (GstXvidEnc *xvidenc) { + gst_xvid_init(); + /* create the sink pad */ xvidenc->sinkpad = gst_pad_new_from_template( gst_static_pad_template_get (&sink_template), @@ -189,10 +249,12 @@ gst_xvidenc_init (GstXvidEnc *xvidenc) gst_element_add_pad(GST_ELEMENT(xvidenc), xvidenc->srcpad); /* bitrate, etc. */ - xvidenc->width = xvidenc->height = xvidenc->csp = -1; - xvidenc->bitrate = 512 * 1024; + xvidenc->width = xvidenc->height = xvidenc->csp = xvidenc->stride = -1; + xvidenc->profile = XVID_PROFILE_S_L0; + xvidenc->bitrate = 512; + xvidenc->max_b_frames = 2; xvidenc->max_key_interval = -1; /* default - 2*fps */ - xvidenc->buffer_size = 512 * 1024; + xvidenc->buffer_size = 512; /* set xvid handle to NULL */ xvidenc->handle = NULL; @@ -202,29 +264,40 @@ gst_xvidenc_init (GstXvidEnc *xvidenc) static gboolean gst_xvidenc_setup (GstXvidEnc *xvidenc) { - XVID_ENC_PARAM xenc; - int ret; - - /* set up xvid codec parameters - grab docs from - * xvid.org for more info */ - memset(&xenc, 0, sizeof(XVID_ENC_PARAM)); + xvid_enc_create_t xenc; + xvid_enc_plugin_t xplugin; + xvid_plugin_single_t xsingle; + gint ret; + + /* see xvid.h for the meaning of all this. */ + gst_xvid_init_struct (xenc); + xenc.profile = xvidenc->profile; xenc.width = xvidenc->width; xenc.height = xvidenc->height; - xenc.fincr = (int)(xvidenc->fps * 1000); - xenc.fbase = 1000; - xenc.rc_bitrate = xvidenc->bitrate; - xenc.rc_reaction_delay_factor = -1; - xenc.rc_averaging_period = -1; - xenc.rc_buffer = -1; - xenc.min_quantizer = 1; - xenc.max_quantizer = 31; + xenc.max_bframes = xvidenc->max_b_frames; + xenc.global = XVID_GLOBAL_PACKED; + xenc.fbase = 1000000; + xenc.fincr = (int)(xenc.fbase / xvidenc->fps); xenc.max_key_interval = (xvidenc->max_key_interval == -1) ? - (2 * xenc.fincr / xenc.fbase) : + (2 * xenc.fbase / xenc.fincr) : xvidenc->max_key_interval; xenc.handle = NULL; + /* CBR bitrate/quant for now */ + gst_xvid_init_struct (xsingle); + xsingle.bitrate = xvidenc->bitrate << 10; + xsingle.reaction_delay_factor = -1; + xsingle.averaging_period = -1; + xsingle.buffer = -1; + + /* set CBR plugin */ + xenc.num_plugins = 1; + xenc.plugins = &xplugin; + xenc.plugins[0].func = xvid_plugin_single; + xenc.plugins[0].param = &xsingle; + if ((ret = xvid_encore(NULL, XVID_ENC_CREATE, - &xenc, NULL)) != XVID_ERR_OK) { + &xenc, NULL)) < 0) { gst_element_error(GST_ELEMENT(xvidenc), "Error setting up xvid encoder: %s (%d)", gst_xvid_error(ret), ret); @@ -242,47 +315,55 @@ gst_xvidenc_chain (GstPad *pad, GstData *_data) { GstBuffer *buf = GST_BUFFER (_data); - GstXvidEnc *xvidenc; + GstXvidEnc *xvidenc = GST_XVIDENC(GST_OBJECT_PARENT(pad)); GstBuffer *outbuf; - XVID_ENC_FRAME xframe; - int ret; + xvid_enc_frame_t xframe; + xvid_enc_stats_t xstats; + gint ret; g_return_if_fail(pad != NULL); g_return_if_fail(GST_IS_PAD(pad)); - g_return_if_fail(buf != NULL); - xvidenc = GST_XVIDENC(GST_OBJECT_PARENT(pad)); - - outbuf = gst_buffer_new_and_alloc(xvidenc->buffer_size); + outbuf = gst_buffer_new_and_alloc(xvidenc->buffer_size << 10); GST_BUFFER_TIMESTAMP(outbuf) = GST_BUFFER_TIMESTAMP(buf); + GST_BUFFER_DURATION(outbuf) = GST_BUFFER_DURATION(buf); /* encode and so ... */ - xframe.image = GST_BUFFER_DATA(buf); + gst_xvid_init_struct (xframe); + xframe.vol_flags = XVID_VOL_MPEGQUANT | + XVID_VOL_GMC; + xframe.par = XVID_PAR_11_VGA; + xframe.vop_flags = XVID_VOP_TRELLISQUANT; + xframe.motion = 0; + xframe.input.csp = xvidenc->csp; + if (xvidenc->width == xvidenc->stride) { + xframe.input.plane[0] = GST_BUFFER_DATA(buf); + xframe.input.plane[1] = xframe.input.plane[0] + (xvidenc->width * xvidenc->height); + xframe.input.plane[2] = xframe.input.plane[1] + (xvidenc->width * xvidenc->height / 4); + xframe.input.stride[0] = xvidenc->width; + xframe.input.stride[1] = xvidenc->width / 2; + xframe.input.stride[2] = xvidenc->width / 2; + } else { + xframe.input.plane[0] = GST_BUFFER_DATA(buf); + xframe.input.stride[0] = xvidenc->stride; + } + xframe.type = XVID_TYPE_AUTO; xframe.bitstream = (void *) GST_BUFFER_DATA(outbuf); xframe.length = GST_BUFFER_MAXSIZE(outbuf); - xframe.intra = -1; - xframe.quant = 0; - xframe.colorspace = xvidenc->csp; - xframe.general = XVID_H263QUANT | - XVID_INTER4V | - XVID_HALFPEL; - xframe.motion = PMV_EARLYSTOP16 | - PMV_HALFPELREFINE16 | - PMV_EXTSEARCH16 | - PMV_EARLYSTOP8 | - PMV_HALFPELREFINE8; + gst_xvid_init_struct (xstats); if ((ret = xvid_encore(xvidenc->handle, XVID_ENC_ENCODE, - &xframe, NULL)) != XVID_ERR_OK) { + &xframe, &xstats)) < 0) { gst_element_error(GST_ELEMENT(xvidenc), "Error encoding xvid frame: %s (%d)", gst_xvid_error(ret), ret); gst_buffer_unref(buf); + gst_buffer_unref(outbuf); return; } - GST_BUFFER_SIZE(outbuf) = xframe.length; - if (xframe.intra) + GST_BUFFER_SIZE(outbuf) = xstats.length; + if (xframe.out_flags & XVID_KEYFRAME) GST_BUFFER_FLAG_SET(outbuf, GST_BUFFER_KEY_UNIT); /* go out, multiply! */ @@ -302,10 +383,10 @@ gst_xvidenc_link (GstPad *pad, { GstXvidEnc *xvidenc; GstStructure *structure; - gint w,h,d; + const gchar *mime; + gint w, h; double fps; - guint32 fourcc; - gint xvid_cs = -1; + gint xvid_cs = -1, stride = -1; xvidenc = GST_XVIDENC(gst_pad_get_parent (pad)); @@ -321,68 +402,27 @@ gst_xvidenc_link (GstPad *pad, gst_structure_get_int (structure, "width", &w); gst_structure_get_int (structure, "height", &h); gst_structure_get_double (structure, "framerate", &fps); - if (gst_structure_has_field_typed (structure, "format", GST_TYPE_FOURCC)) - gst_structure_get_fourcc (structure, "format", &fourcc); - else - fourcc = GST_MAKE_FOURCC('R','G','B',' '); - - switch (fourcc) - { - case GST_MAKE_FOURCC('I','4','2','0'): - case GST_MAKE_FOURCC('I','Y','U','V'): - xvid_cs = XVID_CSP_I420; - break; - case GST_MAKE_FOURCC('Y','U','Y','2'): - xvid_cs = XVID_CSP_YUY2; - break; - case GST_MAKE_FOURCC('Y','V','1','2'): - xvid_cs = XVID_CSP_YV12; - break; - case GST_MAKE_FOURCC('U','Y','V','Y'): - xvid_cs = XVID_CSP_UYVY; - break; - case GST_MAKE_FOURCC('Y','V','Y','U'): - xvid_cs = XVID_CSP_YVYU; - break; - case GST_MAKE_FOURCC('R','G','B',' '): - gst_structure_get_int(structure, "depth", &d); - switch (d) { - case 15: - xvid_cs = XVID_CSP_RGB555; - break; - case 16: - xvid_cs = XVID_CSP_RGB565; - break; - case 24: - xvid_cs = XVID_CSP_RGB24; - break; - case 32: - xvid_cs = XVID_CSP_RGB32; - break; - } - break; - } + mime = gst_structure_get_name (structure); + xvid_cs = gst_xvid_structure_to_csp (structure, w, &stride, NULL); g_return_val_if_fail (xvid_cs != -1, GST_PAD_LINK_REFUSED); xvidenc->csp = xvid_cs; xvidenc->width = w; xvidenc->height = h; + xvidenc->stride = stride; xvidenc->fps = fps; if (gst_xvidenc_setup(xvidenc)) { GstPadLinkReturn ret; GstCaps *new_caps; - new_caps = gst_caps_new_simple( - "video/x-xvid", - "width", G_TYPE_INT, w, - "height", G_TYPE_INT, h, - "framerate", G_TYPE_DOUBLE, fps); - + new_caps = gst_caps_new_simple("video/x-xvid", + "width", G_TYPE_INT, w, + "height", G_TYPE_INT, h, + "framerate", G_TYPE_DOUBLE, fps, NULL); ret = gst_pad_try_set_caps(xvidenc->srcpad, new_caps); - - if (ret <= 0) { + if (GST_PAD_LINK_FAILED (ret)) { if (xvidenc->handle) { xvid_encore(xvidenc->handle, XVID_ENC_DESTROY, NULL, NULL); xvidenc->handle = NULL; @@ -411,11 +451,14 @@ gst_xvidenc_set_property (GObject *object, switch (prop_id) { + case ARG_PROFILE: + xvidenc->profile = g_value_get_enum(value); + break; case ARG_BITRATE: - xvidenc->bitrate = g_value_get_ulong(value); + xvidenc->bitrate = g_value_get_int(value); break; case ARG_BUFSIZE: - xvidenc->buffer_size = g_value_get_ulong(value); + xvidenc->buffer_size = g_value_get_int(value); break; case ARG_MAXKEYINTERVAL: xvidenc->max_key_interval = g_value_get_int(value); @@ -440,11 +483,14 @@ gst_xvidenc_get_property (GObject *object, xvidenc = GST_XVIDENC(object); switch (prop_id) { + case ARG_PROFILE: + g_value_set_enum(value, xvidenc->profile); + break; case ARG_BITRATE: - g_value_set_ulong(value, xvidenc->bitrate); + g_value_set_int(value, xvidenc->bitrate); break; case ARG_BUFSIZE: - g_value_set_ulong(value, xvidenc->buffer_size); + g_value_set_int(value, xvidenc->buffer_size); break; case ARG_MAXKEYINTERVAL: g_value_set_int(value, xvidenc->max_key_interval); @@ -454,3 +500,25 @@ gst_xvidenc_get_property (GObject *object, break; } } + +static GstElementStateReturn +gst_xvidenc_change_state (GstElement *element) +{ + GstXvidEnc *xvidenc = GST_XVIDENC (element); + + switch (GST_STATE_PENDING (element)) { + case GST_STATE_PAUSED_TO_READY: + if (xvidenc->handle) { + xvid_encore(xvidenc->handle, XVID_ENC_DESTROY, NULL, NULL); + xvidenc->handle = NULL; + } + break; + default: + break; + } + + if (parent_class->change_state) + return parent_class->change_state (element); + + return GST_STATE_SUCCESS; +} diff --git a/ext/xvid/gstxvidenc.h b/ext/xvid/gstxvidenc.h index 12f4d2fd..356ce53f 100644 --- a/ext/xvid/gstxvidenc.h +++ b/ext/xvid/gstxvidenc.h @@ -48,11 +48,15 @@ struct _GstXvidEnc { /* pads */ GstPad *sinkpad, *srcpad; - /* quality of encoded JPEG image */ - gulong bitrate; + /* encoding profile */ + gint profile; - /* size of the JPEG buffers */ - gulong buffer_size; + /* quality of encoded image */ + gint bitrate; + gint buffer_size; + + /* max number of B frames between I/P */ + gint max_b_frames; /* max key interval */ gint max_key_interval; @@ -60,8 +64,8 @@ struct _GstXvidEnc { /* xvid handle */ void *handle; gint csp; - gint width, height; - double fps; + gint width, height, stride; + gdouble fps; }; struct _GstXvidEncClass { |