From b6020c813907f0d1fc8e04987d404858bcce0d0e Mon Sep 17 00:00:00 2001 From: Yann Jouanin Date: Fri, 6 Jan 2017 15:42:13 +0100 Subject: [PATCH] mpegtsmux: add support for vpx streams mpegtsdemux: add support for vpx streams This commit enables muxing and demuxing of VPX (vp8 and vp9) streams in mpegts. It adds a private stream type (0xe0) and a custom descriptor --- gst/mpegtsdemux/gstmpegdefs.h | 1 + gst/mpegtsdemux/tsdemux.c | 26 +++++++++ gst/mpegtsmux/mpegtsmux.c | 19 +++++++ gst/mpegtsmux/tsmux/tsmuxstream.c | 41 ++++++++++++++ gst/mpegtsmux/tsmux/tsmuxstream.h | 115 +++++++++++++++++++++----------------- 5 files changed, 150 insertions(+), 52 deletions(-) diff --git a/gst/mpegtsdemux/gstmpegdefs.h b/gst/mpegtsdemux/gstmpegdefs.h index 5336286..f706a9b 100644 --- a/gst/mpegtsdemux/gstmpegdefs.h +++ b/gst/mpegtsdemux/gstmpegdefs.h @@ -44,6 +44,7 @@ /* FIXME: Put these in mpegts lib separate stream type enums */ /* Un-official Dirac extension */ #define ST_VIDEO_DIRAC 0xd1 +#define ST_VIDEO_VPX 0xe0 /* only used internally */ /* private stream types */ #define ST_PS_VIDEO_MPEG2_DCII 0x80 diff --git a/gst/mpegtsdemux/tsdemux.c b/gst/mpegtsdemux/tsdemux.c index c701c37..8356f5e 100644 --- a/gst/mpegtsdemux/tsdemux.c +++ b/gst/mpegtsdemux/tsdemux.c @@ -212,6 +212,8 @@ struct _TSDemuxStream "video/x-h265,stream-format=(string)byte-stream," \ "alignment=(string)nal;" \ "video/x-dirac;" \ + "video/x-vp8;" \ + "video/x-vp9;" \ "video/x-cavs;" \ "video/x-wmv," \ "wmvversion = (int) 3, " \ @@ -1452,6 +1454,30 @@ create_pad_for_stream (MpegTSBase * base, MpegTSBaseStream * bstream, "stream-format", G_TYPE_STRING, "byte-stream", "alignment", G_TYPE_STRING, "nal", NULL); break; + case ST_VIDEO_VPX: + is_private = TRUE; + desc = mpegts_get_descriptor_from_stream (bstream, 0x05); + if (desc) { + if (desc->data[8] == 8) { + GST_DEBUG ("Found a VP8 in descriptor"); + caps = gst_caps_new_simple ("video/x-vp8", + "profile", G_TYPE_INT, desc->data[9], + "height", G_TYPE_INT, *((guint16 *) (desc->data + 12)), + "width", G_TYPE_INT, *((guint16 *) (desc->data + 10)), + "framerate", GST_TYPE_FRACTION, *((guint16 *) (desc->data + 14)), + *((guint16 *) (desc->data + 16)), NULL); + } else if (desc->data[8] == 9) { + GST_DEBUG ("Found a VP9 in descriptor"); + caps = gst_caps_new_simple ("video/x-vp9", + "profile", G_TYPE_INT, desc->data[9], + "height", G_TYPE_INT, *((guint16 *) (desc->data + 12)), + "width", G_TYPE_INT, *((guint16 *) (desc->data + 10)), + "framerate", GST_TYPE_FRACTION, *((guint16 *) (desc->data + 14)), + *((guint16 *) (desc->data + 16)), NULL); + } + break; + } + break; case ST_VIDEO_DIRAC: if (bstream->registration_id == 0x64726163) { GST_LOG ("dirac"); diff --git a/gst/mpegtsmux/mpegtsmux.c b/gst/mpegtsmux/mpegtsmux.c index 67c2b72..f3e0496 100644 --- a/gst/mpegtsmux/mpegtsmux.c +++ b/gst/mpegtsmux/mpegtsmux.c @@ -129,6 +129,8 @@ static GstStaticPadTemplate mpegtsmux_sink_factory = "alignment=(string){au, nal}; " "video/x-h265,stream-format=(string)byte-stream," "alignment=(string){au, nal}; " + "video/x-vp8, profile=(string){ 0, 1, 2, 3 };" + "video/x-vp9, profile=(string){ 0, 1, 2, 3 };" "audio/mpeg, " "parsed = (boolean) TRUE, " "mpegversion = (int) { 1, 2 };" @@ -606,6 +608,10 @@ mpegtsmux_create_stream (MpegTsMux * mux, MpegTsPadData * ts_data) if (strcmp (mt, "video/x-dirac") == 0) { st = TSMUX_ST_VIDEO_DIRAC; + } else if (strcmp (mt, "video/x-vp8") == 0) { + st = TSMUX_ST_PS_VPX; + } else if (strcmp (mt, "video/x-vp9") == 0) { + st = TSMUX_ST_PS_VPX; } else if (strcmp (mt, "audio/x-ac3") == 0) { st = TSMUX_ST_PS_AUDIO_AC3; } else if (strcmp (mt, "audio/x-dts") == 0) { @@ -753,6 +759,19 @@ mpegtsmux_create_stream (MpegTsMux * mux, MpegTsPadData * ts_data) gst_structure_get_int (s, "channels", &ts_data->stream->audio_channels); gst_structure_get_int (s, "bitrate", &ts_data->stream->audio_bitrate); + if (st == TSMUX_ST_PS_VPX) { + if (strcmp (mt, "video/x-vp8") == 0) { + ts_data->stream->vpx_version = 8; + } else if (strcmp (mt, "video/x-vp9") == 0) { + ts_data->stream->vpx_version = 9; + } + ts_data->stream->is_vpx = TRUE; + gst_structure_get_int (s, "profile", &ts_data->stream->vpx_profile); + gst_structure_get_int (s, "height", &ts_data->stream->vpx_height); + gst_structure_get_int (s, "width", &ts_data->stream->vpx_width); + gst_structure_get_fraction (s, "framerate", &ts_data->stream->vpx_fr_num, + &ts_data->stream->vpx_fr_den); + } ts_data->stream->opus_channel_config_code = opus_channel_config_code; tsmux_stream_set_buffer_release_func (ts_data->stream, release_buffer_cb); diff --git a/gst/mpegtsmux/tsmux/tsmuxstream.c b/gst/mpegtsmux/tsmux/tsmuxstream.c index f719d8f..2485184 100644 --- a/gst/mpegtsmux/tsmux/tsmuxstream.c +++ b/gst/mpegtsmux/tsmux/tsmuxstream.c @@ -156,6 +156,7 @@ tsmux_stream_new (guint16 pid, TsMuxStreamType stream_type) case TSMUX_ST_PS_AUDIO_LPCM: case TSMUX_ST_PS_AUDIO_AC3: case TSMUX_ST_PS_AUDIO_DTS: + case TSMUX_ST_PS_VPX: stream->id = 0xFD; /* FIXME: assign sequential extended IDs? */ switch (stream_type) { @@ -163,6 +164,10 @@ tsmux_stream_new (guint16 pid, TsMuxStreamType stream_type) stream->id_extended = 0x60; stream->is_video_stream = TRUE; break; + case TSMUX_ST_PS_VPX: + stream->id_extended = 0x60; + stream->is_video_stream = TRUE; + break; case TSMUX_ST_PS_AUDIO_LPCM: stream->is_audio = TRUE; stream->id_extended = 0x80; @@ -768,6 +773,42 @@ tsmux_stream_get_es_descrs (TsMuxStream * stream, descriptor = gst_mpegts_descriptor_from_registration ("drac", NULL, 0); g_ptr_array_add (pmt_stream->descriptors, descriptor); break; + case TSMUX_ST_PS_VPX: + { + guint8 add_info[12]; + guint8 *pos; + + pos = add_info; + + /* audio_stream_descriptor () | ATSC A/52-2001 Annex A + * + * descriptor_tag 8 uimsbf + * descriptor_length 8 uimsbf + * vpx_version 8 uimsbf + * vpx_profile 8 uimsbf + * vpx_width 16 uimsbf + * vpx_height 16 uimsbf + * vpx_framerate_num 16 uimsbf + * vpx_framerate_den 16 uimsbf + */ + *pos++ = 0xe0; + *pos++ = 0x0c; + *pos++ = stream->vpx_version; + *pos++ = stream->vpx_profile; + *((guint16 *) pos++) = stream->vpx_width; + pos++; + *((guint16 *) pos++) = stream->vpx_height; + pos++; + *((guint16 *) pos++) = stream->vpx_fr_num; + pos++; + *((guint16 *) pos++) = stream->vpx_fr_den; + pos++; + descriptor = gst_mpegts_descriptor_from_registration ("VPX", + add_info, 12); + + g_ptr_array_add (pmt_stream->descriptors, descriptor); + break; + } case TSMUX_ST_PS_AUDIO_AC3: { guint8 add_info[6]; diff --git a/gst/mpegtsmux/tsmux/tsmuxstream.h b/gst/mpegtsmux/tsmux/tsmuxstream.h index 2766718..7a61f91 100644 --- a/gst/mpegtsmux/tsmux/tsmuxstream.h +++ b/gst/mpegtsmux/tsmux/tsmuxstream.h @@ -84,13 +84,11 @@ #include "tsmuxcommon.h" -G_BEGIN_DECLS - -typedef enum TsMuxStreamType TsMuxStreamType; +G_BEGIN_DECLS typedef enum TsMuxStreamType TsMuxStreamType; typedef enum TsMuxStreamState TsMuxStreamState; typedef struct TsMuxStreamBuffer TsMuxStreamBuffer; -typedef void (*TsMuxStreamBufferReleaseFunc) (guint8 *data, void *user_data); +typedef void (*TsMuxStreamBufferReleaseFunc) (guint8 * data, void *user_data); /* Stream type assignments * @@ -117,45 +115,49 @@ typedef void (*TsMuxStreamBufferReleaseFunc) (guint8 *data, void *user_data); * 0x0F-0x7F ITU-T Rec. H.222.0 | ISO/IEC 13818-1 Reserved * 0x80-0xFF User Private */ -enum TsMuxStreamType { - TSMUX_ST_RESERVED = 0x00, - TSMUX_ST_VIDEO_MPEG1 = 0x01, - TSMUX_ST_VIDEO_MPEG2 = 0x02, - TSMUX_ST_AUDIO_MPEG1 = 0x03, - TSMUX_ST_AUDIO_MPEG2 = 0x04, - TSMUX_ST_PRIVATE_SECTIONS = 0x05, - TSMUX_ST_PRIVATE_DATA = 0x06, - TSMUX_ST_MHEG = 0x07, - TSMUX_ST_DSMCC = 0x08, - TSMUX_ST_H222_1 = 0x09, +enum TsMuxStreamType +{ + TSMUX_ST_RESERVED = 0x00, + TSMUX_ST_VIDEO_MPEG1 = 0x01, + TSMUX_ST_VIDEO_MPEG2 = 0x02, + TSMUX_ST_AUDIO_MPEG1 = 0x03, + TSMUX_ST_AUDIO_MPEG2 = 0x04, + TSMUX_ST_PRIVATE_SECTIONS = 0x05, + TSMUX_ST_PRIVATE_DATA = 0x06, + TSMUX_ST_MHEG = 0x07, + TSMUX_ST_DSMCC = 0x08, + TSMUX_ST_H222_1 = 0x09, /* later extensions */ - TSMUX_ST_AUDIO_AAC = 0x0f, - TSMUX_ST_VIDEO_MPEG4 = 0x10, - TSMUX_ST_VIDEO_H264 = 0x1b, - TSMUX_ST_VIDEO_HEVC = 0x24, + TSMUX_ST_AUDIO_AAC = 0x0f, + TSMUX_ST_VIDEO_MPEG4 = 0x10, + TSMUX_ST_VIDEO_H264 = 0x1b, + TSMUX_ST_VIDEO_HEVC = 0x24, /* private stream types */ - TSMUX_ST_PS_AUDIO_AC3 = 0x81, - TSMUX_ST_PS_AUDIO_DTS = 0x8a, - TSMUX_ST_PS_AUDIO_LPCM = 0x8b, - TSMUX_ST_PS_DVB_SUBPICTURE = 0x8c, - TSMUX_ST_PS_TELETEXT = 0x8d, - TSMUX_ST_PS_KLV = 0x8e, /* only used internally */ - TSMUX_ST_PS_OPUS = 0x8f, /* only used internally */ - TSMUX_ST_PS_DVD_SUBPICTURE = 0xff, + TSMUX_ST_PS_AUDIO_AC3 = 0x81, + TSMUX_ST_PS_AUDIO_DTS = 0x8a, + TSMUX_ST_PS_AUDIO_LPCM = 0x8b, + TSMUX_ST_PS_DVB_SUBPICTURE = 0x8c, + TSMUX_ST_PS_TELETEXT = 0x8d, + TSMUX_ST_PS_KLV = 0x8e, /* only used internally */ + TSMUX_ST_PS_OPUS = 0x8f, /* only used internally */ + TSMUX_ST_PS_VPX = 0xe0, /* only used internally */ + TSMUX_ST_PS_DVD_SUBPICTURE = 0xff, /* Non-standard definitions */ - TSMUX_ST_VIDEO_DIRAC = 0xD1 + TSMUX_ST_VIDEO_DIRAC = 0xD1 }; -enum TsMuxStreamState { - TSMUX_STREAM_STATE_HEADER, - TSMUX_STREAM_STATE_PACKET +enum TsMuxStreamState +{ + TSMUX_STREAM_STATE_HEADER, + TSMUX_STREAM_STATE_PACKET }; /* TsMuxStream receives elementary streams for parsing */ -struct TsMuxStream { +struct TsMuxStream +{ TsMuxStreamState state; TsMuxPacketInfo pi; TsMuxStreamType stream_type; @@ -197,7 +199,7 @@ struct TsMuxStream { gint64 last_pts; /* count of programs using this as PCR */ - gint pcr_ref; + gint pcr_ref; /* last time PCR written */ gint64 last_pcr; @@ -216,37 +218,46 @@ struct TsMuxStream { /* Opus */ gboolean is_opus; guint8 opus_channel_config_code; + + /* Google VPx */ + gboolean is_vpx; + guint8 vpx_version; + gint vpx_profile; + gint vpx_width; + gint vpx_height; + gint vpx_fr_num; + gint vpx_fr_den; + }; /* stream management */ -TsMuxStream * tsmux_stream_new (guint16 pid, TsMuxStreamType stream_type); -void tsmux_stream_free (TsMuxStream *stream); +TsMuxStream *tsmux_stream_new (guint16 pid, TsMuxStreamType stream_type); +void tsmux_stream_free (TsMuxStream * stream); -guint16 tsmux_stream_get_pid (TsMuxStream *stream); +guint16 tsmux_stream_get_pid (TsMuxStream * stream); -void tsmux_stream_set_buffer_release_func (TsMuxStream *stream, - TsMuxStreamBufferReleaseFunc func); +void tsmux_stream_set_buffer_release_func (TsMuxStream * stream, + TsMuxStreamBufferReleaseFunc func); /* Add a new buffer to the pool of available bytes. If pts or dts are not -1, they * indicate the PTS or DTS of the first access unit within this packet */ -void tsmux_stream_add_data (TsMuxStream *stream, guint8 *data, guint len, - void *user_data, gint64 pts, gint64 dts, - gboolean random_access); +void tsmux_stream_add_data (TsMuxStream * stream, guint8 * data, guint len, + void *user_data, gint64 pts, gint64 dts, gboolean random_access); -void tsmux_stream_pcr_ref (TsMuxStream *stream); -void tsmux_stream_pcr_unref (TsMuxStream *stream); -gboolean tsmux_stream_is_pcr (TsMuxStream *stream); +void tsmux_stream_pcr_ref (TsMuxStream * stream); +void tsmux_stream_pcr_unref (TsMuxStream * stream); +gboolean tsmux_stream_is_pcr (TsMuxStream * stream); -gboolean tsmux_stream_at_pes_start (TsMuxStream *stream); -void tsmux_stream_get_es_descrs (TsMuxStream *stream, GstMpegtsPMTStream *pmt_stream); +gboolean tsmux_stream_at_pes_start (TsMuxStream * stream); +void tsmux_stream_get_es_descrs (TsMuxStream * stream, + GstMpegtsPMTStream * pmt_stream); -gint tsmux_stream_bytes_in_buffer (TsMuxStream *stream); -gint tsmux_stream_bytes_avail (TsMuxStream *stream); -gboolean tsmux_stream_initialize_pes_packet (TsMuxStream *stream); -gboolean tsmux_stream_get_data (TsMuxStream *stream, guint8 *buf, guint len); +gint tsmux_stream_bytes_in_buffer (TsMuxStream * stream); +gint tsmux_stream_bytes_avail (TsMuxStream * stream); +gboolean tsmux_stream_initialize_pes_packet (TsMuxStream * stream); +gboolean tsmux_stream_get_data (TsMuxStream * stream, guint8 * buf, guint len); -guint64 tsmux_stream_get_pts (TsMuxStream *stream); +guint64 tsmux_stream_get_pts (TsMuxStream * stream); G_END_DECLS - #endif -- 2.9.3