Skip to content

Two packet/buffer lifecycle fixes (encoder persistent packet, decoder input packet ownership) - #968

Open
wangjiamingg wants to merge 3985 commits into
rockchip-linux:developfrom
wangjiamingg:fix/packet-buffer-lifecycle
Open

Two packet/buffer lifecycle fixes (encoder persistent packet, decoder input packet ownership)#968
wangjiamingg wants to merge 3985 commits into
rockchip-linux:developfrom
wangjiamingg:fix/packet-buffer-lifecycle

Conversation

@wangjiamingg

Copy link
Copy Markdown

Two packet/buffer lifecycle fixes (encoder persistent packet, decoder input packet ownership)

Hi,

While chasing a ~1.3 GB/day memory leak in a long-running kiosk product
(RK3588, GStreamer + MPP decode/encode pipelines restarted every few
seconds), we found two lifecycle issues in MPP core. Both are fixed
locally and verified in production for several days.

Patch 1: mpp_enc_impl — stale buffer ref in persistent encoder packet

mpp_enc_check_pkt_buf() assigns pkt->buffer = buffer directly. For
the sync path, enc->packet is a persistent packet reused across
frames, so this raw assignment drops the previous frame's MppBuffer
reference every frame → one leaked MppBuffer per encoded frame.

Fix: use mpp_packet_set_buffer(), which puts the previously attached
buffer before attaching the new one. Teardown behaviour is unchanged.

Repro: any long-running encode (h264/h265) with frequent start/stop;
buffer-group usage grows linearly before, flat after.

Patch 2: mpp_dec_normal — single-owner transfer of input packet to frame meta

When the decoded output frame carries KEY_INPUT_PACKET so that the
consumer can release the bitstream buffer, dec->mpp_pkt_in still owns
the same packet. dec_release_input_packet() can then deinit it a
second time after the consumer already did ("found non-positive
ref_count" on the packet's MppBuffer, then crash).

MppPacket has no inc_ref API and MppMeta set/get copies raw pointers
without touching refcounts, so the only safe hand-off is a single-owner
transfer: clear dec->mpp_pkt_in right after attaching the packet to
the output frame meta.

Repro: decode where the consumer reads KEY_INPUT_PACKET back from the
output frame meta and deinits it (e.g. gstreamer-rockchip drain path);
per-packet alloc/free accounting shows double deinit before, balanced
after.

Both fixes are independent of each other; happy to split/rework as
preferred.

Yanjun Liao and others added 30 commits November 5, 2025 09:08
Use 64-bit literals in bit operations to prevent overflow
when singleton module ID >= 32.

Change-Id: Ib08190bbcbb1a0b46559ea3c2ae57d801b5efadf
Signed-off-by: Yanjun Liao <yanjun.liao@rock-chips.com>
Add dup function for mpp_frame and mpp_meta.
NOTE: The buffer in MppFrame is not dup.

Signed-off-by: Herman Chen <herman.chen@rock-chips.com>
Change-Id: I4965bc6016c8ffca4b72bbd49e2653eab06c7591
When vproc create new output buffer with hdr_info the original hdr_info
in old buffer must be copy to the new one with hdr_offset and hdr_size.

Signed-off-by: Herman Chen <herman.chen@rock-chips.com>
Change-Id: I7cbfec07adf2de8147f2918332e391074291e4c5
If packet is splited outside of mpp and video_sequence_start_code is not
guaranteed, there will not be valid NALS. Thus segment fault will
happen.

Change-Id: Idb5e51772384c6663260d382b94845a8e1ac7c35
Signed-off-by: Johnson Ding <johnson.ding@rock-chips.com>
Change-Id: Ifa84dda229711e9af31967b1a57936079da3bb3a
Signed-off-by: Yanjun Liao <yanjun.liao@rock-chips.com>
fixes c6fa4c9

/usr/lib/gcc-cross/aarch64-linux-gnu/14/../../../../aarch64-linux-gnu/bin/ld: .../lib/librockchip_mpp.so: undefined reference to `log2'
/usr/lib/gcc-cross/aarch64-linux-gnu/14/../../../../aarch64-linux-gnu/bin/ld: .../lib/librockchip_mpp.so: undefined reference to `sincos'
/usr/lib/gcc-cross/aarch64-linux-gnu/14/../../../../aarch64-linux-gnu/bin/ld: .../lib/librockchip_mpp.so: undefined reference to `log'
/usr/lib/gcc-cross/aarch64-linux-gnu/14/../../../../aarch64-linux-gnu/bin/ld: .../lib/librockchip_mpp.so: undefined reference to `pow'

Signed-off-by: nyanmisaka <nst799610810@gmail.com>
Change-Id: I3bda683c4a468b66bc2d7cd84765a89c86e0d9e0
Add aligned(4) to packed structs for alignment.
Tests prove memory usage and performance unaffected.

kernel spcae patch: https://10.10.10.29/c/rk/mpp/+/280064

Change-Id: I23e4c77042721550934962530667d2abc19701d2
Signed-off-by: Yanjun Liao <yanjun.liao@rock-chips.com>
Change-Id: I01d20443cb80b65d156ff2e9f4f7467c4e9446f8
Signed-off-by: xueman.ruan <xueman.ruan@rock-chips.com>
Spec: avs2
Error Case:
Buffers were cleared and re-import when seeking,
ref_base registers carrys old task's buffer fd.
If new task after seeking with no ref frame or ref num
less than old task, will occur dma_buf import issue

Error Log:
[64248.193315][ T4180] mpp_dma_import_fd:224: dma_buf_get fd 126 failed(-9)
[64248.193378][ T4180] rk_vcodec: mpp_task_attach_fd:1841: can't import dma-buf 126
[64248.193394][ T4180] rk_vcodec: mpp_translate_reg_address:1898: reg[165]: 0x0000007e fd 126 failed

Signed-off-by: Chandler Chen <chandler.chen@rock-chips.com>
Change-Id: I446a6f0a4d646fe67af544bfb5400f4a03b27937
1. Align register and structure naming to kmpp
2. Align parameters to kmpp

Change-Id: I9dfbf409fb7c0575462aa7b6107edb362d1c1595
Signed-off-by: Yanjun Liao <yanjun.liao@rock-chips.com>
Change-Id: Ibbf7a35f7f6ca01a613d24d6e01e665361808d94
Signed-off-by: Lankun Lin <lankun.lin@rock-chips.com>
Signed-off-by: Yanjun Liao <yanjun.liao@rock-chips.com>
Change-Id: I404f50950e2934a3d4db66b75751c1e3b84d5c4d
Signed-off-by: Johnson Ding <johnson.ding@rock-chips.com>
GDR decoding faile due to registers configuration breaked by error
reference frame index checking, although disable_error is set.
The issue is introduced by 5f20063.

Change-Id: Iab181d92ad30332f68735cd5500cae1175dbc418
Signed-off-by: Johnson Ding <johnson.ding@rock-chips.com>
Change-Id: Ic4d81241cc0ae4d2dc98ad9f394ad32dcbb0a18d
Signed-off-by: Johnson Ding <johnson.ding@rock-chips.com>
1. Avoid mutual dependencies using forward declaration.
2. remove some unused dependencies

Change-Id: Idb9007dfd107695470ac69cb8afb11ec221e97bb
Signed-off-by: Johnson Ding <johnson.ding@rock-chips.com>
Change-Id: I91a3ae0c65c18ce60b759a22cfb767088e19ed01
Signed-off-by: Johnson Ding <johnson.ding@rock-chips.com>
'#define' and 'undef' shall not be used on a reserved identifier or
reserved macro name.

Change-Id: I5e9633df20b013f3a1686dba3200885e65f5371b
Signed-off-by: Johnson Ding <johnson.ding@rock-chips.com>
Change-Id: Icd1fab0435f3a756be44090c63078a88f7bf0458
Signed-off-by: Johnson Ding <johnson.ding@rock-chips.com>
Serverity level: 2

Function should not declared with an empty parameter list.
"void" should not be omitted when defining a function with no
parameters.

Change-Id: Id2a14d64827e46c050d46e6d0ff003c7897d5f2e
Signed-off-by: Johnson Ding <johnson.ding@rock-chips.com>
Signed-off-by: Chandler Chen <chandler.chen@rock-chips.com>
Change-Id: I68be40f20fd930300809c67dc46f0d833aa85774
The dynamic data maynot carried in every frame,
so it is neccessary to keep the dynamic data.

Change-Id: If6ca0964eb8679134dff128e7dbde7a8a6285069
Signed-off-by: Yandong Lin <yandong.lin@rock-chips.com>
Platform: All
Format: HEVC

Error log:
H265D_PARSER: hevc_frame_start found two frame in one packet do nothing
!
Cause:
split_nal_units() doesn't detect frame boundaries,
processes all NALs causing multi-frame in single iteration.

Solution:
Check first_slice_segment_in_pic_flag in VCL NALs,
break loop when new frame start found

Change-Id: I79a14e5505f2447d766ee66eb81b4741a6d74094
Signed-off-by: Yanjun Liao <yanjun.liao@rock-chips.com>
The extra data(sps/pps) will be lost when the following flow occur:
push extra data -> reset -> push idr data.

Change-Id: I886cd38888050b505dc597a3759f80657a3fa66a
Signed-off-by: Chen Jinsen <kevin.chen@rock-chips.com>
Signed-off-by: Yandong Lin <yandong.lin@rock-chips.com>
Change-Id: I9c397c658998270c318b4c4bfd1fb1481149272f
Change-Id: Ia75de3e19d6025eb826aa934f5e02db24785041e
Signed-off-by: Xiaoxu Chen <xiaoxu.chen@rock-chips.com>
Change-Id: I499246c4670f02a81d413515e376a54d6304232e
Signed-off-by: Xiaoxu Chen <xiaoxu.chen@rock-chips.com>
Change-Id: I291e68da76a0317d3c97288d0290342596af7ae5
Signed-off-by: Xiaoxu Chen <xiaoxu.chen@rock-chips.com>
Change-Id: I8330005ca017c2731b1c202d7bba3a8169d5acdf
Signed-off-by: Xiaoxu Chen <xiaoxu.chen@rock-chips.com>
Change-Id: I2339d314225d324b687e94c6b13a1e96189eeff6
Signed-off-by: Xiaoxu Chen <xiaoxu.chen@rock-chips.com>
Change-Id: Ia1e09ce5875095651fcca7c767b9b7db9279c81e
Signed-off-by: Xiaoxu Chen <xiaoxu.chen@rock-chips.com>
HermanChen and others added 29 commits February 13, 2026 05:56
When stream data is corrupted (e.g., during seeking), extract_length
may become a large negative value like -1347309641 (0xAFAFFB11).
Signed comparison treats negative values as less than positive length,
bypassing the check and causing memcpy to crash with SIGSEGV.

Restore the unsigned cast to correctly detect invalid NAL lengths
from corrupted input data.

Signed-off-by: Herman Chen <herman.chen@rock-chips.com>
Change-Id: I7b447c23a278954d392bc16f7aa771fd49a9ab1f
Change-Id: I1d2198b422293e822e6bfe81d2d554bd82ef9338
Signed-off-by: Yanjun Liao <yanjun.liao@rock-chips.com>
Platform: RK3288/RK3399/RK322X/RK332X which use rkv as H.265 decoder
Spec: h265

Error case:
Bug in introduced in commit:
fix[h265d]: Modify RefPicList array size to 16
When parser found error frame and assignment the array[15] as the
recovery frame the rkv hal driver had only 15 address register. The
recovery frame info will overflow to next register value and corrupt the
frame pixel data.

Err log:
No not but output data is corrupted.

Solution:
Use rkv register number as the loop limit.

Source: video_h265_1920x1080.mkv

Signed-off-by: Herman Chen <herman.chen@rock-chips.com>
Change-Id: I5e1162ec0b9d16d0284b4e7ae934cb7f89bbd0b6
Set tile output with -f 0x2000000.

Change-Id: If4fb2d0ff0b3247563a1a8f1b6d553ef664c22c9
Signed-off-by: Hongjin Li <vic.hong@rock-chips.com>
pu8_inter_interpolation_num_big_lvl and
pu32_inter_interpolation_num_small_lvl should be 0 or 1.

Change-Id: I98c3a1cd5b2d2583a4d4c25313a868bdd9d571e9
Signed-off-by: timkingh.huang <timkingh.huang@rock-chips.com>
1. support loglevel change dynamically
2. eliminate unused-parameter warning
3. update libvdpp version to v1.4.1

Change-Id: Ice164d580cba2ed60b9b24df43249d7b570246fa
Signed-off-by: vance.wu <vance.wu@rock-chips.com>
The frame parallel encoding with task_cnt > 1 is not required on
RK3572/RV1126B platforms. Simplify the HAL context by using single
fixed buffers instead of dynamically indexed arrays.

Changes:
- Replace ext_line_bufs[] with single ext_line_buf
- Replace regs_sets[] with single regs_set pointer
- Convert amend_sets pointer to embedded amend struct
- Remove prefix_sets/slice_sets dynamic allocation
- Remove task_idx rotation and reg_idx tracking
- Remove conditional TSVC async encoding block

This reduces memory footprint and simplifies code flow.

Platform: RK3572/RV1126B
Spec: h264/h265

Change-Id: I505bc840bbcf1979e13b55c38c65bca49153297a
Signed-off-by: Yanjun Liao <yanjun.liao@rock-chips.com>
Use last_frame_type instead of last_frame_fb.frame_type for
colmv_load_hevc judgment.

Change-Id: I5546c9691f550bdb25c8f71a6b890c1c0f2b34fc
Signed-off-by: Yanjun Liao <yanjun.liao@rock-chips.com>
Change-Id: I49812e1a9ac1c201001c172ca59d5434e9a674de
Signed-off-by: Xiaoxu Chen <xiaoxu.chen@rock-chips.com>
Change-Id: I9381dc0ffff4014d1fd675067e45ae06db0fbff7
Signed-off-by: Xiaoxu Chen <xiaoxu.chen@rock-chips.com>
Signed-off-by: Xiaoxu Chen <xiaoxu.chen@rock-chips.com>
Change-Id: Ic0b809430f142a91ace83a9b678fb63105188cfe
Add ELEM_TYPE_arr, ELEM_TYPE_s8, ELEM_TYPE_u8 to ElemType enum

Change-Id: I5afe39046de1904a8c72ca3a687a0f816a2681f8
Signed-off-by: Xiaoxu Chen <xiaoxu.chen@rock-chips.com>
Adapter ELEM_TYPE_s8, ELEM_TYPE_u8, ELEM_TYPE_arr

Change-Id: I2ff4ca0d5a9d5312d2d3e43a5d8c83cb78d41824
Signed-off-by: Xiaoxu Chen <xiaoxu.chen@rock-chips.com>
Change-Id: Idae4a676aaf493c83cc090f057d1f7d423d9cb65
Signed-off-by: Xiaoxu Chen <xiaoxu.chen@rock-chips.com>
The array is arranged with 8 elements per row

Change-Id: I25a4dd3bd73ee6dd70a09ddd023d6676d92d098e
Signed-off-by: Xiaoxu Chen <xiaoxu.chen@rock-chips.com>
Add test cases for new array type support:
- test_typed_arrays: s8/u8/s16/u16/s64/u64/bool/string arrays
- test_object_array: array of objects with multiple fields
- test_nested_array: nested 2D arrays
- test file input with JSON/TOML format auto-detection

Signed-off-by: Herman Chen <herman.chen@rock-chips.com>
Change-Id: I72979954a8c07c740dd461989dcdf939f09170f6
In TSVC scenarios, dual-core frame parallel encoding was timing out
because DCHS synchronization IDs did not follow the frame reference
chain. Correcting this mapping ensures proper hardware handshakes
across temporal layers.

Change-Id: I4735fc291a7fd170ec6417149f17dc08af0d2fe4
Signed-off-by: Chandler.Chen <chandler.chen@rock-chips.com>
Change-Id: I89290be67cd67bfbe7b6e2177d13a886c5836d99
Signed-off-by: timkingh.huang <timkingh.huang@rock-chips.com>
Change-Id: I124de97072a592260427d7f1333152f0fbc6a98b
Signed-off-by: timkingh.huang <timkingh.huang@rock-chips.com>
Change-Id: I2038320d1d5c9ad884f785789e468eb191f8eba5
Signed-off-by: timkingh.huang <timkingh.huang@rock-chips.com>
Platform: all
Spec: h265

Error case:
The hdr meta storage is a global buffer all frame level storage save the
pointer. When next frame's hdr meta is larger than previous one the old
buffer will be released and alloc a new one. But the previous frame
still use the old pointer. So it is a used-after-free issue.

Error log:
backtrace:
      #00 pc 000000000005fb4c  /apex/com.android.runtime/lib64/bionic/libc.so
      rockchip-linux#1 pc 0000000000165e48  /system/lib64/libmpp.so (fill_hdr_meta_to_frame+1332)
      rockchip-linux#2 pc 00000000001c46a4  /system/lib64/libmpp.so (try_proc_dec_task+3544)
      rockchip-linux#3 pc 00000000001c2fb0  /system/lib64/libmpp.so (mpp_dec_parser_thread+724)
      rockchip-linux#4 pc 00000000000cb6a8  /apex/com.android.runtime/lib64/bionic/libc.so
      rockchip-linux#5 pc 000000000006821c  /apex/com.android.runtime/lib64/bionic/libc.so

Solution:
Add hdr meta storage pool module and use storage index to refer the
buffer.

Source: H265-209-Everest.ts

Signed-off-by: Herman Chen <herman.chen@rock-chips.com>
Change-Id: I7f0c2bc021366eeddaa026ee96bee116d5f98252
Signed-off-by: Herman Chen <herman.chen@rock-chips.com>
Change-Id: If381fc96c19db30098fed37c5aee8148936e6ff9
Platform: General
Spec: jpegd

Error case:
in: yuvj444p
out: yuv420

Repro Cmd:
gst-launch-1.0 videotestsrc ! 'video/x-raw,width=4096,height=2160' ! jpegenc ! jpegparse ! mppjpegdec ! fakesink

Err log:
mpp_dec: Assertion slot_size <= buffer_size failed at mpp_dec_advanced_thread:1049
mpp_dec: mpp_dec_advanced_thread required buffer size 26542080 is larger than input buffer size 17694720

Solution:
Synchronize the user-configured output format to jpegd_parser.

Reported-by: Jianfei Chen <jeffy.chen@rock-chips.com>

Change-Id: I46abecca31386bbe70ced57eda10c75a91825935
Signed-off-by: Hongjin Li <vic.hong@rock-chips.com>
Optimize buffer management and enable fast parse
on vdpu383 and vdpu384b platforms.

Change-Id: Ia2d49159f2d1680211652b1386b8f83135be951e
Signed-off-by: Hongjin Li <vic.hong@rock-chips.com>
Change-Id: Ib09d1ef7c4a438b2549ddc890e22d5a06e82c360
Signed-off-by: timkingh.huang <timkingh.huang@rock-chips.com>
Change-Id: Icad644e678bbcdd08de9ecb1e3df9c13e5e53d91
Signed-off-by: timkingh.huang <timkingh.huang@rock-chips.com>
Change-Id: I08bc66cc93ba0fe41f613062c785355c3cd8e653
Signed-off-by: timkingh.huang <timkingh.huang@rock-chips.com>
…packet

In the sync encode path, enc->packet is a persistent packet reused
across frames. mpp_enc_check_pkt_buf() assigned pkt->buffer directly,
silently dropping the reference held by the previous frame's buffer and
leaking one MppBuffer per encoded frame.

Use mpp_packet_set_buffer() so the previously attached buffer is put
before the new one is attached; the final buffer is still released once
at encoder teardown through mpp_packet_deinit().

Reproduction: run an encoder for several hours with frequent start/stop
cycles; before this change RSS grows linearly with buffer-group usage,
after it stays flat.

Signed-off-by: wangjiamingg <wangjiamingg@users.noreply.github.com>
When the decoded output frame carries KEY_INPUT_PACKET in its meta so
that the consumer can release the bitstream buffer, dec->mpp_pkt_in
still owns the same packet. dec_release_input_packet() could then deinit
it a second time after the meta consumer already did ('found
non-positive ref_count' on the packet's MppBuffer, followed by crash).

MppPacket has no inc_ref API and MppMeta set/get copies raw pointers
without touching refcounts, so the only safe hand-off is a single-owner
transfer: clear dec->mpp_pkt_in right after attaching the packet to the
output frame meta.

Verified with per-packet alloc/free accounting (PKT_NEW vs PKT_DEINIT)
over 1820 packets: balanced after the change.

Signed-off-by: wangjiamingg <wangjiamingg@users.noreply.github.com>
@FumasterLin

Copy link
Copy Markdown
Contributor

Thanks for digging into the packet lifecycle! After a careful review against the current code, we don't think these two issues
exist. Details below.

  1. mpp_enc_impl: the buffer leak does not exist, and the fix would introduce one

The direct assignment pkt->buffer = buffer in mpp_enc_check_pkt_buf() only runs when enc->pkt_buf == NULL. This invariant guarantees the packet never holds an old buffer at that point:

• mpp_enc_check_frm_pkt() re-derives enc->pkt_buf from mpp_packet_get_buffer(enc->packet) at the beginning of every task, so the two are always in sync;
• reset_enc_task() clears enc->packet after every terminated task, so each frame starts with a fresh packet from mpp_packet_new().
The "persistent packet reused across frames" scenario described in the commit message cannot be constructed in this code.

More importantly, the proposed change is a leak in the opposite direction: mpp_packet_set_buffer() calls mpp_buffer_inc_ref() on the new buffer, but the reference returned by mpp_buffer_get() is never put. With the patch applied, every newly created output buffer would gain a net +1 reference and never return to the buffer group — which produces exactly the linear RSS growth described in the commit message. If you measured RSS growth before and flat RSS after, the root cause was likely something else.

  1. mpp_dec_normal: the double-free does not exist

dec->mpp_pkt_in is only used by the parser-thread mode (try_get_input_packet() / try_proc_dec_task(), called from
mpp_dec_parser_thread()). The only place that attaches KEY_INPUT_PACKET to a frame meta is mpp_dec_advanced_thread(). The two modes are mutually exclusive (either parser+hal threads, or the advanced thread), so dec->mpp_pkt_in can never alias the packet in the advanced thread, and dec_release_input_packet() cannot deinit the same packet twice.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.