Browse code

Merge commit '8a3d9ca603f4d15ecaa9ca379cbaab4ecaec8ce4'

* commit '8a3d9ca603f4d15ecaa9ca379cbaab4ecaec8ce4':
libavcodec: Add an OpenH264 encoder wrapper

Conflicts:
Changelog
configure
libavcodec/version.h

Merged-by: Michael Niedermayer <michaelni@gmx.at>

Michael Niedermayer authored on 2015/01/07 08:48:23
Showing 6 changed files
... ...
@@ -11,6 +11,7 @@ version <next>:
11 11
 - tblend filter
12 12
 - cropdetect support for non 8bpp, absolute (if limit >= 1) and relative (if limit < 1.0) threshold
13 13
 - Camellia symmetric block cipher
14
+- OpenH264 encoder wrapper
14 15
 
15 16
 
16 17
 version 2.5:
... ...
@@ -226,6 +226,7 @@ External library support:
226 226
   --enable-libopencore-amrnb enable AMR-NB de/encoding via libopencore-amrnb [no]
227 227
   --enable-libopencore-amrwb enable AMR-WB decoding via libopencore-amrwb [no]
228 228
   --enable-libopencv       enable video filtering via libopencv [no]
229
+  --enable-libopenh264     enable H264 encoding via OpenH264 [no]
229 230
   --enable-libopenjpeg     enable JPEG 2000 de/encoding via OpenJPEG [no]
230 231
   --enable-libopus         enable Opus de/encoding via libopus [no]
231 232
   --enable-libpulse        enable Pulseaudio input via libpulse [no]
... ...
@@ -1367,6 +1368,7 @@ EXTERNAL_LIBRARY_LIST="
1367 1367
     libopencore_amrnb
1368 1368
     libopencore_amrwb
1369 1369
     libopencv
1370
+    libopenh264
1370 1371
     libopenjpeg
1371 1372
     libopus
1372 1373
     libpulse
... ...
@@ -2363,6 +2365,7 @@ libopencore_amrnb_decoder_deps="libopencore_amrnb"
2363 2363
 libopencore_amrnb_encoder_deps="libopencore_amrnb"
2364 2364
 libopencore_amrnb_encoder_select="audio_frame_queue"
2365 2365
 libopencore_amrwb_decoder_deps="libopencore_amrwb"
2366
+libopenh264_encoder_deps="libopenh264"
2366 2367
 libopenjpeg_decoder_deps="libopenjpeg"
2367 2368
 libopenjpeg_encoder_deps="libopenjpeg"
2368 2369
 libopus_decoder_deps="libopus"
... ...
@@ -4886,6 +4889,7 @@ enabled libnut            && require libnut libnut.h nut_demuxer_init -lnut
4886 4886
 enabled libopencore_amrnb && require libopencore_amrnb opencore-amrnb/interf_dec.h Decoder_Interface_init -lopencore-amrnb
4887 4887
 enabled libopencore_amrwb && require libopencore_amrwb opencore-amrwb/dec_if.h D_IF_init -lopencore-amrwb
4888 4888
 enabled libopencv         && require_pkg_config opencv opencv/cxcore.h cvCreateImageHeader
4889
+enabled libopenh264       && require_pkg_config openh264 wels/codec_api.h WelsGetCodecVersion
4889 4890
 enabled libopenjpeg       && { check_lib openjpeg.h opj_version -lopenmj2 -DOPJ_STATIC ||
4890 4891
                                check_lib openjpeg-1.5/openjpeg.h opj_version -lopenjpeg -DOPJ_STATIC ||
4891 4892
                                check_lib openjpeg.h opj_version -lopenjpeg -DOPJ_STATIC ||
... ...
@@ -734,6 +734,7 @@ OBJS-$(CONFIG_LIBMP3LAME_ENCODER)         += libmp3lame.o mpegaudiodecheader.o
734 734
 OBJS-$(CONFIG_LIBOPENCORE_AMRNB_DECODER)  += libopencore-amr.o
735 735
 OBJS-$(CONFIG_LIBOPENCORE_AMRNB_ENCODER)  += libopencore-amr.o
736 736
 OBJS-$(CONFIG_LIBOPENCORE_AMRWB_DECODER)  += libopencore-amr.o
737
+OBJS-$(CONFIG_LIBOPENH264_ENCODER)        += libopenh264enc.o
737 738
 OBJS-$(CONFIG_LIBOPENJPEG_DECODER)        += libopenjpegdec.o
738 739
 OBJS-$(CONFIG_LIBOPENJPEG_ENCODER)        += libopenjpegenc.o
739 740
 OBJS-$(CONFIG_LIBOPUS_DECODER)            += libopusdec.o libopus.o     \
... ...
@@ -511,6 +511,7 @@ void avcodec_register_all(void)
511 511
     REGISTER_ENCODER(LIBMP3LAME,        libmp3lame);
512 512
     REGISTER_ENCDEC (LIBOPENCORE_AMRNB, libopencore_amrnb);
513 513
     REGISTER_DECODER(LIBOPENCORE_AMRWB, libopencore_amrwb);
514
+    REGISTER_ENCODER(LIBOPENH264,       libopenh264);
514 515
     REGISTER_ENCDEC (LIBOPENJPEG,       libopenjpeg);
515 516
     REGISTER_ENCDEC (LIBOPUS,           libopus);
516 517
     REGISTER_ENCDEC (LIBSCHROEDINGER,   libschroedinger);
517 518
new file mode 100644
... ...
@@ -0,0 +1,228 @@
0
+/*
1
+ * OpenH264 video encoder
2
+ * Copyright (C) 2014 Martin Storsjo
3
+ *
4
+ * This file is part of FFmpeg.
5
+ *
6
+ * FFmpeg is free software; you can redistribute it and/or
7
+ * modify it under the terms of the GNU Lesser General Public
8
+ * License as published by the Free Software Foundation; either
9
+ * version 2.1 of the License, or (at your option) any later version.
10
+ *
11
+ * FFmpeg is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
+ * Lesser General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU Lesser General Public
17
+ * License along with FFmpeg; if not, write to the Free Software
18
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
+ */
20
+
21
+#include <wels/codec_api.h>
22
+#include <wels/codec_ver.h>
23
+
24
+#include "libavutil/attributes.h"
25
+#include "libavutil/common.h"
26
+#include "libavutil/opt.h"
27
+#include "libavutil/intreadwrite.h"
28
+#include "libavutil/mathematics.h"
29
+
30
+#include "avcodec.h"
31
+#include "internal.h"
32
+
33
+typedef struct SVCContext {
34
+    const AVClass *av_class;
35
+    ISVCEncoder *encoder;
36
+    int slice_mode;
37
+    int loopfilter;
38
+    char *profile;
39
+} SVCContext;
40
+
41
+#define OFFSET(x) offsetof(SVCContext, x)
42
+#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
43
+static const AVOption options[] = {
44
+    { "slice_mode", "Slice mode", OFFSET(slice_mode), AV_OPT_TYPE_INT, { .i64 = SM_AUTO_SLICE }, SM_SINGLE_SLICE, SM_RESERVED, VE, "slice_mode" },
45
+    { "fixed", "A fixed number of slices", 0, AV_OPT_TYPE_CONST, { .i64 = SM_FIXEDSLCNUM_SLICE }, 0, 0, VE, "slice_mode" },
46
+    { "rowmb", "One slice per row of macroblocks", 0, AV_OPT_TYPE_CONST, { .i64 = SM_ROWMB_SLICE }, 0, 0, VE, "slice_mode" },
47
+    { "auto", "Automatic number of slices according to number of threads", 0, AV_OPT_TYPE_CONST, { .i64 = SM_AUTO_SLICE }, 0, 0, VE, "slice_mode" },
48
+    { "loopfilter", "Enable loop filter", OFFSET(loopfilter), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, VE },
49
+    { "profile", "Set profile restrictions", OFFSET(profile), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VE },
50
+    { NULL }
51
+};
52
+
53
+static const AVClass class = {
54
+    "libopenh264enc", av_default_item_name, options, LIBAVUTIL_VERSION_INT
55
+};
56
+
57
+static av_cold int svc_encode_close(AVCodecContext *avctx)
58
+{
59
+    SVCContext *s = avctx->priv_data;
60
+
61
+    if (s->encoder)
62
+        WelsDestroySVCEncoder(s->encoder);
63
+    return 0;
64
+}
65
+
66
+static av_cold int svc_encode_init(AVCodecContext *avctx)
67
+{
68
+    SVCContext *s = avctx->priv_data;
69
+    SEncParamExt param = { 0 };
70
+    int err = AVERROR_UNKNOWN;
71
+    av_unused OpenH264Version libver;
72
+    (void)g_strCodecVer; // Avoid warnings due to unused static members from codec_ver.h
73
+
74
+    // Mingw GCC < 4.7 on x86_32 uses an incorrect/buggy ABI for the WelsGetCodecVersion
75
+    // function (for functions returning larger structs), thus skip the check in those
76
+    // configurations.
77
+#if !defined(_WIN32) || !defined(__GNUC__) || !ARCH_X86_32 || AV_GCC_VERSION_AT_LEAST(4, 7)
78
+    libver = WelsGetCodecVersion();
79
+    if (memcmp(&libver, &g_stCodecVersion, sizeof(libver))) {
80
+        av_log(avctx, AV_LOG_ERROR, "Incorrect library version loaded\n");
81
+        return AVERROR(EINVAL);
82
+    }
83
+#endif
84
+
85
+    if (WelsCreateSVCEncoder(&s->encoder)) {
86
+        av_log(avctx, AV_LOG_ERROR, "Unable to create encoder\n");
87
+        return AVERROR_UNKNOWN;
88
+    }
89
+
90
+    (*s->encoder)->GetDefaultParams(s->encoder, &param);
91
+
92
+    param.fMaxFrameRate              = avctx->time_base.den / avctx->time_base.num;
93
+    param.iPicWidth                  = avctx->width;
94
+    param.iPicHeight                 = avctx->height;
95
+    param.iTargetBitrate             = avctx->bit_rate;
96
+    param.iMaxBitrate                = FFMAX(avctx->rc_max_rate, avctx->bit_rate);
97
+    param.iRCMode                    = RC_QUALITY_MODE;
98
+    param.iTemporalLayerNum          = 1;
99
+    param.iSpatialLayerNum           = 1;
100
+    param.bEnableDenoise             = 0;
101
+    param.bEnableBackgroundDetection = 1;
102
+    param.bEnableAdaptiveQuant       = 1;
103
+    param.bEnableFrameSkip           = 0;
104
+    param.bEnableLongTermReference   = 0;
105
+    param.iLtrMarkPeriod             = 30;
106
+    param.uiIntraPeriod              = avctx->gop_size;
107
+    param.bEnableSpsPpsIdAddition    = 0;
108
+    param.bPrefixNalAddingCtrl       = 0;
109
+    param.iLoopFilterDisableIdc      = !s->loopfilter;
110
+    param.iEntropyCodingModeFlag     = 0;
111
+    param.iMultipleThreadIdc         = avctx->thread_count;
112
+    if (s->profile && !strcmp(s->profile, "main"))
113
+        param.iEntropyCodingModeFlag = 1;
114
+    else if (!s->profile && avctx->coder_type == FF_CODER_TYPE_AC)
115
+        param.iEntropyCodingModeFlag = 1;
116
+
117
+    param.sSpatialLayers[0].iVideoWidth         = param.iPicWidth;
118
+    param.sSpatialLayers[0].iVideoHeight        = param.iPicHeight;
119
+    param.sSpatialLayers[0].fFrameRate          = param.fMaxFrameRate;
120
+    param.sSpatialLayers[0].iSpatialBitrate     = param.iTargetBitrate;
121
+    param.sSpatialLayers[0].iMaxSpatialBitrate  = param.iMaxBitrate;
122
+
123
+    if (avctx->slices > 1)
124
+        s->slice_mode = SM_FIXEDSLCNUM_SLICE;
125
+    param.sSpatialLayers[0].sSliceCfg.uiSliceMode               = s->slice_mode;
126
+    param.sSpatialLayers[0].sSliceCfg.sSliceArgument.uiSliceNum = avctx->slices;
127
+
128
+    if ((*s->encoder)->InitializeExt(s->encoder, &param) != cmResultSuccess) {
129
+        av_log(avctx, AV_LOG_ERROR, "Initialize failed\n");
130
+        goto fail;
131
+    }
132
+
133
+    if (avctx->flags & CODEC_FLAG_GLOBAL_HEADER) {
134
+        SFrameBSInfo fbi = { 0 };
135
+        int i, size = 0;
136
+        (*s->encoder)->EncodeParameterSets(s->encoder, &fbi);
137
+        for (i = 0; i < fbi.sLayerInfo[0].iNalCount; i++)
138
+            size += fbi.sLayerInfo[0].pNalLengthInByte[i];
139
+        avctx->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
140
+        if (!avctx->extradata) {
141
+            err = AVERROR(ENOMEM);
142
+            goto fail;
143
+        }
144
+        avctx->extradata_size = size;
145
+        memcpy(avctx->extradata, fbi.sLayerInfo[0].pBsBuf, size);
146
+    }
147
+
148
+    return 0;
149
+
150
+fail:
151
+    svc_encode_close(avctx);
152
+    return err;
153
+}
154
+
155
+static int svc_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
156
+                            const AVFrame *frame, int *got_packet)
157
+{
158
+    SVCContext *s = avctx->priv_data;
159
+    SFrameBSInfo fbi = { 0 };
160
+    int i, ret;
161
+    int encoded;
162
+    SSourcePicture sp = { 0 };
163
+    int size = 0, layer, first_layer = 0;
164
+    int layer_size[MAX_LAYER_NUM_OF_FRAME] = { 0 };
165
+
166
+    sp.iColorFormat = videoFormatI420;
167
+    for (i = 0; i < 3; i++) {
168
+        sp.iStride[i] = frame->linesize[i];
169
+        sp.pData[i]   = frame->data[i];
170
+    }
171
+    sp.iPicWidth  = avctx->width;
172
+    sp.iPicHeight = avctx->height;
173
+
174
+    encoded = (*s->encoder)->EncodeFrame(s->encoder, &sp, &fbi);
175
+    if (encoded != cmResultSuccess) {
176
+        av_log(avctx, AV_LOG_ERROR, "EncodeFrame failed\n");
177
+        return AVERROR_UNKNOWN;
178
+    }
179
+    if (fbi.eFrameType == videoFrameTypeSkip) {
180
+        av_log(avctx, AV_LOG_DEBUG, "frame skipped\n");
181
+        return 0;
182
+    }
183
+    first_layer = 0;
184
+    // Normal frames are returned with one single layers, while IDR
185
+    // frames have two layers, where the first layer contains the SPS/PPS.
186
+    // If using global headers, don't include the SPS/PPS in the returned
187
+    // packet - thus, only return one layer.
188
+    if (avctx->flags & CODEC_FLAG_GLOBAL_HEADER)
189
+        first_layer = fbi.iLayerNum - 1;
190
+
191
+    for (layer = first_layer; layer < fbi.iLayerNum; layer++) {
192
+        for (i = 0; i < fbi.sLayerInfo[layer].iNalCount; i++)
193
+            layer_size[layer] += fbi.sLayerInfo[layer].pNalLengthInByte[i];
194
+        size += layer_size[layer];
195
+    }
196
+    av_log(NULL, AV_LOG_DEBUG, "%d slices\n", fbi.sLayerInfo[fbi.iLayerNum - 1].iNalCount);
197
+
198
+    if ((ret = ff_alloc_packet(avpkt, size))) {
199
+        av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n");
200
+        return ret;
201
+    }
202
+    size = 0;
203
+    for (layer = first_layer; layer < fbi.iLayerNum; layer++) {
204
+        memcpy(avpkt->data + size, fbi.sLayerInfo[layer].pBsBuf, layer_size[layer]);
205
+        size += layer_size[layer];
206
+    }
207
+    avpkt->pts = frame->pts;
208
+    if (fbi.eFrameType == videoFrameTypeIDR)
209
+        avpkt->flags |= AV_PKT_FLAG_KEY;
210
+    *got_packet = 1;
211
+    return 0;
212
+}
213
+
214
+AVCodec ff_libopenh264_encoder = {
215
+    .name           = "libopenh264",
216
+    .type           = AVMEDIA_TYPE_VIDEO,
217
+    .id             = AV_CODEC_ID_H264,
218
+    .priv_data_size = sizeof(SVCContext),
219
+    .init           = svc_encode_init,
220
+    .encode2        = svc_encode_frame,
221
+    .close          = svc_encode_close,
222
+    .capabilities   = CODEC_CAP_AUTO_THREADS,
223
+    .pix_fmts       = (const enum PixelFormat[]){ AV_PIX_FMT_YUV420P,
224
+                                                  AV_PIX_FMT_NONE },
225
+    .long_name      = NULL_IF_CONFIG_SMALL("OpenH264"),
226
+    .priv_class     = &class,
227
+};
... ...
@@ -29,7 +29,7 @@
29 29
 #include "libavutil/version.h"
30 30
 
31 31
 #define LIBAVCODEC_VERSION_MAJOR 56
32
-#define LIBAVCODEC_VERSION_MINOR  19
32
+#define LIBAVCODEC_VERSION_MINOR  20
33 33
 #define LIBAVCODEC_VERSION_MICRO 100
34 34
 
35 35
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \