Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
C
car-controlserver
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wenzhongjian
car-controlserver
Commits
055aa314
Commit
055aa314
authored
Jul 11, 2026
by
957dd
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
c语言推流基本完成
parent
3585cc8c
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
230 additions
and
53 deletions
+230
-53
main
build/main
+0
-0
car0107_control.c
drivers/devicecontrol/car/car0107_control.c
+97
-0
car0107_control.h
drivers/devicecontrol/car/car0107_control.h
+3
-0
car0107_idle.c
drivers/devicecontrol/car/car0107_idle.c
+5
-26
audioplay.c.bak.20260710_111731
drivers/sensors/audioplay.c.bak.20260710_111731
+0
-0
mpp_h264_source.c
modules/webrtcpush/mpp_h264_source.c
+37
-1
rtc_client.c
modules/webrtcpush/rtc_client.c
+68
-16
webrtcpush_config.h
modules/webrtcpush/webrtcpush_config.h
+19
-9
zlog.conf
zlog.conf
+1
-1
No files found.
build/main
View file @
055aa314
No preview for this file type
drivers/devicecontrol/car/car0107_control.c
View file @
055aa314
...
@@ -28,6 +28,14 @@
...
@@ -28,6 +28,14 @@
#define CAR0107_BACK_US_RUN_MIN 1440
/* val=53 起步即动(须低于死区 1450) */
#define CAR0107_BACK_US_RUN_MIN 1440
/* val=53 起步即动(须低于死区 1450) */
#define CAR0107_BACK_US_RUN_MAX 1300
/* 后退最大速度再降20%:val=200 -> 1300us */
#define CAR0107_BACK_US_RUN_MAX 1300
/* 后退最大速度再降20%:val=200 -> 1300us */
/* idle 唤醒动作:5分钟无控制后 低速后退 -> 低速前进 -> 前进刹车停止 */
#define CAR0107_IDLE_REVERSE_US CAR0107_BACK_US_RUN_MIN
/* 1440us 刚过死区,最低速后退 */
#define CAR0107_IDLE_FORWARD_US CAR0107_FWD_US_RUN_MIN
/* 1560us 最低前进行走脉宽 */
#define CAR0107_IDLE_REVERSE_MS 600
/* 后退保持时长 */
#define CAR0107_IDLE_NEUTRAL_MS 150
/* 后退切前进前中位稳定时长 */
#define CAR0107_IDLE_FORWARD_MS 600
/* 前进保持时长 */
#define CAR0107_IDLE_BRAKE_WAIT_MS 250
/* 等待刹车保持+中位解锁收尾到 NEUTRAL */
typedef
enum
{
typedef
enum
{
CAR0107_ESC_DIR_FORWARD
=
1
,
/* App mode1 前进:高脉宽(与 0101 相反) */
CAR0107_ESC_DIR_FORWARD
=
1
,
/* App mode1 前进:高脉宽(与 0101 相反) */
CAR0107_ESC_DIR_BACK
=
2
,
/* App mode2 后退:低脉宽(与 0101 相反) */
CAR0107_ESC_DIR_BACK
=
2
,
/* App mode2 后退:低脉宽(与 0101 相反) */
...
@@ -1392,3 +1400,92 @@ void car0107_esc_thread_close(void)
...
@@ -1392,3 +1400,92 @@ void car0107_esc_thread_close(void)
pthread_mutex_unlock
(
&
s_esc_start_mutex
);
pthread_mutex_unlock
(
&
s_esc_start_mutex
);
my_zlog_info
(
"car0107 esc thread closed"
);
my_zlog_info
(
"car0107 esc thread closed"
);
}
}
/*
* 0107 idle 唤醒动作:5分钟无控制命令时由 idle 线程调用。
* 顺序:低速后退一点 -> 中位 -> 低速前进一点 -> 前进刹车停止。
* 前进停止遵守电调刹车动作 BRAKE_THEN_NEUTRAL -> NEUTRAL_UNLOCK -> NEUTRAL,
* 由电调专用线程 tick 自动完成刹车保持与中位解锁收尾。
* 动作期间若有真实控制命令介入(control_source 被改为非 NONE)则立即让位。
*/
void
car0107_idle_wakeup_maneuver
(
void
)
{
/* 必须保证电调线程在运行,否则刹车序列无法由 tick 自动收尾到 NEUTRAL */
car0107_esc_thread_start
();
/* 方向盘回正,后退/前进均走直线 */
pthread_mutex_lock
(
&
s_car0107_hw_mutex
);
s_control_source
=
CTRL_NONE
;
/* 阻止 speed_smooth_process 串扰速度 */
s_target_angle
=
90
;
s_current_angle
=
90
;
car0107_calculate_L_R
(
90
);
/* 1) 低速后退:从中位直接跳到刚过死区的后退脉宽 */
car0107_esc_clear_pending_stop
();
s_esc
.
cmd_dir
=
CAR0107_ESC_DIR_BACK
;
s_esc
.
last_drive_dir
=
CAR0107_ESC_DIR_BACK
;
s_esc
.
last_nonzero_mode
=
CAR0107_ESC_DIR_BACK
;
s_esc
.
target_us
=
CAR0107_IDLE_REVERSE_US
;
s_esc
.
current_us
=
CAR0107_IDLE_REVERSE_US
;
s_esc
.
state
=
CAR0107_ESC_REVERSE
;
s_esc
.
trans_phase
=
CAR0107_TRANS_RAMP_RUN
;
car0107_esc_output_us
(
s_esc
.
current_us
,
0
);
pthread_mutex_unlock
(
&
s_car0107_hw_mutex
);
car0107_esc_thread_wake
();
my_zlog_info
(
"car0107 idle maneuver: reverse %dus for %dms"
,
CAR0107_IDLE_REVERSE_US
,
CAR0107_IDLE_REVERSE_MS
);
delay_ms
(
CAR0107_IDLE_REVERSE_MS
);
/* 2) 停止后退:后退松手不刹车,直接回中 */
pthread_mutex_lock
(
&
s_car0107_hw_mutex
);
if
(
s_control_source
!=
CTRL_NONE
)
{
pthread_mutex_unlock
(
&
s_car0107_hw_mutex
);
my_zlog_info
(
"car0107 idle maneuver: yield at neutral (control taken)"
);
return
;
}
car0107_esc_begin_neutral_stop
();
car0107_esc_output_us
(
CAR0107_ESC_US_NEUTRAL
,
0
);
pthread_mutex_unlock
(
&
s_car0107_hw_mutex
);
car0107_esc_thread_wake
();
delay_ms
(
CAR0107_IDLE_NEUTRAL_MS
);
/* 3) 低速前进:从中位直接跳到最低前进行走脉宽 */
pthread_mutex_lock
(
&
s_car0107_hw_mutex
);
if
(
s_control_source
!=
CTRL_NONE
)
{
pthread_mutex_unlock
(
&
s_car0107_hw_mutex
);
my_zlog_info
(
"car0107 idle maneuver: yield before forward (control taken)"
);
return
;
}
car0107_esc_clear_pending_stop
();
s_esc
.
cmd_dir
=
CAR0107_ESC_DIR_FORWARD
;
s_esc
.
last_drive_dir
=
CAR0107_ESC_DIR_FORWARD
;
s_esc
.
last_nonzero_mode
=
CAR0107_ESC_DIR_FORWARD
;
s_esc
.
target_us
=
CAR0107_IDLE_FORWARD_US
;
s_esc
.
current_us
=
CAR0107_IDLE_FORWARD_US
;
s_esc
.
state
=
CAR0107_ESC_FORWARD
;
s_esc
.
trans_phase
=
CAR0107_TRANS_RAMP_RUN
;
car0107_esc_output_us
(
s_esc
.
current_us
,
0
);
pthread_mutex_unlock
(
&
s_car0107_hw_mutex
);
car0107_esc_thread_wake
();
my_zlog_info
(
"car0107 idle maneuver: forward %dus for %dms"
,
CAR0107_IDLE_FORWARD_US
,
CAR0107_IDLE_FORWARD_MS
);
delay_ms
(
CAR0107_IDLE_FORWARD_MS
);
/* 4) 停止前进:遵守刹车动作,由电调线程 tick 自动收尾 */
pthread_mutex_lock
(
&
s_car0107_hw_mutex
);
if
(
s_control_source
!=
CTRL_NONE
)
{
pthread_mutex_unlock
(
&
s_car0107_hw_mutex
);
my_zlog_info
(
"car0107 idle maneuver: yield before brake (control taken)"
);
return
;
}
car0107_esc_begin_forward_brake
();
pthread_mutex_unlock
(
&
s_car0107_hw_mutex
);
car0107_esc_thread_wake
();
my_zlog_info
(
"car0107 idle maneuver: forward brake %dus for %dms"
,
car0107_forward_brake_us
(),
CAR0107_ESC_BRAKE_HOLD_MS
);
delay_ms
(
CAR0107_IDLE_BRAKE_WAIT_MS
);
}
drivers/devicecontrol/car/car0107_control.h
View file @
055aa314
...
@@ -14,4 +14,7 @@ void car0107_esc_thread_start(void);
...
@@ -14,4 +14,7 @@ void car0107_esc_thread_start(void);
void
car0107_esc_thread_wake
(
void
);
void
car0107_esc_thread_wake
(
void
);
void
car0107_esc_thread_close
(
void
);
void
car0107_esc_thread_close
(
void
);
/* idle 唤醒动作:低速后退 -> 低速前进 -> 前进刹车停止 */
void
car0107_idle_wakeup_maneuver
(
void
);
#endif
#endif
drivers/devicecontrol/car/car0107_idle.c
View file @
055aa314
...
@@ -6,16 +6,12 @@
...
@@ -6,16 +6,12 @@
#define CAR0107_IDLE_CHECK_MS 10000
#define CAR0107_IDLE_CHECK_MS 10000
#define CAR0107_IDLE_TIMEOUT_MS (5 * 60 * 1000)
#define CAR0107_IDLE_TIMEOUT_MS (5 * 60 * 1000)
#define CAR0107_IDLE_STEER_HOLD_MS 450
#define CAR0107_IDLE_STEER_LEFT 115
#define CAR0107_IDLE_STEER_RIGHT 65
typedef
struct
{
typedef
struct
{
pthread_mutex_t
mutex
;
pthread_mutex_t
mutex
;
ThreadPool_t
*
pool
;
ThreadPool_t
*
pool
;
bool
shutdown
;
bool
shutdown
;
bool
pool_ready
;
bool
pool_ready
;
int
next_left
;
}
car0107_idle_ctx_t
;
}
car0107_idle_ctx_t
;
static
car0107_idle_ctx_t
s_idle_ctx
=
{
static
car0107_idle_ctx_t
s_idle_ctx
=
{
...
@@ -23,7 +19,6 @@ static car0107_idle_ctx_t s_idle_ctx = {
...
@@ -23,7 +19,6 @@ static car0107_idle_ctx_t s_idle_ctx = {
.
pool
=
NULL
,
.
pool
=
NULL
,
.
shutdown
=
false
,
.
shutdown
=
false
,
.
pool_ready
=
false
,
.
pool_ready
=
false
,
.
next_left
=
1
,
};
};
static
void
car0107_idle_lock
(
void
)
static
void
car0107_idle_lock
(
void
)
...
@@ -67,16 +62,6 @@ static int car0107_idle_pool_init(void)
...
@@ -67,16 +62,6 @@ static int car0107_idle_pool_init(void)
return
0
;
return
0
;
}
}
static
void
car0107_idle_nudge_steering
(
int
turn_left
)
{
int
angle
=
turn_left
?
CAR0107_IDLE_STEER_LEFT
:
CAR0107_IDLE_STEER_RIGHT
;
/* 速度 PWM 只由持有0107硬件锁的控制路径写,idle线程不直接碰速度。 */
car0107_steering_set_angle_sync
(
angle
);
delay_ms
(
CAR0107_IDLE_STEER_HOLD_MS
);
car0107_steering_set_angle_sync
(
90
);
}
static
void
car0107_idle_monitor_task
(
void
*
arg
)
static
void
car0107_idle_monitor_task
(
void
*
arg
)
{
{
(
void
)
arg
;
(
void
)
arg
;
...
@@ -85,7 +70,6 @@ static void car0107_idle_monitor_task(void *arg)
...
@@ -85,7 +70,6 @@ static void car0107_idle_monitor_task(void *arg)
while
(
!
car0107_idle_shutdown_get
())
{
while
(
!
car0107_idle_shutdown_get
())
{
long
long
now
;
long
long
now
;
long
long
last
;
long
long
last
;
int
turn_left
;
delay_ms
(
CAR0107_IDLE_CHECK_MS
);
delay_ms
(
CAR0107_IDLE_CHECK_MS
);
if
(
car0107_idle_shutdown_get
()
||
g_device_type
!=
DEVICE_CAR0107
)
{
if
(
car0107_idle_shutdown_get
()
||
g_device_type
!=
DEVICE_CAR0107
)
{
...
@@ -101,15 +85,10 @@ static void car0107_idle_monitor_task(void *arg)
...
@@ -101,15 +85,10 @@ static void car0107_idle_monitor_task(void *arg)
continue
;
continue
;
}
}
car0107_idle_lock
();
my_zlog_info
(
"car0107 idle %dmin: wakeup maneuver (reverse->forward->brake)"
,
turn_left
=
s_idle_ctx
.
next_left
;
CAR0107_IDLE_TIMEOUT_MS
/
60000
);
s_idle_ctx
.
next_left
=
!
s_idle_ctx
.
next_left
;
/* 低速后退一点 -> 低速前进一点 -> 前进刹车停止(遵守刹车动作)*/
car0107_idle_unlock
();
car0107_idle_wakeup_maneuver
();
my_zlog_info
(
"car0107 idle %dmin: nudge steer %s"
,
CAR0107_IDLE_TIMEOUT_MS
/
60000
,
turn_left
?
"left"
:
"right"
);
car0107_idle_nudge_steering
(
turn_left
);
car0107_notify_control_activity
();
car0107_notify_control_activity
();
}
}
...
@@ -133,7 +112,7 @@ void car0107_idle_startup(int device_id)
...
@@ -133,7 +112,7 @@ void car0107_idle_startup(int device_id)
car0107_idle_unlock
();
car0107_idle_unlock
();
car0107_notify_control_activity
();
car0107_notify_control_activity
();
my_zlog_info
(
"car0107 idle monitor enabled:
steer nudge
every %dmin when idle"
,
my_zlog_info
(
"car0107 idle monitor enabled:
wakeup maneuver
every %dmin when idle"
,
CAR0107_IDLE_TIMEOUT_MS
/
60000
);
CAR0107_IDLE_TIMEOUT_MS
/
60000
);
}
}
...
...
drivers/sensors/audioplay.c.bak.20260710_111731
deleted
100644 → 0
View file @
3585cc8c
This diff is collapsed.
Click to expand it.
modules/webrtcpush/mpp_h264_source.c
View file @
055aa314
...
@@ -73,6 +73,8 @@ struct MppH264Source {
...
@@ -73,6 +73,8 @@ struct MppH264Source {
guint8
*
jpeg_tmp_v
;
guint8
*
jpeg_tmp_v
;
size_t
jpeg_tmp_capacity
;
size_t
jpeg_tmp_capacity
;
guint
keyframe_req
;
guint
keyframe_req
;
gint
pending_bitrate_bps
;
guint
applied_bitrate_bps
;
volatile
gboolean
pending_idr
;
volatile
gboolean
pending_idr
;
gboolean
pending_idr_event_sent
;
gboolean
pending_idr_event_sent
;
gint64
last_keyframe_event_us
;
gint64
last_keyframe_event_us
;
...
@@ -104,6 +106,7 @@ static gboolean pull_sample(MppH264Source *src, gboolean require_idr,
...
@@ -104,6 +106,7 @@ static gboolean pull_sample(MppH264Source *src, gboolean require_idr,
size_t
*
size
,
gboolean
*
is_idr
,
size_t
*
size
,
gboolean
*
is_idr
,
guint64
*
pts_ns
);
guint64
*
pts_ns
);
static
gboolean
send_force_key_unit
(
MppH264Source
*
src
);
static
gboolean
send_force_key_unit
(
MppH264Source
*
src
);
static
void
apply_pending_bitrate
(
MppH264Source
*
src
);
static
gpointer
mjpeg_decode_thread
(
gpointer
user_data
);
static
gpointer
mjpeg_decode_thread
(
gpointer
user_data
);
static
void
timing_mark_encoder_in
(
MppH264Source
*
src
,
guint64
pts_ns
,
static
void
timing_mark_encoder_in
(
MppH264Source
*
src
,
guint64
pts_ns
,
gint64
enc_in_us
);
gint64
enc_in_us
);
...
@@ -1648,6 +1651,9 @@ gboolean mpp_h264_source_pull(MppH264Source *src, gboolean force_idr,
...
@@ -1648,6 +1651,9 @@ gboolean mpp_h264_source_pull(MppH264Source *src, gboolean force_idr,
if
(
!
src
||
!
src
->
appsink
||
!
data
||
!
size
)
if
(
!
src
||
!
src
->
appsink
||
!
data
||
!
size
)
return
FALSE
;
return
FALSE
;
/* 编码帧之间应用动态码率,避免从 REMB/RTP 回调线程直接重配编码器。 */
apply_pending_bitrate
(
src
);
/* bus 报 ERROR 后 pipeline 卡死,这里及时恢复避免长期黑屏 */
/* bus 报 ERROR 后 pipeline 卡死,这里及时恢复避免长期黑屏 */
if
(
src
->
pending_recover
&&
mpp_h264_source_recover
(
src
))
{
if
(
src
->
pending_recover
&&
mpp_h264_source_recover
(
src
))
{
src
->
pending_idr
=
TRUE
;
src
->
pending_idr
=
TRUE
;
...
@@ -1676,7 +1682,7 @@ gboolean mpp_h264_source_pull(MppH264Source *src, gboolean force_idr,
...
@@ -1676,7 +1682,7 @@ gboolean mpp_h264_source_pull(MppH264Source *src, gboolean force_idr,
return
pull_sample
(
src
,
FALSE
,
timeout_ms
,
data
,
size
,
is_idr
,
pts_ns
);
return
pull_sample
(
src
,
FALSE
,
timeout_ms
,
data
,
size
,
is_idr
,
pts_ns
);
}
}
void
mpp_h264_source_set_bitrate
(
MppH264Source
*
src
,
guint
bitrate_bps
)
static
void
apply_bitrate_now
(
MppH264Source
*
src
,
guint
bitrate_bps
)
{
{
GstElementFactory
*
f
;
GstElementFactory
*
f
;
const
gchar
*
name
;
const
gchar
*
name
;
...
@@ -1710,6 +1716,36 @@ void mpp_h264_source_set_bitrate(MppH264Source *src, guint bitrate_bps)
...
@@ -1710,6 +1716,36 @@ void mpp_h264_source_set_bitrate(MppH264Source *src, guint bitrate_bps)
}
else
if
(
name
&&
g_str_has_prefix
(
name
,
"x264enc"
))
{
}
else
if
(
name
&&
g_str_has_prefix
(
name
,
"x264enc"
))
{
g_object_set
(
src
->
enc
,
"bitrate"
,
bitrate_bps
/
1000
,
NULL
);
g_object_set
(
src
->
enc
,
"bitrate"
,
bitrate_bps
/
1000
,
NULL
);
}
}
src
->
applied_bitrate_bps
=
bitrate_bps
;
my_zlog_info
(
"mpp_h264_source: bitrate applied at frame boundary %u kbps"
,
bitrate_bps
/
1000
);
}
static
void
apply_pending_bitrate
(
MppH264Source
*
src
)
{
gint
pending
;
if
(
!
src
)
return
;
pending
=
g_atomic_int_get
(
&
src
->
pending_bitrate_bps
);
if
(
pending
<=
0
||
!
g_atomic_int_compare_and_exchange
(
&
src
->
pending_bitrate_bps
,
pending
,
0
))
return
;
if
((
guint
)
pending
==
src
->
applied_bitrate_bps
)
return
;
apply_bitrate_now
(
src
,
(
guint
)
pending
);
}
void
mpp_h264_source_set_bitrate
(
MppH264Source
*
src
,
guint
bitrate_bps
)
{
if
(
!
src
||
!
bitrate_bps
)
return
;
if
(
bitrate_bps
<
MPP_VIDEO_MIN_BPS
)
bitrate_bps
=
MPP_VIDEO_MIN_BPS
;
if
(
bitrate_bps
>
MPP_VIDEO_MAX_BPS
)
bitrate_bps
=
MPP_VIDEO_MAX_BPS
;
g_atomic_int_set
(
&
src
->
pending_bitrate_bps
,
(
gint
)
bitrate_bps
);
}
}
gboolean
mpp_h264_source_recover
(
MppH264Source
*
src
)
gboolean
mpp_h264_source_recover
(
MppH264Source
*
src
)
...
...
modules/webrtcpush/rtc_client.c
View file @
055aa314
...
@@ -88,6 +88,8 @@ typedef struct {
...
@@ -88,6 +88,8 @@ typedef struct {
guint
last_remb_bitrate
;
guint
last_remb_bitrate
;
guint
remb_filtered
;
guint
remb_filtered
;
guint
remb_down_samples
;
guint
remb_down_samples
;
gboolean
initial_probe_complete
;
gint64
probe_target_reached_us
;
gint64
last_bitrate_ramp_us
;
gint64
last_bitrate_ramp_us
;
gint64
last_mpp_bitrate_apply_us
;
gint64
last_mpp_bitrate_apply_us
;
gint64
last_idr_request_us
;
gint64
last_idr_request_us
;
...
@@ -1021,6 +1023,7 @@ static void apply_bitrate(RtcClient *client, int track, guint bitrate)
...
@@ -1021,6 +1023,7 @@ static void apply_bitrate(RtcClient *client, int track, guint bitrate)
guint
b
;
guint
b
;
guint
old_b
;
guint
old_b
;
guint
old_mpp_b
;
guint
old_mpp_b
;
guint
mpp_apply_b
=
0
;
guint
mpp_delta
;
guint
mpp_delta
;
gint64
now_us
;
gint64
now_us
;
gint64
last_mpp_apply_us
;
gint64
last_mpp_apply_us
;
...
@@ -1039,11 +1042,25 @@ static void apply_bitrate(RtcClient *client, int track, guint bitrate)
...
@@ -1039,11 +1042,25 @@ static void apply_bitrate(RtcClient *client, int track, guint bitrate)
old_mpp_b
=
old_b
?
old_b
:
b
;
old_mpp_b
=
old_b
?
old_b
:
b
;
client
->
target_bitrate
=
b
;
client
->
target_bitrate
=
b
;
mpp_delta
=
bitrate_delta
(
old_mpp_b
,
b
);
mpp_delta
=
bitrate_delta
(
old_mpp_b
,
b
);
if
(
mpp_delta
>=
WEBRTCPUSH_MPP_RECONFIG_MIN_DELTA_BPS
&&
if
((
guint64
)
mpp_delta
*
100U
>=
(
guint64
)
old_mpp_b
*
WEBRTCPUSH_MPP_RECONFIG_MIN_DELTA_PERCENT
&&
now_us
-
last_mpp_apply_us
>=
now_us
-
last_mpp_apply_us
>=
(
gint64
)
WEBRTCPUSH_MPP_RECONFIG_MIN_INTERVAL_MS
*
1000
)
{
(
gint64
)
WEBRTCPUSH_MPP_RECONFIG_MIN_INTERVAL_MS
*
1000
)
{
apply_mpp
=
TRUE
;
apply_mpp
=
TRUE
;
client
->
applied_mpp_bitrate
=
b
;
mpp_apply_b
=
b
;
if
(
b
>
old_mpp_b
)
{
guint
max_up
=
(
guint
)(((
guint64
)
old_mpp_b
*
(
100U
+
WEBRTCPUSH_MPP_RECONFIG_MAX_STEP_PERCENT
))
/
100U
);
if
(
mpp_apply_b
>
max_up
)
mpp_apply_b
=
max_up
;
}
else
{
guint
min_down
=
(
guint
)(((
guint64
)
old_mpp_b
*
(
100U
-
WEBRTCPUSH_MPP_RECONFIG_MAX_STEP_PERCENT
))
/
100U
);
if
(
mpp_apply_b
<
min_down
)
mpp_apply_b
=
min_down
;
}
mpp_apply_b
=
clamp_bitrate
(
mpp_apply_b
);
client
->
applied_mpp_bitrate
=
mpp_apply_b
;
client
->
last_mpp_bitrate_apply_us
=
now_us
;
client
->
last_mpp_bitrate_apply_us
=
now_us
;
}
}
g_mutex_unlock
(
&
client
->
lock
);
g_mutex_unlock
(
&
client
->
lock
);
...
@@ -1058,12 +1075,13 @@ static void apply_bitrate(RtcClient *client, int track, guint bitrate)
...
@@ -1058,12 +1075,13 @@ static void apply_bitrate(RtcClient *client, int track, guint bitrate)
g_mutex_unlock
(
&
client
->
send_lock
);
g_mutex_unlock
(
&
client
->
send_lock
);
}
}
if
(
apply_mpp
)
{
if
(
apply_mpp
)
{
mpp_h264_source_set_bitrate
(
client
->
h264_source
,
b
);
/* 这里只投递原子目标;真正的 mpph264enc 属性更新在拉帧边界执行。 */
my_zlog_info
(
"libdatachannel: RTCP bitrate control -> target=%u->%u kbps, MPP=%u->%u kbps pacing=%u kbps"
,
mpp_h264_source_set_bitrate
(
client
->
h264_source
,
mpp_apply_b
);
old_b
/
1000
,
b
/
1000
,
old_mpp_b
/
1000
,
b
/
1000
,
my_zlog_info
(
"libdatachannel: bitrate control -> target=%u->%u kbps, MPP queued=%u->%u kbps pacing=%u kbps"
,
old_b
/
1000
,
b
/
1000
,
old_mpp_b
/
1000
,
mpp_apply_b
/
1000
,
pacing_bitrate_for_encoder
(
b
)
/
1000
);
pacing_bitrate_for_encoder
(
b
)
/
1000
);
}
else
{
}
else
{
my_zlog_info
(
"libdatachannel:
RTCP
bitrate control -> target=%u->%u kbps, MPP hold=%u kbps pacing=%u kbps"
,
my_zlog_info
(
"libdatachannel: bitrate control -> target=%u->%u kbps, MPP hold=%u kbps pacing=%u kbps"
,
old_b
/
1000
,
b
/
1000
,
old_mpp_b
/
1000
,
old_b
/
1000
,
b
/
1000
,
old_mpp_b
/
1000
,
pacing_bitrate_for_encoder
(
b
)
/
1000
);
pacing_bitrate_for_encoder
(
b
)
/
1000
);
}
}
...
@@ -1093,11 +1111,11 @@ static void ramp_bitrate_toward_ceiling(RtcClient *client, int track)
...
@@ -1093,11 +1111,11 @@ static void ramp_bitrate_toward_ceiling(RtcClient *client, int track)
return
;
/* confirmed decreases are applied by on_remb() */
return
;
/* confirmed decreases are applied by on_remb() */
diff
=
tgt
-
cur
;
diff
=
tgt
-
cur
;
step
=
(
guint
)(((
guint64
)
cur
*
12U
)
/
100U
);
step
=
(
guint
)(((
guint64
)
cur
*
WEBRTCPUSH_BITRATE_RAMP_UP_PERCENT
)
/
100U
);
if
(
step
<
50000U
)
if
(
step
<
WEBRTCPUSH_BITRATE_RAMP_UP_STEP_MIN_BPS
)
step
=
50000U
;
step
=
WEBRTCPUSH_BITRATE_RAMP_UP_STEP_MIN_BPS
;
if
(
step
>
250000U
)
if
(
step
>
WEBRTCPUSH_BITRATE_RAMP_UP_STEP_MAX_BPS
)
step
=
250000U
;
step
=
WEBRTCPUSH_BITRATE_RAMP_UP_STEP_MAX_BPS
;
if
(
step
>
diff
)
if
(
step
>
diff
)
step
=
diff
;
step
=
diff
;
next
=
cur
+
step
;
next
=
cur
+
step
;
...
@@ -1144,8 +1162,10 @@ static void RTC_API on_remb(int track, unsigned int bitrate, void *ptr)
...
@@ -1144,8 +1162,10 @@ static void RTC_API on_remb(int track, unsigned int bitrate, void *ptr)
gboolean
can_step_down
=
FALSE
;
gboolean
can_step_down
=
FALSE
;
gboolean
have_pacing
;
gboolean
have_pacing
;
gboolean
first_frame_sent
;
gboolean
first_frame_sent
;
gboolean
recent_idr
=
FALSE
;
gboolean
remb_sane_floor
=
FALSE
;
gboolean
remb_sane_floor
=
FALSE
;
gboolean
log_remb_sane_floor
=
FALSE
;
gboolean
log_remb_sane_floor
=
FALSE
;
gboolean
probe_completed_now
=
FALSE
;
guint
pacing_packets
=
0
;
guint
pacing_packets
=
0
;
guint
pacing_bytes
=
0
;
guint
pacing_bytes
=
0
;
guint
pacing_delay_ms
=
0
;
guint
pacing_delay_ms
=
0
;
...
@@ -1161,13 +1181,34 @@ static void RTC_API on_remb(int track, unsigned int bitrate, void *ptr)
...
@@ -1161,13 +1181,34 @@ static void RTC_API on_remb(int track, unsigned int bitrate, void *ptr)
g_mutex_lock
(
&
client
->
lock
);
g_mutex_lock
(
&
client
->
lock
);
current
=
client
->
target_bitrate
;
current
=
client
->
target_bitrate
;
first_frame_sent
=
client
->
first_frame_sent
;
first_frame_sent
=
client
->
first_frame_sent
;
recent_idr
=
client
->
last_idr_sent_us
>
0
&&
now_us
-
client
->
last_idr_sent_us
<
(
gint64
)
WEBRTCPUSH_REMB_IDR_GRACE_MS
*
1000
;
client
->
last_remb_bitrate
=
bitrate
;
client
->
last_remb_bitrate
=
bitrate
;
can_step_down
=
now_us
-
client
->
last_bitrate_ramp_us
>=
can_step_down
=
now_us
-
client
->
last_bitrate_ramp_us
>=
(
gint64
)
WEBRTCPUSH_BITRATE_RAMP_DOWN_MS
*
1000
;
(
gint64
)
WEBRTCPUSH_BITRATE_RAMP_DOWN_MS
*
1000
;
/*
* REMB 在低发送量时容易形成“低码率 -> 低估计 -> 永远无法探测”的闭环。
* 初次连接主动爬到健康探测目标并保持一段时间,让接收端用真实流量重新估计。
* 探测完成后仍保留“发送端受限”保护:pacing 健康时,低 REMB 只能阻止
* 继续上升,不能把发送量越压越低。只有持续积压且不在 IDR 窗口才允许下降。
*/
if
(
!
client
->
initial_probe_complete
)
{
if
(
current
+
WEBRTCPUSH_REMB_DOWN_MIN_STEP
>=
WEBRTCPUSH_HEALTHY_PROBE_TARGET_BPS
)
{
if
(
client
->
probe_target_reached_us
==
0
)
client
->
probe_target_reached_us
=
now_us
;
else
if
(
now_us
-
client
->
probe_target_reached_us
>=
(
gint64
)
WEBRTCPUSH_INITIAL_PROBE_HOLD_MS
*
1000
)
{
client
->
initial_probe_complete
=
TRUE
;
probe_completed_now
=
TRUE
;
}
}
}
estimate_bitrate
=
bitrate
;
estimate_bitrate
=
bitrate
;
if
(
first_frame_sent
&&
have_pacing
&&
if
(
first_frame_sent
&&
have_pacing
&&
bitrate
<
WEBRTCPUSH_REMB_SANE_RAW_MAX_BPS
&&
bitrate
<
WEBRTCPUSH_REMB_SANE_RAW_MAX_BPS
&&
pacing_delay_ms
<=
WEBRTCPUSH_REMB_SANE_PACING_MAX_MS
)
{
(
pacing_delay_ms
<=
WEBRTCPUSH_REMB_SANE_PACING_MAX_MS
||
recent_idr
)
)
{
estimate_bitrate
=
WEBRTCPUSH_REMB_SANE_FLOOR_BPS
;
estimate_bitrate
=
WEBRTCPUSH_REMB_SANE_FLOOR_BPS
;
remb_sane_floor
=
TRUE
;
remb_sane_floor
=
TRUE
;
if
(
client
->
last_remb_sane_log_us
==
0
||
if
(
client
->
last_remb_sane_log_us
==
0
||
...
@@ -1234,10 +1275,16 @@ static void RTC_API on_remb(int track, unsigned int bitrate, void *ptr)
...
@@ -1234,10 +1275,16 @@ static void RTC_API on_remb(int track, unsigned int bitrate, void *ptr)
}
}
g_mutex_unlock
(
&
client
->
lock
);
g_mutex_unlock
(
&
client
->
lock
);
if
(
probe_completed_now
)
{
my_zlog_info
(
"libdatachannel: initial bandwidth probe complete at %u kbps; steady sender-limited REMB guard enabled"
,
current
/
1000
);
}
if
(
log_remb_sane_floor
)
{
if
(
log_remb_sane_floor
)
{
my_zlog_info
(
"libdatachannel: RTCP REMB s
uspicious low raw=%u kbps, use=%u kbps (pacing=%u pkt/%u bytes/%ums
)"
,
my_zlog_info
(
"libdatachannel: RTCP REMB s
ender-limited raw=%u kbps, use=%u kbps (pacing=%u pkt/%u bytes/%ums idr_grace=%d
)"
,
bitrate
/
1000
,
estimate_bitrate
/
1000
,
bitrate
/
1000
,
estimate_bitrate
/
1000
,
pacing_packets
,
pacing_bytes
,
pacing_delay_ms
);
pacing_packets
,
pacing_bytes
,
pacing_delay_ms
,
recent_idr
?
1
:
0
);
}
}
if
(
next
)
{
if
(
next
)
{
...
@@ -1492,13 +1539,14 @@ static gpointer send_thread_main(gpointer data)
...
@@ -1492,13 +1539,14 @@ static gpointer send_thread_main(gpointer data)
actual_fps_x10
=
(
guint
)(((
guint64
)
sent_window_frames
*
10U
*
1000000U
)
/
actual_fps_x10
=
(
guint
)(((
guint64
)
sent_window_frames
*
10U
*
1000000U
)
/
elapsed_us
);
elapsed_us
);
}
}
my_zlog_info
(
"libdatachannel: stats encoder=%u actual_h264=%u kbps sent_fps=%u.%u raw_remb=%u filtered_remb=%u ceiling=%u kbps pacing=%u pkt/%u bytes/%ums queue_dropped=%u"
,
my_zlog_info
(
"libdatachannel: stats encoder=%u actual_h264=%u kbps sent_fps=%u.%u raw_remb=%u filtered_remb=%u ceiling=%u kbps pacing=%u pkt/%u bytes/%ums queue_dropped=%u
probe=%s
"
,
target_bps
/
1000
,
actual_kbps
,
target_bps
/
1000
,
actual_kbps
,
actual_fps_x10
/
10
,
actual_fps_x10
%
10
,
actual_fps_x10
/
10
,
actual_fps_x10
%
10
,
raw_remb_bps
/
1000
,
filtered_remb_bps
/
1000
,
raw_remb_bps
/
1000
,
filtered_remb_bps
/
1000
,
remb_bps
/
1000
,
remb_bps
/
1000
,
pacing_packets
,
pacing_bytes
,
pacing_delay_ms
,
pacing_packets
,
pacing_bytes
,
pacing_delay_ms
,
queue_dropped
);
queue_dropped
,
client
->
initial_probe_complete
?
"done"
:
"active"
);
send_datachannel_mbps
(
client
,
actual_kbps
);
send_datachannel_mbps
(
client
,
actual_kbps
);
/* 修复: MPP CBR失控时actual>>target, pacing必须跟actual否则永远堆积 */
/* 修复: MPP CBR失控时actual>>target, pacing必须跟actual否则永远堆积 */
if
(
actual_kbps
>
0
)
{
if
(
actual_kbps
>
0
)
{
...
@@ -1975,6 +2023,8 @@ int rtc_client_start(AppState *app)
...
@@ -1975,6 +2023,8 @@ int rtc_client_start(AppState *app)
client
->
target_bitrate
=
WEBRTCPUSH_INITIAL_BITRATE
;
client
->
target_bitrate
=
WEBRTCPUSH_INITIAL_BITRATE
;
client
->
applied_mpp_bitrate
=
WEBRTCPUSH_INITIAL_BITRATE
;
client
->
applied_mpp_bitrate
=
WEBRTCPUSH_INITIAL_BITRATE
;
client
->
remb_ceiling
=
WEBRTCPUSH_INITIAL_BITRATE
;
client
->
remb_ceiling
=
WEBRTCPUSH_INITIAL_BITRATE
;
client
->
initial_probe_complete
=
FALSE
;
client
->
probe_target_reached_us
=
0
;
client
->
last_remb_bitrate
=
0
;
client
->
last_remb_bitrate
=
0
;
client
->
remb_filtered
=
0
;
client
->
remb_filtered
=
0
;
client
->
remb_down_samples
=
0
;
client
->
remb_down_samples
=
0
;
...
@@ -2201,6 +2251,8 @@ int rtc_client_handle_offer(AppState *app, const char *sdp)
...
@@ -2201,6 +2251,8 @@ int rtc_client_handle_offer(AppState *app, const char *sdp)
client
->
target_bitrate
=
WEBRTCPUSH_INITIAL_BITRATE
;
client
->
target_bitrate
=
WEBRTCPUSH_INITIAL_BITRATE
;
client
->
applied_mpp_bitrate
=
WEBRTCPUSH_INITIAL_BITRATE
;
client
->
applied_mpp_bitrate
=
WEBRTCPUSH_INITIAL_BITRATE
;
client
->
remb_ceiling
=
WEBRTCPUSH_INITIAL_BITRATE
;
client
->
remb_ceiling
=
WEBRTCPUSH_INITIAL_BITRATE
;
client
->
initial_probe_complete
=
FALSE
;
client
->
probe_target_reached_us
=
0
;
client
->
last_remb_bitrate
=
0
;
client
->
last_remb_bitrate
=
0
;
client
->
remb_filtered
=
0
;
client
->
remb_filtered
=
0
;
client
->
remb_down_samples
=
0
;
client
->
remb_down_samples
=
0
;
...
...
modules/webrtcpush/webrtcpush_config.h
View file @
055aa314
...
@@ -8,7 +8,7 @@
...
@@ -8,7 +8,7 @@
*
*
* 原生分支:v4l2 采集 → mpph264enc(或 x264enc 回退)→ libdatachannel 发送。
* 原生分支:v4l2 采集 → mpph264enc(或 x264enc 回退)→ libdatachannel 发送。
*/
*/
#define WEBRTCPUSH_USE_MPP
0
#define WEBRTCPUSH_USE_MPP
1
/* 正常固定 24fps;弱网以降码率为主,后续若启用动态帧率也不得低于 22fps。 */
/* 正常固定 24fps;弱网以降码率为主,后续若启用动态帧率也不得低于 22fps。 */
#define WEBRTCPUSH_H264_FPS 24
#define WEBRTCPUSH_H264_FPS 24
...
@@ -22,24 +22,33 @@
...
@@ -22,24 +22,33 @@
*/
*/
#define WEBRTCPUSH_INITIAL_BITRATE 900000U
#define WEBRTCPUSH_INITIAL_BITRATE 900000U
#define WEBRTCPUSH_MIN_BITRATE 800000U
#define WEBRTCPUSH_MIN_BITRATE 800000U
#define WEBRTCPUSH_MAX_BITRATE
26
00000U
#define WEBRTCPUSH_MAX_BITRATE
30
00000U
#define WEBRTCPUSH_REMB_UTIL_PERCENT 80U
#define WEBRTCPUSH_REMB_UTIL_PERCENT 80U
#define WEBRTCPUSH_REMB_DOWN_MIN_STEP 100000U
#define WEBRTCPUSH_REMB_DOWN_MIN_STEP 100000U
#define WEBRTCPUSH_REMB_DOWN_CONFIRMATIONS 8U
#define WEBRTCPUSH_REMB_DOWN_CONFIRMATIONS 8U
#define WEBRTCPUSH_REMB_SEVERE_CONFIRMATIONS 2U
#define WEBRTCPUSH_REMB_SEVERE_CONFIRMATIONS 2U
#define WEBRTCPUSH_REMB_SEVERE_PERCENT 65U
#define WEBRTCPUSH_REMB_SEVERE_PERCENT 65U
#define WEBRTCPUSH_BITRATE_RAMP_UP_MS 1
8
00U
#define WEBRTCPUSH_BITRATE_RAMP_UP_MS 1
2
00U
#define WEBRTCPUSH_BITRATE_RAMP_DOWN_MS 2000U
#define WEBRTCPUSH_BITRATE_RAMP_DOWN_MS 2000U
#define WEBRTCPUSH_BITRATE_RAMP_UP_PERCENT 12U
#define WEBRTCPUSH_BITRATE_RAMP_UP_STEP_MIN_BPS 70000U
#define WEBRTCPUSH_BITRATE_RAMP_UP_STEP_MAX_BPS 250000U
#define WEBRTCPUSH_REMB_DOWN_STEP_PERCENT 10U
#define WEBRTCPUSH_REMB_DOWN_STEP_PERCENT 10U
#define WEBRTCPUSH_REMB_DOWN_STEP_MIN_BPS 60000U
#define WEBRTCPUSH_REMB_DOWN_STEP_MIN_BPS 60000U
#define WEBRTCPUSH_REMB_DOWN_STEP_MAX_BPS 120000U
#define WEBRTCPUSH_REMB_DOWN_STEP_MAX_BPS 120000U
/* REMB 低估保护:pacing 不堵时,过低浏览器估计不直接压糊 720p。 */
/* REMB 低估保护:pacing 不堵时,过低浏览器估计不直接压糊 720p。 */
#define WEBRTCPUSH_REMB_SANE_FLOOR_BPS 2200000U
#define WEBRTCPUSH_HEALTHY_PROBE_TARGET_BPS 2700000U
#define WEBRTCPUSH_REMB_SANE_RAW_MAX_BPS 1200000U
/* 3.375Mbps * 80% = 2.7Mbps. 这是 REMB 原始估计的探测地板,不是编码码率。 */
#define WEBRTCPUSH_REMB_SANE_FLOOR_BPS 3375000U
#define WEBRTCPUSH_REMB_SANE_RAW_MAX_BPS WEBRTCPUSH_REMB_SANE_FLOOR_BPS
#define WEBRTCPUSH_REMB_SANE_PACING_MAX_MS 100U
#define WEBRTCPUSH_REMB_SANE_PACING_MAX_MS 100U
#define WEBRTCPUSH_PACING_HEADROOM_PERCENT 180U
/* IDR 会产生短时大包,不能在这个窗口内把瞬时 pacing 峰值误判成网络拥塞。 */
#define WEBRTCPUSH_REMB_IDR_GRACE_MS 1000U
/* 达到 2.3Mbps 后继续发送一段时间,让浏览器有真实流量可重新估计带宽。 */
#define WEBRTCPUSH_INITIAL_PROBE_HOLD_MS 6000U
#define WEBRTCPUSH_PACING_HEADROOM_PERCENT 135U
#define WEBRTCPUSH_PACING_INTERVAL_MS 5U
#define WEBRTCPUSH_PACING_INTERVAL_MS 5U
#define WEBRTCPUSH_PACING_MAX_BITRATE 4
0
00000U
#define WEBRTCPUSH_PACING_MAX_BITRATE 4
2
00000U
#define WEBRTCPUSH_PACING_MAX_QUEUE_MS 260U
#define WEBRTCPUSH_PACING_MAX_QUEUE_MS 260U
#define WEBRTCPUSH_PACING_GUARD_COOLDOWN_MS 1000U
#define WEBRTCPUSH_PACING_GUARD_COOLDOWN_MS 1000U
/* 首个/刚恢复的 IDR 允许短暂排队,避免首屏关键帧刚发出就被清队列 */
/* 首个/刚恢复的 IDR 允许短暂排队,避免首屏关键帧刚发出就被清队列 */
...
@@ -48,8 +57,9 @@
...
@@ -48,8 +57,9 @@
#define WEBRTCPUSH_PACING_RESYNC_IDR_MS 5000U
#define WEBRTCPUSH_PACING_RESYNC_IDR_MS 5000U
/* RK MPP 运行中小幅改 bps 容易顿一下;小变化只调 pacing,少重配硬编。 */
/* RK MPP 运行中小幅改 bps 容易顿一下;小变化只调 pacing,少重配硬编。 */
#define WEBRTCPUSH_MPP_RECONFIG_MIN_DELTA_BPS 200000U
#define WEBRTCPUSH_MPP_RECONFIG_MIN_DELTA_PERCENT 20U
#define WEBRTCPUSH_MPP_RECONFIG_MIN_INTERVAL_MS 5000U
#define WEBRTCPUSH_MPP_RECONFIG_MAX_STEP_PERCENT 25U
#define WEBRTCPUSH_MPP_RECONFIG_MIN_INTERVAL_MS 1000U
/* RTP 分片与 NACK(MTU=1200,留 SRTP/DTLS/FU 余量) */
/* RTP 分片与 NACK(MTU=1200,留 SRTP/DTLS/FU 余量) */
#define WEBRTCPUSH_RTP_MAX_FRAGMENT 1050U
#define WEBRTCPUSH_RTP_MAX_FRAGMENT 1050U
...
...
zlog.conf
View file @
055aa314
...
@@ -9,4 +9,4 @@ file perms = 600
...
@@ -9,4 +9,4 @@ file perms = 600
millisecond
=
"%d(%Y-%m-%d %H:%M:%S).%ms [%V] %m%n"
millisecond
=
"%d(%Y-%m-%d %H:%M:%S).%ms [%V] %m%n"
[
rules
]
[
rules
]
my_log
.*
"/home/orangepi/car/master/log/log_2026-07-1
0
.log"
;
millisecond
my_log
.*
"/home/orangepi/car/master/log/log_2026-07-1
1
.log"
;
millisecond
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment