[FFmpeg-devel] [PATCH 2/2] vp9: add superframe merging bitstream filter.
Fixes ticket 4313. --- ffmpeg.c| 1 + libavcodec/Makefile | 1 + libavcodec/allcodecs.c | 1 + libavcodec/vp9_superframe_bsf.c | 189 libavformat/ivfenc.c| 13 +++ libavformat/matroskaenc.c | 5 +- 6 files changed, 209 insertions(+), 1 deletion(-) create mode 100644 libavcodec/vp9_superframe_bsf.c diff --git a/ffmpeg.c b/ffmpeg.c index 8fec1e7..37cd29c 100644 --- a/ffmpeg.c +++ b/ffmpeg.c @@ -712,6 +712,7 @@ static void write_frame(AVFormatContext *s, AVPacket *pkt, OutputStream *ost) if( (avctx->codec_type == AVMEDIA_TYPE_AUDIO || avctx->codec_type == AVMEDIA_TYPE_VIDEO) && pkt->dts != AV_NOPTS_VALUE && +!(avctx->codec_id == AV_CODEC_ID_VP9 && ost->stream_copy) && ost->last_mux_dts != AV_NOPTS_VALUE) { int64_t max = ost->last_mux_dts + !(s->oformat->flags & AVFMT_TS_NONSTRICT); if (pkt->dts < max) { diff --git a/libavcodec/Makefile b/libavcodec/Makefile index f6a4fbb..041684d 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -916,6 +916,7 @@ OBJS-$(CONFIG_MP3_HEADER_DECOMPRESS_BSF) += mp3_header_decompress_bsf.o \ OBJS-$(CONFIG_NOISE_BSF) += noise_bsf.o OBJS-$(CONFIG_REMOVE_EXTRADATA_BSF) += remove_extradata_bsf.o OBJS-$(CONFIG_TEXT2MOVSUB_BSF)+= movsub_bsf.o +OBJS-$(CONFIG_VP9_SUPERFRAME_BSF) += vp9_superframe_bsf.o # thread libraries OBJS-$(HAVE_LIBC_MSVCRT) += file_open.o diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 2097db0..96f5c5c 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -666,4 +666,5 @@ void avcodec_register_all(void) REGISTER_BSF(NOISE, noise); REGISTER_BSF(REMOVE_EXTRADATA, remove_extradata); REGISTER_BSF(TEXT2MOVSUB, text2movsub); +REGISTER_BSF(VP9_SUPERFRAME,vp9_superframe); } diff --git a/libavcodec/vp9_superframe_bsf.c b/libavcodec/vp9_superframe_bsf.c new file mode 100644 index 000..f991a80 --- /dev/null +++ b/libavcodec/vp9_superframe_bsf.c @@ -0,0 +1,189 @@ +/* + * Vp9 invisible (alt-ref) frame to superframe merge bitstream filter + * Copyright (c) 2016 Ronald S. Bultje+ * + * 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/avassert.h" +#include "avcodec.h" +#include "get_bits.h" + +#define MAX_CACHE 8 +typedef struct VP9BSFContext { +int n_cache; +struct CachedBuf { +uint8_t *data; +int size; +} cache[MAX_CACHE]; +} VP9BSFContext; + +static void stats(const struct CachedBuf *in, int n_in, + unsigned *_max, unsigned *_sum) +{ +int n; +unsigned max = 0, sum = 0; + +for (n = 0; n < n_in; n++) { +unsigned sz = in[n].size; + +if (sz > max) +max = sz; +sum += sz; +} + +*_max = max; +*_sum = sum; +} + +static int merge_superframe(const struct CachedBuf *in, int n_in, +uint8_t **poutbuf, int *poutbuf_size) +{ +unsigned max, sum, mag, marker, n, sz; +uint8_t *ptr; + +stats(in, n_in, , ); +mag = av_log2(max) >> 3; +marker = 0xC0 + (mag << 3) + (n_in - 1); +sz = *poutbuf_size = sum + 2 + (mag + 1) * n_in; +ptr = *poutbuf = av_malloc(sz); +if (!ptr) +return AVERROR(ENOMEM); + +for (n = 0; n < n_in; n++) { +memcpy(ptr, in[n].data, in[n].size); +ptr += in[n].size; +} + +#define wloop(mag, wr) \ +for (n = 0; n < n_in; n++) { \ +wr; \ +ptr += mag + 1; \ +} + +// write superframe with marker 110[mag:2][nframes:3] +*ptr++ = marker; +switch (mag) { +case 0: +wloop(mag, *ptr = in[n].size); +break; +case 1: +wloop(mag, AV_WB16(ptr, in[n].size)); +break; +case 2: +wloop(mag, AV_WB24(ptr, in[n].size)); +break; +case 3: +wloop(mag, AV_WB32(ptr, in[n].size)); +break; +} +*ptr++ = marker; +av_assert0(ptr == &(*poutbuf)[*poutbuf_size]); + +return 0; +} + +static int vp9_superframe_filter(AVBitStreamFilterContext *bsfc, + AVCodecContext *avctx, const
[FFmpeg-devel] [PATCH 2/2] vp9: add superframe merging bitstream filter.
Fixes ticket 4313. --- ffmpeg.c| 1 + libavcodec/Makefile | 1 + libavcodec/allcodecs.c | 1 + libavcodec/vp9_superframe_bsf.c | 189 libavformat/ivfenc.c| 13 +++ libavformat/matroskaenc.c | 5 +- 6 files changed, 209 insertions(+), 1 deletion(-) create mode 100644 libavcodec/vp9_superframe_bsf.c diff --git a/ffmpeg.c b/ffmpeg.c index 8fec1e7..37cd29c 100644 --- a/ffmpeg.c +++ b/ffmpeg.c @@ -712,6 +712,7 @@ static void write_frame(AVFormatContext *s, AVPacket *pkt, OutputStream *ost) if( (avctx->codec_type == AVMEDIA_TYPE_AUDIO || avctx->codec_type == AVMEDIA_TYPE_VIDEO) && pkt->dts != AV_NOPTS_VALUE && +!(avctx->codec_id == AV_CODEC_ID_VP9 && ost->stream_copy) && ost->last_mux_dts != AV_NOPTS_VALUE) { int64_t max = ost->last_mux_dts + !(s->oformat->flags & AVFMT_TS_NONSTRICT); if (pkt->dts < max) { diff --git a/libavcodec/Makefile b/libavcodec/Makefile index f6a4fbb..041684d 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -916,6 +916,7 @@ OBJS-$(CONFIG_MP3_HEADER_DECOMPRESS_BSF) += mp3_header_decompress_bsf.o \ OBJS-$(CONFIG_NOISE_BSF) += noise_bsf.o OBJS-$(CONFIG_REMOVE_EXTRADATA_BSF) += remove_extradata_bsf.o OBJS-$(CONFIG_TEXT2MOVSUB_BSF)+= movsub_bsf.o +OBJS-$(CONFIG_VP9_SUPERFRAME_BSF) += vp9_superframe_bsf.o # thread libraries OBJS-$(HAVE_LIBC_MSVCRT) += file_open.o diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 2097db0..96f5c5c 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -666,4 +666,5 @@ void avcodec_register_all(void) REGISTER_BSF(NOISE, noise); REGISTER_BSF(REMOVE_EXTRADATA, remove_extradata); REGISTER_BSF(TEXT2MOVSUB, text2movsub); +REGISTER_BSF(VP9_SUPERFRAME,vp9_superframe); } diff --git a/libavcodec/vp9_superframe_bsf.c b/libavcodec/vp9_superframe_bsf.c new file mode 100644 index 000..f991a80 --- /dev/null +++ b/libavcodec/vp9_superframe_bsf.c @@ -0,0 +1,189 @@ +/* + * Vp9 invisible (alt-ref) frame to superframe merge bitstream filter + * Copyright (c) 2016 Ronald S. Bultje+ * + * 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/avassert.h" +#include "avcodec.h" +#include "get_bits.h" + +#define MAX_CACHE 8 +typedef struct VP9BSFContext { +int n_cache; +struct CachedBuf { +uint8_t *data; +int size; +} cache[MAX_CACHE]; +} VP9BSFContext; + +static void stats(const struct CachedBuf *in, int n_in, + unsigned *_max, unsigned *_sum) +{ +int n; +unsigned max = 0, sum = 0; + +for (n = 0; n < n_in; n++) { +unsigned sz = in[n].size; + +if (sz > max) +max = sz; +sum += sz; +} + +*_max = max; +*_sum = sum; +} + +static int merge_superframe(const struct CachedBuf *in, int n_in, +uint8_t **poutbuf, int *poutbuf_size) +{ +unsigned max, sum, mag, marker, n, sz; +uint8_t *ptr; + +stats(in, n_in, , ); +mag = av_log2(max) >> 3; +marker = 0xC0 + (mag << 3) + (n_in - 1); +sz = *poutbuf_size = sum + 2 + (mag + 1) * n_in; +ptr = *poutbuf = av_malloc(sz); +if (!ptr) +return AVERROR(ENOMEM); + +for (n = 0; n < n_in; n++) { +memcpy(ptr, in[n].data, in[n].size); +ptr += in[n].size; +} + +#define wloop(mag, wr) \ +for (n = 0; n < n_in; n++) { \ +wr; \ +ptr += mag + 1; \ +} + +// write superframe with marker 110[mag:2][nframes:3] +*ptr++ = marker; +switch (mag) { +case 0: +wloop(mag, *ptr = in[n].size); +break; +case 1: +wloop(mag, AV_WB16(ptr, in[n].size)); +break; +case 2: +wloop(mag, AV_WB24(ptr, in[n].size)); +break; +case 3: +wloop(mag, AV_WB32(ptr, in[n].size)); +break; +} +*ptr++ = marker; +av_assert0(ptr == &(*poutbuf)[*poutbuf_size]); + +return 0; +} + +static int vp9_superframe_filter(AVBitStreamFilterContext *bsfc, + AVCodecContext *avctx, const