From patchwork Tue Jan 16 00:50:31 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Almer X-Patchwork-Id: 45608 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a21:8199:b0:199:de12:6fa6 with SMTP id pd25csp1713710pzb; Mon, 15 Jan 2024 16:50:55 -0800 (PST) X-Google-Smtp-Source: AGHT+IE7nN4ICQZbi9bHBRuZvYMrj0N+jPncVHYqttL+X3cHkA9L4tMYHfzflkLU+Fgwtr4wAOsp X-Received: by 2002:a17:906:fb03:b0:a26:84d8:9411 with SMTP id lz3-20020a170906fb0300b00a2684d89411mr2269206ejb.128.1705366255151; Mon, 15 Jan 2024 16:50:55 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1705366255; cv=none; d=google.com; s=arc-20160816; b=nUg0Xnpc/CHepusmifoJCPgjHzbJ8bQnpgiZEdMlhjTkkpXgtyiVrNkycJD4o5yKhw +JRDQ46zy01oPsUXg8NiiSQDbaXQ/PbTeyKRccU9LVVaZleGviSc7l4ziCV9s662M1rH ILDk3Gbmxhj93dYcVew665qa07YmJrD4l3JQFuMzUEE0GQuZ28YYApwrl9Wyt6Lv3ew/ TEDb9UKhFz9dsjq7AL252og6/n1ee2rUh7jE5zNlaVEB1kRca8NoqkxV1aiPCQKCywgN tW3ylAcisdLYbQTNZeHluT0UWHiDkygR/GPVUboZe+r7Wo8HukD+XoUDRjzQrAdTFvAE HgHQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:reply-to:list-subscribe :list-help:list-post:list-archive:list-unsubscribe:list-id :precedence:subject:mime-version:message-id:date:to:from :dkim-signature:delivered-to; bh=LlhgrzRBzWuUPc093sAzfWvwWDwBcMeyooU0EWIss7A=; fh=YOA8vD9MJZuwZ71F/05pj6KdCjf6jQRmzLS+CATXUQk=; b=qGsP0r+RnIOj9Ywv/cw7p3JrtTMI2Eo2tV4Ad7SQm6mcZza+MMVIXLG9kSbpMdmOEN +2k4vwhwTBis8zpcFsJzr830mtv3P74hhRVSMGxh1aC5GddWvnOdQyFekSHf42eHaqaQ 5EXrCE3zbptSiohnWOfkh4RSEtLo1InAbjXZ7570W1KgfnNQCZCtdPP1o2lbD9u7R9W6 rHbWRzLaT8k920WIbWvQ2VTWstVdHnXGNHhUTJjKIq4rTiLStbPa1JiV4GsXUAU3MKgU odGpKyKYUuaXYhJjltbEyIDUeIPiC0SlcEv1JxPmQ+ltxEqLloBXvcwkfrbaf3XXVEhU IS0w== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20230601 header.b=eKiZ7yGh; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id q2-20020a170906a08200b00a28ba1f1028si4091282ejy.408.2024.01.15.16.50.54; Mon, 15 Jan 2024 16:50:55 -0800 (PST) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20230601 header.b=eKiZ7yGh; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 2BFDF68D001; Tue, 16 Jan 2024 02:50:51 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-pg1-f171.google.com (mail-pg1-f171.google.com [209.85.215.171]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 5DD3B68CD84 for ; Tue, 16 Jan 2024 02:50:45 +0200 (EET) Received: by mail-pg1-f171.google.com with SMTP id 41be03b00d2f7-5bdbe2de25fso7310254a12.3 for ; Mon, 15 Jan 2024 16:50:45 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1705366243; x=1705971043; darn=ffmpeg.org; h=content-transfer-encoding:mime-version:message-id:date:subject:to :from:from:to:cc:subject:date:message-id:reply-to; bh=HXbyk4afOxT4qJr3NeG5+6iC7LHaPFUygKQA0xtEII4=; b=eKiZ7yGhkD2FJhw2F86j7lLCFTz70XvoJAJbz5XQxzlOu2Os3ain++yCm0mk+KONpp KY2vdfBA4P8nCaDUauBn0xbXpBmQktLS6vwrxSa4oGMmR+AqsREi5gaPlAC41caQmDHo wYn2C1nmQyL9bGzqL63aeS/u0eULqNJbcXfUeLHgBRlBl7rlKgKmXivSrDS8OLdYXcLD lsNbU3+cnP+24kFs2ef46UGCAltPXLs9s4BFJsPFdHT7DXTdItgkhC1q4BUAL2Vq4qqt +/GEoKRUuLJhCQmdek/sJBXhXSSBZJNQ7tYQX1hWMzG2P4KDxbPw+1L0JvRLl3IZpfqu 8ajQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1705366243; x=1705971043; h=content-transfer-encoding:mime-version:message-id:date:subject:to :from:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=HXbyk4afOxT4qJr3NeG5+6iC7LHaPFUygKQA0xtEII4=; b=hfDk3LZA4Tn9w1KwkOu3twW26aBvi1MeFlOgBOtvced67kg0T324waHDtk8PcNwz0x y3vu3a2HbopBu8HsAwevTCCQ7+TQVy1Zq2h1a1yzDiiDRcaCS0TW+7QFTiHKhIs04igb BiBNgl5AlqLeZvzbziggLwOUNDfKRYjks8IKgMrIz42c8jy9gTfCqH1vkfEFlP9kWucW u57D5Fi1w+H5beWfkNSVLM1RpfR1dbCmpDNOa+ro+JLE4hoR3McKBYFg6iiWaLYQI5tb h9okdJFLA4QbyuoiCAhG7qw+LU0yA9mKiYauE0+QH1eodta5T7UHFriZHZqFCWMQoskI KV1w== X-Gm-Message-State: AOJu0Ywlh8betFvfE62bsz6IpjizvcXr2AYAesEOVreE559jiJh30k1i Fn3dVhhi5dkE2a+UytCwDRB3jLqWILc= X-Received: by 2002:a05:6a20:4392:b0:19a:9a41:d73f with SMTP id i18-20020a056a20439200b0019a9a41d73fmr7529733pzl.86.1705366242054; Mon, 15 Jan 2024 16:50:42 -0800 (PST) Received: from localhost.localdomain (host197.190-225-105.telecom.net.ar. [190.225.105.197]) by smtp.gmail.com with ESMTPSA id c185-20020a6335c2000000b005cee9115cb3sm8844132pga.0.2024.01.15.16.50.40 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 15 Jan 2024 16:50:41 -0800 (PST) From: James Almer To: ffmpeg-devel@ffmpeg.org Date: Mon, 15 Jan 2024 21:50:31 -0300 Message-ID: <20240116005031.30423-1-jamrial@gmail.com> X-Mailer: git-send-email 2.43.0 MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH] avformat: move internal stream related functions and structs to a separate header X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: iwFXo03LHSPD Signed-off-by: James Almer --- libavformat/Makefile | 1 + libavformat/avformat.c | 171 ---------------- libavformat/demux.h | 29 --- libavformat/internal.h | 319 +--------------------------- libavformat/stream.c | 196 ++++++++++++++++++ libavformat/stream_internal.h | 376 ++++++++++++++++++++++++++++++++++ 6 files changed, 574 insertions(+), 518 deletions(-) create mode 100644 libavformat/stream.c create mode 100644 libavformat/stream_internal.h diff --git a/libavformat/Makefile b/libavformat/Makefile index dcc99eeac4..6dd9b10e6b 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -27,6 +27,7 @@ OBJS = allformats.o \ riff.o \ sdp.o \ seek.o \ + stream.o \ url.o \ utils.o \ version.o \ diff --git a/libavformat/avformat.c b/libavformat/avformat.c index 882927f7b1..596d1dfb92 100644 --- a/libavformat/avformat.c +++ b/libavformat/avformat.c @@ -24,7 +24,6 @@ #include "libavutil/avstring.h" #include "libavutil/channel_layout.h" #include "libavutil/frame.h" -#include "libavutil/iamf.h" #include "libavutil/intreadwrite.h" #include "libavutil/mem.h" #include "libavutil/opt.h" @@ -32,89 +31,13 @@ #include "libavutil/samplefmt.h" #include "libavcodec/avcodec.h" #include "libavcodec/codec.h" -#include "libavcodec/bsf.h" #include "libavcodec/codec_desc.h" -#include "libavcodec/packet_internal.h" #include "avformat.h" #include "avio.h" #include "demux.h" #include "mux.h" #include "internal.h" -void ff_free_stream(AVStream **pst) -{ - AVStream *st = *pst; - FFStream *const sti = ffstream(st); - - if (!st) - return; - -#if FF_API_AVSTREAM_SIDE_DATA -FF_DISABLE_DEPRECATION_WARNINGS - for (int i = 0; i < st->nb_side_data; i++) - av_freep(&st->side_data[i].data); - av_freep(&st->side_data); -FF_ENABLE_DEPRECATION_WARNINGS -#endif - - if (st->attached_pic.data) - av_packet_unref(&st->attached_pic); - - av_parser_close(sti->parser); - avcodec_free_context(&sti->avctx); - av_bsf_free(&sti->bsfc); - av_freep(&sti->priv_pts); - av_freep(&sti->index_entries); - av_freep(&sti->probe_data.buf); - - av_bsf_free(&sti->extract_extradata.bsf); - - if (sti->info) { - av_freep(&sti->info->duration_error); - av_freep(&sti->info); - } - - av_dict_free(&st->metadata); - avcodec_parameters_free(&st->codecpar); - av_freep(&st->priv_data); - - av_freep(pst); -} - -void ff_free_stream_group(AVStreamGroup **pstg) -{ - AVStreamGroup *stg = *pstg; - - if (!stg) - return; - - av_freep(&stg->streams); - av_dict_free(&stg->metadata); - av_freep(&stg->priv_data); - switch (stg->type) { - case AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT: { - av_iamf_audio_element_free(&stg->params.iamf_audio_element); - break; - } - case AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION: { - av_iamf_mix_presentation_free(&stg->params.iamf_mix_presentation); - break; - } - default: - break; - } - - av_freep(pstg); -} - -void ff_remove_stream(AVFormatContext *s, AVStream *st) -{ - av_assert0(s->nb_streams>0); - av_assert0(s->streams[ s->nb_streams - 1 ] == st); - - ff_free_stream(&s->streams[ --s->nb_streams ]); -} - /* XXX: suppress the packet queue */ void ff_flush_packet_queue(AVFormatContext *s) { @@ -247,68 +170,6 @@ uint8_t *av_stream_new_side_data(AVStream *st, enum AVPacketSideDataType type, FF_ENABLE_DEPRECATION_WARNINGS #endif -/** - * Copy all stream parameters from source to destination stream, with the - * exception of the index field, which is usually set by avformat_new_stream(). - * - * @param dst pointer to destination AVStream - * @param src pointer to source AVStream - * @return >=0 on success, AVERROR code on error - */ -static int stream_params_copy(AVStream *dst, const AVStream *src) -{ - int ret; - - dst->id = src->id; - dst->time_base = src->time_base; - dst->start_time = src->start_time; - dst->duration = src->duration; - dst->nb_frames = src->nb_frames; - dst->disposition = src->disposition; - dst->discard = src->discard; - dst->sample_aspect_ratio = src->sample_aspect_ratio; - dst->avg_frame_rate = src->avg_frame_rate; - dst->event_flags = src->event_flags; - dst->r_frame_rate = src->r_frame_rate; - dst->pts_wrap_bits = src->pts_wrap_bits; - - av_dict_free(&dst->metadata); - ret = av_dict_copy(&dst->metadata, src->metadata, 0); - if (ret < 0) - return ret; - - ret = avcodec_parameters_copy(dst->codecpar, src->codecpar); - if (ret < 0) - return ret; - - av_packet_unref(&dst->attached_pic); - if (src->attached_pic.data) { - ret = av_packet_ref(&dst->attached_pic, &src->attached_pic); - if (ret < 0) - return ret; - } - - return 0; -} - -AVStream *ff_stream_clone(AVFormatContext *dst_ctx, const AVStream *src) -{ - AVStream *st; - int ret; - - st = avformat_new_stream(dst_ctx, NULL); - if (!st) - return NULL; - - ret = stream_params_copy(st, src); - if (ret < 0) { - ff_remove_stream(dst_ctx, st); - return NULL; - } - - return st; -} - AVProgram *av_new_program(AVFormatContext *ac, int id) { AVProgram *program = NULL; @@ -825,38 +686,6 @@ FF_ENABLE_DEPRECATION_WARNINGS return 0; } -AVRational av_stream_get_codec_timebase(const AVStream *st) -{ - // See avformat_transfer_internal_stream_timing_info() TODO. - return cffstream(st)->avctx->time_base; -} - -void avpriv_set_pts_info(AVStream *st, int pts_wrap_bits, - unsigned int pts_num, unsigned int pts_den) -{ - FFStream *const sti = ffstream(st); - AVRational new_tb; - if (av_reduce(&new_tb.num, &new_tb.den, pts_num, pts_den, INT_MAX)) { - if (new_tb.num != pts_num) - av_log(NULL, AV_LOG_DEBUG, - "st:%d removing common factor %d from timebase\n", - st->index, pts_num / new_tb.num); - } else - av_log(NULL, AV_LOG_WARNING, - "st:%d has too large timebase, reducing\n", st->index); - - if (new_tb.num <= 0 || new_tb.den <= 0) { - av_log(NULL, AV_LOG_ERROR, - "Ignoring attempt to set invalid timebase %d/%d for st:%d\n", - new_tb.num, new_tb.den, - st->index); - return; - } - st->time_base = new_tb; - sti->avctx->pkt_timebase = new_tb; - st->pts_wrap_bits = pts_wrap_bits; -} - const AVCodec *ff_find_decoder(AVFormatContext *s, const AVStream *st, enum AVCodecID codec_id) { diff --git a/libavformat/demux.h b/libavformat/demux.h index d65eb16ff8..ac822e0d58 100644 --- a/libavformat/demux.h +++ b/libavformat/demux.h @@ -26,35 +26,6 @@ #include "libavcodec/packet.h" #include "avformat.h" -#define MAX_STD_TIMEBASES (30*12+30+3+6) -typedef struct FFStreamInfo { - int64_t last_dts; - int64_t duration_gcd; - int duration_count; - int64_t rfps_duration_sum; - double (*duration_error)[2][MAX_STD_TIMEBASES]; - int64_t codec_info_duration; - int64_t codec_info_duration_fields; - int frame_delay_evidence; - - /** - * 0 -> decoder has not been searched for yet. - * >0 -> decoder found - * <0 -> decoder with codec_id == -found_decoder has not been found - */ - int found_decoder; - - int64_t last_duration; - - /** - * Those are used for average framerate estimation. - */ - int64_t fps_first_dts; - int fps_first_dts_idx; - int64_t fps_last_dts; - int fps_last_dts_idx; -} FFStreamInfo; - /** * Returned by demuxers to indicate that data was consumed but discarded * (ignored streams or junk data). The framework will re-call the demuxer. diff --git a/libavformat/internal.h b/libavformat/internal.h index f93832b3c4..f97ebc818f 100644 --- a/libavformat/internal.h +++ b/libavformat/internal.h @@ -26,6 +26,7 @@ #include "libavcodec/packet_internal.h" #include "avformat.h" +#include "stream_internal.h" #define MAX_URL_SIZE 4096 @@ -55,18 +56,6 @@ typedef struct CodecMime{ enum AVCodecID id; } CodecMime; -/*************************************************/ -/* fractional numbers for exact pts handling */ - -/** - * The exact value of the fractional number is: 'val + num / den'. - * num is assumed to be 0 <= num < den. - */ -typedef struct FFFrac { - int64_t val, num, den; -} FFFrac; - - typedef struct FFFormatContext { /** * The public context. @@ -196,258 +185,6 @@ static av_always_inline FFFormatContext *ffformatcontext(AVFormatContext *s) return (FFFormatContext*)s; } -typedef struct FFStream { - /** - * The public context. - */ - AVStream pub; - - AVFormatContext *fmtctx; - /** - * Set to 1 if the codec allows reordering, so pts can be different - * from dts. - */ - int reorder; - - /** - * bitstream filter to run on stream - * - encoding: Set by muxer using ff_stream_add_bitstream_filter - * - decoding: unused - */ - struct AVBSFContext *bsfc; - - /** - * Whether or not check_bitstream should still be run on each packet - */ - int bitstream_checked; - - /** - * The codec context used by avformat_find_stream_info, the parser, etc. - */ - struct AVCodecContext *avctx; - /** - * 1 if avctx has been initialized with the values from the codec parameters - */ - int avctx_inited; - - /* the context for extracting extradata in find_stream_info() - * inited=1/bsf=NULL signals that extracting is not possible (codec not - * supported) */ - struct { - struct AVBSFContext *bsf; - int inited; - } extract_extradata; - - /** - * Whether the internal avctx needs to be updated from codecpar (after a late change to codecpar) - */ - int need_context_update; - - int is_intra_only; - - FFFrac *priv_pts; - - /** - * Stream information used internally by avformat_find_stream_info() - */ - struct FFStreamInfo *info; - - AVIndexEntry *index_entries; /**< Only used if the format does not - support seeking natively. */ - int nb_index_entries; - unsigned int index_entries_allocated_size; - - int64_t interleaver_chunk_size; - int64_t interleaver_chunk_duration; - - /** - * stream probing state - * -1 -> probing finished - * 0 -> no probing requested - * rest -> perform probing with request_probe being the minimum score to accept. - */ - int request_probe; - /** - * Indicates that everything up to the next keyframe - * should be discarded. - */ - int skip_to_keyframe; - - /** - * Number of samples to skip at the start of the frame decoded from the next packet. - */ - int skip_samples; - - /** - * If not 0, the number of samples that should be skipped from the start of - * the stream (the samples are removed from packets with pts==0, which also - * assumes negative timestamps do not happen). - * Intended for use with formats such as mp3 with ad-hoc gapless audio - * support. - */ - int64_t start_skip_samples; - - /** - * If not 0, the first audio sample that should be discarded from the stream. - * This is broken by design (needs global sample count), but can't be - * avoided for broken by design formats such as mp3 with ad-hoc gapless - * audio support. - */ - int64_t first_discard_sample; - - /** - * The sample after last sample that is intended to be discarded after - * first_discard_sample. Works on frame boundaries only. Used to prevent - * early EOF if the gapless info is broken (considered concatenated mp3s). - */ - int64_t last_discard_sample; - - /** - * Number of internally decoded frames, used internally in libavformat, do not access - * its lifetime differs from info which is why it is not in that structure. - */ - int nb_decoded_frames; - - /** - * Timestamp offset added to timestamps before muxing - */ - int64_t mux_ts_offset; - - /** - * This is the lowest ts allowed in this track; it may be set by the muxer - * during init or write_header and influences the automatic timestamp - * shifting code. - */ - int64_t lowest_ts_allowed; - - /** - * Internal data to check for wrapping of the time stamp - */ - int64_t pts_wrap_reference; - - /** - * Options for behavior, when a wrap is detected. - * - * Defined by AV_PTS_WRAP_ values. - * - * If correction is enabled, there are two possibilities: - * If the first time stamp is near the wrap point, the wrap offset - * will be subtracted, which will create negative time stamps. - * Otherwise the offset will be added. - */ - int pts_wrap_behavior; - - /** - * Internal data to prevent doing update_initial_durations() twice - */ - int update_initial_durations_done; - -#define MAX_REORDER_DELAY 16 - - /** - * Internal data to generate dts from pts - */ - int64_t pts_reorder_error[MAX_REORDER_DELAY+1]; - uint8_t pts_reorder_error_count[MAX_REORDER_DELAY+1]; - - int64_t pts_buffer[MAX_REORDER_DELAY+1]; - - /** - * Internal data to analyze DTS and detect faulty mpeg streams - */ - int64_t last_dts_for_order_check; - uint8_t dts_ordered; - uint8_t dts_misordered; - -#if FF_API_AVSTREAM_SIDE_DATA - /** - * Internal data to inject global side data - */ - int inject_global_side_data; -#endif - - /** - * display aspect ratio (0 if unknown) - * - encoding: unused - * - decoding: Set by libavformat to calculate sample_aspect_ratio internally - */ - AVRational display_aspect_ratio; - - AVProbeData probe_data; - - /** - * last packet in packet_buffer for this stream when muxing. - */ - PacketListEntry *last_in_packet_buffer; - - int64_t last_IP_pts; - int last_IP_duration; - - /** - * Number of packets to buffer for codec probing - */ - int probe_packets; - - /* av_read_frame() support */ - enum AVStreamParseType need_parsing; - struct AVCodecParserContext *parser; - - /** - * Number of frames that have been demuxed during avformat_find_stream_info() - */ - int codec_info_nb_frames; - - /** - * Stream Identifier - * This is the MPEG-TS stream identifier +1 - * 0 means unknown - */ - int stream_identifier; - - // Timestamp generation support: - /** - * Timestamp corresponding to the last dts sync point. - * - * Initialized when AVCodecParserContext.dts_sync_point >= 0 and - * a DTS is received from the underlying container. Otherwise set to - * AV_NOPTS_VALUE by default. - */ - int64_t first_dts; - int64_t cur_dts; - - const struct AVCodecDescriptor *codec_desc; -} FFStream; - -static av_always_inline FFStream *ffstream(AVStream *st) -{ - return (FFStream*)st; -} - -static av_always_inline const FFStream *cffstream(const AVStream *st) -{ - return (const FFStream*)st; -} - -typedef struct FFStreamGroup { - /** - * The public context. - */ - AVStreamGroup pub; - - AVFormatContext *fmtctx; -} FFStreamGroup; - - -static av_always_inline FFStreamGroup *ffstreamgroup(AVStreamGroup *stg) -{ - return (FFStreamGroup*)stg; -} - -static av_always_inline const FFStreamGroup *cffstreamgroup(const AVStreamGroup *stg) -{ - return (const FFStreamGroup*)stg; -} - #ifdef __GNUC__ #define dynarray_add(tab, nb_ptr, elem)\ do {\ @@ -596,46 +333,12 @@ enum AVCodecID ff_guess_image2_codec(const char *filename); const struct AVCodec *ff_find_decoder(AVFormatContext *s, const AVStream *st, enum AVCodecID codec_id); -/** - * Set the time base and wrapping info for a given stream. This will be used - * to interpret the stream's timestamps. If the new time base is invalid - * (numerator or denominator are non-positive), it leaves the stream - * unchanged. - * - * @param st stream - * @param pts_wrap_bits number of bits effectively used by the pts - * (used for wrap control) - * @param pts_num time base numerator - * @param pts_den time base denominator - */ -void avpriv_set_pts_info(AVStream *st, int pts_wrap_bits, - unsigned int pts_num, unsigned int pts_den); - /** * Set the timebase for each stream from the corresponding codec timebase and * print it. */ int ff_framehash_write_header(AVFormatContext *s); -/** - * Frees a stream without modifying the corresponding AVFormatContext. - * Must only be called if the latter doesn't matter or if the stream - * is not yet attached to an AVFormatContext. - */ -void ff_free_stream(AVStream **st); -/** - * Remove a stream from its AVFormatContext and free it. - * The stream must be the last stream of the AVFormatContext. - */ -void ff_remove_stream(AVFormatContext *s, AVStream *st); - -/** - * Frees a stream group without modifying the corresponding AVFormatContext. - * Must only be called if the latter doesn't matter or if the stream - * is not yet attached to an AVFormatContext. - */ -void ff_free_stream_group(AVStreamGroup **pstg); - unsigned int ff_codec_get_tag(const AVCodecTag *tags, enum AVCodecID id); enum AVCodecID ff_codec_get_id(const AVCodecTag *tags, unsigned int tag); @@ -657,26 +360,6 @@ int ff_is_intra_only(enum AVCodecID id); */ enum AVCodecID ff_get_pcm_codec_id(int bps, int flt, int be, int sflags); -/** - * Copy side data from source to destination stream - * - * @param dst pointer to destination AVStream - * @param src pointer to source AVStream - * @return >=0 on success, AVERROR code on error - */ -int ff_stream_side_data_copy(AVStream *dst, const AVStream *src); - -/** - * Create a new stream and copy to it all parameters from a source stream, with - * the exception of the index field, which is set when the new stream is - * created. - * - * @param dst_ctx pointer to the context in which the new stream is created - * @param src pointer to source AVStream - * @return pointer to the new stream or NULL on error - */ -AVStream *ff_stream_clone(AVFormatContext *dst_ctx, const AVStream *src); - /** * Wrap ffurl_move() and log if error happens. * diff --git a/libavformat/stream.c b/libavformat/stream.c new file mode 100644 index 0000000000..ceaee393ba --- /dev/null +++ b/libavformat/stream.c @@ -0,0 +1,196 @@ +/* + * Stream related functions and structs + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/avassert.h" +#include "libavutil/iamf.h" + +#include "avformat.h" +#include "stream_internal.h" + +void ff_free_stream(AVStream **pst) +{ + AVStream *st = *pst; + FFStream *const sti = ffstream(st); + + if (!st) + return; + +#if FF_API_AVSTREAM_SIDE_DATA +FF_DISABLE_DEPRECATION_WARNINGS + for (int i = 0; i < st->nb_side_data; i++) + av_freep(&st->side_data[i].data); + av_freep(&st->side_data); +FF_ENABLE_DEPRECATION_WARNINGS +#endif + + if (st->attached_pic.data) + av_packet_unref(&st->attached_pic); + + av_parser_close(sti->parser); + avcodec_free_context(&sti->avctx); + av_bsf_free(&sti->bsfc); + av_freep(&sti->priv_pts); + av_freep(&sti->index_entries); + av_freep(&sti->probe_data.buf); + + av_bsf_free(&sti->extract_extradata.bsf); + + if (sti->info) { + av_freep(&sti->info->duration_error); + av_freep(&sti->info); + } + + av_dict_free(&st->metadata); + avcodec_parameters_free(&st->codecpar); + av_freep(&st->priv_data); + + av_freep(pst); +} + +void ff_free_stream_group(AVStreamGroup **pstg) +{ + AVStreamGroup *stg = *pstg; + + if (!stg) + return; + + av_freep(&stg->streams); + av_dict_free(&stg->metadata); + av_freep(&stg->priv_data); + switch (stg->type) { + case AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT: { + av_iamf_audio_element_free(&stg->params.iamf_audio_element); + break; + } + case AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION: { + av_iamf_mix_presentation_free(&stg->params.iamf_mix_presentation); + break; + } + default: + break; + } + + av_freep(pstg); +} + +void ff_remove_stream(AVFormatContext *s, AVStream *st) +{ + av_assert0(s->nb_streams>0); + av_assert0(s->streams[ s->nb_streams - 1 ] == st); + + ff_free_stream(&s->streams[ --s->nb_streams ]); +} + + +/** + * Copy all stream parameters from source to destination stream, with the + * exception of the index field, which is usually set by avformat_new_stream(). + * + * @param dst pointer to destination AVStream + * @param src pointer to source AVStream + * @return >=0 on success, AVERROR code on error + */ +static int stream_params_copy(AVStream *dst, const AVStream *src) +{ + int ret; + + dst->id = src->id; + dst->time_base = src->time_base; + dst->start_time = src->start_time; + dst->duration = src->duration; + dst->nb_frames = src->nb_frames; + dst->disposition = src->disposition; + dst->discard = src->discard; + dst->sample_aspect_ratio = src->sample_aspect_ratio; + dst->avg_frame_rate = src->avg_frame_rate; + dst->event_flags = src->event_flags; + dst->r_frame_rate = src->r_frame_rate; + dst->pts_wrap_bits = src->pts_wrap_bits; + + av_dict_free(&dst->metadata); + ret = av_dict_copy(&dst->metadata, src->metadata, 0); + if (ret < 0) + return ret; + + ret = avcodec_parameters_copy(dst->codecpar, src->codecpar); + if (ret < 0) + return ret; + + av_packet_unref(&dst->attached_pic); + if (src->attached_pic.data) { + ret = av_packet_ref(&dst->attached_pic, &src->attached_pic); + if (ret < 0) + return ret; + } + + return 0; +} + +AVStream *ff_stream_clone(AVFormatContext *dst_ctx, const AVStream *src) +{ + AVStream *st; + int ret; + + st = avformat_new_stream(dst_ctx, NULL); + if (!st) + return NULL; + + ret = stream_params_copy(st, src); + if (ret < 0) { + ff_remove_stream(dst_ctx, st); + return NULL; + } + + return st; +} + +AVRational av_stream_get_codec_timebase(const AVStream *st) +{ + // See avformat_transfer_internal_stream_timing_info() TODO. + return cffstream(st)->avctx->time_base; +} + +void avpriv_set_pts_info(AVStream *st, int pts_wrap_bits, + unsigned int pts_num, unsigned int pts_den) +{ + FFStream *const sti = ffstream(st); + AVRational new_tb; + if (av_reduce(&new_tb.num, &new_tb.den, pts_num, pts_den, INT_MAX)) { + if (new_tb.num != pts_num) + av_log(NULL, AV_LOG_DEBUG, + "st:%d removing common factor %d from timebase\n", + st->index, pts_num / new_tb.num); + } else + av_log(NULL, AV_LOG_WARNING, + "st:%d has too large timebase, reducing\n", st->index); + + if (new_tb.num <= 0 || new_tb.den <= 0) { + av_log(NULL, AV_LOG_ERROR, + "Ignoring attempt to set invalid timebase %d/%d for st:%d\n", + new_tb.num, new_tb.den, + st->index); + return; + } + st->time_base = new_tb; + sti->avctx->pkt_timebase = new_tb; + st->pts_wrap_bits = pts_wrap_bits; +} diff --git a/libavformat/stream_internal.h b/libavformat/stream_internal.h new file mode 100644 index 0000000000..9759f30e3f --- /dev/null +++ b/libavformat/stream_internal.h @@ -0,0 +1,376 @@ +/* + * Stream related functions and structs + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVFORMAT_STREAM_INTERNAL_H +#define AVFORMAT_STREAM_INTERNAL_H + +#include + +#include "libavcodec/bsf.h" +#include "libavcodec/packet_internal.h" +#include "libavcodec/parser.h" +#include "avformat.h" + +/** + * Fractional numbers for exact pts handling + * + * The exact value of the fractional number is: 'val + num / den'. + * num is assumed to be 0 <= num < den. + */ +typedef struct FFFrac { + int64_t val, num, den; +} FFFrac; + +#define MAX_STD_TIMEBASES (30*12+30+3+6) +typedef struct FFStreamInfo { + int64_t last_dts; + int64_t duration_gcd; + int duration_count; + int64_t rfps_duration_sum; + double (*duration_error)[2][MAX_STD_TIMEBASES]; + int64_t codec_info_duration; + int64_t codec_info_duration_fields; + int frame_delay_evidence; + + /** + * 0 -> decoder has not been searched for yet. + * >0 -> decoder found + * <0 -> decoder with codec_id == -found_decoder has not been found + */ + int found_decoder; + + int64_t last_duration; + + /** + * Those are used for average framerate estimation. + */ + int64_t fps_first_dts; + int fps_first_dts_idx; + int64_t fps_last_dts; + int fps_last_dts_idx; +} FFStreamInfo; + +typedef struct FFStream { + /** + * The public context. + */ + AVStream pub; + + AVFormatContext *fmtctx; + /** + * Set to 1 if the codec allows reordering, so pts can be different + * from dts. + */ + int reorder; + + /** + * bitstream filter to run on stream + * - encoding: Set by muxer using ff_stream_add_bitstream_filter + * - decoding: unused + */ + struct AVBSFContext *bsfc; + + /** + * Whether or not check_bitstream should still be run on each packet + */ + int bitstream_checked; + + /** + * The codec context used by avformat_find_stream_info, the parser, etc. + */ + struct AVCodecContext *avctx; + /** + * 1 if avctx has been initialized with the values from the codec parameters + */ + int avctx_inited; + + /* the context for extracting extradata in find_stream_info() + * inited=1/bsf=NULL signals that extracting is not possible (codec not + * supported) */ + struct { + struct AVBSFContext *bsf; + int inited; + } extract_extradata; + + /** + * Whether the internal avctx needs to be updated from codecpar (after a late change to codecpar) + */ + int need_context_update; + + int is_intra_only; + + FFFrac *priv_pts; + + /** + * Stream information used internally by avformat_find_stream_info() + */ + struct FFStreamInfo *info; + + AVIndexEntry *index_entries; /**< Only used if the format does not + support seeking natively. */ + int nb_index_entries; + unsigned int index_entries_allocated_size; + + int64_t interleaver_chunk_size; + int64_t interleaver_chunk_duration; + + /** + * stream probing state + * -1 -> probing finished + * 0 -> no probing requested + * rest -> perform probing with request_probe being the minimum score to accept. + */ + int request_probe; + /** + * Indicates that everything up to the next keyframe + * should be discarded. + */ + int skip_to_keyframe; + + /** + * Number of samples to skip at the start of the frame decoded from the next packet. + */ + int skip_samples; + + /** + * If not 0, the number of samples that should be skipped from the start of + * the stream (the samples are removed from packets with pts==0, which also + * assumes negative timestamps do not happen). + * Intended for use with formats such as mp3 with ad-hoc gapless audio + * support. + */ + int64_t start_skip_samples; + + /** + * If not 0, the first audio sample that should be discarded from the stream. + * This is broken by design (needs global sample count), but can't be + * avoided for broken by design formats such as mp3 with ad-hoc gapless + * audio support. + */ + int64_t first_discard_sample; + + /** + * The sample after last sample that is intended to be discarded after + * first_discard_sample. Works on frame boundaries only. Used to prevent + * early EOF if the gapless info is broken (considered concatenated mp3s). + */ + int64_t last_discard_sample; + + /** + * Number of internally decoded frames, used internally in libavformat, do not access + * its lifetime differs from info which is why it is not in that structure. + */ + int nb_decoded_frames; + + /** + * Timestamp offset added to timestamps before muxing + */ + int64_t mux_ts_offset; + + /** + * This is the lowest ts allowed in this track; it may be set by the muxer + * during init or write_header and influences the automatic timestamp + * shifting code. + */ + int64_t lowest_ts_allowed; + + /** + * Internal data to check for wrapping of the time stamp + */ + int64_t pts_wrap_reference; + + /** + * Options for behavior, when a wrap is detected. + * + * Defined by AV_PTS_WRAP_ values. + * + * If correction is enabled, there are two possibilities: + * If the first time stamp is near the wrap point, the wrap offset + * will be subtracted, which will create negative time stamps. + * Otherwise the offset will be added. + */ + int pts_wrap_behavior; + + /** + * Internal data to prevent doing update_initial_durations() twice + */ + int update_initial_durations_done; + +#define MAX_REORDER_DELAY 16 + + /** + * Internal data to generate dts from pts + */ + int64_t pts_reorder_error[MAX_REORDER_DELAY+1]; + uint8_t pts_reorder_error_count[MAX_REORDER_DELAY+1]; + + int64_t pts_buffer[MAX_REORDER_DELAY+1]; + + /** + * Internal data to analyze DTS and detect faulty mpeg streams + */ + int64_t last_dts_for_order_check; + uint8_t dts_ordered; + uint8_t dts_misordered; + +#if FF_API_AVSTREAM_SIDE_DATA + /** + * Internal data to inject global side data + */ + int inject_global_side_data; +#endif + + /** + * display aspect ratio (0 if unknown) + * - encoding: unused + * - decoding: Set by libavformat to calculate sample_aspect_ratio internally + */ + AVRational display_aspect_ratio; + + AVProbeData probe_data; + + /** + * last packet in packet_buffer for this stream when muxing. + */ + PacketListEntry *last_in_packet_buffer; + + int64_t last_IP_pts; + int last_IP_duration; + + /** + * Number of packets to buffer for codec probing + */ + int probe_packets; + + /* av_read_frame() support */ + enum AVStreamParseType need_parsing; + struct AVCodecParserContext *parser; + + /** + * Number of frames that have been demuxed during avformat_find_stream_info() + */ + int codec_info_nb_frames; + + /** + * Stream Identifier + * This is the MPEG-TS stream identifier +1 + * 0 means unknown + */ + int stream_identifier; + + // Timestamp generation support: + /** + * Timestamp corresponding to the last dts sync point. + * + * Initialized when AVCodecParserContext.dts_sync_point >= 0 and + * a DTS is received from the underlying container. Otherwise set to + * AV_NOPTS_VALUE by default. + */ + int64_t first_dts; + int64_t cur_dts; + + const struct AVCodecDescriptor *codec_desc; +} FFStream; + +static av_always_inline FFStream *ffstream(AVStream *st) +{ + return (FFStream*)st; +} + +static av_always_inline const FFStream *cffstream(const AVStream *st) +{ + return (const FFStream*)st; +} + +typedef struct FFStreamGroup { + /** + * The public context. + */ + AVStreamGroup pub; + + AVFormatContext *fmtctx; +} FFStreamGroup; + + +static av_always_inline FFStreamGroup *ffstreamgroup(AVStreamGroup *stg) +{ + return (FFStreamGroup*)stg; +} + +static av_always_inline const FFStreamGroup *cffstreamgroup(const AVStreamGroup *stg) +{ + return (const FFStreamGroup*)stg; +} + +/** + * Set the time base and wrapping info for a given stream. This will be used + * to interpret the stream's timestamps. If the new time base is invalid + * (numerator or denominator are non-positive), it leaves the stream + * unchanged. + * + * @param st stream + * @param pts_wrap_bits number of bits effectively used by the pts + * (used for wrap control) + * @param pts_num time base numerator + * @param pts_den time base denominator + */ +void avpriv_set_pts_info(AVStream *st, int pts_wrap_bits, + unsigned int pts_num, unsigned int pts_den); + +/** + * Frees a stream without modifying the corresponding AVFormatContext. + * Must only be called if the latter doesn't matter or if the stream + * is not yet attached to an AVFormatContext. + */ +void ff_free_stream(AVStream **st); +/** + * Remove a stream from its AVFormatContext and free it. + * The stream must be the last stream of the AVFormatContext. + */ +void ff_remove_stream(AVFormatContext *s, AVStream *st); + +/** + * Frees a stream group without modifying the corresponding AVFormatContext. + * Must only be called if the latter doesn't matter or if the stream + * is not yet attached to an AVFormatContext. + */ +void ff_free_stream_group(AVStreamGroup **pstg); + +/** + * Copy side data from source to destination stream + * + * @param dst pointer to destination AVStream + * @param src pointer to source AVStream + * @return >=0 on success, AVERROR code on error + */ +int ff_stream_side_data_copy(AVStream *dst, const AVStream *src); + +/** + * Create a new stream and copy to it all parameters from a source stream, with + * the exception of the index field, which is set when the new stream is + * created. + * + * @param dst_ctx pointer to the context in which the new stream is created + * @param src pointer to source AVStream + * @return pointer to the new stream or NULL on error + */ +AVStream *ff_stream_clone(AVFormatContext *dst_ctx, const AVStream *src); + +#endif /* AVFORMAT_STREAM_INTERNAL_H */