This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TDA2HG: 【ducatih264dec】 How to increase the decode buffer for backend rendering

Part Number: TDA2HG

Hello:

  we'are using the gtreamer to play the local media file (.mp4) on the TDA2HG board. but the video frame roll back ocassionaly. see the video as bellow:

the gstreamer url is  

filesrc location=%1 ! qtdemux ! h264parse ! ducatih264dec  ! videoshmsink crop_x=32 crop_width=1280 crop_y=24 crop_height=720

the videoshmsink is the pluggin which will shared the memory fd to another process who will get the fd and rendering to screen by OpenGL.

for the log, we found the rendering is about 25fps, the videoshm will output about 16  different fd, but look like the only 2 buffer is available.

[2016-01-02 18:15:51.377]-[mediaplayer]-[Note ]: bool TBufferServer::waitAck() waitAck 
[2016-01-02 18:15:51.377]-[mediaplayer]-[Note ]: gst_videoshmsink_render send frame with Count: 627 with fd 47 

[2016-01-02 18:15:51.377]-[mediaplayer]-[Note ]: sendBufferAndFd buf b07a81f0, buf_size 32, fd_send 47
[2016-01-02 18:15:51.396]-[dvr_qt_app]-[Debug]: onFrameSwapped:
[2016-01-02 18:15:51.396]-[dvr_qt_app]-[Debug]: videowidget about to update the window
[2016-01-02 18:15:51.396]-[dvr_qt_app]-[Debug]: videoClient sent the ack
[2016-01-02 18:15:51.401]-[hal]-[Note ]: HandleResourceReceivedEvent fault: 1819042109 num: 1701998435
 
[2016-01-02 18:15:51.411]-[mediaplayer]-[Note ]: bool TBufferServer::waitAck() waitAck 
[2016-01-02 18:15:51.411]-[mediaplayer]-[Note ]: gst_videoshmsink_render send frame with Count: 628 with fd 50 

[2016-01-02 18:15:51.411]-[mediaplayer]-[Note ]: sendBufferAndFd buf b07a81f0, buf_size 32, fd_send 50
[2016-01-02 18:15:51.445]-[dvr_qt_app]-[Debug]: onFrameSwapped:
[2016-01-02 18:15:51.445]-[dvr_qt_app]-[Debug]: videowidget about to update the window
[2016-01-02 18:15:51.446]-[dvr_qt_app]-[Debug]: videoClient sent the ack
[2016-01-02 18:15:51.454]-[hal]-[Note ]: HandleResourceReceivedEvent fault: 1330536274 num: 1163349840
 
[2016-01-02 18:15:51.455]-[hal]-[Note ]: HandleResourceReceivedEvent fault: 0 num: 16
 
[2016-01-02 18:15:51.465]-[mediaplayer]-[Note ]: bool TBufferServer::waitAck() waitAck 
[2016-01-02 18:15:51.465]-[mediaplayer]-[Note ]: gst_videoshmsink_render send frame with Count: 629 with fd 49 

[2016-01-02 18:15:51.465]-[mediaplayer]-[Note ]: sendBufferAndFd buf b07a81f0, buf_size 32, fd_send 49
[2016-01-02 18:15:51.493]-[dvr_qt_app]-[Debug]: onFrameSwapped:
[2016-01-02 18:15:51.493]-[dvr_qt_app]-[Debug]: videowidget about to update the window
[2016-01-02 18:15:51.493]-[dvr_qt_app]-[Debug]: videoClient sent the ack
[2016-01-02 18:15:51.496]-[mediaplayer]-[Note ]: bool TBufferServer::waitAck() waitAck 
[2016-01-02 18:15:51.496]-[mediaplayer]-[Note ]: gst_videoshmsink_render send frame with Count: 630 with fd 52 

[2016-01-02 18:15:51.496]-[mediaplayer]-[Note ]: sendBufferAndFd buf b07a81f0, buf_size 32, fd_send 52
[2016-01-02 18:15:51.518]-[mediaplayer]-[Note ]: bool TBufferServer::waitAck() waitAck 
[2016-01-02 18:15:51.518]-[mediaplayer]-[Note ]: failed to waitAck , error:  Resource temporarily unavailable
[2016-01-02 18:15:51.518]-[mediaplayer]-[Note ]: gst_videoshmsink_render not get ACK, so skip frameCount: 631 with fd 51

Question:

  how to increase the output buffers of ducatih264dec

The videoshmsink source code

 

#include "gstvideoshmsink.h"
#include <fcntl.h>
#include <gst/allocators/gstfdmemory.h>
#include <iostream>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>

#include <sys/syscall.h>

#include <chrono>
#include <loggin/KLog.h>


struct dmabuf_vmem_export
{
    unsigned long vaddr;
    unsigned long size;
    int fd;
};

#define DMABUF_CODE 0xDB
#define DMABUF_BASE 0xD0

#define DBUFIOC_EXPORT_VIRTMEM _IOWR(DMABUF_CODE, DMABUF_BASE + 0, struct dmabuf_vmem_export)

enum
{
    LASST_SIGNAL
};

enum
{
    PROP_0 = 0,
    PROP_BUFFER_MAX_NUM,
    PROP_SOCKET_PATH,
    PROP_CROP_X,
    PROP_CROP_WIDTH,
    PROP_CROP_Y,
    PROP_CROP_HEIGHT,
    PROP_ENABLE_ACK,
    PROP_ENABLE_TEST,
};

#define VIDEOSHMSINK_CAPS GST_STATIC_CAPS_ANY

static GstStaticPadTemplate sink_template =
    GST_STATIC_PAD_TEMPLATE("sink",
                            GST_PAD_SINK,
                            GST_PAD_ALWAYS,
                            GST_STATIC_CAPS_ANY);
#define gst_videoshmsink_parent_class parent_class
G_DEFINE_TYPE(GstVideoShmSink, gst_videoshmsink, GST_TYPE_BASE_SINK);

static void gst_videoshmsink_set_property(GObject *object, guint prop_id,
                                          const GValue *value, GParamSpec *pspec);
static void gst_videoshmsink_get_property(GObject *object, guint prop_id,
                                          GValue *value, GParamSpec *pspec);
static gboolean gst_videoshmsink_start(GstBaseSink *bsink);
static gboolean gst_videoshmsink_stop(GstBaseSink *bsink);
static gboolean gst_videoshmsink_set_caps(GstBaseSink *sink, GstCaps *caps);
static GstFlowReturn gst_videoshmsink_render(GstBaseSink *bsink, GstBuffer *buf);

static void gst_videoshmsink_class_init(GstVideoShmSinkClass *klass)
{
    std::cout << "from " << __FUNCTION__ << std::endl;
    GObjectClass *gobject_class = (GObjectClass *)klass;
    GstElementClass *gstelement_class = (GstElementClass *)klass;
    GstBaseSinkClass *gstbasesink_class = (GstBaseSinkClass *)klass;

    gobject_class->set_property = gst_videoshmsink_set_property;
    gobject_class->get_property = gst_videoshmsink_get_property;

    g_object_class_install_property(
        gobject_class, PROP_BUFFER_MAX_NUM,
        g_param_spec_uint64(
            "buffer_max_num", "Buffer_Max_Num", "max buffer num ",
            1, 8, 2,
            static_cast<GParamFlags>(
                G_PARAM_READWRITE |
                G_PARAM_CONSTRUCT)));

    g_object_class_install_property(
        gobject_class, PROP_SOCKET_PATH,
        g_param_spec_string(
            "socket-path",
            "socket path for buffer transport",
            "socket path of buffer transport between server and client",
            NULL,
            static_cast<GParamFlags>(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT)));

    g_object_class_install_property(
        gobject_class, PROP_CROP_X,
        g_param_spec_uint64(
            "crop_x", "crop_x", "crop from x",
            0, G_MAXUINT64, 0,
            static_cast<GParamFlags>(
                G_PARAM_READWRITE |
                G_PARAM_CONSTRUCT)));

    g_object_class_install_property(
        gobject_class, PROP_CROP_WIDTH,
        g_param_spec_uint64(
            "crop_width", "crop_width", "crop width",
            0, G_MAXUINT64, 1280,
            static_cast<GParamFlags>(
                G_PARAM_READWRITE |
                G_PARAM_CONSTRUCT)));

    g_object_class_install_property(
        gobject_class, PROP_CROP_Y,
        g_param_spec_uint64(
            "crop_y", "crop_y", "crop from y",
            0, G_MAXUINT64, 0,
            static_cast<GParamFlags>(
                G_PARAM_READWRITE |
                G_PARAM_CONSTRUCT)));

    g_object_class_install_property(
        gobject_class, PROP_CROP_HEIGHT,
        g_param_spec_uint64(
            "crop_height", "crop_height", "crop height",
            0, G_MAXUINT64, 720,
            static_cast<GParamFlags>(
                G_PARAM_READWRITE |
                G_PARAM_CONSTRUCT)));

    g_object_class_install_property(
        gobject_class, PROP_ENABLE_ACK,
        g_param_spec_boolean(
            "enable-ack", "Enable Ack", "wait the ack for every frame",
            FALSE,
            static_cast<GParamFlags>(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT)));

    g_object_class_install_property(
        gobject_class, PROP_ENABLE_TEST,
        g_param_spec_boolean(
            "enable-test", "Enable Test", "send buffer fd for test client",
            FALSE,
            static_cast<GParamFlags>(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT)));

    gst_element_class_set_static_metadata(
        gstelement_class,
        "videoshmsink",
        "Sink/Cache",
        "transfer video frame by shm",
        "you.li@ecarx.com.cn");

    gst_element_class_add_pad_template(gstelement_class, gst_static_pad_template_get(&sink_template));
    gstbasesink_class->start = gst_videoshmsink_start;
    gstbasesink_class->stop = gst_videoshmsink_stop;
    gstbasesink_class->set_caps = gst_videoshmsink_set_caps;
    gstbasesink_class->render = gst_videoshmsink_render;
}

static void gst_videoshmsink_init(GstVideoShmSink *self)
{
}

static void gst_videoshmsink_set_property(GObject *object, guint prop_id,
                                          const GValue *value, GParamSpec *pspec)
{
    std::cout << "from " << __FUNCTION__ << std::endl;
    GstVideoShmSink *self = GST_VIDEOSHMSINK(object);
    GST_OBJECT_LOCK(self);
    std::cout << __PRETTY_FUNCTION__ << ": locked" << std::endl;
    switch (prop_id)
    {
    case PROP_BUFFER_MAX_NUM:
    {
        GstState state = GST_STATE(self);
        if (state == GST_STATE_READY || state == GST_STATE_NULL)
        {
            self->buffer_max_size = g_value_get_uint64(value);
        }
    }
    break;
    case PROP_SOCKET_PATH:
    {
        GstState state = GST_STATE(self);
        if (state == GST_STATE_READY || state == GST_STATE_NULL)
        {
            if (self->socket_path)
                g_free(self->socket_path);
            self->socket_path = g_strdup(g_value_get_string(value));
        }
    }
    break;
    case PROP_CROP_X:
        self->crop_x = g_value_get_uint64(value);
        break;
    case PROP_CROP_WIDTH:
        self->crop_width = g_value_get_uint64(value);
        break;
    case PROP_CROP_Y:
        self->crop_y = g_value_get_uint64(value);
        break;
    case PROP_CROP_HEIGHT:
        self->crop_height = g_value_get_uint64(value);
        break;
    case PROP_ENABLE_ACK:
        self->enable_ack = g_value_get_boolean(value);
        break;
    case PROP_ENABLE_TEST:
        self->enable_test = g_value_get_boolean(value);
        break;
    default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
        break;
    }
    GST_OBJECT_UNLOCK(self);
    std::cout << __PRETTY_FUNCTION__ << ": unlocked" << std::endl;
}
static void gst_videoshmsink_get_property(GObject *object, guint prop_id,
                                          GValue *value, GParamSpec *pspec)
{
    std::cout << "from " << __FUNCTION__ << std::endl;
    GstVideoShmSink *self = GST_VIDEOSHMSINK(object);
    GST_OBJECT_LOCK(self);
    std::cout << __PRETTY_FUNCTION__ << ": locked" << std::endl;
    switch (prop_id)
    {
    case PROP_BUFFER_MAX_NUM:
        g_value_set_uint64(value, self->buffer_max_size);
        break;
    case PROP_SOCKET_PATH:
        g_value_set_string(value, self->socket_path);
        break;
    case PROP_CROP_X:
        g_value_set_uint64(value, self->crop_x);
        break;
    case PROP_CROP_WIDTH:
        g_value_set_uint64(value, self->crop_width);
        break;
    case PROP_CROP_Y:
        g_value_set_uint64(value, self->crop_y);
        break;
    case PROP_CROP_HEIGHT:
        g_value_set_uint64(value, self->crop_height);
        break;
    case PROP_ENABLE_ACK:
        g_value_set_boolean(value, self->enable_ack);
        break;
    case PROP_ENABLE_TEST:
        g_value_set_boolean(value, self->enable_test);
        break;
    default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
        break;
    }
    GST_OBJECT_UNLOCK(self);
    std::cout << __PRETTY_FUNCTION__ << ": unlocked" << std::endl;
}

static gboolean gst_videoshmsink_start(GstBaseSink *bsink)
{
    std::cout << "from " << __FUNCTION__ << std::endl;
    GstVideoShmSink *self = GST_VIDEOSHMSINK(bsink);
    std::cout << __PRETTY_FUNCTION__ << ": locked" << std::endl;
    GST_OBJECT_LOCK(self);
    if (self->socket_path == nullptr)
    {
        GST_ELEMENT_ERROR(self, RESOURCE, OPEN_READ_WRITE, ("socket-path is null"), (nullptr));
        return FALSE;
    }
    std::cout << __PRETTY_FUNCTION__ << ": socket_path = " << self->socket_path << std::endl;
    self->frameCount = 0;
    self->bufferServer = new TBufferServer(self->socket_path);
    if (self->enable_test == TRUE)
    {
        self->bufferServer->start(true);
    }
    else
    {
        self->bufferServer->start(false);
    }

    GST_OBJECT_UNLOCK(self);
    std::cout << __PRETTY_FUNCTION__ << ": unlocked" << std::endl;
    std::cout << "exit " << __FUNCTION__ << std::endl;
    return TRUE;
}
static gboolean gst_videoshmsink_stop(GstBaseSink *bsink)
{
    std::cout << "from " << __FUNCTION__ << std::endl;
    GstVideoShmSink *self = GST_VIDEOSHMSINK(bsink);
    GST_OBJECT_LOCK(self);
    std::cout << __PRETTY_FUNCTION__ << ": locked" << std::endl;
    std::cout << "framecount: " << self->frameCount << std::endl;
    self->bufferServer->stop();
    delete self->bufferServer;
    self->bufferServer = nullptr;
    GST_OBJECT_UNLOCK(self);
    std::cout << __PRETTY_FUNCTION__ << ": unlocked" << std::endl;
    return TRUE;
}

static gboolean gst_videoshmsink_set_caps(GstBaseSink *sink, GstCaps *caps)
{
    std::cout << "from " << __FUNCTION__ << std::endl;
    std::cout << "set caps invoked" << std::endl;
    GstVideoShmSink *self = GST_VIDEOSHMSINK(sink);
    std::cout << __PRETTY_FUNCTION__ << ": locked" << std::endl;
    GST_OBJECT_LOCK(self);
    gst_video_info_from_caps(&self->videoInfo, caps);

    GST_OBJECT_UNLOCK(self);
    std::cout << __PRETTY_FUNCTION__ << ": unlocked" << std::endl;
    return TRUE;
}

static GstFlowReturn gst_videoshmsink_render(GstBaseSink *bsink, GstBuffer *buf)
{
    auto begin = std::chrono::high_resolution_clock::now();
    GstVideoShmSink *self = GST_VIDEOSHMSINK(bsink);
    GST_OBJECT_LOCK(self);
    //std::cout << __PRETTY_FUNCTION__ << ": locked" << std::endl;
    BufferInfo info;
    int buff_len = sizeof(info);
    info.width = self->videoInfo.width;
    info.height = self->videoInfo.height;
    info.crop_x = self->crop_x;
    info.crop_y = self->crop_y;
    info.crop_width = self->crop_width;
    info.crop_height = self->crop_height;
    guint memory_num = gst_buffer_n_memory(buf);
    for (int n = 0; n < memory_num; n++)
    {
        GstMemory *mem = gst_buffer_get_memory(buf, n);
        if (gst_is_fd_memory(mem))
        {
            int fd = gst_fd_memory_get_fd(mem);
            info.frameCount = ++self->frameCount;
            static uint32_t lostCount = 0;

            if ((self->bufferServer->waitAck()) || (1 == info.frameCount) || (3 < lostCount++)) {
                KLOG_INFO("gst_videoshmsink_render send frame with Count: %llu with fd %d \n", info.frameCount,fd);
                self->bufferServer->sendBufferAndFd(&info, buff_len, fd);
                lostCount = 0;
            } 
            else {
                KLOG_INFO("gst_videoshmsink_render not get ACK, so skip frameCount: %llu with fd %d \n", info.frameCount,fd);
            }

        }
        else
        {
            //std::cout << __PRETTY_FUNCTION__ << ": normal memory" << std::endl;
            GstMapInfo info;
            gboolean ret = gst_memory_map(mem, &info, GST_MAP_READ);
            if (ret == TRUE)
            {
                struct dmabuf_vmem_export exp;
                exp.vaddr = (unsigned long)info.data;
                exp.size = info.size;
                int devBufFD = open("/dev/vmemexp", O_RDWR | O_CLOEXEC);

                if (devBufFD > 0)
                {
                    /* Export as DMAbuf handle */
                    ret = ioctl(devBufFD, DBUFIOC_EXPORT_VIRTMEM, &exp);
                    if (ret == 0)
                    {
                        std::cout << "vmemexp fd: " << exp.fd << std::endl;
                        bool send_result = self->bufferServer->sendBufferAndFd(&info, buff_len, exp.fd);
                        close(exp.fd);

                        if (send_result && self->enable_ack == TRUE)
                        {
                            self->bufferServer->waitAck();
                        }
                    }
                    else
                    {
                        printf(" exportDmaBuf failed retVal=%d errno %s  addr %p size %d \n", ret, strerror(errno), info.data, info.size);
                    }
                }
                close(devBufFD);
                gst_memory_unmap(mem, &info);
            }
        }
        gst_memory_unref(mem);
    }
    GST_OBJECT_UNLOCK(self);
    return GST_FLOW_OK;
}