Message ID | 20170820224146.21289-14-sw@jkqxz.net |
---|---|
State | Superseded |
Headers | show |
On Sun, Aug 20, 2017 at 11:41:41PM +0100, Mark Thompson wrote: > (cherry picked from commit b78c30d7ec26af67c00ce2002709a189f6a87a7e) > --- > configure | 1 + > doc/bitstream_filters.texi | 36 ++++ > libavcodec/Makefile | 1 + > libavcodec/bitstream_filters.c | 1 + > libavcodec/mpeg2_metadata_bsf.c | 360 ++++++++++++++++++++++++++++++++++++++++ > 5 files changed, 399 insertions(+) > create mode 100644 libavcodec/mpeg2_metadata_bsf.c > > diff --git a/configure b/configure > index 7641bd98d4..1e99038dca 100755 > --- a/configure > +++ b/configure > @@ -2836,6 +2836,7 @@ h264_metadata_bsf_select="cbs_h264" > h264_redundant_pps_bsf_select="cbs_h264" > hevc_metadata_bsf_select="cbs_h265" > mjpeg2jpeg_bsf_select="jpegtables" > +mpeg2_metadata_bsf_select="cbs_mpeg2" > trace_headers_bsf_select="cbs_h264 cbs_h265 cbs_mpeg2" > > # external libraries > diff --git a/doc/bitstream_filters.texi b/doc/bitstream_filters.texi > index 71c307f2e2..8a8756bdcc 100644 > --- a/doc/bitstream_filters.texi > +++ b/doc/bitstream_filters.texi > @@ -324,6 +324,42 @@ See also the @ref{text2movsub} filter. > > Decompress non-standard compressed MP3 audio headers. > > +@section mpeg2_metadata > + > +Modify metadata embedded in an MPEG-2 stream. > + > +@table @option > +@item display_aspect_ratio > +Set the display aspect ratio in the stream. > + > +The following fixed values are supported: > +@table @option > +@item 4/3 > +@item 16/9 > +@item 221/100 > +@end table > +Any other value will result in square pixels being signalled instead > +(see H.262 section 6.3.3 and table 6-3). > + > +@item frame_rate > +Set the frame rate in the stream. This is constructed from a table > +of known values combined with a small multiplier and divisor - if > +the supplied value is not exactly representable, the nearest > +representable value will be used instead (see H.262 section 6.3.3 > +and table 6-4). > + > +@item video_format > +Set the video format in the stream (see H.262 section 6.3.6 and > +table 6-6). > + > +@item colour_primaries > +@item transfer_characteristics > +@item matrix_coefficients > +Set the colour description in the stream (see H.262 section 6.3.6 > +and tables 6-7, 6-8 and 6-9). > + > +@end table > + > @section mpeg4_unpack_bframes > > Unpack DivX-style packed B-frames. > diff --git a/libavcodec/Makefile b/libavcodec/Makefile > index 72f2bb2a12..3da7b9b508 100644 > --- a/libavcodec/Makefile > +++ b/libavcodec/Makefile > @@ -1002,6 +1002,7 @@ OBJS-$(CONFIG_MPEG4_UNPACK_BFRAMES_BSF) += mpeg4_unpack_bframes_bsf.o > OBJS-$(CONFIG_MOV2TEXTSUB_BSF) += movsub_bsf.o > OBJS-$(CONFIG_MP3_HEADER_DECOMPRESS_BSF) += mp3_header_decompress_bsf.o \ > mpegaudiodata.o > +OBJS-$(CONFIG_MPEG2_METADATA_BSF) += mpeg2_metadata_bsf.o > OBJS-$(CONFIG_NOISE_BSF) += noise_bsf.o > OBJS-$(CONFIG_NULL_BSF) += null_bsf.o > OBJS-$(CONFIG_REMOVE_EXTRADATA_BSF) += remove_extradata_bsf.o > diff --git a/libavcodec/bitstream_filters.c b/libavcodec/bitstream_filters.c > index 6e6b894e7f..7b0cb5032a 100644 > --- a/libavcodec/bitstream_filters.c > +++ b/libavcodec/bitstream_filters.c > @@ -38,6 +38,7 @@ extern const AVBitStreamFilter ff_imx_dump_header_bsf; > extern const AVBitStreamFilter ff_mjpeg2jpeg_bsf; > extern const AVBitStreamFilter ff_mjpega_dump_header_bsf; > extern const AVBitStreamFilter ff_mp3_header_decompress_bsf; > +extern const AVBitStreamFilter ff_mpeg2_metadata_bsf; > extern const AVBitStreamFilter ff_mpeg4_unpack_bframes_bsf; > extern const AVBitStreamFilter ff_mov2textsub_bsf; > extern const AVBitStreamFilter ff_noise_bsf; > diff --git a/libavcodec/mpeg2_metadata_bsf.c b/libavcodec/mpeg2_metadata_bsf.c > new file mode 100644 > index 0000000000..b4449eac71 > --- /dev/null > +++ b/libavcodec/mpeg2_metadata_bsf.c > @@ -0,0 +1,360 @@ > +/* > + * 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 "libavutil/avstring.h" > +#include "libavutil/common.h" > +#include "libavutil/opt.h" > + > +#include "bsf.h" > +#include "cbs.h" > +#include "cbs_mpeg2.h" > + > +typedef struct MPEG2MetadataContext { > + const AVClass *class; > + > + CodedBitstreamContext cbc; > + CodedBitstreamFragment fragment; > + > + MPEG2RawExtensionData sequence_display_extension; > + > + AVRational display_aspect_ratio; > + > + AVRational frame_rate; > + > + int video_format; > + int colour_primaries; > + int transfer_characteristics; > + int matrix_coefficients; > + > + int mpeg1_warned; > +} MPEG2MetadataContext; > + > + > +static int mpeg2_metadata_update_fragment(AVBSFContext *bsf, > + CodedBitstreamFragment *frag) > +{ > + MPEG2MetadataContext *ctx = bsf->priv_data; > + MPEG2RawSequenceHeader *sh = NULL; > + MPEG2RawSequenceExtension *se = NULL; > + MPEG2RawSequenceDisplayExtension *sde = NULL; > + int i, se_pos, add_sde = 0; > + > + for (i = 0; i < frag->nb_units; i++) { > + if (frag->units[i].type == MPEG2_START_SEQUENCE_HEADER) { > + sh = frag->units[i].content; > + } else if (frag->units[i].type == MPEG2_START_EXTENSION) { > + MPEG2RawExtensionData *ext = frag->units[i].content; > + if (ext->extension_start_code_identifier == > + MPEG2_EXTENSION_SEQUENCE) { > + se = &ext->data.sequence; > + se_pos = i; > + } else if (ext->extension_start_code_identifier == > + MPEG2_EXTENSION_SEQUENCE_DISPLAY) { > + sde = &ext->data.sequence_display; > + } > + } > + } > + > + if (!sh || !se) { > + // No sequence header and sequence extension: not an MPEG-2 video > + // sequence. > + if (sh && !ctx->mpeg1_warned) { > + av_log(bsf, AV_LOG_WARNING, "Stream contains a sequence " > + "header but not a sequence extension: maybe it's " > + "actually MPEG-1?\n"); > + ctx->mpeg1_warned = 1; > + } > + return 0; > + } > + > + if (ctx->display_aspect_ratio.num && ctx->display_aspect_ratio.den) { > + int num, den; > + > + av_reduce(&num, &den, ctx->display_aspect_ratio.num, > + ctx->display_aspect_ratio.den, 65535); > + > + if (num == 4 && den == 3) > + sh->aspect_ratio_information = 2; > + else if (num == 16 && den == 9) > + sh->aspect_ratio_information = 3; > + else if (num == 221 && den == 100) > + sh->aspect_ratio_information = 4; > + else > + sh->aspect_ratio_information = 1; > + } > + > + if (ctx->frame_rate.num && ctx->frame_rate.den) { > + // Table 6-4. > + static AVRational frame_rate_table[] = { > + { 0, 0 }, > + { 24000, 1001 }, > + { 24, 1 }, > + { 25, 1 }, > + { 30000, 1001 }, > + { 30, 1 }, > + { 50, 1 }, > + { 60000, 1001 }, > + { 60, 1 }, > + }; This is a duplicate of ff_mpeg12_frame_rate_tab also should be static const [...] > +#define OFFSET(x) offsetof(MPEG2MetadataContext, x) > +static const AVOption mpeg2_metadata_options[] = { > + { "display_aspect_ratio", "Set display aspect ratio (table 6-3)", > + OFFSET(display_aspect_ratio), AV_OPT_TYPE_RATIONAL, > + { .i64 = 0 }, 0, 65535 }, > + > + { "frame_rate", "Set frame rate", > + OFFSET(frame_rate), AV_OPT_TYPE_RATIONAL, > + { .i64 = 0 }, 0, UINT_MAX }, for AV_OPT_TYPE_RATIONAL the default is dbl not i64, also this affects some of the other patches as well [...]
On 21/08/17 19:21, Michael Niedermayer wrote: > On Sun, Aug 20, 2017 at 11:41:41PM +0100, Mark Thompson wrote: >> (cherry picked from commit b78c30d7ec26af67c00ce2002709a189f6a87a7e) >> --- >> configure | 1 + >> doc/bitstream_filters.texi | 36 ++++ >> libavcodec/Makefile | 1 + >> libavcodec/bitstream_filters.c | 1 + >> libavcodec/mpeg2_metadata_bsf.c | 360 ++++++++++++++++++++++++++++++++++++++++ >> 5 files changed, 399 insertions(+) >> create mode 100644 libavcodec/mpeg2_metadata_bsf.c >> >> diff --git a/configure b/configure >> index 7641bd98d4..1e99038dca 100755 >> --- a/configure >> +++ b/configure >> @@ -2836,6 +2836,7 @@ h264_metadata_bsf_select="cbs_h264" >> h264_redundant_pps_bsf_select="cbs_h264" >> hevc_metadata_bsf_select="cbs_h265" >> mjpeg2jpeg_bsf_select="jpegtables" >> +mpeg2_metadata_bsf_select="cbs_mpeg2" >> trace_headers_bsf_select="cbs_h264 cbs_h265 cbs_mpeg2" >> >> # external libraries >> diff --git a/doc/bitstream_filters.texi b/doc/bitstream_filters.texi >> index 71c307f2e2..8a8756bdcc 100644 >> --- a/doc/bitstream_filters.texi >> +++ b/doc/bitstream_filters.texi >> @@ -324,6 +324,42 @@ See also the @ref{text2movsub} filter. >> >> Decompress non-standard compressed MP3 audio headers. >> >> +@section mpeg2_metadata >> + >> +Modify metadata embedded in an MPEG-2 stream. >> + >> +@table @option >> +@item display_aspect_ratio >> +Set the display aspect ratio in the stream. >> + >> +The following fixed values are supported: >> +@table @option >> +@item 4/3 >> +@item 16/9 >> +@item 221/100 >> +@end table >> +Any other value will result in square pixels being signalled instead >> +(see H.262 section 6.3.3 and table 6-3). >> + >> +@item frame_rate >> +Set the frame rate in the stream. This is constructed from a table >> +of known values combined with a small multiplier and divisor - if >> +the supplied value is not exactly representable, the nearest >> +representable value will be used instead (see H.262 section 6.3.3 >> +and table 6-4). >> + >> +@item video_format >> +Set the video format in the stream (see H.262 section 6.3.6 and >> +table 6-6). >> + >> +@item colour_primaries >> +@item transfer_characteristics >> +@item matrix_coefficients >> +Set the colour description in the stream (see H.262 section 6.3.6 >> +and tables 6-7, 6-8 and 6-9). >> + >> +@end table >> + >> @section mpeg4_unpack_bframes >> >> Unpack DivX-style packed B-frames. >> diff --git a/libavcodec/Makefile b/libavcodec/Makefile >> index 72f2bb2a12..3da7b9b508 100644 >> --- a/libavcodec/Makefile >> +++ b/libavcodec/Makefile >> @@ -1002,6 +1002,7 @@ OBJS-$(CONFIG_MPEG4_UNPACK_BFRAMES_BSF) += mpeg4_unpack_bframes_bsf.o >> OBJS-$(CONFIG_MOV2TEXTSUB_BSF) += movsub_bsf.o >> OBJS-$(CONFIG_MP3_HEADER_DECOMPRESS_BSF) += mp3_header_decompress_bsf.o \ >> mpegaudiodata.o >> +OBJS-$(CONFIG_MPEG2_METADATA_BSF) += mpeg2_metadata_bsf.o >> OBJS-$(CONFIG_NOISE_BSF) += noise_bsf.o >> OBJS-$(CONFIG_NULL_BSF) += null_bsf.o >> OBJS-$(CONFIG_REMOVE_EXTRADATA_BSF) += remove_extradata_bsf.o >> diff --git a/libavcodec/bitstream_filters.c b/libavcodec/bitstream_filters.c >> index 6e6b894e7f..7b0cb5032a 100644 >> --- a/libavcodec/bitstream_filters.c >> +++ b/libavcodec/bitstream_filters.c >> @@ -38,6 +38,7 @@ extern const AVBitStreamFilter ff_imx_dump_header_bsf; >> extern const AVBitStreamFilter ff_mjpeg2jpeg_bsf; >> extern const AVBitStreamFilter ff_mjpega_dump_header_bsf; >> extern const AVBitStreamFilter ff_mp3_header_decompress_bsf; >> +extern const AVBitStreamFilter ff_mpeg2_metadata_bsf; >> extern const AVBitStreamFilter ff_mpeg4_unpack_bframes_bsf; >> extern const AVBitStreamFilter ff_mov2textsub_bsf; >> extern const AVBitStreamFilter ff_noise_bsf; >> diff --git a/libavcodec/mpeg2_metadata_bsf.c b/libavcodec/mpeg2_metadata_bsf.c >> new file mode 100644 >> index 0000000000..b4449eac71 >> --- /dev/null >> +++ b/libavcodec/mpeg2_metadata_bsf.c >> @@ -0,0 +1,360 @@ >> +/* >> + * 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 "libavutil/avstring.h" >> +#include "libavutil/common.h" >> +#include "libavutil/opt.h" >> + >> +#include "bsf.h" >> +#include "cbs.h" >> +#include "cbs_mpeg2.h" >> + >> +typedef struct MPEG2MetadataContext { >> + const AVClass *class; >> + >> + CodedBitstreamContext cbc; >> + CodedBitstreamFragment fragment; >> + >> + MPEG2RawExtensionData sequence_display_extension; >> + >> + AVRational display_aspect_ratio; >> + >> + AVRational frame_rate; >> + >> + int video_format; >> + int colour_primaries; >> + int transfer_characteristics; >> + int matrix_coefficients; >> + >> + int mpeg1_warned; >> +} MPEG2MetadataContext; >> + >> + >> +static int mpeg2_metadata_update_fragment(AVBSFContext *bsf, >> + CodedBitstreamFragment *frag) >> +{ >> + MPEG2MetadataContext *ctx = bsf->priv_data; >> + MPEG2RawSequenceHeader *sh = NULL; >> + MPEG2RawSequenceExtension *se = NULL; >> + MPEG2RawSequenceDisplayExtension *sde = NULL; >> + int i, se_pos, add_sde = 0; >> + >> + for (i = 0; i < frag->nb_units; i++) { >> + if (frag->units[i].type == MPEG2_START_SEQUENCE_HEADER) { >> + sh = frag->units[i].content; >> + } else if (frag->units[i].type == MPEG2_START_EXTENSION) { >> + MPEG2RawExtensionData *ext = frag->units[i].content; >> + if (ext->extension_start_code_identifier == >> + MPEG2_EXTENSION_SEQUENCE) { >> + se = &ext->data.sequence; >> + se_pos = i; >> + } else if (ext->extension_start_code_identifier == >> + MPEG2_EXTENSION_SEQUENCE_DISPLAY) { >> + sde = &ext->data.sequence_display; >> + } >> + } >> + } >> + >> + if (!sh || !se) { >> + // No sequence header and sequence extension: not an MPEG-2 video >> + // sequence. >> + if (sh && !ctx->mpeg1_warned) { >> + av_log(bsf, AV_LOG_WARNING, "Stream contains a sequence " >> + "header but not a sequence extension: maybe it's " >> + "actually MPEG-1?\n"); >> + ctx->mpeg1_warned = 1; >> + } >> + return 0; >> + } >> + >> + if (ctx->display_aspect_ratio.num && ctx->display_aspect_ratio.den) { >> + int num, den; >> + >> + av_reduce(&num, &den, ctx->display_aspect_ratio.num, >> + ctx->display_aspect_ratio.den, 65535); >> + >> + if (num == 4 && den == 3) >> + sh->aspect_ratio_information = 2; >> + else if (num == 16 && den == 9) >> + sh->aspect_ratio_information = 3; >> + else if (num == 221 && den == 100) >> + sh->aspect_ratio_information = 4; >> + else >> + sh->aspect_ratio_information = 1; >> + } >> + >> + if (ctx->frame_rate.num && ctx->frame_rate.den) { >> + // Table 6-4. > >> + static AVRational frame_rate_table[] = { >> + { 0, 0 }, >> + { 24000, 1001 }, >> + { 24, 1 }, >> + { 25, 1 }, >> + { 30000, 1001 }, >> + { 30, 1 }, >> + { 50, 1 }, >> + { 60000, 1001 }, >> + { 60, 1 }, >> + }; > > This is a duplicate of ff_mpeg12_frame_rate_tab > also should be static const On further thought, I've extracted this framerate-construction fragment into mpeg12framerate.c next to where the table is - it's also wanted by the MPEG-2 VAAPI encoder code. >> +#define OFFSET(x) offsetof(MPEG2MetadataContext, x) >> +static const AVOption mpeg2_metadata_options[] = { >> + { "display_aspect_ratio", "Set display aspect ratio (table 6-3)", >> + OFFSET(display_aspect_ratio), AV_OPT_TYPE_RATIONAL, >> + { .i64 = 0 }, 0, 65535 }, >> + >> + { "frame_rate", "Set frame rate", >> + OFFSET(frame_rate), AV_OPT_TYPE_RATIONAL, >> + { .i64 = 0 }, 0, UINT_MAX }, > > for AV_OPT_TYPE_RATIONAL the default is dbl not i64, also this affects > some of the other patches as well Hmm, yeah - I guess I've always been saved there by only setting it to zero. Will fix. Thanks, - Mark
diff --git a/configure b/configure index 7641bd98d4..1e99038dca 100755 --- a/configure +++ b/configure @@ -2836,6 +2836,7 @@ h264_metadata_bsf_select="cbs_h264" h264_redundant_pps_bsf_select="cbs_h264" hevc_metadata_bsf_select="cbs_h265" mjpeg2jpeg_bsf_select="jpegtables" +mpeg2_metadata_bsf_select="cbs_mpeg2" trace_headers_bsf_select="cbs_h264 cbs_h265 cbs_mpeg2" # external libraries diff --git a/doc/bitstream_filters.texi b/doc/bitstream_filters.texi index 71c307f2e2..8a8756bdcc 100644 --- a/doc/bitstream_filters.texi +++ b/doc/bitstream_filters.texi @@ -324,6 +324,42 @@ See also the @ref{text2movsub} filter. Decompress non-standard compressed MP3 audio headers. +@section mpeg2_metadata + +Modify metadata embedded in an MPEG-2 stream. + +@table @option +@item display_aspect_ratio +Set the display aspect ratio in the stream. + +The following fixed values are supported: +@table @option +@item 4/3 +@item 16/9 +@item 221/100 +@end table +Any other value will result in square pixels being signalled instead +(see H.262 section 6.3.3 and table 6-3). + +@item frame_rate +Set the frame rate in the stream. This is constructed from a table +of known values combined with a small multiplier and divisor - if +the supplied value is not exactly representable, the nearest +representable value will be used instead (see H.262 section 6.3.3 +and table 6-4). + +@item video_format +Set the video format in the stream (see H.262 section 6.3.6 and +table 6-6). + +@item colour_primaries +@item transfer_characteristics +@item matrix_coefficients +Set the colour description in the stream (see H.262 section 6.3.6 +and tables 6-7, 6-8 and 6-9). + +@end table + @section mpeg4_unpack_bframes Unpack DivX-style packed B-frames. diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 72f2bb2a12..3da7b9b508 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -1002,6 +1002,7 @@ OBJS-$(CONFIG_MPEG4_UNPACK_BFRAMES_BSF) += mpeg4_unpack_bframes_bsf.o OBJS-$(CONFIG_MOV2TEXTSUB_BSF) += movsub_bsf.o OBJS-$(CONFIG_MP3_HEADER_DECOMPRESS_BSF) += mp3_header_decompress_bsf.o \ mpegaudiodata.o +OBJS-$(CONFIG_MPEG2_METADATA_BSF) += mpeg2_metadata_bsf.o OBJS-$(CONFIG_NOISE_BSF) += noise_bsf.o OBJS-$(CONFIG_NULL_BSF) += null_bsf.o OBJS-$(CONFIG_REMOVE_EXTRADATA_BSF) += remove_extradata_bsf.o diff --git a/libavcodec/bitstream_filters.c b/libavcodec/bitstream_filters.c index 6e6b894e7f..7b0cb5032a 100644 --- a/libavcodec/bitstream_filters.c +++ b/libavcodec/bitstream_filters.c @@ -38,6 +38,7 @@ extern const AVBitStreamFilter ff_imx_dump_header_bsf; extern const AVBitStreamFilter ff_mjpeg2jpeg_bsf; extern const AVBitStreamFilter ff_mjpega_dump_header_bsf; extern const AVBitStreamFilter ff_mp3_header_decompress_bsf; +extern const AVBitStreamFilter ff_mpeg2_metadata_bsf; extern const AVBitStreamFilter ff_mpeg4_unpack_bframes_bsf; extern const AVBitStreamFilter ff_mov2textsub_bsf; extern const AVBitStreamFilter ff_noise_bsf; diff --git a/libavcodec/mpeg2_metadata_bsf.c b/libavcodec/mpeg2_metadata_bsf.c new file mode 100644 index 0000000000..b4449eac71 --- /dev/null +++ b/libavcodec/mpeg2_metadata_bsf.c @@ -0,0 +1,360 @@ +/* + * 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 "libavutil/avstring.h" +#include "libavutil/common.h" +#include "libavutil/opt.h" + +#include "bsf.h" +#include "cbs.h" +#include "cbs_mpeg2.h" + +typedef struct MPEG2MetadataContext { + const AVClass *class; + + CodedBitstreamContext cbc; + CodedBitstreamFragment fragment; + + MPEG2RawExtensionData sequence_display_extension; + + AVRational display_aspect_ratio; + + AVRational frame_rate; + + int video_format; + int colour_primaries; + int transfer_characteristics; + int matrix_coefficients; + + int mpeg1_warned; +} MPEG2MetadataContext; + + +static int mpeg2_metadata_update_fragment(AVBSFContext *bsf, + CodedBitstreamFragment *frag) +{ + MPEG2MetadataContext *ctx = bsf->priv_data; + MPEG2RawSequenceHeader *sh = NULL; + MPEG2RawSequenceExtension *se = NULL; + MPEG2RawSequenceDisplayExtension *sde = NULL; + int i, se_pos, add_sde = 0; + + for (i = 0; i < frag->nb_units; i++) { + if (frag->units[i].type == MPEG2_START_SEQUENCE_HEADER) { + sh = frag->units[i].content; + } else if (frag->units[i].type == MPEG2_START_EXTENSION) { + MPEG2RawExtensionData *ext = frag->units[i].content; + if (ext->extension_start_code_identifier == + MPEG2_EXTENSION_SEQUENCE) { + se = &ext->data.sequence; + se_pos = i; + } else if (ext->extension_start_code_identifier == + MPEG2_EXTENSION_SEQUENCE_DISPLAY) { + sde = &ext->data.sequence_display; + } + } + } + + if (!sh || !se) { + // No sequence header and sequence extension: not an MPEG-2 video + // sequence. + if (sh && !ctx->mpeg1_warned) { + av_log(bsf, AV_LOG_WARNING, "Stream contains a sequence " + "header but not a sequence extension: maybe it's " + "actually MPEG-1?\n"); + ctx->mpeg1_warned = 1; + } + return 0; + } + + if (ctx->display_aspect_ratio.num && ctx->display_aspect_ratio.den) { + int num, den; + + av_reduce(&num, &den, ctx->display_aspect_ratio.num, + ctx->display_aspect_ratio.den, 65535); + + if (num == 4 && den == 3) + sh->aspect_ratio_information = 2; + else if (num == 16 && den == 9) + sh->aspect_ratio_information = 3; + else if (num == 221 && den == 100) + sh->aspect_ratio_information = 4; + else + sh->aspect_ratio_information = 1; + } + + if (ctx->frame_rate.num && ctx->frame_rate.den) { + // Table 6-4. + static AVRational frame_rate_table[] = { + { 0, 0 }, + { 24000, 1001 }, + { 24, 1 }, + { 25, 1 }, + { 30000, 1001 }, + { 30, 1 }, + { 50, 1 }, + { 60000, 1001 }, + { 60, 1 }, + }; + int code, ext_n, ext_d; + AVRational best_error = { INT_MAX, 1 }; + + for (i = 1; i < FF_ARRAY_ELEMS(frame_rate_table); i++) { + if (av_cmp_q(ctx->frame_rate, frame_rate_table[i]) == 0) { + code = i; + ext_n = 1; + ext_d = 1; + goto found_frame_rate; + } + } + + for (i = 1; i < FF_ARRAY_ELEMS(frame_rate_table); i++) { + AVRational fr, error; + int n, d, cmp; + for (n = 1; n <= 4; n++) { + for (d = 1; d <= 32; d++) { + fr = av_mul_q(frame_rate_table[i], + (AVRational) { n, d }); + cmp = av_cmp_q(fr, ctx->frame_rate); + if (cmp == 0) { + code = i; + ext_n = n; + ext_d = d; + goto found_frame_rate; + } + if (cmp < 0) + error = av_div_q(ctx->frame_rate, fr); + else + error = av_div_q(fr, ctx->frame_rate); + cmp = av_cmp_q(error, best_error); + if (cmp < 0 || (cmp == 0 && n == 1 && d == 1)) { + code = i; + ext_n = n; + ext_d = d; + best_error = error; + } + } + } + } + + found_frame_rate: + sh->frame_rate_code = code; + se->frame_rate_extension_n = ext_n - 1; + se->frame_rate_extension_d = ext_d - 1; + } + + if (ctx->video_format >= 0 || + ctx->colour_primaries >= 0 || + ctx->transfer_characteristics >= 0 || + ctx->matrix_coefficients >= 0) { + if (!sde) { + add_sde = 1; + ctx->sequence_display_extension.extension_start_code = + MPEG2_START_EXTENSION; + ctx->sequence_display_extension.extension_start_code_identifier = + MPEG2_EXTENSION_SEQUENCE_DISPLAY; + sde = &ctx->sequence_display_extension.data.sequence_display; + + *sde = (MPEG2RawSequenceDisplayExtension) { + .video_format = 5, + + .colour_description = 0, + .colour_primaries = 2, + .transfer_characteristics = 2, + .matrix_coefficients = 2, + + .display_horizontal_size = + se->horizontal_size_extension << 12 | sh->horizontal_size_value, + .display_vertical_size = + se->vertical_size_extension << 12 | sh->vertical_size_value, + }; + } + + if (ctx->video_format >= 0) + sde->video_format = ctx->video_format; + + if (ctx->colour_primaries >= 0 || + ctx->transfer_characteristics >= 0 || + ctx->matrix_coefficients >= 0) { + sde->colour_description = 1; + + if (ctx->colour_primaries >= 0) + sde->colour_primaries = ctx->colour_primaries; + else if (add_sde) + sde->colour_primaries = 2; + + if (ctx->transfer_characteristics >= 0) + sde->transfer_characteristics = ctx->transfer_characteristics; + else if (add_sde) + sde->transfer_characteristics = 2; + + if (ctx->matrix_coefficients >= 0) + sde->matrix_coefficients = ctx->matrix_coefficients; + else if (add_sde) + sde->matrix_coefficients = 2; + } + } + + if (add_sde) { + int err; + + err = ff_cbs_insert_unit_content(&ctx->cbc, frag, se_pos + 1, + MPEG2_START_EXTENSION, + &ctx->sequence_display_extension); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to insert new sequence " + "display extension.\n"); + return err; + } + } + + return 0; +} + +static int mpeg2_metadata_filter(AVBSFContext *bsf, AVPacket *out) +{ + MPEG2MetadataContext *ctx = bsf->priv_data; + AVPacket *in = NULL; + CodedBitstreamFragment *frag = &ctx->fragment; + int err; + + err = ff_bsf_get_packet(bsf, &in); + if (err < 0) + goto fail; + + err = ff_cbs_read_packet(&ctx->cbc, frag, in); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to read packet.\n"); + goto fail; + } + + err = mpeg2_metadata_update_fragment(bsf, frag); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to update frame fragment.\n"); + goto fail; + } + + err = ff_cbs_write_packet(&ctx->cbc, out, frag); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to write packet.\n"); + goto fail; + } + + err = av_packet_copy_props(out, in); + if (err < 0) { + av_packet_unref(out); + goto fail; + } + + err = 0; +fail: + ff_cbs_fragment_uninit(&ctx->cbc, frag); + + av_packet_free(&in); + + return err; +} + +static int mpeg2_metadata_init(AVBSFContext *bsf) +{ + MPEG2MetadataContext *ctx = bsf->priv_data; + CodedBitstreamFragment *frag = &ctx->fragment; + int err; + + err = ff_cbs_init(&ctx->cbc, AV_CODEC_ID_MPEG2VIDEO, bsf); + if (err < 0) + return err; + + if (bsf->par_in->extradata) { + err = ff_cbs_read_extradata(&ctx->cbc, frag, bsf->par_in); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to read extradata.\n"); + goto fail; + } + + err = mpeg2_metadata_update_fragment(bsf, frag); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to update metadata fragment.\n"); + goto fail; + } + + err = ff_cbs_write_extradata(&ctx->cbc, bsf->par_out, frag); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to write extradata.\n"); + goto fail; + } + } + + err = 0; +fail: + ff_cbs_fragment_uninit(&ctx->cbc, frag); + return err; +} + +static void mpeg2_metadata_close(AVBSFContext *bsf) +{ + MPEG2MetadataContext *ctx = bsf->priv_data; + ff_cbs_close(&ctx->cbc); +} + +#define OFFSET(x) offsetof(MPEG2MetadataContext, x) +static const AVOption mpeg2_metadata_options[] = { + { "display_aspect_ratio", "Set display aspect ratio (table 6-3)", + OFFSET(display_aspect_ratio), AV_OPT_TYPE_RATIONAL, + { .i64 = 0 }, 0, 65535 }, + + { "frame_rate", "Set frame rate", + OFFSET(frame_rate), AV_OPT_TYPE_RATIONAL, + { .i64 = 0 }, 0, UINT_MAX }, + + { "video_format", "Set video format (table 6-6)", + OFFSET(video_format), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 7 }, + { "colour_primaries", "Set colour primaries (table 6-7)", + OFFSET(colour_primaries), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 255 }, + { "transfer_characteristics", "Set transfer characteristics (table 6-8)", + OFFSET(transfer_characteristics), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 255 }, + { "matrix_coefficients", "Set matrix coefficients (table 6-9)", + OFFSET(matrix_coefficients), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 255 }, + + { NULL } +}; + +static const AVClass mpeg2_metadata_class = { + .class_name = "mpeg2_metadata_bsf", + .item_name = av_default_item_name, + .option = mpeg2_metadata_options, + .version = LIBAVCODEC_VERSION_MAJOR, +}; + +static const enum AVCodecID mpeg2_metadata_codec_ids[] = { + AV_CODEC_ID_MPEG2VIDEO, AV_CODEC_ID_NONE, +}; + +const AVBitStreamFilter ff_mpeg2_metadata_bsf = { + .name = "mpeg2_metadata", + .priv_data_size = sizeof(MPEG2MetadataContext), + .priv_class = &mpeg2_metadata_class, + .init = &mpeg2_metadata_init, + .close = &mpeg2_metadata_close, + .filter = &mpeg2_metadata_filter, + .codec_ids = mpeg2_metadata_codec_ids, +};