데보션앱 소개페이지 바로가기
로그인 선택

신고하기

CLOSE
신고사유 (대표 사유 1개)
상세내용 (선택)
0/200
  • 신고한 게시글은 더 이상 보이지 않습니다.
  • 이용약관과 운영정책에 따라 신고사유에 해당하는지 검토 후 조치됩니다.
  • 허위 신고인 경우, 신고자의 서비스 이용이 제한될 수 있으니 유의하시어 신중하게 신고해 주세요.
(이 회원이 작성한 모든 댓글과 커뮤니티 게시물이 보이지 않고, 알림도 오지 않습니다.)

미리보기

커뮤니티

      1,234

      badge 23.06.15

      글 등록

      카테고리를 선택해주세요.

      DEVOTEE를 활성화 시키면
      지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.

      버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.

      임시저장함에 저장되었습니다. 저장일시 : 2022.5.17 14:29:08

      임시저장함

      제목을 선택하시면 이어서 작성이 가능하며,
      최대 20건까지 저장합니다.
      컨텐츠 유형, 제목, 저장일시, 삭제로 이뤄진 임시저장 목록
      컨텐츠 유형 제목 저장일 삭제

      데보션 블로그 게재 요청

      CLOSE
      • *
      • *

      본인인증

      효율적인 데보션 서비스 이용 및
      고객님의 소중한 개인정보보호를 위해
      본인인증을 진행해주세요. 본인인증 미 진행 시 로그인이 제한됩니다.
      본인인증 실패

      본인인증 로그인에 실패하였습니다.
      회원이 아니시거나 본인인증 등록이
      완료되지 않은 사용자입니다.

      회원정보 연결

      FFmpeg Custom Video Filter 만들기 #1

      fromDK 23.05.09
      2,145 12 0

      FFmpeg의 Custom Video Filter 만들어 달라는 의뢰가 들어 왔습니다.


      우선, 구현을 하기 전에 ChatGPT에 물어봤습니다.


      image.png


      아니! 아니! Video Filter 사용법 말고 RGB를 YUV로 변환하는 Custom Video Filter로 구현 방법 알려줘!


      image.png

      #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...

      댓글 0

      DEVOTEE를 활성화 시키면
      지금 작성한 댓글에 AI가 댓글을 달아줍니다.

      fromDK 님의 최신 블로그

      더보기
      동영상 기고하기