blob: 6333fe4979823fe30dfa52aa60298887361eecda [file] [log] [blame]
Sebastian Dröge4139fce2015-03-17 09:38:41 +01001/*
2 * Copyright (c) 2014, Ericsson AB. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification,
5 * are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this
11 * list of conditions and the following disclaimer in the documentation and/or other
12 * materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
18 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
21 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
23 * OF SUCH DAMAGE.
24 */
25
26#ifdef HAVE_CONFIG_H
27#include "config.h"
28#endif
29
30#include <wels/codec_api.h>
31#include <wels/codec_app_def.h>
32#include <wels/codec_def.h>
33
34#include "gstopenh264dec.h"
35#include <gst/gst.h>
36#include <gst/video/video.h>
37#include <gst/video/gstvideodecoder.h>
38#include <string.h> /* for memcpy */
39
40
41#define GST_OPENH264DEC_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ( \
42 (obj), GST_TYPE_OPENH264DEC, \
43 GstOpenh264DecPrivate))
44
45GST_DEBUG_CATEGORY_STATIC (gst_openh264dec_debug_category);
46#define GST_CAT_DEFAULT gst_openh264dec_debug_category
47
48/* prototypes */
49
50
51static void gst_openh264dec_set_property (GObject * object,
52 guint property_id, const GValue * value, GParamSpec * pspec);
53static void gst_openh264dec_get_property (GObject * object, guint property_id,
54 GValue * value, GParamSpec * pspec);
55
56static gboolean gst_openh264dec_start (GstVideoDecoder * decoder);
57static gboolean gst_openh264dec_stop (GstVideoDecoder * decoder);
58
59static gboolean gst_openh264dec_set_format (GstVideoDecoder * decoder,
60 GstVideoCodecState * state);
61static gboolean gst_openh264dec_reset (GstVideoDecoder * decoder,
62 gboolean hard);
63static GstFlowReturn gst_openh264dec_finish (GstVideoDecoder * decoder);
64static GstFlowReturn gst_openh264dec_handle_frame (GstVideoDecoder * decoder,
65 GstVideoCodecFrame * frame);
66static gboolean gst_openh264dec_decide_allocation (GstVideoDecoder * decoder,
67 GstQuery * query);
68
69enum
70{
71 PROP_0,
72 N_PROPERTIES
73};
74
75struct _GstOpenh264DecPrivate
76{
77 ISVCDecoder *decoder;
78 GstVideoCodecState *input_state;
79 guint width, height;
80};
81
82/* pad templates */
83
84static GstStaticPadTemplate gst_openh264dec_sink_template =
85GST_STATIC_PAD_TEMPLATE ("sink",
86 GST_PAD_SINK,
87 GST_PAD_ALWAYS,
88 GST_STATIC_CAPS
89 ("video/x-h264, stream-format=(string)byte-stream, alignment=(string)au,profile=(string){constrained-baseline,baseline}"));
90
91static GstStaticPadTemplate gst_openh264dec_src_template =
92GST_STATIC_PAD_TEMPLATE ("src",
93 GST_PAD_SRC,
94 GST_PAD_ALWAYS,
95 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("I420")));
96
97/* class initialization */
98
99G_DEFINE_TYPE_WITH_CODE (GstOpenh264Dec, gst_openh264dec,
100 GST_TYPE_VIDEO_DECODER,
101 GST_DEBUG_CATEGORY_INIT (gst_openh264dec_debug_category, "openh264dec", 0,
102 "debug category for openh264dec element"));
103
104static void
105gst_openh264dec_class_init (GstOpenh264DecClass * klass)
106{
107 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
108 GstVideoDecoderClass *video_decoder_class = GST_VIDEO_DECODER_CLASS (klass);
109
110 g_type_class_add_private (klass, sizeof (GstOpenh264DecPrivate));
111
112 /* Setting up pads and setting metadata should be moved to
113 base_class_init if you intend to subclass this class. */
114 gst_element_class_add_pad_template (GST_ELEMENT_CLASS (klass),
115 gst_static_pad_template_get (&gst_openh264dec_sink_template));
116 gst_element_class_add_pad_template (GST_ELEMENT_CLASS (klass),
117 gst_static_pad_template_get (&gst_openh264dec_src_template));
118
119 gst_element_class_set_static_metadata (GST_ELEMENT_CLASS (klass),
120 "OpenH264 video decoder", "Decoder/Video", "OpenH264 video decoder",
121 "Ericsson AB, http://www.ericsson.com");
122 gobject_class->set_property = gst_openh264dec_set_property;
123 gobject_class->get_property = gst_openh264dec_get_property;
124
125 video_decoder_class->start = GST_DEBUG_FUNCPTR (gst_openh264dec_start);
126 video_decoder_class->stop = GST_DEBUG_FUNCPTR (gst_openh264dec_stop);
127
128 video_decoder_class->set_format =
129 GST_DEBUG_FUNCPTR (gst_openh264dec_set_format);
130 video_decoder_class->reset = GST_DEBUG_FUNCPTR (gst_openh264dec_reset);
131 video_decoder_class->finish = GST_DEBUG_FUNCPTR (gst_openh264dec_finish);
132 video_decoder_class->handle_frame =
133 GST_DEBUG_FUNCPTR (gst_openh264dec_handle_frame);
134 video_decoder_class->decide_allocation =
135 GST_DEBUG_FUNCPTR (gst_openh264dec_decide_allocation);
136}
137
138static void
139gst_openh264dec_init (GstOpenh264Dec * openh264dec)
140{
141 openh264dec->priv = GST_OPENH264DEC_GET_PRIVATE (openh264dec);
142 openh264dec->priv->decoder = NULL;
143
144 gst_video_decoder_set_packetized (GST_VIDEO_DECODER (openh264dec), TRUE);
145 gst_video_decoder_set_needs_format (GST_VIDEO_DECODER (openh264dec), TRUE);
146}
147
148void
149gst_openh264dec_set_property (GObject * object, guint property_id,
150 const GValue * value, GParamSpec * pspec)
151{
152 GstOpenh264Dec *openh264dec = GST_OPENH264DEC (object);
153
154 GST_DEBUG_OBJECT (openh264dec, "set_property");
155
156 switch (property_id) {
157 default:
158 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
159 break;
160 }
161}
162
163void
164gst_openh264dec_get_property (GObject * object, guint property_id,
165 GValue * value, GParamSpec * pspec)
166{
167 GstOpenh264Dec *openh264dec = GST_OPENH264DEC (object);
168
169 GST_DEBUG_OBJECT (openh264dec, "get_property");
170
171 switch (property_id) {
172 default:
173 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
174 break;
175 }
176}
177
178static gboolean
179gst_openh264dec_start (GstVideoDecoder * decoder)
180{
181 GstOpenh264Dec *openh264dec = GST_OPENH264DEC (decoder);
182 gint ret;
183 SDecodingParam dec_param = { 0 };
184
185 if (openh264dec->priv->decoder != NULL) {
186 openh264dec->priv->decoder->Uninitialize ();
187 WelsDestroyDecoder (openh264dec->priv->decoder);
188 openh264dec->priv->decoder = NULL;
189 }
190 WelsCreateDecoder (&(openh264dec->priv->decoder));
191
192 dec_param.uiTargetDqLayer = 255;
193 dec_param.eEcActiveIdc = ERROR_CON_FRAME_COPY;
194 dec_param.eOutputColorFormat = videoFormatI420;
195 dec_param.sVideoProperty.eVideoBsType = VIDEO_BITSTREAM_AVC;
196
197 ret = openh264dec->priv->decoder->Initialize (&dec_param);
198
199 GST_DEBUG_OBJECT (openh264dec,
200 "openh264_dec_start called, openh264dec %sinitialized OK!",
201 (ret != cmResultSuccess) ? "NOT " : "");
202
203 return (ret == cmResultSuccess);
204}
205
206static gboolean
207gst_openh264dec_stop (GstVideoDecoder * decoder)
208{
209 GstOpenh264Dec *openh264dec = GST_OPENH264DEC (decoder);
Sebastian Dröge4139fce2015-03-17 09:38:41 +0100210
211 if (openh264dec->priv->decoder) {
Sebastian Drögedbfbfdc2015-08-19 13:33:51 +0300212 openh264dec->priv->decoder->Uninitialize ();
Sebastian Dröge4139fce2015-03-17 09:38:41 +0100213 WelsDestroyDecoder (openh264dec->priv->decoder);
214 openh264dec->priv->decoder = NULL;
215 }
216
217 if (openh264dec->priv->input_state) {
218 gst_video_codec_state_unref (openh264dec->priv->input_state);
219 openh264dec->priv->input_state = NULL;
220 }
221 openh264dec->priv->width = openh264dec->priv->height = 0;
222
Sebastian Drögedbfbfdc2015-08-19 13:33:51 +0300223 return TRUE;
Sebastian Dröge4139fce2015-03-17 09:38:41 +0100224}
225
226static gboolean
227gst_openh264dec_set_format (GstVideoDecoder * decoder,
228 GstVideoCodecState * state)
229{
230 GstOpenh264Dec *openh264dec = GST_OPENH264DEC (decoder);
231
232 GST_DEBUG_OBJECT (openh264dec,
233 "openh264_dec_set_format called, caps: %" GST_PTR_FORMAT, state->caps);
234
235 if (openh264dec->priv->input_state) {
236 gst_video_codec_state_unref (openh264dec->priv->input_state);
237 openh264dec->priv->input_state = NULL;
238 }
239 openh264dec->priv->input_state = gst_video_codec_state_ref (state);
240
241 return TRUE;
242}
243
244static gboolean
245gst_openh264dec_reset (GstVideoDecoder * decoder, gboolean hard)
246{
247 GstOpenh264Dec *openh264dec = GST_OPENH264DEC (decoder);
248
249 GST_DEBUG_OBJECT (openh264dec, "reset");
250
251 return TRUE;
252}
253
254static GstFlowReturn
255gst_openh264dec_handle_frame (GstVideoDecoder * decoder,
256 GstVideoCodecFrame * frame)
257{
258 GstOpenh264Dec *openh264dec = GST_OPENH264DEC (decoder);
259 GstMapInfo map_info;
260 GstVideoCodecState *state;
261 SBufferInfo dst_buf_info;
262 DECODING_STATE ret;
263 guint8 *yuvdata[3];
264 GstFlowReturn flow_status;
265 GstVideoFrame video_frame;
266 guint actual_width, actual_height;
267 guint i;
268 guint8 *p;
269 guint row_stride, component_width, component_height, src_width, row;
270
271 if (frame) {
272 if (!gst_buffer_map (frame->input_buffer, &map_info, GST_MAP_READ)) {
273 GST_ERROR_OBJECT (openh264dec, "Cannot map input buffer!");
Sebastian Drögedbfbfdc2015-08-19 13:33:51 +0300274 gst_video_codec_frame_unref (frame);
Sebastian Dröge4139fce2015-03-17 09:38:41 +0100275 return GST_FLOW_ERROR;
276 }
277
278 GST_LOG_OBJECT (openh264dec, "handle frame, %d",
279 map_info.size > 4 ? map_info.data[4] & 0x1f : -1);
280
281 memset (&dst_buf_info, 0, sizeof (SBufferInfo));
282 ret =
283 openh264dec->priv->decoder->DecodeFrame2 (map_info.data, map_info.size,
284 yuvdata, &dst_buf_info);
285
286 if (ret == dsNoParamSets) {
287 GST_DEBUG_OBJECT (openh264dec, "Requesting a key unit");
288 gst_pad_push_event (GST_VIDEO_DECODER_SINK_PAD (decoder),
289 gst_video_event_new_upstream_force_key_unit (GST_CLOCK_TIME_NONE,
290 FALSE, 0));
291 }
292
293 if (ret != dsErrorFree && ret != dsNoParamSets) {
294 GST_DEBUG_OBJECT (openh264dec, "Requesting a key unit");
295 gst_pad_push_event (GST_VIDEO_DECODER_SINK_PAD (decoder),
296 gst_video_event_new_upstream_force_key_unit (GST_CLOCK_TIME_NONE,
297 FALSE, 0));
298 GST_LOG_OBJECT (openh264dec, "error decoding nal, return code: %d", ret);
299 }
300
301 gst_buffer_unmap (frame->input_buffer, &map_info);
302 gst_video_codec_frame_unref (frame);
303 frame = NULL;
304 } else {
305 memset (&dst_buf_info, 0, sizeof (SBufferInfo));
306 ret =
307 openh264dec->priv->decoder->DecodeFrame2 (NULL, 0, yuvdata,
308 &dst_buf_info);
Sebastian Drögedbfbfdc2015-08-19 13:33:51 +0300309 if (ret != dsErrorFree) {
310 gst_video_codec_frame_unref (frame);
Sebastian Dröge4139fce2015-03-17 09:38:41 +0100311 return GST_FLOW_EOS;
Sebastian Drögedbfbfdc2015-08-19 13:33:51 +0300312 }
Sebastian Dröge4139fce2015-03-17 09:38:41 +0100313 }
314
315 /* FIXME: openh264 has no way for us to get a connection
316 * between the input and output frames, we just have to
317 * guess based on the input. Fortunately openh264 can
318 * only do baseline profile. */
319 frame = gst_video_decoder_get_oldest_frame (decoder);
320 if (!frame) {
321 /* Can only happen in finish() */
322 return GST_FLOW_EOS;
323 }
324
325 /* No output available yet */
326 if (dst_buf_info.iBufferStatus != 1) {
Sebastian Drögedbfbfdc2015-08-19 13:33:51 +0300327 gst_video_codec_frame_unref (frame);
Sebastian Dröge4139fce2015-03-17 09:38:41 +0100328 return (frame ? GST_FLOW_OK : GST_FLOW_EOS);
329 }
330
331 actual_width = dst_buf_info.UsrData.sSystemBuffer.iWidth;
332 actual_height = dst_buf_info.UsrData.sSystemBuffer.iHeight;
333
334 if (!gst_pad_has_current_caps (GST_VIDEO_DECODER_SRC_PAD (openh264dec))
335 || actual_width != openh264dec->priv->width
336 || actual_height != openh264dec->priv->height) {
337 state =
338 gst_video_decoder_set_output_state (decoder, GST_VIDEO_FORMAT_I420,
339 actual_width, actual_height, openh264dec->priv->input_state);
340 openh264dec->priv->width = actual_width;
341 openh264dec->priv->height = actual_height;
342
343 if (!gst_video_decoder_negotiate (decoder)) {
344 GST_ERROR_OBJECT (openh264dec,
345 "Failed to negotiate with downstream elements");
Sebastian Drögedbfbfdc2015-08-19 13:33:51 +0300346 gst_video_codec_state_unref (state);
347 gst_video_codec_frame_unref (frame);
Sebastian Dröge4139fce2015-03-17 09:38:41 +0100348 return GST_FLOW_NOT_NEGOTIATED;
349 }
350 } else {
351 state = gst_video_decoder_get_output_state (decoder);
352 }
353
354 flow_status = gst_video_decoder_allocate_output_frame (decoder, frame);
355 if (flow_status != GST_FLOW_OK) {
356 gst_video_codec_state_unref (state);
Sebastian Drögedbfbfdc2015-08-19 13:33:51 +0300357 gst_video_codec_frame_unref (frame);
Sebastian Dröge4139fce2015-03-17 09:38:41 +0100358 return flow_status;
359 }
360
361 if (!gst_video_frame_map (&video_frame, &state->info, frame->output_buffer,
362 GST_MAP_WRITE)) {
363 GST_ERROR_OBJECT (openh264dec, "Cannot map output buffer!");
364 gst_video_codec_state_unref (state);
Sebastian Drögedbfbfdc2015-08-19 13:33:51 +0300365 gst_video_codec_frame_unref (frame);
Sebastian Dröge4139fce2015-03-17 09:38:41 +0100366 return GST_FLOW_ERROR;
367 }
368
369 for (i = 0; i < 3; i++) {
370 p = GST_VIDEO_FRAME_COMP_DATA (&video_frame, i);
371 row_stride = GST_VIDEO_FRAME_COMP_STRIDE (&video_frame, i);
372 component_width = GST_VIDEO_FRAME_COMP_WIDTH (&video_frame, i);
373 component_height = GST_VIDEO_FRAME_COMP_HEIGHT (&video_frame, i);
374 src_width =
375 i <
376 1 ? dst_buf_info.UsrData.sSystemBuffer.
377 iStride[0] : dst_buf_info.UsrData.sSystemBuffer.iStride[1];
378 for (row = 0; row < component_height; row++) {
379 memcpy (p, yuvdata[i], component_width);
380 p += row_stride;
381 yuvdata[i] += src_width;
382 }
383 }
384 gst_video_codec_state_unref (state);
385 gst_video_frame_unmap (&video_frame);
386
387 return gst_video_decoder_finish_frame (decoder, frame);
388}
389
390static GstFlowReturn
391gst_openh264dec_finish (GstVideoDecoder * decoder)
392{
393 GstOpenh264Dec *openh264dec = GST_OPENH264DEC (decoder);
394
395 GST_DEBUG_OBJECT (openh264dec, "finish");
396
397 /* Decoder not negotiated yet */
398 if (openh264dec->priv->width == 0)
399 return GST_FLOW_OK;
400
401 /* Drain all pending frames */
402 while ((gst_openh264dec_handle_frame (decoder, NULL)) == GST_FLOW_OK);
403
404 return GST_FLOW_OK;
405}
406
407static gboolean
408gst_openh264dec_decide_allocation (GstVideoDecoder * decoder, GstQuery * query)
409{
410 GstVideoCodecState *state;
411 GstBufferPool *pool;
412 guint size, min, max;
413 GstStructure *config;
414
415 if (!GST_VIDEO_DECODER_CLASS (gst_openh264dec_parent_class)->decide_allocation
416 (decoder, query))
417 return FALSE;
418
419 state = gst_video_decoder_get_output_state (decoder);
420
421 gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
422
423 config = gst_buffer_pool_get_config (pool);
424 if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL)) {
425 gst_buffer_pool_config_add_option (config,
426 GST_BUFFER_POOL_OPTION_VIDEO_META);
427 }
428
429 gst_buffer_pool_set_config (pool, config);
430
431 gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
432
433 gst_object_unref (pool);
434 gst_video_codec_state_unref (state);
435
436 return TRUE;
437}