685 - First Unique Number In Stream

本文介绍了一种使用LinkedHashMap来解决寻找数组中第一个非唯一出现的数字的问题的方法。该方法适用于需要保持元素插入顺序的场景。

2017.9.29

这个题目是要求输出第一个非唯一的元素。如果直接用HashMap的话会失去顺序,所以需要使用LinkedHashMap。

public class Solution {
    /*
     * @param : a continuous stream of numbers
     * @param : a number
     * @return: returns the first unique number
     */
  	public int firstUniqueNumber(int[] nums, int number) {
        // Write your code here
		if(nums == null){
			return -1;
		}
		int res = -1;
		LinkedHashMap<Integer,Integer> map = new LinkedHashMap<>();
		boolean find = false;
		for(int i = 0; i < nums.length; i++){
			if(nums[i] == number){
				find = true;
				break;
			}
			if(!map.containsKey(nums[i])){
				map.put(nums[i], 1);
			}
			else{
				map.put(nums[i], map.get(nums[i]) + 1);
			}
		}
		if(find == false){
			return res;
		}
		Iterator ite = map.keySet().iterator();
		while(ite.hasNext()){
			int tmp = (int)ite.next();
			if(map.get(tmp) == 1){
				res = tmp;
				break;
			}
		}
		return res;
    }
};


内容概要:本文系统阐述了Java Persistence API(JPA)的核心概念、技术架构、核心组件及实践应用,重点介绍了JPA作为Java官方定义的对象关系映射(ORM)规范,如何通过实体类、EntityManager、JPQL和persistence.xml配置文件实现Java对象与数据库表之间的映射与操作。文章详细说明了JPA解决的传统JDBC开发痛点,如代码冗余、对象映射繁琐、跨数据库兼容性差等问题,并解析了JPA与Hibernate、EclipseLink等实现框架的关系。同时提供了基于Hibernate和MySQL的完整实践案例,涵盖Maven依赖配置、实体类定义、CRUD操作实现等关键步骤,并列举了常用JPA注解及其用途。最后总结了JPA的标准化优势、开发效率提升能力及在Spring生态中的延伸应用。 适合人群:具备一定Java基础,熟悉基本数据库操作,工作1-3年的后端开发人员或正在学习ORM技术的中级开发者。 使用场景及目标:①理解JPA作为ORM规范的核心原理与组件协作机制;②掌握基于JPA+Hibernate进行数据库操作的开发流程;③为技术选型、团队培训或向Spring Data JPA过渡提供理论与实践基础。 阅读建议:此资源以理论结合实践的方式讲解JPA,建议读者在学习过程中同步搭建环境,动手实现文中示例代码,重点关注EntityManager的使用、JPQL语法特点以及注解配置规则,从而深入理解JPA的设计思想与工程价值。
[2025-10-29 13:15:44] [ERROR] _ctx_put_unit():2161 - [AVDM]avdm5 new buffer offset is 0, available len is 0x40000, potiental len is 0x40000 [2025-10-29 13:15:44] [ERROR] _ctx_attach_next_unit():2406 - [AVDM]first time get avdm5 next unit, return lastest unit [2025-10-29 13:15:44] [ERROR] __pack_block():903 - [AVDM]avdm5 block(index:0,seq:0,unit number:1,buffer offset:0x0,buffer len:1048 Bytes) has been packed [2025-10-29 13:15:44] [ERROR] _ctx_put_unit():2161 - [AVDM]avdm5 new buffer offset is 0, available len is 0x40000, potiental len is 0x40000 [2025-10-29 13:15:44] [ERROR] __free_a_block():837 - [AVDM]Freed a avdm5 block(index:0,seq:0,unitcnt:1,offset:0x0,len:1048 Bytes) that is never been consumed [2025-10-29 13:15:44] [ERROR] _ctx_attach_next_unit():2515 - [AVDM]Stream 5: Unit Overwrite happened. cursor seq 0, current seq 0, state 0, latest seq 1 [2025-10-29 13:15:44] [ERROR] _ctx_attach_next_unit():2516 - [AVDM]Return lastest unit [2025-10-29 13:15:44] [ERROR] __pack_block():903 - [AVDM]avdm5 block(index:1,seq:1,unit number:1,buffer offset:0x0,buffer len:1048 Bytes) has been packed [2025-10-29 13:15:44] [ERROR] _ctx_put_unit():2161 - [AVDM]avdm5 new buffer offset is 0, available len is 0x40000, potiental len is 0x40000 [2025-10-29 13:15:44] [ERROR] __free_a_block():837 - [AVDM]Freed a avdm5 block(index:1,seq:1,unitcnt:1,offset:0x0,len:1048 Bytes) that is never been consumed [2025-10-29 13:15:44] [ERROR] _ctx_attach_next_unit():2515 - [AVDM]Stream 5: Unit Overwrite happened. cursor seq 1, current seq 1, state 0, latest seq 2 [2025-10-29 13:15:44] [ERROR] _ctx_attach_next_unit():2516 - [AVDM]Return lastest unit [2025-10-29 13:15:44] [ERROR] __pack_block():903 - [AVDM]avdm5 block(index:2,seq:2,unit number:1,buffer offset:0x0,buffer len:1048 Bytes) has been packed [2025-10-29 13:15:44] [ERROR] _ctx_put_unit():2161 - [AVDM]avdm5 new buffer offset is 0, available len is 0x40000, potiental len is 0x40000 [2025-10-29 13:15:44] [ERROR] __free_a_block():837 - [AVDM]Freed a avdm5 block(index:2,seq:2,unitcnt:1,offset:0x0,len:1048 Bytes) that is never been consumed [2025-10-29 13:15:44] [ERROR] _ctx_attach_next_unit():2515 - [AVDM]Stream 5: Unit Overwrite happened. cursor seq 2, current seq 2, state 0, latest seq 3 [2025-10-29 13:15:44] [ERROR] _ctx_attach_next_unit():2516 - [AVDM]Return lastest unit [2025-10-29 13:15:44] [ERROR] __pack_block():903 - [AVDM]avdm5 block(index:3,seq:3,unit number:1,buffer offset:0x0,buffer len:1048 Bytes) has been packed [2025-10-29 13:15:44] [ERROR] _ctx_put_unit():2161 - [AVDM]avdm5 new buffer offset is 0, available len is 0x40000, potiental len is 0x40000 [2025-10-29 13:15:44] [ERROR] __free_a_block():837 - [AVDM]Freed a avdm5 block(index:3,seq:3,unitcnt:1,offset:0x0,len:1048 Bytes) that is never been consumed [2025-10-29 13:15:44] [ERROR] _ctx_attach_next_unit():2515 - [AVDM]Stream 5: Unit Overwrite happened. cursor seq 3, current seq 3, state 0, latest seq 4 [2025-10-29 13:15:44] [ERROR] _ctx_attach_next_unit():2516 - [AVDM]Return lastest unit [2025-10-29 13:15:44] [ERROR] __pack_block():903 - [AVDM]avdm5 block(index:4,seq:4,unit number:1,buffer offset:0x0,buffer len:1048 Bytes) has been packed [2025-10-29 13:15:44] [ERROR] _ctx_put_unit():2161 - [AVDM]avdm5 new buffer offset is 0, available len is 0x40000, potiental len is 0x40000 [2025-10-29 13:15:44] [ERROR] __free_a_block():837 - [AVDM]Freed a avdm5 block(index:4,seq:4,unitcnt:1,offset:0x0,len:1048 Bytes) that is never been consumed [2025-10-29 13:15:44] [ERROR] _ctx_attach_next_unit():2515 - [AVDM]Stream 5: Unit Overwrite happened. cursor seq 4, current seq 4, state 0, latest seq 5 [2025-10-29 13:15:44] [ERROR] _ctx_attach_next_unit():2516 - [AVDM]Return lastest unit [2025-10-29 13:15:44] [ERROR] __pack_block():903 - [AVDM]avdm5 block(index:5,seq:5,unit number:1,buffer offset:0x0,buffer len:1048 Bytes) has been packed [2025-10-29 13:15:44] [ERROR] avdm_video_recv_cb():3514 - [AVDM]put video buffer(type:2) to avdm0 failed [2025-10-29 13:15:44] [ERROR] _ctx_put_unit():2161 - [AVDM]avdm5 new buffer offset is 0, available len is 0x40000, potiental len is 0x40000 [2025-10-29 13:15:44] [ERROR] __pack_block():903 - [AVDM]avdm1 block(index:0,seq:90,unit number:40,buffer offset:0x7d1b4,buffer len:116436 Bytes) has been packed [2025-10-29 13:15:44] [ERROR] __free_a_block():837 - [AVDM]Freed a avdm5 block(index:5,seq:5,unitcnt:1,offset:0x0,len:1048 Bytes) that is never been consumed [2025-10-29 13:15:44] [ERROR] _ctx_put_unit():2161 - [AVDM]avdm1 new buffer offset is 0x99888, available len is 0x50000, potiental len is 0x66778 [2025-10-29 13:15:44] [ERROR] _ctx_attach_next_unit():2515 - [AVDM]Stream 5: Unit Overwrite happened. cursor seq 5, current seq 5, state 0, latest seq 6 [2025-10-29 13:15:44] [ERROR] _ctx_attach_next_unit():2516 - [AVDM]Return lastest unit [2025-10-29 13:15:44] [ERROR] __pack_block():903 - [AVDM]avdm5 block(index:6,seq:6,unit number:1,buffer offset:0x0,buffer len:1048 Bytes) has been packed [2025-10-29 13:15:44] [ERROR] _ctx_put_unit():2161 - [AVDM]avdm5 new buffer offset is 0, available len is 0x40000, potiental len is 0x40000 [2025-10-29 13:15:44] [ERROR] __free_a_block():837 - [AVDM]Freed a avdm5 block(index:6,seq:6,unitcnt:1,offset:0x0,len:1048 Bytes) that is never been consumed [2025-10-29 13:15:44] [ERROR] _ctx_attach_next_unit():2515 - [AVDM]Stream 5: Unit Overwrite happened. cursor seq 6, current seq 6, state 0, latest seq 7 [2025-10-29 13:15:44] [ERROR] _ctx_attach_next_unit():2516 - [AVDM]Return lastest unit [2025-10-29 13:15:44] [ERROR] __pack_block():903 - [AVDM]avdm5 block(index:7,seq:7,unit number:1,buffer offset:0x0,buffer len:1048 Bytes) has been packed [2025-10-29 13:15:44] [ERROR] _ctx_put_unit():2161 - [AVDM]avdm5 new buffer offset is 0, available len is 0x40000, potiental len is 0x40000 [2025-10-29 13:15:44] [ERROR] __free_a_block():837 - [AVDM]Freed a avdm5 block(index:7,seq:7,unitcnt:1,offset:0x0,len:1048 Bytes) that is never been consumed [2025-10-29 13:15:44] [ERROR] _ctx_attach_next_unit():2515 - [AVDM]Stream 5: Unit Overwrite happened. cursor seq 7, current seq 7, state 0, latest seq 8 [2025-10-29 13:15:44] [ERROR] _ctx_attach_next_unit():2516 - [AVDM]Return lastest unit [2025-10-29 13:15:44] [ERROR] __pack_block():903 - [AVDM]avdm5 block(index:8,seq:8,unit number:1,buffer offset:0x0,buffer len:1048 Bytes) has been packed [2025-10-29 13:15:44] [ERROR] _ctx_put_unit():2161 - [AVDM]avdm5 new buffer offset is 0, available len is 0x40000, potiental len is 0x40000 [2025-10-29 13:15:44] [ERROR] __free_a_block():837 - [AVDM]Freed a avdm5 block(index:8,seq:8,unitcnt:1,offset:0x0,len:1048 Bytes) that is never been consumed [2025-10-29 13:15:44] [ERROR] _ctx_attach_next_unit():2515 - [AVDM]Stream 5: Unit Overwrite happened. cursor seq 8, current seq 8, state 0, latest seq 9 [2025-10-29 13:15:44] [ERROR] _ctx_attach_next_unit():2516 - [AVDM]Return lastest unit [2025-10-29 13:15:44] [ERROR] _ctx_put_unit():2199 - [AVDM]drop P frame because previous P frame was droped [2025-10-29 13:15:44] [ERROR] avdm_video_recv_cb():3514 - [AVDM]put video buffer(type:2) to avdm0 failed [2025-10-29 13:15:44] [ERROR] __pack_block():903 - [AVDM]avdm5 block(index:9,seq:9,unit number:1,buffer offset:0x0,buffer len:1048 Bytes) has been packed [2025-10-29 13:15:44] [ERROR] _ctx_put_unit():2161 - [AVDM]avdm5 new buffer offset is 0, available len is 0x40000, potiental len is 0x40000 [2025-10-29 13:15:44] [ERROR] __free_a_block():837 - [AVDM]Freed a avdm5 block(index:9,seq:9,unitcnt:1,offset:0x0,len:1048 Bytes) that is never been consumed [2025-10-29 13:15:44] [ERROR] _ctx_put_unit():2199 - [AVDM]drop P frame because previous P frame was droped这里的5是我想要取到的,但是返回报错,其中static S32 _ctx_attach_next_block(avdm_context_t *ctx, avdm_cursor_t *cur, avdm_block_t *block) { S32 ret = 0; avdm_ring_t *ring = ctx->ring; block_desc_t *bdesc = NULL; if (NULL == cur) { AVDM_ERROR("wrong params"); return -ERR_WRONG_PARAMS; } pthread_rwlock_rdlock(&ctx->rwlock); if (AVDM_BUFFER_IS_EMPTY(ctx)) { AVDM_ERROR("buffer is empty"); ret = -ERR_FRAME_NOT_READY; goto exit; } // if ((ring->last_bdesc == NULL) || (ring->last_bdesc->attr.state != DESC_STATE_OCCUPIED)) if ((ring->last_bdesc == NULL)) { AVDM_ERROR("avdm%d lastest block not ready yet", ctx->type); ret = -ERR_FRAME_NOT_READY; goto exit; } if ((ring->last_bdesc->attr.state != DESC_STATE_OCCUPIED)) { AVDM_ERROR("avdm%d lastest block not ready yet", ctx->type); ret = -ERR_FRAME_NOT_READY; goto exit; } if (NULL == cur->desc) { if (TRUE == cur->attaching) { ret = -ERR_WRONG_PARAMS; goto exit; } else { AVDM_ERROR("first time get avdm%d next block, return lastest block", ctx->type); __ctx_attach_block(ctx, ring->last_bdesc, cur, block); if (is_local_video_type(ctx) || is_network_video_type(ctx)) { cur->pre.happen_time = ring->last_bdesc->block.unique_info.video.iframe_timestamp; } ret = OK; goto exit; } } /* * 最新的已完成结点与cursor相同,表示新的block还未到来,将当前 * cursor的引用去掉,此时该线程不会引用任何avdm desc */ if ((ring->last_bdesc == (block_desc_t*)cur->desc) || (ring->last_bdesc->attr.seq == cur->seq)) { AVDM_ERROR("avdm%d next block not ready yet", ctx->type); __ctx_detach_block(ctx, cur); ret = -ERR_FRAME_NOT_READY; goto exit; } bdesc = (block_desc_t*)cur->desc; bdesc = bdesc->next_used; if (NULL == bdesc || bdesc->attr.seq != AVDM_NEXT_SEQ(cur->seq)) { /* cur的desc已经被释放(next_used为空)或者seq序号不连续,发生覆盖,获取最新的block */ if (NULL == bdesc) { AVDM_ERROR("Stream %d: Block Overwrite happened. seq %d, next desc is empty", ctx->type, cur->seq); } else { AVDM_ERROR("Stream %d: Block Overwrite happened. seq %d, nexseq %d, state %d", ctx->type, cur->seq, bdesc->attr.seq, bdesc->attr.state); } AVDM_ERROR("Return lastest block"); __ctx_detach_block(ctx, cur); __ctx_attach_block(ctx, ring->last_bdesc, cur, block); if (is_local_video_type(ctx) || is_network_video_type(ctx)) { cur->pre.happen_time = ring->last_bdesc->block.unique_info.video.iframe_timestamp; } ret = -ERR_OW_GET_LATEST; } else { /* 获取下一个block,同时更新下一次获取预录时需要比对的block信息 */ __ctx_detach_block(ctx, cur); __ctx_attach_block(ctx, bdesc, cur, block); if (is_local_video_type(ctx) || is_network_video_type(ctx)) { cur->pre.happen_time = bdesc->block.unique_info.video.iframe_timestamp; } ret = OK; } exit: pthread_rwlock_unlock(&ctx->rwlock); return ret; },这里返回了ring->last_bdesc == NULL的报错,其中/* * 描述buffer环的结构 */ typedef struct __avdm_ring { U32 bdesc_num; /* block描述符个数 */ U32 block_max_size; /* block预设最大值(可以超过) */ block_desc_t *cur_bdesc; /* 当前正在使用的block描述符 */ unit_desc_t *cur_udesc; /* 当前正在使用的unit描述符 */ block_desc_t *last_bdesc; /* 上一个已使用的block描述符 */ unit_desc_t *last_udesc; /* 上一个已使用的unit描述符 */ struct list_head unit_cblist; /* 新desc内容完成时执行cb_list的回调 */ struct list_head block_cblist; /* 新desc内容完成时执行cb_list的回调 */ unit_list_t *udesc_list; /* 指向unit空闲描述符列表 */ block_buffer_t bbuffer; /* 当前block可占用的内存空间描述 */ block_desc_t desc[0]; } avdm_ring_t;
10-30
你提供的日志和代码片段来自一个名为 **AVDM**(可能是 Audio-Video Data Manager)的底层音视频数据管理模块,其核心是一个环形缓冲区(ring buffer)结构,用于管理音视频帧的写入与读取。你在尝试从某个流(Stream 5)中获取下一个 block 单元时失败了,报错的关键信息是: ``` [ERROR] _ctx_attach_next_unit():2406 - [AVDM]first time get avdm5 next unit, return lastest unit ... [ERROR] _ctx_attach_next_unit():2515 - [AVDM]Stream 5: Unit Overwrite happened. cursor seq 8, current seq 8, state 0, latest seq 9 [ERROR] _ctx_attach_next_unit():2516 - [AVDM]Return lastest unit ``` 以及最终: ``` avdm_video_recv_cb():3514 - [AVDM]put video buffer(type:2) to avdm0 failed _ctx_put_unit():2199 - [AVDM]drop P frame because previous P frame was droped ``` --- ### ✅ 问题分析 你的目标是从 `avdm5` 流中获取数据(比如视频帧),但始终返回错误或“最新单元”,说明: - **消费者(读取方)速度太慢** - 导致生产者不断覆盖旧数据 - 最终造成 **buffer 被覆盖(overwrite)** - 于是 `_ctx_attach_next_block()` 函数无法按顺序找到下一个 block,只能返回最新的 block - 并触发 `ERR_OW_GET_LATEST` 错误码,甚至丢弃 P 帧 关键点在于这段逻辑: ```c if ((ring->last_bdesc == NULL) || (ring->last_bdesc->attr.state != DESC_STATE_OCCUPIED)) { AVDM_ERROR("avdm%d lastest block not ready yet", ctx->type); ret = -ERR_FRAME_NOT_READY; goto exit; } ``` 这个判断表示:如果 `last_bdesc` 是空的,或者它的状态不是已占用(OCCUPIED),就认为没有可用 block。 但从后续日志看,其实有 block 被打包了(`__pack_block()` 执行成功),所以 `last_bdesc` 不应为 NULL —— 除非: > ❗ **在调用 `_ctx_attach_next_block` 时,生产者尚未完成 block 提交,或 ring 已被重置/未初始化。** 然而更可能的情况是: > ⚠️ **虽然 block 被写了,但由于消费线程没及时推进 cursor,导致 ring 中所有 block 都被新写入覆盖,老的 block 被释放,而 consumer 的 cur->desc 指向已被释放节点 → 触发 overwrite 回退机制。** --- ### 🔍 关键函数解析:`_ctx_attach_next_block` 我们来逐段解释该函数的行为: ```c static S32 _ctx_attach_next_block(avdm_context_t *ctx, avdm_cursor_t *cur, avdm_block_t *block) { S32 ret = 0; avdm_ring_t *ring = ctx->ring; block_desc_t *bdesc = NULL; if (NULL == cur) { AVDM_ERROR("wrong params"); return -ERR_WRONG_PARAMS; } pthread_rwlock_rdlock(&ctx->rwlock); if (AVDM_BUFFER_IS_EMPTY(ctx)) // 判断 buffer 是否为空 { AVDM_ERROR("buffer is empty"); ret = -ERR_FRAME_NOT_READY; goto exit; } // 检查 last_bdesc 是否存在且处于 OCCUPIED 状态 if ((ring->last_bdesc == NULL)) { AVDM_ERROR("avdm%d lastest block not ready yet", ctx->type); ret = -ERR_FRAME_NOT_READY; goto exit; } if ((ring->last_bdesc->attr.state != DESC_STATE_OCCUPIED)) { AVDM_ERROR("avdm%d lastest block not ready yet", ctx->type); ret = -ERR_FRAME_NOT_READY; goto exit; } ``` ➡️ 这里检查的是:是否有任何已完成的 block?如果没有,直接报错。 接着处理首次获取的情况: ```c if (NULL == cur->desc) { if (TRUE == cur->attaching) { ret = -ERR_WRONG_PARAMS; goto exit; } else { AVDM_ERROR("first time get avdm%d next block, return lastest block", ctx->type); __ctx_attach_block(ctx, ring->last_bdesc, cur, block); // 直接绑定到最后一个 block ret = OK; goto exit; } } ``` ➡️ 第一次读取时,`cur->desc` 为空,直接返回最新的 block(这是允许的,属于正常行为)。 然后是重点逻辑:尝试获取下一个 block: ```c if ((ring->last_bdesc == (block_desc_t*)cur->desc) || (ring->last_bdesc->attr.seq == cur->seq)) { AVDM_ERROR("avdm%d next block not ready yet", ctx->type); __ctx_detach_block(ctx, cur); ret = -ERR_FRAME_NOT_READY; goto exit; } ``` ➡️ 如果当前 cursor 已经指向最后一个 block,说明还没有新的 block 写入 → 返回 `-ERR_FRAME_NOT_READY`。 最后尝试跳转到下一个 block: ```c bdesc = (block_desc_t*)cur->desc; bdesc = bdesc->next_used; if (NULL == bdesc || bdesc->attr.seq != AVDM_NEXT_SEQ(cur->seq)) { /* 发生覆盖 */ AVDM_ERROR("Stream %d: Block Overwrite happened..."); __ctx_detach_block(ctx, cur); __ctx_attach_block(ctx, ring->last_bdesc, cur, block); ret = -ERR_OW_GET_LATEST; // 特殊错误码:因覆盖只能返回最新 block } else { __ctx_detach_block(ctx, cur); __ctx_attach_block(ctx, bdesc, cur, block); ret = OK; } ``` ➡️ 只要 `next_used` 为空 或 `seq` 不连续,就判定为 **覆盖发生**,强制跳转到 `last_bdesc`。 --- ### 📌 根本原因总结 | 日志特征 | 含义 | |--------|------| | `Unit Overwrite happened. cursor seq X, current seq X, latest seq Y` | 表示消费者停留在 seq=X,但生产者已经写到了 seq=Y,中间的数据全丢了 | | `Freed a ... block that is never been consumed` | block 被回收前从未被读取过 → 消费者太慢 | | `drop P frame because previous P frame was dropped` | 解码链断裂:P帧依赖前面的帧,前面丢了就不能解 | 👉 **结论:消费者读取速度远低于生产者写入速度,导致 buffer 被反复覆盖,无法顺序读取,只能不断“追赶”最新帧。** --- ### ✅ 解决方案建议 #### ✅ 1. **提升消费者处理速度** 确保读取线程不阻塞,例如: - 不要在回调中做耗时操作(如编码、网络发送) - 使用独立线程取出数据后快速返回 ```c // 示例:非阻塞地取帧 while (1) { avdm_block_t block; int ret = avdm_get_next_block(ctx, &cursor, &block); if (ret == OK) { // 复制数据到队列 enqueue_block(&my_queue, &block); } else if (ret == -ERR_OW_GET_LATEST) { // 警告:发生了覆盖,可记录统计 log_warn("AVDM Stream %d: Frame lost due to overrun", ctx->type); continue; } else { usleep(1000); // 短暂休眠避免忙等 } } ``` #### ✅ 2. **增大 Ring Buffer 容量** 修改 `bdesc_num`(block 描述符数量)以容纳更多帧: ```c // 初始化 ring 时增加大小 ring->bdesc_num = 64; // 原来可能是 16,改为更大值 ``` 这样可以容忍短时间的消费延迟。 #### ✅ 3. **控制生产速率(限流)** 如果是本地采集,可以限制帧率(如 25fps),避免突发大量帧。 #### ✅ 4. **避免频繁 seek / detach** 不要频繁调用 `detach` 后又 `attach`,否则容易触发“首次获取”逻辑,总是拿最新帧。 #### ✅ 5. **添加监控机制** 记录以下指标: - 覆盖次数(`ERR_OW_GET_LATEST`) - 未消费就被释放的 block 数量 - 平均消费延迟 用于评估系统负载。 --- ### 💡 如何正确获取 Stream 5 的数据? 你需要保证: 1. 创建专用读取线程; 2. 使用稳定 cursor; 3. 快速处理每个 block; 4. 不要 sleep 在回调中; 示例代码框架: ```c void* avdm_consumer_thread(void* arg) { avdm_context_t* ctx = (avdm_context_t*)arg; avdm_cursor_t cursor = {0}; avdm_block_t block; // 初始化 cursor avdm_cursor_init(ctx, &cursor); while (!g_stop) { int ret = _ctx_attach_next_block(ctx, &cursor, &block); if (ret == OK) { // 成功拿到下一帧 process_video_frame(&block); // 尽快复制并返回 } else if (ret == -ERR_OW_GET_LATEST) { printf("[WARN] Stream %d: Missed frames, recovering...\n", ctx->type); // 可选择重新同步 } else if (ret == -ERR_FRAME_NOT_READY) { usleep(1000); // 等待新帧 } else { usleep(1000); } } avdm_cursor_deinit(&cursor); return NULL; } ``` 启动线程: ```c pthread_t tid; pthread_create(&tid, NULL, avdm_consumer_thread, avdm_ctx_array[5]); ``` --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值