LCOV - code coverage report
Current view: top level - filters - ff_dmx.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 325 423 76.8 %
Date: 2021-04-29 23:48:07 Functions: 15 15 100.0 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2017-2021
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / ffmpeg demux 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/setup.h>
      27             : 
      28             : #ifdef GPAC_HAS_FFMPEG
      29             : 
      30             : #include "ff_common.h"
      31             : 
      32             : //for NTP clock
      33             : #include <gpac/network.h>
      34             : 
      35             : enum
      36             : {
      37             :         COPY_NO,
      38             :         COPY_A,
      39             :         COPY_V,
      40             :         COPY_AV
      41             : };
      42             : 
      43             : typedef struct
      44             : {
      45             :         //options
      46             :         const char *src;
      47             :         u32 block_size;
      48             :         u32 copy, probes;
      49             :         Bool sclock;
      50             :         const char *fmt, *dev;
      51             : 
      52             :         //internal data
      53             :         const char *fname;
      54             :         u32 log_class;
      55             : 
      56             :         Bool initialized;
      57             :         Bool raw_data;
      58             :         //input file
      59             :         AVFormatContext *demuxer;
      60             :         //demux options
      61             :         AVDictionary *options;
      62             : 
      63             :         GF_FilterPid **pids;
      64             : 
      65             :         Bool raw_pck_out;
      66             :         u32 nb_playing;
      67             :         Bool stop_seen;
      68             :         u64 first_sample_clock, last_frame_ts;
      69             :         u32 probe_frames;
      70             :     u32 nb_pck_sent;
      71             : 
      72             :         AVPacket pkt;
      73             :         s32 audio_idx, video_idx;
      74             : 
      75             :         u64 *probe_times;
      76             : 
      77             :         Bool copy_audio, copy_video;
      78             : 
      79             :         u8 *avio_ctx_buffer;
      80             :         AVIOContext *avio_ctx;
      81             :         FILE *gfio;
      82             : } GF_FFDemuxCtx;
      83             : 
      84           7 : static void ffdmx_finalize(GF_Filter *filter)
      85             : {
      86           7 :         GF_FFDemuxCtx *ctx = (GF_FFDemuxCtx *) gf_filter_get_udta(filter);
      87           7 :         if (ctx->pids)
      88           7 :                 gf_free(ctx->pids);
      89           7 :         if (ctx->options)
      90           0 :                 av_dict_free(&ctx->options);
      91           7 :         if (ctx->probe_times)
      92           1 :                 gf_free(ctx->probe_times);
      93           7 :         if (ctx->demuxer) {
      94           7 :                 avformat_close_input(&ctx->demuxer);
      95           7 :                 avformat_free_context(ctx->demuxer);
      96             :         }
      97           7 :         if (ctx->avio_ctx) {
      98           1 :                 if (ctx->avio_ctx->buffer) av_freep(&ctx->avio_ctx->buffer);
      99           1 :                 av_freep(&ctx->avio_ctx);
     100             :         }
     101           7 :         if (ctx->gfio) gf_fclose(ctx->gfio);
     102           7 :         return;
     103             : }
     104             : 
     105           6 : void ffdmx_shared_pck_release(GF_Filter *filter, GF_FilterPid *pid, GF_FilterPacket *pck)
     106             : {
     107           6 :         GF_FFDemuxCtx *ctx = (GF_FFDemuxCtx *) gf_filter_get_udta(filter);
     108           6 :         if (ctx->raw_pck_out) {
     109           6 :                 av_free_packet(&ctx->pkt);
     110           6 :                 ctx->raw_pck_out = GF_FALSE;
     111           6 :                 gf_filter_post_process_task(filter);
     112             :         }
     113           6 : }
     114             : 
     115        1202 : static GF_Err ffdmx_process(GF_Filter *filter)
     116             : {
     117             :         GF_Err e;
     118             :         u32 i;
     119             :         u64 sample_time;
     120             :         u8 *data_dst;
     121             :         Bool copy = GF_TRUE;
     122             :         GF_FilterPacket *pck_dst;
     123        1202 :         GF_FFDemuxCtx *ctx = (GF_FFDemuxCtx *) gf_filter_get_udta(filter);
     124             : 
     125        1202 :         if (!ctx->nb_playing)
     126             :                 return GF_EOS;
     127             : 
     128        1188 :         if (ctx->raw_pck_out)
     129             :                 return GF_EOS;
     130             : 
     131        1188 :         sample_time = gf_sys_clock_high_res();
     132        1188 :         av_init_packet(&ctx->pkt);
     133        1188 :         ctx->pkt.stream_index = -1;
     134             :         /*EOF*/
     135        1188 :         if (av_read_frame(ctx->demuxer, &ctx->pkt) <0) {
     136           5 :                 av_free_packet(&ctx->pkt);
     137           5 :                 if (!ctx->raw_data) {
     138           5 :                         for (i=0; i<ctx->demuxer->nb_streams; i++) {
     139           5 :                                 if (ctx->pids[i]) gf_filter_pid_set_eos(ctx->pids[i]);
     140             :                         }
     141             :                         return GF_EOS;
     142             :                 }
     143             :                 return GF_OK;
     144             :         }
     145             : 
     146             :         assert(ctx->pkt.stream_index>=0);
     147             :         assert(ctx->pkt.stream_index < (s32) ctx->demuxer->nb_streams);
     148             : 
     149        1183 :         if (ctx->pkt.pts == AV_NOPTS_VALUE) {
     150           0 :                 if (ctx->pkt.dts == AV_NOPTS_VALUE) {
     151           0 :                         GF_LOG(GF_LOG_WARNING, ctx->log_class, ("[%s] No PTS for packet on stream %d\n", ctx->fname, ctx->pkt.stream_index ));
     152             :                 } else {
     153           0 :                         ctx->pkt.pts = ctx->pkt.dts;
     154             :                 }
     155             :         }
     156             : 
     157        1183 :         if (! ctx->pids[ctx->pkt.stream_index] ) {
     158           0 :                 GF_LOG(GF_LOG_DEBUG, ctx->log_class, ("[%s] No PID defined for given stream %d\n", ctx->fname, ctx->pkt.stream_index ));
     159           0 :                 av_free_packet(&ctx->pkt);
     160           0 :                 return GF_OK;
     161             :         }
     162        1183 :     if (ctx->stop_seen && ! gf_filter_pid_is_playing( ctx->pids[ctx->pkt.stream_index] ) ) {
     163           0 :         av_free_packet(&ctx->pkt);
     164           0 :         return GF_OK;
     165             :     }
     166        1183 :         if (ctx->raw_data && (ctx->probe_frames<ctx->probes) ) {
     167          10 :                 if (ctx->pkt.stream_index==ctx->audio_idx) {
     168           0 :                         av_free_packet(&ctx->pkt);
     169           0 :                         return GF_OK;
     170             :                 }
     171             : 
     172          10 :                 ctx->probe_times[ctx->probe_frames] = ctx->sclock ? sample_time : ctx->pkt.pts;
     173          10 :                 ctx->probe_frames++;
     174          10 :                 if (ctx->probe_frames==ctx->probes) {
     175             :                         u32 best_diff=0, max_stat=0;
     176          10 :                         for (i=0; i<ctx->probes; i++) {
     177          10 :                                 if (i) {
     178             :                                         u32 j, nb_stats=0;
     179           9 :                                         u32 diff = (u32) (ctx->probe_times[i]-ctx->probe_times[i-1]);
     180          90 :                                         for (j=1; j<ctx->probes; j++) {
     181          81 :                                                 s32 sdiff = (s32) (ctx->probe_times[j]-ctx->probe_times[j-1]);
     182          81 :                                                 sdiff -= (s32) diff;
     183          81 :                                                 if (sdiff<0) sdiff = -sdiff;
     184          81 :                                                 if (sdiff<2000) nb_stats++;
     185             :                                         }
     186           9 :                                         if (max_stat<nb_stats) {
     187             :                                                 max_stat = nb_stats;
     188             :                                                 best_diff = diff;
     189             :                                         }
     190             :                                 }
     191             :                         }
     192           1 :                         GF_LOG(GF_LOG_INFO, ctx->log_class, ("[%s] Video probing done, frame diff is %d us (for %d frames out of %d)\n", ctx->fname, best_diff, max_stat, ctx->probes));
     193             :                 } else {
     194           9 :                         av_free_packet(&ctx->pkt);
     195           9 :                         return GF_OK;
     196             :                 }
     197             :         }
     198             : 
     199        1174 :         if (ctx->raw_data) {
     200           6 :                 if (ctx->pkt.stream_index==ctx->audio_idx) copy = ctx->copy_audio;
     201           6 :                 else copy = ctx->copy_video;
     202             :         }
     203             : 
     204        1174 :         if (ctx->raw_data && !copy) {
     205             :                 //we don't use shared memory on demuxers since they are usually the ones performing all the buffering
     206           6 :                 pck_dst = gf_filter_pck_new_shared(ctx->pids[ctx->pkt.stream_index], ctx->pkt.data, ctx->pkt.size, ffdmx_shared_pck_release);
     207           6 :                 if (!pck_dst) return GF_OUT_OF_MEM;
     208           6 :                 ctx->raw_pck_out = GF_TRUE;
     209             :         } else {
     210             :                 //we don't use shared memory on demuxers since they are usually the ones performing all the buffering
     211        1168 :                 pck_dst = gf_filter_pck_new_alloc(ctx->pids[ctx->pkt.stream_index] , ctx->pkt.size, &data_dst);
     212        1168 :                 if (!pck_dst) return GF_OUT_OF_MEM;
     213             :                 assert(pck_dst);
     214        1168 :                 memcpy(data_dst, ctx->pkt.data, ctx->pkt.size);
     215             :         }
     216             : 
     217             : 
     218        1177 :         if (ctx->raw_data && ctx->sclock) {
     219             :                 u64 ts;
     220           3 :                 if (!ctx->first_sample_clock) {
     221           1 :                         ctx->last_frame_ts = ctx->first_sample_clock = sample_time;
     222             :                 }
     223           3 :                 ts = sample_time - ctx->first_sample_clock;
     224           3 :                 gf_filter_pck_set_cts(pck_dst, ts );
     225           3 :                 ctx->last_frame_ts = ts;
     226        1171 :         } else if (ctx->pkt.pts != AV_NOPTS_VALUE) {
     227        1171 :                 AVStream *stream = ctx->demuxer->streams[ctx->pkt.stream_index];
     228             :                 u64 ts;
     229        1171 :                 if ((stream->first_dts!=AV_NOPTS_VALUE) && (stream->first_dts<0))
     230           0 :                         ts = (ctx->pkt.pts - stream->first_dts) * stream->time_base.num;
     231             :                 else
     232        1171 :                         ts = ctx->pkt.pts * stream->time_base.num;
     233             : 
     234        1171 :                 gf_filter_pck_set_cts(pck_dst, ts );
     235             : 
     236        1171 :                 if (ctx->pkt.dts != AV_NOPTS_VALUE) {
     237        1167 :                         if ((stream->first_dts!=AV_NOPTS_VALUE) && (stream->first_dts<0))
     238           0 :                                 ts = (ctx->pkt.dts - stream->first_dts) * stream->time_base.num;
     239             :                         else
     240        1167 :                                 ts = ctx->pkt.dts * stream->time_base.num;
     241             : 
     242        1167 :                         gf_filter_pck_set_dts(pck_dst, ts);
     243             :                 }
     244             : 
     245        1171 :                 if (ctx->pkt.duration)
     246         928 :                         gf_filter_pck_set_duration(pck_dst, (u32) ctx->pkt.duration);
     247             :         }
     248             : 
     249             :         //fixme: try to identify SAP type 2 and more
     250        1174 :         if (ctx->pkt.flags & AV_PKT_FLAG_KEY)
     251         352 :                 gf_filter_pck_set_sap(pck_dst, GF_FILTER_SAP_1);
     252             : 
     253        1174 :         if (ctx->pkt.flags & AV_PKT_FLAG_CORRUPT)
     254           0 :                 gf_filter_pck_set_corrupted(pck_dst, GF_TRUE);
     255             : 
     256        1174 :         gf_net_get_utc();
     257             : 
     258        1174 :         if (ctx->raw_data) {
     259           6 :                 u64 ntp = gf_net_get_ntp_ts();
     260           6 :                 gf_filter_pck_set_property(pck_dst, GF_PROP_PCK_SENDER_NTP, &PROP_LONGUINT(ntp) );
     261             :         }
     262        1174 :         e = gf_filter_pck_send(pck_dst);
     263        1174 :     ctx->nb_pck_sent++;
     264        1174 :         if (!ctx->raw_pck_out)
     265        1170 :                 av_free_packet(&ctx->pkt);
     266             :         return e;
     267             : }
     268             : 
     269             : 
     270           7 : static GF_Err ffdmx_update_arg(GF_Filter *filter, const char *arg_name, const GF_PropertyValue *arg_val)
     271             : {
     272             :         s32 res;
     273           7 :         GF_FFDemuxCtx *ctx = gf_filter_get_udta(filter);
     274             : 
     275             :         //initial parsing of arguments
     276           7 :         if (!ctx->initialized) {
     277           2 :                 switch (arg_val->type) {
     278           2 :                 case GF_PROP_STRING:
     279           2 :                         res = av_dict_set(&ctx->options, arg_name, arg_val->value.string, 0);
     280           2 :                         if (res<0) {
     281           0 :                                 GF_LOG(GF_LOG_ERROR, ctx->log_class, ("[%s] Failed to set option %s:%s\n", ctx->fname, arg_name, arg_val ));
     282             :                         }
     283             :                         break;
     284           0 :                 default:
     285           0 :                         GF_LOG(GF_LOG_ERROR, ctx->log_class, ("[%s] Failed to set option %s:%s, unrecognized type %d\n", ctx->fname, arg_name, arg_val, arg_val->type ));
     286             :                         return GF_NOT_SUPPORTED;
     287             :                 }
     288             :                 return GF_OK;
     289             :         }
     290             :         //updates of arguments, not supported for ffmpeg demuxers
     291             :         return GF_NOT_SUPPORTED;
     292             : }
     293             : 
     294           7 : GF_Err ffdmx_init_common(GF_Filter *filter, GF_FFDemuxCtx *ctx, Bool is_grab)
     295             : {
     296             :         u32 i;
     297             :         u32 nb_a, nb_v;
     298             : #ifdef FF_SUB_SUPPORT
     299             :         u32 nb_t = 0;
     300             : #endif
     301             :         char szName[50];
     302             : 
     303             : 
     304           7 :         ctx->pids = gf_malloc(sizeof(GF_FilterPid *)*ctx->demuxer->nb_streams);
     305           7 :         memset(ctx->pids, 0, sizeof(GF_FilterPid *)*ctx->demuxer->nb_streams);
     306             : 
     307             :         nb_a = nb_v = 0;
     308          14 :         for (i = 0; i < ctx->demuxer->nb_streams; i++) {
     309             :                 GF_FilterPid *pid=NULL;
     310             :                 Bool force_reframer = GF_FALSE;
     311             :                 Bool expose_ffdec=GF_FALSE;
     312           7 :                 AVStream *stream = ctx->demuxer->streams[i];
     313           7 :                 AVCodecContext *codec = stream->codec;
     314             :                 u32 gpac_codec_id;
     315             : 
     316           7 :                 switch(codec->codec_type) {
     317           1 :                 case AVMEDIA_TYPE_AUDIO:
     318           1 :                         pid = gf_filter_pid_new(filter);
     319           1 :                         if (!pid) return GF_OUT_OF_MEM;
     320           1 :                         gf_filter_pid_set_property(pid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(GF_STREAM_AUDIO) );
     321           1 :                         nb_a++;
     322             :                         sprintf(szName, "audio%d", nb_a);
     323           1 :                         if (ctx->audio_idx<0)
     324           0 :                                 ctx->audio_idx = i;
     325             :                         break;
     326             : 
     327           6 :                 case AVMEDIA_TYPE_VIDEO:
     328           6 :                         pid = gf_filter_pid_new(filter);
     329           6 :                         if (!pid) return GF_OUT_OF_MEM;
     330           6 :                         gf_filter_pid_set_property(pid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(GF_STREAM_VISUAL) );
     331           6 :                         nb_v++;
     332             :                         sprintf(szName, "video%d", nb_v);
     333           6 :                         if (ctx->video_idx<0)
     334           2 :                                 ctx->video_idx = i;
     335             :                         break;
     336             : #ifdef FF_SUB_SUPPORT
     337             :                 case AVMEDIA_TYPE_SUBTITLE:
     338             :                         pid = gf_filter_pid_new(filter);
     339             :                         if (!pid) return GF_OUT_OF_MEM;
     340             :                         gf_filter_pid_set_property(pid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(GF_STREAM_TEXT) );
     341             :                         nb_t++;
     342             :                         sprintf(szName, "text%d", nb_t);
     343             :                         break;
     344             : #endif
     345           0 :                 default:
     346           0 :                         sprintf(szName, "ffdmx%d", i+1);
     347             :                         break;
     348             :                 }
     349           7 :                 if (!pid) continue;
     350           7 :                 ctx->pids[i] = pid;
     351           7 :                 gf_filter_pid_set_udta(pid, stream);
     352             : 
     353           7 :                 gf_filter_pid_set_property(pid, GF_PROP_PID_ID, &PROP_UINT(stream->id ? stream->id : i+1) );
     354           7 :                 gf_filter_pid_set_name(pid, szName);
     355             : 
     356           7 :                 if (ctx->raw_data && ctx->sclock) {
     357           1 :                         gf_filter_pid_set_property(pid, GF_PROP_PID_TIMESCALE, &PROP_UINT(1000000) );
     358             :                 } else {
     359           6 :                         gf_filter_pid_set_property(pid, GF_PROP_PID_TIMESCALE, &PROP_UINT(stream->time_base.den) );
     360             :                 }
     361             : 
     362           7 :                 if (!ctx->raw_data) {
     363           5 :                         if (stream->duration>=0)
     364           1 :                                 gf_filter_pid_set_property(pid, GF_PROP_PID_DURATION, &PROP_FRAC64_INT(stream->duration, stream->time_base.den) );
     365           4 :                         else if (ctx->demuxer->duration>=0)
     366           4 :                                 gf_filter_pid_set_property(pid, GF_PROP_PID_DURATION, &PROP_FRAC64_INT(ctx->demuxer->duration, AV_TIME_BASE) );
     367             : 
     368           5 :                         if ((stream->first_dts!=AV_NOPTS_VALUE) && (stream->first_dts<0))
     369           0 :                                 gf_filter_pid_set_property(pid, GF_PROP_PID_DELAY, &PROP_LONGSINT( stream->first_dts) );
     370             :                 }
     371             : 
     372           7 :                 if (stream->sample_aspect_ratio.num && stream->sample_aspect_ratio.den)
     373           2 :                         gf_filter_pid_set_property(pid, GF_PROP_PID_SAR, &PROP_FRAC_INT( stream->sample_aspect_ratio.num, stream->sample_aspect_ratio.den ) );
     374             : 
     375           7 :                 if (stream->metadata) {
     376             :                         AVDictionaryEntry *ent=NULL;
     377             :                         while (1) {
     378          12 :                                 ent = av_dict_get(stream->metadata, "", ent, AV_DICT_IGNORE_SUFFIX);
     379           8 :                                 if (!ent) break;
     380             : 
     381             :                                 //we use the same syntax as ffmpeg here
     382           4 :                                 gf_filter_pid_set_property_str(pid, ent->key, &PROP_STRING(ent->value) );
     383             :                         }
     384             :                 }
     385             : 
     386           7 :                 gpac_codec_id = ffmpeg_codecid_to_gpac(codec->codec_id);
     387           7 :                 if (!gpac_codec_id) {
     388           0 :                         gf_filter_pid_set_property(pid, GF_PROP_PID_CODECID, &PROP_UINT(GF_CODECID_FFMPEG) );
     389             :                         expose_ffdec=GF_TRUE;
     390             :                 } else {
     391           7 :                         gf_filter_pid_set_property(pid, GF_PROP_PID_CODECID, &PROP_UINT(gpac_codec_id) );
     392             :                 }
     393             : 
     394           7 :                 if (is_grab)
     395           2 :                         gf_filter_pid_set_property(pid, GF_PROP_PID_RAWGRAB, &PROP_BOOL(GF_TRUE) );
     396           5 :                 else if (ctx->demuxer->iformat) {
     397           5 :                         if ((ctx->demuxer->iformat->flags & AVFMT_SEEK_TO_PTS) || ctx->demuxer->iformat->read_seek)
     398           4 :                                 gf_filter_pid_set_property(pid, GF_PROP_PID_PLAYBACK_MODE, &PROP_UINT(GF_PLAYBACK_MODE_FASTFORWARD ) );
     399             :                 }
     400             : 
     401             :                 //force reframer for the following formats if no DSI is found
     402           7 :                 if (!codec->extradata_size) {
     403           4 :                         switch (gpac_codec_id) {
     404           1 :                         case GF_CODECID_AC3:
     405             :                         case GF_CODECID_AAC_MPEG4:
     406             :                         case GF_CODECID_AAC_MPEG2_MP:
     407             :                         case GF_CODECID_AAC_MPEG2_LCP:
     408             :                         case GF_CODECID_AAC_MPEG2_SSRP:
     409             :                         case GF_CODECID_AVC:
     410             :                         case GF_CODECID_HEVC:
     411             :                         case GF_CODECID_AV1:
     412             :                                 force_reframer = GF_TRUE;
     413           1 :                                 break;
     414             :                         }
     415             :                 }
     416           7 :                 if (expose_ffdec) {
     417           0 :                         const char *cname = avcodec_get_name(codec->codec_id);
     418           0 :                         gf_filter_pid_set_property(pid, GF_FFMPEG_DECODER_CONFIG, &PROP_POINTER( (void*)codec ) );
     419             : 
     420           0 :                         if (cname)
     421           0 :                                 gf_filter_pid_set_property_str(pid, "ffmpeg:codec", &PROP_STRING(cname ) );
     422           7 :                 } else if (codec->extradata_size) {
     423             : 
     424             :                         //avc/hevc read by ffmpeg is still in annex B format
     425           3 :                         if (ctx->demuxer->iformat) {
     426           3 :                                 if (!strcmp(ctx->demuxer->iformat->name, "h264") || !strcmp(ctx->demuxer->iformat->name, "hevc")) {
     427             :                                         force_reframer = GF_TRUE;
     428             :                                 }
     429             :                         }
     430             : 
     431           3 :                         if (!force_reframer) {
     432             :                                 //expose as const data
     433           3 :                                 gf_filter_pid_set_property(pid, GF_PROP_PID_DECODER_CONFIG, &PROP_CONST_DATA( (char *)codec->extradata, codec->extradata_size) );
     434             :                         }
     435             :                 }
     436             : 
     437           7 :                 if (force_reframer) {
     438           1 :                         gf_filter_pid_set_property(pid, GF_PROP_PID_UNFRAMED, &PROP_BOOL(GF_TRUE) );
     439             :                 }
     440             : 
     441             : 
     442           7 :                 if (codec->sample_rate)
     443           1 :                         gf_filter_pid_set_property(pid, GF_PROP_PID_SAMPLE_RATE, &PROP_UINT( codec->sample_rate ) );
     444           7 :                 if (codec->frame_size)
     445           1 :                         gf_filter_pid_set_property(pid, GF_PROP_PID_SAMPLES_PER_FRAME, &PROP_UINT( codec->frame_size ) );
     446           7 :                 if (codec->channels)
     447           1 :                         gf_filter_pid_set_property(pid, GF_PROP_PID_NUM_CHANNELS, &PROP_UINT( codec->channels ) );
     448             : 
     449           7 :                 if (codec->width)
     450           6 :                         gf_filter_pid_set_property(pid, GF_PROP_PID_WIDTH, &PROP_UINT( codec->width ) );
     451           7 :                 if (codec->height)
     452           6 :                         gf_filter_pid_set_property(pid, GF_PROP_PID_HEIGHT, &PROP_UINT( codec->height ) );
     453             : #if LIBAVCODEC_VERSION_MAJOR >= 58
     454             :                 if (codec->framerate.num && codec->framerate.den)
     455             :                         gf_filter_pid_set_property(pid, GF_PROP_PID_FPS, &PROP_FRAC_INT( codec->framerate.num, codec->framerate.den ) );
     456             : #endif
     457             : 
     458           7 :                 if (codec->field_order>AV_FIELD_PROGRESSIVE)
     459           0 :                         gf_filter_pid_set_property(pid, GF_PROP_PID_INTERLACED, &PROP_BOOL(GF_TRUE) );
     460             : 
     461           7 :                 if ((codec->codec_type==AVMEDIA_TYPE_VIDEO)
     462           6 :                         && (codec->pix_fmt || ((codec->codec_id==AV_CODEC_ID_RAWVIDEO) && codec->codec_tag))
     463             :                 ) {
     464           3 :                         Bool is_full_range = GF_FALSE;
     465             :                         u32 pfmt = 0;
     466             : 
     467           3 :                         if (codec->pix_fmt) {
     468           3 :                                 pfmt = ffmpeg_pixfmt_to_gpac(codec->pix_fmt);
     469           3 :                                 is_full_range = ffmpeg_pixfmt_is_fullrange(codec->pix_fmt);
     470           0 :                         } else if (codec->codec_tag) {
     471           0 :                                 pfmt = ffmpeg_pixfmt_from_codec_tag(codec->codec_tag, &is_full_range);
     472             :                         }
     473             : 
     474           3 :                         if (!pfmt) {
     475           0 :                                 GF_LOG(GF_LOG_WARNING, ctx->log_class, ("[%s] Unsupported pixel format %d\n", ctx->fname, codec->pix_fmt));
     476             :                         } else {
     477           3 :                                 gf_filter_pid_set_property(pid, GF_PROP_PID_PIXFMT, &PROP_UINT( pfmt) );
     478           3 :                                 if (is_full_range)
     479           0 :                                         gf_filter_pid_set_property(pid, GF_PROP_PID_COLR_RANGE, &PROP_BOOL( GF_TRUE ) );
     480             :                         }
     481             :                 }
     482             : 
     483             : 
     484           7 :                 if (codec->sample_fmt>0) {
     485             :                         u32 sfmt = 0;
     486           1 :                         switch (codec->sample_fmt) {
     487             :                         case AV_SAMPLE_FMT_U8: sfmt = GF_AUDIO_FMT_U8; break;
     488           0 :                         case AV_SAMPLE_FMT_S16: sfmt = GF_AUDIO_FMT_S16; break;
     489           0 :                         case AV_SAMPLE_FMT_S32: sfmt = GF_AUDIO_FMT_S32; break;
     490           0 :                         case AV_SAMPLE_FMT_FLT: sfmt = GF_AUDIO_FMT_FLT; break;
     491           0 :                         case AV_SAMPLE_FMT_DBL: sfmt = GF_AUDIO_FMT_DBL; break;
     492           0 :                         case AV_SAMPLE_FMT_U8P: sfmt = GF_AUDIO_FMT_U8P; break;
     493           0 :                         case AV_SAMPLE_FMT_S16P: sfmt = GF_AUDIO_FMT_S16P; break;
     494           0 :                         case AV_SAMPLE_FMT_S32P: sfmt = GF_AUDIO_FMT_S32P; break;
     495           1 :                         case AV_SAMPLE_FMT_FLTP: sfmt = GF_AUDIO_FMT_FLTP; break;
     496           0 :                         case AV_SAMPLE_FMT_DBLP: sfmt = GF_AUDIO_FMT_DBLP; break;
     497           0 :                         default:
     498           0 :                                 GF_LOG(GF_LOG_WARNING, ctx->log_class, ("[%s] Unsupported sample format %d\n", ctx->fname, codec->sample_fmt));
     499             :                         }
     500           1 :                         gf_filter_pid_set_property(pid, GF_PROP_PID_AUDIO_FORMAT, &PROP_UINT( sfmt) );
     501             :                 }
     502             : 
     503           7 :                 if (codec->bit_rate)
     504           1 :                         gf_filter_pid_set_property(pid, GF_PROP_PID_BITRATE, &PROP_UINT( (u32) codec->bit_rate ) );
     505             : 
     506           7 :                 gf_filter_pid_set_property(pid, GF_PROP_PID_URL, &PROP_STRING(ctx->demuxer->filename));
     507             :         }
     508             : 
     509           7 :         if (!nb_a && !nb_v
     510             : #ifdef FF_SUB_SUPPORT
     511             :                 && !nb_t
     512             : #endif
     513             :         )
     514             :                 return GF_NOT_SUPPORTED;
     515             : 
     516           7 :         return GF_OK;
     517             : }
     518             : 
     519          27 : static int ffavio_read_packet(void *opaque, uint8_t *buf, int buf_size)
     520             : {
     521             :         GF_FFDemuxCtx *ctx = (GF_FFDemuxCtx *)opaque;
     522          27 :         return (int) gf_fread(buf, buf_size, ctx->gfio);
     523             : }
     524             : 
     525           4 : static int64_t ffavio_seek(void *opaque, int64_t offset, int whence)
     526             : {
     527             :         GF_FFDemuxCtx *ctx = (GF_FFDemuxCtx *)opaque;
     528           4 :         if (whence==AVSEEK_SIZE) {
     529           4 :                 u64 pos = gf_ftell(ctx->gfio);
     530           4 :                 u64 size = gf_fsize(ctx->gfio);
     531           4 :                 gf_fseek(ctx->gfio, pos, SEEK_SET);
     532           4 :                 return size;
     533             :         }
     534           0 :         return (int64_t) gf_fseek(ctx->gfio, offset, whence);
     535             : }
     536             : 
     537           5 : static GF_Err ffdmx_initialize(GF_Filter *filter)
     538             : {
     539           5 :         GF_FFDemuxCtx *ctx = gf_filter_get_udta(filter);
     540             :         GF_Err e;
     541             :         s32 res;
     542             :         char *ext;
     543             :         const char *url;
     544             :         AVInputFormat *av_in = NULL;
     545           5 :         ctx->fname = "FFDmx";
     546           5 :         ctx->log_class = GF_LOG_CONTAINER;
     547             : 
     548           5 :         ffmpeg_setup_logs(ctx->log_class);
     549             : 
     550           5 :         ctx->initialized = GF_TRUE;
     551             : #ifdef GPAC_ENABLE_COVERAGE
     552           5 :         if (gf_sys_is_cov_mode()) {
     553           5 :                 ffdmx_update_arg(filter, NULL, NULL);
     554             :         }
     555             : #endif
     556           5 :         if (!ctx->src) {
     557           0 :                 GF_LOG(GF_LOG_ERROR, ctx->log_class, ("[%s] Missing file name, cannot open\n", ctx->fname));
     558             :                 return GF_SERVICE_ERROR;
     559             :         }
     560             :         /*some extensions not supported by ffmpeg, overload input format*/
     561           5 :         ext = strrchr(ctx->src, '.');
     562           5 :         if (ext) {
     563           4 :                 if (!stricmp(ext+1, "cmp")) av_in = av_find_input_format("m4v");
     564             :         }
     565             : 
     566           5 :         GF_LOG(GF_LOG_DEBUG, ctx->log_class, ("[%s] opening file %s - av_in %08x\n", ctx->fname, ctx->src, av_in));
     567             : 
     568           5 :         ctx->demuxer = avformat_alloc_context();
     569           5 :         ffmpeg_set_mx_dmx_flags(ctx->options, ctx->demuxer);
     570             : 
     571           5 :         url = ctx->src;
     572           5 :         if (!strncmp(ctx->src, "gfio://", 7)) {
     573           1 :                 ctx->gfio = gf_fopen(ctx->src, "rb");
     574           1 :                 if (!ctx->gfio) {
     575           0 :                         GF_LOG(GF_LOG_ERROR, ctx->log_class, ("[%s] Failed to open %s\n", ctx->fname, ctx->src));
     576             :                         return GF_URL_ERROR;
     577             :                 }
     578           1 :                 ctx->avio_ctx_buffer = av_malloc(ctx->block_size);
     579           1 :                 if (!ctx->avio_ctx_buffer) {
     580             :                         return GF_OUT_OF_MEM;
     581             :                 }
     582           1 :                 ctx->avio_ctx = avio_alloc_context(ctx->avio_ctx_buffer, ctx->block_size,
     583             :                                                                           0, ctx, &ffavio_read_packet, NULL, &ffavio_seek);
     584             : 
     585           1 :                 if (!ctx->avio_ctx) {
     586           0 :                         GF_LOG(GF_LOG_ERROR, ctx->log_class, ("[%s] Failed to create AVIO context for %s\n", ctx->fname, ctx->src));
     587             :                         return GF_OUT_OF_MEM;
     588             :                 }
     589           1 :                 ctx->demuxer->pb = ctx->avio_ctx;
     590           1 :                 url = gf_fileio_translate_url(ctx->src);
     591             :         }
     592             : 
     593           5 :         res = avformat_open_input(&ctx->demuxer, url, av_in, ctx->options ? &ctx->options : NULL);
     594             : 
     595           5 :         switch (res) {
     596             :         case 0:
     597             :                 e = GF_OK;
     598             :                 break;
     599             :         case AVERROR_INVALIDDATA:
     600             :                 e = GF_NON_COMPLIANT_BITSTREAM;
     601             :                 break;
     602             :         case AVERROR_DEMUXER_NOT_FOUND:
     603             :         case -ENOENT:
     604             :                 e = GF_URL_ERROR;
     605             :                 break;
     606             :         case AVERROR_EOF:
     607             :                 e = GF_EOS;
     608             :                 break;
     609             :         default:
     610             :                 e = GF_NOT_SUPPORTED;
     611             :                 break;
     612             :         }
     613             :         if (e) {
     614           0 :                 GF_LOG(GF_LOG_ERROR, ctx->log_class, ("[%s] Fail to open %s - error %s\n", ctx->fname, ctx->src, av_err2str(res) ));
     615           0 :                 avformat_close_input(&ctx->demuxer);
     616           0 :                 avformat_free_context(ctx->demuxer);
     617           0 :                 return e;
     618             :         }
     619             : 
     620             : 
     621           5 :         ffmpeg_report_unused_options(filter, ctx->options);
     622             : 
     623           5 :         res = avformat_find_stream_info(ctx->demuxer, ctx->options ? &ctx->options : NULL);
     624           5 :         if (res <0) {
     625           0 :                 GF_LOG(GF_LOG_ERROR, ctx->log_class, ("[%s] cannot locate streams - error %s\n", ctx->fname, av_err2str(res)));
     626             :                 e = GF_NOT_SUPPORTED;
     627           0 :                 avformat_close_input(&ctx->demuxer);
     628           0 :                 avformat_free_context(ctx->demuxer);
     629           0 :                 return e;
     630             :         }
     631           5 :         GF_LOG(GF_LOG_DEBUG, ctx->log_class, ("[%s] file %s opened - %d streams\n", ctx->fname, ctx->src, ctx->demuxer->nb_streams));
     632             : 
     633           5 :         return ffdmx_init_common(filter, ctx, GF_FALSE);
     634             : }
     635             : 
     636             : 
     637           9 : static Bool ffdmx_process_event(GF_Filter *filter, const GF_FilterEvent *com)
     638             : {
     639           9 :         GF_FFDemuxCtx *ctx = gf_filter_get_udta(filter);
     640             : 
     641           9 :         switch (com->base.type) {
     642           7 :         case GF_FEVT_PLAY:
     643           7 :                 if (!ctx->nb_playing && !ctx->raw_data
     644           5 :                         && (ctx->stop_seen || (com->play.start_range>0))
     645             :                 ) {
     646           0 :                         int res = av_seek_frame(ctx->demuxer, -1, (s64) (AV_TIME_BASE*com->play.start_range), AVSEEK_FLAG_BACKWARD);
     647           0 :                         if (res<0) {
     648           0 :                                 GF_LOG(GF_LOG_WARNING, ctx->log_class, ("[%s] Fail to seek %s to %g - error %s\n", ctx->fname, ctx->src, com->play.start_range, av_err2str(res) ));
     649             :                         }
     650             :                 }
     651           7 :                 ctx->nb_playing++;
     652           7 :                 ctx->stop_seen = GF_FALSE;
     653             :                 //cancel event
     654           7 :                 return GF_TRUE;
     655             : 
     656           2 :         case GF_FEVT_STOP:
     657           2 :                 if (ctx->nb_playing) {
     658           2 :                         ctx->nb_playing--;
     659           2 :                         if (!ctx->nb_playing && ctx->nb_pck_sent)
     660           2 :                                 ctx->stop_seen = GF_TRUE;
     661             :                 }
     662             :                 //cancel event
     663             :                 return GF_TRUE;
     664             : 
     665             :         case GF_FEVT_SET_SPEED:
     666             :                 //cancel event
     667             :                 return GF_TRUE;
     668             :         default:
     669             :                 break;
     670             :         }
     671             :         //by default don't cancel event - to rework once we have downloading in place
     672           0 :         return GF_FALSE;
     673             : }
     674             : 
     675        2938 : static GF_FilterProbeScore ffdmx_probe_url(const char *url, const char *mime)
     676             : {
     677        2938 :         if (!strncmp(url, "video://", 8)) return GF_FPROBE_NOT_SUPPORTED;
     678        2938 :         if (!strncmp(url, "audio://", 8)) return GF_FPROBE_NOT_SUPPORTED;
     679        2938 :         if (!strncmp(url, "av://", 5)) return GF_FPROBE_NOT_SUPPORTED;
     680        2938 :         if (!strncmp(url, "pipe://", 7)) return GF_FPROBE_NOT_SUPPORTED;
     681        2930 :         return GF_FPROBE_MAYBE_SUPPORTED;
     682             : }
     683             : 
     684             : 
     685        3063 : static const char *ffdmx_probe_data(const u8 *data, u32 size, GF_FilterProbeScore *score)
     686             : {
     687             :         int ffscore;
     688             :         AVInputFormat *probe_fmt;
     689             :         AVProbeData pb;
     690             : 
     691        3063 :         av_register_all();
     692             : 
     693             : 
     694             :         memset(&pb, 0, sizeof(AVProbeData));
     695             :         //not setting this crashes some probers in ffmpeg
     696        3063 :         pb.filename = "";
     697        3063 :         if (size <= AVPROBE_PADDING_SIZE) {
     698           4 :                 pb.buf = gf_malloc(sizeof(char)*(size+AVPROBE_PADDING_SIZE) );
     699           4 :                 memcpy(pb.buf, data, sizeof(char)*size);
     700           4 :                 pb.buf_size = size;
     701           4 :                 probe_fmt = av_probe_input_format3(&pb, GF_FALSE, &ffscore);
     702           4 :                 gf_free(pb.buf);
     703             :         } else {
     704        3059 :                 pb.buf =  (char *) data;
     705        3059 :                 pb.buf_size = size - AVPROBE_PADDING_SIZE;
     706        3059 :                 probe_fmt = av_probe_input_format3(&pb, GF_FALSE, &ffscore);
     707             :         }
     708             : 
     709        3063 :         if (!probe_fmt) return NULL;
     710           0 :         if (probe_fmt->mime_type) {
     711             :                 //TODO try to refine based on ffprobe score
     712           0 :                 *score = GF_FPROBE_MAYBE_SUPPORTED;
     713           0 :                 return probe_fmt->mime_type;
     714             :         }
     715             :         return NULL;
     716             : }
     717             : 
     718             : #define OFFS(_n)        #_n, offsetof(GF_FFDemuxCtx, _n)
     719             : 
     720             : static const GF_FilterCapability FFDmxCaps[] =
     721             : {
     722             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
     723             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
     724             : };
     725             : 
     726             : 
     727             : GF_FilterRegister FFDemuxRegister = {
     728             :         .name = "ffdmx",
     729             :         .version=LIBAVFORMAT_IDENT,
     730             :         GF_FS_SET_DESCRIPTION("FFMPEG demuxer")
     731             :         GF_FS_SET_HELP("Demultiplexes files and open protocol using FFMPEG.\n"
     732             :         "See FFMPEG documentation (https://ffmpeg.org/documentation.html) for more details.\n"
     733             :         "To list all supported demuxers for your GPAC build, use `gpac -h ffdmx:*`.\n"
     734             :         "This will list both supported input formats and protocols.\n"
     735             :         "Input protocols are listed with `Description: Input protocol`, and the subclass name identitfes the protocol scheme.\n"
     736             :         "For example, if `ffdmx:rtmp` is listed as input protocol, this means `rtmp://` source URLs are supported.\n"
     737             :         )
     738             :         .private_size = sizeof(GF_FFDemuxCtx),
     739             :         SETCAPS(FFDmxCaps),
     740             :         .initialize = ffdmx_initialize,
     741             :         .finalize = ffdmx_finalize,
     742             :         .process = ffdmx_process,
     743             :         .update_arg = ffdmx_update_arg,
     744             :         .probe_url = ffdmx_probe_url,
     745             :         .probe_data = ffdmx_probe_data,
     746             :         .process_event = ffdmx_process_event,
     747             :         .flags = GF_FS_REG_META,
     748             : };
     749             : 
     750             : 
     751             : static const GF_FilterArgs FFDemuxArgs[] =
     752             : {
     753             :         { OFFS(src), "URL of source content", GF_PROP_NAME, NULL, NULL, 0},
     754             :         { "*", -1, "any possible options defined for AVFormatContext and sub-classes. See `gpac -hx ffdmx` and `gpac -hx ffdmx:*`", GF_PROP_STRING, NULL, NULL, GF_FS_ARG_META},
     755             :         {0}
     756             : };
     757             : 
     758             : 
     759        2877 : const GF_FilterRegister *ffdmx_register(GF_FilterSession *session)
     760             : {
     761        2877 :         ffmpeg_build_register(session, &FFDemuxRegister, FFDemuxArgs, 2, FF_REG_TYPE_DEMUX);
     762        2877 :         return &FFDemuxRegister;
     763             : }
     764             : 
     765             : 
     766             : 
     767           2 : static GF_Err ffavin_initialize(GF_Filter *filter)
     768             : {
     769           2 :         s32 res, i, dev_idx=-1;
     770             :         Bool has_a, has_v;
     771             :         char szPatchedName[1024];
     772             :         const char *dev_name=NULL;
     773             :         const char *default_fmt=NULL;
     774             :         AVInputFormat *dev_fmt=NULL;
     775           2 :         GF_FFDemuxCtx *ctx = gf_filter_get_udta(filter);
     776             :         Bool wants_audio = GF_FALSE;
     777             :         Bool wants_video = GF_FALSE;
     778           2 :         ctx->fname = "FFAVIn";
     779           2 :         ctx->log_class = GF_LOG_MMIO;
     780             : 
     781           2 :         ffmpeg_setup_logs(ctx->log_class);
     782             : 
     783           2 :         avdevice_register_all();
     784           2 :         ctx->initialized = GF_TRUE;
     785           2 :         if (!ctx->src) {
     786           0 :                 GF_LOG(GF_LOG_ERROR, ctx->log_class, ("[%s] No source URL specified, expecting video://, audio:/ or av://\n", ctx->fname));
     787             :                 return GF_SERVICE_ERROR;
     788             :         }
     789           2 :         default_fmt = ctx->fmt;
     790           2 :         if (!default_fmt) {
     791             : #ifdef WIN32
     792             :                 default_fmt = "dshow";
     793             : #elif defined(__DARWIN) || defined(__APPLE__)
     794             :                 default_fmt = "avfoundation";
     795             : #else
     796             :                 default_fmt = "video4linux2";
     797             : #endif
     798             :         }
     799             : 
     800           2 :         if (default_fmt) {
     801           2 :                 dev_fmt = av_find_input_format(default_fmt);
     802           2 :                 if (dev_fmt == NULL) {
     803           0 :                         GF_LOG(GF_LOG_ERROR, ctx->log_class, ("[%s] Cannot find the input format %s\n", ctx->fname, ctx->fmt));
     804             :                 }
     805             : #if LIBAVCODEC_VERSION_MAJOR >= 58
     806             :                 else if (dev_fmt->priv_class->category!=AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT) {
     807             :                         GF_LOG(GF_LOG_ERROR, ctx->log_class, ("[%s]] %s is not a video input device\n", ctx->fname, ctx->fmt));
     808             :                         dev_fmt = NULL;
     809             :                 }
     810             : #else
     811             :                 //not supported for old FFMPE versions
     812             : #endif
     813             :         }
     814             : #if (LIBAVCODEC_VERSION_MAJOR >= 58) && (LIBAVCODEC_VERSION_MINOR>=20)
     815             :         if (!dev_fmt) {
     816             :                 while (1) {
     817             :                         dev_fmt = av_input_video_device_next(dev_fmt);
     818             :                         if (!dev_fmt) break;
     819             :                         if (!dev_fmt || !dev_fmt->priv_class) continue;
     820             :                         if ((dev_fmt->priv_class->category != AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT) && (dev_fmt->priv_class->category != AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT))
     821             :                                 continue;
     822             : 
     823             :                         //listing devices is on its way of implementation in ffmpeg ... for now break at first provider
     824             :                         break;
     825             :                 }
     826             :         }
     827             : #endif
     828           2 :         if (!dev_fmt) {
     829           0 :                 GF_LOG(GF_LOG_ERROR, ctx->log_class, ("[%s] No input format specified\n", ctx->fname, ctx->fmt));
     830             :                 return GF_BAD_PARAM;
     831             :         }
     832             : 
     833           2 :         dev_name = ctx->dev;
     834             : 
     835           2 :         if (!strncmp(ctx->src, "video://", 8)) wants_video = GF_TRUE;
     836           0 :         else if (!strncmp(ctx->src, "audio://", 8)) wants_audio = GF_TRUE;
     837           0 :         else if (!strncmp(ctx->src, "av://", 5)) wants_video = wants_audio = GF_TRUE;
     838             : 
     839           2 :         if (sscanf(dev_name, "%d", &dev_idx)==1) {
     840           0 :                 sprintf(szPatchedName, "%d", dev_idx);
     841           0 :                 if (strcmp(szPatchedName, dev_name)) 
     842           0 :                         dev_idx = -1;
     843             :         } else {
     844           2 :                 dev_idx = -1;
     845             :         }
     846             : 
     847           2 :         szPatchedName[0]=0;
     848             : 
     849             : #if defined(__DARWIN) || defined(__APPLE__)
     850             :         if (!strncmp(dev_name, "screen", 6)) {
     851             :                 strcpy(szPatchedName, "Capture screen ");
     852             :                 strcat(szPatchedName, dev_name+6);
     853             :                 dev_name = (char *) szPatchedName;
     854             :         }
     855             : #endif
     856           2 :         if (!strncmp(dev_fmt->priv_class->class_name, "V4L2", 4) && (dev_idx>=0) ) {
     857           0 :                 if (wants_audio) {
     858             :                         sprintf(szPatchedName, "/dev/video%d:hw:%d", dev_idx, dev_idx);
     859             :                 } else {
     860             :                         sprintf(szPatchedName, "/dev/video%d", dev_idx);
     861             :                 }
     862             :                 dev_name = (char *) szPatchedName;
     863             :         }
     864             : 
     865           2 :         else if (wants_video && wants_audio && (dev_idx>=0)) {
     866             :                 sprintf(szPatchedName, "%d:%d", dev_idx, dev_idx);
     867             :                 dev_name = (char *) szPatchedName;
     868             :         }
     869             : #if defined(__APPLE__) && !defined(GPAC_CONFIG_IOS)
     870             :         else if (!strncmp(dev_fmt->priv_class->class_name, "AVFoundation", 12) && wants_audio) {
     871             :                 if (ctx->dev[0] != ':') {
     872             :                         strcpy(szPatchedName, ":");
     873             :                         strcat(szPatchedName, ctx->dev);
     874             :                         dev_name = (char *) szPatchedName;
     875             :                 }
     876             :         }
     877             : #endif
     878             : 
     879             :         /* Open video */
     880           2 :         ctx->demuxer = avformat_alloc_context();
     881           2 :         ffmpeg_set_mx_dmx_flags(ctx->options, ctx->demuxer);
     882             : 
     883           2 :         res = avformat_open_input(&ctx->demuxer, dev_name, dev_fmt, &ctx->options);
     884           2 :         if ( (res < 0) && !stricmp(ctx->dev, "screen-capture-recorder") ) {
     885           0 :                 GF_LOG(GF_LOG_ERROR, ctx->log_class, ("[%s] Buggy screen capture input (open failed with code %d), retrying without specifying resolution\n", ctx->fname, res));
     886           0 :                 av_dict_set(&ctx->options, "video_size", NULL, 0);
     887           0 :                 res = avformat_open_input(&ctx->demuxer, ctx->dev, dev_fmt, &ctx->options);
     888             :         }
     889             : 
     890           2 :         if (res < 0) {
     891           0 :                 if (ctx->options) {
     892           0 :                         av_dict_free(&ctx->options);
     893           0 :                         GF_LOG(GF_LOG_ERROR, ctx->log_class, ("[%s] Error %d opening input - retrying without options\n", ctx->fname, res));
     894           0 :                         res = avformat_open_input(&ctx->demuxer, dev_name, dev_fmt, NULL);
     895             :                 }
     896           0 :                 if (res<0) {
     897           0 :                         av_dict_set(&ctx->options, "framerate", "30", 0);
     898           0 :                         GF_LOG(GF_LOG_ERROR, ctx->log_class, ("[%s] Error %d opening input - retrying with 30 fps\n", ctx->fname, res));
     899           0 :                         res = avformat_open_input(&ctx->demuxer, dev_name, dev_fmt, &ctx->options);
     900           0 :                         if (res < 0) {
     901           0 :                                 av_dict_set(&ctx->options, "framerate", "25", 0);
     902           0 :                                 GF_LOG(GF_LOG_ERROR, ctx->log_class, ("[%s] Error %d opening input - retrying with 25 fps\n", ctx->fname, res));
     903           0 :                                 res = avformat_open_input(&ctx->demuxer, dev_name, dev_fmt, &ctx->options);
     904             :                         }
     905             :                 }
     906             :         }
     907             : 
     908           2 :         if (res < 0) {
     909           0 :                 GF_LOG(GF_LOG_ERROR, ctx->log_class, ("[%s] Cannot open device %s:%s\n", ctx->fname, dev_fmt->priv_class->class_name, ctx->dev));
     910             :                 return -1;
     911             :         }
     912             : 
     913           2 :         ffmpeg_report_unused_options(filter, ctx->options);
     914             : 
     915           2 :         av_dump_format(ctx->demuxer, 0, ctx->dev, 0);
     916           2 :         ctx->raw_data = GF_TRUE;
     917           2 :         ctx->audio_idx = ctx->video_idx = -1;
     918             : 
     919           2 :         res = avformat_find_stream_info(ctx->demuxer, ctx->options ? &ctx->options : NULL);
     920             : 
     921           2 :         if (res <0) {
     922           0 :                 GF_LOG(GF_LOG_ERROR, ctx->log_class, ("[%s] cannot locate streams - error %s\n", ctx->fname,  av_err2str(res)));
     923             :                 return GF_NOT_SUPPORTED;
     924             :         }
     925             : 
     926             :         //check we have the stream we want
     927             :         has_a = has_v = GF_FALSE;
     928           2 :         for (i = 0; (u32) i < ctx->demuxer->nb_streams; i++) {
     929           2 :                 switch(ctx->demuxer->streams[i]->codec->codec_type) {
     930           0 :                 case AVMEDIA_TYPE_AUDIO:
     931             :                         has_a = GF_TRUE;
     932           0 :                         break;
     933           2 :                 case AVMEDIA_TYPE_VIDEO:
     934             :                         has_v = GF_TRUE;
     935           2 :                         break;
     936             :                 default:
     937             :                         break;
     938             :                 }
     939             :         }
     940           2 :         if (wants_audio && !has_a) {
     941           0 :                 GF_LOG(GF_LOG_ERROR, ctx->log_class, ("[%s] No audio stream in input device\n", ctx->fname));
     942             :                 return GF_NOT_SUPPORTED;
     943             :         }
     944           2 :         if (wants_video && !has_v) {
     945           0 :                 GF_LOG(GF_LOG_ERROR, ctx->log_class, ("[%s] No video stream in input device\n", ctx->fname));
     946             :                 return GF_NOT_SUPPORTED;
     947             :         }
     948           2 :         ctx->probe_frames = ctx->probes;
     949           2 :         if (has_v && ctx->probes) {
     950           1 :                 ctx->probe_times = gf_malloc(sizeof(u64) * ctx->probes);
     951           1 :                 memset(ctx->probe_times, 0, sizeof(u64) * ctx->probes);
     952             :                 //we probe timestamps in either modes because timestamps of first frames are sometimes off
     953           1 :                 ctx->probe_frames = 0;
     954             :         }
     955             : 
     956           2 :         GF_LOG(GF_LOG_INFO, ctx->log_class, ("[%s] device %s:%s opened - %d streams\n", ctx->fname, dev_fmt->priv_class->class_name, ctx->dev, ctx->demuxer->nb_streams));
     957             : 
     958           2 :         ctx->copy_audio = ctx->copy_video = GF_FALSE;
     959           2 :         switch (ctx->copy) {
     960             :         case COPY_NO:
     961             :                 break;
     962           1 :         case COPY_A:
     963           1 :                 ctx->copy_audio = GF_TRUE;
     964           1 :                 break;
     965           0 :         case COPY_V:
     966           0 :                 ctx->copy_video = GF_TRUE;
     967           0 :                 break;
     968           0 :         default:
     969           0 :                 ctx->copy_audio = ctx->copy_video = GF_TRUE;
     970           0 :                 break;
     971             :         }
     972           2 :         if (wants_audio && wants_video) {
     973           0 :                 if (!ctx->copy_audio || !ctx->copy_video) {
     974           0 :                         GF_LOG(GF_LOG_WARNING, ctx->log_class, ("[%s] using muxed capture av:// without copy on %s, this might introduce packet losses due to blocking modes or delayed consumption of the frames. If experiencing problems, either set [-copy]() to `AV` or consider using two filters video:// and audio://\n", ctx->fname, (!ctx->copy_audio && !ctx->copy_video) ? "audio and video streams" : ctx->copy_video ? "audio stream" : "video stream"));
     975             :                 }
     976             :         }
     977           2 :         return ffdmx_init_common(filter, ctx, GF_TRUE);
     978             : }
     979             : 
     980        2941 : static GF_FilterProbeScore ffavin_probe_url(const char *url, const char *mime)
     981             : {
     982        2941 :         if (!strncmp(url, "video://", 8)) return GF_FPROBE_MAYBE_SUPPORTED;
     983        2939 :         if (!strncmp(url, "audio://", 8)) return GF_FPROBE_MAYBE_SUPPORTED;
     984        2939 :         if (!strncmp(url, "av://", 5)) return GF_FPROBE_MAYBE_SUPPORTED;
     985        2939 :         return GF_FPROBE_NOT_SUPPORTED;
     986             : }
     987             : 
     988             : static const GF_FilterCapability FFAVInCaps[] =
     989             : {
     990             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
     991             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL)
     992             :         //do not expose a specific codec ID (eg raw) as some grabbers might give us mjpeg
     993             : };
     994             : 
     995             : GF_FilterRegister FFAVInRegister = {
     996             :         .name = "ffavin",
     997             :         .version = LIBAVDEVICE_IDENT,
     998             :         GF_FS_SET_DESCRIPTION("FFMPEG AV Capture")
     999             :         GF_FS_SET_HELP("Reads from audio/video capture devices using FFMPEG.\n"
    1000             :         "See FFMPEG documentation (https://ffmpeg.org/documentation.html) for more details.\n"
    1001             :         "To list all supported grabbers for your GPAC build, use `gpac -h ffavin:*`.\n"
    1002             :         "\n"
    1003             :         "# Device identification\n"
    1004             :         "Typical classes are `dshow` on windows, `avfoundation` on OSX, `video4linux2` or `x11grab` on linux\n"
    1005             :         "\n"
    1006             :         "Typical device name can be the webcam name:\n"
    1007             :         "- `FaceTime HD Camera` on OSX, device name on windows, `/dev/video0` on linux\n"
    1008             :         "- `screen-capture-recorder`, see http://screencapturer.sf.net/ on windows\n"
    1009             :         "- `Capture screen 0` on OSX (0=first screen), or `screenN` for short\n"
    1010             :         "- X display name (eg `:0.0`) on linux\n"
    1011             :         "\n"
    1012             :         "The general mapping from ffmpeg command line is:\n"
    1013             :         "- ffmpeg `-f` maps to [-fmt]() option\n"
    1014             :         "- ffmpeg `-i` maps to [-dev]() option\n"
    1015             :         "\n"
    1016             :         "EX ffmpeg -f libndi_newtek -i MY_NDI_TEST ...\n"
    1017             :         "EX gpac -i av://:fmt=libndi_newtek:dev=MY_NDI_TEST ...\n"
    1018             :         "\n"
    1019             :         )
    1020             :         .private_size = sizeof(GF_FFDemuxCtx),
    1021             :         SETCAPS(FFAVInCaps),
    1022             :         .initialize = ffavin_initialize,
    1023             :         .finalize = ffdmx_finalize,
    1024             :         .process = ffdmx_process,
    1025             :         .update_arg = ffdmx_update_arg,
    1026             :         .probe_url = ffavin_probe_url,
    1027             :         .process_event = ffdmx_process_event,
    1028             :         .flags = GF_FS_REG_META,
    1029             : };
    1030             : 
    1031             : 
    1032             : static const GF_FilterArgs FFAVInArgs[] =
    1033             : {
    1034             :         { OFFS(src), "url of device, `video://`, `audio://` or `av://`", GF_PROP_STRING, NULL, NULL, 0},
    1035             :         { OFFS(fmt), "name of device class - see filter help. If not set, defaults to first device class", GF_PROP_STRING, NULL, NULL, 0},
    1036             :         { OFFS(dev), "name of device or index of device - see filter help", GF_PROP_STRING, "0", NULL, 0},
    1037             :         { OFFS(copy), "set copy mode of raw frames\n"
    1038             :                 "- N: frames are only forwarded (shared memory, no copy)\n"
    1039             :                 "- A: audio frames are copied, video frames are forwarded\n"
    1040             :                 "- V: video frames are copied, audio frames are forwarded\n"
    1041             :                 "- AV: all frames are copied"
    1042             :                 "", GF_PROP_UINT, "A", "N|A|V|AV", GF_FS_ARG_HINT_ADVANCED},
    1043             :         { OFFS(sclock), "use system clock (us) instead of device timestamp (for buggy devices)", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
    1044             :         { OFFS(probes), "probe a given number of video frames before emitting - this usually helps with bad timing of the first frames", GF_PROP_UINT, "10", "0-100", GF_FS_ARG_HINT_EXPERT},
    1045             :         { OFFS(block_size), "block size used to read file when using avio context", GF_PROP_UINT, "4096", NULL, GF_FS_ARG_HINT_EXPERT},
    1046             :         { "*", -1, "any possible options defined for AVInputFormat and AVFormatContext. See `gpac -hx ffavin` and `gpac -hx ffavin:*`", GF_PROP_STRING, NULL, NULL, GF_FS_ARG_META},
    1047             :         {0}
    1048             : };
    1049             : 
    1050             : 
    1051             : //number of arguments defined above
    1052             : const int FFAVIN_STATIC_ARGS = (sizeof (FFAVInArgs) / sizeof (GF_FilterArgs)) - 1;
    1053             : 
    1054        2877 : const GF_FilterRegister *ffavin_register(GF_FilterSession *session)
    1055             : {
    1056        2877 :         ffmpeg_build_register(session, &FFAVInRegister, FFAVInArgs, FFAVIN_STATIC_ARGS, FF_REG_TYPE_DEV_IN);
    1057        2877 :         return &FFAVInRegister;
    1058             : }
    1059             : 
    1060             : #else
    1061             : 
    1062             : #include <gpac/filters.h>
    1063             : 
    1064             : const GF_FilterRegister *ffdmx_register(GF_FilterSession *session)
    1065             : {
    1066             :         return NULL;
    1067             : }
    1068             : 
    1069             : const GF_FilterRegister *ffavin_register(GF_FilterSession *session)
    1070             : {
    1071             :         return NULL;
    1072             : }
    1073             : #endif

Generated by: LCOV version 1.13