LCOV - code coverage report
Current view: top level - filters - rewrite_mhas.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 80 106 75.5 %
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 2020-2021
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / MHAS write 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             : 
      30             : #include <gpac/avparse.h>
      31             : 
      32             : 
      33             : typedef struct
      34             : {
      35             :         //opts
      36             :         Bool exporter, syncp;
      37             : 
      38             :         //only one input pid declared
      39             :         GF_FilterPid *ipid;
      40             :         //only one output pid declared
      41             :         GF_FilterPid *opid;
      42             : 
      43             :         Bool is_mpha;
      44             : 
      45             :         GF_BitStream *bs_w;
      46             : 
      47             :         u8 *dsi;
      48             :         u32 dsi_size;
      49             :         u32 dsi_crc;
      50             :         Bool update_dsi;
      51             :         GF_Fraction fdsi;
      52             :         u64 last_cts;
      53             :         u32 timescale;
      54             : } GF_MHASMxCtx;
      55             : 
      56             : 
      57             : 
      58             : 
      59           1 : GF_Err mhasmx_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
      60             : {
      61             :         u32 crc;
      62             :         const GF_PropertyValue *p;
      63           1 :         GF_MHASMxCtx *ctx = gf_filter_get_udta(filter);
      64             : 
      65           1 :         if (is_remove) {
      66           0 :                 ctx->ipid = NULL;
      67           0 :                 if (ctx->opid) {
      68           0 :                         gf_filter_pid_remove(ctx->opid);
      69           0 :                         ctx->opid = NULL;
      70             :                 }
      71             :                 return GF_OK;
      72             :         }
      73           1 :         if (! gf_filter_pid_check_caps(pid))
      74             :                 return GF_NOT_SUPPORTED;
      75             : 
      76           1 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_CODECID);
      77           1 :         if (!p) return GF_NOT_SUPPORTED;
      78           1 :         ctx->is_mpha = (p->value.uint==GF_CODECID_MPHA) ? GF_TRUE : GF_FALSE;
      79             : 
      80           1 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_SAMPLE_RATE);
      81           1 :         if (!p) return GF_NOT_SUPPORTED;
      82             : 
      83           1 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_DECODER_CONFIG);
      84           1 :         if (!p) {
      85           0 :                 if (ctx->is_mpha)
      86             :                         return GF_NOT_SUPPORTED;
      87           0 :                 ctx->dsi_crc = 0;
      88           0 :                 ctx->dsi = NULL;
      89           0 :                 ctx->dsi_size = 0;
      90           1 :         } else if (p->value.data.size<=5) {
      91             :                 return GF_NON_COMPLIANT_BITSTREAM;
      92             :         } else {
      93           1 :                 crc = gf_crc_32(p->value.data.ptr, p->value.data.size);
      94           1 :                 if (crc != ctx->dsi_crc) {
      95           1 :                         ctx->dsi_crc = crc;
      96           1 :                         ctx->update_dsi = GF_TRUE;
      97           1 :                         ctx->dsi = p->value.data.ptr + 5;
      98           1 :                         ctx->dsi_size = p->value.data.size - 5;
      99             :                 }
     100             :         }
     101             : 
     102           1 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_TIMESCALE);
     103           1 :         if (!p) return GF_NOT_SUPPORTED;
     104           1 :         ctx->timescale = p->value.uint;
     105             : 
     106           1 :         if (!ctx->opid) {
     107           1 :                 ctx->opid = gf_filter_pid_new(filter);
     108             :         }
     109           1 :         ctx->ipid = pid;
     110           1 :         gf_filter_pid_copy_properties(ctx->opid, pid);
     111           1 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DECODER_CONFIG, NULL);
     112           1 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_UNFRAMED, &PROP_BOOL(GF_TRUE) );
     113           1 :         gf_filter_pid_set_framing_mode(ctx->ipid, GF_TRUE);
     114           1 :         return GF_OK;
     115             : }
     116             : 
     117             : 
     118             : 
     119        1340 : GF_Err mhasmx_process(GF_Filter *filter)
     120             : {
     121        1340 :         GF_MHASMxCtx *ctx = gf_filter_get_udta(filter);
     122             :         GF_FilterPacket *pck, *dst_pck;
     123             :         u8 *data, *output;
     124             :         u32 pck_size, size;
     125             :         Bool sap;
     126             :         Bool has_sync = GF_FALSE;
     127             : 
     128        1340 :         pck = gf_filter_pid_get_packet(ctx->ipid);
     129        1340 :         if (!pck) {
     130          49 :                 if (gf_filter_pid_is_eos(ctx->ipid)) {
     131           1 :                         gf_filter_pid_set_eos(ctx->opid);
     132           1 :                         return GF_EOS;
     133             :                 }
     134             :                 return GF_OK;
     135             :         }
     136             : 
     137        1291 :         data = (char *) gf_filter_pck_get_data(pck, &pck_size);
     138             : 
     139        1291 :         sap = (gf_filter_pck_get_sap(pck)==GF_FILTER_SAP_1) ? GF_TRUE : GF_FALSE;
     140             : 
     141        1291 :         if (ctx->is_mpha) {
     142             :                 u32 hdr_size = 0;
     143        1291 :                 if (ctx->syncp || sap) {
     144             :                         hdr_size += 3;
     145             :                 }
     146        1291 :                 if (sap) {
     147          31 :                         hdr_size += ctx->dsi_size + 2; //base header needs 2 bytes
     148          31 :                         if (ctx->dsi_size > 2046)
     149           0 :                                 hdr_size += 3;
     150             :                 }
     151        1291 :                 hdr_size += 2; //base header needs 2 bytes
     152        1291 :                 if (pck_size>2046)
     153           0 :                         hdr_size += 3;
     154             : 
     155        1291 :                 size = pck_size + hdr_size;
     156        1291 :                 dst_pck = gf_filter_pck_new_alloc(ctx->opid, size, &output);
     157        1291 :                 if (!dst_pck) return GF_OUT_OF_MEM;
     158             : 
     159        1291 :                 gf_bs_reassign_buffer(ctx->bs_w, output, size);
     160             : 
     161             :                 //write MASH headers
     162        1291 :                 if (ctx->syncp || sap) {
     163        1291 :                         gf_bs_write_u8(ctx->bs_w, 0xC0);
     164        1291 :                         gf_bs_write_u8(ctx->bs_w, 0x01);
     165        1291 :                         gf_bs_write_u8(ctx->bs_w, 0xA5);
     166             :                 }
     167        1291 :                 if (sap) {
     168          31 :                         gf_bs_write_int(ctx->bs_w, 1, 3); //pck type = config
     169          31 :                         gf_bs_write_int(ctx->bs_w, 0, 2); //label = 0
     170             :                         //size
     171          31 :                         if (ctx->dsi_size > 2046) {
     172           0 :                                 gf_bs_write_int(ctx->bs_w, 2047, 11);
     173           0 :                                 gf_bs_write_int(ctx->bs_w, ctx->dsi_size - 2047, 24);
     174             :                         } else {
     175          31 :                                 gf_bs_write_int(ctx->bs_w, ctx->dsi_size, 11);
     176             :                         }
     177          31 :                         gf_bs_write_data(ctx->bs_w, ctx->dsi, ctx->dsi_size);
     178             :                 }
     179        1291 :                 gf_bs_write_int(ctx->bs_w, 2, 3); //pck type = frame
     180        1291 :                 gf_bs_write_int(ctx->bs_w, 1, 2); //label
     181        1291 :                 if (pck_size > 2046) {
     182           0 :                         gf_bs_write_int(ctx->bs_w, 2047, 11);
     183           0 :                         gf_bs_write_int(ctx->bs_w, pck_size - 2047, 24);
     184             :                 } else {
     185        1291 :                         gf_bs_write_int(ctx->bs_w, pck_size, 11);
     186             :                 }
     187             :                 //copy payload
     188        1291 :                 memcpy(output+hdr_size, data, pck_size);
     189             : 
     190             :         } else {
     191           0 :                 if ((data[0]==0xC0) && (data[1]==0x01) && (data[2]==0xA5))
     192             :                         has_sync = GF_TRUE;
     193             : 
     194           0 :                 size = pck_size;
     195           0 :                 if ((ctx->syncp && !has_sync) || (sap && !has_sync)) {
     196           0 :                         size += 3;
     197           0 :                         dst_pck = gf_filter_pck_new_alloc(ctx->opid, size, &output);
     198           0 :                         if (output) {
     199           0 :                                 output[0] = 0xC0;
     200           0 :                                 output[1] = 0x01;
     201           0 :                                 output[2] = 0xA5;
     202           0 :                                 memcpy(output+3, data, pck_size);
     203             :                         }
     204             :                 } else {
     205           0 :                         dst_pck = gf_filter_pck_new_ref(ctx->opid, 0, 0, pck);
     206             :                 }
     207           0 :                 if (!dst_pck) return GF_OUT_OF_MEM;
     208             :         }
     209             : 
     210        1291 :         gf_filter_pck_merge_properties(pck, dst_pck);
     211        1291 :         gf_filter_pck_set_byte_offset(dst_pck, GF_FILTER_NO_BO);
     212             : 
     213        1291 :         gf_filter_pck_set_framing(dst_pck, GF_TRUE, GF_TRUE);
     214             : 
     215        1291 :         gf_filter_pck_send(dst_pck);
     216        1291 :         gf_filter_pid_drop_packet(ctx->ipid);
     217        1291 :         return GF_OK;
     218             : }
     219             : 
     220           1 : static GF_Err mhasmx_initialize(GF_Filter *filter)
     221             : {
     222           1 :         GF_MHASMxCtx *ctx = gf_filter_get_udta(filter);
     223           1 :         ctx->bs_w = gf_bs_new((u8*)ctx, 1, GF_BITSTREAM_WRITE);
     224           1 :         return GF_OK;
     225             : }
     226             : 
     227           1 : static void mhasmx_finalize(GF_Filter *filter)
     228             : {
     229           1 :         GF_MHASMxCtx *ctx = gf_filter_get_udta(filter);
     230           1 :         if (ctx->bs_w) gf_bs_del(ctx->bs_w);
     231           1 : }
     232             : 
     233             : static const GF_FilterCapability MHASMxCaps[] =
     234             : {
     235             :         CAP_UINT(GF_CAPS_INPUT_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
     236             :         CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_CODECID, GF_CODECID_MPHA),
     237             :         CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_CODECID, GF_CODECID_MHAS),
     238             :         CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
     239             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_MHAS),
     240             :         CAP_BOOL(GF_CAPS_OUTPUT, GF_PROP_PID_UNFRAMED, GF_TRUE),
     241             : };
     242             : 
     243             : 
     244             : #define OFFS(_n)        #_n, offsetof(GF_MHASMxCtx, _n)
     245             : static const GF_FilterArgs MHASMxArgs[] =
     246             : {
     247             :         { OFFS(syncp), "if set, insert sync packet at each frame, otherwise only at SAP", GF_PROP_BOOL, "yes", NULL, GF_FS_ARG_HINT_ADVANCED},
     248             :         {0}
     249             : };
     250             : 
     251             : 
     252             : GF_FilterRegister MHASMxRegister = {
     253             :         .name = "ufmhas",
     254             :         GF_FS_SET_DESCRIPTION("MHAS writer")
     255             :         GF_FS_SET_HELP("This filter converts MPEG-H Audio streams into MHAS encapsulated data.")
     256             :         .private_size = sizeof(GF_MHASMxCtx),
     257             :         .args = MHASMxArgs,
     258             :         .initialize = mhasmx_initialize,
     259             :         .finalize = mhasmx_finalize,
     260             :         SETCAPS(MHASMxCaps),
     261             :         .configure_pid = mhasmx_configure_pid,
     262             :         .process = mhasmx_process
     263             : };
     264             : 
     265             : 
     266        2877 : const GF_FilterRegister *mhasmx_register(GF_FilterSession *session)
     267             : {
     268        2877 :         return &MHASMxRegister;
     269             : }
     270             : 

Generated by: LCOV version 1.13