[FFmpeg-devel] [PATCH 2/2] vp9: add superframe merging bitstream filter.

2016-02-29 Thread Ronald S. Bultje
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.

2016-02-29 Thread Ronald S. Bultje
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