Esempio n. 1
0
/**
 * Main working loop for stuff coming in from the CCNx network
 *
 * The only kind of content we work with are data messages. They are in response to the
 * interest messages we send out. The work involves 2 pieces: packing the data from ccn message
 * sizes into buffer sizes we use internally, and detecting when the stream of data is done.
 * 
 * The first is fairly simple. Each internal buffer we 'fill' is placed onto the fifo queue
 * so the main thread can take it off and reply to the pipeline request for more data.
 *
 * Determining the end of stream at the moment is a bit of a hack and could use some work.
 * \todo volunteers?  8-)
 *
 * \param	selfp		-> a context structure we created when registering this call-back
 * \param	kind		specifies the type of call-back being processed, see the \b switch statement
 * \param	info		context information about the call-back itself; interests, data, etc.
 * \return a response as to how successful we were in processing the call-back
 * \retval CCN_UPCALL_RESULT_OK		things went well
 * \retval CCN_UPCALL_RESULT_VERIFY	need to verify the contents of what we received
 * \retval CCN_UPCALL_RESULT_REEXPRESS an interest timedout waiting for data, so we try again
 * \retval CCN_UPCALL_RESULT_ERR	some error was encountered
 */
static enum ccn_upcall_res
incoming_content (struct ccn_closure *selfp,
    enum ccn_upcall_kind kind, struct ccn_upcall_info *info)
{
  Gstccnxsrc *me = GST_CCNXSRC (selfp->data);

  const unsigned char *ccnb = NULL;
  size_t ccnb_size = 0;
  const unsigned char *ib = NULL;       /* info->interest_ccnb */
  struct ccn_indexbuf *ic = NULL;
  unsigned int i;
  uintmax_t segment;
  CcnxInterestState *istate = NULL;
  gint res;
  const unsigned char *cp;
  size_t sz;
  const unsigned char *data = NULL;
  size_t data_size = 0;
  gboolean b_last = FALSE;

  GST_INFO ("content has arrived!");

  /* Do some basic sanity and type checks to see if we want to process this data */

  if (CCN_UPCALL_FINAL == kind) {
    GST_LOG_OBJECT (me, "CCN upcall final %p", selfp);
    if (me->i_bufoffset > 0) {
      GST_BUFFER_SIZE (me->buf) = me->i_bufoffset;
      fifo_put (me, me->buf);
      me->buf = gst_buffer_new_and_alloc (CCN_FIFO_BLOCK_SIZE);
      me->i_bufoffset = 0;
    }
/*
 * Should emit an eos here instead of the empty buffer
 */
    GST_BUFFER_SIZE (me->buf) = 0;
    fifo_put (me, me->buf);
    me->i_bufoffset = 0;
    return (CCN_UPCALL_RESULT_OK);
  }

  if (!info)
    return CCN_UPCALL_RESULT_ERR;       // Now why would this happen?

  // show_comps( info->content_ccnb, info->content_comps);

  if (CCN_UPCALL_INTEREST_TIMED_OUT == kind) {
    if (selfp != me->ccn_closure) {
      GST_LOG_OBJECT (me, "CCN Interest timed out on dead closure %p", selfp);
      return (CCN_UPCALL_RESULT_OK);
    }
    segment =
        ccn_ccnb_fetch_segment (info->interest_ccnb, info->interest_comps);
    GST_INFO ("...looks to be for segment: %d", segment);
    GST_LOG_OBJECT (me, "CCN upcall reexpress -- timed out");
    istate = fetchSegmentInterest (me, segment);
    if (istate) {
      if (istate->timeouts > 5) {
        GST_LOG_OBJECT (me, "CCN upcall reexpress -- too many reexpressions");
        if (segment == me->post_seg)    // We have been waiting for this one...process as an empty block to trigger other activity
          process_or_queue (me, me->post_seg, NULL, 0, FALSE);
        else
          freeInterestState (me, istate);
        post_next_interest (me);        // make sure to ask for new stuff if needed, or else we stall waiting for nothing
        return (CCN_UPCALL_RESULT_OK);
      } else {
        istate->timeouts++;
        return (CCN_UPCALL_RESULT_REEXPRESS);
      }
    } else {
      GST_LOG_OBJECT (me, "segment not found in cache: %d", segment);
      return (CCN_UPCALL_RESULT_OK);
    }

  } else if (CCN_UPCALL_CONTENT_UNVERIFIED == kind) {
    if (selfp != me->ccn_closure) {
      GST_LOG_OBJECT (me, "CCN unverified content on dead closure %p", selfp);
      return (CCN_UPCALL_RESULT_OK);
    }
    return (CCN_UPCALL_RESULT_VERIFY);

  } else if (CCN_UPCALL_CONTENT != kind) {
    GST_LOG_OBJECT (me, "CCN upcall result error");
    return (CCN_UPCALL_RESULT_ERR);
  }

  segment = ccn_ccnb_fetch_segment (info->content_ccnb, info->content_comps);
  GST_INFO ("...looks to be for segment: %d", segment);
  if (selfp != me->ccn_closure) {
    GST_LOG_OBJECT (me, "CCN content on dead closure %p", selfp);
    return (CCN_UPCALL_RESULT_OK);
  }


  /* At this point it seems we have a data message we want to process */

  ccnb = info->content_ccnb;
  ccnb_size = info->pco->offset[CCN_PCO_E];

  /* spit out some debug information */
  for (i = 0; i < 5; ++i) {
    GST_DEBUG ("%3d: ", i);
    if (0 > ccn_name_comp_get (info->content_ccnb, info->content_comps, i, &cp,
            &sz)) {
      // fprintf(stderr, "could not get comp\n");
    } else {
      // hDump( DUMP_ADDR( cp ), DUMP_SIZE( sz ) );
    }
  }

  /* go get the data and process it...note that the data pointer here is only temporary, a copy is needed to keep the data */
  ib = info->interest_ccnb;
  ic = info->interest_comps;
  res = ccn_content_get_value (ccnb, ccnb_size, info->pco, &data, &data_size);
  if (res < 0) {
    GST_LOG_OBJECT (me, "CCN error on get value of size");
    process_or_queue (me, segment, NULL, 0, FALSE);     // process null block to adjust interest array queue
    post_next_interest (me);    // Keep the data flowing
    return (CCN_UPCALL_RESULT_ERR);
  }

  /* was this the last block? [code taken from a ccnx tool */
  /* \todo  the test below should get refactored into the library */
  if (info->pco->offset[CCN_PCO_B_FinalBlockID] !=
      info->pco->offset[CCN_PCO_E_FinalBlockID]) {
    const unsigned char *finalid = NULL;
    size_t finalid_size = 0;
    const unsigned char *nameid = NULL;
    size_t nameid_size = 0;
    struct ccn_indexbuf *cc = info->content_comps;
    ccn_ref_tagged_BLOB (CCN_DTAG_FinalBlockID, ccnb,
        info->pco->offset[CCN_PCO_B_FinalBlockID],
        info->pco->offset[CCN_PCO_E_FinalBlockID], &finalid, &finalid_size);
    if (cc->n < 2)
      abort ();                 // \todo we need to behave better than this
    ccn_ref_tagged_BLOB (CCN_DTAG_Component, ccnb,
        cc->buf[cc->n - 2], cc->buf[cc->n - 1], &nameid, &nameid_size);
    if (finalid_size == nameid_size
        && 0 == memcmp (finalid, nameid, nameid_size)) {
      b_last = TRUE;
    }
  }

  /* a short block can also indicate the end, if the client isn't using FinalBlockID */
  if (data_size < CCN_CHUNK_SIZE)
    b_last = TRUE;

  /* something to process */
  process_or_queue (me, segment, data, data_size, b_last);
  post_next_interest (me);

  if (!b_last)
    return post_next_interest (me);

  return (CCN_UPCALL_RESULT_OK);

}
Esempio n. 2
0
static GstFlowReturn
gst_goo_encjpeg_chain (GstPad* pad, GstBuffer* buffer)
{
	GST_LOG ("");

	GstGooEncJpeg* self = GST_GOO_ENCJPEG (gst_pad_get_parent (pad));
	GstGooEncJpegPrivate* priv = GST_GOO_ENCJPEG_GET_PRIVATE (self);
	GstFlowReturn ret = GST_FLOW_OK;
	GstGooAdapter* adapter = self->adapter;
	OMX_BUFFERHEADERTYPE* omx_buffer = NULL;

	GstClockTime timestamp, duration;
	guint64 offset, offsetend;
	GstBuffer* outbuf = NULL;

	if (goo_port_is_tunneled (self->inport))
	{
		GST_INFO ("Inport is tunneled");
		ret = GST_FLOW_OK;
		priv->incount++;
		goto process_output;
	}

	if (goo_port_is_eos (self->inport))
	{
		GST_INFO ("port is eos");
		ret = GST_FLOW_UNEXPECTED;
		goto fail;
	}

	if (self->component->cur_state != OMX_StateExecuting)
	{
		goto fail;
	}

	/* let's copy the timestamp meta data */
	timestamp = GST_BUFFER_TIMESTAMP (buffer);
	duration  = GST_BUFFER_DURATION (buffer);
	offset	  = GST_BUFFER_OFFSET (buffer);
	offsetend = GST_BUFFER_OFFSET_END (buffer);

	if (GST_IS_GOO_BUFFER (buffer) &&
	    goo_port_is_my_buffer (self->inport,
				   GST_GOO_BUFFER (buffer)->omx_buffer))
	{
		GST_INFO ("My own OMX buffer");
		priv->incount++;
		gst_buffer_unref (buffer); /* let's push the buffer to omx */
		ret = GST_FLOW_OK;
	}
	else if (GST_IS_GOO_BUFFER (buffer) &&
		 !goo_port_is_my_buffer (self->inport,
					 GST_GOO_BUFFER (buffer)->omx_buffer))
	{
		GST_INFO ("Other OMX buffer");

		if (GST_BUFFER_SIZE (buffer) != priv->omxbufsiz)
		{
			GST_ELEMENT_ERROR (self, STREAM, FORMAT,
					   ("Frame is incomplete (%u!=%u)",
					    GST_BUFFER_SIZE (buffer),
					    priv->omxbufsiz),
					   ("Frame is incomplete (%u!=%u)",
					    GST_BUFFER_SIZE (buffer),
					    priv->omxbufsiz));
			ret = GST_FLOW_ERROR;
		}

		omx_buffer = goo_port_grab_buffer (self->inport);
		memcpy (omx_buffer->pBuffer, GST_BUFFER_DATA (buffer),
			priv->omxbufsiz);
		omx_buffer->nFilledLen = priv->omxbufsiz;
		priv->incount++;
		goo_component_release_buffer (self->component, omx_buffer);
		gst_buffer_unref (buffer);
		ret = GST_FLOW_OK;
	}
	else
	{
		if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT))
		{
			gst_goo_adapter_clear (adapter);
		}

		GST_LOG ("size = %d bytes", GST_BUFFER_SIZE (buffer));
		gst_goo_adapter_push (adapter, buffer);

		guint tmp = priv->incount;
		while (gst_goo_adapter_available (adapter) >= priv->omxbufsiz &&
		       ret == GST_FLOW_OK)
		{
			GST_DEBUG ("Pushing data to OMX");
			OMX_BUFFERHEADERTYPE* omx_buffer;
			omx_buffer = goo_port_grab_buffer (self->inport);
			gst_goo_adapter_peek (adapter, priv->omxbufsiz,
					      omx_buffer);
			omx_buffer->nFilledLen = priv->omxbufsiz;
			gst_goo_adapter_flush (adapter, priv->omxbufsiz);
			priv->incount++;
			goo_component_release_buffer (self->component,
						      omx_buffer);
			ret = GST_FLOW_OK;
		}

		if (tmp == priv->incount)
		{
			goto done;
		}
	}

process_output:
	if (goo_port_is_tunneled (self->outport))
	{
		outbuf = gst_ghost_buffer_new ();
		GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_READONLY);
		GST_BUFFER_DATA (outbuf)       = NULL;
		GST_BUFFER_SIZE (outbuf)       = 0;
		GST_BUFFER_TIMESTAMP (outbuf)  = timestamp;
		GST_BUFFER_DURATION (outbuf)   = duration;
		GST_BUFFER_OFFSET (outbuf)     = offset;
		GST_BUFFER_OFFSET_END (outbuf) = offsetend;
		gst_buffer_set_caps (outbuf, GST_PAD_CAPS (self->srcpad));
		gst_pad_push (self->srcpad, outbuf);
		goto done;
	}

	GST_DEBUG ("Poping out buffer from OMX");
	omx_buffer = goo_port_grab_buffer (self->outport);

	if (omx_buffer->nFilledLen <= 0)
	{
		ret = GST_FLOW_ERROR;
		goto done;
	}

	if (gst_pad_alloc_buffer (self->srcpad, priv->outcount,
				  omx_buffer->nFilledLen,
				  GST_PAD_CAPS (self->srcpad),
				  &outbuf) == GST_FLOW_OK)
	{
		priv->outcount++;

		/* if the buffer is a goo buffer of the peer element */
		if (GST_IS_GOO_BUFFER (outbuf))
		{
			GST_INFO ("It is a OMX buffer!");
			memcpy (GST_GOO_BUFFER (outbuf)->omx_buffer->pBuffer,
				omx_buffer->pBuffer, omx_buffer->nFilledLen);
			GST_GOO_BUFFER (outbuf)->omx_buffer->nFilledLen =
				omx_buffer->nFilledLen;
			GST_GOO_BUFFER (outbuf)->omx_buffer->nFlags =
				omx_buffer->nFlags;
			GST_GOO_BUFFER (outbuf)->omx_buffer->nTimeStamp =
				GST2OMX_TIMESTAMP (timestamp);
			goo_component_release_buffer (self->component,
						      omx_buffer);
		}
		else
		{
			/* @fixme! */
			/* we do this because there is a buffer extarbation
			 * when a filesink is used.
			 * Maybe using multiple buffers it could be solved.
			 */
			memcpy (GST_BUFFER_DATA (outbuf),
				omx_buffer->pBuffer, omx_buffer->nFilledLen);
			goo_component_release_buffer (self->component,
						      omx_buffer);

/* 			gst_buffer_unref (outbuf); */
/* 			outbuf = GST_BUFFER (gst_goo_buffer_new ()); */
/* 			gst_goo_buffer_set_data (outbuf, */
/* 						 self->component, */
/* 						 omx_buffer); */
		}

		GST_BUFFER_TIMESTAMP (outbuf)  = timestamp;
		GST_BUFFER_DURATION (outbuf)   = duration;
		GST_BUFFER_OFFSET (outbuf)     = offset;
		GST_BUFFER_OFFSET_END (outbuf) = offsetend;

		gst_buffer_set_caps (outbuf, GST_PAD_CAPS (self->srcpad));
		g_signal_emit (G_OBJECT (self),
			       gst_goo_encjpeg_signals[FRAME_ENCODED], 0);
	
		ret = gst_pad_push (self->srcpad, outbuf);
		if (omx_buffer->nFlags & OMX_BUFFERFLAG_EOS ||
		   	goo_port_is_eos (self->outport))
		{
			GST_INFO ("EOS flag found in output buffer (%d)",
			  	omx_buffer->nFilledLen);
			goo_component_set_done (self->component);

		}

		goto done;
	}
	else
	{
		ret = GST_FLOW_ERROR;
		goto done;
	}

fail:
	gst_buffer_unref (buffer);
	gst_goo_adapter_clear (adapter);

done:
	gst_object_unref (self);
	return ret;

}
Esempio n. 3
0
/*****************************************************************************
 * gst_tidmaiaccel_prepare_output_buffer
 *    Function is used to allocate output buffer
 *****************************************************************************/
static GstFlowReturn gst_tidmaiaccel_prepare_output_buffer (GstBaseTransform
    *trans, GstBuffer *inBuf, gint size, GstCaps *caps, GstBuffer **outBuf)
{
    GstTIDmaiaccel *dmaiaccel = GST_TIDMAIACCEL(trans);
    Buffer_Handle   hOutBuf;
    Bool isContiguous = FALSE;
    UInt32 phys = 0;

    /* Always check if the buffer is contiguous */
    phys = Memory_getBufferPhysicalAddress(
                    GST_BUFFER_DATA(inBuf),
                    GST_BUFFER_SIZE(inBuf),
                    &isContiguous);

    if (isContiguous && dmaiaccel->width){
        GST_DEBUG("Is contiguous video buffer");

        Memory_registerContigBuf((UInt32)GST_BUFFER_DATA(inBuf),
            GST_BUFFER_SIZE(inBuf),phys);
        /* This is a contiguous buffer, create a dmai buffer transport */
        BufferGfx_Attrs gfxAttrs    = BufferGfx_Attrs_DEFAULT;

        gfxAttrs.bAttrs.reference   = TRUE;
        gfxAttrs.dim.width          = dmaiaccel->width;
        gfxAttrs.dim.height         = dmaiaccel->height;
        gfxAttrs.colorSpace         = dmaiaccel->colorSpace;
        gfxAttrs.dim.lineLength     = dmaiaccel->lineLength;

        hOutBuf = Buffer_create(GST_BUFFER_SIZE(inBuf), &gfxAttrs.bAttrs);
        BufferGfx_setDimensions(hOutBuf,&gfxAttrs.dim);
        BufferGfx_setColorSpace(hOutBuf,gfxAttrs.colorSpace);
        Buffer_setUserPtr(hOutBuf, (Int8*)GST_BUFFER_DATA(inBuf));
        Buffer_setNumBytesUsed(hOutBuf, GST_BUFFER_SIZE(inBuf));
        *outBuf = gst_tidmaibuffertransport_new(hOutBuf, NULL, NULL, FALSE);
        gst_buffer_set_data(*outBuf, (guint8*) Buffer_getUserPtr(hOutBuf),
            Buffer_getSize(hOutBuf));
        gst_buffer_copy_metadata(*outBuf,inBuf,GST_BUFFER_COPY_ALL);
        gst_buffer_set_caps(*outBuf, GST_PAD_CAPS(trans->srcpad));

        /* We need to grab a reference to the input buffer since we have 
         * a pointer to his buffer */
        gst_buffer_ref(inBuf);

        gst_tidmaibuffertransport_set_release_callback(
            (GstTIDmaiBufferTransport *)*outBuf,
            dmaiaccel_release_cb,inBuf);

        return GST_FLOW_OK;
    } else {
        GST_DEBUG("Copying into contiguous video buffer");
        /* This is a contiguous buffer, create a dmai buffer transport */
        if (!dmaiaccel->bufTabAllocated){
            /* Initialize our buffer tab */
            BufferGfx_Attrs gfxAttrs    = BufferGfx_Attrs_DEFAULT;

            gfxAttrs.dim.width          = dmaiaccel->width;
            gfxAttrs.dim.height         = dmaiaccel->height;
            gfxAttrs.colorSpace         = dmaiaccel->colorSpace;
            gfxAttrs.dim.lineLength     = dmaiaccel->lineLength;

            dmaiaccel->hOutBufTab =
                        BufTab_create(2, GST_BUFFER_SIZE(inBuf),
                            BufferGfx_getBufferAttrs(&gfxAttrs));
            pthread_mutex_init(&dmaiaccel->bufTabMutex, NULL);
            pthread_cond_init(&dmaiaccel->bufTabCond, NULL);
            if (dmaiaccel->hOutBufTab == NULL) {
                GST_ELEMENT_ERROR(dmaiaccel,RESOURCE,NO_SPACE_LEFT,(NULL),
                    ("failed to create output buffer tab"));
                return GST_FLOW_ERROR;
            }
            dmaiaccel->bufTabAllocated = TRUE;
        }

        pthread_mutex_lock(&dmaiaccel->bufTabMutex);
        hOutBuf = BufTab_getFreeBuf(dmaiaccel->hOutBufTab);
        if (hOutBuf == NULL) {
            GST_INFO("Failed to get free buffer, waiting on bufTab\n");
            pthread_cond_wait(&dmaiaccel->bufTabCond, &dmaiaccel->bufTabMutex);

            hOutBuf = BufTab_getFreeBuf(dmaiaccel->hOutBufTab);

            if (hOutBuf == NULL) {
                GST_ELEMENT_ERROR(dmaiaccel,RESOURCE,NO_SPACE_LEFT,(NULL),
                    ("failed to get a free contiguous buffer from BufTab"));
                pthread_mutex_unlock(&dmaiaccel->bufTabMutex);
                return GST_FLOW_ERROR;
            }
        }
        pthread_mutex_unlock(&dmaiaccel->bufTabMutex);

        memcpy(Buffer_getUserPtr(hOutBuf),GST_BUFFER_DATA(inBuf),
            GST_BUFFER_SIZE(inBuf));
        Buffer_setNumBytesUsed(hOutBuf, GST_BUFFER_SIZE(inBuf));
        *outBuf = gst_tidmaibuffertransport_new(hOutBuf, &dmaiaccel->bufTabMutex,
            &dmaiaccel->bufTabCond, FALSE);
        gst_buffer_set_data(*outBuf, (guint8*) Buffer_getUserPtr(hOutBuf),
            Buffer_getSize(hOutBuf));
        gst_buffer_copy_metadata(*outBuf,inBuf,GST_BUFFER_COPY_ALL);
        gst_buffer_set_caps(*outBuf, GST_PAD_CAPS(trans->srcpad));

        return GST_FLOW_OK;
    }
}
Esempio n. 4
0
static GstFlowReturn
gst_xvidenc_chain (GstPad * pad, GstBuffer * buf)
{
  GstXvidEnc *xvidenc = GST_XVIDENC (GST_PAD_PARENT (pad));
  GstBuffer *outbuf;
  xvid_enc_frame_t xframe;

  const gint motion_presets[] = {
    0, 0, 0, 0,
    XVID_ME_HALFPELREFINE16,
    XVID_ME_HALFPELREFINE16 | XVID_ME_ADVANCEDDIAMOND16,
    XVID_ME_HALFPELREFINE16 | XVID_ME_EXTSEARCH16
        | XVID_ME_HALFPELREFINE8 | XVID_ME_USESQUARES16
  };

  if (!xvidenc->handle) {
    GST_ELEMENT_ERROR (xvidenc, CORE, NEGOTIATION, (NULL),
        ("format wasn't negotiated before chain function"));
    gst_buffer_unref (buf);
    return GST_FLOW_NOT_NEGOTIATED;
  }

  GST_DEBUG_OBJECT (xvidenc,
      "Received buffer of time %" GST_TIME_FORMAT ", size %d",
      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), GST_BUFFER_SIZE (buf));

  if (xvidenc->xframe_cache)
    memcpy (&xframe, xvidenc->xframe_cache, sizeof (xframe));
  else {                        /* need to build some inital xframe to be cached */
    /* encode and so ... */
    gst_xvid_init_struct (xframe);

    if (xvidenc->par_width == xvidenc->par_height)
      xframe.par = XVID_PAR_11_VGA;
    else {
      xframe.par = XVID_PAR_EXT;
      xframe.par_width = xvidenc->par_width;
      xframe.par_height = xvidenc->par_height;
    }

    /* handle options */
    xframe.vol_flags |= xvidenc->quant_type;
    xframe.vop_flags = XVID_VOP_HALFPEL;
    xframe.motion = motion_presets[xvidenc->motion];

    if (xvidenc->me_chroma) {
      xframe.motion |= XVID_ME_CHROMA_PVOP;
      xframe.motion |= XVID_ME_CHROMA_BVOP;
    }

    if (xvidenc->me_vhq >= 1) {
      xframe.vop_flags |= XVID_VOP_MODEDECISION_RD;
    }
    if (xvidenc->me_vhq >= 2) {
      xframe.motion |= XVID_ME_HALFPELREFINE16_RD;
      xframe.motion |= XVID_ME_QUARTERPELREFINE16_RD;
    }
    if (xvidenc->me_vhq >= 3) {
      xframe.motion |= XVID_ME_HALFPELREFINE8_RD;
      xframe.motion |= XVID_ME_QUARTERPELREFINE8_RD;
      xframe.motion |= XVID_ME_CHECKPREDICTION_RD;
    }
    if (xvidenc->me_vhq >= 4) {
      xframe.motion |= XVID_ME_EXTSEARCH_RD;
    }

    /* no motion estimation, then only intra */
    if (xvidenc->motion == 0) {
      xframe.type = XVID_TYPE_IVOP;
    } else {
      xframe.type = XVID_TYPE_AUTO;
    }

    if (xvidenc->motion > 4) {
      xframe.vop_flags |= XVID_VOP_INTER4V;
    }

    if (xvidenc->me_quarterpel) {
      xframe.vol_flags |= XVID_VOL_QUARTERPEL;
      xframe.motion |= XVID_ME_QUARTERPELREFINE16;
      xframe.motion |= XVID_ME_QUARTERPELREFINE8;
    }

    if (xvidenc->gmc) {
      xframe.vol_flags |= XVID_VOL_GMC;
      xframe.motion |= XVID_ME_GME_REFINE;
    }

    if (xvidenc->interlaced) {
      xframe.vol_flags |= XVID_VOL_INTERLACING;
    }

    if (xvidenc->trellis) {
      xframe.vop_flags |= XVID_VOP_TRELLISQUANT;
    }

    if (xvidenc->hqacpred) {
      xframe.vop_flags |= XVID_VOP_HQACPRED;
    }

    if (xvidenc->greyscale) {
      xframe.vop_flags |= XVID_VOP_GREYSCALE;
    }

    if (xvidenc->cartoon) {
      xframe.vop_flags |= XVID_VOP_CARTOON;
      xframe.motion |= XVID_ME_DETECT_STATIC_MOTION;
    }

    xframe.bframe_threshold = xvidenc->bframe_threshold;
    xframe.input.csp = xvidenc->csp;

    /* save in cache */
    xvidenc->xframe_cache = g_memdup (&xframe, sizeof (xframe));
  }

  outbuf = gst_xvidenc_encode (xvidenc, buf, xframe);

  if (!outbuf)                  /* error or no data yet */
    return GST_FLOW_OK;

  /* go out, multiply! */
  return gst_pad_push (xvidenc->srcpad, outbuf);
}
Esempio n. 5
0
static GstFlowReturn
gst_rtp_speex_pay_handle_buffer (GstBaseRTPPayload * basepayload,
    GstBuffer * buffer)
{
  GstRtpSPEEXPay *rtpspeexpay;
  guint size, payload_len;
  GstBuffer *outbuf;
  guint8 *payload, *data;
  GstClockTime timestamp, duration;
  GstFlowReturn ret;

  rtpspeexpay = GST_RTP_SPEEX_PAY (basepayload);

  size = GST_BUFFER_SIZE (buffer);
  data = GST_BUFFER_DATA (buffer);

  switch (rtpspeexpay->packet) {
    case 0:
      /* ident packet. We need to parse the headers to construct the RTP
       * properties. */
      if (!gst_rtp_speex_pay_parse_ident (rtpspeexpay, data, size))
        goto parse_error;

      ret = GST_FLOW_OK;
      goto done;
    case 1:
      /* comment packet, we ignore it */
      ret = GST_FLOW_OK;
      goto done;
    default:
      /* other packets go in the payload */
      break;
  }

  timestamp = GST_BUFFER_TIMESTAMP (buffer);
  duration = GST_BUFFER_DURATION (buffer);

  /* FIXME, only one SPEEX frame per RTP packet for now */
  payload_len = size;

  outbuf = gst_rtp_buffer_new_allocate (payload_len, 0, 0);
  /* FIXME, assert for now */
  g_assert (payload_len <= GST_BASE_RTP_PAYLOAD_MTU (rtpspeexpay));

  /* copy timestamp and duration */
  GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
  GST_BUFFER_DURATION (outbuf) = duration;

  /* get payload */
  payload = gst_rtp_buffer_get_payload (outbuf);

  /* copy data in payload */
  memcpy (&payload[0], data, size);

  ret = gst_basertppayload_push (basepayload, outbuf);

done:
  gst_buffer_unref (buffer);

  rtpspeexpay->packet++;

  return ret;

  /* ERRORS */
parse_error:
  {
    GST_ELEMENT_ERROR (rtpspeexpay, STREAM, DECODE, (NULL),
        ("Error parsing first identification packet."));
    gst_buffer_unref (buffer);
    return GST_FLOW_ERROR;
  }
}
HRESULT AudioFakeSink::DoRenderSample(IMediaSample *pMediaSample)
{
  GstBuffer *out_buf = NULL;
  gboolean in_seg = FALSE;
  GstClockTime buf_start, buf_stop;
  gint64 clip_start = 0, clip_stop = 0;
  guint start_offset = 0, stop_offset;
  GstClockTime duration;

  if(pMediaSample)
  {
    BYTE *pBuffer = NULL;
    LONGLONG lStart = 0, lStop = 0;
    long size = pMediaSample->GetActualDataLength();

    pMediaSample->GetPointer(&pBuffer);
    pMediaSample->GetTime(&lStart, &lStop);
    
    if (!GST_CLOCK_TIME_IS_VALID (mDec->timestamp)) {
      // Convert REFERENCE_TIME to GST_CLOCK_TIME
      mDec->timestamp = (GstClockTime)lStart * 100;
    }
    duration = (lStop - lStart) * 100;

    buf_start = mDec->timestamp;
    buf_stop = mDec->timestamp + duration;

    /* save stop position to start next buffer with it */
    mDec->timestamp = buf_stop;

    /* check if this buffer is in our current segment */
    in_seg = gst_segment_clip (mDec->segment, GST_FORMAT_TIME,
        buf_start, buf_stop, &clip_start, &clip_stop);

    /* if the buffer is out of segment do not push it downstream */
    if (!in_seg) {
      GST_DEBUG_OBJECT (mDec,
          "buffer is out of segment, start %" GST_TIME_FORMAT " stop %"
          GST_TIME_FORMAT, GST_TIME_ARGS (buf_start), GST_TIME_ARGS (buf_stop));
      goto done;
    }

    /* buffer is entirely or partially in-segment, so allocate a
     * GstBuffer for output, and clip if required */

    /* allocate a new buffer for raw audio */
    mDec->last_ret = gst_pad_alloc_buffer (mDec->srcpad, 
        GST_BUFFER_OFFSET_NONE,
        size,
        GST_PAD_CAPS (mDec->srcpad), &out_buf);
    if (!out_buf) {
      GST_WARNING_OBJECT (mDec, "cannot allocate a new GstBuffer");
      goto done;
    }

    /* set buffer properties */
    GST_BUFFER_TIMESTAMP (out_buf) = buf_start;
    GST_BUFFER_DURATION (out_buf) = duration;
    memcpy (GST_BUFFER_DATA (out_buf), pBuffer,
        MIN ((unsigned int)size, GST_BUFFER_SIZE (out_buf)));

    /* we have to remove some heading samples */
    if ((GstClockTime) clip_start > buf_start) {
      start_offset = (guint)gst_util_uint64_scale_int (clip_start - buf_start,
          mDec->rate, GST_SECOND) * mDec->depth / 8 * mDec->channels;
    }
    else
      start_offset = 0;
    /* we have to remove some trailing samples */
    if ((GstClockTime) clip_stop < buf_stop) {
      stop_offset = (guint)gst_util_uint64_scale_int (buf_stop - clip_stop,
          mDec->rate, GST_SECOND) * mDec->depth / 8 * mDec->channels;
    }
    else
      stop_offset = size;

    /* truncating */
    if ((start_offset != 0) || (stop_offset != (size_t) size)) {
      GstBuffer *subbuf = gst_buffer_create_sub (out_buf, start_offset,
          stop_offset - start_offset);

      if (subbuf) {
        gst_buffer_set_caps (subbuf, GST_PAD_CAPS (mDec->srcpad));
        gst_buffer_unref (out_buf);
        out_buf = subbuf;
      }
    }

    GST_BUFFER_TIMESTAMP (out_buf) = clip_start;
    GST_BUFFER_DURATION (out_buf) = clip_stop - clip_start;

    /* replace the saved stop position by the clipped one */
    mDec->timestamp = clip_stop;

    GST_DEBUG_OBJECT (mDec,
        "push_buffer (size %d)=> pts %" GST_TIME_FORMAT " stop %" GST_TIME_FORMAT
        " duration %" GST_TIME_FORMAT, size,
        GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (out_buf)),
        GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (out_buf) +
            GST_BUFFER_DURATION (out_buf)),
        GST_TIME_ARGS (GST_BUFFER_DURATION (out_buf)));

    mDec->last_ret = gst_pad_push (mDec->srcpad, out_buf);
  }

done:
  return S_OK;
}
Esempio n. 7
0
static GstFlowReturn
gst_tta_dec_chain (GstPad * pad, GstBuffer * in)
{
  GstTtaDec *ttadec;
  GstBuffer *outbuf, *buf = GST_BUFFER (in);
  guchar *data, *p;
  decoder *dec;
  unsigned long outsize;
  unsigned long size;
  guint32 frame_samples;
  long res;
  long *prev;

  ttadec = GST_TTA_DEC (GST_OBJECT_PARENT (pad));

  data = GST_BUFFER_DATA (buf);
  size = GST_BUFFER_SIZE (buf);

  ttadec->tta_buf.bit_count = 0;
  ttadec->tta_buf.bit_cache = 0;
  ttadec->tta_buf.bitpos = ttadec->tta_buf.buffer_end;
  ttadec->tta_buf.offset = 0;
  decoder_init (ttadec->tta, ttadec->channels, ttadec->bytes);

  if (GST_BUFFER_DURATION_IS_VALID (buf)) {
    frame_samples =
        ceil ((gdouble) (GST_BUFFER_DURATION (buf) * ttadec->samplerate) /
        (gdouble) GST_SECOND);
  } else {
    frame_samples = ttadec->samplerate * FRAME_TIME;
  }
  outsize = ttadec->channels * frame_samples * ttadec->bytes;

  dec = ttadec->tta;
  p = ttadec->decdata;
  prev = ttadec->cache;
  for (res = 0;
      p < ttadec->decdata + frame_samples * ttadec->channels * ttadec->bytes;) {
    unsigned long unary, binary, depth, k;
    long value, temp_value;
    fltst *fst = &dec->fst;
    adapt *rice = &dec->rice;
    long *last = &dec->last;

    // decode Rice unsigned
    get_unary (&ttadec->tta_buf, data, size, &unary);

    switch (unary) {
      case 0:
        depth = 0;
        k = rice->k0;
        break;
      default:
        depth = 1;
        k = rice->k1;
        unary--;
    }

    if (k) {
      get_binary (&ttadec->tta_buf, data, size, &binary, k);
      value = (unary << k) + binary;
    } else
      value = unary;

    switch (depth) {
      case 1:
        rice->sum1 += value - (rice->sum1 >> 4);
        if (rice->k1 > 0 && rice->sum1 < shift_16[rice->k1])
          rice->k1--;
        else if (rice->sum1 > shift_16[rice->k1 + 1])
          rice->k1++;
        value += bit_shift[rice->k0];
      default:
        rice->sum0 += value - (rice->sum0 >> 4);
        if (rice->k0 > 0 && rice->sum0 < shift_16[rice->k0])
          rice->k0--;
        else if (rice->sum0 > shift_16[rice->k0 + 1])
          rice->k0++;
    }

    /* this only uses a temporary variable to silence a gcc warning */
    temp_value = DEC (value);
    value = temp_value;

    // decompress stage 1: adaptive hybrid filter
    hybrid_filter (fst, &value);

    // decompress stage 2: fixed order 1 prediction
    switch (ttadec->bytes) {
      case 1:
        value += PREDICTOR1 (*last, 4);
        break;                  // bps 8
      case 2:
        value += PREDICTOR1 (*last, 5);
        break;                  // bps 16
      case 3:
        value += PREDICTOR1 (*last, 5);
        break;                  // bps 24
      case 4:
        value += *last;
        break;                  // bps 32
    }
    *last = value;

    if (dec < ttadec->tta + ttadec->channels - 1) {
      *prev++ = value;
      dec++;
    } else {
      *prev = value;
      if (ttadec->channels > 1) {
        long *r = prev - 1;

        for (*prev += *r / 2; r >= ttadec->cache; r--)
          *r = *(r + 1) - *r;
        for (r = ttadec->cache; r < prev; r++)
          WRITE_BUFFER (r, ttadec->bytes, p);
      }
      WRITE_BUFFER (prev, ttadec->bytes, p);
      prev = ttadec->cache;
      res++;
      dec = ttadec->tta;
    }
  }

  outbuf = gst_buffer_new_and_alloc (outsize);
  memcpy (GST_BUFFER_DATA (outbuf), ttadec->decdata, outsize);
  GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
  GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
  gst_buffer_set_caps (outbuf, GST_PAD_CAPS (ttadec->srcpad));
  return gst_pad_push (ttadec->srcpad, outbuf);
}
Esempio n. 8
0
static gboolean
gst_aiff_parse_parse_comm (GstAiffParse * aiff, GstBuffer * buf)
{
  guint8 *data;
  int size;

  if (aiff->is_aifc)
    size = 22;
  else
    size = 18;

  if (GST_BUFFER_SIZE (buf) < size) {
    GST_WARNING_OBJECT (aiff, "COMM chunk too short, cannot parse header");
    return FALSE;
  }

  data = GST_BUFFER_DATA (buf);

  aiff->channels = GST_READ_UINT16_BE (data);
  aiff->total_frames = GST_READ_UINT32_BE (data + 2);
  aiff->depth = GST_READ_UINT16_BE (data + 6);
  aiff->width = GST_ROUND_UP_8 (aiff->depth);
  aiff->rate = (int) gst_aiff_parse_read_IEEE80 (data + 8);

  aiff->floating_point = FALSE;

  if (aiff->is_aifc) {
    guint32 fourcc = GST_READ_UINT32_LE (data + 18);

    /* We only support the 'trivial' uncompressed AIFC, but it can be
     * either big or little endian */
    switch (fourcc) {
      case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
        aiff->endianness = G_BIG_ENDIAN;
        break;
      case GST_MAKE_FOURCC ('s', 'o', 'w', 't'):
        aiff->endianness = G_LITTLE_ENDIAN;
        break;
      case GST_MAKE_FOURCC ('F', 'L', '3', '2'):
      case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
        aiff->floating_point = TRUE;
        aiff->width = aiff->depth = 32;
        aiff->endianness = G_BIG_ENDIAN;
        break;
      case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
        aiff->floating_point = TRUE;
        aiff->width = aiff->depth = 64;
        aiff->endianness = G_BIG_ENDIAN;
        break;
      default:
        GST_WARNING_OBJECT (aiff, "Unsupported compression in AIFC "
            "file: %" GST_FOURCC_FORMAT,
            GST_FOURCC_ARGS (GST_READ_UINT32_LE (data + 18)));
        return FALSE;

    }
  } else
    aiff->endianness = G_BIG_ENDIAN;

  return TRUE;
}
Esempio n. 9
0
static GstFlowReturn
gst_aiff_parse_stream_headers (GstAiffParse * aiff)
{
  GstFlowReturn res;
  GstBuffer *buf;
  guint32 tag, size;
  gboolean gotdata = FALSE;
  gboolean done = FALSE;
  GstEvent **event_p;
  GstFormat bformat;
  gint64 upstream_size = 0;

  bformat = GST_FORMAT_BYTES;
  gst_pad_query_peer_duration (aiff->sinkpad, &bformat, &upstream_size);
  GST_DEBUG_OBJECT (aiff, "upstream size %" G_GUINT64_FORMAT, upstream_size);

  /* loop headers until we get data */
  while (!done) {
    if (aiff->streaming) {
      if (!gst_aiff_parse_peek_chunk_info (aiff, &tag, &size))
        return GST_FLOW_OK;
    } else {
      if ((res =
              gst_pad_pull_range (aiff->sinkpad, aiff->offset, 8,
                  &buf)) != GST_FLOW_OK)
        goto header_read_error;
      tag = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf));
      size = GST_READ_UINT32_BE (GST_BUFFER_DATA (buf) + 4);
    }

    GST_INFO_OBJECT (aiff,
        "Got TAG: %" GST_FOURCC_FORMAT ", offset %" G_GUINT64_FORMAT,
        GST_FOURCC_ARGS (tag), aiff->offset);

    /* We just keep reading chunks until we find the one we're interested in.
     */
    switch (tag) {
      case GST_MAKE_FOURCC ('C', 'O', 'M', 'M'):{
        if (aiff->streaming) {
          if (!gst_aiff_parse_peek_chunk (aiff, &tag, &size))
            return GST_FLOW_OK;

          gst_adapter_flush (aiff->adapter, 8);
          aiff->offset += 8;

          buf = gst_adapter_take_buffer (aiff->adapter, size);
        } else {
          if ((res = gst_aiff_parse_read_chunk (aiff,
                      &aiff->offset, &tag, &buf)) != GST_FLOW_OK)
            return res;
        }

        if (!gst_aiff_parse_parse_comm (aiff, buf)) {
          gst_buffer_unref (buf);
          goto parse_header_error;
        }

        gst_buffer_unref (buf);

        /* do sanity checks of header fields */
        if (aiff->channels == 0)
          goto no_channels;
        if (aiff->rate == 0)
          goto no_rate;

        GST_DEBUG_OBJECT (aiff, "creating the caps");

        aiff->caps = gst_aiff_parse_create_caps (aiff);
        if (!aiff->caps)
          goto unknown_format;

        gst_pad_set_caps (aiff->srcpad, aiff->caps);

        aiff->bytes_per_sample = aiff->channels * aiff->width / 8;
        aiff->bps = aiff->bytes_per_sample * aiff->rate;

        if (aiff->bytes_per_sample <= 0)
          goto no_bytes_per_sample;

        aiff->got_comm = TRUE;
        break;
      }
      case GST_MAKE_FOURCC ('S', 'S', 'N', 'D'):{
        GstBuffer *ssndbuf = NULL;
        const guint8 *ssnddata = NULL;
        guint32 datasize;

        GST_DEBUG_OBJECT (aiff, "Got 'SSND' TAG, size : %d", size);

        /* Now, read the 8-byte header in the SSND chunk */
        if (aiff->streaming) {
          if (!gst_aiff_parse_peek_data (aiff, 16, &ssnddata))
            return GST_FLOW_OK;
        } else {
          gst_buffer_unref (buf);
          if ((res =
                  gst_pad_pull_range (aiff->sinkpad, aiff->offset, 16,
                      &ssndbuf)) != GST_FLOW_OK)
            goto header_read_error;
          ssnddata = GST_BUFFER_DATA (ssndbuf);
        }

        aiff->ssnd_offset = GST_READ_UINT32_BE (ssnddata + 8);
        aiff->ssnd_blocksize = GST_READ_UINT32_BE (ssnddata + 12);

        gotdata = TRUE;
        if (aiff->streaming) {
          gst_adapter_flush (aiff->adapter, 16);
        } else {
          gst_buffer_unref (ssndbuf);
        }
        /* 8 byte chunk header, 8 byte SSND header */
        aiff->offset += 16;

        datasize = size - 16;

        aiff->datastart = aiff->offset + aiff->ssnd_offset;
        /* file might be truncated */
        if (upstream_size) {
          size = MIN (datasize, (upstream_size - aiff->datastart));
        }
        aiff->datasize = (guint64) datasize;
        aiff->dataleft = (guint64) datasize;
        aiff->end_offset = datasize + aiff->datastart;
        if (!aiff->streaming) {
          /* We will continue looking at chunks until the end - to read tags,
           * etc. */
          aiff->offset += datasize;
        }
        GST_DEBUG_OBJECT (aiff, "datasize = %d", datasize);
        if (aiff->streaming) {
          done = TRUE;
        }
        break;
      }
      case GST_MAKE_FOURCC ('I', 'D', '3', ' '):{
        GstTagList *tags;

        if (aiff->streaming) {
          if (!gst_aiff_parse_peek_chunk (aiff, &tag, &size))
            return GST_FLOW_OK;

          gst_adapter_flush (aiff->adapter, 8);
          aiff->offset += 8;

          buf = gst_adapter_take_buffer (aiff->adapter, size);
        } else {
          if ((res = gst_aiff_parse_read_chunk (aiff,
                      &aiff->offset, &tag, &buf)) != GST_FLOW_OK)
            return res;
        }

        GST_LOG_OBJECT (aiff, "ID3 chunk of size %u", GST_BUFFER_SIZE (buf));

        tags = gst_tag_list_from_id3v2_tag (buf);
        gst_buffer_unref (buf);

        GST_INFO_OBJECT (aiff, "ID3 tags: %" GST_PTR_FORMAT, tags);

        if (aiff->tags == NULL) {
          aiff->tags = tags;
        } else {
          gst_tag_list_insert (aiff->tags, tags, GST_TAG_MERGE_APPEND);
          gst_tag_list_free (tags);
        }
        break;
      }
      default:
        gst_aiff_parse_ignore_chunk (aiff, buf, tag, size);
    }

    if (upstream_size && (aiff->offset >= upstream_size)) {
      /* Now we have gone through the whole file */
      done = TRUE;
    }
  }

  /* We read all the chunks (in pull mode) or reached the SSND chunk
   * (in push mode). We must have both COMM and SSND now; error out 
   * otherwise.
   */
  if (!aiff->got_comm) {
    GST_WARNING_OBJECT (aiff, "Failed to find COMM chunk");
    goto no_header;
  }
  if (!gotdata) {
    GST_WARNING_OBJECT (aiff, "Failed to find SSND chunk");
    goto no_data;
  }

  GST_DEBUG_OBJECT (aiff, "Finished parsing headers");

  if (gst_aiff_parse_calculate_duration (aiff)) {
    gst_segment_init (&aiff->segment, GST_FORMAT_TIME);
    gst_segment_set_duration (&aiff->segment, GST_FORMAT_TIME, aiff->duration);
  } else {
    /* no bitrate, let downstream peer do the math, we'll feed it bytes. */
    gst_segment_init (&aiff->segment, GST_FORMAT_BYTES);
    gst_segment_set_duration (&aiff->segment, GST_FORMAT_BYTES, aiff->datasize);
  }

  /* now we have all the info to perform a pending seek if any, if no
   * event, this will still do the right thing and it will also send
   * the right newsegment event downstream. */
  gst_aiff_parse_perform_seek (aiff, aiff->seek_event);
  /* remove pending event */
  event_p = &aiff->seek_event;
  gst_event_replace (event_p, NULL);

  /* we just started, we are discont */
  aiff->discont = TRUE;

  aiff->state = AIFF_PARSE_DATA;

  return GST_FLOW_OK;

  /* ERROR */
no_header:
  {
    GST_ELEMENT_ERROR (aiff, STREAM, TYPE_NOT_FOUND, (NULL),
        ("Invalid AIFF header (no COMM found)"));
    return GST_FLOW_ERROR;
  }
no_data:
  {
    GST_ELEMENT_ERROR (aiff, STREAM, TYPE_NOT_FOUND, (NULL),
        ("Invalid AIFF: no SSND found"));
    return GST_FLOW_ERROR;
  }
parse_header_error:
  {
    GST_ELEMENT_ERROR (aiff, STREAM, DEMUX, (NULL),
        ("Couldn't parse audio header"));
    return GST_FLOW_ERROR;
  }
no_channels:
  {
    GST_ELEMENT_ERROR (aiff, STREAM, FAILED, (NULL),
        ("Stream claims to contain no channels - invalid data"));
    return GST_FLOW_ERROR;
  }
no_rate:
  {
    GST_ELEMENT_ERROR (aiff, STREAM, FAILED, (NULL),
        ("Stream with sample_rate == 0 - invalid data"));
    return GST_FLOW_ERROR;
  }
no_bytes_per_sample:
  {
    GST_ELEMENT_ERROR (aiff, STREAM, FAILED, (NULL),
        ("Could not caluclate bytes per sample - invalid data"));
    return GST_FLOW_ERROR;
  }
unknown_format:
  {
    GST_ELEMENT_ERROR (aiff, STREAM, TYPE_NOT_FOUND, (NULL),
        ("No caps found for format 0x%x, %d channels, %d Hz",
            aiff->format, aiff->channels, aiff->rate));
    return GST_FLOW_ERROR;
  }
header_read_error:
  {
    GST_ELEMENT_ERROR (aiff, STREAM, DEMUX, (NULL),
        ("Couldn't read in header"));
    return GST_FLOW_ERROR;
  }
}
Esempio n. 10
0
/* protected helper method which can be used by derived classes:
 */
GstFlowReturn
gst_omx_base_src_create_from_port (GstOmxBaseSrc *self,
                                   GOmxPort *out_port,
                                   GstBuffer **ret_buf)
{
    GOmxCore *gomx;
    GstFlowReturn ret = GST_FLOW_OK;

    gomx = self->gomx;

    GST_LOG_OBJECT (self, "begin");

    if (out_port->enabled)
    {
        if (G_UNLIKELY (gomx->omx_state == OMX_StateIdle))
        {
            GST_INFO_OBJECT (self, "omx: play");
            g_omx_core_start (gomx);
        }

        if (G_UNLIKELY (gomx->omx_state != OMX_StateExecuting))
        {
            GST_ERROR_OBJECT (self, "Whoa! very wrong");
            ret = GST_FLOW_ERROR;
            goto beach;
        }

        while (out_port->enabled)
        {
            gpointer obj = g_omx_port_recv (out_port);

            if (G_UNLIKELY (!obj))
            {
                ret = GST_FLOW_ERROR;
                break;
            }

            if (G_LIKELY (GST_IS_BUFFER (obj)))
            {
                GstBuffer *buf = GST_BUFFER (obj);
                if (G_LIKELY (GST_BUFFER_SIZE (buf) > 0))
                {
                    PRINT_BUFFER (self, buf);
                    *ret_buf = buf;
                    break;
                }
            }
            else if (GST_IS_EVENT (obj))
            {
                GST_INFO_OBJECT (self, "got eos");
                g_omx_core_set_done (gomx);
                break;
            }
        }
    }

    if (!out_port->enabled)
    {
        GST_WARNING_OBJECT (self, "done");
        ret = GST_FLOW_UNEXPECTED;
    }

beach:

    GST_LOG_OBJECT (self, "end");

    return ret;
}
Esempio n. 11
0
static GstFlowReturn
gst_aiff_parse_stream_data (GstAiffParse * aiff)
{
  GstBuffer *buf = NULL;
  GstFlowReturn res = GST_FLOW_OK;
  guint64 desired, obtained;
  GstClockTime timestamp, next_timestamp, duration;
  guint64 pos, nextpos;

iterate_adapter:
  GST_LOG_OBJECT (aiff,
      "offset: %" G_GINT64_FORMAT " , end: %" G_GINT64_FORMAT " , dataleft: %"
      G_GINT64_FORMAT, aiff->offset, aiff->end_offset, aiff->dataleft);

  /* Get the next n bytes and output them */
  if (aiff->dataleft == 0 || aiff->dataleft < aiff->bytes_per_sample)
    goto found_eos;

  /* scale the amount of data by the segment rate so we get equal
   * amounts of data regardless of the playback rate */
  desired =
      MIN (gst_guint64_to_gdouble (aiff->dataleft),
      MAX_BUFFER_SIZE * aiff->segment.abs_rate);

  if (desired >= aiff->bytes_per_sample && aiff->bytes_per_sample > 0)
    desired -= (desired % aiff->bytes_per_sample);

  GST_LOG_OBJECT (aiff, "Fetching %" G_GINT64_FORMAT " bytes of data "
      "from the sinkpad", desired);

  if (aiff->streaming) {
    guint avail = gst_adapter_available (aiff->adapter);

    if (avail < desired) {
      GST_LOG_OBJECT (aiff, "Got only %d bytes of data from the sinkpad",
          avail);
      return GST_FLOW_OK;
    }

    buf = gst_adapter_take_buffer (aiff->adapter, desired);
  } else {
    if ((res = gst_pad_pull_range (aiff->sinkpad, aiff->offset,
                desired, &buf)) != GST_FLOW_OK)
      goto pull_error;
  }

  /* If we have a pending close/start segment, send it now. */
  if (G_UNLIKELY (aiff->close_segment != NULL)) {
    gst_pad_push_event (aiff->srcpad, aiff->close_segment);
    aiff->close_segment = NULL;
  }
  if (G_UNLIKELY (aiff->start_segment != NULL)) {
    gst_pad_push_event (aiff->srcpad, aiff->start_segment);
    aiff->start_segment = NULL;
  }
  if (G_UNLIKELY (aiff->tags != NULL)) {
    gst_element_found_tags_for_pad (GST_ELEMENT_CAST (aiff), aiff->srcpad,
        aiff->tags);
    aiff->tags = NULL;
  }

  obtained = GST_BUFFER_SIZE (buf);

  /* our positions in bytes */
  pos = aiff->offset - aiff->datastart;
  nextpos = pos + obtained;

  /* update offsets, does not overflow. */
  GST_BUFFER_OFFSET (buf) = pos / aiff->bytes_per_sample;
  GST_BUFFER_OFFSET_END (buf) = nextpos / aiff->bytes_per_sample;

  if (aiff->bps > 0) {
    /* and timestamps if we have a bitrate, be careful for overflows */
    timestamp =
        gst_util_uint64_scale_ceil (pos, GST_SECOND, (guint64) aiff->bps);
    next_timestamp =
        gst_util_uint64_scale_ceil (nextpos, GST_SECOND, (guint64) aiff->bps);
    duration = next_timestamp - timestamp;

    /* update current running segment position */
    gst_segment_set_last_stop (&aiff->segment, GST_FORMAT_TIME, next_timestamp);
  } else {
    /* no bitrate, all we know is that the first sample has timestamp 0, all
     * other positions and durations have unknown timestamp. */
    if (pos == 0)
      timestamp = 0;
    else
      timestamp = GST_CLOCK_TIME_NONE;
    duration = GST_CLOCK_TIME_NONE;
    /* update current running segment position with byte offset */
    gst_segment_set_last_stop (&aiff->segment, GST_FORMAT_BYTES, nextpos);
  }
  if (aiff->discont) {
    GST_DEBUG_OBJECT (aiff, "marking DISCONT");
    GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
    aiff->discont = FALSE;
  }

  GST_BUFFER_TIMESTAMP (buf) = timestamp;
  GST_BUFFER_DURATION (buf) = duration;
  gst_buffer_set_caps (buf, aiff->caps);

  GST_LOG_OBJECT (aiff,
      "Got buffer. timestamp:%" GST_TIME_FORMAT " , duration:%" GST_TIME_FORMAT
      ", size:%u", GST_TIME_ARGS (timestamp), GST_TIME_ARGS (duration),
      GST_BUFFER_SIZE (buf));

  if ((res = gst_pad_push (aiff->srcpad, buf)) != GST_FLOW_OK)
    goto push_error;

  if (obtained < aiff->dataleft) {
    aiff->offset += obtained;
    aiff->dataleft -= obtained;
  } else {
    aiff->offset += aiff->dataleft;
    aiff->dataleft = 0;
  }

  /* Iterate until need more data, so adapter size won't grow */
  if (aiff->streaming) {
    GST_LOG_OBJECT (aiff,
        "offset: %" G_GINT64_FORMAT " , end: %" G_GINT64_FORMAT, aiff->offset,
        aiff->end_offset);
    goto iterate_adapter;
  }
  return res;

  /* ERROR */
found_eos:
  {
    GST_DEBUG_OBJECT (aiff, "found EOS");
    return GST_FLOW_UNEXPECTED;
  }
pull_error:
  {
    /* check if we got EOS */
    if (res == GST_FLOW_UNEXPECTED)
      goto found_eos;

    GST_WARNING_OBJECT (aiff,
        "Error getting %" G_GINT64_FORMAT " bytes from the "
        "sinkpad (dataleft = %" G_GINT64_FORMAT ")", desired, aiff->dataleft);
    return res;
  }
push_error:
  {
    GST_INFO_OBJECT (aiff,
        "Error pushing on srcpad %s:%s, reason %s, is linked? = %d",
        GST_DEBUG_PAD_NAME (aiff->srcpad), gst_flow_get_name (res),
        gst_pad_is_linked (aiff->srcpad));
    return res;
  }
}
Esempio n. 12
0
/**
 * gst_tag_list_from_xmp_buffer:
 * @buffer: buffer
 *
 * Parse a xmp packet into a taglist.
 *
 * Returns: new taglist or %NULL, free the list when done
 *
 * Since: 0.10.29
 */
GstTagList *
gst_tag_list_from_xmp_buffer (const GstBuffer * buffer)
{
  GstTagList *list = NULL;
  const gchar *xps, *xp1, *xp2, *xpe, *ns, *ne;
  guint len, max_ft_len;
  gboolean in_tag;
  gchar *part, *pp;
  guint i;
  const gchar *last_tag = NULL;
  XmpTag *last_xmp_tag = NULL;
  GSList *pending_tags = NULL;

  xmp_tags_initialize ();

  g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
  g_return_val_if_fail (GST_BUFFER_SIZE (buffer) > 0, NULL);

  xps = (const gchar *) GST_BUFFER_DATA (buffer);
  len = GST_BUFFER_SIZE (buffer);
  xpe = &xps[len + 1];

  /* check header and footer */
  xp1 = g_strstr_len (xps, len, "<?xpacket begin");
  if (!xp1)
    goto missing_header;
  xp1 = &xp1[strlen ("<?xpacket begin")];
  while (*xp1 != '>' && *xp1 != '<' && xp1 < xpe)
    xp1++;
  if (*xp1 != '>')
    goto missing_header;

  max_ft_len = 1 + strlen ("<?xpacket end=\".\"?>\n");
  if (len < max_ft_len)
    goto missing_footer;

  GST_DEBUG ("checking footer: [%s]", &xps[len - max_ft_len]);
  xp2 = g_strstr_len (&xps[len - max_ft_len], max_ft_len, "<?xpacket ");
  if (!xp2)
    goto missing_footer;

  GST_INFO ("xmp header okay");

  /* skip > and text until first xml-node */
  xp1++;
  while (*xp1 != '<' && xp1 < xpe)
    xp1++;

  /* no tag can be longer that the whole buffer */
  part = g_malloc (xp2 - xp1);
  list = gst_tag_list_new ();

  /* parse data into a list of nodes */
  /* data is between xp1..xp2 */
  in_tag = TRUE;
  ns = ne = xp1;
  pp = part;
  while (ne < xp2) {
    if (in_tag) {
      ne++;
      while (ne < xp2 && *ne != '>' && *ne != '<') {
        if (*ne == '\n' || *ne == '\t' || *ne == ' ') {
          while (ne < xp2 && (*ne == '\n' || *ne == '\t' || *ne == ' '))
            ne++;
          *pp++ = ' ';
        } else {
          *pp++ = *ne++;
        }
      }
      *pp = '\0';
      if (*ne != '>')
        goto broken_xml;
      /* create node */
      /* {XML, ns, ne-ns} */
      if (ns[0] != '/') {
        gchar *as = strchr (part, ' ');
        /* only log start nodes */
        GST_INFO ("xml: %s", part);

        if (as) {
          gchar *ae, *d;

          /* skip ' ' and scan the attributes */
          as++;
          d = ae = as;

          /* split attr=value pairs */
          while (*ae != '\0') {
            if (*ae == '=') {
              /* attr/value delimmiter */
              d = ae;
            } else if (*ae == '"') {
              /* scan values */
              gchar *v;

              ae++;
              while (*ae != '\0' && *ae != '"')
                ae++;

              *d = *ae = '\0';
              v = &d[2];
              GST_INFO ("   : [%s][%s]", as, v);
              if (!strncmp (as, "xmlns:", 6)) {
                i = 0;
                /* we need to rewrite known namespaces to what we use in
                 * tag_matches */
                while (ns_match[i].ns_prefix) {
                  if (!strcmp (ns_match[i].ns_uri, v))
                    break;
                  i++;
                }
                if (ns_match[i].ns_prefix) {
                  if (strcmp (ns_map[i].original_ns, &as[6])) {
                    ns_map[i].gstreamer_ns = g_strdup (&as[6]);
                  }
                }
              } else {
                const gchar *gst_tag;
                XmpTag *xmp_tag = NULL;
                /* FIXME: eventualy rewrite ns
                 * find ':'
                 * check if ns before ':' is in ns_map and ns_map[i].gstreamer_ns!=NULL
                 * do 2 stage filter in tag_matches
                 */
                gst_tag = _xmp_tag_get_mapping_reverse (as, &xmp_tag);
                if (gst_tag) {
                  PendingXmpTag *ptag;

                  ptag = g_slice_new (PendingXmpTag);
                  ptag->gst_tag = gst_tag;
                  ptag->xmp_tag = xmp_tag;
                  ptag->str = g_strdup (v);

                  pending_tags = g_slist_append (pending_tags, ptag);
                }
              }
              /* restore chars overwritten by '\0' */
              *d = '=';
              *ae = '"';
            } else if (*ae == '\0' || *ae == ' ') {
              /* end of attr/value pair */
              as = &ae[1];
            }
            /* to next char if not eos */
            if (*ae != '\0')
              ae++;
          }
        } else {
          /*
             <dc:type><rdf:Bag><rdf:li>Image</rdf:li></rdf:Bag></dc:type>
             <dc:creator><rdf:Seq><rdf:li/></rdf:Seq></dc:creator>
           */
          /* FIXME: eventualy rewrite ns */

          /* skip rdf tags for now */
          if (strncmp (part, "rdf:", 4)) {
            const gchar *parttag;

            parttag = _xmp_tag_get_mapping_reverse (part, &last_xmp_tag);
            if (parttag) {
              last_tag = parttag;
            }
          }
        }
      }
      /* next cycle */
      ne++;
      if (ne < xp2) {
        if (*ne != '<')
          in_tag = FALSE;
        ns = ne;
        pp = part;
      }
    } else {
      while (ne < xp2 && *ne != '<') {
        *pp++ = *ne;
        ne++;
      }
      *pp = '\0';
      /* create node */
      /* {TXT, ns, (ne-ns)-1} */
      if (ns[0] != '\n' && &ns[1] <= ne) {
        /* only log non-newline nodes, we still have to parse them */
        GST_INFO ("txt: %s", part);
        if (last_tag) {
          PendingXmpTag *ptag;

          ptag = g_slice_new (PendingXmpTag);
          ptag->gst_tag = last_tag;
          ptag->xmp_tag = last_xmp_tag;
          ptag->str = g_strdup (part);

          pending_tags = g_slist_append (pending_tags, ptag);
        }
      }
      /* next cycle */
      in_tag = TRUE;
      ns = ne;
      pp = part;
    }
  }

  while (pending_tags) {
    PendingXmpTag *ptag = (PendingXmpTag *) pending_tags->data;

    pending_tags = g_slist_delete_link (pending_tags, pending_tags);

    read_one_tag (list, ptag->gst_tag, ptag->xmp_tag, ptag->str, &pending_tags);

    g_free (ptag->str);
    g_slice_free (PendingXmpTag, ptag);
  }

  GST_INFO ("xmp packet parsed, %d entries",
      gst_structure_n_fields ((GstStructure *) list));

  /* free resources */
  i = 0;
  while (ns_map[i].original_ns) {
    g_free (ns_map[i].gstreamer_ns);
    i++;
  }
  g_free (part);

  return list;

  /* Errors */
missing_header:
  GST_WARNING ("malformed xmp packet header");
  return NULL;
missing_footer:
  GST_WARNING ("malformed xmp packet footer");
  return NULL;
broken_xml:
  GST_WARNING ("malformed xml tag: %s", part);
  return NULL;
}
Esempio n. 13
0
static gboolean
spc_setup (GstSpcDec * spc)
{
  spc_tag_info *info;
  GstTagList *taglist;
  guint64 total_duration;

  if (!spc->buf || !spc_negotiate (spc)) {
    return FALSE;
  }

  info = &(spc->tag_info);

  spc_tag_get_info (GST_BUFFER_DATA (spc->buf), GST_BUFFER_SIZE (spc->buf),
      info);

  taglist = gst_tag_list_new ();

  if (info->title)
    gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_TITLE,
        info->title, NULL);
  if (info->artist)
    gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_ARTIST,
        info->artist, NULL);
  /* Prefer the name of the official soundtrack over the name of the game (since this is
   * how track numbers are derived)
   */
  if (info->album)
    gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_ALBUM,
        info->album, NULL);
  else if (info->game)
    gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_ALBUM, info->game,
        NULL);
  if (info->year) {
    GDate *date = g_date_new_dmy (1, 1, info->year);

    gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_DATE, date, NULL);
    g_date_free (date);
  }
  if (info->track) {
    gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_TRACK_NUMBER,
        info->track, NULL);
  }
  if (info->comment)
    gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_COMMENT,
        info->comment, NULL);
  if (info->disc)
    gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
        GST_TAG_ALBUM_VOLUME_NUMBER, info->disc, NULL);
  if (info->publisher)
    gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_ORGANIZATION,
        info->publisher, NULL);
  if (info->dumper)
    gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_CONTACT,
        info->dumper, NULL);
  if (info->emulator)
    gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER,
        info->emulator == EMU_ZSNES ? "ZSNES" : "Snes9x", NULL);

  total_duration = (guint64) (gst_spc_duration (spc) + gst_spc_fadeout (spc));

  gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
      GST_TAG_DURATION, total_duration,
      GST_TAG_GENRE, "Game", GST_TAG_CODEC, "SPC700", NULL);

  gst_element_found_tags_for_pad (GST_ELEMENT (spc), spc->srcpad, taglist);

  /* spc_tag_info_free(&info); */


  if (OSPC_Init (GST_BUFFER_DATA (spc->buf), GST_BUFFER_SIZE (spc->buf)) != 0) {
    return FALSE;
  }

  gst_pad_push_event (spc->srcpad, gst_event_new_new_segment (FALSE, 1.0,
          GST_FORMAT_TIME, 0, -1, 0));

  gst_pad_start_task (spc->srcpad, (GstTaskFunction) spc_play, spc->srcpad);

  /* We can't unreference this buffer because we might need to re-initialize
   * the emulator with the original data during a reverse seek
   * gst_buffer_unref (spc->buf);
   * spc->buf = NULL;
   */
  spc->initialized = TRUE;
  spc->seeking = FALSE;
  spc->seekpoint = 0;
  spc->byte_pos = 0;
  return spc->initialized;
}
Esempio n. 14
0
static void
spc_play (GstPad * pad)
{
  GstSpcDec *spc = GST_SPC_DEC (gst_pad_get_parent (pad));
  GstFlowReturn flow_return;
  GstBuffer *out;
  gboolean seeking = spc->seeking;
  gint64 duration, fade, end, position;

  if (!seeking) {
    out = gst_buffer_new_and_alloc (1600 * 4);
    gst_buffer_set_caps (out, GST_PAD_CAPS (pad));
    GST_BUFFER_TIMESTAMP (out) =
        (gint64) gst_util_uint64_scale ((guint64) spc->byte_pos, GST_SECOND,
        32000 * 2 * 2);
    spc->byte_pos += OSPC_Run (-1, (short *) GST_BUFFER_DATA (out), 1600 * 4);
  } else {
    if (spc->seekpoint < spc->byte_pos) {
      OSPC_Init (GST_BUFFER_DATA (spc->buf), GST_BUFFER_SIZE (spc->buf));
      spc->byte_pos = 0;
    }
    spc->byte_pos += OSPC_Run (-1, NULL, 1600 * 4);
    if (spc->byte_pos >= spc->seekpoint) {
      spc->seeking = FALSE;
    }
    out = gst_buffer_new ();
    gst_buffer_set_caps (out, GST_PAD_CAPS (pad));
  }

  duration = gst_spc_duration (spc);
  fade = gst_spc_fadeout (spc);
  end = duration + fade;
  position =
      (gint64) gst_util_uint64_scale ((guint64) spc->byte_pos, GST_SECOND,
      32000 * 2 * 2);

  if (position >= duration) {
    gint16 *data = (gint16 *) GST_BUFFER_DATA (out);
    guint32 size = GST_BUFFER_SIZE (out) / sizeof (gint16);
    unsigned int i;

    gint64 num = (fade - (position - duration));

    for (i = 0; i < size; i++) {
      /* Apply a parabolic volume envelope */
      data[i] = (gint16) (data[i] * num / fade * num / fade);
    }
  }

  if ((flow_return = gst_pad_push (spc->srcpad, out)) != GST_FLOW_OK) {
    GST_DEBUG_OBJECT (spc, "pausing task, reason %s",
        gst_flow_get_name (flow_return));

    gst_pad_pause_task (pad);

    if (flow_return <= GST_FLOW_UNEXPECTED
        || flow_return == GST_FLOW_NOT_LINKED) {
      gst_pad_push_event (pad, gst_event_new_eos ());
    }
  }

  if (position >= end) {
    gst_pad_pause_task (pad);
    gst_pad_push_event (pad, gst_event_new_eos ());
  }

  gst_object_unref (spc);

  return;
}
Esempio n. 15
0
static gboolean
gst_vdp_h264_dec_set_sink_caps (GstBaseVideoDecoder * base_video_decoder,
    GstCaps * caps)
{
  GstVdpH264Dec *h264_dec;
  GstStructure *structure;
  const GValue *value;

  h264_dec = GST_VDP_H264_DEC (base_video_decoder);

  structure = gst_caps_get_structure (caps, 0);
  /* packetized video has a codec_data */
  if ((value = gst_structure_get_value (structure, "codec_data"))) {
    GstBuffer *buf;
    GstBitReader reader;
    guint8 version;
    guint8 n_sps, n_pps;
    gint i;

    GST_DEBUG_OBJECT (h264_dec, "have packetized h264");
    h264_dec->packetized = TRUE;

    buf = gst_value_get_buffer (value);
    GST_MEMDUMP ("avcC:", GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));

    /* parse the avcC data */
    if (GST_BUFFER_SIZE (buf) < 7) {
      GST_ERROR_OBJECT (h264_dec, "avcC size %u < 7", GST_BUFFER_SIZE (buf));
      return FALSE;
    }

    gst_bit_reader_init_from_buffer (&reader, buf);

    READ_UINT8 (&reader, version, 8);
    if (version != 1)
      return FALSE;

    SKIP (&reader, 30);

    READ_UINT8 (&reader, h264_dec->nal_length_size, 2);
    h264_dec->nal_length_size += 1;
    GST_DEBUG_OBJECT (h264_dec, "nal length %u", h264_dec->nal_length_size);

    SKIP (&reader, 3);

    READ_UINT8 (&reader, n_sps, 5);
    for (i = 0; i < n_sps; i++) {
      guint16 sps_length;
      guint8 *data;

      READ_UINT16 (&reader, sps_length, 16);
      sps_length -= 1;
      SKIP (&reader, 8);

      data = GST_BUFFER_DATA (buf) + gst_bit_reader_get_pos (&reader) / 8;
      if (!gst_h264_parser_parse_sequence (h264_dec->parser, data, sps_length))
        return FALSE;

      SKIP (&reader, sps_length * 8);
    }

    READ_UINT8 (&reader, n_pps, 8);
    for (i = 0; i < n_pps; i++) {
      guint16 pps_length;
      guint8 *data;

      READ_UINT16 (&reader, pps_length, 16);
      pps_length -= 1;
      SKIP (&reader, 8);

      data = GST_BUFFER_DATA (buf) + gst_bit_reader_get_pos (&reader) / 8;
      if (!gst_h264_parser_parse_picture (h264_dec->parser, data, pps_length))
        return FALSE;

      SKIP (&reader, pps_length * 8);
    }
  }

  return TRUE;
}
Esempio n. 16
0
/**
 * gst_tag_image_data_to_image_buffer:
 * @image_data: the (encoded) image
 * @image_data_len: the length of the encoded image data at @image_data
 * @image_type: type of the image, or #GST_TAG_IMAGE_TYPE_UNDEFINED. Pass
 *     #GST_TAG_IMAGE_TYPE_NONE if no image type should be set at all (e.g.
 *     for preview images)
 *
 * Helper function for tag-reading plugins to create a #GstBuffer suitable to
 * add to a #GstTagList as an image tag (such as #GST_TAG_IMAGE or
 * #GST_TAG_PREVIEW_IMAGE) from the encoded image data and an (optional) image
 * type.
 *
 * Background: cover art and other images in tags are usually stored as a
 * blob of binary image data, often accompanied by a MIME type or some other
 * content type string (e.g. 'png', 'jpeg', 'jpg'). Sometimes there is also an
 * 'image type' to indicate what kind of image this is (e.g. front cover,
 * back cover, artist, etc.). The image data may also be an URI to the image
 * rather than the image itself.
 *
 * In GStreamer, image tags are #GstBuffer<!-- -->s containing the raw image
 * data, with the buffer caps describing the content type of the image
 * (e.g. image/jpeg, image/png, text/uri-list). The buffer caps may contain
 * an additional 'image-type' field of #GST_TYPE_TAG_IMAGE_TYPE to describe
 * the type of image (front cover, back cover etc.). #GST_TAG_PREVIEW_IMAGE
 * tags should not carry an image type, their type is already indicated via
 * the special tag name.
 *
 * This function will do various checks and typefind the encoded image
 * data (we can't trust the declared mime type).
 *
 * Returns: a newly-allocated image buffer for use in tag lists, or NULL
 *
 * Since: 0.10.20
 */
GstBuffer *
gst_tag_image_data_to_image_buffer (const guint8 * image_data,
    guint image_data_len, GstTagImageType image_type)
{
  const gchar *name;

  GstBuffer *image;

  GstCaps *caps;

  g_return_val_if_fail (image_data != NULL, NULL);
  g_return_val_if_fail (image_data_len > 0, NULL);
  g_return_val_if_fail (gst_tag_image_type_is_valid (image_type), NULL);

  GST_DEBUG ("image data len: %u bytes", image_data_len);

  /* allocate space for a NUL terminator for an uri too */
  image = gst_buffer_try_new_and_alloc (image_data_len + 1);
  if (image == NULL) {
    GST_WARNING ("failed to allocate buffer of %d for image", image_data_len);
    return NULL;
  }

  memcpy (GST_BUFFER_DATA (image), image_data, image_data_len);
  GST_BUFFER_DATA (image)[image_data_len] = '\0';

  /* Find GStreamer media type, can't trust declared type */
  caps = gst_type_find_helper_for_buffer (NULL, image, NULL);

  if (caps == NULL)
    goto no_type;

  GST_DEBUG ("Found GStreamer media type: %" GST_PTR_FORMAT, caps);

  /* sanity check: make sure typefound/declared caps are either URI or image */
  name = gst_structure_get_name (gst_caps_get_structure (caps, 0));

  if (!g_str_has_prefix (name, "image/") &&
      !g_str_has_prefix (name, "video/") &&
      !g_str_equal (name, "text/uri-list")) {
    GST_DEBUG ("Unexpected image type '%s', ignoring image frame", name);
    goto error;
  }

  /* Decrease size by 1 if we don't have an URI list
   * to keep the original size of the image
   */
  if (!g_str_equal (name, "text/uri-list"))
    GST_BUFFER_SIZE (image) = image_data_len;

  if (image_type != GST_TAG_IMAGE_TYPE_NONE) {
    GST_LOG ("Setting image type: %d", image_type);
    caps = gst_caps_make_writable (caps);
    gst_caps_set_simple (caps, "image-type", GST_TYPE_TAG_IMAGE_TYPE,
        image_type, NULL);
  }

  gst_buffer_set_caps (image, caps);
  gst_caps_unref (caps);
  return image;

/* ERRORS */
no_type:
  {
    GST_DEBUG ("Could not determine GStreamer media type, ignoring image");
    /* fall through */
  }
error:
  {
    if (image)
      gst_buffer_unref (image);
    if (caps)
      gst_caps_unref (caps);
    return NULL;
  }
}
Esempio n. 17
0
static GstFlowReturn
gst_gio_base_src_create (GstBaseSrc * base_src, guint64 offset, guint size,
    GstBuffer ** buf_return)
{
  GstGioBaseSrc *src = GST_GIO_BASE_SRC (base_src);
  GstBuffer *buf;
  GstFlowReturn ret = GST_FLOW_OK;

  g_return_val_if_fail (G_IS_INPUT_STREAM (src->stream), GST_FLOW_ERROR);

  /* If we have the requested part in our cache take a subbuffer of that,
   * otherwise fill the cache again with at least 4096 bytes from the
   * requested offset and return a subbuffer of that.
   *
   * We need caching because every read/seek operation will need to go
   * over DBus if our backend is GVfs and this is painfully slow. */
  if (src->cache && offset >= GST_BUFFER_OFFSET (src->cache) &&
      offset + size <= GST_BUFFER_OFFSET_END (src->cache)) {

    GST_DEBUG_OBJECT (src, "Creating subbuffer from cached buffer: offset %"
        G_GUINT64_FORMAT " length %u", offset, size);

    buf = gst_buffer_create_sub (src->cache,
        offset - GST_BUFFER_OFFSET (src->cache), size);

    GST_BUFFER_OFFSET (buf) = offset;
    GST_BUFFER_OFFSET_END (buf) = offset + size;
    GST_BUFFER_SIZE (buf) = size;
  } else {
    guint cachesize = MAX (4096, size);

    gssize read, res;

    gboolean success, eos;

    GError *err = NULL;

    if (src->cache) {
      gst_buffer_unref (src->cache);
      src->cache = NULL;
    }

    if (G_UNLIKELY (offset != src->position)) {
      if (!GST_GIO_STREAM_IS_SEEKABLE (src->stream))
        return GST_FLOW_NOT_SUPPORTED;

      GST_DEBUG_OBJECT (src, "Seeking to position %" G_GUINT64_FORMAT, offset);
      ret = gst_gio_seek (src, G_SEEKABLE (src->stream), offset, src->cancel);

      if (ret == GST_FLOW_OK)
        src->position = offset;
      else
        return ret;
    }

    src->cache = gst_buffer_try_new_and_alloc (cachesize);
    if (G_UNLIKELY (src->cache == NULL)) {
      GST_ERROR_OBJECT (src, "Failed to allocate %u bytes", cachesize);
      return GST_FLOW_ERROR;
    }

    GST_LOG_OBJECT (src, "Reading %u bytes from offset %" G_GUINT64_FORMAT,
        cachesize, offset);

    /* GIO sometimes gives less bytes than requested although
     * it's not at the end of file. SMB for example only
     * supports reads up to 64k. So we loop here until we get at
     * at least the requested amount of bytes or a read returns
     * nothing. */
    read = 0;
    while (size - read > 0 && (res =
            g_input_stream_read (G_INPUT_STREAM (src->stream),
                GST_BUFFER_DATA (src->cache) + read, cachesize - read,
                src->cancel, &err)) > 0) {
      read += res;
    }

    success = (read >= 0);
    eos = (cachesize > 0 && read == 0);

    if (!success && !gst_gio_error (src, "g_input_stream_read", &err, &ret)) {
      GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
          ("Could not read from stream: %s", err->message));
      g_clear_error (&err);
    }

    if (success && !eos) {
      src->position += read;
      GST_BUFFER_SIZE (src->cache) = read;

      GST_BUFFER_OFFSET (src->cache) = offset;
      GST_BUFFER_OFFSET_END (src->cache) = offset + read;

      GST_DEBUG_OBJECT (src, "Read successful");
      GST_DEBUG_OBJECT (src, "Creating subbuffer from new "
          "cached buffer: offset %" G_GUINT64_FORMAT " length %u", offset,
          size);

      buf = gst_buffer_create_sub (src->cache, 0, MIN (size, read));

      GST_BUFFER_OFFSET (buf) = offset;
      GST_BUFFER_OFFSET_END (buf) = offset + MIN (size, read);
      GST_BUFFER_SIZE (buf) = MIN (size, read);
    } else {
      GST_DEBUG_OBJECT (src, "Read not successful");
      gst_buffer_unref (src->cache);
      src->cache = NULL;
      buf = NULL;
    }

    if (eos)
      ret = GST_FLOW_UNEXPECTED;
  }

  *buf_return = buf;

  return ret;
}
Esempio n. 18
0
static GstFlowReturn
gst_base_video_parse_chain (GstPad * pad, GstBuffer * buf)
{
  GstBaseVideoParse *base_video_parse;
  GstBaseVideoParseClass *klass;
  GstBuffer *buffer;
  GstFlowReturn ret;

  GST_DEBUG ("chain with %d bytes", GST_BUFFER_SIZE (buf));

  base_video_parse = GST_BASE_VIDEO_PARSE (GST_PAD_PARENT (pad));
  klass = GST_BASE_VIDEO_PARSE_GET_CLASS (base_video_parse);

  if (!base_video_parse->started) {
    klass->start (base_video_parse);
    base_video_parse->started = TRUE;
  }

  if (G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT))) {
    GST_DEBUG_OBJECT (base_video_parse, "received DISCONT buffer");
    gst_base_video_parse_reset (base_video_parse);
    base_video_parse->discont = TRUE;
    base_video_parse->have_sync = FALSE;
  }

  if (GST_BUFFER_TIMESTAMP (buf) != GST_CLOCK_TIME_NONE) {
    base_video_parse->last_timestamp = GST_BUFFER_TIMESTAMP (buf);
  }
  gst_adapter_push (base_video_parse->input_adapter, buf);

  if (!base_video_parse->have_sync) {
    int n, m;

    GST_DEBUG ("no sync, scanning");

    n = gst_adapter_available (base_video_parse->input_adapter);
    m = klass->scan_for_sync (base_video_parse->input_adapter, FALSE, 0, n);

    gst_adapter_flush (base_video_parse->input_adapter, m);

    if (m < n) {
      GST_DEBUG ("found possible sync after %d bytes (of %d)", m, n);

      /* this is only "maybe" sync */
      base_video_parse->have_sync = TRUE;
    }

    if (!base_video_parse->have_sync) {
      return GST_FLOW_OK;
    }
  }

  /* FIXME: use gst_adapter_prev_timestamp() here instead? */
  buffer = gst_adapter_get_buffer (base_video_parse->input_adapter);

  gst_buffer_unref (buffer);

  /* FIXME check klass->parse_data */

  do {
    ret = klass->parse_data (base_video_parse, FALSE);
  } while (ret == GST_FLOW_OK);

  if (ret == GST_BASE_VIDEO_PARSE_FLOW_NEED_DATA) {
    return GST_FLOW_OK;
  }
  return ret;
}
static AM_MEDIA_TYPE *
dshowaudiodec_set_input_format (GstDshowAudioDec *adec, GstCaps *caps)
{
  AM_MEDIA_TYPE *mediatype;
  WAVEFORMATEX *format;
  GstDshowAudioDecClass *klass =
      (GstDshowAudioDecClass *) G_OBJECT_GET_CLASS (adec);
  const AudioCodecEntry *codec_entry = klass->entry;
  int size;

  mediatype = (AM_MEDIA_TYPE *)g_malloc0 (sizeof(AM_MEDIA_TYPE));
  mediatype->majortype = MEDIATYPE_Audio;
  GUID subtype = GUID_MEDIASUBTYPE_FROM_FOURCC (0x00000000);
  subtype.Data1 = codec_entry->format;
  mediatype->subtype = subtype;
  mediatype->bFixedSizeSamples = TRUE;
  mediatype->bTemporalCompression = FALSE;
  if (adec->block_align)
    mediatype->lSampleSize = adec->block_align;
  else
    mediatype->lSampleSize = 8192; /* need to evaluate it dynamically */
  mediatype->formattype = FORMAT_WaveFormatEx;

  /* We need this special behaviour for layers 1 and 2 (layer 3 uses a different
   * decoder which doesn't need this */
  if (adec->layer == 1 || adec->layer == 2) {
    MPEG1WAVEFORMAT *mpeg1_format;
    int samples, version;
    GstStructure *structure = gst_caps_get_structure (caps, 0);

    size = sizeof (MPEG1WAVEFORMAT);
    format = (WAVEFORMATEX *)g_malloc0 (size);
    format->cbSize = sizeof (MPEG1WAVEFORMAT) - sizeof (WAVEFORMATEX);
    format->wFormatTag = WAVE_FORMAT_MPEG;

    mpeg1_format = (MPEG1WAVEFORMAT *) format;

    mpeg1_format->wfx.nChannels = adec->channels;
    if (adec->channels == 2)
      mpeg1_format->fwHeadMode = ACM_MPEG_STEREO;
    else
      mpeg1_format->fwHeadMode = ACM_MPEG_SINGLECHANNEL;
    
    mpeg1_format->fwHeadModeExt = 0;
    mpeg1_format->wHeadEmphasis = 0;
    mpeg1_format->fwHeadFlags = 0;

    switch (adec->layer) {
      case 1:
        mpeg1_format->fwHeadLayer = ACM_MPEG_LAYER3;
        break;
      case 2:
        mpeg1_format->fwHeadLayer = ACM_MPEG_LAYER2;
        break;
      case 3:
        mpeg1_format->fwHeadLayer = ACM_MPEG_LAYER1;
        break;
    };

    gst_structure_get_int (structure, "mpegaudioversion", &version);
    if (adec->layer == 1) {
      samples = 384;
    } else {
      if (version == 1) {
        samples = 576;
      } else {
        samples = 1152;
      }
    }
    mpeg1_format->wfx.nBlockAlign = (WORD) samples;
    mpeg1_format->wfx.nSamplesPerSec = adec->rate;
    mpeg1_format->dwHeadBitrate = 128000; /* This doesn't seem to matter */
    mpeg1_format->wfx.nAvgBytesPerSec = mpeg1_format->dwHeadBitrate / 8;
  } 
  else 
  {
    size = sizeof (WAVEFORMATEX) +
        (adec->codec_data ? GST_BUFFER_SIZE (adec->codec_data) : 0);

    if (adec->layer == 3) {
      MPEGLAYER3WAVEFORMAT *mp3format;

      /* The WinXP mp3 decoder doesn't actually check the size of this structure, 
       * but requires that this be allocated and filled out (or we get obscure
       * random crashes)
       */
      size = sizeof (MPEGLAYER3WAVEFORMAT);
      mp3format = (MPEGLAYER3WAVEFORMAT *)g_malloc0 (size);
      format = (WAVEFORMATEX *)mp3format;
      format->cbSize = MPEGLAYER3_WFX_EXTRA_BYTES;

      mp3format->wID = MPEGLAYER3_ID_MPEG;
      mp3format->fdwFlags = MPEGLAYER3_FLAG_PADDING_ISO; /* No idea what this means for a decoder */

      /* The XP decoder divides by nBlockSize, so we must set this to a
         non-zero value, but it doesn't matter what - this is meaningless
         for VBR mp3 anyway */
      mp3format->nBlockSize = 1;
      mp3format->nFramesPerBlock = 1;
      mp3format->nCodecDelay = 0;
    }
    else {
      format = (WAVEFORMATEX *)g_malloc0 (size);
      if (adec->codec_data) {     /* Codec data is appended after our header */
        memcpy (((guchar *) format) + sizeof (WAVEFORMATEX),
            GST_BUFFER_DATA (adec->codec_data),
            GST_BUFFER_SIZE (adec->codec_data));
        format->cbSize = GST_BUFFER_SIZE (adec->codec_data);
      }
    }

    format->wFormatTag = codec_entry->format;
    format->nChannels = adec->channels;
    format->nSamplesPerSec = adec->rate;
    format->nAvgBytesPerSec = adec->bitrate / 8;
    format->nBlockAlign = adec->block_align;
    format->wBitsPerSample = adec->depth;
  }

  mediatype->cbFormat = size;
  mediatype->pbFormat = (BYTE *) format;

  return mediatype;
}
Esempio n. 20
0
static GstFlowReturn
gst_wavpack_parse_resync_loop (GstWavpackParse * parse, WavpackHeader * header)
{
  GstFlowReturn flow_ret = GST_FLOW_UNEXPECTED;
  GstBuffer *buf = NULL;

  /* loop until we have a frame header or reach the end of the stream */
  while (1) {
    guint8 *data, *marker;

    guint len, size;

    if (buf) {
      gst_buffer_unref (buf);
      buf = NULL;
    }

    if (parse->upstream_length == 0 ||
        parse->upstream_length <= parse->current_offset) {
      parse->upstream_length = gst_wavpack_parse_get_upstream_length (parse);
      if (parse->upstream_length == 0 ||
          parse->upstream_length <= parse->current_offset) {
        break;
      }
    }

    len = MIN (parse->upstream_length - parse->current_offset, 2048);

    GST_LOG_OBJECT (parse, "offset: %" G_GINT64_FORMAT, parse->current_offset);

    buf = gst_wavpack_parse_pull_buffer (parse, parse->current_offset,
        len, &flow_ret);

    /* whatever the problem is, there's nothing more for us to do for now */
    if (flow_ret != GST_FLOW_OK)
      break;

    data = GST_BUFFER_DATA (buf);
    size = GST_BUFFER_SIZE (buf);

    /* not enough data for a header? */
    if (size < sizeof (WavpackHeader))
      break;

    /* got a header right where we are at now? */
    if (gst_wavpack_read_header (header, data))
      break;

    /* nope, let's see if we can find one */
    marker = gst_wavpack_parse_find_marker (data + 1, size - 1);

    if (marker) {
      parse->current_offset += marker - data;
      /* do one more loop iteration to make sure we pull enough
       * data for a full header, we'll bail out then */
    } else {
      parse->current_offset += len - 4;
    }
  }

  if (buf)
    gst_buffer_unref (buf);

  return flow_ret;
}
Esempio n. 21
0
/* encodes frame according to info in xframe;
   - buf is input buffer, can be NULL if dummy
   - buf is disposed of prior to exit
   - resulting buffer is returned, NULL if no encoder output or error
*/
static inline GstBuffer *
gst_xvidenc_encode (GstXvidEnc * xvidenc, GstBuffer * buf,
    xvid_enc_frame_t xframe)
{
  GstBuffer *outbuf;
  gint ret;

  /* compressed frame should fit in the rough size of an uncompressed one */
  outbuf = gst_buffer_new_and_alloc (gst_xvid_image_get_size (xvidenc->csp,
          xvidenc->width, xvidenc->height));

  xframe.bitstream = (void *) GST_BUFFER_DATA (outbuf);
  xframe.length = GST_BUFFER_SIZE (outbuf);

  /* now provide input image data where-abouts, if needed */
  if (buf)
    gst_xvid_image_fill (&xframe.input, GST_BUFFER_DATA (buf), xvidenc->csp,
        xvidenc->width, xvidenc->height);

  GST_DEBUG_OBJECT (xvidenc, "encoding frame into buffer of size %d",
      GST_BUFFER_SIZE (outbuf));
  ret = xvid_encore (xvidenc->handle, XVID_ENC_ENCODE, &xframe, NULL);

  if (ret < 0) {
    /* things can be nasty if we are trying to flush, so don't signal error then */
    if (buf) {
      GST_ELEMENT_WARNING (xvidenc, LIBRARY, ENCODE, (NULL),
          ("Error encoding xvid frame: %s (%d)", gst_xvid_error (ret), ret));
      gst_buffer_unref (buf);
    }
    gst_buffer_unref (outbuf);
    return NULL;
  } else if (ret > 0) {         /* make sub-buffer */
    GstBuffer *sub;

    GST_DEBUG_OBJECT (xvidenc, "xvid produced output of size %d", ret);
    sub = gst_buffer_create_sub (outbuf, 0, ret);

    /* parent no longer needed, will go away with child buffer */
    gst_buffer_unref (outbuf);
    outbuf = sub;
  } else {                      /* encoder did not yet produce something */
    GST_DEBUG_OBJECT (xvidenc, "xvid produced no output");
    gst_buffer_unref (outbuf);
    g_queue_push_tail (xvidenc->delay, buf);
    return NULL;
  }

  /* finish decoration and return */
  if (!(xframe.out_flags & XVID_KEYFRAME))
    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
  gst_buffer_set_caps (outbuf, GST_PAD_CAPS (xvidenc->srcpad));

  /* now we need the right buf to take timestamps from;
     note that timestamps from a display order input buffer can end up with
     another encode order output buffer, but other than this permutation,
     the overall time progress is tracked,
     and keyframes should have the correct stamp */
  if (!g_queue_is_empty (xvidenc->delay)) {
    if (buf)
      g_queue_push_tail (xvidenc->delay, buf);
    buf = g_queue_pop_head (xvidenc->delay);
  }
  if (buf) {
    GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
    GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
    gst_buffer_unref (buf);
  }

  return outbuf;
}
Esempio n. 22
0
static gboolean
gst_wavpack_parse_create_src_pad (GstWavpackParse * wvparse, GstBuffer * buf,
    WavpackHeader * header)
{
  GstWavpackMetadata meta;
  GstCaps *caps = NULL;
  guchar *bufptr;

  g_assert (wvparse->srcpad == NULL);

  bufptr = GST_BUFFER_DATA (buf) + sizeof (WavpackHeader);

  while (gst_wavpack_read_metadata (&meta, GST_BUFFER_DATA (buf), &bufptr)) {
    switch (meta.id) {
      case ID_WVC_BITSTREAM:{
        caps = gst_caps_new_simple ("audio/x-wavpack-correction",
            "framed", G_TYPE_BOOLEAN, TRUE, NULL);
        wvparse->srcpad =
            gst_pad_new_from_template (gst_element_class_get_pad_template
            (GST_ELEMENT_GET_CLASS (wvparse), "wvcsrc"), "wvcsrc");
        break;
      }
      case ID_WV_BITSTREAM:
      case ID_WVX_BITSTREAM:{
        WavpackStreamReader *stream_reader = gst_wavpack_stream_reader_new ();

        WavpackContext *wpc;

        gchar error_msg[80];

        read_id rid;

        gint channel_mask;

        rid.buffer = GST_BUFFER_DATA (buf);
        rid.length = GST_BUFFER_SIZE (buf);
        rid.position = 0;

        wpc =
            WavpackOpenFileInputEx (stream_reader, &rid, NULL, error_msg, 0, 0);

        if (!wpc)
          return FALSE;

        wvparse->samplerate = WavpackGetSampleRate (wpc);
        wvparse->channels = WavpackGetNumChannels (wpc);
        wvparse->total_samples =
            (header->total_samples ==
            0xffffffff) ? G_GINT64_CONSTANT (-1) : header->total_samples;

        caps = gst_caps_new_simple ("audio/x-wavpack",
            "width", G_TYPE_INT, WavpackGetBitsPerSample (wpc),
            "channels", G_TYPE_INT, wvparse->channels,
            "rate", G_TYPE_INT, wvparse->samplerate,
            "framed", G_TYPE_BOOLEAN, TRUE, NULL);
#ifdef WAVPACK_OLD_API
        channel_mask = wpc->config.channel_mask;
#else
        channel_mask = WavpackGetChannelMask (wpc);
#endif
        if (channel_mask == 0)
          channel_mask =
              gst_wavpack_get_default_channel_mask (wvparse->channels);

        if (channel_mask != 0) {
          if (!gst_wavpack_set_channel_layout (caps, channel_mask)) {
            GST_WARNING_OBJECT (wvparse, "Failed to set channel layout");
            gst_caps_unref (caps);
            caps = NULL;
            WavpackCloseFile (wpc);
            g_free (stream_reader);
            break;
          }
        }

        wvparse->srcpad =
            gst_pad_new_from_template (gst_element_class_get_pad_template
            (GST_ELEMENT_GET_CLASS (wvparse), "src"), "src");
        WavpackCloseFile (wpc);
        g_free (stream_reader);
        break;
      }
      default:{
        GST_LOG_OBJECT (wvparse, "unhandled ID: 0x%02x", meta.id);
        break;
      }
    }
    if (caps != NULL)
      break;
  }

  if (caps == NULL || wvparse->srcpad == NULL)
    return FALSE;

  GST_DEBUG_OBJECT (wvparse, "Added src pad with caps %" GST_PTR_FORMAT, caps);

  gst_pad_set_query_function (wvparse->srcpad,
      GST_DEBUG_FUNCPTR (gst_wavpack_parse_src_query));
  gst_pad_set_query_type_function (wvparse->srcpad,
      GST_DEBUG_FUNCPTR (gst_wavpack_parse_get_src_query_types));
  gst_pad_set_event_function (wvparse->srcpad,
      GST_DEBUG_FUNCPTR (gst_wavpack_parse_src_event));

  gst_pad_set_caps (wvparse->srcpad, caps);
  gst_caps_unref (caps);
  gst_pad_use_fixed_caps (wvparse->srcpad);

  gst_object_ref (wvparse->srcpad);
  gst_pad_set_active (wvparse->srcpad, TRUE);
  gst_element_add_pad (GST_ELEMENT (wvparse), wvparse->srcpad);
  gst_element_no_more_pads (GST_ELEMENT (wvparse));

  return TRUE;
}
Esempio n. 23
0
static GstFlowReturn
gst_multi_file_sink_render (GstBaseSink * sink, GstBuffer * buffer)
{
  GstMultiFileSink *multifilesink;
  guint size;
  guint8 *data;
  gchar *filename;
  gboolean ret;
  GError *error = NULL;

  size = GST_BUFFER_SIZE (buffer);
  data = GST_BUFFER_DATA (buffer);

  multifilesink = GST_MULTI_FILE_SINK (sink);

  switch (multifilesink->next_file) {
    case GST_MULTI_FILE_SINK_NEXT_BUFFER:
      filename = g_strdup_printf (multifilesink->filename,
          multifilesink->index);

      ret = g_file_set_contents (filename, (char *) data, size, &error);
      if (!ret)
        goto write_error;

      gst_multi_file_sink_post_message (multifilesink, buffer, filename);
      multifilesink->index++;

      g_free (filename);
      break;
    case GST_MULTI_FILE_SINK_NEXT_DISCONT:
      if (GST_BUFFER_IS_DISCONT (buffer)) {
        if (multifilesink->file) {
          fclose (multifilesink->file);
          multifilesink->file = NULL;

          filename = g_strdup_printf (multifilesink->filename,
              multifilesink->index);
          gst_multi_file_sink_post_message (multifilesink, buffer, filename);
          g_free (filename);
          multifilesink->index++;
        }
      }

      if (multifilesink->file == NULL) {
        filename = g_strdup_printf (multifilesink->filename,
            multifilesink->index);
        multifilesink->file = g_fopen (filename, "wb");
        g_free (filename);

        if (multifilesink->file == NULL)
          goto stdio_write_error;
      }

      ret = fwrite (GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer), 1,
          multifilesink->file);
      if (ret != 1)
        goto stdio_write_error;

      break;
    case GST_MULTI_FILE_SINK_NEXT_KEY_FRAME:
      if (multifilesink->next_segment == GST_CLOCK_TIME_NONE) {
        if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) {
          multifilesink->next_segment = GST_BUFFER_TIMESTAMP (buffer) +
              10 * GST_SECOND;
        }
      }

      if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer) &&
          GST_BUFFER_TIMESTAMP (buffer) >= multifilesink->next_segment &&
          !GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT)) {
        if (multifilesink->file) {
          fclose (multifilesink->file);
          multifilesink->file = NULL;

          filename = g_strdup_printf (multifilesink->filename,
              multifilesink->index);
          gst_multi_file_sink_post_message (multifilesink, buffer, filename);
          g_free (filename);
          multifilesink->index++;
        }

        multifilesink->next_segment += 10 * GST_SECOND;
      }

      if (multifilesink->file == NULL) {
        filename = g_strdup_printf (multifilesink->filename,
            multifilesink->index);
        multifilesink->file = g_fopen (filename, "wb");
        g_free (filename);

        if (multifilesink->file == NULL)
          goto stdio_write_error;
      }

      ret = fwrite (GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer), 1,
          multifilesink->file);
      if (ret != 1)
        goto stdio_write_error;

      break;
    default:
      g_assert_not_reached ();
  }

  return GST_FLOW_OK;

  /* ERRORS */
write_error:
  {
    switch (error->code) {
      case G_FILE_ERROR_NOSPC:{
        GST_ELEMENT_ERROR (multifilesink, RESOURCE, NO_SPACE_LEFT, (NULL),
            (NULL));
        break;
      }
      default:{
        GST_ELEMENT_ERROR (multifilesink, RESOURCE, WRITE,
            ("Error while writing to file \"%s\".", filename),
            ("%s", g_strerror (errno)));
      }
    }
    g_error_free (error);
    g_free (filename);

    return GST_FLOW_ERROR;
  }
stdio_write_error:
  GST_ELEMENT_ERROR (multifilesink, RESOURCE, WRITE,
      ("Error while writing to file."), (NULL));
  return GST_FLOW_ERROR;
}
Esempio n. 24
0
static GstFlowReturn
vorbis_handle_comment_packet (GstVorbisDec * vd, ogg_packet * packet)
{
    guint bitrate = 0;
    gchar *encoder = NULL;
    GstTagList *list;
    GstBuffer *buf;

    GST_DEBUG_OBJECT (vd, "parsing comment packet");

    buf = gst_buffer_new ();
    GST_BUFFER_DATA (buf) = gst_ogg_packet_data (packet);
    GST_BUFFER_SIZE (buf) = gst_ogg_packet_size (packet);

    list =
        gst_tag_list_from_vorbiscomment_buffer (buf, (guint8 *) "\003vorbis", 7,
                &encoder);

    if (!list) {
        GST_ERROR_OBJECT (vd, "couldn't decode comments");
        list = gst_tag_list_new ();
    }

    gst_buffer_unref (buf);

    if (encoder) {
        if (encoder[0])
            gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
                              GST_TAG_ENCODER, encoder, NULL);
        g_free (encoder);
    }
    gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
                      GST_TAG_ENCODER_VERSION, vd->vi.version,
                      GST_TAG_AUDIO_CODEC, "Vorbis", NULL);
    if (vd->vi.bitrate_nominal > 0 && vd->vi.bitrate_nominal <= 0x7FFFFFFF) {
        gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
                          GST_TAG_NOMINAL_BITRATE, (guint) vd->vi.bitrate_nominal, NULL);
        bitrate = vd->vi.bitrate_nominal;
    }
    if (vd->vi.bitrate_upper > 0 && vd->vi.bitrate_upper <= 0x7FFFFFFF) {
        gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
                          GST_TAG_MAXIMUM_BITRATE, (guint) vd->vi.bitrate_upper, NULL);
        if (!bitrate)
            bitrate = vd->vi.bitrate_upper;
    }
    if (vd->vi.bitrate_lower > 0 && vd->vi.bitrate_lower <= 0x7FFFFFFF) {
        gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
                          GST_TAG_MINIMUM_BITRATE, (guint) vd->vi.bitrate_lower, NULL);
        if (!bitrate)
            bitrate = vd->vi.bitrate_lower;
    }
    if (bitrate) {
        gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
                          GST_TAG_BITRATE, (guint) bitrate, NULL);
    }

    gst_audio_decoder_merge_tags (GST_AUDIO_DECODER_CAST (vd), list,
                                  GST_TAG_MERGE_REPLACE);
    if (vd->initialized) {
        gst_tag_list_free (list);
    } else {
        /* Only post them as messages for the time being. *
         * They will be pushed on the pad once the decoder is initialized */
        gst_element_post_message (GST_ELEMENT_CAST (vd),
                                  gst_message_new_tag (GST_OBJECT (vd), list));
    }

    return GST_FLOW_OK;
}
Esempio n. 25
0
static GstFlowReturn
gst_mulawenc_chain (GstPad * pad, GstBuffer * buffer)
{
  GstMuLawEnc *mulawenc;
  gint16 *linear_data;
  guint linear_size;
  guint8 *mulaw_data;
  guint mulaw_size;
  GstBuffer *outbuf;
  GstFlowReturn ret;
  GstClockTime timestamp, duration;

  mulawenc = GST_MULAWENC (gst_pad_get_parent (pad));

  if (!mulawenc->rate || !mulawenc->channels)
    goto not_negotiated;

  linear_data = (gint16 *) GST_BUFFER_DATA (buffer);
  linear_size = GST_BUFFER_SIZE (buffer);

  mulaw_size = linear_size / 2;

  timestamp = GST_BUFFER_TIMESTAMP (buffer);
  duration = GST_BUFFER_DURATION (buffer);

  ret = gst_pad_alloc_buffer_and_set_caps (mulawenc->srcpad,
      GST_BUFFER_OFFSET_NONE, mulaw_size, GST_PAD_CAPS (mulawenc->srcpad),
      &outbuf);
  if (ret != GST_FLOW_OK)
    goto alloc_failed;

  if (duration == -1) {
    duration = gst_util_uint64_scale_int (mulaw_size,
        GST_SECOND, mulawenc->rate * mulawenc->channels);
  }

  if (GST_BUFFER_SIZE (outbuf) < mulaw_size) {
    /* pad-alloc can suggest a smaller size */
    gst_buffer_unref (outbuf);
    outbuf = gst_buffer_new_and_alloc (mulaw_size);
  }

  mulaw_data = (guint8 *) GST_BUFFER_DATA (outbuf);

  /* copy discont flag */
  if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT))
    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);

  GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
  GST_BUFFER_DURATION (outbuf) = duration;

  gst_buffer_set_caps (outbuf, GST_PAD_CAPS (mulawenc->srcpad));

  mulaw_encode (linear_data, mulaw_data, mulaw_size);

  gst_buffer_unref (buffer);

  ret = gst_pad_push (mulawenc->srcpad, outbuf);

done:
  gst_object_unref (mulawenc);

  return ret;

not_negotiated:
  {
    GST_DEBUG_OBJECT (mulawenc, "no format negotiated");
    ret = GST_FLOW_NOT_NEGOTIATED;
    gst_buffer_unref (buffer);
    goto done;
  }
alloc_failed:
  {
    GST_DEBUG_OBJECT (mulawenc, "pad alloc failed");
    gst_buffer_unref (buffer);
    goto done;
  }
}
Esempio n. 26
0
static GstFlowReturn
vorbis_handle_data_packet (GstVorbisDec * vd, ogg_packet * packet,
                           GstClockTime timestamp, GstClockTime duration)
{
#ifdef USE_TREMOLO
    vorbis_sample_t *pcm;
#else
    vorbis_sample_t **pcm;
#endif
    guint sample_count;
    GstBuffer *out = NULL;
    GstFlowReturn result;
    gint size;

    if (G_UNLIKELY (!vd->initialized)) {
        result = vorbis_dec_handle_header_caps (vd);
        if (result != GST_FLOW_OK)
            goto not_initialized;
    }

    /* normal data packet */
    /* FIXME, we can skip decoding if the packet is outside of the
     * segment, this is however not very trivial as we need a previous
     * packet to decode the current one so we must be careful not to
     * throw away too much. For now we decode everything and clip right
     * before pushing data. */

#ifdef USE_TREMOLO
    if (G_UNLIKELY (vorbis_dsp_synthesis (&vd->vd, packet, 1)))
        goto could_not_read;
#else
    if (G_UNLIKELY (vorbis_synthesis (&vd->vb, packet)))
        goto could_not_read;

    if (G_UNLIKELY (vorbis_synthesis_blockin (&vd->vd, &vd->vb) < 0))
        goto not_accepted;
#endif

    /* assume all goes well here */
    result = GST_FLOW_OK;

    /* count samples ready for reading */
#ifdef USE_TREMOLO
    if ((sample_count = vorbis_dsp_pcmout (&vd->vd, NULL, 0)) == 0)
#else
    if ((sample_count = vorbis_synthesis_pcmout (&vd->vd, NULL)) == 0)
        goto done;
#endif

        size = sample_count * vd->vi.channels * vd->width;
    GST_LOG_OBJECT (vd, "%d samples ready for reading, size %d", sample_count,
                    size);

    /* alloc buffer for it */
    result =
        gst_pad_alloc_buffer_and_set_caps (GST_AUDIO_DECODER_SRC_PAD (vd),
                                           GST_BUFFER_OFFSET_NONE, size,
                                           GST_PAD_CAPS (GST_AUDIO_DECODER_SRC_PAD (vd)), &out);
    if (G_UNLIKELY (result != GST_FLOW_OK))
        goto done;

    /* get samples ready for reading now, should be sample_count */
#ifdef USE_TREMOLO
    pcm = GST_BUFFER_DATA (out);
    if (G_UNLIKELY (vorbis_dsp_pcmout (&vd->vd, pcm, sample_count) !=
                    sample_count))
#else
    if (G_UNLIKELY (vorbis_synthesis_pcmout (&vd->vd, &pcm) != sample_count))
#endif
        goto wrong_samples;

#ifndef USE_TREMOLO
    /* copy samples in buffer */
    vd->copy_samples ((vorbis_sample_t *) GST_BUFFER_DATA (out), pcm,
                      sample_count, vd->vi.channels, vd->width);
#endif

    GST_LOG_OBJECT (vd, "setting output size to %d", size);
    GST_BUFFER_SIZE (out) = size;

done:
    /* whether or not data produced, consume one frame and advance time */
    result = gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (vd), out, 1);

#ifdef USE_TREMOLO
    vorbis_dsp_read (&vd->vd, sample_count);
#else
    vorbis_synthesis_read (&vd->vd, sample_count);
#endif

    return result;

    /* ERRORS */
not_initialized:
    {
        GST_ELEMENT_ERROR (GST_ELEMENT (vd), STREAM, DECODE,
                           (NULL), ("no header sent yet"));
        return GST_FLOW_NOT_NEGOTIATED;
    }
could_not_read:
    {
        GST_ELEMENT_ERROR (GST_ELEMENT (vd), STREAM, DECODE,
                           (NULL), ("couldn't read data packet"));
        return GST_FLOW_ERROR;
    }
not_accepted:
    {
        GST_ELEMENT_ERROR (GST_ELEMENT (vd), STREAM, DECODE,
                           (NULL), ("vorbis decoder did not accept data packet"));
        return GST_FLOW_ERROR;
    }
wrong_samples:
    {
        gst_buffer_unref (out);
        GST_ELEMENT_ERROR (GST_ELEMENT (vd), STREAM, DECODE,
                           (NULL), ("vorbis decoder reported wrong number of samples"));
        return GST_FLOW_ERROR;
    }
}
Esempio n. 27
0
static void
do_perfect_stream_test (guint rate, guint width, gdouble drop_probability,
    gdouble inject_probability)
{
  GstElement *pipe, *src, *conv, *filter, *injector, *audiorate, *sink;
  GstMessage *msg;
  GstCaps *caps;
  GstPad *srcpad;
  GList *l, *bufs = NULL;
  GstClockTime next_time = GST_CLOCK_TIME_NONE;
  guint64 next_offset = GST_BUFFER_OFFSET_NONE;

  caps = gst_caps_new_simple ("audio/x-raw-int", "rate", G_TYPE_INT,
      rate, "width", G_TYPE_INT, width, NULL);

  GST_INFO ("-------- drop=%.0f%% caps = %" GST_PTR_FORMAT " ---------- ",
      drop_probability * 100.0, caps);

  g_assert (drop_probability >= 0.0 && drop_probability <= 1.0);
  g_assert (inject_probability >= 0.0 && inject_probability <= 1.0);
  g_assert (width > 0 && (width % 8) == 0);

  pipe = gst_pipeline_new ("pipeline");
  fail_unless (pipe != NULL);

  src = gst_element_factory_make ("audiotestsrc", "audiotestsrc");
  fail_unless (src != NULL);

  g_object_set (src, "num-buffers", 100, NULL);

  conv = gst_element_factory_make ("audioconvert", "audioconvert");
  fail_unless (conv != NULL);

  filter = gst_element_factory_make ("capsfilter", "capsfilter");
  fail_unless (filter != NULL);

  g_object_set (filter, "caps", caps, NULL);

  injector_inject_probability = inject_probability;

  injector = GST_ELEMENT (g_object_new (test_injector_get_type (), NULL));

  srcpad = gst_element_get_pad (injector, "src");
  fail_unless (srcpad != NULL);
  gst_pad_add_buffer_probe (srcpad, G_CALLBACK (probe_cb), &drop_probability);
  gst_object_unref (srcpad);

  audiorate = gst_element_factory_make ("audiorate", "audiorate");
  fail_unless (audiorate != NULL);

  sink = gst_element_factory_make ("fakesink", "fakesink");
  fail_unless (sink != NULL);

  g_object_set (sink, "signal-handoffs", TRUE, NULL);

  g_signal_connect (sink, "handoff", G_CALLBACK (got_buf), &bufs);

  gst_bin_add_many (GST_BIN (pipe), src, conv, filter, injector, audiorate,
      sink, NULL);
  gst_element_link_many (src, conv, filter, injector, audiorate, sink, NULL);

  fail_unless_equals_int (gst_element_set_state (pipe, GST_STATE_PLAYING),
      GST_STATE_CHANGE_ASYNC);

  fail_unless_equals_int (gst_element_get_state (pipe, NULL, NULL, -1),
      GST_STATE_CHANGE_SUCCESS);

  msg = gst_bus_poll (GST_ELEMENT_BUS (pipe),
      GST_MESSAGE_EOS | GST_MESSAGE_ERROR, -1);
  fail_unless_equals_string (GST_MESSAGE_TYPE_NAME (msg), "eos");

  for (l = bufs; l != NULL; l = l->next) {
    GstBuffer *buf = GST_BUFFER (l->data);
    guint num_samples;

    fail_unless (GST_BUFFER_TIMESTAMP_IS_VALID (buf));
    fail_unless (GST_BUFFER_DURATION_IS_VALID (buf));
    fail_unless (GST_BUFFER_OFFSET_IS_VALID (buf));
    fail_unless (GST_BUFFER_OFFSET_END_IS_VALID (buf));

    GST_LOG ("buffer: ts=%" GST_TIME_FORMAT ", end_ts=%" GST_TIME_FORMAT
        " off=%" G_GINT64_FORMAT ", end_off=%" G_GINT64_FORMAT,
        GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
        GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf)),
        GST_BUFFER_OFFSET (buf), GST_BUFFER_OFFSET_END (buf));

    if (GST_CLOCK_TIME_IS_VALID (next_time)) {
      fail_unless_equals_uint64 (next_time, GST_BUFFER_TIMESTAMP (buf));
    }
    if (next_offset != GST_BUFFER_OFFSET_NONE) {
      fail_unless_equals_uint64 (next_offset, GST_BUFFER_OFFSET (buf));
    }

    /* check buffer size for sanity */
    fail_unless_equals_int (GST_BUFFER_SIZE (buf) % (width / 8), 0);

    /* check there is actually as much data as there should be */
    num_samples = GST_BUFFER_OFFSET_END (buf) - GST_BUFFER_OFFSET (buf);
    fail_unless_equals_int (GST_BUFFER_SIZE (buf), num_samples * (width / 8));

    next_time = GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf);
    next_offset = GST_BUFFER_OFFSET_END (buf);
  }

  gst_message_unref (msg);
  gst_element_set_state (pipe, GST_STATE_NULL);
  gst_object_unref (pipe);

  g_list_foreach (bufs, (GFunc) gst_mini_object_unref, NULL);
  g_list_free (bufs);

  gst_caps_unref (caps);
}
Esempio n. 28
0
static GstFlowReturn
gst_vdp_h264_dec_parse_data (GstBaseVideoDecoder * base_video_decoder,
    GstBuffer * buf, gboolean at_eos, GstVideoFrame * frame)
{
  GstVdpH264Dec *h264_dec = GST_VDP_H264_DEC (base_video_decoder);
  GstBitReader reader;
  GstNalUnit nal_unit;
  guint8 forbidden_zero_bit;

  guint8 *data;
  guint size;
  gint i;

  GstFlowReturn ret = GST_FLOW_OK;

  GST_MEMDUMP ("data", GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));

  gst_bit_reader_init_from_buffer (&reader, buf);

  /* skip nal_length or sync code */
  gst_bit_reader_skip (&reader, h264_dec->nal_length_size * 8);

  if (!gst_bit_reader_get_bits_uint8 (&reader, &forbidden_zero_bit, 1))
    goto invalid_packet;
  if (forbidden_zero_bit != 0) {
    GST_WARNING ("forbidden_zero_bit != 0");
    return GST_FLOW_ERROR;
  }

  if (!gst_bit_reader_get_bits_uint16 (&reader, &nal_unit.ref_idc, 2))
    goto invalid_packet;
  GST_DEBUG ("nal_ref_idc: %u", nal_unit.ref_idc);

  /* read nal_unit_type */
  if (!gst_bit_reader_get_bits_uint16 (&reader, &nal_unit.type, 5))
    goto invalid_packet;

  GST_DEBUG ("nal_unit_type: %u", nal_unit.type);
  if (nal_unit.type == 14 || nal_unit.type == 20) {
    if (!gst_bit_reader_skip (&reader, 24))
      goto invalid_packet;
  }
  nal_unit.IdrPicFlag = (nal_unit.type == 5 ? 1 : 0);

  data = GST_BUFFER_DATA (buf) + gst_bit_reader_get_pos (&reader) / 8;
  size = gst_bit_reader_get_remaining (&reader) / 8;

  i = size - 1;
  while (size >= 0 && data[i] == 0x00) {
    size--;
    i--;
  }

  if (GST_VIDEO_FRAME_FLAG_IS_SET (frame, GST_H264_FRAME_GOT_PRIMARY)) {
    if (nal_unit.type == GST_NAL_SPS || nal_unit.type == GST_NAL_PPS ||
        nal_unit.type == GST_NAL_SEI || nal_unit.type == GST_NAL_AU_DELIMITER ||
        (nal_unit.type >= 14 && nal_unit.type <= 18))
      ret =
          gst_base_video_decoder_have_frame (base_video_decoder, FALSE, &frame);
  }

  if (nal_unit.type >= GST_NAL_SLICE && nal_unit.type <= GST_NAL_SLICE_IDR) {
    GstH264Slice slice;

    if (!gst_h264_parser_parse_slice_header (h264_dec->parser, &slice, data,
            size, nal_unit))
      goto invalid_packet;

    if (slice.redundant_pic_cnt == 0) {
      if (GST_VIDEO_FRAME_FLAG_IS_SET (frame, GST_H264_FRAME_GOT_PRIMARY)) {
        GstH264Slice *p_slice;
        guint8 pic_order_cnt_type, p_pic_order_cnt_type;
        gboolean finish_frame = FALSE;

        p_slice = &(GST_H264_FRAME_CAST (frame)->slice_hdr);
        pic_order_cnt_type = slice.picture->sequence->pic_order_cnt_type;
        p_pic_order_cnt_type = p_slice->picture->sequence->pic_order_cnt_type;

        if (slice.frame_num != p_slice->frame_num)
          finish_frame = TRUE;

        else if (slice.picture != p_slice->picture)
          finish_frame = TRUE;

        else if (slice.bottom_field_flag != p_slice->bottom_field_flag)
          finish_frame = TRUE;

        else if (nal_unit.ref_idc != p_slice->nal_unit.ref_idc &&
            (nal_unit.ref_idc == 0 || p_slice->nal_unit.ref_idc == 0))
          finish_frame = TRUE;

        else if ((pic_order_cnt_type == 0 && p_pic_order_cnt_type == 0) &&
            (slice.pic_order_cnt_lsb != p_slice->pic_order_cnt_lsb ||
                slice.delta_pic_order_cnt_bottom !=
                p_slice->delta_pic_order_cnt_bottom))
          finish_frame = TRUE;

        else if ((p_pic_order_cnt_type == 1 && p_pic_order_cnt_type == 1) &&
            (slice.delta_pic_order_cnt[0] != p_slice->delta_pic_order_cnt[0] ||
                slice.delta_pic_order_cnt[1] !=
                p_slice->delta_pic_order_cnt[1]))
          finish_frame = TRUE;

        if (finish_frame)
          ret =
              gst_base_video_decoder_have_frame (base_video_decoder, FALSE,
              &frame);

      }

      if (!GST_VIDEO_FRAME_FLAG_IS_SET (frame, GST_H264_FRAME_GOT_PRIMARY)) {
        if (GST_H264_IS_I_SLICE (slice.type)
            || GST_H264_IS_SI_SLICE (slice.type))
          GST_VIDEO_FRAME_FLAG_SET (frame, GST_VIDEO_FRAME_FLAG_KEYFRAME);

        GST_H264_FRAME_CAST (frame)->slice_hdr = slice;
        GST_VIDEO_FRAME_FLAG_SET (frame, GST_H264_FRAME_GOT_PRIMARY);
      }
    }
    gst_h264_frame_add_slice ((GstH264Frame *) frame, buf);
  }

  if (nal_unit.type == GST_NAL_SPS) {
    if (!gst_h264_parser_parse_sequence (h264_dec->parser, data, size))
      goto invalid_packet;
  }

  if (nal_unit.type == GST_NAL_PPS) {
    if (!gst_h264_parser_parse_picture (h264_dec->parser, data, size))
      goto invalid_packet;
  }

  gst_buffer_unref (buf);
  return ret;

invalid_packet:
  GST_WARNING ("Invalid packet size!");
  gst_buffer_unref (buf);

  return GST_FLOW_OK;
}
Esempio n. 29
0
static GstFlowReturn
gst_visual_chain (GstPad * pad, GstBuffer * buffer)
{
  GstBuffer *outbuf = NULL;
  guint i;
  GstVisual *visual = GST_VISUAL (gst_pad_get_parent (pad));
  GstFlowReturn ret = GST_FLOW_OK;
  guint avail;

  GST_DEBUG_OBJECT (visual, "chain function called");

  /* If we don't have an output format yet, preallocate a buffer to try and
   * set one */
  if (GST_PAD_CAPS (visual->srcpad) == NULL) {
    ret = get_buffer (visual, &outbuf);
    if (ret != GST_FLOW_OK) {
      gst_buffer_unref (buffer);
      goto beach;
    }
  }

  /* resync on DISCONT */
  if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) {
    gst_adapter_clear (visual->adapter);
    visual->next_ts = -1;
  }

  /* Match timestamps from the incoming audio */
  if (GST_BUFFER_TIMESTAMP (buffer) != GST_CLOCK_TIME_NONE)
    visual->next_ts = GST_BUFFER_TIMESTAMP (buffer);

  GST_DEBUG_OBJECT (visual,
      "Input buffer has %d samples, time=%" G_GUINT64_FORMAT,
      GST_BUFFER_SIZE (buffer) / visual->bps, GST_BUFFER_TIMESTAMP (buffer));

  gst_adapter_push (visual->adapter, buffer);

  while (TRUE) {
    gboolean need_skip;
    const guint16 *data;

    GST_DEBUG_OBJECT (visual, "processing buffer");

    avail = gst_adapter_available (visual->adapter);
    GST_DEBUG_OBJECT (visual, "avail now %u", avail);

    /* we need at least 512 samples */
    if (avail < 512 * visual->bps)
      break;

    /* we need at least enough samples to make one frame */
    if (avail < visual->spf * visual->bps)
      break;

    if (visual->next_ts != -1) {
      gint64 qostime;

      /* QoS is done on running time */
      qostime = gst_segment_to_running_time (&visual->segment, GST_FORMAT_TIME,
          visual->next_ts);

      GST_OBJECT_LOCK (visual);
      /* check for QoS, don't compute buffers that are known to be late */
      need_skip = visual->earliest_time != -1 &&
          qostime <= visual->earliest_time;
      GST_OBJECT_UNLOCK (visual);

      if (need_skip) {
        GST_WARNING_OBJECT (visual,
            "QoS: skip ts: %" GST_TIME_FORMAT ", earliest: %" GST_TIME_FORMAT,
            GST_TIME_ARGS (qostime), GST_TIME_ARGS (visual->earliest_time));
        goto skip;
      }
    }

    /* Read 512 samples per channel */
    data =
        (const guint16 *) gst_adapter_peek (visual->adapter, 512 * visual->bps);

#if defined(VISUAL_API_VERSION) && VISUAL_API_VERSION >= 4000 && VISUAL_API_VERSION < 5000
    {
      VisBuffer *lbuf, *rbuf;
      guint16 ldata[512], rdata[512];
      VisAudioSampleRateType rate;

      lbuf = visual_buffer_new_with_buffer (ldata, sizeof (ldata), NULL);
      rbuf = visual_buffer_new_with_buffer (rdata, sizeof (rdata), NULL);

      if (visual->channels == 2) {
        for (i = 0; i < 512; i++) {
          ldata[i] = *data++;
          rdata[i] = *data++;
        }
      } else {
        for (i = 0; i < 512; i++) {
          ldata[i] = *data;
          rdata[i] = *data++;
        }
      }

      switch (visual->rate) {
        case 8000:
          rate = VISUAL_AUDIO_SAMPLE_RATE_8000;
          break;
        case 11250:
          rate = VISUAL_AUDIO_SAMPLE_RATE_11250;
          break;
        case 22500:
          rate = VISUAL_AUDIO_SAMPLE_RATE_22500;
          break;
        case 32000:
          rate = VISUAL_AUDIO_SAMPLE_RATE_32000;
          break;
        case 44100:
          rate = VISUAL_AUDIO_SAMPLE_RATE_44100;
          break;
        case 48000:
          rate = VISUAL_AUDIO_SAMPLE_RATE_48000;
          break;
        case 96000:
          rate = VISUAL_AUDIO_SAMPLE_RATE_96000;
          break;
        default:
          visual_object_unref (VISUAL_OBJECT (lbuf));
          visual_object_unref (VISUAL_OBJECT (rbuf));
          GST_ERROR_OBJECT (visual, "unsupported rate %d", visual->rate);
          ret = GST_FLOW_ERROR;
          goto beach;
          break;
      }

      visual_audio_samplepool_input_channel (visual->audio->samplepool,
          lbuf,
          rate, VISUAL_AUDIO_SAMPLE_FORMAT_S16, VISUAL_AUDIO_CHANNEL_LEFT);
      visual_audio_samplepool_input_channel (visual->audio->samplepool,
          rbuf,
          rate, VISUAL_AUDIO_SAMPLE_FORMAT_S16, VISUAL_AUDIO_CHANNEL_RIGHT);

      visual_object_unref (VISUAL_OBJECT (lbuf));
      visual_object_unref (VISUAL_OBJECT (rbuf));

    }
#else
    if (visual->channels == 2) {
      for (i = 0; i < 512; i++) {
        visual->audio->plugpcm[0][i] = *data++;
        visual->audio->plugpcm[1][i] = *data++;
      }
    } else {
      for (i = 0; i < 512; i++) {
        visual->audio->plugpcm[0][i] = *data;
        visual->audio->plugpcm[1][i] = *data++;
      }
    }
#endif

    /* alloc a buffer if we don't have one yet, this happens
     * when we pushed a buffer in this while loop before */
    if (outbuf == NULL) {
      ret = get_buffer (visual, &outbuf);
      if (ret != GST_FLOW_OK) {
        goto beach;
      }
    }
    visual_video_set_buffer (visual->video, GST_BUFFER_DATA (outbuf));
    visual_audio_analyze (visual->audio);
    visual_actor_run (visual->actor, visual->audio);
    visual_video_set_buffer (visual->video, NULL);
    GST_DEBUG_OBJECT (visual, "rendered one frame");

    GST_BUFFER_TIMESTAMP (outbuf) = visual->next_ts;
    GST_BUFFER_DURATION (outbuf) = visual->duration;

    ret = gst_pad_push (visual->srcpad, outbuf);
    outbuf = NULL;

  skip:
    /* interpollate next timestamp */
    if (visual->next_ts != -1)
      visual->next_ts += visual->duration;

    GST_DEBUG_OBJECT (visual, "finished frame, flushing %u samples from input",
        visual->spf);

    /* Flush out the number of samples per frame */
    gst_adapter_flush (visual->adapter, visual->spf * visual->bps);

    /* quit the loop if something was wrong */
    if (ret != GST_FLOW_OK)
      break;
  }

beach:

  if (outbuf != NULL)
    gst_buffer_unref (outbuf);

  gst_object_unref (visual);

  return ret;
}
Esempio n. 30
0
static void
pgs_composition_object_render (PgsCompositionObject * obj, SpuState * state,
    GstBuffer * dest_buf)
{
  SpuColour *colour;
  guint8 *planes[3];            /* YUV frame pointers */
  guint8 *data, *end;
  guint16 obj_w;
  guint16 obj_h G_GNUC_UNUSED;
  guint x, y, i, min_x, max_x;

  if (G_UNLIKELY (obj->rle_data == NULL || obj->rle_data_size == 0
          || obj->rle_data_used != obj->rle_data_size))
    return;

  data = obj->rle_data;
  end = data + obj->rle_data_used;

  if (data + 4 > end)
    return;

  /* FIXME: Calculate and use the cropping window for the output, as the
   * intersection of the crop rectangle for this object (if any) and the
   * window specified by the object's window_id */

  /* Store the start of each plane */
  planes[0] = GST_BUFFER_DATA (dest_buf);
  planes[1] = planes[0] + (state->Y_height * state->Y_stride);
  planes[2] = planes[1] + (state->UV_height * state->UV_stride);

  /* Sanity check */
  g_return_if_fail (planes[2] + (state->UV_height * state->UV_stride) <=
      GST_BUFFER_DATA (dest_buf) + GST_BUFFER_SIZE (dest_buf));

  y = MIN (obj->y, state->Y_height);

  planes[0] += state->Y_stride * y;
  planes[1] += state->UV_stride * (y / 2);
  planes[2] += state->UV_stride * (y / 2);

  /* RLE data: */
  obj_w = GST_READ_UINT16_BE (data);
  obj_h = GST_READ_UINT16_BE (data + 2);
  data += 4;

  min_x = MIN (obj->x, state->Y_stride);
  max_x = MIN (obj->x + obj_w, state->Y_stride);

  state->comp_left = x = min_x;
  state->comp_right = max_x;

  gstspu_clear_comp_buffers (state);

  while (data < end) {
    guint8 pal_id;
    guint16 run_len;

    pal_id = *data++;
    if (pal_id != 0) {
      run_len = 1;
    } else {
      if (data + 1 > end)
        return;
      switch (data[0] & 0xC0) {
        case 0x00:
          run_len = (data[0] & 0x3f);
          data++;
          break;
        case 0x40:
          if (data + 2 > end)
            return;
          run_len = ((data[0] << 8) | data[1]) & 0x3fff;
          data += 2;
          break;
        case 0x80:
          if (data + 2 > end)
            return;
          run_len = (data[0] & 0x3f);
          pal_id = data[1];
          data += 2;
          break;
        case 0xC0:
          if (data + 3 > end)
            return;
          run_len = ((data[0] << 8) | data[1]) & 0x3fff;
          pal_id = data[2];
          data += 3;
          break;
        default:
          run_len = 0;
          break;
      }
    }

    colour = &state->pgs.palette[pal_id];
    if (colour->A) {
      guint32 inv_A = 0xff - colour->A;
      if (G_UNLIKELY (x + run_len > max_x))
        run_len = (max_x - x);

      for (i = 0; i < run_len; i++) {
        planes[0][x] = (inv_A * planes[0][x] + colour->Y) / 0xff;

        state->comp_bufs[0][x / 2] += colour->U;
        state->comp_bufs[1][x / 2] += colour->V;
        state->comp_bufs[2][x / 2] += colour->A;
        x++;
      }
    } else {
      x += run_len;
    }

    if (!run_len || x > max_x) {
      x = min_x;
      planes[0] += state->Y_stride;

      if (y % 2) {
        gstspu_blend_comp_buffers (state, planes);
        gstspu_clear_comp_buffers (state);

        planes[1] += state->UV_stride;
        planes[2] += state->UV_stride;
      }
      y++;
      if (y >= state->Y_height)
        return;                 /* Hit the bottom */
    }
  }

  if (y % 2)
    gstspu_blend_comp_buffers (state, planes);
}