LCOV - code coverage report
Current view: top level - filters - reframe_ac3.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 215 258 83.3 %
Date: 2021-04-29 23:48:07 Functions: 8 8 100.0 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2017-2021
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / AC3 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             : #ifndef GPAC_DISABLE_AV_PARSERS
      31             : 
      32             : typedef struct
      33             : {
      34             :         u64 pos;
      35             :         Double duration;
      36             : } AC3Idx;
      37             : 
      38             : #define AC3_FRAME_SIZE 1536
      39             : 
      40             : typedef struct
      41             : {
      42             :         //filter args
      43             :         Double index;
      44             : 
      45             :         //only one input pid declared
      46             :         GF_FilterPid *ipid;
      47             :         //only one output pid declared
      48             :         GF_FilterPid *opid;
      49             : 
      50             :         GF_BitStream *bs;
      51             :         u64 file_pos, cts;
      52             :         u32 sample_rate, nb_ch;
      53             :         GF_Fraction64 duration;
      54             :         Double start_range;
      55             :         Bool in_seek;
      56             :         u32 timescale;
      57             : 
      58             :         GF_AC3Config hdr;
      59             :         u8 *ac3_buffer;
      60             :         u32 ac3_buffer_size, ac3_buffer_alloc, resume_from;
      61             :         u64 byte_offset;
      62             : 
      63             :         Bool is_playing;
      64             :         Bool is_file, file_loaded;
      65             :         Bool initial_play_done;
      66             : 
      67             :         Bool is_eac3;
      68             :         Bool (*ac3_parser_bs)(GF_BitStream*, GF_AC3Config*, Bool);
      69             : 
      70             :         GF_FilterPacket *src_pck;
      71             : 
      72             :         AC3Idx *indexes;
      73             :         u32 index_alloc_size, index_size;
      74             :         u32 bitrate;
      75             : } GF_AC3DmxCtx;
      76             : 
      77             : 
      78             : 
      79             : 
      80          17 : GF_Err ac3dmx_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
      81             : {
      82             :         const GF_PropertyValue *p;
      83          17 :         GF_AC3DmxCtx *ctx = gf_filter_get_udta(filter);
      84             : 
      85          17 :         if (is_remove) {
      86           0 :                 ctx->ipid = NULL;
      87           0 :                 if (ctx->opid) {
      88           0 :                         gf_filter_pid_remove(ctx->opid);
      89           0 :                         ctx->opid = NULL;
      90             :                 }
      91             :                 return GF_OK;
      92             :         }
      93          17 :         if (! gf_filter_pid_check_caps(pid))
      94             :                 return GF_NOT_SUPPORTED;
      95             : 
      96          17 :         ctx->ipid = pid;
      97          17 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_TIMESCALE);
      98          17 :         if (p) ctx->timescale = p->value.uint;
      99             : 
     100          17 :         ctx->ac3_parser_bs = gf_ac3_parser_bs;
     101             : 
     102          17 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_CODECID);
     103          17 :         if (p && p->value.uint==GF_CODECID_EAC3) ctx->is_eac3 = GF_TRUE;
     104             :         else {
     105          17 :                 p = gf_filter_pid_get_property(pid, GF_PROP_PID_MIME);
     106          17 :                 if (p && p->value.string && strstr(p->value.string, "eac3")) ctx->is_eac3 = GF_TRUE;
     107             :                 else {
     108          17 :                         p = gf_filter_pid_get_property(pid, GF_PROP_PID_FILE_EXT);
     109          17 :                         if (p && p->value.string && strstr(p->value.string, "eac3")) ctx->is_eac3 = GF_TRUE;
     110             :                 }
     111             :         }
     112          17 :         if (ctx->is_eac3) {
     113           3 :                 ctx->ac3_parser_bs = gf_eac3_parser_bs;
     114             :         }
     115             : 
     116          17 :         if (ctx->timescale && !ctx->opid) {
     117           3 :                 ctx->opid = gf_filter_pid_new(filter);
     118           3 :                 gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
     119           3 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_UNFRAMED, NULL);
     120             :         }
     121             :         return GF_OK;
     122             : }
     123             : 
     124        1164 : static void ac3dmx_check_dur(GF_Filter *filter, GF_AC3DmxCtx *ctx)
     125             : {
     126             :         FILE *stream;
     127             :         GF_BitStream *bs;
     128             :         GF_AC3Config hdr;
     129             :         u64 duration, cur_dur, rate;
     130             :         s32 sr = -1;
     131             :         const GF_PropertyValue *p;
     132        2321 :         if (!ctx->opid || ctx->timescale || ctx->file_loaded) return;
     133             : 
     134          14 :         if (ctx->index<=0) {
     135           7 :                 ctx->file_loaded = GF_TRUE;
     136             :                 return;
     137             :         }
     138             : 
     139           7 :         p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILEPATH);
     140           7 :         if (!p || !p->value.string || !strncmp(p->value.string, "gmem://", 7)) {
     141           0 :                 ctx->is_file = GF_FALSE;
     142           0 :                 ctx->file_loaded = GF_TRUE;
     143             :                 return;
     144             :         }
     145           7 :         ctx->is_file = GF_TRUE;
     146             : 
     147           7 :         stream = gf_fopen(p->value.string, "rb");
     148           7 :         if (!stream) return;
     149             : 
     150           7 :         ctx->index_size = 0;
     151             : 
     152           7 :         bs = gf_bs_from_file(stream, GF_BITSTREAM_READ);
     153             :         duration = 0;
     154             :         cur_dur = 0;
     155        4467 :         while ( ctx->ac3_parser_bs(bs, &hdr, GF_FALSE) ) {
     156        4460 :                 if ((sr>=0) && (sr != hdr.sample_rate)) {
     157           0 :                         duration *= hdr.sample_rate;
     158           0 :                         duration /= sr;
     159             : 
     160           0 :                         cur_dur *= hdr.sample_rate;
     161           0 :                         cur_dur /= sr;
     162             :                 }
     163        4460 :                 sr = hdr.sample_rate;
     164        4460 :                 duration += AC3_FRAME_SIZE;
     165        4460 :                 cur_dur += AC3_FRAME_SIZE;
     166        4460 :                 if (cur_dur > ctx->index * sr) {
     167         150 :                         if (!ctx->index_alloc_size) ctx->index_alloc_size = 10;
     168         144 :                         else if (ctx->index_alloc_size == ctx->index_size) ctx->index_alloc_size *= 2;
     169         150 :                         ctx->indexes = gf_realloc(ctx->indexes, sizeof(AC3Idx)*ctx->index_alloc_size);
     170         150 :                         ctx->indexes[ctx->index_size].pos = gf_bs_get_position(bs);
     171         150 :                         ctx->indexes[ctx->index_size].duration = (Double) duration;
     172         150 :                         ctx->indexes[ctx->index_size].duration /= sr;
     173         150 :                         ctx->index_size ++;
     174             :                         cur_dur = 0;
     175             :                 }
     176             : 
     177        4460 :                 gf_bs_skip_bytes(bs, hdr.framesize);
     178             :         }
     179           7 :         rate = gf_bs_get_position(bs);
     180           7 :         gf_bs_del(bs);
     181           7 :         gf_fclose(stream);
     182             : 
     183           7 :         if (!ctx->duration.num || (ctx->duration.num  * sr != duration * ctx->duration.den)) {
     184           7 :                 ctx->duration.num = (s32) duration;
     185           7 :                 ctx->duration.den = sr;
     186             : 
     187           7 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DURATION, & PROP_FRAC64(ctx->duration));
     188             : 
     189           7 :                 if (duration && !gf_sys_is_test_mode() ) {
     190           0 :                         rate *= 8 * ctx->duration.den;
     191           0 :                         rate /= ctx->duration.num;
     192           0 :                         ctx->bitrate = (u32) rate;
     193             :                 }
     194             :         }
     195             : 
     196           7 :         p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILE_CACHED);
     197           7 :         if (p && p->value.boolean) ctx->file_loaded = GF_TRUE;
     198           7 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CAN_DATAREF, & PROP_BOOL(GF_TRUE ) );
     199             : }
     200             : 
     201        7193 : static void ac3dmx_check_pid(GF_Filter *filter, GF_AC3DmxCtx *ctx)
     202             : {
     203             :         u8 *data;
     204             :         u32 size;
     205        7193 :         if (!ctx->opid) {
     206          14 :                 ctx->opid = gf_filter_pid_new(filter);
     207          14 :                 ac3dmx_check_dur(filter, ctx);
     208             :         }
     209       14369 :         if ((ctx->sample_rate == ctx->hdr.sample_rate) && (ctx->nb_ch == ctx->hdr.channels) ) return;
     210             : 
     211             :         //copy properties at init or reconfig
     212          17 :         gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
     213          17 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STREAM_TYPE, & PROP_UINT( GF_STREAM_AUDIO));
     214          17 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAMPLES_PER_FRAME, & PROP_UINT(AC3_FRAME_SIZE) );
     215          17 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_UNFRAMED, & PROP_BOOL(GF_FALSE) );
     216             : 
     217          17 :         if (ctx->duration.num)
     218           7 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DURATION, & PROP_FRAC64(ctx->duration));
     219             : 
     220             : 
     221          17 :         ctx->nb_ch = ctx->hdr.channels;
     222          17 :         if (!ctx->timescale) {
     223             :                 //we change sample rate, change cts
     224          14 :                 if (ctx->cts && (ctx->sample_rate != ctx->hdr.sample_rate)) {
     225           0 :                         ctx->cts *= ctx->hdr.sample_rate;
     226           0 :                         ctx->cts /= ctx->sample_rate;
     227             :                 }
     228             :         }
     229          17 :         ctx->sample_rate = ctx->hdr.sample_rate;
     230             : 
     231          17 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_TIMESCALE, & PROP_UINT(ctx->timescale ? ctx->timescale : ctx->sample_rate));
     232          17 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAMPLE_RATE, & PROP_UINT(ctx->sample_rate));
     233          17 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_NUM_CHANNELS, & PROP_UINT(ctx->nb_ch) );
     234             : 
     235          17 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, & PROP_UINT(ctx->is_eac3 ? GF_CODECID_EAC3 : GF_CODECID_AC3) );
     236             : 
     237          17 :         ctx->hdr.is_ec3 = ctx->is_eac3;
     238          17 :         gf_odf_ac3_cfg_write(&ctx->hdr, &data, &size);
     239          17 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DECODER_CONFIG, & PROP_DATA_NO_COPY(data, size) );
     240             : 
     241          17 :         if (ctx->bitrate) {
     242           0 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_BITRATE, & PROP_UINT(ctx->bitrate));
     243             :         }
     244             : 
     245          17 :         if (ctx->is_file && ctx->index) {
     246           7 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_PLAYBACK_MODE, & PROP_UINT(GF_PLAYBACK_MODE_FASTFORWARD) );
     247             :         }
     248             : }
     249             : 
     250         688 : static Bool ac3dmx_process_event(GF_Filter *filter, const GF_FilterEvent *evt)
     251             : {
     252             :         u32 i;
     253             :         GF_FilterEvent fevt;
     254         688 :         GF_AC3DmxCtx *ctx = gf_filter_get_udta(filter);
     255             : 
     256         688 :         switch (evt->base.type) {
     257          17 :         case GF_FEVT_PLAY:
     258          17 :                 if (!ctx->is_playing) {
     259          17 :                         ctx->is_playing = GF_TRUE;
     260          17 :                         ctx->cts = 0;
     261          17 :                         ctx->ac3_buffer_size = 0;
     262          17 :                         ctx->resume_from = 0;
     263             :                 }
     264          17 :                 if (! ctx->is_file) {
     265             :                         return GF_FALSE;
     266             :                 }
     267           7 :                 ctx->start_range = evt->play.start_range;
     268           7 :                 ctx->in_seek = GF_TRUE;
     269           7 :                 ctx->file_pos = 0;
     270           7 :                 if (ctx->start_range) {
     271           0 :                         for (i=1; i<ctx->index_size; i++) {
     272           0 :                                 if (ctx->indexes[i].duration>ctx->start_range) {
     273           0 :                                         ctx->cts = (u64) (ctx->indexes[i-1].duration * ctx->sample_rate);
     274           0 :                                         ctx->file_pos = ctx->indexes[i-1].pos;
     275           0 :                                         break;
     276             :                                 }
     277             :                         }
     278             :                 }
     279           7 :                 if (!ctx->initial_play_done) {
     280           7 :                         ctx->initial_play_done = GF_TRUE;
     281             :                         //seek will not change the current source state, don't send a seek
     282           7 :                         if (!ctx->file_pos)
     283             :                                 return GF_TRUE;
     284             :                 }
     285           0 :                 ctx->ac3_buffer_size = 0;
     286           0 :                 ctx->resume_from = 0;
     287             :                 //post a seek
     288           0 :                 GF_FEVT_INIT(fevt, GF_FEVT_SOURCE_SEEK, ctx->ipid);
     289           0 :                 fevt.seek.start_offset = ctx->file_pos;
     290           0 :                 gf_filter_pid_send_event(ctx->ipid, &fevt);
     291             : 
     292             :                 //cancel event
     293           0 :                 return GF_TRUE;
     294             : 
     295           6 :         case GF_FEVT_STOP:
     296             :                 //don't cancel event
     297           6 :                 ctx->is_playing = GF_FALSE;
     298           6 :                 return GF_FALSE;
     299             : 
     300             :         case GF_FEVT_SET_SPEED:
     301             :                 //cancel event
     302             :                 return GF_TRUE;
     303             :         default:
     304             :                 break;
     305             :         }
     306             :         //by default don't cancel event - to rework once we have downloading in place
     307         665 :         return GF_FALSE;
     308             : }
     309             : 
     310             : static GFINLINE void ac3dmx_update_cts(GF_AC3DmxCtx *ctx)
     311             : {
     312        7179 :         if (ctx->timescale) {
     313             :                 u64 inc = AC3_FRAME_SIZE;
     314         893 :                 inc *= ctx->timescale;
     315         893 :                 inc /= ctx->sample_rate;
     316         893 :                 ctx->cts += inc;
     317             :         } else {
     318        6286 :                 ctx->cts += AC3_FRAME_SIZE;
     319             :         }
     320             : }
     321             : 
     322        1594 : GF_Err ac3dmx_process(GF_Filter *filter)
     323             : {
     324        1594 :         GF_AC3DmxCtx *ctx = gf_filter_get_udta(filter);
     325             :         GF_FilterPacket *pck, *dst_pck;
     326             :         u8 *output;
     327             :         u8 *start;
     328             :         u32 pck_size, remain, prev_pck_size;
     329             :         u64 cts = GF_FILTER_NO_TS;
     330             : 
     331             :         //always reparse duration
     332        1594 :         if (!ctx->duration.num)
     333        1150 :                 ac3dmx_check_dur(filter, ctx);
     334             : 
     335        1594 :         if (ctx->opid && !ctx->is_playing)
     336             :                 return GF_OK;
     337             : 
     338        1563 :         pck = gf_filter_pid_get_packet(ctx->ipid);
     339        1563 :         if (!pck) {
     340          84 :                 if (gf_filter_pid_is_eos(ctx->ipid)) {
     341          14 :                         if (!ctx->ac3_buffer_size) {
     342          12 :                                 if (ctx->opid)
     343          12 :                                         gf_filter_pid_set_eos(ctx->opid);
     344          12 :                                 if (ctx->src_pck) gf_filter_pck_unref(ctx->src_pck);
     345          12 :                                 ctx->src_pck = NULL;
     346          12 :                                 return GF_EOS;
     347             :                         }
     348             :                 } else {
     349             :                         return GF_OK;
     350             :                 }
     351             :         }
     352             : 
     353        1481 :         prev_pck_size = ctx->ac3_buffer_size;
     354        1481 :         if (pck && !ctx->resume_from) {
     355        1479 :                 const u8 *data = gf_filter_pck_get_data(pck, &pck_size);
     356        1479 :                 if (!pck_size) {
     357           0 :                         gf_filter_pid_drop_packet(ctx->ipid);
     358           0 :                         return GF_OK;
     359             :                 }
     360             : 
     361        1479 :                 if (ctx->byte_offset != GF_FILTER_NO_BO) {
     362         589 :                         u64 byte_offset = gf_filter_pck_get_byte_offset(pck);
     363         589 :                         if (!ctx->ac3_buffer_size) {
     364          41 :                                 ctx->byte_offset = byte_offset;
     365         548 :                         } else if (ctx->byte_offset + ctx->ac3_buffer_size != byte_offset) {
     366           0 :                                 ctx->byte_offset = GF_FILTER_NO_BO;
     367           0 :                                 if ((byte_offset != GF_FILTER_NO_BO) && (byte_offset>ctx->ac3_buffer_size) ) {
     368           0 :                                         ctx->byte_offset = byte_offset - ctx->ac3_buffer_size;
     369             :                                 }
     370             :                         }
     371             :                 }
     372             : 
     373        1479 :                 if (ctx->ac3_buffer_size + pck_size > ctx->ac3_buffer_alloc) {
     374          34 :                         ctx->ac3_buffer_alloc = ctx->ac3_buffer_size + pck_size;
     375          34 :                         ctx->ac3_buffer = gf_realloc(ctx->ac3_buffer, ctx->ac3_buffer_alloc);
     376             :                 }
     377        1479 :                 memcpy(ctx->ac3_buffer + ctx->ac3_buffer_size, data, pck_size);
     378        1479 :                 ctx->ac3_buffer_size += pck_size;
     379             :         }
     380             : 
     381             :         //input pid sets some timescale - we flushed pending data , update cts
     382        1481 :         if (ctx->timescale && pck) {
     383         893 :                 cts = gf_filter_pck_get_cts(pck);
     384             :         }
     385             : 
     386         893 :         if (cts == GF_FILTER_NO_TS) {
     387             :                 //avoids updating cts
     388             :                 prev_pck_size = 0;
     389             :         }
     390             : 
     391        1481 :         remain = ctx->ac3_buffer_size;
     392        1481 :         start = ctx->ac3_buffer;
     393             : 
     394        1481 :         if (ctx->resume_from) {
     395           0 :                 start += ctx->resume_from - 1;
     396           0 :                 remain -= ctx->resume_from - 1;
     397           0 :                 ctx->resume_from = 0;
     398             :         }
     399             : 
     400        1481 :         if (!ctx->bs) {
     401          17 :                 ctx->bs = gf_bs_new(start, remain, GF_BITSTREAM_READ);
     402             :         } else {
     403        1464 :                 gf_bs_reassign_buffer(ctx->bs, start, remain);
     404             :         }
     405        8660 :         while (remain) {
     406             :                 u8 *sync;
     407             :                 Bool res;
     408             :                 u32 sync_pos, bytes_to_drop=0;
     409             : 
     410             : 
     411        7750 :                 res = ctx->ac3_parser_bs(ctx->bs, &ctx->hdr, GF_TRUE);
     412             : 
     413        7750 :                 sync_pos = (u32) gf_bs_get_position(ctx->bs);
     414             : 
     415             :                 //startcode not found or not enough bytes, gather more
     416        7750 :                 if (!res || (remain < sync_pos + ctx->hdr.framesize))
     417             :                         break;
     418             : 
     419        7193 :                 ac3dmx_check_pid(filter, ctx);
     420             : 
     421        7193 :                 if (!ctx->is_playing) {
     422          14 :                         ctx->resume_from = 1 + ctx->ac3_buffer_size - remain;
     423          14 :                         return GF_OK;
     424             :                 }
     425             : 
     426        7179 :                 if (sync_pos) {
     427           0 :                         GF_LOG(GF_LOG_WARNING, GF_LOG_MEDIA, ("[AC3Dmx] %d bytes unrecovered before sync word\n", sync_pos));
     428             :                 }
     429        7179 :                 sync = start + sync_pos;
     430             : 
     431        7179 :                 if (ctx->in_seek) {
     432           7 :                         u64 nb_samples_at_seek = (u64) (ctx->start_range * ctx->hdr.sample_rate);
     433           7 :                         if (ctx->cts + AC3_FRAME_SIZE >= nb_samples_at_seek) {
     434             :                                 //u32 samples_to_discard = (ctx->cts + ctx->dts_inc) - nb_samples_at_seek;
     435           7 :                                 ctx->in_seek = GF_FALSE;
     436             :                         }
     437             :                 }
     438             : 
     439        7179 :                 bytes_to_drop = sync_pos + ctx->hdr.framesize;
     440        7179 :                 if (ctx->timescale && !prev_pck_size &&  (cts != GF_FILTER_NO_TS) ) {
     441             :                         //trust input CTS if diff is more than one sec
     442         893 :                         if ((cts > ctx->cts + ctx->timescale) || (ctx->cts > cts + ctx->timescale))
     443           0 :                                 ctx->cts = cts;
     444             :                         cts = GF_FILTER_NO_TS;
     445             :                 }
     446             : 
     447        7179 :                 if (!ctx->in_seek) {
     448        7179 :                         dst_pck = gf_filter_pck_new_alloc(ctx->opid, ctx->hdr.framesize, &output);
     449        7179 :                         if (!dst_pck) return GF_OUT_OF_MEM;
     450             :                         
     451        7179 :                         if (ctx->src_pck) gf_filter_pck_merge_properties(ctx->src_pck, dst_pck);
     452             : 
     453        7179 :                         memcpy(output, sync, ctx->hdr.framesize);
     454        7179 :                         gf_filter_pck_set_dts(dst_pck, ctx->cts);
     455        7179 :                         gf_filter_pck_set_cts(dst_pck, ctx->cts);
     456        7179 :                         gf_filter_pck_set_duration(dst_pck, AC3_FRAME_SIZE);
     457        7179 :                         gf_filter_pck_set_sap(dst_pck, GF_FILTER_SAP_1);
     458        7179 :                         gf_filter_pck_set_framing(dst_pck, GF_TRUE, GF_TRUE);
     459             : 
     460        7179 :                         if (ctx->byte_offset != GF_FILTER_NO_BO) {
     461        6286 :                                 gf_filter_pck_set_byte_offset(dst_pck, ctx->byte_offset + ctx->hdr.framesize);
     462             :                         }
     463             : 
     464        7179 :                         gf_filter_pck_send(dst_pck);
     465             :                 }
     466        7179 :                 ac3dmx_update_cts(ctx);
     467             : 
     468             :                 //truncated last frame
     469        7179 :                 if (bytes_to_drop>remain) {
     470           0 :                         GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[ADTSDmx] truncated AC3 frame!\n"));
     471             :                         bytes_to_drop=remain;
     472             :                 }
     473             : 
     474        7179 :                 if (!bytes_to_drop) {
     475             :                         bytes_to_drop = 1;
     476             :                 }
     477        7179 :                 start += bytes_to_drop;
     478        7179 :                 remain -= bytes_to_drop;
     479        7179 :                 gf_bs_reassign_buffer(ctx->bs, start, remain);
     480             : 
     481        7179 :                 if (prev_pck_size) {
     482           0 :                         if (prev_pck_size > bytes_to_drop) prev_pck_size -= bytes_to_drop;
     483             :                         else {
     484             :                                 prev_pck_size=0;
     485           0 :                                 if (ctx->src_pck) gf_filter_pck_unref(ctx->src_pck);
     486           0 :                                 ctx->src_pck = pck;
     487           0 :                                 if (pck)
     488           0 :                                         gf_filter_pck_ref_props(&ctx->src_pck);
     489             :                         }
     490             :                 }
     491        7179 :                 if (ctx->byte_offset != GF_FILTER_NO_BO)
     492        6286 :                         ctx->byte_offset += bytes_to_drop;
     493             :         }
     494             : 
     495        1467 :         if (!pck) {
     496           2 :                 ctx->ac3_buffer_size = 0;
     497           2 :                 return ac3dmx_process(filter);
     498             :         } else {
     499        1465 :                 if (remain) {
     500         555 :                         memmove(ctx->ac3_buffer, start, remain);
     501             :                 }
     502        1465 :                 ctx->ac3_buffer_size = remain;
     503        1465 :                 gf_filter_pid_drop_packet(ctx->ipid);
     504             :         }
     505        1465 :         return GF_OK;
     506             : }
     507             : 
     508          17 : static void ac3dmx_finalize(GF_Filter *filter)
     509             : {
     510          17 :         GF_AC3DmxCtx *ctx = gf_filter_get_udta(filter);
     511          17 :         if (ctx->bs) gf_bs_del(ctx->bs);
     512          17 :         if (ctx->ac3_buffer) gf_free(ctx->ac3_buffer);
     513          17 :         if (ctx->indexes) gf_free(ctx->indexes);
     514          17 : }
     515             : 
     516        3074 : static const char *ac3dmx_probe_data(const u8 *data, u32 size, GF_FilterProbeScore *score)
     517             : {
     518             :         u32 nb_frames=0;
     519             :         Bool has_broken_frames = GF_FALSE;
     520        3074 :         u32 pos=0;
     521          79 :         while (1) {
     522             :                 GF_AC3Config ahdr;
     523        3153 :                 if (! gf_ac3_parser((u8 *) data, size, &pos, &ahdr, GF_FALSE) )
     524             :                         break;
     525         157 :                 u32 fsize = ahdr.framesize;
     526         157 :                 if (pos) {
     527             :                         nb_frames=0;
     528             :                         has_broken_frames = GF_TRUE;
     529             :                         //what is before is bigger than max ac3 frame size (1920), this is packaged ac3 (mkv) at best
     530          86 :                         if (pos > 2000)
     531             :                                 break;
     532             :                 }
     533          95 :                 nb_frames++;
     534          95 :                 if (fsize > size+pos) break;
     535          93 :                 if (nb_frames>4) break;
     536          79 :                 if (size < fsize+pos) break;
     537          79 :                 size -= fsize+pos;
     538          79 :                 data += fsize+pos;
     539             :         }
     540        3074 :         if (nb_frames>2) {
     541          16 :                 *score = has_broken_frames ? GF_FPROBE_MAYBE_SUPPORTED : GF_FPROBE_SUPPORTED;
     542          16 :                 return "audio/ac3";
     543             :         }
     544             :         return NULL;
     545             : }
     546             : 
     547             : static const GF_FilterCapability AC3DmxCaps[] =
     548             : {
     549             :         CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
     550             :         CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_FILE_EXT, "ac3|eac3"),
     551             :         CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_MIME, "audio/x-ac3|audio/ac3|audio/x-eac3|audio/eac3"),
     552             :         CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
     553             :         CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_AC3),
     554             :         CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_EAC3),
     555             :         CAP_BOOL(GF_CAPS_OUTPUT_STATIC_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
     556             :         {0},
     557             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
     558             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AC3),
     559             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_EAC3),
     560             :         CAP_BOOL(GF_CAPS_INPUT,GF_PROP_PID_UNFRAMED, GF_TRUE),
     561             : };
     562             : 
     563             : #define OFFS(_n)        #_n, offsetof(GF_AC3DmxCtx, _n)
     564             : static const GF_FilterArgs AC3DmxArgs[] =
     565             : {
     566             :         { OFFS(index), "indexing window length", GF_PROP_DOUBLE, "1.0", NULL, 0},
     567             :         {0}
     568             : };
     569             : 
     570             : 
     571             : GF_FilterRegister AC3DmxRegister = {
     572             :         .name = "rfac3",
     573             :         GF_FS_SET_DESCRIPTION("AC3 reframer")
     574             :         GF_FS_SET_HELP("This filter parses AC3 and E-AC3 files/data and outputs corresponding audio PID and frames.")
     575             :         .private_size = sizeof(GF_AC3DmxCtx),
     576             :         .args = AC3DmxArgs,
     577             :         .finalize = ac3dmx_finalize,
     578             :         SETCAPS(AC3DmxCaps),
     579             :         .configure_pid = ac3dmx_configure_pid,
     580             :         .process = ac3dmx_process,
     581             :         .probe_data = ac3dmx_probe_data,
     582             :         .process_event = ac3dmx_process_event
     583             : };
     584             : 
     585             : 
     586        2877 : const GF_FilterRegister *ac3dmx_register(GF_FilterSession *session)
     587             : {
     588        2877 :         return &AC3DmxRegister;
     589             : }
     590             : 
     591             : #else
     592             : 
     593             : const GF_FilterRegister *ac3dmx_register(GF_FilterSession *session)
     594             : {
     595             :         return NULL;
     596             : }
     597             : #endif // GPAC_DISABLE_AV_PARSERS

Generated by: LCOV version 1.13