blob: d68423e0f8f934fc2d99f41fd3bed5e2594f5b85 [file] [log] [blame]
Sreerenj Balachandrand8448322013-10-09 10:54:14 +03001/* GStreamer H.265 Parser
2 * Copyright (C) 2013 Intel Corporation
3 * Contact:Sreerenj Balachandran <sreerenj.balachandran@intel.com>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21#ifdef HAVE_CONFIG_H
22# include "config.h"
23#endif
24
Sebastian Dröge843de8d2013-12-16 10:19:36 +010025#include <gst/base/base.h>
26#include <gst/pbutils/pbutils.h>
Sreerenj Balachandrand8448322013-10-09 10:54:14 +030027#include <gst/video/video.h>
28#include "gsth265parse.h"
29
30#include <string.h>
31
32GST_DEBUG_CATEGORY (h265_parse_debug);
33#define GST_CAT_DEFAULT h265_parse_debug
34
35#define DEFAULT_CONFIG_INTERVAL (0)
36
37enum
38{
39 PROP_0,
Luis de Bethencourtc9440932015-04-24 16:48:23 +010040 PROP_CONFIG_INTERVAL
Sreerenj Balachandrand8448322013-10-09 10:54:14 +030041};
42
43enum
44{
45 GST_H265_PARSE_FORMAT_NONE,
46 GST_H265_PARSE_FORMAT_HVC1,
47 GST_H265_PARSE_FORMAT_HEV1,
48 GST_H265_PARSE_FORMAT_BYTE
49};
50
51enum
52{
53 GST_H265_PARSE_ALIGN_NONE = 0,
54 GST_H265_PARSE_ALIGN_NAL,
55 GST_H265_PARSE_ALIGN_AU
56};
57
58static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
59 GST_PAD_SINK,
60 GST_PAD_ALWAYS,
61 GST_STATIC_CAPS ("video/x-h265"));
62
63static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
64 GST_PAD_SRC,
65 GST_PAD_ALWAYS,
66 GST_STATIC_CAPS ("video/x-h265, parsed = (boolean) true, "
67 "stream-format=(string) { hvc1, hev1, byte-stream }, "
68 "alignment=(string) { au, nal }"));
69
70#define parent_class gst_h265_parse_parent_class
71G_DEFINE_TYPE (GstH265Parse, gst_h265_parse, GST_TYPE_BASE_PARSE);
72
73static void gst_h265_parse_finalize (GObject * object);
74
75static gboolean gst_h265_parse_start (GstBaseParse * parse);
76static gboolean gst_h265_parse_stop (GstBaseParse * parse);
77static GstFlowReturn gst_h265_parse_handle_frame (GstBaseParse * parse,
78 GstBaseParseFrame * frame, gint * skipsize);
79static GstFlowReturn gst_h265_parse_parse_frame (GstBaseParse * parse,
80 GstBaseParseFrame * frame);
81static GstFlowReturn gst_h265_parse_pre_push_frame (GstBaseParse * parse,
82 GstBaseParseFrame * frame);
83
84static void gst_h265_parse_set_property (GObject * object, guint prop_id,
85 const GValue * value, GParamSpec * pspec);
86static void gst_h265_parse_get_property (GObject * object, guint prop_id,
87 GValue * value, GParamSpec * pspec);
88
89static gboolean gst_h265_parse_set_caps (GstBaseParse * parse, GstCaps * caps);
90static GstCaps *gst_h265_parse_get_caps (GstBaseParse * parse,
91 GstCaps * filter);
92static gboolean gst_h265_parse_event (GstBaseParse * parse, GstEvent * event);
93static gboolean gst_h265_parse_src_event (GstBaseParse * parse,
94 GstEvent * event);
95
96static void
97gst_h265_parse_class_init (GstH265ParseClass * klass)
98{
99 GObjectClass *gobject_class = (GObjectClass *) klass;
100 GstBaseParseClass *parse_class = GST_BASE_PARSE_CLASS (klass);
101 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
102
103 GST_DEBUG_CATEGORY_INIT (h265_parse_debug, "h265parse", 0, "h265 parser");
104
105 gobject_class->finalize = gst_h265_parse_finalize;
106 gobject_class->set_property = gst_h265_parse_set_property;
107 gobject_class->get_property = gst_h265_parse_get_property;
108
109 g_object_class_install_property (gobject_class, PROP_CONFIG_INTERVAL,
110 g_param_spec_uint ("config-interval",
111 "VPS SPS PPS Send Interval",
112 "Send VPS, SPS and PPS Insertion Interval in seconds (sprop parameter sets "
113 "will be multiplexed in the data stream when detected.) (0 = disabled)",
114 0, 3600, DEFAULT_CONFIG_INTERVAL,
115 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
116 /* Override BaseParse vfuncs */
117 parse_class->start = GST_DEBUG_FUNCPTR (gst_h265_parse_start);
118 parse_class->stop = GST_DEBUG_FUNCPTR (gst_h265_parse_stop);
119 parse_class->handle_frame = GST_DEBUG_FUNCPTR (gst_h265_parse_handle_frame);
120 parse_class->pre_push_frame =
121 GST_DEBUG_FUNCPTR (gst_h265_parse_pre_push_frame);
122 parse_class->set_sink_caps = GST_DEBUG_FUNCPTR (gst_h265_parse_set_caps);
123 parse_class->get_sink_caps = GST_DEBUG_FUNCPTR (gst_h265_parse_get_caps);
124 parse_class->sink_event = GST_DEBUG_FUNCPTR (gst_h265_parse_event);
125 parse_class->src_event = GST_DEBUG_FUNCPTR (gst_h265_parse_src_event);
126
Vineeth TM8cdfb132016-03-04 15:50:26 +0900127 gst_element_class_add_static_pad_template (gstelement_class, &srctemplate);
128 gst_element_class_add_static_pad_template (gstelement_class, &sinktemplate);
Sreerenj Balachandrand8448322013-10-09 10:54:14 +0300129
130 gst_element_class_set_static_metadata (gstelement_class, "H.265 parser",
131 "Codec/Parser/Converter/Video",
132 "Parses H.265 streams",
133 "Sreerenj Balachandran <sreerenj.balachandran@intel.com>");
134}
135
136static void
137gst_h265_parse_init (GstH265Parse * h265parse)
138{
139 h265parse->frame_out = gst_adapter_new ();
140 gst_base_parse_set_pts_interpolation (GST_BASE_PARSE (h265parse), FALSE);
Wim Taymans9ac2cee2013-12-04 09:13:31 +0100141 GST_PAD_SET_ACCEPT_INTERSECT (GST_BASE_PARSE_SINK_PAD (h265parse));
Thiago Santosc4cd1ce2015-08-14 11:43:18 -0300142 GST_PAD_SET_ACCEPT_TEMPLATE (GST_BASE_PARSE_SINK_PAD (h265parse));
Sreerenj Balachandrand8448322013-10-09 10:54:14 +0300143}
144
145
146static void
147gst_h265_parse_finalize (GObject * object)
148{
149 GstH265Parse *h265parse = GST_H265_PARSE (object);
150
151 g_object_unref (h265parse->frame_out);
152
153 G_OBJECT_CLASS (parent_class)->finalize (object);
154}
155
156static void
157gst_h265_parse_reset_frame (GstH265Parse * h265parse)
158{
159 GST_DEBUG_OBJECT (h265parse, "reset frame");
160
161 /* done parsing; reset state */
162 h265parse->current_off = -1;
163
164 h265parse->picture_start = FALSE;
165 h265parse->update_caps = FALSE;
166 h265parse->idr_pos = -1;
167 h265parse->sei_pos = -1;
168 h265parse->keyframe = FALSE;
Josep Torra4b43e952014-11-07 15:41:15 +0100169 h265parse->header = FALSE;
Sreerenj Balachandrand8448322013-10-09 10:54:14 +0300170 gst_adapter_clear (h265parse->frame_out);
171}
172
173static void
174gst_h265_parse_reset (GstH265Parse * h265parse)
175{
176 h265parse->width = 0;
177 h265parse->height = 0;
178 h265parse->fps_num = 0;
179 h265parse->fps_den = 0;
180 h265parse->upstream_par_n = -1;
181 h265parse->upstream_par_d = -1;
182 h265parse->parsed_par_n = 0;
183 h265parse->parsed_par_n = 0;
184 gst_buffer_replace (&h265parse->codec_data, NULL);
185 gst_buffer_replace (&h265parse->codec_data_in, NULL);
186 h265parse->nal_length_size = 4;
187 h265parse->packetized = FALSE;
188 h265parse->transform = FALSE;
189
190 h265parse->align = GST_H265_PARSE_ALIGN_NONE;
191 h265parse->format = GST_H265_PARSE_FORMAT_NONE;
192
193 h265parse->last_report = GST_CLOCK_TIME_NONE;
194 h265parse->push_codec = FALSE;
195 h265parse->have_pps = FALSE;
196 h265parse->have_sps = FALSE;
197 h265parse->have_vps = FALSE;
198
Sebastian Dröge843de8d2013-12-16 10:19:36 +0100199 h265parse->sent_codec_tag = FALSE;
200
Sreerenj Balachandrand8448322013-10-09 10:54:14 +0300201 h265parse->pending_key_unit_ts = GST_CLOCK_TIME_NONE;
202 h265parse->force_key_unit_event = NULL;
203
204 gst_h265_parse_reset_frame (h265parse);
205}
206
207static gboolean
208gst_h265_parse_start (GstBaseParse * parse)
209{
210 GstH265Parse *h265parse = GST_H265_PARSE (parse);
211
212 GST_DEBUG_OBJECT (parse, "start");
213 gst_h265_parse_reset (h265parse);
214
215 h265parse->nalparser = gst_h265_parser_new ();
216
217 gst_base_parse_set_min_frame_size (parse, 7);
218
219 return TRUE;
220}
221
222static gboolean
223gst_h265_parse_stop (GstBaseParse * parse)
224{
225 guint i;
226 GstH265Parse *h265parse = GST_H265_PARSE (parse);
227
228 GST_DEBUG_OBJECT (parse, "stop");
229 gst_h265_parse_reset (h265parse);
230
Sreerenj Balachandran5770a962015-04-10 15:34:40 +0300231 for (i = 0; i < GST_H265_MAX_VPS_COUNT; i++)
Sreerenj Balachandrand8448322013-10-09 10:54:14 +0300232 gst_buffer_replace (&h265parse->vps_nals[i], NULL);
233 for (i = 0; i < GST_H265_MAX_SPS_COUNT; i++)
234 gst_buffer_replace (&h265parse->sps_nals[i], NULL);
235 for (i = 0; i < GST_H265_MAX_PPS_COUNT; i++)
236 gst_buffer_replace (&h265parse->pps_nals[i], NULL);
237
238 gst_h265_parser_free (h265parse->nalparser);
239
240 return TRUE;
241}
242
243static const gchar *
244gst_h265_parse_get_string (GstH265Parse * parse, gboolean format, gint code)
245{
246 if (format) {
247 switch (code) {
248 case GST_H265_PARSE_FORMAT_HVC1:
249 return "hvc1";
250 case GST_H265_PARSE_FORMAT_HEV1:
251 return "hev1";
252 case GST_H265_PARSE_FORMAT_BYTE:
253 return "byte-stream";
254 default:
255 return "none";
256 }
257 } else {
258 switch (code) {
259 case GST_H265_PARSE_ALIGN_NAL:
260 return "nal";
261 case GST_H265_PARSE_ALIGN_AU:
262 return "au";
263 default:
264 return "none";
265 }
266 }
267}
268
269static void
270gst_h265_parse_format_from_caps (GstCaps * caps, guint * format, guint * align)
271{
272 g_return_if_fail (gst_caps_is_fixed (caps));
273
274 GST_DEBUG ("parsing caps: %" GST_PTR_FORMAT, caps);
275
276 if (format)
277 *format = GST_H265_PARSE_FORMAT_NONE;
278
279 if (align)
280 *align = GST_H265_PARSE_ALIGN_NONE;
281
282 if (caps && gst_caps_get_size (caps) > 0) {
283 GstStructure *s = gst_caps_get_structure (caps, 0);
284 const gchar *str = NULL;
285
286 if (format) {
287 if ((str = gst_structure_get_string (s, "stream-format"))) {
288 if (strcmp (str, "hvc1") == 0)
289 *format = GST_H265_PARSE_FORMAT_HVC1;
290 else if (strcmp (str, "hev1") == 0)
291 *format = GST_H265_PARSE_FORMAT_HEV1;
292 else if (strcmp (str, "byte-stream") == 0)
293 *format = GST_H265_PARSE_FORMAT_BYTE;
294 }
295 }
296
297 if (align) {
298 if ((str = gst_structure_get_string (s, "alignment"))) {
299 if (strcmp (str, "au") == 0)
300 *align = GST_H265_PARSE_ALIGN_AU;
301 else if (strcmp (str, "nal") == 0)
302 *align = GST_H265_PARSE_ALIGN_NAL;
303 }
304 }
305 }
306}
307
308/* check downstream caps to configure format and alignment */
309static void
310gst_h265_parse_negotiate (GstH265Parse * h265parse, gint in_format,
311 GstCaps * in_caps)
312{
313 GstCaps *caps;
314 guint format = GST_H265_PARSE_FORMAT_NONE;
315 guint align = GST_H265_PARSE_ALIGN_NONE;
316
317 g_return_if_fail ((in_caps == NULL) || gst_caps_is_fixed (in_caps));
318
319 caps = gst_pad_get_allowed_caps (GST_BASE_PARSE_SRC_PAD (h265parse));
320 GST_DEBUG_OBJECT (h265parse, "allowed caps: %" GST_PTR_FORMAT, caps);
321
Luis de Bethencourt8899efa2015-05-08 13:54:06 +0100322 /* concentrate on leading structure, since decodebin parser
Sreerenj Balachandrand8448322013-10-09 10:54:14 +0300323 * capsfilter always includes parser template caps */
324 if (caps) {
325 caps = gst_caps_truncate (caps);
326 GST_DEBUG_OBJECT (h265parse, "negotiating with caps: %" GST_PTR_FORMAT,
327 caps);
328 }
329
330 if (in_caps && caps) {
331 if (gst_caps_can_intersect (in_caps, caps)) {
332 GST_DEBUG_OBJECT (h265parse, "downstream accepts upstream caps");
333 gst_h265_parse_format_from_caps (in_caps, &format, &align);
334 gst_caps_unref (caps);
335 caps = NULL;
336 }
337 }
338
Nicolas Dufresneb392a6e2015-08-26 10:52:46 -0400339 /* FIXME We could fail the negotiation immediatly if caps are empty */
340 if (caps && !gst_caps_is_empty (caps)) {
Sreerenj Balachandrand8448322013-10-09 10:54:14 +0300341 /* fixate to avoid ambiguity with lists when parsing */
342 caps = gst_caps_fixate (caps);
343 gst_h265_parse_format_from_caps (caps, &format, &align);
Sreerenj Balachandrand8448322013-10-09 10:54:14 +0300344 }
345
346 /* default */
347 if (!format)
348 format = GST_H265_PARSE_FORMAT_BYTE;
349 if (!align)
350 align = GST_H265_PARSE_ALIGN_AU;
351
352 GST_DEBUG_OBJECT (h265parse, "selected format %s, alignment %s",
353 gst_h265_parse_get_string (h265parse, TRUE, format),
354 gst_h265_parse_get_string (h265parse, FALSE, align));
355
356 h265parse->format = format;
357 h265parse->align = align;
358
359 h265parse->transform = (in_format != h265parse->format);
Vincent Penquerc'h9fae0052017-05-12 10:00:56 +0100360
361 if (caps)
362 gst_caps_unref (caps);
Sreerenj Balachandrand8448322013-10-09 10:54:14 +0300363}
364
365static GstBuffer *
366gst_h265_parse_wrap_nal (GstH265Parse * h265parse, guint format, guint8 * data,
367 guint size)
368{
369 GstBuffer *buf;
370 guint nl = h265parse->nal_length_size;
371 guint32 tmp;
372
373 GST_DEBUG_OBJECT (h265parse, "nal length %d", size);
374
375 buf = gst_buffer_new_allocate (NULL, 4 + size, NULL);
376 if (format == GST_H265_PARSE_FORMAT_HVC1
377 || format == GST_H265_PARSE_FORMAT_HEV1) {
378 tmp = GUINT32_TO_BE (size << (32 - 8 * nl));
379 } else {
380 /* HACK: nl should always be 4 here, otherwise this won't work.
381 * There are legit cases where nl in hevc stream is 2, but byte-stream
382 * SC is still always 4 bytes. */
383 nl = 4;
384 tmp = GUINT32_TO_BE (1);
385 }
386
387 gst_buffer_fill (buf, 0, &tmp, sizeof (guint32));
388 gst_buffer_fill (buf, nl, data, size);
389 gst_buffer_set_size (buf, size + nl);
390
391 return buf;
392}
393
394static void
395gst_h265_parser_store_nal (GstH265Parse * h265parse, guint id,
396 GstH265NalUnitType naltype, GstH265NalUnit * nalu)
397{
398 GstBuffer *buf, **store;
399 guint size = nalu->size, store_size;
400
401 if (naltype == GST_H265_NAL_VPS) {
402 store_size = GST_H265_MAX_VPS_COUNT;
403 store = h265parse->vps_nals;
404 GST_DEBUG_OBJECT (h265parse, "storing vps %u", id);
405 } else if (naltype == GST_H265_NAL_SPS) {
406 store_size = GST_H265_MAX_SPS_COUNT;
407 store = h265parse->sps_nals;
408 GST_DEBUG_OBJECT (h265parse, "storing sps %u", id);
409 } else if (naltype == GST_H265_NAL_PPS) {
410 store_size = GST_H265_MAX_PPS_COUNT;
411 store = h265parse->pps_nals;
412 GST_DEBUG_OBJECT (h265parse, "storing pps %u", id);
413 } else
414 return;
415
416 if (id >= store_size) {
417 GST_DEBUG_OBJECT (h265parse, "unable to store nal, id out-of-range %d", id);
418 return;
419 }
420
421 buf = gst_buffer_new_allocate (NULL, size, NULL);
422 gst_buffer_fill (buf, 0, nalu->data + nalu->offset, size);
423
Josep Torra4b43e952014-11-07 15:41:15 +0100424 /* Indicate that buffer contain a header needed for decoding */
425 if (naltype >= GST_H265_NAL_VPS && naltype <= GST_H265_NAL_PPS)
426 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
427
Sreerenj Balachandrand8448322013-10-09 10:54:14 +0300428 if (store[id])
429 gst_buffer_unref (store[id]);
430
431 store[id] = buf;
432}
433
434#ifndef GST_DISABLE_GST_DEBUG
435static const gchar *nal_names[] = {
436 "Slice_TRAIL_N",
437 "Slice_TRAIL_R",
438 "Slice_TSA_N",
439 "Slice_TSA_R",
440 "Slice_STSA_N",
441 "Slice_STSA_R",
442 "Slice_RADL_N",
443 "Slice_RADL_R",
444 "SLICE_RASL_N",
445 "SLICE_RASL_R",
Sebastian Dröge57c195e2014-01-06 14:48:26 +0100446 "Invalid (10)",
447 "Invalid (11)",
448 "Invalid (12)",
449 "Invalid (13)",
450 "Invalid (14)",
451 "Invalid (15)",
Sreerenj Balachandrand8448322013-10-09 10:54:14 +0300452 "SLICE_BLA_W_LP",
453 "SLICE_BLA_W_RADL",
454 "SLICE_BLA_N_LP",
455 "SLICE_IDR_W_RADL",
456 "SLICE_IDR_N_LP",
457 "SLICE_CRA_NUT",
Sebastian Dröge57c195e2014-01-06 14:48:26 +0100458 "Invalid (22)",
459 "Invalid (23)",
460 "Invalid (24)",
461 "Invalid (25)",
462 "Invalid (26)",
463 "Invalid (27)",
464 "Invalid (28)",
465 "Invalid (29)",
466 "Invalid (30)",
467 "Invalid (31)",
Sreerenj Balachandrand8448322013-10-09 10:54:14 +0300468 "VPS",
469 "SPS",
470 "PPS",
471 "AUD",
472 "EOS",
473 "EOB",
474 "FD",
475 "PREFIX_SEI",
Sebastian Dröge57c195e2014-01-06 14:48:26 +0100476 "SUFFIX_SEI"
Sreerenj Balachandrand8448322013-10-09 10:54:14 +0300477};
478
479static const gchar *
480_nal_name (GstH265NalUnitType nal_type)
481{
482 if (nal_type <= GST_H265_NAL_SUFFIX_SEI)
483 return nal_names[nal_type];
484 return "Invalid";
485}
486#endif
487
488/* caller guarantees 2 bytes of nal payload */
489static void
490gst_h265_parse_process_nal (GstH265Parse * h265parse, GstH265NalUnit * nalu)
491{
492 GstH265PPS pps = { 0, };
493 GstH265SPS sps = { 0, };
494 GstH265VPS vps = { 0, };
495 gboolean is_irap;
496 guint nal_type;
497 GstH265Parser *nalparser = h265parse->nalparser;
498 GstH265ParserResult pres = GST_H265_PARSER_ERROR;
499
500 /* nothing to do for broken input */
Sreerenj Balachandran2775b202015-08-11 03:47:42 +0300501 if (G_UNLIKELY (nalu->size < 2)) {
Sreerenj Balachandrand8448322013-10-09 10:54:14 +0300502 GST_DEBUG_OBJECT (h265parse, "not processing nal size %u", nalu->size);
503 return;
504 }
505
506 /* we have a peek as well */
507 nal_type = nalu->type;
508
509 GST_DEBUG_OBJECT (h265parse, "processing nal of type %u %s, size %u",
510 nal_type, _nal_name (nal_type), nalu->size);
511 switch (nal_type) {
512 case GST_H265_NAL_VPS:
513 /* It is not mandatory to have VPS in the stream. But it might
514 * be needed for other extensions like svc */
515 pres = gst_h265_parser_parse_vps (nalparser, nalu, &vps);
516 if (pres != GST_H265_PARSER_OK)
517 GST_WARNING_OBJECT (h265parse, "failed to parse VPS");
518
519 GST_DEBUG_OBJECT (h265parse, "triggering src caps check");
520 h265parse->update_caps = TRUE;
521 h265parse->have_vps = TRUE;
522 if (h265parse->push_codec && h265parse->have_pps) {
523 /* VPS/SPS/PPS found in stream before the first pre_push_frame, no need
524 * to forcibly push at start */
525 GST_INFO_OBJECT (h265parse, "have VPS/SPS/PPS in stream");
526 h265parse->push_codec = FALSE;
527 h265parse->have_vps = FALSE;
528 h265parse->have_sps = FALSE;
529 h265parse->have_pps = FALSE;
530 }
531
532 gst_h265_parser_store_nal (h265parse, vps.id, nal_type, nalu);
Josep Torra4b43e952014-11-07 15:41:15 +0100533 h265parse->header |= TRUE;
Sreerenj Balachandrand8448322013-10-09 10:54:14 +0300534 break;
535 case GST_H265_NAL_SPS:
536 pres = gst_h265_parser_parse_sps (nalparser, nalu, &sps, TRUE);
537
538
539 /* arranged for a fallback sps.id, so use that one and only warn */
540 if (pres != GST_H265_PARSER_OK)
541 GST_WARNING_OBJECT (h265parse, "failed to parse SPS:");
542
543 GST_DEBUG_OBJECT (h265parse, "triggering src caps check");
544 h265parse->update_caps = TRUE;
545 h265parse->have_sps = TRUE;
546 if (h265parse->push_codec && h265parse->have_pps) {
547 /* SPS and PPS found in stream before the first pre_push_frame, no need
548 * to forcibly push at start */
549 GST_INFO_OBJECT (h265parse, "have SPS/PPS in stream");
550 h265parse->push_codec = FALSE;
551 h265parse->have_sps = FALSE;
552 h265parse->have_pps = FALSE;
553 }
554
555 gst_h265_parser_store_nal (h265parse, sps.id, nal_type, nalu);
Josep Torra4b43e952014-11-07 15:41:15 +0100556 h265parse->header |= TRUE;
Sreerenj Balachandrand8448322013-10-09 10:54:14 +0300557 break;
558 case GST_H265_NAL_PPS:
559 pres = gst_h265_parser_parse_pps (nalparser, nalu, &pps);
560
561
562 /* arranged for a fallback pps.id, so use that one and only warn */
563 if (pres != GST_H265_PARSER_OK)
564 GST_WARNING_OBJECT (h265parse, "failed to parse PPS:");
565
566 /* parameters might have changed, force caps check */
567 if (!h265parse->have_pps) {
568 GST_DEBUG_OBJECT (h265parse, "triggering src caps check");
569 h265parse->update_caps = TRUE;
570 }
571 h265parse->have_pps = TRUE;
572 if (h265parse->push_codec && h265parse->have_sps) {
573 /* SPS and PPS found in stream before the first pre_push_frame, no need
574 * to forcibly push at start */
575 GST_INFO_OBJECT (h265parse, "have SPS/PPS in stream");
576 h265parse->push_codec = FALSE;
577 h265parse->have_sps = FALSE;
578 h265parse->have_pps = FALSE;
579 }
580
581 gst_h265_parser_store_nal (h265parse, pps.id, nal_type, nalu);
Josep Torra4b43e952014-11-07 15:41:15 +0100582 h265parse->header |= TRUE;
Sreerenj Balachandrand8448322013-10-09 10:54:14 +0300583 break;
584 case GST_H265_NAL_PREFIX_SEI:
585 case GST_H265_NAL_SUFFIX_SEI:
586 /*Fixme: parse sei messages */
587 /* mark SEI pos */
588 if (h265parse->sei_pos == -1) {
589 if (h265parse->transform)
590 h265parse->sei_pos = gst_adapter_available (h265parse->frame_out);
591 else
592 h265parse->sei_pos = nalu->sc_offset;
593 GST_DEBUG_OBJECT (h265parse, "marking SEI in frame at offset %d",
594 h265parse->sei_pos);
595 }
596 break;
597
598 case GST_H265_NAL_SLICE_TRAIL_N:
599 case GST_H265_NAL_SLICE_TRAIL_R:
600 case GST_H265_NAL_SLICE_TSA_N:
601 case GST_H265_NAL_SLICE_TSA_R:
602 case GST_H265_NAL_SLICE_STSA_N:
603 case GST_H265_NAL_SLICE_STSA_R:
604 case GST_H265_NAL_SLICE_RADL_N:
605 case GST_H265_NAL_SLICE_RADL_R:
606 case GST_H265_NAL_SLICE_RASL_N:
607 case GST_H265_NAL_SLICE_RASL_R:
608 case GST_H265_NAL_SLICE_BLA_W_LP:
609 case GST_H265_NAL_SLICE_BLA_W_RADL:
610 case GST_H265_NAL_SLICE_BLA_N_LP:
611 case GST_H265_NAL_SLICE_IDR_W_RADL:
612 case GST_H265_NAL_SLICE_IDR_N_LP:
613 case GST_H265_NAL_SLICE_CRA_NUT:
614 {
615 GstH265SliceHdr slice;
616
617 pres = gst_h265_parser_parse_slice_hdr (nalparser, nalu, &slice);
618
619 if (pres == GST_H265_PARSER_OK) {
620 if (GST_H265_IS_I_SLICE (&slice))
621 h265parse->keyframe |= TRUE;
622 }
623 if (slice.first_slice_segment_in_pic_flag == 1)
624 GST_DEBUG_OBJECT (h265parse,
625 "frame start, first_slice_segment_in_pic_flag = 1");
626
627 GST_DEBUG_OBJECT (h265parse,
628 "parse result %d, first slice_segment: %u, slice type: %u",
629 pres, slice.first_slice_segment_in_pic_flag, slice.type);
630
631 gst_h265_slice_hdr_free (&slice);
632 }
633
634 is_irap = ((nal_type >= GST_H265_NAL_SLICE_BLA_W_LP)
635 && (nal_type <= GST_H265_NAL_SLICE_CRA_NUT)) ? TRUE : FALSE;
636 if (G_LIKELY (!is_irap && !h265parse->push_codec))
637 break;
638
639 /* if we need to sneak codec NALs into the stream,
640 * this is a good place, so fake it as IDR
641 * (which should be at start anyway) */
642 /* mark where config needs to go if interval expired */
643 /* mind replacement buffer if applicable */
644 if (h265parse->idr_pos == -1) {
645 if (h265parse->transform)
646 h265parse->idr_pos = gst_adapter_available (h265parse->frame_out);
647 else
648 h265parse->idr_pos = nalu->sc_offset;
649 GST_DEBUG_OBJECT (h265parse, "marking IDR in frame at offset %d",
650 h265parse->idr_pos);
651 }
652 /* if SEI preceeds (faked) IDR, then we have to insert config there */
653 if (h265parse->sei_pos >= 0 && h265parse->idr_pos > h265parse->sei_pos) {
654 h265parse->idr_pos = h265parse->sei_pos;
655 GST_DEBUG_OBJECT (h265parse, "moved IDR mark to SEI position %d",
656 h265parse->idr_pos);
657 }
658 break;
659 default:
660 gst_h265_parser_parse_nal (nalparser, nalu);
661 }
662
663 /* if HEVC output needed, collect properly prefixed nal in adapter,
664 * and use that to replace outgoing buffer data later on */
665 if (h265parse->transform) {
666 GstBuffer *buf;
667
668 GST_LOG_OBJECT (h265parse, "collecting NAL in HEVC frame");
669 buf = gst_h265_parse_wrap_nal (h265parse, h265parse->format,
670 nalu->data + nalu->offset, nalu->size);
671 gst_adapter_push (h265parse->frame_out, buf);
672 }
673}
674
675/* caller guarantees at least 3 bytes of nal payload for each nal
676 * returns TRUE if next_nal indicates that nal terminates an AU */
677static inline gboolean
678gst_h265_parse_collect_nal (GstH265Parse * h265parse, const guint8 * data,
679 guint size, GstH265NalUnit * nalu)
680{
681 gboolean complete;
682 GstH265ParserResult parse_res;
683 GstH265NalUnitType nal_type = nalu->type;
684 GstH265NalUnit nnalu;
685
686 GST_DEBUG_OBJECT (h265parse, "parsing collected nal");
687 parse_res = gst_h265_parser_identify_nalu (h265parse->nalparser, data,
688 nalu->offset + nalu->size, size, &nnalu);
689
690 if (parse_res == GST_H265_PARSER_ERROR)
691 return FALSE;
692
693 /* determine if AU complete */
694 GST_LOG_OBJECT (h265parse, "nal type: %d %s", nal_type, _nal_name (nal_type));
695 /* coded slice NAL starts a picture,
696 * i.e. other types become aggregated in front of it */
697 h265parse->picture_start |= ((nal_type >= GST_H265_NAL_SLICE_TRAIL_N
Sreerenj Balachandrana83dabd2015-08-11 04:14:19 +0300698 && nal_type <= GST_H265_NAL_SLICE_RASL_R)
Sreerenj Balachandrand8448322013-10-09 10:54:14 +0300699 || (nal_type >= GST_H265_NAL_SLICE_BLA_W_LP
700 && nal_type <= RESERVED_IRAP_NAL_TYPE_MAX));
701
702 /* consider a coded slices (IRAP or not) to start a picture,
703 * (so ending the previous one) if first_slice_segment_in_pic_flag == 1*/
704 nal_type = nnalu.type;
705 complete = h265parse->picture_start && ((nal_type >= GST_H265_NAL_VPS
706 && nal_type <= GST_H265_NAL_AUD)
707 || nal_type == GST_H265_NAL_PREFIX_SEI || (nal_type >= 41
708 && nal_type <= 44) || (nal_type >= 48 && nal_type <= 55));
709
710 GST_LOG_OBJECT (h265parse, "next nal type: %d %s", nal_type,
711 _nal_name (nal_type));
712
713 /* Any VCL Nal unit with first_slice_segment_in_pic_flag == 1 considered start of frame */
714 complete |= h265parse->picture_start
715 && (((nal_type >= GST_H265_NAL_SLICE_TRAIL_N
Sreerenj Balachandrana83dabd2015-08-11 04:14:19 +0300716 && nal_type <= GST_H265_NAL_SLICE_RASL_R)
Sreerenj Balachandrand8448322013-10-09 10:54:14 +0300717 || (nal_type >= GST_H265_NAL_SLICE_BLA_W_LP
718 && nal_type <= RESERVED_IRAP_NAL_TYPE_MAX))
719 && (nnalu.data[nnalu.offset + 2] & 0x80));
720
721 GST_LOG_OBJECT (h265parse, "au complete: %d", complete);
722 return complete;
723}
724
725static GstFlowReturn
726gst_h265_parse_handle_frame_packetized (GstBaseParse * parse,
727 GstBaseParseFrame * frame)
728{
729 GstH265Parse *h265parse = GST_H265_PARSE (parse);
730 GstBuffer *buffer = frame->buffer;
731 GstFlowReturn ret = GST_FLOW_OK;
732 GstH265ParserResult parse_res;
733 GstH265NalUnit nalu;
734 const guint nl = h265parse->nal_length_size;
735 GstMapInfo map;
736 gint left;
737
738 if (nl < 1 || nl > 4) {
739 GST_DEBUG_OBJECT (h265parse, "insufficient data to split input");
740 return GST_FLOW_NOT_NEGOTIATED;
741 }
742
743 /* need to save buffer from invalidation upon _finish_frame */
744 if (h265parse->split_packetized)
745 buffer = gst_buffer_copy (frame->buffer);
746
747 gst_buffer_map (buffer, &map, GST_MAP_READ);
748
749 left = map.size;
750
751 GST_LOG_OBJECT (h265parse,
752 "processing packet buffer of size %" G_GSIZE_FORMAT, map.size);
753
754 parse_res = gst_h265_parser_identify_nalu_hevc (h265parse->nalparser,
755 map.data, 0, map.size, nl, &nalu);
756
757 while (parse_res == GST_H265_PARSER_OK) {
758 GST_DEBUG_OBJECT (h265parse, "HEVC nal offset %d", nalu.offset + nalu.size);
759
760 /* either way, have a look at it */
761 gst_h265_parse_process_nal (h265parse, &nalu);
762
763 /* dispatch per NALU if needed */
764 if (h265parse->split_packetized) {
Sreerenj Balachandran92f4eb42016-03-11 17:34:03 +0200765 GstBaseParseFrame tmp_frame;
766
767 gst_base_parse_frame_init (&tmp_frame);
768 tmp_frame.flags |= frame->flags;
769 tmp_frame.offset = frame->offset;
770 tmp_frame.overhead = frame->overhead;
771 tmp_frame.buffer = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL,
772 nalu.offset, nalu.size);
773
Sreerenj Balachandrand8448322013-10-09 10:54:14 +0300774 /* note we don't need to come up with a sub-buffer, since
775 * subsequent code only considers input buffer's metadata.
776 * Real data is either taken from input by baseclass or
777 * a replacement output buffer is provided anyway. */
Sreerenj Balachandran92f4eb42016-03-11 17:34:03 +0200778 gst_h265_parse_parse_frame (parse, &tmp_frame);
779 ret = gst_base_parse_finish_frame (parse, &tmp_frame, nl + nalu.size);
Sreerenj Balachandrand8448322013-10-09 10:54:14 +0300780 left -= nl + nalu.size;
781 }
782
783 parse_res = gst_h265_parser_identify_nalu_hevc (h265parse->nalparser,
784 map.data, nalu.offset + nalu.size, map.size, nl, &nalu);
785 }
786
787 gst_buffer_unmap (buffer, &map);
788
789 if (!h265parse->split_packetized) {
790 gst_h265_parse_parse_frame (parse, frame);
791 ret = gst_base_parse_finish_frame (parse, frame, map.size);
792 } else {
793 gst_buffer_unref (buffer);
794 if (G_UNLIKELY (left)) {
795 /* should not be happening for nice HEVC */
796 GST_WARNING_OBJECT (parse, "skipping leftover HEVC data %d", left);
797 frame->flags |= GST_BASE_PARSE_FRAME_FLAG_DROP;
798 ret = gst_base_parse_finish_frame (parse, frame, map.size);
799 }
800 }
801
802 if (parse_res == GST_H265_PARSER_NO_NAL_END ||
803 parse_res == GST_H265_PARSER_BROKEN_DATA) {
804
805 if (h265parse->split_packetized) {
806 GST_ELEMENT_ERROR (h265parse, STREAM, FAILED, (NULL),
807 ("invalid HEVC input data"));
808 gst_buffer_unref (buffer);
809
810 return GST_FLOW_ERROR;
811 } else {
812 /* do not meddle to much in this case */
813 GST_DEBUG_OBJECT (h265parse, "parsing packet failed");
814 }
815 }
816
817 return ret;
818}
819
820static GstFlowReturn
821gst_h265_parse_handle_frame (GstBaseParse * parse,
822 GstBaseParseFrame * frame, gint * skipsize)
823{
824 GstH265Parse *h265parse = GST_H265_PARSE (parse);
825 GstBuffer *buffer = frame->buffer;
826 GstMapInfo map;
827 guint8 *data;
828 gsize size;
829 gint current_off = 0;
830 gboolean drain, nonext;
831 GstH265Parser *nalparser = h265parse->nalparser;
832 GstH265NalUnit nalu;
833 GstH265ParserResult pres;
834 gint framesize;
835
836 /* delegate in packetized case, no skipping should be needed */
837 if (h265parse->packetized)
838 return gst_h265_parse_handle_frame_packetized (parse, frame);
839
840 gst_buffer_map (buffer, &map, GST_MAP_READ);
841 data = map.data;
842 size = map.size;
843
844 /* expect at least 3 bytes startcode == sc, and 3 bytes NALU payload */
845 if (G_UNLIKELY (size < 6)) {
846 gst_buffer_unmap (buffer, &map);
847 *skipsize = 1;
848 return GST_FLOW_OK;
849 }
850
851 /* need to configure aggregation */
852 if (G_UNLIKELY (h265parse->format == GST_H265_PARSE_FORMAT_NONE))
853 gst_h265_parse_negotiate (h265parse, GST_H265_PARSE_FORMAT_BYTE, NULL);
854
855 /* avoid stale cached parsing state */
856 if (frame->flags & GST_BASE_PARSE_FRAME_FLAG_NEW_FRAME) {
857 GST_LOG_OBJECT (h265parse, "parsing new frame");
858 gst_h265_parse_reset_frame (h265parse);
859 } else {
860 GST_LOG_OBJECT (h265parse, "resuming frame parsing");
861 }
862
863 drain = GST_BASE_PARSE_DRAINING (parse);
864 nonext = FALSE;
865
866 current_off = h265parse->current_off;
867 if (current_off < 0)
868 current_off = 0;
869 g_assert (current_off < size);
870 GST_DEBUG_OBJECT (h265parse, "last parse position %d", current_off);
871
872 /* check for initial skip */
873 if (h265parse->current_off == -1) {
874 pres =
875 gst_h265_parser_identify_nalu_unchecked (nalparser, data, current_off,
876 size, &nalu);
877 switch (pres) {
878 case GST_H265_PARSER_OK:
879 if (nalu.sc_offset > 0) {
880 *skipsize = nalu.sc_offset;
881 goto skip;
882 }
883 break;
884 case GST_H265_PARSER_NO_NAL:
885 *skipsize = size - 3;
886 goto skip;
Sreerenj Balachandrand8448322013-10-09 10:54:14 +0300887 default:
Sebastian Drögecb4ccec2016-11-26 12:16:18 +0200888 /* should not really occur either */
889 GST_ELEMENT_ERROR (h265parse, STREAM, FORMAT,
890 ("Error parsing H.265 stream"), ("Invalid H.265 stream"));
891 goto invalid_stream;
Sreerenj Balachandrand8448322013-10-09 10:54:14 +0300892 }
893 }
894
895 while (TRUE) {
896 pres =
897 gst_h265_parser_identify_nalu (nalparser, data, current_off, size,
898 &nalu);
899
900 switch (pres) {
901 case GST_H265_PARSER_OK:
902 GST_DEBUG_OBJECT (h265parse, "complete nal (offset, size): (%u, %u) ",
903 nalu.offset, nalu.size);
904 break;
905 case GST_H265_PARSER_NO_NAL_END:
906 GST_DEBUG_OBJECT (h265parse, "not a complete nal found at offset %u",
907 nalu.offset);
908 /* if draining, accept it as complete nal */
909 if (drain) {
910 nonext = TRUE;
911 nalu.size = size - nalu.offset;
912 GST_DEBUG_OBJECT (h265parse, "draining, accepting with size %u",
913 nalu.size);
914 /* if it's not too short at least */
915 if (nalu.size < 3)
916 goto broken;
917 break;
918 }
919 /* otherwise need more */
920 goto more;
921 case GST_H265_PARSER_BROKEN_LINK:
922 GST_ELEMENT_ERROR (h265parse, STREAM, FORMAT,
923 ("Error parsing H.265 stream"),
924 ("The link to structure needed for the parsing couldn't be found"));
925 goto invalid_stream;
926 case GST_H265_PARSER_ERROR:
927 /* should not really occur either */
928 GST_ELEMENT_ERROR (h265parse, STREAM, FORMAT,
929 ("Error parsing H.265 stream"), ("Invalid H.265 stream"));
930 goto invalid_stream;
931 case GST_H265_PARSER_NO_NAL:
932 GST_ELEMENT_ERROR (h265parse, STREAM, FORMAT,
933 ("Error parsing H.265 stream"), ("No H.265 NAL unit found"));
934 goto invalid_stream;
935 case GST_H265_PARSER_BROKEN_DATA:
936 GST_WARNING_OBJECT (h265parse, "input stream is corrupt; "
937 "it contains a NAL unit of length %u", nalu.size);
938 broken:
939 /* broken nal at start -> arrange to skip it,
940 * otherwise have it terminate current au
941 * (and so it will be skipped on next frame round) */
942 if (current_off == 0) {
943 GST_DEBUG_OBJECT (h265parse, "skipping broken nal");
944 *skipsize = nalu.offset;
945 goto skip;
946 } else {
947 GST_DEBUG_OBJECT (h265parse, "terminating au");
948 nalu.size = 0;
949 nalu.offset = nalu.sc_offset;
950 goto end;
951 }
Sreerenj Balachandrand8448322013-10-09 10:54:14 +0300952 default:
953 g_assert_not_reached ();
954 break;
955 }
956
957 GST_DEBUG_OBJECT (h265parse, "%p complete nal found. Off: %u, Size: %u",
958 data, nalu.offset, nalu.size);
959
960 /* simulate no next nal if none needed */
961 nonext = nonext || (h265parse->align == GST_H265_PARSE_ALIGN_NAL);
962
963 if (!nonext) {
964 if (nalu.offset + nalu.size + 5 + 2 > size) {
965 GST_DEBUG_OBJECT (h265parse, "not enough data for next NALU");
966 if (drain) {
967 GST_DEBUG_OBJECT (h265parse, "but draining anyway");
968 nonext = TRUE;
969 } else {
970 goto more;
971 }
972 }
973 }
974
975 if (nalu.type == GST_H265_NAL_VPS ||
976 nalu.type == GST_H265_NAL_SPS ||
977 nalu.type == GST_H265_NAL_PPS ||
978 (h265parse->have_sps && h265parse->have_pps)) {
979 gst_h265_parse_process_nal (h265parse, &nalu);
980 } else {
981 GST_WARNING_OBJECT (h265parse,
982 "no SPS/PPS yet, nal Type: %d %s, Size: %u will be dropped",
983 nalu.type, _nal_name (nalu.type), nalu.size);
984 *skipsize = nalu.size;
985 goto skip;
986 }
987
988 if (nonext)
989 break;
990
991 /* if no next nal, we know it's complete here */
992 if (gst_h265_parse_collect_nal (h265parse, data, size, &nalu))
993 break;
994
995 GST_DEBUG_OBJECT (h265parse, "Looking for more");
996 current_off = nalu.offset + nalu.size;
997 }
998
999end:
1000 framesize = nalu.offset + nalu.size;
1001
1002 gst_buffer_unmap (buffer, &map);
1003
1004 gst_h265_parse_parse_frame (parse, frame);
1005
1006 return gst_base_parse_finish_frame (parse, frame, framesize);
1007
1008more:
1009 *skipsize = 0;
1010
1011 /* Restart parsing from here next time */
1012 if (current_off > 0)
1013 h265parse->current_off = current_off;
1014
1015 /* Fall-through. */
1016out:
1017 gst_buffer_unmap (buffer, &map);
1018 return GST_FLOW_OK;
1019
1020skip:
1021 GST_DEBUG_OBJECT (h265parse, "skipping %d", *skipsize);
1022 gst_h265_parse_reset_frame (h265parse);
1023 goto out;
1024
1025invalid_stream:
1026 gst_buffer_unmap (buffer, &map);
1027 return GST_FLOW_ERROR;
1028}
1029
1030/* byte together hevc codec data based on collected pps and sps so far */
1031static GstBuffer *
1032gst_h265_parse_make_codec_data (GstH265Parse * h265parse)
1033{
1034 GstBuffer *buf, *nal;
1035 gint i, j, k = 0;
1036 guint vps_size = 0, sps_size = 0, pps_size = 0;
1037 guint num_vps = 0, num_sps = 0, num_pps = 0;
1038 gboolean found = FALSE;
1039 GstMapInfo map;
1040 guint8 *data;
1041 gint nl;
1042 guint8 num_arrays = 0;
1043 GstH265SPS *sps = NULL;
1044 guint16 min_spatial_segmentation_idc = 0;
1045 GstH265ProfileTierLevel *pft;
1046
1047 /* only nal payload in stored nals */
1048 /* Fixme: Current implementation is not embedding SEI in codec_data */
1049 for (i = 0; i < GST_H265_MAX_VPS_COUNT; i++) {
1050 if ((nal = h265parse->vps_nals[i])) {
1051 num_vps++;
1052 /* size bytes also count */
1053 vps_size += gst_buffer_get_size (nal) + 2;
1054 }
1055 }
1056 if (num_vps > 0)
1057 num_arrays++;
1058
1059 for (i = 0; i < GST_H265_MAX_SPS_COUNT; i++) {
1060 if ((nal = h265parse->sps_nals[i])) {
1061 num_sps++;
1062 /* size bytes also count */
1063 sps_size += gst_buffer_get_size (nal) + 2;
1064 found = TRUE;
1065 }
1066 }
1067 if (num_sps > 0)
1068 num_arrays++;
1069
1070 for (i = 0; i < GST_H265_MAX_PPS_COUNT; i++) {
1071 if ((nal = h265parse->pps_nals[i])) {
1072 num_pps++;
1073 /* size bytes also count */
1074 pps_size += gst_buffer_get_size (nal) + 2;
1075 }
1076 }
1077 if (num_pps > 0)
1078 num_arrays++;
1079
1080 GST_DEBUG_OBJECT (h265parse,
1081 "constructing codec_data: num_vps =%d num_sps=%d, num_pps=%d", num_vps,
1082 num_sps, num_pps);
1083
1084 if (!found)
1085 return NULL;
1086
Vineeth TMe3892112016-01-25 13:33:09 +09001087 sps = h265parse->nalparser->last_sps;
1088 if (!sps)
1089 return NULL;
1090
Sreerenj Balachandrand8448322013-10-09 10:54:14 +03001091 buf =
1092 gst_buffer_new_allocate (NULL,
Sebastian Drögeeb1f1ff2017-05-18 11:42:17 +03001093 23 + (3 * num_arrays) + vps_size + sps_size + pps_size, NULL);
Sreerenj Balachandrand8448322013-10-09 10:54:14 +03001094 gst_buffer_map (buf, &map, GST_MAP_WRITE);
1095 data = map.data;
1096 memset (data, 0, map.size);
1097 nl = h265parse->nal_length_size;
1098
Sreerenj Balachandrand8448322013-10-09 10:54:14 +03001099 pft = &sps->profile_tier_level;
1100 if (sps->vui_parameters_present_flag)
1101 min_spatial_segmentation_idc = sps->vui_params.min_spatial_segmentation_idc;
1102
1103 /* HEVCDecoderConfigurationVersion = 1
1104 * profile_space | tier_flat | profile_idc |
1105 * profile_compatibility_flags | constraint_indicator_flags |
1106 * level_idc */
1107 data[0] = 1;
1108 data[1] =
1109 (pft->profile_space << 5) | (pft->tier_flag << 5) | pft->profile_idc;
1110 for (i = 2; i < 6; i++) {
1111 for (j = 7; j >= 0; j--) {
1112 data[i] |= (pft->profile_compatibility_flag[k] << j);
1113 k++;
1114 }
1115 }
1116 data[6] |=
1117 (pft->progressive_source_flag << 7) | (pft->interlaced_source_flag << 6) |
1118 (pft->non_packed_constraint_flag << 5) | (pft->
1119 frame_only_constraint_flag << 4);
1120 data[12] = pft->level_idc;
1121 /* min_spatial_segmentation_idc */
1122 GST_WRITE_UINT16_BE (data + 13, min_spatial_segmentation_idc);
1123 data[13] |= 0xf0;
1124 data[15] = 0xfc; /* keeping parrallelismType as zero (unknown) */
1125 data[16] = 0xfc | sps->chroma_format_idc;
1126 data[17] = 0xf8 | sps->bit_depth_luma_minus8;
1127 data[18] = 0xf8 | sps->bit_depth_chroma_minus8;
1128 data[19] = 0x00; /* keep avgFrameRate as unspecified */
1129 data[20] = 0x00; /* keep avgFrameRate as unspecified */
1130 /* constFrameRate(2 bits): 0, stream may or may not be of constant framerate
1131 * numTemporalLayers (3 bits): number of temporal layers, value from SPS
1132 * TemporalIdNested (1 bit): sps_temporal_id_nesting_flag from SPS
1133 * lengthSizeMinusOne (2 bits): plus 1 indicates the length of the NALUnitLength */
1134 data[21] =
1135 0x00 | ((sps->max_sub_layers_minus1 +
1136 1) << 3) | (sps->temporal_id_nesting_flag << 2) | (nl - 1);
1137 GST_WRITE_UINT8 (data + 22, num_arrays); /* numOfArrays */
1138
1139 data += 23;
1140
1141 /* VPS */
1142 if (num_vps > 0) {
1143 /* array_completeness | reserved_zero bit | nal_unit_type */
1144 data[0] = 0x00 | 0x20;
1145 data++;
1146
1147 GST_WRITE_UINT16_BE (data, num_vps);
1148 data += 2;
1149
Scott D Phillips3edd6412016-05-25 16:57:49 -07001150 for (i = 0; i < GST_H265_MAX_VPS_COUNT; i++) {
Sreerenj Balachandrand8448322013-10-09 10:54:14 +03001151 if ((nal = h265parse->vps_nals[i])) {
1152 gsize nal_size = gst_buffer_get_size (nal);
1153 GST_WRITE_UINT16_BE (data, nal_size);
1154 gst_buffer_extract (nal, 0, data + 2, nal_size);
1155 data += 2 + nal_size;
1156 }
1157 }
1158 }
1159
1160 /* SPS */
1161 if (num_sps > 0) {
1162 /* array_completeness | reserved_zero bit | nal_unit_type */
1163 data[0] = 0x00 | 0x21;
1164 data++;
1165
1166 GST_WRITE_UINT16_BE (data, num_sps);
1167 data += 2;
1168
Scott D Phillips3edd6412016-05-25 16:57:49 -07001169 for (i = 0; i < GST_H265_MAX_SPS_COUNT; i++) {
Sreerenj Balachandrand8448322013-10-09 10:54:14 +03001170 if ((nal = h265parse->sps_nals[i])) {
1171 gsize nal_size = gst_buffer_get_size (nal);
1172 GST_WRITE_UINT16_BE (data, nal_size);
1173 gst_buffer_extract (nal, 0, data + 2, nal_size);
1174 data += 2 + nal_size;
1175 }
1176 }
1177 }
1178
1179 /* PPS */
1180 if (num_pps > 0) {
1181 /* array_completeness | reserved_zero bit | nal_unit_type */
1182 data[0] = 0x00 | 0x22;
1183 data++;
1184
1185 GST_WRITE_UINT16_BE (data, num_pps);
1186 data += 2;
1187
Scott D Phillips3edd6412016-05-25 16:57:49 -07001188 for (i = 0; i < GST_H265_MAX_PPS_COUNT; i++) {
Sreerenj Balachandrand8448322013-10-09 10:54:14 +03001189 if ((nal = h265parse->pps_nals[i])) {
1190 gsize nal_size = gst_buffer_get_size (nal);
1191 GST_WRITE_UINT16_BE (data, nal_size);
1192 gst_buffer_extract (nal, 0, data + 2, nal_size);
1193 data += 2 + nal_size;
1194 }
1195 }
1196 }
1197 gst_buffer_unmap (buf, &map);
1198
1199 return buf;
1200}
1201
1202static void
1203gst_h265_parse_get_par (GstH265Parse * h265parse, gint * num, gint * den)
1204{
1205 if (h265parse->upstream_par_n != -1 && h265parse->upstream_par_d != -1) {
1206 *num = h265parse->upstream_par_n;
1207 *den = h265parse->upstream_par_d;
1208 } else {
1209 *num = h265parse->parsed_par_n;
1210 *den = h265parse->parsed_par_d;
1211 }
1212}
1213
Sreerenj Balachandrana70c4f32015-04-30 18:36:35 +03001214static const gchar *
1215digit_to_string (guint digit)
1216{
1217 static const char itoa[][2] = {
1218 "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
1219 };
1220
1221 if (G_LIKELY (digit < 10))
1222 return itoa[digit];
1223 else
1224 return NULL;
1225}
1226
1227static const gchar *
Guillaume Desmottesd252f502018-03-01 11:08:44 +01001228get_profile_string (GstH265Profile profile)
Sreerenj Balachandrana70c4f32015-04-30 18:36:35 +03001229{
Guillaume Desmottesd252f502018-03-01 11:08:44 +01001230 switch (profile) {
1231 case GST_H265_PROFILE_MAIN:
1232 return "main";
1233 case GST_H265_PROFILE_MAIN_10:
1234 return "main-10";
1235 case GST_H265_PROFILE_MAIN_STILL_PICTURE:
1236 return "main-still-picture";
Guillaume Desmottes9f25fcd2018-02-26 17:26:07 +01001237 case GST_H265_PROFILE_MONOCHROME:
1238 return "monochrome";
1239 case GST_H265_PROFILE_MONOCHROME_12:
1240 return "monochrome-12";
1241 case GST_H265_PROFILE_MONOCHROME_16:
1242 return "monochrome-16";
1243 case GST_H265_PROFILE_MAIN_12:
1244 return "main-12";
1245 case GST_H265_PROFILE_MAIN_422_10:
1246 return "main-422-10";
1247 case GST_H265_PROFILE_MAIN_422_12:
1248 return "main-422-12";
1249 case GST_H265_PROFILE_MAIN_444:
1250 return "main-444";
1251 case GST_H265_PROFILE_MAIN_444_10:
1252 return "main-444-10";
1253 case GST_H265_PROFILE_MAIN_444_12:
1254 return "main-444-12";
1255 case GST_H265_PROFILE_MAIN_INTRA:
1256 return "main-intra";
1257 case GST_H265_PROFILE_MAIN_10_INTRA:
1258 return "main-10-intra";
1259 case GST_H265_PROFILE_MAIN_12_INTRA:
1260 return "main-12-intra";
1261 case GST_H265_PROFILE_MAIN_422_10_INTRA:
1262 return "main-422-10-intra";
1263 case GST_H265_PROFILE_MAIN_422_12_INTRA:
1264 return "main-422-12-intra";
1265 case GST_H265_PROFILE_MAIN_444_INTRA:
1266 return "main-444-intra";
1267 case GST_H265_PROFILE_MAIN_444_10_INTRA:
1268 return "main-444-10-intra";
1269 case GST_H265_PROFILE_MAIN_444_12_INTRA:
1270 return "main-444-12-intra";
1271 case GST_H265_PROFILE_MAIN_444_16_INTRA:
1272 return "main-444-16-intra";
1273 case GST_H265_PROFILE_MAIN_444_STILL_PICTURE:
1274 return "main-444-still-picture";
1275 case GST_H265_PROFILE_MAIN_444_16_STILL_PICTURE:
1276 return "main-444-16-still-picture";
Guillaume Desmottesd252f502018-03-01 11:08:44 +01001277 default:
1278 break;
1279 }
Sreerenj Balachandrana70c4f32015-04-30 18:36:35 +03001280
Guillaume Desmottesd252f502018-03-01 11:08:44 +01001281 return NULL;
Sreerenj Balachandrana70c4f32015-04-30 18:36:35 +03001282}
1283
1284static const gchar *
1285get_tier_string (guint8 tier_flag)
1286{
1287 const gchar *tier = NULL;
1288
1289 if (tier_flag)
1290 tier = "high";
1291 else
1292 tier = "main";
1293
1294 return tier;
1295}
1296
1297static const gchar *
1298get_level_string (guint8 level_idc)
1299{
Sebastian Dröge920ad272016-04-25 16:50:55 +03001300 if (level_idc == 0)
1301 return NULL;
1302 else if (level_idc % 30 == 0)
Sreerenj Balachandrana70c4f32015-04-30 18:36:35 +03001303 return digit_to_string (level_idc / 30);
1304 else {
1305 switch (level_idc) {
1306 case 63:
1307 return "2.1";
1308 break;
1309 case 93:
1310 return "3.1";
1311 break;
1312 case 123:
1313 return "4.1";
1314 break;
1315 case 153:
1316 return "5.1";
1317 break;
1318 case 156:
1319 return "5.2";
1320 break;
1321 case 183:
1322 return "6.1";
1323 break;
1324 case 186:
1325 return "6.2";
1326 break;
1327 default:
1328 return NULL;
1329 }
1330 }
1331}
1332
Sreerenj Balachandran69becd72015-08-07 05:58:22 +03001333static GstCaps *
1334get_compatible_profile_caps (GstH265SPS * sps)
1335{
1336 GstCaps *caps = NULL;
1337 const gchar **profiles = NULL;
1338 gint i;
1339 GValue compat_profiles = G_VALUE_INIT;
1340 g_value_init (&compat_profiles, GST_TYPE_LIST);
1341
1342 switch (sps->profile_tier_level.profile_idc) {
Guillaume Desmottesd252f502018-03-01 11:08:44 +01001343 case GST_H265_PROFILE_IDC_MAIN_10:
Sreerenj Balachandran69becd72015-08-07 05:58:22 +03001344 if (sps->profile_tier_level.profile_compatibility_flag[1]) {
1345 if (sps->profile_tier_level.profile_compatibility_flag[3]) {
1346 static const gchar *profile_array[] =
1347 { "main", "main-still-picture", NULL };
1348 profiles = profile_array;
1349 } else {
1350 static const gchar *profile_array[] = { "main", NULL };
1351 profiles = profile_array;
1352 }
1353 }
1354 break;
Guillaume Desmottesd252f502018-03-01 11:08:44 +01001355 case GST_H265_PROFILE_IDC_MAIN:
Sreerenj Balachandran69becd72015-08-07 05:58:22 +03001356 if (sps->profile_tier_level.profile_compatibility_flag[3]) {
1357 static const gchar *profile_array[] =
1358 { "main-still-picture", "main-10", NULL
1359 };
1360 profiles = profile_array;
1361 } else {
1362 static const gchar *profile_array[] = { "main-10", NULL };
1363 profiles = profile_array;
1364 }
1365 break;
Guillaume Desmottesd252f502018-03-01 11:08:44 +01001366 case GST_H265_PROFILE_IDC_MAIN_STILL_PICTURE:
Sreerenj Balachandran69becd72015-08-07 05:58:22 +03001367 {
1368 static const gchar *profile_array[] = { "main", "main-10", NULL
1369 };
1370 profiles = profile_array;
1371 }
1372 break;
1373 default:
1374 break;
1375 }
1376
1377 if (profiles) {
1378 GValue value = G_VALUE_INIT;
1379 caps = gst_caps_new_empty_simple ("video/x-h265");
1380 for (i = 0; profiles[i]; i++) {
1381 g_value_init (&value, G_TYPE_STRING);
1382 g_value_set_string (&value, profiles[i]);
1383 gst_value_list_append_value (&compat_profiles, &value);
1384 g_value_unset (&value);
1385 }
1386 gst_caps_set_value (caps, "profile", &compat_profiles);
1387 g_value_unset (&compat_profiles);
1388 }
1389
1390 return caps;
1391}
1392
1393/* if downstream didn't support the exact profile indicated in sps header,
1394 * check for the compatible profiles also */
1395static void
1396ensure_caps_profile (GstH265Parse * h265parse, GstCaps * caps, GstH265SPS * sps)
1397{
Matthew Waters2a498112016-02-04 18:15:56 +11001398 GstCaps *peer_caps, *compat_caps;
Sreerenj Balachandran69becd72015-08-07 05:58:22 +03001399
Matthew Waters2a498112016-02-04 18:15:56 +11001400 peer_caps = gst_pad_get_current_caps (GST_BASE_PARSE_SRC_PAD (h265parse));
1401 if (!peer_caps || !gst_caps_can_intersect (caps, peer_caps)) {
1402 GstCaps *filter_caps = gst_caps_new_empty_simple ("video/x-h265");
1403
1404 if (peer_caps)
1405 gst_caps_unref (peer_caps);
1406 peer_caps =
1407 gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (h265parse),
1408 filter_caps);
1409
1410 gst_caps_unref (filter_caps);
1411 }
Sreerenj Balachandran69becd72015-08-07 05:58:22 +03001412
1413 if (peer_caps && !gst_caps_can_intersect (caps, peer_caps)) {
1414 GstStructure *structure;
1415
1416 compat_caps = get_compatible_profile_caps (sps);
1417 if (compat_caps != NULL) {
1418 GstCaps *res_caps = NULL;
1419
1420 res_caps = gst_caps_intersect (peer_caps, compat_caps);
1421
1422 if (res_caps && !gst_caps_is_empty (res_caps)) {
1423 const gchar *profile_str = NULL;
1424
1425 res_caps = gst_caps_fixate (res_caps);
1426 structure = gst_caps_get_structure (res_caps, 0);
1427 profile_str = gst_structure_get_string (structure, "profile");
1428 if (profile_str) {
1429 gst_caps_set_simple (caps, "profile", G_TYPE_STRING, profile_str,
1430 NULL);
1431 GST_DEBUG_OBJECT (h265parse,
1432 "Setting compatible profile %s to the caps", profile_str);
1433 }
1434 }
1435 if (res_caps)
1436 gst_caps_unref (res_caps);
1437 gst_caps_unref (compat_caps);
1438 }
1439 }
1440 if (peer_caps)
1441 gst_caps_unref (peer_caps);
Sreerenj Balachandran69becd72015-08-07 05:58:22 +03001442}
1443
Sreerenj Balachandrand8448322013-10-09 10:54:14 +03001444static void
1445gst_h265_parse_update_src_caps (GstH265Parse * h265parse, GstCaps * caps)
1446{
1447 GstH265SPS *sps;
1448 GstCaps *sink_caps, *src_caps;
1449 gboolean modified = FALSE;
1450 GstBuffer *buf = NULL;
1451 GstStructure *s = NULL;
1452
1453 if (G_UNLIKELY (!gst_pad_has_current_caps (GST_BASE_PARSE_SRC_PAD
1454 (h265parse))))
1455 modified = TRUE;
1456 else if (G_UNLIKELY (!h265parse->update_caps))
1457 return;
1458
1459 /* if this is being called from the first _setcaps call, caps on the sinkpad
1460 * aren't set yet and so they need to be passed as an argument */
1461 if (caps)
1462 sink_caps = gst_caps_ref (caps);
1463 else
1464 sink_caps = gst_pad_get_current_caps (GST_BASE_PARSE_SINK_PAD (h265parse));
1465
1466 /* carry over input caps as much as possible; override with our own stuff */
1467 if (!sink_caps)
1468 sink_caps = gst_caps_new_empty_simple ("video/x-h265");
1469 else
1470 s = gst_caps_get_structure (sink_caps, 0);
1471
1472 sps = h265parse->nalparser->last_sps;
1473 GST_DEBUG_OBJECT (h265parse, "sps: %p", sps);
1474
1475 /* only codec-data for nice-and-clean au aligned packetized hevc format */
1476 if ((h265parse->format == GST_H265_PARSE_FORMAT_HVC1
1477 || h265parse->format == GST_H265_PARSE_FORMAT_HEV1)
1478 && h265parse->align == GST_H265_PARSE_ALIGN_AU) {
1479 buf = gst_h265_parse_make_codec_data (h265parse);
1480 if (buf && h265parse->codec_data) {
1481 GstMapInfo map;
1482
1483 gst_buffer_map (buf, &map, GST_MAP_READ);
1484 if (map.size != gst_buffer_get_size (h265parse->codec_data) ||
1485 gst_buffer_memcmp (h265parse->codec_data, 0, map.data, map.size))
1486 modified = TRUE;
1487
1488 gst_buffer_unmap (buf, &map);
1489 } else {
1490 if (!buf && h265parse->codec_data_in)
1491 buf = gst_buffer_ref (h265parse->codec_data_in);
1492 modified = TRUE;
1493 }
1494 }
1495
1496 caps = NULL;
1497 if (G_UNLIKELY (!sps)) {
1498 caps = gst_caps_copy (sink_caps);
1499 } else {
Sreerenj Balachandran6fc55a92015-04-30 19:08:25 +03001500 gint crop_width, crop_height;
Guillaume Desmottesa1b271d2017-11-06 12:39:32 +01001501 const gchar *chroma_format = NULL;
1502 guint bit_depth_chroma;
Sreerenj Balachandran6fc55a92015-04-30 19:08:25 +03001503
1504 if (sps->conformance_window_flag) {
1505 crop_width = sps->crop_rect_width;
1506 crop_height = sps->crop_rect_height;
1507 } else {
1508 crop_width = sps->width;
1509 crop_height = sps->height;
1510 }
1511
1512 if (G_UNLIKELY (h265parse->width != crop_width ||
1513 h265parse->height != crop_height)) {
1514 GST_INFO_OBJECT (h265parse, "resolution changed %dx%d",
1515 crop_width, crop_height);
1516 h265parse->width = crop_width;
1517 h265parse->height = crop_height;
1518 modified = TRUE;
1519 }
Sreerenj Balachandrand8448322013-10-09 10:54:14 +03001520
1521 /* 0/1 is set as the default in the codec parser */
1522 if (sps->vui_params.timing_info_present_flag &&
1523 !(sps->fps_num == 0 && sps->fps_den == 1)) {
1524 if (G_UNLIKELY (h265parse->fps_num != sps->fps_num
1525 || h265parse->fps_den != sps->fps_den)) {
1526 GST_INFO_OBJECT (h265parse, "framerate changed %d/%d",
1527 sps->fps_num, sps->fps_den);
1528 h265parse->fps_num = sps->fps_num;
1529 h265parse->fps_den = sps->fps_den;
1530 modified = TRUE;
1531 }
1532 }
1533
1534 if (sps->vui_params.aspect_ratio_info_present_flag) {
1535 if (G_UNLIKELY ((h265parse->parsed_par_n != sps->vui_params.par_n)
1536 && (h265parse->parsed_par_d != sps->vui_params.par_d))) {
1537 h265parse->parsed_par_n = sps->vui_params.par_n;
1538 h265parse->parsed_par_d = sps->vui_params.par_d;
1539 GST_INFO_OBJECT (h265parse, "pixel aspect ratio has been changed %d/%d",
1540 h265parse->parsed_par_n, h265parse->parsed_par_d);
1541 modified = TRUE;
1542 }
1543
1544 }
1545
1546 if (G_UNLIKELY (modified || h265parse->update_caps)) {
1547 gint fps_num = h265parse->fps_num;
1548 gint fps_den = h265parse->fps_den;
1549 gint width, height;
1550 GstClockTime latency;
1551
1552 caps = gst_caps_copy (sink_caps);
1553
1554 /* sps should give this but upstream overrides */
1555 if (s && gst_structure_has_field (s, "width"))
1556 gst_structure_get_int (s, "width", &width);
1557 else
1558 width = h265parse->width;
1559
1560 if (s && gst_structure_has_field (s, "height"))
1561 gst_structure_get_int (s, "height", &height);
1562 else
1563 height = h265parse->height;
1564
1565 gst_caps_set_simple (caps, "width", G_TYPE_INT, width,
1566 "height", G_TYPE_INT, height, NULL);
1567
1568 /* upstream overrides */
1569 if (s && gst_structure_has_field (s, "framerate"))
1570 gst_structure_get_fraction (s, "framerate", &fps_num, &fps_den);
1571
1572 /* but not necessarily or reliably this */
1573 if (fps_num > 0 && fps_den > 0) {
1574 GST_INFO_OBJECT (h265parse, "setting framerate in caps");
1575 gst_caps_set_simple (caps, "framerate",
1576 GST_TYPE_FRACTION, fps_num, fps_den, NULL);
1577 gst_base_parse_set_frame_rate (GST_BASE_PARSE (h265parse),
1578 fps_num, fps_den, 0, 0);
1579 latency = gst_util_uint64_scale (GST_SECOND, fps_den, fps_num);
1580 gst_base_parse_set_latency (GST_BASE_PARSE (h265parse), latency,
1581 latency);
1582 }
Guillaume Desmottesa1b271d2017-11-06 12:39:32 +01001583
1584 bit_depth_chroma = sps->bit_depth_chroma_minus8 + 8;
1585
1586 switch (sps->chroma_format_idc) {
1587 case 0:
1588 chroma_format = "4:0:0";
1589 bit_depth_chroma = 0;
1590 break;
1591 case 1:
1592 chroma_format = "4:2:0";
1593 break;
1594 case 2:
1595 chroma_format = "4:2:2";
1596 break;
1597 case 3:
1598 chroma_format = "4:4:4";
1599 break;
1600 default:
1601 break;
1602 }
1603
1604 if (chroma_format)
1605 gst_caps_set_simple (caps, "chroma-format", G_TYPE_STRING,
1606 chroma_format, "bit-depth-luma", G_TYPE_UINT,
1607 sps->bit_depth_luma_minus8 + 8, "bit-depth-chroma", G_TYPE_UINT,
1608 bit_depth_chroma, NULL);
Sreerenj Balachandrand8448322013-10-09 10:54:14 +03001609 }
1610 }
1611
1612 if (caps) {
1613 gint par_n, par_d;
1614
1615 gst_caps_set_simple (caps, "parsed", G_TYPE_BOOLEAN, TRUE,
1616 "stream-format", G_TYPE_STRING,
1617 gst_h265_parse_get_string (h265parse, TRUE, h265parse->format),
1618 "alignment", G_TYPE_STRING,
1619 gst_h265_parse_get_string (h265parse, FALSE, h265parse->align), NULL);
1620
1621 gst_h265_parse_get_par (h265parse, &par_n, &par_d);
1622 if (par_n != 0 && par_d != 0 &&
1623 (!s || !gst_structure_has_field (s, "pixel-aspect-ratio"))) {
1624 GST_INFO_OBJECT (h265parse, "PAR %d/%d", par_n, par_d);
1625 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
1626 par_n, par_d, NULL);
1627 }
1628
Sebastian Drögedf648622014-11-06 11:53:04 +01001629 /* set profile and level in caps */
1630 if (sps) {
Sreerenj Balachandrana70c4f32015-04-30 18:36:35 +03001631 const gchar *profile, *tier, *level;
Guillaume Desmottesd252f502018-03-01 11:08:44 +01001632 GstH265Profile p;
Sebastian Drögedf648622014-11-06 11:53:04 +01001633
Guillaume Desmottesd252f502018-03-01 11:08:44 +01001634 p = gst_h265_profile_tier_level_get_profile (&sps->profile_tier_level);
1635 profile = get_profile_string (p);
Sreerenj Balachandrana70c4f32015-04-30 18:36:35 +03001636 if (profile != NULL)
1637 gst_caps_set_simple (caps, "profile", G_TYPE_STRING, profile, NULL);
1638
1639 tier = get_tier_string (sps->profile_tier_level.tier_flag);
1640 if (tier != NULL)
1641 gst_caps_set_simple (caps, "tier", G_TYPE_STRING, tier, NULL);
1642
1643 level = get_level_string (sps->profile_tier_level.level_idc);
1644 if (level != NULL)
1645 gst_caps_set_simple (caps, "level", G_TYPE_STRING, level, NULL);
Sreerenj Balachandran69becd72015-08-07 05:58:22 +03001646
1647 /* relax the profile constraint to find a suitable decoder */
1648 ensure_caps_profile (h265parse, caps, sps);
Sebastian Drögedf648622014-11-06 11:53:04 +01001649 }
1650
Sreerenj Balachandrand8448322013-10-09 10:54:14 +03001651 src_caps = gst_pad_get_current_caps (GST_BASE_PARSE_SRC_PAD (h265parse));
1652
Matthew Waters2a498112016-02-04 18:15:56 +11001653 if (src_caps) {
Sreerenj Balachandrand8448322013-10-09 10:54:14 +03001654 /* use codec data from old caps for comparison; we don't want to resend caps
1655 if everything is same except codec data; */
Matthew Waters2a498112016-02-04 18:15:56 +11001656 if (gst_structure_has_field (gst_caps_get_structure (src_caps, 0),
1657 "codec_data")) {
1658 gst_caps_set_value (caps, "codec_data",
1659 gst_structure_get_value (gst_caps_get_structure (src_caps, 0),
1660 "codec_data"));
1661 } else if (!buf) {
1662 GstStructure *s;
1663 /* remove any left-over codec-data hanging around */
1664 s = gst_caps_get_structure (caps, 0);
1665 gst_structure_remove_field (s, "codec_data");
1666 }
Sreerenj Balachandrand8448322013-10-09 10:54:14 +03001667 }
Matthew Waters2a498112016-02-04 18:15:56 +11001668
Sreerenj Balachandrand8448322013-10-09 10:54:14 +03001669 if (!(src_caps && gst_caps_is_strictly_equal (src_caps, caps))) {
1670 /* update codec data to new value */
1671 if (buf) {
1672 gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, buf, NULL);
1673 gst_buffer_replace (&h265parse->codec_data, buf);
1674 gst_buffer_unref (buf);
1675 buf = NULL;
1676 } else {
1677 GstStructure *s;
1678 /* remove any left-over codec-data hanging around */
1679 s = gst_caps_get_structure (caps, 0);
1680 gst_structure_remove_field (s, "codec_data");
1681 gst_buffer_replace (&h265parse->codec_data, NULL);
1682 }
1683
1684 gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (h265parse), caps);
1685 }
1686
1687 if (src_caps)
1688 gst_caps_unref (src_caps);
1689 gst_caps_unref (caps);
1690 }
1691
1692 gst_caps_unref (sink_caps);
1693 if (buf)
1694 gst_buffer_unref (buf);
1695
1696}
1697
1698static GstFlowReturn
1699gst_h265_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
1700{
1701 GstH265Parse *h265parse;
1702 GstBuffer *buffer;
1703 guint av;
1704
1705 h265parse = GST_H265_PARSE (parse);
1706 buffer = frame->buffer;
1707
1708 gst_h265_parse_update_src_caps (h265parse, NULL);
1709
1710 /* Fixme: Implement timestamp interpolation based on SEI Messagses */
1711 GST_FIXME_OBJECT (h265parse,
1712 "Implement timestamp/duration interpolation based on SEI message");
1713
1714 if (h265parse->keyframe)
1715 GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
1716 else
1717 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
1718
Josep Torra4b43e952014-11-07 15:41:15 +01001719 if (h265parse->header)
1720 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_HEADER);
1721 else
1722 GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_HEADER);
1723
Sreerenj Balachandrand8448322013-10-09 10:54:14 +03001724 /* replace with transformed HEVC output if applicable */
1725 av = gst_adapter_available (h265parse->frame_out);
1726 if (av) {
1727 GstBuffer *buf;
1728
1729 buf = gst_adapter_take_buffer (h265parse->frame_out, av);
1730 gst_buffer_copy_into (buf, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
1731 gst_buffer_replace (&frame->out_buffer, buf);
1732 gst_buffer_unref (buf);
1733 }
1734
1735 return GST_FLOW_OK;
1736}
1737
1738/* sends a codec NAL downstream, decorating and transforming as needed.
1739 * No ownership is taken of @nal */
1740static GstFlowReturn
1741gst_h265_parse_push_codec_buffer (GstH265Parse * h265parse, GstBuffer * nal,
1742 GstClockTime ts)
1743{
1744 GstMapInfo map;
1745
1746 gst_buffer_map (nal, &map, GST_MAP_READ);
1747 nal = gst_h265_parse_wrap_nal (h265parse, h265parse->format,
1748 map.data, map.size);
1749 gst_buffer_unmap (nal, &map);
1750
1751 GST_BUFFER_TIMESTAMP (nal) = ts;
1752 GST_BUFFER_DURATION (nal) = 0;
1753
1754 return gst_pad_push (GST_BASE_PARSE_SRC_PAD (h265parse), nal);
1755}
1756
1757static GstEvent *
1758check_pending_key_unit_event (GstEvent * pending_event, GstSegment * segment,
1759 GstClockTime timestamp, guint flags, GstClockTime pending_key_unit_ts)
1760{
1761 GstClockTime running_time, stream_time;
1762 gboolean all_headers;
1763 guint count;
1764 GstEvent *event = NULL;
1765
1766 g_return_val_if_fail (segment != NULL, NULL);
1767
1768 if (pending_event == NULL)
1769 goto out;
1770
1771 if (GST_CLOCK_TIME_IS_VALID (pending_key_unit_ts) &&
1772 timestamp == GST_CLOCK_TIME_NONE)
1773 goto out;
1774
1775 running_time = gst_segment_to_running_time (segment,
1776 GST_FORMAT_TIME, timestamp);
1777
1778 GST_INFO ("now %" GST_TIME_FORMAT " wanted %" GST_TIME_FORMAT,
1779 GST_TIME_ARGS (running_time), GST_TIME_ARGS (pending_key_unit_ts));
1780 if (GST_CLOCK_TIME_IS_VALID (pending_key_unit_ts) &&
1781 running_time < pending_key_unit_ts)
1782 goto out;
1783
1784 if (flags & GST_BUFFER_FLAG_DELTA_UNIT) {
1785 GST_DEBUG ("pending force key unit, waiting for keyframe");
1786 goto out;
1787 }
1788
1789 stream_time = gst_segment_to_stream_time (segment,
1790 GST_FORMAT_TIME, timestamp);
1791
Aleksander Wabikd8e681b2016-03-17 19:24:32 +00001792 if (!gst_video_event_parse_upstream_force_key_unit (pending_event,
1793 NULL, &all_headers, &count)) {
1794 gst_video_event_parse_downstream_force_key_unit (pending_event, NULL,
1795 NULL, NULL, &all_headers, &count);
1796 }
Sreerenj Balachandrand8448322013-10-09 10:54:14 +03001797
1798 event =
1799 gst_video_event_new_downstream_force_key_unit (timestamp, stream_time,
1800 running_time, all_headers, count);
1801 gst_event_set_seqnum (event, gst_event_get_seqnum (pending_event));
1802
1803out:
1804 return event;
1805}
1806
1807static void
1808gst_h265_parse_prepare_key_unit (GstH265Parse * parse, GstEvent * event)
1809{
1810 GstClockTime running_time;
1811 guint count;
1812#ifndef GST_DISABLE_GST_DEBUG
1813 gboolean have_vps, have_sps, have_pps;
1814 gint i;
1815#endif
1816
1817 parse->pending_key_unit_ts = GST_CLOCK_TIME_NONE;
1818 gst_event_replace (&parse->force_key_unit_event, NULL);
1819
1820 gst_video_event_parse_downstream_force_key_unit (event,
1821 NULL, NULL, &running_time, NULL, &count);
1822
1823 GST_INFO_OBJECT (parse, "pushing downstream force-key-unit event %d "
1824 "%" GST_TIME_FORMAT " count %d", gst_event_get_seqnum (event),
1825 GST_TIME_ARGS (running_time), count);
1826 gst_pad_push_event (GST_BASE_PARSE_SRC_PAD (parse), event);
1827
1828#ifndef GST_DISABLE_GST_DEBUG
1829 have_vps = have_sps = have_pps = FALSE;
1830 for (i = 0; i < GST_H265_MAX_VPS_COUNT; i++) {
1831 if (parse->vps_nals[i] != NULL) {
1832 have_vps = TRUE;
1833 break;
1834 }
1835 }
1836 for (i = 0; i < GST_H265_MAX_SPS_COUNT; i++) {
1837 if (parse->sps_nals[i] != NULL) {
1838 have_sps = TRUE;
1839 break;
1840 }
1841 }
1842 for (i = 0; i < GST_H265_MAX_PPS_COUNT; i++) {
1843 if (parse->pps_nals[i] != NULL) {
1844 have_pps = TRUE;
1845 break;
1846 }
1847 }
1848
1849 GST_INFO_OBJECT (parse,
1850 "preparing key unit, have vps %d have sps %d have pps %d", have_vps,
1851 have_sps, have_pps);
1852#endif
1853
1854 /* set push_codec to TRUE so that pre_push_frame sends VPS/SPS/PPS again */
1855 parse->push_codec = TRUE;
1856}
1857
1858static GstFlowReturn
1859gst_h265_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
1860{
1861 GstH265Parse *h265parse;
1862 GstBuffer *buffer;
1863 GstEvent *event;
1864
1865 h265parse = GST_H265_PARSE (parse);
Sebastian Dröge843de8d2013-12-16 10:19:36 +01001866
1867 if (!h265parse->sent_codec_tag) {
1868 GstTagList *taglist;
1869 GstCaps *caps;
1870
Sebastian Dröge843de8d2013-12-16 10:19:36 +01001871 /* codec tag */
1872 caps = gst_pad_get_current_caps (GST_BASE_PARSE_SRC_PAD (parse));
Dave Craig88d7beb2015-12-15 17:10:00 +00001873 if (G_UNLIKELY (caps == NULL)) {
1874 if (GST_PAD_IS_FLUSHING (GST_BASE_PARSE_SRC_PAD (parse))) {
1875 GST_INFO_OBJECT (parse, "Src pad is flushing");
1876 return GST_FLOW_FLUSHING;
1877 } else {
1878 GST_INFO_OBJECT (parse, "Src pad is not negotiated!");
1879 return GST_FLOW_NOT_NEGOTIATED;
1880 }
1881 }
1882
1883 taglist = gst_tag_list_new_empty ();
Sebastian Dröge843de8d2013-12-16 10:19:36 +01001884 gst_pb_utils_add_codec_description_to_tag_list (taglist,
1885 GST_TAG_VIDEO_CODEC, caps);
1886 gst_caps_unref (caps);
1887
Olivier CrĂªte567b1e82015-03-17 17:55:26 -04001888 gst_base_parse_merge_tags (parse, taglist, GST_TAG_MERGE_REPLACE);
1889 gst_tag_list_unref (taglist);
Sebastian Dröge843de8d2013-12-16 10:19:36 +01001890
1891 /* also signals the end of first-frame processing */
1892 h265parse->sent_codec_tag = TRUE;
1893 }
1894
Sreerenj Balachandrand8448322013-10-09 10:54:14 +03001895 buffer = frame->buffer;
1896
1897 if ((event = check_pending_key_unit_event (h265parse->force_key_unit_event,
1898 &parse->segment, GST_BUFFER_TIMESTAMP (buffer),
1899 GST_BUFFER_FLAGS (buffer), h265parse->pending_key_unit_ts))) {
1900 gst_h265_parse_prepare_key_unit (h265parse, event);
1901 }
1902
1903 /* periodic VPS/SPS/PPS sending */
1904 if (h265parse->interval > 0 || h265parse->push_codec) {
1905 GstClockTime timestamp = GST_BUFFER_TIMESTAMP (buffer);
1906 guint64 diff;
1907
1908 /* init */
1909 if (!GST_CLOCK_TIME_IS_VALID (h265parse->last_report)) {
1910 h265parse->last_report = timestamp;
1911 }
1912
1913 if (h265parse->idr_pos >= 0) {
1914 GST_LOG_OBJECT (h265parse, "IDR nal at offset %d", h265parse->idr_pos);
1915
1916 if (timestamp > h265parse->last_report)
1917 diff = timestamp - h265parse->last_report;
1918 else
1919 diff = 0;
1920
1921 GST_LOG_OBJECT (h265parse,
1922 "now %" GST_TIME_FORMAT ", last VPS/SPS/PPS %" GST_TIME_FORMAT,
1923 GST_TIME_ARGS (timestamp), GST_TIME_ARGS (h265parse->last_report));
1924
1925 GST_DEBUG_OBJECT (h265parse,
1926 "interval since last VPS/SPS/PPS %" GST_TIME_FORMAT,
1927 GST_TIME_ARGS (diff));
1928
1929 if (GST_TIME_AS_SECONDS (diff) >= h265parse->interval ||
1930 h265parse->push_codec) {
1931 GstBuffer *codec_nal;
1932 gint i;
1933 GstClockTime new_ts;
1934
1935 /* avoid overwriting a perfectly fine timestamp */
1936 new_ts = GST_CLOCK_TIME_IS_VALID (timestamp) ? timestamp :
1937 h265parse->last_report;
1938
1939 if (h265parse->align == GST_H265_PARSE_ALIGN_NAL) {
1940 /* send separate config NAL buffers */
1941 GST_DEBUG_OBJECT (h265parse, "- sending VPS/SPS/PPS");
1942 for (i = 0; i < GST_H265_MAX_VPS_COUNT; i++) {
1943 if ((codec_nal = h265parse->vps_nals[i])) {
1944 GST_DEBUG_OBJECT (h265parse, "sending VPS nal");
1945 gst_h265_parse_push_codec_buffer (h265parse, codec_nal,
1946 timestamp);
1947 h265parse->last_report = new_ts;
1948 }
1949 }
1950 for (i = 0; i < GST_H265_MAX_SPS_COUNT; i++) {
1951 if ((codec_nal = h265parse->sps_nals[i])) {
1952 GST_DEBUG_OBJECT (h265parse, "sending SPS nal");
1953 gst_h265_parse_push_codec_buffer (h265parse, codec_nal,
1954 timestamp);
1955 h265parse->last_report = new_ts;
1956 }
1957 }
1958 for (i = 0; i < GST_H265_MAX_PPS_COUNT; i++) {
1959 if ((codec_nal = h265parse->pps_nals[i])) {
1960 GST_DEBUG_OBJECT (h265parse, "sending PPS nal");
1961 gst_h265_parse_push_codec_buffer (h265parse, codec_nal,
1962 timestamp);
1963 h265parse->last_report = new_ts;
1964 }
1965 }
1966 } else {
1967 /* insert config NALs into AU */
1968 GstByteWriter bw;
1969 GstBuffer *new_buf;
1970 const gboolean bs = h265parse->format == GST_H265_PARSE_FORMAT_BYTE;
1971 const gint nls = 4 - h265parse->nal_length_size;
1972 gboolean ok;
1973
1974 gst_byte_writer_init_with_size (&bw, gst_buffer_get_size (buffer),
1975 FALSE);
1976 ok = gst_byte_writer_put_buffer (&bw, buffer, 0, h265parse->idr_pos);
1977 GST_DEBUG_OBJECT (h265parse, "- inserting VPS/SPS/PPS");
1978 for (i = 0; i < GST_H265_MAX_VPS_COUNT; i++) {
1979 if ((codec_nal = h265parse->vps_nals[i])) {
1980 gsize nal_size = gst_buffer_get_size (codec_nal);
1981 GST_DEBUG_OBJECT (h265parse, "inserting VPS nal");
1982 if (bs) {
1983 ok &= gst_byte_writer_put_uint32_be (&bw, 1);
1984 } else {
1985 ok &= gst_byte_writer_put_uint32_be (&bw,
1986 (nal_size << (nls * 8)));
1987 ok &= gst_byte_writer_set_pos (&bw,
1988 gst_byte_writer_get_pos (&bw) - nls);
1989 }
1990
1991 ok &= gst_byte_writer_put_buffer (&bw, codec_nal, 0, nal_size);
1992 h265parse->last_report = new_ts;
1993 }
1994 }
1995 for (i = 0; i < GST_H265_MAX_SPS_COUNT; i++) {
1996 if ((codec_nal = h265parse->sps_nals[i])) {
1997 gsize nal_size = gst_buffer_get_size (codec_nal);
1998 GST_DEBUG_OBJECT (h265parse, "inserting SPS nal");
1999 if (bs) {
2000 ok &= gst_byte_writer_put_uint32_be (&bw, 1);
2001 } else {
2002 ok &= gst_byte_writer_put_uint32_be (&bw,
2003 (nal_size << (nls * 8)));
2004 ok &= gst_byte_writer_set_pos (&bw,
2005 gst_byte_writer_get_pos (&bw) - nls);
2006 }
2007
2008 ok &= gst_byte_writer_put_buffer (&bw, codec_nal, 0, nal_size);
2009 h265parse->last_report = new_ts;
2010 }
2011 }
2012 for (i = 0; i < GST_H265_MAX_PPS_COUNT; i++) {
2013 if ((codec_nal = h265parse->pps_nals[i])) {
2014 gsize nal_size = gst_buffer_get_size (codec_nal);
2015 GST_DEBUG_OBJECT (h265parse, "inserting PPS nal");
2016 if (bs) {
2017 ok &= gst_byte_writer_put_uint32_be (&bw, 1);
2018 } else {
2019 ok &= gst_byte_writer_put_uint32_be (&bw,
2020 (nal_size << (nls * 8)));
2021 ok &= gst_byte_writer_set_pos (&bw,
2022 gst_byte_writer_get_pos (&bw) - nls);
2023 }
2024 ok &= gst_byte_writer_put_buffer (&bw, codec_nal, 0, nal_size);
2025 h265parse->last_report = new_ts;
2026 }
2027 }
2028 ok &=
2029 gst_byte_writer_put_buffer (&bw, buffer, h265parse->idr_pos, -1);
2030 /* collect result and push */
2031 new_buf = gst_byte_writer_reset_and_get_buffer (&bw);
2032 gst_buffer_copy_into (new_buf, buffer, GST_BUFFER_COPY_METADATA, 0,
2033 -1);
2034 /* should already be keyframe/IDR, but it may not have been,
2035 * so mark it as such to avoid being discarded by picky decoder */
2036 GST_BUFFER_FLAG_UNSET (new_buf, GST_BUFFER_FLAG_DELTA_UNIT);
2037 gst_buffer_replace (&frame->out_buffer, new_buf);
2038 gst_buffer_unref (new_buf);
2039 /* some result checking seems to make some compilers happy */
2040 if (G_UNLIKELY (!ok)) {
2041 GST_ERROR_OBJECT (h265parse, "failed to insert SPS/PPS");
2042 }
2043 }
2044 }
2045 /* we pushed whatever we had */
2046 h265parse->push_codec = FALSE;
2047 h265parse->have_vps = FALSE;
2048 h265parse->have_sps = FALSE;
2049 h265parse->have_pps = FALSE;
2050 }
2051 }
2052
2053 gst_h265_parse_reset_frame (h265parse);
2054
2055 return GST_FLOW_OK;
2056}
2057
2058static gboolean
2059gst_h265_parse_set_caps (GstBaseParse * parse, GstCaps * caps)
2060{
2061 GstH265Parse *h265parse;
2062 GstStructure *str;
2063 const GValue *value;
2064 GstBuffer *codec_data = NULL;
2065 gsize off, size;
2066 guint format, align;
2067 guint num_nals, i, j;
2068 GstH265NalUnit nalu;
2069 GstH265ParserResult parseres;
2070
2071 h265parse = GST_H265_PARSE (parse);
2072
2073 /* reset */
2074 h265parse->push_codec = FALSE;
2075
2076 str = gst_caps_get_structure (caps, 0);
2077
2078 /* accept upstream info if provided */
2079 gst_structure_get_int (str, "width", &h265parse->width);
2080 gst_structure_get_int (str, "height", &h265parse->height);
2081 gst_structure_get_fraction (str, "framerate", &h265parse->fps_num,
2082 &h265parse->fps_den);
2083 gst_structure_get_fraction (str, "pixel-aspect-ratio",
2084 &h265parse->upstream_par_n, &h265parse->upstream_par_d);
2085
2086 /* get upstream format and align from caps */
2087 gst_h265_parse_format_from_caps (caps, &format, &align);
2088
2089 /* packetized video has a codec_data */
2090 if (format != GST_H265_PARSE_FORMAT_BYTE &&
2091 (value = gst_structure_get_value (str, "codec_data"))) {
2092 GstMapInfo map;
2093 guint8 *data;
Sebastian Dröge43736e52016-11-23 10:52:05 +02002094 guint num_nal_arrays;
Sreerenj Balachandrand8448322013-10-09 10:54:14 +03002095
2096 GST_DEBUG_OBJECT (h265parse, "have packetized h265");
2097 /* make note for optional split processing */
2098 h265parse->packetized = TRUE;
2099
2100 codec_data = gst_value_get_buffer (value);
2101 if (!codec_data)
2102 goto wrong_type;
2103 gst_buffer_map (codec_data, &map, GST_MAP_READ);
2104 data = map.data;
2105 size = map.size;
2106
2107 /* parse the hvcC data */
Chris Bassd9d4a912014-06-17 14:23:43 +01002108 if (size < 23) {
Sreerenj Balachandrand8448322013-10-09 10:54:14 +03002109 gst_buffer_unmap (codec_data, &map);
2110 goto hvcc_too_small;
2111 }
Sebastian Dröge63fee312014-01-06 14:52:54 +01002112 /* parse the version, this must be one but
2113 * is zero until the spec is finalized */
2114 if (data[0] != 0 && data[0] != 1) {
Sreerenj Balachandrand8448322013-10-09 10:54:14 +03002115 gst_buffer_unmap (codec_data, &map);
2116 goto wrong_version;
2117 }
2118
2119 h265parse->nal_length_size = (data[21] & 0x03) + 1;
2120 GST_DEBUG_OBJECT (h265parse, "nal length size %u",
2121 h265parse->nal_length_size);
2122
Sebastian Dröge43736e52016-11-23 10:52:05 +02002123 num_nal_arrays = data[22];
Sreerenj Balachandrand8448322013-10-09 10:54:14 +03002124 off = 23;
Sebastian Dröge43736e52016-11-23 10:52:05 +02002125
2126 for (i = 0; i < num_nal_arrays; i++) {
2127 if (off + 3 >= size) {
2128 gst_buffer_unmap (codec_data, &map);
2129 goto hvcc_too_small;
2130 }
2131
Sebastian Dröge63fee312014-01-06 14:52:54 +01002132 num_nals = GST_READ_UINT16_BE (data + off + 1);
Kyungyong Kim214a0412016-09-26 11:15:25 +09002133 off += 3;
Sreerenj Balachandrand8448322013-10-09 10:54:14 +03002134 for (j = 0; j < num_nals; j++) {
2135 parseres = gst_h265_parser_identify_nalu_hevc (h265parse->nalparser,
Kyungyong Kim214a0412016-09-26 11:15:25 +09002136 data, off, size, 2, &nalu);
Sreerenj Balachandrand8448322013-10-09 10:54:14 +03002137
2138 if (parseres != GST_H265_PARSER_OK) {
2139 gst_buffer_unmap (codec_data, &map);
2140 goto hvcc_too_small;
2141 }
2142
2143 gst_h265_parse_process_nal (h265parse, &nalu);
2144 off = nalu.offset + nalu.size;
2145 }
2146 }
Vineeth TM6a35a402016-01-25 12:05:12 +09002147 gst_buffer_unmap (codec_data, &map);
Sreerenj Balachandrand8448322013-10-09 10:54:14 +03002148 } else {
2149 GST_DEBUG_OBJECT (h265parse, "have bytestream h265");
2150 /* nothing to pre-process */
2151 h265parse->packetized = FALSE;
2152 /* we have 4 sync bytes */
2153 h265parse->nal_length_size = 4;
2154
2155 if (format == GST_H265_PARSE_FORMAT_NONE) {
2156 format = GST_H265_PARSE_FORMAT_BYTE;
2157 align = GST_H265_PARSE_ALIGN_AU;
2158 }
2159 }
2160
2161 {
2162 GstCaps *in_caps;
2163
2164 /* prefer input type determined above */
2165 in_caps = gst_caps_new_simple ("video/x-h265",
2166 "parsed", G_TYPE_BOOLEAN, TRUE,
2167 "stream-format", G_TYPE_STRING,
2168 gst_h265_parse_get_string (h265parse, TRUE, format),
2169 "alignment", G_TYPE_STRING,
2170 gst_h265_parse_get_string (h265parse, FALSE, align), NULL);
2171 /* negotiate with downstream, sets ->format and ->align */
2172 gst_h265_parse_negotiate (h265parse, format, in_caps);
2173 gst_caps_unref (in_caps);
2174 }
2175
2176 if (format == h265parse->format && align == h265parse->align) {
Vineeth TM09992f32015-07-30 08:58:48 +09002177 /* do not set CAPS and passthrough mode if SPS/PPS have not been parsed */
2178 if (h265parse->have_sps && h265parse->have_pps) {
duhui.leecd8c0222014-01-20 15:21:42 +09002179 gst_base_parse_set_passthrough (parse, TRUE);
Sreerenj Balachandrand8448322013-10-09 10:54:14 +03002180
duhui.leecd8c0222014-01-20 15:21:42 +09002181 /* we did parse codec-data and might supplement src caps */
2182 gst_h265_parse_update_src_caps (h265parse, caps);
2183 }
Sreerenj Balachandrand8448322013-10-09 10:54:14 +03002184 } else if (format == GST_H265_PARSE_FORMAT_HVC1
2185 || format == GST_H265_PARSE_FORMAT_HEV1) {
2186 /* if input != output, and input is hevc, must split before anything else */
2187 /* arrange to insert codec-data in-stream if needed.
2188 * src caps are only arranged for later on */
2189 h265parse->push_codec = TRUE;
2190 h265parse->have_vps = FALSE;
2191 h265parse->have_sps = FALSE;
2192 h265parse->have_pps = FALSE;
2193 if (h265parse->align == GST_H265_PARSE_ALIGN_NAL)
2194 h265parse->split_packetized = TRUE;
2195 h265parse->packetized = TRUE;
2196 }
2197
2198 return TRUE;
2199
2200 /* ERRORS */
2201hvcc_too_small:
2202 {
Chris Bassd9d4a912014-06-17 14:23:43 +01002203 GST_DEBUG_OBJECT (h265parse, "hvcC size %" G_GSIZE_FORMAT " < 23", size);
Sreerenj Balachandrand8448322013-10-09 10:54:14 +03002204 goto refuse_caps;
2205 }
2206wrong_version:
2207 {
2208 GST_DEBUG_OBJECT (h265parse, "wrong hvcC version");
2209 goto refuse_caps;
2210 }
2211wrong_type:
2212 {
2213 GST_DEBUG_OBJECT (h265parse, "wrong codec-data type");
2214 goto refuse_caps;
2215 }
2216refuse_caps:
2217 {
2218 GST_WARNING_OBJECT (h265parse, "refused caps %" GST_PTR_FORMAT, caps);
2219 return FALSE;
2220 }
2221}
2222
Wim Taymansd5a16bc2013-12-04 09:00:43 +01002223static void
Guillaume Desmottes00874852017-11-20 17:54:54 +01002224remove_fields (GstCaps * caps, gboolean all)
Wim Taymansd5a16bc2013-12-04 09:00:43 +01002225{
2226 guint i, n;
2227
2228 n = gst_caps_get_size (caps);
2229 for (i = 0; i < n; i++) {
2230 GstStructure *s = gst_caps_get_structure (caps, i);
2231
Guillaume Desmottes00874852017-11-20 17:54:54 +01002232 if (all) {
2233 gst_structure_remove_field (s, "alignment");
2234 gst_structure_remove_field (s, "stream-format");
2235 }
Wim Taymansd5a16bc2013-12-04 09:00:43 +01002236 gst_structure_remove_field (s, "parsed");
2237 }
2238}
2239
Sreerenj Balachandrand8448322013-10-09 10:54:14 +03002240static GstCaps *
2241gst_h265_parse_get_caps (GstBaseParse * parse, GstCaps * filter)
2242{
2243 GstCaps *peercaps, *templ;
Guillaume Desmottes00874852017-11-20 17:54:54 +01002244 GstCaps *res, *tmp, *pcopy;
Sreerenj Balachandrand8448322013-10-09 10:54:14 +03002245
2246 templ = gst_pad_get_pad_template_caps (GST_BASE_PARSE_SINK_PAD (parse));
Wim Taymanse9dd2df2013-12-04 09:03:45 +01002247 if (filter) {
2248 GstCaps *fcopy = gst_caps_copy (filter);
2249 /* Remove the fields we convert */
Guillaume Desmottes00874852017-11-20 17:54:54 +01002250 remove_fields (fcopy, TRUE);
Wim Taymanse9dd2df2013-12-04 09:03:45 +01002251 peercaps = gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (parse), fcopy);
2252 gst_caps_unref (fcopy);
2253 } else
2254 peercaps = gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (parse), NULL);
2255
Guillaume Desmottes00874852017-11-20 17:54:54 +01002256 pcopy = gst_caps_copy (peercaps);
2257 remove_fields (pcopy, TRUE);
Sreerenj Balachandrand8448322013-10-09 10:54:14 +03002258
Guillaume Desmottes00874852017-11-20 17:54:54 +01002259 res = gst_caps_intersect_full (pcopy, templ, GST_CAPS_INTERSECT_FIRST);
2260 gst_caps_unref (pcopy);
2261 gst_caps_unref (templ);
Sreerenj Balachandrand8448322013-10-09 10:54:14 +03002262
2263 if (filter) {
2264 GstCaps *tmp = gst_caps_intersect_full (res, filter,
2265 GST_CAPS_INTERSECT_FIRST);
2266 gst_caps_unref (res);
2267 res = tmp;
2268 }
2269
Guillaume Desmottes00874852017-11-20 17:54:54 +01002270 /* Try if we can put the downstream caps first */
Seungha Yangc65a5372018-04-06 23:22:39 +09002271 pcopy = gst_caps_copy (peercaps);
2272 remove_fields (pcopy, FALSE);
2273 tmp = gst_caps_intersect_full (pcopy, res, GST_CAPS_INTERSECT_FIRST);
2274 gst_caps_unref (pcopy);
Guillaume Desmottes00874852017-11-20 17:54:54 +01002275 if (!gst_caps_is_empty (tmp))
2276 res = gst_caps_merge (tmp, res);
2277 else
2278 gst_caps_unref (tmp);
2279
2280 gst_caps_unref (peercaps);
Sreerenj Balachandrand8448322013-10-09 10:54:14 +03002281 return res;
2282}
2283
2284static gboolean
2285gst_h265_parse_event (GstBaseParse * parse, GstEvent * event)
2286{
2287 gboolean res;
2288 GstH265Parse *h265parse = GST_H265_PARSE (parse);
2289
2290 switch (GST_EVENT_TYPE (event)) {
2291 case GST_EVENT_CUSTOM_DOWNSTREAM:
2292 {
2293 GstClockTime timestamp, stream_time, running_time;
2294 gboolean all_headers;
2295 guint count;
2296
2297 if (gst_video_event_is_force_key_unit (event)) {
2298 gst_video_event_parse_downstream_force_key_unit (event,
2299 &timestamp, &stream_time, &running_time, &all_headers, &count);
2300
2301 GST_INFO_OBJECT (h265parse, "received downstream force key unit event, "
2302 "seqnum %d running_time %" GST_TIME_FORMAT
2303 " all_headers %d count %d", gst_event_get_seqnum (event),
2304 GST_TIME_ARGS (running_time), all_headers, count);
2305 if (h265parse->force_key_unit_event) {
2306 GST_INFO_OBJECT (h265parse, "ignoring force key unit event "
2307 "as one is already queued");
2308 } else {
2309 h265parse->pending_key_unit_ts = running_time;
2310 gst_event_replace (&h265parse->force_key_unit_event, event);
2311 }
2312 gst_event_unref (event);
2313 res = TRUE;
2314 } else {
2315 res = GST_BASE_PARSE_CLASS (parent_class)->sink_event (parse, event);
2316 break;
2317 }
2318 break;
2319 }
2320 case GST_EVENT_FLUSH_STOP:
Nicolas Dufresnefe116092015-12-02 18:28:15 -05002321 h265parse->push_codec = TRUE;
Sreerenj Balachandrand8448322013-10-09 10:54:14 +03002322 res = GST_BASE_PARSE_CLASS (parent_class)->sink_event (parse, event);
2323 break;
2324 case GST_EVENT_SEGMENT:
2325 {
2326 res = GST_BASE_PARSE_CLASS (parent_class)->sink_event (parse, event);
2327 break;
2328 }
2329 default:
2330 res = GST_BASE_PARSE_CLASS (parent_class)->sink_event (parse, event);
2331 break;
2332 }
2333 return res;
2334}
2335
2336static gboolean
2337gst_h265_parse_src_event (GstBaseParse * parse, GstEvent * event)
2338{
2339 gboolean res;
2340 GstH265Parse *h265parse = GST_H265_PARSE (parse);
2341
2342 switch (GST_EVENT_TYPE (event)) {
2343 case GST_EVENT_CUSTOM_UPSTREAM:
2344 {
2345 GstClockTime running_time;
2346 gboolean all_headers;
2347 guint count;
2348
2349 if (gst_video_event_is_force_key_unit (event)) {
2350 gst_video_event_parse_upstream_force_key_unit (event,
2351 &running_time, &all_headers, &count);
2352
2353 GST_INFO_OBJECT (h265parse, "received upstream force-key-unit event, "
2354 "seqnum %d running_time %" GST_TIME_FORMAT
2355 " all_headers %d count %d", gst_event_get_seqnum (event),
2356 GST_TIME_ARGS (running_time), all_headers, count);
2357
2358 if (all_headers) {
2359 h265parse->pending_key_unit_ts = running_time;
2360 gst_event_replace (&h265parse->force_key_unit_event, event);
2361 }
2362 }
2363 res = GST_BASE_PARSE_CLASS (parent_class)->src_event (parse, event);
2364 break;
2365 }
2366 default:
2367 res = GST_BASE_PARSE_CLASS (parent_class)->src_event (parse, event);
2368 break;
2369 }
2370
2371 return res;
2372}
2373
2374static void
2375gst_h265_parse_set_property (GObject * object, guint prop_id,
2376 const GValue * value, GParamSpec * pspec)
2377{
2378 GstH265Parse *parse;
2379 parse = GST_H265_PARSE (object);
2380
2381 switch (prop_id) {
2382 case PROP_CONFIG_INTERVAL:
2383 parse->interval = g_value_get_uint (value);
2384 break;
2385 default:
2386 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2387 break;
2388 }
2389}
2390
2391static void
2392gst_h265_parse_get_property (GObject * object, guint prop_id, GValue * value,
2393 GParamSpec * pspec)
2394{
2395 GstH265Parse *parse;
2396 parse = GST_H265_PARSE (object);
2397
2398 switch (prop_id) {
2399 case PROP_CONFIG_INTERVAL:
2400 g_value_set_uint (value, parse->interval);
2401 break;
2402 default:
2403 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2404 break;
2405 }
2406}