/* * GStreamer * Copyright (c) 2010, Texas Instruments Incorporated * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * SECTION:element-ducativc1dec * * FIXME:Describe ducativc1dec here. * * * Example launch line * |[ * gst-launch -v -m fakesrc ! ducativc1dec ! fakesink silent=TRUE * ]| * */ #ifdef HAVE_CONFIG_H # include #endif #include "gstducativc1dec.h" #define PADX 32 #define PADY 40 #define GST_BUFFER_FLAG_B_FRAME (GST_BUFFER_FLAG_LAST << 0) GST_BOILERPLATE (GstDucatiVC1Dec, gst_ducati_vc1dec, GstDucatiVidDec, GST_TYPE_DUCATIVIDDEC); static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS ("video/x-wmv, " "wmvversion = (int) 3, " "format = (fourcc){ WVC1, WMV3 }, " "width = (int)[ 16, 2048 ], " "height = (int)[ 16, 2048 ], " "framerate = (fraction)[ 0, max ];") ); /* GstDucatiVidDec vmethod implementations */ static gboolean gst_ducati_vc1dec_parse_caps (GstDucatiVidDec * vdec, GstStructure * s) { GstDucatiVC1Dec *self = GST_DUCATIVC1DEC (vdec); if (parent_class->parse_caps (vdec, s)) { guint32 format; gboolean ret = gst_structure_get_fourcc (s, "format", &format); if (ret) { switch (format) { case GST_MAKE_FOURCC ('W', 'V', 'C', '1'): self->level = 4; break; case GST_MAKE_FOURCC ('W', 'M', 'V', '3'): self->level = 3; break; default: ret = FALSE; break; } } return ret; } GST_INFO_OBJECT (vdec, "level %d", self->level); return FALSE; } static void gst_ducati_vc1dec_update_buffer_size (GstDucatiVidDec * self) { gint w = self->width; gint h = self->height; /* calculate output buffer parameters: */ self->padded_width = ALIGN2 (w + (2 * PADX), 7); self->padded_height = (ALIGN2 (h / 2, 4) * 2) + 2 * PADY; self->min_buffers = 8; } static gboolean gst_ducati_vc1dec_allocate_params (GstDucatiVidDec * self, gint params_sz, gint dynparams_sz, gint status_sz, gint inargs_sz, gint outargs_sz) { gboolean ret = parent_class->allocate_params (self, sizeof (IVC1VDEC_Params), sizeof (IVC1VDEC_DynamicParams), sizeof (IVC1VDEC_Status), sizeof (IVC1VDEC_InArgs), sizeof (IVC1VDEC_OutArgs)); if (ret) { IVC1VDEC_Params *params = (IVC1VDEC_Params *) self->params; self->params->maxBitRate = 45000000; self->params->displayDelay = IVIDDEC3_DISPLAY_DELAY_AUTO; /* this indicates whether buffers are prefixed with the frame layer struct * or not. See Table 266: Frame Layer Data Structure from the spec */ params->frameLayerDataPresentFlag = FALSE; /* enable concealment */ params->ErrorConcealmentON = 1; /* codec wants lateAcquireArg = -1 */ self->dynParams->lateAcquireArg = -1; } return ret; } static GstBuffer * gst_ducati_vc1dec_push_input (GstDucatiVidDec * vdec, GstBuffer * buf) { GstDucatiVC1Dec *self = GST_DUCATIVC1DEC (vdec); IVC1VDEC_Params *params = (IVC1VDEC_Params *) vdec->params; guint32 val; /* need a base ts for frame layer timestamps */ if (self->first_ts == GST_CLOCK_TIME_NONE) self->first_ts = GST_BUFFER_TIMESTAMP (buf); if (G_UNLIKELY (vdec->first_in_buffer) && vdec->codec_data) { if (self->level == 4) { /* for VC-1 Advanced Profile, strip off first byte, and * send rest of codec_data unmodified; */ push_input (vdec, GST_BUFFER_DATA (vdec->codec_data) + 1, GST_BUFFER_SIZE (vdec->codec_data) - 1); } else { /* for VC-1 Simple and Main Profile, build the Table 265 Sequence * Layer Data Structure header (refer to VC-1 spec, Annex L): */ val = 0xc5ffffff; /* we don't know the number of frames */ push_input (vdec, (guint8 *) & val, 4); /* STRUCT_C (preceded by length).. see Table 263, 264 */ val = 0x00000004; push_input (vdec, (guint8 *) & val, 4); val = GST_READ_UINT32_LE (GST_BUFFER_DATA (vdec->codec_data)); /* FIXME: i have NO idea why asfdemux gives me something I need to patch... */ val |= 0x01 << 24; push_input (vdec, (guint8 *) & val, 4); /* STRUCT_A.. see Table 260 and Annex J.2 */ val = vdec->height; push_input (vdec, (guint8 *) & val, 4); val = vdec->width; push_input (vdec, (guint8 *) & val, 4); GST_INFO_OBJECT (vdec, "seq hdr resolution: %dx%d", vdec->width, vdec->height); val = 0x0000000c; push_input (vdec, (guint8 *) & val, 4); /* STRUCT_B.. see Table 261, 262 */ val = 0x00000000; /* not sure how to populate, but codec ignores anyways */ push_input (vdec, (guint8 *) & val, 4); push_input (vdec, (guint8 *) & val, 4); push_input (vdec, (guint8 *) & val, 4); } } /* VC-1 Advanced profile needs start-code prepended: */ if (self->level == 4) { static guint8 sc[] = { 0x00, 0x00, 0x01, 0x0d }; /* start code */ push_input (vdec, sc, sizeof (sc)); } if (params->frameLayerDataPresentFlag) { val = GST_BUFFER_SIZE (buf); if (!GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) val |= 0x80 << 24; else val |= 0x00 << 24; push_input (vdec, (guint8 *) & val, 4); val = GST_TIME_AS_MSECONDS (GST_BUFFER_TIMESTAMP (buf) - self->first_ts); push_input (vdec, (guint8 *) & val, 4); } push_input (vdec, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); gst_buffer_unref (buf); return NULL; } static gint gst_ducati_vc1dec_handle_error (GstDucatiVidDec * self, gint ret, gint extended_error, gint status_extended_error) { if (extended_error == 0x00409000) /* the codec sets some IVC1DEC_ERR_PICHDR (corrupted picture headers) errors * as fatal even though it's able to recover */ ret = XDM_EOK; else ret = parent_class->handle_error (self, ret, extended_error, status_extended_error); return ret; } static gboolean gst_ducati_vc1dec_can_drop_frame (GstDucatiVidDec * self, GstBuffer * buf, gint64 diff) { gboolean is_bframe = GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_B_FRAME); if (diff >= 0 && is_bframe) return TRUE; return FALSE; } /* GstElement vmethod implementations */ static GstStateChangeReturn gst_ducati_vc1dec_change_state (GstElement * element, GstStateChange transition) { GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; GstDucatiVC1Dec *self = GST_DUCATIVC1DEC (element); GST_INFO_OBJECT (self, "begin: changing state %s -> %s", gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)), gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition))); ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); if (ret == GST_STATE_CHANGE_FAILURE) goto leave; switch (transition) { case GST_STATE_CHANGE_PAUSED_TO_READY: self->level = -1; self->first_ts = GST_CLOCK_TIME_NONE; break; default: break; } leave: GST_LOG_OBJECT (self, "end"); return ret; } /* GObject vmethod implementations */ static void gst_ducati_vc1dec_base_init (gpointer gclass) { GstElementClass *element_class = GST_ELEMENT_CLASS (gclass); gst_element_class_set_details_simple (element_class, "DucatiVC1Dec", "Codec/Decoder/Video", "Decodes video in WMV3/VC-1 format with ducati", "Rob Clark "); gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&sink_factory)); } static void gst_ducati_vc1dec_class_init (GstDucatiVC1DecClass * klass) { GstDucatiVidDecClass *bclass = GST_DUCATIVIDDEC_CLASS (klass); GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_ducati_vc1dec_change_state); bclass->codec_name = "ivahd_vc1vdec"; bclass->parse_caps = GST_DEBUG_FUNCPTR (gst_ducati_vc1dec_parse_caps); bclass->update_buffer_size = GST_DEBUG_FUNCPTR (gst_ducati_vc1dec_update_buffer_size); bclass->allocate_params = GST_DEBUG_FUNCPTR (gst_ducati_vc1dec_allocate_params); bclass->push_input = GST_DEBUG_FUNCPTR (gst_ducati_vc1dec_push_input); bclass->handle_error = GST_DEBUG_FUNCPTR (gst_ducati_vc1dec_handle_error); bclass->can_drop_frame = GST_DEBUG_FUNCPTR (gst_ducati_vc1dec_can_drop_frame); } static void gst_ducati_vc1dec_init (GstDucatiVC1Dec * self, GstDucatiVC1DecClass * gclass) { GstDucatiVidDec *vdec = GST_DUCATIVIDDEC (self); self->level = -1; self->first_ts = GST_CLOCK_TIME_NONE; vdec->pageMemType = XDM_MEMTYPE_RAW; }