{
GST_H264_PARSE_FORMAT_NONE,
GST_H264_PARSE_FORMAT_AVC,
- GST_H264_PARSE_FORMAT_BYTE
+ GST_H264_PARSE_FORMAT_BYTE,
+ GST_H264_PARSE_FORMAT_AVC3
};
enum
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-h264, parsed = (boolean) true, "
- "stream-format=(string) { avc, byte-stream }, "
+ "stream-format=(string) { avc, avc3, byte-stream }, "
"alignment=(string) { au, nal }"));
#define parent_class gst_h264_parse_parent_class
return "avc";
case GST_H264_PARSE_FORMAT_BYTE:
return "byte-stream";
+ case GST_H264_PARSE_FORMAT_AVC3:
+ return "avc3";
default:
return "none";
}
*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;
}
}
GST_DEBUG_OBJECT (h264parse, "nal length %d", size);
buf = gst_buffer_new_allocate (NULL, 4 + size, NULL);
- if (format == GST_H264_PARSE_FORMAT_AVC) {
+ if (format == GST_H264_PARSE_FORMAT_AVC
+ || format == GST_H264_PARSE_FORMAT_AVC3) {
tmp = GUINT32_TO_BE (size << (32 - 8 * nl));
} else {
/* HACK: nl should always be 4 here, otherwise this won't work.
}
}
}
- for (i = 0; i < GST_H264_MAX_PPS_COUNT; i++) {
+ for (i = 0;
+ i < GST_H264_MAX_PPS_COUNT
+ && h264parse->format != GST_H264_PARSE_FORMAT_AVC3; i++) {
if ((nal = h264parse->pps_nals[i])) {
num_pps++;
/* size bytes also count */
}
}
+ if (h264parse->format == GST_H264_PARSE_FORMAT_AVC3) {
+ num_sps = sps_size = 0;
+ }
+
GST_DEBUG_OBJECT (h264parse,
"constructing codec_data: num_sps=%d, num_pps=%d", num_sps, num_pps);
- if (!found || !num_pps)
+ if (!found || (0 == num_pps
+ && GST_H264_PARSE_FORMAT_AVC3 != h264parse->format))
return NULL;
buf = gst_buffer_new_allocate (NULL, 5 + 1 + sps_size + 1 + pps_size, NULL);
data[5] = 0xe0 | num_sps; /* number of SPSs */
data += 6;
- for (i = 0; i < GST_H264_MAX_SPS_COUNT; i++) {
+ for (i = 0; i < num_sps; i++) {
if ((nal = h264parse->sps_nals[i])) {
gsize nal_size = gst_buffer_get_size (nal);
GST_WRITE_UINT16_BE (data, nal_size);
data[0] = num_pps;
data++;
- for (i = 0; i < GST_H264_MAX_PPS_COUNT; i++) {
+ for (i = 0; i < num_pps; i++) {
if ((nal = h264parse->pps_nals[i])) {
gsize nal_size = gst_buffer_get_size (nal);
GST_WRITE_UINT16_BE (data, nal_size);
GST_DEBUG_OBJECT (h264parse, "sps: %p", sps);
/* only codec-data for nice-and-clean au aligned packetized avc format */
- if (h264parse->format == GST_H264_PARSE_FORMAT_AVC &&
- h264parse->align == GST_H264_PARSE_ALIGN_AU) {
+ if ((h264parse->format == GST_H264_PARSE_FORMAT_AVC
+ || h264parse->format == GST_H264_PARSE_FORMAT_AVC3)
+ && h264parse->align == GST_H264_PARSE_ALIGN_AU) {
buf = gst_h264_parse_make_codec_data (h264parse);
if (buf && h264parse->codec_data) {
GstMapInfo map;
size = map.size;
/* parse the avcC data */
- if (size < 8) {
+ if (size < 7) { /* when numSPS==0 and numPPS==0, length is 7 bytes */
gst_buffer_unmap (codec_data, &map);
goto avcc_too_small;
}
/* we did parse codec-data and might supplement src caps */
gst_h264_parse_update_src_caps (h264parse, caps);
}
- } else if (format == GST_H264_PARSE_FORMAT_AVC) {
+ } else if (format == GST_H264_PARSE_FORMAT_AVC
+ || format == GST_H264_PARSE_FORMAT_AVC3) {
/* if input != output, and input is avc, must split before anything else */
/* arrange to insert codec-data in-stream if needed.
* src caps are only arranged for later on */
", stream-format = (string) avc, alignment = (string) au")
);
+GstStaticPadTemplate sinktemplate_avc3_au = GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (SINK_CAPS_TMPL
+ ", stream-format = (string) avc3, alignment = (string) au")
+ );
+
GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
};
/* combines to this codec-data */
-static guint8 h264_codec_data[] = {
+static guint8 h264_avc_codec_data[] = {
0x01, 0x4d, 0x40, 0x15, 0xff, 0xe1, 0x00, 0x17,
0x67, 0x4d, 0x40, 0x15, 0xec, 0xa4, 0xbf, 0x2e,
0x02, 0x20, 0x00, 0x00, 0x03, 0x00, 0x2e, 0xe6,
0x00, 0x04, 0x68, 0xeb, 0xec, 0xb2
};
+/* codec-data for avc3 where there are no SPS/PPS in the codec_data */
+static guint8 h264_avc3_codec_data[] = {
+ 0x01, /* config version, always == 1 */
+ 0x4d, /* profile */
+ 0x40, /* profile compatibility */
+ 0x15, 0xff, /* 6 reserved bits, lengthSizeMinusOne */
+ 0xe0, /* 3 reserved bits, numSPS */
+ 0x00 /* numPPS */
+};
+
+static guint8 *h264_codec_data = NULL;
+static guint8 h264_codec_data_size = 0;
+
+
/* keyframes all around */
static guint8 h264_idrframe[] = {
0x00, 0x00, 0x00, 0x01, 0x65, 0x88, 0x84, 0x00,
fail_unless (val != NULL);
buf = gst_value_get_buffer (val);
fail_unless (buf != NULL);
- fail_unless (gst_buffer_get_size (buf) == sizeof (h264_codec_data));
+ fail_unless (gst_buffer_get_size (buf) == h264_codec_data_size);
fail_unless (gst_buffer_memcmp (buf, 0, h264_codec_data,
gst_buffer_get_size (buf)) == 0);
}
caps = gst_caps_from_string (SRC_CAPS_TMPL);
cdata =
gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, h264_codec_data,
- sizeof (h264_codec_data), 0, sizeof (h264_codec_data), NULL, NULL);
+ h264_codec_data_size, 0, h264_codec_data_size, NULL, NULL);
gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, cdata, NULL);
gst_buffer_unref (cdata);
desc = gst_caps_to_string (caps);
ctx_no_metadata = TRUE;
ctx_codec_data = FALSE;
+ h264_codec_data = h264_avc_codec_data;
+ h264_codec_data_size = sizeof (h264_avc_codec_data);
+
ctx_suite = "h264parse_to_bs_nal";
s = h264parse_suite ();
sr = srunner_create (s);
nf += srunner_ntests_failed (sr);
srunner_free (sr);
+ /* setup and tweak to handle avc3 au output */
+ h264_codec_data = h264_avc3_codec_data;
+ h264_codec_data_size = sizeof (h264_avc3_codec_data);
+ ctx_suite = "h264parse_to_avc3_au";
+ ctx_sink_template = &sinktemplate_avc3_au;
+ ctx_discard = 0;
+ ctx_codec_data = TRUE;
+
+ s = h264parse_suite ();
+ sr = srunner_create (s);
+ srunner_run_all (sr, CK_NORMAL);
+ nf += srunner_ntests_failed (sr);
+ srunner_free (sr);
+
/* setup and tweak to handle avc packetized input */
+ h264_codec_data = h264_avc_codec_data;
+ h264_codec_data_size = sizeof (h264_avc_codec_data);
ctx_suite = "h264parse_packetized";
/* turn into separate byte stream NALs */
ctx_sink_template = &sinktemplate_bs_nal;