LCOV - code coverage report
Current view: top level - filters - reframe_prores.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 212 301 70.4 %
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 2019-2021
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / ProRes 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             :         //filter args
      36             :         GF_Fraction fps;
      37             :         Bool findex;
      38             :         char *cid;
      39             : 
      40             :         //only one input pid declared
      41             :         GF_FilterPid *ipid;
      42             :         //only one output pid declared
      43             :         GF_FilterPid *opid;
      44             : 
      45             :         GF_BitStream *bs;
      46             :         u64 cts;
      47             :         GF_Fraction64 duration;
      48             :         u64 file_size, file_pos;
      49             :         Double start_range;
      50             :         Bool rewind;
      51             :         u32 cur_frame;
      52             :         u32 timescale;
      53             :         GF_Fraction cur_fps;
      54             : 
      55             :         u8 *buffer;
      56             :         u32 buf_size, alloc_size;
      57             : 
      58             :         GF_ProResFrameInfo cur_cfg;
      59             : 
      60             :         Bool is_playing;
      61             :         Bool is_file, file_loaded;
      62             :         Bool initial_play_done;
      63             : 
      64             :         //when source is not a file/pipe/net stream
      65             :         GF_FilterPacket *src_pck;
      66             : 
      67             :         /*frame index 0/NULL if findex is not set*/
      68             :         u32 nb_frames;
      69             :         u32 *frame_sizes;
      70             : 
      71             :         u32 bitrate;
      72             : } GF_ProResDmxCtx;
      73             : 
      74             : 
      75           2 : GF_Err proresdmx_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
      76             : {
      77             :         const GF_PropertyValue *p;
      78           2 :         GF_ProResDmxCtx *ctx = gf_filter_get_udta(filter);
      79             : 
      80           2 :         if (is_remove) {
      81           0 :                 ctx->ipid = NULL;
      82           0 :                 if (ctx->opid) {
      83           0 :                         gf_filter_pid_remove(ctx->opid);
      84           0 :                         ctx->opid = NULL;
      85             :                 }
      86             :                 return GF_OK;
      87             :         }
      88           2 :         if (! gf_filter_pid_check_caps(pid))
      89             :                 return GF_NOT_SUPPORTED;
      90             : 
      91           2 :         ctx->ipid = pid;
      92           2 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_TIMESCALE);
      93           2 :         if (p) ctx->timescale = p->value.uint;
      94             : 
      95           2 :         if (ctx->timescale && !ctx->opid) {
      96           0 :                 ctx->opid = gf_filter_pid_new(filter);
      97           0 :                 gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
      98           0 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_UNFRAMED, NULL);
      99             :         }
     100           2 :         if (ctx->timescale) {
     101             :                 //if we have a FPS prop, use it
     102           0 :                 p = gf_filter_pid_get_property(pid, GF_PROP_PID_FPS);
     103           0 :                 if (p) ctx->cur_fps = p->value.frac;
     104             :         }
     105             :         return GF_OK;
     106             : }
     107             : 
     108             : 
     109           2 : static void proresdmx_check_dur(GF_Filter *filter, GF_ProResDmxCtx *ctx)
     110             : {
     111             :         FILE *stream;
     112             :         GF_BitStream *bs;
     113             :         u64 duration, rate;
     114             :         u32 idx_size;
     115             :         const char *filepath=NULL;
     116             :         const GF_PropertyValue *p;
     117           2 :         if (!ctx->opid || ctx->timescale || ctx->file_loaded) return;
     118             : 
     119           2 :         p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILE_CACHED);
     120           2 :         if (p && p->value.boolean) ctx->file_loaded = GF_TRUE;
     121             : 
     122           2 :         p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILEPATH);
     123           2 :         if (!p || !p->value.string || !strncmp(p->value.string, "gmem://", 7)) {
     124           0 :                 ctx->is_file = GF_FALSE;
     125           0 :                 ctx->file_loaded = GF_TRUE;
     126             :                 return;
     127             :         }
     128             :         filepath = p->value.string;
     129           2 :         ctx->is_file = GF_TRUE;
     130             : 
     131           2 :         if (ctx->findex==1) {
     132           2 :                 if (gf_opts_get_bool("temp", "force_indexing")) {
     133           0 :                         ctx->findex = 2;
     134             :                 } else {
     135           2 :                         p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_DOWN_SIZE);
     136           2 :                         if (!p || (p->value.longuint > 100000000)) {
     137           0 :                                 GF_LOG(GF_LOG_INFO, GF_LOG_PARSER, ("[ProResDmx] Source file larger than 100M, skipping indexing\n"));
     138             :                         } else {
     139           2 :                                 ctx->findex = 2;
     140             :                         }
     141             :                 }
     142             :         }
     143           2 :         if (!ctx->findex)
     144             :                 return;
     145             : 
     146           2 :         stream = gf_fopen(filepath, "rb");
     147           2 :         if (!stream) return;
     148             : 
     149           2 :         bs = gf_bs_from_file(stream, GF_BITSTREAM_READ);
     150             : 
     151           2 :         idx_size = ctx->nb_frames;
     152           2 :         ctx->nb_frames = 0;
     153           2 :         ctx->file_size = gf_bs_available(bs);
     154             : 
     155             :         duration = 0;
     156          64 :         while (gf_bs_available(bs)) {
     157          62 :                 u64 frame_start = gf_bs_get_position(bs);
     158          62 :                 u32 fsize = gf_bs_read_u32(bs);
     159          62 :                 u32 fmark = gf_bs_read_u32(bs);
     160          62 :                 gf_bs_seek(bs, frame_start + fsize);
     161          62 :                 if (fmark != GF_4CC('i','c','p','f'))
     162             :                         break;
     163             : 
     164          62 :                 duration += ctx->cur_fps.den;
     165             : 
     166          62 :                 if (!idx_size) idx_size = 10;
     167          60 :                 else if (idx_size == ctx->nb_frames) idx_size += 10;
     168          62 :                 ctx->frame_sizes = gf_realloc(ctx->frame_sizes, sizeof(u32)*idx_size);
     169          62 :                 ctx->frame_sizes[ctx->nb_frames] = fsize;
     170          62 :                 ctx->nb_frames++;
     171             :         }
     172           2 :         rate = gf_bs_get_position(bs);
     173           2 :         gf_bs_del(bs);
     174           2 :         gf_fclose(stream);
     175             : 
     176           2 :         if (!ctx->duration.num || (ctx->duration.num  * ctx->cur_fps.num != duration * ctx->duration.den)) {
     177           2 :                 ctx->duration.num = (s32) duration;
     178           2 :                 ctx->duration.den = ctx->cur_fps.num;
     179             : 
     180           2 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DURATION, & PROP_FRAC64(ctx->duration));
     181             : 
     182           2 :                 if (duration && (!gf_sys_is_test_mode() || gf_opts_get_bool("temp", "force_indexing"))) {
     183           0 :                         rate *= 8 * ctx->duration.den;
     184           0 :                         rate /= ctx->duration.num;
     185           0 :                         ctx->bitrate = (u32) rate;
     186             :                 }
     187             :         }
     188           2 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CAN_DATAREF, & PROP_BOOL(GF_TRUE) );
     189             : }
     190             : 
     191             : 
     192        3110 : static Bool proresdmx_process_event(GF_Filter *filter, const GF_FilterEvent *evt)
     193             : {
     194             :         u32 i;
     195             :         u64 file_pos = 0;
     196             :         GF_FilterEvent fevt;
     197        3110 :         GF_ProResDmxCtx *ctx = gf_filter_get_udta(filter);
     198             : 
     199        3110 :         switch (evt->base.type) {
     200           2 :         case GF_FEVT_PLAY:
     201           2 :                 if (!ctx->is_playing) {
     202           2 :                         ctx->is_playing = GF_TRUE;
     203           2 :                         ctx->cts = 0;
     204             :                 }
     205           2 :                 if (! ctx->is_file) {
     206           0 :                         ctx->buf_size = 0;
     207           0 :                         return GF_FALSE;
     208             :                 }
     209           2 :                 ctx->start_range = evt->play.start_range;
     210             : 
     211           2 :                 if (ctx->start_range) {
     212           1 :                         ctx->cur_frame = 0;
     213             : 
     214           1 :                         if (ctx->findex==1) {
     215           0 :                                 ctx->findex = 2;
     216           0 :                                 ctx->file_loaded = GF_FALSE;
     217           0 :                                 ctx->duration.den = ctx->duration.num = 0;
     218           0 :                                 GF_LOG(GF_LOG_INFO, GF_LOG_PARSER, ("[ProResDmx] Play request from %d, building index\n", ctx->start_range));
     219           0 :                                 proresdmx_check_dur(filter, ctx);
     220             :                         }
     221           1 :                         if ((evt->play.speed<0) && (ctx->start_range<0)) {
     222           0 :                                 ctx->start_range = (Double) ctx->duration.num;
     223           0 :                                 ctx->start_range /= ctx->duration.den;
     224             :                         }
     225             : 
     226          31 :                         for (i=0; i<ctx->nb_frames; i++) {
     227          31 :                                 Double t = ctx->cur_frame * ctx->cur_fps.den / ctx->cur_fps.num;
     228          31 :                                 ctx->cts = ctx->cur_frame * ctx->cur_fps.den;
     229          31 :                                 if (t>=ctx->start_range) {
     230             :                                         break;
     231             :                                 }
     232          31 :                                 if (i+1==ctx->nb_frames)
     233             :                                         break;
     234          30 :                                 ctx->cur_frame++;
     235          30 :                                 file_pos += ctx->frame_sizes[i];
     236             :                         }
     237             :                 }
     238             : 
     239           2 :                 ctx->rewind = (ctx->nb_frames && (evt->play.speed<0)) ? GF_TRUE : GF_FALSE;
     240             : 
     241           2 :                 if (!ctx->initial_play_done) {
     242           2 :                         ctx->initial_play_done = GF_TRUE;
     243             :                         //seek will not change the current source state, don't send a seek
     244           2 :                         if (!file_pos)
     245             :                                 return GF_TRUE;
     246             :                 }
     247           1 :                 ctx->buf_size = 0;
     248           1 :                 ctx->file_pos = file_pos;
     249             : 
     250             :                 //post a seek
     251           1 :                 GF_FEVT_INIT(fevt, GF_FEVT_SOURCE_SEEK, ctx->ipid);
     252           1 :                 fevt.seek.start_offset = file_pos;
     253           1 :                 gf_filter_pid_send_event(ctx->ipid, &fevt);
     254             : 
     255             :                 //cancel event
     256           1 :                 return GF_TRUE;
     257             : 
     258           0 :         case GF_FEVT_STOP:
     259             :                 //don't cancel event
     260           0 :                 ctx->is_playing = GF_FALSE;
     261           0 :                 return GF_FALSE;
     262             : 
     263             :         case GF_FEVT_SET_SPEED:
     264             :                 //cancel event
     265             :                 return GF_TRUE;
     266             :         default:
     267             :                 break;
     268             :         }
     269             :         //by default don't cancel event - to rework once we have downloading in place
     270        3108 :         return GF_FALSE;
     271             : }
     272             : 
     273             : static GFINLINE void proresdmx_update_cts(GF_ProResDmxCtx *ctx)
     274             : {
     275             :         u64 inc;
     276             :         assert(ctx->cur_fps.num);
     277             :         assert(ctx->cur_fps.den);
     278             : 
     279          61 :         if (ctx->timescale) {
     280           0 :                 inc = ctx->cur_fps.den;
     281           0 :                 inc *= ctx->timescale;
     282           0 :                 inc /= ctx->cur_fps.num;
     283             :         } else {
     284          61 :                 inc = ctx->cur_fps.den;
     285             :         }
     286          61 :         if (ctx->rewind)
     287          30 :                 ctx->cts -= inc;
     288             :         else
     289          31 :                 ctx->cts += inc;
     290             : }
     291             : 
     292        3135 : static void proresdmx_check_pid(GF_Filter *filter, GF_ProResDmxCtx *ctx, GF_ProResFrameInfo *finfo)
     293             : {
     294             :         Bool same_cfg = GF_TRUE;
     295             :         u32 codec_id;
     296             :         u64 bitrate;
     297             :         GF_Fraction fps;
     298             : 
     299             : #define CHECK_CFG(_name) if (ctx->cur_cfg._name!=finfo->_name) same_cfg = GF_FALSE;
     300             : 
     301        3135 :         CHECK_CFG(width)
     302        3135 :         CHECK_CFG(height)
     303        3135 :         CHECK_CFG(chroma_format)
     304        3135 :         CHECK_CFG(interlaced_mode)
     305        3135 :         CHECK_CFG(aspect_ratio_information)
     306        3135 :         CHECK_CFG(framerate_code)
     307        3135 :         CHECK_CFG(color_primaries)
     308        3135 :         CHECK_CFG(transfer_characteristics)
     309        3135 :         CHECK_CFG(matrix_coefficients)
     310        3135 :         CHECK_CFG(alpha_channel_type)
     311             : 
     312             : #undef CHECK_CFG
     313             : 
     314        3135 :         if (same_cfg) return;
     315             :         fps.num = fps.den = 0;
     316             :         switch (finfo->framerate_code) {
     317             :         case 1: fps.num = 24000; fps.den = 1001; break;
     318             :         case 2: fps.num = 24; fps.den = 1; break;
     319             :         case 3: fps.num = 24; fps.den = 1; break;
     320             :         case 4: fps.num = 30000; fps.den = 1001; break;
     321             :         case 5: fps.num = 30; fps.den = 1; break;
     322             :         case 6: fps.num = 50; fps.den = 1; break;
     323             :         case 7: fps.num = 60000; fps.den = 1001; break;
     324             :         case 8: fps.num = 60; fps.den = 1; break;
     325             :         case 9: fps.num = 100; fps.den = 1; break;
     326             :         case 10: fps.num = 120000; fps.den = 1001; break;
     327             :         case 11: fps.num = 120; fps.den = 1; break;
     328             :         }
     329             : 
     330           2 :         ctx->cur_fps = ctx->fps;
     331           2 :         if (!ctx->fps.num || !ctx->fps.den) {
     332           2 :                 if (fps.num && fps.den) {
     333           0 :                         ctx->cur_fps = fps;
     334             :                 } else {
     335           2 :                         ctx->cur_fps.num = 25000;
     336           2 :                         ctx->cur_fps.den = 1000;
     337             :                 }
     338             :         }
     339             : 
     340           2 :         if (!ctx->opid) {
     341           2 :                 ctx->opid = gf_filter_pid_new(filter);
     342           2 :                 proresdmx_check_dur(filter, ctx);
     343             :         }
     344             : 
     345             :         bitrate = 0;
     346           2 :         if (ctx->nb_frames && ctx->file_size && ctx->cur_fps.den) {
     347           2 :                 bitrate = ctx->file_size * 8;
     348           2 :                 bitrate *= ctx->cur_fps.num;
     349           2 :                 bitrate /= ctx->nb_frames * ctx->cur_fps.den;
     350             :         }
     351           2 :         memcpy(&ctx->cur_cfg, finfo, sizeof(GF_ProResFrameInfo));
     352           2 :         if (ctx->cid && (strlen(ctx->cid)>4)) {
     353           0 :                 codec_id = GF_4CC(ctx->cid[0],ctx->cid[1],ctx->cid[2],ctx->cid[3]);
     354           2 :         } else if (finfo->chroma_format==3) {
     355             :                 codec_id = GF_CODECID_AP4H;
     356             :         } else {
     357             :                 codec_id = GF_CODECID_APCH;
     358             :         }
     359             : 
     360             :         //copy properties at init or reconfig
     361           2 :         gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
     362           2 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STREAM_TYPE, & PROP_UINT(GF_STREAM_VISUAL));
     363           2 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, & PROP_UINT(codec_id));
     364             : 
     365           2 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_TIMESCALE, & PROP_UINT(ctx->cur_fps.num));
     366           2 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_FPS, & PROP_FRAC(ctx->cur_fps));
     367           2 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_WIDTH, & PROP_UINT(finfo->width));
     368           2 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_HEIGHT, & PROP_UINT(finfo->height));
     369           2 :         switch (finfo->alpha_channel_type) {
     370           0 :         case 1:
     371             :         case 2:
     372           0 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_ALPHA, & PROP_BOOL(GF_TRUE));
     373           0 :                 break;
     374           2 :         default:
     375           2 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_ALPHA, NULL);
     376           2 :                 break;
     377             :         }
     378             : 
     379           2 :         switch (finfo->aspect_ratio_information) {
     380           2 :         case 0:
     381           2 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAR, NULL);
     382           2 :                 break;
     383           0 :         case 1:
     384           0 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAR, & PROP_FRAC_INT(1, 1) );
     385           0 :                 break;
     386           0 :         case 2:
     387           0 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAR, & PROP_FRAC_INT(4, 3) );
     388           0 :                 break;
     389           0 :         case 3:
     390           0 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAR, & PROP_FRAC_INT(16, 9) );
     391           0 :                 break;
     392           0 :         default:
     393           0 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAR, NULL);
     394           0 :                 break;
     395             :         }
     396             : 
     397           2 :         if (ctx->duration.num)
     398           2 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DURATION, & PROP_FRAC64(ctx->duration));
     399             : 
     400           2 :         if (ctx->bitrate) {
     401           0 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_BITRATE, & PROP_UINT(ctx->bitrate));
     402             :         }
     403             : 
     404             :         /*prores is all intra, we support rewind*/
     405           2 :         if (ctx->is_file && ctx->findex) {
     406           2 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_PLAYBACK_MODE, & PROP_UINT(GF_PLAYBACK_MODE_REWIND) );
     407             :         }
     408           2 :         if (bitrate && !gf_sys_is_test_mode())
     409           0 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_BITRATE, & PROP_UINT((u32)bitrate) );
     410             : 
     411           2 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_COLR_PRIMARIES, & PROP_UINT(finfo->color_primaries) );
     412           2 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_COLR_TRANSFER, & PROP_UINT(finfo->transfer_characteristics) );
     413           2 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_COLR_MX, & PROP_UINT(finfo->matrix_coefficients) );
     414             : 
     415             :         //set interlaced or remove interlaced property
     416           2 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_INTERLACED, ctx->cur_cfg.interlaced_mode ? & PROP_UINT(GF_TRUE) : NULL);
     417             : }
     418             : 
     419             : 
     420             : 
     421        3108 : GF_Err proresdmx_process_buffer(GF_Filter *filter, GF_ProResDmxCtx *ctx, const u8 *data, u32 data_size, Bool is_copy)
     422             : {
     423             :         u32 last_frame_end = 0;
     424             :         GF_Err e = GF_OK;
     425             : 
     426        3108 :         if (!ctx->bs) ctx->bs = gf_bs_new(data, data_size, GF_BITSTREAM_READ);
     427        3106 :         else gf_bs_reassign_buffer(ctx->bs, data, data_size);
     428             : 
     429        3139 :         while (gf_bs_available(ctx->bs)) {
     430             :                 u8 *output;
     431             :                 GF_FilterPacket *pck;
     432             :                 GF_ProResFrameInfo finfo;
     433        3138 :                 e = gf_media_prores_parse_bs(ctx->bs, &finfo);
     434             : 
     435        3138 :                 if (e) {
     436             :                         break;
     437             :                 }
     438        3135 :                 proresdmx_check_pid(filter, ctx, &finfo);
     439             : 
     440        3135 :                 if (!ctx->is_playing && ctx->opid)
     441             :                         break;
     442             : 
     443        3133 :                 if (gf_bs_available(ctx->bs)<finfo.frame_size)
     444             :                         break;
     445             : 
     446          61 :                 pck = gf_filter_pck_new_alloc(ctx->opid, finfo.frame_size, &output);
     447          61 :                 if (!pck) break;
     448          61 :                 gf_bs_read_data(ctx->bs, output, finfo.frame_size);
     449             : 
     450          61 :                 if (ctx->src_pck) gf_filter_pck_merge_properties(ctx->src_pck, pck);
     451             : 
     452          61 :                 gf_filter_pck_set_dts(pck, ctx->cts);
     453          61 :                 gf_filter_pck_set_cts(pck, ctx->cts);
     454          61 :                 gf_filter_pck_set_sap(pck, GF_FILTER_SAP_1);
     455          61 :                 gf_filter_pck_set_byte_offset(pck, ctx->file_pos);
     456             : 
     457          61 :                 gf_filter_pck_send(pck);
     458             :                 proresdmx_update_cts(ctx);
     459          61 :                 last_frame_end = (u32) gf_bs_get_position(ctx->bs);
     460             : 
     461          61 :                 if (ctx->rewind) {
     462          30 :                         ctx->buf_size = 0;
     463             :                         last_frame_end = 0;
     464             :                         assert(ctx->cur_frame);
     465          30 :                         ctx->cur_frame--;
     466          30 :                         if (!ctx->cur_frame) {
     467           1 :                                 if (ctx->opid)
     468           1 :                                         gf_filter_pid_set_eos(ctx->opid);
     469             :                         } else {
     470             :                                 GF_FilterEvent fevt;
     471          29 :                                 ctx->file_pos -= ctx->frame_sizes[ctx->cur_frame];
     472             :                                 //post a seek
     473          29 :                                 GF_FEVT_INIT(fevt, GF_FEVT_SOURCE_SEEK, ctx->ipid);
     474          29 :                                 fevt.seek.start_offset = ctx->file_pos;
     475          29 :                                 gf_filter_pid_send_event(ctx->ipid, &fevt);
     476             :                         }
     477             :                         break;
     478             :                 } else {
     479          31 :                         ctx->file_pos += finfo.frame_size;
     480             :                 }
     481             :         }
     482             : 
     483        3108 :         if (is_copy && last_frame_end) {
     484             :                 assert(ctx->buf_size >= last_frame_end);
     485          31 :                 memmove(ctx->buffer, ctx->buffer+last_frame_end, sizeof(char) * (ctx->buf_size-last_frame_end));
     486          31 :                 ctx->buf_size -= last_frame_end;
     487             :         }
     488        3108 :         if (e==GF_EOS) return GF_OK;
     489        3108 :         if (e==GF_BUFFER_TOO_SMALL) return GF_OK;
     490        3105 :         return e;
     491             : }
     492             : 
     493        3145 : GF_Err proresdmx_process(GF_Filter *filter)
     494             : {
     495             :         GF_Err e;
     496        3145 :         GF_ProResDmxCtx *ctx = gf_filter_get_udta(filter);
     497             :         GF_FilterPacket *pck;
     498             :         char *data;
     499             :         u32 pck_size;
     500             : 
     501        3145 :         if (!ctx->is_playing && ctx->opid)
     502             :                 return GF_OK;
     503             : 
     504        3141 :         if (ctx->rewind && !ctx->cur_frame) {
     505           0 :                 gf_filter_pid_set_discard(ctx->ipid, GF_TRUE);
     506           0 :                 return GF_OK;
     507             :         }
     508             : 
     509        3141 :         pck = gf_filter_pid_get_packet(ctx->ipid);
     510        3141 :         if (!pck) {
     511          33 :                 if (gf_filter_pid_is_eos(ctx->ipid)) {
     512             :                         //flush
     513           1 :                         while (ctx->buf_size) {
     514             :                                 u32 buf_size = ctx->buf_size;
     515           0 :                                 e = proresdmx_process_buffer(filter, ctx, ctx->buffer, ctx->buf_size, GF_TRUE);
     516           0 :                                 if (e) break;
     517           0 :                                 if (buf_size == ctx->buf_size) {
     518             :                                         break;
     519             :                                 }
     520             :                         }
     521             : 
     522           1 :                         ctx->buf_size = 0;
     523           1 :                         if (ctx->opid)
     524           1 :                                 gf_filter_pid_set_eos(ctx->opid);
     525           1 :                         if (ctx->src_pck) gf_filter_pck_unref(ctx->src_pck);
     526           1 :                         ctx->src_pck = NULL;
     527           1 :                         return GF_EOS;
     528             :                 }
     529             :                 return GF_OK;
     530             :         }
     531             : 
     532        3108 :         if (ctx->opid) {
     533        3106 :                 if (!ctx->is_playing || gf_filter_pid_would_block(ctx->opid))
     534             :                         return GF_OK;
     535             :         }
     536             : 
     537        3108 :         data = (char *) gf_filter_pck_get_data(pck, &pck_size);
     538             : 
     539             :         //input pid sets some timescale - we flushed pending data , update cts
     540        3108 :         if (ctx->timescale) {
     541             :                 Bool start, end;
     542             :                 u64 cts;
     543             : 
     544             :                 e = GF_OK;
     545             : 
     546           0 :                 gf_filter_pck_get_framing(pck, &start, &end);
     547             :                 //middle or end of frame, reaggregation
     548           0 :                 if (!start) {
     549           0 :                         if (ctx->alloc_size < ctx->buf_size + pck_size) {
     550           0 :                                 ctx->alloc_size = ctx->buf_size + pck_size;
     551           0 :                                 ctx->buffer = gf_realloc(ctx->buffer, ctx->alloc_size);
     552             :                         }
     553           0 :                         memcpy(ctx->buffer+ctx->buf_size, data, pck_size);
     554           0 :                         ctx->buf_size += pck_size;
     555             : 
     556             :                         //end of frame, process av1
     557           0 :                         if (end) {
     558           0 :                                 e = proresdmx_process_buffer(filter, ctx, ctx->buffer, ctx->buf_size, GF_TRUE);
     559             :                         }
     560           0 :                         ctx->buf_size=0;
     561           0 :                         gf_filter_pid_drop_packet(ctx->ipid);
     562           0 :                         return e;
     563             :                 }
     564             :                 //flush of pending frame (might have lost something)
     565           0 :                 if (ctx->buf_size) {
     566           0 :                         e = proresdmx_process_buffer(filter, ctx, ctx->buffer, ctx->buf_size, GF_TRUE);
     567           0 :                         ctx->buf_size = 0;
     568           0 :                         if (e) return e;
     569             :                 }
     570             : 
     571             :                 //beginning of a new frame
     572           0 :                 cts = gf_filter_pck_get_cts(pck);
     573           0 :                 if (cts != GF_FILTER_NO_TS)
     574           0 :                         ctx->cts = cts;
     575           0 :                 if (ctx->src_pck) gf_filter_pck_unref(ctx->src_pck);
     576           0 :                 ctx->src_pck = pck;
     577           0 :                 gf_filter_pck_ref_props(&ctx->src_pck);
     578           0 :                 ctx->buf_size = 0;
     579             : 
     580           0 :                 if (!end) {
     581           0 :                         if (ctx->alloc_size < ctx->buf_size + pck_size) {
     582           0 :                                 ctx->alloc_size = ctx->buf_size + pck_size;
     583           0 :                                 ctx->buffer = gf_realloc(ctx->buffer, ctx->alloc_size);
     584             :                         }
     585           0 :                         memcpy(ctx->buffer+ctx->buf_size, data, pck_size);
     586           0 :                         ctx->buf_size += pck_size;
     587           0 :                         gf_filter_pid_drop_packet(ctx->ipid);
     588           0 :                         return GF_OK;
     589             :                 }
     590             :                 assert(start && end);
     591             :                 //process
     592           0 :                 e = proresdmx_process_buffer(filter, ctx, data, pck_size, GF_FALSE);
     593             : 
     594           0 :                 gf_filter_pid_drop_packet(ctx->ipid);
     595           0 :                 return e;
     596             :         }
     597             : 
     598             :         //not from framed stream, copy buffer
     599        3108 :         if (ctx->alloc_size < ctx->buf_size + pck_size) {
     600         115 :                 ctx->alloc_size = ctx->buf_size + pck_size;
     601         115 :                 ctx->buffer = gf_realloc(ctx->buffer, ctx->alloc_size);
     602             :         }
     603        3108 :         memcpy(ctx->buffer+ctx->buf_size, data, pck_size);
     604        3108 :         ctx->buf_size += pck_size;
     605        3108 :         e = proresdmx_process_buffer(filter, ctx, ctx->buffer, ctx->buf_size, GF_TRUE);
     606        3108 :         gf_filter_pid_drop_packet(ctx->ipid);
     607        3108 :         return e;
     608             : }
     609             : 
     610           2 : static void proresdmx_finalize(GF_Filter *filter)
     611             : {
     612           2 :         GF_ProResDmxCtx *ctx = gf_filter_get_udta(filter);
     613           2 :         if (ctx->bs) gf_bs_del(ctx->bs);
     614           2 :         if (ctx->frame_sizes) gf_free(ctx->frame_sizes);
     615           2 :         if (ctx->buffer) gf_free(ctx->buffer);
     616           2 : }
     617             : 
     618        3065 : static const char * proresdmx_probe_data(const u8 *data, u32 size, GF_FilterProbeScore *score)
     619             : {
     620        3065 :         if (size<8) return NULL;
     621             : 
     622        3063 :         if ((data[4] == 'i') && (data[5] == 'c') && (data[6] == 'p') && (data[7] == 'f')) {
     623           2 :                 *score = GF_FPROBE_SUPPORTED;
     624           2 :                 return "video/prores";
     625             :         }
     626             :         return NULL;
     627             : }
     628             : 
     629             : static const GF_FilterCapability ProResDmxCaps[] =
     630             : {
     631             :         CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
     632             :         CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_FILE_EXT, "prores"),
     633             :         CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_MIME, "video/prores"),
     634             :         CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
     635             :         CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_APCN),
     636             :         CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_APCO),
     637             :         CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_APCH),
     638             :         CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_APCS),
     639             :         CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_AP4X),
     640             :         CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_AP4H),
     641             :         CAP_BOOL(GF_CAPS_OUTPUT_STATIC_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
     642             :         {0},
     643             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
     644             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_APCN),
     645             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_APCO),
     646             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_APCH),
     647             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_APCS),
     648             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AP4X),
     649             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AP4H),
     650             :         CAP_BOOL(GF_CAPS_INPUT,GF_PROP_PID_UNFRAMED, GF_TRUE),
     651             : };
     652             : 
     653             : #define OFFS(_n)        #_n, offsetof(GF_ProResDmxCtx, _n)
     654             : static const GF_FilterArgs ProResDmxArgs[] =
     655             : {
     656             :         { OFFS(fps), "import frame rate (0 default to FPS from bitstream or 25 Hz)", GF_PROP_FRACTION, "0/1000", NULL, 0},
     657             :         { OFFS(findex), "index frames. If true, filter will be able to work in rewind mode", GF_PROP_BOOL, "true", NULL, 0},
     658             : 
     659             :         { OFFS(cid), "set QT 4CC for the imported media. If not set, defaults to 'ap4h' for YUV444 or 'apch' for YUV422", GF_PROP_STRING, NULL, NULL, GF_FS_ARG_HINT_ADVANCED},
     660             :         {0}
     661             : };
     662             : 
     663             : 
     664             : GF_FilterRegister ProResDmxRegister = {
     665             :         .name = "rfprores",
     666             :         GF_FS_SET_DESCRIPTION("ProRes reframer")
     667             :         GF_FS_SET_HELP("This filter parses ProRes raw files/data and outputs corresponding visual PID and frames.")
     668             :         .private_size = sizeof(GF_ProResDmxCtx),
     669             :         .args = ProResDmxArgs,
     670             :         .finalize = proresdmx_finalize,
     671             :         SETCAPS(ProResDmxCaps),
     672             :         .configure_pid = proresdmx_configure_pid,
     673             :         .process = proresdmx_process,
     674             :         .probe_data = proresdmx_probe_data,
     675             :         .process_event = proresdmx_process_event
     676             : };
     677             : 
     678             : 
     679        2877 : const GF_FilterRegister *proresdmx_register(GF_FilterSession *session)
     680             : {
     681        2877 :         return &ProResDmxRegister;
     682             : }
     683             : 
     684             : #else
     685             : const GF_FilterRegister *proresdmx_register(GF_FilterSession *session)
     686             : {
     687             :         return NULL;
     688             : }
     689             : #endif // GPAC_DISABLE_AV_PARSERS
     690             : 

Generated by: LCOV version 1.13