From: Tiphaine Inguere <tifaine.inguere@xxxxxx> If the input stream format is MPEG1 or MPEG2, the stream is parsed using mpeg parser library to build mpeg metadata. Change-Id: I767cd0a8ea546755bcdc031ca4a2808690cccf63 signed-off-by: Tiphaine Inguere <tifaine.inguere@xxxxxx> Signed-off-by: Hugues Fruchet <hugues.fruchet@xxxxxx> --- lib/libv4l-delta/Makefile.am | 4 + lib/libv4l-delta/libv4l-delta-mpeg2.c | 211 ++++++++++++++++++++++++++++++++++ lib/libv4l-delta/libv4l-delta.c | 6 +- 3 files changed, 220 insertions(+), 1 deletion(-) create mode 100644 lib/libv4l-delta/libv4l-delta-mpeg2.c diff --git a/lib/libv4l-delta/Makefile.am b/lib/libv4l-delta/Makefile.am index fa401b6..3812de5 100644 --- a/lib/libv4l-delta/Makefile.am +++ b/lib/libv4l-delta/Makefile.am @@ -6,6 +6,10 @@ SUBDIRS = codecparsers libv4l_delta_la_SOURCES = libv4l-delta.c libv4l-delta.h +##### MPEG2 decoder ##### +libv4l_delta_la_SOURCES += libv4l-delta-mpeg2.c + +##### Codecparser interface ##### libv4l_delta_la_CPPFLAGS = $(CFLAG_VISIBILITY) libv4l_delta_la_CFLAGS = $(GST_CFLAGS) -DGST_USE_UNSTABLE_API libv4l_delta_la_LDFLAGS = -avoid-version -module -shared -export-dynamic -lpthread diff --git a/lib/libv4l-delta/libv4l-delta-mpeg2.c b/lib/libv4l-delta/libv4l-delta-mpeg2.c new file mode 100644 index 0000000..7f69dd4 --- /dev/null +++ b/lib/libv4l-delta/libv4l-delta-mpeg2.c @@ -0,0 +1,211 @@ +/* + * libv4l-delta-mpeg2.c + * + * Copyright (C) STMicroelectronics SA 2014 + * Authors: Tifaine Inguere <tifaine.inguere@xxxxxx> + * Hugues Fruchet <hugues.fruchet@xxxxxx> + */ +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#include "codecparsers/gstmpegvideoparser.h" +#include "libv4l-delta.h" + +/* FIXME + * - meta coherency check (what is mandatory vs optional) + * - meta compatibility check (GST types must be aligned with V4L2 ones) + * - parsing errors tracing (trace in case of gst_parse_xxx fails) + * - do not parse all access unit (currently needed to detect the + * second slice of a field interlaced bitstream) + */ + +unsigned int delta_mpeg2_decode_header(void *au_addr, + unsigned int au_size, + struct v4l2_ctrl_mpeg2_meta *meta) +{ + unsigned char ExtensionCode; + unsigned int startcode_found = 0; + unsigned int header_found = 0; + GstMpegVideoPacket packet_data; + unsigned int slice_index = 0; + + DELTA_LOG_DEBUG("> %s\n", __func__); + + if ((!au_addr) || (!au_size) || (!meta)) { + DELTA_LOG_ERR("%s: invalid input: au_addr=%p, au_size=%d, meta=%p\n", + __func__, au_addr, au_size, meta); + return 0; + } + + memset(meta, 0, sizeof(*meta)); + meta->struct_size = sizeof(*meta); + + memset(&packet_data, 0, sizeof(packet_data)); + + while (((packet_data.offset + 4) < au_size)) { + DELTA_LOG_DEBUG("%s: parsing input from offset=%d\n", __func__, + packet_data.offset); + startcode_found = gst_mpeg_video_parse(&packet_data, au_addr, au_size, + packet_data.offset); + if (!startcode_found) { + DELTA_LOG_DEBUG("%s: parsing is over\n", __func__); + break; + } + DELTA_LOG_DEBUG("%s: found starcode @offset=%u, code=0x%02x\n", + __func__, packet_data.offset - 4, packet_data.type); + + switch (packet_data.type) { + case GST_MPEG_VIDEO_PACKET_PICTURE: + if (gst_mpeg_video_packet_parse_picture_header + (&packet_data, + (GstMpegVideoPictureHdr *)&(meta->pic[slice_index].pic_h))) { + meta->flags |= V4L2_CTRL_MPEG2_FLAG_PIC; + meta->pic[slice_index].flags |= MPEG2_META_PIC_FLAG_HDR; + DELTA_LOG_DEBUG("%s: MPEG2_META_PIC_FLAG_HDR\n", __func__); + header_found = 1; + } + break; + + case GST_MPEG_VIDEO_PACKET_SLICE_MIN: + /* new slice encountered */ + /* FIXME we can avoid to parse too much data here by stopping + * at first slice encountered but not in the case of field + * interlaced where 2 slices are expected + */ + if (slice_index > 1) { + DELTA_LOG_ERR("%s: more than 2 slices detected @offset=%d, ignoring this slice...\n", + __func__, packet_data.offset); + break; + } + + /* store its offset & size, including startcode */ + meta->pic[slice_index].offset = packet_data.offset - 4; + + slice_index++; + + DELTA_LOG_DEBUG("%s: start of slice @ offset=%d\n", __func__, packet_data.offset); + header_found = 1; + break; + + case GST_MPEG_VIDEO_PACKET_USER_DATA: + /* not implemented : do nothing */ + DELTA_LOG_DEBUG("%s: user-data case not implemented\n", __func__); + break; + + case GST_MPEG_VIDEO_PACKET_SEQUENCE: + if (gst_mpeg_video_packet_parse_sequence_header + (&packet_data, + (GstMpegVideoSequenceHdr *)&(meta->seq.seq_h))) { + meta->flags |= V4L2_CTRL_MPEG2_FLAG_SEQ; + meta->seq.flags |= MPEG2_META_SEQ_FLAG_HDR; + DELTA_LOG_DEBUG("%s: MPEG2_META_SEQ_FLAG_HDR\n", __func__); + header_found = 1; + } + break; + + case GST_MPEG_VIDEO_PACKET_EXTENSION: + ExtensionCode = get_extension_code(&packet_data); + DELTA_LOG_DEBUG("%s: ExtensionCode=0x%02x \n", __func__, ExtensionCode); + + switch (ExtensionCode) { + case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE: + if (gst_mpeg_video_packet_parse_sequence_extension + (&packet_data, + (GstMpegVideoSequenceExt *)&(meta->seq.seq_e))) { + meta->flags |= V4L2_CTRL_MPEG2_FLAG_SEQ; + meta->seq.flags |= MPEG2_META_SEQ_FLAG_EXT; + DELTA_LOG_DEBUG("%s: MPEG2_META_SEQ_FLAG_EXT\n", __func__); + header_found = 1; + } + break; + + case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_DISPLAY: + if (gst_mpeg_video_packet_parse_sequence_display_extension + (&packet_data, + (GstMpegVideoSequenceDisplayExt *)&(meta->seq.seq_d))) { + meta->flags |= V4L2_CTRL_MPEG2_FLAG_SEQ; + meta->seq.flags |= MPEG2_META_SEQ_FLAG_DISPLAY_EXT; + DELTA_LOG_DEBUG("%s: MPEG2_META_SEQ_FLAG_DISPLAY_EXT\n", __func__); + header_found = 1; + } + break; + + case GST_MPEG_VIDEO_PACKET_EXT_QUANT_MATRIX: + if (gst_mpeg_video_packet_parse_quant_matrix_extension + (&packet_data, + (GstMpegVideoQuantMatrixExt *)&(meta->seq.qua_m))) { + meta->flags |= V4L2_CTRL_MPEG2_FLAG_SEQ; + meta->seq.flags |= MPEG2_META_SEQ_FLAG_MATRIX_EXT; + DELTA_LOG_DEBUG("%s: MPEG2_META_SEQ_FLAG_MATRIX_EXT\n", __func__); + header_found = 1; + } + break; + + case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_SCALABLE: + if (gst_mpeg_video_packet_parse_sequence_scalable_extension + (&packet_data, + (GstMpegVideoSequenceScalableExt *)&(meta->seq.seq_s))) { + meta->flags |= V4L2_CTRL_MPEG2_FLAG_SEQ; + meta->seq.flags |= MPEG2_META_SEQ_FLAG_SCALABLE_EXT; + DELTA_LOG_DEBUG("%s: MPEG2_META_SEQ_FLAG_SCALABLE_EXT\n", __func__); + header_found = 1; + } + break; + + case GST_MPEG_VIDEO_PACKET_EXT_PICTURE: + if (gst_mpeg_video_packet_parse_picture_extension + (&packet_data, + (GstMpegVideoPictureExt *)&(meta->pic[slice_index].pic_e))) { + meta->flags |= V4L2_CTRL_MPEG2_FLAG_PIC; + meta->pic[slice_index].flags |= MPEG2_META_PIC_FLAG_EXT; + DELTA_LOG_DEBUG("%s: MPEG2_META_PIC_FLAG_EXT top_field_first=%d\n", + __func__, meta->pic[slice_index].pic_e.top_field_first); + header_found = 1; + } + break; + + default: + break; + } + break; + + case GST_MPEG_VIDEO_PACKET_SEQUENCE_END: + DELTA_LOG_DEBUG("%s: end of packet sequence\n", __func__); + break; + + case GST_MPEG_VIDEO_PACKET_GOP: + if (gst_mpeg_video_packet_parse_gop + (&packet_data, + (GstMpegVideoGop *)&(meta->pic[slice_index].g_o_p))) { + meta->flags |= V4L2_CTRL_MPEG2_FLAG_PIC; + meta->pic[slice_index].flags |= MPEG2_META_PIC_FLAG_GOP; + DELTA_LOG_DEBUG("%s: MPEG2_META_PIC_FLAG_GOP\n", __func__); + header_found = 1; + } + break; + + default: + DELTA_LOG_DEBUG("%s: unknown/unsupported header %02x\n", + __func__, packet_data.type); + break; + } + } + + DELTA_LOG_DEBUG("< %s\n", __func__); + return header_found; +} + +const struct delta_metadata mpeg2meta = { + .name = "mpeg2", + .stream_format = V4L2_PIX_FMT_MPEG2, + .meta_size = sizeof(struct v4l2_ctrl_mpeg2_meta), + .decode_header = delta_mpeg2_decode_header, +}; + +const struct delta_metadata mpeg1meta = { + .name = "mpeg1", + .stream_format = V4L2_PIX_FMT_MPEG1, + .meta_size = sizeof(struct v4l2_ctrl_mpeg2_meta), + .decode_header = delta_mpeg2_decode_header, +}; diff --git a/lib/libv4l-delta/libv4l-delta.c b/lib/libv4l-delta/libv4l-delta.c index aa33e94..97e709a 100644 --- a/lib/libv4l-delta/libv4l-delta.c +++ b/lib/libv4l-delta/libv4l-delta.c @@ -50,8 +50,12 @@ ((type == V4L2_BUF_TYPE_VIDEO_CAPTURE) ? "CAPTURE" : "?")) /* available metadata builders */ -const struct delta_metadata *delta_meta[] = { +extern const struct delta_metadata mpeg2meta; +extern const struct delta_metadata mpeg1meta; +const struct delta_metadata *delta_meta[] = { + &mpeg2meta, + &mpeg1meta, }; static void *delta_plugin_init(int fd) -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html