1 /* GStreamer Intel MSDK plugin
2 * Copyright (c) 2016, Oblong Industries, Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
28 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
29 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #ifdef HAVE_CONFIG_H
33 # include <config.h>
34 #endif
35
36 #include <mfxplugin.h>
37 #include <mfxvp8.h>
38
39 #include "gstmsdkvp8enc.h"
40
41 GST_DEBUG_CATEGORY_EXTERN (gst_msdkvp8enc_debug);
42 #define GST_CAT_DEFAULT gst_msdkvp8enc_debug
43
44 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
45 GST_PAD_SRC,
46 GST_PAD_ALWAYS,
47 GST_STATIC_CAPS ("video/x-vp8, "
48 "framerate = (fraction) [0/1, MAX], "
49 "width = (int) [ 1, MAX ], height = (int) [ 1, MAX ], "
50 "profile = (string) { 0, 1, 2, 3 }")
51 );
52
53 #define gst_msdkvp8enc_parent_class parent_class
54 G_DEFINE_TYPE (GstMsdkVP8Enc, gst_msdkvp8enc, GST_TYPE_MSDKENC);
55
56 static gboolean
gst_msdkvp8enc_set_format(GstMsdkEnc * encoder)57 gst_msdkvp8enc_set_format (GstMsdkEnc * encoder)
58 {
59 GstMsdkVP8Enc *thiz = GST_MSDKVP8ENC (encoder);
60 GstCaps *template_caps;
61 GstCaps *allowed_caps = NULL;
62
63 thiz->profile = 0;
64
65 template_caps = gst_static_pad_template_get_caps (&src_factory);
66 allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (encoder));
67
68 /* If downstream has ANY caps let encoder decide profile and level */
69 if (allowed_caps == template_caps) {
70 GST_INFO_OBJECT (thiz,
71 "downstream has ANY caps, profile/level set to auto");
72 } else if (allowed_caps) {
73 GstStructure *s;
74 const gchar *profile;
75
76 if (gst_caps_is_empty (allowed_caps)) {
77 gst_caps_unref (allowed_caps);
78 gst_caps_unref (template_caps);
79 return FALSE;
80 }
81
82 allowed_caps = gst_caps_make_writable (allowed_caps);
83 allowed_caps = gst_caps_fixate (allowed_caps);
84 s = gst_caps_get_structure (allowed_caps, 0);
85
86 profile = gst_structure_get_string (s, "profile");
87 if (profile) {
88 if (!strcmp (profile, "3")) {
89 thiz->profile = MFX_PROFILE_VP8_3;
90 } else if (!strcmp (profile, "2")) {
91 thiz->profile = MFX_PROFILE_VP8_2;
92 } else if (!strcmp (profile, "1")) {
93 thiz->profile = MFX_PROFILE_VP8_1;
94 } else if (!strcmp (profile, "0")) {
95 thiz->profile = MFX_PROFILE_VP8_0;
96 } else {
97 g_assert_not_reached ();
98 }
99 }
100
101 gst_caps_unref (allowed_caps);
102 }
103
104 gst_caps_unref (template_caps);
105
106 return TRUE;
107 }
108
109 static gboolean
gst_msdkvp8enc_configure(GstMsdkEnc * encoder)110 gst_msdkvp8enc_configure (GstMsdkEnc * encoder)
111 {
112 GstMsdkVP8Enc *thiz = GST_MSDKVP8ENC (encoder);
113 mfxSession session;
114 mfxStatus status;
115
116 if (encoder->hardware) {
117 session = gst_msdk_context_get_session (encoder->context);
118 status = MFXVideoUSER_Load (session, &MFX_PLUGINID_VP8E_HW, 1);
119 if (status < MFX_ERR_NONE) {
120 GST_ERROR_OBJECT (thiz, "Media SDK Plugin load failed (%s)",
121 msdk_status_to_string (status));
122 return FALSE;
123 } else if (status > MFX_ERR_NONE) {
124 GST_WARNING_OBJECT (thiz, "Media SDK Plugin load warning: %s",
125 msdk_status_to_string (status));
126 }
127 }
128
129 encoder->param.mfx.CodecId = MFX_CODEC_VP8;
130 encoder->param.mfx.CodecProfile = thiz->profile;
131 encoder->param.mfx.CodecLevel = 0;
132
133 /* Enable Extended Coding options */
134 gst_msdkenc_ensure_extended_coding_options (encoder);
135
136 return TRUE;
137 }
138
139 static inline const gchar *
profile_to_string(gint profile)140 profile_to_string (gint profile)
141 {
142 switch (profile) {
143 case MFX_PROFILE_VP8_3:
144 return "3";
145 case MFX_PROFILE_VP8_2:
146 return "2";
147 case MFX_PROFILE_VP8_1:
148 return "1";
149 case MFX_PROFILE_VP8_0:
150 return "0";
151 default:
152 break;
153 }
154
155 return NULL;
156 }
157
158 static GstCaps *
gst_msdkvp8enc_set_src_caps(GstMsdkEnc * encoder)159 gst_msdkvp8enc_set_src_caps (GstMsdkEnc * encoder)
160 {
161 GstCaps *caps;
162 GstStructure *structure;
163 const gchar *profile;
164
165 caps = gst_caps_new_empty_simple ("video/x-vp8");
166 structure = gst_caps_get_structure (caps, 0);
167
168 profile = profile_to_string (encoder->param.mfx.CodecProfile);
169 if (profile)
170 gst_structure_set (structure, "profile", G_TYPE_STRING, profile, NULL);
171
172 return caps;
173 }
174
175 static void
gst_msdkvp8enc_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)176 gst_msdkvp8enc_set_property (GObject * object, guint prop_id,
177 const GValue * value, GParamSpec * pspec)
178 {
179 GstMsdkVP8Enc *thiz = GST_MSDKVP8ENC (object);
180
181 if (!gst_msdkenc_set_common_property (object, prop_id, value, pspec))
182 GST_WARNING_OBJECT (thiz, "Failed to set common encode property");
183 }
184
185 static void
gst_msdkvp8enc_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)186 gst_msdkvp8enc_get_property (GObject * object, guint prop_id, GValue * value,
187 GParamSpec * pspec)
188 {
189 GstMsdkVP8Enc *thiz = GST_MSDKVP8ENC (object);
190
191 if (!gst_msdkenc_get_common_property (object, prop_id, value, pspec))
192 GST_WARNING_OBJECT (thiz, "Failed to get common encode property");
193 }
194
195 static void
gst_msdkvp8enc_class_init(GstMsdkVP8EncClass * klass)196 gst_msdkvp8enc_class_init (GstMsdkVP8EncClass * klass)
197 {
198 GObjectClass *gobject_class;
199 GstElementClass *element_class;
200 GstMsdkEncClass *encoder_class;
201
202 gobject_class = G_OBJECT_CLASS (klass);
203 element_class = GST_ELEMENT_CLASS (klass);
204 encoder_class = GST_MSDKENC_CLASS (klass);
205
206 gobject_class->set_property = gst_msdkvp8enc_set_property;
207 gobject_class->get_property = gst_msdkvp8enc_get_property;
208
209 encoder_class->set_format = gst_msdkvp8enc_set_format;
210 encoder_class->configure = gst_msdkvp8enc_configure;
211 encoder_class->set_src_caps = gst_msdkvp8enc_set_src_caps;
212
213 gst_msdkenc_install_common_properties (encoder_class);
214
215 gst_element_class_set_static_metadata (element_class,
216 "Intel MSDK VP8 encoder",
217 "Codec/Encoder/Video/Hardware",
218 "VP8 video encoder based on Intel Media SDK",
219 "Josep Torra <jtorra@oblong.com>");
220
221 gst_element_class_add_static_pad_template (element_class, &src_factory);
222 }
223
224 static void
gst_msdkvp8enc_init(GstMsdkVP8Enc * thiz)225 gst_msdkvp8enc_init (GstMsdkVP8Enc * thiz)
226 {
227 }
228