LCOV - code coverage report
Current view: top level - filters - reframe_mpgvid.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 492 551 89.3 %
Date: 2021-04-29 23:48:07 Functions: 11 11 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 / MPEG-1/2/4(Part2) video 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             : #include <gpac/internal/media_dev.h>
      30             : 
      31             : #ifndef GPAC_DISABLE_AV_PARSERS
      32             : 
      33             : typedef struct
      34             : {
      35             :         u64 pos;
      36             :         Double start_time;
      37             : } MPGVidIdx;
      38             : 
      39             : typedef struct
      40             : {
      41             :         //filter args
      42             :         GF_Fraction fps;
      43             :         Double index;
      44             :         Bool vfr, importer;
      45             : 
      46             :         //only one input pid declared
      47             :         GF_FilterPid *ipid;
      48             :         //only one output pid declared
      49             :         GF_FilterPid *opid;
      50             : 
      51             :         GF_BitStream *bs;
      52             :         u64 cts, dts, prev_dts;
      53             :         u32 width, height;
      54             :         GF_Fraction64 duration;
      55             :         Double start_range;
      56             :         Bool in_seek;
      57             :         u32 timescale;
      58             : 
      59             :         u32 resume_from;
      60             :         GF_Fraction cur_fps;
      61             : 
      62             :         Bool is_mpg12, forced_packed;
      63             :         GF_M4VParser *vparser;
      64             :         GF_M4VDecSpecInfo dsi;
      65             :         u32 b_frames;
      66             :         Bool is_packed, is_vfr;
      67             :         GF_List *pck_queue;
      68             :         u64 last_ref_cts;
      69             :         Bool frame_started;
      70             : 
      71             :         u32 nb_i, nb_p, nb_b, nb_frames, max_b;
      72             : 
      73             :         u32 bytes_in_header;
      74             :         char *hdr_store;
      75             :         u32 hdr_store_size, hdr_store_alloc;
      76             : 
      77             :         Bool is_playing;
      78             :         Bool is_file, file_loaded;
      79             :         Bool initial_play_done;
      80             : 
      81             :         Bool input_is_au_start, input_is_au_end;
      82             :         Bool recompute_cts;
      83             : 
      84             :         GF_FilterPacket *src_pck;
      85             : 
      86             :         MPGVidIdx *indexes;
      87             :         u32 index_alloc_size, index_size;
      88             :         u32 bitrate;
      89             : } GF_MPGVidDmxCtx;
      90             : 
      91             : 
      92         111 : GF_Err mpgviddmx_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
      93             : {
      94             :         Bool was_mpeg12;
      95             :         const GF_PropertyValue *p;
      96         111 :         GF_MPGVidDmxCtx *ctx = gf_filter_get_udta(filter);
      97             : 
      98         111 :         if (is_remove) {
      99           3 :                 ctx->ipid = NULL;
     100           3 :                 if (ctx->opid) {
     101           3 :                         gf_filter_pid_remove(ctx->opid);
     102           3 :                         ctx->opid = NULL;
     103             :                 }
     104             :                 return GF_OK;
     105             :         }
     106         108 :         if (! gf_filter_pid_check_caps(pid))
     107             :                 return GF_NOT_SUPPORTED;
     108             : 
     109         108 :         ctx->ipid = pid;
     110         108 :         ctx->cur_fps = ctx->fps;
     111         108 :         if (!ctx->fps.num || !ctx->fps.den) {
     112         108 :                 ctx->cur_fps.num = 25000;
     113         108 :                 ctx->cur_fps.den = 1000;
     114             :         }
     115             : 
     116         108 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_TIMESCALE);
     117         108 :         if (p) {
     118          33 :                 ctx->timescale = ctx->cur_fps.num = p->value.uint;
     119          33 :                 ctx->cur_fps.den = 0;
     120          33 :                 p = gf_filter_pid_get_property(pid, GF_PROP_PID_FPS);
     121          33 :                 if (p) {
     122          11 :                         ctx->cur_fps = p->value.frac;
     123             :                 }
     124          33 :                 p = gf_filter_pid_get_property_str(pid, "nocts");
     125          33 :                 if (p && p->value.boolean) ctx->recompute_cts = GF_TRUE;
     126             :         }
     127             : 
     128         108 :         was_mpeg12 = ctx->is_mpg12;
     129             : 
     130         108 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_CODECID);
     131         108 :         if (p) {
     132          33 :                 switch (p->value.uint) {
     133          25 :                 case GF_CODECID_MPEG1:
     134             :                 case GF_CODECID_MPEG2_422:
     135             :                 case GF_CODECID_MPEG2_SNR:
     136             :                 case GF_CODECID_MPEG2_HIGH:
     137             :                 case GF_CODECID_MPEG2_MAIN:
     138             :                 case GF_CODECID_MPEG2_SIMPLE:
     139             :                 case GF_CODECID_MPEG2_SPATIAL:
     140          25 :                         ctx->is_mpg12 = GF_TRUE;
     141          25 :                         break;
     142             :                 }
     143             :         }
     144             :         else {
     145          75 :                 p = gf_filter_pid_get_property(pid, GF_PROP_PID_MIME);
     146          75 :                 if (p && p->value.string && (strstr(p->value.string, "m1v") || strstr(p->value.string, "m2v")) ) ctx->is_mpg12 = GF_TRUE;
     147             :                 else {
     148          75 :                         p = gf_filter_pid_get_property(pid, GF_PROP_PID_FILE_EXT);
     149          75 :                         if (p && p->value.string && (strstr(p->value.string, "m1v") || strstr(p->value.string, "m2v")) ) ctx->is_mpg12 = GF_TRUE;
     150             :                 }
     151             :         }
     152             : 
     153         108 :         if (ctx->vparser && (was_mpeg12 != ctx->is_mpg12)) {
     154           0 :                 gf_m4v_parser_del_no_bs(ctx->vparser);
     155           0 :                 ctx->vparser = NULL;
     156             :         }
     157             : 
     158         108 :         if (ctx->timescale && !ctx->opid) {
     159          23 :                 ctx->opid = gf_filter_pid_new(filter);
     160          23 :                 gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
     161          23 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_UNFRAMED, NULL);
     162             :         }
     163             :         return GF_OK;
     164             : }
     165             : 
     166             : 
     167       14479 : static void mpgviddmx_check_dur(GF_Filter *filter, GF_MPGVidDmxCtx *ctx)
     168             : {
     169             : 
     170             :         FILE *stream;
     171             :         GF_BitStream *bs;
     172             :         GF_M4VParser *vparser;
     173             :         GF_M4VDecSpecInfo dsi;
     174             :         GF_Err e;
     175             :         u64 duration, cur_dur, rate;
     176             :         const GF_PropertyValue *p;
     177       28905 :         if (!ctx->opid || ctx->timescale || ctx->file_loaded) return;
     178             : 
     179          75 :         if (ctx->index<=0) {
     180          22 :                 ctx->file_loaded = GF_TRUE;
     181             :                 return;
     182             :         }
     183             : 
     184          53 :         p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILEPATH);
     185          53 :         if (!p || !p->value.string || !strncmp(p->value.string, "gmem://", 7)) {
     186           0 :                 ctx->is_file = GF_FALSE;
     187           0 :                 ctx->file_loaded = GF_TRUE;
     188             :                 return;
     189             :         }
     190          53 :         ctx->is_file = GF_TRUE;
     191             : 
     192          53 :         stream = gf_fopen(p->value.string, "rb");
     193          53 :         if (!stream) return;
     194             : 
     195          53 :         ctx->index_size = 0;
     196             : 
     197          53 :         bs = gf_bs_from_file(stream, GF_BITSTREAM_READ);
     198             : 
     199          53 :         vparser = gf_m4v_parser_bs_new(bs, ctx->is_mpg12);
     200          53 :         e = gf_m4v_parse_config(vparser, &dsi);
     201          53 :         if (e) {
     202           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[MPGVid] Could not parse video header - duration  not estimated\n"));
     203           0 :                 ctx->file_loaded = GF_TRUE;
     204             :                 return;
     205             :         }
     206             : 
     207             :         duration = 0;
     208             :         cur_dur = 0;
     209       13125 :         while (gf_bs_available(bs)) {
     210             :                 u8 ftype;
     211             :                 u32 tinc;
     212             :                 u64 fsize, start;
     213             :                 Bool is_coded;
     214             :                 u64 pos;
     215       13072 :                 pos = gf_m4v_get_object_start(vparser);
     216       13072 :                 e = gf_m4v_parse_frame(vparser, &dsi, &ftype, &tinc, &fsize, &start, &is_coded);
     217       13072 :                 if (e<0) {
     218           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[MPGVid] Could not parse video frame\n"));
     219           0 :                         continue;
     220             :                 }
     221             : 
     222       13072 :                 duration += ctx->cur_fps.den;
     223       13072 :                 cur_dur += ctx->cur_fps.den;
     224             :                 //only index at I-frame start
     225       13072 :                 if (pos && (ftype==0) && (cur_dur >= ctx->index * ctx->cur_fps.num) ) {
     226         463 :                         if (!ctx->index_alloc_size) ctx->index_alloc_size = 10;
     227         413 :                         else if (ctx->index_alloc_size == ctx->index_size) ctx->index_alloc_size *= 2;
     228         463 :                         ctx->indexes = gf_realloc(ctx->indexes, sizeof(MPGVidIdx)*ctx->index_alloc_size);
     229         463 :                         ctx->indexes[ctx->index_size].pos = pos;
     230         463 :                         ctx->indexes[ctx->index_size].start_time = (Double) (duration-ctx->cur_fps.den);
     231         463 :                         ctx->indexes[ctx->index_size].start_time /= ctx->cur_fps.num;
     232         463 :                         ctx->index_size ++;
     233             :                         cur_dur = 0;
     234             :                 }
     235             :         }
     236          53 :         rate = gf_bs_get_position(bs);
     237          53 :         gf_m4v_parser_del(vparser);
     238          53 :         gf_fclose(stream);
     239             : 
     240          53 :         if (!ctx->duration.num || (ctx->duration.num  * ctx->cur_fps.num != duration * ctx->duration.den)) {
     241          53 :                 ctx->duration.num = (s32) duration;
     242          53 :                 ctx->duration.den = ctx->cur_fps.num;
     243             : 
     244          53 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DURATION, & PROP_FRAC64(ctx->duration));
     245             : 
     246          53 :                 if (duration && !gf_sys_is_test_mode() ) {
     247           0 :                         rate *= 8 * ctx->duration.den;
     248           0 :                         rate /= ctx->duration.num;
     249           0 :                         ctx->bitrate = (u32) rate;
     250             :                 }
     251             :         }
     252             : 
     253          53 :         p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILE_CACHED);
     254          53 :         if (p && p->value.boolean) ctx->file_loaded = GF_TRUE;
     255          53 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CAN_DATAREF, & PROP_BOOL(GF_TRUE ) );
     256             : }
     257             : 
     258             : 
     259       34704 : static void mpgviddmx_enqueue_or_dispatch(GF_MPGVidDmxCtx *ctx, GF_FilterPacket *pck, Bool flush_ref, Bool is_eos)
     260             : {
     261             :         //TODO: we are dispatching frames in "negctts mode", ie we may have DTS>CTS
     262             :         //need to signal this for consumers using DTS (eg MPEG-2 TS)
     263       34704 :         if (flush_ref && ctx->pck_queue) {
     264             :                 //send all reference packet queued
     265        8013 :                 u32 i, count = gf_list_count(ctx->pck_queue);
     266             : 
     267       34474 :                 for (i=0; i<count; i++) {
     268             :                         u64 cts;
     269       26461 :                         GF_FilterPacket *q_pck = gf_list_get(ctx->pck_queue, i);
     270       26461 :                         u8 carousel = gf_filter_pck_get_carousel_version(q_pck);
     271       26461 :                         if (!carousel) {
     272        5795 :                                 gf_filter_pck_send(q_pck);
     273        5795 :                                 continue;
     274             :                         }
     275       20666 :                         gf_filter_pck_set_carousel_version(q_pck, 0);
     276       20666 :                         cts = gf_filter_pck_get_cts(q_pck);
     277       20666 :                         if (cts != GF_FILTER_NO_TS) {
     278             :                                 //offset the cts of the ref frame to the number of B frames in-between
     279       18265 :                                 if (ctx->last_ref_cts == cts) {
     280        7080 :                                         cts += ctx->b_frames * ctx->cur_fps.den;
     281        7080 :                                         gf_filter_pck_set_cts(q_pck, cts);
     282             :                                 } else {
     283             :                                         //shift all other frames (i.e. pending Bs) by 1 frame in the past since we move the ref frame after them
     284             :                                         assert(cts >= ctx->cur_fps.den);
     285       11185 :                                         cts -= ctx->cur_fps.den;
     286       11185 :                                         gf_filter_pck_set_cts(q_pck, cts);
     287             :                                 }
     288             :                         }
     289       20666 :                         if (is_eos && (i+1==count)) {
     290             :                                 Bool start, end;
     291          45 :                                 gf_filter_pck_get_framing(q_pck, &start, &end);
     292          45 :                                 gf_filter_pck_set_framing(q_pck, start, GF_TRUE);
     293             :                         }
     294       20666 :                         gf_filter_pck_send(q_pck);
     295             :                 }
     296        8013 :                 gf_list_reset(ctx->pck_queue);
     297             :         }
     298       34704 :         if (!pck) return;
     299             : 
     300       26517 :         if (!ctx->pck_queue) ctx->pck_queue = gf_list_new();
     301       26517 :         gf_list_add(ctx->pck_queue, pck);
     302             : }
     303             : 
     304         261 : static void mpgviddmx_check_pid(GF_Filter *filter, GF_MPGVidDmxCtx *ctx, u32 vosh_size, u8 *data)
     305             : {
     306         261 :         if (!ctx->opid) {
     307          75 :                 ctx->opid = gf_filter_pid_new(filter);
     308          75 :                 gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
     309          75 :                 mpgviddmx_check_dur(filter, ctx);
     310             :         }
     311             : 
     312         261 :         if ((ctx->width == ctx->dsi.width) && (ctx->height == ctx->dsi.height)) return;
     313             : 
     314             :         //copy properties at init or reconfig
     315         101 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STREAM_TYPE, & PROP_UINT(GF_STREAM_VISUAL));
     316         101 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_TIMESCALE, & PROP_UINT(ctx->timescale ? ctx->timescale : ctx->cur_fps.num));
     317         101 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_FPS, & PROP_FRAC(ctx->cur_fps));
     318         101 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_UNFRAMED, NULL);
     319         101 :         if (ctx->duration.num)
     320          56 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DURATION, & PROP_FRAC64(ctx->duration));
     321             : 
     322         101 :         mpgviddmx_enqueue_or_dispatch(ctx, NULL, GF_TRUE, GF_FALSE);
     323             : 
     324         101 :         ctx->width = ctx->dsi.width;
     325         101 :         ctx->height = ctx->dsi.height;
     326         101 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_WIDTH, & PROP_UINT( ctx->dsi.width));
     327         101 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_HEIGHT, & PROP_UINT( ctx->dsi.height));
     328         101 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAR, & PROP_FRAC_INT(ctx->dsi.par_num, ctx->dsi.par_den));
     329             : 
     330         101 :         if (ctx->is_mpg12) {
     331          27 :                 const GF_PropertyValue *cid = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_CODECID);
     332          27 :                 u32 PL = ctx->dsi.VideoPL;
     333          27 :                 if (cid) {
     334          15 :                         switch (cid->value.uint) {
     335             :                         case GF_CODECID_MPEG2_MAIN:
     336             :                         case GF_CODECID_MPEG2_422:
     337             :                         case GF_CODECID_MPEG2_SNR:
     338             :                         case GF_CODECID_MPEG2_HIGH:
     339             :                                 //keep same signaling
     340             :                                 PL = cid->value.uint;
     341             :                                 break;
     342             :                         default:
     343             :                                 break;
     344             :                         }
     345          12 :                 }
     346          27 :                 if (!PL) PL = GF_CODECID_MPEG2_MAIN;
     347          27 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, & PROP_UINT(PL));
     348             :         } else {
     349          74 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, & PROP_UINT(GF_CODECID_MPEG4_PART2));
     350             :         }
     351         101 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_PROFILE_LEVEL, & PROP_UINT (ctx->dsi.VideoPL) );
     352             : 
     353         101 :         if (ctx->bitrate) {
     354           0 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_BITRATE, & PROP_UINT(ctx->bitrate));
     355             :         }
     356             : 
     357         101 :         ctx->b_frames = 0;
     358             : 
     359         101 :         if (vosh_size) {
     360             :                 u32 i;
     361          74 :                 char * dcfg = gf_malloc(sizeof(char)*vosh_size);
     362             :                 memcpy(dcfg, data, sizeof(char)*vosh_size);
     363             : 
     364             :                 /*remove packed flag if any (VOSH user data)*/
     365          74 :                 ctx->is_packed = ctx->is_vfr = ctx->forced_packed = GF_FALSE;
     366             :                 i=0;
     367         300 :                 while (1) {
     368             :                         char *frame = dcfg;
     369         374 :                         while ((i+3<vosh_size)  && ((frame[i]!=0) || (frame[i+1]!=0) || (frame[i+2]!=1))) i++;
     370         374 :                         if (i+4>=vosh_size) break;
     371         370 :                         if (strncmp(frame+i+4, "DivX", 4)) {
     372             :                                 i += 4;
     373         300 :                                 continue;
     374             :                         }
     375          70 :                         frame = strchr(dcfg + i + 4, 'p');
     376          70 :                         if (frame) {
     377           6 :                                 ctx->forced_packed = GF_TRUE;
     378           6 :                                 frame[0] = 'n';
     379             :                         }
     380             :                         break;
     381             :                 }
     382          74 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DECODER_CONFIG, & PROP_DATA_NO_COPY(dcfg, vosh_size));
     383             :         }
     384             : 
     385         101 :         if (ctx->is_file && ctx->index) {
     386          56 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_PLAYBACK_MODE, & PROP_UINT(GF_PLAYBACK_MODE_FASTFORWARD) );
     387             :         }
     388             : }
     389             : 
     390        5128 : static Bool mpgviddmx_process_event(GF_Filter *filter, const GF_FilterEvent *evt)
     391             : {
     392             :         u32 i;
     393             :         u64 file_pos = 0;
     394             :         GF_FilterEvent fevt;
     395        5128 :         GF_MPGVidDmxCtx *ctx = gf_filter_get_udta(filter);
     396             : 
     397        5128 :         switch (evt->base.type) {
     398          99 :         case GF_FEVT_PLAY:
     399          99 :                 if (!ctx->is_playing) {
     400          99 :                         ctx->is_playing = GF_TRUE;
     401          99 :                         ctx->cts = 0;
     402          99 :                         ctx->bytes_in_header = 0;
     403             :                 }
     404          99 :                 if (! ctx->is_file) {
     405          45 :                         if (!ctx->initial_play_done) {
     406          45 :                                 ctx->initial_play_done = GF_TRUE;
     407          45 :                                 if (evt->play.start_range>0.1) ctx->resume_from = 0;
     408             :                         }
     409             :                         return GF_FALSE;
     410             :                 }
     411          54 :                 ctx->start_range = evt->play.start_range;
     412          54 :                 ctx->in_seek = GF_TRUE;
     413             : 
     414          54 :                 if (ctx->start_range) {
     415           2 :                         for (i=1; i<ctx->index_size; i++) {
     416           2 :                                 if ((ctx->indexes[i].start_time > ctx->start_range) || (i+1==ctx->index_size)) {
     417           1 :                                         ctx->cts = (u64) (ctx->indexes[i-1].start_time * ctx->cur_fps.num);
     418           1 :                                         file_pos = ctx->indexes[i-1].pos;
     419           1 :                                         break;
     420             :                                 }
     421             :                         }
     422             :                 }
     423          54 :                 ctx->dts = ctx->cts;
     424          54 :                 if (!ctx->initial_play_done) {
     425          53 :                         ctx->initial_play_done = GF_TRUE;
     426             :                         //seek will not change the current source state, don't send a seek
     427          53 :                         if (!file_pos)
     428             :                                 return GF_TRUE;
     429             :                 }
     430           1 :                 ctx->resume_from = 0;
     431           1 :                 ctx->bytes_in_header = 0;
     432             :                 //post a seek
     433           1 :                 GF_FEVT_INIT(fevt, GF_FEVT_SOURCE_SEEK, ctx->ipid);
     434           1 :                 fevt.seek.start_offset = file_pos;
     435           1 :                 gf_filter_pid_send_event(ctx->ipid, &fevt);
     436             : 
     437             :                 //cancel event
     438           1 :                 return GF_TRUE;
     439             : 
     440          43 :         case GF_FEVT_STOP:
     441          43 :                 ctx->is_playing = GF_FALSE;
     442          43 :                 if (ctx->src_pck) gf_filter_pck_unref(ctx->src_pck);
     443          43 :                 ctx->src_pck = NULL;
     444          43 :                 if (ctx->pck_queue) {
     445          98 :                         while (gf_list_count(ctx->pck_queue)) {
     446          56 :                                 GF_FilterPacket *pck=gf_list_pop_front(ctx->pck_queue);
     447          56 :                                 gf_filter_pck_discard(pck);
     448             :                         }
     449             :                 }
     450             :                 //don't cancel event
     451             :                 return GF_FALSE;
     452             : 
     453             :         case GF_FEVT_SET_SPEED:
     454             :                 //cancel event
     455             :                 return GF_TRUE;
     456             :         default:
     457             :                 break;
     458             :         }
     459             :         //by default don't cancel event - to rework once we have downloading in place
     460        4982 :         return GF_FALSE;
     461             : }
     462             : 
     463       21035 : static GFINLINE void mpgviddmx_update_time(GF_MPGVidDmxCtx *ctx)
     464             : {
     465             :         assert(ctx->cur_fps.num);
     466             : 
     467       21035 :         if (ctx->timescale) {
     468             :                 u64 inc = 3000;
     469        6182 :                 if (ctx->cur_fps.den && ctx->cur_fps.num) {
     470        6170 :                         inc = ctx->cur_fps.den;
     471        6170 :                         if (ctx->cur_fps.num != ctx->timescale) {
     472        2039 :                                 inc *= ctx->timescale;
     473        2039 :                                 inc /= ctx->cur_fps.num;
     474             :                         }
     475             :                 }
     476        6182 :                 ctx->cts += inc;
     477        6182 :                 ctx->dts += inc;
     478             :         } else {
     479             :                 assert(ctx->cur_fps.den);
     480       14853 :                 ctx->cts += ctx->cur_fps.den;
     481       14853 :                 ctx->dts += ctx->cur_fps.den;
     482             :         }
     483       21035 : }
     484             : 
     485             : 
     486             : static s32 mpgviddmx_next_start_code(u8 *data, u32 size)
     487             : {
     488             :         u32 v, bpos, found;
     489             :         s64 start, end;
     490             : 
     491             :         bpos = 0;
     492             :         found = 0;
     493             :         start = 0;
     494             :         end = 0;
     495             : 
     496             :         v = 0xffffffff;
     497             :         while (!end) {
     498     4028533 :                 if (bpos == size)
     499             :                         return -1;
     500     4028165 :                 v = ( (v<<8) & 0xFFFFFF00) | data[bpos];
     501             : 
     502     4028165 :                 bpos++;
     503     4028165 :                 if ((v & 0xFFFFFF00) == 0x00000100) {
     504             :                         end = start + bpos - 4;
     505             :                         found = 1;
     506             :                         break;
     507             :                 }
     508             :         }
     509             :         if (!found)
     510             :                 return -1;
     511             :         assert(end >= start);
     512       22271 :         return (s32) (end - start);
     513             : }
     514             : 
     515       16291 : GF_Err mpgviddmx_process(GF_Filter *filter)
     516             : {
     517       16291 :         GF_MPGVidDmxCtx *ctx = gf_filter_get_udta(filter);
     518             :         GF_FilterPacket *pck, *dst_pck;
     519             :         u64 byte_offset;
     520             :         s64 vosh_start = -1;
     521             :         s64 vosh_end = -1;
     522             :         GF_Err e;
     523             :         char *data;
     524             :         u8 *start;
     525             :         u32 pck_size;
     526             :         s32 remain;
     527             : 
     528             :         //always reparse duration
     529       16291 :         if (!ctx->duration.num)
     530       14404 :                 mpgviddmx_check_dur(filter, ctx);
     531             : 
     532       16291 :         pck = gf_filter_pid_get_packet(ctx->ipid);
     533       16291 :         if (!pck) {
     534        7150 :                 if (gf_filter_pid_is_eos(ctx->ipid)) {
     535          61 :                         mpgviddmx_enqueue_or_dispatch(ctx, NULL, GF_TRUE, GF_TRUE);
     536          61 :                         if (ctx->opid)
     537          61 :                                 gf_filter_pid_set_eos(ctx->opid);
     538          61 :                         if (ctx->src_pck) gf_filter_pck_unref(ctx->src_pck);
     539          61 :                         ctx->src_pck = NULL;
     540          61 :                         return GF_EOS;
     541             :                 }
     542             :                 return GF_OK;
     543             :         }
     544             : 
     545        9141 :         data = (char *) gf_filter_pck_get_data(pck, &pck_size);
     546        9141 :         byte_offset = gf_filter_pck_get_byte_offset(pck);
     547             : 
     548             :         start = data;
     549        9141 :         remain = pck_size;
     550             : 
     551             :         //input pid sets some timescale - we flushed pending data , update cts
     552        9141 :         if (!ctx->resume_from && ctx->timescale) {
     553        6179 :                 u64 ts = gf_filter_pck_get_cts(pck);
     554        6179 :                 if (ts != GF_FILTER_NO_TS) {
     555        6179 :                         if (!ctx->cts || !ctx->recompute_cts)
     556        2725 :                                 ctx->cts = ts;
     557             :                 }
     558        6179 :                 ts = gf_filter_pck_get_dts(pck);
     559        6179 :                 if (ts != GF_FILTER_NO_TS) {
     560        6179 :                         if (!ctx->dts || !ctx->recompute_cts)
     561        2725 :                                 ctx->dts = ts;
     562             : 
     563        6179 :                         if (!ctx->prev_dts) ctx->prev_dts = ts;
     564        6145 :                         else if (ctx->prev_dts != ts) {
     565             :                                 u64 diff = ts;
     566        6145 :                                 diff -= ctx->prev_dts;
     567        6145 :                                 if (!ctx->cur_fps.den) ctx->cur_fps.den = (u32) diff;
     568        6123 :                                 else if (ctx->cur_fps.den > diff)
     569           0 :                                         ctx->cur_fps.den = (u32) diff;
     570             :                         }
     571             :                 }
     572        6179 :                 gf_filter_pck_get_framing(pck, &ctx->input_is_au_start, &ctx->input_is_au_end);
     573             :                 //this will force CTS recomput of each frame
     574        6179 :                 if (ctx->recompute_cts) ctx->input_is_au_start = GF_FALSE;
     575        6179 :                 if (ctx->src_pck) gf_filter_pck_unref(ctx->src_pck);
     576        6179 :                 ctx->src_pck = pck;
     577        6179 :                 gf_filter_pck_ref_props(&ctx->src_pck);
     578             :         }
     579             : 
     580             :         //we stored some data to find the complete vosh, aggregate this packet with current one
     581        9141 :         if (!ctx->resume_from && ctx->hdr_store_size) {
     582           0 :                 if (ctx->hdr_store_alloc < ctx->hdr_store_size + pck_size) {
     583           0 :                         ctx->hdr_store_alloc = ctx->hdr_store_size + pck_size;
     584           0 :                         ctx->hdr_store = gf_realloc(ctx->hdr_store, sizeof(char)*ctx->hdr_store_alloc);
     585             :                 }
     586           0 :                 memcpy(ctx->hdr_store + ctx->hdr_store_size, data, sizeof(char)*pck_size);
     587           0 :                 if (byte_offset != GF_FILTER_NO_BO) {
     588           0 :                         if (byte_offset >= ctx->hdr_store_size)
     589           0 :                                 byte_offset -= ctx->hdr_store_size;
     590             :                         else
     591             :                                 byte_offset = GF_FILTER_NO_BO;
     592             :                 }
     593           0 :                 ctx->hdr_store_size += pck_size;
     594           0 :                 start = data = ctx->hdr_store;
     595           0 :                 remain = pck_size = ctx->hdr_store_size;
     596             :         }
     597             : 
     598        9141 :         if (ctx->resume_from) {
     599         266 :                 if (gf_filter_pid_would_block(ctx->opid))
     600             :                         return GF_OK;
     601             : 
     602             :                 //resume from data copied internally
     603         266 :                 if (ctx->hdr_store_size) {
     604             :                         assert(ctx->resume_from <= ctx->hdr_store_size);
     605           0 :                         start = data = ctx->hdr_store + ctx->resume_from;
     606           0 :                         remain = pck_size = ctx->hdr_store_size - ctx->resume_from;
     607             :                 } else {
     608             :                         assert(remain >= (s32) ctx->resume_from);
     609         266 :                         start += ctx->resume_from;
     610         266 :                         remain -= ctx->resume_from;
     611             :                 }
     612         266 :                 ctx->resume_from = 0;
     613             :         }
     614             : 
     615        9141 :         if (!ctx->bs) {
     616          98 :                 ctx->bs = gf_bs_new(start, remain, GF_BITSTREAM_READ);
     617             :         } else {
     618        9043 :                 gf_bs_reassign_buffer(ctx->bs, start, remain);
     619             :         }
     620        9141 :         if (!ctx->vparser) {
     621          98 :                 ctx->vparser = gf_m4v_parser_bs_new(ctx->bs, ctx->is_mpg12);
     622             :         }
     623             : 
     624             : 
     625       24991 :         while (remain) {
     626             :                 Bool full_frame;
     627             :                 u8 *pck_data;
     628             :                 s32 current;
     629             :                 u8 sc_type, forced_sc_type=0;
     630             :                 Bool sc_type_forced = GF_FALSE;
     631             :                 Bool skip_pck = GF_FALSE;
     632             :                 u8 ftype;
     633             :                 u32 tinc;
     634       22548 :                 u64 size=0;
     635             :                 u64 fstart;
     636             :                 Bool is_coded;
     637             :                 u32 bytes_from_store = 0;
     638             :                 u32 hdr_offset = 0;
     639             :                 Bool copy_last_bytes = GF_FALSE;
     640             : 
     641             :                 //not enough bytes to parse start code
     642       22548 :                 if (remain<5) {
     643           2 :                         memcpy(ctx->hdr_store, start, remain);
     644           2 :                         ctx->bytes_in_header = remain;
     645        6411 :                         break;
     646             :                 }
     647             :                 current = -1;
     648             : 
     649             :                 //we have some potential bytes of a start code in the store, copy some more bytes and check if valid start code.
     650             :                 //if not, dispatch these bytes as continuation of the data
     651       22546 :                 if (ctx->bytes_in_header) {
     652             : 
     653        2813 :                         memcpy(ctx->hdr_store + ctx->bytes_in_header, start, 8 - ctx->bytes_in_header);
     654        2813 :                         current = mpgviddmx_next_start_code(ctx->hdr_store, 8);
     655             : 
     656             :                         //no start code in stored buffer
     657        2813 :                         if ((current<0) || (current >= (s32) ctx->bytes_in_header) )  {
     658        2806 :                                 dst_pck = gf_filter_pck_new_alloc(ctx->opid, ctx->bytes_in_header, &pck_data);
     659        3095 :                                 if (!dst_pck) return GF_OUT_OF_MEM;
     660             : 
     661        2806 :                                 if (ctx->src_pck) gf_filter_pck_merge_properties(ctx->src_pck, dst_pck);
     662        2806 :                                 gf_filter_pck_set_cts(dst_pck, GF_FILTER_NO_TS);
     663        2806 :                                 gf_filter_pck_set_dts(dst_pck, GF_FILTER_NO_TS);
     664        2806 :                                 memcpy(pck_data, ctx->hdr_store, ctx->bytes_in_header);
     665        2806 :                                 gf_filter_pck_set_framing(dst_pck, GF_FALSE, GF_FALSE);
     666             : 
     667        2806 :                                 if (byte_offset != GF_FILTER_NO_BO) {
     668          93 :                                         gf_filter_pck_set_byte_offset(dst_pck, byte_offset - ctx->bytes_in_header);
     669             :                                 }
     670             : 
     671        2806 :                                 mpgviddmx_enqueue_or_dispatch(ctx, dst_pck, GF_FALSE, GF_FALSE);
     672        2806 :                                 if (current<0) current = -1;
     673        2713 :                                 else current -= ctx->bytes_in_header;
     674        2806 :                                 ctx->bytes_in_header = 0;
     675             :                         } else {
     676             :                                 //we have a valid start code, check which byte in our store or in the packet payload is the start code type
     677             :                                 //and remember its location to reinit the parser from there
     678           7 :                                 hdr_offset = 4 - ctx->bytes_in_header + current;
     679             :                                 //bytes still to dispatch
     680             :                                 bytes_from_store = ctx->bytes_in_header;
     681           7 :                                 ctx->bytes_in_header = 0;
     682           7 :                                 if (!hdr_offset) {
     683           2 :                                         forced_sc_type = ctx->hdr_store[current+3];
     684             :                                 } else {
     685           5 :                                         forced_sc_type = start[hdr_offset-1];
     686             :                                 }
     687             :                                 sc_type_forced = GF_TRUE;
     688             :                         }
     689             :                 }
     690             :                 //no starcode in store, look for startcode in packet
     691       22546 :                 if (current == -1) {
     692             :                         //locate next start code
     693       19826 :                         current = mpgviddmx_next_start_code(start, remain);
     694             :                         //no start code, dispatch the block
     695       19826 :                         if (current<0) {
     696             :                                 u8 b3, b2, b1;
     697         275 :                                 if (! ctx->frame_started) {
     698           0 :                                         GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[MPGVid] no start code in block and no frame started, discarding data\n" ));
     699             :                                         break;
     700             :                                 }
     701         275 :                                 size = remain;
     702         275 :                                 b3 = start[remain-3];
     703         275 :                                 b2 = start[remain-2];
     704         275 :                                 b1 = start[remain-1];
     705             :                                 //we may have a startcode at the end of the packet, store it and don't dispatch the last 3 bytes !
     706         275 :                                 if (!b1 || !b2 || !b3) {
     707             :                                         copy_last_bytes = GF_TRUE;
     708             :                                         assert(size >= 3);
     709          16 :                                         size -= 3;
     710          16 :                                         ctx->bytes_in_header = 3;
     711             :                                 }
     712             : 
     713         275 :                                 dst_pck = gf_filter_pck_new_alloc(ctx->opid, (u32) size, &pck_data);
     714         275 :                                 if (!dst_pck) return GF_OUT_OF_MEM;
     715             : 
     716         275 :                                 if (ctx->src_pck) gf_filter_pck_merge_properties(ctx->src_pck, dst_pck);
     717         275 :                                 memcpy(pck_data, start, (size_t) size);
     718         275 :                                 gf_filter_pck_set_framing(dst_pck, GF_FALSE, GF_FALSE);
     719         275 :                                 gf_filter_pck_set_cts(dst_pck, GF_FILTER_NO_TS);
     720         275 :                                 gf_filter_pck_set_dts(dst_pck, GF_FILTER_NO_TS);
     721             : 
     722         275 :                                 if (byte_offset != GF_FILTER_NO_BO) {
     723         275 :                                         gf_filter_pck_set_byte_offset(dst_pck, byte_offset);
     724             :                                 }
     725             : 
     726         275 :                                 mpgviddmx_enqueue_or_dispatch(ctx, dst_pck, GF_FALSE, GF_FALSE);
     727         275 :                                 if (copy_last_bytes) {
     728          16 :                                         memcpy(ctx->hdr_store, start+remain-3, 3);
     729             :                                 }
     730             :                                 break;
     731             :                         }
     732             :                 }
     733             : 
     734             :                 assert(current>=0);
     735             : 
     736             :                 //if we are in the middle of parsing the vosh, skip over bytes remaining from previous obj not parsed
     737       22271 :                 if ((vosh_start>=0) && current) {
     738             :                         assert(remain>=current);
     739          91 :                         start += current;
     740          91 :                         remain -= current;
     741             :                         current = 0;
     742             :                 }
     743             :                 //also skip if no output pid
     744       22271 :                 if (!ctx->opid && current) {
     745             :                         assert(remain>=current);
     746           0 :                         start += current;
     747           0 :                         remain -= current;
     748             :                         current = 0;
     749             :                 }
     750             :                 //dispatch remaining bytes
     751       22271 :                 if (current>0) {
     752             :                         //flush remaining
     753        2401 :                         dst_pck = gf_filter_pck_new_alloc(ctx->opid, current, &pck_data);
     754        2401 :                         if (!dst_pck) return GF_OUT_OF_MEM;
     755             : 
     756        2401 :                         if (ctx->src_pck) gf_filter_pck_merge_properties(ctx->src_pck, dst_pck);
     757        2401 :                         gf_filter_pck_set_cts(dst_pck, GF_FILTER_NO_TS);
     758        2401 :                         gf_filter_pck_set_dts(dst_pck, GF_FILTER_NO_TS);
     759        2401 :                         gf_filter_pck_set_framing(dst_pck, GF_FALSE, GF_TRUE);
     760             :                         //bytes were partly in store, partly in packet
     761        2401 :                         if (bytes_from_store) {
     762           4 :                                 if (byte_offset != GF_FILTER_NO_BO) {
     763           4 :                                         gf_filter_pck_set_byte_offset(dst_pck, byte_offset - bytes_from_store);
     764             :                                 }
     765             :                                 assert(bytes_from_store>=(u32) current);
     766           4 :                                 bytes_from_store -= current;
     767           4 :                                 memcpy(pck_data, ctx->hdr_store, current);
     768             :                         } else {
     769             :                                 //bytes were only in packet
     770        2397 :                                 if (byte_offset != GF_FILTER_NO_BO) {
     771        2397 :                                         gf_filter_pck_set_byte_offset(dst_pck, byte_offset);
     772             :                                 }
     773        2397 :                                 memcpy(pck_data, start, current);
     774             :                                 assert(remain>=current);
     775        2397 :                                 start += current;
     776        2397 :                                 remain -= current;
     777             :                                 current = 0;
     778             :                         }
     779        2401 :                         gf_filter_pck_set_carousel_version(dst_pck, 1);
     780             : 
     781        2401 :                         mpgviddmx_enqueue_or_dispatch(ctx, dst_pck, GF_FALSE, GF_FALSE);
     782             :                 }
     783             : 
     784             :                 //parse headers
     785             : 
     786             :                 //we have a start code loaded, eg the data packet does not have a full start code at the beginning
     787       22271 :                 if (sc_type_forced) {
     788           7 :                         gf_bs_reassign_buffer(ctx->bs, start + hdr_offset, remain - hdr_offset);
     789             :                         sc_type = forced_sc_type;
     790             :                 } else {
     791       22264 :                         gf_bs_reassign_buffer(ctx->bs, start, remain);
     792       22264 :                         gf_bs_read_int(ctx->bs, 24);
     793       22264 :                         sc_type = gf_bs_read_int(ctx->bs, 8);
     794             :                 }
     795             : 
     796       22271 :                 if (ctx->is_mpg12) {
     797        7246 :                         switch (sc_type) {
     798         170 :                         case M2V_SEQ_START_CODE:
     799             :                         case M2V_EXT_START_CODE:
     800         170 :                                 gf_bs_reassign_buffer(ctx->bs, start, remain);
     801         170 :                                 e = gf_m4v_parse_config(ctx->vparser, &ctx->dsi);
     802             :                                 //not enough data, accumulate until we can parse the full header
     803         170 :                                 if (e==GF_EOS) {
     804           0 :                                         if (vosh_start<0) vosh_start = 0;
     805           0 :                                         if (ctx->hdr_store_alloc < ctx->hdr_store_size + pck_size - vosh_start) {
     806           0 :                                                 ctx->hdr_store_alloc = (u32) (ctx->hdr_store_size + pck_size - vosh_start);
     807           0 :                                                 ctx->hdr_store = gf_realloc(ctx->hdr_store, sizeof(char)*ctx->hdr_store_alloc);
     808             :                                         }
     809           0 :                                         memcpy(ctx->hdr_store + ctx->hdr_store_size, data + vosh_start, (size_t) (pck_size - vosh_start) );
     810           0 :                                         ctx->hdr_store_size += pck_size - (u32) vosh_start;
     811           0 :                                         gf_filter_pid_drop_packet(ctx->ipid);
     812           0 :                                         return GF_OK;
     813         170 :                                 } else if (e != GF_OK) {
     814           0 :                                         GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[MPGVid] Failed to parse VOS header: %s\n", gf_error_to_string(e) ));
     815             :                                 } else {
     816         170 :                                         mpgviddmx_check_pid(filter, ctx, 0, NULL);
     817             :                                 }
     818             :                                 break;
     819             :                         case M2V_PIC_START_CODE:
     820             :                                 break;
     821             :                         default:
     822             :                                 break;
     823             :                         }
     824             : 
     825             :                 } else {
     826             :                         u8 PL;
     827       15025 :                         switch (sc_type) {
     828          91 :                         case M4V_VOS_START_CODE:
     829          91 :                                 ctx->dsi.VideoPL = (u8) gf_bs_read_u8(ctx->bs);
     830          91 :                                 vosh_start = start - (u8 *)data;
     831             :                                 skip_pck = GF_TRUE;
     832             :                                 assert(remain>=5);
     833          91 :                                 start += 5;
     834          91 :                                 remain -= 5;
     835          91 :                                 break;
     836          91 :                         case M4V_VOL_START_CODE:
     837          91 :                                 gf_bs_reassign_buffer(ctx->bs, start, remain);
     838          91 :                                 PL = ctx->dsi.VideoPL;
     839          91 :                                 e = gf_m4v_parse_config(ctx->vparser, &ctx->dsi);
     840          91 :                                 ctx->dsi.VideoPL = PL;
     841             :                                 //not enough data, accumulate until we can parse the full header
     842          91 :                                 if (e==GF_EOS) {
     843           0 :                                         if (vosh_start<0) vosh_start = 0;
     844           0 :                                         if (ctx->hdr_store_alloc < ctx->hdr_store_size + pck_size - vosh_start) {
     845           0 :                                                 ctx->hdr_store_alloc = (u32) (ctx->hdr_store_size + pck_size - (u32) vosh_start);
     846           0 :                                                 ctx->hdr_store = gf_realloc(ctx->hdr_store, sizeof(char)*ctx->hdr_store_alloc);
     847             :                                         }
     848           0 :                                         memcpy(ctx->hdr_store + ctx->hdr_store_size, data + vosh_start, (size_t) (pck_size - vosh_start) );
     849           0 :                                         ctx->hdr_store_size += pck_size - (u32) vosh_start;
     850           0 :                                         gf_filter_pid_drop_packet(ctx->ipid);
     851           0 :                                         return GF_OK;
     852          91 :                                 } else if (e != GF_OK) {
     853           0 :                                         GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[MPGVid] Failed to parse VOS header: %s\n", gf_error_to_string(e) ));
     854             :                                 } else {
     855          91 :                                         u32 obj_size = (u32) gf_m4v_get_object_start(ctx->vparser);
     856          91 :                                         if (vosh_start<0) vosh_start = 0;
     857          91 :                                         vosh_end = start - (u8 *)data + obj_size;
     858          91 :                                         vosh_end -= vosh_start;
     859          91 :                                         mpgviddmx_check_pid(filter, ctx,(u32)  vosh_end, data+vosh_start);
     860             :                                         skip_pck = GF_TRUE;
     861             :                                         assert(remain>=(s32) obj_size);
     862          91 :                                         start += obj_size;
     863          91 :                                         remain -= obj_size;
     864             :                                 }
     865             :                                 break;
     866             :                         case M4V_VOP_START_CODE:
     867             :                         case M4V_GOV_START_CODE:
     868             :                                 break;
     869             : 
     870         182 :                         case M4V_VO_START_CODE:
     871             :                         case M4V_VISOBJ_START_CODE:
     872             :                         default:
     873         182 :                                 if (vosh_start>=0) {
     874             :                                         skip_pck = GF_TRUE;
     875             :                                         assert(remain>=4);
     876         182 :                                         start += 4;
     877         182 :                                         remain -= 4;
     878             :                                 }
     879             :                                 break;
     880             :                         }
     881             :                 }
     882             : 
     883       22271 :                 if (skip_pck) {
     884        1311 :                         continue;
     885             :                 }
     886             : 
     887       21907 :                 if (!ctx->opid) {
     888             :                         assert(remain>=4);
     889           0 :                         start += 4;
     890           0 :                         remain -= 4;
     891           0 :                         continue;
     892             :                 }
     893             : 
     894       21907 :                 if (!ctx->is_playing) {
     895         289 :                         ctx->resume_from = (u32) ((char *)start -  (char *)data);
     896         289 :                         return GF_OK;
     897             :                 }
     898             :                 //at this point, we no longer reaggregate packets
     899       21618 :                 ctx->hdr_store_size = 0;
     900             : 
     901       21618 :                 if (ctx->in_seek) {
     902          53 :                         u64 nb_frames_at_seek = (u64) (ctx->start_range * ctx->cur_fps.num);
     903          53 :                         if (ctx->cts + ctx->cur_fps.den >= nb_frames_at_seek) {
     904             :                                 //u32 samples_to_discard = (ctx->cts + ctx->dts_inc) - nb_samples_at_seek;
     905          53 :                                 ctx->in_seek = GF_FALSE;
     906             :                         }
     907             :                 }
     908             :                 //may happen that after all our checks, only 4 bytes are left, continue to store these 4 bytes
     909       21618 :                 if (remain<5)
     910           0 :                         continue;
     911             : 
     912             :                 //good to go
     913       21618 :                 gf_m4v_parser_reset(ctx->vparser, sc_type_forced ? forced_sc_type + 1 : 0);
     914       21618 :                 size = 0;
     915       21618 :                 e = gf_m4v_parse_frame(ctx->vparser, &ctx->dsi, &ftype, &tinc, &size, &fstart, &is_coded);
     916             :                 //true if we strip VO and VISOBJ assert(!fstart);
     917             : 
     918             :                 //we skipped bytes already in store + end of start code present in packet, so the size of the first object
     919             :                 //needs adjustement
     920       21618 :                 if (bytes_from_store) {
     921           7 :                         size += bytes_from_store + hdr_offset;
     922             :                 }
     923             : 
     924       21618 :                 if ((e == GF_EOS) && !ctx->input_is_au_end) {
     925        6132 :                         u8 b3 = start[remain-3];
     926        6132 :                         u8 b2 = start[remain-2];
     927        6132 :                         u8 b1 = start[remain-1];
     928             : 
     929             :                         //we may have a startcode at the end of the packet, store it and don't dispatch the last 3 bytes !
     930        6132 :                         if (!b1 || !b2 || !b3) {
     931             :                                 copy_last_bytes = GF_TRUE;
     932             :                                 assert(size >= 3);
     933        2798 :                                 size -= 3;
     934        2798 :                                 ctx->bytes_in_header = 3;
     935             :                         }
     936             :                         full_frame = GF_FALSE;
     937             :                 } else {
     938             :                         full_frame = GF_TRUE;
     939             :                 }
     940             : 
     941       21618 :                 if (!is_coded) {
     942             :                         /*if prev is B and we're parsing a packed bitstream discard n-vop*/
     943         583 :                         if (ctx->forced_packed && ctx->b_frames) {
     944         583 :                                 ctx->is_packed = GF_TRUE;
     945             :                                 assert(remain>=size);
     946         583 :                                 start += size;
     947         583 :                                 remain -= (s32) size;
     948         583 :                                 continue;
     949             :                         }
     950             :                         /*policy is to import at variable frame rate, skip*/
     951           0 :                         if (ctx->vfr) {
     952           0 :                                 ctx->is_vfr = GF_TRUE;
     953           0 :                                 mpgviddmx_update_time(ctx);
     954             :                                 assert(remain>=size);
     955           0 :                                 start += size;
     956           0 :                                 remain -= (s32) size;
     957           0 :                                 continue;
     958             :                         }
     959             :                         /*policy is to keep non coded frame (constant frame rate), add*/
     960             :                 }
     961             : 
     962       21035 :                 if (ftype==2) {
     963             :                         //count number of B-frames since last ref
     964       13010 :                         ctx->b_frames++;
     965       13010 :                         ctx->nb_b++;
     966             :                 } else {
     967             :                         //flush all pending packets
     968        8025 :                         mpgviddmx_enqueue_or_dispatch(ctx, NULL, GF_TRUE, GF_FALSE);
     969             :                         //remeber the CTS of the last ref
     970        8025 :                         ctx->last_ref_cts = ctx->cts;
     971        8025 :                         if (ctx->max_b < ctx->b_frames) ctx->max_b = ctx->b_frames;
     972             :                         
     973        8025 :                         ctx->b_frames = 0;
     974        8025 :                         if (ftype)
     975        7064 :                                 ctx->nb_p++;
     976             :                         else
     977         961 :                                 ctx->nb_i++;
     978             :                 }
     979       21035 :                 ctx->nb_frames++;
     980             : 
     981       21035 :                 dst_pck = gf_filter_pck_new_alloc(ctx->opid, (u32) size, &pck_data);
     982       21035 :                 if (!dst_pck) return GF_OUT_OF_MEM;
     983             : 
     984       21035 :                 if (ctx->src_pck) gf_filter_pck_merge_properties(ctx->src_pck, dst_pck);
     985             :                 //bytes come from both our store and the data packet
     986       21035 :                 if (bytes_from_store) {
     987           7 :                         memcpy(pck_data, ctx->hdr_store+current, bytes_from_store);
     988             :                         assert(size >= bytes_from_store);
     989           7 :                         size -= bytes_from_store;
     990           7 :                         if (byte_offset != GF_FILTER_NO_BO) {
     991           7 :                                 gf_filter_pck_set_byte_offset(dst_pck, byte_offset - bytes_from_store);
     992             :                         }
     993           7 :                         memcpy(pck_data + bytes_from_store, start, (size_t) size);
     994             :                 } else {
     995             :                         //bytes only come the data packet
     996       21028 :                         memcpy(pck_data, start, (size_t) size);
     997       21028 :                         if (byte_offset != GF_FILTER_NO_BO) {
     998       16275 :                                 gf_filter_pck_set_byte_offset(dst_pck, byte_offset + start - (u8 *) data);
     999             :                         }
    1000             :                 }
    1001             :                 assert(pck_data[0] == 0);
    1002             :                 assert(pck_data[1] == 0);
    1003             :                 assert(pck_data[2] == 0x01);
    1004             : 
    1005       21035 :                 gf_filter_pck_set_framing(dst_pck, GF_TRUE, (full_frame || ctx->input_is_au_end) ? GF_TRUE : GF_FALSE);
    1006       21035 :                 gf_filter_pck_set_cts(dst_pck, ctx->cts);
    1007       21035 :                 gf_filter_pck_set_dts(dst_pck, ctx->dts);
    1008       21035 :                 if (ctx->input_is_au_start) {
    1009        2714 :                         ctx->input_is_au_start = GF_FALSE;
    1010             :                 } else {
    1011             :                         //we use the carousel flag temporarly to indicate the cts must be recomputed
    1012       18321 :                         gf_filter_pck_set_carousel_version(dst_pck, 1);
    1013             :                 }
    1014       21035 :                 gf_filter_pck_set_sap(dst_pck, ftype ? GF_FILTER_SAP_NONE : GF_FILTER_SAP_1);
    1015       21035 :                 gf_filter_pck_set_duration(dst_pck, ctx->cur_fps.den);
    1016       21035 :                 if (ctx->in_seek) gf_filter_pck_set_seek_flag(dst_pck, GF_TRUE);
    1017       21035 :                 ctx->frame_started = GF_TRUE;
    1018             : 
    1019       21035 :                 mpgviddmx_enqueue_or_dispatch(ctx, dst_pck, GF_FALSE, GF_FALSE);
    1020             : 
    1021       21035 :                 mpgviddmx_update_time(ctx);
    1022             : 
    1023       21035 :                 if (!full_frame) {
    1024        6132 :                         if (copy_last_bytes) {
    1025        2798 :                                 memcpy(ctx->hdr_store, start+remain-3, 3);
    1026             :                         }
    1027             :                         break;
    1028             :                 }
    1029             :                 assert(remain>=size);
    1030       14903 :                 start += size;
    1031       14903 :                 remain -= (s32) size;
    1032             :         }
    1033        8852 :         gf_filter_pid_drop_packet(ctx->ipid);
    1034             : 
    1035        8852 :         return GF_OK;
    1036             : }
    1037             : 
    1038          98 : static GF_Err mpgviddmx_initialize(GF_Filter *filter)
    1039             : {
    1040          98 :         GF_MPGVidDmxCtx *ctx = gf_filter_get_udta(filter);
    1041          98 :         ctx->hdr_store_size = 0;
    1042          98 :         ctx->hdr_store_alloc = 8;
    1043          98 :         ctx->hdr_store = gf_malloc(sizeof(char)*8);
    1044          98 :         return GF_OK;
    1045             : }
    1046             : 
    1047          98 : static void mpgviddmx_finalize(GF_Filter *filter)
    1048             : {
    1049          98 :         GF_MPGVidDmxCtx *ctx = gf_filter_get_udta(filter);
    1050          98 :         if (ctx->bs) gf_bs_del(ctx->bs);
    1051          98 :         if (ctx->vparser) gf_m4v_parser_del_no_bs(ctx->vparser);
    1052          98 :         if (ctx->indexes) gf_free(ctx->indexes);
    1053          98 :         if (ctx->hdr_store) gf_free(ctx->hdr_store);
    1054          98 :         if (ctx->pck_queue) {
    1055          98 :                 while (gf_list_count(ctx->pck_queue)) {
    1056           0 :                         GF_FilterPacket *pck = gf_list_pop_back(ctx->pck_queue);
    1057           0 :                         gf_filter_pck_discard(pck);
    1058             :                 }
    1059          98 :                 gf_list_del(ctx->pck_queue);
    1060             :         }
    1061          98 :         if (ctx->src_pck) gf_filter_pck_unref(ctx->src_pck);
    1062          98 :         if (ctx->importer) {
    1063          25 :                 GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("%s Import results: %d VOPs (%d Is - %d Ps - %d Bs)\n", ctx->is_mpg12 ? "MPEG-1/2" : "MPEG-4 (Part 2)", ctx->nb_frames, ctx->nb_i, ctx->nb_p, ctx->nb_b));
    1064          25 :                 if (ctx->nb_b) {
    1065          25 :                         GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("\t%d max consecutive B-frames%s\n", ctx->max_b, ctx->is_packed ? " - packed bitstream" : "" ));
    1066             :                 }
    1067          25 :                 if (ctx->is_vfr && ctx->nb_b && ctx->is_packed) {
    1068           0 :                         GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("Warning: Mix of non-coded frames: packed bitstream and encoder skiped - unpredictable timing\n"));
    1069             :                 }
    1070             :         }
    1071          98 : }
    1072             : 
    1073             : u32 gf_m4v_parser_get_obj_type(GF_M4VParser *m4v);
    1074             : 
    1075        3072 : static const char * mpgvdmx_probe_data(const u8 *data, u32 size, GF_FilterProbeScore *score)
    1076             : {
    1077             :         GF_M4VParser *parser;
    1078             :         u8 ftype;
    1079             :         u32 tinc, nb_frames;
    1080             :         u64 fsize, start;
    1081             :         Bool is_coded;
    1082             :         GF_Err e;
    1083             :         GF_M4VDecSpecInfo dsi;
    1084             : 
    1085             :         memset(&dsi, 0, sizeof(GF_M4VDecSpecInfo));
    1086        3072 :         parser = gf_m4v_parser_new((char*)data, size, GF_FALSE);
    1087             :         nb_frames = 0;
    1088             :         while (1) {
    1089        4530 :                 ftype = 0;
    1090        3801 :                 is_coded = GF_FALSE;
    1091        3801 :                 e = gf_m4v_parse_frame(parser, &dsi, &ftype, &tinc, &fsize, &start, &is_coded);
    1092             :                 //if start is more than 4 (start-code size), we have garbage at the beginning, do not parse
    1093        3801 :                 if (!nb_frames && (start>4))
    1094             :                         break;
    1095        3577 :                 if (is_coded) nb_frames++;
    1096        3577 :                 if (e==GF_EOS) {
    1097             :                         //special case if the only frame we have is not coded
    1098        2848 :                         if (gf_m4v_parser_get_obj_type(parser) == M4V_VOP_START_CODE) {
    1099          66 :                                 if (!nb_frames) nb_frames++;
    1100          66 :                                 is_coded = 1;
    1101             :                         }
    1102             : 
    1103        2848 :                         if (is_coded) nb_frames++;
    1104             :                         e = GF_OK;
    1105             :                         break;
    1106             :                 }
    1107         729 :                 if (ftype>2) break;
    1108         729 :                 if (e) break;
    1109         729 :                 nb_frames++;
    1110             :         }
    1111        3072 :         gf_m4v_parser_del(parser);
    1112        3072 :         if ((e==GF_OK) && (nb_frames>1)) {
    1113          66 :                 *score = GF_FPROBE_MAYBE_SUPPORTED;
    1114          66 :                 return "video/mp4v-es";
    1115             :         }
    1116             : 
    1117             :         memset(&dsi, 0, sizeof(GF_M4VDecSpecInfo));
    1118        3006 :         parser = gf_m4v_parser_new((char*)data, size, GF_TRUE);
    1119             :         nb_frames = 0;
    1120             :         while (1) {
    1121        3100 :                 ftype = 0;
    1122        3053 :                 is_coded = GF_FALSE;
    1123        3053 :                 e = gf_m4v_parse_frame(parser, &dsi, &ftype, &tinc, &fsize, &start, &is_coded);
    1124             :                 //if start is more than 4 (start-code size), we have garbage at the beginning, do not parse
    1125        3053 :                 if (!nb_frames && (start>4))
    1126             :                         break;
    1127        2254 :                 if (is_coded) nb_frames++;
    1128        2254 :                 if (e==GF_EOS) {
    1129        2207 :                         if (is_coded) nb_frames++;
    1130             :                         e = GF_OK;
    1131             :                         break;
    1132             :                 }
    1133          47 :                 if (ftype>2) break;
    1134          47 :                 if (e) break;
    1135          47 :                 nb_frames++;
    1136             :         }
    1137        3006 :         gf_m4v_parser_del(parser);
    1138        3006 :         if ((e==GF_OK) && (nb_frames>1)) {
    1139           9 :                 *score = GF_FPROBE_MAYBE_SUPPORTED;
    1140           9 :                 return "video/mpgv-es";
    1141             :         }
    1142             :         return NULL;
    1143             : }
    1144             : 
    1145             : static const GF_FilterCapability MPGVidDmxCaps[] =
    1146             : {
    1147             :         CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
    1148             :         CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_FILE_EXT, "cmp|m1v|m2v"),
    1149             :         CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_MIME, "video/mp4v-es|video/mpgv-es"),
    1150             :         CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
    1151             :         CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_MPEG4_PART2),
    1152             :         CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_MPEG1),
    1153             :         CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_MPEG2_SIMPLE),
    1154             :         CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_MPEG2_SPATIAL),
    1155             :         CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_MPEG2_SNR),
    1156             :         CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_MPEG2_MAIN),
    1157             :         CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_MPEG2_HIGH),
    1158             :         CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_MPEG2_422),
    1159             :         CAP_BOOL(GF_CAPS_OUTPUT_STATIC_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
    1160             :         {0},
    1161             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
    1162             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG4_PART2),
    1163             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG1),
    1164             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG2_SPATIAL),
    1165             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG2_SNR),
    1166             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG2_SIMPLE),
    1167             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG2_MAIN),
    1168             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG2_HIGH),
    1169             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG2_422),
    1170             :         CAP_BOOL(GF_CAPS_INPUT,GF_PROP_PID_UNFRAMED, GF_TRUE),
    1171             : };
    1172             : 
    1173             : 
    1174             : #define OFFS(_n)        #_n, offsetof(GF_MPGVidDmxCtx, _n)
    1175             : static const GF_FilterArgs MPGVidDmxArgs[] =
    1176             : {
    1177             :         { OFFS(fps), "import frame rate (0 default to FPS from bitstream or 25 Hz)", GF_PROP_FRACTION, "0/1000", NULL, 0},
    1178             :         { OFFS(index), "indexing window length", GF_PROP_DOUBLE, "1.0", NULL, 0},
    1179             :         { OFFS(vfr), "set variable frame rate import", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
    1180             :         { OFFS(importer), "compatibility with old importer, displays import results", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
    1181             :         {0}
    1182             : };
    1183             : 
    1184             : 
    1185             : GF_FilterRegister MPGVidDmxRegister = {
    1186             :         .name = "rfmpgvid",
    1187             :         GF_FS_SET_DESCRIPTION("M1V/M2V/M4V reframer")
    1188             :         GF_FS_SET_HELP("This filter parses MPEG-1/2 and MPEG-4 part 2 video files/data and outputs corresponding video PID and frames.\n"
    1189             :                 "Note: The demux uses negative CTS offsets: CTS is corrrect, but some frames may have DTS greater than CTS.")
    1190             :         .private_size = sizeof(GF_MPGVidDmxCtx),
    1191             :         .args = MPGVidDmxArgs,
    1192             :         .initialize = mpgviddmx_initialize,
    1193             :         .finalize = mpgviddmx_finalize,
    1194             :         SETCAPS(MPGVidDmxCaps),
    1195             :         .configure_pid = mpgviddmx_configure_pid,
    1196             :         .process = mpgviddmx_process,
    1197             :         .probe_data = mpgvdmx_probe_data,
    1198             :         .process_event = mpgviddmx_process_event
    1199             : };
    1200             : 
    1201             : 
    1202        2877 : const GF_FilterRegister *mpgviddmx_register(GF_FilterSession *session)
    1203             : {
    1204        2877 :         return &MPGVidDmxRegister;
    1205             : }
    1206             : 
    1207             : #else
    1208             : const GF_FilterRegister *mpgviddmx_register(GF_FilterSession *session)
    1209             : {
    1210             :         return NULL;
    1211             : }
    1212             : #endif // GPAC_DISABLE_AV_PARSERS
    1213             : 
    1214             : 

Generated by: LCOV version 1.13