summaryrefslogtreecommitdiff
path: root/gst/h264parse/gsth264parse.c
diff options
context:
space:
mode:
authorTim-Philipp Müller <tim.muller@collabora.co.uk>2012-02-08 20:09:39 +0000
committerTim-Philipp Müller <tim.muller@collabora.co.uk>2012-02-08 20:09:39 +0000
commit8765068879331b2f911d70ee88baa36c4217aec2 (patch)
tree2cce04449b09b8f82b55cb3ef889dd392a07322a /gst/h264parse/gsth264parse.c
parentde1f89bf07b2ad3244b1ece3c4c276046f7e8a09 (diff)
downloadgstreamer-plugins-bad-8765068879331b2f911d70ee88baa36c4217aec2.tar.gz
Remove legacyh264parse element
One h264 parser ought to be enough for anybody. https://bugzilla.gnome.org/show_bug.cgi?id=648002
Diffstat (limited to 'gst/h264parse/gsth264parse.c')
-rw-r--r--gst/h264parse/gsth264parse.c2743
1 files changed, 0 insertions, 2743 deletions
diff --git a/gst/h264parse/gsth264parse.c b/gst/h264parse/gsth264parse.c
deleted file mode 100644
index 90a537bb7..000000000
--- a/gst/h264parse/gsth264parse.c
+++ /dev/null
@@ -1,2743 +0,0 @@
-/* GStreamer h264 parser
- * Copyright (C) 2005 Michal Benes <michal.benes@itonis.tv>
- * (C) 2008 Wim Taymans <wim.taymans@gmail.com>
- * (C) 2009 Mark Nauwelaerts <mnauw users sf net>
- * (C) 2009 Nokia Corporation. All rights reserved.
- * Contact: Stefan Kost <stefan.kost@nokia.com>
- *
- * gsth264parse.c:
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include <stdlib.h>
-#include <string.h>
-
-#include <gst/base/gstbytewriter.h>
-
-#include "gsth264parse.h"
-
-static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
- GST_PAD_SINK,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("video/x-h264"));
-
-static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
- GST_PAD_SRC,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("video/x-h264"));
-
-GST_DEBUG_CATEGORY_STATIC (h264_parse_debug);
-#define GST_CAT_DEFAULT h264_parse_debug
-
-#define DEFAULT_SPLIT_PACKETIZED FALSE
-#define DEFAULT_ACCESS_UNIT FALSE
-#define DEFAULT_OUTPUT_FORMAT GST_H264_PARSE_FORMAT_INPUT
-#define DEFAULT_CONFIG_INTERVAL (0)
-
-enum
-{
- PROP_0,
- PROP_SPLIT_PACKETIZED,
- PROP_ACCESS_UNIT,
- PROP_CONFIG_INTERVAL,
- PROP_OUTPUT_FORMAT,
- PROP_LAST
-};
-
-enum
-{
- GST_H264_PARSE_FORMAT_SAMPLE = 0,
- GST_H264_PARSE_FORMAT_BYTE,
- GST_H264_PARSE_FORMAT_INPUT
-};
-
-#define GST_H264_PARSE_FORMAT_TYPE (gst_h264_parse_format_get_type())
-static GType
-gst_h264_parse_format_get_type (void)
-{
- static GType format_type = 0;
-
- static const GEnumValue format_types[] = {
- {GST_H264_PARSE_FORMAT_SAMPLE, "AVC Sample Format", "sample"},
- {GST_H264_PARSE_FORMAT_BYTE, "Bytestream Format", "byte"},
- {GST_H264_PARSE_FORMAT_INPUT, "Input Format", "input"},
- {0, NULL, NULL}
- };
-
- if (!format_type) {
- format_type = g_enum_register_static ("GstH264ParseFormat", format_types);
- }
- return format_type;
-}
-
-typedef enum
-{
- NAL_UNKNOWN = 0,
- NAL_SLICE = 1,
- NAL_SLICE_DPA = 2,
- NAL_SLICE_DPB = 3,
- NAL_SLICE_DPC = 4,
- NAL_SLICE_IDR = 5,
- NAL_SEI = 6,
- NAL_SPS = 7,
- NAL_PPS = 8,
- NAL_AU_DELIMITER = 9,
- NAL_SEQ_END = 10,
- NAL_STREAM_END = 11,
- NAL_FILTER_DATA = 12
-} GstNalUnitType;
-
-/* small linked list implementation to allocate the list entry and the data in
- * one go */
-struct _GstNalList
-{
- GstNalList *next;
-
- gint nal_type;
- gint nal_ref_idc;
- gint first_mb_in_slice;
- gint slice_type;
- gboolean slice;
- gboolean i_frame;
-
- GstBuffer *buffer;
-};
-
-static GstNalList *
-gst_nal_list_new (GstBuffer * buffer)
-{
- GstNalList *new_list;
-
- new_list = g_slice_new0 (GstNalList);
- new_list->buffer = buffer;
-
- return new_list;
-}
-
-static GstNalList *
-gst_nal_list_prepend_link (GstNalList * list, GstNalList * link)
-{
- link->next = list;
-
- return link;
-}
-
-static GstNalList *
-gst_nal_list_delete_head (GstNalList * list)
-{
- if (list) {
- GstNalList *old = list;
-
- list = list->next;
-
- g_slice_free (GstNalList, old);
- }
- return list;
-}
-
-/* simple bitstream parser, automatically skips over
- * emulation_prevention_three_bytes. */
-typedef struct
-{
- const guint8 *data;
- const guint8 *end;
- gint head; /* bitpos in the cache of next bit */
- guint64 cache; /* cached bytes */
-} GstNalBs;
-
-static void
-gst_nal_bs_init (GstNalBs * bs, const guint8 * data, guint size)
-{
- bs->data = data;
- bs->end = data + size;
- bs->head = 0;
- /* fill with something other than 0 to detect emulation prevention bytes */
- bs->cache = 0xffffffff;
-}
-
-static guint32
-gst_nal_bs_read (GstNalBs * bs, guint n)
-{
- guint32 res = 0;
- gint shift;
-
- if (n == 0)
- return res;
-
- /* fill up the cache if we need to */
- while (bs->head < n) {
- guint8 byte;
- gboolean check_three_byte;
-
- check_three_byte = TRUE;
- next_byte:
- if (bs->data >= bs->end) {
- /* we're at the end, can't produce more than head number of bits */
- n = bs->head;
- break;
- }
- /* get the byte, this can be an emulation_prevention_three_byte that we need
- * to ignore. */
- byte = *bs->data++;
- if (check_three_byte && byte == 0x03 && ((bs->cache & 0xffff) == 0)) {
- /* next byte goes unconditionally to the cache, even if it's 0x03 */
- check_three_byte = FALSE;
- goto next_byte;
- }
- /* shift bytes in cache, moving the head bits of the cache left */
- bs->cache = (bs->cache << 8) | byte;
- bs->head += 8;
- }
-
- /* bring the required bits down and truncate */
- if ((shift = bs->head - n) > 0)
- res = bs->cache >> shift;
- else
- res = bs->cache;
-
- /* mask out required bits */
- if (n < 32)
- res &= (1 << n) - 1;
-
- bs->head = shift;
-
- return res;
-}
-
-static gboolean
-gst_nal_bs_eos (GstNalBs * bs)
-{
- return (bs->data >= bs->end) && (bs->head == 0);
-}
-
-/* read unsigned Exp-Golomb code */
-static gint
-gst_nal_bs_read_ue (GstNalBs * bs)
-{
- gint i = 0;
-
- while (gst_nal_bs_read (bs, 1) == 0 && !gst_nal_bs_eos (bs) && i < 32)
- i++;
-
- return ((1 << i) - 1 + gst_nal_bs_read (bs, i));
-}
-
-/* read signed Exp-Golomb code */
-static gint
-gst_nal_bs_read_se (GstNalBs * bs)
-{
- gint i = 0;
-
- i = gst_nal_bs_read_ue (bs);
- /* (-1)^(i+1) Ceil (i / 2) */
- i = (i + 1) / 2 * (i & 1 ? 1 : -1);
-
- return i;
-}
-
-
-/* SEI type */
-typedef enum
-{
- SEI_BUF_PERIOD = 0,
- SEI_PIC_TIMING = 1
- /* and more... */
-} GstSeiPayloadType;
-
-/* SEI pic_struct type */
-typedef enum
-{
- SEI_PIC_STRUCT_FRAME = 0, /* 0: %frame */
- SEI_PIC_STRUCT_TOP_FIELD = 1, /* 1: top field */
- SEI_PIC_STRUCT_BOTTOM_FIELD = 2, /* 2: bottom field */
- SEI_PIC_STRUCT_TOP_BOTTOM = 3, /* 3: top field, bottom field, in that order */
- SEI_PIC_STRUCT_BOTTOM_TOP = 4, /* 4: bottom field, top field, in that order */
- SEI_PIC_STRUCT_TOP_BOTTOM_TOP = 5, /* 5: top field, bottom field, top field repeated, in that order */
- SEI_PIC_STRUCT_BOTTOM_TOP_BOTTOM = 6, /* 6: bottom field, top field, bottom field repeated, in that order */
- SEI_PIC_STRUCT_FRAME_DOUBLING = 7, /* 7: %frame doubling */
- SEI_PIC_STRUCT_FRAME_TRIPLING = 8 /* 8: %frame tripling */
-} GstSeiPicStructType;
-
-/* pic_struct to NumClockTS lookup table */
-static const guint8 sei_num_clock_ts_table[9] = {
- 1, 1, 1, 2, 2, 3, 3, 2, 3
-};
-
-#define Extended_SAR 255
-
-/* SPS: sequential parameter sets */
-struct _GstH264Sps
-{
- guint8 profile_idc;
- guint8 level_idc;
-
- guint8 sps_id;
-
- guint8 pic_order_cnt_type;
-
- guint8 log2_max_frame_num_minus4;
- gboolean frame_mbs_only_flag;
- guint8 log2_max_pic_order_cnt_lsb_minus4;
-
- gboolean frame_cropping_flag;
-
- /* VUI parameters */
- gboolean vui_parameters_present_flag;
-
- gboolean timing_info_present_flag;
- guint32 num_units_in_tick;
- guint32 time_scale;
- gboolean fixed_frame_rate_flag;
-
- gboolean nal_hrd_parameters_present_flag;
- gboolean vcl_hrd_parameters_present_flag;
- /* hrd parameters */
- guint8 cpb_cnt_minus1;
- gint initial_cpb_removal_delay_length_minus1; /* initial_cpb_removal_delay_length_minus1 */
- gint cpb_removal_delay_length_minus1; /* cpb_removal_delay_length_minus1 */
- gint dpb_output_delay_length_minus1; /* dpb_output_delay_length_minus1 */
- gboolean time_offset_length_minus1;
-
- gboolean pic_struct_present_flag;
- /* And more... */
-
- /* derived values */
- gint width, height;
-};
-/* PPS: pic parameter sets */
-struct _GstH264Pps
-{
- guint8 pps_id;
- guint8 sps_id;
-};
-
-static GstH264Sps *
-gst_h264_parse_get_sps (GstH264Parse * h, guint8 sps_id)
-{
- GstH264Sps *sps;
- g_return_val_if_fail (h != NULL, NULL);
-
- if (sps_id >= MAX_SPS_COUNT) {
- GST_DEBUG_OBJECT (h, "requested sps_id=%04x out of range", sps_id);
- return NULL;
- }
- sps = h->sps_buffers[sps_id];
- if (sps == NULL) {
- GST_DEBUG_OBJECT (h, "Creating sps with sps_id=%04x", sps_id);
- sps = h->sps_buffers[sps_id] = g_slice_new0 (GstH264Sps);
- if (sps == NULL) {
- GST_DEBUG_OBJECT (h, "Allocation failed!");
- }
- }
-
- h->sps = h->sps_buffers[sps_id] = sps;
- return sps;
-}
-
-static GstH264Pps *
-gst_h264_parse_get_pps (GstH264Parse * h, guint8 pps_id)
-{
- GstH264Pps *pps;
- g_return_val_if_fail (h != NULL, NULL);
-
- pps = h->pps_buffers[pps_id];
- if (pps == NULL) {
- GST_DEBUG_OBJECT (h, "Creating pps with pps_id=%04x", pps_id);
- pps = g_slice_new0 (GstH264Pps);
- if (pps == NULL) {
- GST_DEBUG_OBJECT (h, "Failed!");
- }
- }
-
- h->pps = h->pps_buffers[pps_id] = pps;
- return pps;
-}
-
-/* decode hrd parameters */
-static gboolean
-gst_vui_decode_hrd_parameters (GstH264Parse * h, GstNalBs * bs)
-{
- GstH264Sps *sps = h->sps;
- gint sched_sel_idx;
-
- sps->cpb_cnt_minus1 = gst_nal_bs_read_ue (bs);
- if (sps->cpb_cnt_minus1 > 31U) {
- GST_ERROR_OBJECT (h, "cpb_cnt_minus1 = %d out of range",
- sps->cpb_cnt_minus1);
- return FALSE;
- }
-
- gst_nal_bs_read (bs, 4); /* bit_rate_scale */
- gst_nal_bs_read (bs, 4); /* cpb_size_scale */
-
- for (sched_sel_idx = 0; sched_sel_idx <= sps->cpb_cnt_minus1; sched_sel_idx++) {
- gst_nal_bs_read_ue (bs); /* bit_rate_value_minus1 */
- gst_nal_bs_read_ue (bs); /* cpb_size_value_minus1 */
- gst_nal_bs_read (bs, 1); /* cbr_flag */
- }
-
- sps->initial_cpb_removal_delay_length_minus1 = gst_nal_bs_read (bs, 5);
- sps->cpb_removal_delay_length_minus1 = gst_nal_bs_read (bs, 5);
- sps->dpb_output_delay_length_minus1 = gst_nal_bs_read (bs, 5);
- sps->time_offset_length_minus1 = gst_nal_bs_read (bs, 5);
-
- return TRUE;
-}
-
-/* decode vui parameters */
-static gboolean
-gst_sps_decode_vui (GstH264Parse * h, GstNalBs * bs)
-{
- GstH264Sps *sps = h->sps;
-
- if (gst_nal_bs_read (bs, 1)) { /* aspect_ratio_info_present_flag */
- if (gst_nal_bs_read (bs, 8) == Extended_SAR) { /* aspect_ratio_idc */
- gst_nal_bs_read (bs, 16); /* sar_width */
- gst_nal_bs_read (bs, 16); /* sar_height */
- }
- }
-
- if (gst_nal_bs_read (bs, 1)) { /* overscan_info_present_flag */
- gst_nal_bs_read (bs, 1); /* overscan_appropriate_flag */
- }
-
- if (gst_nal_bs_read (bs, 1)) { /* video_signal_type_present_flag */
- gst_nal_bs_read (bs, 3); /* video_format */
- gst_nal_bs_read (bs, 1); /* video_full_range_flag */
-
- if (gst_nal_bs_read (bs, 1)) { /* colour_description_present_flag */
- gst_nal_bs_read (bs, 8); /* colour_primaries */
- gst_nal_bs_read (bs, 8); /* transfer_characteristics */
- gst_nal_bs_read (bs, 8); /* matrix_coefficients */
- }
- }
-
- if (gst_nal_bs_read (bs, 1)) { /* chroma_loc_info_present_flag */
- gst_nal_bs_read_ue (bs); /* chroma_sample_loc_type_top_field */
- gst_nal_bs_read_ue (bs); /* chroma_sample_loc_type_bottom_field */
- }
-
- /*
- GST_DEBUG_OBJECT (h,
- "aspect_ratio_info_present_flag = %d, "
- "overscan_info_present_flag = %d, "
- "video_signal_type_present_flag = %d, "
- "chroma_loc_info_present_flag = %d\n",
- sps->aspect_ratio_info_present_flag, sps->overscan_info_present_flag,
- sps->video_signal_type_present_flag, sps->chroma_loc_info_present_flag);
- */
-
- sps->timing_info_present_flag = gst_nal_bs_read (bs, 1);
- if (sps->timing_info_present_flag) {
- guint32 num_units_in_tick = gst_nal_bs_read (bs, 32);
- guint32 time_scale = gst_nal_bs_read (bs, 32);
-
- /* If any of these parameters = 0, discard all timing_info */
- if (time_scale == 0) {
- GST_WARNING_OBJECT (h,
- "time_scale = 0 detected in stream (incompliant to H.264 E.2.1)."
- " Discarding related info.");
- } else if (num_units_in_tick == 0) {
- GST_WARNING_OBJECT (h,
- "num_units_in_tick = 0 detected in stream (incompliant to H.264 E.2.1)."
- " Discarding related info.");
- } else {
- sps->num_units_in_tick = num_units_in_tick;
- sps->time_scale = time_scale;
- sps->fixed_frame_rate_flag = gst_nal_bs_read (bs, 1);
- GST_DEBUG_OBJECT (h, "timing info: dur=%d/%d fixed=%d",
- num_units_in_tick, time_scale, sps->fixed_frame_rate_flag);
- }
- }
-
- sps->nal_hrd_parameters_present_flag = gst_nal_bs_read (bs, 1);
- if (sps->nal_hrd_parameters_present_flag) {
- gst_vui_decode_hrd_parameters (h, bs);
- }
- sps->vcl_hrd_parameters_present_flag = gst_nal_bs_read (bs, 1);
- if (sps->vcl_hrd_parameters_present_flag) {
- gst_vui_decode_hrd_parameters (h, bs);
- }
- if (sps->nal_hrd_parameters_present_flag
- || sps->vcl_hrd_parameters_present_flag) {
- gst_nal_bs_read (bs, 1); /* low_delay_hrd_flag */
- }
-
- sps->pic_struct_present_flag = gst_nal_bs_read (bs, 1);
-
-
-#if 0
- /* Not going down anymore */
-
- if (gst_nal_bs_read (bs, 1)) { /* bitstream_restriction_flag */
- gst_nal_bs_read (bs, 1); /* motion_vectors_over_pic_boundaries_flag */
- gst_nal_bs_read_ue (bs); /* max_bytes_per_pic_denom */
- gst_nal_bs_read_ue (bs); /* max_bits_per_mb_denom */
- gst_nal_bs_read_ue (bs); /* log2_max_mv_length_horizontal */
- gst_nal_bs_read_ue (bs); /* log2_max_mv_length_vertical */
- gst_nal_bs_read_ue (bs); /* num_reorder_frames */
- gst_nal_bs_read_ue (bs); /* max_dec_frame_buffering */
- }
-#endif
-
- return TRUE;
-}
-
-/* decode sequential parameter sets */
-static gboolean
-gst_nal_decode_sps (GstH264Parse * h, GstNalBs * bs)
-{
- guint8 profile_idc, level_idc;
- guint8 sps_id;
- GstH264Sps *sps = NULL;
- guint subwc[] = { 1, 2, 2, 1 };
- guint subhc[] = { 1, 2, 1, 1 };
- guint chroma;
- guint fc_top, fc_bottom, fc_left, fc_right;
- gint width, height;
-
- profile_idc = gst_nal_bs_read (bs, 8);
- gst_nal_bs_read (bs, 1); /* constraint_set0_flag */
- gst_nal_bs_read (bs, 1); /* constraint_set1_flag */
- gst_nal_bs_read (bs, 1); /* constraint_set2_flag */
- gst_nal_bs_read (bs, 1); /* constraint_set3_flag */
- gst_nal_bs_read (bs, 4); /* reserved */
- level_idc = gst_nal_bs_read (bs, 8);
-
- sps_id = gst_nal_bs_read_ue (bs);
- sps = gst_h264_parse_get_sps (h, sps_id);
- if (sps == NULL) {
- return FALSE;
- }
- sps->profile_idc = profile_idc;
- sps->level_idc = level_idc;
-
- if (profile_idc == 100 || profile_idc == 110 || profile_idc == 122
- || profile_idc == 244 || profile_idc == 44 ||
- profile_idc == 83 || profile_idc == 86) {
- gint scp_flag = 0;
-
- if ((chroma = gst_nal_bs_read_ue (bs)) == 3) { /* chroma_format_idc */
- scp_flag = gst_nal_bs_read (bs, 1); /* separate_colour_plane_flag */
- }
- gst_nal_bs_read_ue (bs); /* bit_depth_luma_minus8 */
- gst_nal_bs_read_ue (bs); /* bit_depth_chroma_minus8 */
- gst_nal_bs_read (bs, 1); /* qpprime_y_zero_transform_bypass_flag */
- if (gst_nal_bs_read (bs, 1)) { /* seq_scaling_matrix_present_flag */
- gint i, j, m, d;
-
- m = (chroma != 3) ? 8 : 12;
- for (i = 0; i < m; i++) {
- /* seq_scaling_list_present_flag[i] */
- d = gst_nal_bs_read (bs, 1);
- if (d) {
- gint lastScale = 8, nextScale = 8, deltaScale;
-
- j = (i < 6) ? 16 : 64;
- for (; j > 0; j--) {
- if (nextScale != 0) {
- deltaScale = gst_nal_bs_read_se (bs);
- nextScale = (lastScale + deltaScale + 256) % 256;
- }
- if (nextScale != 0)
- lastScale = nextScale;
- }
- }
- }
- }
- if (scp_flag)
- chroma = 0;
- } else {
- /* inferred value */
- chroma = 1;
- }
-
- sps->log2_max_frame_num_minus4 = gst_nal_bs_read_ue (bs); /* between 0 and 12 */
- if (sps->log2_max_frame_num_minus4 > 12) {
- GST_DEBUG_OBJECT (h, "log2_max_frame_num_minus4 = %d out of range"
- " [0,12]", sps->log2_max_frame_num_minus4);
- return FALSE;
- }
-
- sps->pic_order_cnt_type = gst_nal_bs_read_ue (bs);
- if (sps->pic_order_cnt_type == 0) {
- sps->log2_max_pic_order_cnt_lsb_minus4 = gst_nal_bs_read_ue (bs);
- } else if (sps->pic_order_cnt_type == 1) {
- gint d;
-
- /* delta_pic_order_always_zero_flag */
- gst_nal_bs_read (bs, 1);
- /* offset_for_non_ref_pic */
- gst_nal_bs_read_ue (bs);
- /* offset_for_top_to_bottom_field */
- gst_nal_bs_read_ue (bs);
- /* num_ref_frames_in_pic_order_cnt_cycle */
- d = gst_nal_bs_read_ue (bs);
- for (; d > 0; d--) {
- /* offset_for_ref_frame[i] */
- gst_nal_bs_read_ue (bs);
- }
- }
-
- gst_nal_bs_read_ue (bs); /* max_num_ref_frames */
- gst_nal_bs_read (bs, 1); /* gaps_in_frame_num_value_allowed_flag */
- width = gst_nal_bs_read_ue (bs); /* pic_width_in_mbs_minus1 */
- height = gst_nal_bs_read_ue (bs); /* pic_height_in_map_units_minus1 */
-
- sps->frame_mbs_only_flag = gst_nal_bs_read (bs, 1);
- if (!sps->frame_mbs_only_flag) {
- gst_nal_bs_read (bs, 1); /* mb_adaptive_frame_field_flag */
- }
-
- width++;
- width *= 16;
- height++;
- height *= 16 * (2 - sps->frame_mbs_only_flag);
-
- gst_nal_bs_read (bs, 1); /* direct_8x8_inference_flag */
- if (gst_nal_bs_read (bs, 1)) { /* frame_cropping_flag */
- fc_left = gst_nal_bs_read_ue (bs); /* frame_crop_left_offset */
- fc_right = gst_nal_bs_read_ue (bs); /* frame_crop_right_offset */
- fc_top = gst_nal_bs_read_ue (bs); /* frame_crop_top_offset */
- fc_bottom = gst_nal_bs_read_ue (bs); /* frame_crop_bottom_offset */
- } else
- fc_left = fc_right = fc_top = fc_bottom = 0;
-
- GST_DEBUG_OBJECT (h, "Decoding SPS: profile_idc = %d, "
- "level_idc = %d, "
- "sps_id = %d, "
- "pic_order_cnt_type = %d, "
- "frame_mbs_only_flag = %d\n",
- sps->profile_idc,
- sps->level_idc,
- sps_id, sps->pic_order_cnt_type, sps->frame_mbs_only_flag);
-
- /* calculate width and height */
- GST_DEBUG_OBJECT (h, "initial width=%d, height=%d", width, height);
- GST_DEBUG_OBJECT (h, "crop (%d,%d)(%d,%d)",
- fc_left, fc_top, fc_right, fc_bottom);
- if (chroma > 3) {
- GST_DEBUG_OBJECT (h, "chroma=%d in SPS is out of range", chroma);
- return FALSE;
- }
- width -= (fc_left + fc_right) * subwc[chroma];
- height -=
- (fc_top + fc_bottom) * subhc[chroma] * (2 - sps->frame_mbs_only_flag);
- if (width < 0 || height < 0) {
- GST_DEBUG_OBJECT (h, "invalid width/height in SPS");
- return FALSE;
- }
- GST_DEBUG_OBJECT (h, "final width=%u, height=%u", width, height);
- sps->width = width;
- sps->height = height;
-
- sps->vui_parameters_present_flag = gst_nal_bs_read (bs, 1);
- if (sps->vui_parameters_present_flag) {
- gst_sps_decode_vui (h, bs);
- }
-
- return TRUE;
-}
-
-/* decode pic parameter set */
-static gboolean
-gst_nal_decode_pps (GstH264Parse * h, GstNalBs * bs)
-{
- gint pps_id;
- GstH264Pps *pps = NULL;
-
- pps_id = gst_nal_bs_read_ue (bs);
- if (pps_id >= MAX_PPS_COUNT) {
- GST_DEBUG_OBJECT (h, "requested pps_id=%04x out of range", pps_id);
- return FALSE;
- }
-
- pps = gst_h264_parse_get_pps (h, pps_id);
- if (pps == NULL) {
- return FALSE;
- }
- h->pps = pps;
-
- pps->sps_id = gst_nal_bs_read_ue (bs);
-
- /* not parsing the rest for the time being */
- return TRUE;
-}
-
-/* decode buffering periods */
-static gboolean
-gst_sei_decode_buffering_period (GstH264Parse * h, GstNalBs * bs)
-{
- guint8 sps_id;
- gint sched_sel_idx;
- GstH264Sps *sps;
-
- sps_id = gst_nal_bs_read_ue (bs);
- sps = gst_h264_parse_get_sps (h, sps_id);
- if (!sps)
- return FALSE;
-
- if (sps->nal_hrd_parameters_present_flag) {
- for (sched_sel_idx = 0; sched_sel_idx <= sps->cpb_cnt_minus1;
- sched_sel_idx++) {
- h->initial_cpb_removal_delay[sched_sel_idx]
- = gst_nal_bs_read (bs,
- sps->initial_cpb_removal_delay_length_minus1 + 1);
- gst_nal_bs_read (bs, sps->initial_cpb_removal_delay_length_minus1 + 1); /* initial_cpb_removal_delay_offset */
- }
- }
- if (sps->vcl_hrd_parameters_present_flag) {
- for (sched_sel_idx = 0; sched_sel_idx <= sps->cpb_cnt_minus1;
- sched_sel_idx++) {
- h->initial_cpb_removal_delay[sched_sel_idx]
- = gst_nal_bs_read (bs,
- sps->initial_cpb_removal_delay_length_minus1 + 1);
- gst_nal_bs_read (bs, sps->initial_cpb_removal_delay_length_minus1 + 1); /* initial_cpb_removal_delay_offset */
- }
- }
-#if 0
- h->ts_trn_nb = MPEGTIME_TO_GSTTIME (h->initial_cpb_removal_delay[0]); /* Assuming SchedSelIdx=0 */
-#endif
- if (h->ts_trn_nb == GST_CLOCK_TIME_NONE || h->dts == GST_CLOCK_TIME_NONE)
- h->ts_trn_nb = 0;
- else
- h->ts_trn_nb = h->dts;
-
- GST_DEBUG_OBJECT (h, "h->ts_trn_nb updated: %" GST_TIME_FORMAT,
- GST_TIME_ARGS (h->ts_trn_nb));
-
- return 0;
-}
-
-/* decode SEI picture timing message */
-static gboolean
-gst_sei_decode_picture_timing (GstH264Parse * h, GstNalBs * bs)
-{
- GstH264Sps *sps = h->sps;
-
- if (sps == NULL) {
- GST_WARNING_OBJECT (h, "h->sps=NULL; delayed decoding of picture timing "
- "info not implemented yet");
- return FALSE;
- }
-
- if (sps->nal_hrd_parameters_present_flag
- || sps->vcl_hrd_parameters_present_flag) {
- h->sei_cpb_removal_delay =
- gst_nal_bs_read (bs, sps->cpb_removal_delay_length_minus1 + 1);
- h->sei_dpb_output_delay =
- gst_nal_bs_read (bs, sps->dpb_output_delay_length_minus1 + 1);
- }
- if (sps->pic_struct_present_flag) {
- guint i, num_clock_ts;
- h->sei_pic_struct = gst_nal_bs_read (bs, 4);
- h->sei_ct_type = 0;
-
- if (h->sei_pic_struct > SEI_PIC_STRUCT_FRAME_TRIPLING)
- return FALSE;
-
- num_clock_ts = sei_num_clock_ts_table[h->sei_pic_struct];
-
- for (i = 0; i < num_clock_ts; i++) {
- if (gst_nal_bs_read (bs, 1)) { /* clock_timestamp_flag */
- guint full_timestamp_flag;
- h->sei_ct_type |= 1 << gst_nal_bs_read (bs, 2);
- gst_nal_bs_read (bs, 1); /* nuit_field_based_flag */
- gst_nal_bs_read (bs, 5); /* counting_type */
- full_timestamp_flag = gst_nal_bs_read (bs, 1);
- gst_nal_bs_read (bs, 1); /* discontinuity_flag */
- gst_nal_bs_read (bs, 1); /* cnt_dropped_flag */
- gst_nal_bs_read (bs, 8); /* n_frames */
- if (full_timestamp_flag) {
- gst_nal_bs_read (bs, 6); /* seconds_value 0..59 */
- gst_nal_bs_read (bs, 6); /* minutes_value 0..59 */
- gst_nal_bs_read (bs, 5); /* hours_value 0..23 */
- } else {
- if (gst_nal_bs_read (bs, 1)) { /* seconds_flag */
- gst_nal_bs_read (bs, 6); /* seconds_value range 0..59 */
- if (gst_nal_bs_read (bs, 1)) { /* minutes_flag */
- gst_nal_bs_read (bs, 6); /* minutes_value 0..59 */
- if (gst_nal_bs_read (bs, 1)) /* hours_flag */
- gst_nal_bs_read (bs, 5); /* hours_value 0..23 */
- }
- }
- }
- if (sps->time_offset_length_minus1 >= 0)
- gst_nal_bs_read (bs, sps->time_offset_length_minus1 + 1); /* time_offset */
- }
- }
-
- GST_DEBUG_OBJECT (h, "ct_type:%X pic_struct:%d\n", h->sei_ct_type,
- h->sei_pic_struct);
- }
- return 0;
-}
-
-/* decode supplimental enhancement information */
-static gboolean
-gst_nal_decode_sei (GstH264Parse * h, GstNalBs * bs)
-{
- guint8 tmp;
- GstSeiPayloadType payloadType = 0;
- gint8 payloadSize = 0;
-
- do {
- tmp = gst_nal_bs_read (bs, 8);
- payloadType += tmp;
- } while (tmp == 255);
- do {
- tmp = gst_nal_bs_read (bs, 8);
- payloadSize += tmp;
- } while (tmp == 255);
- GST_DEBUG_OBJECT (h,
- "SEI message received: payloadType = %d, payloadSize = %d bytes",
- payloadType, payloadSize);
-
- switch (payloadType) {
- case SEI_BUF_PERIOD:
- if (!gst_sei_decode_buffering_period (h, bs))
- return FALSE;
- break;
- case SEI_PIC_TIMING:
- /* TODO: According to H264 D2.2 Note1, it might be the case that the
- * picture timing SEI message is encountered before the corresponding SPS
- * is specified. Need to hold down the message and decode it later. */
- if (!gst_sei_decode_picture_timing (h, bs))
- return FALSE;
- break;
- default:
- GST_DEBUG_OBJECT (h, "SEI message of payloadType = %d is recieved but not"
- " parsed", payloadType);
- }
-
- return TRUE;
-}
-
-/* decode slice header */
-static gboolean
-gst_nal_decode_slice_header (GstH264Parse * h, GstNalBs * bs)
-{
- guint8 pps_id, sps_id;
- h->first_mb_in_slice = gst_nal_bs_read_ue (bs);
- h->slice_type = gst_nal_bs_read_ue (bs);
-
- pps_id = gst_nal_bs_read_ue (bs);
- h->pps = gst_h264_parse_get_pps (h, pps_id);
- if (!h->pps)
- return FALSE;
- /* FIXME: note that pps might be uninitialized */
- sps_id = h->pps->sps_id;
- h->sps = gst_h264_parse_get_sps (h, sps_id);
- if (!h->sps)
- return FALSE;
- /* FIXME: in some streams sps/pps may not be ready before the first slice
- * header. In this case it is not a good idea to _get_sps()/_pps() at this
- * point
- * TODO: scan one round beforehand for SPS/PPS before decoding slice headers?
- * */
-
- /* TODO: separate_color_plane_flag: from SPS, not implemented yet, assumed to
- * be false */
-
- h->frame_num =
- gst_nal_bs_read (bs, h->sps->log2_max_pic_order_cnt_lsb_minus4 + 4);
-
- if (!h->sps && !h->sps->frame_mbs_only_flag) {
- h->field_pic_flag = gst_nal_bs_read (bs, 1);
- if (h->field_pic_flag)
- h->bottom_field_flag = gst_nal_bs_read (bs, 1);
- }
-
- /* not parsing the rest for the time being */
- return TRUE;
-}
-
-typedef GstH264Parse GstLegacyH264Parse;
-typedef GstH264ParseClass GstLegacyH264ParseClass;
-GST_BOILERPLATE (GstLegacyH264Parse, gst_h264_parse, GstElement,
- GST_TYPE_ELEMENT);
-
-static void gst_h264_parse_reset (GstH264Parse * h264parse);
-static void gst_h264_parse_finalize (GObject * object);
-static void gst_h264_parse_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec);
-static void gst_h264_parse_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec);
-
-static GstFlowReturn gst_h264_parse_chain (GstPad * pad, GstBuffer * buf);
-static gboolean gst_h264_parse_sink_event (GstPad * pad, GstEvent * event);
-static gboolean gst_h264_parse_sink_setcaps (GstPad * pad, GstCaps * caps);
-
-static GstStateChangeReturn gst_h264_parse_change_state (GstElement * element,
- GstStateChange transition);
-
-static void
-gst_h264_parse_base_init (gpointer g_class)
-{
- GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&srctemplate));
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&sinktemplate));
- gst_element_class_set_details_simple (gstelement_class, "H264Parse",
- "Codec/Parser/Video",
- "Parses raw h264 stream",
- "Michal Benes <michal.benes@itonis.tv>,"
- "Wim Taymans <wim.taymans@gmail.com>");
-
- GST_DEBUG_CATEGORY_INIT (h264_parse_debug, "legacy h264parse", 0,
- "legacy h264 parser");
-}
-
-static void
-gst_h264_parse_class_init (GstH264ParseClass * klass)
-{
- GObjectClass *gobject_class;
- GstElementClass *gstelement_class;
-
- gobject_class = G_OBJECT_CLASS (klass);
- gstelement_class = (GstElementClass *) klass;
-
- gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_h264_parse_finalize);
- gobject_class->set_property = gst_h264_parse_set_property;
- gobject_class->get_property = gst_h264_parse_get_property;
-
- g_object_class_install_property (gobject_class, PROP_SPLIT_PACKETIZED,
- g_param_spec_boolean ("split-packetized", "Split packetized",
- "Split NAL units of packetized streams", DEFAULT_SPLIT_PACKETIZED,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, PROP_ACCESS_UNIT,
- g_param_spec_boolean ("access-unit", "Access Units",
- "Output Acess Units rather than NALUs", DEFAULT_ACCESS_UNIT,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, PROP_OUTPUT_FORMAT,
- g_param_spec_enum ("output-format", "Output Format",
- "Output Format of stream (bytestream or otherwise)",
- GST_H264_PARSE_FORMAT_TYPE, DEFAULT_OUTPUT_FORMAT,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, PROP_CONFIG_INTERVAL,
- g_param_spec_uint ("config-interval",
- "SPS PPS Send Interval",
- "Send SPS and PPS Insertion Interval in seconds (sprop parameter sets "
- "will be multiplexed in the data stream when detected.) (0 = disabled)",
- 0, 3600, DEFAULT_CONFIG_INTERVAL,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- gstelement_class->change_state = gst_h264_parse_change_state;
-}
-
-static void
-gst_h264_parse_init (GstH264Parse * h264parse, GstH264ParseClass * g_class)
-{
- h264parse->sinkpad = gst_pad_new_from_static_template (&sinktemplate, "sink");
- gst_pad_set_chain_function (h264parse->sinkpad,
- GST_DEBUG_FUNCPTR (gst_h264_parse_chain));
- gst_pad_set_event_function (h264parse->sinkpad,
- GST_DEBUG_FUNCPTR (gst_h264_parse_sink_event));
- gst_pad_set_setcaps_function (h264parse->sinkpad,
- GST_DEBUG_FUNCPTR (gst_h264_parse_sink_setcaps));
- gst_element_add_pad (GST_ELEMENT (h264parse), h264parse->sinkpad);
-
- h264parse->srcpad = gst_pad_new_from_static_template (&srctemplate, "src");
- gst_element_add_pad (GST_ELEMENT (h264parse), h264parse->srcpad);
-
- h264parse->split_packetized = DEFAULT_SPLIT_PACKETIZED;
- h264parse->adapter = gst_adapter_new ();
-
- h264parse->merge = DEFAULT_ACCESS_UNIT;
- h264parse->picture_adapter = gst_adapter_new ();
-
- h264parse->interval = DEFAULT_CONFIG_INTERVAL;
- h264parse->last_report = GST_CLOCK_TIME_NONE;
-
- h264parse->format = GST_H264_PARSE_FORMAT_INPUT;
-
- gst_h264_parse_reset (h264parse);
-}
-
-static void
-gst_h264_parse_reset (GstH264Parse * h264parse)
-{
- gint i;
- GSList *list;
-
- for (i = 0; i < MAX_SPS_COUNT; i++) {
- if (h264parse->sps_buffers[i])
- g_slice_free (GstH264Sps, h264parse->sps_buffers[i]);
- h264parse->sps_buffers[i] = NULL;
- gst_buffer_replace (&h264parse->sps_nals[i], NULL);
- }
- for (i = 0; i < MAX_PPS_COUNT; i++) {
- if (h264parse->pps_buffers[i])
- g_slice_free (GstH264Pps, h264parse->pps_buffers[i]);
- h264parse->pps_buffers[i] = NULL;
- gst_buffer_replace (&h264parse->pps_nals[i], NULL);
- }
- h264parse->sps = NULL;
- h264parse->pps = NULL;
-
- h264parse->first_mb_in_slice = -1;
- h264parse->slice_type = -1;
- h264parse->pps_id = -1;
- h264parse->frame_num = -1;
- h264parse->field_pic_flag = FALSE;
- h264parse->bottom_field_flag = FALSE;
-
- for (i = 0; i < 32; i++)
- h264parse->initial_cpb_removal_delay[i] = -1;
- h264parse->sei_cpb_removal_delay = 0;
- h264parse->sei_dpb_output_delay = 0;
- h264parse->sei_pic_struct = -1;
- h264parse->sei_ct_type = -1;
-
- h264parse->dts = GST_CLOCK_TIME_NONE;
- h264parse->ts_trn_nb = GST_CLOCK_TIME_NONE;
- h264parse->cur_duration = 0;
- h264parse->last_outbuf_dts = GST_CLOCK_TIME_NONE;
-
- list = h264parse->codec_nals;
- g_slist_foreach (list, (GFunc) gst_buffer_unref, NULL);
- g_slist_free (h264parse->codec_nals);
- h264parse->codec_nals = NULL;
- h264parse->picture_start = FALSE;
- h264parse->idr_offset = -1;
-
- if (h264parse->pending_segment)
- gst_event_unref (h264parse->pending_segment);
- h264parse->pending_segment = NULL;
-
- g_list_foreach (h264parse->pending_events, (GFunc) gst_event_unref, NULL);
- g_list_free (h264parse->pending_events);
- h264parse->pending_events = NULL;
-
- gst_caps_replace (&h264parse->src_caps, NULL);
-}
-
-static void
-gst_h264_parse_finalize (GObject * object)
-{
- GstH264Parse *h264parse;
-
- h264parse = GST_H264PARSE (object);
-
- gst_h264_parse_reset (h264parse);
-
- g_object_unref (h264parse->adapter);
- g_object_unref (h264parse->picture_adapter);
-
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static void
-gst_h264_parse_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstH264Parse *parse;
-
- parse = GST_H264PARSE (object);
-
- switch (prop_id) {
- case PROP_SPLIT_PACKETIZED:
- parse->split_packetized = g_value_get_boolean (value);
- break;
- case PROP_ACCESS_UNIT:
- parse->merge = g_value_get_boolean (value);
- break;
- case PROP_OUTPUT_FORMAT:
- parse->format = g_value_get_enum (value);
- break;
- case PROP_CONFIG_INTERVAL:
- parse->interval = g_value_get_uint (value);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-gst_h264_parse_get_property (GObject * object, guint prop_id, GValue * value,
- GParamSpec * pspec)
-{
- GstH264Parse *parse;
-
- parse = GST_H264PARSE (object);
-
- switch (prop_id) {
- case PROP_SPLIT_PACKETIZED:
- g_value_set_boolean (value, parse->split_packetized);
- break;
- case PROP_ACCESS_UNIT:
- g_value_set_boolean (value, parse->merge);
- break;
- case PROP_OUTPUT_FORMAT:
- g_value_set_enum (value, parse->format);
- break;
- case PROP_CONFIG_INTERVAL:
- g_value_set_uint (value, parse->interval);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-/* make a buffer consisting of a 4-byte start code following by
- * (a copy of) given nal data */
-static GstBuffer *
-gst_h264_parse_make_nal (GstH264Parse * h264parse, const guint8 * data,
- guint len)
-{
- GstBuffer *buf;
-
- buf = gst_buffer_new_and_alloc (4 + len);
- GST_WRITE_UINT32_BE (GST_BUFFER_DATA (buf), 1);
- memcpy (GST_BUFFER_DATA (buf) + 4, data, len);
-
- return buf;
-}
-
-/* byte together avc codec data based on collected pps and sps so far */
-static GstBuffer *
-gst_h264_parse_make_codec_data (GstH264Parse * h264parse)
-{
- GstBuffer *buf, *nal;
- gint i, sps_size = 0, pps_size = 0, num_sps = 0, num_pps = 0;
- guint8 profile_idc = 0, profile_comp = 0, level_idc = 0;
- gboolean found = FALSE;
- guint8 *data;
-
- /* sps_nals and pps_nals contain start code */
-
- for (i = 0; i < MAX_SPS_COUNT; i++) {
- if ((nal = h264parse->sps_nals[i])) {
- num_sps++;
- /* size bytes also count */
- sps_size += GST_BUFFER_SIZE (nal) - 4 + 2;
- if (GST_BUFFER_SIZE (nal) >= 8) {
- found = TRUE;
- profile_idc = (GST_BUFFER_DATA (nal))[5];
- profile_comp = (GST_BUFFER_DATA (nal))[6];
- level_idc = (GST_BUFFER_DATA (nal))[7];
- }
- }
- }
- for (i = 0; i < MAX_PPS_COUNT; i++) {
- if ((nal = h264parse->pps_nals[i])) {
- num_pps++;
- /* size bytes also count */
- pps_size += GST_BUFFER_SIZE (nal) - 4 + 2;
- }
- }
-
- GST_DEBUG_OBJECT (h264parse,
- "constructing codec_data: num_sps=%d, num_pps=%d", num_sps, num_pps);
-
- if (!found || !num_pps)
- return NULL;
-
- buf = gst_buffer_new_and_alloc (5 + 1 + sps_size + 1 + pps_size);
- data = GST_BUFFER_DATA (buf);
-
- data[0] = 1; /* AVC Decoder Configuration Record ver. 1 */
- data[1] = profile_idc; /* profile_idc */
- data[2] = profile_comp; /* profile_compability */
- data[3] = level_idc; /* level_idc */
- data[4] = 0xfc | (4 - 1); /* nal_length_size_minus1 */
- data[5] = 0xe0 | num_sps; /* number of SPSs */
-
- data += 6;
- for (i = 0; i < MAX_SPS_COUNT; i++) {
- if ((nal = h264parse->sps_nals[i])) {
- GST_WRITE_UINT16_BE (data, GST_BUFFER_SIZE (nal) - 4);
- memcpy (data + 2, GST_BUFFER_DATA (nal) + 4, GST_BUFFER_SIZE (nal) - 4);
- data += 2 + GST_BUFFER_SIZE (nal) - 4;
- }
- }
-
- data[0] = num_pps;
- data++;
- for (i = 0; i < MAX_PPS_COUNT; i++) {
- if ((nal = h264parse->pps_nals[i])) {
- GST_WRITE_UINT16_BE (data, GST_BUFFER_SIZE (nal) - 4);
- memcpy (data + 2, GST_BUFFER_DATA (nal) + 4, GST_BUFFER_SIZE (nal) - 4);
- data += 2 + GST_BUFFER_SIZE (nal) - 4;
- }
- }
-
- return buf;
-}
-
-static guint
-gst_h264_parse_parse_stream_format (GstH264Parse * h264parse,
- const gchar * stream_format)
-{
- if (strcmp (stream_format, "avc") == 0) {
- return GST_H264_PARSE_FORMAT_SAMPLE;
- } else if (strcmp (stream_format, "byte-stream") == 0) {
- return GST_H264_PARSE_FORMAT_BYTE;
- }
- return GST_H264_PARSE_FORMAT_INPUT; /* this means we don't know */
-}
-
-static gboolean
-gst_h264_parse_update_src_caps (GstH264Parse * h264parse, GstCaps * caps)
-{
- GstH264Sps *sps = NULL;
- GstCaps *src_caps = NULL;
- GstStructure *structure;
- gboolean modified = FALSE;
- const gchar *stream_format, *alignment;
-
- /* current PPS dictates which SPS to use */
- if (h264parse->pps && h264parse->pps->sps_id < MAX_SPS_COUNT) {
- sps = h264parse->sps_buffers[h264parse->pps->sps_id];
- }
- /* failing that, we'll take most recent SPS we can get */
- if (!sps) {
- sps = h264parse->sps;
- }
-
- if (G_UNLIKELY (h264parse->src_caps == NULL)) {
- src_caps = gst_caps_copy (caps);
- modified = TRUE;
- } else {
- src_caps = gst_caps_ref (h264parse->src_caps);
- }
- src_caps = gst_caps_make_writable (src_caps);
-
- g_return_val_if_fail (src_caps != NULL, FALSE);
-
- /* if some upstream metadata missing, fill in from parsed stream */
- /* width / height */
- if (sps && (sps->width > 0 && sps->height > 0) &&
- (h264parse->width != sps->width || h264parse->height != sps->height)) {
- gint width, height;
-
- width = h264parse->width = sps->width;
- height = h264parse->height = sps->height;
-
- GST_DEBUG_OBJECT (h264parse, "updating caps w/h %dx%d", width, height);
- gst_caps_set_simple (src_caps, "width", G_TYPE_INT, width,
- "height", G_TYPE_INT, height, NULL);
- modified = TRUE;
- }
-
- /* framerate */
- if (sps && (sps->time_scale > 0 && sps->num_units_in_tick > 0) &&
- (h264parse->fps_num != sps->time_scale ||
- h264parse->fps_den != sps->num_units_in_tick)) {
- gint fps_num, fps_den;
-
- fps_num = h264parse->fps_num = sps->time_scale;
- fps_den = h264parse->fps_den = sps->num_units_in_tick;
-
- /* FIXME verify / also handle other cases */
- if (sps->fixed_frame_rate_flag && sps->frame_mbs_only_flag &&
- !sps->pic_struct_present_flag) {
- fps_den *= 2; /* picture is a frame = 2 fields */
- GST_DEBUG_OBJECT (h264parse, "updating caps fps %d/%d", fps_num, fps_den);
- gst_caps_set_simple (src_caps,
- "framerate", GST_TYPE_FRACTION, fps_num, fps_den, NULL);
- modified = TRUE;
- }
- }
-
- structure = gst_caps_get_structure (src_caps, 0);
-
- /* we replace the stream-format on caps if needed */
- stream_format = gst_structure_get_string (structure, "stream-format");
- if (stream_format) {
- guint input_format;
- guint output_format;
-
- input_format = gst_h264_parse_parse_stream_format (h264parse,
- stream_format);
- output_format = h264parse->format;
-
- if (output_format == GST_H264_PARSE_FORMAT_INPUT) {
- if (h264parse->packetized) {
- output_format = GST_H264_PARSE_FORMAT_SAMPLE;
- } else {
- output_format = GST_H264_PARSE_FORMAT_BYTE;
- }
- }
-
- if (input_format != output_format) {
- /* we need to replace it */
- stream_format = NULL;
- }
- }
-
- /* we need to add a new stream-format */
- if (stream_format == NULL) {
- gst_structure_remove_field (structure, "stream-format");
- if (h264parse->format == GST_H264_PARSE_FORMAT_SAMPLE) {
- stream_format = "avc";
- } else if (h264parse->format == GST_H264_PARSE_FORMAT_BYTE) {
- stream_format = "byte-stream";
- } else {
- if (h264parse->packetized) {
- stream_format = "avc";
- } else {
- stream_format = "byte-stream";
- }
- }
- gst_structure_set (structure, "stream-format", G_TYPE_STRING, stream_format,
- NULL);
- modified = TRUE;
- }
-
- /* set alignment field */
- if (h264parse->merge) {
- alignment = "au";
- } else {
- if (h264parse->packetized) {
- if (h264parse->split_packetized)
- alignment = "nal";
- else {
- /* if packetized input is not split,
- * take upstream alignment if validly provided,
- * otherwise assume au aligned ... */
- alignment = gst_structure_get_string (structure, "alignment");
- if (!alignment || (alignment &&
- strcmp (alignment, "au") != 0 &&
- strcmp (alignment, "nal") != 0)) {
- alignment = "au";
- }
- }
- } else {
- alignment = "nal";
- }
- }
- /* now only set if changed */
- {
- const gchar *old_alignment;
-
- old_alignment = gst_structure_get_string (structure, "alignment");
- if (!old_alignment || strcmp (alignment, old_alignment) != 0) {
- gst_structure_set (structure, "alignment", G_TYPE_STRING, alignment,
- NULL);
- modified = TRUE;
- }
- }
-
- /* transforming to non-bytestream needs to make codec-data */
- if (h264parse->format == GST_H264_PARSE_FORMAT_SAMPLE) {
- GstBuffer *buf;
- const GValue *value = NULL;
- const GstBuffer *codec_data = NULL;
-
- value = gst_structure_get_value (structure, "codec_data");
- if (value != NULL)
- codec_data = gst_value_get_buffer (value);
- buf = gst_h264_parse_make_codec_data (h264parse);
- if (buf) {
- if (!codec_data || GST_BUFFER_SIZE (buf) != GST_BUFFER_SIZE (codec_data)
- || memcmp (GST_BUFFER_DATA (buf), GST_BUFFER_DATA (codec_data),
- GST_BUFFER_SIZE (buf))) {
- GST_DEBUG_OBJECT (h264parse, "setting new codec_data");
- gst_caps_set_simple (src_caps, "codec_data", GST_TYPE_BUFFER, buf,
- NULL);
- modified = TRUE;
- }
- gst_buffer_unref (buf);
- } else {
- GST_DEBUG_OBJECT (h264parse, "no codec_data yet");
- }
- } else if (h264parse->format == GST_H264_PARSE_FORMAT_BYTE) {
- /* need to remove the codec_data */
- if (gst_structure_has_field (structure, "codec_data")) {
- gst_structure_remove_field (structure, "codec_data");
- modified = TRUE;
- }
- }
-
- /* save as new caps, caps will be set when pushing data */
- /* avoid replacing caps by a mere identical copy, thereby triggering
- * negotiating (which e.g. some container might not appreciate) */
- if (modified)
- gst_caps_replace (&h264parse->src_caps, src_caps);
- gst_caps_unref (src_caps);
-
- return TRUE;
-}
-
-static gboolean
-gst_h264_parse_sink_setcaps (GstPad * pad, GstCaps * caps)
-{
- GstH264Parse *h264parse;
- GstStructure *str;
- const GValue *value;
- guint8 *data;
- guint size, num_sps, num_pps;
-
- h264parse = GST_H264PARSE (GST_PAD_PARENT (pad));
-
- str = gst_caps_get_structure (caps, 0);
-
- /* accept upstream info if provided */
- gst_structure_get_int (str, "width", &h264parse->width);
- gst_structure_get_int (str, "height", &h264parse->height);
- gst_structure_get_fraction (str, "framerate", &h264parse->fps_num,
- &h264parse->fps_den);
-
- /* packetized video has a codec_data */
- if ((value = gst_structure_get_value (str, "codec_data"))) {
- GstBuffer *buffer;
- gint profile;
- GstNalBs bs;
- gint i, len;
- GSList *nlist = NULL;
-
- GST_DEBUG_OBJECT (h264parse, "have packetized h264");
- h264parse->packetized = TRUE;
-
- buffer = gst_value_get_buffer (value);
- data = GST_BUFFER_DATA (buffer);
- size = GST_BUFFER_SIZE (buffer);
-
- /* parse the avcC data */
- if (size < 7)
- goto avcc_too_small;
- /* parse the version, this must be 1 */
- if (data[0] != 1)
- goto wrong_version;
-
- /* AVCProfileIndication */
- /* profile_compat */
- /* AVCLevelIndication */
- profile = (data[1] << 16) | (data[2] << 8) | data[3];
- GST_DEBUG_OBJECT (h264parse, "profile %06x", profile);
-
- /* 6 bits reserved | 2 bits lengthSizeMinusOne */
- /* this is the number of bytes in front of the NAL units to mark their
- * length */
- h264parse->nal_length_size = (data[4] & 0x03) + 1;
- GST_DEBUG_OBJECT (h264parse, "nal length %u", h264parse->nal_length_size);
-
- num_sps = data[5] & 0x1f;
- data += 6;
- size -= 6;
- for (i = 0; i < num_sps; i++) {
- len = GST_READ_UINT16_BE (data);
- if (size < len + 2)
- goto avcc_too_small;
- gst_nal_bs_init (&bs, data + 2 + 1, len - 1);
- gst_nal_decode_sps (h264parse, &bs);
- /* store for later use, e.g. insertion */
- if (h264parse->sps) {
- h264parse->sps_nals[h264parse->sps->sps_id] =
- gst_h264_parse_make_nal (h264parse, data + 2, len);
- }
- if (h264parse->format == GST_H264_PARSE_FORMAT_BYTE)
- nlist = g_slist_append (nlist,
- gst_h264_parse_make_nal (h264parse, data + 2, len));
- data += len + 2;
- size -= len + 2;
- }
- num_pps = data[0];
- data++;
- size++;
- for (i = 0; i < num_pps; i++) {
- len = GST_READ_UINT16_BE (data);
- if (size < len + 2)
- goto avcc_too_small;
- gst_nal_bs_init (&bs, data + 2 + 1, len - 1);
- gst_nal_decode_pps (h264parse, &bs);
- /* store for later use, e.g. insertion */
- if (h264parse->pps) {
- h264parse->pps_nals[h264parse->pps->pps_id] =
- gst_h264_parse_make_nal (h264parse, data + 2, len);
- }
- if (h264parse->format == GST_H264_PARSE_FORMAT_BYTE)
- nlist = g_slist_append (nlist,
- gst_h264_parse_make_nal (h264parse, data + 2, len));
- data += len + 2;
- size -= len + 2;
- }
- h264parse->codec_nals = nlist;
- } else {
- GST_DEBUG_OBJECT (h264parse, "have bytestream h264");
- h264parse->packetized = FALSE;
- /* we have 4 sync bytes */
- h264parse->nal_length_size = 4;
- }
-
- /* forward the caps */
- return gst_h264_parse_update_src_caps (h264parse, caps);
-
- /* ERRORS */
-avcc_too_small:
- {
- GST_ERROR_OBJECT (h264parse, "avcC size %u < 7", size);
- return FALSE;
- }
-wrong_version:
- {
- GST_ERROR_OBJECT (h264parse, "wrong avcC version");
- return FALSE;
- }
-}
-
-/* if forced output mode,
- * ensures that NALU @nal starts with start code or length
- * takes ownership of nal and returns buffer
- */
-static GstBuffer *
-gst_h264_parse_write_nal_prefix (GstH264Parse * h264parse, GstBuffer * nal)
-{
- guint nal_length = h264parse->nal_length_size;
- gint i;
-
- g_assert (nal_length <= 4);
-
- /* ensure proper transformation on prefix if needed */
- if (h264parse->format == GST_H264_PARSE_FORMAT_SAMPLE) {
- nal = gst_buffer_make_writable (nal);
- switch (nal_length) {
- case 1:
- GST_WRITE_UINT8 (GST_BUFFER_DATA (nal),
- GST_BUFFER_SIZE (nal) - nal_length);
- break;
- case 2:
- GST_WRITE_UINT16_BE (GST_BUFFER_DATA (nal),
- GST_BUFFER_SIZE (nal) - nal_length);
- break;
- case 3:
- GST_WRITE_UINT24_BE (GST_BUFFER_DATA (nal),
- GST_BUFFER_SIZE (nal) - nal_length);
- break;
- case 4:
- GST_WRITE_UINT32_BE (GST_BUFFER_DATA (nal),
- GST_BUFFER_SIZE (nal) - nal_length);
- break;
- default:
- g_assert_not_reached ();
- break;
- }
- } else if (h264parse->format == GST_H264_PARSE_FORMAT_BYTE) {
- gint offset = 0;
- guint nalu_size = 0;
-
- if (nal_length == 4) {
- nal = gst_buffer_make_writable (nal);
- while (offset + 4 <= GST_BUFFER_SIZE (nal)) {
- nalu_size = GST_READ_UINT32_BE (GST_BUFFER_DATA (nal) + offset);
- /* input may already be in byte-stream */
- if (nalu_size == 1)
- break;
- GST_WRITE_UINT32_BE (GST_BUFFER_DATA (nal) + offset, 0x01);
- offset += nalu_size + 4;
- }
- } else {
- GstAdapter *adapter = gst_adapter_new ();
- GstBuffer *sub;
- while (offset + nal_length <= GST_BUFFER_SIZE (nal)) {
- nalu_size = 0;
- for (i = 0; i < nal_length; i++)
- nalu_size = (nalu_size << 8) | GST_BUFFER_DATA (nal)[i];
- if (nalu_size > GST_BUFFER_SIZE (nal) - nal_length - offset) {
- GST_WARNING_OBJECT (h264parse, "NAL size %u is larger than buffer, "
- "reducing it to the buffer size: %u", nalu_size,
- GST_BUFFER_SIZE (nal) - nal_length - offset);
- nalu_size = GST_BUFFER_SIZE (nal) - nal_length - offset;
- }
-
- sub = gst_h264_parse_make_nal (h264parse,
- GST_BUFFER_DATA (nal) + nal_length + offset, nalu_size);
- gst_adapter_push (adapter, sub);
- offset += nalu_size + nal_length;
- }
- sub = gst_adapter_take_buffer (adapter, gst_adapter_available (adapter));
- gst_buffer_copy_metadata (sub, nal, GST_BUFFER_COPY_ALL);
- gst_buffer_unref (nal);
- nal = sub;
- g_object_unref (adapter);
- }
- }
-
- /* in any case, ensure metadata can be messed with later on */
- nal = gst_buffer_make_metadata_writable (nal);
-
- return nal;
-}
-
-/* sends a codec NAL downstream, decorating and transforming as needed.
- * No ownership is taken of @nal */
-static GstFlowReturn
-gst_h264_parse_push_codec_buffer (GstH264Parse * h264parse, GstBuffer * nal,
- GstClockTime ts)
-{
- nal = gst_buffer_copy (nal);
- nal = gst_h264_parse_write_nal_prefix (h264parse, nal);
-
- GST_BUFFER_TIMESTAMP (nal) = ts;
- GST_BUFFER_DURATION (nal) = 0;
-
- gst_buffer_set_caps (nal, h264parse->src_caps);
-
- return gst_pad_push (h264parse->srcpad, nal);
-}
-
-/* sends buffer downstream, inserting codec_data NALUs if needed */
-static GstFlowReturn
-gst_h264_parse_push_buffer (GstH264Parse * h264parse, GstBuffer * buf)
-{
- GstFlowReturn res = GST_FLOW_OK;
-
- /* We can send pending events if this is the first call, since we now have
- * caps for the srcpad */
- if (G_UNLIKELY (h264parse->pending_segment != NULL)) {
- gst_pad_push_event (h264parse->srcpad, h264parse->pending_segment);
- h264parse->pending_segment = NULL;
-
- if (G_UNLIKELY (h264parse->pending_events != NULL)) {
- GList *l;
-
- for (l = h264parse->pending_events; l != NULL; l = l->next)
- gst_pad_push_event (h264parse->srcpad, GST_EVENT (l->data));
-
- g_list_free (h264parse->pending_events);
- h264parse->pending_events = NULL;
- }
- }
-
- if (G_UNLIKELY (h264parse->width == 0 || h264parse->height == 0)) {
- GST_DEBUG ("Delaying actual push until we are configured");
- h264parse->gather = g_list_append (h264parse->gather, buf);
- goto beach;
- }
-
- if (G_UNLIKELY (h264parse->gather)) {
- GList *pendingbuffers = h264parse->gather;
- GList *tmp;
-
- GST_DEBUG ("Pushing out pending buffers");
-
- /* Yes, we're recursively calling in... */
- h264parse->gather = NULL;
- for (tmp = pendingbuffers; tmp; tmp = tmp->next) {
- res = gst_h264_parse_push_buffer (h264parse, (GstBuffer *) tmp->data);
- if (res != GST_FLOW_OK && res != GST_FLOW_NOT_LINKED)
- break;
- }
- g_list_free (pendingbuffers);
-
- if (res != GST_FLOW_OK && res != GST_FLOW_NOT_LINKED) {
- gst_buffer_unref (buf);
- goto beach;
- }
- }
-
- /* start of picture is good time to slip in codec_data NALUs
- * (when outputting NALS and transforming to bytestream) */
- if (G_UNLIKELY (h264parse->codec_nals && h264parse->picture_start)) {
- GSList *nals = h264parse->codec_nals;
- while (nals) {
- GST_DEBUG_OBJECT (h264parse, "pushing codec_nal of size %d",
- GST_BUFFER_SIZE (nals->data));
- GST_BUFFER_TIMESTAMP (nals->data) = GST_BUFFER_TIMESTAMP (buf);
- GST_BUFFER_DURATION (nals->data) = 0;
-
- gst_buffer_set_caps (nals->data, h264parse->src_caps);
- (void) gst_pad_push (h264parse->srcpad, nals->data);
- nals = g_slist_delete_link (nals, nals);
- }
- h264parse->codec_nals = NULL;
- }
-
- /* periodic SPS/PPS sending */
- if (h264parse->interval > 0) {
- gint nal_type = 0;
- guint8 *data = GST_BUFFER_DATA (buf);
- guint nal_length = h264parse->nal_length_size;
- guint64 diff;
- GstClockTime timestamp = GST_BUFFER_TIMESTAMP (buf);
-
- /* init */
- if (!GST_CLOCK_TIME_IS_VALID (h264parse->last_report)) {
- h264parse->last_report = timestamp;
- }
-
- if (!h264parse->merge) {
- nal_type = data[nal_length] & 0x1f;
- GST_LOG_OBJECT (h264parse, "- nal type: %d", nal_type);
- } else if (h264parse->idr_offset >= 0) {
- GST_LOG_OBJECT (h264parse, "AU has IDR nal at offset %d",
- h264parse->idr_offset);
- nal_type = 5;
- }
-
- /* insert on IDR */
- if (G_UNLIKELY (nal_type == 5)) {
- if (timestamp > h264parse->last_report)
- diff = timestamp - h264parse->last_report;
- else
- diff = 0;
-
- GST_LOG_OBJECT (h264parse,
- "now %" GST_TIME_FORMAT ", last SPS/PPS %" GST_TIME_FORMAT,
- GST_TIME_ARGS (timestamp), GST_TIME_ARGS (h264parse->last_report));
-
- GST_DEBUG_OBJECT (h264parse,
- "interval since last SPS/PPS %" GST_TIME_FORMAT,
- GST_TIME_ARGS (diff));
-
- if (GST_TIME_AS_SECONDS (diff) >= h264parse->interval) {
- gint i;
-
- if (!h264parse->merge) {
- /* send separate config NAL buffers */
- GST_DEBUG_OBJECT (h264parse, "- sending SPS/PPS");
- for (i = 0; i < MAX_SPS_COUNT; i++) {
- if (h264parse->sps_nals[i]) {
- GST_DEBUG_OBJECT (h264parse, "sending SPS nal");
- gst_h264_parse_push_codec_buffer (h264parse,
- h264parse->sps_nals[i], timestamp);
- h264parse->last_report = timestamp;
- }
- }
- for (i = 0; i < MAX_PPS_COUNT; i++) {
- if (h264parse->pps_nals[i]) {
- GST_DEBUG_OBJECT (h264parse, "sending PPS nal");
- gst_h264_parse_push_codec_buffer (h264parse,
- h264parse->pps_nals[i], timestamp);
- h264parse->last_report = timestamp;
- }
- }
- } else {
- /* insert config NALs into AU */
- GstByteWriter bw;
- GstBuffer *codec_nal, *new_buf;
-
- gst_byte_writer_init_with_size (&bw, GST_BUFFER_SIZE (buf), FALSE);
- gst_byte_writer_put_data (&bw, GST_BUFFER_DATA (buf),
- h264parse->idr_offset);
- GST_DEBUG_OBJECT (h264parse, "- inserting SPS/PPS");
- for (i = 0; i < MAX_SPS_COUNT; i++) {
- if (h264parse->sps_nals[i]) {
- GST_DEBUG_OBJECT (h264parse, "inserting SPS nal");
- codec_nal = gst_buffer_copy (h264parse->sps_nals[i]);
- codec_nal =
- gst_h264_parse_write_nal_prefix (h264parse, codec_nal);
- gst_byte_writer_put_data (&bw, GST_BUFFER_DATA (codec_nal),
- GST_BUFFER_SIZE (codec_nal));
- h264parse->last_report = timestamp;
- }
- }
- for (i = 0; i < MAX_PPS_COUNT; i++) {
- if (h264parse->pps_nals[i]) {
- GST_DEBUG_OBJECT (h264parse, "inserting PPS nal");
- codec_nal = gst_buffer_copy (h264parse->pps_nals[i]);
- codec_nal =
- gst_h264_parse_write_nal_prefix (h264parse, codec_nal);
- gst_byte_writer_put_data (&bw, GST_BUFFER_DATA (codec_nal),
- GST_BUFFER_SIZE (codec_nal));
- h264parse->last_report = timestamp;
- }
- }
- gst_byte_writer_put_data (&bw,
- GST_BUFFER_DATA (buf) + h264parse->idr_offset,
- GST_BUFFER_SIZE (buf) - h264parse->idr_offset);
- /* collect result and push */
- new_buf = gst_byte_writer_reset_and_get_buffer (&bw);
- gst_buffer_copy_metadata (new_buf, buf, GST_BUFFER_COPY_ALL);
- gst_buffer_unref (buf);
- buf = new_buf;
- }
- }
- }
- }
-
- gst_buffer_set_caps (buf, h264parse->src_caps);
- res = gst_pad_push (h264parse->srcpad, buf);
-
-beach:
- return res;
-}
-
-/* takes over ownership of nal and returns fresh buffer */
-static GstBuffer *
-gst_h264_parse_push_nal (GstH264Parse * h264parse, GstBuffer * nal,
- guint8 * next_nal, gboolean * _start)
-{
- gint nal_type;
- guint8 *data;
- GstBuffer *outbuf = NULL;
- guint outsize, size, nal_length = h264parse->nal_length_size;
- gboolean start;
- gboolean complete;
-
- data = GST_BUFFER_DATA (nal);
- size = GST_BUFFER_SIZE (nal);
-
- /* deal with 3-byte start code by normalizing to 4-byte here */
- if (!h264parse->packetized && data[2] == 0x01) {
- GstBuffer *tmp;
-
- /* ouch, copy */
- GST_DEBUG_OBJECT (h264parse, "replacing 3-byte startcode");
- tmp = gst_buffer_new_and_alloc (1);
- GST_BUFFER_DATA (tmp)[0] = 0;
- gst_buffer_ref (nal);
- tmp = gst_buffer_join (tmp, nal);
- GST_BUFFER_TIMESTAMP (tmp) = GST_BUFFER_TIMESTAMP (nal);
- gst_buffer_unref (nal);
- nal = tmp;
-
- data = GST_BUFFER_DATA (nal);
- size = GST_BUFFER_SIZE (nal);
- }
-
- /* caller ensures number of bytes available */
- g_return_val_if_fail (size >= nal_length + 1, NULL);
-
- /* determine if AU complete */
- nal_type = data[nal_length] & 0x1f;
- GST_LOG_OBJECT (h264parse, "nal type: %d", nal_type);
- h264parse->picture_start |= (nal_type == 1 || nal_type == 2 || nal_type == 5);
- /* first_mb_in_slice == 0 considered start of frame */
- start = h264parse->picture_start && (data[nal_length + 1] & 0x80);
- if (G_UNLIKELY (!next_nal)) {
- complete = TRUE;
- } else {
- /* consider a coded slices (IDR or not) to start a picture,
- * (so ending the previous one) if first_mb_in_slice == 0
- * (non-0 is part of previous one) */
- /* NOTE this is not entirely according to Access Unit specs in 7.4.1.2.4,
- * but in practice it works in sane cases, needs not much parsing,
- * and also works with broken frame_num in NAL
- * (where spec-wise would fail) */
- nal_type = next_nal[nal_length] & 0x1f;
- GST_LOG_OBJECT (h264parse, "next nal type: %d", nal_type);
- complete = h264parse->picture_start && (nal_type >= 6 && nal_type <= 9);
- complete |= h264parse->picture_start &&
- (nal_type == 1 || nal_type == 2 || nal_type == 5) &&
- (next_nal[nal_length + 1] & 0x80);
- }
-
- /* collect SPS and PPS NALUs to make up codec_data, if so needed */
- nal_type = data[nal_length] & 0x1f;
- if (G_UNLIKELY (nal_type == NAL_SPS)) {
- GstNalBs bs;
- guint id;
-
- gst_nal_bs_init (&bs, data + nal_length + 1, size - nal_length - 1);
- gst_nal_bs_read (&bs, 24); /* profile_idc, profile_compatibility, level_idc */
- id = gst_nal_bs_read_ue (&bs);
- if (!gst_nal_bs_eos (&bs) && id < MAX_SPS_COUNT) {
- GST_DEBUG_OBJECT (h264parse, "storing SPS id %d", id);
- gst_buffer_replace (&h264parse->sps_nals[id], NULL);
- h264parse->sps_nals[id] =
- gst_h264_parse_make_nal (h264parse, data + nal_length,
- size - nal_length);
- gst_h264_parse_update_src_caps (h264parse, NULL);
- }
- } else if (G_UNLIKELY (nal_type == NAL_PPS)) {
- GstNalBs bs;
- guint id;
-
- gst_nal_bs_init (&bs, data + nal_length + 1, size - nal_length - 1);
- id = gst_nal_bs_read_ue (&bs);
- if (!gst_nal_bs_eos (&bs) && id < MAX_PPS_COUNT) {
- GST_DEBUG_OBJECT (h264parse, "storing PPS id %d", id);
- gst_buffer_replace (&h264parse->pps_nals[id], NULL);
- h264parse->pps_nals[id] =
- gst_h264_parse_make_nal (h264parse, data + nal_length,
- size - nal_length);
- gst_h264_parse_update_src_caps (h264parse, NULL);
- }
- }
-
- if (h264parse->merge) {
- /* clear IDR mark state */
- if (gst_adapter_available (h264parse->picture_adapter) == 0)
- h264parse->idr_offset = -1;
-
- /* proper prefix */
- nal = gst_h264_parse_write_nal_prefix (h264parse, nal);
-
- /* start of a picture is a good time to insert codec SPS and PPS */
- if (G_UNLIKELY (h264parse->codec_nals && h264parse->picture_start)) {
- while (h264parse->codec_nals) {
- GST_DEBUG_OBJECT (h264parse, "inserting codec_nal of size %d into AU",
- GST_BUFFER_SIZE (h264parse->codec_nals->data));
- gst_adapter_push (h264parse->picture_adapter,
- h264parse->codec_nals->data);
- h264parse->codec_nals =
- g_slist_delete_link (h264parse->codec_nals, h264parse->codec_nals);
- }
- }
-
- /* mark IDR nal location for later possible config insertion */
- if (nal_type == 5 && h264parse->idr_offset < 0)
- h264parse->idr_offset =
- gst_adapter_available (h264parse->picture_adapter);
-
- /* regardless, collect this NALU */
- gst_adapter_push (h264parse->picture_adapter, nal);
-
- if (complete) {
- GstClockTime ts;
-
- h264parse->picture_start = FALSE;
- ts = gst_adapter_prev_timestamp (h264parse->picture_adapter, NULL);
- outsize = gst_adapter_available (h264parse->picture_adapter);
- outbuf = gst_adapter_take_buffer (h264parse->picture_adapter, outsize);
- outbuf = gst_buffer_make_metadata_writable (outbuf);
- GST_BUFFER_TIMESTAMP (outbuf) = ts;
-
- /* AU always starts a frame */
- start = TRUE;
- }
- } else {
- outbuf = gst_h264_parse_write_nal_prefix (h264parse, nal);
- }
-
- if (_start)
- *_start = start;
-
- return outbuf;
-}
-
-static void
-gst_h264_parse_clear_queues (GstH264Parse * h264parse)
-{
- g_list_foreach (h264parse->gather, (GFunc) gst_mini_object_unref, NULL);
- g_list_free (h264parse->gather);
- h264parse->gather = NULL;
- while (h264parse->decode) {
- gst_buffer_unref (h264parse->decode->buffer);
- h264parse->decode = gst_nal_list_delete_head (h264parse->decode);
- }
- h264parse->decode = NULL;
- h264parse->decode_len = 0;
- if (h264parse->prev) {
- gst_buffer_unref (h264parse->prev);
- h264parse->prev = NULL;
- }
- gst_adapter_clear (h264parse->adapter);
- h264parse->have_i_frame = FALSE;
- gst_adapter_clear (h264parse->picture_adapter);
- h264parse->picture_start = FALSE;
-}
-
-static GstFlowReturn
-gst_h264_parse_chain_forward (GstH264Parse * h264parse, gboolean discont,
- GstBuffer * buffer)
-{
- GstFlowReturn res = GST_FLOW_OK;
- const guint8 *data;
-
- if (discont) {
- gst_adapter_clear (h264parse->adapter);
- h264parse->discont = TRUE;
- }
-
- gst_adapter_push (h264parse->adapter, buffer);
-
- while (res == GST_FLOW_OK) {
- gint i;
- gint next_nalu_pos = -1;
- gint avail;
- gboolean delta_unit = FALSE;
- gboolean got_frame = FALSE;
-
- avail = gst_adapter_available (h264parse->adapter);
- if (avail < h264parse->nal_length_size + 2)
- break;
- data = gst_adapter_peek (h264parse->adapter, avail);
-
- if (!h264parse->packetized) {
- /* Bytestream format, first 3/4 bytes are sync code */
- /* re-sync; locate initial startcode */
- if (G_UNLIKELY (h264parse->discont)) {
- guint32 value;
-
- /* check for initial 00 00 01 */
- i = gst_adapter_masked_scan_uint32 (h264parse->adapter, 0xffffff00,
- 0x00000100, 0, 4);
- if (i < 0) {
- i = gst_adapter_masked_scan_uint32_peek (h264parse->adapter,
- 0x00ffffff, 0x01, 0, avail, &value);
- if (i < 0) {
- /* no sync code, flush and try next time */
- gst_adapter_flush (h264parse->adapter, avail - 2);
- break;
- } else {
- if (value >> 24 != 00)
- /* so a 3 byte startcode */
- i++;
- gst_adapter_flush (h264parse->adapter, i);
- avail -= i;
- data = gst_adapter_peek (h264parse->adapter, avail);
- }
- }
- GST_DEBUG_OBJECT (h264parse, "re-sync found startcode at %d", i);
- }
- /* Find next NALU header, might be 3 or 4 bytes */
- for (i = 1; i < avail - 4; ++i) {
- if (data[i + 1] == 0 && data[i + 2] == 0 && data[i + 3] == 1) {
- if (data[i + 0] == 0)
- next_nalu_pos = i;
- else
- next_nalu_pos = i + 1;
- break;
- }
- }
- /* skip sync */
- if (data[2] == 0x1) {
- data += 3;
- avail -= 3;
- } else {
- data += 4;
- avail -= 4;
- }
- } else {
- guint32 nalu_size;
-
- nalu_size = 0;
- for (i = 0; i < h264parse->nal_length_size; i++)
- nalu_size = (nalu_size << 8) | data[i];
-
- GST_LOG_OBJECT (h264parse, "got NALU size %u", nalu_size);
-
- /* check for invalid NALU sizes, assume the size if the available bytes
- * when something is fishy */
- if (nalu_size <= 1 || nalu_size + h264parse->nal_length_size > avail) {
- nalu_size = avail - h264parse->nal_length_size;
- GST_DEBUG_OBJECT (h264parse, "fixing invalid NALU size to %u",
- nalu_size);
- }
-
- /* Packetized format, see if we have to split it, usually splitting is not
- * a good idea as decoders have no way of handling it. */
- if (h264parse->split_packetized) {
- if (nalu_size + h264parse->nal_length_size <= avail)
- next_nalu_pos = nalu_size + h264parse->nal_length_size;
- } else {
- next_nalu_pos = avail;
- }
- /* skip nalu_size bytes */
- data += h264parse->nal_length_size;
- avail -= h264parse->nal_length_size;
- }
-
- /* Figure out if this is a delta unit */
- {
- GstNalUnitType nal_type;
- gint nal_ref_idc;
- GstNalBs bs;
-
- nal_type = (data[0] & 0x1f);
- nal_ref_idc = (data[0] & 0x60) >> 5;
-
- GST_DEBUG_OBJECT (h264parse, "NAL type: %d, ref_idc: %d", nal_type,
- nal_ref_idc);
-
- gst_nal_bs_init (&bs, data + 1, avail - 1);
-
- /* first parse some things needed to get to the frame type */
- switch (nal_type) {
- case NAL_SLICE:
- case NAL_SLICE_DPA:
- case NAL_SLICE_DPB:
- case NAL_SLICE_DPC:
- case NAL_SLICE_IDR:
- {
- gint first_mb_in_slice, slice_type;
-
- gst_nal_decode_slice_header (h264parse, &bs);
- first_mb_in_slice = h264parse->first_mb_in_slice;
- slice_type = h264parse->slice_type;
-
- GST_DEBUG_OBJECT (h264parse, "first MB: %d, slice type: %d",
- first_mb_in_slice, slice_type);
-
- switch (slice_type) {
- case 0:
- case 5:
- case 3:
- case 8: /* SP */
- /* P frames */
- GST_DEBUG_OBJECT (h264parse, "we have a P slice");
- delta_unit = TRUE;
- break;
- case 1:
- case 6:
- /* B frames */
- GST_DEBUG_OBJECT (h264parse, "we have a B slice");
- delta_unit = TRUE;
- break;
- case 2:
- case 7:
- case 4:
- case 9:
- /* I frames */
- GST_DEBUG_OBJECT (h264parse, "we have an I slice");
- got_frame = TRUE;
- break;
- }
- break;
-
- }
- case NAL_SEI:
- GST_DEBUG_OBJECT (h264parse, "we have an SEI NAL");
- gst_nal_decode_sei (h264parse, &bs);
- break;
- case NAL_SPS:
- GST_DEBUG_OBJECT (h264parse, "we have an SPS NAL");
- gst_nal_decode_sps (h264parse, &bs);
- break;
- case NAL_PPS:
- GST_DEBUG_OBJECT (h264parse, "we have a PPS NAL");
- gst_nal_decode_pps (h264parse, &bs);
- break;
- case NAL_AU_DELIMITER:
- GST_DEBUG_OBJECT (h264parse, "we have an access unit delimiter.");
- break;
- default:
- GST_DEBUG_OBJECT (h264parse,
- "NAL of nal_type = %d encountered but not parsed", nal_type);
- }
- }
-
- /* we have a packet */
- if (next_nalu_pos > 0) {
- GstBuffer *outbuf;
- GstClockTime outbuf_dts = GST_CLOCK_TIME_NONE;
- gboolean start;
- guint8 *next_data;
-
- outbuf_dts = gst_adapter_prev_timestamp (h264parse->adapter, NULL); /* Better value for the second parameter? */
- outbuf = gst_adapter_take_buffer (h264parse->adapter, next_nalu_pos);
-
- /* packetized will have no next data, which serves fine here */
- next_data = (guint8 *) gst_adapter_peek (h264parse->adapter, 6);
- outbuf = gst_h264_parse_push_nal (h264parse, outbuf, next_data, &start);
- if (!outbuf) {
- /* no complete unit yet, go for next round */
- continue;
- }
-
- /* Ignore upstream dts that stalls or goes backward. Upstream elements
- * like filesrc would keep on writing timestamp=0. XXX: is this correct?
- * TODO: better way to detect whether upstream timstamps are useful */
- if (h264parse->last_outbuf_dts != GST_CLOCK_TIME_NONE
- && outbuf_dts != GST_CLOCK_TIME_NONE
- && outbuf_dts <= h264parse->last_outbuf_dts)
- outbuf_dts = GST_CLOCK_TIME_NONE;
-
- if ((got_frame || delta_unit) && start) {
- GstH264Sps *sps = h264parse->sps;
- gint duration = 1;
-
- if (!sps) {
- GST_DEBUG_OBJECT (h264parse, "referred SPS invalid");
- goto TIMESTAMP_FINISH;
- } else if (!sps->timing_info_present_flag) {
- GST_DEBUG_OBJECT (h264parse,
- "unable to compute timestamp: timing info not present");
- goto TIMESTAMP_FINISH;
- } else if (sps->time_scale == 0) {
- GST_DEBUG_OBJECT (h264parse,
- "unable to compute timestamp: time_scale = 0 "
- "(this is forbidden in spec; bitstream probably contains error)");
- goto TIMESTAMP_FINISH;
- }
-
- if (sps->pic_struct_present_flag
- && h264parse->sei_pic_struct != (guint8) - 1) {
- /* Note that when h264parse->sei_pic_struct == -1 (unspecified), there
- * are ways to infer its value. This is related to computing the
- * TopFieldOrderCnt and BottomFieldOrderCnt, which looks
- * complicated and thus not implemented for the time being. Yet
- * the value we have here is correct for many applications
- */
- switch (h264parse->sei_pic_struct) {
- case SEI_PIC_STRUCT_TOP_FIELD:
- case SEI_PIC_STRUCT_BOTTOM_FIELD:
- duration = 1;
- break;
- case SEI_PIC_STRUCT_FRAME:
- case SEI_PIC_STRUCT_TOP_BOTTOM:
- case SEI_PIC_STRUCT_BOTTOM_TOP:
- duration = 2;
- break;
- case SEI_PIC_STRUCT_TOP_BOTTOM_TOP:
- case SEI_PIC_STRUCT_BOTTOM_TOP_BOTTOM:
- duration = 3;
- break;
- case SEI_PIC_STRUCT_FRAME_DOUBLING:
- duration = 4;
- break;
- case SEI_PIC_STRUCT_FRAME_TRIPLING:
- duration = 6;
- break;
- default:
- GST_DEBUG_OBJECT (h264parse,
- "h264parse->sei_pic_struct of unknown value %d. Not parsed",
- h264parse->sei_pic_struct);
- }
- } else {
- duration = h264parse->field_pic_flag ? 1 : 2;
- }
-
- /*
- * h264parse.264 C.1.2 Timing of coded picture removal (equivalent to DTS):
- * Tr,n(0) = initial_cpb_removal_delay[ SchedSelIdx ] / 90000
- * Tr,n(n) = Tr,n(nb) + Tc * cpb_removal_delay(n)
- * where
- * Tc = num_units_in_tick / time_scale
- */
-
- if (h264parse->ts_trn_nb != GST_CLOCK_TIME_NONE) {
- /* buffering period is present */
- if (outbuf_dts != GST_CLOCK_TIME_NONE) {
- /* If upstream timestamp is valid, we respect it and adjust current
- * reference point */
- h264parse->ts_trn_nb = outbuf_dts -
- (GstClockTime) gst_util_uint64_scale_int
- (h264parse->sei_cpb_removal_delay * GST_SECOND,
- sps->num_units_in_tick, sps->time_scale);
- } else {
- /* If no upstream timestamp is given, we write in new timestamp */
- h264parse->dts = h264parse->ts_trn_nb +
- (GstClockTime) gst_util_uint64_scale_int
- (h264parse->sei_cpb_removal_delay * GST_SECOND,
- sps->num_units_in_tick, sps->time_scale);
- }
- } else {
- /* naive method: no removal delay specified, use best guess (add prev
- * frame duration) */
- if (outbuf_dts != GST_CLOCK_TIME_NONE)
- h264parse->dts = outbuf_dts;
- else if (h264parse->dts != GST_CLOCK_TIME_NONE)
- h264parse->dts += (GstClockTime)
- gst_util_uint64_scale_int (h264parse->cur_duration * GST_SECOND,
- sps->num_units_in_tick, sps->time_scale);
- else
- h264parse->dts = 0; /* initialization */
-
- /* TODO: better approach: construct a buffer queue and put all these
- * NALs into the buffer. Wait until we are able to get any valid dts
- * or such like, and dump the buffer and estimate the timestamps of
- * the NALs by their duration.
- */
- }
-
- h264parse->cur_duration = duration;
- h264parse->frame_cnt += 1;
- if (outbuf_dts != GST_CLOCK_TIME_NONE)
- h264parse->last_outbuf_dts = outbuf_dts;
- }
-
- if (outbuf_dts == GST_CLOCK_TIME_NONE)
- outbuf_dts = h264parse->dts;
- else
- h264parse->dts = outbuf_dts;
-
- TIMESTAMP_FINISH:
- GST_BUFFER_TIMESTAMP (outbuf) = outbuf_dts;
-
- GST_DEBUG_OBJECT (h264parse,
- "pushing buffer %p, size %u, ts %" GST_TIME_FORMAT, outbuf,
- next_nalu_pos, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
-
- if (h264parse->discont) {
- GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
- h264parse->discont = FALSE;
- }
-
- if (delta_unit)
- GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
- else
- GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
-
- res = gst_h264_parse_push_buffer (h264parse, outbuf);
- } else {
- /* NALU can not be parsed yet, we wait for more data in the adapter. */
- break;
- }
- }
- return res;
-}
-
-static GstFlowReturn
-gst_h264_parse_flush_decode (GstH264Parse * h264parse)
-{
- GstFlowReturn res = GST_FLOW_OK;
- gboolean first = TRUE;
-
- while (h264parse->decode) {
- GstNalList *link;
- GstBuffer *buf;
-
- link = h264parse->decode;
- buf = link->buffer;
-
- h264parse->decode = gst_nal_list_delete_head (h264parse->decode);
- h264parse->decode_len--;
-
- GST_DEBUG_OBJECT (h264parse, "have type: %d, I frame: %d", link->nal_type,
- link->i_frame);
-
- buf = gst_h264_parse_push_nal (h264parse, buf,
- h264parse->decode ? GST_BUFFER_DATA (h264parse->decode->buffer) : NULL,
- NULL);
- if (!buf)
- continue;
-
- if (first) {
- /* first buffer has discont */
- GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
- first = FALSE;
- } else {
- /* next buffers are not discont */
- GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
- }
-
- if (link->i_frame)
- GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
- else
- GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
-
- GST_DEBUG_OBJECT (h264parse, "pushing buffer %p, ts %" GST_TIME_FORMAT,
- buf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
-
- gst_buffer_set_caps (buf, h264parse->src_caps);
- res = gst_pad_push (h264parse->srcpad, buf);
-
- }
- /* the i frame is gone now */
- h264parse->have_i_frame = FALSE;
-
- return res;
-}
-
-/* check that the decode queue contains a valid sync code that should be pushed
- * out before adding @buffer to the decode queue */
-static GstFlowReturn
-gst_h264_parse_queue_buffer (GstH264Parse * parse, GstBuffer * buffer)
-{
- guint8 *data;
- guint size;
- guint32 nalu_size;
- GstNalBs bs;
- GstNalList *link;
- GstFlowReturn res = GST_FLOW_OK;
- GstClockTime timestamp;
-
- /* create new NALU link */
- link = gst_nal_list_new (buffer);
-
- /* first parse the buffer */
- data = GST_BUFFER_DATA (buffer);
- size = GST_BUFFER_SIZE (buffer);
- timestamp = GST_BUFFER_TIMESTAMP (buffer);
-
- link->slice = FALSE;
- link->i_frame = FALSE;
-
- GST_DEBUG_OBJECT (parse,
- "analyse buffer of size %u, timestamp %" GST_TIME_FORMAT, size,
- GST_TIME_ARGS (timestamp));
-
- /* now parse all the NAL units in this buffer, for bytestream we only have one
- * NAL unit but for packetized streams we can have multiple ones */
- while (size >= parse->nal_length_size + 1) {
- gint i;
-
- nalu_size = 0;
- if (parse->packetized) {
- for (i = 0; i < parse->nal_length_size; i++)
- nalu_size = (nalu_size << 8) | data[i];
- }
-
- /* skip nalu_size or sync bytes */
- data += parse->nal_length_size;
- size -= parse->nal_length_size;
-
- link->nal_ref_idc = (data[0] & 0x60) >> 5;
- link->nal_type = (data[0] & 0x1f);
-
- /* nalu_size is 0 for bytestream, we have a complete packet */
- GST_DEBUG_OBJECT (parse, "size: %u, NAL type: %d, ref_idc: %d",
- nalu_size, link->nal_type, link->nal_ref_idc);
-
- /* first parse some things needed to get to the frame type */
- if (link->nal_type >= NAL_SLICE && link->nal_type <= NAL_SLICE_IDR) {
- gst_nal_bs_init (&bs, data + 1, size - 1);
-
- link->first_mb_in_slice = gst_nal_bs_read_ue (&bs);
- link->slice_type = gst_nal_bs_read_ue (&bs);
- link->slice = TRUE;
-
- GST_DEBUG_OBJECT (parse, "first MB: %d, slice type: %d",
- link->first_mb_in_slice, link->slice_type);
-
- switch (link->slice_type) {
- case 0:
- case 5:
- case 3:
- case 8: /* SP */
- /* P frames */
- GST_DEBUG_OBJECT (parse, "we have a P slice");
- break;
- case 1:
- case 6:
- /* B frames */
- GST_DEBUG_OBJECT (parse, "we have a B slice");
- break;
- case 2:
- case 7:
- case 4:
- case 9:
- /* I frames */
- GST_DEBUG_OBJECT (parse, "we have an I slice");
- link->i_frame = TRUE;
- break;
- }
- }
- /* bytestream, we can exit now */
- if (!parse->packetized)
- break;
-
- /* packetized format, continue parsing all packets, skip size, we already
- * skipped the nal_length_size bytes */
- data += nalu_size;
- size -= nalu_size;
- }
-
- /* we have an I frame in the queue, this new NAL unit is a slice but not
- * an I frame, output the decode queue */
- GST_DEBUG_OBJECT (parse, "have_I_frame: %d, I_frame: %d, slice: %d",
- parse->have_i_frame, link->i_frame, link->slice);
- if (parse->have_i_frame && !link->i_frame && link->slice) {
- GST_DEBUG_OBJECT (parse, "flushing decode queue");
- res = gst_h264_parse_flush_decode (parse);
- }
- if (link->i_frame)
- /* we're going to add a new I-frame in the queue */
- parse->have_i_frame = TRUE;
-
- parse->decode = gst_nal_list_prepend_link (parse->decode, link);
- parse->decode_len++;
- GST_DEBUG_OBJECT (parse,
- "copied %d bytes of NAL to decode queue. queue size %d", size,
- parse->decode_len);
-
- return res;
-}
-
-static guint
-gst_h264_parse_find_start_reverse (GstH264Parse * parse, guint8 * data,
- guint size, guint32 * code)
-{
- guint32 search = *code;
-
- while (size > 0) {
- /* the sync code is kept in reverse */
- search = (search << 8) | (data[size - 1]);
- if (search == 0x01000000)
- break;
-
- size--;
- }
- *code = search;
-
- return size - 1;
-}
-
-static GstFlowReturn
-gst_h264_parse_chain_reverse (GstH264Parse * h264parse, gboolean discont,
- GstBuffer * buffer)
-{
- GstFlowReturn res = GST_FLOW_OK;
- GstBuffer *gbuf = NULL;
-
- /* if we have a discont, move buffers to the decode list */
- if (G_UNLIKELY (discont)) {
- guint start, last;
- guint32 code;
- GstBuffer *prev;
- GstClockTime timestamp;
-
- GST_DEBUG_OBJECT (h264parse,
- "received discont, copy gathered buffers for decoding");
-
- /* init start code accumulator */
- prev = h264parse->prev;
- h264parse->prev = NULL;
-
- while (h264parse->gather) {
- guint8 *data;
-
- /* get new buffer and init the start code search to the end position */
- if (gbuf != NULL)
- gst_buffer_unref (gbuf);
- gbuf = GST_BUFFER_CAST (h264parse->gather->data);
-
- /* remove from the gather list, they are in reverse order */
- h264parse->gather =
- g_list_delete_link (h264parse->gather, h264parse->gather);
-
- if (h264parse->packetized) {
- /* packetized the packets are already split, we can just parse and
- * store them */
- GST_DEBUG_OBJECT (h264parse, "copied packetized buffer");
- res = gst_h264_parse_queue_buffer (h264parse, gbuf);
- gbuf = NULL;
- } else {
- /* bytestream, we have to split the NALUs on the sync markers */
- code = 0xffffffff;
- if (prev) {
- /* if we have a previous buffer or a leftover, merge them together
- * now */
- GST_DEBUG_OBJECT (h264parse, "merging previous buffer");
- gbuf = gst_buffer_join (gbuf, prev);
- prev = NULL;
- }
-
- last = GST_BUFFER_SIZE (gbuf);
- data = GST_BUFFER_DATA (gbuf);
- timestamp = GST_BUFFER_TIMESTAMP (gbuf);
-
- GST_DEBUG_OBJECT (h264parse,
- "buffer size: %u, timestamp %" GST_TIME_FORMAT, last,
- GST_TIME_ARGS (timestamp));
-
- while (last > 0) {
- GST_DEBUG_OBJECT (h264parse, "scan from %u", last);
- /* find a start code searching backwards in this buffer */
- start =
- gst_h264_parse_find_start_reverse (h264parse, data, last, &code);
- if (start != -1) {
- GstBuffer *decode;
-
- GST_DEBUG_OBJECT (h264parse, "found start code at %u", start);
-
- /* we found a start code, copy everything starting from it to the
- * decode queue. */
- decode = gst_buffer_create_sub (gbuf, start, last - start);
-
- GST_BUFFER_TIMESTAMP (decode) = timestamp;
-
- /* see what we have here */
- res = gst_h264_parse_queue_buffer (h264parse, decode);
-
- last = start;
- } else {
- /* no start code found, keep the buffer and merge with potential next
- * buffer. */
- GST_DEBUG_OBJECT (h264parse, "no start code, keeping buffer to %u",
- last);
- prev = gst_buffer_create_sub (gbuf, 0, last);
- gst_buffer_unref (gbuf);
- gbuf = NULL;
- break;
- }
- }
- }
- }
- if (prev) {
- GST_DEBUG_OBJECT (h264parse, "keeping buffer");
- h264parse->prev = prev;
- }
- }
- if (buffer) {
- /* add buffer to gather queue */
- GST_DEBUG_OBJECT (h264parse, "gathering buffer %p, size %u", buffer,
- GST_BUFFER_SIZE (buffer));
- h264parse->gather = g_list_prepend (h264parse->gather, buffer);
- }
-
- if (gbuf) {
- gst_buffer_unref (gbuf);
- gbuf = NULL;
- }
-
- return res;
-}
-
-static GstFlowReturn
-gst_h264_parse_chain (GstPad * pad, GstBuffer * buffer)
-{
- GstFlowReturn res;
- GstH264Parse *h264parse;
- gboolean discont;
- GstCaps *caps;
-
- h264parse = GST_H264PARSE (GST_PAD_PARENT (pad));
-
- if (!h264parse->src_caps) {
- /* Set default caps if the sink caps were not negotiated, this is when we
- * are reading from a file or so */
- caps = gst_caps_new_simple ("video/x-h264", NULL);
-
- /* we assume the bytestream format. If the data turns out to be packetized,
- * we have a problem because we don't know the length of the nalu_size
- * indicator. Packetized input MUST set the codec_data. */
- h264parse->packetized = FALSE;
- h264parse->nal_length_size = 4;
-
- h264parse->src_caps = caps;
- }
-
- discont = GST_BUFFER_IS_DISCONT (buffer);
-
- GST_DEBUG_OBJECT (h264parse, "received buffer of size %u",
- GST_BUFFER_SIZE (buffer));
-
- if (h264parse->segment.rate > 0.0)
- res = gst_h264_parse_chain_forward (h264parse, discont, buffer);
- else
- res = gst_h264_parse_chain_reverse (h264parse, discont, buffer);
-
- return res;
-}
-
-static gboolean
-gst_h264_parse_sink_event (GstPad * pad, GstEvent * event)
-{
- GstH264Parse *h264parse;
- gboolean res;
-
- h264parse = GST_H264PARSE (gst_pad_get_parent (pad));
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_FLUSH_STOP:
- GST_DEBUG_OBJECT (h264parse, "received FLUSH stop");
- gst_segment_init (&h264parse->segment, GST_FORMAT_UNDEFINED);
- gst_h264_parse_clear_queues (h264parse);
- h264parse->last_outbuf_dts = GST_CLOCK_TIME_NONE;
- res = gst_pad_push_event (h264parse->srcpad, event);
- break;
- case GST_EVENT_EOS:
- GST_DEBUG_OBJECT (h264parse, "received EOS");
- if (h264parse->pending_segment) {
- /* Send pending newsegment before EOS */
- gst_pad_push_event (h264parse->srcpad, h264parse->pending_segment);
- h264parse->pending_segment = NULL;
- }
- if (h264parse->segment.rate < 0.0) {
- gst_h264_parse_chain_reverse (h264parse, TRUE, NULL);
- gst_h264_parse_flush_decode (h264parse);
- }
- res = gst_pad_push_event (h264parse->srcpad, event);
- break;
- case GST_EVENT_NEWSEGMENT:
- {
- gdouble rate, applied_rate;
- GstFormat format;
- gint64 start, stop, pos;
- gboolean update;
- GstEvent **ev;
-
- gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
- &format, &start, &stop, &pos);
-
- /* now configure the values */
- gst_segment_set_newsegment_full (&h264parse->segment, update,
- rate, applied_rate, format, start, stop, pos);
-
- GST_DEBUG_OBJECT (h264parse,
- "Keeping newseg rate %g, applied rate %g, format %d, start %"
- G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT ", pos %" G_GINT64_FORMAT,
- rate, applied_rate, format, start, stop, pos);
-
- ev = &h264parse->pending_segment;
- gst_event_replace (ev, event);
- gst_event_unref (event);
- res = TRUE;
- break;
- }
- case GST_EVENT_FLUSH_START:
- {
- res = gst_pad_push_event (h264parse->srcpad, event);
- break;
- }
- default:
- {
- if (G_UNLIKELY (h264parse->src_caps == NULL ||
- h264parse->pending_segment)) {
- /* We don't yet have enough data to set caps on the srcpad, so collect
- * non-critical events till we do */
- h264parse->pending_events = g_list_append (h264parse->pending_events,
- event);
- res = TRUE;
- } else
- res = gst_pad_push_event (h264parse->srcpad, event);
-
- break;
- }
- }
- gst_object_unref (h264parse);
-
- return res;
-}
-
-static GstStateChangeReturn
-gst_h264_parse_change_state (GstElement * element, GstStateChange transition)
-{
- GstH264Parse *h264parse;
- GstStateChangeReturn ret;
-
- h264parse = GST_H264PARSE (element);
-
- switch (transition) {
- case GST_STATE_CHANGE_READY_TO_PAUSED:
- gst_segment_init (&h264parse->segment, GST_FORMAT_UNDEFINED);
- break;
- default:
- break;
- }
-
- ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
-
- switch (transition) {
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- gst_h264_parse_clear_queues (h264parse);
- gst_h264_parse_reset (h264parse);
- break;
- default:
- break;
- }
-
- return ret;
-}
-
-
-static gboolean
-plugin_init (GstPlugin * plugin)
-{
- return gst_element_register (plugin, "legacyh264parse",
- GST_RANK_NONE, GST_TYPE_H264PARSE);
-}
-
-GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
- GST_VERSION_MINOR,
- "h264parse",
- "Element parsing raw h264 streams",
- plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)