23.06.15
DEVOTEE를 활성화 시키면
지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.
버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.
| 컨텐츠 유형 | 제목 | 저장일 | 삭제 |
|---|
본인인증 로그인에 실패하였습니다.
회원이 아니시거나 본인인증 등록이
완료되지 않은 사용자입니다.
FFmpeg의 Custom Video Filter 만들어 달라는 의뢰가 들어 왔습니다.
우선, 구현을 하기 전에 ChatGPT에 물어봤습니다.
아니! 아니! Video Filter 사용법 말고 RGB를 YUV로 변환하는 Custom Video Filter로 구현 방법 알려줘!
#include <libavutil/imgutils.h>
#include <libavutil/samplefmt.h>
#include <libavutil/timestamp.h>
#include <libavfilter/avfilter.h>
#include <libavfilter/buffersrc.h>
#include <libavfilter/buffersink.h>
static void yuv2rgb(int y, int u, int v, uint8_t *r, uint8_t *g, uint8_t *b)
{
*r = av_clip_uint8((298 * y + 409 * v + 128) >> 8);
*g = av_clip_uint8((298 * y - 100 * u - 208 * v + 128) >> 8);
*b = av_clip_uint8((298 * y + 516 * u + 128) >> 8);
}
static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
{
AVFilterContext *ctx = inlink->dst;
AVFilterLink *outlink = ctx->outputs[0];
AVFrame *out_frame;
int ret;
// Allocate output frame and copy properties from input frame
ret = av_frame_make_writable(frame);
if (ret < 0)
return ret;
ret = av_frame_get_buffer(frame, 32);
if (ret < 0)
return ret;
out_frame = av_frame_clone(frame);
if (!out_frame)
return AVERROR(ENOMEM);
// Convert YUV to RGB
for (int y = 0; y < frame->height; y++) {
for (int x = 0; x < frame->width; x++) {
int y_index = y * frame->linesize[0] + x;
int u_index = (y / 2) * frame->linesize[1] + (x / 2);
int v_index = (y / 2) * frame->linesize[2] + (x / 2);
uint8_t y = frame->data[0][y_index];
uint8_t u = frame->data[1][u_index];
uint8_t v = frame->data[2][v_index];
uint8_t r, g, b;
yuv2rgb(y, u, v, &r, &g, &b);
int rgb_index = y_index * 3;
out_frame->data[0][rgb_index] = r;
out_frame->data[0][rgb_index + 1] = g;
out_frame->data[0][rgb_index + 2] = b;
}
}
// Push output frame to next filter in chain
out_frame->pts = frame->pts;
ret = av_buffersink_get_frame(outlink, out_frame);
av_frame_free(&out_frame);
return ret;
}
static const AVFilterPad rgb2yuv_inputs[] = {
{
.name = "default",
.type = AVMEDIA_TYPE_VIDEO,
.filter_frame = filter_frame,
},
{ NULL }
};
static const AVFilterPad rgb2yuv_outputs[] = {
{
.name = "default",
.type = AVMEDIA_TYPE_VIDEO,
},
{ NULL }
};
AVFilter ff_vf_rgb2yuv = {
.name = "rgb2yuv",
.description = "Converts YUV to RGB.",
.inputs = rgb2yuv_inputs,
.outputs = rgb2y오오~ 뭔가 그럴듯하게 나온다!! 았싸!! 이걸 컴파일 해서 돌려보자...
바로 Segmentation Fault발생하며 죽네요... ㅠㅠ
소스보니 뭔가 이상한데요....
YUV를 RGB로 변환했는데 왜 PIXEL Format Type을 변화하는 코드가 없지?
그리고, YUV보다 RGB가 메모리 사이가 더 큰데 입력 프레임과 출력 프레임이 같은 크기의 메모리를 할당 했네요....
out_frame = av_frame_clone(frame);예를 들면, 1920x1080 해상도의 8bit depth RGB영상은 1920 x 1080 x 3(RGB) 사이즈의 메모리라 필요한데요,
YUV444인 경우 RGB와 동일한 크기의 메모리가 필요합니다만, YUV 420 같은 경우 Y : 1920x1080, UV는 각각 960x540의 사이즈의 메모리가 필요합니다.
아래 코드에 (x / 2) 및 (y/ 2) 로 구현된거 보니 YUV420인거 같긴한데요. 아무튼 여기서 문제가 발생하네요.
그리고, converting 할때는 Interleaved RGB로 한 plane에 RGB를 다 저장했네요.
이러면, 1920x1080 사이즈의 메모리에 1920x1080x3 의 데이터를 저장하게 되어서 할당된 메모리보다 더 많은 데이터를 저장하게 되어 버립니다.
// Convert YUV to RGB
for (int y = 0; y < frame->height; y++) {
for (int x = 0; x < frame->width; x++) {
int y_index = y * frame->linesize[0] + x;
int u_index = (y / 2) * frame->linesize[1] + (x / 2);
int v_index = (y / 2) * frame->linesize[2] + (x / 2);
uint8_t y = frame->data[0][y_index];
uint8_t u = frame->data[1][u_index];
uint8_t v = frame->data[2][v_index];
uint8_t r, g, b;
yuv2rgb(y, u, v, &r, &g, &b);
int rgb_index = y_index * 3;
out_frame->data[0][rgb_index] = r;
out_frame->data[0][rgb_index + 1] = g;
out_frame->data[0][rgb_index + 2] = b;
}
}아... 이러니 동작 안할 수 밖에....
아직 AI가 아닌 개발자가 필요한 이유를 확인했네요!!!
To be continue...
DEVOTEE를 활성화 시키면
지금 작성한 댓글에 AI가 댓글을 달아줍니다.