在gstreamer中,h264的格式有:
static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-h264, parsed = (boolean) true, "
"stream-format=(string) { avc, avc3, byte-stream }, "
"alignment=(string) { au, nal }"));
H264有两种对齐方式:
1、AVC (length-prefixed)
2、Annex B (0x000001 start code prefix)
还有同学问SVC和MVC,这里拓展一下:
/**
* GstH264NalUnitExtensionType:
* @GST_H264_NAL_EXTENSION_NONE: No NAL unit header extension is available
* @GST_H264_NAL_EXTENSION_SVC: NAL unit header extension for SVC (Annex G)
* @GST_H264_NAL_EXTENSION_MVC: NAL unit header extension for MVC (Annex H)
*
* Indicates the type of H.264 NAL unit extension.
*
* Since: 1.6
*/
typedef enum
{
GST_H264_NAL_EXTENSION_NONE = 0,
GST_H264_NAL_EXTENSION_SVC,
GST_H264_NAL_EXTENSION_MVC,
} GstH264NalUnitExtensionType;
那么,看下面:
"stream-format=(string) { avc, avc3, byte-stream }, "
"alignment=(string) { au, nal }"));
这两个要从gsth264parser.c中看:
gst_h264_parse_get_string (GstH264Parse * parse, gboolean format, gint code)
{
if (format) {
switch (code) {
case GST_H264_PARSE_FORMAT_AVC:
return "avc";
case GST_H264_PARSE_FORMAT_BYTE:
return "byte-stream";
case GST_H264_PARSE_FORMAT_AVC3:
return "avc3";
default:
return "none";
}
} else {
switch (code) {
case GST_H264_PARSE_ALIGN_NAL:
return "nal";
case GST_H264_PARSE_ALIGN_AU:
return "au";
default:
return "none";
}
}
}
static void
gst_h264_parse_format_from_caps (GstCaps * caps, guint * format, guint * align)
{
if (format)
*format = GST_H264_PARSE_FORMAT_NONE;
if (align)
*align = GST_H264_PARSE_ALIGN_NONE;
g_return_if_fail (gst_caps_is_fixed (caps));
GST_DEBUG ("parsing caps: %" GST_PTR_FORMAT, caps);
if (caps && gst_caps_get_size (caps) > 0) {
GstStructure *s = gst_caps_get_structure (caps, 0);
const gchar *str = NULL;
if (format) {
if ((str = gst_structure_get_string (s, "stream-format"))) {
if (strcmp (str, "avc") == 0)
*format = GST_H264_PARSE_FORMAT_AVC;
else if (strcmp (str, "byte-stream") == 0)
*format = GST_H264_PARSE_FORMAT_BYTE;
else if (strcmp (str, "avc3") == 0)
*format = GST_H264_PARSE_FORMAT_AVC3;
}
}
if (align) {
if ((str = gst_structure_get_string (s, "alignment"))) {
if (strcmp (str, "au") == 0)
*align = GST_H264_PARSE_ALIGN_AU;
else if (strcmp (str, "nal") == 0)
*align = GST_H264_PARSE_ALIGN_NAL;
}
}
}
}
/* fix up caps witho
ut stream-format for max. backwards compatibility */
if (format == GST_H264_PARSE_FORMAT_NONE) {
/* codec_data implies avc */
if (codec_data_value != NULL) {
GST_ERROR ("video/x-h264 caps with codec_data but no stream-format=avc");
//这里对齐格式是AVC,也就是指定了nal的长度
format = GST_H264_PARSE_FORMAT_AVC;
} else {
/* otherwise assume bytestream input */
GST_ERROR ("video/x-h264 caps without codec_data or stream-format");
//那么这里应该就是start code
format = GST_H264_PARSE_FORMAT_BYTE;
}
}
/* avc caps sanity checks */
if (format == GST_H264_PARSE_FORMAT_AVC) {
/* AVC requires codec_data, AVC3 might have one and/or SPS/PPS inline */
if (codec_data_value == NULL)
goto avc_caps_codec_data_missing;
/* AVC implies alignment=au, everything else is not allowed */
//如果是AVC那么对齐格式就必须是AU
if (align == GST_H264_PARSE_ALIGN_NONE)
align = GST_H264_PARSE_ALIGN_AU;
else if (align != GST_H264_PARSE_ALIGN_AU)
goto avc_caps_wrong_alignment;
}
/* bytestream caps sanity checks */
if (format == GST_H264_PARSE_FORMAT_BYTE) {
/* should have SPS/PSS in-band (and/or oob in streamheader field) */
if (codec_data_value != NULL)
goto bytestream_caps_with_codec_data;
}
/* packetized video has codec_data (required for AVC, optional for AVC3) */
if (codec_data_value != NULL) {
GstMapInfo map;
guint8 *data;
guint num_sps, num_pps;
#ifndef GST_DISABLE_GST_DEBUG
guint profile;
#endif
gint i;
GST_DEBUG_OBJECT (h264parse, "have packetized h264");
/* make note for optional split processing */
h264parse->packetized = TRUE;
/* codec_data field should hold a buffer */
if (!GST_VALUE_HOLDS_BUFFER (codec_data_value))
goto avc_caps_codec_data_wrong_type;
codec_data = gst_value_get_buffer (codec_data_value);
if (!codec_data)
goto avc_caps_codec_data_missing;
gst_buffer_map (codec_data, &map, GST_MAP_READ);
data = map.data;
size = map.size;
/* parse the avcC data */
if (size < 7) { /* when numSPS==0 and numPPS==0, length is 7 bytes */
gst_buffer_unmap (codec_data, &map);
goto avcc_too_small;
}
/* parse the version, this must be 1 */
if (data[0] != 1) {
gst_buffer_unmap (codec_data, &map);
goto wrong_version;
}
#ifndef GST_DISABLE_GST_DEBUG
/* AVCProfileIndication */
/* profile_compat */
/* AVCLevelIndication */
profile = (data[1] << 16) | (data[2] << 8) | data[3];
GST_DEBUG_OBJECT (h264parse, "profile %06x", profile);
#endif
/* 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 size %u",
h264parse->nal_length_size);
num_sps = data[5] & 0x1f;
off = 6;
for (i = 0; i < num_sps; i++) {
parseres = gst_h264_parser_identify_nalu_avc (h264parse->nalparser,
data, off, size, 2, &nalu);
if (parseres != GST_H264_PARSER_OK) {
gst_buffer_unmap (codec_data, &map);
goto avcc_too_small;
}
gst_h264_parse_process_nal (h264parse, &nalu);
off = nalu.offset + nalu.size;
}
if (off >= size) {
gst_buffer_unmap (codec_data, &map);
goto avcc_too_small;
}
num_pps = data[off];
off++;
for (i = 0; i < num_pps; i++) {
parseres = gst_h264_parser_identify_nalu_avc (h264parse->nalparser,
data, off, size, 2, &nalu);
if (parseres != GST_H264_PARSER_OK) {
gst_buffer_unmap (codec_data, &map);
goto avcc_too_small;
}
gst_h264_parse_process_nal (h264parse, &nalu);
off = nalu.offset + nalu.size;
}
gst_buffer_unmap (codec_data, &map);
gst_buffer_replace (&h264parse->codec_data_in, codec_data);
/* don't confuse codec_data with inband sps/pps */
h264parse->have_sps_in_frame = FALSE;
h264parse->have_pps_in_frame = FALSE;
} else if (format == GST_H264_PARSE_FORMAT_BYTE) {
//这里明显看到GST_H264_PARSE_FORMAT_BYTE就是start code
GST_DEBUG_OBJECT (h264parse, "have bytestream h264");
/* nothing to pre-process */
h264parse->packetized = FALSE;
/* we have 4 sync bytes */
h264parse->nal_length_size = 4;
} else {
/* probably AVC3 without codec_data field, anything to do here? */
}
一定要看这个:入口