LCOV - code coverage report
Current view: top level - filters - vcrop.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 232 303 76.6 %
Date: 2021-04-29 23:48:07 Functions: 7 7 100.0 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2018-2021
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / video cropping filter
       9             :  *
      10             :  *  GPAC is free software; you can redistribute it and/or modify
      11             :  *  it under the terms of the GNU Lesser General Public License as published by
      12             :  *  the Free Software Foundation; either version 2, or (at your option)
      13             :  *  any later version.
      14             :  *
      15             :  *  GPAC is distributed in the hope that it will be useful,
      16             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :  *  GNU Lesser General Public License for more details.
      19             :  *
      20             :  *  You should have received a copy of the GNU Lesser General Public
      21             :  *  License along with this library; see the file COPYING.  If not, write to
      22             :  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
      23             :  *
      24             :  */
      25             : 
      26             : #include <gpac/filters.h>
      27             : #include <gpac/list.h>
      28             : #include <gpac/constants.h>
      29             : #include <gpac/network.h>
      30             : 
      31             : typedef struct
      32             : {
      33             :         //options
      34             :         const char *wnd;
      35             :         Bool copy;
      36             :         u32 round;
      37             : 
      38             :         //internal data
      39             :         Bool initialized;
      40             : 
      41             :         GF_FilterPid *ipid, *opid;
      42             :         u32 w, h, stride, s_pfmt;
      43             :         GF_Fraction ar;
      44             :         Bool passthrough;
      45             : 
      46             :         u32 dst_stride[5];
      47             :         u32 src_stride[5];
      48             :         u32 nb_planes, nb_src_planes, out_size, out_src_size, src_uv_height, dst_uv_height;
      49             : 
      50             :         Bool use_reference;
      51             :         u32 dst_width, dst_height;
      52             :         s32 src_x, src_y;
      53             :         Bool packed_422;
      54             : 
      55             :         GF_List *frames, *frames_res;
      56             : } GF_VCropCtx;
      57             : 
      58             : typedef struct
      59             : {
      60             :         GF_FilterFrameInterface frame_ifce;
      61             : 
      62             :         //reference to the source packet
      63             :         GF_FilterPacket *pck;
      64             :         u8 *planes[5];
      65             :         u32 stride[5];
      66             : 
      67             :         GF_VCropCtx *ctx;
      68             : } GF_VCropFrame;
      69             : 
      70             : 
      71        1446 : GF_Err vcrop_frame_get_plane(GF_FilterFrameInterface *frame, u32 plane_idx, const u8 **outPlane, u32 *outStride)
      72             : {
      73        1446 :         GF_VCropFrame *vframe = frame->user_data;
      74             : 
      75        1446 :         if (plane_idx>=vframe->ctx->nb_planes) return GF_BAD_PARAM;
      76        1446 :         if (outPlane) *outPlane = vframe->planes[plane_idx];
      77        1446 :         if (outStride) *outStride = vframe->stride[plane_idx];
      78             :         return GF_OK;
      79             : }
      80             : 
      81         698 : void vcrop_packet_destruct(GF_Filter *filter, GF_FilterPid *pid, GF_FilterPacket *pck)
      82             : {
      83             :         GF_VCropFrame *vframe;
      84         698 :         GF_FilterFrameInterface *frame_ifce = gf_filter_pck_get_frame_interface(pck);
      85         698 :         if (!frame_ifce) return;
      86         698 :         vframe = frame_ifce->user_data;
      87             :         assert(vframe->pck);
      88         698 :         gf_filter_pck_unref(vframe->pck);
      89         698 :         vframe->pck = NULL;
      90         698 :         gf_list_add(vframe->ctx->frames_res, vframe);
      91             : }
      92             : 
      93             : 
      94        1745 : static GF_Err vcrop_process(GF_Filter *filter)
      95             : {
      96             :         const u8 *data;
      97             :         u8 *output;
      98             :         u32 size;
      99             :         u32 bps;
     100             :         u32 s_off_x, s_off_y, d_off_x, d_off_y, i, copy_w, copy_h;
     101             :         u8 *src, *dst;
     102             :         u8 *src_planes[5];
     103             :         u8 *dst_planes[5];
     104             :         Bool do_memset = GF_FALSE;
     105             :         GF_FilterPacket *dst_pck;
     106             :         GF_FilterFrameInterface *frame_ifce;
     107        1745 :         GF_VCropCtx *ctx = gf_filter_get_udta(filter);
     108        1745 :         GF_FilterPacket *pck = gf_filter_pid_get_packet(ctx->ipid);
     109             : 
     110        1745 :         if (!pck) {
     111         534 :                 if (gf_filter_pid_is_eos(ctx->ipid)) {
     112          40 :                         gf_filter_pid_set_eos(ctx->opid);
     113          40 :                         return GF_EOS;
     114             :                 }
     115             :                 return GF_OK;
     116             :         }
     117             : 
     118        1211 :         if (ctx->passthrough) {
     119           0 :                 gf_filter_pck_forward(pck, ctx->opid);
     120           0 :                 gf_filter_pid_drop_packet(ctx->ipid);
     121           0 :                 return GF_OK;
     122             :         }
     123        1211 :         data = gf_filter_pck_get_data(pck, &size);
     124        1211 :         frame_ifce = gf_filter_pck_get_frame_interface(pck);
     125             : 
     126             :         memset(src_planes, 0, sizeof(src_planes));
     127             :         memset(dst_planes, 0, sizeof(dst_planes));
     128             : 
     129        1211 :         if (data) {
     130        1211 :                 src_planes[0] = (u8 *) data;
     131             : 
     132        1211 :                 if (ctx->nb_src_planes==1) {
     133         617 :                 } else if (ctx->nb_src_planes==2) {
     134         108 :                         src_planes[1] = src_planes[0] + ctx->src_stride[0]*ctx->h;
     135         509 :                 } else if (ctx->nb_src_planes==3) {
     136         509 :                         src_planes[1] = src_planes[0] + ctx->src_stride[0] * ctx->h;
     137         509 :                         src_planes[2] = src_planes[1] + ctx->src_stride[1] * ctx->src_uv_height;
     138           0 :                 } else if (ctx->nb_src_planes==4) {
     139           0 :                         src_planes[1] = src_planes[0] + ctx->src_stride[0] * ctx->h;
     140           0 :                         src_planes[2] = src_planes[1] + ctx->src_stride[1] * ctx->src_uv_height;
     141           0 :                         src_planes[3] = src_planes[2] + ctx->src_stride[2] * ctx->src_uv_height;
     142             :                 }
     143           0 :         } else if (frame_ifce && frame_ifce->get_plane) {
     144           0 :                 for (i=0; i<4; i++) {
     145           0 :                         if (frame_ifce->get_plane(frame_ifce, i, (const u8 **) &src_planes[i], &ctx->src_stride[i])!=GF_OK)
     146             :                                 break;
     147             :                 }
     148             :         } else {
     149           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[VCrop] No data associated with packet, not supported\n"));
     150           0 :                 gf_filter_pid_drop_packet(ctx->ipid);
     151           0 :                 return GF_NOT_SUPPORTED;
     152             :         }
     153             : 
     154        1211 :         bps = gf_pixel_get_bytes_per_pixel(ctx->s_pfmt);
     155             : 
     156        1211 :         copy_w = ctx->dst_width;
     157        1211 :         copy_h = ctx->dst_height;
     158             :         s_off_x = s_off_y = d_off_x = d_off_y = 0;
     159        1211 :         if (ctx->src_x>=0) {
     160        1211 :                 s_off_x = ctx->src_x;
     161             :         } else {
     162           0 :                 d_off_x = (u32) (-ctx->src_x);
     163           0 :                 copy_w = (s32) ctx->dst_width + ctx->src_x;
     164             :                 do_memset = GF_TRUE;
     165             :         }
     166        1211 :         if (s_off_x + copy_w > ctx->w) {
     167           0 :                 copy_w = ctx->w - s_off_x;
     168             :                 do_memset = GF_TRUE;
     169             :         }
     170        1211 :         if (ctx->src_y>=0) {
     171        1211 :                 s_off_y = ctx->src_y;
     172             :         } else {
     173           0 :                 d_off_y = (u32) (-ctx->src_y);
     174           0 :                 copy_h = (s32) ctx->dst_height + ctx->src_y;
     175             :                 do_memset = GF_TRUE;
     176             :         }
     177        1211 :         if (s_off_y + copy_h > ctx->h) {
     178           0 :                 copy_h = ctx->h - s_off_y;
     179             :                 do_memset = GF_TRUE;
     180             :         }
     181             : 
     182        1211 :         if (ctx->use_reference) {
     183         698 :                 GF_VCropFrame *vframe = gf_list_pop_back(ctx->frames_res);
     184         698 :                 if (!vframe) {
     185          21 :                         GF_SAFEALLOC(vframe, GF_VCropFrame);
     186          21 :                         if (!vframe) return GF_OUT_OF_MEM;
     187             :                 }
     188         698 :                 vframe->ctx = ctx;
     189         698 :                 memcpy(vframe->stride, ctx->src_stride, sizeof(vframe->stride));
     190         698 :                 if (ctx->packed_422) {
     191         108 :                         vframe->planes[0] = src_planes[0] + s_off_x * bps * 2 + ctx->src_stride[0] * s_off_y;
     192             :                 } else {
     193         590 :                         vframe->planes[0] = src_planes[0] + s_off_x * bps + ctx->src_stride[0] * s_off_y;
     194             :                 }
     195             :                 //nv12/21
     196         698 :                 if (ctx->nb_planes==2) {
     197          54 :                         vframe->planes[1] = src_planes[1] + s_off_x * bps + ctx->src_stride[1] * s_off_y/2;
     198         644 :                 } else if (ctx->nb_planes>=3) {
     199             :                         u32 div_x, div_y;
     200             :                         //alpha/depth/other plane, treat as luma plane
     201         347 :                         if (ctx->nb_planes==4) {
     202           0 :                                 vframe->planes[3] = src_planes[3] + s_off_x * bps + ctx->src_stride[3] * s_off_y;
     203             :                         }
     204         347 :                         div_x = (ctx->src_stride[1]==ctx->src_stride[0]) ? 1 : 2;
     205         347 :                         div_y = (ctx->src_uv_height==ctx->h) ? 1 : 2;
     206             : 
     207         347 :                         vframe->planes[1] = src_planes[1] + s_off_x * bps / div_x + ctx->src_stride[1] * s_off_y / div_y;
     208         347 :                         vframe->planes[2] =src_planes[2] + s_off_x * bps / div_x + ctx->src_stride[2] * s_off_y / div_y;
     209             :                 }
     210         698 :                 vframe->frame_ifce.user_data = vframe;
     211         698 :                 vframe->frame_ifce.get_plane = vcrop_frame_get_plane;
     212         698 :                 dst_pck = gf_filter_pck_new_frame_interface(ctx->opid, &vframe->frame_ifce, vcrop_packet_destruct);
     213         698 :                 if (!dst_pck) return GF_OUT_OF_MEM;
     214             : 
     215             :                 //keep a ref to input packet
     216         698 :                 vframe->pck = pck;
     217         698 :                 gf_filter_pck_ref(&vframe->pck);
     218         698 :                 gf_filter_pck_merge_properties(pck, dst_pck);
     219         698 :                 gf_filter_pck_send(dst_pck);
     220             :                 //remove input packet
     221         698 :                 gf_filter_pid_drop_packet(ctx->ipid);
     222         698 :                 return GF_OK;
     223             :         }
     224             : 
     225             : 
     226         513 :         dst_pck = gf_filter_pck_new_alloc(ctx->opid, ctx->out_size, &output);
     227         513 :         if (!dst_pck) return GF_OUT_OF_MEM;
     228             :         
     229         513 :         gf_filter_pck_merge_properties(pck, dst_pck);
     230         513 :         dst_planes[0] = output;
     231         513 :         if (ctx->nb_planes==1) {
     232         216 :         } else if (ctx->nb_planes==2) {
     233          54 :                 dst_planes[1] = output + ctx->dst_stride[0] * ctx->dst_height;
     234         162 :         } else if (ctx->nb_planes==3) {
     235         162 :                 dst_planes[1] = output + ctx->dst_stride[0] * ctx->dst_height;
     236         162 :                 dst_planes[2] = dst_planes[1] + ctx->dst_stride[1]*ctx->dst_uv_height;
     237           0 :         } else if (ctx->nb_planes==4) {
     238           0 :                 dst_planes[1] = output + ctx->dst_stride[0] * ctx->dst_height;
     239           0 :                 dst_planes[2] = dst_planes[1] + ctx->dst_stride[1]*ctx->dst_uv_height;
     240           0 :                 dst_planes[3] = dst_planes[2] + ctx->dst_stride[2]*ctx->dst_uv_height;
     241             :         } else {
     242           0 :                 gf_filter_pid_drop_packet(ctx->ipid);
     243           0 :                 return GF_NOT_SUPPORTED;
     244             :         }
     245             : 
     246         513 :         if (do_memset) {
     247           0 :                 memset(output, 0x00, sizeof(char)*ctx->out_size);
     248             :         }
     249             : 
     250             :         //YUYV variations need *2 on horizontal dimension
     251         513 :         if (ctx->packed_422) {
     252         108 :                 src = src_planes[0] + s_off_x * bps * 2 + ctx->src_stride[0] * s_off_y;
     253         108 :                 dst = dst_planes[0] + d_off_x * bps * 2 + ctx->dst_stride[0] * d_off_y;
     254        7020 :                 for (i=0; i<copy_h; i++) {
     255        6912 :                         memcpy(dst, src, bps * copy_w * 2);
     256        6912 :                         src += ctx->src_stride[0];
     257        6912 :                         dst += ctx->dst_stride[0];
     258             :                 }
     259             :         } else {
     260             :                 //copy first plane
     261         405 :                 src = src_planes[0] + s_off_x * bps + ctx->src_stride[0] * s_off_y;
     262         405 :                 dst = dst_planes[0] + d_off_x * bps + ctx->dst_stride[0] * d_off_y;
     263       26325 :                 for (i=0; i<copy_h; i++) {
     264       25920 :                         memcpy(dst, src, bps * copy_w);
     265       25920 :                         src += ctx->src_stride[0];
     266       25920 :                         dst += ctx->dst_stride[0];
     267             :                 }
     268             :         }
     269             : 
     270             :         //nv12/21
     271         513 :         if (ctx->nb_planes==2) {
     272          54 :                 src = src_planes[1] + s_off_x * bps + ctx->src_stride[1] * s_off_y/2;
     273          54 :                 dst = dst_planes[1] + d_off_x * bps + ctx->dst_stride[1] * d_off_y/2;
     274             :                 //half vertical res (/2)
     275        1782 :                 for (i=0; i<copy_h/2; i++) {
     276             :                         //half horizontal res (/2) but two chroma packed per pixel (*2)
     277        1728 :                         memcpy(dst, src, bps * copy_w);
     278        1728 :                         src += ctx->src_stride[1];
     279        1728 :                         dst += ctx->dst_stride[1];
     280             :                 }
     281         459 :         } else if ((ctx->nb_planes==3) || (ctx->nb_planes==4)) {
     282             :                 u32 div_x, div_y;
     283             :                 //alpha/depth/other plane, treat as luma plane
     284         162 :                 if (ctx->nb_planes==4) {
     285           0 :                         src = src_planes[3] + s_off_x * bps + ctx->src_stride[3] * s_off_y;
     286           0 :                         dst = dst_planes[3] + d_off_x * bps + ctx->dst_stride[3] * d_off_y;
     287           0 :                         for (i=0; i<copy_h; i++) {
     288           0 :                                 memcpy(dst, src, bps * copy_w);
     289           0 :                                 src += ctx->src_stride[3];
     290           0 :                                 dst += ctx->dst_stride[3];
     291             :                         }
     292             :                 }
     293             : 
     294         162 :                 div_x = (ctx->src_stride[1]==ctx->src_stride[0]) ? 1 : 2;
     295         162 :                 div_y = (ctx->src_uv_height==ctx->h) ? 1 : 2;
     296             : 
     297         162 :                 src = src_planes[1] + s_off_x * bps / div_x + ctx->src_stride[1] * s_off_y / div_y;
     298         162 :                 dst = dst_planes[1] + d_off_x * bps / div_x + ctx->dst_stride[1] * d_off_y / div_y;
     299         162 :                 copy_h /= div_y;
     300         162 :                 copy_w /= div_x;
     301             : 
     302        8802 :                 for (i=0; i<copy_h; i++) {
     303        8640 :                         memcpy(dst, src, bps * copy_w);
     304        8640 :                         src += ctx->src_stride[1];
     305        8640 :                         dst += ctx->dst_stride[1];
     306             :                 }
     307             : 
     308         162 :                 src = src_planes[2] + s_off_x * bps / div_x + ctx->src_stride[2] * s_off_y / div_y;
     309         162 :                 dst = dst_planes[2] + d_off_x * bps / div_x + ctx->dst_stride[2] * d_off_y / div_y;
     310        8802 :                 for (i=0; i<copy_h; i++) {
     311        8640 :                         memcpy(dst, src, bps * copy_w);
     312        8640 :                         src += ctx->src_stride[1];
     313        8640 :                         dst += ctx->dst_stride[1];
     314             :                 }
     315             :         }
     316             : 
     317         513 :         gf_filter_pck_send(dst_pck);
     318         513 :         gf_filter_pid_drop_packet(ctx->ipid);
     319         513 :         return GF_OK;
     320             : }
     321             : 
     322          42 : static Bool parse_crop_props(GF_VCropCtx *ctx, u32 src_w, u32 src_h, GF_PixelFormat pfmt)
     323             : {
     324             :         s32 dim[4];
     325             :         s32 dim_off[4];
     326             :         Bool dim_pc[4];
     327             :         u32 nb_dim=0;
     328          42 :         char *args = (char *)ctx->wnd;
     329             : 
     330             :         memset(dim, 0, sizeof(dim));
     331             :         memset(dim_pc, 0, sizeof(dim_pc));
     332             :         memset(dim_off, 0, sizeof(dim_off));
     333             : 
     334         168 :         while (args) {
     335             :                 char *sep_offset=NULL, *sep_pc, sign=0;
     336         168 :                 char *sep = strchr(args, 'x');
     337         168 :                 if (sep) sep[0] = 0;
     338             : 
     339         168 :                 sep_pc = strchr(args, '%');
     340         168 :                 if (sep_pc) {
     341           0 :                         sep_pc[0] = 0;
     342           0 :                         dim[nb_dim] = atoi(args);
     343           0 :                         sep_pc[0] = '%';
     344           0 :                         dim_pc[nb_dim] = GF_TRUE;
     345             : 
     346           0 :                         sep_offset = strchr(sep_pc, '+');
     347           0 :                         if (sep_offset) {
     348           0 :                                 sign = sep_offset[0];
     349           0 :                                 dim_off[nb_dim] = atoi(sep_offset+1);
     350           0 :                                 sep_offset[0] = 0;
     351             :                         } else {
     352           0 :                                 sep_offset = strchr(args, '-');
     353           0 :                                 if (sep_offset) {
     354           0 :                                         sign = sep_offset[0];
     355           0 :                                         dim_off[nb_dim] = - atoi(sep_offset+1);
     356           0 :                                         sep_offset[0] = 0;
     357             :                                 }
     358             :                         }
     359             : 
     360             :                 } else {
     361         168 :                         dim[nb_dim] = atoi(args);
     362             :                 }
     363             : 
     364           0 :                 if (sep_offset) sep_offset[0] = sign;
     365         168 :                 nb_dim++;
     366         168 :                 if (!sep) break;
     367         126 :                 sep[0] = 'x';
     368         126 :                 args = sep+1;
     369         126 :                 if (nb_dim==4) break;
     370             :         }
     371             : 
     372             : #define GET_DIM(_dst, _i, _s) if (dim_pc[_i]) \
     373             :                                                                 _dst = (dim[_i] * (s32) _s / 100) + dim_off[_i]; \
     374             :                                                         else \
     375             :                                                                 _dst = dim[_i] + dim_off[_i]; \
     376             : 
     377             : 
     378          42 :         if (nb_dim==2) {
     379           0 :                 ctx->src_x = 0;
     380           0 :                 ctx->src_y = 0;
     381           0 :                 GET_DIM(ctx->dst_width, 0, src_w)
     382           0 :                 GET_DIM(ctx->dst_height, 1, src_h)
     383          42 :         } else if (nb_dim==4) {
     384          42 :                 GET_DIM(ctx->src_x, 0, src_w)
     385          42 :                 GET_DIM(ctx->src_y, 1, src_h)
     386          42 :                 GET_DIM(ctx->dst_width, 2, src_w)
     387          42 :                 GET_DIM(ctx->dst_height, 3, src_h)
     388             :         } else {
     389           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[VCrop] Cannot parse crop parameters, expected 2 or 4 numbers, got %d\n", nb_dim));
     390             :                 return GF_FALSE;
     391             :         }
     392          42 :         if ((s32) ctx->dst_width < 0) {
     393           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[VCrop] Negative destination width %d !\n", (s32) ctx->dst_width));
     394             :                 return GF_FALSE;
     395             :         }
     396          42 :         if ((s32) ctx->dst_height < 0) {
     397           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[VCrop] Negative destination height %d !\n", (s32) ctx->dst_height));
     398             :                 return GF_FALSE;
     399             :         }
     400             : 
     401             : #define ROUND_IT(_a) { if ((ctx->round==0) || (ctx->round==2)) { (_a)++; } else { (_a)--; } }
     402             : 
     403             :         //for YUV 420, adjust to multiple of 2 on both dim
     404          42 :         ctx->packed_422 = GF_FALSE;
     405          42 :         switch (pfmt) {
     406          12 :         case GF_PIXEL_YUV:
     407             :         case GF_PIXEL_YVU:
     408             :         case GF_PIXEL_NV21:
     409             :         case GF_PIXEL_NV21_10:
     410             :         case GF_PIXEL_NV12:
     411             :         case GF_PIXEL_NV12_10:
     412             :         case GF_PIXEL_YUVA:
     413             :         case GF_PIXEL_YUVD:
     414             :         case GF_PIXEL_YUV_10:
     415          12 :                 if (ctx->src_x % 2) ROUND_IT(ctx->src_x);
     416          12 :                 if (ctx->src_y % 2) ROUND_IT(ctx->src_y);
     417          12 :                 if ((ctx->src_x + ctx->dst_width) % 2) ROUND_IT(ctx->dst_width);
     418          12 :                 if ((ctx->src_y + ctx->dst_height) % 2) ROUND_IT(ctx->dst_height);
     419             :                 break;
     420             :         //for YUV 422, adjust to multiple of 2 on horizontal dim
     421           8 :         case GF_PIXEL_YUYV:
     422             :         case GF_PIXEL_YVYU:
     423             :         case GF_PIXEL_UYVY:
     424             :         case GF_PIXEL_VYUY:
     425           8 :                 ctx->packed_422 = GF_TRUE;
     426          12 :         case GF_PIXEL_YUV422:
     427             :         case GF_PIXEL_YUV422_10:
     428          12 :                 if (ctx->src_x % 2) ROUND_IT(ctx->src_x);
     429          12 :                 if ((ctx->src_x + ctx->dst_width) % 2) ROUND_IT(ctx->dst_width);
     430          12 :                 if (ctx->round>1) {
     431           0 :                         if (ctx->src_y % 2) ROUND_IT(ctx->src_y);
     432           0 :                         if ((ctx->src_y + ctx->dst_height) % 2) ROUND_IT(ctx->dst_height);
     433             :                 }
     434             :                 break;
     435          18 :         default:
     436          18 :                 if (ctx->round>1) {
     437           0 :                         if (ctx->src_x % 2) ROUND_IT(ctx->src_x);
     438           0 :                         if (ctx->src_y % 2) ROUND_IT(ctx->src_y);
     439           0 :                         if ((ctx->src_x + ctx->dst_width) % 2) ROUND_IT(ctx->dst_width);
     440           0 :                         if ((ctx->src_y + ctx->dst_height) % 2) ROUND_IT(ctx->dst_height);
     441             :                 }
     442             :                 break;
     443             :         }
     444             :         return GF_TRUE;
     445             : }
     446             : 
     447          42 : static GF_Err vcrop_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
     448             : {
     449             :         GF_PropVec2i vec;
     450             :         const GF_PropertyValue *p;
     451             :         u32 w, h, stride, pfmt;
     452             :         GF_Fraction sar;
     453          42 :         GF_VCropCtx *ctx = gf_filter_get_udta(filter);
     454             : 
     455          42 :         if (is_remove) {
     456           0 :                 if (ctx->opid) {
     457           0 :                         gf_filter_pid_remove(ctx->opid);
     458           0 :                         ctx->opid = NULL;
     459             :                 }
     460             :                 return GF_OK;
     461             :         }
     462          42 :         if (! gf_filter_pid_check_caps(pid))
     463             :                 return GF_NOT_SUPPORTED;
     464             : 
     465          42 :         if (!ctx->opid) {
     466          40 :                 ctx->opid = gf_filter_pid_new(filter);
     467             :         }
     468             :         //copy properties at init or reconfig
     469          42 :         gf_filter_pid_copy_properties(ctx->opid, pid);
     470             : 
     471          42 :         if (!ctx->ipid) {
     472          40 :                 ctx->ipid = pid;
     473             :         }
     474             :         w = h = pfmt = stride = 0;
     475          42 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_WIDTH);
     476          42 :         if (p) w = p->value.uint;
     477          42 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_HEIGHT);
     478          42 :         if (p) h = p->value.uint;
     479          42 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_STRIDE);
     480          42 :         if (p) stride = p->value.uint;
     481          42 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_PIXFMT);
     482          42 :         if (p) pfmt = p->value.uint;
     483          42 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_SAR);
     484          42 :         if (p) sar = p->value.frac;
     485             :         else sar.den = sar.num = 1;
     486             : 
     487          42 :         if (!w || !h || !pfmt) {
     488           0 :                 ctx->passthrough = GF_TRUE;
     489           0 :                 return GF_OK;
     490             :         }
     491          42 :         ctx->passthrough = GF_FALSE;
     492             : 
     493          42 :         if ((ctx->w == w) && (ctx->h == h) && (ctx->s_pfmt == pfmt) && (ctx->stride == stride)) {
     494             :                 //nothing to reconfigure
     495             :         } else {
     496             :                 Bool res;
     497          42 :                 if (! parse_crop_props(ctx, w, h, pfmt)) {
     498             :                         return GF_BAD_PARAM;
     499             :                 }
     500             : 
     501          42 :                 if (ctx->src_x<0) ctx->use_reference = GF_FALSE;
     502          42 :                 else if (ctx->src_y<0) ctx->use_reference = GF_FALSE;
     503          42 :                 else if (ctx->src_x + ctx->dst_width > w) ctx->use_reference = GF_FALSE;
     504          42 :                 else if (ctx->src_y + ctx->dst_height > h) ctx->use_reference = GF_FALSE;
     505          42 :                 else ctx->use_reference = ctx->copy ? GF_FALSE : GF_TRUE;
     506             : 
     507          42 :                 if (ctx->use_reference) {
     508          23 :                         if (!ctx->frames) ctx->frames = gf_list_new();
     509          23 :                         if (!ctx->frames_res) ctx->frames_res = gf_list_new();
     510             :                 }
     511             : 
     512             :                 //get layout info for source
     513          42 :                 memset(ctx->src_stride, 0, sizeof(ctx->src_stride));
     514          42 :                 if (ctx->stride) ctx->src_stride[0] = ctx->stride;
     515             : 
     516          42 :                 res = gf_pixel_get_size_info(pfmt, w, h, &ctx->out_src_size, &ctx->src_stride[0], &ctx->src_stride[1], &ctx->nb_src_planes, &ctx->src_uv_height);
     517          42 :                 if (!res) {
     518           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[VCrop] Failed to query source pixel format characteristics\n"));
     519             :                         return GF_NOT_SUPPORTED;
     520             :                 }
     521          42 :                 if (ctx->nb_src_planes==3) ctx->src_stride[2] = ctx->src_stride[1];
     522          42 :                 if (ctx->nb_src_planes==4) ctx->src_stride[3] = ctx->src_stride[0];
     523             : 
     524             : 
     525             :                 //get layout info for dest
     526          42 :                 memset(ctx->dst_stride, 0, sizeof(ctx->dst_stride));
     527          42 :                 res = gf_pixel_get_size_info(pfmt, ctx->dst_width, ctx->dst_height, &ctx->out_size, &ctx->dst_stride[0], &ctx->dst_stride[1], &ctx->nb_planes, &ctx->dst_uv_height);
     528          42 :                 if (!res) {
     529           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[VCrop] Failed to query output pixel format characteristics\n"));
     530             :                         return GF_NOT_SUPPORTED;
     531             :                 }
     532          42 :                 if (ctx->nb_planes==3) ctx->dst_stride[2] = ctx->dst_stride[1];
     533          42 :                 if (ctx->nb_planes==4) ctx->dst_stride[3] = ctx->dst_stride[0];
     534             : 
     535             : 
     536          42 :                 ctx->w = w;
     537          42 :                 ctx->h = h;
     538          42 :                 ctx->s_pfmt = pfmt;
     539             : 
     540          42 :                 GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[VCrop] Configured output window to crop %dx%dx%dx%d from full frame size %dx%d\n", ctx->src_x, ctx->src_y, ctx->dst_width, ctx->dst_height, ctx->w, ctx->h));
     541             : 
     542          42 :                 if (!ctx->src_x && !ctx->src_y && (ctx->dst_width==ctx->w) &&  (ctx->dst_height==ctx->h) ) {
     543           0 :                         ctx->passthrough = GF_TRUE;
     544             :                 }
     545             :         }
     546             : 
     547          42 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_WIDTH, &PROP_UINT(ctx->dst_width));
     548          42 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_HEIGHT, &PROP_UINT(ctx->dst_height));
     549          42 :         if (ctx->use_reference) {
     550          23 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STRIDE, &PROP_UINT(ctx->src_stride[0] ));
     551          23 :                 if (ctx->nb_planes>1)
     552          12 :                         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STRIDE_UV, &PROP_UINT(ctx->src_stride[1]));
     553             :         } else {
     554          19 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STRIDE, &PROP_UINT(ctx->dst_stride[0] ));
     555          19 :                 if (ctx->nb_planes>1)
     556           8 :                         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STRIDE_UV, &PROP_UINT(ctx->dst_stride[1]));
     557             :         }
     558          42 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAR, &PROP_FRAC(sar) );
     559          42 :         vec.x = ctx->src_x;
     560          42 :         vec.y = ctx->src_y;
     561          42 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CROP_POS, &PROP_VEC2I(vec) );
     562          42 :         vec.x = ctx->w;
     563          42 :         vec.y = ctx->h;
     564          42 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_ORIG_SIZE, &PROP_VEC2I(vec) );
     565             : 
     566          42 :         return GF_OK;
     567             : }
     568             : 
     569          40 : void vcrop_finalize(GF_Filter *filter)
     570             : {
     571          40 :         GF_VCropCtx *ctx = gf_filter_get_udta(filter);
     572          40 :         if (ctx->frames) {
     573          21 :                 while (gf_list_count(ctx->frames)) {
     574           0 :                         GF_VCropFrame *vframe = gf_list_pop_back(ctx->frames);
     575           0 :                         gf_free(vframe);
     576             :                 }
     577          21 :                 gf_list_del(ctx->frames);
     578             :         }
     579          40 :         if (ctx->frames_res) {
     580          42 :                 while (gf_list_count(ctx->frames_res)) {
     581          21 :                         GF_VCropFrame *vframe = gf_list_pop_back(ctx->frames_res);
     582          21 :                         gf_free(vframe);
     583             :                 }
     584          21 :                 gf_list_del(ctx->frames_res);
     585             :         }
     586          40 : }
     587             : 
     588             : 
     589             : #define OFFS(_n)        #_n, offsetof(GF_VCropCtx, _n)
     590             : static GF_FilterArgs VCropArgs[] =
     591             : {
     592             :         { OFFS(wnd), "size of output to crop, indicated as TxLxWxH. If % is indicated after a number, the value is in percent of the source width (for L and W) or height (for T and H). An absolute offset (+x, -x) can be added after percent", GF_PROP_STRING, NULL, NULL, 0},
     593             :         { OFFS(copy), "copy the source pixels. By default the filter will try to forward crop frames by adjusting offsets and strides of the source if possible (window contained in frame)", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
     594             :         { OFFS(round), "adjust dimension to be a multiple of 2\n"
     595             :         "- up: up rounding\n"
     596             :         "- down: down rounding\n"
     597             :         "- allup: up rounding on formats that do not require it (RGB, YUV444)\n"
     598             :         "- alldown: down rounding on formats that do not require it (RGB, YUV444)", GF_PROP_UINT, "up", "up|down|allup|alldown", GF_FS_ARG_HINT_ADVANCED},
     599             :         {0}
     600             : };
     601             : 
     602             : static const GF_FilterCapability VCropCaps[] =
     603             : {
     604             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
     605             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_RAW),
     606             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
     607             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_RAW),
     608             : };
     609             : 
     610             : GF_FilterRegister VCropRegister = {
     611             :         .name = "vcrop",
     612             :         GF_FS_SET_DESCRIPTION("Video crop")
     613             :         GF_FS_SET_HELP("This filter is used to crop raw video data.")
     614             :         .private_size = sizeof(GF_VCropCtx),
     615             :         .flags = GF_FS_REG_EXPLICIT_ONLY,
     616             :         .args = VCropArgs,
     617             :         .configure_pid = vcrop_configure_pid,
     618             :         SETCAPS(VCropCaps),
     619             :         .process = vcrop_process,
     620             :         .finalize = vcrop_finalize,
     621             : };
     622             : 
     623             : 
     624             : 
     625        2877 : const GF_FilterRegister *vcrop_register(GF_FilterSession *session)
     626             : {
     627        2877 :         return &VCropRegister;
     628             : }

Generated by: LCOV version 1.13