LCOV - code coverage report
Current view: top level - filters - reframe_truehd.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 213 319 66.8 %
Date: 2021-04-29 23:48:07 Functions: 9 9 100.0 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2021
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / TrueHD 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             : typedef struct
      31             : {
      32             :         u64 pos;
      33             :         Double duration;
      34             : } TrueHDIdx;
      35             : 
      36             : typedef struct
      37             : {
      38             :         u32 frame_size;
      39             :         u32 time;
      40             :         u32 sync;
      41             :         u32 format;
      42             : 
      43             :         u32 sample_rate;
      44             :         Bool mc_6_ch, mc_8_ch;
      45             :         u8 ch_2_modif, ch_6_modif, ch_8_modif, ch_6_assign;
      46             :         u16 ch_8_assign;
      47             :         u16 peak_rate;
      48             : } TrueHDHdr;
      49             : 
      50             : typedef struct
      51             : {
      52             :         //filter args
      53             :         Double index;
      54             : 
      55             :         //only one input pid declared
      56             :         GF_FilterPid *ipid;
      57             :         //only one output pid declared
      58             :         GF_FilterPid *opid;
      59             : 
      60             :         GF_BitStream *bs;
      61             :         u64 file_pos, cts;
      62             :         u32 sample_rate, nb_ch, format;
      63             :         GF_Fraction64 duration;
      64             :         Double start_range;
      65             :         Bool in_seek;
      66             :         u32 timescale, frame_dur;
      67             : 
      68             :         u8 *truehd_buffer;
      69             :         u32 truehd_buffer_size, truehd_buffer_alloc, resume_from;
      70             :         u64 byte_offset;
      71             : 
      72             :         Bool is_playing;
      73             :         Bool is_file, file_loaded;
      74             :         Bool initial_play_done;
      75             : 
      76             :         GF_FilterPacket *src_pck;
      77             : 
      78             :         TrueHDIdx *indexes;
      79             :         u32 index_alloc_size, index_size;
      80             : } GF_TrueHDDmxCtx;
      81             : 
      82             : 
      83             : 
      84             : 
      85           2 : GF_Err truehd_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
      86             : {
      87             :         const GF_PropertyValue *p;
      88           2 :         GF_TrueHDDmxCtx *ctx = gf_filter_get_udta(filter);
      89             : 
      90           2 :         if (is_remove) {
      91           0 :                 ctx->ipid = NULL;
      92           0 :                 if (ctx->opid) {
      93           0 :                         gf_filter_pid_remove(ctx->opid);
      94           0 :                         ctx->opid = NULL;
      95             :                 }
      96             :                 return GF_OK;
      97             :         }
      98           2 :         if (! gf_filter_pid_check_caps(pid))
      99             :                 return GF_NOT_SUPPORTED;
     100             : 
     101           2 :         ctx->ipid = pid;
     102           2 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_TIMESCALE);
     103           2 :         if (p) ctx->timescale = p->value.uint;
     104             : 
     105           2 :         if (ctx->timescale && !ctx->opid) {
     106           0 :                 ctx->opid = gf_filter_pid_new(filter);
     107           0 :                 gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
     108           0 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_UNFRAMED, NULL);
     109             :         }
     110             :         return GF_OK;
     111             : }
     112             : 
     113       79034 : static GF_Err truehd_parse_frame(GF_BitStream *bs, TrueHDHdr *hdr)
     114             : {
     115             :         memset(hdr, 0, sizeof(TrueHDHdr));
     116       79034 :         /*u8 nibble = */gf_bs_read_int(bs, 4);
     117       79034 :         hdr->frame_size = 2 * gf_bs_read_int(bs, 12);
     118       79034 :         hdr->time = gf_bs_read_u16(bs);
     119       79034 :         hdr->sync = gf_bs_read_u32(bs);
     120       79034 :         if (hdr->sync != 0xF8726FBA) {
     121       78293 :                 hdr->sync = 0;
     122       78293 :                 return GF_OK;
     123             :         }
     124         741 :         hdr->format = gf_bs_peek_bits(bs, 32, 0);
     125         741 :         u8 sr_idx = gf_bs_read_int(bs, 4);
     126         741 :         switch (sr_idx) {
     127           0 :         case 0: hdr->sample_rate = 48000; break;
     128           0 :         case 1: hdr->sample_rate = 96000; break;
     129           0 :         case 2: hdr->sample_rate = 192000; break;
     130         741 :         case 8: hdr->sample_rate = 44100; break;
     131           0 :         case 9: hdr->sample_rate = 88200; break;
     132           0 :         case 10: hdr->sample_rate = 176400; break;
     133             :         default:
     134             :                 return GF_NON_COMPLIANT_BITSTREAM;
     135             :         }
     136         741 :         hdr->mc_6_ch = gf_bs_read_int(bs, 1);
     137         741 :         hdr->mc_8_ch = gf_bs_read_int(bs, 1);
     138         741 :         gf_bs_read_int(bs, 2);
     139         741 :         hdr->ch_2_modif = gf_bs_read_int(bs, 2);
     140         741 :         hdr->ch_6_modif = gf_bs_read_int(bs, 2);
     141         741 :         hdr->ch_6_assign = gf_bs_read_int(bs, 5);
     142         741 :         hdr->ch_8_modif = gf_bs_read_int(bs, 2);
     143         741 :         hdr->ch_8_assign = gf_bs_read_int(bs, 13);
     144             : 
     145         741 :         u16 sig = gf_bs_read_u16(bs);
     146         741 :         if (sig != 0xB752)
     147             :                 return GF_NON_COMPLIANT_BITSTREAM;
     148             : 
     149         741 :         gf_bs_read_u16(bs);
     150         741 :         gf_bs_read_u16(bs);
     151         741 :         gf_bs_read_int(bs, 1);
     152         741 :         hdr->peak_rate = gf_bs_read_int(bs, 15);
     153             : 
     154             : 
     155         741 :         return GF_OK;
     156             : }
     157             : 
     158             : static u32 truehd_frame_dur(u32 sample_rate)
     159             : {
     160             : 
     161         702 :         switch (sample_rate) {
     162           0 :         case 48000:
     163             :         case 96000:
     164             :         case 192000:
     165           0 :                 return sample_rate / 1200;
     166         702 :         case 44100:
     167             :         case 88200:
     168             :         case 176400:
     169         702 :                 return sample_rate * 2 / 2205;
     170             :         default:
     171             :                 return 0;
     172             :         }
     173             : }
     174         155 : static void truehd_check_dur(GF_Filter *filter, GF_TrueHDDmxCtx *ctx)
     175             : {
     176             :         FILE *stream;
     177             :         GF_BitStream *bs;
     178             :         u64 duration, cur_dur;
     179             :         s32 sr = -1;
     180             :         u32 frame_dur = 0;
     181             :         const GF_PropertyValue *p;
     182         155 :         if (!ctx->opid || ctx->timescale || ctx->file_loaded) return;
     183             : 
     184           2 :         if (ctx->index<=0) {
     185           2 :                 ctx->file_loaded = GF_TRUE;
     186             :                 return;
     187             :         }
     188             : 
     189           0 :         p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILEPATH);
     190           0 :         if (!p || !p->value.string || !strncmp(p->value.string, "gmem://", 7)) {
     191           0 :                 ctx->is_file = GF_FALSE;
     192           0 :                 ctx->file_loaded = GF_TRUE;
     193             :                 return;
     194             :         }
     195           0 :         ctx->is_file = GF_TRUE;
     196             : 
     197           0 :         stream = gf_fopen(p->value.string, "rb");
     198           0 :         if (!stream) return;
     199             : 
     200           0 :         ctx->index_size = 0;
     201             : 
     202           0 :         bs = gf_bs_from_file(stream, GF_BITSTREAM_READ);
     203             :         duration = 0;
     204             :         cur_dur = 0;
     205           0 :         while ( gf_bs_available(bs) > 8 ) {
     206             :                 TrueHDHdr hdr;
     207           0 :                 u64 pos = gf_bs_get_position(bs);
     208           0 :                 GF_Err e = truehd_parse_frame(bs, &hdr);
     209           0 :                 if (e) break;
     210             : 
     211           0 :                 if (hdr.sync) {
     212           0 :                         if ((sr>=0) && (sr != hdr.sample_rate)) {
     213           0 :                                 duration *= hdr.sample_rate;
     214           0 :                                 duration /= sr;
     215             : 
     216           0 :                                 cur_dur *= hdr.sample_rate;
     217           0 :                                 cur_dur /= sr;
     218             :                         }
     219           0 :                         sr = hdr.sample_rate;
     220             :                         frame_dur = truehd_frame_dur(hdr.sample_rate);
     221             :                 }
     222             : 
     223           0 :                 duration += frame_dur;
     224           0 :                 cur_dur += frame_dur;
     225             : 
     226           0 :                 if (hdr.sync && (cur_dur > ctx->index * sr)) {
     227           0 :                         if (!ctx->index_alloc_size) ctx->index_alloc_size = 10;
     228           0 :                         else if (ctx->index_alloc_size == ctx->index_size) ctx->index_alloc_size *= 2;
     229           0 :                         ctx->indexes = gf_realloc(ctx->indexes, sizeof(TrueHDIdx)*ctx->index_alloc_size);
     230           0 :                         ctx->indexes[ctx->index_size].pos = gf_bs_get_position(bs);
     231           0 :                         ctx->indexes[ctx->index_size].duration = (Double) duration;
     232           0 :                         ctx->indexes[ctx->index_size].duration /= sr;
     233           0 :                         ctx->index_size ++;
     234             :                         cur_dur = 0;
     235             :                 }
     236             : 
     237           0 :                 if (!hdr.frame_size) break;
     238           0 :                 gf_bs_seek(bs, pos + hdr.frame_size);
     239             :         }
     240           0 :         gf_bs_del(bs);
     241           0 :         gf_fclose(stream);
     242             : 
     243           0 :         if (!ctx->duration.num || (ctx->duration.num  * sr != duration * ctx->duration.den)) {
     244           0 :                 ctx->duration.num = (s32) duration;
     245           0 :                 ctx->duration.den = sr;
     246             : 
     247           0 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DURATION, & PROP_FRAC64(ctx->duration));
     248             :         }
     249             : 
     250           0 :         p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILE_CACHED);
     251           0 :         if (p && p->value.boolean) ctx->file_loaded = GF_TRUE;
     252           0 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CAN_DATAREF, & PROP_BOOL(GF_TRUE ) );
     253             : }
     254             : 
     255         702 : static void truehd_check_pid(GF_Filter *filter, GF_TrueHDDmxCtx *ctx, TrueHDHdr *hdr)
     256             : {
     257             :         u8 *data;
     258             :         u32 size, max_rate;
     259             :         GF_BitStream *bs;
     260         702 :         if (!ctx->opid) {
     261           2 :                 ctx->opid = gf_filter_pid_new(filter);
     262           2 :                 truehd_check_dur(filter, ctx);
     263             :         }
     264         702 :         if ((ctx->sample_rate == hdr->sample_rate) && (ctx->format == hdr->format)  )
     265           0 :                 return;
     266             : 
     267         702 :         ctx->frame_dur = truehd_frame_dur(hdr->sample_rate);
     268             : 
     269             :         //copy properties at init or reconfig
     270         702 :         gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
     271         702 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STREAM_TYPE, & PROP_UINT( GF_STREAM_AUDIO));
     272         702 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAMPLES_PER_FRAME, & PROP_UINT(ctx->frame_dur) );
     273         702 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_UNFRAMED, & PROP_BOOL(GF_FALSE) );
     274             : 
     275         702 :         if (ctx->duration.num)
     276           0 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DURATION, & PROP_FRAC64(ctx->duration));
     277             : 
     278         702 :         if (hdr->ch_2_modif==1) {
     279           0 :                 ctx->nb_ch = 1;
     280             :         } else {
     281         702 :                 ctx->nb_ch = 2;
     282         702 :                 if (hdr->ch_6_assign) {
     283         702 :                         ctx->nb_ch = 0;
     284         702 :                         if (hdr->ch_6_assign & 1) ctx->nb_ch += 2;
     285         702 :                         if (hdr->ch_6_assign & 1<<1) ctx->nb_ch += 1;
     286         702 :                         if (hdr->ch_6_assign & 1<<2) ctx->nb_ch += 1;
     287         702 :                         if (hdr->ch_6_assign & 1<<3) ctx->nb_ch += 2;
     288         702 :                         if (hdr->ch_6_assign & 1<<4) ctx->nb_ch += 2;
     289             :                 }
     290         702 :                 if (hdr->ch_8_assign) {
     291         702 :                         ctx->nb_ch = 0;
     292         702 :                         if (hdr->ch_8_assign & 1) ctx->nb_ch += 2;
     293         702 :                         if (hdr->ch_8_assign & 1<<1) ctx->nb_ch += 1;
     294         702 :                         if (hdr->ch_8_assign & 1<<2) ctx->nb_ch += 1;
     295         702 :                         if (hdr->ch_8_assign & 1<<3) ctx->nb_ch += 2;
     296         702 :                         if (hdr->ch_8_assign & 1<<4) ctx->nb_ch += 2;
     297         702 :                         if (hdr->ch_8_assign & 1<<5) ctx->nb_ch += 2;
     298         702 :                         if (hdr->ch_8_assign & 1<<6) ctx->nb_ch += 2;
     299         702 :                         if (hdr->ch_8_assign & 1<<7) ctx->nb_ch += 1;
     300         702 :                         if (hdr->ch_8_assign & 1<<8) ctx->nb_ch += 1;
     301         702 :                         if (hdr->ch_8_assign & 1<<9) ctx->nb_ch += 2;
     302         702 :                         if (hdr->ch_8_assign & 1<<10) ctx->nb_ch += 2;
     303         702 :                         if (hdr->ch_8_assign & 1<<11) ctx->nb_ch += 1;
     304         702 :                         if (hdr->ch_8_assign & 1<<12) ctx->nb_ch += 1;
     305             :                 }
     306             :         }
     307             : 
     308         702 :         if (!ctx->timescale) {
     309             :                 //we change sample rate, change cts
     310         702 :                 if (ctx->cts && (ctx->sample_rate != hdr->sample_rate)) {
     311           0 :                         ctx->cts *= hdr->sample_rate;
     312           0 :                         ctx->cts /= ctx->sample_rate;
     313             :                 }
     314             :         }
     315         702 :         ctx->sample_rate = hdr->sample_rate;
     316             : 
     317         702 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_TIMESCALE, & PROP_UINT(ctx->timescale ? ctx->timescale : ctx->sample_rate));
     318         702 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAMPLE_RATE, & PROP_UINT(ctx->sample_rate));
     319         702 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_NUM_CHANNELS, & PROP_UINT(ctx->nb_ch) );
     320             : 
     321         702 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, & PROP_UINT(GF_CODECID_TRUEHD) );
     322             : 
     323         702 :         max_rate = hdr->peak_rate;
     324         702 :         max_rate *= hdr->sample_rate;
     325         702 :         max_rate /= 16;
     326         702 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_BITRATE, & PROP_UINT(max_rate) );
     327             : 
     328         702 :         bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
     329         702 :         gf_bs_write_u32(bs, hdr->format);
     330         702 :         gf_bs_write_int(bs, hdr->peak_rate, 15);
     331         702 :         gf_bs_write_int(bs, 0, 1);
     332         702 :         gf_bs_write_u32(bs, 0);
     333         702 :         gf_bs_get_content(bs, &data, &size);
     334         702 :         gf_bs_del(bs);
     335         702 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DECODER_CONFIG, & PROP_DATA_NO_COPY(data, size) );
     336             : 
     337         702 :         if (ctx->is_file && ctx->index) {
     338           0 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_PLAYBACK_MODE, & PROP_UINT(GF_PLAYBACK_MODE_FASTFORWARD) );
     339             :         }
     340             : }
     341             : 
     342         153 : static Bool truehd_process_event(GF_Filter *filter, const GF_FilterEvent *evt)
     343             : {
     344             :         u32 i;
     345             :         GF_FilterEvent fevt;
     346         153 :         GF_TrueHDDmxCtx *ctx = gf_filter_get_udta(filter);
     347             : 
     348         153 :         switch (evt->base.type) {
     349           2 :         case GF_FEVT_PLAY:
     350           2 :                 if (!ctx->is_playing) {
     351           2 :                         ctx->is_playing = GF_TRUE;
     352           2 :                         ctx->cts = 0;
     353           2 :                         ctx->truehd_buffer_size = 0;
     354           2 :                         ctx->resume_from = 0;
     355             :                 }
     356           2 :                 if (! ctx->is_file) {
     357             :                         return GF_FALSE;
     358             :                 }
     359           0 :                 ctx->start_range = evt->play.start_range;
     360           0 :                 ctx->in_seek = GF_TRUE;
     361           0 :                 ctx->file_pos = 0;
     362           0 :                 if (ctx->start_range) {
     363           0 :                         for (i=1; i<ctx->index_size; i++) {
     364           0 :                                 if (ctx->indexes[i].duration>ctx->start_range) {
     365           0 :                                         ctx->cts = (u64) (ctx->indexes[i-1].duration * ctx->sample_rate);
     366           0 :                                         ctx->file_pos = ctx->indexes[i-1].pos;
     367           0 :                                         break;
     368             :                                 }
     369             :                         }
     370             :                 }
     371           0 :                 if (!ctx->initial_play_done) {
     372           0 :                         ctx->initial_play_done = GF_TRUE;
     373             :                         //seek will not change the current source state, don't send a seek
     374           0 :                         if (!ctx->file_pos)
     375             :                                 return GF_TRUE;
     376             :                 }
     377           0 :                 ctx->truehd_buffer_size = 0;
     378           0 :                 ctx->resume_from = 0;
     379             :                 //post a seek
     380           0 :                 GF_FEVT_INIT(fevt, GF_FEVT_SOURCE_SEEK, ctx->ipid);
     381           0 :                 fevt.seek.start_offset = ctx->file_pos;
     382           0 :                 gf_filter_pid_send_event(ctx->ipid, &fevt);
     383             : 
     384             :                 //cancel event
     385           0 :                 return GF_TRUE;
     386             : 
     387           1 :         case GF_FEVT_STOP:
     388             :                 //don't cancel event
     389           1 :                 ctx->is_playing = GF_FALSE;
     390           1 :                 return GF_FALSE;
     391             : 
     392             :         case GF_FEVT_SET_SPEED:
     393             :                 //cancel event
     394             :                 return GF_TRUE;
     395             :         default:
     396             :                 break;
     397             :         }
     398             :         //by default don't cancel event - to rework once we have downloading in place
     399         150 :         return GF_FALSE;
     400             : }
     401             : 
     402             : static GFINLINE void truehd_update_cts(GF_TrueHDDmxCtx *ctx, TrueHDHdr *hdr)
     403             : {
     404       11199 :         if (ctx->timescale) {
     405           0 :                 u64 inc = ctx->frame_dur;
     406           0 :                 inc *= ctx->timescale;
     407           0 :                 inc /= ctx->sample_rate;
     408           0 :                 ctx->cts += inc;
     409             :         } else {
     410       11199 :                 ctx->cts += ctx->frame_dur;
     411             :         }
     412             : }
     413             : 
     414         153 : GF_Err truehd_process(GF_Filter *filter)
     415             : {
     416         153 :         GF_TrueHDDmxCtx *ctx = gf_filter_get_udta(filter);
     417             :         GF_FilterPacket *pck, *dst_pck;
     418             :         u8 *output;
     419             :         u8 *start;
     420             :         GF_Err e = GF_OK;
     421             :         u32 pck_size, remain, prev_pck_size;
     422             :         u64 cts = GF_FILTER_NO_TS;
     423             : 
     424             :         //always reparse duration
     425         153 :         if (!ctx->duration.num)
     426         153 :                 truehd_check_dur(filter, ctx);
     427             : 
     428         153 :         if (ctx->opid && !ctx->is_playing)
     429             :                 return GF_OK;
     430             : 
     431         150 :         pck = gf_filter_pid_get_packet(ctx->ipid);
     432         150 :         if (!pck) {
     433           1 :                 if (gf_filter_pid_is_eos(ctx->ipid)) {
     434           1 :                         if (!ctx->truehd_buffer_size) {
     435           1 :                                 if (ctx->opid)
     436           1 :                                         gf_filter_pid_set_eos(ctx->opid);
     437           1 :                                 if (ctx->src_pck) gf_filter_pck_unref(ctx->src_pck);
     438           1 :                                 ctx->src_pck = NULL;
     439           1 :                                 return GF_EOS;
     440             :                         }
     441             :                 } else {
     442             :                         return GF_OK;
     443             :                 }
     444             :         }
     445             : 
     446         149 :         prev_pck_size = ctx->truehd_buffer_size;
     447         149 :         if (pck && !ctx->resume_from) {
     448         149 :                 const u8 *data = gf_filter_pck_get_data(pck, &pck_size);
     449         149 :                 if (!pck_size) {
     450           0 :                         gf_filter_pid_drop_packet(ctx->ipid);
     451           0 :                         return GF_OK;
     452             :                 }
     453             : 
     454         149 :                 if (ctx->byte_offset != GF_FILTER_NO_BO) {
     455         149 :                         u64 byte_offset = gf_filter_pck_get_byte_offset(pck);
     456         149 :                         if (!ctx->truehd_buffer_size) {
     457           4 :                                 ctx->byte_offset = byte_offset;
     458         145 :                         } else if (ctx->byte_offset + ctx->truehd_buffer_size != byte_offset) {
     459           0 :                                 ctx->byte_offset = GF_FILTER_NO_BO;
     460           0 :                                 if ((byte_offset != GF_FILTER_NO_BO) && (byte_offset>ctx->truehd_buffer_size) ) {
     461           0 :                                         ctx->byte_offset = byte_offset - ctx->truehd_buffer_size;
     462             :                                 }
     463             :                         }
     464             :                 }
     465             : 
     466         149 :                 if (ctx->truehd_buffer_size + pck_size > ctx->truehd_buffer_alloc) {
     467           7 :                         ctx->truehd_buffer_alloc = ctx->truehd_buffer_size + pck_size;
     468           7 :                         ctx->truehd_buffer = gf_realloc(ctx->truehd_buffer, ctx->truehd_buffer_alloc);
     469           7 :                         if (!ctx->truehd_buffer) return GF_OUT_OF_MEM;
     470             :                 }
     471         149 :                 memcpy(ctx->truehd_buffer + ctx->truehd_buffer_size, data, pck_size);
     472         149 :                 ctx->truehd_buffer_size += pck_size;
     473             :         }
     474             : 
     475             :         //input pid sets some timescale - we flushed pending data , update cts
     476         149 :         if (ctx->timescale && pck) {
     477           0 :                 cts = gf_filter_pck_get_cts(pck);
     478             :         }
     479             : 
     480           0 :         if (cts == GF_FILTER_NO_TS) {
     481             :                 //avoids updating cts
     482             :                 prev_pck_size = 0;
     483             :         }
     484             : 
     485         149 :         remain = ctx->truehd_buffer_size;
     486         149 :         start = ctx->truehd_buffer;
     487             : 
     488         149 :         if (ctx->resume_from) {
     489           0 :                 start += ctx->resume_from - 1;
     490           0 :                 remain -= ctx->resume_from - 1;
     491           0 :                 ctx->resume_from = 0;
     492             :         }
     493             : 
     494         149 :         if (!ctx->bs) {
     495           2 :                 ctx->bs = gf_bs_new(start, remain, GF_BITSTREAM_READ);
     496             :         } else {
     497         147 :                 gf_bs_reassign_buffer(ctx->bs, start, remain);
     498             :         }
     499       11348 :         while (remain > 8) {
     500             :                 u8 *frame;
     501             :                 TrueHDHdr hdr;
     502             :                 u32 frame_start, bytes_to_drop=0;
     503             : 
     504       11324 :                 frame_start = (u32) gf_bs_get_position(ctx->bs);
     505       11324 :                 e = truehd_parse_frame(ctx->bs, &hdr);
     506       11324 :                 if (e) {
     507             :                         remain = 0;
     508         123 :                         break;
     509             :                 }
     510       11324 :                 if (!hdr.frame_size) {
     511             :                         remain = 0;
     512             :                         break;
     513             :                 }
     514             : 
     515             :                 //frame not complete, wait
     516       11324 :                 if (remain < frame_start + hdr.frame_size)
     517             :                         break;
     518             : 
     519       11201 :                 if (hdr.sync)
     520         702 :                         truehd_check_pid(filter, ctx, &hdr);
     521             : 
     522       11201 :                 if (!ctx->is_playing) {
     523           2 :                         ctx->resume_from = 1 + ctx->truehd_buffer_size - remain;
     524           4 :                         return GF_OK;
     525             :                 }
     526             : 
     527       11199 :                 frame = start + frame_start;
     528             : 
     529       11199 :                 if (ctx->in_seek) {
     530           0 :                         u64 nb_samples_at_seek = (u64) (ctx->start_range * hdr.sample_rate);
     531           0 :                         if (ctx->cts + ctx->frame_dur >= nb_samples_at_seek) {
     532             :                                 //u32 samples_to_discard = (ctx->cts + ctx->dts_inc) - nb_samples_at_seek;
     533           0 :                                 ctx->in_seek = GF_FALSE;
     534             :                         }
     535             :                 }
     536             : 
     537       11199 :                 bytes_to_drop = hdr.frame_size;
     538       11199 :                 if (ctx->timescale && !prev_pck_size &&  (cts != GF_FILTER_NO_TS) ) {
     539             :                         //trust input CTS if diff is more than one sec
     540           0 :                         if ((cts > ctx->cts + ctx->timescale) || (ctx->cts > cts + ctx->timescale))
     541           0 :                                 ctx->cts = cts;
     542             :                         cts = GF_FILTER_NO_TS;
     543             :                 }
     544             : 
     545       11199 :                 if (!ctx->in_seek) {
     546       11199 :                         dst_pck = gf_filter_pck_new_alloc(ctx->opid, hdr.frame_size, &output);
     547       11199 :                         if (!dst_pck) return GF_OUT_OF_MEM;
     548       11199 :                         if (ctx->src_pck) gf_filter_pck_merge_properties(ctx->src_pck, dst_pck);
     549             : 
     550       11199 :                         memcpy(output, frame, hdr.frame_size);
     551       11199 :                         gf_filter_pck_set_dts(dst_pck, ctx->cts);
     552       11199 :                         gf_filter_pck_set_cts(dst_pck, ctx->cts);
     553       11199 :                         if (hdr.sync)
     554         700 :                                 gf_filter_pck_set_sap(dst_pck, GF_FILTER_SAP_1);
     555       11199 :                         gf_filter_pck_set_framing(dst_pck, GF_TRUE, GF_TRUE);
     556             : 
     557       11199 :                         if (ctx->byte_offset != GF_FILTER_NO_BO) {
     558       11199 :                                 gf_filter_pck_set_byte_offset(dst_pck, ctx->byte_offset + hdr.frame_size);
     559             :                         }
     560             : 
     561       11199 :                         gf_filter_pck_send(dst_pck);
     562             :                 }
     563             :                 truehd_update_cts(ctx, &hdr);
     564             : 
     565             :                 //truncated last frame
     566       11199 :                 if (bytes_to_drop > remain) {
     567           0 :                         GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[TrueHDDmx] truncated TrueHD frame!\n"));
     568             :                         bytes_to_drop = remain;
     569             :                 }
     570             : 
     571       11199 :                 if (!bytes_to_drop) {
     572             :                         bytes_to_drop = 1;
     573             :                 }
     574       11199 :                 start += bytes_to_drop;
     575       11199 :                 remain -= bytes_to_drop;
     576       11199 :                 gf_bs_reassign_buffer(ctx->bs, start, remain);
     577             : 
     578       11199 :                 if (prev_pck_size) {
     579           0 :                         if (prev_pck_size > bytes_to_drop) prev_pck_size -= bytes_to_drop;
     580             :                         else {
     581             :                                 prev_pck_size=0;
     582           0 :                                 if (ctx->src_pck) gf_filter_pck_unref(ctx->src_pck);
     583           0 :                                 ctx->src_pck = pck;
     584           0 :                                 if (pck)
     585           0 :                                         gf_filter_pck_ref_props(&ctx->src_pck);
     586             :                         }
     587             :                 }
     588       11199 :                 if (ctx->byte_offset != GF_FILTER_NO_BO)
     589       11199 :                         ctx->byte_offset += bytes_to_drop;
     590             :         }
     591             : 
     592         147 :         if (!pck) {
     593           0 :                 ctx->truehd_buffer_size = 0;
     594           0 :                 return truehd_process(filter);
     595             :         } else {
     596         147 :                 if (remain) {
     597         146 :                         memmove(ctx->truehd_buffer, start, remain);
     598             :                 }
     599         147 :                 ctx->truehd_buffer_size = remain;
     600         147 :                 gf_filter_pid_drop_packet(ctx->ipid);
     601             :         }
     602         147 :         return e;
     603             : }
     604             : 
     605           2 : static void truehd_finalize(GF_Filter *filter)
     606             : {
     607           2 :         GF_TrueHDDmxCtx *ctx = gf_filter_get_udta(filter);
     608           2 :         if (ctx->bs) gf_bs_del(ctx->bs);
     609           2 :         if (ctx->truehd_buffer) gf_free(ctx->truehd_buffer);
     610           2 :         if (ctx->indexes) gf_free(ctx->indexes);
     611           2 : }
     612             : 
     613        3065 : static const char *truehd_probe_data(const u8 *data, u32 size, GF_FilterProbeScore *score)
     614             : {
     615             :         u32 nb_frames=0;
     616        3065 :         GF_BitStream *bs = gf_bs_new(data, size, GF_BITSTREAM_READ);
     617       72222 :         while (gf_bs_available(bs) > 8 ) {
     618             :                 TrueHDHdr hdr;
     619       67710 :                 u64 pos = gf_bs_get_position(bs);
     620       67710 :                 GF_Err e = truehd_parse_frame(bs, &hdr);
     621       67710 :                 if (e || !hdr.frame_size) {
     622             :                         nb_frames = 0;
     623        1618 :                         break;
     624             :                 }
     625       66092 :                 if (hdr.sync) nb_frames++;
     626       66092 :                 gf_bs_seek(bs, pos + hdr.frame_size);
     627             :         }
     628        3065 :         gf_bs_del(bs);
     629        3065 :         if (nb_frames) {
     630           2 :                 *score = GF_FPROBE_MAYBE_SUPPORTED;
     631           2 :                 return "audio/truehd";
     632             :         }
     633             :         return NULL;
     634             : }
     635             : 
     636             : static const GF_FilterCapability TrueHDDmxCaps[] =
     637             : {
     638             :         CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
     639             :         CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_FILE_EXT, "mlp|thd|truehd"),
     640             :         CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_MIME, "audio/truehd|audio/x-truehd"),
     641             :         CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
     642             :         CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_TRUEHD),
     643             :         CAP_BOOL(GF_CAPS_OUTPUT_STATIC_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
     644             :         {0},
     645             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
     646             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_TRUEHD),
     647             :         CAP_BOOL(GF_CAPS_INPUT,GF_PROP_PID_UNFRAMED, GF_TRUE),
     648             : };
     649             : 
     650             : #define OFFS(_n)        #_n, offsetof(GF_TrueHDDmxCtx, _n)
     651             : static const GF_FilterArgs TrueHDDmxArgs[] =
     652             : {
     653             :         { OFFS(index), "indexing window length", GF_PROP_DOUBLE, "1.0", NULL, 0},
     654             :         {0}
     655             : };
     656             : 
     657             : 
     658             : GF_FilterRegister TrueHDDmxRegister = {
     659             :         .name = "rftruehd",
     660             :         GF_FS_SET_DESCRIPTION("TrueHD reframer")
     661             :         GF_FS_SET_HELP("This filter parses Dolby TrueHD files/data and outputs corresponding audio PID and frames.")
     662             :         .private_size = sizeof(GF_TrueHDDmxCtx),
     663             :         .args = TrueHDDmxArgs,
     664             :         .finalize = truehd_finalize,
     665             :         SETCAPS(TrueHDDmxCaps),
     666             :         .configure_pid = truehd_configure_pid,
     667             :         .process = truehd_process,
     668             :         .probe_data = truehd_probe_data,
     669             :         .process_event = truehd_process_event
     670             : };
     671             : 
     672             : 
     673        2877 : const GF_FilterRegister *truehd_register(GF_FilterSession *session)
     674             : {
     675        2877 :         return &TrueHDDmxRegister;
     676             : }
     677             : 

Generated by: LCOV version 1.13