This patch aims to show some of the changes that will be needed to
support the new Opus in TS spec. It is similar to AAC in LATM.

Design comments welcome.

---
 libavcodec/allcodecs.c   |    2 ++
 libavcodec/avcodec.h     |    1 +
 libavcodec/codec_desc.c  |    7 ++++
 libavcodec/opus_parser.c |   88 ++++++++++++++++++++++++++++++++++++++++++++++
 libavcodec/opusdec.c     |   41 +++++++++++++++++++++
 libavformat/mpegts.c     |   14 +++++++-
 6 files changed, 152 insertions(+), 1 deletion(-)

diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index bd74e0b..24f0eba 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -332,6 +332,7 @@ void avcodec_register_all(void)
     REGISTER_ENCDEC (NELLYMOSER,        nellymoser);
     REGISTER_DECODER(ON2AVC,            on2avc);
     REGISTER_DECODER(OPUS,              opus);
+    REGISTER_DECODER(OPUS_TS,           opus_ts);
     REGISTER_DECODER(PAF_AUDIO,         paf_audio);
     REGISTER_DECODER(QCELP,             qcelp);
     REGISTER_DECODER(QDM2,              qdm2);
@@ -485,6 +486,7 @@ void avcodec_register_all(void)
     REGISTER_PARSER(MPEGAUDIO,          mpegaudio);
     REGISTER_PARSER(MPEGVIDEO,          mpegvideo);
     REGISTER_PARSER(OPUS,               opus);
+    REGISTER_PARSER(OPUS_TS,            opus_ts);
     REGISTER_PARSER(PNG,                png);
     REGISTER_PARSER(PNM,                pnm);
     REGISTER_PARSER(RV30,               rv30);
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index cc74aee..cc92fce 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -444,6 +444,7 @@ enum AVCodecID {
     AV_CODEC_ID_METASOUND,
     AV_CODEC_ID_PAF_AUDIO,
     AV_CODEC_ID_ON2AVC,
+    AV_CODEC_ID_OPUS_TS,

     /* subtitle codecs */
     AV_CODEC_ID_FIRST_SUBTITLE = 0x17000,          ///< A dummy ID
pointing at the start of subtitle codecs.
diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
index f0a6dad..bd042b0 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -2292,6 +2292,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
         .long_name = NULL_IF_CONFIG_SMALL("On2 Audio for Video Codec"),
         .props     = AV_CODEC_PROP_LOSSY,
     },
+    {
+        .id        = AV_CODEC_ID_OPUS_TS,
+        .type      = AVMEDIA_TYPE_AUDIO,
+        .name      = "opus_ts",
+        .long_name = NULL_IF_CONFIG_SMALL("Opus in TS syntax"),
+        .props     = AV_CODEC_PROP_LOSSY,
+    },

     /* subtitle codecs */
     {
diff --git a/libavcodec/opus_parser.c b/libavcodec/opus_parser.c
index 8a2bc22..d41beec 100644
--- a/libavcodec/opus_parser.c
+++ b/libavcodec/opus_parser.c
@@ -27,11 +27,14 @@

 #include "avcodec.h"
 #include "opus.h"
+#include "parser.h"

 typedef struct OpusParseContext {
     OpusContext ctx;
     OpusPacket pkt;
     int extradata_parsed;
+    ParseContext pc;
+    int count;
 } OpusParseContext;

 static int opus_parse(AVCodecParserContext *ctx, AVCodecContext *avctx,
@@ -68,8 +71,93 @@ fail:
     return buf_size;
 }

+#define OPUS_TS_HEADER     0x3FF000        // 0x3ff (10 bits)
+#define OPUS_TS_MASK       0x3FF000        // top 10 bits
+
+/**
+ * Find the end of the current frame in the bitstream.
+ * @return the position of the first byte of the next frame, or -1
+ */
+static int opus_ts_find_frame_end(AVCodecParserContext *s1, const uint8_t *buf,
+                                   int buf_size)
+{
+    OpusParseContext *s = s1->priv_data;
+    ParseContext *pc    = &s->pc;
+    int pic_found, i, size = 0;
+    uint32_t state;
+
+    pic_found = pc->frame_start_found;
+    state     = pc->state;
+
+    i = 0;
+    if (!pic_found) {
+        for (i = 0; i < buf_size; i++) {
+            state = (state<<8) | buf[i];
+            if ((state & OPUS_TS_MASK) == OPUS_TS_HEADER) {
+                i++;
+                s->count  = -i;
+                pic_found = 1;
+                break;
+            }
+        }
+    }
+
+    if (pic_found) {
+        /* EOF considered as end of frame */
+        if (buf_size == 0)
+            return 0;
+        while (i < buf_size-1 && buf[i] == 0xff){
+            size += buf[i];
+            i++;
+        }
+        size += buf[i];
+        if (size - s->count <= buf_size) {
+            pc->frame_start_found = 0;
+            pc->state             = -1;
+            return size - s->count;
+        }
+    }
+
+    s->count             += buf_size;
+    pc->frame_start_found = pic_found;
+    pc->state             = state;
+
+    return END_NOT_FOUND;
+}
+
+
+static int opus_parse_ts(AVCodecParserContext *ctx, AVCodecContext *avctx,
+                          const uint8_t **poutbuf, int *poutbuf_size,
+                          const uint8_t *buf, int buf_size)
+{
+    OpusParseContext *s = ctx->priv_data;
+    ParseContext *pc    = &s->pc;
+    int next;
+
+    if (ctx->flags & PARSER_FLAG_COMPLETE_FRAMES) {
+        next = buf_size;
+    } else {
+        next = opus_ts_find_frame_end(ctx, buf, buf_size);
+
+        if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) {
+            *poutbuf      = NULL;
+            *poutbuf_size = 0;
+            return buf_size;
+        }
+    }
+    *poutbuf      = buf;
+    *poutbuf_size = buf_size;
+    return next;
+}
+
 AVCodecParser ff_opus_parser = {
     .codec_ids      = { AV_CODEC_ID_OPUS },
     .priv_data_size = sizeof(OpusParseContext),
     .parser_parse   = opus_parse,
 };
+
+AVCodecParser ff_opus_ts_parser = {
+    .codec_ids      = { AV_CODEC_ID_OPUS_TS },
+    .priv_data_size = sizeof(OpusParseContext),
+    .parser_parse   = opus_parse_ts,
+};
diff --git a/libavcodec/opusdec.c b/libavcodec/opusdec.c
index bf3a54b..65991b9 100644
--- a/libavcodec/opusdec.c
+++ b/libavcodec/opusdec.c
@@ -672,3 +672,44 @@ AVCodec ff_opus_decoder = {
     .flush           = opus_decode_flush,
     .capabilities    = CODEC_CAP_DR1 | CODEC_CAP_DELAY,
 };
+
+static int opus_ts_decode_packet(AVCodecContext *avctx, void *data,
+                                  int *got_frame_ptr, AVPacket *avpkt)
+{
+    int                 err;
+    GetBitContext       gb;
+    OpusContext *c      = avctx->priv_data;
+    int offset;
+
+
+    if ((err = init_get_bits(&gb, avpkt->data, avpkt->size * 8)) < 0)
+        return err;
+
+    if (get_bits(&gb, 10) != 0x3ff)
+        return AVERROR_INVALIDDATA;
+
+    while (get_bits(&gb, 8) == 0xff){
+    }
+    get_bits(&gb, 8);
+
+    offset = get_bits_count(&gb);
+    c->nb_streams = 1;
+    avpkt->data += offset >> 3;
+    opus_decode_packet(avctx, data, got_frame_ptr, avpkt);
+
+
+    return 0;
+}
+
+AVCodec ff_opus_ts_decoder = {
+    .name            = "opus_ts",
+    .long_name       = NULL_IF_CONFIG_SMALL("Opus TS"),
+    .type            = AVMEDIA_TYPE_AUDIO,
+    .id              = AV_CODEC_ID_OPUS_TS,
+    .priv_data_size  = sizeof(OpusContext),
+    .init            = opus_decode_init,
+    .close           = opus_decode_close,
+    .decode          = opus_ts_decode_packet,
+    .flush           = opus_decode_flush,
+    .capabilities    = CODEC_CAP_DR1 | CODEC_CAP_DELAY,
+};
diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c
index fb58e1f..4d5d5d5 100644
--- a/libavformat/mpegts.c
+++ b/libavformat/mpegts.c
@@ -595,6 +595,7 @@ static const StreamType REGD_types[] = {
     { MKTAG('D', 'T', 'S', '3'), AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_DTS   },
     { MKTAG('H', 'E', 'V', 'C'), AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_HEVC  },
     { MKTAG('V', 'C', '-', '1'), AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_VC1   },
+    { MKTAG('O', 'p', 'u', 's'), AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_OPUS_TS },
     { 0 },
 };

@@ -1302,7 +1303,7 @@ int ff_parse_mpeg2_descriptor(AVFormatContext
*fc, AVStream *st, int stream_type
                               MpegTSContext *ts)
 {
     const uint8_t *desc_end;
-    int desc_len, desc_tag, desc_es_id;
+    int desc_len, desc_tag, desc_es_id, ext_desc_len, ext_desc_tag;
     char language[252];
     int i;

@@ -1423,6 +1424,17 @@ int ff_parse_mpeg2_descriptor(AVFormatContext
*fc, AVStream *st, int stream_type
         if (st->codec->codec_id == AV_CODEC_ID_NONE)
             mpegts_find_stream_type(st, st->codec->codec_tag, REGD_types);
         break;
+    case 0x7f: /* DVB extension descriptor */
+        ext_desc_tag = bytestream_get_byte(pp);
+        ext_desc_len = bytestream_get_byte(pp);
+        if (st->codec->codec_id == AV_CODEC_ID_OPUS_TS &&
+            ext_desc_tag  == 0x80){ /* User defined (provisional Opus) */
+            st->codec->channels = 2;
+            st->codec->sample_rate = 48000;
+            st->codec->sample_fmt = AV_SAMPLE_FMT_FLT;
+            st->need_parsing      = AVSTREAM_PARSE_FULL;
+        }
+        break;
     default:
         break;
     }
--
1.7.9.5
_______________________________________________
libav-devel mailing list
libav-devel@libav.org
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to