LCOV - code coverage report
Current view: top level - filters - reframe_rawvid.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 125 150 83.3 %
Date: 2021-04-29 23:48:07 Functions: 4 4 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 / RAW video (YUV,RGB) reframer 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/avparse.h>
      27             : #include <gpac/constants.h>
      28             : #include <gpac/filters.h>
      29             : 
      30             : typedef struct
      31             : {
      32             :         //opts
      33             :         GF_PropVec2i size;
      34             :         GF_PixelFormat spfmt;
      35             :         GF_Fraction fps;
      36             :         Bool copy;
      37             : 
      38             :         //only one input pid declared
      39             :         GF_FilterPid *ipid;
      40             :         //only one output pid declared
      41             :         GF_FilterPid *opid;
      42             : 
      43             :         Bool file_loaded, is_playing, initial_play_done;
      44             :         u64 cts;
      45             :         u32 frame_size, nb_bytes_in_frame;
      46             :         u64 filepos, total_frames;
      47             :         GF_FilterPacket *out_pck;
      48             :         u8 *out_data;
      49             :         Bool reverse_play, done;
      50             :         Bool is_v210;
      51             : } GF_RawVidReframeCtx;
      52             : 
      53             : 
      54             : 
      55             : 
      56         282 : GF_Err rawvidreframe_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
      57             : {
      58             :         const GF_PropertyValue *p;
      59             :         u32 stride, stride_uv;
      60         282 :         GF_RawVidReframeCtx *ctx = gf_filter_get_udta(filter);
      61             : 
      62         282 :         if (is_remove) {
      63           2 :                 ctx->ipid = NULL;
      64           2 :                 if (ctx->opid) {
      65           2 :                         gf_filter_pid_remove(ctx->opid);
      66           2 :                         ctx->opid = NULL;
      67             :                 }
      68             :                 return GF_OK;
      69             :         }
      70         280 :         if (! gf_filter_pid_check_caps(pid))
      71             :                 return GF_NOT_SUPPORTED;
      72             : 
      73         280 :         ctx->ipid = pid;
      74         280 :         ctx->is_v210 = GF_FALSE;
      75         280 :         if (!ctx->spfmt) {
      76         280 :                 p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILE_EXT);
      77         280 :                 if (p && p->value.string) {
      78         280 :                         if (!strcmp(p->value.string, "v210")) {
      79           0 :                                 ctx->is_v210 = GF_TRUE;
      80             :                         } else {
      81         280 :                                 ctx->spfmt = gf_pixel_fmt_parse(p->value.string);
      82             :                         }
      83             :                 }
      84             :         }
      85         280 :         if (!ctx->spfmt && !ctx->is_v210) {
      86           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[RawVidReframe] Missing pixel format, cannot parse\n"));
      87             :                 return GF_BAD_PARAM;
      88             :         }
      89         280 :         if (!ctx->size.x || !ctx->size.y) {
      90           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[RawVidReframe] Missing video frame size, cannot parse\n"));
      91             :                 return GF_BAD_PARAM;
      92             :         }
      93             : 
      94         280 :         stride = stride_uv = 0;
      95         280 :         if (ctx->is_v210) {
      96             : #define V210_HORIZ_ALIGN_PIXEL 48
      97           0 :                 if (ctx->size.x % V210_HORIZ_ALIGN_PIXEL)
      98           0 :                         stride = ((ctx->size.x / V210_HORIZ_ALIGN_PIXEL) + 1) * V210_HORIZ_ALIGN_PIXEL;
      99             :                 else
     100           0 :                         stride = ctx->size.x;
     101           0 :                 stride = stride * 16 / 6;
     102           0 :                 ctx->frame_size = stride *  ctx->size.y;
     103             :         } else {
     104         280 :                 if (! gf_pixel_get_size_info(ctx->spfmt, ctx->size.x, ctx->size.y, &ctx->frame_size, &stride, &stride_uv, NULL, NULL)) {
     105           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[RawVidReframe] Failed to query pixel format size info\n"));
     106             :                         return GF_BAD_PARAM;
     107             :                 }
     108             :         }
     109             : 
     110         280 :         if (!ctx->opid)
     111         280 :                 ctx->opid = gf_filter_pid_new(filter);
     112             : 
     113         280 :         gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
     114         280 :         gf_filter_pid_set_framing_mode(ctx->ipid, GF_FALSE);
     115         280 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(GF_STREAM_VISUAL));
     116         280 :         if (ctx->is_v210) {
     117           0 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, &PROP_UINT(GF_CODECID_V210));
     118             :         } else {
     119         280 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, &PROP_UINT(GF_CODECID_RAW));
     120             :         }
     121         280 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_WIDTH, &PROP_UINT(ctx->size.x));
     122         280 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_HEIGHT, &PROP_UINT(ctx->size.y));
     123         280 :         if (ctx->spfmt)
     124         280 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_PIXFMT, &PROP_UINT(ctx->spfmt));
     125         280 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_FPS, &PROP_FRAC(ctx->fps));
     126         280 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_TIMESCALE, &PROP_UINT(ctx->fps.num));
     127             : 
     128         280 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STRIDE, &PROP_UINT(stride));
     129         280 :         if (stride_uv)
     130         103 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STRIDE_UV, &PROP_UINT(stride_uv));
     131         280 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_PLAYBACK_MODE, &PROP_UINT(GF_PLAYBACK_MODE_REWIND));
     132         280 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CAN_DATAREF, &PROP_BOOL(GF_TRUE));
     133             : 
     134         280 :         if (!gf_sys_is_test_mode() ) {
     135           0 :                 u32 osize = 0;
     136           0 :                 gf_pixel_get_size_info(ctx->spfmt, ctx->size.x, ctx->size.y, &osize, &stride, &stride_uv, NULL, NULL);
     137           0 :                 if (osize) {
     138           0 :                         u32 rate = osize * 8 * ctx->fps.num / ctx->fps.den;
     139           0 :                         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_BITRATE, & PROP_UINT(rate));
     140             :                 }
     141             :         }
     142             : 
     143             : 
     144         280 :         p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILE_CACHED);
     145         280 :         if (p && p->value.boolean) ctx->file_loaded = GF_TRUE;
     146             : 
     147         280 :         p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_DOWN_SIZE);
     148         280 :         if (p && p->value.longuint) {
     149             :                 u64 nb_frames = p->value.longuint;
     150         280 :                 nb_frames /= ctx->frame_size;
     151         280 :                 ctx->total_frames = nb_frames;
     152         280 :                 nb_frames *= ctx->fps.den;
     153         280 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DURATION, &PROP_FRAC64_INT(nb_frames, ctx->fps.num));
     154             :         }
     155             : 
     156         280 :         if (!ctx->copy) {
     157         261 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_PLAY_BUFFER, &PROP_UINT(0));
     158         261 :                 if (!gf_sys_is_test_mode())
     159           0 :                         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_RE_BUFFER, &PROP_UINT(0));
     160             :         }
     161             :         return GF_OK;
     162             : }
     163             : 
     164        3930 : static Bool rawvidreframe_process_event(GF_Filter *filter, const GF_FilterEvent *evt)
     165             : {
     166             :         u32 nb_frames;
     167             :         GF_FilterEvent fevt;
     168        3930 :         GF_RawVidReframeCtx *ctx = gf_filter_get_udta(filter);
     169             : 
     170        3930 :         switch (evt->base.type) {
     171         280 :         case GF_FEVT_PLAY:
     172         280 :                 if (!ctx->is_playing) {
     173         280 :                         ctx->is_playing = GF_TRUE;
     174         280 :                         ctx->cts = 0;
     175             :                 }
     176         280 :                 ctx->done = GF_FALSE;
     177         280 :                 if (evt->play.start_range>=0) {
     178         280 :                         nb_frames = (u32) (evt->play.start_range * ctx->fps.num);
     179             :                 } else {
     180           0 :                         nb_frames = (u32) (ctx->cts / ctx->fps.den);
     181             :                 }
     182         280 :                 if (nb_frames>=ctx->total_frames)
     183           1 :                         nb_frames = (u32) ctx->total_frames-1;
     184             : 
     185         280 :                 ctx->cts = nb_frames * ctx->fps.den;
     186         280 :                 ctx->filepos = nb_frames * ctx->frame_size;
     187         280 :                 ctx->reverse_play =  (evt->play.speed<0) ? GF_TRUE : GF_FALSE;
     188             : 
     189             :                 //post a seek even for the beginning, to try to load frame by frame
     190         280 :                 GF_FEVT_INIT(fevt, GF_FEVT_SOURCE_SEEK, ctx->ipid);
     191         280 :                 fevt.seek.start_offset = ctx->filepos;
     192         280 :                 fevt.seek.hint_block_size = ctx->frame_size;
     193         280 :                 gf_filter_pid_send_event(ctx->ipid, &fevt);
     194             : 
     195             :                 //cancel event
     196         280 :                 return GF_TRUE;
     197             : 
     198           0 :         case GF_FEVT_STOP:
     199             :                 //don't cancel event
     200           0 :                 ctx->is_playing = GF_FALSE;
     201           0 :                 return GF_FALSE;
     202             : 
     203             :         case GF_FEVT_SET_SPEED:
     204             :                 //cancel event
     205             :                 return GF_TRUE;
     206             :         default:
     207             :                 break;
     208             :         }
     209             :         //by default don't cancel event - to rework once we have downloading in place
     210        3539 :         return GF_FALSE;
     211             : }
     212             : 
     213        7614 : GF_Err rawvidreframe_process(GF_Filter *filter)
     214             : {
     215        7614 :         GF_RawVidReframeCtx *ctx = gf_filter_get_udta(filter);
     216             :         GF_FilterPacket *pck;
     217             :         u64 byte_offset;
     218             :         char *data;
     219             :         u32 pck_size, offset_in_pck;
     220             : 
     221        7614 :         if (ctx->done) return GF_EOS;
     222             : 
     223        7614 :         if (!ctx->is_playing && ctx->opid) return GF_OK;
     224             : 
     225        7018 :         pck = gf_filter_pid_get_packet(ctx->ipid);
     226        7018 :         if (!pck) {
     227        3498 :                 if (gf_filter_pid_is_eos(ctx->ipid) && !ctx->reverse_play) {
     228         428 :                         if (ctx->out_pck) {
     229           0 :                                 gf_filter_pck_send(ctx->out_pck);
     230           0 :                                 ctx->out_pck = NULL;
     231             :                         }
     232         428 :                         if (ctx->opid)
     233         428 :                                 gf_filter_pid_set_eos(ctx->opid);
     234             :                         return GF_EOS;
     235             :                 }
     236             :                 return GF_OK;
     237             :         }
     238             : 
     239        3520 :         data = (char *) gf_filter_pck_get_data(pck, &pck_size);
     240        3520 :         byte_offset = gf_filter_pck_get_byte_offset(pck);
     241             :         offset_in_pck = 0;
     242             : 
     243       10533 :         while (pck_size) {
     244             :                 Bool use_ref = GF_FALSE;
     245        3520 :                 if (!ctx->out_pck) {
     246             :                         assert(! ctx->nb_bytes_in_frame);
     247        3520 :                         if (!ctx->copy && (pck_size >= ctx->frame_size)) {
     248        3007 :                                 ctx->out_pck = gf_filter_pck_new_ref(ctx->opid, offset_in_pck, ctx->frame_size, pck);
     249        3007 :                                 use_ref = GF_TRUE;
     250             :                         } else {
     251         513 :                                 ctx->out_pck = gf_filter_pck_new_alloc(ctx->opid, ctx->frame_size, &ctx->out_data);
     252             :                         }
     253        3520 :                         if (!ctx->out_pck) return GF_OUT_OF_MEM;
     254             : 
     255        3520 :                         gf_filter_pck_set_cts(ctx->out_pck, ctx->cts);
     256        3520 :                         gf_filter_pck_set_sap(ctx->out_pck, GF_FILTER_SAP_1);
     257        3520 :                         gf_filter_pck_set_duration(ctx->out_pck, ctx->fps.den);
     258        3520 :                         gf_filter_pck_set_byte_offset(ctx->out_pck, byte_offset);
     259             :                 }
     260             : 
     261        3520 :                 if (pck_size + ctx->nb_bytes_in_frame < ctx->frame_size) {
     262           0 :                         memcpy(ctx->out_data + ctx->nb_bytes_in_frame, data, pck_size);
     263           0 :                         ctx->nb_bytes_in_frame += pck_size;
     264           0 :                         pck_size = 0;
     265             :                 } else {
     266        3520 :                         u32 remain = ctx->frame_size - ctx->nb_bytes_in_frame;
     267        3520 :                         if (!use_ref) {
     268         513 :                                 memcpy(ctx->out_data + ctx->nb_bytes_in_frame, data, remain);
     269             :                         }
     270        3520 :                         gf_filter_pck_send(ctx->out_pck);
     271             : 
     272        3520 :                         pck_size -= remain;
     273        3520 :                         data += remain;
     274        3520 :                         byte_offset += remain;
     275        3520 :                         offset_in_pck += remain;
     276             :                         
     277        3520 :                         ctx->out_pck = NULL;
     278        3520 :                         ctx->nb_bytes_in_frame = 0;
     279             : 
     280             :                         //reverse playback, the remaining data is for the next frame, we want the previous one.
     281             :                         //Trash packet and seek to previous frame
     282        3520 :                         if (ctx->reverse_play) {
     283             :                                 GF_FilterEvent fevt;
     284          27 :                                 if (!ctx->cts) {
     285           1 :                                         if (ctx->opid)
     286           1 :                                                 gf_filter_pid_set_eos(ctx->opid);
     287           1 :                                         ctx->done = GF_TRUE;
     288           1 :                                         return GF_EOS;
     289             :                                 }
     290          26 :                                 ctx->cts -= ctx->fps.den;
     291          26 :                                 ctx->filepos -= ctx->frame_size;
     292          26 :                                 gf_filter_pid_drop_packet(ctx->ipid);
     293             :                                 //post a seek, this will trash remaining packets in buffers
     294          26 :                                 GF_FEVT_INIT(fevt, GF_FEVT_SOURCE_SEEK, ctx->ipid);
     295          26 :                                 fevt.seek.start_offset = ctx->filepos;
     296          26 :                                 gf_filter_pid_send_event(ctx->ipid, &fevt);
     297          26 :                                 return GF_OK;
     298             :                         }
     299        3493 :                         ctx->cts += ctx->fps.den;
     300             :                 }
     301             :         }
     302        3493 :         gf_filter_pid_drop_packet(ctx->ipid);
     303        3493 :         return GF_OK;
     304             : }
     305             : 
     306             : 
     307             : static GF_FilterCapability RawVidReframeCaps[] =
     308             : {
     309             :         CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
     310             :         CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_FILE_EXT, "yuv"),
     311             :         CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_MIME, "video/x-yuv"),
     312             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
     313             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_RAW),
     314             :         CAP_UINT(GF_CAPS_OUTPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
     315             :         {0},
     316             :         CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
     317             :         CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_FILE_EXT, "v210"),
     318             :         CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_MIME, "video/x-raw-v210"),
     319             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
     320             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_V210),
     321             :         CAP_UINT(GF_CAPS_OUTPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
     322             : };
     323             : 
     324             : #define OFFS(_n)        #_n, offsetof(GF_RawVidReframeCtx, _n)
     325             : static GF_FilterArgs RawVidReframeArgs[] =
     326             : {
     327             :         { OFFS(size), "source video resolution", GF_PROP_VEC2I, "0x0", NULL, 0},
     328             :         { OFFS(spfmt), "source pixel format. When not set, derived from file extension", GF_PROP_PIXFMT, "none", NULL, 0},
     329             :         { OFFS(fps), "number of frames per second", GF_PROP_FRACTION, "25/1", NULL, 0},
     330             :         { OFFS(copy), "copy source bytes into output frame. If not set, source bytes are referenced only", GF_PROP_BOOL, "false", NULL, 0},
     331             :         {0}
     332             : };
     333             : 
     334             : 
     335             : GF_FilterRegister RawVidReframeRegister = {
     336             :         .name = "rfrawvid",
     337             :         GF_FS_SET_DESCRIPTION("RAW video reframer")
     338             :         GF_FS_SET_HELP("This filter parses raw YUV and RGB files/data and outputs corresponding raw video PID and frames.")
     339             :         .private_size = sizeof(GF_RawVidReframeCtx),
     340             :         .args = RawVidReframeArgs,
     341             :         SETCAPS(RawVidReframeCaps),
     342             :         .configure_pid = rawvidreframe_configure_pid,
     343             :         .process = rawvidreframe_process,
     344             :         .process_event = rawvidreframe_process_event
     345             : };
     346             : 
     347             : 
     348        2877 : const GF_FilterRegister *rawvidreframe_register(GF_FilterSession *session)
     349             : {
     350        2877 :         RawVidReframeArgs[1].min_max_enum = gf_pixel_fmt_all_names();
     351        2877 :         RawVidReframeCaps[1].val.value.string = (char *) gf_pixel_fmt_all_shortnames();
     352        2877 :         return &RawVidReframeRegister;
     353             : }
     354             : 

Generated by: LCOV version 1.13