1
0
mirror of https://git.ffmpeg.org/ffmpeg.git synced 2026-10-24 02:09:03 +03:00

avcodec/bsf: add the side_data bitstream filter

Add a filter that removes side data of the given types from packets and from
the stream, or keeps only the packets carrying side data of any of the given
types, as the select mode of the sidedata frame filter does for frames, but
with a list of types. The types are named by their handle, as option
constants joined with '+'.
This commit is contained in:
Romain Beauxis
2026-10-15 15:38:48 +02:00
committed by Romain Beauxis
parent 5664e9e97f
commit 368aee9d25
11 changed files with 238 additions and 0 deletions

View File

@@ -24,6 +24,7 @@ version 9.1:
- Infinity IMM6 video decoder
- Remove the asf_o demuxer
- D3D12 DirectML zero-copy inference for the ONNX Runtime DNN backend
- side_data bitstream filter
version 9.0:

View File

@@ -1059,6 +1059,30 @@ ffmpeg -i INPUT -c:a copy -bsf:a setts=pts=DTS out.mkv
Log basic packet information. Mainly useful for testing, debugging,
and development.
@section side_data
Remove side data from packets and from the stream, or select packets by their
side data.
It accepts the following parameters:
@table @option
@item remove
Set the side data types to remove, joined with @samp{+}, from the packets and
from the side data of the stream. Each type is given by its handle;
@command{ffmpeg -h bsf=side_data} lists them.
@item select
Set the side data types of the packets to keep, joined with @samp{+}. A packet
is kept if it carries any of them, and dropped otherwise. The selection looks
at the side data before @option{remove} applies. Dropping a packet breaks the
decoding of the packets that depend on it, so this is meant for analysis or for
streams where each packet decodes on its own.
@end table
For example, to drop the display matrix and the replay gain of a stream:
@example
ffmpeg -i INPUT -c copy -bsf:v side_data=remove=displaymatrix+replaygain output.mkv
@end example
@section smpte436m_to_eia608
Convert from a @code{SMPTE_436M_ANC} data stream to a @code{EIA_608} stream,

View File

@@ -66,6 +66,7 @@ extern const FFBitStreamFilter ff_pgs_frame_merge_bsf;
extern const FFBitStreamFilter ff_prores_metadata_bsf;
extern const FFBitStreamFilter ff_remove_extradata_bsf;
extern const FFBitStreamFilter ff_setts_bsf;
extern const FFBitStreamFilter ff_side_data_bsf;
extern const FFBitStreamFilter ff_showinfo_bsf;
extern const FFBitStreamFilter ff_smpte436m_to_eia608_bsf;
extern const FFBitStreamFilter ff_text2movsub_bsf;

View File

@@ -48,6 +48,7 @@ OBJS-$(CONFIG_PRORES_METADATA_BSF) += bsf/prores_metadata.o
OBJS-$(CONFIG_REMOVE_EXTRADATA_BSF) += bsf/remove_extradata.o
OBJS-$(CONFIG_SETTS_BSF) += bsf/setts.o
OBJS-$(CONFIG_SHOWINFO_BSF) += bsf/showinfo.o
OBJS-$(CONFIG_SIDE_DATA_BSF) += bsf/side_data.o
OBJS-$(CONFIG_SMPTE436M_TO_EIA608_BSF) += bsf/smpte436m_to_eia608.o
OBJS-$(CONFIG_TEXT2MOVSUB_BSF) += bsf/movsub.o
OBJS-$(CONFIG_TRACE_HEADERS_BSF) += bsf/trace_headers.o

111
libavcodec/bsf/side_data.c Normal file
View File

@@ -0,0 +1,111 @@
/*
* 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
*/
/**
* @file
* Side data bitstream filter -- remove side data from packets and from the
* stream, or select packets by their side data.
*/
#include "libavcodec/bsf.h"
#include "libavcodec/bsf_internal.h"
#include "libavcodec/packet_internal.h"
#include "libavutil/opt.h"
typedef struct SideDataContext {
const AVClass *class;
int *remove;
unsigned nb_remove;
int *select;
unsigned nb_select;
} SideDataContext;
static int side_data_init(AVBSFContext *ctx)
{
SideDataContext *s = ctx->priv_data;
for (unsigned i = 0; i < s->nb_remove; i++)
av_packet_side_data_remove(ctx->par_out->coded_side_data,
&ctx->par_out->nb_coded_side_data,
s->remove[i]);
return 0;
}
static int is_selected(const SideDataContext *s, const AVPacket *pkt)
{
if (!s->nb_select)
return 1;
for (unsigned i = 0; i < s->nb_select; i++)
if (av_packet_side_data_get(pkt->side_data, pkt->side_data_elems,
s->select[i]))
return 1;
return 0;
}
static int side_data_filter(AVBSFContext *ctx, AVPacket *pkt)
{
SideDataContext *s = ctx->priv_data;
int ret = ff_bsf_get_packet_ref(ctx, pkt);
if (ret < 0)
return ret;
if (!is_selected(s, pkt)) {
av_packet_unref(pkt);
return AVERROR(EAGAIN);
}
for (unsigned i = 0; i < s->nb_remove; i++)
av_packet_side_data_remove(pkt->side_data, &pkt->side_data_elems,
s->remove[i]);
return 0;
}
static const AVOptionArrayDef types_def = { .sep = '+' };
#define OFFSET(x) offsetof(SideDataContext, x)
#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_BSF_PARAM)
#define TYPE_CONST(type, handle) \
{ handle, NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_PKT_DATA_ ## type }, .flags = FLAGS, .unit = "type" },
static const AVOption options[] = {
{ "remove", "side data types to remove, joined with '+'", OFFSET(remove), AV_OPT_TYPE_INT | AV_OPT_TYPE_FLAG_ARRAY, { .arr = &types_def }, 0, AV_PKT_DATA_NB - 1, FLAGS, .unit = "type" },
{ "select", "side data types of the packets to keep, joined with '+'", OFFSET(select), AV_OPT_TYPE_INT | AV_OPT_TYPE_FLAG_ARRAY, { .arr = &types_def }, 0, AV_PKT_DATA_NB - 1, FLAGS, .unit = "type" },
FF_PACKET_SIDE_DATA_HANDLES(TYPE_CONST)
{ NULL },
};
static const AVClass side_data_class = {
.class_name = "side_data bsf",
.item_name = av_default_item_name,
.option = options,
.version = LIBAVUTIL_VERSION_INT,
};
const FFBitStreamFilter ff_side_data_bsf = {
.p.name = "side_data",
.p.priv_class = &side_data_class,
.priv_data_size = sizeof(SideDataContext),
.init = side_data_init,
.filter = side_data_filter,
};

View File

@@ -300,6 +300,25 @@ fate-ffmpeg-trim-bsf-priming-duration: CMD = framecrc -copyts -i $(TARGET_SAMPLE
FATE_SAMPLES_FFMPEG-$(call DEMMUX, MOV, FRAMECRC, TRIM_BSF PIPE_PROTOCOL) += fate-ffmpeg-trim-bsf-priming-untrimmed
fate-ffmpeg-trim-bsf-priming-untrimmed: CMD = framecrc -copyts -i $(TARGET_SAMPLES)/audiomatch/tones_afconvert_16000_mono_aac_lc.m4a -c:a copy -bsf:a trim=start=1:start_type=pkt_index:trim_packets=0 -frames:a 3
FATE_SAMPLES_FFMPEG-$(call DEMMUX, MOV, FRAMECRC, SIDE_DATA_BSF PIPE_PROTOCOL) += fate-ffmpeg-side-data-bsf-remove
fate-ffmpeg-side-data-bsf-remove: CMD = framecrc -i $(TARGET_SAMPLES)/audiomatch/tones_afconvert_16000_mono_aac_lc.m4a -c:a copy -bsf:a side_data=remove=skip_samples -frames:a 2
# Only the first and the last packets carry skip samples: the priming and the
# padding.
FATE_SAMPLES_FFMPEG-$(call DEMMUX, MOV, FRAMECRC, SIDE_DATA_BSF PIPE_PROTOCOL) += fate-ffmpeg-side-data-bsf-select
fate-ffmpeg-side-data-bsf-select: CMD = framecrc -i $(TARGET_SAMPLES)/audiomatch/tones_afconvert_16000_mono_aac_lc.m4a -c:a copy -bsf:a side_data=select=skip_samples -frames:a 2
FATE_SAMPLES_FFMPEG-$(call DEMMUX, MOV, FRAMECRC, SIDE_DATA_BSF PIPE_PROTOCOL) += fate-ffmpeg-side-data-bsf-select-none
fate-ffmpeg-side-data-bsf-select-none: CMD = framecrc -i $(TARGET_SAMPLES)/audiomatch/tones_afconvert_16000_mono_aac_lc.m4a -c:a copy -bsf:a side_data=select=palette -frames:a 2
# The display matrix is stream side data, which ffprobe shows on the output.
# Removing another type keeps it.
FATE_SAMPLES_FFMPEG_FFPROBE-$(call REMUX, MOV, SIDE_DATA_BSF) += fate-ffmpeg-side-data-bsf-keep-stream
fate-ffmpeg-side-data-bsf-keep-stream: CMD = transcode mov $(TARGET_SAMPLES)/filter/sample-in-issue-505.mov mov "-c copy -an -t 0.5 -bsf:v side_data=remove=palette" "-c copy" "-select_streams v -show_entries stream_side_data_list"
FATE_SAMPLES_FFMPEG_FFPROBE-$(call REMUX, MOV, SIDE_DATA_BSF) += fate-ffmpeg-side-data-bsf-remove-stream
fate-ffmpeg-side-data-bsf-remove-stream: CMD = transcode mov $(TARGET_SAMPLES)/filter/sample-in-issue-505.mov mov "-c copy -an -t 0.5 -bsf:v side_data=remove=displaymatrix" "-c copy" "-select_streams v -show_entries stream_side_data_list"
# The composed skips cover 800 + 300 of the 1024 samples, leaving nothing.
FATE_SAMPLES_FFMPEG-$(call DEMMUX, AAC, FRAMECRC, AAC_PARSER TRIM_BSF PIPE_PROTOCOL) += fate-ffmpeg-trim-bsf-skip-samples-empty
fate-ffmpeg-trim-bsf-skip-samples-empty: CMD = framecrc -i $(TARGET_SAMPLES)/audiomatch/tones_afconvert_16000_mono_aac_lc.adts -c:a copy -bsf:a trim=start=3217536,trim=end=3083472

View File

@@ -0,0 +1,34 @@
5e6354ce54a9c6e031beee981a3befbd *tests/data/fate/ffmpeg-side-data-bsf-keep-stream.mov
61851 tests/data/fate/ffmpeg-side-data-bsf-keep-stream.mov
#extradata 0: 29, 0x757e07f6
#tb 0: 1/19200
#media_type 0: video
#codec_id 0: h264
#dimensions 0: 480x272
#sar 0: 0/1
0, 0, 0, 640, 21606, 0x5ac94251
0, 640, 640, 640, 3931, 0x753d20e1, F=0x0
0, 1280, 1280, 640, 3086, 0xe338e2f2, F=0x0
0, 1920, 1920, 640, 1770, 0xcfaf2034, F=0x0
0, 2560, 2560, 640, 3240, 0xaa21fc9b, F=0x0
0, 3200, 3200, 640, 1283, 0x63254a14, F=0x0
0, 3840, 3840, 640, 2747, 0x1eaf0ce0, F=0x0
0, 4480, 4480, 640, 2765, 0x12700d6d, F=0x0
0, 5120, 5120, 640, 3109, 0xd340baa5, F=0x0
0, 5760, 5760, 640, 3435, 0xb2cc6f4b, F=0x0
0, 6400, 6400, 640, 3255, 0xd79c0f3e, F=0x0
0, 7040, 7040, 640, 2968, 0xf29089f2, F=0x0
0, 7680, 7680, 640, 2825, 0x270546c9, F=0x0
0, 8320, 8320, 640, 2543, 0x6a95941c, F=0x0
0, 8960, 8960, 640, 2355, 0x476128dc, F=0x0
[STREAM]
[SIDE_DATA]
side_data_type=Display Matrix
displaymatrix=
00000000: 0 65536 0
00000001: -65536 0 0
00000002: 17825792 0 1073741824
rotation=-90
[/SIDE_DATA]
[/STREAM]

View File

@@ -0,0 +1,8 @@
#extradata 0: 2, 0x0030001c
#tb 0: 1/16000
#media_type 0: audio
#codec_id 0: aac
#sample_rate 0: 16000
#channel_layout_name 0: mono
0, -2112, -2112, 1024, 4, 0x02f70117
0, -1088, -1088, 1024, 163, 0xd5f85007

View File

@@ -0,0 +1,25 @@
7c5b0bf7edaabe9d5267a69d2261cf00 *tests/data/fate/ffmpeg-side-data-bsf-remove-stream.mov
61851 tests/data/fate/ffmpeg-side-data-bsf-remove-stream.mov
#extradata 0: 29, 0x757e07f6
#tb 0: 1/19200
#media_type 0: video
#codec_id 0: h264
#dimensions 0: 480x272
#sar 0: 0/1
0, 0, 0, 640, 21606, 0x5ac94251
0, 640, 640, 640, 3931, 0x753d20e1, F=0x0
0, 1280, 1280, 640, 3086, 0xe338e2f2, F=0x0
0, 1920, 1920, 640, 1770, 0xcfaf2034, F=0x0
0, 2560, 2560, 640, 3240, 0xaa21fc9b, F=0x0
0, 3200, 3200, 640, 1283, 0x63254a14, F=0x0
0, 3840, 3840, 640, 2747, 0x1eaf0ce0, F=0x0
0, 4480, 4480, 640, 2765, 0x12700d6d, F=0x0
0, 5120, 5120, 640, 3109, 0xd340baa5, F=0x0
0, 5760, 5760, 640, 3435, 0xb2cc6f4b, F=0x0
0, 6400, 6400, 640, 3255, 0xd79c0f3e, F=0x0
0, 7040, 7040, 640, 2968, 0xf29089f2, F=0x0
0, 7680, 7680, 640, 2825, 0x270546c9, F=0x0
0, 8320, 8320, 640, 2543, 0x6a95941c, F=0x0
0, 8960, 8960, 640, 2355, 0x476128dc, F=0x0
[STREAM]
[/STREAM]

View File

@@ -0,0 +1,8 @@
#extradata 0: 2, 0x0030001c
#tb 0: 1/16000
#media_type 0: audio
#codec_id 0: aac
#sample_rate 0: 16000
#channel_layout_name 0: mono
0, -2112, -2112, 1024, 4, 0x02f70117, S=1, Skip Samples, 10, 0x02c80048
0, 31680, 31680, 1024, 137, 0x90c639e0, S=1, Skip Samples, 10, 0x048a00c2

View File

@@ -0,0 +1,6 @@
#extradata 0: 2, 0x0030001c
#tb 0: 1/16000
#media_type 0: audio
#codec_id 0: aac
#sample_rate 0: 16000
#channel_layout_name 0: mono