本文主要分析gsbuffer的创建,memory,meta的分配。
一 分析gstBuffer
gstBuffer
typedef struct _GstBuffer GstBuffer;
struct _GstBuffer {
GstMiniObject mini_object;
/* timestamp */
GstClockTime pts; //时间戳
GstClockTime dts;
.....
};
typedef struct
{
GstBuffer buffer;
gsize slice_size;
/* the memory blocks */
guint len; //mem的当前的个数
GstMemory *mem[GST_BUFFER_MEM_MAX]; //存储数据,GST_BUFFER_MEM_MAX为16
/* memory of the buffer when allocated from 1 chunk */
GstMemory *bufmem;
/* FIXME, make metadata allocation more efficient by using part of the
* GstBufferImpl */
GstMetaItem *item; //头指针
GstMetaItem *tail_item; //尾指针
} GstBufferImpl;
可以看到GstBuffer包含时间戳等成员。GstBufferImpl继承自GstBuffer,包含GstMemory, GstMetaItem等成员,GstMemory用来装数据,GstMeta用来装meta数据,GstMetaItem是个链表,可以为GstBuffer添加,删除GstMeta。
这里有一些操作的宏:
#define GST_BUFFER_SLICE_SIZE(b) (((GstBufferImpl *)(b))->slice_size)
#define GST_BUFFER_MEM_LEN(b) (((GstBufferImpl *)(b))->len)
#define GST_BUFFER_MEM_ARRAY(b) (((GstBufferImpl *)(b))->mem)
#define GST_BUFFER_MEM_PTR(b,i) (((GstBufferImpl *)(b))->mem[i])
#define GST_BUFFER_BUFMEM(b) (((GstBufferImpl *)(b))->bufmem)
#define GST_BUFFER_META(b) (((GstBufferImpl *)(b))->item)
#define GST_BUFFER_TAIL_META(b) (((GstBufferImpl *)(b))->tail_item)
gst_buffer_new
GstBuffer * gst_buffer_new (void)
{
GstBufferImpl *newbuf;
newbuf = g_slice_new (GstBufferImpl);
GST_CAT_LOG (GST_CAT_BUFFER, "new %p", newbuf);
gst_buffer_init (newbuf, sizeof (GstBufferImpl));
return GST_BUFFER_CAST (newbuf);
}
如上函数,可以看到创建一个GstBuffer,就是创建一个GstBufferImpl。在gst_buffer_new_allocate里,可以看到先创建GstBuffer,在创建GstMemory,再将GstMemory添加到GstBuffer。
gst_buffer_new_allocate{
GstBuffer *newbuf;
GstMemory *mem;
mem = gst_allocator_alloc (allocator, size, params);
newbuf = gst_buffer_new ();
_memory_add (newbuf, -1, mem); //-1表示加到数组的最后一个空位。
return newbuf;
}
GstMeta
定义在gstmeta.h
typedef struct _GstMeta GstMeta;
struct _GstMeta {
GstMetaFlags flags;
const GstMetaInfo *info;
};
GstMetaItem定义在gst_private.h
typedef struct _GstMetaItem GstMetaItem;
struct _GstMetaItem {
GstMetaItem *next;
guint64 seq_num; //编号
GstMeta meta;
};
可以看到GstMetaItem是一个GstMeta的链表。
GstMemory
struct _GstMemory {
GstMiniObject mini_object;
GstAllocator *allocator;
GstMemory *parent;
gsize maxsize;
gsize align;
gsize offset;
gsize size;
};
看起来_GstMemory包含了内存的大小size,以及分配者allocator。
/* default memory implementation */
typedef struct
{
GstMemory mem;
gsize slice_size;
guint8 *data;
gpointer user_data;
GDestroyNotify notify;
} GstMemorySystem;
GstMemorySystem会对GstMemory再进行封装,真正的包含了内存的指针data,可以参考_sysmem_new。
GstMemory相关的重要函数有:
Getting access to the data of the memory is performed with gst_memory_map. The call will return a pointer to offset bytes into the region of memory. After the memory access is completed, gst_memory_unmap should be called.
gst_buffer_append_memory (GstBuffer * buffer, GstMemory * mem)->gst_buffer_insert_memory->_memory_add-> GST_BUFFER_MEM_PTR (buffer, idx) = mem;
二 分析memory
GstMemory 的例子, 分配一段buff,并改写。
GstMemory *mem;
GstMapInfo info;
gint i;
/* allocate 100 bytes */
mem = gst_allocator_alloc (NULL, 100, NULL);
/* get access to the memory in write mode */
gst_memory_map (mem, &info, GST_MAP_WRITE);
/* fill with pattern */
for (i = 0; i < info.size; i++)
info.data[i] = i;
/* release memory */
gst_memory_unmap (mem, &info);
gst_allocator_alloc的定义在gstallocator.c中,如果第一个参数为空,会调用_default_allocator类的alloc函数,那_default_allocator从哪里来呢?gstallocator.c中定义了一个类GstAllocatorSysmem,G_DEFINE_TYPE (GstAllocatorSysmem, gst_allocator_sysmem, GST_TYPE_ALLOCATOR);
在初始化函数_priv_gst_allocator_initialize (void)中,创建了GstAllocatorSysmem的对象_sysmem_allocator( _default_allocator = gst_object_ref (_sysmem_allocator);),然后赋给了_default_allocator,所以_default_allocator是GstAllocatorSysmem对象的指针。GstAllocatorSysmem类的alloc函数是default_alloc,最终调用的顺序是:
GstMemory * gst_allocator_alloc(gstallocator.c)->default_alloc->_sysmem_new_block->g_slice_alloc(gslice.c)->调g_malloc,slab
如果gst_allocator_alloc的第一个参数不为NULL, 参见另一篇分析:GstBufferPool与nvpreprocess_茄子船长的博客-CSDN博客
三 分析meta.
gst_buffer_add_meta
Arbitrary extra metadata can be set on a buffer with gst_buffer_add_meta. Metadata can be retrieved with gst_buffer_get_meta. See also GstMeta.
GstMeta *gst_buffer_add_meta (GstBuffer * buffer, const GstMetaInfo * info, gpointer params)
{
GstMetaItem *item;
GstMeta *result = NULL;
gsize size;
g_return_val_if_fail (buffer != NULL, NULL);
g_return_val_if_fail (info != NULL, NULL);
g_return_val_if_fail (gst_buffer_is_writable (buffer), NULL);
/* create a new slice */
size = ITEM_SIZE (info);
/* We warn in gst_meta_register() about metas without
* init function but let's play safe here and prevent
* uninitialized memory
*/
if (!info->init_func)
item = g_slice_alloc0 (size);
else
item = g_slice_alloc (size);
result = &item->meta;
result->info = info;
result->flags = GST_META_FLAG_NONE;
。。。。。
/* call the init_func when needed */
if (info->init_func)
if (!info->init_func (result, params, buffer))
goto init_failed;
item->seq_num = gst_atomic_int64_inc (&meta_seq);
item->next = NULL;
if (!GST_BUFFER_META (buffer)) { //插入到链表尾部
GST_BUFFER_META (buffer) = item;
GST_BUFFER_TAIL_META (buffer) = item;
} else {
GST_BUFFER_TAIL_META (buffer)->next = item;
GST_BUFFER_TAIL_META (buffer) = item;
}
。。。。。。
}
关键是第二个参数,传入GstMetaInfo类型,返回GstMetaInfo对应meta,例如注册一个GstParentBufferMeta名称的的GstMetaInfo。
const GstMetaInfo *
gst_parent_buffer_meta_get_info (void) {
static const GstMetaInfo *meta_info = NULL;
if (g_once_init_enter ((GstMetaInfo **) & meta_info)) {
const GstMetaInfo *meta =
gst_meta_register (gst_parent_buffer_meta_api_get_type (),
"GstParentBufferMeta",
sizeof (GstParentBufferMeta),
(GstMetaInitFunction) _gst_parent_buffer_meta_init,
(GstMetaFreeFunction) _gst_parent_buffer_meta_free,
_gst_parent_buffer_meta_transform);
g_once_init_leave ((GstMetaInfo **) & meta_info, (GstMetaInfo *) meta);
}
return meta_info;
}
GstParentBufferMeta *
gst_buffer_add_parent_buffer_meta (GstBuffer * buffer, GstBuffer * ref)
{
GstParentBufferMeta *meta;
g_return_val_if_fail (GST_IS_BUFFER (ref), NULL);
meta =
(GstParentBufferMeta *) gst_buffer_add_meta (buffer,
GST_PARENT_BUFFER_META_INFO, NULL);
if (!meta)
return NULL;
meta->buffer = gst_buffer_ref (ref);
return meta;
}
第三方库的应用(deepstream)
deepstream用于AI推理,比如输入交通上的视频,推理得出汽车的位置,车牌的位置等,这些推理后的数据都存放在meta当中。deepstream有个streammux插件,在mux之前,meta绑定在GstBuffer上,如用户加一些自定义的meta ,streammux之后,所有数据打成一个batch,之前所有的meta数据都会挂到batch meta的链表下。以deepstream_gst_metadata.c为例,pipeline是 file-source -> h264-parser -> nvh264-decoder -> nvinfer -> nvvidconv -> nvosd -> video-renderer,
用户添加的meta:
/* nvdecoder_src_pad_buffer_probe() will attach decoder metadata to gstreamer
* buffer on src pad. The decoder can not attach to NvDsBatchMeta metadata because
* batch level metadata is created by nvstreammux component. The decoder
* component is present is before nvstreammmux. So it attached the metadata
* using gstnvdsmeta API's. */
static GstPadProbeReturn
nvdecoder_src_pad_buffer_probe (GstPad * pad, GstPadProbeInfo * info,
gpointer u_data)
{
GstBuffer *buf = (GstBuffer *) info->data;
NvDsMeta *meta = NULL;
NvDecoderMeta *decoder_meta = (NvDecoderMeta *)g_malloc0(sizeof(NvDecoderMeta));
if(decoder_meta == NULL)
{
return GST_FLOW_ERROR;
}
/* Add dummy metadata */
decoder_meta->frame_type = (frame_number % 3);
decoder_meta->frame_num = frame_number++;
decoder_meta->dec_err = ((frame_number % 4) / 3);
/* Attach decoder metadata to gst buffer using gst_buffer_add_nvds_meta() */
meta = gst_buffer_add_nvds_meta (buf, decoder_meta, NULL,
decoder_meta_copy_func, decoder_meta_release_func);
/* Set metadata type */
meta->meta_type = (GstNvDsMetaType)NVDS_DECODER_GST_META_EXAMPLE;
/* Set transform function to transform decoder metadata from Gst meta to
* nvds meta */
meta->gst_to_nvds_meta_transform_func = decoder_gst_to_nvds_meta_transform_func;
需要设置转换函数,streammux之后,meta会转到bachmeta下的链表下。
/* Set release function to release the transformed nvds metadata */
meta->gst_to_nvds_meta_release_func = decoder_gst_nvds_meta_release_func;
g_print("GST Dec Meta attached with gst decoder output buffer for Frame_Num = %d\n",
decoder_meta->frame_num);
g_print("Attached decoder Metadata: frame type = %d, frame_num = %d decode_error_status = %d\n\n",
decoder_meta->frame_type, decoder_meta->frame_num,
decoder_meta->dec_err);
return GST_PAD_PROBE_OK;
}
infer过后,读取用户之前添加的meta,
/* nvinfer_src_pad_buffer_probe() will extract the metadata received on nvinfer
* src pad.
* It explains the mechanism to extract the decoder metadata (which is attached
* using gstnvdsmeta API's in nvdecoder_src_pad_buffer_probe()),
* now transformed into nvdsmeta. Decoder meta, attached to gst buffer
* is set as user data at NvDsFrameMeta level
* It also extracts metadata attached on src pad of h264parse element. */
static GstPadProbeReturn
nvinfer_src_pad_buffer_probe (GstPad * pad, GstPadProbeInfo * info,
gpointer u_data)
{
GstBuffer *buf = (GstBuffer *) info->data;
NvDsMetaList * l_frame = NULL;
NvDsUserMeta *user_meta = NULL;
NvDecoderMeta * decoder_meta = NULL;
H264parseMeta * h264parse_meta = NULL;
NvDsMetaList * l_user_meta = NULL;
NvDsBatchMeta *batch_meta = gst_buffer_get_nvds_batch_meta (buf);
for (l_frame = batch_meta->frame_meta_list; l_frame != NULL;
l_frame = l_frame->next) {
NvDsFrameMeta *frame_meta = (NvDsFrameMeta *) (l_frame->data);
for (l_user_meta = frame_meta->frame_user_meta_list; l_user_meta != NULL;
l_user_meta = l_user_meta->next) {
user_meta = (NvDsUserMeta *) (l_user_meta->data);
if(user_meta->base_meta.meta_type == NVDS_DECODER_GST_META_EXAMPLE)
{
decoder_meta = (NvDecoderMeta *)user_meta->user_meta_data;
g_print("Dec Meta retrieved as NVDS USER METADTA For Frame_Num = %d \n",
decoder_meta->frame_num);
g_print("Retrieved Decoder Metadata: frame type = %d, frame_num = %d decode_error_status = %d\n\n",
decoder_meta->frame_type, decoder_meta->frame_num,
decoder_meta->dec_err);
}
}
}
return GST_PAD_PROBE_OK;
}
我在开发的Rails3网站的一些搜索功能上遇到了一个小问题。我有一个简单的Post模型,如下所示:classPost我正在使用acts_as_taggable_on来更轻松地向我的帖子添加标签。当我有一个标记为“rails”的帖子并执行以下操作时,一切正常:@posts=Post.tagged_with("rails")问题是,我还想搜索帖子的标题。当我有一篇标题为“Helloworld”并标记为“rails”的帖子时,我希望能够通过搜索“hello”或“rails”来找到这篇帖子。因此,我希望标题列的LIKE语句与acts_as_taggable_on提供的tagged_with方法
“输出”是一个序列化的OpenStruct。定义标题try(:output).try(:data).try(:title)结束什么会更好?:) 最佳答案 或者只是这样:deftitleoutput.data.titlerescuenilend 关于ruby-on-rails-更好的替代方法try(:output).try(:data).try(:name)?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.c
我正在为我正在处理的一些新ChefRecipe编写InSpec测试。我想利用Recipe使用的data_bags遍历数据包项。我不知道如何在我的InSpec测试中访问它们!这些Recipe使用了search、data_bag和data_bag_item方法。但是这些方法在我的InSpec测试中似乎不可用。我怀疑这些是ChefDSL特定的方法?data_bags的源代码受源代码控制,因此我可以在我的本地文件系统上访问它们的json。如何使用InSpec语法访问Chef_zero中的这些数据包?我在网上找到了几个示例,但我没有看到data_bags实际上是如何由chef_zero加载的,以
我正在尝试向浏览器发送多个文件。我不能像下面的代码一样为每条记录调用send_data,因为我收到双重渲染错误。根据thispost我需要创建文件并压缩它们,以便我可以在一个请求中发送它们。@records.eachdo|r|ActiveRecord::Base.include_root_in_json=true@json=r.to_jsona=ActiveSupport::MessageEncryptor.new(Rails.application.config.secret_token)@json_encrypted=a.encrypt_and_sign(@json)send_da
我使用ruby1.9.3和redmine1.4.4据此->Pleasehelpmesendajpgfileusingsend_data,我在Controller中这样做:@file=temp.pathFile.open(@file,'r')do|f|send_dataf.read,:filename=>"myfile.pdf",:type=>"application/pdf",:disposition=>"attachment"endFile.delete(@file)但它返回ArgumentError(UTF-8中的无效字节序列),为什么? 最佳答案
我错过了什么?我正在尝试使用Active资源的休息服务,我有以下内容:classUser"Test",:email=>"test.user@domain.com")puserifuser.saveputs"success:#{user.uuid}"elseputs"error:#{user.errors.full_messages.to_sentence}"end以及用户的以下输出:#"Test","email"=>"test.user@domain.com"}>和这个错误:/Library/Ruby/Gems/1.8/gems/activeresource-3.0.10/lib/ac
我已经阅读了net-ssh文档,但我仍然感到困惑。我可以手动进行身份验证(使用ssh-i...),也可以将key放在文件中并使用:keys参数。但是,我不想使用:keys参数,我想使用:key_data参数。任何人都可以举一个工作的例子吗?出于某种原因,直接将字符串输入:key_data是行不通的,它给出了错误:“既不是PUBkey也不是PRIVkey::嵌套的asn1错误”。当然,我用谷歌搜索了一下,它基本上告诉我要确保key是PEM格式。而且,当然是。有任何想法吗?如果需要,我可以提供更详细的信息... 最佳答案 我看到这个问题
我正在尝试在Aptana3中调试简单的ruby文件。classHelloWorlddefinitialize()enddefgreet()puts"helloworld"endendh=HelloWorld.newh.greet断点设置为h.greet在我开始调试后,调试器启动,但是当它尝试初始化ruby类时,调试器断开连接并显示消息FastDebugger(ruby-debug-ide0.4.9)listenson:54749ExceptioninDebugThreadloop:undefinedmethod`is_binary_data?'for"#":String当我将断
我正在编写一个Ruby扩展,我正在使用函数Data_wrap_struct。为了参与Ruby的标记和清除垃圾收集过程,我需要定义一个例程来释放我的结构,以及一个例程来标记从我的结构到其他结构的任何引用。我通过经典的free函数来释放内存,但我不知道如何使用标记函数。我的结构听起来像这样typedefstruct{intx;inty;}A;typedefstruct{Acollection[10];intcurrent;}B;我认为我需要一个标记函数来标记结构B的collection中的引用。谁能给我看一个例子,看看标记函数是如何工作的? 最佳答案
这不是RubyequivalentofPerlData::Dumper的副本.这个问题已经超过3.5年了,因此想检查从那时起Ruby中是否有任何可用的新选项。我正在寻找perl的Dumper在ruby中的等价物。我不在乎Dumper在幕后做了什么。我已经广泛使用它在perl中打印深度嵌套的哈希和数组。到目前为止,我还没有在ruby中找到替代品(或者我可能没有找到一种方法来充分利用Ruby中的可用替代品)。这是我的perl代码及其输出:#!/usr/bin/perl-wusestrict;useData::Dumper;my$hash;$hash->{what}->{where}