/****************************************************************************** * Display_v4l2_put ******************************************************************************/ Int Display_v4l2_put(Display_Handle hDisplay, Buffer_Handle hBuf) { Int idx; assert(hDisplay); assert(hBuf); idx = getUsedIdx(hDisplay->bufDescs, BufTab_getNumBufs(hDisplay->hBufTab)); if (idx < 0) { Dmai_err0("No v4l2 buffers available\n"); return Dmai_ENOMEM; } hDisplay->bufDescs[idx].v4l2buf.m.userptr = (Int)Buffer_getUserPtr(hBuf); hDisplay->bufDescs[idx].v4l2buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; /* Issue captured frame buffer back to device driver */ if (ioctl(hDisplay->fd, VIDIOC_QBUF, &hDisplay->bufDescs[idx].v4l2buf) == -1) { Dmai_err1("VIDIOC_QBUF failed (%s)\n", strerror(errno)); return Dmai_EFAIL; } hDisplay->bufDescs[idx].hBuf = hBuf; hDisplay->bufDescs[idx].used = FALSE; return Dmai_EOK; }
/****************************************************************************** * Capture_put ******************************************************************************/ Int Capture_put(Capture_Handle hCapture, Buffer_Handle hBuf) { Int idx; assert(hCapture); assert(hBuf); idx = getUsedIdx(hCapture->bufDescs, BufTab_getNumBufs(hCapture->hBufTab)); if (idx < 0) { Dmai_err0("You must get a captured buffer before putting one\n"); return Dmai_ENOMEM; } hCapture->bufDescs[idx].v4l2buf.m.userptr = (Int) Buffer_getUserPtr(hBuf); hCapture->bufDescs[idx].v4l2buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; /* Issue captured frame buffer back to device driver */ if (ioctl(hCapture->fd, VIDIOC_QBUF, &hCapture->bufDescs[idx].v4l2buf) == -1) { Dmai_err1("VIDIOC_QBUF failed (%s)\n", strerror(errno)); return Dmai_EFAIL; } hCapture->bufDescs[idx].hBuf = hBuf; hCapture->bufDescs[idx].used = FALSE; return Dmai_EOK; }
/****************************************************************************** * cleanup ******************************************************************************/ static Int cleanup(Display_Handle hDisplay) { Int ret = Dmai_EOK; BufTab_Handle hBufTab = hDisplay->hBufTab; enum v4l2_buf_type type; Int bufIdx; Buffer_Handle hDispBuf; if (hDisplay->fd != -1) { if (hDisplay->started) { /* Shut off the video display */ type = V4L2_BUF_TYPE_VIDEO_OUTPUT; if (ioctl(hDisplay->fd, VIDIOC_STREAMOFF, &type) == -1) { Dmai_err1("VIDIOC_STREAMOFF failed (%s)\n", strerror(errno)); ret = Dmai_EFAIL; } } if (close(hDisplay->fd) == -1) { Dmai_err1("Failed to close capture device (%s)\n", strerror(errno)); ret = Dmai_EIO; } if (hDisplay->userAlloc == FALSE) { if (hBufTab) { for (bufIdx = 0; bufIdx < BufTab_getNumBufs(hBufTab); bufIdx++) { hDispBuf = BufTab_getBuf(hBufTab, bufIdx); if (munmap(Buffer_getUserPtr(hDispBuf), Buffer_getSize(hDispBuf)) == -1) { Dmai_err1("Failed to unmap capture buffer%d\n", bufIdx); ret = Dmai_EFAIL; } } } } } if (hDisplay->bufDescs) { free(hDisplay->bufDescs); } free(hDisplay); return ret; }
/****************************************************************************** * cleanup ******************************************************************************/ static Int cleanup(Capture_Handle hCapture) { BufTab_Handle hBufTab = hCapture->hBufTab; Int ret = Dmai_EOK; Int8 *capBufPtr; enum v4l2_buf_type type; Uns bufIdx; Buffer_Handle hCapBuf; if (hCapture->fd != -1) { if (hCapture->started) { /* Shut off the video capture */ type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (ioctl(hCapture->fd, VIDIOC_STREAMOFF, &type) == -1) { Dmai_err1("VIDIOC_STREAMOFF failed (%s)\n", strerror(errno)); ret = Dmai_EFAIL; } } if (close(hCapture->fd) == -1) { Dmai_err1("Failed to close capture device (%s)\n", strerror(errno)); ret = Dmai_EIO; } if (hCapture->userAlloc == FALSE && hBufTab) { for (bufIdx = 0; bufIdx < BufTab_getNumBufs(hBufTab); bufIdx++) { hCapBuf = BufTab_getBuf(hBufTab, bufIdx); capBufPtr = Buffer_getUserPtr(hCapBuf); if (munmap(capBufPtr - hCapture->topOffset, Buffer_getSize(hCapBuf)) == -1) { Dmai_err1("Failed to unmap capture buffer%d\n", bufIdx); ret = Dmai_EFAIL; } } } if (hCapture->bufDescs) { free(hCapture->bufDescs); } } free(hCapture); return ret; }
/****************************************************************************** * Display_fbdev_put ******************************************************************************/ Int Display_fbdev_put(Display_Handle hDisplay, Buffer_Handle hBuf) { BufTab_Handle hBufTab = hDisplay->hBufTab; Int32 numBufs; assert(hDisplay); assert(hBuf); numBufs = BufTab_getNumBufs(hBufTab); hDisplay->displayIdx = (hDisplay->displayIdx + 1) % numBufs; hDisplay->workingIdx = (hDisplay->workingIdx + 1) % numBufs; return setDisplayBuffer(hDisplay, hDisplay->displayIdx); }
/****************************************************************************** * Capture_put ******************************************************************************/ Int Capture_put(Capture_Handle hCapture, Buffer_Handle hBuf) { Int idx; assert(hCapture); assert(hBuf); /* * The used Flag as part of bufdesc is with respect to the use of buffer * by the application. If Used = TRUE then the index is available for * storing new buffer information. This is set to FALSE once it contains * valid information about the buffer. */ idx = getUsedIdx(hCapture->bufDescs, BufTab_getNumBufs(hCapture->hBufTab)); if (idx < 0) { Dmai_err0("You must get a captured buffer before putting one\n"); return Dmai_ENOMEM; } hCapture->bufDescs[idx].v4l2buf.m.userptr = (Int) Buffer_getUserPtr(hBuf); hCapture->bufDescs[idx].v4l2buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; /* Issue captured frame buffer back to device driver */ if (ioctl(hCapture->fd, VIDIOC_QBUF, &hCapture->bufDescs[idx].v4l2buf) == -1) { Dmai_err1("VIDIOC_QBUF failed (%s)\n", strerror(errno)); return Dmai_EFAIL; } hCapture->bufDescs[idx].hBuf = hBuf; hCapture->bufDescs[idx].used = FALSE; return Dmai_EOK; }
/******************************************************************************* * gst_tidmaivideosink_init_display * * This function will intialize the display. To do so it will: * * 1. Determine the Cpu device and set the defaults for that device * 2. If the user specified display parameters on the command line * override the defaults with those parameters. * 3. Create the display device handle * 4. Create the frame copy device handle * * * TODO: As of now this function will need to be updated for how to set the * default display attributes whenever a new device is added. Hopefully * there is a way around that. *******************************************************************************/ static gboolean gst_tidmaivideosink_init_display(GstTIDmaiVideoSink * sink, ColorSpace_Type colorSpace) { Framecopy_Attrs fcAttrs = Framecopy_Attrs_DEFAULT; GST_DEBUG("Begin\n"); /* This is an extra check that the display was not already created */ if (sink->hDisplay != NULL) return TRUE; /* This loop will exit if one of the following conditions occurs: * 1. The display was created * 2. The display standard specified by the user was invalid * 3. autoselect was enabled and no working standard could be found */ while (TRUE) { if (!gst_tidmaivideosink_set_display_attrs(sink,colorSpace)) { GST_ELEMENT_ERROR(sink,STREAM,FAILED,(NULL), ("Error while trying to set the display attributes")); return FALSE; } /* Create the display device using the attributes set above */ sink->hDisplay = Display_create(NULL, &sink->dAttrs); if ((sink->hDisplay == NULL) && (sink->autoselect == TRUE)) { GST_DEBUG("Could not create display with videoStd %d. " "Searching for next valid standard.\n", sink->dAttrs.videoStd); sink->prevVideoStd = sink->dAttrs.videoStd; continue; } else { if (!sink->hDisplay){ GST_ELEMENT_ERROR(sink,STREAM,FAILED,(NULL), ("Failed to create display")); return FALSE; } /* This code create a array to control the buffers cleaned after * change of capabilities or some properties */ sink->numBuffers = BufTab_getNumBufs(Display_getBufTab(sink->hDisplay)); sink->cleanBufCtrl = (gchar *)g_malloc0(sink->numBuffers); sink->unusedBuffers = g_malloc0(sink->numBuffers * sizeof(Buffer_Handle)); sink->numUnusedBuffers = 0; sink->allocatedBuffers = g_malloc0(sink->numBuffers * sizeof(GstBuffer *)); sink->numAllocatedBuffers = 0; break; } } if (sink->hDisplay == NULL) { GST_ELEMENT_ERROR(sink,STREAM,FAILED,(NULL), ("Failed to open display device\n")); return FALSE; } GST_DEBUG("Display Device Created\n"); /* Use an accelerated frame copy */ fcAttrs.accel = sink->accelFrameCopy; sink->hFc = Framecopy_create(&fcAttrs); if (sink->hFc == NULL) { GST_ELEMENT_ERROR(sink,STREAM,FAILED,(NULL), ("Failed to create framcopy\n")); return FALSE; } GST_DEBUG("Frame Copy Device Created\n"); GST_DEBUG("Finish\n"); return TRUE; }
/******************************************************************************* * gst_tidmaivideosink_render *******************************************************************************/ static GstFlowReturn gst_tidmaivideosink_render(GstBaseSink * bsink, GstBuffer * buf) { BufferGfx_Attrs gfxAttrs = BufferGfx_Attrs_DEFAULT; Buffer_Handle hDispBuf = NULL; Buffer_Handle inBuf = NULL; BufferGfx_Dimensions inDimSave; GstTIDmaiVideoSink *sink = GST_TIDMAIVIDEOSINK_CAST(bsink); GST_DEBUG("Begin, buffer %p",buf); /* The base sink send us the first buffer twice, so we avoid processing * it again, since the Display_put may fail on this case when using * pad_allocation */ if (sink->prerolledBuffer == buf){ GST_DEBUG("Not displaying previously pre-rolled buffer"); sink->prerolledBuffer = NULL; return GST_FLOW_OK; } sink->prerolledBuffer = NULL; /* If the input buffer is non dmai buffer, then allocate dmai buffer and * copy input buffer in dmai buffer using memcpy routine. */ if (GST_IS_TIDMAIBUFFERTRANSPORT(buf)) { inBuf = GST_TIDMAIBUFFERTRANSPORT_DMAIBUF(buf); } else { /* allocate DMAI buffer */ if (sink->tempDmaiBuf == NULL) { GST_DEBUG("Input buffer is non-dmai, allocating new buffer"); gfxAttrs.dim.width = sink->width; gfxAttrs.dim.height = sink->height; gfxAttrs.dim.lineLength = BufferGfx_calcLineLength(sink->width, sink->colorSpace); gfxAttrs.colorSpace = sink->colorSpace; sink->tempDmaiBuf = Buffer_create(GST_BUFFER_SIZE(buf), BufferGfx_getBufferAttrs(&gfxAttrs)); if (sink->tempDmaiBuf == NULL) { GST_ELEMENT_ERROR(sink,STREAM,FAILED,(NULL), ("Failed to allocate memory for the input buffer")); return GST_FLOW_UNEXPECTED; } } inBuf = sink->tempDmaiBuf; memcpy(Buffer_getUserPtr(inBuf), buf->data, buf->size); } if (Buffer_getBufTab(inBuf) == Display_getBufTab(sink->hDisplay)) { GST_DEBUG("Flipping pad allocated buffer"); /* We got a buffer that is already on video memory, just flip it */ hDispBuf = inBuf; if (sink->numAllocatedBuffers) sink->numAllocatedBuffers--; sink->allocatedBuffers[Buffer_getId(inBuf)] = NULL; if (buf == sink->lastAllocatedBuffer){ sink->lastAllocatedBuffer = NULL; } } else { /* Check if we can allocate a new buffer, otherwise we may need * to drop the buffer */ BufferGfx_getDimensions(inBuf, &inDimSave); if ((sink->numAllocatedBuffers >= (BufTab_getNumBufs(Display_getBufTab(sink->hDisplay)) - 1)) && (sink->numUnusedBuffers == 0)){ GST_ELEMENT_WARNING(sink,RESOURCE,NO_SPACE_LEFT,(NULL), ("Dropping incoming buffers because no display buffer" " available")); return GST_FLOW_OK; } else { GST_DEBUG("Obtaining display buffer"); hDispBuf = gst_tidmaivideosink_get_display_buffer(sink,inBuf); if (!hDispBuf){ return GST_FLOW_UNEXPECTED; } } if (Framecopy_config(sink->hFc, inBuf, hDispBuf) < 0) { GST_ELEMENT_ERROR(sink,STREAM,FAILED,(NULL), ("Failed to configure the frame copy")); return GST_FLOW_UNEXPECTED; } if (Framecopy_execute(sink->hFc, inBuf, hDispBuf) < 0) { GST_ELEMENT_ERROR(sink,STREAM,FAILED,(NULL), ("Failed to execute the frame copy")); return GST_FLOW_UNEXPECTED; } BufferGfx_resetDimensions(hDispBuf); BufferGfx_setDimensions(inBuf, &inDimSave); } /* Send filled buffer to display device driver to be displayed */ if (Display_put(sink->hDisplay, hDispBuf) < 0) { GST_ELEMENT_ERROR(sink,STREAM,FAILED,(NULL), ("Failed to put the buffer on display")); return GST_FLOW_UNEXPECTED; } GST_DEBUG("Finish"); return GST_FLOW_OK; }
/****************************************************************************** * appMain ******************************************************************************/ Int appMain(Args * args) { Framecopy_Attrs fcAttrs = Framecopy_Attrs_DEFAULT; BufferGfx_Attrs gfxAttrs = BufferGfx_Attrs_DEFAULT; Smooth_Attrs smAttrs = Smooth_Attrs_DEFAULT; Time_Attrs tAttrs = Time_Attrs_DEFAULT; BufTab_Handle hCapBufTab = NULL; BufTab_Handle hDisBufTab = NULL; Display_Handle hDisplay = NULL; Capture_Handle hCapture = NULL; Framecopy_Handle hFc = NULL; Smooth_Handle hSmooth = NULL; Time_Handle hTime = NULL; Int numFrame = 0; Display_Attrs dAttrs; Capture_Attrs cAttrs; Buffer_Handle cBuf, dBuf; Cpu_Device device; Int bufIdx; UInt32 time; BufferGfx_Dimensions dim; Int32 bufSize; Int ret = Dmai_EOK; /* Initialize DMAI */ Dmai_init(); if (args->benchmark) { hTime = Time_create(&tAttrs); if (hTime == NULL) { ret = Dmai_EFAIL; fprintf(stderr,"Failed to create Time object\n"); goto cleanup; } } /* Determine which device the application is running on */ if (Cpu_getDevice(NULL, &device) < 0) { ret = Dmai_EFAIL; fprintf(stderr,"Failed to determine target board\n"); goto cleanup; } /* Set the display and capture attributes depending on device */ switch (device) { case Cpu_Device_DM6467: dAttrs = Display_Attrs_DM6467_VID_DEFAULT; cAttrs = Capture_Attrs_DM6467_DEFAULT; break; case Cpu_Device_DM365: case Cpu_Device_DM368: dAttrs = Display_Attrs_DM365_VID_DEFAULT; cAttrs = Capture_Attrs_DM365_DEFAULT; dAttrs.colorSpace = ColorSpace_YUV420PSEMI; cAttrs.colorSpace = dAttrs.colorSpace; break; case Cpu_Device_OMAPL138: dAttrs = Display_Attrs_OMAPL138_VID_DEFAULT; cAttrs = Capture_Attrs_OMAPL138_DEFAULT; break; case Cpu_Device_OMAP3530: case Cpu_Device_DM3730: dAttrs = Display_Attrs_O3530_VID_DEFAULT; cAttrs = Capture_Attrs_OMAP3530_DEFAULT; dAttrs.colorSpace = cAttrs.colorSpace = ColorSpace_UYVY; dAttrs.rotation = 270; break; default: dAttrs = Display_Attrs_DM6446_DM355_VID_DEFAULT; cAttrs = Capture_Attrs_DM6446_DM355_DEFAULT; break; } if (args->displayStd != -1) { dAttrs.displayStd = args->displayStd; } if (args->displayDevice) { dAttrs.displayDevice = args->displayDevice; } if (args->displayNumBufs != -1) { dAttrs.numBufs = args->displayNumBufs; } /* Enable cropping in capture driver if selected */ if (args->width != -1 && args->height != -1 && args->crop) { cAttrs.cropX = args->xIn; cAttrs.cropY = args->yIn; cAttrs.cropWidth = args->width; cAttrs.cropHeight = args->height; } cAttrs.videoInput = args->videoInput; if (Capture_detectVideoStd(NULL, &cAttrs.videoStd, &cAttrs) < 0) { ret = Dmai_EFAIL; fprintf(stderr,"Failed to detect capture video standard\n"); goto cleanup; } /* The color space of the capture buffers depend on the device */ gfxAttrs.colorSpace = cAttrs.colorSpace; if (VideoStd_getResolution(cAttrs.videoStd, &gfxAttrs.dim.width, &gfxAttrs.dim.height) < 0) { goto cleanup; } gfxAttrs.dim.lineLength = Dmai_roundUp(BufferGfx_calcLineLength(gfxAttrs.dim.width, gfxAttrs.colorSpace), 32); gfxAttrs.dim.x = 0; gfxAttrs.dim.y = 0; if (gfxAttrs.colorSpace == ColorSpace_YUV422PSEMI) { bufSize = gfxAttrs.dim.lineLength * gfxAttrs.dim.height * 2; } else if (gfxAttrs.colorSpace == ColorSpace_YUV420PSEMI) { bufSize = gfxAttrs.dim.lineLength * gfxAttrs.dim.height * 3 / 2; } else { bufSize = gfxAttrs.dim.lineLength * gfxAttrs.dim.height; } if (args->captureUalloc) { /* Create a table of video buffers to use with the capture device */ hCapBufTab = BufTab_create(cAttrs.numBufs, bufSize, BufferGfx_getBufferAttrs(&gfxAttrs)); if (hCapBufTab == NULL) { ret = Dmai_EFAIL; fprintf(stderr,"Failed to allocate contiguous buffers\n"); goto cleanup; } } /* Create the capture device driver instance */ hCapture = Capture_create(hCapBufTab, &cAttrs); if (hCapture == NULL) { ret = Dmai_EFAIL; fprintf(stderr,"Failed to create capture device\n"); goto cleanup; } /* Create the display device driver instance */ dAttrs.videoStd = Capture_getVideoStd(hCapture); dAttrs.videoOutput = args->videoOutput; if (args->displayUalloc) { /* Create a table of video buffers to use with the display device */ hDisBufTab = BufTab_create(dAttrs.numBufs, bufSize, BufferGfx_getBufferAttrs(&gfxAttrs)); if (hDisBufTab == NULL) { ret = Dmai_EFAIL; fprintf(stderr,"Failed to allocate contiguous buffers\n"); goto cleanup; } } hDisplay = Display_create(hDisBufTab, &dAttrs); if (hDisplay == NULL) { ret = Dmai_EFAIL; fprintf(stderr,"Failed to create display device\n"); goto cleanup; } if (args->smooth) { /* Create the smooth job */ hSmooth = Smooth_create(&smAttrs); if (hSmooth == NULL) { ret = Dmai_EFAIL; fprintf(stderr,"Failed to create smooth job\n"); } } else { /* Create the frame copy job */ fcAttrs.accel = args->accel; hFc = Framecopy_create(&fcAttrs); if (hFc == NULL) { ret = Dmai_EFAIL; fprintf(stderr,"Failed to create frame copy job\n"); goto cleanup; } } /* * If cropping is not used, alter the dimensions of the captured * buffers and position the smaller image inside the full screen. */ if (args->width != -1 && args->height != -1 && !args->crop) { for (bufIdx = 0; bufIdx < BufTab_getNumBufs(Capture_getBufTab(hCapture)); bufIdx++) { cBuf = BufTab_getBuf(Capture_getBufTab(hCapture), bufIdx); BufferGfx_getDimensions(cBuf, &dim); dim.width = args->width; dim.height = args->height; dim.x = args->xIn; dim.y = args->yIn; if (BufferGfx_setDimensions(cBuf, &dim) < 0) { ret = Dmai_EFAIL; fprintf(stderr,"Input resolution does not fit in capture frame\n"); goto cleanup; } } } /* * Alter the dimensions of the display buffers and position * the smaller image inside the full screen. */ if (args->width != -1 && args->height != -1) { for (bufIdx = 0; bufIdx < BufTab_getNumBufs(Display_getBufTab(hDisplay)); bufIdx++) { dBuf = BufTab_getBuf(Display_getBufTab(hDisplay), bufIdx); BufferGfx_getDimensions(dBuf, &dim); dim.width = args->width; dim.height = args->height; dim.x = args->xOut; dim.y = args->yOut; if (BufferGfx_setDimensions(dBuf, &dim) < 0) { ret = Dmai_EFAIL; fprintf(stderr,"Output resolution does not fit in display frame\n"); goto cleanup; } } } if (args->smooth) { if (Smooth_config(hSmooth, BufTab_getBuf(Capture_getBufTab(hCapture), 0), BufTab_getBuf(Display_getBufTab(hDisplay), 0)) < 0) { ret = Dmai_EFAIL; fprintf(stderr,"Failed to configure smooth job\n"); goto cleanup; } } else { /* Configure the frame copy job */ if (Framecopy_config(hFc, BufTab_getBuf(Capture_getBufTab(hCapture), 0), BufTab_getBuf(Display_getBufTab(hDisplay), 0)) < 0) { ret = Dmai_EFAIL; fprintf(stderr,"Failed to configure frame copy job\n"); goto cleanup; } } while (numFrame++ < args->numFrames || args->numFrames == 0) { if (args->benchmark) { if (Time_reset(hTime) < 0) { ret = Dmai_EFAIL; fprintf(stderr,"Failed to reset timer\n"); goto cleanup; } } /* Get a captured frame from the capture device */ if (Capture_get(hCapture, &cBuf) < 0) { ret = Dmai_EFAIL; fprintf(stderr,"Failed to get capture buffer\n"); goto cleanup; } /* Get a frame from the display device to be filled with data */ if (Display_get(hDisplay, &dBuf) < 0) { ret = Dmai_EFAIL; fprintf(stderr,"Failed to get display buffer\n"); goto cleanup; } if (args->benchmark) { if (Time_delta(hTime, &time) < 0) { ret = Dmai_EFAIL; fprintf(stderr,"Failed to get timer delta\n"); goto cleanup; } } if (args->smooth) { /* * Remove interlacing artifacts from the captured buffer and * store the result in the display buffer. */ if (Smooth_execute(hSmooth, cBuf, dBuf) < 0) { ret = Dmai_EFAIL; fprintf(stderr,"Failed to execute smooth job\n"); goto cleanup; } } else { /* Copy the captured buffer to the display buffer */ if (Framecopy_execute(hFc, cBuf, dBuf) < 0) { ret = Dmai_EFAIL; fprintf(stderr,"Failed to execute frame copy job\n"); goto cleanup; } } if (args->benchmark) { if (Time_delta(hTime, &time) < 0) { ret = Dmai_EFAIL; fprintf(stderr,"Failed to get timer delta\n"); goto cleanup; } printf("Smooth / Framecopy: %uus ", (Uns) time); } /* Give captured buffer back to the capture device driver */ if (Capture_put(hCapture, cBuf) < 0) { ret = Dmai_EFAIL; fprintf(stderr,"Failed to put capture buffer\n"); goto cleanup; } /* Send filled buffer to display device driver to be displayed */ if (Display_put(hDisplay, dBuf) < 0) { ret = Dmai_EFAIL; fprintf(stderr,"Failed to put display buffer\n"); goto cleanup; } if (args->benchmark) { if (Time_total(hTime, &time) < 0) { ret = Dmai_EFAIL; fprintf(stderr,"Failed to get timer total\n"); goto cleanup; } printf("Frame time: %uus\n", (Uns) time); } } cleanup: /* Clean up the application */ if (hSmooth) { Smooth_delete(hSmooth); } if (hFc) { Framecopy_delete(hFc); } if (hCapture) { Capture_delete(hCapture); } if (hDisplay) { Display_delete(hDisplay); } if (hTime) { Time_delete(hTime); } if (hCapBufTab) { BufTab_delete(hCapBufTab); } if (hDisBufTab) { BufTab_delete(hDisBufTab); } if (ret == Dmai_EFAIL) return 1; else return 0; }
/****************************************************************************** * 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; }