LCOV - code coverage report
Current view: top level - filters - dec_ac52.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 81 97 83.5 %
Date: 2021-04-29 23:48:07 Functions: 6 6 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 / AC3 liba52 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             : #include <gpac/filters.h>
      27             : #include <gpac/constants.h>
      28             : 
      29             : #ifdef GPAC_HAS_LIBA52
      30             : 
      31             : #if !defined(__GNUC__)
      32             : # if defined(_WIN32_WCE) || defined (WIN32)
      33             : #  pragma comment(lib, "liba52")
      34             : # endif
      35             : #endif
      36             : 
      37             : 
      38             : #ifndef uint32_t
      39             : #define uint32_t u32
      40             : #endif
      41             : #ifndef uint8_t
      42             : #define uint8_t u8
      43             : #endif
      44             : 
      45             : #include <a52dec/mm_accel.h>
      46             : #include <a52dec/a52.h>
      47             : 
      48             : #define AC3_FRAME_SIZE 1536
      49             : 
      50             : typedef struct
      51             : {
      52             :         GF_FilterPid *ipid, *opid;
      53             :         
      54             :         a52_state_t *codec;
      55             :         sample_t* samples;
      56             : 
      57             :         u32 sample_rate, flags, bit_rate;
      58             :         u8 num_channels;
      59             :         u32 channel_mask;
      60             :         u64 last_cts;
      61             :         u32 timescale;
      62             : } GF_A52DecCtx;
      63             : 
      64             : 
      65           1 : static GF_Err a52dec_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
      66             : {
      67           1 :         GF_A52DecCtx *ctx = gf_filter_get_udta(filter);
      68             : 
      69           1 :         if (is_remove) {
      70           0 :                 if (ctx->opid) {
      71           0 :                         gf_filter_pid_remove(ctx->opid);
      72           0 :                         ctx->opid = NULL;
      73             :                 }
      74           0 :                 ctx->ipid = NULL;
      75           0 :                 return GF_OK;
      76             :         }
      77           1 :         if (! gf_filter_pid_check_caps(pid))
      78             :                 return GF_NOT_SUPPORTED;
      79             : 
      80           1 :         ctx->ipid = pid;
      81           1 :         gf_filter_pid_set_framing_mode(ctx->ipid, GF_TRUE);
      82           1 :         if (!ctx->opid) {
      83             :                 u32 flags = MM_ACCEL_DJBFFT;
      84             : #if !defined (GPAC_CONFIG_IOS) && !defined (GPAC_CONFIG_ANDROID)
      85             :                 flags |= MM_ACCEL_X86_MMX | MM_ACCEL_X86_3DNOW | MM_ACCEL_X86_MMXEXT;
      86             : #endif
      87           1 :                 ctx->codec = a52_init(flags);
      88           1 :                 if (!ctx->codec) {
      89           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[A52] Error initializing decoder\n"));
      90             :                         return GF_IO_ERR;
      91             :                 }
      92             : 
      93           1 :                 ctx->samples = a52_samples(ctx->codec);
      94           1 :                 if (!ctx->samples) {
      95           0 :                         a52_free(ctx->codec);
      96           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[A52] Error initializing decoder\n"));
      97             :                         return GF_IO_ERR;
      98             :                 }
      99             : 
     100           1 :                 ctx->opid = gf_filter_pid_new(filter);
     101             :         }
     102             :         //copy properties at init or reconfig
     103           1 :         gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
     104           1 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, &PROP_UINT(GF_CODECID_RAW) );
     105           1 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_AUDIO_FORMAT, &PROP_UINT(GF_AUDIO_FMT_S16) );
     106           1 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAMPLES_PER_FRAME, &PROP_UINT(AC3_FRAME_SIZE) );
     107           1 :         return GF_OK;
     108             : }
     109             : 
     110           1 : static void a52dec_finalize(GF_Filter *filter)
     111             : {
     112           1 :         GF_A52DecCtx *ctx = gf_filter_get_udta(filter);
     113           1 :         if (ctx->codec) a52_free(ctx->codec);
     114           1 : }
     115             : 
     116             : 
     117          12 : static void a52dec_check_mc_config(GF_A52DecCtx *ctx)
     118             : {
     119             :         u32 channel_mask = 0;
     120             : 
     121          12 :         switch (ctx->flags & A52_CHANNEL_MASK) {
     122             :         case A52_CHANNEL1:
     123             :         case A52_CHANNEL2:
     124             :         case A52_MONO:
     125             :                 channel_mask = GF_AUDIO_CH_FRONT_CENTER;
     126             :                 break;
     127             :         case A52_CHANNEL:
     128             :         case A52_STEREO:
     129             :                 channel_mask = GF_AUDIO_CH_FRONT_LEFT | GF_AUDIO_CH_FRONT_RIGHT;
     130             :                 break;
     131             :         case A52_DOLBY:
     132             :                 break;
     133             :         case A52_3F:
     134             :                 channel_mask = GF_AUDIO_CH_FRONT_CENTER | GF_AUDIO_CH_FRONT_LEFT | GF_AUDIO_CH_FRONT_RIGHT;
     135             :                 break;
     136             :         case A52_2F1R:
     137             :                 channel_mask = GF_AUDIO_CH_REAR_CENTER | GF_AUDIO_CH_FRONT_LEFT | GF_AUDIO_CH_FRONT_RIGHT;
     138             :                 break;
     139             :         case A52_3F1R:
     140             :                 channel_mask = GF_AUDIO_CH_FRONT_CENTER | GF_AUDIO_CH_FRONT_LEFT | GF_AUDIO_CH_FRONT_RIGHT | GF_AUDIO_CH_REAR_CENTER;
     141             :                 break;
     142             :         case A52_2F2R:
     143             :                 channel_mask = GF_AUDIO_CH_FRONT_LEFT | GF_AUDIO_CH_FRONT_RIGHT | GF_AUDIO_CH_SURROUND_LEFT | GF_AUDIO_CH_SURROUND_RIGHT;
     144             :                 break;
     145             :         case A52_3F2R:
     146             :                 channel_mask = GF_AUDIO_CH_FRONT_CENTER | GF_AUDIO_CH_FRONT_LEFT | GF_AUDIO_CH_FRONT_RIGHT | GF_AUDIO_CH_SURROUND_LEFT | GF_AUDIO_CH_SURROUND_RIGHT;
     147             :                 break;
     148             :         }
     149          12 :         if (ctx->flags & A52_LFE)
     150           0 :                 channel_mask |= GF_AUDIO_CH_LFE;
     151             : 
     152          12 :         if (ctx->channel_mask != channel_mask) {
     153           1 :                 ctx->channel_mask = channel_mask;
     154           1 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CHANNEL_LAYOUT, &PROP_LONGUINT(channel_mask) );
     155             :         }
     156          12 : }
     157             : 
     158             : 
     159             : /**** the following two functions comes from a52dec */
     160             : static GFINLINE s32 blah (s32 i)
     161             : {
     162       18432 :         if (i > 0x43c07fff)
     163             :                 return 32767;
     164       18432 :         else if (i < 0x43bf8000)
     165             :                 return -32768;
     166       18432 :         return i - 0x43c00000;
     167             : }
     168             : 
     169          72 : static GFINLINE void float_to_int (float * _f, s16 *samps, int nchannels)
     170             : {
     171             :         int i, j, c;
     172             :         s32 * f = (s32 *) _f;       // XXX assumes IEEE float format
     173             : 
     174             :         j = 0;
     175          72 :         nchannels *= 256;
     176       18504 :         for (i = 0; i < 256; i++) {
     177       18432 :                 for (c = 0; c < nchannels; c += 256)
     178       36864 :                         samps[j++] = blah (f[i + c]);
     179             :         }
     180          72 : }
     181             : 
     182             : /**** end */
     183             : 
     184             : static const int ac3_channels[8] = {
     185             :         2, 1, 2, 3, 3, 4, 4, 5
     186             : };
     187             : 
     188          13 : static GF_Err a52dec_process(GF_Filter *filter)
     189             : {
     190             :         short *out_samples;
     191             :         int i, len, bit_rate;
     192             :         u32 size;
     193             :         const char *data;
     194             :         u8 *buffer;
     195             :         u32 sample_rate, flags;
     196             :         u8 num_channels;
     197             :         sample_t level;
     198          13 :         GF_A52DecCtx *ctx = gf_filter_get_udta(filter);
     199             :         GF_FilterPacket *dst_pck;
     200          13 :         GF_FilterPacket *pck = gf_filter_pid_get_packet(ctx->ipid);
     201             : 
     202          13 :         if (!pck) {
     203           1 :                 if ( gf_filter_pid_is_eos(ctx->ipid)) {
     204           1 :                         gf_filter_pid_set_eos(ctx->opid);
     205           1 :                         return GF_EOS;
     206             :                 }
     207             :                 return GF_OK;
     208             :         }
     209          12 :         GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[A52] Decoding AU\n"));
     210             : 
     211          12 :         data = gf_filter_pck_get_data(pck, &size);
     212          12 :         len = a52_syncinfo((u8 *) data, &flags, &sample_rate, &bit_rate);
     213          12 :         if (!len) return GF_NON_COMPLIANT_BITSTREAM;
     214             : 
     215          12 :         num_channels = ac3_channels[flags & 7];
     216          12 :         if (flags & A52_LFE) num_channels++;
     217          12 :         flags |= A52_ADJUST_LEVEL;
     218          12 :         if ((sample_rate != ctx->sample_rate) || (num_channels != ctx->num_channels) || (ctx->flags != flags) ) {
     219          12 :                 ctx->num_channels = num_channels;
     220          12 :                 ctx->sample_rate = sample_rate;
     221          12 :                 ctx->flags = flags;
     222             : 
     223          12 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAMPLE_RATE, &PROP_UINT(ctx->sample_rate) );
     224          12 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_NUM_CHANNELS, &PROP_UINT(ctx->num_channels) );
     225          12 :                 a52dec_check_mc_config(ctx);
     226             :         }
     227          12 :         if (ctx->bit_rate != bit_rate) {
     228           1 :                 ctx->bit_rate = bit_rate;
     229           1 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_BITRATE, &PROP_UINT(ctx->bit_rate) );
     230             :         }
     231          12 :         level = 1;
     232          12 :         if ( a52_frame(ctx->codec, (u8 *) data, &ctx->flags, &level, 384)) {
     233           0 :                 GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[A52] Error decoding AU\n" ));
     234           0 :                 if (pck) gf_filter_pid_drop_packet(ctx->ipid);
     235           0 :                 return GF_NON_COMPLIANT_BITSTREAM;
     236             :         }
     237          12 :         dst_pck = gf_filter_pck_new_alloc(ctx->opid, ctx->num_channels * sizeof(short) * AC3_FRAME_SIZE, &buffer);
     238          12 :         if (!dst_pck) return GF_OUT_OF_MEM;
     239             : 
     240             :         if (pck) {
     241          12 :                 ctx->last_cts = gf_filter_pck_get_cts(pck);
     242          12 :                 ctx->timescale = gf_filter_pck_get_timescale(pck);
     243          12 :                 gf_filter_pck_merge_properties(pck, dst_pck);
     244             : 
     245          12 :                 gf_filter_pid_drop_packet(ctx->ipid);
     246             :         }
     247          12 :         gf_filter_pck_set_cts(dst_pck, ctx->last_cts);
     248          12 :         if (ctx->timescale != ctx->sample_rate) {
     249           0 :                 u64 dur = AC3_FRAME_SIZE * ctx->timescale;
     250           0 :                 dur /= ctx->sample_rate;
     251           0 :                 gf_filter_pck_set_duration(dst_pck, (u32) dur);
     252           0 :                 ctx->last_cts += dur;
     253             :         } else {
     254          12 :                 gf_filter_pck_set_duration(dst_pck, AC3_FRAME_SIZE);
     255          12 :                 ctx->last_cts += AC3_FRAME_SIZE;
     256             :         }
     257             : 
     258          12 :         out_samples = (short*)buffer;
     259          84 :         for (i=0; i<6; i++) {
     260          72 :                 if (a52_block(ctx->codec))
     261             :                         return GF_NON_COMPLIANT_BITSTREAM;
     262             : 
     263          72 :                 float_to_int(ctx->samples, out_samples + i * 256 * ctx->num_channels, ctx->num_channels);
     264             :         }
     265          12 :         gf_filter_pck_send(dst_pck);
     266             : 
     267          12 :         return GF_OK;
     268             : }
     269             : 
     270             : 
     271             : 
     272             : static const GF_FilterCapability A52DecCaps[] =
     273             : {
     274             :         CAP_UINT(GF_CAPS_INPUT_OUTPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
     275             :         CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
     276             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AC3),
     277             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_RAW),
     278             : };
     279             : 
     280             : GF_FilterRegister A52DecRegister = {
     281             :         .name = "a52dec",
     282             :         GF_FS_SET_DESCRIPTION("A52 decoder")
     283             :         GF_FS_SET_HELP("This filter decodes AC3 streams through a52dec library.")
     284             :         .private_size = sizeof(GF_A52DecCtx),
     285             :         .priority = 1,
     286             :         SETCAPS(A52DecCaps),
     287             :         .configure_pid = a52dec_configure_pid,
     288             :         .process = a52dec_process,
     289             :         .finalize = a52dec_finalize
     290             : };
     291             : 
     292             : #endif
     293             : 
     294        2877 : const GF_FilterRegister *a52dec_register(GF_FilterSession *session)
     295             : {
     296             : #ifdef GPAC_HAS_LIBA52
     297        2877 :         return &A52DecRegister;
     298             : #else
     299             :         return NULL;
     300             : #endif
     301             : }

Generated by: LCOV version 1.13