xref: /OK3568_Linux_fs/external/mpp/mpp/hal/common/h264/hal_h264e_stream_amend.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Copyright 2022 Rockchip Electronics Co. LTD
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define MODULE_TAG "hal_h264e_amend"
18 
19 #include <stdio.h>
20 #include <string.h>
21 #include <unistd.h>
22 #include "mpp_common.h"
23 #include "mpp_enc_cfg.h"
24 #include "mpp_enc_refs.h"
25 #include "mpp_mem.h"
26 #include "hal_h264e_debug.h"
27 #include "hal_h264e_stream_amend.h"
28 #include "h264e_sps.h"
29 #include "h264e_pps.h"
30 #include "h264e_slice.h"
31 
32 #define START_CODE 0x000001 ///< start_code_prefix_one_3bytes
33 
get_next_nal(RK_U8 * buf,RK_S32 * length)34 static RK_S32 get_next_nal(RK_U8 *buf, RK_S32 *length)
35 {
36     RK_S32 i, consumed = 0;
37     RK_S32 len = *length;
38     RK_U8 *tmp_buf = buf;
39 
40     /* search start code */
41     while (len >= 4) {
42         if (tmp_buf[2] == 0) {
43             len--;
44             tmp_buf++;
45             continue;
46         }
47 
48         if (tmp_buf[0] != 0 || tmp_buf[1] != 0 || tmp_buf[2] != 1) {
49             RK_U32 state = (RK_U32) - 1;
50             RK_S32 has_nal = 0;
51 
52             for (i = 0; i < (RK_S32)len; i++) {
53                 state = (state << 8) | tmp_buf[i];
54                 if (((state >> 8) & 0xFFFFFF) == START_CODE) {
55                     has_nal = 1;
56                     i = i - 3;
57                     break;
58                 }
59             }
60 
61             if (has_nal) {
62                 len -= i;
63                 tmp_buf += i;
64                 consumed = *length - len - 1;
65                 break;
66             }
67 
68             consumed = *length;
69             break;
70         }
71         tmp_buf   += 3;
72         len       -= 3;
73     }
74 
75     *length = *length - consumed;
76     return consumed;
77 }
78 
h264e_vepu_stream_amend_init(HalH264eVepuStreamAmend * ctx)79 MPP_RET h264e_vepu_stream_amend_init(HalH264eVepuStreamAmend *ctx)
80 {
81     memset(ctx, 0, sizeof(*ctx));
82     ctx->buf_size = SZ_128K;
83     return MPP_OK;
84 }
85 
h264e_vepu_stream_amend_deinit(HalH264eVepuStreamAmend * ctx)86 MPP_RET h264e_vepu_stream_amend_deinit(HalH264eVepuStreamAmend *ctx)
87 {
88     MPP_FREE(ctx->src_buf);
89     MPP_FREE(ctx->dst_buf);
90     return MPP_OK;
91 }
92 
h264e_vepu_stream_amend_config(HalH264eVepuStreamAmend * ctx,MppPacket packet,MppEncCfgSet * cfg,H264eSlice * slice,H264ePrefixNal * prefix)93 MPP_RET h264e_vepu_stream_amend_config(HalH264eVepuStreamAmend *ctx,
94                                        MppPacket packet, MppEncCfgSet *cfg,
95                                        H264eSlice *slice, H264ePrefixNal *prefix)
96 {
97     MppEncRefCfgImpl *ref = (MppEncRefCfgImpl *)cfg->ref_cfg;
98     MppEncH264Cfg    *h264 = &cfg->codec.h264;
99     MppEncH264HwCfg  *hw_cfg = &h264->hw_cfg;
100 
101     if (ref->lt_cfg_cnt || ref->st_cfg_cnt > 1 ||
102         hw_cfg->hw_poc_type != h264->poc_type ||
103         hw_cfg->hw_log2_max_frame_num_minus4 != h264->log2_max_frame_num) {
104         ctx->enable = 1;
105         ctx->slice_enabled = 0;
106         ctx->diable_split_out = 1;
107 
108         if (NULL == ctx->dst_buf)
109             ctx->dst_buf = mpp_calloc(RK_U8, ctx->buf_size);
110         if (NULL == ctx->src_buf)
111             ctx->src_buf = mpp_calloc(RK_U8, ctx->buf_size);
112     } else {
113         MPP_FREE(ctx->dst_buf);
114         MPP_FREE(ctx->src_buf);
115         h264e_vepu_stream_amend_init(ctx);
116     }
117 
118     slice->pic_order_cnt_type = cfg->codec.h264.poc_type;
119 
120     ctx->slice = slice;
121     if (ref->lt_cfg_cnt || ref->st_cfg_cnt > 1)
122         ctx->prefix = prefix;
123 
124     ctx->packet = packet;
125     ctx->buf_base = mpp_packet_get_length(packet);
126     ctx->old_length = 0;
127     ctx->new_length = 0;
128 
129     return MPP_OK;
130 }
131 
h264e_vepu_stream_amend_proc(HalH264eVepuStreamAmend * ctx,MppEncH264HwCfg * hw_cfg)132 MPP_RET h264e_vepu_stream_amend_proc(HalH264eVepuStreamAmend *ctx, MppEncH264HwCfg *hw_cfg)
133 {
134     H264ePrefixNal *prefix = ctx->prefix;
135     H264eSlice *slice = ctx->slice;
136     MppPacket pkt = ctx->packet;
137     RK_U8 *p = mpp_packet_get_pos(pkt);
138     RK_S32 size = mpp_packet_get_size(pkt);
139     RK_S32 base = ctx->buf_base;
140     RK_S32 len = ctx->old_length;
141     RK_S32 hw_len_bit = 0;
142     RK_S32 sw_len_bit = 0;
143     RK_S32 hw_len_byte = 0;
144     RK_S32 sw_len_byte = 0;
145     RK_S32 diff_size = 0;
146     RK_S32 tail_0bit = 0;
147     RK_U8  tail_byte = 0;
148     RK_U8  tail_tmp = 0;
149     RK_U8 *dst_buf = NULL;
150     RK_S32 buf_size;
151     RK_S32 final_len = 0;
152     RK_S32 last_slice = 0;
153     const MppPktSeg *seg = mpp_packet_get_segment_info(pkt);
154     if (seg) {
155         while (seg && seg->type != 1 && seg->type != 5) {
156             seg = seg->next;
157         }
158     }
159 
160     {
161         RK_S32 more_buf = 0;
162         while (len > ctx->buf_size - 16) {
163             ctx->buf_size *= 2;
164             more_buf = 1;
165         }
166 
167         if (more_buf) {
168             MPP_FREE(ctx->src_buf);
169             MPP_FREE(ctx->dst_buf);
170             ctx->src_buf = mpp_malloc(RK_U8, ctx->buf_size);
171             ctx->dst_buf = mpp_malloc(RK_U8, ctx->buf_size);
172         }
173     }
174 
175     memset(ctx->dst_buf, 0, ctx->buf_size);
176     memset(ctx->src_buf, 0, ctx->buf_size);
177     dst_buf = ctx->dst_buf;
178     buf_size = ctx->buf_size;
179     p += base;
180 
181     do {
182         RK_U32 nal_len = 0;
183         tail_0bit = 0;
184         // copy hw stream to stream buffer first
185         if (slice->is_multi_slice) {
186             if ((!seg) || ctx->diable_split_out) {
187                 nal_len = get_next_nal(p, &len);
188                 last_slice = (len == 0);
189             } else {
190                 nal_len = seg->len;
191                 len -= seg->len;
192                 seg = seg->next;
193                 if (!seg || !len)
194                     last_slice = 1;
195             }
196             memcpy(ctx->src_buf, p, nal_len);
197             p += nal_len;
198         } else {
199             memcpy(ctx->src_buf, p, len);
200             nal_len = len;
201             last_slice = 1;
202         }
203 
204         hal_h264e_dbg_amend("nal_len %d multi %d last %d prefix %p\n",
205                             nal_len, slice->is_multi_slice, last_slice, prefix);
206 
207         if (prefix) {
208             /* add prefix for each slice */
209             RK_S32 prefix_bit = h264e_slice_write_prefix_nal_unit_svc(prefix, dst_buf, buf_size);
210 
211             prefix_bit = (prefix_bit + 7) / 8;
212 
213             dst_buf += prefix_bit;
214             buf_size -= prefix_bit;
215             final_len += prefix_bit;
216         }
217 
218         H264eSlice slice_rd;
219 
220         memcpy(&slice_rd, slice, sizeof(slice_rd));
221 
222         /* update slice by hw_cfg */
223         slice_rd.pic_order_cnt_type = hw_cfg->hw_poc_type;
224         slice_rd.log2_max_frame_num = hw_cfg->hw_log2_max_frame_num_minus4 + 4;
225 
226         if (ctx->reorder) {
227             slice_rd.reorder = ctx->reorder;
228             h264e_reorder_init(slice_rd.reorder);
229         }
230         if (ctx->marking) {
231             slice_rd.marking = ctx->marking;
232             h264e_marking_init(slice_rd.marking);
233         }
234 
235         hw_len_bit = h264e_slice_read(&slice_rd, ctx->src_buf, size);
236 
237         // write new header to header buffer
238         slice->qp_delta = slice_rd.qp_delta;
239         slice->first_mb_in_slice = slice_rd.first_mb_in_slice;
240 
241         if (ctx->reorder)
242             slice->reorder = slice_rd.reorder;
243         if (ctx->marking)
244             slice->marking = slice_rd.marking;
245 
246         sw_len_bit = h264e_slice_write(slice, dst_buf, buf_size);
247 
248         hw_len_byte = (hw_len_bit + 7) / 8;
249         sw_len_byte = (sw_len_bit + 7) / 8;
250 
251         tail_byte = ctx->src_buf[nal_len - 1];
252         tail_tmp = tail_byte;
253 
254         while (!(tail_tmp & 1) && tail_0bit < 8) {
255             tail_tmp >>= 1;
256             tail_0bit++;
257         }
258 
259         mpp_assert(tail_0bit < 8);
260 
261         // move the reset slice data from src buffer to dst buffer
262         diff_size = h264e_slice_move(dst_buf, ctx->src_buf,
263                                      sw_len_bit, hw_len_bit, nal_len);
264 
265         hal_h264e_dbg_amend("tail 0x%02x %d hw_hdr %d sw_hdr %d len %d hw_byte %d sw_byte %d diff %d\n",
266                             tail_byte, tail_0bit, hw_len_bit, sw_len_bit, nal_len, hw_len_byte, sw_len_byte, diff_size);
267 
268         if (slice->entropy_coding_mode) {
269             memcpy(dst_buf + sw_len_byte, ctx->src_buf + hw_len_byte,
270                    nal_len - hw_len_byte);
271             final_len += nal_len - hw_len_byte + sw_len_byte;
272             nal_len = nal_len - hw_len_byte + sw_len_byte;
273         } else {
274             RK_S32 hdr_diff_bit = sw_len_bit - hw_len_bit;
275             RK_S32 bit_len = nal_len * 8 - tail_0bit + hdr_diff_bit;
276             RK_S32 new_len = (bit_len + diff_size * 8 + 7) / 8;
277 
278             hal_h264e_dbg_amend("frm %4d %c len %d bit hw %d sw %d byte hw %d sw %d diff %d -> %d\n",
279                                 slice->frame_num, (slice->idr_flag ? 'I' : 'P'),
280                                 nal_len, hw_len_bit, sw_len_bit,
281                                 hw_len_byte, sw_len_byte, diff_size, new_len);
282 
283             hal_h264e_dbg_amend("%02x %02x %02x %02x -> %02x %02x %02x %02x\n",
284                                 ctx->src_buf[nal_len - 4], ctx->src_buf[nal_len - 3],
285                                 ctx->src_buf[nal_len - 2], ctx->src_buf[nal_len - 1],
286                                 dst_buf[new_len - 4], dst_buf[new_len - 3],
287                                 dst_buf[new_len - 2], dst_buf[new_len - 1]);
288             nal_len = new_len;
289             final_len += new_len;
290         }
291 
292         if (last_slice) {
293             p = mpp_packet_get_pos(pkt);
294             p += base;
295             memcpy(p, ctx->dst_buf, final_len);
296 
297             if (slice->entropy_coding_mode) {
298                 if (final_len < ctx->old_length)
299                     memset(p + final_len, 0,  ctx->old_length - final_len);
300             } else
301                 p[final_len] = 0;
302 
303             break;
304         }
305 
306         dst_buf += nal_len;
307         buf_size -= nal_len;
308     } while (1);
309 
310     ctx->new_length = final_len;
311 
312     return MPP_OK;
313 }
314 
h264e_vepu_stream_amend_sync_ref_idc(HalH264eVepuStreamAmend * ctx)315 MPP_RET h264e_vepu_stream_amend_sync_ref_idc(HalH264eVepuStreamAmend *ctx)
316 {
317     H264eSlice *slice = ctx->slice;
318     MppPacket pkt = ctx->packet;
319     RK_S32 base = ctx->buf_base;
320     RK_S32 len = ctx->old_length;
321     RK_U8 *p = mpp_packet_get_pos(pkt) + base;
322     RK_U8 val = p[4];
323     RK_S32 hw_nal_ref_idc = (val >> 5) & 0x3;
324     RK_S32 sw_nal_ref_idc = slice->nal_reference_idc;
325 
326     if (hw_nal_ref_idc == sw_nal_ref_idc)
327         return MPP_OK;
328 
329     /* fix nal_ref_idc in all slice */
330     if (!slice->is_multi_slice) {
331         /* single slice do NOT scan */
332         val = val & (~0x60);
333         val |= (sw_nal_ref_idc << 5) & 0x60;
334         p[4] = val;
335         return MPP_OK;
336     }
337 
338     /* multi-slice fix each nal_ref_idc */
339     do {
340         RK_U32 nal_len = get_next_nal(p, &len);
341 
342         val = p[4];
343         val = val & (~0x60);
344         val |= (sw_nal_ref_idc << 5) & 0x60;
345         p[4] = val;
346 
347         if (len == 0)
348             break;
349 
350         p += nal_len;
351     } while (1);
352 
353     return MPP_OK;
354 }
355