1 /* GStreamer
2 * Copyright (C) 2019 Seungha Yang <seungha.yang@navercorp.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20 /*
21 * Copyright 2015 The Chromium Authors. All rights reserved.
22 *
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions are
25 * met:
26 *
27 * * Redistributions of source code must retain the above copyright
28 * notice, this list of conditions and the following disclaimer.
29 * * Redistributions in binary form must reproduce the above
30 * copyright notice, this list of conditions and the following disclaimer
31 * in the documentation and/or other materials provided with the
32 * distribution.
33 * * Neither the name of Google Inc. nor the names of its
34 * contributors may be used to endorse or promote products derived from
35 * this software without specific prior written permission.
36 *
37 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
38 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
39 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
40 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
41 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
44 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
45 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
46 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
47 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48 */
49 /**
50 * SECTION:gstvp9decoder
51 * @title: Gstvp9Decoder
52 * @short_description: Base class to implement stateless VP9 decoders
53 * @sources:
54 * - gstvp9picture.h
55 */
56
57 #ifdef HAVE_CONFIG_H
58 #include <config.h>
59 #endif
60
61 #include <gst/base/base.h>
62 #include "gstvp9decoder.h"
63
64 GST_DEBUG_CATEGORY (gst_vp9_decoder_debug);
65 #define GST_CAT_DEFAULT gst_vp9_decoder_debug
66
67 struct _GstVp9DecoderPrivate
68 {
69 gint frame_width;
70 gint frame_height;
71 gint render_width;
72 gint render_height;
73 GstVP9Profile profile;
74
75 gboolean had_sequence;
76
77 GstVp9StatefulParser *parser;
78 GstVp9Dpb *dpb;
79
80 gboolean support_non_kf_change;
81
82 gboolean wait_keyframe;
83 /* controls how many frames to delay when calling output_picture() */
84 guint preferred_output_delay;
85 GstQueueArray *output_queue;
86 gboolean is_live;
87 };
88
89 typedef struct
90 {
91 GstVideoCodecFrame *frame;
92 GstVp9Picture *picture;
93 GstVp9Decoder *self;
94 } GstVp9DecoderOutputFrame;
95
96 #define parent_class gst_vp9_decoder_parent_class
97 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstVp9Decoder, gst_vp9_decoder,
98 GST_TYPE_VIDEO_DECODER,
99 G_ADD_PRIVATE (GstVp9Decoder);
100 GST_DEBUG_CATEGORY_INIT (gst_vp9_decoder_debug, "vp9decoder", 0,
101 "VP9 Video Decoder"));
102
103 static gboolean gst_vp9_decoder_start (GstVideoDecoder * decoder);
104 static gboolean gst_vp9_decoder_stop (GstVideoDecoder * decoder);
105 static gboolean gst_vp9_decoder_set_format (GstVideoDecoder * decoder,
106 GstVideoCodecState * state);
107 static GstFlowReturn gst_vp9_decoder_finish (GstVideoDecoder * decoder);
108 static gboolean gst_vp9_decoder_flush (GstVideoDecoder * decoder);
109 static GstFlowReturn gst_vp9_decoder_drain (GstVideoDecoder * decoder);
110 static GstFlowReturn gst_vp9_decoder_handle_frame (GstVideoDecoder * decoder,
111 GstVideoCodecFrame * frame);
112
113 static void
114 gst_vp9_decoder_clear_output_frame (GstVp9DecoderOutputFrame * output_frame);
115 static void gst_vp9_decoder_drain_output_queue (GstVp9Decoder * self,
116 guint num, GstFlowReturn * ret);
117 static GstFlowReturn gst_vp9_decoder_drain_internal (GstVp9Decoder * self,
118 gboolean wait_keyframe);
119
120 static void
gst_vp9_decoder_class_init(GstVp9DecoderClass * klass)121 gst_vp9_decoder_class_init (GstVp9DecoderClass * klass)
122 {
123 GstVideoDecoderClass *decoder_class = GST_VIDEO_DECODER_CLASS (klass);
124
125 decoder_class->start = GST_DEBUG_FUNCPTR (gst_vp9_decoder_start);
126 decoder_class->stop = GST_DEBUG_FUNCPTR (gst_vp9_decoder_stop);
127 decoder_class->set_format = GST_DEBUG_FUNCPTR (gst_vp9_decoder_set_format);
128 decoder_class->finish = GST_DEBUG_FUNCPTR (gst_vp9_decoder_finish);
129 decoder_class->flush = GST_DEBUG_FUNCPTR (gst_vp9_decoder_flush);
130 decoder_class->drain = GST_DEBUG_FUNCPTR (gst_vp9_decoder_drain);
131 decoder_class->handle_frame =
132 GST_DEBUG_FUNCPTR (gst_vp9_decoder_handle_frame);
133 }
134
135 static void
gst_vp9_decoder_init(GstVp9Decoder * self)136 gst_vp9_decoder_init (GstVp9Decoder * self)
137 {
138 gst_video_decoder_set_packetized (GST_VIDEO_DECODER (self), TRUE);
139
140 self->priv = gst_vp9_decoder_get_instance_private (self);
141
142 /* Assume subclass can support non-keyframe format change by default */
143 self->priv->support_non_kf_change = TRUE;
144 }
145
146 static gboolean
gst_vp9_decoder_start(GstVideoDecoder * decoder)147 gst_vp9_decoder_start (GstVideoDecoder * decoder)
148 {
149 GstVp9Decoder *self = GST_VP9_DECODER (decoder);
150 GstVp9DecoderPrivate *priv = self->priv;
151
152 priv->parser = gst_vp9_stateful_parser_new ();
153 priv->dpb = gst_vp9_dpb_new ();
154 priv->wait_keyframe = TRUE;
155 priv->profile = GST_VP9_PROFILE_UNDEFINED;
156 priv->frame_width = 0;
157 priv->frame_height = 0;
158 priv->render_width = 0;
159 priv->render_height = 0;
160
161 priv->output_queue =
162 gst_queue_array_new_for_struct (sizeof (GstVp9DecoderOutputFrame), 1);
163 gst_queue_array_set_clear_func (priv->output_queue,
164 (GDestroyNotify) gst_vp9_decoder_clear_output_frame);
165
166 return TRUE;
167 }
168
169 static gboolean
gst_vp9_decoder_stop(GstVideoDecoder * decoder)170 gst_vp9_decoder_stop (GstVideoDecoder * decoder)
171 {
172 GstVp9Decoder *self = GST_VP9_DECODER (decoder);
173 GstVp9DecoderPrivate *priv = self->priv;
174
175 g_clear_pointer (&self->input_state, gst_video_codec_state_unref);
176 g_clear_pointer (&priv->parser, gst_vp9_stateful_parser_free);
177 g_clear_pointer (&priv->dpb, gst_vp9_dpb_free);
178 gst_queue_array_free (priv->output_queue);
179
180 return TRUE;
181 }
182
183 static gboolean
gst_vp9_decoder_is_format_change(GstVp9Decoder * self,const GstVp9FrameHeader * frame_hdr)184 gst_vp9_decoder_is_format_change (GstVp9Decoder * self,
185 const GstVp9FrameHeader * frame_hdr)
186 {
187 GstVp9DecoderPrivate *priv = self->priv;
188
189 if (priv->frame_width != frame_hdr->width
190 || priv->frame_height != frame_hdr->height) {
191 GST_INFO_OBJECT (self, "frame resolution changed %dx%d", frame_hdr->width,
192 frame_hdr->height);
193 return TRUE;
194 }
195
196 if (priv->render_width != frame_hdr->render_width
197 || priv->render_height != frame_hdr->render_height) {
198 GST_INFO_OBJECT (self, "render resolution changed %dx%d",
199 frame_hdr->render_width, frame_hdr->render_height);
200 return TRUE;
201 }
202
203 if (priv->profile != frame_hdr->profile) {
204 GST_INFO_OBJECT (self, "profile changed %d", frame_hdr->profile);
205 return TRUE;
206 }
207
208 return FALSE;
209 }
210
211 static GstFlowReturn
gst_vp9_decoder_check_codec_change(GstVp9Decoder * self,const GstVp9FrameHeader * frame_hdr)212 gst_vp9_decoder_check_codec_change (GstVp9Decoder * self,
213 const GstVp9FrameHeader * frame_hdr)
214 {
215 GstVp9DecoderPrivate *priv = self->priv;
216 GstVp9DecoderClass *klass = GST_VP9_DECODER_GET_CLASS (self);
217 GstFlowReturn ret = GST_FLOW_OK;
218
219 if (priv->had_sequence && !gst_vp9_decoder_is_format_change (self, frame_hdr)) {
220 return GST_FLOW_OK;
221 }
222
223 priv->frame_width = frame_hdr->width;
224 priv->frame_height = frame_hdr->height;
225 priv->render_width = frame_hdr->render_width;
226 priv->render_height = frame_hdr->render_height;
227 priv->profile = frame_hdr->profile;
228
229 /* Drain before new sequence */
230 ret = gst_vp9_decoder_drain_internal (self, FALSE);
231 if (ret != GST_FLOW_OK) {
232 GST_WARNING_OBJECT (self, "Failed to drain pending frames, returned %s",
233 gst_flow_get_name (ret));
234 return ret;
235 }
236
237 priv->had_sequence = TRUE;
238
239 if (klass->get_preferred_output_delay) {
240 priv->preferred_output_delay =
241 klass->get_preferred_output_delay (self, priv->is_live);
242 } else {
243 priv->preferred_output_delay = 0;
244 }
245
246 if (klass->new_sequence)
247 ret = klass->new_sequence (self, frame_hdr);
248
249 if (ret != GST_FLOW_OK)
250 priv->had_sequence = FALSE;
251
252 return ret;
253 }
254
255 static gboolean
gst_vp9_decoder_set_format(GstVideoDecoder * decoder,GstVideoCodecState * state)256 gst_vp9_decoder_set_format (GstVideoDecoder * decoder,
257 GstVideoCodecState * state)
258 {
259 GstVp9Decoder *self = GST_VP9_DECODER (decoder);
260 GstVp9DecoderPrivate *priv = self->priv;
261 GstQuery *query;
262
263 GST_DEBUG_OBJECT (decoder, "Set format");
264
265 if (self->input_state)
266 gst_video_codec_state_unref (self->input_state);
267
268 self->input_state = gst_video_codec_state_ref (state);
269
270 query = gst_query_new_latency ();
271 if (gst_pad_peer_query (GST_VIDEO_DECODER_SINK_PAD (self), query))
272 gst_query_parse_latency (query, &priv->is_live, NULL, NULL);
273 gst_query_unref (query);
274
275 return TRUE;
276 }
277
278 static void
gst_vp9_decoder_reset(GstVp9Decoder * self)279 gst_vp9_decoder_reset (GstVp9Decoder * self)
280 {
281 GstVp9DecoderPrivate *priv = self->priv;
282
283 if (priv->dpb)
284 gst_vp9_dpb_clear (priv->dpb);
285
286 priv->wait_keyframe = TRUE;
287 gst_queue_array_clear (priv->output_queue);
288 }
289
290 static GstFlowReturn
gst_vp9_decoder_drain_internal(GstVp9Decoder * self,gboolean wait_keyframe)291 gst_vp9_decoder_drain_internal (GstVp9Decoder * self, gboolean wait_keyframe)
292 {
293 GstFlowReturn ret = GST_FLOW_OK;
294 GstVp9DecoderPrivate *priv = self->priv;
295
296 gst_vp9_decoder_drain_output_queue (self, 0, &ret);
297 if (priv->dpb)
298 gst_vp9_dpb_clear (priv->dpb);
299
300 priv->wait_keyframe = wait_keyframe;
301
302 return ret;
303 }
304
305 static GstFlowReturn
gst_vp9_decoder_finish(GstVideoDecoder * decoder)306 gst_vp9_decoder_finish (GstVideoDecoder * decoder)
307 {
308 GST_DEBUG_OBJECT (decoder, "finish");
309
310 return gst_vp9_decoder_drain_internal (GST_VP9_DECODER (decoder), TRUE);
311 }
312
313 static gboolean
gst_vp9_decoder_flush(GstVideoDecoder * decoder)314 gst_vp9_decoder_flush (GstVideoDecoder * decoder)
315 {
316 GST_DEBUG_OBJECT (decoder, "flush");
317
318 gst_vp9_decoder_reset (GST_VP9_DECODER (decoder));
319
320 return TRUE;
321 }
322
323 static GstFlowReturn
gst_vp9_decoder_drain(GstVideoDecoder * decoder)324 gst_vp9_decoder_drain (GstVideoDecoder * decoder)
325 {
326 GST_DEBUG_OBJECT (decoder, "drain");
327
328 return gst_vp9_decoder_drain_internal (GST_VP9_DECODER (decoder), TRUE);
329 }
330
331 static void
gst_vp9_decoder_clear_output_frame(GstVp9DecoderOutputFrame * output_frame)332 gst_vp9_decoder_clear_output_frame (GstVp9DecoderOutputFrame * output_frame)
333 {
334 if (!output_frame)
335 return;
336
337 if (output_frame->frame) {
338 gst_video_decoder_release_frame (GST_VIDEO_DECODER (output_frame->self),
339 output_frame->frame);
340 output_frame->frame = NULL;
341 }
342
343 gst_vp9_picture_clear (&output_frame->picture);
344 }
345
346 static GstFlowReturn
gst_vp9_decoder_handle_frame(GstVideoDecoder * decoder,GstVideoCodecFrame * frame)347 gst_vp9_decoder_handle_frame (GstVideoDecoder * decoder,
348 GstVideoCodecFrame * frame)
349 {
350 GstVp9Decoder *self = GST_VP9_DECODER (decoder);
351 GstVp9DecoderClass *klass = GST_VP9_DECODER_GET_CLASS (self);
352 GstVp9DecoderPrivate *priv = self->priv;
353 GstBuffer *in_buf = frame->input_buffer;
354 GstVp9FrameHeader frame_hdr;
355 GstVp9Picture *picture = NULL;
356 GstVp9ParserResult pres;
357 GstMapInfo map;
358 GstFlowReturn ret = GST_FLOW_OK;
359 gboolean intra_only = FALSE;
360 gboolean check_codec_change = FALSE;
361 GstVp9DecoderOutputFrame output_frame;
362
363 GST_LOG_OBJECT (self, "handle frame %" GST_PTR_FORMAT, in_buf);
364
365 if (!gst_buffer_map (in_buf, &map, GST_MAP_READ)) {
366 GST_ERROR_OBJECT (self, "Cannot map input buffer");
367 ret = GST_FLOW_ERROR;
368 goto error;
369 }
370
371 pres =
372 gst_vp9_stateful_parser_parse_uncompressed_frame_header (priv->parser,
373 &frame_hdr, map.data, map.size);
374
375 if (pres != GST_VP9_PARSER_OK) {
376 GST_ERROR_OBJECT (self, "Failed to parsing frame header");
377 ret = GST_FLOW_ERROR;
378 goto unmap_and_error;
379 }
380
381 if (self->parse_compressed_headers && !frame_hdr.show_existing_frame) {
382 pres =
383 gst_vp9_stateful_parser_parse_compressed_frame_header (priv->parser,
384 &frame_hdr, map.data + frame_hdr.frame_header_length_in_bytes,
385 map.size);
386
387 if (pres != GST_VP9_PARSER_OK) {
388 GST_ERROR_OBJECT (self, "Failed to parse the compressed frame header");
389 goto unmap_and_error;
390 }
391 }
392
393 if (frame_hdr.show_existing_frame) {
394 /* This is a non-intra, dummy frame */
395 intra_only = FALSE;
396 } else if (frame_hdr.frame_type == GST_VP9_KEY_FRAME || frame_hdr.intra_only) {
397 intra_only = TRUE;
398 }
399
400 if (intra_only) {
401 if (frame_hdr.frame_type == GST_VP9_KEY_FRAME) {
402 /* Always check codec change per keyframe */
403 check_codec_change = TRUE;
404 } else if (priv->wait_keyframe) {
405 /* Or, if we are waiting for leading keyframe, but this is intra-only,
406 * try decoding this frame, it's allowed as per spec */
407 check_codec_change = TRUE;
408 }
409 }
410
411 if (priv->wait_keyframe && !intra_only) {
412 GST_DEBUG_OBJECT (self, "Drop frame before initial keyframe");
413 gst_buffer_unmap (in_buf, &map);
414
415 gst_video_decoder_release_frame (decoder, frame);;
416
417 return GST_FLOW_OK;
418 }
419
420 if (check_codec_change) {
421 ret = gst_vp9_decoder_check_codec_change (self, &frame_hdr);
422 if (ret != GST_FLOW_OK) {
423 GST_WARNING_OBJECT (self, "Subclass cannot handle codec change");
424 goto unmap_and_error;
425 }
426 } else if (!frame_hdr.show_existing_frame && !priv->support_non_kf_change &&
427 gst_vp9_decoder_is_format_change (self, &frame_hdr)) {
428 GST_DEBUG_OBJECT (self, "Drop frame on non-keyframe format change");
429
430 gst_buffer_unmap (in_buf, &map);
431 gst_video_decoder_release_frame (decoder, frame);
432
433 /* Drains frames if any and waits for keyframe again */
434 return gst_vp9_decoder_drain_internal (self, TRUE);
435 }
436
437 if (!priv->had_sequence) {
438 GST_WARNING_OBJECT (self, "No handled frame header, drop frame");
439 goto unmap_and_error;
440 }
441
442 priv->wait_keyframe = FALSE;
443
444 if (frame_hdr.show_existing_frame) {
445 GstVp9Picture *pic_to_dup;
446
447 if (frame_hdr.frame_to_show_map_idx >= GST_VP9_REF_FRAMES ||
448 !priv->dpb->pic_list[frame_hdr.frame_to_show_map_idx]) {
449 GST_ERROR_OBJECT (self, "Invalid frame_to_show_map_idx %d",
450 frame_hdr.frame_to_show_map_idx);
451 goto unmap_and_error;
452 }
453
454 /* If not implemented by subclass, we can just drop this picture
455 * since this frame header indicates the frame index to be duplicated
456 * and also this frame header doesn't affect reference management */
457 if (!klass->duplicate_picture) {
458 gst_buffer_unmap (in_buf, &map);
459 GST_VIDEO_CODEC_FRAME_SET_DECODE_ONLY (frame);
460
461 gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), frame);
462 }
463
464 pic_to_dup = priv->dpb->pic_list[frame_hdr.frame_to_show_map_idx];
465 picture = klass->duplicate_picture (self, frame, pic_to_dup);
466
467 if (!picture) {
468 GST_ERROR_OBJECT (self, "subclass didn't provide duplicated picture");
469 goto unmap_and_error;
470 }
471 } else {
472 picture = gst_vp9_picture_new ();
473 picture->frame_hdr = frame_hdr;
474 picture->system_frame_number = frame->system_frame_number;
475 picture->data = map.data;
476 picture->size = map.size;
477
478 if (klass->new_picture) {
479 ret = klass->new_picture (self, frame, picture);
480 if (ret != GST_FLOW_OK) {
481 GST_WARNING_OBJECT (self, "subclass failed to handle new picture");
482 goto unmap_and_error;
483 }
484 }
485
486 if (klass->start_picture) {
487 ret = klass->start_picture (self, picture);
488 if (ret != GST_FLOW_OK) {
489 GST_WARNING_OBJECT (self, "subclass failed to handle start picture");
490 goto unmap_and_error;
491 }
492 }
493
494 if (klass->decode_picture) {
495 ret = klass->decode_picture (self, picture, priv->dpb);
496 if (ret != GST_FLOW_OK) {
497 GST_WARNING_OBJECT (self, "subclass failed to decode current picture");
498 goto unmap_and_error;
499 }
500 }
501
502 if (klass->end_picture) {
503 ret = klass->end_picture (self, picture);
504 if (ret != GST_FLOW_OK) {
505 GST_WARNING_OBJECT (self, "subclass failed to handle end picture");
506 goto unmap_and_error;
507 }
508 }
509
510 /* Just pass our picture to dpb object.
511 * Even if this picture does not need to be added to dpb
512 * (i.e., not a reference frame), gst_vp9_dpb_add() will take care of
513 * the case as well */
514 gst_vp9_dpb_add (priv->dpb, gst_vp9_picture_ref (picture));
515 }
516
517 gst_buffer_unmap (in_buf, &map);
518
519 if (!frame_hdr.show_frame && !frame_hdr.show_existing_frame) {
520 GST_LOG_OBJECT (self, "Decode only picture %p", picture);
521 GST_VIDEO_CODEC_FRAME_SET_DECODE_ONLY (frame);
522
523 gst_vp9_picture_unref (picture);
524
525 ret = gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), frame);
526 } else {
527 output_frame.frame = frame;
528 output_frame.picture = picture;
529 output_frame.self = self;
530 gst_queue_array_push_tail_struct (priv->output_queue, &output_frame);
531 }
532
533 gst_vp9_decoder_drain_output_queue (self, priv->preferred_output_delay, &ret);
534
535 if (ret == GST_FLOW_ERROR) {
536 GST_VIDEO_DECODER_ERROR (self, 1, STREAM, DECODE,
537 ("Failed to decode data"), (NULL), ret);
538 return ret;
539 }
540
541 return ret;
542
543 unmap_and_error:
544 {
545 gst_buffer_unmap (in_buf, &map);
546 goto error;
547 }
548
549 error:
550 {
551 if (picture)
552 gst_vp9_picture_unref (picture);
553
554 if (ret == GST_FLOW_ERROR) {
555 GST_VIDEO_DECODER_ERROR (self, 1, STREAM, DECODE,
556 ("Failed to decode data"), (NULL), ret);
557 }
558
559 gst_video_decoder_drop_frame (decoder, frame);
560
561 return ret;
562 }
563 }
564
565 static void
gst_vp9_decoder_drain_output_queue(GstVp9Decoder * self,guint num,GstFlowReturn * ret)566 gst_vp9_decoder_drain_output_queue (GstVp9Decoder * self, guint num,
567 GstFlowReturn * ret)
568 {
569 GstVp9DecoderPrivate *priv = self->priv;
570 GstVp9DecoderClass *klass = GST_VP9_DECODER_GET_CLASS (self);
571
572 g_assert (klass->output_picture);
573
574 while (gst_queue_array_get_length (priv->output_queue) > num) {
575 GstVp9DecoderOutputFrame *output_frame = (GstVp9DecoderOutputFrame *)
576 gst_queue_array_pop_head_struct (priv->output_queue);
577 /* Output queued frames whatever the return value is, in order to empty
578 * the queue */
579 GstFlowReturn flow_ret = klass->output_picture (self,
580 output_frame->frame, output_frame->picture);
581
582 /* Then, update @ret with new flow return value only if @ret was
583 * GST_FLOW_OK. This is to avoid pattern such that
584 * ```c
585 * GstFlowReturn my_return = GST_FLOW_OK;
586 * do something
587 *
588 * if (my_return == GST_FLOW_OK) {
589 * my_return = gst_vp9_decoder_drain_output_queue ();
590 * } else {
591 * // Ignore flow return of this method, but current `my_return` error code
592 * gst_vp9_decoder_drain_output_queue ();
593 * }
594 *
595 * return my_return;
596 * ```
597 */
598 if (*ret == GST_FLOW_OK)
599 *ret = flow_ret;
600 }
601 }
602
603 /**
604 * gst_vp9_decoder_set_non_keyframe_format_change_support:
605 * @decoder: a #GstVp9Decoder
606 * @support: whether subclass can support non-keyframe format change
607 *
608 * Called to set non-keyframe format change awareness
609 *
610 * Since: 1.20
611 */
612 void
gst_vp9_decoder_set_non_keyframe_format_change_support(GstVp9Decoder * decoder,gboolean support)613 gst_vp9_decoder_set_non_keyframe_format_change_support (GstVp9Decoder * decoder,
614 gboolean support)
615 {
616 g_return_if_fail (GST_IS_VP9_DECODER (decoder));
617
618 decoder->priv->support_non_kf_change = support;
619 }
620