LCOV - code coverage report
Current view: top level - filters - rewrite_obu.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 157 187 84.0 %
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 / AV1 OBU rewrite 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/constants.h>
      28             : #include <gpac/bitstream.h>
      29             : #include <gpac/internal/media_dev.h>
      30             : 
      31             : #ifndef GPAC_DISABLE_AV_PARSERS
      32             : 
      33             : typedef struct
      34             : {
      35             :         //opts
      36             :         Bool rcfg, tsep;
      37             : 
      38             :         //only one input pid declared
      39             :         GF_FilterPid *ipid;
      40             :         //only one output pid declared
      41             :         GF_FilterPid *opid;
      42             : 
      43             :         u32 crc;
      44             : 
      45             :         Bool ivf_hdr;
      46             :         u32 mode;
      47             :         GF_BitStream *bs_w;
      48             :         GF_BitStream *bs_r;
      49             :         u32 w, h;
      50             :         GF_Fraction fps;
      51             :         GF_AV1Config *av1c;
      52             :         u32 av1b_cfg_size;
      53             :         u32 codec_id;
      54             : } GF_OBUMxCtx;
      55             : 
      56           4 : GF_Err obumx_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
      57             : {
      58             :         u32 crc;
      59             :         const GF_PropertyValue *p, *dcd;
      60           4 :         GF_OBUMxCtx *ctx = gf_filter_get_udta(filter);
      61             : 
      62           4 :         if (is_remove) {
      63           0 :                 ctx->ipid = NULL;
      64           0 :                 if (ctx->opid) {
      65           0 :                         gf_filter_pid_remove(ctx->opid);
      66           0 :                         ctx->opid = NULL;
      67             :                 }
      68             :                 return GF_OK;
      69             :         }
      70           4 :         if (! gf_filter_pid_check_caps(pid))
      71             :                 return GF_NOT_SUPPORTED;
      72             : 
      73           4 :         dcd = gf_filter_pid_get_property(pid, GF_PROP_PID_DECODER_CONFIG);
      74           4 :         if (!dcd) return GF_NON_COMPLIANT_BITSTREAM;
      75             : 
      76           4 :         crc = gf_crc_32(dcd->value.data.ptr, dcd->value.data.size);
      77           4 :         if (ctx->crc == crc) return GF_OK;
      78           4 :         ctx->crc = crc;
      79             : 
      80           4 :         if (!ctx->opid) {
      81           4 :                 ctx->opid = gf_filter_pid_new(filter);
      82             :         }
      83             :         //copy properties at init or reconfig
      84           4 :         gf_filter_pid_copy_properties(ctx->opid, pid);
      85             : 
      86           4 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_UNFRAMED, &PROP_BOOL(GF_TRUE) );
      87             : 
      88           4 :         ctx->ipid = pid;
      89             : 
      90           4 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DECODER_CONFIG, NULL);
      91             : 
      92           4 :         p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_CODECID);
      93           4 :         ctx->codec_id = p ? p->value.uint : 0;
      94           4 :         switch (ctx->codec_id) {
      95           4 :         case GF_CODECID_AV1:
      96             :                 //check output type OBU vs av1b
      97           4 :                 p = gf_filter_pid_caps_query(ctx->opid, GF_PROP_PID_FILE_EXT);
      98           4 :                 if (p) {
      99           4 :                         if (!strcmp(p->value.string, "obu")) ctx->mode = 0;
     100           3 :                         else if (!strcmp(p->value.string, "av1b") || !strcmp(p->value.string, "av1")) ctx->mode = 1;
     101             :                         //we might want to add a generic IVF read/write at some point
     102           1 :                         else if (!strcmp(p->value.string, "ivf")) {
     103           1 :                                 ctx->mode = 2;
     104           1 :                                 ctx->ivf_hdr = 1;
     105             :                         }
     106             :                 } else {
     107           0 :                         GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[OBUWrite] Couldn't guess desired output format type, assuming plain OBU\n"));
     108             :                 }
     109             :                 break;
     110           0 :         case GF_CODECID_VP8:
     111             :         case GF_CODECID_VP9:
     112             :         case GF_CODECID_VP10:
     113           0 :                 ctx->mode = 2; //IVF only
     114           0 :                 ctx->ivf_hdr = 1;
     115           0 :                 break;
     116             :         }
     117             : 
     118           4 :         if (ctx->av1c) gf_odf_av1_cfg_del(ctx->av1c);
     119           4 :         ctx->av1c = NULL;
     120           4 :         if (ctx->mode==1) {
     121           2 :                 u32 i=0;
     122             :                 GF_AV1_OBUArrayEntry *obu;
     123           2 :                 ctx->av1c = gf_odf_av1_cfg_read(dcd->value.data.ptr, dcd->value.data.size);
     124           2 :                 if (!ctx->av1c) {
     125           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[OBUWrite] Invalid av1 config\n"));
     126           0 :                         return GF_NON_COMPLIANT_BITSTREAM;
     127             :                 }
     128           2 :                 ctx->av1b_cfg_size = 0;
     129             : 
     130           6 :                 while ((obu = gf_list_enum(ctx->av1c->obu_array, &i))) {
     131             :                         //we don't output sequence header since it shall be present in sync sample
     132             :                         //this avoids creating duplicate of the seqeunce header in the output stream
     133           2 :                         if (obu->obu_type==OBU_SEQUENCE_HEADER) {
     134           2 :                                 i--;
     135           2 :                                 gf_list_rem(ctx->av1c->obu_array, i);
     136           2 :                                 gf_free(obu->obu);
     137           2 :                                 gf_free(obu);
     138           2 :                                 continue;
     139             :                         }
     140           0 :                         ctx->av1b_cfg_size += (u32) obu->obu_length;
     141           0 :                         ctx->av1b_cfg_size += gf_av1_leb128_size(obu->obu_length);
     142             :                 }
     143             :         }
     144             : 
     145             : 
     146           4 :         p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_WIDTH);
     147           4 :         if (p) ctx->w = p->value.uint;
     148           4 :         p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_HEIGHT);
     149           4 :         if (p) ctx->h = p->value.uint;
     150           4 :         p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FPS);
     151           4 :         if (p) ctx->fps = p->value.frac;
     152           4 :         if (!ctx->fps.num || !ctx->fps.den) {
     153           1 :                 ctx->fps.num = 25;
     154           1 :                 ctx->fps.den = 1;
     155             :         }
     156           4 :         gf_filter_pid_set_property_str(ctx->opid, "obu:mode", &PROP_UINT(ctx->mode) );
     157           4 :         gf_filter_pid_set_framing_mode(ctx->ipid, GF_TRUE);
     158             : 
     159           4 :         return GF_OK;
     160             : }
     161             : 
     162             : 
     163         524 : GF_Err obumx_process(GF_Filter *filter)
     164             : {
     165             :         u32 i;
     166             :         u32 frame_sizes[128], max_frames;
     167         524 :         GF_OBUMxCtx *ctx = gf_filter_get_udta(filter);
     168             :         GF_FilterPacket *pck, *dst_pck;
     169             :         u8 *data, *output;
     170             :         u32 pck_size, size, sap_type, hdr_size, av1b_frame_size=0;
     171             : 
     172             : 
     173         524 :         pck = gf_filter_pid_get_packet(ctx->ipid);
     174         524 :         if (!pck) {
     175           4 :                 if (gf_filter_pid_is_eos(ctx->ipid)) {
     176           4 :                         gf_filter_pid_set_eos(ctx->opid);
     177           4 :                         return GF_EOS;
     178             :                 }
     179             :                 return GF_OK;
     180             :         }
     181             : 
     182         520 :         data = (char *) gf_filter_pck_get_data(pck, &pck_size);
     183             :         hdr_size = 0;
     184         520 :         size = pck_size;
     185             :         //always add temporal delim
     186         520 :         if (ctx->codec_id==GF_CODECID_AV1)
     187         520 :                 size += 2;
     188             : 
     189         520 :         sap_type = gf_filter_pck_get_sap(pck);
     190         520 :         if (!sap_type) {
     191         516 :                 u8 flags = gf_filter_pck_get_dependency_flags(pck);
     192         516 :                 if (flags) {
     193             :                         //get dependsOn
     194           0 :                         flags>>=4;
     195           0 :                         flags &= 0x3;
     196           0 :                         if (flags==2) sap_type = 3; //could be 1, 2 or 3
     197             :                 }
     198             :         }
     199             : 
     200             :         memset(frame_sizes, 0, sizeof(u32)*128);
     201         520 :         if (ctx->mode==2) {
     202         173 :                 if (ctx->ivf_hdr) hdr_size += 32;
     203         173 :                 hdr_size += 12;
     204             :         }
     205         520 :         if (ctx->mode==1) {
     206             :                 u32 obu_sizes=0;
     207             :                 u32 frame_idx=0;
     208             : 
     209         174 :                 obu_sizes = frame_sizes[0] = 3;
     210         174 :                 if (sap_type && ctx->av1b_cfg_size) {
     211           0 :                         frame_sizes[0] += ctx->av1b_cfg_size;
     212             :                         obu_sizes += ctx->av1b_cfg_size;
     213             :                 }
     214             : 
     215         174 :                 if (!ctx->bs_r) ctx->bs_r = gf_bs_new(data, pck_size, GF_BITSTREAM_READ);
     216         172 :                 else gf_bs_reassign_buffer(ctx->bs_r, data, pck_size);
     217             : 
     218         367 :                 while (gf_bs_available(ctx->bs_r)) {
     219             :                         ObuType obu_type;
     220             :                         u32 obu_size;
     221             :                         Bool obu_extension_flag, obu_has_size_field;
     222             :                         u8 temporal_id, spatial_id;
     223         193 :                         u32 obu_hdr_size = (u32) gf_bs_get_position(ctx->bs_r);
     224             : 
     225         193 :                         gf_av1_parse_obu_header(ctx->bs_r, &obu_type, &obu_extension_flag, &obu_has_size_field, &temporal_id, &spatial_id);
     226             : 
     227         193 :                         if (!obu_has_size_field) {
     228           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_CODING, ("[OBUWrite] OBU without size field, bug in demux filter !!\n"));
     229           0 :                                 return GF_NON_COMPLIANT_BITSTREAM;
     230             :                         }
     231         193 :                         obu_size = (u32)gf_av1_leb128_read(ctx->bs_r, NULL);
     232         193 :                         obu_hdr_size = (u32) gf_bs_get_position(ctx->bs_r) - obu_hdr_size;
     233         193 :                         gf_bs_skip_bytes(ctx->bs_r, obu_size);
     234             : 
     235         193 :                         obu_size += obu_hdr_size;
     236         193 :                         obu_sizes += obu_size + gf_av1_leb128_size(obu_size);
     237             : 
     238         193 :                         if (obu_type==OBU_FRAME) {
     239         191 :                                 frame_idx++;
     240         191 :                                 if (frame_idx==128) {
     241           0 :                                         GF_LOG(GF_LOG_ERROR, GF_LOG_CODING, ("[OBUWrite] more than 128 frames in a temporal unit not supported\n"));
     242             :                                         return GF_NOT_SUPPORTED;
     243             :                                 }
     244         191 :                                 if (frame_idx>1)
     245          17 :                                         frame_sizes[frame_idx-1] = 0;
     246             :                         }
     247         193 :                         frame_sizes[frame_idx ? (frame_idx-1) : 0] += obu_size + gf_av1_leb128_size(obu_size);
     248             :                 }
     249             :                 max_frames = frame_idx;
     250             :                 size = obu_sizes;
     251             :                 //packet without frame
     252         174 :                 if (!max_frames) {
     253           0 :                         size += gf_av1_leb128_size(frame_sizes[0]);
     254             :                 } else {
     255         365 :                         for (i=0;i<max_frames; i++) {
     256         191 :                                 size += gf_av1_leb128_size(frame_sizes[i]);
     257             :                         }
     258             :                 }
     259             :                 av1b_frame_size = size;
     260         174 :                 size += gf_av1_leb128_size(size);
     261             :         } else {
     262         346 :                 if (sap_type && ctx->av1b_cfg_size) size += ctx->av1b_cfg_size;
     263             :         }
     264             : 
     265         520 :         dst_pck = gf_filter_pck_new_alloc(ctx->opid, hdr_size+size, &output);
     266         520 :         if (!dst_pck) return GF_OUT_OF_MEM;
     267             :         
     268         520 :         gf_filter_pck_merge_properties(pck, dst_pck);
     269             : 
     270         520 :         if (!ctx->bs_w) ctx->bs_w = gf_bs_new(output, hdr_size+size, GF_BITSTREAM_WRITE);
     271         516 :         else gf_bs_reassign_buffer(ctx->bs_w, output, hdr_size+size);
     272             : 
     273         520 :         if (ctx->mode==1) {
     274             :                 u32 frame_idx = 0;
     275             :                 //temporal unit
     276         174 :                 gf_av1_leb128_write(ctx->bs_w, av1b_frame_size);
     277             :                 assert(frame_sizes[0]);
     278         174 :                 gf_av1_leb128_write(ctx->bs_w, frame_sizes[0]);
     279             : 
     280             :                 //write temporal delim with obu size set
     281         174 :                 gf_av1_leb128_write(ctx->bs_w, 2);
     282         174 :                 gf_bs_write_u8(ctx->bs_w, 0x12);
     283         174 :                 gf_bs_write_u8(ctx->bs_w, 0);
     284             : 
     285         174 :                 if (sap_type && ctx->av1b_cfg_size) {
     286             :                         GF_AV1_OBUArrayEntry *obu;
     287           0 :                         i=0;
     288           0 :                         while ((obu = gf_list_enum(ctx->av1c->obu_array, &i))) {
     289           0 :                                 gf_av1_leb128_write(ctx->bs_w, obu->obu_length);
     290           0 :                                 gf_bs_write_data(ctx->bs_w, obu->obu, (u32) obu->obu_length);
     291             :                         }
     292             :                 }
     293             : 
     294         174 :                 gf_bs_reassign_buffer(ctx->bs_r, data, pck_size);
     295             : 
     296         541 :                 while (gf_bs_available(ctx->bs_r)) {
     297             :                         ObuType obu_type;
     298             :                         u32 obu_size;
     299             :                         Bool obu_extension_flag, obu_has_size_field;
     300             :                         u8 temporal_id, spatial_id;
     301         193 :                         u32 obu_hdr_size, start = (u32) gf_bs_get_position(ctx->bs_r);
     302             : 
     303         193 :                         gf_av1_parse_obu_header(ctx->bs_r, &obu_type, &obu_extension_flag, &obu_has_size_field, &temporal_id, &spatial_id);
     304         193 :                         obu_size = (u32)gf_av1_leb128_read(ctx->bs_r, NULL);
     305             : 
     306         193 :                         obu_hdr_size = (u32) gf_bs_get_position(ctx->bs_r) - start;
     307         193 :                         gf_bs_skip_bytes(ctx->bs_r, obu_size);
     308             : 
     309         193 :                         if (obu_type==OBU_FRAME) {
     310         191 :                                 frame_idx++;
     311         191 :                                 if (frame_idx>1) {
     312          17 :                                         gf_av1_leb128_write(ctx->bs_w, frame_sizes[frame_idx-1] );
     313             :                                 }
     314             :                         }
     315             : 
     316         193 :                         obu_size += obu_hdr_size;
     317         193 :                         gf_av1_leb128_write(ctx->bs_w, obu_size);
     318         193 :                         gf_bs_write_data(ctx->bs_w, data+start, obu_size);
     319             : 
     320             :                 }
     321             :                 assert(gf_bs_get_position(ctx->bs_w) == size);
     322             :         } else {
     323             : 
     324             :                 //write IVF headers
     325         346 :                 if (ctx->ivf_hdr) {
     326           1 :                         gf_bs_write_u32(ctx->bs_w, GF_4CC('D', 'K', 'I', 'F'));
     327           1 :                         gf_bs_write_u16_le(ctx->bs_w, 0);
     328           1 :                         gf_bs_write_u16_le(ctx->bs_w, 32);
     329             : 
     330           1 :                         gf_bs_write_u32(ctx->bs_w, GF_4CC('A', 'V', '0', '1') ); //codec_fourcc
     331           1 :                         gf_bs_write_u16_le(ctx->bs_w, ctx->w);
     332           1 :                         gf_bs_write_u16_le(ctx->bs_w, ctx->h);
     333           1 :                         gf_bs_write_u32_le(ctx->bs_w, ctx->fps.num);
     334           1 :                         gf_bs_write_u32_le(ctx->bs_w, ctx->fps.den);
     335           1 :                         gf_bs_write_u32_le(ctx->bs_w, 0); //nb frames
     336           1 :                         gf_bs_write_u32_le(ctx->bs_w, 0);
     337           1 :                         ctx->ivf_hdr = 0;
     338             :                 }
     339         346 :                 if (ctx->mode==2) {
     340         173 :                         u64 cts = gf_filter_pck_get_cts(pck);
     341         173 :                         cts *= ctx->fps.den;
     342         173 :                         cts /= ctx->fps.num;
     343         173 :                         cts /= gf_filter_pck_get_timescale(pck);
     344         173 :                         gf_bs_write_u32_le(ctx->bs_w, size);
     345         173 :                         gf_bs_write_u64(ctx->bs_w, cts);
     346             :                 }
     347         346 :                 if (ctx->codec_id==GF_CODECID_AV1) {
     348             :                         //write temporal delim with obu size set
     349         346 :                         gf_bs_write_u8(ctx->bs_w, 0x12);
     350         346 :                         gf_bs_write_u8(ctx->bs_w, 0);
     351             : 
     352         346 :                         if (sap_type && ctx->av1b_cfg_size) {
     353             :                                 GF_AV1_OBUArrayEntry *obu;
     354           0 :                                 i=0;
     355           0 :                                 while ((obu = gf_list_enum(ctx->av1c->obu_array, &i))) {
     356           0 :                                         gf_av1_leb128_write(ctx->bs_w, obu->obu_length);
     357           0 :                                         gf_bs_write_data(ctx->bs_w, obu->obu, (u32) obu->obu_length);
     358             :                                 }
     359             :                         }
     360             :                 }
     361         346 :                 gf_bs_write_data(ctx->bs_w, data, pck_size);
     362             :         }
     363             : 
     364         520 :         if (!ctx->rcfg) {
     365           0 :                 ctx->av1b_cfg_size = 0;
     366             :         }
     367         520 :         gf_filter_pck_send(dst_pck);
     368         520 :         gf_filter_pid_drop_packet(ctx->ipid);
     369             : 
     370         520 :         return GF_OK;
     371             : }
     372           4 : static void obumx_finalize(GF_Filter *filter)
     373             : {
     374           4 :         GF_OBUMxCtx *ctx = gf_filter_get_udta(filter);
     375           4 :         if (ctx->bs_r) gf_bs_del(ctx->bs_r);
     376           4 :         if (ctx->bs_w) gf_bs_del(ctx->bs_w);
     377           4 :         if (ctx->av1c) gf_odf_av1_cfg_del(ctx->av1c);
     378           4 : }
     379             : 
     380             : static const GF_FilterCapability OBUMxCaps[] =
     381             : {
     382             :         CAP_UINT(GF_CAPS_INPUT_OUTPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
     383             :         CAP_UINT(GF_CAPS_INPUT_OUTPUT,GF_PROP_PID_CODECID, GF_CODECID_AV1),
     384             :         CAP_UINT(GF_CAPS_INPUT_OUTPUT,GF_PROP_PID_CODECID, GF_CODECID_VP8),
     385             :         CAP_UINT(GF_CAPS_INPUT_OUTPUT,GF_PROP_PID_CODECID, GF_CODECID_VP9),
     386             :         CAP_UINT(GF_CAPS_INPUT_OUTPUT,GF_PROP_PID_CODECID, GF_CODECID_VP10),
     387             :         CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
     388             :         CAP_BOOL(GF_CAPS_OUTPUT, GF_PROP_PID_UNFRAMED, GF_TRUE),
     389             : };
     390             : 
     391             : 
     392             : 
     393             : #define OFFS(_n)        #_n, offsetof(GF_OBUMxCtx, _n)
     394             : static const GF_FilterArgs OBUMxArgs[] =
     395             : {
     396             :         { OFFS(rcfg), "force repeating decoder config at each I-frame", GF_PROP_BOOL, "true", NULL, 0},
     397             :         {0}
     398             : };
     399             : 
     400             : 
     401             : GF_FilterRegister OBUMxRegister = {
     402             :         .name = "ufobu",
     403             :         GF_FS_SET_DESCRIPTION("IVF/OBU/annexB writer")
     404             :         GF_FS_SET_HELP("This filter is used to rewrite AV1 OBU bitstream into IVF, annex B or OBU sequence, reinserting the temporal delimiter OBU.")
     405             :         .private_size = sizeof(GF_OBUMxCtx),
     406             :         .args = OBUMxArgs,
     407             :         SETCAPS(OBUMxCaps),
     408             :         .finalize = obumx_finalize,
     409             :         .configure_pid = obumx_configure_pid,
     410             :         .process = obumx_process
     411             : };
     412             : 
     413             : 
     414        2877 : const GF_FilterRegister *obumx_register(GF_FilterSession *session)
     415             : {
     416        2877 :         return &OBUMxRegister;
     417             : }
     418             : 
     419             : #else
     420             : const GF_FilterRegister *obumx_register(GF_FilterSession *session)
     421             : {
     422             :         return NULL;
     423             : }
     424             : #endif // GPAC_DISABLE_AV_PARSERS
     425             : 

Generated by: LCOV version 1.13