コード例 #1
0
ファイル: gsttiaudenc1.c プロジェクト: xieran1988/parents
/******************************************************************************
 * gst_tiaudenc1_chain
 *    This is the main processing routine.  This function receives a buffer
 *    from the sink pad, processes it, and pushes the result to the source
 *    pad.
 ******************************************************************************/
static GstFlowReturn gst_tiaudenc1_chain(GstPad * pad, GstBuffer * buf)
{
    GstTIAudenc1  *audenc1 = GST_TIAUDENC1(GST_OBJECT_PARENT(pad));
    GstFlowReturn  flow    = GST_FLOW_OK;
    gboolean       checkResult;

    /* If the encode thread aborted, signal it to let it know it's ok to
     * shut down, and communicate the failure to the pipeline.
     */
    if (gst_tithread_check_status(audenc1, TIThread_CODEC_ABORTED,
            checkResult)) {
       flow = GST_FLOW_UNEXPECTED;
       goto exit;
    }

    /* If our engine handle is currently NULL, then either this is our first
     * buffer or the upstream element has re-negotiated our capabilities which
     * resulted in our engine being closed.  In either case, we need to
     * initialize (or re-initialize) our audio encoder to handle the new
     * stream.
     */
    if (audenc1->hEngine == NULL) {
        if (!gst_tiaudenc1_init_audio(audenc1)) {
            GST_ELEMENT_ERROR(audenc1, RESOURCE, FAILED,
            ("Unable to initialize audio\n"), (NULL));
            flow = GST_FLOW_UNEXPECTED;
            goto exit;
        }

        GST_TICIRCBUFFER_TIMESTAMP(audenc1->circBuf) =
            GST_CLOCK_TIME_IS_VALID(GST_BUFFER_TIMESTAMP(buf)) ?
            GST_BUFFER_TIMESTAMP(buf) : 0ULL;
    }

    /* Queue up the encoded data stream into a circular buffer */
    if (!gst_ticircbuffer_queue_data(audenc1->circBuf, buf)) {
        GST_ELEMENT_ERROR(audenc1, RESOURCE, WRITE,
        ("Failed to queue input buffer into circular buffer\n"), (NULL));
        flow = GST_FLOW_UNEXPECTED;
        goto exit;
    }

exit:
    gst_buffer_unref(buf);
    return flow;
}
コード例 #2
0
/******************************************************************************
 * gst_ticircbuffer_queue_data
 *     Append received encoded data to end of circular buffer
 ******************************************************************************/
gboolean gst_ticircbuffer_queue_data(GstTICircBuffer *circBuf, GstBuffer *buf)
{
    gboolean result = TRUE;
    Int32    writeSpace;

    /* If the circular buffer doesn't exist, do nothing */
    if (circBuf == NULL) {
        goto exit_fail;
    }

    /* Reset our mutex condition so a call to wait_on_consumer will block */
    Rendezvous_reset(circBuf->waitOnConsumer);

    /* If the consumer aborted, abort the buffer queuing.  We don't want to
     * queue buffers that no one will read.
     */
    if (circBuf->consumerAborted) {
        goto exit_fail;
    }

    /* If we run out of space, we need to move the data from the last buffer
     * window to the first window and continue queuing new data in the second
     * window.  If the consumer isn't done with the first window yet, we need
     * to block until it is.
     */
    while ((writeSpace = gst_ticircbuffer_write_space(circBuf)) <
            GST_BUFFER_SIZE(buf)) {

        /* If the write pointer is ahead of the read pointer, check to see if
         * the first window is free.  If it is, we may be able to shift the
         * data without blocking.
         */
        if (circBuf->contiguousData &&
            gst_ticircbuffer_first_window_free(circBuf)) {

            if (gst_ticircbuffer_shift_data(circBuf)) {
                continue;
            }
        }

        /* If there is some space available in the circular buffer, process as
         * much of the input buffer as we can before we block.  The ability to
         * do this is critical for both encode and decode operations.  For
         * encode, this guarantees that we will always provide a full window
         * to encode and never starve the codec.  For decode, this guarantees
         * the write pointer will always reach the last window of the circular
         * buffer before blocking, which is critical for the write pointer to
         * be reset properly.
         */
        if (writeSpace > 0) {

            GstBuffer* subBuf;
            gboolean   tmpResult;

            GST_LOG("splitting input buffer of size %u into two pieces of "
                "sizes %lu and %lu\n",  GST_BUFFER_SIZE(buf), writeSpace,
                GST_BUFFER_SIZE(buf) - writeSpace);

            subBuf = gst_buffer_create_sub(buf, 0, writeSpace);
            tmpResult = gst_ticircbuffer_queue_data(circBuf, subBuf);
            gst_buffer_unref(subBuf);

            if (!tmpResult) { goto exit_fail; }

            subBuf = gst_buffer_create_sub(buf, writeSpace,
                         GST_BUFFER_SIZE(buf) - writeSpace);
            tmpResult = gst_ticircbuffer_queue_data(circBuf, subBuf);
            gst_buffer_unref(subBuf);

            if (!tmpResult) { goto exit_fail; }

            goto exit;
        }

        /* Block until either the first window is free, or there is enough
         * free space available to put our buffer.
         */
        GST_LOG("blocking input until processing thread catches up\n");
        gst_ticircbuffer_wait_on_consumer(circBuf, GST_BUFFER_SIZE(buf));
        GST_LOG("unblocking input\n");

        /* Reset our mutex condition so calling wait_on_consumer will block */
        Rendezvous_reset(circBuf->waitOnConsumer);

        /* If the consumer aborted, abort the buffer queuing.  We don't want to
         * queue buffers that no one will read.
         */
        if (circBuf->consumerAborted) {
            goto exit_fail;
        }

        gst_ticircbuffer_shift_data(circBuf);
    }

    /* Log the buffer timestamp if available */
    if (GST_CLOCK_TIME_IS_VALID(GST_BUFFER_TIMESTAMP(buf))) {
        GST_LOG("buffer received:  timestamp:  %llu, duration:  "
            "%llu\n", GST_BUFFER_TIMESTAMP(buf), GST_BUFFER_DURATION(buf));
    }
    else {
        GST_LOG("buffer received:  no timestamp available\n");
    }

    /* Copy the buffer using user defined function */
    if (circBuf->userCopy) {
        GST_LOG("copying input buffer using user provided copy fxn\n");
        if (circBuf->userCopy(circBuf->writePtr, buf, 
              circBuf->userCopyData) < 0) {
            GST_ERROR("failed to copy input buffer.\n");
            goto exit_fail;
        }
    }
    else {        
        memcpy(circBuf->writePtr, GST_BUFFER_DATA(buf), GST_BUFFER_SIZE(buf));
    }
    circBuf->writePtr += GST_BUFFER_SIZE(buf);

    /* Copy new data to the end of the buffer */
    GST_LOG("queued %u bytes of data\n", GST_BUFFER_SIZE(buf));

    /* Output the buffer status to stdout if buffer debug is enabled */
    if (circBuf->displayBuffer) {
        gst_ticircbuffer_display(circBuf);
    }

    /* If the upstream elements are providing time information, update the
     * duration of time stored by the encoded data.
     */
    if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_DURATION(buf))) {
        circBuf->dataDuration = GST_CLOCK_TIME_NONE;
    }
    else if (GST_CLOCK_TIME_IS_VALID(circBuf->dataDuration)) {
        circBuf->dataDuration += GST_BUFFER_DURATION(buf);
    }


    /* If our buffer got low, some consuming threads may have blocked waiting
     * for more data.  If there is at least a window and our specified read
     * ahead available in the buffer, unblock any threads.
     */
    if (gst_ticircbuffer_data_size(circBuf) >=
        circBuf->windowSize + circBuf->readAheadSize) {
        gst_ticircbuffer_broadcast_producer(circBuf);
    }

    goto exit;

exit_fail:
    result = FALSE;
exit:
    return result;
}