libxcoder 5.8.0
Loading...
Searching...
No Matches
mctf.c
Go to the documentation of this file.
1#include "../build/xcoder_auto_headers.h"
2
3#ifdef NI_HAVE_MCTF
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7#include <stdint.h>
8#include <stdbool.h>
9#include <math.h>
10#include <assert.h>
11#include <time.h>
12#include <sys/time.h>
13
14#include <unistd.h>
15#include "mctf.h"
16#include "ni_mctf.h"
17#include "ni_log.h"
18#include "ni_util.h"
19
20#define MCTF_PERIOD 4
21#define WINDOW_SIZE (MCTF_LOOKBACK + 1 + MCTF_LOOKAHEAD)
22static const int lookback = MCTF_LOOKBACK;
23static const int lookahead = MCTF_LOOKAHEAD;
24
25typedef struct MCTFContext {
26 ni_frame_t frameBuffer[MCTF_LOOKAHEAD];
27 uint64_t frame_number;
28 void *mctf_handle;
29} MCTFContext;
30
31static void copy_ni_frame(ni_frame_t* dst, ni_frame_t* src)
32{
33 void *p_metadata_buffer = dst->p_metadata_buffer;
34 uint8_t separate_metadata = src->separate_metadata;
35 uint8_t separate_start = (src->separate_start && src->total_start_len) ? 1 : 0;
36 if (separate_metadata) {
37 if ((p_metadata_buffer == NULL) ||
39 {
40 if (p_metadata_buffer)
41 free(p_metadata_buffer);
42
43 if (ni_posix_memalign(&p_metadata_buffer, sysconf(_SC_PAGESIZE), src->metadata_buffer_size))
44 {
45 ni_log(NI_LOG_ERROR, "ERROR: memory allocation failed for metadata buffer\n");
46 return;
47 }
48 }
49 memcpy(p_metadata_buffer, src->p_metadata_buffer, src->metadata_buffer_size);
50 }
51
52 void* p_start_buffer = dst->p_start_buffer;
53 if (separate_start) {
54 if ((dst->p_start_buffer == NULL) ||
56 {
57 if (dst->p_start_buffer)
58 free(dst->p_start_buffer);
59
60 if (ni_posix_memalign(&p_start_buffer, sysconf(_SC_PAGESIZE), src->start_buffer_size))
61 {
62 ni_log(NI_LOG_ERROR, "ERROR: memory allocation failed for start buffer\n");
63 return;
64 }
65 }
66 memcpy(p_start_buffer, src->p_start_buffer, src->start_buffer_size);
67 }
68
69 void* frame_buffer = dst->p_buffer;
70 if (frame_buffer == NULL || dst->buffer_size < src->buffer_size)
71 {
72 if (frame_buffer)
73 free(frame_buffer);
74 if (ni_posix_memalign(&frame_buffer, sysconf(_SC_PAGESIZE), src->buffer_size))
75 {
76 ni_log(NI_LOG_ERROR, "ERROR: memory allocation failed for frame buffer\n");
77 return;
78 }
79 }
80 uint32_t frame_size_bytes = src->data_len[0] + src->data_len[1] + src->data_len[2] + src->data_len[3] + src->extra_data_len;
81 memcpy(frame_buffer, src->p_buffer, frame_size_bytes);
82
83 memcpy(dst, src, sizeof(ni_frame_t));
84 dst->p_buffer = (uint8_t*)frame_buffer;
85 dst->p_metadata_buffer = (uint8_t*)p_metadata_buffer;
86 dst->p_start_buffer = (uint8_t*)p_start_buffer;
87 if (src->p_data[0] != NULL)
88 dst->p_data[0] = dst->p_buffer + (src->p_data[0] - src->p_buffer);
89 if (src->p_data[1] != NULL)
90 dst->p_data[1] = dst->p_buffer + (src->p_data[1] - src->p_buffer);
91 if (src->p_data[2] != NULL)
92 dst->p_data[2] = dst->p_buffer + (src->p_data[2] - src->p_buffer);
93 if (src->p_data[3] != NULL)
94 dst->p_data[3] = dst->p_buffer + (src->p_data[3] - src->p_buffer);
95}
96
97int performMCTF(ni_session_context_t *p_ctx, ni_frame_t *ni_frame, int32_t source_width, int32_t source_height)
98{
99 int ret = 0;
100 int is_ref = 0;
101 int mctf_filter_poc = 0;
102 MCTFContext *ctx = (MCTFContext *)(p_ctx->mctf);
103 if (ni_frame->end_of_stream) {
104 if (p_ctx->frame_num < ctx->frame_number) {
105 return MCTF_RET_EOS_PENDING;
106 } else {
107 return MCTF_RET_EOS_DONE;
108 }
109 }
110
111 // check if current pic needs copy
112 mctf_filter_poc = ni_mctf_get_filter_poc(ctx->mctf_handle);
113 if ((ctx->frame_number >= mctf_filter_poc && ctx->frame_number - mctf_filter_poc <= lookahead) ||
114 (ctx->frame_number < mctf_filter_poc && mctf_filter_poc - ctx->frame_number <= lookback)) {
115 is_ref = true;
116 }
117
118 if (is_ref) {
119 //construct niYUVFrame from ni_frame_t
120 niYUVFrame ref_frame;
121 int plane_stride[4] = {0};
122 int plane_height[4] = {0};
123
124 memset(&ref_frame, 0, sizeof(niYUVFrame));
125 ni_get_hw_yuv420p_dim(source_width, source_height, 1, 0, plane_stride, plane_height);
126 for (int i = 0; i < 3; i++) {
127 ref_frame.planes[i].ptr = ni_frame->p_data[i];
128 ref_frame.planes[i].width = source_width;
129 ref_frame.planes[i].height = plane_height[i];
130 ref_frame.planes[i].stride = plane_stride[i];
131
132 if (i > 0) {
133 ref_frame.planes[i].width /= 2;
134 }
135 }
136
137 //frame will be buffered in the internally specified YUV layout
138 //once the frames collected are ready, the MCTF filter process will be performed
139 ni_mctf_buffer_ref_frame(ctx->mctf_handle, &ref_frame, ctx->frame_number);
140
141 if ((ctx->frame_number >= mctf_filter_poc) && (ctx->frame_number - mctf_filter_poc < lookahead)) {
142 // need to wait for future reference frames
143 // buffer current frame
144 int idx = (ctx->frame_number - mctf_filter_poc);
145 copy_ni_frame(&(ctx->frameBuffer[idx]), ni_frame);
146 ret = MCTF_RET_BUFFERED;
147 } else if (ctx->frame_number == (mctf_filter_poc + lookahead)) {
148 // do MCTF now
149 niYUVFrame filtered_frame;
150 memset(&filtered_frame, 0, sizeof(niYUVFrame));
151
152 for (int i = 0; i < 3; i++) {
153 filtered_frame.planes[i].ptr = ctx->frameBuffer[0].p_data[i];
154 filtered_frame.planes[i].width = source_width;
155 filtered_frame.planes[i].height = plane_height[i];
156 filtered_frame.planes[i].stride = plane_stride[i];
157
158 if (i > 0) {
159 filtered_frame.planes[i].width /= 2;
160 }
161 }
162
163 ni_mctf_process_directly (ctx->mctf_handle, &filtered_frame);
164 ret = MCTF_RET_FILTERED;
165 } else {
166 ret = MCTF_RET_LOOKBACK_REF;
167 }
168 } else {
169 ret = MCTF_RET_NOT_REF;
170 }
171
172 ctx->frame_number++;
173
174 return ret;
175}
176
177ni_frame_t* get_mctf_result(ni_session_context_t *p_ctx, int waitCnt)
178{
179 MCTFContext *ctx = (MCTFContext *)(p_ctx->mctf);
180 if (waitCnt > 0) {
181 int idx = lookahead - waitCnt;
182 if (ctx && ctx->frameBuffer[idx].p_buffer) {
183 ni_frame_t *result_frame = &(ctx->frameBuffer[idx]);
184 return result_frame;
185 }
186 }
187 return NULL; // No result available
188}
189
190int initMCTF(ni_session_context_t *p_ctx)
191{
192 MCTFContext *ctx = (MCTFContext *)calloc(1, sizeof(MCTFContext));
193 if (!ctx) {
194 return -1; // Memory allocation failed
195 }
196
197 ctx->mctf_handle = ni_mctf_handle_create();
198 if (!ctx->mctf_handle) {
199 free(ctx);
200 return -1; // MCTF handle allocation failed
201 }
202
203 if (!ni_mctf_initialize(ctx->mctf_handle, p_ctx->active_video_width, p_ctx->active_video_height,
204 MCTF_PERIOD, MCTF_LOOKBACK, MCTF_LOOKAHEAD, WINDOW_SIZE)) {
205 ni_mctf_handle_release(ctx->mctf_handle);
206 free(ctx);
207 return -1; // init failed
208 }
209
210 ni_log(NI_LOG_INFO, "MCTF init, wxh %dx%d\n", p_ctx->active_video_width, p_ctx->active_video_height);
211 p_ctx->mctf = ctx;
212
213 return 0;
214}
215
216void clearMCTF(ni_session_context_t *p_ctx)
217{
218 if (p_ctx->mctf) {
219 MCTFContext *ctx = (MCTFContext *)p_ctx->mctf;
220 for (int i = 0; i < lookahead; i++) {
221 ni_frame_buffer_free(&(ctx->frameBuffer[i]));
222 }
223 ni_mctf_handle_release(ctx->mctf_handle);
224 free(p_ctx->mctf);
225 p_ctx->mctf = NULL;
226 }
227}
228#endif
ni_retcode_t ni_frame_buffer_free(ni_frame_t *p_frame)
Free frame buffer that was previously allocated with either ni_frame_buffer_alloc or ni_encoder_frame...
void ni_log(ni_log_level_t level, const char *fmt,...)
print log message using ni_log_callback
Definition ni_log.c:183
Logging definitions.
@ NI_LOG_ERROR
Definition ni_log.h:62
@ NI_LOG_INFO
Definition ni_log.h:63
int ni_posix_memalign(void **memptr, size_t alignment, size_t size)
Allocate aligned memory.
Definition ni_util.c:206
void ni_get_hw_yuv420p_dim(int width, int height, int factor, int is_semiplanar, int plane_stride[NI_MAX_NUM_DATA_POINTERS], int plane_height[NI_MAX_NUM_DATA_POINTERS])
Get dimension information of Netint HW YUV420p frame to be sent to encoder for encoding....
Definition ni_util.c:2743
Utility definitions.
uint32_t data_len[NI_MAX_NUM_DATA_POINTERS]
uint8_t * p_buffer
uint32_t start_buffer_size
uint32_t end_of_stream
uint8_t separate_metadata
uint32_t metadata_buffer_size
uint8_t * p_data[NI_MAX_NUM_DATA_POINTERS]
uint32_t total_start_len
unsigned int extra_data_len
uint8_t * p_start_buffer
uint32_t buffer_size
uint8_t separate_start
uint8_t * p_metadata_buffer