LCOV - code coverage report
Current view: top level - filters - reframe_h263.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 260 302 86.1 %
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 2000-2021
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / H263 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             : } H263Idx;
      35             : 
      36             : typedef struct
      37             : {
      38             :         //filter args
      39             :         GF_Fraction fps;
      40             :         Double index;
      41             : 
      42             :         //only one input pid declared
      43             :         GF_FilterPid *ipid;
      44             :         //only one output pid declared
      45             :         GF_FilterPid *opid;
      46             : 
      47             :         GF_BitStream *bs;
      48             :         u64 cts;
      49             :         u32 width, height;
      50             :         GF_Fraction64 duration;
      51             :         Double start_range;
      52             :         Bool in_seek;
      53             :         u32 timescale;
      54             : 
      55             :         u32 resume_from;
      56             : 
      57             : 
      58             :         u32 bytes_in_header;
      59             :         char hdr_store[8];
      60             : 
      61             :         Bool is_playing;
      62             :         Bool is_file, file_loaded;
      63             :         Bool initial_play_done;
      64             : 
      65             :         GF_FilterPacket *src_pck;
      66             : 
      67             :         H263Idx *indexes;
      68             :         u32 index_alloc_size, index_size;
      69             :         u32 bitrate;
      70             : } GF_H263DmxCtx;
      71             : 
      72             : 
      73           7 : GF_Err h263dmx_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
      74             : {
      75             :         const GF_PropertyValue *p;
      76           7 :         GF_H263DmxCtx *ctx = gf_filter_get_udta(filter);
      77             : 
      78           7 :         if (is_remove) {
      79           0 :                 ctx->ipid = NULL;
      80           0 :                 if (ctx->opid) {
      81           0 :                         gf_filter_pid_remove(ctx->opid);
      82           0 :                         ctx->opid = NULL;
      83             :                 }
      84             :                 return GF_OK;
      85             :         }
      86           7 :         if (! gf_filter_pid_check_caps(pid))
      87             :                 return GF_NOT_SUPPORTED;
      88             : 
      89           7 :         ctx->ipid = pid;
      90           7 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_TIMESCALE);
      91           7 :         if (p) ctx->timescale = p->value.uint;
      92             : 
      93           7 :         if (ctx->timescale && !ctx->opid) {
      94           0 :                 ctx->opid = gf_filter_pid_new(filter);
      95           0 :                 gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
      96           0 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_UNFRAMED, NULL);
      97             :         }
      98             :         return GF_OK;
      99             : }
     100             : 
     101             : #define H263_CACHE_SIZE 4096
     102         628 : static u32 h263dmx_next_start_code_bs(GF_BitStream *bs)
     103             : {
     104             :         u32 v, bpos;
     105             :         unsigned char h263_cache[H263_CACHE_SIZE];
     106             :         u64 end, cache_start, load_size;
     107         628 :         u64 start = gf_bs_get_position(bs);
     108             : 
     109             :         /*skip 16b header*/
     110         628 :         gf_bs_read_u16(bs);
     111             :         bpos = 0;
     112             :         load_size = 0;
     113             :         cache_start = 0;
     114             :         end = 0;
     115             :         v = 0xffffffff;
     116      374633 :         while (!end) {
     117             :                 /*refill cache*/
     118      373380 :                 if (bpos == (u32) load_size) {
     119         635 :                         if (!gf_bs_available(bs)) break;
     120         632 :                         load_size = gf_bs_available(bs);
     121         632 :                         if (load_size>H263_CACHE_SIZE) load_size=H263_CACHE_SIZE;
     122             :                         bpos = 0;
     123         632 :                         cache_start = gf_bs_get_position(bs);
     124         632 :                         gf_bs_read_data(bs, (char *) h263_cache, (u32) load_size);
     125             :                 }
     126      373377 :                 v = (v<<8) | h263_cache[bpos];
     127      373377 :                 bpos++;
     128      373377 :                 if ((v >> (32-22)) == 0x20) end = cache_start+bpos-4;
     129             :         }
     130         628 :         gf_bs_seek(bs, start);
     131         628 :         if (!end) end = gf_bs_get_size(bs);
     132         628 :         return (u32) (end-start);
     133             : }
     134         494 : static void h263dmx_check_dur(GF_Filter *filter, GF_H263DmxCtx *ctx)
     135             : {
     136             : 
     137             :         FILE *stream;
     138             :         GF_BitStream *bs;
     139             :         u64 duration, cur_dur, rate;
     140             :         const GF_PropertyValue *p;
     141         494 :         if (!ctx->opid || ctx->timescale || ctx->file_loaded) return;
     142             : 
     143           7 :         if (ctx->index<=0) {
     144           4 :                 ctx->file_loaded = GF_TRUE;
     145             :                 return;
     146             :         }
     147             : 
     148           3 :         p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILEPATH);
     149           3 :         if (!p || !p->value.string || !strncmp(p->value.string, "gmem://", 7)) {
     150           0 :                 ctx->is_file = GF_FALSE;
     151           0 :                 ctx->file_loaded = GF_TRUE;
     152             :                 return;
     153             :         }
     154           3 :         ctx->is_file = GF_TRUE;
     155             : 
     156           3 :         stream = gf_fopen(p->value.string, "rb");
     157           3 :         if (!stream) return;
     158             : 
     159           3 :         ctx->index_size = 0;
     160             : 
     161           3 :         bs = gf_bs_from_file(stream, GF_BITSTREAM_READ);
     162             :         duration = 0;
     163             :         cur_dur = 0;
     164         631 :         while (gf_bs_available(bs)) {
     165             :                 u8 type;
     166         628 :                 u64 pos = gf_bs_get_position(bs);
     167         628 :                 u64 next_pos = pos + h263dmx_next_start_code_bs(bs);
     168         628 :                 gf_bs_read_u32(bs);
     169         628 :                 type = gf_bs_read_u8(bs);
     170             : 
     171         628 :                 if (type & 0x02) type = 0;
     172             :                 else
     173             :                         type = 1;
     174             : 
     175             : 
     176         628 :                 duration += ctx->fps.den;
     177         628 :                 cur_dur += ctx->fps.den;
     178             :                 //only index at I-frame start
     179         628 :                 if (pos && type && (cur_dur > ctx->index * ctx->fps.num) ) {
     180           7 :                         if (!ctx->index_alloc_size) ctx->index_alloc_size = 10;
     181           6 :                         else if (ctx->index_alloc_size == ctx->index_size) ctx->index_alloc_size *= 2;
     182           7 :                         ctx->indexes = gf_realloc(ctx->indexes, sizeof(H263Idx)*ctx->index_alloc_size);
     183           7 :                         ctx->indexes[ctx->index_size].pos = pos;
     184           7 :                         ctx->indexes[ctx->index_size].duration = (Double) duration;
     185           7 :                         ctx->indexes[ctx->index_size].duration /= ctx->fps.num;
     186           7 :                         ctx->index_size ++;
     187             :                         cur_dur = 0;
     188             :                 }
     189             : 
     190         628 :                 gf_bs_seek(bs, next_pos);
     191             :         }
     192           3 :         rate = gf_bs_get_position(bs);
     193           3 :         gf_bs_del(bs);
     194           3 :         gf_fclose(stream);
     195             : 
     196           3 :         if (!ctx->duration.num || (ctx->duration.num  * ctx->fps.num != duration * ctx->duration.den)) {
     197           3 :                 ctx->duration.num = (s32) duration;
     198           3 :                 ctx->duration.den = ctx->fps.num;
     199             : 
     200           3 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DURATION, & PROP_FRAC64(ctx->duration));
     201             : 
     202             : 
     203           3 :                 if (duration && !gf_sys_is_test_mode() ) {
     204           0 :                         rate *= 8 * ctx->duration.den;
     205           0 :                         rate /= ctx->duration.num;
     206           0 :                         ctx->bitrate = (u32) rate;
     207             :                 }
     208             :         }
     209             : 
     210           3 :         p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILE_CACHED);
     211           3 :         if (p && p->value.boolean) ctx->file_loaded = GF_TRUE;
     212           3 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CAN_DATAREF, & PROP_BOOL(GF_TRUE ) );
     213             : }
     214             : 
     215        1125 : static void h263dmx_check_pid(GF_Filter *filter, GF_H263DmxCtx *ctx, u32 width, u32 height)
     216             : {
     217             : 
     218        1125 :         if (!ctx->opid) {
     219           7 :                 ctx->opid = gf_filter_pid_new(filter);
     220           7 :                 h263dmx_check_dur(filter, ctx);
     221             :         }
     222        1125 :         if ((ctx->width == width) && (ctx->height == height)) return;
     223             : 
     224             :         //copy properties at init or reconfig
     225           7 :         gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
     226           7 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_UNFRAMED, NULL);
     227           7 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STREAM_TYPE, & PROP_UINT(GF_STREAM_VISUAL));
     228           7 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, & PROP_UINT(GF_CODECID_H263));
     229           7 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_TIMESCALE, & PROP_UINT(ctx->fps.num));
     230           7 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_FPS, & PROP_FRAC(ctx->fps));
     231             : 
     232           7 :         if (ctx->duration.num)
     233           3 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DURATION, & PROP_FRAC64(ctx->duration));
     234             : 
     235           7 :         ctx->width = width;
     236           7 :         ctx->height = height;
     237           7 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_WIDTH, & PROP_UINT( width));
     238           7 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_HEIGHT, & PROP_UINT( height));
     239             : 
     240           7 :         if (ctx->bitrate) {
     241           0 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_BITRATE, & PROP_UINT(ctx->bitrate));
     242             :         }
     243             : 
     244           7 :         if (ctx->is_file && ctx->index) {
     245           3 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_PLAYBACK_MODE, & PROP_UINT(GF_PLAYBACK_MODE_FASTFORWARD) );
     246             :         }
     247             : }
     248             : 
     249        1129 : static Bool h263dmx_process_event(GF_Filter *filter, const GF_FilterEvent *evt)
     250             : {
     251             :         u32 i;
     252             :         u64 file_pos = 0;
     253             :         GF_FilterEvent fevt;
     254        1129 :         GF_H263DmxCtx *ctx = gf_filter_get_udta(filter);
     255             : 
     256        1129 :         switch (evt->base.type) {
     257           7 :         case GF_FEVT_PLAY:
     258           7 :                 if (!ctx->is_playing) {
     259           7 :                         ctx->is_playing = GF_TRUE;
     260           7 :                         ctx->cts = 0;
     261           7 :                         ctx->bytes_in_header = 0;
     262             :                 }
     263           7 :                 if (! ctx->is_file) {
     264             :                         return GF_FALSE;
     265             :                 }
     266           3 :                 ctx->start_range = evt->play.start_range;
     267           3 :                 ctx->in_seek = GF_TRUE;
     268             : 
     269           3 :                 if (ctx->start_range) {
     270           0 :                         for (i=1; i<ctx->index_size; i++) {
     271           0 :                                 if (ctx->indexes[i].duration>ctx->start_range) {
     272           0 :                                         ctx->cts = (u64) (ctx->indexes[i-1].duration * ctx->fps.num);
     273           0 :                                         file_pos = ctx->indexes[i-1].pos;
     274           0 :                                         break;
     275             :                                 }
     276             :                         }
     277             :                 }
     278           3 :                 if (!ctx->initial_play_done) {
     279           3 :                         ctx->initial_play_done = GF_TRUE;
     280             :                         //seek will not change the current source state, don't send a seek
     281           3 :                         if (!file_pos)
     282             :                                 return GF_TRUE;
     283             :                 }
     284             :                 //post a seek
     285           0 :                 GF_FEVT_INIT(fevt, GF_FEVT_SOURCE_SEEK, ctx->ipid);
     286           0 :                 fevt.seek.start_offset = file_pos;
     287           0 :                 gf_filter_pid_send_event(ctx->ipid, &fevt);
     288             : 
     289             :                 //cancel event
     290           0 :                 return GF_TRUE;
     291             : 
     292           3 :         case GF_FEVT_STOP:
     293             :                 //don't cancel event
     294           3 :                 ctx->is_playing = GF_FALSE;
     295           3 :                 return GF_FALSE;
     296             : 
     297             :         case GF_FEVT_SET_SPEED:
     298             :                 //cancel event
     299             :                 return GF_TRUE;
     300             :         default:
     301             :                 break;
     302             :         }
     303             :         //by default don't cancel event - to rework once we have downloading in place
     304        1119 :         return GF_FALSE;
     305             : }
     306             : 
     307             : static GFINLINE void h263dmx_update_cts(GF_H263DmxCtx *ctx)
     308             : {
     309             :         assert(ctx->fps.num);
     310             :         assert(ctx->fps.den);
     311             : 
     312        1100 :         if (ctx->timescale) {
     313           0 :                 u64 inc = ctx->fps.den;
     314           0 :                 inc *= ctx->timescale;
     315           0 :                 inc /= ctx->fps.num;
     316           0 :                 ctx->cts += inc;
     317             :         } else {
     318        1100 :                 ctx->cts += ctx->fps.den;
     319             :         }
     320             : }
     321             : 
     322             : 
     323             : static s32 h263dmx_next_start_code(u8 *data, u32 size)
     324             : {
     325             :         u32 v, bpos;
     326             :         s64 end;
     327             :         s64 start = 0;
     328             : 
     329             :         /*skip 16b header*/
     330             :         start+=2;
     331             :         bpos = 0;
     332             :         end = 0;
     333             :         v = 0xffffffff;
     334    10321085 :         while (!end) {
     335    10318307 :                 if (bpos == size) return -1;
     336    10315608 :                 v = (v<<8) | data[bpos];
     337    10315608 :                 bpos++;
     338    10315608 :                 if ((v >> (32-22)) == 0x20) end = start + bpos - 4;
     339             :         }
     340             : 
     341        2778 :         return (s32) (end-start);
     342             : }
     343             : 
     344             : static void h263_get_pic_size(GF_BitStream *bs, u32 fmt, u32 *w, u32 *h)
     345             : {
     346             :         switch (fmt) {
     347             :         case 1:
     348             :                 *w = 128;
     349             :                 *h = 96;
     350             :                 break;
     351             :         case 2:
     352             :                 *w = 176;
     353             :                 *h = 144;
     354             :                 break;
     355             :         case 3:
     356             :                 *w = 352;
     357             :                 *h = 288;
     358             :                 break;
     359             :         case 4:
     360             :                 *w = 704;
     361             :                 *h = 576;
     362             :                 break;
     363             :         case 5:
     364             :                 *w = 1409;
     365             :                 *h = 1152 ;
     366             :                 break;
     367             :         default:
     368             :                 *w = *h = 0;
     369             :                 break;
     370             :         }
     371             : }
     372             : 
     373        1126 : GF_Err h263dmx_process(GF_Filter *filter)
     374             : {
     375        1126 :         GF_H263DmxCtx *ctx = gf_filter_get_udta(filter);
     376             :         GF_FilterPacket *pck, *dst_pck;
     377             :         u64 byte_offset;
     378             :         char *data;
     379             :         u8 *start;
     380             :         Bool first_frame_found = GF_FALSE;
     381             :         u32 pck_size;
     382             :         s32 remain;
     383             : 
     384             :         //always reparse duration
     385        1126 :         if (!ctx->duration.num)
     386         487 :                 h263dmx_check_dur(filter, ctx);
     387             : 
     388        1126 :         pck = gf_filter_pid_get_packet(ctx->ipid);
     389        1126 :         if (!pck) {
     390           7 :                 if (gf_filter_pid_is_eos(ctx->ipid)) {
     391           4 :                         if (ctx->opid)
     392           4 :                                 gf_filter_pid_set_eos(ctx->opid);
     393           4 :                         if (ctx->src_pck) gf_filter_pck_unref(ctx->src_pck);
     394           4 :                         ctx->src_pck = NULL;
     395           4 :                         return GF_EOS;
     396             :                 }
     397             :                 return GF_OK;
     398             :         }
     399             : 
     400        1119 :         data = (char *) gf_filter_pck_get_data(pck, &pck_size);
     401        1119 :         byte_offset = gf_filter_pck_get_byte_offset(pck);
     402             : 
     403             :         start = data;
     404        1119 :         remain = pck_size;
     405             : 
     406             : 
     407        1119 :         if (ctx->bytes_in_header) {
     408             : #if 0
     409             :                 if (ctx->bytes_in_header + remain < 7) {
     410             :                         memcpy(ctx->header + ctx->bytes_in_header, start, remain);
     411             :                         ctx->bytes_in_header += remain;
     412             :                         gf_filter_pid_drop_packet(ctx->ipid);
     413             :                         return GF_OK;
     414             :                 }
     415             :                 alread_sync = 7 - ctx->bytes_in_header;
     416             :                 memcpy(ctx->header + ctx->bytes_in_header, start, alread_sync);
     417             :                 start += alread_sync;
     418             :                 remain -= alread_sync;
     419             :                 ctx->bytes_in_header = 0;
     420             :                 alread_sync = GF_TRUE;
     421             : #endif
     422             : 
     423             :         }
     424             :         //input pid sets some timescale - we flushed pending data , update cts
     425        1114 :         else if (ctx->timescale) {
     426           0 :                 u64 cts = gf_filter_pck_get_cts(pck);
     427           0 :                 if (cts != GF_FILTER_NO_TS)
     428           0 :                         ctx->cts = cts;
     429           0 :                 if (ctx->src_pck) gf_filter_pck_unref(ctx->src_pck);
     430           0 :                 ctx->src_pck = pck;
     431           0 :                 gf_filter_pck_ref_props(&ctx->src_pck);
     432             :         }
     433             : 
     434        1119 :         if (ctx->resume_from) {
     435         974 :                 if (gf_filter_pid_would_block(ctx->opid))
     436             :                         return GF_OK;
     437         974 :                 start += ctx->resume_from;
     438         974 :                 remain -= ctx->resume_from;
     439         974 :                 ctx->resume_from = 0;
     440             :         }
     441             : 
     442        1126 :         while (remain) {
     443             :                 u32 size=0;
     444             :                 Bool full_frame;
     445             :                 u8 *pck_data;
     446             :                 s32 current, next;
     447             :                 u32 fmt, w, h;
     448             : 
     449             :                 //not enough bytes
     450        1126 :                 if (remain<5) {
     451           0 :                         memcpy(ctx->hdr_store, start, remain);
     452           0 :                         ctx->bytes_in_header = remain;
     453         127 :                         break;
     454             :                 }
     455             : 
     456        1126 :                 if (ctx->bytes_in_header) {
     457           5 :                         if (first_frame_found) {
     458           0 :                                 GF_LOG(GF_LOG_WARNING, GF_LOG_MMIO, ("[H263Dmx] corrupted frame!\n"));
     459             :                         }
     460             : 
     461           5 :                         memcpy(ctx->hdr_store + ctx->bytes_in_header, start, 8 - ctx->bytes_in_header);
     462             :                         current = h263dmx_next_start_code(ctx->hdr_store, 8);
     463             : 
     464             :                         //no start code in stored buffer
     465           5 :                         if (current<0) {
     466           4 :                                 dst_pck = gf_filter_pck_new_alloc(ctx->opid, ctx->bytes_in_header, &pck_data);
     467         996 :                                 if (!dst_pck) return GF_OUT_OF_MEM;
     468             : 
     469           4 :                                 if (ctx->src_pck) gf_filter_pck_merge_properties(ctx->src_pck, dst_pck);
     470             : 
     471           4 :                                 memcpy(pck_data, ctx->hdr_store, ctx->bytes_in_header);
     472           4 :                                 gf_filter_pck_set_framing(dst_pck, GF_FALSE, GF_FALSE);
     473           4 :                                 gf_filter_pck_set_cts(dst_pck, ctx->cts);
     474           4 :                                 gf_filter_pck_set_duration(dst_pck, ctx->fps.den);
     475           4 :                                 if (ctx->in_seek) gf_filter_pck_set_seek_flag(dst_pck, GF_TRUE);
     476             : 
     477           4 :                                 if (byte_offset != GF_FILTER_NO_BO) {
     478           4 :                                         gf_filter_pck_set_byte_offset(dst_pck, byte_offset - ctx->bytes_in_header);
     479             :                                 }
     480           4 :                                 gf_filter_pck_send(dst_pck);
     481           4 :                                 ctx->bytes_in_header = 0;
     482             : 
     483           4 :                                 current = h263dmx_next_start_code(start, remain);
     484             :                         }
     485             :                 } else {
     486             :                         //locate next start code
     487        1121 :                         current = h263dmx_next_start_code(start, remain);
     488             :                 }
     489             : 
     490             : 
     491        1126 :                 if (current<0) {
     492             :                         //not enough bytes to process start code !!
     493             :                         break;
     494             :                 }
     495             : 
     496        1125 :                 if (current>0) {
     497         119 :                         if (!ctx->opid) {
     498           0 :                                 if (ctx->bytes_in_header) {
     499           0 :                                         ctx->bytes_in_header -= current;
     500             :                                 } else {
     501           0 :                                         start += current;
     502           0 :                                         remain -= current;
     503             :                                 }
     504           0 :                                 GF_LOG(GF_LOG_WARNING, GF_LOG_MMIO, ("[H263Dmx] garbage before first frame!\n"));
     505           0 :                                 continue;
     506             :                         }
     507         119 :                         if (first_frame_found) {
     508           0 :                                 GF_LOG(GF_LOG_WARNING, GF_LOG_MMIO, ("[H263Dmx] corrupted frame!\n"));
     509             :                         }
     510             :                         //flush remaining
     511         119 :                         dst_pck = gf_filter_pck_new_alloc(ctx->opid, current, &pck_data);
     512         119 :                         if (!dst_pck) return GF_OUT_OF_MEM;
     513             : 
     514         119 :                         if (ctx->src_pck) gf_filter_pck_merge_properties(ctx->src_pck, dst_pck);
     515             : 
     516         119 :                         if (ctx->bytes_in_header) {
     517           1 :                                 if (byte_offset != GF_FILTER_NO_BO) {
     518           1 :                                         gf_filter_pck_set_byte_offset(dst_pck, byte_offset - ctx->bytes_in_header);
     519             :                                 }
     520           1 :                                 ctx->bytes_in_header -= current;
     521           1 :                                 memcpy(pck_data, ctx->hdr_store, current);
     522             :                         } else {
     523         118 :                                 if (byte_offset != GF_FILTER_NO_BO) {
     524         118 :                                         gf_filter_pck_set_byte_offset(dst_pck, byte_offset);
     525             :                                 }
     526         118 :                                 memcpy(pck_data, start, current);
     527         118 :                                 start += current;
     528         118 :                                 remain -= current;
     529             :                         }
     530         119 :                         gf_filter_pck_set_framing(dst_pck, GF_FALSE, GF_TRUE);
     531         119 :                         gf_filter_pck_set_cts(dst_pck, ctx->cts);
     532         119 :                         gf_filter_pck_set_duration(dst_pck, ctx->fps.den);
     533         119 :                         if (ctx->in_seek) gf_filter_pck_set_seek_flag(dst_pck, GF_TRUE);
     534         119 :                         gf_filter_pck_send(dst_pck);
     535             : 
     536             :                         h263dmx_update_cts(ctx);
     537             :                 }
     538             : 
     539        1125 :                 if (ctx->bytes_in_header) {
     540           1 :                         gf_bs_reassign_buffer(ctx->bs, ctx->hdr_store+current, 8-current);
     541        1124 :                 } else if (!ctx->bs) {
     542           7 :                         ctx->bs = gf_bs_new(start, remain, GF_BITSTREAM_READ);
     543             :                 } else {
     544        1117 :                         gf_bs_reassign_buffer(ctx->bs, start, remain);
     545             :                 }
     546             :                 /*parse header*/
     547        1125 :                 gf_bs_read_int(ctx->bs, 22);
     548        1125 :                 gf_bs_read_int(ctx->bs, 8);
     549             :                 /*spare+0+split_screen_indicator+document_camera_indicator+freeze_picture_release*/
     550        1125 :                 gf_bs_read_int(ctx->bs, 5);
     551             : 
     552        1125 :                 fmt = gf_bs_read_int(ctx->bs, 3);
     553             :                 h263_get_pic_size(ctx->bs, fmt, &w, &h);
     554             : 
     555        1125 :                 h263dmx_check_pid(filter, ctx, w, h);
     556             : 
     557        1125 :                 if (!ctx->is_playing) {
     558          18 :                         ctx->resume_from = (u32) ( (char *)start -  (char *)data );
     559          18 :                         return GF_OK;
     560             :                 }
     561             : 
     562        1107 :                 if (ctx->in_seek) {
     563           3 :                         u64 nb_frames_at_seek = (u64) (ctx->start_range * ctx->fps.num);
     564           3 :                         if (ctx->cts + ctx->fps.den >= nb_frames_at_seek) {
     565             :                                 //u32 samples_to_discard = (ctx->cts + ctx->dts_inc) - nb_samples_at_seek;
     566           3 :                                 ctx->in_seek = GF_FALSE;
     567             :                         }
     568             :                 }
     569             : 
     570             :                 //good to go
     571        1107 :                 next = h263dmx_next_start_code(start+1, remain-1);
     572             : 
     573        1107 :                 if (next>0) {
     574         981 :                         size = next+1 + ctx->bytes_in_header;
     575             :                         full_frame = GF_TRUE;
     576             :                 } else {
     577         126 :                         u8 b3 = start[remain-3];
     578         126 :                         u8 b2 = start[remain-2];
     579         126 :                         u8 b1 = start[remain-1];
     580             :                         //we may have a startcode here !
     581         126 :                         if (!b1 || !b2 || !b3) {
     582           5 :                                 memcpy(ctx->hdr_store, start+remain-3, 3);
     583           5 :                                 remain -= 3;
     584           5 :                                 ctx->bytes_in_header = 3;
     585             :                         }
     586         126 :                         size = remain;
     587             :                         full_frame = GF_FALSE;
     588             :                 }
     589             : 
     590        1107 :                 dst_pck = gf_filter_pck_new_alloc(ctx->opid, size, &pck_data);
     591        1107 :                 if (!dst_pck) return GF_OUT_OF_MEM;
     592             : 
     593        1107 :                 if (ctx->src_pck) gf_filter_pck_merge_properties(ctx->src_pck, dst_pck);
     594        1107 :                 if (ctx->bytes_in_header && current) {
     595           1 :                         memcpy(pck_data, ctx->hdr_store+current, ctx->bytes_in_header);
     596           1 :                         size -= ctx->bytes_in_header;
     597           1 :                         ctx->bytes_in_header = 0;
     598           1 :                         if (byte_offset != GF_FILTER_NO_BO) {
     599           1 :                                 gf_filter_pck_set_byte_offset(dst_pck, byte_offset + ctx->bytes_in_header);
     600             :                         }
     601           1 :                         memcpy(pck_data, start, size);
     602             :                 } else {
     603        1106 :                         memcpy(pck_data, start, size);
     604        1106 :                         if (byte_offset != GF_FILTER_NO_BO) {
     605        1106 :                                 gf_filter_pck_set_byte_offset(dst_pck, byte_offset + start - (u8 *) data);
     606             :                         }
     607             :                 }
     608             : 
     609        1107 :                 gf_filter_pck_set_framing(dst_pck, GF_TRUE, full_frame);
     610        1107 :                 gf_filter_pck_set_cts(dst_pck, ctx->cts);
     611        1107 :                 gf_filter_pck_set_sap(dst_pck, (start[4]&0x02) ? GF_FILTER_SAP_NONE : GF_FILTER_SAP_1);
     612        1107 :                 gf_filter_pck_set_duration(dst_pck, ctx->fps.den);
     613        1107 :                 if (ctx->in_seek) gf_filter_pck_set_seek_flag(dst_pck, GF_TRUE);
     614        1107 :                 gf_filter_pck_send(dst_pck);
     615             : 
     616             :                 first_frame_found = GF_TRUE;
     617        1107 :                 start += size;
     618        1107 :                 remain -= size;
     619        1107 :                 if (!full_frame) break;
     620             :                 h263dmx_update_cts(ctx);
     621             : 
     622             : 
     623             :                 //don't demux too much of input, abort when we would block. This avoid dispatching
     624             :                 //a huge number of frames in a single call
     625         981 :                 if (gf_filter_pid_would_block(ctx->opid)) {
     626         974 :                         ctx->resume_from = (u32) ( (char *)start -  (char *)data);
     627         974 :                         return GF_OK;
     628             :                 }
     629             :         }
     630         127 :         gf_filter_pid_drop_packet(ctx->ipid);
     631             : 
     632         127 :         return GF_OK;
     633             : }
     634             : 
     635           7 : static void h263dmx_finalize(GF_Filter *filter)
     636             : {
     637           7 :         GF_H263DmxCtx *ctx = gf_filter_get_udta(filter);
     638           7 :         if (ctx->bs) gf_bs_del(ctx->bs);
     639           7 :         if (ctx->indexes) gf_free(ctx->indexes);
     640           7 : }
     641             : 
     642        3072 : static const char * h263dmx_probe_data(const u8 *data, u32 size, GF_FilterProbeScore *score)
     643             : {
     644             :         u32 nb_frames=0;
     645             :         u32 max_nb_frames=0;
     646             :         u32 prev_fmt=0;
     647             :         u32 nb_fail=0;
     648             :         s32 current = h263dmx_next_start_code((u8*)data, size);
     649        3212 :         while (size && (current>=0) && (current< (s32) size)) {
     650             :                 u32 fmt=0;
     651         672 :                 data += current;
     652         672 :                 size -= current;
     653             : 
     654         672 :                 GF_BitStream *bs = gf_bs_new((u8 *)data, size, GF_BITSTREAM_READ);
     655             : 
     656             :                 /*parse header*/
     657         672 :                 gf_bs_read_int(bs, 22);
     658         672 :                 gf_bs_read_int(bs, 8);
     659         672 :                 gf_bs_read_int(bs, 5);
     660             : 
     661         672 :                 fmt = gf_bs_read_int(bs, 3);
     662         672 :                 gf_bs_del(bs);
     663             : 
     664         672 :                 if (fmt>=1 && (fmt<=5)) {
     665         168 :                         if (!prev_fmt || (prev_fmt==fmt)) {
     666         156 :                                 nb_frames++;
     667             :                         } else {
     668          12 :                                 if (nb_frames>max_nb_frames) {
     669             :                                         max_nb_frames = nb_frames;
     670             :                                 }
     671             :                         }
     672             :                         prev_fmt=fmt;
     673             :                 } else {
     674             :                         nb_frames=0;
     675             :                         nb_fail++;
     676             :                         break;
     677             :                 }
     678         168 :                 current = h263dmx_next_start_code((u8*)data+1, size-1);
     679         168 :                 if (current<=0) break;
     680         140 :                 current++;
     681         140 :                 if ((s32) size < current) break;
     682             :         }
     683        3072 :         if (nb_fail) return NULL;
     684        2568 :         if (nb_frames>max_nb_frames) {
     685             :                 max_nb_frames = nb_frames;
     686             :         }
     687             : 
     688        2568 :         if (max_nb_frames>1) {
     689             :                 // *score = max_nb_frames>4 ? GF_FPROBE_SUPPORTED : GF_FPROBE_MAYBE_SUPPORTED;
     690             :                 //above fails the following test:
     691             :                 //gpac -mem-track -mem-track-stack -blacklist=nvdec  -i results/temp/hevc-split-merge/high_832x0.hvc  @ vout
     692             :                 //returning a score GF_FPROBE_SUPPORTED conflicting with naludmx_probe_data which also returns GF_FPROBE_SUPPORTED
     693             :                 //TODO Change the following code line in order that only naludmx_probe_data is GF_FPROBE_SUPPORTED:
     694             :                 //Tips: "nb_frames of naludmx is larger than the one of h263" may be considered.
     695          10 :                 *score = GF_FPROBE_MAYBE_SUPPORTED;
     696          10 :                 return "video/h263";
     697             :         }
     698             :         return NULL;
     699             : }
     700             : 
     701             : static const GF_FilterCapability H263DmxCaps[] =
     702             : {
     703             :         CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
     704             :         CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_FILE_EXT, "263|h263|s263"),
     705             :         CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_MIME, "video/h263"),
     706             :         CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
     707             :         CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_S263),
     708             :         CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_H263),
     709             :         CAP_BOOL(GF_CAPS_OUTPUT_STATIC_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
     710             :         {0},
     711             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
     712             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_S263),
     713             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_H263),
     714             :         CAP_BOOL(GF_CAPS_INPUT,GF_PROP_PID_UNFRAMED, GF_TRUE),
     715             : };
     716             : 
     717             : #define OFFS(_n)        #_n, offsetof(GF_H263DmxCtx, _n)
     718             : static const GF_FilterArgs H263DmxArgs[] =
     719             : {
     720             :         { OFFS(fps), "import frame rate", GF_PROP_FRACTION, "15000/1000", NULL, 0},
     721             :         { OFFS(index), "indexing window length", GF_PROP_DOUBLE, "1.0", NULL, 0},
     722             :         {0}
     723             : };
     724             : 
     725             : 
     726             : GF_FilterRegister H263DmxRegister = {
     727             :         .name = "rfh263",
     728             :         GF_FS_SET_DESCRIPTION("H263 reframer")
     729             :         GF_FS_SET_HELP("This filter parses H263 files/data and outputs corresponding visual PID and frames.")
     730             :         .private_size = sizeof(GF_H263DmxCtx),
     731             :         .args = H263DmxArgs,
     732             :         .finalize = h263dmx_finalize,
     733             :         SETCAPS(H263DmxCaps),
     734             :         .configure_pid = h263dmx_configure_pid,
     735             :         .process = h263dmx_process,
     736             :         .probe_data = h263dmx_probe_data,
     737             :         .process_event = h263dmx_process_event
     738             : };
     739             : 
     740             : 
     741        2877 : const GF_FilterRegister *h263dmx_register(GF_FilterSession *session)
     742             : {
     743        2877 :         return &H263DmxRegister;
     744             : }

Generated by: LCOV version 1.13