LCOV - code coverage report
Current view: top level - filters - ff_enc.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 630 788 79.9 %
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 2018-2021
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / ffmpeg encode 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             : #include <gpac/bitstream.h>
      28             : #include <gpac/avparse.h>
      29             : 
      30             : #ifdef GPAC_HAS_FFMPEG
      31             : 
      32             : #include "ff_common.h"
      33             : 
      34             : #define ENC_BUF_ALLOC_SAFE      10000
      35             : 
      36             : typedef struct _gf_ffenc_ctx
      37             : {
      38             :         //opts
      39             :         Bool all_intra;
      40             :         char *c;
      41             :         Bool ls;
      42             :         u32 pfmt;
      43             :         GF_Fraction fintra;
      44             :         Bool rc;
      45             : 
      46             :         //internal data
      47             :         Bool initialized;
      48             : 
      49             :         u32 gop_size;
      50             :         u32 target_rate;
      51             : 
      52             :         AVCodecContext *encoder;
      53             :         //encode options
      54             :         AVDictionary *options;
      55             : 
      56             :         GF_FilterPid *in_pid, *out_pid;
      57             :         //media type
      58             :         u32 type;
      59             :         u32 timescale;
      60             : 
      61             :         u32 nb_frames_out, nb_frames_in;
      62             :         u64 time_spent;
      63             : 
      64             :         Bool low_delay;
      65             : 
      66             :         GF_Err (*process)(GF_Filter *filter, struct _gf_ffenc_ctx *ctx);
      67             :         //gpac one
      68             :         u32 codecid;
      69             :         //done flushing encoder (eg sent NULL frames)
      70             :         u32 flush_done;
      71             :         //frame used by both video and audio encoder
      72             :         AVFrame *frame;
      73             : 
      74             :         //encoding buffer - we allocate ENC_BUF_ALLOC_SAFE+WxH for the video (some image codecs in ffmpeg require more than WxH for headers), ENC_BUF_ALLOC_SAFE+nb_ch*samplerate for the audio
      75             :         //this should be enough to hold any lossless compression formats
      76             :         char *enc_buffer;
      77             :         u32 enc_buffer_size;
      78             : 
      79             :         Bool init_cts_setup;
      80             : 
      81             :         //video state
      82             :         u32 width, height, stride, stride_uv, nb_planes, uv_height;
      83             :         //ffmpeg one
      84             :         enum AVPixelFormat pixel_fmt;
      85             :         u64 cts_first_frame_plus_one;
      86             : 
      87             :         //audio state
      88             :         u32 channels, sample_rate, channel_layout, bytes_per_sample;
      89             :         //ffmpeg one
      90             :         u32 sample_fmt;
      91             :         //we store input audio frame in this buffer until we have enough data for one encoder frame
      92             :         //we also store the remaining of a consumed frame here, so that input packet is realeased ASAP
      93             :         char *audio_buffer;
      94             :         u32 audio_buffer_size;
      95             :         u32 samples_in_audio_buffer;
      96             :         //cts of first byte in frame
      97             :         u64 first_byte_cts;
      98             :         Bool planar_audio;
      99             : 
     100             :         //shift of TS - ffmpeg may give pkt-> PTS < frame->PTS to indicate discard samples
     101             :         //we convert back to frame PTS but signal discard samples at the PID level
     102             :         s64 ts_shift;
     103             : 
     104             :         GF_List *src_packets;
     105             : 
     106             :         GF_BitStream *sdbs;
     107             : 
     108             :         Bool reconfig_pending;
     109             :         Bool infmt_negociate;
     110             :         Bool remap_ts;
     111             :         Bool force_reconfig;
     112             : 
     113             :         u32 dsi_crc;
     114             : 
     115             :         u32 gpac_pixel_fmt;
     116             :         u32 gpac_audio_fmt;
     117             : 
     118             :         Bool fintra_setup;
     119             :         u64 orig_ts;
     120             :         u32 nb_forced;
     121             : 
     122             :         AVCodec *force_codec;
     123             : 
     124             :         //we don't forward media delay, we directly offset CTS/DTS
     125             :         s64 in_tk_delay;
     126             : 
     127             :         Bool discontunity;
     128             :         GF_FilterPacket *disc_pck_ref;
     129             : } GF_FFEncodeCtx;
     130             : 
     131             : static GF_Err ffenc_configure_pid_ex(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove, Bool is_force_reconf);
     132             : 
     133             : static const GF_FilterCapability FFEncodeCapsVideo[] =
     134             : {
     135             :         CAP_UINT(GF_CAPS_INPUT_OUTPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
     136             :         CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_CODECID, GF_CODECID_RAW),
     137             :         CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
     138             :         CAP_UINT(GF_CAPS_OUTPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_RAW),
     139             :         CAP_BOOL(GF_CAPS_OUTPUT_EXCLUDED, GF_PROP_PID_TILE_BASE, GF_TRUE)
     140             : };
     141             : 
     142             : static const GF_FilterCapability FFEncodeCapsAudio[] =
     143             : {
     144             :         CAP_UINT(GF_CAPS_INPUT_OUTPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
     145             :         CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
     146             :         CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_CODECID, GF_CODECID_RAW),
     147             :         CAP_UINT(GF_CAPS_OUTPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_RAW)
     148             : };
     149             : 
     150          14 : static void ffenc_override_caps(GF_Filter *filter, u32 media_type)
     151             : {
     152          14 :         if (media_type==AVMEDIA_TYPE_AUDIO) {
     153           4 :                 gf_filter_override_caps(filter, FFEncodeCapsAudio, GF_ARRAY_LENGTH(FFEncodeCapsAudio) );
     154             :         } else {
     155          10 :                 gf_filter_override_caps(filter, FFEncodeCapsVideo, GF_ARRAY_LENGTH(FFEncodeCapsVideo) );
     156             :         }
     157          14 : }
     158             : 
     159          32 : static GF_Err ffenc_initialize(GF_Filter *filter)
     160             : {
     161             :         u32 codec_id;
     162          32 :         GF_FFEncodeCtx *ctx = (GF_FFEncodeCtx *) gf_filter_get_udta(filter);
     163          32 :         ctx->initialized = GF_TRUE;
     164          32 :         ctx->src_packets = gf_list_new();
     165          32 :         ctx->sdbs = gf_bs_new((u8*)ctx, 1, GF_BITSTREAM_READ);
     166             : 
     167          32 :         ffmpeg_setup_logs(GF_LOG_CODEC);
     168             : 
     169             : 
     170          32 :         if (!ctx->c) return GF_OK;
     171             : 
     172             :         //first look by name, to handle cases such as "aac" vs "vo_aacenc"
     173          14 :         ctx->force_codec = avcodec_find_encoder_by_name(ctx->c);
     174          14 :         if (ctx->force_codec) {
     175           4 :                 ffenc_override_caps(filter, ctx->force_codec->type);
     176           4 :                 return GF_OK;
     177             :         }
     178             :         //then look by codec ID
     179          10 :         codec_id = gf_codecid_parse(ctx->c);
     180          10 :         if (codec_id!=GF_CODECID_NONE) {
     181          10 :                 ctx->force_codec = avcodec_find_encoder(ffmpeg_codecid_from_gpac(codec_id, NULL) );
     182             :         }
     183          10 :         if (!ctx->force_codec) return GF_NOT_SUPPORTED;
     184          10 :         ffenc_override_caps(filter, ctx->force_codec->type);
     185          10 :         ctx->force_codec = NULL;
     186          10 :         return GF_OK;
     187             : }
     188             : 
     189          32 : static void ffenc_finalize(GF_Filter *filter)
     190             : {
     191          32 :         GF_FFEncodeCtx *ctx = (GF_FFEncodeCtx *) gf_filter_get_udta(filter);
     192          32 :         if (ctx->options) av_dict_free(&ctx->options);
     193          32 :         if (ctx->frame) av_frame_free(&ctx->frame);
     194          32 :         if (ctx->enc_buffer) gf_free(ctx->enc_buffer);
     195          32 :         if (ctx->audio_buffer) gf_free(ctx->audio_buffer);
     196             : 
     197          35 :         while (gf_list_count(ctx->src_packets)) {
     198           3 :                 GF_FilterPacket *pck = gf_list_pop_back(ctx->src_packets);
     199           3 :                 gf_filter_pck_unref(pck);
     200             :         }
     201          32 :         gf_list_del(ctx->src_packets);
     202             : 
     203          32 :         if (ctx->encoder) {
     204          32 :                 avcodec_free_context(&ctx->encoder);
     205             :         }
     206          32 :         if (ctx->sdbs) gf_bs_del(ctx->sdbs);
     207          32 :         return;
     208             : }
     209             : 
     210          92 : static void ffenc_copy_pid_props(GF_FFEncodeCtx *ctx)
     211             : {
     212             :         //copy properties at init or reconfig
     213          92 :         gf_filter_pid_copy_properties(ctx->out_pid, ctx->in_pid);
     214          92 :         gf_filter_pid_set_property(ctx->out_pid, GF_PROP_PID_DECODER_CONFIG, NULL);
     215          92 :         gf_filter_pid_set_property(ctx->out_pid, GF_PROP_PID_CODECID, &PROP_UINT(ctx->codecid) );
     216          92 :         gf_filter_pid_set_property(ctx->out_pid, GF_PROP_PID_ISOM_STSD_TEMPLATE, NULL);
     217             : 
     218          92 :         switch (ctx->codecid) {
     219          32 :         case GF_CODECID_AVC:
     220             :         case GF_CODECID_HEVC:
     221             :         case GF_CODECID_MPEG4_PART2:
     222          32 :                 gf_filter_pid_set_property(ctx->out_pid, GF_PROP_PID_UNFRAMED, &PROP_BOOL(GF_TRUE) );
     223          32 :                 gf_filter_pid_set_property(ctx->out_pid, GF_PROP_PID_UNFRAMED_FULL_AU, &PROP_BOOL(GF_TRUE) );
     224          32 :                 break;
     225          60 :         default:
     226          60 :                 if (ctx->encoder && ctx->encoder->extradata_size && ctx->encoder->extradata) {
     227           4 :                         gf_filter_pid_set_property(ctx->out_pid, GF_PROP_PID_DECODER_CONFIG, &PROP_DATA(ctx->encoder->extradata, ctx->encoder->extradata_size) );
     228             :                 }
     229             :                 break;
     230             :         }
     231             :         //if target rate is not known yet (encoder default and we setup an adaptation chain for the PID), signal a default 100k
     232             :         //this prevents a warning in the dasher complaining that no rate is set, unaware that we will reconfigure the PID before sending data
     233          92 :         gf_filter_pid_set_property(ctx->out_pid, GF_PROP_PID_BITRATE, &PROP_UINT(ctx->target_rate ? ctx->target_rate : 100000));
     234             : 
     235          92 :         gf_filter_pid_set_property(ctx->out_pid, GF_PROP_PID_TARGET_RATE, NULL);
     236             : 
     237          92 :         if (ctx->ts_shift) {
     238           0 :                 gf_filter_pid_set_property(ctx->out_pid, GF_PROP_PID_DELAY, &PROP_LONGSINT( - ctx->ts_shift) );
     239             :         } else {
     240          92 :                 gf_filter_pid_set_property(ctx->out_pid, GF_PROP_PID_DELAY, NULL);
     241             :         }
     242          92 :         if (ctx->width && ctx->height) {
     243          44 :                 gf_filter_pid_set_property(ctx->out_pid, GF_PROP_PID_HAS_SYNC, ctx->all_intra ? NULL : &PROP_BOOL(GF_TRUE) );
     244             :         }
     245          92 : }
     246             : 
     247       10427 : static u64 ffenc_get_cts(GF_FFEncodeCtx *ctx, GF_FilterPacket *pck)
     248             : {
     249       10427 :         u64 ts = gf_filter_pck_get_cts(pck);
     250       10427 :         if ((ctx->in_tk_delay<0) && (ts < (u64) -ctx->in_tk_delay)) {
     251           0 :                 GF_LOG(GF_LOG_WARNING, GF_LOG_CODEC, ("[FFEnc] Negative input TS \n"));
     252             :                 return 0;
     253             :         }
     254       10427 :         return ts + ctx->in_tk_delay;
     255             : }
     256             : 
     257             : //TODO add more feedback
     258        2806 : static void ffenc_log_video(GF_Filter *filter, struct _gf_ffenc_ctx *ctx, AVPacket *pkt, Bool do_reporting)
     259             : {
     260             :         Double fps=0;
     261             :         s32 q=-1;
     262             :         u8 pictype=0;
     263             : #if LIBAVCODEC_VERSION_MAJOR >= 58
     264             :         u64 errors[10];
     265             :         u32 i;
     266             :         u8 nb_errors = 0;
     267             : #endif
     268             :         const char *ptype = "U";
     269             : 
     270        2806 :         if (!ctx->ls && !do_reporting) return;
     271             : 
     272             : 
     273             : #if LIBAVCODEC_VERSION_MAJOR >= 58
     274             :         u32 sq_size;
     275             :         u8 *side_q = av_packet_get_side_data(pkt, AV_PKT_DATA_QUALITY_STATS, &sq_size);
     276             :         if (side_q) {
     277             :                 gf_bs_reassign_buffer(ctx->sdbs, side_q, sq_size);
     278             :                 q = gf_bs_read_u32_le(ctx->sdbs);
     279             :                 pictype = gf_bs_read_u8(ctx->sdbs);
     280             :                 nb_errors = gf_bs_read_u8(ctx->sdbs);
     281             :                 /*res*/gf_bs_read_u16(ctx->sdbs);
     282             :                 if (nb_errors>10) nb_errors = 10;
     283             :                 for (i=0; i<nb_errors; i++) {
     284             :                         errors[i] = gf_bs_read_u64_le(ctx->sdbs);
     285             :                 }
     286             :         }
     287             : #endif
     288         262 :         if (ctx->time_spent) {
     289         262 :                 fps = ctx->nb_frames_out;
     290         262 :                 fps *= 1000000;
     291         262 :                 fps /= ctx->time_spent;
     292             :         }
     293             :         switch (pictype) {
     294             :         case AV_PICTURE_TYPE_I: ptype = "I"; break;
     295             :         case AV_PICTURE_TYPE_P: ptype = "P"; break;
     296             :         case AV_PICTURE_TYPE_S: ptype = "S"; break;
     297             :         case AV_PICTURE_TYPE_SP: ptype = "SP"; break;
     298             :         case AV_PICTURE_TYPE_B: ptype = "B"; break;
     299             :         case AV_PICTURE_TYPE_BI: ptype = "B"; break;
     300             :         }
     301             : 
     302         262 :         if (ctx->ls) {
     303         262 :                 fprintf(stderr, "[FFEnc] FPS %.02f F %d DTS "LLD" CTS "LLD" Q %02.02f PT %s (F_in %d)", fps, ctx->nb_frames_out, pkt->dts+ctx->ts_shift, pkt->pts+ctx->ts_shift, ((Double)q) /  FF_QP2LAMBDA, ptype, ctx->nb_frames_in);
     304             : #if LIBAVCODEC_VERSION_MAJOR >= 58
     305             :                 if (nb_errors) {
     306             :                         fprintf(stderr, "PSNR");
     307             :                         for (i=0; i<nb_errors; i++) {
     308             :                                 Double psnr = (Double) errors[i];
     309             :                                 psnr /= ctx->width * ctx->height * 255.0 * 255.0;
     310             :                                 fprintf(stderr, " %02.02f", psnr);
     311             :                         }
     312             :                 }
     313             : #endif
     314         262 :                 fprintf(stderr, "\r");
     315             :         }
     316             : 
     317         262 :         if (do_reporting) {
     318             :                 char szStatus[1024];
     319           0 :                 sprintf(szStatus, "[FFEnc] FPS %.02f F %d DTS "LLD" CTS "LLD" Q %02.02f PT %s (F_in %d)", fps, ctx->nb_frames_out, pkt->dts+ctx->ts_shift, pkt->pts+ctx->ts_shift, ((Double)q) /  FF_QP2LAMBDA, ptype, ctx->nb_frames_in);
     320           0 :                 gf_filter_update_status(filter, -1, szStatus);
     321             :         }
     322             : }
     323             : 
     324        3141 : static GF_Err ffenc_process_video(GF_Filter *filter, struct _gf_ffenc_ctx *ctx)
     325             : {
     326             :         AVPacket pkt;
     327             :         s32 gotpck;
     328             :         const char *data = NULL;
     329        3141 :         u32 size=0, i, count, offset, to_copy;
     330             :         s32 res;
     331             :         u64 now;
     332             :         u8 *output;
     333             :         u32 force_intra = 0;
     334             :         Bool insert_jp2c = GF_FALSE;
     335             :         GF_FilterPacket *dst_pck, *src_pck;
     336             :         GF_FilterPacket *pck;
     337             :         const GF_PropertyValue *p;
     338             : 
     339        3141 :         if (!ctx->in_pid) return GF_EOS;
     340             : 
     341        3141 :         pck = gf_filter_pid_get_packet(ctx->in_pid);
     342             : 
     343        3141 :         if (!ctx->encoder) {
     344           4 :                 if (ctx->infmt_negociate) return GF_OK;
     345             : 
     346           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[FFEnc] encoder reconfiguration failed, aborting stream\n"));
     347           0 :                 gf_filter_pid_set_eos(ctx->out_pid);
     348           0 :                 return GF_EOS;
     349             :         }
     350             : 
     351        3137 :         if (!pck) {
     352         331 :                 if (! gf_filter_pid_is_eos(ctx->in_pid)) return GF_OK;
     353         331 :                 if (ctx->flush_done) return GF_OK;
     354             :         }
     355             : 
     356        3129 :         if (ctx->reconfig_pending) pck = NULL;
     357             : 
     358        3129 :         if (pck) data = gf_filter_pck_get_data(pck, &size);
     359             : 
     360        3129 :         av_init_packet(&pkt);
     361        3129 :         pkt.data = (uint8_t*)ctx->enc_buffer;
     362        3129 :         pkt.size = ctx->enc_buffer_size;
     363             : 
     364        3129 :         ctx->frame->pict_type = 0;
     365        3129 :         ctx->frame->width = ctx->width;
     366        3129 :         ctx->frame->height = ctx->height;
     367        3129 :         ctx->frame->format = ctx->pixel_fmt;
     368             : 
     369        3129 :         ctx->frame->pict_type = AV_PICTURE_TYPE_NONE;
     370             : 
     371             :         //force picture type
     372        3129 :         if (ctx->all_intra)
     373           0 :                 ctx->frame->pict_type = AV_PICTURE_TYPE_I;
     374             : 
     375             :         //if PCK_FILENUM is set on input, this is a file boundary, force IDR sync
     376        3129 :         if (pck && gf_filter_pck_get_property(pck, GF_PROP_PCK_FILENUM)) {
     377             :                 force_intra = 2;
     378             :         }
     379             :         //if CUE_START is set on input, this is a segment boundary, force IDR sync
     380        3129 :         p = pck ? gf_filter_pck_get_property(pck, GF_PROP_PCK_CUE_START) : NULL;
     381        2806 :         if (p && p->value.boolean) {
     382             :                 force_intra = 2;
     383             :         }
     384             : 
     385             :         //check if we need to force a closed gop
     386        3129 :         if (pck && (ctx->fintra.den && (ctx->fintra.num>0)) && !ctx->force_reconfig) {
     387        1538 :                 u64 cts = ffenc_get_cts(ctx, pck);
     388        1538 :                 if (!ctx->fintra_setup) {
     389           8 :                         ctx->fintra_setup = GF_TRUE;
     390           8 :                         ctx->orig_ts = cts;
     391             :                         force_intra = 1;
     392           8 :                         ctx->nb_forced=1;
     393        1530 :                 } else if (cts < ctx->orig_ts) {
     394           0 :                         GF_LOG(GF_LOG_WARNING, GF_LOG_CODEC, ("[FFEnc] timestamps not increasing monotonuously, reseting forced intra state !\n"));
     395           0 :                         ctx->orig_ts = cts;
     396             :                         force_intra = 1;
     397           0 :                         ctx->nb_forced=1;
     398             :                 } else {
     399        1530 :                         u64 ts_diff = cts - ctx->orig_ts;
     400        1530 :                         if (ts_diff * ctx->fintra.den >= ctx->nb_forced * ctx->fintra.num * ctx->timescale) {
     401             :                                 force_intra = 1;
     402          54 :                                 ctx->nb_forced++;
     403          54 :                                 GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("[FFEnc] Forcing IDR at frame %d (CTS %d / %d)\n", ctx->nb_frames_in, cts, ctx->timescale));
     404             :                         }
     405             :                 }
     406             :         }
     407             : 
     408        3067 :         if (force_intra) {
     409             :                 //file switch we force a full reset to force injecting xPS in the stream
     410             :                 //we could also inject them manually but we don't have them !!
     411          62 :                 if ((ctx->rc && ctx->nb_frames_in) || (force_intra==2)) {
     412           0 :                         if (!ctx->force_reconfig) {
     413           0 :                                 ctx->reconfig_pending = GF_TRUE;
     414           0 :                                 ctx->force_reconfig = GF_TRUE;
     415           0 :                                 pck = NULL;
     416             :                         } else {
     417           0 :                                 ctx->force_reconfig = GF_FALSE;
     418             :                         }
     419             :                 }
     420          62 :                 ctx->frame->pict_type = AV_PICTURE_TYPE_I;
     421             :         }
     422             : 
     423             : 
     424        3129 :         now = gf_sys_clock_high_res();
     425        3129 :         gotpck = 0;
     426        3129 :         if (pck) {
     427             :                 u32 ilaced;
     428        2806 :                 if (data) {
     429        2621 :                         ctx->frame->data[0] = (u8 *) data;
     430        2621 :                         ctx->frame->linesize[0] = ctx->stride;
     431        2621 :                         if (ctx->nb_planes>1) {
     432        2619 :                                 ctx->frame->data[1] = (u8 *) data + ctx->stride * ctx->height;
     433        2619 :                                 ctx->frame->linesize[1] = ctx->stride_uv ? ctx->stride_uv : ctx->stride/2;
     434        2619 :                                 if (ctx->nb_planes>2) {
     435        2619 :                                         ctx->frame->data[2] = (u8 *) ctx->frame->data[1] + ctx->stride_uv * ctx->height/2;
     436        2619 :                                         ctx->frame->linesize[2] = ctx->frame->linesize[1];
     437             :                                 } else {
     438           0 :                                         ctx->frame->linesize[2] = 0;
     439             :                                 }
     440             :                         } else {
     441           2 :                                 ctx->frame->linesize[1] = 0;
     442             :                         }
     443             :                 } else {
     444             :                         GF_Err e=GF_NOT_SUPPORTED;
     445         185 :                         GF_FilterFrameInterface *frame_ifce = gf_filter_pck_get_frame_interface(pck);
     446         185 :                         if (frame_ifce && frame_ifce->get_plane) {
     447         185 :                                 e = frame_ifce->get_plane(frame_ifce, 0, (const u8 **) &ctx->frame->data[0], &ctx->frame->linesize[0]);
     448         185 :                                 if (!e && (ctx->nb_planes>1)) {
     449         185 :                                         e = frame_ifce->get_plane(frame_ifce, 1, (const u8 **) &ctx->frame->data[1], &ctx->frame->linesize[1]);
     450         185 :                                         if (!e && (ctx->nb_planes>2)) {
     451         185 :                                                 e = frame_ifce->get_plane(frame_ifce, 1, (const u8 **) &ctx->frame->data[2], &ctx->frame->linesize[2]);
     452             :                                         }
     453             :                                 }
     454             :                         }
     455         185 :                         if (e) {
     456           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[FFEnc] Failed to fetch %sframe data: %s\n", frame_ifce ? "hardware " : "", gf_error_to_string(e) ));
     457           0 :                                 gf_filter_pid_drop_packet(ctx->in_pid);
     458           0 :                                 return e;
     459             :                         }
     460             :                 }
     461             : 
     462        2806 :                 ilaced = gf_filter_pck_get_interlaced(pck);
     463        2806 :                 if (!ilaced) {
     464        2806 :                         ctx->frame->interlaced_frame = 0;
     465             :                 } else {
     466           0 :                         ctx->frame->interlaced_frame = 1;
     467           0 :                         ctx->frame->top_field_first = (ilaced==2) ? 1 : 0;
     468             :                 }
     469        2806 :                 ctx->frame->pts = ffenc_get_cts(ctx, pck);
     470        2806 :                 ctx->frame->pkt_duration = gf_filter_pck_get_duration(pck);
     471             : 
     472             : #define SCALE_TS(_ts) if (_ts != GF_FILTER_NO_TS) { _ts *= ctx->encoder->time_base.den; _ts /= ctx->timescale; }
     473             : #define UNSCALE_TS(_ts) if (_ts != AV_NOPTS_VALUE)  { _ts *= ctx->timescale; _ts /= ctx->encoder->time_base.den; }
     474             : #define UNSCALE_DUR(_ts) { _ts *= ctx->timescale; _ts /= ctx->encoder->time_base.den; }      
     475             :         
     476             :                 //store first frame CTS before rescaling, we use it after rescaling the output packet timing to compute CTS-DTS
     477        2806 :                 if (!ctx->cts_first_frame_plus_one) {
     478          24 :                         ctx->cts_first_frame_plus_one = 1 + ctx->frame->pts;
     479             :                 }
     480             : 
     481        2806 :                 if (ctx->remap_ts) {
     482        2803 :                         SCALE_TS(ctx->frame->pts);
     483             : 
     484        2803 :                         SCALE_TS(ctx->frame->pkt_duration);
     485             :                 }
     486             : 
     487        2806 :                 ctx->frame->pkt_dts = ctx->frame->pkt_pts = ctx->frame->pts;
     488        2806 :                 res = avcodec_encode_video2(ctx->encoder, &pkt, ctx->frame, &gotpck);
     489        2806 :                 ctx->nb_frames_in++;
     490             : 
     491             :                 //keep ref to ource properties
     492        2806 :                 gf_filter_pck_ref_props(&pck);
     493        2806 :                 gf_list_add(ctx->src_packets, pck);
     494        2806 :                 if (ctx->discontunity) {
     495           0 :                         ctx->discontunity = GF_FALSE;
     496           0 :                         ctx->disc_pck_ref = pck;
     497             :                 }
     498             : 
     499        2806 :                 gf_filter_pid_drop_packet(ctx->in_pid);
     500             : 
     501        2806 :                 if (ctx->remap_ts) {
     502        2803 :                         UNSCALE_TS(ctx->frame->pts);
     503        2803 :                         UNSCALE_TS(ctx->frame->pkt_duration);
     504             : 
     505        2803 :                         UNSCALE_TS(pkt.dts);
     506        2803 :                         UNSCALE_TS(pkt.pts);
     507        2803 :                         UNSCALE_DUR(pkt.duration);
     508             :                 }
     509             :         } else {
     510         323 :                 res = avcodec_encode_video2(ctx->encoder, &pkt, NULL, &gotpck);
     511         323 :                 if (!gotpck) {
     512             :                         //done flushing encoder while reconfiguring
     513          24 :                         if (ctx->reconfig_pending) {
     514             :                                 GF_Err e;
     515           0 :                                 Bool bck_init_cts = ctx->init_cts_setup;
     516           0 :                                 ctx->reconfig_pending = GF_FALSE;
     517           0 :                                 ctx->force_reconfig = GF_FALSE;
     518           0 :                                 GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[FFEnc] codec flush done, triggering reconfiguration\n"));
     519           0 :                                 avcodec_close(ctx->encoder);
     520           0 :                                 ctx->encoder = NULL;
     521           0 :                                 e = ffenc_configure_pid_ex(filter, ctx->in_pid, GF_FALSE, GF_TRUE);
     522           0 :                                 ctx->init_cts_setup = bck_init_cts;
     523           0 :                                 return e;
     524             :                         }
     525          24 :                         ctx->flush_done = 1;
     526          24 :                         gf_filter_pid_set_eos(ctx->out_pid);
     527          24 :                         return GF_EOS;
     528             :                 }
     529         299 :                 if (ctx->remap_ts) {
     530         299 :                         UNSCALE_TS(pkt.dts);
     531         299 :                         UNSCALE_TS(pkt.pts);
     532         299 :                         UNSCALE_DUR(pkt.duration);
     533             :                 }
     534             :         }
     535        3105 :         now = gf_sys_clock_high_res() - now;
     536        3105 :         ctx->time_spent += now;
     537             : 
     538        3105 :         if (res<0) {
     539           0 :                 av_packet_free_side_data(&pkt);
     540           0 :                 ctx->nb_frames_out++;
     541           0 :                 return GF_SERVICE_ERROR;
     542             :         }
     543             : 
     544        3105 :         if (!gotpck) {
     545         299 :                 av_packet_free_side_data(&pkt);
     546         299 :                 return GF_OK;
     547             :         }
     548             : 
     549        2806 :         ctx->nb_frames_out++;
     550        2806 :         if (ctx->init_cts_setup) {
     551          24 :                 ctx->init_cts_setup = GF_FALSE;
     552          24 :                 if (ctx->frame->pts != pkt.pts) {
     553             :                         //check shift in PTS - most of the time this is 0 (ffmpeg does not restamp video pts)
     554          14 :                         ctx->ts_shift = (s64) ctx->cts_first_frame_plus_one - 1 - (s64) pkt.pts;
     555             : 
     556             :                         //check shift in DTS
     557          14 :                         ctx->ts_shift += (s64) ctx->cts_first_frame_plus_one - 1 - (s64) pkt.dts;
     558             :                 }
     559             : 
     560             :                 //if ts_shift>0, this means we have a skip
     561          24 :                 if (ctx->ts_shift) {
     562          12 :                         gf_filter_pid_set_property(ctx->out_pid, GF_PROP_PID_DELAY, &PROP_LONGSINT( -ctx->ts_shift ) );
     563             :                 } else {
     564          12 :                         gf_filter_pid_set_property(ctx->out_pid, GF_PROP_PID_DELAY, NULL);
     565             :                 }
     566             :         }
     567             : 
     568             :         src_pck = NULL;
     569        2806 :         count = gf_list_count(ctx->src_packets);
     570        3888 :         for (i=0; i<count; i++) {
     571        3888 :                 src_pck = gf_list_get(ctx->src_packets, i);
     572        3888 :                 if (ffenc_get_cts(ctx, src_pck) == pkt.pts) break;
     573             :                 src_pck = NULL;
     574             :         }
     575             : 
     576             :         offset = 0;
     577        2806 :         to_copy = size = pkt.size;
     578             : 
     579        2806 :         if (ctx->codecid == GF_CODECID_J2K) {
     580         262 :                 u32 b4cc = GF_4CC(pkt.data[4], pkt.data[5], pkt.data[6], pkt.data[7]);
     581         262 :                 if (b4cc == GF_4CC('j','P',' ',' ')) {
     582             :                         u32 jp2h_offset = 0;
     583             :                         offset = 12;
     584       17292 :                         while (offset+8 < (u32) pkt.size) {
     585       17292 :                                 b4cc = GF_4CC(pkt.data[offset+4], pkt.data[offset+5], pkt.data[offset+6], pkt.data[offset+7]);
     586       17292 :                                 if (b4cc == GF_4CC('j','p','2','c')) {
     587             :                                         break;
     588             :                                 }
     589       17030 :                                 if (b4cc == GF_4CC('j','p','2','h')) {
     590             :                                         jp2h_offset = offset;
     591             :                                 }
     592       17030 :                                 offset++;
     593             :                         }
     594         262 :                         if (jp2h_offset) {
     595         262 :                                 u32 len = pkt.data[jp2h_offset];
     596         262 :                                 len <<= 8;
     597         262 :                                 len |= pkt.data[jp2h_offset+1];
     598         262 :                                 len <<= 8;
     599         262 :                                 len |= pkt.data[jp2h_offset+2];
     600         262 :                                 len <<= 8;
     601         262 :                                 len |= pkt.data[jp2h_offset+3];
     602             : 
     603         262 :                                 u32 dsi_crc = gf_crc_32(pkt.data + jp2h_offset + 8, len-8);
     604         262 :                                 if (dsi_crc != ctx->dsi_crc) {
     605           2 :                                         ctx->dsi_crc = dsi_crc;
     606           2 :                                         gf_filter_pid_set_property(ctx->out_pid, GF_PROP_PID_DECODER_CONFIG, &PROP_DATA(pkt.data + jp2h_offset + 8, len-8) );
     607             :                                 }
     608             :                         }
     609         262 :                         size -= offset;
     610         262 :                         to_copy -= offset;
     611             :                 } else {
     612           0 :                         size += 8;
     613             : 
     614           0 :                         if (!ctx->dsi_crc) {
     615             :                                 u8 *dsi;
     616             :                                 u32 dsi_len;
     617           0 :                                 GF_BitStream *bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
     618           0 :                                 gf_bs_write_u32(bs, 14+8);
     619           0 :                                 gf_bs_write_u32(bs, GF_4CC('i','h','d','r'));
     620           0 :                                 gf_bs_write_u32(bs, ctx->height);
     621           0 :                                 gf_bs_write_u32(bs, ctx->width);
     622           0 :                                 gf_bs_write_u16(bs, ctx->nb_planes);
     623           0 :                                 gf_bs_write_u8(bs, gf_pixel_get_bytes_per_pixel(ctx->gpac_pixel_fmt));
     624           0 :                                 gf_bs_write_u8(bs, 7); //COMP
     625           0 :                                 gf_bs_write_u8(bs, 0);
     626           0 :                                 gf_bs_write_u8(bs, 0);
     627           0 :                                 gf_bs_get_content(bs, &dsi, &dsi_len);
     628           0 :                                 gf_bs_del(bs);
     629           0 :                                 gf_filter_pid_set_property(ctx->out_pid, GF_PROP_PID_DECODER_CONFIG, &PROP_DATA_NO_COPY(dsi, dsi_len) );
     630           0 :                                 ctx->dsi_crc = 1;
     631             :                         }
     632             :                 }
     633             :         }
     634             : 
     635        2806 :         dst_pck = gf_filter_pck_new_alloc(ctx->out_pid, size, &output);
     636        2806 :         if (!dst_pck) return GF_OUT_OF_MEM;
     637             : 
     638             :         if (insert_jp2c) {
     639             :                 u32 bsize = pkt.size + 8;
     640             :                 output[0] = (bsize >> 24) & 0xFF;
     641             :                 output[1] = (bsize >> 16) & 0xFF;
     642             :                 output[2] = (bsize >> 8) & 0xFF;
     643             :                 output[3] = (bsize) & 0xFF;
     644             :                 output[4] = 'j';
     645             :                 output[5] = 'p';
     646             :                 output[6] = '2';
     647             :                 output[7] = 'c';
     648             :                 output += 8;
     649             :         }
     650        2806 :         memcpy(output, pkt.data + offset, to_copy);
     651             : 
     652        2806 :         if (src_pck) {
     653        2806 :                 if (ctx->disc_pck_ref == src_pck) {
     654           0 :                         ctx->disc_pck_ref = NULL;
     655           0 :                         ffenc_copy_pid_props(ctx);
     656             :                 }
     657             : 
     658        2806 :                 gf_filter_pck_merge_properties(src_pck, dst_pck);
     659        2806 :                 gf_list_del_item(ctx->src_packets, src_pck);
     660        2806 :                 gf_filter_pck_unref(src_pck);
     661             :         } else {
     662           0 :                 if (pkt.duration) {
     663           0 :                         gf_filter_pck_set_duration(dst_pck, (u32) pkt.duration);
     664             :                 } else {
     665           0 :                         gf_filter_pck_set_duration(dst_pck, (u32) ctx->frame->pkt_duration);
     666             :                 }
     667             :         }
     668             : 
     669        2806 :         ffenc_log_video(filter, ctx, &pkt, gf_filter_reporting_enabled(filter));
     670             : 
     671        2806 :         gf_filter_pck_set_cts(dst_pck, pkt.pts + ctx->ts_shift);
     672        2806 :         gf_filter_pck_set_dts(dst_pck, pkt.dts + ctx->ts_shift);
     673             : 
     674             :         //this is not 100% correct since we don't have any clue if this is SAP1/2/3/4 ...
     675             :         //since we send the output to our reframers we should be fine
     676        2806 :         if (pkt.flags & AV_PKT_FLAG_KEY) {
     677         404 :                 gf_filter_pck_set_sap(dst_pck, GF_FILTER_SAP_1);
     678         404 :                 GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[FFEnc] frame %d is SAP\n", ctx->nb_frames_out));
     679             :         }
     680             :         else
     681        2402 :                 gf_filter_pck_set_sap(dst_pck, 0);
     682             : 
     683             : #if LIBAVCODEC_VERSION_MAJOR >= 58
     684             :         if (pkt.flags & AV_PKT_FLAG_DISPOSABLE) {
     685             :                 gf_filter_pck_set_dependency_flags(dst_pck, 0x8);
     686             :         }
     687             : #endif
     688        2806 :         gf_filter_pck_send(dst_pck);
     689             : 
     690        2806 :         av_packet_free_side_data(&pkt);
     691             : 
     692             :         //we're in final flush, request a process task until all frames flushe
     693             :         //we could recursiveley call ourselves, same result
     694        2806 :         if (!pck) {
     695         299 :                 gf_filter_post_process_task(filter);
     696             :         }
     697             :         return GF_OK;
     698             : }
     699             : 
     700             : 
     701             : 
     702        2878 : static void ffenc_audio_append_samples(struct _gf_ffenc_ctx *ctx, const u8 *data, u32 size, u32 sample_offset, u32 nb_samples)
     703             : {
     704             :         u8 *dst;
     705             :         u32 f_idx, s_idx;
     706             :         u32 i, bytes_per_chan, src_frame_size;
     707             : 
     708        2878 :         if (!ctx->audio_buffer || !nb_samples)
     709             :                 return;
     710             : 
     711        2878 :         if (!ctx->planar_audio) {
     712         618 :                 u32 offset_src = sample_offset * ctx->bytes_per_sample;
     713         618 :                 u32 offset_dst = ctx->samples_in_audio_buffer * ctx->bytes_per_sample;
     714         618 :                 u32 len = nb_samples * ctx->bytes_per_sample;
     715         618 :                 if (data)
     716         617 :                         memcpy(ctx->audio_buffer + offset_dst, data + offset_src, sizeof(u8)*len);
     717             :                 else
     718           1 :                         memset(ctx->audio_buffer + offset_dst, 0, sizeof(u8)*len);
     719         618 :                 ctx->samples_in_audio_buffer += nb_samples;
     720         618 :                 return;
     721             :         }
     722             : 
     723        2260 :         bytes_per_chan = ctx->bytes_per_sample / ctx->channels;
     724        2260 :         src_frame_size = size / ctx->bytes_per_sample;
     725             :         assert(ctx->samples_in_audio_buffer + nb_samples <= (u32) ctx->audio_buffer_size);
     726             :         assert(!data || (sample_offset + nb_samples <= src_frame_size));
     727             :         assert(ctx->encoder->frame_size);
     728             : 
     729        2260 :         f_idx = ctx->samples_in_audio_buffer / ctx->encoder->frame_size;
     730        2260 :         s_idx = ctx->samples_in_audio_buffer % ctx->encoder->frame_size;
     731             :         if (s_idx) {
     732             :                 assert(s_idx + nb_samples <= (u32) ctx->encoder->frame_size);
     733             :         }
     734        2260 :         dst = ctx->audio_buffer + (f_idx * ctx->channels * ctx->encoder->frame_size + s_idx) * bytes_per_chan;
     735        6780 :         while (nb_samples) {
     736             :                 const u8 *src = NULL;
     737             :                 u32 nb_samples_to_copy = nb_samples;
     738        2260 :                 if (nb_samples_to_copy > (u32) ctx->encoder->frame_size)
     739             :                         nb_samples_to_copy = ctx->encoder->frame_size;
     740             : 
     741        2260 :                 if (data) {
     742             :                         assert(sample_offset<src_frame_size);
     743        2256 :                         src = data + sample_offset * bytes_per_chan;
     744             :                 }
     745             : 
     746        4520 :                 for (i=0; i<ctx->channels; i++) {
     747        4520 :                         if (src) {
     748        4512 :                                 memcpy(dst, src, sizeof(u8) * nb_samples_to_copy * bytes_per_chan);
     749        4512 :                                 src += src_frame_size * bytes_per_chan;
     750             :                         } else {
     751           8 :                                 memset(dst, 0, sizeof(u8) * nb_samples_to_copy * bytes_per_chan);
     752             :                         }
     753        4520 :                         dst += ctx->encoder->frame_size * bytes_per_chan;
     754             :                 }
     755        2260 :                 ctx->samples_in_audio_buffer += nb_samples_to_copy;
     756        2260 :                 nb_samples -= nb_samples_to_copy;
     757        2260 :                 sample_offset += nb_samples_to_copy;
     758             :         }
     759             : }
     760             : 
     761        1942 : static GF_Err ffenc_process_audio(GF_Filter *filter, struct _gf_ffenc_ctx *ctx)
     762             : {
     763             :         AVPacket pkt;
     764             :         s32 gotpck;
     765             :         const char *data = NULL;
     766        1942 :         u32 size=0, nb_copy=0, i, count;
     767             :         Bool from_internal_buffer_only = GF_FALSE;
     768             :         s32 res;
     769             :         u32 nb_samples=0;
     770             :         u64 ts_diff;
     771             :         u8 *output;
     772             :         GF_FilterPacket *dst_pck, *src_pck;
     773             :         GF_FilterPacket *pck;
     774             : 
     775        1942 :         if (!ctx->in_pid) return GF_EOS;
     776             : 
     777        1942 :         pck = gf_filter_pid_get_packet(ctx->in_pid);
     778             : 
     779        1942 :         if (!ctx->encoder) {
     780           0 :                 if (ctx->infmt_negociate) return GF_OK;
     781             :                 
     782           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[FFEnc] encoder reconfiguration failed, aborting stream\n"));
     783           0 :                 gf_filter_pid_set_eos(ctx->out_pid);
     784           0 :                 return GF_EOS;
     785             :         }
     786             : 
     787        1942 :         if (!pck) {
     788          21 :                 if (! gf_filter_pid_is_eos(ctx->in_pid)) return GF_OK;
     789          21 :                 if (ctx->flush_done) return GF_EOS;
     790             :         }
     791             : 
     792        1942 :         if (ctx->reconfig_pending) pck = NULL;
     793             : 
     794        1942 :         if (ctx->encoder->frame_size && (ctx->encoder->frame_size <= (s32) ctx->samples_in_audio_buffer)) {
     795           0 :                 avcodec_fill_audio_frame(ctx->frame, ctx->channels, ctx->sample_fmt, ctx->audio_buffer, ctx->bytes_per_sample * ctx->encoder->frame_size, 0);
     796             : 
     797           0 :                 from_internal_buffer_only = GF_TRUE;
     798             : 
     799        1942 :         } else if (pck) {
     800        1919 :                 data = gf_filter_pck_get_data(pck, &size);
     801        1919 :                 if (!data) {
     802           0 :                         GF_LOG(GF_LOG_WARNING, GF_LOG_CODEC, ("[FFEnc] Packet without associated data\n"));
     803           0 :                         gf_filter_pid_drop_packet(ctx->in_pid);
     804           0 :                         return GF_OK;
     805             :                 }
     806             : 
     807        1919 :                 if (!ctx->samples_in_audio_buffer) {
     808         166 :                         ctx->first_byte_cts = ffenc_get_cts(ctx, pck);
     809             :                 }
     810             : 
     811        1919 :                 src_pck = pck;
     812        1919 :                 gf_filter_pck_ref_props(&src_pck);
     813        1919 :                 gf_list_add(ctx->src_packets, src_pck);
     814        1919 :                 if (ctx->discontunity) {
     815           0 :                         ctx->disc_pck_ref = src_pck;
     816           0 :                         ctx->discontunity = GF_FALSE;
     817             :                 }
     818             : 
     819        1919 :                 nb_samples = size / ctx->bytes_per_sample;
     820        1919 :                 if (ctx->encoder->frame_size && (nb_samples + ctx->samples_in_audio_buffer < (u32) ctx->encoder->frame_size)) {
     821         804 :                         ffenc_audio_append_samples(ctx, data, size, 0, nb_samples);
     822         804 :                         gf_filter_pid_drop_packet(ctx->in_pid);
     823         804 :                         return GF_OK;
     824             :                 }
     825             : 
     826        1115 :                 if (ctx->encoder->frame_size) {
     827        1115 :                         nb_copy = ctx->encoder->frame_size - ctx->samples_in_audio_buffer;
     828        1115 :                         ffenc_audio_append_samples(ctx, data, size, 0, nb_copy);
     829             : 
     830        1115 :                         ctx->frame->nb_samples = ctx->encoder->frame_size;
     831        1115 :                         res = avcodec_fill_audio_frame(ctx->frame, ctx->channels, ctx->sample_fmt, ctx->audio_buffer, ctx->encoder->frame_size*ctx->bytes_per_sample, 0);
     832             : 
     833             :                 } else {
     834           0 :                         ctx->frame->nb_samples = size / ctx->bytes_per_sample;
     835           0 :                         res = avcodec_fill_audio_frame(ctx->frame, ctx->channels, ctx->sample_fmt, data, size, 0);
     836             :                         data = NULL;
     837           0 :                         size = 0;
     838             :                 }
     839        1115 :                 if (res<0) {
     840           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[FFEnc] Error filling raw audio frame: %s\n", av_err2str(res) ));
     841             :                         //discard
     842           0 :                         ctx->samples_in_audio_buffer = 0;
     843           0 :                         if (data && (nb_samples > nb_copy)) {
     844           0 :                                 ffenc_audio_append_samples(ctx, data, size, nb_copy, nb_samples - nb_copy);
     845           0 :                                 ts_diff = nb_copy;
     846           0 :                                 ts_diff *= ctx->timescale;
     847           0 :                                 ts_diff /= ctx->sample_rate;
     848           0 :                                 ctx->first_byte_cts = ffenc_get_cts(ctx, pck) + ts_diff;
     849             :                         }
     850           0 :                         gf_filter_pid_drop_packet(ctx->in_pid);
     851           0 :                         return GF_SERVICE_ERROR;
     852             :                 }
     853          23 :         } else if (ctx->samples_in_audio_buffer) {
     854             :                 u32 real_samples = ctx->samples_in_audio_buffer;
     855           5 :                 if (ctx->encoder->frame_size) {
     856           5 :                         nb_samples = ctx->encoder->frame_size - ctx->samples_in_audio_buffer;
     857           5 :                         ffenc_audio_append_samples(ctx, NULL, 0, 0, nb_samples);
     858           5 :                         res = avcodec_fill_audio_frame(ctx->frame, ctx->channels, ctx->sample_fmt, ctx->audio_buffer, ctx->encoder->frame_size * ctx->bytes_per_sample, 0);
     859             :                 } else {
     860           0 :                         res = avcodec_fill_audio_frame(ctx->frame, ctx->channels, ctx->sample_fmt, ctx->audio_buffer, ctx->samples_in_audio_buffer * ctx->bytes_per_sample, 0);
     861             :                 }
     862           5 :                 ctx->frame->nb_samples = real_samples;
     863           5 :                 if (res<0) {
     864           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[FFEnc] Error filling raw audio frame: %s\n", av_err2str(res) ));
     865           0 :                         ctx->samples_in_audio_buffer = 0;
     866             :                 } else {
     867           5 :                         ctx->samples_in_audio_buffer = real_samples;
     868           5 :                         if (ctx->ts_shift && ctx->encoder->frame_size && (ctx->encoder->frame_size>ctx->ts_shift)) {
     869           2 :                                 ctx->samples_in_audio_buffer += (u32) ctx->ts_shift;
     870           2 :                                 if (ctx->samples_in_audio_buffer > (u32) ctx->encoder->frame_size)
     871           0 :                                         ctx->samples_in_audio_buffer = ctx->encoder->frame_size;
     872             :                         }
     873             :                 }
     874             :         }
     875             : 
     876        1138 :         av_init_packet(&pkt);
     877        1138 :         pkt.data = (uint8_t*)ctx->enc_buffer;
     878        1138 :         pkt.size = ctx->enc_buffer_size;
     879             : 
     880        1138 :         if (pck)
     881        1115 :                 ctx->frame->nb_samples = ctx->encoder->frame_size;
     882        1138 :         ctx->frame->format = ctx->encoder->sample_fmt;
     883        1138 :         ctx->frame->channels = ctx->encoder->channels;
     884        1138 :         ctx->frame->channel_layout = ctx->encoder->channel_layout;
     885        1138 :         gotpck = 0;
     886        1138 :         if (pck || ctx->samples_in_audio_buffer) {
     887        1120 :                 ctx->frame->pkt_dts = ctx->frame->pkt_pts = ctx->frame->pts = ctx->first_byte_cts;
     888        1120 :                 res = avcodec_encode_audio2(ctx->encoder, &pkt, ctx->frame, &gotpck);
     889        1120 :                 if (!pck) {
     890           5 :                         if (! (ctx->encoder->codec->capabilities & AV_CODEC_CAP_DELAY)) {
     891           2 :                                 pkt.duration = ctx->samples_in_audio_buffer;
     892           2 :                                 if (ctx->timescale != ctx->sample_rate) {
     893           0 :                                         pkt.duration *= ctx->timescale;
     894           0 :                                         pkt.duration /= ctx->sample_rate;
     895             :                                 }
     896             :                         }
     897           5 :                         ctx->samples_in_audio_buffer = 0;
     898             :                 }
     899             :         } else {
     900          18 :                 res = avcodec_encode_audio2(ctx->encoder, &pkt, NULL, &gotpck);
     901          18 :                 if (!gotpck) {
     902             :                         //done flushing encoder while reconfiguring
     903          10 :                         if (ctx->reconfig_pending) {
     904             :                                 GF_Err e;
     905           2 :                                 Bool bck_init_cts = ctx->init_cts_setup;
     906             : 
     907           2 :                                 ctx->reconfig_pending = GF_FALSE;
     908           2 :                                 avcodec_free_context(&ctx->encoder);
     909           2 :                                 ctx->encoder = NULL;
     910           2 :                                 GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[FFEnc] codec flush done, triggering reconfiguration\n"));
     911           2 :                                 e = ffenc_configure_pid_ex(filter, ctx->in_pid, GF_FALSE, GF_TRUE);
     912           2 :                                 ctx->init_cts_setup = bck_init_cts;
     913           2 :                                 return e;
     914             :                         }
     915           8 :                         ctx->flush_done = 1;
     916           8 :                         gf_filter_pid_set_eos(ctx->out_pid);
     917           8 :                         return GF_EOS;
     918             :                 }
     919             :         }
     920             : 
     921        1128 :         if (from_internal_buffer_only) {
     922             :                 //avcodec_fill_audio_frame does not perform copy, so make sure we discard internal buffer AFTER we encode
     923             :                 u32 offset, len, nb_samples_to_drop;
     924             : 
     925             :                 //we always drop a complete encoder frame size, so same code for planar and packed
     926           0 :                 nb_samples_to_drop = ctx->encoder->frame_size;
     927             : 
     928           0 :                 if (ctx->samples_in_audio_buffer > nb_samples_to_drop) {
     929           0 :                         offset = nb_samples_to_drop * ctx->bytes_per_sample;
     930           0 :                         len = (ctx->samples_in_audio_buffer - nb_samples_to_drop) * ctx->bytes_per_sample;
     931           0 :                         memmove(ctx->audio_buffer, ctx->audio_buffer + offset, sizeof(u8)*len);
     932           0 :                         ctx->samples_in_audio_buffer -= nb_samples_to_drop;
     933             :                 } else {
     934           0 :                         ctx->samples_in_audio_buffer = 0;
     935             :                 }
     936             : 
     937             :         }
     938             : 
     939             :         //increase timestamp
     940        1128 :         ts_diff = ctx->frame->nb_samples;
     941        1128 :         if (ctx->timescale!=ctx->sample_rate) {
     942           0 :                 ts_diff *= ctx->timescale;
     943           0 :                 ts_diff /= ctx->sample_rate;
     944             :         }
     945        1128 :         ctx->first_byte_cts += ts_diff;
     946             : 
     947        1128 :         if (pck && !from_internal_buffer_only) {
     948        1115 :                 ctx->samples_in_audio_buffer = 0;
     949        1115 :                 if (nb_samples > nb_copy) {
     950         954 :                         ffenc_audio_append_samples(ctx, data, size, nb_copy, nb_samples - nb_copy);
     951             :                 }
     952        1115 :                 gf_filter_pid_drop_packet(ctx->in_pid);
     953             :         }
     954             : 
     955        1128 :         if (res<0) {
     956           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[FFEnc] Error encoding frame: %s\n", av_err2str(res) ));
     957           0 :                 av_packet_free_side_data(&pkt);
     958           0 :                 return GF_SERVICE_ERROR;
     959             :         }
     960        1128 :         if (!gotpck) {
     961           4 :                 av_packet_free_side_data(&pkt);
     962           4 :                 return GF_OK;
     963             :         }
     964        1124 :         dst_pck = gf_filter_pck_new_alloc(ctx->out_pid, pkt.size, &output);
     965        1124 :         if (!dst_pck) return GF_OUT_OF_MEM;
     966        1124 :         memcpy(output, pkt.data, pkt.size);
     967             : 
     968        1124 :         if (ctx->init_cts_setup) {
     969             :                 u64 octs;
     970           8 :                 ctx->init_cts_setup = GF_FALSE;
     971           8 :                 src_pck = gf_list_get(ctx->src_packets, 0);
     972           8 :                 octs = src_pck ? ffenc_get_cts(ctx, src_pck) : ctx->frame->pts;
     973           8 :                 if (octs != pkt.pts) {
     974           8 :                         ctx->ts_shift = (s64) octs - (s64) pkt.pts;
     975             :                 }
     976           8 :                 if (ctx->ts_shift) {
     977           8 :                         gf_filter_pid_set_property(ctx->out_pid, GF_PROP_PID_DELAY, &PROP_LONGSINT( - ctx->ts_shift) );
     978             :                 }
     979             :         }
     980             : 
     981             :         //try to locate first source packet with CTS
     982             :         //- greater than or equal to this packet cts
     983             :         //- strictly less than next packet cts
     984             :         // and use it as source for properties
     985             :         //this is not optimal because we dont produce N for N because of different window coding sizes
     986        1124 :         src_pck = NULL;
     987        1124 :         count = gf_list_count(ctx->src_packets);
     988        2026 :         for (i=0; i<count; i++) {
     989             :                 u64 acts;
     990             :                 u32 adur;
     991        2021 :                 src_pck = gf_list_get(ctx->src_packets, i);
     992        2021 :                 acts = ffenc_get_cts(ctx, src_pck);
     993        2021 :                 adur = gf_filter_pck_get_duration(src_pck);
     994             : 
     995        2021 :                 if (((s64) acts >= pkt.pts) && ((s64) acts < pkt.pts + pkt.duration)) {
     996             :                         break;
     997             :                 }
     998             : 
     999         902 :                 if (acts + adur <= (u64) ( pkt.pts + ctx->ts_shift) ) {
    1000         797 :                         gf_list_rem(ctx->src_packets, i);
    1001         797 :                         gf_filter_pck_unref(src_pck);
    1002         797 :                         i--;
    1003         797 :                         count--;
    1004             :                 }
    1005         902 :                 src_pck = NULL;
    1006             :         }
    1007        1124 :         if (src_pck) {
    1008        1119 :                 if (src_pck==ctx->disc_pck_ref) {
    1009           0 :                         ctx->disc_pck_ref = NULL;
    1010           0 :                         ffenc_copy_pid_props(ctx);
    1011             :                 }
    1012             : 
    1013        1119 :                 gf_filter_pck_merge_properties(src_pck, dst_pck);
    1014        1119 :                 gf_list_del_item(ctx->src_packets, src_pck);
    1015        1119 :                 gf_filter_pck_unref(src_pck);
    1016             :         }
    1017             : 
    1018        1124 :         gf_filter_pck_set_cts(dst_pck, pkt.pts + ctx->ts_shift);
    1019        1124 :         gf_filter_pck_set_dts(dst_pck, pkt.dts + ctx->ts_shift);
    1020             :         //this is not 100% correct since we don't have any clue if this is SAP1/4 (roll info missing)
    1021        1124 :         if (pkt.flags & AV_PKT_FLAG_KEY)
    1022        1124 :                 gf_filter_pck_set_sap(dst_pck, GF_FILTER_SAP_1);
    1023             :         else
    1024           0 :                 gf_filter_pck_set_sap(dst_pck, 0);
    1025             : 
    1026        1124 :         gf_filter_pck_set_duration(dst_pck, (u32) pkt.duration);
    1027             : 
    1028        1124 :         gf_filter_pck_send(dst_pck);
    1029             : 
    1030        1124 :         av_packet_free_side_data(&pkt);
    1031             :         //we're in final flush, request a process task until all frames flushe
    1032             :         //we could recursiveley call ourselves, same result
    1033        1124 :         if (!pck) {
    1034          13 :                 gf_filter_post_process_task(filter);
    1035             :         }
    1036             :         return GF_OK;
    1037             : }
    1038             : 
    1039        5083 : static GF_Err ffenc_process(GF_Filter *filter)
    1040             : {
    1041        5083 :         GF_FFEncodeCtx *ctx = (GF_FFEncodeCtx *) gf_filter_get_udta(filter);
    1042        5083 :         if (!ctx->out_pid || gf_filter_pid_would_block(ctx->out_pid))
    1043             :                 return GF_OK;
    1044        5083 :         return ctx->process(filter, ctx);
    1045             : }
    1046             : 
    1047          62 : static GF_Err ffenc_configure_pid_ex(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove, Bool is_force_reconf)
    1048             : {
    1049             :         s32 res;
    1050          62 :         u32 type=0, fftype, ff_codectag=0;
    1051             :         u32 i=0;
    1052          62 :         AVDictionary *options = NULL;
    1053             :         u32 change_input_fmt = 0;
    1054             :         const GF_PropertyValue *prop;
    1055             :         const AVCodec *codec=NULL;
    1056             :         const AVCodec *desired_codec=NULL;
    1057             :         u32 codec_id, pfmt, afmt;
    1058          62 :         GF_FFEncodeCtx *ctx = (GF_FFEncodeCtx *) gf_filter_get_udta(filter);
    1059             : 
    1060             :         //disconnect of src pid (not yet supported)
    1061          62 :         if (is_remove) {
    1062           0 :                 ctx->in_pid = NULL;
    1063           0 :                 if (ctx->out_pid) {
    1064           0 :                         gf_filter_pid_remove(ctx->out_pid);
    1065           0 :                         ctx->out_pid = NULL;
    1066             :                 }
    1067             :                 return GF_OK;
    1068             :         }
    1069             :         //check our PID: streamtype and codecid
    1070          62 :         prop = gf_filter_pid_get_property(pid, GF_PROP_PID_STREAM_TYPE);
    1071          62 :         if (!prop) return GF_NOT_SUPPORTED;
    1072             : 
    1073          62 :         type = prop->value.uint;
    1074          62 :         switch (type) {
    1075             :         case GF_STREAM_AUDIO:
    1076             :         case GF_STREAM_VISUAL:
    1077             :                 break;
    1078             :         default:
    1079             :                 return GF_NOT_SUPPORTED;
    1080             :         }
    1081          62 :         prop = gf_filter_pid_get_property(pid, GF_PROP_PID_CODECID);
    1082          62 :         if (!prop || prop->value.uint!=GF_CODECID_RAW) return GF_NOT_SUPPORTED;
    1083             : 
    1084          62 :         if (!ctx->force_codec) {
    1085             :                 //figure out if output was preconfigured during filter chain setup
    1086          52 :                 prop = gf_filter_pid_caps_query(pid, GF_PROP_PID_CODECID);
    1087          52 :                 if (prop) {
    1088          36 :                         ctx->codecid = prop->value.uint;
    1089          16 :                 } else if (!ctx->codecid && ctx->c) {
    1090          10 :                         ctx->codecid = gf_codecid_parse(ctx->c);
    1091          10 :                         if (!ctx->codecid) {
    1092           0 :                                 codec = avcodec_find_encoder_by_name(ctx->c);
    1093           0 :                                 if (codec)
    1094           0 :                                         ctx->codecid = ffmpeg_codecid_to_gpac(codec->id);
    1095             :                         }
    1096             :                 }
    1097             :         } else {
    1098          10 :                 ctx->codecid = ffmpeg_codecid_to_gpac(ctx->force_codec->id);
    1099          10 :                 desired_codec = ctx->force_codec;
    1100             :         }
    1101             : 
    1102          62 :         if (!ctx->codecid && !desired_codec) {
    1103           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[FFEnc] No codecid specified\n" ));
    1104             :                 return GF_BAD_PARAM;
    1105             :         }
    1106             : 
    1107             :         //initial config or update
    1108          62 :         if (!ctx->in_pid || (ctx->in_pid==pid)) {
    1109          62 :                 ctx->in_pid = pid;
    1110          62 :                 if (!ctx->type) ctx->type = type;
    1111             :                 //no support for dynamic changes of stream types
    1112          30 :                 else if (ctx->type != type) {
    1113             :                         return GF_NOT_SUPPORTED;
    1114             :                 }
    1115             :         } else {
    1116             :                 //only one input pid in ctx
    1117             :                 if (ctx->in_pid) return GF_REQUIRES_NEW_INSTANCE;
    1118             :         }
    1119             : 
    1120          62 :         if (ctx->codecid) {
    1121          62 :                 codec_id = ffmpeg_codecid_from_gpac(ctx->codecid, &ff_codectag);
    1122          62 :                 if (codec_id) {
    1123          62 :                         if (desired_codec && desired_codec->id==codec_id)
    1124             :                                 codec = desired_codec;
    1125             :                         else
    1126          52 :                                 codec = avcodec_find_encoder(codec_id);
    1127             :                 }
    1128             :         } else {
    1129             :                 codec = desired_codec;
    1130             :         }
    1131          62 :         if (!codec) {
    1132           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[FFEnc] Cannot find encoder for codec %s\n", gf_codecid_name(ctx->codecid) ));
    1133             :                 return GF_NOT_SUPPORTED;
    1134             :         }
    1135          62 :         codec_id = codec->id;
    1136          62 :         if (!ctx->codecid)
    1137           0 :                 ctx->codecid = ffmpeg_codecid_to_gpac(codec->id);
    1138             : 
    1139          62 :         fftype = ffmpeg_stream_type_to_gpac(codec->type);
    1140          62 :         if (fftype != type) {
    1141           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[FFEnc] Mismatch between stream type, codec indicates %s but source type is %s\n", gf_stream_type_name(fftype), gf_stream_type_name(type) ));
    1142             :                 return GF_NOT_SUPPORTED;
    1143             :         }
    1144             : 
    1145             :         //declare our output pid to make sure we connect the chain
    1146          62 :         ctx->in_pid = pid;
    1147          62 :         if (!ctx->out_pid) {
    1148             :                 char szCodecName[1000];
    1149          32 :                 ctx->out_pid = gf_filter_pid_new(filter);
    1150             : 
    1151             :                 //to change once we implement on-the-fly codec change
    1152          32 :                 sprintf(szCodecName, "ffenc:%s", codec->name ? codec->name : "unknown");
    1153          32 :                 gf_filter_set_name(filter, szCodecName);
    1154          32 :                 gf_filter_pid_set_framing_mode(ctx->in_pid, GF_TRUE);
    1155             :         }
    1156          62 :         if (type==GF_STREAM_AUDIO) {
    1157          18 :                 ctx->process = ffenc_process_audio;
    1158             :         } else {
    1159          44 :                 ctx->process = ffenc_process_video;
    1160             :         }
    1161             : 
    1162          62 :         prop = gf_filter_pid_get_property(pid, GF_PROP_PID_TARGET_RATE);
    1163          62 :         if (prop && prop->value.uint && (prop->value.uint != ctx->target_rate)) {
    1164             :                 char szRate[100];
    1165           0 :                 ctx->target_rate = prop->value.uint;
    1166             :                 snprintf(szRate, 99, "%d", ctx->target_rate);
    1167           0 :                 szRate[99] = 0;
    1168           0 :                 av_dict_set(&ctx->options, "b", szRate, 0);
    1169             :         }
    1170             : 
    1171          62 :         if (!is_force_reconf) {
    1172             :                 //not yet setup or no delay, copy directly props, otherwise signal discontinuity
    1173          60 :                 if (!ctx->encoder || !gf_list_count(ctx->src_packets)) {
    1174          60 :                         ffenc_copy_pid_props(ctx);
    1175             :                 } else {
    1176           0 :                         ctx->discontunity = GF_TRUE;
    1177             :                 }
    1178             :         }
    1179             : 
    1180             : #define GET_PROP(_a, _code, _name) \
    1181             :         prop = gf_filter_pid_get_property(pid, _code); \
    1182             :         if (!prop) {\
    1183             :                 GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("[FFEnc] Input %s unknown, waiting for reconfigure\n", _name)); \
    1184             :                 return GF_OK; \
    1185             :         }\
    1186             :         _a = prop->value.uint;
    1187             : 
    1188             :         pfmt = afmt = 0;
    1189          62 :         if (type==GF_STREAM_VISUAL) {
    1190          44 :                 GET_PROP(ctx->width, GF_PROP_PID_WIDTH, "width")
    1191          44 :                 GET_PROP(ctx->height, GF_PROP_PID_HEIGHT, "height")
    1192          44 :                 GET_PROP(pfmt, GF_PROP_PID_PIXFMT, "pixel format")
    1193             : 
    1194          40 :                 prop = gf_filter_pid_caps_query(pid, GF_PROP_PID_STRIDE);
    1195             :                 //keep stride and stride_uv to 0 i fnot set, and recompute from pixel format
    1196          40 :                 if (prop) ctx->stride = prop->value.uint;
    1197          40 :                 prop = gf_filter_pid_caps_query(pid, GF_PROP_PID_STRIDE_UV);
    1198          40 :                 if (prop) ctx->stride_uv = prop->value.uint;
    1199             :         } else {
    1200          18 :                 GET_PROP(ctx->sample_rate, GF_PROP_PID_SAMPLE_RATE, "sample rate")
    1201          18 :                 GET_PROP(ctx->channels, GF_PROP_PID_NUM_CHANNELS, "nb channels")
    1202          18 :                 GET_PROP(afmt, GF_PROP_PID_AUDIO_FORMAT, "audio format")
    1203             :         }
    1204             : 
    1205             : 
    1206          58 :         if (ctx->encoder) {
    1207             :                 Bool reuse = GF_FALSE;
    1208          14 :                 codec_id = ffmpeg_codecid_from_gpac(ctx->codecid, &ff_codectag);
    1209             : 
    1210          14 :                 if ((type==GF_STREAM_AUDIO)
    1211           0 :                         && (ctx->encoder->codec->id==codec_id) && (ctx->encoder->sample_rate==ctx->sample_rate)
    1212           0 :                         && (ctx->encoder->channels==ctx->channels) && (ctx->gpac_audio_fmt == afmt )
    1213             :                 ) {
    1214             :                         reuse = GF_TRUE;
    1215          14 :                 } else if ((ctx->encoder->codec->id==codec_id)
    1216          14 :                         && (ctx->encoder->width==ctx->width) && (ctx->encoder->height==ctx->height)
    1217          14 :                         && (ctx->gpac_pixel_fmt == pfmt)
    1218             :                 ) {
    1219             :                         reuse = GF_TRUE;
    1220             :                 }
    1221             :                 if (reuse) {
    1222             :                         //delay may have change
    1223          14 :                         prop = gf_filter_pid_get_property(pid, GF_PROP_PID_DELAY);
    1224          14 :                         ctx->in_tk_delay = prop ? prop->value.longsint : 0;
    1225          14 :                         return GF_OK;
    1226             :                 }
    1227             : 
    1228           0 :                 GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[FFEnc] codec reconfiguration, beginning flush\n"));
    1229           0 :                 ctx->reconfig_pending = GF_TRUE;
    1230           0 :                 return GF_OK;
    1231             :         }
    1232             : 
    1233          44 :         if (type==GF_STREAM_VISUAL) {
    1234             :                 u32 force_pfmt = AV_PIX_FMT_NONE;
    1235          26 :                 if (ctx->pfmt) {
    1236           0 :                         u32 ff_pfmt = ffmpeg_pixfmt_from_gpac(ctx->pfmt);
    1237             :                         i=0;
    1238           0 :                         while (codec->pix_fmts) {
    1239           0 :                                 if (codec->pix_fmts[i] == AV_PIX_FMT_NONE) break;
    1240           0 :                                 if (codec->pix_fmts[i] == ff_pfmt) {
    1241             :                                         force_pfmt = ff_pfmt;
    1242             :                                         break;
    1243             :                                 }
    1244             :                                 //handle pixel formats aliases
    1245           0 :                                 if (ffmpeg_pixfmt_to_gpac(codec->pix_fmts[i]) == ctx->pfmt) {
    1246           0 :                                         force_pfmt = ctx->pixel_fmt;
    1247           0 :                                         break;
    1248             :                                 }
    1249           0 :                                 i++;
    1250             :                         }
    1251           0 :                         if (force_pfmt == AV_PIX_FMT_NONE) {
    1252           0 :                                 GF_LOG(GF_LOG_WARNING, GF_LOG_CODEC, ("[FFEnc] Requested source format %s not supported by codec, using default one\n", gf_pixel_fmt_name(ctx->pfmt) ));
    1253             :                         } else {
    1254             :                                 change_input_fmt = force_pfmt;
    1255             :                         }
    1256             :                 }
    1257          26 :                 ctx->pixel_fmt = ffmpeg_pixfmt_from_gpac(pfmt);
    1258             :                 //check pixel format
    1259          26 :                 if (force_pfmt == AV_PIX_FMT_NONE) {
    1260             :                         change_input_fmt = AV_PIX_FMT_NONE;
    1261             :                         i=0;
    1262          38 :                         while (codec->pix_fmts) {
    1263          38 :                                 if (codec->pix_fmts[i] == AV_PIX_FMT_NONE) break;
    1264          36 :                                 if (codec->pix_fmts[i] == ctx->pixel_fmt) {
    1265          22 :                                         change_input_fmt = ctx->pixel_fmt;
    1266          22 :                                         break;
    1267             :                                 }
    1268             :                                 //handle pixel formats aliases
    1269          14 :                                 if (ffmpeg_pixfmt_to_gpac(codec->pix_fmts[i]) == pfmt) {
    1270           2 :                                         ctx->pixel_fmt = change_input_fmt = codec->pix_fmts[i];
    1271           2 :                                         break;
    1272             :                                 }
    1273          12 :                                 i++;
    1274             :                         }
    1275          26 :                         if (!ctx->force_codec && (change_input_fmt == AV_PIX_FMT_NONE)) {
    1276             : #if (LIBAVCODEC_VERSION_MAJOR >= 58) && (LIBAVCODEC_VERSION_MINOR>=20)
    1277             :                                 void *ff_opaque=NULL;
    1278             : #else
    1279             :                                 AVCodec *codec_alt = NULL;
    1280             : #endif
    1281             :                                 while (1) {
    1282             : #if (LIBAVCODEC_VERSION_MAJOR >= 58) && (LIBAVCODEC_VERSION_MINOR>=20)
    1283             :                                         const AVCodec *codec_alt = av_codec_iterate(&ff_opaque);
    1284             : #else
    1285        1290 :                                         codec_alt = av_codec_next(codec_alt);
    1286             : #endif
    1287        1290 :                                         if (!codec_alt) break;
    1288        1288 :                                         if (codec_alt==codec) continue;
    1289        1286 :                                         if (codec_alt->id == codec_id) {
    1290             :                                                 i=0;
    1291          16 :                                                 while (codec_alt->pix_fmts) {
    1292          14 :                                                         if (codec_alt->pix_fmts[i] == AV_PIX_FMT_NONE) break;
    1293          10 :                                                         if (codec_alt->pix_fmts[i] == ctx->pixel_fmt) {
    1294           0 :                                                                 change_input_fmt = ctx->pixel_fmt;
    1295           0 :                                                                 GF_LOG(GF_LOG_WARNING, GF_LOG_CODEC, ("[FFEnc] Reassigning codec from %s to %s to match pixel format\n", codec->name, codec_alt->name ));
    1296             :                                                                 codec = codec_alt;
    1297             :                                                                 break;
    1298             :                                                         }
    1299          10 :                                                         i++;
    1300             :                                                 }
    1301             :                                         }
    1302             :                                 }
    1303             :                         }
    1304             :                 }
    1305             : 
    1306          26 :                 if (ctx->pixel_fmt != change_input_fmt) {
    1307             :                         u32 ff_pmft = ctx->pixel_fmt;
    1308             : 
    1309           2 :                         if (force_pfmt == AV_PIX_FMT_NONE) {
    1310             :                                 ff_pmft = AV_PIX_FMT_NONE;
    1311             :                                 i=0;
    1312             :                                 //find a mapped pixel format
    1313           2 :                                 while (codec->pix_fmts) {
    1314           2 :                                         if (codec->pix_fmts[i] == AV_PIX_FMT_NONE) break;
    1315           2 :                                         if (ffmpeg_pixfmt_to_gpac(codec->pix_fmts[i])) {
    1316           2 :                                                 ff_pmft = codec->pix_fmts[i];
    1317           2 :                                                 break;
    1318             :                                         }
    1319           0 :                                         i++;
    1320             :                                 }
    1321           2 :                                 if (ff_pmft == AV_PIX_FMT_NONE) {
    1322           0 :                                         GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[FFEnc] Could not find a matching GPAC pixel format for encoder %s\n", codec->name ));
    1323             :                                         return GF_NOT_SUPPORTED;
    1324             :                                 }
    1325           0 :                         } else if (ctx->pfmt) {
    1326           0 :                                 ff_pmft = ffmpeg_pixfmt_from_gpac(ctx->pfmt);
    1327             :                         }
    1328           2 :                         pfmt = ffmpeg_pixfmt_to_gpac(ff_pmft);
    1329           2 :                         gf_filter_pid_negociate_property(ctx->in_pid, GF_PROP_PID_PIXFMT, &PROP_UINT(pfmt) );
    1330           2 :                         ctx->infmt_negociate = GF_TRUE;
    1331             :                 } else {
    1332          24 :                         ctx->infmt_negociate = GF_FALSE;
    1333             :                 }
    1334             :         } else {
    1335             :                 u32 change_input_sr = 0;
    1336             :                 //check audio format
    1337          18 :                 ctx->sample_fmt = ffmpeg_audio_fmt_from_gpac(afmt);
    1338             :                 change_input_fmt = 0;
    1339          44 :                 while (codec->sample_fmts) {
    1340          26 :                         if (codec->sample_fmts[i] == AV_SAMPLE_FMT_NONE) break;
    1341          18 :                         if (codec->sample_fmts[i] == ctx->sample_fmt) {
    1342             :                                 change_input_fmt = ctx->sample_fmt;
    1343             :                                 break;
    1344             :                         }
    1345           8 :                         i++;
    1346             :                 }
    1347             :                 i=0;
    1348          18 :                 if (!codec->supported_samplerates)
    1349           4 :                         change_input_sr = ctx->sample_rate;
    1350             : 
    1351          92 :                 while (codec->supported_samplerates) {
    1352          88 :                         if (!codec->supported_samplerates[i]) break;
    1353          88 :                         if (codec->supported_samplerates[i]==ctx->sample_rate) {
    1354             :                                 change_input_sr = ctx->sample_rate;
    1355             :                                 break;
    1356             :                         }
    1357          74 :                         i++;
    1358             :                 }
    1359          18 :                 if ((ctx->sample_fmt != change_input_fmt) || (ctx->sample_rate != change_input_sr)) {
    1360           8 :                         if (ctx->sample_fmt != change_input_fmt) {
    1361           8 :                                 ctx->sample_fmt = codec->sample_fmts ? codec->sample_fmts[0] : AV_SAMPLE_FMT_S16;
    1362           8 :                                 afmt = ffmpeg_audio_fmt_to_gpac(ctx->sample_fmt);
    1363           8 :                                 gf_filter_pid_negociate_property(ctx->in_pid, GF_PROP_PID_AUDIO_FORMAT, &PROP_UINT(afmt) );
    1364             :                         }
    1365           8 :                         if (ctx->sample_rate != change_input_sr) {
    1366           0 :                                 gf_filter_pid_negociate_property(ctx->in_pid, GF_PROP_PID_SAMPLE_RATE, &PROP_UINT(codec->supported_samplerates[0]) );
    1367             :                         }
    1368           8 :                         ctx->infmt_negociate = GF_TRUE;
    1369             :                 } else {
    1370          10 :                         ctx->infmt_negociate = GF_FALSE;
    1371             :                 }
    1372             :         }
    1373             : 
    1374             :         //renegociate input, wait for reconfig call
    1375          44 :         if (ctx->infmt_negociate) return GF_OK;
    1376             : 
    1377          34 :         ctx->gpac_pixel_fmt = pfmt;
    1378          34 :         ctx->gpac_audio_fmt = afmt;
    1379          34 :         ctx->dsi_crc = 0;
    1380             : 
    1381          34 :         prop = gf_filter_pid_get_property(pid, GF_PROP_PID_DELAY);
    1382          34 :         ctx->in_tk_delay = prop ? prop->value.longsint : 0;
    1383             : 
    1384          34 :         ctx->encoder = avcodec_alloc_context3(codec);
    1385          34 :         if (! ctx->encoder) return GF_OUT_OF_MEM;
    1386             : 
    1387          34 :         ctx->encoder->codec_tag = ff_codectag;
    1388          34 :         if (type==GF_STREAM_VISUAL) {
    1389          24 :                 ctx->encoder->width = ctx->width;
    1390          24 :                 ctx->encoder->height = ctx->height;
    1391          24 :                 prop = gf_filter_pid_get_property(pid, GF_PROP_PID_SAR);
    1392          24 :                 if (prop) {
    1393          13 :                         ctx->encoder->sample_aspect_ratio.num = prop->value.frac.num;
    1394          13 :                         ctx->timescale = ctx->encoder->sample_aspect_ratio.den = prop->value.frac.den;
    1395             :                 } else {
    1396          11 :                         ctx->encoder->sample_aspect_ratio.num = 1;
    1397          11 :                         ctx->encoder->sample_aspect_ratio.den = 1;
    1398             :                 }
    1399             :                 //CHECKME: do we need to use 1/FPS ?
    1400          24 :                 prop = gf_filter_pid_get_property(pid, GF_PROP_PID_TIMESCALE);
    1401          24 :                 if (prop) {
    1402          24 :                         ctx->encoder->time_base.num = 1;
    1403          24 :                         ctx->timescale = ctx->encoder->time_base.den = prop->value.uint;
    1404             :                 }
    1405          24 :                 prop = gf_filter_pid_get_property(pid, GF_PROP_PID_FPS);
    1406          24 :                 if (prop) {
    1407          22 :                         ctx->encoder->gop_size = prop->value.frac.num / prop->value.frac.den;
    1408          22 :                         ctx->encoder->time_base.num = prop->value.frac.den;
    1409          22 :                         ctx->encoder->time_base.den = prop->value.frac.num;
    1410             :                 }
    1411             : 
    1412          24 :                 gf_media_get_reduced_frame_rate(&ctx->encoder->time_base.den, &ctx->encoder->time_base.num);
    1413             : 
    1414          24 :                 if (ctx->low_delay) {
    1415           0 :                         av_dict_set(&ctx->options, "profile", "baseline", 0);
    1416           0 :                         av_dict_set(&ctx->options, "preset", "ultrafast", 0);
    1417           0 :                         av_dict_set(&ctx->options, "tune", "zerolatency", 0);
    1418           0 :                         if (ctx->codecid==GF_CODECID_AVC) {
    1419           0 :                                 av_dict_set(&ctx->options, "x264opts", "no-mbtree:sliced-threads:sync-lookahead=0", 0);
    1420             :                         }
    1421             : #if LIBAVCODEC_VERSION_MAJOR >= 58
    1422             :                         ctx->encoder->flags |= AV_CODEC_FLAG_LOW_DELAY;
    1423             : #endif
    1424             :                 }
    1425             : 
    1426          24 :                 if (ctx->fintra.den && (ctx->fintra.num>0) && !ctx->rc) {
    1427           8 :                         av_dict_set(&ctx->options, "forced-idr", "1", 0);
    1428             :                 }
    1429             : 
    1430             :                 //we don't use out of band headers, since x264 in ffmpeg (and likely other) do not output in MP4 format but
    1431             :                 //in annexB (extradata only contains SPS/PPS/etc in annexB)
    1432             :                 //so we indicate unframed for these codecs and use our own filter for annexB->MP4
    1433             : 
    1434          24 :                 if (!ctx->frame)
    1435          24 :                         ctx->frame = av_frame_alloc();
    1436             : 
    1437          24 :                 ctx->enc_buffer_size = ctx->width*ctx->height + ENC_BUF_ALLOC_SAFE;
    1438          24 :                 ctx->enc_buffer = gf_realloc(ctx->enc_buffer, sizeof(char)*ctx->enc_buffer_size);
    1439             : 
    1440          24 :                 gf_pixel_get_size_info(pfmt, ctx->width, ctx->height, NULL, &ctx->stride, &ctx->stride_uv, &ctx->nb_planes, &ctx->uv_height);
    1441             : 
    1442          24 :                 ctx->encoder->pix_fmt = ctx->pixel_fmt;
    1443          24 :                 ctx->init_cts_setup = GF_TRUE;
    1444          24 :                 ctx->frame->format = ctx->encoder->pix_fmt;
    1445          10 :         } else if (type==GF_STREAM_AUDIO) {
    1446          10 :                 ctx->process = ffenc_process_audio;
    1447             : 
    1448          10 :                 ctx->encoder->sample_rate = ctx->sample_rate;
    1449          10 :                 ctx->encoder->channels = ctx->channels;
    1450             : 
    1451             :                 //TODO
    1452          10 :                 prop = gf_filter_pid_get_property(pid, GF_PROP_PID_CHANNEL_LAYOUT);
    1453          10 :                 if (prop) {
    1454          10 :                         ctx->encoder->channel_layout = ffmpeg_channel_layout_from_gpac(prop->value.longuint);
    1455           0 :                 } else if (ctx->channels==1) {
    1456           0 :                         ctx->encoder->channel_layout = AV_CH_LAYOUT_MONO;
    1457           0 :                 } else if (ctx->channels==2) {
    1458           0 :                         ctx->encoder->channel_layout = AV_CH_LAYOUT_STEREO;
    1459             :                 }
    1460             : 
    1461          10 :                 prop = gf_filter_pid_get_property(pid, GF_PROP_PID_TIMESCALE);
    1462          10 :                 if (prop) {
    1463          10 :                         ctx->encoder->time_base.num = 1;
    1464          10 :                         ctx->encoder->time_base.den = prop->value.uint;
    1465          10 :                         ctx->timescale = prop->value.uint;
    1466             :                 } else {
    1467           0 :                         ctx->encoder->time_base.num = 1;
    1468           0 :                         ctx->encoder->time_base.den = ctx->sample_rate;
    1469           0 :                         ctx->timescale = ctx->sample_rate;
    1470             :                 }
    1471             : 
    1472             :                 //for aac
    1473          10 :                 switch (ctx->codecid) {
    1474           6 :                 case GF_CODECID_AAC_MPEG4:
    1475             :                 case GF_CODECID_AAC_MPEG2_MP:
    1476             :                 case GF_CODECID_AAC_MPEG2_LCP:
    1477             :                 case GF_CODECID_AAC_MPEG2_SSRP:
    1478           6 :                         av_dict_set(&ctx->options, "strict", "experimental", 0);
    1479           6 :                         break;
    1480             :                 }
    1481             : 
    1482          10 :                 if (!ctx->frame)
    1483           8 :                         ctx->frame = av_frame_alloc();
    1484             : 
    1485          10 :                 ctx->enc_buffer_size = ctx->channels*ctx->sample_rate + ENC_BUF_ALLOC_SAFE;
    1486          10 :                 ctx->enc_buffer = gf_realloc(ctx->enc_buffer, sizeof(char) * ctx->enc_buffer_size);
    1487             : 
    1488          10 :                 ctx->encoder->sample_fmt = ctx->sample_fmt;
    1489          10 :                 ctx->planar_audio = gf_audio_fmt_is_planar(afmt);
    1490          10 :                 ctx->frame->format = ctx->encoder->sample_fmt;
    1491             : 
    1492          10 :                 ctx->audio_buffer_size = ctx->sample_rate;
    1493          10 :                 ctx->audio_buffer = gf_realloc(ctx->audio_buffer, sizeof(char) * ctx->enc_buffer_size);
    1494          10 :                 ctx->bytes_per_sample = ctx->channels * gf_audio_fmt_bit_depth(afmt) / 8;
    1495          10 :                 ctx->init_cts_setup = GF_TRUE;
    1496             : 
    1497          10 :                 switch (ctx->codecid) {
    1498           6 :                 case GF_CODECID_AAC_MPEG4:
    1499             :                 case GF_CODECID_AAC_MPEG2_MP:
    1500             :                 case GF_CODECID_AAC_MPEG2_LCP:
    1501             :                 case GF_CODECID_AAC_MPEG2_SSRP:
    1502           6 :                         if (!is_force_reconf) {
    1503             : #ifndef GPAC_DISABLE_AV_PARSERS
    1504             :                                 GF_M4ADecSpecInfo acfg;
    1505             :                                 u8 *dsi;
    1506             :                                 u32 dsi_len;
    1507             :                                 memset(&acfg, 0, sizeof(GF_M4ADecSpecInfo));
    1508           4 :                                 acfg.base_object_type = GF_M4A_AAC_LC;
    1509           4 :                                 acfg.base_sr = ctx->sample_rate;
    1510           4 :                                 acfg.nb_chan = ctx->channels;
    1511             :                                 acfg.sbr_object_type = 0;
    1512           4 :                                 acfg.audioPL = gf_m4a_get_profile(&acfg);
    1513             : 
    1514           4 :                                 gf_m4a_write_config(&acfg, &dsi, &dsi_len);
    1515           4 :                                 gf_filter_pid_set_property(ctx->out_pid, GF_PROP_PID_DECODER_CONFIG, &PROP_DATA_NO_COPY(dsi, dsi_len) );
    1516             : #endif
    1517             :                         }
    1518             :                         break;
    1519             :                 }
    1520             :         }
    1521             : 
    1522          34 :         ffmpeg_set_enc_dec_flags(ctx->options, ctx->encoder);
    1523             : 
    1524          34 :         if (ctx->all_intra) ctx->encoder->gop_size = 0;
    1525          34 :         else if (ctx->gop_size) ctx->encoder->gop_size = ctx->gop_size;
    1526             : 
    1527             :         //by default let libavcodec decide - if single thread is required, let the user define -threads option
    1528          34 :         if (codec->capabilities & AV_CODEC_CAP_AUTO_THREADS)
    1529          10 :                 ctx->encoder->thread_count = 0;
    1530             : 
    1531             : 
    1532          34 :         av_dict_copy(&options, ctx->options, 0);
    1533          34 :         res = avcodec_open2(ctx->encoder, codec, &options );
    1534          34 :         if (res < 0) {
    1535           0 :                 if (options) av_dict_free(&options);
    1536           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[FFEnc] PID %s failed to open codec context: %s\n", gf_filter_pid_get_name(pid), av_err2str(res) ));
    1537             :                 return GF_BAD_PARAM;
    1538             :         }
    1539          34 :         ctx->remap_ts = (ctx->encoder->time_base.den && (ctx->encoder->time_base.den != ctx->timescale)) ? GF_TRUE : GF_FALSE;
    1540          34 :         if (!ctx->target_rate)
    1541          30 :                 ctx->target_rate = (u32)ctx->encoder->bit_rate;
    1542             : 
    1543          34 :         if (options) {
    1544           2 :                 ffmpeg_report_unused_options(filter, options);
    1545           2 :                 av_dict_free(&options);
    1546             :         }
    1547             : 
    1548          34 :         if (!is_force_reconf)
    1549          32 :                 ffenc_copy_pid_props(ctx);
    1550             :         return GF_OK;
    1551             : }
    1552             : 
    1553          60 : static GF_Err ffenc_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
    1554             : {
    1555          60 :         return ffenc_configure_pid_ex(filter, pid, is_remove, GF_FALSE);
    1556             : 
    1557             : }
    1558             : 
    1559             : 
    1560           8 : static GF_Err ffenc_update_arg(GF_Filter *filter, const char *arg_name, const GF_PropertyValue *arg_val)
    1561             : {
    1562             :         s32 res;
    1563             :         char szOverrideOpt[1000];
    1564             :         Bool do_override = GF_FALSE;
    1565           8 :         GF_FFEncodeCtx *ctx = gf_filter_get_udta(filter);
    1566             : 
    1567           8 :         if (!strcmp(arg_name, "global_header"))       return GF_OK;
    1568           8 :         else if (!strcmp(arg_name, "local_header"))   return GF_OK;
    1569           8 :         else if (!strcmp(arg_name, "low_delay"))      ctx->low_delay = GF_TRUE;
    1570             :         //remap some options
    1571           8 :         else if (!strcmp(arg_name, "bitrate") || !strcmp(arg_name, "rate")) arg_name = "b";
    1572             : //      else if (!strcmp(arg_name, "gop")) arg_name = "g";
    1573             :         //disable low delay if these options are set
    1574           8 :         else if (!strcmp(arg_name, "x264opts")) ctx->low_delay = GF_FALSE;
    1575           8 :         else if (!strcmp(arg_name, "profile")) ctx->low_delay = GF_FALSE;
    1576           6 :         else if (!strcmp(arg_name, "preset")) ctx->low_delay = GF_FALSE;
    1577           6 :         else if (!strcmp(arg_name, "tune")) ctx->low_delay = GF_FALSE;
    1578             : 
    1579           8 :         if (!strcmp(arg_name, "g") || !strcmp(arg_name, "gop"))
    1580           0 :                 ctx->gop_size = arg_val->value.string ? atoi(arg_val->value.string) : 25;
    1581             : 
    1582           8 :         if (!strcmp(arg_name, "b") && arg_val->value.string) {
    1583           2 :                 ctx->target_rate = atoi(arg_val->value.string);
    1584           2 :                 if (strchr(arg_val->value.string, 'm') || strchr(arg_val->value.string, 'M'))
    1585           0 :                         ctx->target_rate *= 1000000;
    1586           2 :                 else if (strchr(arg_val->value.string, 'k') || strchr(arg_val->value.string, 'K'))
    1587           2 :                         ctx->target_rate *= 1000;
    1588             : 
    1589           2 :                 sprintf(szOverrideOpt, "%d", ctx->target_rate);
    1590             :                 do_override = GF_TRUE;
    1591             :         }
    1592             : 
    1593             :         //initial parsing of arguments
    1594           8 :         if (!ctx->initialized) {
    1595             :                 const char *arg_val_str;
    1596           8 :                 switch (arg_val->type) {
    1597           8 :                 case GF_PROP_STRING:
    1598           8 :                         if (do_override)
    1599             :                                 arg_val_str = szOverrideOpt;
    1600             :                         else {
    1601           6 :                                 arg_val_str = arg_val->value.string;
    1602           6 :                                 if (!arg_val_str) arg_val_str = "1";
    1603             :                         }
    1604           8 :                         res = av_dict_set(&ctx->options, arg_name, arg_val_str, 0);
    1605           8 :                         if (res<0) {
    1606           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[FFEnc] Failed to set option %s:%s\n", arg_name, arg_val ));
    1607             :                         }
    1608             :                         break;
    1609           0 :                 default:
    1610           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[FFEnc] Failed to set option %s:%s, unrecognized type %d\n", arg_name, arg_val, arg_val->type ));
    1611             :                         return GF_NOT_SUPPORTED;
    1612             :                 }
    1613             :                 return GF_OK;
    1614             :         }
    1615             :         //updates of arguments, not supported for ffmpeg decoders
    1616             :         return GF_NOT_SUPPORTED;
    1617             : }
    1618             : 
    1619        1025 : static Bool ffenc_process_event(GF_Filter *filter, const GF_FilterEvent *evt)
    1620             : {
    1621        1025 :         if (evt->base.type==GF_FEVT_ENCODE_HINTS) {
    1622          32 :                 GF_FFEncodeCtx *ctx = gf_filter_get_udta(filter);
    1623          32 :                 if ((ctx->fintra.num<0) && evt->encode_hints.intra_period.den && evt->encode_hints.intra_period.num) {
    1624           2 :                         ctx->fintra = evt->encode_hints.intra_period;
    1625           2 :                         if (!ctx->rc || (gf_list_count(ctx->src_packets) && !ctx->force_reconfig)) {
    1626           2 :                                 ctx->reconfig_pending = GF_TRUE;
    1627           2 :                                 ctx->force_reconfig = GF_TRUE;
    1628             :                         }
    1629             :                 }
    1630             :                 return GF_TRUE;
    1631             :         }
    1632             :         return GF_FALSE;
    1633             : }
    1634             : 
    1635             : static const GF_FilterCapability FFEncodeCaps[] =
    1636             : {
    1637             :         CAP_UINT(GF_CAPS_INPUT_OUTPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
    1638             :         CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_CODECID, GF_CODECID_RAW),
    1639             :         CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
    1640             :         CAP_UINT(GF_CAPS_OUTPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_RAW),
    1641             :         CAP_BOOL(GF_CAPS_OUTPUT_EXCLUDED, GF_PROP_PID_TILE_BASE, GF_TRUE),
    1642             :         //some video encoding dumps in unframe mode, we declare the pid property at runtime
    1643             :         {0},
    1644             :         CAP_UINT(GF_CAPS_INPUT_OUTPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
    1645             :         CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
    1646             :         CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_CODECID, GF_CODECID_RAW),
    1647             :         CAP_UINT(GF_CAPS_OUTPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_RAW),
    1648             : };
    1649             : 
    1650             : GF_FilterRegister FFEncodeRegister = {
    1651             :         .name = "ffenc",
    1652             :         .version=LIBAVCODEC_IDENT,
    1653             :         GF_FS_SET_DESCRIPTION("FFMPEG encoder")
    1654             :         GF_FS_SET_HELP("Encodes audio and video streams.\n"
    1655             :                 "See FFMPEG documentation (https://ffmpeg.org/documentation.html) for more details.\n"
    1656             :                 "To list all supported encoders for your GPAC build, use `gpac -h ffenc:*`.\n"
    1657             :                 "\n"
    1658             :                 "The filter will try to resolve the codec name in [-c]() against a libavcodec codec name (eg `libx264`) and use it if found.\n"
    1659             :                 "If not found, it will consider the name to be a GPAC codec name and find a codec for it. In that case, if no pixel format is given, codecs will be enumerated to find a matching pixel format.\n"
    1660             :                 "\n"
    1661             :                 "Options can be passed from prompt using `-+OPT=VAL` (global options) or appending `::OPT=VAL` to the desired encoder filter.\n"
    1662             :                 "\n"
    1663             :                 "The filter will look for property `TargetRate` on input PID to set the desired bitrate per PID.\n"
    1664             :                 "\n"
    1665             :                 "The filter will force a closed gop boundary:\n"
    1666             :                 "- at each packet with a `FileNumber` property set or a `CueStart` property set to true.\n"
    1667             :                 "- if [-fintra]() and [-rc]() is set.\n"
    1668             :                 "When forcing a closed GOP boundary, the filter will flush, destroy and recreate the encoder to make sure a clean context is used, as currently many encoders in libavcodec do not support clean reset when forcing picture types.\n"
    1669             :                 "If [-fintra]() is not set and the output of the encoder is a DASH session in live profile without segment timeline, [-fintra]() will be set to the target segment duration and [-rc]() will be set.\n"
    1670             :         )
    1671             :         .private_size = sizeof(GF_FFEncodeCtx),
    1672             :         SETCAPS(FFEncodeCaps),
    1673             :         .initialize = ffenc_initialize,
    1674             :         .finalize = ffenc_finalize,
    1675             :         .configure_pid = ffenc_configure_pid,
    1676             :         .process = ffenc_process,
    1677             :         .process_event = ffenc_process_event,
    1678             :         .update_arg = ffenc_update_arg,
    1679             :         .flags = GF_FS_REG_META,
    1680             : };
    1681             : 
    1682             : #define OFFS(_n)        #_n, offsetof(GF_FFEncodeCtx, _n)
    1683             : static const GF_FilterArgs FFEncodeArgs[] =
    1684             : {
    1685             :         { OFFS(c), "codec identifier. Can be any supported GPAC codec name or ffmpeg codec name", GF_PROP_STRING, NULL, NULL, 0},
    1686             :         { OFFS(pfmt), "pixel format for input video. When not set, input format is used", GF_PROP_PIXFMT, "none", NULL, 0},
    1687             :         { OFFS(fintra), "force intra / IDR frames at the given period in sec, eg `fintra=60000/1001` will force an intra every 2 seconds on 29.97 fps video; ignored for audio", GF_PROP_FRACTION, "-1/1", NULL, 0},
    1688             : 
    1689             :         { OFFS(all_intra), "only produce intra frames", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_UPDATE|GF_FS_ARG_HINT_ADVANCED},
    1690             :         { OFFS(ls), "log stats", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
    1691             :         { OFFS(rc), "reset encoder when forcing intra frame (some encoders might not support intra frame forcing)", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
    1692             : 
    1693             :         { "*", -1, "any possible options defined for AVCodecContext and sub-classes. see `gpac -hx ffenc` and `gpac -hx ffenc:*`", GF_PROP_STRING, NULL, NULL, GF_FS_ARG_META},
    1694             :         {0}
    1695             : };
    1696             : 
    1697             : const int FFENC_STATIC_ARGS = (sizeof (FFEncodeArgs) / sizeof (GF_FilterArgs)) - 1;
    1698             : 
    1699        2877 : const GF_FilterRegister *ffenc_register(GF_FilterSession *session)
    1700             : {
    1701        2877 :         ffmpeg_build_register(session, &FFEncodeRegister, FFEncodeArgs, FFENC_STATIC_ARGS, FF_REG_TYPE_ENCODE);
    1702        2877 :         return &FFEncodeRegister;
    1703             : }
    1704             : 
    1705             : 
    1706             : #else
    1707             : #include <gpac/filters.h>
    1708             : const GF_FilterRegister *ffenc_register(GF_FilterSession *session)
    1709             : {
    1710             :         return NULL;
    1711             : }
    1712             : 
    1713             : #endif //GPAC_HAS_FFMPEG
    1714             : 

Generated by: LCOV version 1.13