Skip to content

Commit 12a27f3

Browse files
authored
[Rust]Ported AVC Module to Rust (#1730)
* AVC Module: ported AVC Module to Rust * AVC module: Minor semantic changes * AVC Module: Failing CI * AVC Module: SIMD Optimisations * AVC Module: Optimization in SEI * AVC Module: removed panic
1 parent ba59eb0 commit 12a27f3

File tree

11 files changed

+2315
-378
lines changed

11 files changed

+2315
-378
lines changed

src/lib_ccx/avc_functions.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,14 @@ void do_NAL(struct encoder_ctx *enc_ctx, struct lib_cc_decode *dec_ctx, unsigned
147147

148148
// Process inbuf bytes in buffer holding and AVC (H.264) video stream.
149149
// The number of processed bytes is returned.
150+
#ifndef DISABLE_RUST
151+
size_t ccxr_process_avc(struct encoder_ctx *enc_ctx, struct lib_cc_decode *dec_ctx, unsigned char *avcbuf, size_t avcbuflen, struct cc_subtitle *sub);
152+
#endif
150153
size_t process_avc(struct encoder_ctx *enc_ctx, struct lib_cc_decode *dec_ctx, unsigned char *avcbuf, size_t avcbuflen, struct cc_subtitle *sub)
151154
{
155+
#ifndef DISABLE_RUST
156+
return ccxr_process_avc(enc_ctx, dec_ctx, avcbuf, avcbuflen, sub);
157+
#else
152158
unsigned char *buffer_position = avcbuf;
153159
unsigned char *NAL_start;
154160
unsigned char *NAL_stop;
@@ -250,6 +256,7 @@ size_t process_avc(struct encoder_ctx *enc_ctx, struct lib_cc_decode *dec_ctx, u
250256
}
251257

252258
return avcbuflen;
259+
#endif
253260
}
254261

255262
#define ZEROBYTES_SHORTSTARTCODE 2

src/rust/build.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ fn main() {
1313
"version",
1414
"set_binary_mode",
1515
"net_send_header", // shall be removed after NET
16+
"realloc",
17+
"anchor_hdcc",
18+
"process_hdcc",
19+
"store_hdcc",
1620
"write_spumux_footer",
1721
"write_spumux_header",
1822
]);

src/rust/lib_ccxr/src/common/constants.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ pub const UTF8_MAX_BYTES: usize = 6;
155155
pub const XMLRPC_CHUNK_SIZE: usize = 64 * 1024; // 64 Kb per chunk, to avoid too many realloc()
156156

157157
// AVC NAL types
158+
#[derive(Debug, Eq, PartialEq)]
158159
pub enum AvcNalType {
159160
Unspecified0 = 0,
160161
CodedSliceNonIdrPicture1 = 1,

src/rust/src/avc/common_types.rs

Lines changed: 311 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,311 @@
1+
use crate::avc::FromCType;
2+
use crate::bindings::*;
3+
use crate::common::CType;
4+
5+
pub const ZEROBYTES_SHORTSTARTCODE: i32 = 2;
6+
pub const AVC_CC_DATA_INITIAL_SIZE: usize = 1024;
7+
pub const MAXBFRAMES: i32 = 50;
8+
9+
#[derive(Debug, Clone)]
10+
pub struct AvcContextRust {
11+
pub cc_count: u8,
12+
pub cc_data: Vec<u8>,
13+
pub cc_databufsize: usize,
14+
pub cc_buffer_saved: bool,
15+
16+
pub got_seq_para: bool,
17+
pub nal_ref_idc: u32,
18+
pub seq_parameter_set_id: i64,
19+
pub log2_max_frame_num: i32,
20+
pub pic_order_cnt_type: i32,
21+
pub log2_max_pic_order_cnt_lsb: i32,
22+
pub frame_mbs_only_flag: bool,
23+
24+
// Statistics for debugging
25+
pub num_nal_unit_type_7: i64,
26+
pub num_vcl_hrd: i64,
27+
pub num_nal_hrd: i64,
28+
pub num_jump_in_frames: i64,
29+
pub num_unexpected_sei_length: i64,
30+
31+
pub ccblocks_in_avc_total: i32,
32+
pub ccblocks_in_avc_lost: i32,
33+
34+
pub frame_num: i64,
35+
pub lastframe_num: i64,
36+
pub currref: i32,
37+
pub maxidx: i32,
38+
pub lastmaxidx: i32,
39+
40+
// Used to find tref zero in PTS mode
41+
pub minidx: i32,
42+
pub lastminidx: i32,
43+
44+
// Used to remember the max temporal reference number (poc mode)
45+
pub maxtref: i32,
46+
pub last_gop_maxtref: i32,
47+
48+
// Used for PTS ordering of CC blocks
49+
pub currefpts: i64,
50+
pub last_pic_order_cnt_lsb: i64,
51+
pub last_slice_pts: i64,
52+
}
53+
54+
impl Default for AvcContextRust {
55+
fn default() -> Self {
56+
AvcContextRust {
57+
cc_count: 0,
58+
cc_data: Vec::with_capacity(1024),
59+
cc_databufsize: 1024,
60+
cc_buffer_saved: true,
61+
62+
got_seq_para: false,
63+
nal_ref_idc: 0,
64+
seq_parameter_set_id: 0,
65+
log2_max_frame_num: 0,
66+
pic_order_cnt_type: 0,
67+
log2_max_pic_order_cnt_lsb: 0,
68+
frame_mbs_only_flag: false,
69+
70+
num_nal_unit_type_7: 0,
71+
num_vcl_hrd: 0,
72+
num_nal_hrd: 0,
73+
num_jump_in_frames: 0,
74+
num_unexpected_sei_length: 0,
75+
76+
ccblocks_in_avc_total: 0,
77+
ccblocks_in_avc_lost: 0,
78+
79+
frame_num: -1,
80+
lastframe_num: -1,
81+
currref: 0,
82+
maxidx: -1,
83+
lastmaxidx: -1,
84+
85+
minidx: 10000,
86+
lastminidx: 10000,
87+
88+
maxtref: 0,
89+
last_gop_maxtref: 0,
90+
91+
currefpts: 0,
92+
last_pic_order_cnt_lsb: -1,
93+
last_slice_pts: -1,
94+
}
95+
}
96+
}
97+
98+
impl FromCType<avc_ctx> for AvcContextRust {
99+
unsafe fn from_ctype(ctx: avc_ctx) -> Option<Self> {
100+
// Convert cc_data from C pointer to Vec
101+
let cc_data = if !ctx.cc_data.is_null() && ctx.cc_databufsize > 0 {
102+
std::slice::from_raw_parts(ctx.cc_data, ctx.cc_databufsize as usize).to_vec()
103+
} else {
104+
Vec::with_capacity(1024)
105+
};
106+
107+
Some(AvcContextRust {
108+
cc_count: ctx.cc_count,
109+
cc_data,
110+
cc_databufsize: ctx.cc_databufsize as usize,
111+
cc_buffer_saved: ctx.cc_buffer_saved != 0,
112+
113+
got_seq_para: ctx.got_seq_para != 0,
114+
nal_ref_idc: ctx.nal_ref_idc,
115+
seq_parameter_set_id: ctx.seq_parameter_set_id,
116+
log2_max_frame_num: ctx.log2_max_frame_num,
117+
pic_order_cnt_type: ctx.pic_order_cnt_type,
118+
log2_max_pic_order_cnt_lsb: ctx.log2_max_pic_order_cnt_lsb,
119+
frame_mbs_only_flag: ctx.frame_mbs_only_flag != 0,
120+
121+
num_nal_unit_type_7: ctx.num_nal_unit_type_7 as _,
122+
num_vcl_hrd: ctx.num_vcl_hrd as _,
123+
num_nal_hrd: ctx.num_nal_hrd as _,
124+
num_jump_in_frames: ctx.num_jump_in_frames as _,
125+
num_unexpected_sei_length: ctx.num_unexpected_sei_length as _,
126+
127+
ccblocks_in_avc_total: ctx.ccblocks_in_avc_total,
128+
ccblocks_in_avc_lost: ctx.ccblocks_in_avc_lost,
129+
130+
frame_num: ctx.frame_num,
131+
lastframe_num: ctx.lastframe_num,
132+
currref: ctx.currref,
133+
maxidx: ctx.maxidx,
134+
lastmaxidx: ctx.lastmaxidx,
135+
136+
minidx: ctx.minidx,
137+
lastminidx: ctx.lastminidx,
138+
139+
maxtref: ctx.maxtref,
140+
last_gop_maxtref: ctx.last_gop_maxtref,
141+
142+
currefpts: ctx.currefpts,
143+
last_pic_order_cnt_lsb: ctx.last_pic_order_cnt_lsb,
144+
last_slice_pts: ctx.last_slice_pts,
145+
})
146+
}
147+
}
148+
149+
impl CType<avc_ctx> for AvcContextRust {
150+
unsafe fn to_ctype(&self) -> avc_ctx {
151+
// Allocate cc_data buffer
152+
let cc_data_ptr = if !self.cc_data.is_empty() {
153+
let data_box = self.cc_data.clone().into_boxed_slice();
154+
Box::into_raw(data_box) as *mut u8
155+
} else {
156+
std::ptr::null_mut()
157+
};
158+
159+
avc_ctx {
160+
cc_count: self.cc_count,
161+
cc_data: cc_data_ptr,
162+
cc_databufsize: self.cc_databufsize as _,
163+
cc_buffer_saved: if self.cc_buffer_saved { 1 } else { 0 },
164+
165+
got_seq_para: if self.got_seq_para { 1 } else { 0 },
166+
nal_ref_idc: self.nal_ref_idc,
167+
seq_parameter_set_id: self.seq_parameter_set_id,
168+
log2_max_frame_num: self.log2_max_frame_num,
169+
pic_order_cnt_type: self.pic_order_cnt_type,
170+
log2_max_pic_order_cnt_lsb: self.log2_max_pic_order_cnt_lsb,
171+
frame_mbs_only_flag: if self.frame_mbs_only_flag { 1 } else { 0 },
172+
173+
num_nal_unit_type_7: self.num_nal_unit_type_7 as _,
174+
num_vcl_hrd: self.num_vcl_hrd as _,
175+
num_nal_hrd: self.num_nal_hrd as _,
176+
num_jump_in_frames: self.num_jump_in_frames as _,
177+
num_unexpected_sei_length: self.num_unexpected_sei_length as _,
178+
179+
ccblocks_in_avc_total: self.ccblocks_in_avc_total,
180+
ccblocks_in_avc_lost: self.ccblocks_in_avc_lost,
181+
182+
frame_num: self.frame_num,
183+
lastframe_num: self.lastframe_num,
184+
currref: self.currref,
185+
maxidx: self.maxidx,
186+
lastmaxidx: self.lastmaxidx,
187+
188+
minidx: self.minidx,
189+
lastminidx: self.lastminidx,
190+
191+
maxtref: self.maxtref,
192+
last_gop_maxtref: self.last_gop_maxtref,
193+
194+
currefpts: self.currefpts,
195+
last_pic_order_cnt_lsb: self.last_pic_order_cnt_lsb,
196+
last_slice_pts: self.last_slice_pts,
197+
}
198+
}
199+
}
200+
201+
// SEI payload types
202+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
203+
#[repr(u32)]
204+
pub enum SeiPayloadType {
205+
BufferingPeriod = 0,
206+
PicTiming = 1,
207+
PanScanRect = 2,
208+
FillerPayload = 3,
209+
UserDataRegisteredItuTT35 = 4,
210+
UserDataUnregistered = 5,
211+
RecoveryPoint = 6,
212+
DecRefPicMarkingRepetition = 7,
213+
SparePic = 8,
214+
SceneInfo = 9,
215+
SubSeqInfo = 10,
216+
SubSeqLayerCharacteristics = 11,
217+
SubSeqCharacteristics = 12,
218+
FullFrameFreeze = 13,
219+
FullFrameFreezeRelease = 14,
220+
FullFrameSnapshot = 15,
221+
ProgressiveRefinementSegmentStart = 16,
222+
ProgressiveRefinementSegmentEnd = 17,
223+
MotionConstrainedSliceGroupSet = 18,
224+
FilmGrainCharacteristics = 19,
225+
DeblockingFilterDisplayPreference = 20,
226+
StereoVideoInfo = 21,
227+
}
228+
229+
impl From<u32> for SeiPayloadType {
230+
fn from(value: u32) -> Self {
231+
match value {
232+
0 => SeiPayloadType::BufferingPeriod,
233+
1 => SeiPayloadType::PicTiming,
234+
2 => SeiPayloadType::PanScanRect,
235+
3 => SeiPayloadType::FillerPayload,
236+
4 => SeiPayloadType::UserDataRegisteredItuTT35,
237+
5 => SeiPayloadType::UserDataUnregistered,
238+
6 => SeiPayloadType::RecoveryPoint,
239+
7 => SeiPayloadType::DecRefPicMarkingRepetition,
240+
8 => SeiPayloadType::SparePic,
241+
9 => SeiPayloadType::SceneInfo,
242+
10 => SeiPayloadType::SubSeqInfo,
243+
11 => SeiPayloadType::SubSeqLayerCharacteristics,
244+
12 => SeiPayloadType::SubSeqCharacteristics,
245+
13 => SeiPayloadType::FullFrameFreeze,
246+
14 => SeiPayloadType::FullFrameFreezeRelease,
247+
15 => SeiPayloadType::FullFrameSnapshot,
248+
16 => SeiPayloadType::ProgressiveRefinementSegmentStart,
249+
17 => SeiPayloadType::ProgressiveRefinementSegmentEnd,
250+
18 => SeiPayloadType::MotionConstrainedSliceGroupSet,
251+
19 => SeiPayloadType::FilmGrainCharacteristics,
252+
20 => SeiPayloadType::DeblockingFilterDisplayPreference,
253+
21 => SeiPayloadType::StereoVideoInfo,
254+
_ => SeiPayloadType::UserDataUnregistered, // Default fallback
255+
}
256+
}
257+
}
258+
// NAL unit types from H.264 standard
259+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
260+
#[repr(u8)]
261+
pub enum NalUnitType {
262+
Unspecified = 0,
263+
CodedSliceNonIdr = 1,
264+
CodedSliceDataPartitionA = 2,
265+
CodedSliceDataPartitionB = 3,
266+
CodedSliceDataPartitionC = 4,
267+
CodedSliceIdr = 5,
268+
Sei = 6,
269+
SequenceParameterSet = 7,
270+
PictureParameterSet = 8,
271+
AccessUnitDelimiter = 9,
272+
EndOfSequence = 10,
273+
EndOfStream = 11,
274+
FillerData = 12,
275+
SequenceParameterSetExtension = 13,
276+
PrefixNalUnit = 14,
277+
SubsetSequenceParameterSet = 15,
278+
DepthParameterSet = 16,
279+
// 17-18 reserved
280+
CodedSliceAuxiliary = 19,
281+
CodedSliceExtension = 20,
282+
// 21-23 reserved
283+
// 24-31 unspecified
284+
}
285+
286+
impl From<u8> for NalUnitType {
287+
fn from(value: u8) -> Self {
288+
match value {
289+
0 => NalUnitType::Unspecified,
290+
1 => NalUnitType::CodedSliceNonIdr,
291+
2 => NalUnitType::CodedSliceDataPartitionA,
292+
3 => NalUnitType::CodedSliceDataPartitionB,
293+
4 => NalUnitType::CodedSliceDataPartitionC,
294+
5 => NalUnitType::CodedSliceIdr,
295+
6 => NalUnitType::Sei,
296+
7 => NalUnitType::SequenceParameterSet,
297+
8 => NalUnitType::PictureParameterSet,
298+
9 => NalUnitType::AccessUnitDelimiter,
299+
10 => NalUnitType::EndOfSequence,
300+
11 => NalUnitType::EndOfStream,
301+
12 => NalUnitType::FillerData,
302+
13 => NalUnitType::SequenceParameterSetExtension,
303+
14 => NalUnitType::PrefixNalUnit,
304+
15 => NalUnitType::SubsetSequenceParameterSet,
305+
16 => NalUnitType::DepthParameterSet,
306+
19 => NalUnitType::CodedSliceAuxiliary,
307+
20 => NalUnitType::CodedSliceExtension,
308+
_ => NalUnitType::Unspecified,
309+
}
310+
}
311+
}

0 commit comments

Comments
 (0)