LCOV - code coverage report
Current view: top level - filters - dec_xvid.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 129 146 88.4 %
Date: 2021-04-29 23:48:07 Functions: 5 5 100.0 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2000-2021
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / MPEG-4 visual p2 xvid decoder 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             : 
      27             : #include <gpac/filters.h>
      28             : #include <gpac/avparse.h>
      29             : #include <gpac/constants.h>
      30             : 
      31             : 
      32             : /*if we don't have M4V (A)SP parser, we con't get width and height and xvid is then unusable ...*/
      33             : #if !defined(GPAC_DISABLE_AV_PARSERS) && defined(GPAC_HAS_XVID)
      34             : 
      35             : #if !defined(__GNUC__)
      36             : # if defined(_WIN32_WCE) || defined (WIN32)
      37             : #  pragma comment(lib, "libxvidcore")
      38             : # endif
      39             : #endif
      40             : 
      41             : 
      42             : #include <xvid.h>
      43             : 
      44             : #ifndef XVID_DEC_FRAME
      45             : #define XVID_DEC_FRAME xvid_dec_frame_t
      46             : #define XVID_DEC_PARAM xvid_dec_create_t
      47             : #else
      48             : #define XVID_USE_OLD_API
      49             : #endif
      50             : 
      51             : //#undef XVID_USE_OLD_API
      52             : 
      53             : static Bool xvid_is_init = GF_FALSE;
      54             : 
      55             : typedef struct
      56             : {
      57             :         Bool deblock_y;
      58             :         Bool deblock_uv;
      59             : #ifndef XVID_USE_OLD_API
      60             :         Bool film_effect;
      61             :         Bool dering_y;
      62             :         Bool dering_uv;
      63             : #endif
      64             : 
      65             :         GF_FilterPid *ipid, *opid;
      66             :         u32 cfg_crc;
      67             :         void *codec;
      68             : 
      69             :         u32 width, height, out_size;
      70             :         GF_Fraction pixel_ar;
      71             :         Bool first_frame;
      72             :         s32 base_filters;
      73             :         Float FPS;
      74             :         u32 offset;
      75             : 
      76             :         GF_List *src_packets;
      77             :         u64 next_cts;
      78             : 
      79             : } GF_XVIDCtx;
      80             : 
      81          29 : static GF_Err xviddec_initialize(GF_Filter *filter)
      82             : {
      83          29 :         GF_XVIDCtx *ctx = gf_filter_get_udta(filter);
      84          29 :         if (!xvid_is_init) {
      85             : #ifdef XVID_USE_OLD_API
      86             :                 XVID_INIT_PARAM init;
      87             :                 init.api_version = 0;
      88             :                 init.core_build = 0;
      89             :                 /*get info*/
      90             :                 init.cpu_flags = XVID_CPU_CHKONLY;
      91             :                 xvid_init(NULL, 0, &init, NULL);
      92             :                 /*then init*/
      93             :                 xvid_init(NULL, 0, &init, NULL);
      94             : #else
      95             :                 xvid_gbl_init_t init;
      96          29 :                 init.debug = 0;
      97          29 :                 init.version = XVID_VERSION;
      98          29 :                 init.cpu_flags = 0; /*autodetect*/
      99          29 :                 xvid_global(NULL, 0, &init, NULL);
     100             : #endif
     101          29 :                 xvid_is_init = GF_TRUE;
     102             :         }
     103             : 
     104             : #ifndef XVID_USE_OLD_API
     105          29 :         if (ctx->film_effect) ctx->base_filters |= XVID_FILMEFFECT;
     106             : #endif
     107             : 
     108             : #ifdef XVID_USE_OLD_API
     109             :         if (ctx->deblock_y) ctx->base_filters |= XVID_DEC_DEBLOCKY;
     110             : #else
     111          29 :         if (ctx->deblock_y) ctx->base_filters |= XVID_DEBLOCKY;
     112             : #endif
     113             : 
     114             : #ifdef XVID_USE_OLD_API
     115             :         if (ctx->deblock_uv) ctx->base_filters |= XVID_DEC_DEBLOCKUV;
     116             : #else
     117          29 :         if (ctx->deblock_uv) ctx->base_filters |= XVID_DEBLOCKUV;
     118             : #endif
     119             : 
     120             : #ifndef XVID_USE_OLD_API
     121          29 :         if (ctx->dering_y) ctx->base_filters |= XVID_DERINGY | XVID_DEBLOCKY;
     122          29 :         if (ctx->dering_uv) ctx->base_filters |= XVID_DERINGUV | XVID_DEBLOCKUV;
     123             : #endif
     124          29 :         ctx->src_packets = gf_list_new();
     125          29 :         return GF_OK;
     126             : }
     127             : 
     128          30 : static GF_Err xviddec_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
     129             : {
     130             :         const GF_PropertyValue *p;
     131             :         GF_M4VDecSpecInfo dsi;
     132             :         GF_Err e;
     133             :         Bool is_first = GF_FALSE;
     134             : #ifdef XVID_USE_OLD_API
     135             :         XVID_DEC_FRAME frame;
     136             :         XVID_DEC_PARAM par;
     137             : #else
     138             :         xvid_dec_frame_t frame;
     139             :         xvid_dec_create_t par;
     140             : #endif
     141          30 :         GF_XVIDCtx *ctx = gf_filter_get_udta(filter);
     142             : 
     143          30 :         if (is_remove) {
     144           0 :                 if (ctx->opid) {
     145           0 :                         gf_filter_pid_remove(ctx->opid);
     146           0 :                         ctx->opid = NULL;
     147             :                 }
     148           0 :                 ctx->ipid = NULL;
     149           0 :                 return GF_OK;
     150             :         }
     151          30 :         if (! gf_filter_pid_check_caps(pid))
     152             :                 return GF_NOT_SUPPORTED;
     153             : 
     154          29 :         ctx->ipid = pid;
     155          29 :         if (!ctx->opid) {
     156          29 :                 ctx->opid = gf_filter_pid_new(filter);
     157          29 :                 gf_filter_pid_set_framing_mode(ctx->ipid, GF_TRUE);
     158             :                 is_first = GF_TRUE;
     159             :         }
     160             :         //copy properties at init or reconfig
     161          29 :         gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
     162          29 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, &PROP_UINT(GF_CODECID_RAW) );
     163             : 
     164          29 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_DECODER_CONFIG);
     165          29 :         if (p && p->value.data.ptr && p->value.data.size) {
     166          29 :                 u32 ex_crc = gf_crc_32(p->value.data.ptr, p->value.data.size);
     167          29 :                 if (ctx->cfg_crc == ex_crc) return GF_OK;
     168             : 
     169             :                 //shoud we flush ?
     170          29 :                 if (ctx->codec) xvid_decore(ctx->codec, XVID_DEC_DESTROY, NULL, NULL);
     171          29 :                 ctx->codec = NULL;
     172             : 
     173          29 :                 ctx->cfg_crc = ex_crc;
     174           0 :         } else if (!is_first) {
     175           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[XVID] Reconfiguring without DSI not yet supported\n"));
     176             :                 return GF_NOT_SUPPORTED;
     177             :         } else {
     178             :                 return GF_OK;
     179             :         }
     180             : 
     181             :         /*decode DSI*/
     182          29 :         e = gf_m4v_get_config(p->value.data.ptr, p->value.data.size, &dsi);
     183          29 :         if (e) return e;
     184          29 :         if (!dsi.width || !dsi.height) return GF_NON_COMPLIANT_BITSTREAM;
     185             : 
     186             :         memset(&par, 0, sizeof(par));
     187          29 :         par.width = dsi.width;
     188          29 :         par.height = dsi.height;
     189             :         /*note that this may be irrelevant when used through systems (FPS is driven by systems CTS)*/
     190          29 :         ctx->FPS = dsi.clock_rate;
     191          29 :         ctx->FPS /= 1000;
     192          29 :         if (!ctx->FPS) ctx->FPS = 30.0f;
     193          29 :         ctx->pixel_ar.num = dsi.par_num;
     194          29 :         ctx->pixel_ar.den = dsi.par_den;
     195             : 
     196             : #ifndef XVID_USE_OLD_API
     197          29 :         par.version = XVID_VERSION;
     198             : #endif
     199             : 
     200          29 :         if (xvid_decore(NULL, XVID_DEC_CREATE, &par, NULL) < 0) return GF_NON_COMPLIANT_BITSTREAM;
     201             : 
     202          29 :         ctx->width = par.width;
     203          29 :         ctx->height = par.height;
     204          29 :         ctx->codec = par.handle;
     205             : 
     206             :         /*init decoder*/
     207             :         memset(&frame, 0, sizeof(frame));
     208          29 :         frame.bitstream = (void *) p->value.data.ptr;
     209          29 :         frame.length = p->value.data.size;
     210             : #ifndef XVID_USE_OLD_API
     211          29 :         frame.version = XVID_VERSION;
     212          29 :         xvid_decore(ctx->codec, XVID_DEC_DECODE, &frame, NULL);
     213             : #else
     214             :         /*don't perform error check, XviD doesn't like DSI only frame ...*/
     215             :         xvid_decore(ctx->codec, XVID_DEC_DECODE, &frame, NULL);
     216             : #endif
     217             : 
     218          29 :         ctx->first_frame = GF_TRUE;
     219          29 :         ctx->out_size = ctx->width * ctx->height * 3 / 2;
     220             : 
     221          29 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_WIDTH, &PROP_UINT(ctx->width) );
     222          29 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_HEIGHT, &PROP_UINT(ctx->height) );
     223          29 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STRIDE, &PROP_UINT(ctx->width) );
     224          29 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_PAR, &PROP_FRAC(ctx->pixel_ar) );
     225          29 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_PIXFMT, &PROP_UINT(GF_PIXEL_YUV) );
     226             : 
     227          29 :         return GF_OK;
     228             : }
     229             : 
     230          29 : static void xviddec_finalize(GF_Filter *filter)
     231             : {
     232          29 :         GF_XVIDCtx *ctx = gf_filter_get_udta(filter);
     233          29 :         if (ctx->codec) xvid_decore(ctx->codec, XVID_DEC_DESTROY, NULL, NULL);
     234          35 :         while (gf_list_count(ctx->src_packets)) {
     235           6 :                 GF_FilterPacket *pck = gf_list_pop_back(ctx->src_packets);
     236           6 :                 gf_filter_pck_unref(pck);
     237             :         }
     238          29 :         gf_list_del(ctx->src_packets);
     239          29 : }
     240             : 
     241        4106 : static GF_Err xviddec_process(GF_Filter *filter)
     242             : {
     243             : #ifdef XVID_USE_OLD_API
     244             :         XVID_DEC_FRAME frame;
     245             : #else
     246             :         xvid_dec_frame_t frame;
     247             : #endif
     248             :         u8 *buffer;
     249             :         u32 i, count;
     250             :         Bool is_seek;
     251             : #if 0
     252             :         s32 postproc;
     253             : #endif
     254             :         s32 res;
     255        4106 :         GF_XVIDCtx *ctx = gf_filter_get_udta(filter);
     256             :         GF_FilterPacket *pck, *pck_ref, *src_pck, *dst_pck;
     257             : 
     258        4106 :         pck = gf_filter_pid_get_packet(ctx->ipid);
     259             : 
     260        4106 :         if (!ctx->codec)
     261           0 :                 return ctx->cfg_crc ? GF_SERVICE_ERROR : GF_OK;
     262             : 
     263             :         memset(&frame, 0, sizeof(frame));
     264        4106 :         if (pck) {
     265        4021 :                 u64 cts = gf_filter_pck_get_cts(pck);;
     266        4021 :                 frame.bitstream = (char *) gf_filter_pck_get_data(pck, &frame.length);
     267             : 
     268             :                 //append in cts order since we get output frames in cts order
     269        4021 :                 pck_ref = pck;
     270        4021 :                 gf_filter_pck_ref_props(&pck_ref);
     271        4021 :                 count = gf_list_count(ctx->src_packets);
     272             :                 src_pck = NULL;
     273        5453 :                 for (i=0; i<count; i++) {
     274             :                         u64 acts;
     275        3992 :                         src_pck = gf_list_get(ctx->src_packets, i);
     276        3992 :                         acts = gf_filter_pck_get_cts(src_pck);
     277        3992 :                         if (acts==cts) {
     278           0 :                                 gf_filter_pck_unref(pck_ref);
     279           0 :                                 break;
     280             :                         }
     281        3992 :                         if (acts>cts) {
     282        2560 :                                 gf_list_insert(ctx->src_packets, pck_ref, i);
     283        2560 :                                 break;
     284             :                         }
     285             :                         src_pck = NULL;
     286             :                 }
     287        4021 :                 if (!src_pck)
     288        1461 :                         gf_list_add(ctx->src_packets, pck_ref);
     289             : 
     290             : 
     291             :         } else {
     292             :                 frame.bitstream = NULL;
     293          85 :                 frame.length = -1;
     294             :         }
     295             : 
     296             : packed_frame :
     297             : 
     298        4106 :         dst_pck = gf_filter_pck_new_alloc(ctx->opid, ctx->width*ctx->height*3/2, &buffer);
     299        4106 :         if (!dst_pck) return GF_OUT_OF_MEM;
     300             : 
     301             : #ifdef XVID_USE_OLD_API
     302             :         frame.colorspace = XVID_CSP_I420;
     303             :         frame.stride = ctx->width;
     304             :         frame.image = (void *) buffer;
     305             : #else
     306        4106 :         frame.version = XVID_VERSION;
     307        4106 :         frame.output.csp = XVID_CSP_I420;
     308        4106 :         frame.output.stride[0] = ctx->width;
     309        4106 :         frame.output.plane[0] = (void *) buffer;
     310             : #endif
     311             : 
     312             : 
     313             : #if 0
     314             :         postproc = ctx->base_filters;
     315             :         /*to check, not convinced yet by results...*/
     316             :         switch (mmlevel) {
     317             :         case GF_CODEC_LEVEL_SEEK:
     318             :         case GF_CODEC_LEVEL_DROP:
     319             :                 /*turn off all post-proc*/
     320             : #ifdef XVID_USE_OLD_API
     321             :                 postproc &= ~XVID_DEC_DEBLOCKY;
     322             :                 postproc &= ~XVID_DEC_DEBLOCKUV;
     323             : #else
     324             :                 postproc &= ~XVID_DEBLOCKY;
     325             :                 postproc &= ~XVID_DEBLOCKUV;
     326             :                 postproc &= ~XVID_FILMEFFECT;
     327             : #endif
     328             :                 break;
     329             :         case GF_CODEC_LEVEL_VERY_LATE:
     330             :                 /*turn off post-proc*/
     331             : #ifdef XVID_USE_OLD_API
     332             :                 postproc &= ~XVID_DEC_DEBLOCKY;
     333             : #else
     334             :                 postproc &= ~XVID_FILMEFFECT;
     335             :                 postproc &= ~XVID_DEBLOCKY;
     336             : #endif
     337             :                 break;
     338             :         case GF_CODEC_LEVEL_LATE:
     339             : #ifdef XVID_USE_OLD_API
     340             :                 postproc &= ~XVID_DEC_DEBLOCKUV;
     341             : #else
     342             :                 postproc &= ~XVID_DEBLOCKUV;
     343             :                 postproc &= ~XVID_FILMEFFECT;
     344             : #endif
     345             :                 break;
     346             :         }
     347             : #endif
     348             : 
     349             :         /*xvid may keep the first I frame and force a 1-frame delay, so we simply trick it*/
     350        4106 :         if (ctx->first_frame) {
     351          29 :                 buffer[0] = 'v';
     352          29 :                 buffer[1] = 'o';
     353          29 :                 buffer[2] = 'i';
     354          29 :                 buffer[3] = 'd';
     355             :         }
     356        4106 :         src_pck = gf_list_get(ctx->src_packets, 0);
     357             : 
     358        4106 :         res = xvid_decore(ctx->codec, XVID_DEC_DECODE, &frame, NULL);
     359        4106 :         if (res < 0) {
     360          62 :                 gf_filter_pck_discard(dst_pck);
     361          62 :                 if (pck) gf_filter_pid_drop_packet(ctx->ipid);
     362          62 :                 if (src_pck) {
     363           0 :                         gf_filter_pck_unref(src_pck);
     364           0 :                         gf_list_pop_front(ctx->src_packets);
     365             :                 }
     366          62 :                 if (gf_filter_pid_is_eos(ctx->ipid)) {
     367          11 :                         gf_filter_pid_set_eos(ctx->opid);
     368          11 :                         return GF_EOS;
     369             :                 }
     370          51 :                 return pck ? GF_NON_COMPLIANT_BITSTREAM : GF_OK;
     371             :         }
     372             : 
     373        4044 :         if (ctx->first_frame) {
     374          29 :                 ctx->first_frame = GF_FALSE;
     375          29 :                 if ((buffer[0] == 'v') && (buffer[1] == 'o') && (buffer[2] == 'i') && (buffer[3] =='d')) {
     376          29 :                         gf_filter_pck_discard(dst_pck);
     377          29 :                         if (pck) gf_filter_pid_drop_packet(ctx->ipid);
     378             :                         return GF_OK;
     379             :                 }
     380             :         }
     381             : 
     382        4015 :         if (src_pck) {
     383        4015 :                 gf_filter_pck_merge_properties(src_pck, dst_pck);
     384        4015 :                 is_seek = gf_filter_pck_get_seek_flag(src_pck);
     385        4015 :                 ctx->next_cts = gf_filter_pck_get_cts(src_pck);
     386        4015 :                 ctx->next_cts += gf_filter_pck_get_duration(src_pck);
     387        4015 :                 gf_filter_pck_unref(src_pck);
     388        4015 :                 gf_list_pop_front(ctx->src_packets);
     389             :         } else {
     390             :                 is_seek = 0;
     391           0 :                 gf_filter_pck_set_cts(dst_pck, ctx->next_cts);
     392             :         }
     393             : 
     394        4015 :         if (!pck || !is_seek )
     395        4015 :                 gf_filter_pck_send(dst_pck);
     396             :         else
     397           0 :                 gf_filter_pck_discard(dst_pck);
     398             : 
     399        4015 :         if (res + 6 < frame.length) {
     400           0 :                 frame.bitstream = ((char *)frame.bitstream) + res;
     401           0 :                 frame.length -= res;
     402           0 :                 goto packed_frame;
     403             :         }
     404             : 
     405        4015 :         if (pck) {
     406        3992 :                 gf_filter_pid_drop_packet(ctx->ipid);
     407             :         }
     408             :         //flush all frames if eos is detected
     409          23 :         else if (gf_filter_pid_is_eos(ctx->ipid)) {
     410           6 :                 return xviddec_process(filter);
     411             :         }
     412             : 
     413             :         return GF_OK;
     414             : }
     415             : 
     416             : static const GF_FilterCapability XVIDCaps[] =
     417             : {
     418             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
     419             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG4_PART2),
     420             :         CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
     421             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
     422             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_RAW),
     423             : };
     424             : 
     425             : #define OFFS(_n)        #_n, offsetof(GF_XVIDCtx, _n)
     426             : 
     427             : static const GF_FilterArgs XVIDArgs[] =
     428             : {
     429             :         { OFFS(deblock_y), "enable Y deblocking", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
     430             :         { OFFS(deblock_uv), "enable UV deblocking", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
     431             : #ifndef XVID_USE_OLD_API
     432             :         { OFFS(film_effect), "enable film effect", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
     433             :         { OFFS(dering_y), "enable Y deblocking", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
     434             :         { OFFS(dering_uv), "enable UV deblocking", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
     435             : #endif
     436             :         {0}
     437             : };
     438             : 
     439             : GF_FilterRegister XVIDRegister = {
     440             :         .name = "xviddec",
     441             :         GF_FS_SET_DESCRIPTION("XVid decoder")
     442             :         GF_FS_SET_HELP("This filter decodes MPEG-4 part 2 (and DivX) through libxvidcore library.")
     443             :         .private_size = sizeof(GF_XVIDCtx),
     444             :         .args = XVIDArgs,
     445             :         SETCAPS(XVIDCaps),
     446             :         .initialize = xviddec_initialize,
     447             :         .finalize = xviddec_finalize,
     448             :         .configure_pid = xviddec_configure_pid,
     449             :         .process = xviddec_process,
     450             :         //use low priorty, below ffmpeg one, so that hardware decs/other native impl in gpac can take over if needed
     451             :         //don't use lowest one since we use this for scalable codecs
     452             :         .priority = 100
     453             : };
     454             : 
     455             : #endif
     456             : 
     457        2877 : const GF_FilterRegister *xviddec_register(GF_FilterSession *session)
     458             : {
     459             : #if !defined(GPAC_DISABLE_AV_PARSERS) && defined(GPAC_HAS_XVID)
     460        2877 :         return &XVIDRegister;
     461             : #else
     462             :         return NULL;
     463             : #endif
     464             : }

Generated by: LCOV version 1.13