[FFmpeg-devel,10/12] lavf/mxfdec: demux s436m as eia608 subtitle track

Submitted by Baptiste Coudurier on July 4, 2018, 6:35 p.m.

Details

Message ID 20180704183514.71654-10-baptiste.coudurier@gmail.com
State Accepted
Headers show

Commit Message

Baptiste Coudurier July 4, 2018, 6:35 p.m.
---
 libavformat/mxfdec.c | 102 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 102 insertions(+)

Comments

Marton Balint July 4, 2018, 8:50 p.m.
On Wed, 4 Jul 2018, Baptiste Coudurier wrote:

> ---
> libavformat/mxfdec.c | 102 +++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 102 insertions(+)
>
> diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c
> index 3f443bbbc9..54e4be7934 100644
> --- a/libavformat/mxfdec.c
> +++ b/libavformat/mxfdec.c
> @@ -52,6 +52,7 @@
> #include "libavutil/intreadwrite.h"
> #include "libavutil/parseutils.h"
> #include "libavutil/timecode.h"
> +#include "libavutil/opt.h"
> #include "avformat.h"
> #include "internal.h"
> #include "mxf.h"
> @@ -263,6 +264,7 @@ typedef struct MXFIndexTable {
> } MXFIndexTable;
> 
> typedef struct MXFContext {
> +    const AVClass *class;     /**< Class for private options. */
>     MXFPartition *partitions;
>     unsigned partitions_count;
>     MXFOP op;
> @@ -287,6 +289,8 @@ typedef struct MXFContext {
>     int64_t current_edit_unit;
>     int nb_index_tables;
>     MXFIndexTable *index_tables;
> +    int edit_units_per_packet;      ///< how many edit units to read at a time (PCM, OPAtom)

This seems unused, probably remained after a merge. (edit_units_per_packet 
is now an MXFTrack property).

> +    int eia608_extract;
> } MXFContext;
> 
> /* NOTE: klv_offset is not set (-1) for local keys */
> @@ -449,6 +453,78 @@ static int find_body_sid_by_offset(MXFContext *mxf, int64_t offset)
>     return mxf->partitions[a].body_sid;
> }
> 
> +static int mxf_get_eia608_packet(AVFormatContext *s, AVStream *st, AVPacket *pkt, int64_t length)
> +{
> +    int count = avio_rb16(s->pb);
> +    int i, ret;
> +
> +    for (i = 0; i < count; i++) {
> +        if (length < 6) {
> +            av_log(s, AV_LOG_ERROR, "error reading s436m packet %"PRId64"\n", length);
> +            return AVERROR_INVALIDDATA;
> +        }
> +        int line_num = avio_rb16(s->pb);
> +        int wrapping_type = avio_r8(s->pb);
> +        int sample_coding = avio_r8(s->pb);
> +        int sample_count = avio_rb16(s->pb);
> +        av_log(s, AV_LOG_DEBUG, "len %"PRId64" line %d wrap type %d coding %d count %d\n",
> +               length, line_num, wrapping_type, sample_coding, sample_count);
> +        length -= 6 + 8 + sample_count;
> +        if (line_num != 9 && line_num != 11)
> +            break;
> +        if (sample_coding == 7 || sample_coding == 8 || sample_coding == 9) {
> +            av_log(s, AV_LOG_ERROR, "unsupported s436m 10 bit sample coding\n");
> +            return 0;
> +        }
> +        if (length < 0)
> +            return AVERROR_INVALIDDATA;
> +
> +        int array_count = avio_rb32(s->pb);
> +        int array_elem_size = avio_rb32(s->pb);
> +        av_log(s, AV_LOG_DEBUG, "array count %d elem size %d\n", array_count, array_elem_size);
> +        int did = avio_r8(s->pb);
> +        int sdid = avio_r8(s->pb);
> +        int data_count = avio_r8(s->pb);
> +        av_log(s, AV_LOG_DEBUG, "did %x sdid %x count %d\n", did, sdid, data_count);
> +        if (did != 0x61)
> +            break;
> +        int cdp_id = avio_rb16(s->pb);
> +        int cdp_data_count = avio_r8(s->pb);
> +        int cdp_framing_rate = avio_r8(s->pb) >> 4;
> +        int cdp_flags = avio_r8(s->pb);
> +        int cdp_counter = avio_rb16(s->pb);
> +        int cdp_data_section = avio_r8(s->pb);
> +        if (cdp_data_section != 0x72) {
> +            av_log(s, AV_LOG_ERROR, "wrong cdp data section %x\n", cdp_data_section);
> +            return AVERROR_INVALIDDATA;
> +        }
> +        int flags = avio_r8(s->pb);
> +        int cc_count = flags & 0x1f;
> +        av_log(s, AV_LOG_DEBUG, "cdp id %x dcount %d frame rate %d cdp flags %x flags %x "
> +               "cc count %d counter %d section %x\n", cdp_id, cdp_data_count, cdp_framing_rate,
> +               cdp_flags, flags, cc_count, cdp_counter, cdp_data_section);
> +        ret = av_get_packet(s->pb, pkt, cc_count * 3);
> +        if (ret < 0)
> +            return ret;
> +        if (cdp_data_count - 9 - 4 <  cc_count * 3) {
> +            av_log(s, AV_LOG_ERROR, "wrong cdp size %d cc count %d\n", data_count, cc_count);
> +            return AVERROR_INVALIDDATA;
> +        }
> +        avio_skip(s->pb, data_count - 9 - 4 - cc_count * 3);
> +        int cdp_footer_section = avio_r8(s->pb);
> +        if (cdp_footer_section != 0x74) {
> +            av_log(s, AV_LOG_ERROR, "wrong cdp footer section %x\n", cdp_footer_section);
> +            return AVERROR_INVALIDDATA;
> +        }
> +        int cdp_counter2 = avio_rb16(s->pb);
> +        int cdp_checksum = avio_r8(s->pb);
> +        av_log(s, AV_LOG_DEBUG, "cdp counter %d checksum %x\n", cdp_counter2, cdp_checksum);
> +        break;
> +    }
> +
> +    return 0;
> +}
> +
> /* XXX: use AVBitStreamFilter */
> static int mxf_get_d10_aes3_packet(AVIOContext *pb, AVStream *st, AVPacket *pkt, int64_t length)
> {
> @@ -2415,6 +2491,11 @@ static int mxf_parse_structural_metadata(MXFContext *mxf)
>                 st->codecpar->codec_type = type;
>             if (container_ul->desc)
>                 av_dict_set(&st->metadata, "data_type", container_ul->desc, 0);
> +            if (mxf->eia608_extract &&
> +                !strcmp(container_ul->desc, "vbi_vanc_smpte_436M")) {
> +                st->codecpar->codec_type = AVMEDIA_TYPE_SUBTITLE;
> +                st->codecpar->codec_id = AV_CODEC_ID_EIA_608;
> +            }
>         }
>         if (descriptor->extradata) {
>             if (!ff_alloc_extradata(st->codecpar, descriptor->extradata_size)) {
> @@ -3356,6 +3437,11 @@ static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt)
>                     av_log(s, AV_LOG_ERROR, "error reading D-10 aes3 frame\n");
>                     return ret;
>                 }
> +            } else if (mxf->eia608_extract &&
> +                       s->streams[index]->codecpar->codec_id == AV_CODEC_ID_EIA_608) {
> +                ret = mxf_get_eia608_packet(s, s->streams[index], pkt, klv.length);
> +                if (ret < 0)
> +                    return ret;

After my clip wrapped patches this probably needs to be:

                    if (ret < 0) {
                        mxf->current_klv_data = (KLVPacket){{0}};
                        return ret;
                    }

Thanks,
Marton
Baptiste Coudurier Oct. 12, 2018, 7:35 p.m.
On Wed, Jul 4, 2018 at 1:50 PM Marton Balint <cus@passwd.hu> wrote:

>
>
> On Wed, 4 Jul 2018, Baptiste Coudurier wrote:
>
> > ---
> > libavformat/mxfdec.c | 102 +++++++++++++++++++++++++++++++++++++++++++
> > 1 file changed, 102 insertions(+)
> >
> > diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c
> > index 3f443bbbc9..54e4be7934 100644
> > --- a/libavformat/mxfdec.c
> > +++ b/libavformat/mxfdec.c
> > @@ -52,6 +52,7 @@
> > #include "libavutil/intreadwrite.h"
> > #include "libavutil/parseutils.h"
> > #include "libavutil/timecode.h"
> > +#include "libavutil/opt.h"
> > #include "avformat.h"
> > #include "internal.h"
> > #include "mxf.h"
> > @@ -263,6 +264,7 @@ typedef struct MXFIndexTable {
> > } MXFIndexTable;
> >
> > typedef struct MXFContext {
> > +    const AVClass *class;     /**< Class for private options. */
> >     MXFPartition *partitions;
> >     unsigned partitions_count;
> >     MXFOP op;
> > @@ -287,6 +289,8 @@ typedef struct MXFContext {
> >     int64_t current_edit_unit;
> >     int nb_index_tables;
> >     MXFIndexTable *index_tables;
> > +    int edit_units_per_packet;      ///< how many edit units to read at
> a time (PCM, OPAtom)
>
> This seems unused, probably remained after a merge. (edit_units_per_packet
> is now an MXFTrack property).
>
> > +    int eia608_extract;
> > } MXFContext;
> >
> > /* NOTE: klv_offset is not set (-1) for local keys */
> > @@ -449,6 +453,78 @@ static int find_body_sid_by_offset(MXFContext *mxf,
> int64_t offset)
> >     return mxf->partitions[a].body_sid;
> > }
> >
> > +static int mxf_get_eia608_packet(AVFormatContext *s, AVStream *st,
> AVPacket *pkt, int64_t length)
> > +{
> > +    int count = avio_rb16(s->pb);
> > +    int i, ret;
> > +
> > +    for (i = 0; i < count; i++) {
> > +        if (length < 6) {
> > +            av_log(s, AV_LOG_ERROR, "error reading s436m packet
> %"PRId64"\n", length);
> > +            return AVERROR_INVALIDDATA;
> > +        }
> > +        int line_num = avio_rb16(s->pb);
> > +        int wrapping_type = avio_r8(s->pb);
> > +        int sample_coding = avio_r8(s->pb);
> > +        int sample_count = avio_rb16(s->pb);
> > +        av_log(s, AV_LOG_DEBUG, "len %"PRId64" line %d wrap type %d
> coding %d count %d\n",
> > +               length, line_num, wrapping_type, sample_coding,
> sample_count);
> > +        length -= 6 + 8 + sample_count;
> > +        if (line_num != 9 && line_num != 11)
> > +            break;
> > +        if (sample_coding == 7 || sample_coding == 8 || sample_coding
> == 9) {
> > +            av_log(s, AV_LOG_ERROR, "unsupported s436m 10 bit sample
> coding\n");
> > +            return 0;
> > +        }
> > +        if (length < 0)
> > +            return AVERROR_INVALIDDATA;
> > +
> > +        int array_count = avio_rb32(s->pb);
> > +        int array_elem_size = avio_rb32(s->pb);
> > +        av_log(s, AV_LOG_DEBUG, "array count %d elem size %d\n",
> array_count, array_elem_size);
> > +        int did = avio_r8(s->pb);
> > +        int sdid = avio_r8(s->pb);
> > +        int data_count = avio_r8(s->pb);
> > +        av_log(s, AV_LOG_DEBUG, "did %x sdid %x count %d\n", did, sdid,
> data_count);
> > +        if (did != 0x61)
> > +            break;
> > +        int cdp_id = avio_rb16(s->pb);
> > +        int cdp_data_count = avio_r8(s->pb);
> > +        int cdp_framing_rate = avio_r8(s->pb) >> 4;
> > +        int cdp_flags = avio_r8(s->pb);
> > +        int cdp_counter = avio_rb16(s->pb);
> > +        int cdp_data_section = avio_r8(s->pb);
> > +        if (cdp_data_section != 0x72) {
> > +            av_log(s, AV_LOG_ERROR, "wrong cdp data section %x\n",
> cdp_data_section);
> > +            return AVERROR_INVALIDDATA;
> > +        }
> > +        int flags = avio_r8(s->pb);
> > +        int cc_count = flags & 0x1f;
> > +        av_log(s, AV_LOG_DEBUG, "cdp id %x dcount %d frame rate %d cdp
> flags %x flags %x "
> > +               "cc count %d counter %d section %x\n", cdp_id,
> cdp_data_count, cdp_framing_rate,
> > +               cdp_flags, flags, cc_count, cdp_counter,
> cdp_data_section);
> > +        ret = av_get_packet(s->pb, pkt, cc_count * 3);
> > +        if (ret < 0)
> > +            return ret;
> > +        if (cdp_data_count - 9 - 4 <  cc_count * 3) {
> > +            av_log(s, AV_LOG_ERROR, "wrong cdp size %d cc count %d\n",
> data_count, cc_count);
> > +            return AVERROR_INVALIDDATA;
> > +        }
> > +        avio_skip(s->pb, data_count - 9 - 4 - cc_count * 3);
> > +        int cdp_footer_section = avio_r8(s->pb);
> > +        if (cdp_footer_section != 0x74) {
> > +            av_log(s, AV_LOG_ERROR, "wrong cdp footer section %x\n",
> cdp_footer_section);
> > +            return AVERROR_INVALIDDATA;
> > +        }
> > +        int cdp_counter2 = avio_rb16(s->pb);
> > +        int cdp_checksum = avio_r8(s->pb);
> > +        av_log(s, AV_LOG_DEBUG, "cdp counter %d checksum %x\n",
> cdp_counter2, cdp_checksum);
> > +        break;
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> > /* XXX: use AVBitStreamFilter */
> > static int mxf_get_d10_aes3_packet(AVIOContext *pb, AVStream *st,
> AVPacket *pkt, int64_t length)
> > {
> > @@ -2415,6 +2491,11 @@ static int
> mxf_parse_structural_metadata(MXFContext *mxf)
> >                 st->codecpar->codec_type = type;
> >             if (container_ul->desc)
> >                 av_dict_set(&st->metadata, "data_type",
> container_ul->desc, 0);
> > +            if (mxf->eia608_extract &&
> > +                !strcmp(container_ul->desc, "vbi_vanc_smpte_436M")) {
> > +                st->codecpar->codec_type = AVMEDIA_TYPE_SUBTITLE;
> > +                st->codecpar->codec_id = AV_CODEC_ID_EIA_608;
> > +            }
> >         }
> >         if (descriptor->extradata) {
> >             if (!ff_alloc_extradata(st->codecpar,
> descriptor->extradata_size)) {
> > @@ -3356,6 +3437,11 @@ static int mxf_read_packet_old(AVFormatContext
> *s, AVPacket *pkt)
> >                     av_log(s, AV_LOG_ERROR, "error reading D-10 aes3
> frame\n");
> >                     return ret;
> >                 }
> > +            } else if (mxf->eia608_extract &&
> > +                       s->streams[index]->codecpar->codec_id ==
> AV_CODEC_ID_EIA_608) {
> > +                ret = mxf_get_eia608_packet(s, s->streams[index], pkt,
> klv.length);
> > +                if (ret < 0)
> > +                    return ret;
>
> After my clip wrapped patches this probably needs to be:
>
>                     if (ret < 0) {
>                         mxf->current_klv_data = (KLVPacket){{0}};
>                         return ret;
>                     }
>

Fixed and applied.

Patch hide | download patch | download mbox

diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c
index 3f443bbbc9..54e4be7934 100644
--- a/libavformat/mxfdec.c
+++ b/libavformat/mxfdec.c
@@ -52,6 +52,7 @@ 
 #include "libavutil/intreadwrite.h"
 #include "libavutil/parseutils.h"
 #include "libavutil/timecode.h"
+#include "libavutil/opt.h"
 #include "avformat.h"
 #include "internal.h"
 #include "mxf.h"
@@ -263,6 +264,7 @@  typedef struct MXFIndexTable {
 } MXFIndexTable;
 
 typedef struct MXFContext {
+    const AVClass *class;     /**< Class for private options. */
     MXFPartition *partitions;
     unsigned partitions_count;
     MXFOP op;
@@ -287,6 +289,8 @@  typedef struct MXFContext {
     int64_t current_edit_unit;
     int nb_index_tables;
     MXFIndexTable *index_tables;
+    int edit_units_per_packet;      ///< how many edit units to read at a time (PCM, OPAtom)
+    int eia608_extract;
 } MXFContext;
 
 /* NOTE: klv_offset is not set (-1) for local keys */
@@ -449,6 +453,78 @@  static int find_body_sid_by_offset(MXFContext *mxf, int64_t offset)
     return mxf->partitions[a].body_sid;
 }
 
+static int mxf_get_eia608_packet(AVFormatContext *s, AVStream *st, AVPacket *pkt, int64_t length)
+{
+    int count = avio_rb16(s->pb);
+    int i, ret;
+
+    for (i = 0; i < count; i++) {
+        if (length < 6) {
+            av_log(s, AV_LOG_ERROR, "error reading s436m packet %"PRId64"\n", length);
+            return AVERROR_INVALIDDATA;
+        }
+        int line_num = avio_rb16(s->pb);
+        int wrapping_type = avio_r8(s->pb);
+        int sample_coding = avio_r8(s->pb);
+        int sample_count = avio_rb16(s->pb);
+        av_log(s, AV_LOG_DEBUG, "len %"PRId64" line %d wrap type %d coding %d count %d\n",
+               length, line_num, wrapping_type, sample_coding, sample_count);
+        length -= 6 + 8 + sample_count;
+        if (line_num != 9 && line_num != 11)
+            break;
+        if (sample_coding == 7 || sample_coding == 8 || sample_coding == 9) {
+            av_log(s, AV_LOG_ERROR, "unsupported s436m 10 bit sample coding\n");
+            return 0;
+        }
+        if (length < 0)
+            return AVERROR_INVALIDDATA;
+
+        int array_count = avio_rb32(s->pb);
+        int array_elem_size = avio_rb32(s->pb);
+        av_log(s, AV_LOG_DEBUG, "array count %d elem size %d\n", array_count, array_elem_size);
+        int did = avio_r8(s->pb);
+        int sdid = avio_r8(s->pb);
+        int data_count = avio_r8(s->pb);
+        av_log(s, AV_LOG_DEBUG, "did %x sdid %x count %d\n", did, sdid, data_count);
+        if (did != 0x61)
+            break;
+        int cdp_id = avio_rb16(s->pb);
+        int cdp_data_count = avio_r8(s->pb);
+        int cdp_framing_rate = avio_r8(s->pb) >> 4;
+        int cdp_flags = avio_r8(s->pb);
+        int cdp_counter = avio_rb16(s->pb);
+        int cdp_data_section = avio_r8(s->pb);
+        if (cdp_data_section != 0x72) {
+            av_log(s, AV_LOG_ERROR, "wrong cdp data section %x\n", cdp_data_section);
+            return AVERROR_INVALIDDATA;
+        }
+        int flags = avio_r8(s->pb);
+        int cc_count = flags & 0x1f;
+        av_log(s, AV_LOG_DEBUG, "cdp id %x dcount %d frame rate %d cdp flags %x flags %x "
+               "cc count %d counter %d section %x\n", cdp_id, cdp_data_count, cdp_framing_rate,
+               cdp_flags, flags, cc_count, cdp_counter, cdp_data_section);
+        ret = av_get_packet(s->pb, pkt, cc_count * 3);
+        if (ret < 0)
+            return ret;
+        if (cdp_data_count - 9 - 4 <  cc_count * 3) {
+            av_log(s, AV_LOG_ERROR, "wrong cdp size %d cc count %d\n", data_count, cc_count);
+            return AVERROR_INVALIDDATA;
+        }
+        avio_skip(s->pb, data_count - 9 - 4 - cc_count * 3);
+        int cdp_footer_section = avio_r8(s->pb);
+        if (cdp_footer_section != 0x74) {
+            av_log(s, AV_LOG_ERROR, "wrong cdp footer section %x\n", cdp_footer_section);
+            return AVERROR_INVALIDDATA;
+        }
+        int cdp_counter2 = avio_rb16(s->pb);
+        int cdp_checksum = avio_r8(s->pb);
+        av_log(s, AV_LOG_DEBUG, "cdp counter %d checksum %x\n", cdp_counter2, cdp_checksum);
+        break;
+    }
+
+    return 0;
+}
+
 /* XXX: use AVBitStreamFilter */
 static int mxf_get_d10_aes3_packet(AVIOContext *pb, AVStream *st, AVPacket *pkt, int64_t length)
 {
@@ -2415,6 +2491,11 @@  static int mxf_parse_structural_metadata(MXFContext *mxf)
                 st->codecpar->codec_type = type;
             if (container_ul->desc)
                 av_dict_set(&st->metadata, "data_type", container_ul->desc, 0);
+            if (mxf->eia608_extract &&
+                !strcmp(container_ul->desc, "vbi_vanc_smpte_436M")) {
+                st->codecpar->codec_type = AVMEDIA_TYPE_SUBTITLE;
+                st->codecpar->codec_id = AV_CODEC_ID_EIA_608;
+            }
         }
         if (descriptor->extradata) {
             if (!ff_alloc_extradata(st->codecpar, descriptor->extradata_size)) {
@@ -3356,6 +3437,11 @@  static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt)
                     av_log(s, AV_LOG_ERROR, "error reading D-10 aes3 frame\n");
                     return ret;
                 }
+            } else if (mxf->eia608_extract &&
+                       s->streams[index]->codecpar->codec_id == AV_CODEC_ID_EIA_608) {
+                ret = mxf_get_eia608_packet(s, s->streams[index], pkt, klv.length);
+                if (ret < 0)
+                    return ret;
             } else {
                 ret = av_get_packet(s->pb, pkt, klv.length);
                 if (ret < 0)
@@ -3596,6 +3682,21 @@  static int mxf_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti
     return 0;
 }
 
+static const AVOption options[] = {
+    { "eia608_extract", "extract eia 608 captions from s436m track",
+      offsetof(MXFContext, eia608_extract), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1,
+      AV_OPT_FLAG_DECODING_PARAM },
+    { NULL },
+};
+
+static const AVClass demuxer_class = {
+    .class_name = "mxf",
+    .item_name  = av_default_item_name,
+    .option     = options,
+    .version    = LIBAVUTIL_VERSION_INT,
+    .category   = AV_CLASS_CATEGORY_DEMUXER,
+};
+
 AVInputFormat ff_mxf_demuxer = {
     .name           = "mxf",
     .long_name      = NULL_IF_CONFIG_SMALL("MXF (Material eXchange Format)"),
@@ -3606,4 +3707,5 @@  AVInputFormat ff_mxf_demuxer = {
     .read_packet    = mxf_read_packet,
     .read_close     = mxf_read_close,
     .read_seek      = mxf_read_seek,
+    .priv_class     = &demuxer_class,
 };