• 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 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 
24 #include <gst/codecparsers/gstvp9parser.h>
25 #include <gst/video/video.h>
26 #include "gstvideoparserselements.h"
27 #include "gstvp9parse.h"
28 
29 #include <string.h>
30 
31 GST_DEBUG_CATEGORY (vp9_parse_debug);
32 #define GST_CAT_DEFAULT vp9_parse_debug
33 
34 typedef enum
35 {
36   GST_VP9_PARSE_ALIGN_NONE = 0,
37   GST_VP9_PARSE_ALIGN_SUPER_FRAME,
38   GST_VP9_PARSE_ALIGN_FRAME,
39 } GstVp9ParseAligment;
40 
41 struct _GstVp9Parse
42 {
43   GstBaseParse parent;
44 
45   /* parsed from the last keyframe */
46   gint width;
47   gint height;
48   gint subsampling_x;
49   gint subsampling_y;
50   GstVp9ColorSpace color_space;
51   GstVp9ColorRange color_range;
52   GstVP9Profile profile;
53   GstVp9BitDepth bit_depth;
54   gboolean codec_alpha;
55 
56   GstVp9ParseAligment in_align;
57   GstVp9ParseAligment align;
58 
59   GstVp9Parser *parser;
60   gboolean update_caps;
61 
62   /* per frame status */
63   gboolean discont;
64 };
65 
66 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
67     GST_PAD_SINK,
68     GST_PAD_ALWAYS,
69     GST_STATIC_CAPS ("video/x-vp9"));
70 
71 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
72     GST_PAD_SRC,
73     GST_PAD_ALWAYS,
74     GST_STATIC_CAPS ("video/x-vp9, parsed = (boolean) true, "
75         "alignment=(string) { super-frame, frame }"));
76 
77 #define parent_class gst_vp9_parse_parent_class
78 G_DEFINE_TYPE (GstVp9Parse, gst_vp9_parse, GST_TYPE_BASE_PARSE);
79 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (vp9parse, "vp9parse", GST_RANK_SECONDARY,
80     GST_TYPE_VP9_PARSE, videoparsers_element_init (plugin));
81 
82 static gboolean gst_vp9_parse_start (GstBaseParse * parse);
83 static gboolean gst_vp9_parse_stop (GstBaseParse * parse);
84 static GstFlowReturn gst_vp9_parse_handle_frame (GstBaseParse * parse,
85     GstBaseParseFrame * frame, gint * skipsize);
86 static gboolean gst_vp9_parse_set_sink_caps (GstBaseParse * parse,
87     GstCaps * caps);
88 static GstCaps *gst_vp9_parse_get_sink_caps (GstBaseParse * parse,
89     GstCaps * filter);
90 static void gst_vp9_parse_update_src_caps (GstVp9Parse * self, GstCaps * caps);
91 static GstFlowReturn gst_vp9_parse_parse_frame (GstVp9Parse * self,
92     GstBaseParseFrame * frame, GstVp9FrameHdr * frame_hdr);
93 
94 static void
gst_vp9_parse_class_init(GstVp9ParseClass * klass)95 gst_vp9_parse_class_init (GstVp9ParseClass * klass)
96 {
97   GstBaseParseClass *parse_class = GST_BASE_PARSE_CLASS (klass);
98   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
99 
100   parse_class->start = GST_DEBUG_FUNCPTR (gst_vp9_parse_start);
101   parse_class->stop = GST_DEBUG_FUNCPTR (gst_vp9_parse_stop);
102   parse_class->handle_frame = GST_DEBUG_FUNCPTR (gst_vp9_parse_handle_frame);
103   parse_class->set_sink_caps = GST_DEBUG_FUNCPTR (gst_vp9_parse_set_sink_caps);
104   parse_class->get_sink_caps = GST_DEBUG_FUNCPTR (gst_vp9_parse_get_sink_caps);
105 
106   gst_element_class_add_static_pad_template (element_class, &srctemplate);
107   gst_element_class_add_static_pad_template (element_class, &sinktemplate);
108 
109   gst_element_class_set_static_metadata (element_class, "VP9 parser",
110       "Codec/Parser/Converter/Video",
111       "Parses VP9 streams", "Seungha Yang <seungha@centricular.com>");
112 
113   GST_DEBUG_CATEGORY_INIT (vp9_parse_debug, "vp9parse", 0, "vp9 parser");
114 }
115 
116 static void
gst_vp9_parse_init(GstVp9Parse * self)117 gst_vp9_parse_init (GstVp9Parse * self)
118 {
119   gst_base_parse_set_pts_interpolation (GST_BASE_PARSE (self), FALSE);
120   gst_base_parse_set_infer_ts (GST_BASE_PARSE (self), FALSE);
121 
122   GST_PAD_SET_ACCEPT_INTERSECT (GST_BASE_PARSE_SINK_PAD (self));
123   GST_PAD_SET_ACCEPT_TEMPLATE (GST_BASE_PARSE_SINK_PAD (self));
124 }
125 
126 static void
gst_vp9_parse_reset(GstVp9Parse * self)127 gst_vp9_parse_reset (GstVp9Parse * self)
128 {
129   self->width = 0;
130   self->height = 0;
131   self->subsampling_x = -1;
132   self->subsampling_y = -1;
133   self->color_space = GST_VP9_CS_UNKNOWN;
134   self->color_range = GST_VP9_CR_LIMITED;
135   self->profile = GST_VP9_PROFILE_UNDEFINED;
136   self->bit_depth = (GstVp9BitDepth) 0;
137   self->codec_alpha = FALSE;
138 }
139 
140 static gboolean
gst_vp9_parse_start(GstBaseParse * parse)141 gst_vp9_parse_start (GstBaseParse * parse)
142 {
143   GstVp9Parse *self = GST_VP9_PARSE (parse);
144 
145   GST_DEBUG_OBJECT (self, "start");
146 
147   self->parser = gst_vp9_parser_new ();
148   gst_vp9_parse_reset (self);
149 
150   /* short frame header with one byte */
151   gst_base_parse_set_min_frame_size (parse, 1);
152 
153   return TRUE;
154 }
155 
156 static gboolean
gst_vp9_parse_stop(GstBaseParse * parse)157 gst_vp9_parse_stop (GstBaseParse * parse)
158 {
159   GstVp9Parse *self = GST_VP9_PARSE (parse);
160 
161   GST_DEBUG_OBJECT (self, "stop");
162   g_clear_pointer (&self->parser, gst_vp9_parser_free);
163 
164   return TRUE;
165 }
166 
167 static const gchar *
gst_vp9_parse_profile_to_string(GstVP9Profile profile)168 gst_vp9_parse_profile_to_string (GstVP9Profile profile)
169 {
170   switch (profile) {
171     case GST_VP9_PROFILE_0:
172       return "0";
173     case GST_VP9_PROFILE_1:
174       return "1";
175     case GST_VP9_PROFILE_2:
176       return "2";
177     case GST_VP9_PROFILE_3:
178       return "3";
179     default:
180       break;
181   }
182 
183   return NULL;
184 }
185 
186 static GstVP9Profile
gst_vp9_parse_profile_from_string(const gchar * profile)187 gst_vp9_parse_profile_from_string (const gchar * profile)
188 {
189   if (!profile)
190     return GST_VP9_PROFILE_UNDEFINED;
191 
192   if (g_strcmp0 (profile, "0") == 0)
193     return GST_VP9_PROFILE_0;
194   else if (g_strcmp0 (profile, "1") == 0)
195     return GST_VP9_PROFILE_1;
196   else if (g_strcmp0 (profile, "2") == 0)
197     return GST_VP9_PROFILE_2;
198   else if (g_strcmp0 (profile, "3") == 0)
199     return GST_VP9_PROFILE_3;
200 
201   return GST_VP9_PROFILE_UNDEFINED;
202 }
203 
204 static const gchar *
gst_vp9_parse_alignment_to_string(GstVp9ParseAligment align)205 gst_vp9_parse_alignment_to_string (GstVp9ParseAligment align)
206 {
207   switch (align) {
208     case GST_VP9_PARSE_ALIGN_SUPER_FRAME:
209       return "super-frame";
210     case GST_VP9_PARSE_ALIGN_FRAME:
211       return "frame";
212     default:
213       break;
214   }
215 
216   return NULL;
217 }
218 
219 static GstVp9ParseAligment
gst_vp9_parse_alignment_from_string(const gchar * align)220 gst_vp9_parse_alignment_from_string (const gchar * align)
221 {
222   if (!align)
223     return GST_VP9_PARSE_ALIGN_NONE;
224 
225   if (g_strcmp0 (align, "super-frame") == 0)
226     return GST_VP9_PARSE_ALIGN_SUPER_FRAME;
227   else if (g_strcmp0 (align, "frame") == 0)
228     return GST_VP9_PARSE_ALIGN_FRAME;
229 
230   return GST_VP9_PARSE_ALIGN_NONE;
231 }
232 
233 static void
gst_vp9_parse_alignment_from_caps(GstCaps * caps,GstVp9ParseAligment * align)234 gst_vp9_parse_alignment_from_caps (GstCaps * caps, GstVp9ParseAligment * align)
235 {
236   *align = GST_VP9_PARSE_ALIGN_NONE;
237 
238   GST_DEBUG ("parsing caps: %" GST_PTR_FORMAT, caps);
239 
240   if (caps && gst_caps_get_size (caps) > 0) {
241     GstStructure *s = gst_caps_get_structure (caps, 0);
242     const gchar *str = NULL;
243 
244     if ((str = gst_structure_get_string (s, "alignment"))) {
245       *align = gst_vp9_parse_alignment_from_string (str);
246     }
247   }
248 }
249 
250 /* implement custom semantic for codec-alpha */
251 static gboolean
gst_vp9_parse_check_codec_alpha(GstStructure * s,gboolean codec_alpha)252 gst_vp9_parse_check_codec_alpha (GstStructure * s, gboolean codec_alpha)
253 {
254   gboolean value;
255 
256   if (gst_structure_get_boolean (s, "codec-alpha", &value))
257     return value == codec_alpha;
258 
259   return codec_alpha == FALSE;
260 }
261 
262 /* check downstream caps to configure format and alignment */
263 static void
gst_vp9_parse_negotiate(GstVp9Parse * self,GstVp9ParseAligment in_align,GstCaps * in_caps)264 gst_vp9_parse_negotiate (GstVp9Parse * self, GstVp9ParseAligment in_align,
265     GstCaps * in_caps)
266 {
267   GstCaps *caps;
268   GstVp9ParseAligment align = self->align;
269 
270   caps = gst_pad_get_allowed_caps (GST_BASE_PARSE_SRC_PAD (self));
271   GST_DEBUG_OBJECT (self, "allowed caps: %" GST_PTR_FORMAT, caps);
272 
273   /* concentrate on leading structure, since decodebin parser
274    * capsfilter always includes parser template caps */
275   if (caps) {
276     while (gst_caps_get_size (caps) > 0) {
277       GstStructure *s = gst_caps_get_structure (caps, 0);
278 
279       if (gst_vp9_parse_check_codec_alpha (s, self->codec_alpha))
280         break;
281 
282       gst_caps_remove_structure (caps, 0);
283     }
284 
285     /* this may happen if there is simply no codec alpha decoder in the
286      * gstreamer installation, in this case, pick the first non-alpha decoder.
287      */
288     if (gst_caps_is_empty (caps)) {
289       gst_caps_unref (caps);
290       caps = gst_pad_get_allowed_caps (GST_BASE_PARSE_SRC_PAD (self));
291     }
292 
293     caps = gst_caps_truncate (caps);
294     GST_DEBUG_OBJECT (self, "negotiating with caps: %" GST_PTR_FORMAT, caps);
295   }
296 
297   if (in_caps && caps) {
298     if (gst_caps_can_intersect (in_caps, caps)) {
299       GST_DEBUG_OBJECT (self, "downstream accepts upstream caps");
300       gst_vp9_parse_alignment_from_caps (in_caps, &align);
301       gst_clear_caps (&caps);
302     }
303   }
304 
305   /* FIXME We could fail the negotiation immediately if caps are empty */
306   if (caps && !gst_caps_is_empty (caps)) {
307     /* fixate to avoid ambiguity with lists when parsing */
308     caps = gst_caps_fixate (caps);
309     gst_vp9_parse_alignment_from_caps (caps, &align);
310   }
311 
312   /* default */
313   if (align == GST_VP9_PARSE_ALIGN_NONE)
314     align = GST_VP9_PARSE_ALIGN_SUPER_FRAME;
315 
316   GST_DEBUG_OBJECT (self, "selected alignment %s",
317       gst_vp9_parse_alignment_to_string (align));
318 
319   self->align = align;
320 
321   gst_clear_caps (&caps);
322 }
323 
324 static gboolean
gst_vp9_parse_is_info_valid(GstVp9Parse * self)325 gst_vp9_parse_is_info_valid (GstVp9Parse * self)
326 {
327   if (self->width <= 0 || self->height <= 0)
328     return FALSE;
329 
330   if (self->subsampling_x < 0 || self->subsampling_y < 0)
331     return FALSE;
332 
333   if (self->profile == GST_VP9_PROFILE_UNDEFINED)
334     return FALSE;
335 
336   if (self->bit_depth < (GstVp9BitDepth) GST_VP9_BIT_DEPTH_8)
337     return FALSE;
338 
339   return TRUE;
340 }
341 
342 static gboolean
gst_vp9_parse_process_frame(GstVp9Parse * self,GstVp9FrameHdr * frame_hdr)343 gst_vp9_parse_process_frame (GstVp9Parse * self, GstVp9FrameHdr * frame_hdr)
344 {
345   GstVp9Parser *parser = self->parser;
346   gint width, height;
347 
348   /* the resolution might be varying. Update our status per key frame */
349   if (frame_hdr->frame_type != GST_VP9_KEY_FRAME ||
350       frame_hdr->show_existing_frame) {
351     /* Need to continue to get some valid info. */
352     if (gst_vp9_parse_is_info_valid (self))
353       return TRUE;
354   }
355 
356   width = frame_hdr->width;
357   height = frame_hdr->height;
358   if (frame_hdr->display_size_enabled &&
359       frame_hdr->display_width > 0 && frame_hdr->display_height) {
360     width = frame_hdr->display_width;
361     height = frame_hdr->display_height;
362   }
363 
364   if (width != self->width || height != self->height) {
365     GST_DEBUG_OBJECT (self, "resolution change from %dx%d to %dx%d",
366         self->width, self->height, width, height);
367     self->width = width;
368     self->height = height;
369     self->update_caps = TRUE;
370   }
371 
372   if (self->subsampling_x != parser->subsampling_x ||
373       self->subsampling_y != parser->subsampling_y) {
374     GST_DEBUG_OBJECT (self,
375         "subsampling changed from x: %d, y: %d to x: %d, y: %d",
376         self->subsampling_x, self->subsampling_y,
377         parser->subsampling_x, parser->subsampling_y);
378     self->subsampling_x = parser->subsampling_x;
379     self->subsampling_y = parser->subsampling_y;
380     self->update_caps = TRUE;
381   }
382 
383   if (parser->color_space != GST_VP9_CS_UNKNOWN &&
384       parser->color_space != GST_VP9_CS_RESERVED_2 &&
385       parser->color_space != self->color_space) {
386     GST_DEBUG_OBJECT (self, "colorspace changed from %d to %d",
387         self->color_space, parser->color_space);
388     self->color_space = parser->color_space;
389     self->update_caps = TRUE;
390   }
391 
392   if (parser->color_range != self->color_range) {
393     GST_DEBUG_OBJECT (self, "color range changed from %d to %d",
394         self->color_range, parser->color_range);
395     self->color_range = parser->color_range;
396     self->update_caps = TRUE;
397   }
398 
399   if (frame_hdr->profile != GST_VP9_PROFILE_UNDEFINED &&
400       frame_hdr->profile != self->profile) {
401     GST_DEBUG_OBJECT (self, "profile changed from %d to %d", self->profile,
402         frame_hdr->profile);
403     self->profile = frame_hdr->profile;
404     self->update_caps = TRUE;
405   }
406 
407   if (parser->bit_depth != self->bit_depth) {
408     GST_DEBUG_OBJECT (self, "bit-depth changed from %d to %d",
409         self->bit_depth, parser->bit_depth);
410     self->bit_depth = parser->bit_depth;
411     self->update_caps = TRUE;
412   }
413 
414   return TRUE;
415 }
416 
417 static GstFlowReturn
gst_vp9_parse_handle_frame(GstBaseParse * parse,GstBaseParseFrame * frame,gint * skipsize)418 gst_vp9_parse_handle_frame (GstBaseParse * parse, GstBaseParseFrame * frame,
419     gint * skipsize)
420 {
421   GstVp9Parse *self = GST_VP9_PARSE (parse);
422   GstBuffer *buffer = frame->buffer;
423   GstFlowReturn ret = GST_FLOW_OK;
424   GstVp9ParserResult parse_res = GST_VP9_PARSER_ERROR;
425   GstMapInfo map;
426   gsize offset = 0;
427   GstVp9SuperframeInfo superframe_info;
428   guint i;
429   GstVp9FrameHdr frame_hdr;
430 
431   if (GST_BUFFER_FLAG_IS_SET (frame->buffer, GST_BUFFER_FLAG_DISCONT))
432     self->discont = TRUE;
433   else
434     self->discont = FALSE;
435 
436   /* need to save buffer from invalidation upon _finish_frame */
437   if (self->align == GST_VP9_PARSE_ALIGN_FRAME)
438     buffer = gst_buffer_copy (frame->buffer);
439 
440   if (!gst_buffer_map (buffer, &map, GST_MAP_READ)) {
441     GST_ELEMENT_ERROR (parse, CORE, NOT_IMPLEMENTED, (NULL),
442         ("Couldn't map incoming buffer"));
443 
444     return GST_FLOW_ERROR;
445   }
446 
447   GST_TRACE_OBJECT (self, "processing buffer of size %" G_GSIZE_FORMAT,
448       map.size);
449 
450   /* superframe_info will be zero initialized by GstVp9Parser */
451   parse_res = gst_vp9_parser_parse_superframe_info (self->parser,
452       &superframe_info, map.data, map.size);
453 
454   if (parse_res != GST_VP9_PARSER_OK) {
455     /* just finish this frame anyway, so that we don't too strict
456      * regarding parsing vp9 stream.
457      * Downstream might be able to handle this stream even though
458      * it's very unlikely */
459     GST_WARNING_OBJECT (self, "Couldn't parse superframe res: %d", parse_res);
460     goto done;
461   }
462 
463   for (i = 0; i < superframe_info.frames_in_superframe; i++) {
464     guint32 frame_size;
465 
466     frame_size = superframe_info.frame_sizes[i];
467     parse_res = gst_vp9_parser_parse_frame_header (self->parser,
468         &frame_hdr, map.data + offset, frame_size);
469 
470     if (parse_res != GST_VP9_PARSER_OK) {
471       GST_WARNING_OBJECT (self, "Parsing error %d", parse_res);
472       break;
473     }
474 
475     gst_vp9_parse_process_frame (self, &frame_hdr);
476 
477     if (self->align == GST_VP9_PARSE_ALIGN_FRAME) {
478       GstBaseParseFrame subframe;
479 
480       gst_base_parse_frame_init (&subframe);
481       subframe.flags |= frame->flags;
482       subframe.offset = frame->offset;
483       subframe.overhead = frame->overhead;
484       subframe.buffer = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL,
485           offset, frame_size);
486 
487       /* note we don't need to come up with a sub-buffer, since
488        * subsequent code only considers input buffer's metadata.
489        * Real data is either taken from input by baseclass or
490        * a replacement output buffer is provided anyway. */
491       gst_vp9_parse_parse_frame (self, &subframe, &frame_hdr);
492       ret = gst_base_parse_finish_frame (parse, &subframe, frame_size);
493     } else {
494       /* FIXME: need to parse all frames belong to this superframe? */
495       break;
496     }
497 
498     offset += frame_size;
499   }
500 
501 done:
502   gst_buffer_unmap (buffer, &map);
503 
504   if (self->align != GST_VP9_PARSE_ALIGN_FRAME) {
505     if (parse_res == GST_VP9_PARSER_OK)
506       gst_vp9_parse_parse_frame (self, frame, &frame_hdr);
507     ret = gst_base_parse_finish_frame (parse, frame, map.size);
508   } else {
509     gst_buffer_unref (buffer);
510     if (offset != map.size) {
511       gsize left = map.size - offset;
512       if (left != superframe_info.superframe_index_size) {
513         GST_WARNING_OBJECT (parse,
514             "Skipping leftover frame data %" G_GSIZE_FORMAT, left);
515       }
516       frame->flags |= GST_BASE_PARSE_FRAME_FLAG_DROP;
517       ret = gst_base_parse_finish_frame (parse, frame, left);
518     }
519   }
520 
521   return ret;
522 }
523 
524 static void
gst_vp9_parse_update_src_caps(GstVp9Parse * self,GstCaps * caps)525 gst_vp9_parse_update_src_caps (GstVp9Parse * self, GstCaps * caps)
526 {
527   GstCaps *sink_caps, *src_caps;
528   GstCaps *final_caps = NULL;
529   GstStructure *s = NULL;
530   gint width, height;
531   gint par_n = 0, par_d = 0;
532   gint fps_n = 0, fps_d = 0;
533   gint bitdepth = 0;
534   gchar *colorimetry = NULL;
535   const gchar *chroma_format = NULL;
536   const gchar *profile = NULL;
537 
538   if (!self->update_caps)
539     return;
540 
541   /* if this is being called from the first _setcaps call, caps on the sinkpad
542    * aren't set yet and so they need to be passed as an argument */
543   if (caps)
544     sink_caps = gst_caps_ref (caps);
545   else
546     sink_caps = gst_pad_get_current_caps (GST_BASE_PARSE_SINK_PAD (self));
547 
548   /* carry over input caps as much as possible; override with our own stuff */
549   if (!sink_caps)
550     sink_caps = gst_caps_new_empty_simple ("video/x-vp9");
551   else
552     s = gst_caps_get_structure (sink_caps, 0);
553 
554   final_caps = gst_caps_copy (sink_caps);
555 
556   /* frame header should give this but upstream overrides */
557   if (s && gst_structure_has_field (s, "width") &&
558       gst_structure_has_field (s, "height")) {
559     gst_structure_get_int (s, "width", &width);
560     gst_structure_get_int (s, "height", &height);
561   } else {
562     width = self->width;
563     height = self->height;
564   }
565 
566   if (width > 0 && height > 0)
567     gst_caps_set_simple (final_caps, "width", G_TYPE_INT, width,
568         "height", G_TYPE_INT, height, NULL);
569 
570   if (s && gst_structure_get_fraction (s, "pixel-aspect-ratio", &par_n, &par_d)) {
571     if (par_n != 0 && par_d != 0) {
572       gst_caps_set_simple (final_caps, "pixel-aspect-ratio",
573           GST_TYPE_FRACTION, par_n, par_d, NULL);
574     }
575   }
576 
577   if (s && gst_structure_has_field (s, "framerate")) {
578     gst_structure_get_fraction (s, "framerate", &fps_n, &fps_d);
579   }
580 
581   if (fps_n > 0 && fps_d > 0) {
582     gst_caps_set_simple (final_caps, "framerate",
583         GST_TYPE_FRACTION, fps_n, fps_d, NULL);
584     gst_base_parse_set_frame_rate (GST_BASE_PARSE (self), fps_n, fps_d, 0, 0);
585   }
586 
587   if (self->color_space != GST_VP9_CS_UNKNOWN &&
588       self->color_space != GST_VP9_CS_RESERVED_2) {
589     GstVideoColorimetry cinfo;
590     gboolean have_cinfo = TRUE;
591 
592     memset (&cinfo, 0, sizeof (GstVideoColorimetry));
593 
594     switch (self->parser->color_space) {
595       case GST_VP9_CS_BT_601:
596         gst_video_colorimetry_from_string (&cinfo, GST_VIDEO_COLORIMETRY_BT601);
597         break;
598       case GST_VP9_CS_BT_709:
599         gst_video_colorimetry_from_string (&cinfo, GST_VIDEO_COLORIMETRY_BT709);
600         break;
601       case GST_VP9_CS_SMPTE_170:
602         gst_video_colorimetry_from_string (&cinfo, GST_VIDEO_COLORIMETRY_BT601);
603         break;
604       case GST_VP9_CS_SMPTE_240:
605         gst_video_colorimetry_from_string (&cinfo,
606             GST_VIDEO_COLORIMETRY_SMPTE240M);
607         break;
608       case GST_VP9_CS_BT_2020:
609         if (self->parser->bit_depth == GST_VP9_BIT_DEPTH_12) {
610           gst_video_colorimetry_from_string (&cinfo,
611               GST_VIDEO_COLORIMETRY_BT2020);
612         } else {
613           gst_video_colorimetry_from_string (&cinfo,
614               GST_VIDEO_COLORIMETRY_BT2020_10);
615         }
616         break;
617       case GST_VP9_CS_SRGB:
618         gst_video_colorimetry_from_string (&cinfo, GST_VIDEO_COLORIMETRY_SRGB);
619         break;
620       default:
621         have_cinfo = FALSE;
622         break;
623     }
624 
625     if (have_cinfo) {
626       if (self->parser->color_range == GST_VP9_CR_LIMITED)
627         cinfo.range = GST_VIDEO_COLOR_RANGE_16_235;
628       else
629         cinfo.range = GST_VIDEO_COLOR_RANGE_0_255;
630 
631       colorimetry = gst_video_colorimetry_to_string (&cinfo);
632     }
633   }
634 
635   if (self->color_space != GST_VP9_CS_SRGB) {
636     if (self->parser->subsampling_x == 1 && self->parser->subsampling_y == 1)
637       chroma_format = "4:2:0";
638     else if (self->parser->subsampling_x == 1 &&
639         self->parser->subsampling_y == 0)
640       chroma_format = "4:2:2";
641     else if (self->parser->subsampling_x == 0 &&
642         self->parser->subsampling_y == 1)
643       chroma_format = "4:4:0";
644     else if (self->parser->subsampling_x == 0 &&
645         self->parser->subsampling_y == 0)
646       chroma_format = "4:4:4";
647 
648     if (chroma_format)
649       gst_caps_set_simple (final_caps,
650           "chroma-format", G_TYPE_STRING, chroma_format, NULL);
651   }
652 
653   switch (self->bit_depth) {
654     case GST_VP9_BIT_DEPTH_8:
655       bitdepth = 8;
656       break;
657     case GST_VP9_BIT_DEPTH_10:
658       bitdepth = 10;
659       break;
660     case GST_VP9_BIT_DEPTH_12:
661       bitdepth = 12;
662       break;
663     default:
664       break;
665   }
666 
667   if (bitdepth) {
668     gst_caps_set_simple (final_caps,
669         "bit-depth-luma", G_TYPE_UINT, bitdepth,
670         "bit-depth-chroma", G_TYPE_UINT, bitdepth, NULL);
671   }
672 
673   if (colorimetry && (!s || !gst_structure_has_field (s, "colorimetry"))) {
674     gst_caps_set_simple (final_caps,
675         "colorimetry", G_TYPE_STRING, colorimetry, NULL);
676   }
677 
678   g_free (colorimetry);
679 
680   gst_caps_set_simple (final_caps, "parsed", G_TYPE_BOOLEAN, TRUE,
681       "alignment", G_TYPE_STRING,
682       gst_vp9_parse_alignment_to_string (self->align), NULL);
683 
684   profile = gst_vp9_parse_profile_to_string (self->profile);
685   if (profile)
686     gst_caps_set_simple (final_caps, "profile", G_TYPE_STRING, profile, NULL);
687 
688   gst_caps_set_simple (final_caps, "codec-alpha", G_TYPE_BOOLEAN,
689       self->codec_alpha, NULL);
690 
691   src_caps = gst_pad_get_current_caps (GST_BASE_PARSE_SRC_PAD (self));
692 
693   if (!(src_caps && gst_caps_is_strictly_equal (src_caps, final_caps))) {
694     GST_DEBUG_OBJECT (self, "Update src caps %" GST_PTR_FORMAT, final_caps);
695     gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (self), final_caps);
696   }
697 
698   gst_clear_caps (&src_caps);
699   gst_caps_unref (final_caps);
700   gst_caps_unref (sink_caps);
701 
702   self->update_caps = FALSE;
703 }
704 
705 static GstFlowReturn
gst_vp9_parse_parse_frame(GstVp9Parse * self,GstBaseParseFrame * frame,GstVp9FrameHdr * frame_hdr)706 gst_vp9_parse_parse_frame (GstVp9Parse * self, GstBaseParseFrame * frame,
707     GstVp9FrameHdr * frame_hdr)
708 {
709   GstBuffer *buffer;
710 
711   buffer = frame->buffer;
712 
713   gst_vp9_parse_update_src_caps (self, NULL);
714 
715   if (frame_hdr->frame_type == GST_VP9_KEY_FRAME)
716     GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
717   else
718     GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
719 
720   if (self->align == GST_VP9_PARSE_ALIGN_FRAME) {
721     if (!frame_hdr->show_frame)
722       GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DECODE_ONLY);
723     else
724       GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DECODE_ONLY);
725   }
726 
727   if (self->discont) {
728     GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
729     self->discont = FALSE;
730   }
731 
732   return GST_FLOW_OK;
733 }
734 
735 static gboolean
gst_vp9_parse_set_sink_caps(GstBaseParse * parse,GstCaps * caps)736 gst_vp9_parse_set_sink_caps (GstBaseParse * parse, GstCaps * caps)
737 {
738   GstVp9Parse *self = GST_VP9_PARSE (parse);
739   GstStructure *str;
740   GstVp9ParseAligment align;
741   GstCaps *in_caps = NULL;
742   const gchar *profile;
743 
744   str = gst_caps_get_structure (caps, 0);
745 
746   /* accept upstream info if provided */
747   gst_structure_get_int (str, "width", &self->width);
748   gst_structure_get_int (str, "height", &self->height);
749   profile = gst_structure_get_string (str, "profile");
750   if (profile)
751     self->profile = gst_vp9_parse_profile_from_string (profile);
752   gst_structure_get_boolean (str, "codec-alpha", &self->codec_alpha);
753 
754   /* get upstream align from caps */
755   gst_vp9_parse_alignment_from_caps (caps, &align);
756 
757   /* default */
758   if (align == GST_VP9_PARSE_ALIGN_NONE)
759     align = GST_VP9_PARSE_ALIGN_SUPER_FRAME;
760 
761   /* prefer alignment type determined above */
762   in_caps = gst_caps_copy (caps);
763   gst_caps_set_simple (in_caps, "alignment", G_TYPE_STRING,
764       gst_vp9_parse_alignment_to_string (align), NULL);
765 
766   /* negotiate with downstream, set output align */
767   gst_vp9_parse_negotiate (self, align, in_caps);
768 
769   self->update_caps = TRUE;
770 
771   /* if all of decoder's capability related values are provided
772    * by upstream, update src caps now */
773   if (self->width > 0 && self->height > 0 && profile)
774     gst_vp9_parse_update_src_caps (self, in_caps);
775 
776   gst_caps_unref (in_caps);
777 
778   self->in_align = align;
779 
780   return TRUE;
781 }
782 
783 static void
remove_fields(GstCaps * caps,gboolean all)784 remove_fields (GstCaps * caps, gboolean all)
785 {
786   guint i, n;
787 
788   n = gst_caps_get_size (caps);
789   for (i = 0; i < n; i++) {
790     GstStructure *s = gst_caps_get_structure (caps, i);
791 
792     if (all) {
793       gst_structure_remove_field (s, "alignment");
794     }
795     gst_structure_remove_field (s, "parsed");
796   }
797 }
798 
799 static GstCaps *
gst_vp9_parse_get_sink_caps(GstBaseParse * parse,GstCaps * filter)800 gst_vp9_parse_get_sink_caps (GstBaseParse * parse, GstCaps * filter)
801 {
802   GstCaps *peercaps, *templ;
803   GstCaps *res, *tmp, *pcopy;
804 
805   templ = gst_pad_get_pad_template_caps (GST_BASE_PARSE_SINK_PAD (parse));
806   if (filter) {
807     GstCaps *fcopy = gst_caps_copy (filter);
808     /* Remove the fields we convert */
809     remove_fields (fcopy, TRUE);
810     peercaps = gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (parse), fcopy);
811     gst_caps_unref (fcopy);
812   } else {
813     peercaps = gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (parse), NULL);
814   }
815 
816   pcopy = gst_caps_copy (peercaps);
817   remove_fields (pcopy, TRUE);
818 
819   res = gst_caps_intersect_full (pcopy, templ, GST_CAPS_INTERSECT_FIRST);
820   gst_caps_unref (pcopy);
821   gst_caps_unref (templ);
822 
823   if (filter) {
824     GstCaps *tmp = gst_caps_intersect_full (res, filter,
825         GST_CAPS_INTERSECT_FIRST);
826     gst_caps_unref (res);
827     res = tmp;
828   }
829 
830   /* Try if we can put the downstream caps first */
831   pcopy = gst_caps_copy (peercaps);
832   remove_fields (pcopy, FALSE);
833   tmp = gst_caps_intersect_full (pcopy, res, GST_CAPS_INTERSECT_FIRST);
834   gst_caps_unref (pcopy);
835   if (!gst_caps_is_empty (tmp))
836     res = gst_caps_merge (tmp, res);
837   else
838     gst_caps_unref (tmp);
839 
840   gst_caps_unref (peercaps);
841 
842   return res;
843 }
844