static gboolean gst_h264_parse_check_valid_frame (GstBaseParse * parse, GstBaseParseFrame * frame, guint * framesize, gint * skipsize) { GstH264Parse *h264parse = GST_H264_PARSE (parse); GstBuffer *buffer = frame->buffer; gint sc_pos, nal_pos, next_sc_pos, next_nal_pos; guint8 *data; guint size; gboolean drain; /* expect at least 3 bytes startcode == sc, and 2 bytes NALU payload */ if (G_UNLIKELY (GST_BUFFER_SIZE (buffer) < 5)) return FALSE; /* need to configure aggregation */ if (G_UNLIKELY (h264parse->format == GST_H264_PARSE_FORMAT_NONE)) gst_h264_parse_negotiate (h264parse); data = GST_BUFFER_DATA (buffer); size = GST_BUFFER_SIZE (buffer); GST_LOG_OBJECT (h264parse, "last_nal_pos: %d, last_scan_pos %d", h264parse->last_nal_pos, h264parse->next_sc_pos); nal_pos = h264parse->last_nal_pos; next_sc_pos = h264parse->next_sc_pos; if (!next_sc_pos) { sc_pos = gst_h264_parse_find_sc (buffer, 0); if (sc_pos == -1) { /* SC not found, need more data */ sc_pos = GST_BUFFER_SIZE (buffer) - 3; goto more; } nal_pos = sc_pos + 3; next_sc_pos = nal_pos; /* sc might have 2 or 3 0-bytes */ if (sc_pos > 0 && data[sc_pos - 1] == 00) sc_pos--; GST_LOG_OBJECT (h264parse, "found sc at offset %d", sc_pos); } else { /* previous checks already arrange sc at start */ sc_pos = 0; } drain = GST_BASE_PARSE_FRAME_DRAIN (frame); while (TRUE) { gint prev_sc_pos; next_sc_pos = gst_h264_parse_find_sc (buffer, next_sc_pos); if (next_sc_pos == -1) { GST_LOG_OBJECT (h264parse, "no next sc"); if (drain) { /* FLUSH/EOS, it's okay if we can't find the next frame */ next_sc_pos = size; next_nal_pos = size; } else { next_sc_pos = size - 3; goto more; } } else { next_nal_pos = next_sc_pos + 3; if (data[next_sc_pos - 1] == 00) next_sc_pos--; GST_LOG_OBJECT (h264parse, "found next sc at offset %d", next_sc_pos); /* need at least 1 more byte of next NAL */ if (!drain && (next_nal_pos == size - 1)) goto more; } /* determine nal's sc position */ prev_sc_pos = nal_pos - 3; g_assert (prev_sc_pos >= 0); if (prev_sc_pos > 0 && data[prev_sc_pos - 1] == 0) prev_sc_pos--; /* already consume and gather info from NAL */ gst_h264_parse_process_nal (h264parse, data, prev_sc_pos, nal_pos, next_sc_pos - nal_pos); if (next_nal_pos >= size - 1 || gst_h264_parse_collect_nal (h264parse, data + nal_pos, data + next_nal_pos)) break; /* move along */ next_sc_pos = nal_pos = next_nal_pos; } *skipsize = sc_pos; *framesize = next_sc_pos - sc_pos; return TRUE; more: /* Ask for 1024 bytes more - this is an arbitrary choice */ gst_base_parse_set_min_frame_size (parse, GST_BUFFER_SIZE (buffer) + 1024); /* skip up to initial startcode */ *skipsize = sc_pos; /* resume scanning here next time */ h264parse->last_nal_pos = nal_pos; h264parse->next_sc_pos = next_sc_pos; return FALSE; }
static gboolean gst_h264_parse_check_valid_frame (GstBaseParse * parse, GstBaseParseFrame * frame, guint * framesize, gint * skipsize) { GstH264Parse *h264parse = GST_H264_PARSE (parse); GstBuffer *buffer = frame->buffer; gint sc_pos, nal_pos, next_sc_pos, next_nal_pos; guint8 *data; guint size; gboolean drain; /* expect at least 3 bytes startcode == sc, and 2 bytes NALU payload */ if (G_UNLIKELY (GST_BUFFER_SIZE (buffer) < 5)) return FALSE; /* need to configure aggregation */ if (G_UNLIKELY (h264parse->format == GST_H264_PARSE_FORMAT_NONE)) gst_h264_parse_negotiate (h264parse); /* avoid stale cached parsing state */ if (!(frame->flags & GST_BASE_PARSE_FRAME_FLAG_PARSING)) { GST_LOG_OBJECT (h264parse, "parsing new frame"); gst_h264_parse_reset_frame (h264parse); frame->flags |= GST_BASE_PARSE_FRAME_FLAG_PARSING; } else { GST_LOG_OBJECT (h264parse, "resuming frame parsing"); } data = GST_BUFFER_DATA (buffer); size = GST_BUFFER_SIZE (buffer); GST_LOG_OBJECT (h264parse, "last_nal_pos: %d, last_scan_pos %d", h264parse->last_nal_pos, h264parse->next_sc_pos); nal_pos = h264parse->last_nal_pos; next_sc_pos = h264parse->next_sc_pos; if (!next_sc_pos) { sc_pos = gst_h264_parse_find_sc (buffer, 0); if (sc_pos == -1) { /* SC not found, need more data */ sc_pos = GST_BUFFER_SIZE (buffer) - 3; /* avoid going < 0 later on */ nal_pos = next_sc_pos = sc_pos; goto more; } nal_pos = sc_pos + 3; next_sc_pos = nal_pos; /* sc might have 2 or 3 0-bytes */ if (sc_pos > 0 && data[sc_pos - 1] == 00) sc_pos--; GST_LOG_OBJECT (h264parse, "found sc at offset %d", sc_pos); } else { /* previous checks already arrange sc at start */ sc_pos = 0; } drain = GST_BASE_PARSE_DRAINING (parse); while (TRUE) { gint prev_sc_pos; next_sc_pos = gst_h264_parse_find_sc (buffer, next_sc_pos); if (next_sc_pos == -1) { GST_LOG_OBJECT (h264parse, "no next sc"); if (drain) { /* FLUSH/EOS, it's okay if we can't find the next frame */ next_sc_pos = size; next_nal_pos = size; } else { next_sc_pos = size - 3; goto more; } } else { next_nal_pos = next_sc_pos + 3; if (data[next_sc_pos - 1] == 00) next_sc_pos--; GST_LOG_OBJECT (h264parse, "found next sc at offset %d", next_sc_pos); /* need at least 1 more byte of next NAL */ if (!drain && (next_nal_pos == size - 1)) goto more; } /* determine nal's sc position */ prev_sc_pos = nal_pos - 3; g_assert (prev_sc_pos >= 0); if (prev_sc_pos > 0 && data[prev_sc_pos - 1] == 0) prev_sc_pos--; /* already consume and gather info from NAL */ if (G_UNLIKELY (next_sc_pos - nal_pos < 2)) { GST_WARNING_OBJECT (h264parse, "input stream is corrupt; " "it contains a NAL unit of length %d", next_sc_pos - nal_pos); /* broken nal at start -> arrange to skip it, * otherwise have it terminate current au * (and so it will be skippd on next frame round) */ if (prev_sc_pos == sc_pos) { *skipsize = sc_pos + 2; return FALSE; } else { next_sc_pos = prev_sc_pos; break; } } gst_h264_parse_process_nal (h264parse, data, prev_sc_pos, nal_pos, next_sc_pos - nal_pos); if (next_nal_pos >= size - 1 || gst_h264_parse_collect_nal (h264parse, data + nal_pos, data + next_nal_pos)) break; /* move along */ next_sc_pos = nal_pos = next_nal_pos; } *skipsize = sc_pos; *framesize = next_sc_pos - sc_pos; return TRUE; more: /* ask for best next available */ *framesize = G_MAXUINT; /* skip up to initial startcode */ *skipsize = sc_pos; /* resume scanning here next time */ h264parse->last_nal_pos = nal_pos - sc_pos; h264parse->next_sc_pos = next_sc_pos - sc_pos; return FALSE; }