/** call control(FLUSH), and then process() to pop out all buffers */ static gboolean codec_flush (GstDucatiVidDec * self, gboolean eos) { gint err; GST_DEBUG_OBJECT (self, "flush: eos=%d", eos); /* note: flush is synchronized against _chain() to avoid calling * the codec from multiple threads */ GST_PAD_STREAM_LOCK (self->sinkpad); if (G_UNLIKELY (self->first_in_buffer)) { return TRUE; } if (G_UNLIKELY (!self->codec)) { GST_WARNING_OBJECT (self, "no codec"); return TRUE; } err = VIDDEC3_control (self->codec, XDM_FLUSH, self->dynParams, self->status); if (err) { GST_ERROR_OBJECT (self, "failed XDM_FLUSH"); goto out; } self->inBufs->descs[0].bufSize.bytes = 0; self->inArgs->numBytes = 0; self->inArgs->inputID = 0; do { err = codec_process (self, eos, TRUE); } while (err != XDM_EFAIL); /* on a flush, it is normal (and not an error) for the last _process() call * to return an error.. */ err = XDM_EOK; out: GST_PAD_STREAM_UNLOCK (self->sinkpad); GST_DEBUG_OBJECT (self, "done"); return !err; }
static void gst_ducati_viddec_get_property (GObject * obj, guint prop_id, GValue * value, GParamSpec * pspec) { GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj); switch (prop_id) { case PROP_VERSION: { int err; char *version = gst_ducati_alloc_1d (VERSION_LENGTH); /* in case something fails: */ snprintf (version, VERSION_LENGTH, "unsupported"); if (! self->engine) engine_open (self); if (! self->codec) codec_create (self); if (self->codec) { self->status->data.buf = (XDAS_Int8 *) TilerMem_VirtToPhys (version); self->status->data.bufSize = VERSION_LENGTH; err = VIDDEC3_control (self->codec, XDM_GETVERSION, self->dynParams, self->status); if (err) { GST_ERROR_OBJECT (self, "failed XDM_GETVERSION"); } self->status->data.buf = NULL; self->status->data.bufSize = 0; } g_value_set_string (value, version); MemMgr_Free (version); break; } default: { G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); break; } } }
static gboolean codec_create (GstDucatiVidDec * self) { gint err; const gchar *codec_name; codec_delete (self); if (G_UNLIKELY (!self->engine)) { GST_ERROR_OBJECT (self, "no engine"); return FALSE; } /* these need to be set before VIDDEC3_create */ self->params->maxWidth = self->width; self->params->maxHeight = self->height; codec_name = GST_DUCATIVIDDEC_GET_CLASS (self)->codec_name; /* create codec: */ GST_DEBUG_OBJECT (self, "creating codec: %s", codec_name); self->codec = VIDDEC3_create (self->engine, (String)codec_name, self->params); if (!self->codec) { return FALSE; } err = VIDDEC3_control (self->codec, XDM_SETPARAMS, self->dynParams, self->status); if (err) { GST_ERROR_OBJECT (self, "failed XDM_SETPARAMS"); return FALSE; } self->first_in_buffer = TRUE; self->first_out_buffer = TRUE; /* allocate input buffer and initialize inBufs: */ self->inBufs->numBufs = 1; self->input = gst_ducati_alloc_1d (self->width * self->height); self->inBufs->descs[0].buf = (XDAS_Int8 *) TilerMem_VirtToPhys (self->input); self->inBufs->descs[0].memType = XDM_MEMTYPE_RAW; return TRUE; }
static gint codec_process (GstDucatiVidDec * self, gboolean send, gboolean flush) { gint err; GstClockTime t; GstBuffer *outbuf = NULL; gint i; self->outArgs->outputID[0] = 0; self->outArgs->freeBufID[0] = 0; t = gst_util_get_timestamp (); err = VIDDEC3_process (self->codec, self->inBufs, self->outBufs, self->inArgs, self->outArgs); GST_INFO_OBJECT (self, "%10dns", (gint) (gst_util_get_timestamp () - t)); if (err) { GST_WARNING_OBJECT (self, "err=%d, extendedError=%08x", err, self->outArgs->extendedError); err = VIDDEC3_control (self->codec, XDM_GETSTATUS, self->dynParams, self->status); GST_WARNING_OBJECT (self, "XDM_GETSTATUS: err=%d, extendedError=%08x", err, self->status->extendedError); if (XDM_ISFATALERROR (self->outArgs->extendedError) || flush) { /* we are processing for display and it is a non-fatal error, so lets * try to recover.. otherwise return the error */ err = XDM_EFAIL; } } for (i = 0; self->outArgs->outputID[i]; i++) { if (G_UNLIKELY (self->first_out_buffer) && send) { /* send region of interest to sink on first buffer: */ XDM_Rect *r = &(self->outArgs->displayBufs.bufDesc[0].activeFrameRegion); GST_DEBUG_OBJECT (self, "setting crop to %d, %d, %d, %d", r->topLeft.x, r->topLeft.y, r->bottomRight.x, r->bottomRight.y); gst_pad_push_event (self->srcpad, gst_event_new_crop (r->topLeft.y, r->topLeft.x, r->bottomRight.x - r->topLeft.x, r->bottomRight.y - r->topLeft.y)); self->first_out_buffer = FALSE; } outbuf = codec_get_outbuf (self, self->outArgs->outputID[i]); if (send) { if (GST_IS_DUCATIBUFFER (outbuf)) { outbuf = gst_ducati_buffer_get (GST_DUCATIBUFFER (outbuf)); } GST_DEBUG_OBJECT (self, "got buffer: %d %p (%" GST_TIME_FORMAT ")", i, outbuf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf))); gst_pad_push (self->srcpad, outbuf); } else { GST_DEBUG_OBJECT (self, "free buffer: %d %p", i, outbuf); gst_buffer_unref (outbuf); } } for (i = 0; self->outArgs->freeBufID[i]; i++) { codec_unlock_outbuf (self, self->outArgs->freeBufID[i]); } return err; }
/* * ======== call ======== */ static VISA_Status call(VISA_Handle visaHandle, VISA_Msg visaMsg) { _VIDDEC3_Msg *msg = (_VIDDEC3_Msg *)visaMsg; VIDDEC3_Handle handle = (VIDDEC3_Handle)visaHandle; Int i; XDM2_BufDesc inBufs; XDM2_BufDesc outBufs; IVIDDEC3_OutArgs *pOutArgs; IVIDDEC3_Status *pStatus; IVIDDEC3_CodecClassConfig *codecClassConfig; Int numBufs; Bool success; /* get stub/skeleton config data; can be NULL (for old codecs) */ codecClassConfig = (IVIDDEC3_CodecClassConfig *)VISA_getCodecClassConfig(visaHandle); /* perform the requested VIDDEC2 operation by parsing message. */ switch (msg->visa.cmd) { case _VIDDEC3_CPROCESS: { /* unmarshall inBufs and outBufs */ inBufs = msg->cmd.process.inBufs; outBufs = msg->cmd.process.outBufs; /* invalidate cache for all input buffers */ for (i = 0, numBufs = 0; i < XDM_MAX_IO_BUFFERS; i++) { if (inBufs.descs[i].buf != NULL) { /* valid member of sparse array, * invalidate it unless user configured it not to */ if (codecClassConfig != NULL && codecClassConfig->manageInBufsCache[i] == FALSE) { /* do nothing, i.e. don't invalidate */ } else { if (inBufs.descs[i].memType == XDM_MEMTYPE_RAW) { Memory_cacheInv(inBufs.descs[i].buf, inBufs.descs[i].bufSize.bytes); } else { /* TODO:H are tiled buffers cacheable? */ } } if (++numBufs == inBufs.numBufs) { break; } } } /* invalidate cache for all output buffers */ for (i = 0, numBufs = 0; i < XDM_MAX_IO_BUFFERS; i++) { if (outBufs.descs[i].buf != NULL) { /* valid member of sparse array, * invalidate it unless user configured it not to */ if (codecClassConfig != NULL && codecClassConfig->manageOutBufsCache[i] == FALSE) { /* do nothing, i.e. don't invalidate */ } else { if (outBufs.descs[i].memType == XDM_MEMTYPE_RAW) { Memory_cacheInv(outBufs.descs[i].buf, outBufs.descs[i].bufSize.bytes); } else { /* TODO:H are tiled buffers cacheable? */ } } if (++numBufs == outBufs.numBufs) { break; } } } /* unmarshall outArgs based on the "size" of inArgs */ pOutArgs = (IVIDDEC3_OutArgs *)((UInt)(&(msg->cmd.process.inArgs)) + msg->cmd.process.inArgs.size); /* * Note, there's no need to invalidate cache for * pOutArgs->decodedBuf bufs nor pOutArgs->displayBufs * bufs as the app doesn't provide OUT buffers to the * algorithm via these fields. */ /* make the process call */ msg->visa.status = VIDDEC3_process(handle, &inBufs, &outBufs, &(msg->cmd.process.inArgs), pOutArgs); /* * We probably should only be doing this if msg->visa.status * is IVIDDEC3_EOK or _EFAIL and .extendedError is non-fatal. */ /* * Writeback cache for all output buffers: * - .decodedBufs * - .displayBufs */ /* * ======== .decodedBufs ======== */ success = writebackVideo2BufDesc(&pOutArgs->decodedBufs); if (!success) { return (VISA_EFAIL); } /* * ======== .displayBufs ======== */ /* identify which mode the displayBufs are returned as */ if (pOutArgs->displayBufsMode == IVIDDEC3_DISPLAYBUFS_EMBEDDED) { /* the display buffers are embedded in the outArgs struct */ for (i = 0; (pOutArgs->outputID[i] != 0) && (i < IVIDEO2_MAX_IO_BUFFERS); i++) { success = writebackVideo2BufDesc( &(pOutArgs->displayBufs.bufDesc[i])); if (!success) { return (VISA_EFAIL); } } } else { /* the display buffers are pointed to in the outArgs struct */ for (i = 0; (pOutArgs->outputID[i] != 0) && (i < IVIDEO2_MAX_IO_BUFFERS); i++) { success = writebackVideo2BufDesc( pOutArgs->displayBufs.pBufDesc[i]); if (!success) { return (VISA_EFAIL); } } } /* * Note that any changes to individual outBufs[i] values made by * the codec will automatically update msg->cmd.process.outBufs * as we pass the outBufs array by reference. */ break; } case _VIDDEC3_CCONTROL: { /* unmarshall status based on the "size" of params */ pStatus = (IVIDDEC3_Status *)((UInt)(&(msg->cmd.control.params)) + msg->cmd.control.params.size); /* invalidate data buffer */ if (pStatus->data.buf != NULL) { Memory_cacheInv(pStatus->data.buf, pStatus->data.bufSize); } msg->visa.status = VIDDEC3_control(handle, msg->cmd.control.id, &(msg->cmd.control.params), pStatus); /* writeback data buffer */ if ((pStatus->data.buf != NULL) && XDM_ISACCESSMODE_WRITE(pStatus->data.accessMask)) { Memory_cacheWb(pStatus->data.buf, pStatus->data.bufSize); /* * Since we've cacheWb this buffer, we arguably should * reflect this cache state and clear the WRITE bit in * the .accessMask field. However, we know the stub * doesn't propogate this field to the calling app, so * this extra buffer management detail isn't necessary: * * XDM_CLEARACCESSMODE_WRITE(pStatus->data.accessMask); */ } break; } default: { msg->visa.status = VISA_EFAIL; break; } } return (VISA_EOK); }