我正在尝试为Gstreamer缓冲区实现自定义队列。问题是,当我试图出列时,似乎我正在失去队列的头部。每当我尝试两次出队时,我都会遇到分段错误。我也注意到头部总是等于头部 - >接下来。现在我不确定入队或出队是否有问题。请帮帮我。谢谢。
typedef struct _GstBUFFERQUEUE GstBufferQueue;
struct _GstBUFFERQUEUE {
GstBuffer *buf;
guint buf_size;
struct _GstBUFFERQUEUE *next;
};
void enqueue_gstbuffer(GstBufferQueue **head, GstBufferQueue **tail, guint *queue_size, GstBuffer *buf)
{
if (*queue_size == 0)
{
*head = malloc(sizeof(GstBufferQueue));
(*head)->buf = gst_buffer_try_new_and_alloc (GST_BUFFER_SIZE(buf));
(*head)->buf = gst_buffer_copy(buf);
*tail = *head;
}
else
{
if ((*tail)->next = malloc(sizeof(GstBufferQueue))) {
(*tail)->next->buf = gst_buffer_try_new_and_alloc (GST_BUFFER_SIZE(buf));
(*tail)->next->buf = gst_buffer_copy(buf);
(*tail) = (*tail)->next;
}
else {
GST_WARNING("Error allocating memory for new buffer in queue");
}
}
(*tail)->next = NULL;
(*queue_size)++;
}
void dequeue_gstbuffer(GstBufferQueue **head, GstBufferQueue **tail, guint *queue_size, GstBuffer **buf)
{
GstBufferQueue **tmpPtr = head;
GstBufferQueue **nextPtr;
*nextPtr = (*head)->next;
*buf = gst_buffer_try_new_and_alloc (GST_BUFFER_SIZE((*tmpPtr)->buf));
*buf = gst_buffer_copy((*tmpPtr)->buf);
gst_buffer_unref((*tmpPtr)->buf);
free((*tmpPtr));
*head = *nextPtr;
if ((*head) == NULL)
(*tail) = NULL;
(*queue_size)--;
}
答案 0 :(得分:5)
当通过添加足够的伪基础设施来模拟GST系统转换为可编译代码时,GCC会发出警告,这几乎肯定是您遇到麻烦的根源:
gstq.c: In function ‘dequeue_gstbuffer’:
gstq.c:73:12: warning: ‘nextPtr’ is used uninitialized in this function [-Wuninitialized]
这些行是:
72 GstBufferQueue **nextPtr;
73 *nextPtr = (*head)->next;
在这些方面,你需要:
GstBufferQueue *nextPtr = (*head)->next;
您还需要使用:
(*head)->next = nextPtr;
注意编译器警告。如果编译器没有发出警告,请执行此操作。如果您无法发出警告,请获得更好的编译器。
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#define GST_BUFFER_SIZE(x) sizeof(x)
#define GST_WARNING(x) fprintf(stderr, "%s\n", x)
typedef struct GstBuffer { int value; } GstBuffer;
typedef unsigned int guint;
static GstBuffer *gst_buffer_try_new_and_alloc(int size)
{
GstBuffer *buf = malloc(sizeof(GstBuffer));
assert(buf != 0);
buf->value = size;
return buf;
}
static GstBuffer *gst_buffer_copy(const GstBuffer *buf)
{
GstBuffer *new_buf = malloc(sizeof(GstBuffer));
assert(new_buf != 0);
new_buf->value = buf->value;
return new_buf;
}
static void gst_buffer_unref(GstBuffer *buf)
{
buf->value = -1;
}
typedef struct _GstBUFFERQUEUE GstBufferQueue;
struct _GstBUFFERQUEUE {
GstBuffer *buf;
guint buf_size;
struct _GstBUFFERQUEUE *next;
};
extern void enqueue_gstbuffer(GstBufferQueue **head, GstBufferQueue **tail, guint *queue_size, GstBuffer *buf);
extern void dequeue_gstbuffer(GstBufferQueue **head, GstBufferQueue **tail, guint *queue_size, GstBuffer **buf);
void enqueue_gstbuffer(GstBufferQueue **head, GstBufferQueue **tail, guint *queue_size, GstBuffer *buf)
{
if (*queue_size == 0)
{
*head = malloc(sizeof(GstBufferQueue));
(*head)->buf = gst_buffer_try_new_and_alloc(GST_BUFFER_SIZE(buf));
(*head)->buf = gst_buffer_copy(buf);
*tail = *head;
}
else
{
if (((*tail)->next = malloc(sizeof(GstBufferQueue))) != 0)
{
(*tail)->next->buf = gst_buffer_try_new_and_alloc(GST_BUFFER_SIZE(buf));
(*tail)->next->buf = gst_buffer_copy(buf);
(*tail) = (*tail)->next;
}
else
{
GST_WARNING("Error allocating memory for new buffer in queue");
}
}
(*tail)->next = NULL;
(*queue_size)++;
}
void dequeue_gstbuffer(GstBufferQueue **head, GstBufferQueue **tail, guint *queue_size, GstBuffer **buf)
{
GstBufferQueue **tmpPtr = head;
GstBufferQueue *nextPtr;
nextPtr = (*head)->next;
*buf = gst_buffer_try_new_and_alloc (GST_BUFFER_SIZE((*tmpPtr)->buf));
*buf = gst_buffer_copy((*tmpPtr)->buf);
gst_buffer_unref((*tmpPtr)->buf);
free((*tmpPtr));
*head = nextPtr;
if ((*head) == NULL)
(*tail) = NULL;
(*queue_size)--;
}
int main(void)
{
GstBufferQueue *q_head = 0;
GstBufferQueue *q_tail = 0;
guint q_size = 0;
for (int i = 0; i < 10; i++)
{
GstBuffer *buf = gst_buffer_try_new_and_alloc(i + 100);
enqueue_gstbuffer(&q_head, &q_tail, &q_size, buf);
printf("EQ: %d\n", buf->value);
free(buf);
if (i % 2 == 1)
{
GstBuffer *buf;
dequeue_gstbuffer(&q_head, &q_tail, &q_size, &buf);
printf("DQ: %d\n", buf->value);
free(buf);
}
}
while (q_size > 0)
{
GstBuffer *buf;
dequeue_gstbuffer(&q_head, &q_tail, &q_size, &buf);
printf("DQ: %d\n", buf->value);
free(buf);
}
printf("All done\n");
return(0);
}
EQ: 100
EQ: 101
DQ: 100
EQ: 102
EQ: 103
DQ: 101
EQ: 104
EQ: 105
DQ: 102
EQ: 106
EQ: 107
DQ: 103
EQ: 108
EQ: 109
DQ: 104
DQ: 105
DQ: 106
DQ: 107
DQ: 108
DQ: 109
All done
请注意,上面的SSCCE代码泄漏比筛子差。我没有计划修复泄漏,因为它们在模拟GST缓冲区管理的代码中。请检查您的代码是否没有内存泄漏。
我认为你应该以不同方式打包'队列'。你所谓的GstBufferQueue
应该是GstBufferQueueItem
,你的实际GstBufferQueue
应该包含头尾指针和大小。您将指向(修订的)GstBufferQueue
的指针传递给enqueue_gstbuffer()
和dequeue_gstbuffer()
函数,而不是传递3个单独的参数。
typedef struct GstBufferQueueItem GstBufferQueueItem;
struct GstBufferQueueItem
{
GstBuffer *buf;
guint buf_size;
GstBufferQueueItem *next;
};
typedef struct GstBufferQueue GstBufferQueue;
struct GstBufferQueue
{
GstBufferQueueItem *head;
GstBufferQueueItem *tail;
guint size;
};
// Uncompiled - but to give you an idea
void dequeue_gstbuffer(GstBufferQueue *q, GstBuffer **buf)
{
GstBufferQueueItem *item = q->head;
GstBufferQueueItem *next = item->next;
*buf = gst_buffer_try_new_and_alloc(GST_BUFFER_SIZE(item->buf));
*buf = gst_buffer_copy(item->buf);
gst_buffer_unref(item->buf);
free(item);
q->head = next;
if (q->head == NULL)
q->tail = NULL;
q->size--;
}
请注意,这些名称会避免使用前导下划线。这样的名字很危险。带有下划线和大写字母的名称保留用于任何目的的实现。带有下划线和小写字母的名字保留不同的单词,但使用其中任何一个都是狡猾的(尽管标准对下划线和数字很少说,不要用它们玩游戏 - 将前导下划线视为'保留用于系统'除非你写'系统'。)
- 所有以下划线和大写字母或其他字母开头的标识符 下划线总是保留用于任何用途。
- 所有以下划线开头的标识符始终保留用作标识符 在普通名称和标签名称空间中都有文件范围。
答案 1 :(得分:3)
替换
GstBufferQueue **nextPtr;
*nextPtr = (*head)->next;
...
*head = *nextPtr;
通过
GstBufferQueue *nextPtr;
nextPtr = (*head)->next;
...
*head = nextPtr;
答案 2 :(得分:0)
有一点让我感到高兴的是,当您第一次分配队列时(当* queue_size == 0时),您没有将新创建的节点的“下一个”指针设置为NULL。
在分配和分配到(* head)之后无法保证它是NULL,所以当你执行出队时你的(* head) - &gt; next可能指向一个垃圾地址。