2

Gstreamer バッファ用のカスタム キューを実装しようとしています。問題は、デキューしようとすると、キューの先頭を失っているように見えることです。デキューを 2 回試みるたびに、セグメンテーション違反が発生します。また、head は常に head->next と等しいことに気付きました。エンキューまたはデキューに問題があるかどうかはわかりません。私を助けてください。ありがとうございました。

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)--;   
}
4

3 に答える 3

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;

コンパイラの警告に注意してください。コンパイラが警告しない場合は、警告するようにします。警告を表示できない場合は、より優れたコンパイラを入手してください。


SSCCE

#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 バッファー管理をシミュレートするコードにリークがあるため、リークを修正する予定はありません。コードがメモリ リークの影響を受けていないことを確認してください。


「キュー」を別の方法でパッケージ化する必要があると思います。a と呼ぶものGstBufferQueueは実際には aGstBufferQueueItemである必要があり、実際GstBufferQueueにはヘッドとテールのポインター、およびサイズが含まれている必要があります。3 つの個別のパラメーターを渡す代わりに、(改訂された)GstBufferQueueへのポインターをenqueue_gstbuffer()anddequeue_gstbuffer()関数に渡します。

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--;   
}

これらの名前では、先頭のアンダースコアを避けることに注意してください。このような名前は危険です。アンダースコアと大文字を含む名前は、目的を問わず実装用に予約されています。アンダースコアと小文字を含む名前は異なる単語で予約されていますが、どちらを使用しても危険です (標準ではアンダースコアと数字についてほとんど言及されていませんが、それらでゲームをしないでください — 先頭のアンダースコアを「予約済み」として扱います)。 「システム」と書いていない限り)。

ISO/IEC 9899:2011 §7.1.3 予約済み識別子

  • アンダースコアと大文字または別のアンダースコアで始まるすべての識別子は、常に予約されています。
  • アンダースコアで始まるすべての識別子は、通常の名前空間とタグ名空間の両方で、ファイル スコープの識別子として使用するために常に予約されています。
于 2012-12-31T17:38:44.167 に答える
3

交換

GstBufferQueue **nextPtr;
*nextPtr = (*head)->next;
...
*head = *nextPtr;

GstBufferQueue *nextPtr;
nextPtr = (*head)->next;
...
*head = nextPtr;
于 2012-12-31T17:41:47.433 に答える
0

私にとって際立っていることの 1 つは、キューを初めて割り当てるとき ( *queue_size == 0 の場合)、新しく作成されたノードの「次の」ポインターを NULL に設定していないことです。

(*head) への割り当てと割り当ての後に NULL になるという保証はありません。そのため、デキューを行うと、(*head)->next がガベージ アドレスを指している可能性があります。

于 2012-12-31T16:59:47.150 に答える