avformat: add av_program_copy()

Helper to transfer programs from one muxing context to another.
This commit is contained in:
Gyan Doshi
2023-02-07 18:45:30 +05:30
parent 7623379a77
commit 5c557dd5d5
4 changed files with 140 additions and 1 deletions
+3
View File
@@ -2,6 +2,9 @@ The last version increases of all libraries were on 2025-03-28
API changes, most recent first:
2026-05-05 - xxxxxxxxxxx - lavf 62.15.100 - avformat.h
Add av_program_copy().
2026-05-05 - xxxxxxxxxxx - lavf 62.14.100 - avformat.h
Add av_program_add_stream_index2().
+105
View File
@@ -335,6 +335,111 @@ void av_program_add_stream_index(AVFormatContext *ac, int progid, unsigned idx)
return;
}
int av_program_copy(AVFormatContext *dst, const AVFormatContext *src, int progid, int flags)
{
const AVProgram *src_prog = NULL;
AVProgram *dst_prog = NULL;
int ret, idx = -1, match = -1;
int overwrite = flags & AVFMT_PROGCOPY_OVERWRITE;
if ((flags & AVFMT_PROGCOPY_MATCH_BY_ID) && (flags & AVFMT_PROGCOPY_MATCH_BY_INDEX))
return AVERROR(EINVAL);
else if (flags & AVFMT_PROGCOPY_MATCH_BY_ID)
match = 0;
else if (flags & AVFMT_PROGCOPY_MATCH_BY_INDEX)
match = 1;
for (unsigned i = 0; i < src->nb_programs; i++) {
if (src->programs[i]->id == progid) {
if (src_prog) {
av_log(dst, AV_LOG_ERROR, "multiple programs found in source with same id 0x%04x. Not copying.\n", progid);
return AVERROR(EINVAL);
} else {
src_prog = src->programs[i];
}
}
}
if (!src_prog) {
av_log(dst, AV_LOG_ERROR, "source program not found: id=0x%04x\n", progid);
return AVERROR(EINVAL);
}
for (unsigned i = 0; i < dst->nb_programs; i++) {
if (dst->programs[i]->id == progid) {
if (idx > -1) {
av_log(dst, AV_LOG_ERROR, "multiple programs found in target with same id 0x%04x. Not copying.\n", progid);
return AVERROR(EINVAL);
} else {
idx = i;
}
}
}
if (idx >= 0 && !overwrite)
return AVERROR(EEXIST);
av_log(dst, AV_LOG_TRACE, "%s program: id=0x%04x\n", idx >= 0 ? "overwriting" : "copying", progid);
if (idx >= 0) {
dst_prog = dst->programs[idx];
av_dict_free(&dst_prog->metadata);
av_freep(&dst_prog->stream_index);
dst_prog->nb_stream_indexes = 0;
} else {
dst_prog = av_new_program(dst, progid);
if (!dst_prog)
return AVERROR(ENOMEM);
}
/* public fields */
dst_prog->id = src_prog->id;
dst_prog->flags = src_prog->flags;
dst_prog->discard = src_prog->discard;
dst_prog->program_num = src_prog->program_num;
dst_prog->pmt_pid = src_prog->pmt_pid;
dst_prog->pcr_pid = src_prog->pcr_pid;
dst_prog->pmt_version = src_prog->pmt_version;
if (match == -1 && src->nb_streams) {
match = 0;
for (unsigned i = 0; i < src->nb_streams && !match; i++) {
int src_id = src->streams[i]->id;
if (!src_id) {
match = 1;
break;
}
for (unsigned j=i+1; j < src->nb_streams; j++) {
int sib_id = src->streams[j]->id;
if (src_id == sib_id) {
match = 1;
break;
}
}
}
}
for (unsigned i = 0; i < dst->nb_streams; i++) {
int dst_val = match ? i : dst->streams[i]->id;
for (unsigned j = 0; j < src_prog->nb_stream_indexes; j++) {
int src_val = match ? src_prog->stream_index[j] : src->streams[src_prog->stream_index[j]]->id;
if (dst_val == src_val) {
ret = av_program_add_stream_index2(dst, dst_prog->id, i);
if (ret < 0)
return ret;
}
}
}
ret = av_dict_copy(&dst_prog->metadata, src_prog->metadata, 0);
if (ret < 0)
return ret;
return 0;
}
AVProgram *av_find_program_from_stream(AVFormatContext *ic, AVProgram *last, int s)
{
for (unsigned i = 0; i < ic->nb_programs; i++) {
+31
View File
@@ -2069,6 +2069,37 @@ int avformat_stream_group_add_stream(AVStreamGroup *stg, AVStream *st);
AVProgram *av_new_program(AVFormatContext *s, int id);
#define AVFMT_PROGCOPY_MATCH_BY_ID (1 << 0) ///< match streams using stream id
#define AVFMT_PROGCOPY_MATCH_BY_INDEX (1 << 1) ///< match streams using stream index
#define AVFMT_PROGCOPY_OVERWRITE (1 << 8) ///< overwrite pre-existing program having same ID
/**
* Copy an AVProgram from one AVFormatContext to another.
*
* Streams in the destination context whose designated attribute match the attribute of
* the streams in the source AVProgram index are added to the stream index of the copied
* AVProgram. The attribute is designated using AVFMT_PROGCOPY_MATCH_ flags.
*
* If a new program has to be added, the function expects and requires any existing buffer
* holding the array of pointers to AVPrograms in the destination context to have its size
* be a power-of-two value. This should be the case if all earlier programs were created
* using av_new_program or this function.
*
* @param dst pointer to the target muxer context
* @param src pointer to the source muxer context
* @param progid ID of the program to be copied
* @param flags combination of flags which determine how streams are matched and
* whether pre-existing AVProgram in target is overwritten.
* If no match condition is set, streams will be matched by ids if
* all source stream ids are non-zero and unique, else by index.
*
* @return >= 0 in case of success, Error EEXIST if target already has program with same ID
* and overwrite flag isn't set, else a negative AVERROR code in case of other
* failures.
*/
int av_program_copy(AVFormatContext *dst, const AVFormatContext *src, int progid, int flags);
/**
* @}
*/
+1 -1
View File
@@ -31,7 +31,7 @@
#include "version_major.h"
#define LIBAVFORMAT_VERSION_MINOR 14
#define LIBAVFORMAT_VERSION_MINOR 15
#define LIBAVFORMAT_VERSION_MICRO 100
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \