[FFmpeg-devel] [PATCH] avformat: move internal AVStream related functions and structs to a separate header

James Almer jamrial at gmail.com
Mon Nov 6 17:04:49 EET 2023


Signed-off-by: James Almer <jamrial at gmail.com>
---
 libavformat/Makefile   |   1 +
 libavformat/avformat.c | 214 --------------------------
 libavformat/demux.h    |  29 ----
 libavformat/internal.h | 291 +----------------------------------
 libavformat/stream.c   | 243 +++++++++++++++++++++++++++++
 libavformat/stream.h   | 338 +++++++++++++++++++++++++++++++++++++++++
 6 files changed, 583 insertions(+), 533 deletions(-)
 create mode 100644 libavformat/stream.c
 create mode 100644 libavformat/stream.h

diff --git a/libavformat/Makefile b/libavformat/Makefile
index 329055ccfd..7e457d4695 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 5b8bb7879e..437b043ffd 100644
--- a/libavformat/avformat.c
+++ b/libavformat/avformat.c
@@ -40,54 +40,6 @@
 #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_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)
 {
@@ -144,140 +96,6 @@ void avformat_free_context(AVFormatContext *s)
     av_free(s);
 }
 
-#if FF_API_AVSTREAM_SIDE_DATA
-FF_DISABLE_DEPRECATION_WARNINGS
-uint8_t *av_stream_get_side_data(const AVStream *st,
-                                 enum AVPacketSideDataType type, size_t *size)
-{
-    for (int i = 0; i < st->nb_side_data; i++) {
-        if (st->side_data[i].type == type) {
-            if (size)
-                *size = st->side_data[i].size;
-            return st->side_data[i].data;
-        }
-    }
-    if (size)
-        *size = 0;
-    return NULL;
-}
-
-int av_stream_add_side_data(AVStream *st, enum AVPacketSideDataType type,
-                            uint8_t *data, size_t size)
-{
-    AVPacketSideData *sd, *tmp;
-
-    for (int i = 0; i < st->nb_side_data; i++) {
-        sd = &st->side_data[i];
-
-        if (sd->type == type) {
-            av_freep(&sd->data);
-            sd->data = data;
-            sd->size = size;
-            return 0;
-        }
-    }
-
-    if (st->nb_side_data + 1U > FFMIN(INT_MAX, SIZE_MAX / sizeof(*tmp)))
-        return AVERROR(ERANGE);
-
-    tmp = av_realloc_array(st->side_data, st->nb_side_data + 1, sizeof(*tmp));
-    if (!tmp) {
-        return AVERROR(ENOMEM);
-    }
-
-    st->side_data = tmp;
-    st->nb_side_data++;
-
-    sd = &st->side_data[st->nb_side_data - 1];
-    sd->type = type;
-    sd->data = data;
-    sd->size = size;
-
-    return 0;
-}
-
-uint8_t *av_stream_new_side_data(AVStream *st, enum AVPacketSideDataType type,
-                                 size_t size)
-{
-    int ret;
-    uint8_t *data = av_malloc(size);
-
-    if (!data)
-        return NULL;
-
-    ret = av_stream_add_side_data(st, type, data, size);
-    if (ret < 0) {
-        av_freep(&data);
-        return NULL;
-    }
-
-    return data;
-}
-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;
@@ -752,38 +570,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 1f57e062f6..0682147776 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 7702986c9c..9996b7a770 100644
--- a/libavformat/internal.h
+++ b/libavformat/internal.h
@@ -26,6 +26,7 @@
 #include "libavcodec/packet_internal.h"
 
 #include "avformat.h"
+#include "stream.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,237 +185,6 @@ static av_always_inline FFFormatContext *ffformatcontext(AVFormatContext *s)
     return (FFFormatContext*)s;
 }
 
-typedef struct FFStream {
-    /**
-     * The public context.
-     */
-    AVStream pub;
-
-    /**
-     * 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;
-}
-
 #ifdef __GNUC__
 #define dynarray_add(tab, nb_ptr, elem)\
 do {\
@@ -575,39 +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);
-
 unsigned int ff_codec_get_tag(const AVCodecTag *tags, enum AVCodecID id);
 
 enum AVCodecID ff_codec_get_id(const AVCodecTag *tags, unsigned int tag);
@@ -629,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..79ade33b74
--- /dev/null
+++ b/libavformat/stream.c
@@ -0,0 +1,243 @@
+/*
+ * AVStream 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 <stdint.h>
+
+#include "libavutil/avassert.h"
+
+#include "libavcodec/bsf.h"
+#include "libavcodec/parser.h"
+
+#include "avformat.h"
+#include "stream.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_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 ]);
+}
+
+#if FF_API_AVSTREAM_SIDE_DATA
+FF_DISABLE_DEPRECATION_WARNINGS
+uint8_t *av_stream_get_side_data(const AVStream *st,
+                                 enum AVPacketSideDataType type, size_t *size)
+{
+    for (int i = 0; i < st->nb_side_data; i++) {
+        if (st->side_data[i].type == type) {
+            if (size)
+                *size = st->side_data[i].size;
+            return st->side_data[i].data;
+        }
+    }
+    if (size)
+        *size = 0;
+    return NULL;
+}
+
+int av_stream_add_side_data(AVStream *st, enum AVPacketSideDataType type,
+                            uint8_t *data, size_t size)
+{
+    AVPacketSideData *sd, *tmp;
+
+    for (int i = 0; i < st->nb_side_data; i++) {
+        sd = &st->side_data[i];
+
+        if (sd->type == type) {
+            av_freep(&sd->data);
+            sd->data = data;
+            sd->size = size;
+            return 0;
+        }
+    }
+
+    if (st->nb_side_data + 1U > FFMIN(INT_MAX, SIZE_MAX / sizeof(*tmp)))
+        return AVERROR(ERANGE);
+
+    tmp = av_realloc_array(st->side_data, st->nb_side_data + 1, sizeof(*tmp));
+    if (!tmp) {
+        return AVERROR(ENOMEM);
+    }
+
+    st->side_data = tmp;
+    st->nb_side_data++;
+
+    sd = &st->side_data[st->nb_side_data - 1];
+    sd->type = type;
+    sd->data = data;
+    sd->size = size;
+
+    return 0;
+}
+
+uint8_t *av_stream_new_side_data(AVStream *st, enum AVPacketSideDataType type,
+                                 size_t size)
+{
+    int ret;
+    uint8_t *data = av_malloc(size);
+
+    if (!data)
+        return NULL;
+
+    ret = av_stream_add_side_data(st, type, data, size);
+    if (ret < 0) {
+        av_freep(&data);
+        return NULL;
+    }
+
+    return data;
+}
+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;
+}
+
+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.h b/libavformat/stream.h
new file mode 100644
index 0000000000..d3ca8d626c
--- /dev/null
+++ b/libavformat/stream.h
@@ -0,0 +1,338 @@
+/*
+ * AVStream 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_H
+#define AVFORMAT_STREAM_H
+
+#include <stdint.h>
+
+#include "libavcodec/packet_internal.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;
+
+    /**
+     * 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;
+}
+
+/**
+ * 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);
+
+/**
+ * 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_H */
-- 
2.42.0



More information about the ffmpeg-devel mailing list