• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer
2  * Copyright (C) 2020 Seungha Yang <seungha@centricular.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  * SECTION:gstvp8decoder
22  * @title: GstVp8Decoder
23  * @short_description: Base class to implement stateless VP8 decoders
24  * @sources:
25  * - gstvp8picture.h
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 
32 #include <gst/base/base.h>
33 #include "gstvp8decoder.h"
34 
35 GST_DEBUG_CATEGORY (gst_vp8_decoder_debug);
36 #define GST_CAT_DEFAULT gst_vp8_decoder_debug
37 
38 struct _GstVp8DecoderPrivate
39 {
40   gint width;
41   gint height;
42 
43   gboolean had_sequence;
44   GstVp8Parser parser;
45   gboolean wait_keyframe;
46   guint preferred_output_delay;
47   /* for delayed output */
48   GstQueueArray *output_queue;
49   gboolean is_live;
50 };
51 
52 typedef struct
53 {
54   GstVideoCodecFrame *frame;
55   GstVp8Picture *picture;
56   GstVp8Decoder *self;
57 } GstVp8DecoderOutputFrame;
58 
59 #define parent_class gst_vp8_decoder_parent_class
60 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstVp8Decoder, gst_vp8_decoder,
61     GST_TYPE_VIDEO_DECODER,
62     G_ADD_PRIVATE (GstVp8Decoder);
63     GST_DEBUG_CATEGORY_INIT (gst_vp8_decoder_debug, "vp8decoder", 0,
64         "VP8 Video Decoder"));
65 
66 static gboolean gst_vp8_decoder_start (GstVideoDecoder * decoder);
67 static gboolean gst_vp8_decoder_stop (GstVideoDecoder * decoder);
68 static gboolean gst_vp8_decoder_set_format (GstVideoDecoder * decoder,
69     GstVideoCodecState * state);
70 static GstFlowReturn gst_vp8_decoder_finish (GstVideoDecoder * decoder);
71 static gboolean gst_vp8_decoder_flush (GstVideoDecoder * decoder);
72 static GstFlowReturn gst_vp8_decoder_drain (GstVideoDecoder * decoder);
73 static GstFlowReturn gst_vp8_decoder_handle_frame (GstVideoDecoder * decoder,
74     GstVideoCodecFrame * frame);
75 static void gst_vp8_decoder_clear_output_frame (GstVp8DecoderOutputFrame *
76     output_frame);
77 static void gst_vp8_decoder_drain_output_queue (GstVp8Decoder * self,
78     guint num, GstFlowReturn * ret);
79 static GstFlowReturn gst_vp8_decoder_drain_internal (GstVp8Decoder * self,
80     gboolean wait_keyframe);
81 
82 static void
gst_vp8_decoder_class_init(GstVp8DecoderClass * klass)83 gst_vp8_decoder_class_init (GstVp8DecoderClass * klass)
84 {
85   GstVideoDecoderClass *decoder_class = GST_VIDEO_DECODER_CLASS (klass);
86 
87   decoder_class->start = GST_DEBUG_FUNCPTR (gst_vp8_decoder_start);
88   decoder_class->stop = GST_DEBUG_FUNCPTR (gst_vp8_decoder_stop);
89   decoder_class->set_format = GST_DEBUG_FUNCPTR (gst_vp8_decoder_set_format);
90   decoder_class->finish = GST_DEBUG_FUNCPTR (gst_vp8_decoder_finish);
91   decoder_class->flush = GST_DEBUG_FUNCPTR (gst_vp8_decoder_flush);
92   decoder_class->drain = GST_DEBUG_FUNCPTR (gst_vp8_decoder_drain);
93   decoder_class->handle_frame =
94       GST_DEBUG_FUNCPTR (gst_vp8_decoder_handle_frame);
95 }
96 
97 static void
gst_vp8_decoder_init(GstVp8Decoder * self)98 gst_vp8_decoder_init (GstVp8Decoder * self)
99 {
100   gst_video_decoder_set_packetized (GST_VIDEO_DECODER (self), TRUE);
101 
102   self->priv = gst_vp8_decoder_get_instance_private (self);
103 }
104 
105 static gboolean
gst_vp8_decoder_start(GstVideoDecoder * decoder)106 gst_vp8_decoder_start (GstVideoDecoder * decoder)
107 {
108   GstVp8Decoder *self = GST_VP8_DECODER (decoder);
109   GstVp8DecoderPrivate *priv = self->priv;
110 
111   gst_vp8_parser_init (&priv->parser);
112   priv->wait_keyframe = TRUE;
113 
114   priv->output_queue =
115       gst_queue_array_new_for_struct (sizeof (GstVp8DecoderOutputFrame), 1);
116   gst_queue_array_set_clear_func (priv->output_queue,
117       (GDestroyNotify) gst_vp8_decoder_clear_output_frame);
118 
119   return TRUE;
120 }
121 
122 static void
gst_vp8_decoder_reset(GstVp8Decoder * self)123 gst_vp8_decoder_reset (GstVp8Decoder * self)
124 {
125   GstVp8DecoderPrivate *priv = self->priv;
126 
127   gst_vp8_picture_clear (&self->last_picture);
128   gst_vp8_picture_clear (&self->golden_ref_picture);
129   gst_vp8_picture_clear (&self->alt_ref_picture);
130 
131   priv->wait_keyframe = TRUE;
132   gst_queue_array_clear (priv->output_queue);
133 }
134 
135 static gboolean
gst_vp8_decoder_stop(GstVideoDecoder * decoder)136 gst_vp8_decoder_stop (GstVideoDecoder * decoder)
137 {
138   GstVp8Decoder *self = GST_VP8_DECODER (decoder);
139   GstVp8DecoderPrivate *priv = self->priv;
140 
141   if (self->input_state) {
142     gst_video_codec_state_unref (self->input_state);
143     self->input_state = NULL;
144   }
145 
146   gst_vp8_decoder_reset (self);
147   gst_queue_array_free (priv->output_queue);
148 
149   return TRUE;
150 }
151 
152 static GstFlowReturn
gst_vp8_decoder_check_codec_change(GstVp8Decoder * self,const GstVp8FrameHdr * frame_hdr)153 gst_vp8_decoder_check_codec_change (GstVp8Decoder * self,
154     const GstVp8FrameHdr * frame_hdr)
155 {
156   GstVp8DecoderPrivate *priv = self->priv;
157   GstFlowReturn ret = GST_FLOW_OK;
158   gboolean changed = FALSE;
159 
160   if (priv->width != frame_hdr->width || priv->height != frame_hdr->height) {
161     GST_INFO_OBJECT (self, "resolution changed %dx%d", frame_hdr->width,
162         frame_hdr->height);
163     priv->width = frame_hdr->width;
164     priv->height = frame_hdr->height;
165     changed = TRUE;
166   }
167 
168   if (changed || !priv->had_sequence) {
169     GstVp8DecoderClass *klass = GST_VP8_DECODER_GET_CLASS (self);
170 
171     /* Drain before new sequence */
172     ret = gst_vp8_decoder_drain_internal (self, FALSE);
173     if (ret != GST_FLOW_OK) {
174       GST_WARNING_OBJECT (self, "Failed to drain pending frames, returned %s",
175           gst_flow_get_name (ret));
176       return ret;
177     }
178 
179     priv->had_sequence = TRUE;
180 
181     if (klass->get_preferred_output_delay)
182       priv->preferred_output_delay =
183           klass->get_preferred_output_delay (self, priv->is_live);
184     else
185       priv->preferred_output_delay = 0;
186 
187     if (klass->new_sequence)
188       ret = klass->new_sequence (self, frame_hdr);
189   }
190 
191   return ret;
192 }
193 
194 static gboolean
gst_vp8_decoder_set_format(GstVideoDecoder * decoder,GstVideoCodecState * state)195 gst_vp8_decoder_set_format (GstVideoDecoder * decoder,
196     GstVideoCodecState * state)
197 {
198   GstVp8Decoder *self = GST_VP8_DECODER (decoder);
199   GstVp8DecoderPrivate *priv = self->priv;
200   GstQuery *query;
201 
202   GST_DEBUG_OBJECT (decoder, "Set format");
203 
204   if (self->input_state)
205     gst_video_codec_state_unref (self->input_state);
206 
207   self->input_state = gst_video_codec_state_ref (state);
208 
209   priv->width = GST_VIDEO_INFO_WIDTH (&state->info);
210   priv->height = GST_VIDEO_INFO_HEIGHT (&state->info);
211 
212   query = gst_query_new_latency ();
213   if (gst_pad_peer_query (GST_VIDEO_DECODER_SINK_PAD (self), query))
214     gst_query_parse_latency (query, &priv->is_live, NULL, NULL);
215   gst_query_unref (query);
216 
217   return TRUE;
218 }
219 
220 static gboolean
gst_vp8_decoder_update_reference(GstVp8Decoder * self,GstVp8Picture * picture)221 gst_vp8_decoder_update_reference (GstVp8Decoder * self, GstVp8Picture * picture)
222 {
223   GstVp8FrameHdr *frame_hdr = &picture->frame_hdr;
224 
225   if (frame_hdr->key_frame) {
226     gst_vp8_picture_replace (&self->last_picture, picture);
227     gst_vp8_picture_replace (&self->golden_ref_picture, picture);
228     gst_vp8_picture_replace (&self->alt_ref_picture, picture);
229 
230     goto done;
231   }
232 
233   if (frame_hdr->refresh_alternate_frame) {
234     gst_vp8_picture_replace (&self->alt_ref_picture, picture);
235   } else {
236     switch (frame_hdr->copy_buffer_to_alternate) {
237       case 0:
238         /* do nothing */
239         break;
240       case 1:
241         gst_vp8_picture_replace (&self->alt_ref_picture, self->last_picture);
242         break;
243       case 2:
244         gst_vp8_picture_replace (&self->alt_ref_picture,
245             self->golden_ref_picture);
246         break;
247       default:
248         GST_WARNING_OBJECT (self, "unrecognized copy_buffer_to_alternate %d",
249             frame_hdr->copy_buffer_to_alternate);
250         break;
251     }
252   }
253 
254   if (frame_hdr->refresh_golden_frame) {
255     gst_vp8_picture_replace (&self->golden_ref_picture, picture);
256   } else {
257     switch (frame_hdr->copy_buffer_to_golden) {
258       case 0:
259         /* do nothing */
260         break;
261       case 1:
262         gst_vp8_picture_replace (&self->golden_ref_picture, self->last_picture);
263         break;
264       case 2:
265         gst_vp8_picture_replace (&self->golden_ref_picture,
266             self->alt_ref_picture);
267         break;
268       default:
269         GST_WARNING_OBJECT (self, "unrecognized copy_buffer_to_golden %d",
270             frame_hdr->copy_buffer_to_alternate);
271         break;
272     }
273   }
274 
275   if (frame_hdr->refresh_last)
276     gst_vp8_picture_replace (&self->last_picture, picture);
277 
278 done:
279   gst_vp8_picture_unref (picture);
280 
281   return TRUE;
282 }
283 
284 static GstFlowReturn
gst_vp8_decoder_drain_internal(GstVp8Decoder * self,gboolean wait_keyframe)285 gst_vp8_decoder_drain_internal (GstVp8Decoder * self, gboolean wait_keyframe)
286 {
287   GstFlowReturn ret = GST_FLOW_OK;
288   GstVp8DecoderPrivate *priv = self->priv;
289 
290   gst_vp8_decoder_drain_output_queue (self, 0, &ret);
291   gst_vp8_picture_clear (&self->last_picture);
292   gst_vp8_picture_clear (&self->golden_ref_picture);
293   gst_vp8_picture_clear (&self->alt_ref_picture);
294 
295   priv->wait_keyframe = wait_keyframe;
296 
297   return ret;
298 }
299 
300 static GstFlowReturn
gst_vp8_decoder_finish(GstVideoDecoder * decoder)301 gst_vp8_decoder_finish (GstVideoDecoder * decoder)
302 {
303   GST_DEBUG_OBJECT (decoder, "finish");
304 
305   return gst_vp8_decoder_drain_internal (GST_VP8_DECODER (decoder), TRUE);
306 }
307 
308 static gboolean
gst_vp8_decoder_flush(GstVideoDecoder * decoder)309 gst_vp8_decoder_flush (GstVideoDecoder * decoder)
310 {
311   GstVp8Decoder *self = GST_VP8_DECODER (decoder);
312 
313   GST_DEBUG_OBJECT (self, "flush");
314 
315   gst_vp8_decoder_reset (self);
316 
317   return TRUE;
318 }
319 
320 static GstFlowReturn
gst_vp8_decoder_drain(GstVideoDecoder * decoder)321 gst_vp8_decoder_drain (GstVideoDecoder * decoder)
322 {
323   GST_DEBUG_OBJECT (decoder, "drain");
324 
325   return gst_vp8_decoder_drain_internal (GST_VP8_DECODER (decoder), TRUE);
326 }
327 
328 static void
gst_vp8_decoder_clear_output_frame(GstVp8DecoderOutputFrame * output_frame)329 gst_vp8_decoder_clear_output_frame (GstVp8DecoderOutputFrame * output_frame)
330 {
331   if (!output_frame)
332     return;
333 
334   if (output_frame->frame) {
335     gst_video_decoder_release_frame (GST_VIDEO_DECODER (output_frame->self),
336         output_frame->frame);
337     output_frame->frame = NULL;
338   }
339 
340   gst_vp8_picture_clear (&output_frame->picture);
341 }
342 
343 static GstFlowReturn
gst_vp8_decoder_handle_frame(GstVideoDecoder * decoder,GstVideoCodecFrame * frame)344 gst_vp8_decoder_handle_frame (GstVideoDecoder * decoder,
345     GstVideoCodecFrame * frame)
346 {
347   GstVp8Decoder *self = GST_VP8_DECODER (decoder);
348   GstVp8DecoderClass *klass = GST_VP8_DECODER_GET_CLASS (self);
349   GstVp8DecoderPrivate *priv = self->priv;
350   GstBuffer *in_buf = frame->input_buffer;
351   GstMapInfo map;
352   GstVp8FrameHdr frame_hdr;
353   GstVp8ParserResult pres;
354   GstVp8Picture *picture = NULL;
355   GstFlowReturn ret = GST_FLOW_OK;
356   GstVp8DecoderOutputFrame output_frame;
357 
358   GST_LOG_OBJECT (self,
359       "handle frame, PTS: %" GST_TIME_FORMAT ", DTS: %"
360       GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (in_buf)),
361       GST_TIME_ARGS (GST_BUFFER_DTS (in_buf)));
362 
363   if (!gst_buffer_map (in_buf, &map, GST_MAP_READ)) {
364     GST_ERROR_OBJECT (self, "Cannot map buffer");
365     ret = GST_FLOW_ERROR;
366     goto error;
367   }
368 
369   pres = gst_vp8_parser_parse_frame_header (&priv->parser,
370       &frame_hdr, map.data, map.size);
371 
372   if (pres != GST_VP8_PARSER_OK) {
373     GST_ERROR_OBJECT (self, "Cannot parser frame header");
374     ret = GST_FLOW_ERROR;
375     goto unmap_and_error;
376   }
377 
378   if (priv->wait_keyframe) {
379     if (!frame_hdr.key_frame) {
380       GST_DEBUG_OBJECT (self, "Waiting initial keyframe, drop buffer %"
381           GST_PTR_FORMAT, in_buf);
382 
383       gst_buffer_unmap (in_buf, &map);
384       gst_video_decoder_drop_frame (decoder, frame);
385 
386       return GST_FLOW_OK;
387     }
388   }
389 
390   priv->wait_keyframe = FALSE;
391 
392   if (frame_hdr.key_frame) {
393     ret = gst_vp8_decoder_check_codec_change (self, &frame_hdr);
394     if (ret != GST_FLOW_OK) {
395       GST_WARNING_OBJECT (self, "Subclass cannot handle codec change");
396       goto unmap_and_error;
397     }
398   }
399 
400   picture = gst_vp8_picture_new ();
401   picture->frame_hdr = frame_hdr;
402   picture->pts = GST_BUFFER_PTS (in_buf);
403   picture->data = map.data;
404   picture->size = map.size;
405   picture->system_frame_number = frame->system_frame_number;
406 
407   if (klass->new_picture) {
408     ret = klass->new_picture (self, frame, picture);
409     if (ret != GST_FLOW_OK) {
410       GST_WARNING_OBJECT (self, "subclass failed to handle new picture");
411       goto unmap_and_error;
412     }
413   }
414 
415   if (klass->start_picture) {
416     ret = klass->start_picture (self, picture);
417     if (ret != GST_FLOW_OK) {
418       GST_WARNING_OBJECT (self, "subclass failed to handle start picture");
419       goto unmap_and_error;
420     }
421   }
422 
423   if (klass->decode_picture) {
424     ret = klass->decode_picture (self, picture, &priv->parser);
425     if (ret != GST_FLOW_OK) {
426       GST_WARNING_OBJECT (self, "subclass failed to decode current picture");
427       goto unmap_and_error;
428     }
429   }
430 
431   if (klass->end_picture) {
432     ret = klass->end_picture (self, picture);
433     if (ret != GST_FLOW_OK) {
434       GST_WARNING_OBJECT (self, "subclass failed to handle end picture");
435       goto unmap_and_error;
436     }
437   }
438 
439   gst_buffer_unmap (in_buf, &map);
440 
441   gst_vp8_decoder_update_reference (self, gst_vp8_picture_ref (picture));
442 
443   if (!picture->frame_hdr.show_frame) {
444     GST_LOG_OBJECT (self, "Decode only picture %p", picture);
445     GST_VIDEO_CODEC_FRAME_SET_DECODE_ONLY (frame);
446 
447     gst_vp8_picture_unref (picture);
448 
449     ret = gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), frame);
450   } else {
451     output_frame.frame = frame;
452     output_frame.picture = picture;
453     output_frame.self = self;
454     gst_queue_array_push_tail_struct (priv->output_queue, &output_frame);
455   }
456 
457   gst_vp8_decoder_drain_output_queue (self, priv->preferred_output_delay, &ret);
458 
459   if (ret == GST_FLOW_ERROR) {
460     GST_VIDEO_DECODER_ERROR (self, 1, STREAM, DECODE,
461         ("Failed to decode data"), (NULL), ret);
462     return ret;
463   }
464 
465   return ret;
466 
467 unmap_and_error:
468   {
469     gst_buffer_unmap (in_buf, &map);
470     goto error;
471   }
472 
473 error:
474   {
475     if (picture)
476       gst_vp8_picture_unref (picture);
477 
478     if (ret == GST_FLOW_ERROR) {
479       GST_VIDEO_DECODER_ERROR (self, 1, STREAM, DECODE,
480           ("Failed to decode data"), (NULL), ret);
481     }
482 
483     gst_video_decoder_drop_frame (decoder, frame);
484 
485     return ret;
486   }
487 }
488 
489 static void
gst_vp8_decoder_drain_output_queue(GstVp8Decoder * self,guint num,GstFlowReturn * ret)490 gst_vp8_decoder_drain_output_queue (GstVp8Decoder * self, guint num,
491     GstFlowReturn * ret)
492 {
493   GstVp8DecoderPrivate *priv = self->priv;
494   GstVp8DecoderClass *klass = GST_VP8_DECODER_GET_CLASS (self);
495 
496   g_assert (klass->output_picture);
497 
498   while (gst_queue_array_get_length (priv->output_queue) > num) {
499     GstVp8DecoderOutputFrame *output_frame = (GstVp8DecoderOutputFrame *)
500         gst_queue_array_pop_head_struct (priv->output_queue);
501     /* Output queued frames whatever the return value is, in order to empty
502      * the queue */
503     GstFlowReturn flow_ret = klass->output_picture (self,
504         output_frame->frame, output_frame->picture);
505 
506     /* Then, update @ret with new flow return value only if @ret was
507      * GST_FLOW_OK. This is to avoid pattern such that
508      * ```c
509      * GstFlowReturn my_return = GST_FLOW_OK;
510      * do something
511      *
512      * if (my_return == GST_FLOW_OK) {
513      *   my_return = gst_vp8_decoder_drain_output_queue ();
514      * } else {
515      *   // Ignore flow return of this method, but current `my_return` error code
516      *   gst_vp8_decoder_drain_output_queue ();
517      * }
518      *
519      * return my_return;
520      * ```
521      */
522     if (*ret == GST_FLOW_OK)
523       *ret = flow_ret;
524   }
525 }
526