/***************************************************************************** * gst_tiprepencbuf_prepare_output_buffer * Function is used to allocate output buffer *****************************************************************************/ static GstFlowReturn gst_tiprepencbuf_prepare_output_buffer(GstBaseTransform * trans, GstBuffer * inBuf, gint size, GstCaps * caps, GstBuffer ** outBuf) { GstTIPrepEncBuf *prepencbuf = GST_TIPREPENCBUF(trans); Buffer_Handle hOutBuf; GST_LOG("begin prepare output buffer\n"); /* Get free buffer from buftab */ if (!(hOutBuf = gst_tidmaibuftab_get_buf(prepencbuf->hOutBufTab))) { GST_ELEMENT_ERROR(prepencbuf, RESOURCE, READ, ("failed to get free buffer\n"), (NULL)); return GST_FLOW_ERROR; } /* Create a DMAI transport buffer object to carry a DMAI buffer to * the source pad. The transport buffer knows how to release the * buffer for re-use in this element when the source pad calls * gst_buffer_unref(). */ GST_LOG("creating dmai transport buffer\n"); *outBuf = gst_tidmaibuffertransport_new(hOutBuf, prepencbuf->hOutBufTab, NULL, NULL); gst_buffer_set_data(*outBuf, (guint8 *) Buffer_getUserPtr(hOutBuf), Buffer_getSize(hOutBuf)); gst_buffer_set_caps(*outBuf, GST_PAD_CAPS(trans->srcpad)); GST_LOG("end prepare output buffer\n"); return GST_FLOW_OK; }
/******************************************************************************* * gst_tidmaivideosink_buffer_alloc * * Function used to allocate a buffer from upstream elements *******************************************************************************/ static GstFlowReturn gst_tidmaivideosink_buffer_alloc(GstBaseSink *bsink, guint64 offset, guint size, GstCaps *caps, GstBuffer **buf){ Buffer_Handle hBuf; GstTIDmaiVideoSink *sink = GST_TIDMAIVIDEOSINK_CAST(bsink); if (!sink->zeromemcpy){ return GST_FLOW_OK; } if (!sink->capsAreSet){ if (!gst_tidmaivideosink_set_caps(bsink,caps)){ return GST_FLOW_UNEXPECTED; } } if (!sink->dmaiElementUpstream){ return GST_FLOW_OK; } hBuf = gst_tidmaivideosink_get_display_buffer(sink,NULL); if (hBuf){ *buf = gst_tidmaibuffertransport_new(hBuf,NULL, NULL, FALSE); sink->allocatedBuffers[Buffer_getId(hBuf)] = *buf; gst_tidmaibuffertransport_set_release_callback( (GstTIDmaiBufferTransport *)*buf, allocated_buffer_release_cb,sink); gst_buffer_set_caps(*buf,caps); GST_BUFFER_SIZE(*buf) = gst_ti_calculate_bufSize( sink->oattrs.width,sink->oattrs.height,sink->colorSpace); sink->numAllocatedBuffers++; GST_LOG("Number of pad allocated buffers is %d, current %p",sink->numAllocatedBuffers,*buf); sink->lastAllocatedBuffer = *buf; } else { return GST_FLOW_UNEXPECTED; } GST_DEBUG("Leave with buffer %p",*buf); return GST_FLOW_OK; }
static GstFlowReturn create(GstPushSrc *base, GstBuffer **buf) { GstTICaptureSrc *src = (GstTICaptureSrc *)base; Buffer_Handle hDstBuf; GstBuffer *outBuf; gint ret = GST_FLOW_OK; BufferGfx_Attrs gfxAttrs = BufferGfx_Attrs_DEFAULT; Int32 width, height; GST_LOG("create begin"); /* create capture device */ if (src->hCapture == NULL) { /* set framerate based on video standard */ switch(dmai_video_std(src->video_standard)) { case VideoStd_D1_NTSC: gst_value_set_fraction(&src->framerate,30000,1001); break; case VideoStd_D1_PAL: gst_value_set_fraction(&src->framerate,25,1); break; default: gst_value_set_fraction(&src->framerate,30,1); break; } /* set width & height based on video standard */ src->cAttrs.videoStd = dmai_video_std(src->video_standard); VideoStd_getResolution(src->cAttrs.videoStd, &width, &height); width = 720; height = 576; GST_WARNING("force video size to %dx%d", src->width, src->height); src->width = width; src->height = height; gfxAttrs.dim.height = src->height; gfxAttrs.dim.width = src->width; src->cAttrs.captureDimension = &gfxAttrs.dim; if (!capture_create(src)) return GST_FLOW_ERROR; } /* Get buffer from driver */ if (Capture_get(src->hCapture, &hDstBuf)) { GST_ELEMENT_ERROR(src, RESOURCE, FAILED, ("Failed to allocate buffer\n"), (NULL)); return GST_FLOW_ERROR; } /* Create a DMAI transport buffer object to carry a DMAI buffer to * the source pad. The transport buffer knows how to release the * buffer for re-use in this element when the source pad calls * gst_buffer_unref(). */ outBuf = gst_tidmaibuffertransport_new(hDstBuf, src->hBufTab, capture_buffer_finalize, (void*)src); gst_buffer_set_data(outBuf, GST_BUFFER_DATA(outBuf), Buffer_getSize(hDstBuf)); *buf = outBuf; /* set buffer metadata */ if (G_LIKELY (ret == GST_FLOW_OK && *buf)) { GstClock *clock; GstClockTime timestamp; GST_BUFFER_OFFSET (*buf) = src->offset++; GST_BUFFER_OFFSET_END (*buf) = src->offset; /* timestamps, LOCK to get clock and base time. */ GST_OBJECT_LOCK (src); if ((clock = GST_ELEMENT_CLOCK (src))) { /* we have a clock, get base time and ref clock */ timestamp = GST_ELEMENT (src)->base_time; gst_object_ref (clock); } else { /* no clock, can't set timestamps */ timestamp = GST_CLOCK_TIME_NONE; } GST_OBJECT_UNLOCK (src); if (G_LIKELY (clock)) { /* the time now is the time of the clock minus the base time */ timestamp = gst_clock_get_time (clock) - timestamp; gst_object_unref (clock); /* if we have a framerate adjust timestamp for frame latency */ if (GST_CLOCK_TIME_IS_VALID (src->duration)) { if (timestamp > src->duration) timestamp -= src->duration; else timestamp = 0; } } /* FIXME: use the timestamp from the buffer itself! */ GST_BUFFER_TIMESTAMP (*buf) = timestamp; GST_BUFFER_DURATION (*buf) = src->duration; } /* Create caps for buffer */ GstCaps *mycaps; GstStructure *structure; mycaps = gst_caps_new_empty(); if (src->cAttrs.colorSpace == ColorSpace_UYVY) { structure = gst_structure_new( "video/x-raw-yuv", "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC('U', 'Y', 'V', 'Y'), "framerate", GST_TYPE_FRACTION, gst_value_get_fraction_numerator(&src->framerate), gst_value_get_fraction_denominator(&src->framerate), "width", G_TYPE_INT, src->width, "height", G_TYPE_INT, src->height, (gchar*) NULL); } else if(src->cAttrs.colorSpace == ColorSpace_YUV420PSEMI) { structure = gst_structure_new( "video/x-raw-yuv", "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC('N', 'V', '1', '2'), "framerate", GST_TYPE_FRACTION, gst_value_get_fraction_numerator(&src->framerate), gst_value_get_fraction_denominator(&src->framerate), "width", G_TYPE_INT, src->width, "height", G_TYPE_INT, src->height, (gchar*) NULL); } else { GST_ERROR("unsupported fourcc\n"); return FALSE; } gst_caps_append_structure(mycaps, gst_structure_copy (structure)); gst_structure_free(structure); gst_buffer_set_caps(*buf, mycaps); gst_caps_unref(mycaps); { static int fn; fn++; GST_INFO("capture frame %d", fn); } GST_LOG("create end"); return GST_FLOW_OK; }
/* Default implementation for _chain */ static GstFlowReturn gst_tidmai_base_video_dualencoder_default_realize_instance (GstTIDmaiBaseVideoDualEncoder *video_dualencoder, GstTIDmaiDualEncInstance *encoder_instance, GstBuffer *entry_buffer) { GST_DEBUG_OBJECT (video_dualencoder, "Entry gst_tidmai_base_video_dualencoder_default_realize_instance"); /* Only for test */ //GstClockTime time_start, time_start2, time_end, time_end2; //GstClockTimeDiff time_diff; Buffer_Attrs Attrs; Buffer_Handle outBufHandle; //Buffer_Attrs inAttrs; //Buffer_Handle inBufHandle; GstTIDmaiVideoInfo *video_info; UInt32 phys = 10; Bool isContiguous = FALSE; //time_start = gst_util_get_timestamp (); int ret; GstBuffer *buffer_push_out; /* Tests if the buffer */ phys = Memory_getBufferPhysicalAddress( GST_BUFFER_DATA(entry_buffer), GST_BUFFER_SIZE(entry_buffer), &isContiguous); if(phys == 0) { GST_ERROR_OBJECT (video_dualencoder, "Entry buffer isn't CMEM"); return GST_FLOW_NOT_SUPPORTED; } else { GST_DEBUG_OBJECT (video_dualencoder, "Using buffers with contiguos memory"); encoder_instance->input_buffer = entry_buffer; } /* Check for the output_buffer */ if (GST_TI_DMAI_BASE_DUALENCODER (video_dualencoder)->submitted_output_buffers == NULL) { video_info = (GstTIDmaiVideoInfo *) GST_TI_DMAI_BASE_DUALENCODER (video_dualencoder)->high_resolution_encoder->media_info; GST_TI_DMAI_BASE_DUALENCODER (video_dualencoder)->inBufSize = (video_info->width * video_info->height) * 1.8; if (GST_TI_DMAI_BASE_DUALENCODER (video_dualencoder)->outBufSize == 0) { /* Default value for the out buffer size */ GST_TI_DMAI_BASE_DUALENCODER (video_dualencoder)->outBufSize = GST_TI_DMAI_BASE_DUALENCODER (video_dualencoder)->inBufSize * 5; } /* Add the free memory slice to the list */ struct cmemSlice *slice = g_malloc0 (sizeof (struct cmemSlice)); slice->start = 0; slice->end = GST_TI_DMAI_BASE_DUALENCODER (video_dualencoder)->outBufSize; slice->size = GST_TI_DMAI_BASE_DUALENCODER (video_dualencoder)->outBufSize; #ifdef GLIB_2_31_AND_UP g_mutex_init(&(GST_TI_DMAI_BASE_DUALENCODER (video_dualencoder)->freeMutex)); #else GST_TI_DMAI_BASE_DUALENCODER (video_dualencoder)->freeMutex = g_mutex_new(); #endif GST_TI_DMAI_BASE_DUALENCODER (video_dualencoder)->freeSlices = g_list_append (GST_TI_DMAI_BASE_DUALENCODER (video_dualencoder)->freeSlices, slice); /* Allocate the circular buffer */ Attrs = Buffer_Attrs_DEFAULT; Attrs.useMask = gst_tidmaibuffertransport_GST_FREE; outBufHandle = Buffer_create(GST_TI_DMAI_BASE_DUALENCODER (video_dualencoder)->outBufSize, &Attrs); GST_TI_DMAI_BASE_DUALENCODER (video_dualencoder)->submitted_output_buffers = gst_tidmaibuffertransport_new(outBufHandle, NULL, NULL, FALSE); } /* Encode the actual buffer */ buffer_push_out = gst_tidmai_base_dualencoder_encode (GST_TI_DMAI_BASE_DUALENCODER (video_dualencoder), encoder_instance); gst_buffer_copy_metadata(buffer_push_out, entry_buffer, GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS); //time_end = gst_util_get_timestamp (); //time_diff = GST_CLOCK_DIFF (time_start, time_end); //g_print ("DualEncoder time: %" G_GUINT64_FORMAT " ns.\n", time_diff); /* push the buffer and check for any error */ //time_start2 = gst_util_get_timestamp (); GST_BUFFER_CAPS (buffer_push_out) = gst_caps_ref(GST_PAD_CAPS(encoder_instance->src_pad)); ret = gst_pad_push (encoder_instance->src_pad, buffer_push_out); //time_end2 = gst_util_get_timestamp (); //time_diff = GST_CLOCK_DIFF (time_start2, time_end2); //g_print ("\nPush time: %" G_GUINT64_FORMAT " ns.\n\n", time_diff); if (GST_FLOW_OK != ret) { GST_ERROR_OBJECT (video_dualencoder, "Push buffer return with error: %d", ret); } GST_DEBUG_OBJECT (video_dualencoder, "Leave gst_tidmai_base_video_dualencoder_default_realize_instance"); return ret; }
/****************************************************************************** * gst_ticircbuffer_get_data ******************************************************************************/ GstBuffer* gst_ticircbuffer_get_data(GstTICircBuffer *circBuf) { Buffer_Handle hCircBufWindow; Buffer_Attrs bAttrs; GstBuffer *result; Int32 bufSize; if (circBuf == NULL) { return NULL; } /* Reset our mutex condition so calling wait_on_consumer will block */ Rendezvous_reset(circBuf->waitOnProducer); /* Reset the read pointer to the beginning of the buffer when we're * approaching the buffer's end (see function definition for reset * conditions). */ gst_ticircbuffer_reset_read_pointer(circBuf); /* Don't return any data util we have a full window available */ while (!circBuf->drain && !gst_ticircbuffer_window_available(circBuf)) { GST_LOG("blocking output until a full window is available\n"); gst_ticircbuffer_wait_on_producer(circBuf); GST_LOG("unblocking output\n"); gst_ticircbuffer_reset_read_pointer(circBuf); /* Reset our mutex condition so calling wait_on_consumer will block */ Rendezvous_reset(circBuf->waitOnProducer); } /* Set the size of the buffer to be no larger than the window size. Some * audio codecs have an issue when you pass a buffer larger than 64K. * We need to pass it smaller buffer sizes though, as the EOS is detected * when we return a 0 size buffer. */ bufSize = gst_ticircbuffer_data_available(circBuf); if (bufSize > circBuf->windowSize) { bufSize = circBuf->windowSize; } /* Return a reference buffer that points to the area of the circular * buffer we want to decode. */ Buffer_getAttrs(circBuf->hBuf, &bAttrs); bAttrs.reference = TRUE; hCircBufWindow = Buffer_create(bufSize, &bAttrs); Buffer_setUserPtr(hCircBufWindow, circBuf->readPtr); Buffer_setNumBytesUsed(hCircBufWindow, bufSize); GST_LOG("returning data at offset %u\n", circBuf->readPtr - Buffer_getUserPtr(circBuf->hBuf)); result = (GstBuffer*)(gst_tidmaibuffertransport_new(hCircBufWindow, NULL)); GST_BUFFER_TIMESTAMP(result) = circBuf->dataTimeStamp; GST_BUFFER_DURATION(result) = GST_CLOCK_TIME_NONE; return result; }
/***************************************************************************** * 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; } }
/****************************************************************************** * gst_tiaudenc1_encode_thread * Call the audio codec to process a full input buffer ******************************************************************************/ static void* gst_tiaudenc1_encode_thread(void *arg) { GstTIAudenc1 *audenc1 = GST_TIAUDENC1(gst_object_ref(arg)); void *threadRet = GstTIThreadSuccess; Buffer_Handle hDstBuf; Int32 encDataConsumed; GstBuffer *encDataWindow = NULL; GstClockTime encDataTime; Buffer_Handle hEncDataWindow; GstBuffer *outBuf; GstClockTime sampleDuration; guint sampleRate; guint numSamples; Int bufIdx; Int ret; GST_LOG("starting audenc encode thread\n"); /* Initialize codec engine */ ret = gst_tiaudenc1_codec_start(audenc1); /* Notify main thread that it is ok to continue initialization */ Rendezvous_meet(audenc1->waitOnEncodeThread); Rendezvous_reset(audenc1->waitOnEncodeThread); if (ret == FALSE) { GST_ELEMENT_ERROR(audenc1, RESOURCE, FAILED, ("Failed to start codec\n"), (NULL)); goto thread_exit; } while (TRUE) { /* Obtain an raw data frame */ encDataWindow = gst_ticircbuffer_get_data(audenc1->circBuf); encDataTime = GST_BUFFER_TIMESTAMP(encDataWindow); hEncDataWindow = GST_TIDMAIBUFFERTRANSPORT_DMAIBUF(encDataWindow); /* Check if there is enough encoded data to be sent to the codec. * The last frame of data may not be sufficient to meet the codec * requirements for the amount of input data. If so just throw * away the last bit of data rather than filling with bogus * data. */ if (GST_BUFFER_SIZE(encDataWindow) < Aenc1_getInBufSize(audenc1->hAe)) { GST_LOG("Not enough audio data remains\n"); if (!audenc1->drainingEOS) { goto thread_failure; } goto thread_exit; } /* Obtain a free output buffer for the encoded data */ if (!(hDstBuf = gst_tidmaibuftab_get_buf(audenc1->hOutBufTab))) { GST_ELEMENT_ERROR(audenc1, RESOURCE, READ, ("Failed to get a free contiguous buffer from BufTab\n"), (NULL)); goto thread_exit; } /* Invoke the audio encoder */ GST_LOG("Invoking the audio encoder at 0x%08lx with %u bytes\n", (unsigned long)Buffer_getUserPtr(hEncDataWindow), GST_BUFFER_SIZE(encDataWindow)); ret = Aenc1_process(audenc1->hAe, hEncDataWindow, hDstBuf); encDataConsumed = Buffer_getNumBytesUsed(hEncDataWindow); if (ret < 0) { GST_ELEMENT_ERROR(audenc1, STREAM, ENCODE, ("Failed to encode audio buffer\n"), (NULL)); goto thread_failure; } /* If no encoded data was used we cannot find the next frame */ if (ret == Dmai_EBITERROR && encDataConsumed == 0) { GST_ELEMENT_ERROR(audenc1, STREAM, ENCODE, ("Fatal bit error\n"), (NULL)); goto thread_failure; } if (ret > 0) { GST_LOG("Aenc1_process returned success code %d\n", ret); } sampleRate = audenc1->samplefreq; numSamples = encDataConsumed / (2 * audenc1->channels) ; sampleDuration = GST_FRAMES_TO_CLOCK_TIME(numSamples, sampleRate); /* Release the reference buffer, and tell the circular buffer how much * data was consumed. */ ret = gst_ticircbuffer_data_consumed(audenc1->circBuf, encDataWindow, encDataConsumed); encDataWindow = NULL; if (!ret) { goto thread_failure; } /* Set the source pad capabilities based on the encoded frame * properties. */ gst_tiaudenc1_set_source_caps(audenc1); /* Create a DMAI transport buffer object to carry a DMAI buffer to * the source pad. The transport buffer knows how to release the * buffer for re-use in this element when the source pad calls * gst_buffer_unref(). */ outBuf = gst_tidmaibuffertransport_new(hDstBuf, audenc1->hOutBufTab, NULL, NULL); gst_buffer_set_data(outBuf, GST_BUFFER_DATA(outBuf), Buffer_getNumBytesUsed(hDstBuf)); gst_buffer_set_caps(outBuf, GST_PAD_CAPS(audenc1->srcpad)); /* Set timestamp on output buffer */ if (audenc1->genTimeStamps) { GST_BUFFER_DURATION(outBuf) = sampleDuration; GST_BUFFER_TIMESTAMP(outBuf) = encDataTime; } else { GST_BUFFER_TIMESTAMP(outBuf) = GST_CLOCK_TIME_NONE; } /* Tell circular buffer how much time we consumed */ gst_ticircbuffer_time_consumed(audenc1->circBuf, sampleDuration); /* Push the transport buffer to the source pad */ GST_LOG("pushing buffer to source pad with timestamp : %" GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP(outBuf)), GST_TIME_ARGS (GST_BUFFER_DURATION(outBuf))); if (gst_pad_push(audenc1->srcpad, outBuf) != GST_FLOW_OK) { GST_DEBUG("push to source pad failed\n"); goto thread_failure; } /* Release buffers no longer in use by the codec */ Buffer_freeUseMask(hDstBuf, gst_tidmaibuffer_CODEC_FREE); } thread_failure: gst_tithread_set_status(audenc1, TIThread_CODEC_ABORTED); gst_ticircbuffer_consumer_aborted(audenc1->circBuf); threadRet = GstTIThreadFailure; thread_exit: /* Re-claim any buffers owned by the codec */ bufIdx = BufTab_getNumBufs(GST_TIDMAIBUFTAB_BUFTAB(audenc1->hOutBufTab)); while (bufIdx-- > 0) { Buffer_Handle hBuf = BufTab_getBuf( GST_TIDMAIBUFTAB_BUFTAB(audenc1->hOutBufTab), bufIdx); Buffer_freeUseMask(hBuf, gst_tidmaibuffer_CODEC_FREE); } /* Release the last buffer we retrieved from the circular buffer */ if (encDataWindow) { gst_ticircbuffer_data_consumed(audenc1->circBuf, encDataWindow, 0); } /* We have to wait to shut down this thread until we can guarantee that * no more input buffers will be queued into the circular buffer * (we're about to delete it). */ Rendezvous_meet(audenc1->waitOnEncodeThread); Rendezvous_reset(audenc1->waitOnEncodeThread); /* Notify main thread that we are done draining before we shutdown the * codec, or we will hang. We proceed in this order so the EOS event gets * propagated downstream before we attempt to shut down the codec. The * codec-shutdown process will block until all BufTab buffers have been * released, and downstream-elements may hang on to buffers until * they get the EOS. */ Rendezvous_force(audenc1->waitOnEncodeDrain); /* Initialize codec engine */ if (gst_tiaudenc1_codec_stop(audenc1) < 0) { GST_ERROR("failed to stop codec\n"); GST_ELEMENT_ERROR(audenc1, RESOURCE, FAILED, ("Failed to stop codec\n"), (NULL)); } gst_object_unref(audenc1); GST_LOG("exit audio encode_thread (%d)\n", (int)threadRet); return threadRet; }