Hi,

----- Mail original -----
> Hi,
> 
> ----- Mail original -----
> > On Tue, Oct 07, 2014 at 03:02:38PM +0200, Benoit Fouet wrote:
> > > Support only one independent substream right now, and only
> > > syncframes
> > > containing 6 blocks.
> > > 
> > > Fixes part of ticket #3074
> > > ---
> > > 
> > > Right now, this produces the same output as the previous patch
> > > for
> > > supported
> > > streams, and rejects the unsupported ones.
> > > Support for syncframes concatenation will come afterwards.
> > > 
> > >  libavformat/isom.c   |   1 +
> > >  libavformat/movenc.c | 184
> > >  +++++++++++++++++++++++++++++++++++++++++++++++++++
> > >  libavformat/movenc.h |   2 +
> > >  3 files changed, 187 insertions(+)
> > > 
> 
> [...]
> 
> > > diff --git a/libavformat/movenc.c b/libavformat/movenc.c
> > > index bfee866..18c5955 100644
> > > --- a/libavformat/movenc.c
> > > +++ b/libavformat/movenc.c
> 
> [...]
> 
> > > @@ -292,6 +293,178 @@ static int mov_write_ac3_tag(AVIOContext
> > > *pb,
> > > MOVTrack *track)
> 
> [...]
> 
> > > +static int handle_eac3(AVPacket *pkt, MOVTrack *track)
> > > +{
> > > +    GetBitContext gbc;
> > > +    AC3HeaderInfo tmp, *hdr = &tmp;
> > > +    struct eac3_info *info;
> > > +    int ret, num_blocks;
> > > +
> > > +    if (!track->eac3_priv && !(track->eac3_priv =
> > > av_mallocz(sizeof(*info))))
> > > +        return AVERROR(ENOMEM);
> > > +    info = track->eac3_priv;
> > > +
> > 
> > > +    init_get_bits(&gbc, pkt->data, pkt->size * 8);
> > > +    if ((ret = avpriv_ac3_parse_header2(&gbc, &hdr)) < 0)
> > > +        return ret;
> > 
> > [...]
> > > +                if ((ret = avpriv_ac3_parse_header2(&gbc, &hdr))
> > > <
> > > 0)
> > > +                    return ret;
> > 
> > these forward internal error codes like
> > AAC_AC3_PARSE_ERROR_FRAME_TYPE
> > to the lib user
> > av_strerror() for example will not be able to interpret these
> > 
> 
> True.
> 
> > also this would prevent remuxing a stream that contains a
> > single damaged packet if i understand correctly, this may be
> > annoying for sources recoded over somewhat noisy channels
> > 
> 
> Also true, though I'm not sure how to handle this. Dropping the
> packet would presumably be a way of dealing with this.
> Please note that the E-AC-3 stream passes through the E-AC-3 parser
> before muxing, so these errors shouldn't really happen in practice,
> except for the first frame (or maybe I missed something in the way
> the parser works?).
> A solution here could be to drop the packet if it is the first one,
> and error out if not (with an AV_ error code), what do you think?
> 
> > also how can this patch be tested ?
> > carls testcase from the ticket does not seem to work
> > 
> 
> If we drop the erroneous packet instead of erroring out, the testcase
> works fine.
> 

New patch attached, as reference.

-- 
Ben
From 067c95cdab127612019a50c3f6c8485a132cac18 Mon Sep 17 00:00:00 2001
From: Benoit Fouet <benoit.fo...@free.fr>
Date: Tue, 7 Oct 2014 14:57:19 +0200
Subject: [PATCH] avformat/movenc: add EAC3 muxing support.

Support only one independent substream right now, and only syncframes
containing 6 blocks.

Fixes part of ticket #3074
---
 libavformat/isom.c   |   1 +
 libavformat/movenc.c | 188 +++++++++++++++++++++++++++++++++++++++++++++++++++
 libavformat/movenc.h |   2 +
 3 files changed, 191 insertions(+)

diff --git a/libavformat/isom.c b/libavformat/isom.c
index d768c32..1509021 100644
--- a/libavformat/isom.c
+++ b/libavformat/isom.c
@@ -57,6 +57,7 @@ const AVCodecTag ff_mp4_obj_type[] = {
     { AV_CODEC_ID_VC1         , 0xA3 },
     { AV_CODEC_ID_DIRAC       , 0xA4 },
     { AV_CODEC_ID_AC3         , 0xA5 },
+    { AV_CODEC_ID_EAC3        , 0xA6 },
     { AV_CODEC_ID_DTS         , 0xA9 }, /* mp4ra.org */
     { AV_CODEC_ID_VORBIS      , 0xDD }, /* non standard, gpac uses it */
     { AV_CODEC_ID_DVD_SUBTITLE, 0xE0 }, /* non standard, see unsupported-embedded-subs-2.mp4 */
diff --git a/libavformat/movenc.c b/libavformat/movenc.c
index bfee866..f592c9c 100644
--- a/libavformat/movenc.c
+++ b/libavformat/movenc.c
@@ -31,6 +31,7 @@
 #include "avio.h"
 #include "isom.h"
 #include "avc.h"
+#include "libavcodec/ac3_parser.h"
 #include "libavcodec/get_bits.h"
 #include "libavcodec/put_bits.h"
 #include "libavcodec/vc1_common.h"
@@ -292,6 +293,182 @@ static int mov_write_ac3_tag(AVIOContext *pb, MOVTrack *track)
     return 11;
 }
 
+struct eac3_info {
+    uint8_t ec3_done;
+
+    /* Layout of the EC3SpecificBox */
+    /* maximum bitrate */
+    uint16_t data_rate;
+    /* number of independent substreams */
+    uint8_t  num_ind_sub;
+    struct {
+        /* sample rate code (see ff_ac3_sample_rate_tab) 2 bits */
+        uint8_t fscod;
+        /* bit stream identification 5 bits */
+        uint8_t bsid;
+        /* one bit reserved */
+        /* audio service mixing (not supported yet) 1 bit */
+        /* bit stream mode 3 bits */
+        uint8_t bsmod;
+        /* audio coding mode 3 bits */
+        uint8_t acmod;
+        /* sub woofer on 1 bit */
+        uint8_t lfeon;
+        /* 3 bits reserved */
+        /* number of dependent substreams associated with this substream 4 bits */
+        uint8_t num_dep_sub;
+        /* channel locations of the dependent substream(s), if any, 9 bits */
+        uint16_t chan_loc;
+        /* if there is no dependent substream, then one bit reserved instead */
+    } substream[1]; /* TODO: support 8 independent substreams */
+};
+
+static int handle_eac3(AVPacket *pkt, MOVTrack *track)
+{
+    GetBitContext gbc;
+    AC3HeaderInfo tmp, *hdr = &tmp;
+    struct eac3_info *info;
+    int num_blocks;
+
+    if (!track->eac3_priv && !(track->eac3_priv = av_mallocz(sizeof(*info))))
+        return AVERROR(ENOMEM);
+    info = track->eac3_priv;
+
+    init_get_bits(&gbc, pkt->data, pkt->size * 8);
+    if (avpriv_ac3_parse_header2(&gbc, &hdr) < 0) {
+        /* drop the packets until we see a good one */
+        if (!track->entry)
+            return 0;
+        return AVERROR_INVALIDDATA;
+    }
+
+    info->data_rate = FFMAX(info->data_rate, hdr->bit_rate);
+    num_blocks = hdr->num_blocks;
+
+    if (!info->ec3_done) {
+        /* AC-3 substream must be the first one */
+        if (hdr->bitstream_id <= 10 && hdr->substreamid != 0)
+            return AVERROR(EINVAL);
+
+        /* this should always be the case, given that our AC-3 parser
+         * concatenates dependent frames to their independent parent */
+        if (hdr->frame_type == EAC3_FRAME_TYPE_INDEPENDENT) {
+            /* substream ids must be incremental */
+            if (hdr->substreamid > info->num_ind_sub + 1)
+                return AVERROR(EINVAL);
+
+            if (hdr->substreamid == info->num_ind_sub + 1) {
+                //info->num_ind_sub++;
+                avpriv_request_sample(track->enc, "Multiple independent substreams");
+                return AVERROR_PATCHWELCOME;
+            } else if (hdr->substreamid < info->num_ind_sub ||
+                       hdr->substreamid == 0 && info->substream[0].bsid) {
+                info->ec3_done = 1;
+                goto concatenate;
+            }
+        }
+
+        /* fill the info needed for the "dec3" atom */
+        info->substream[hdr->substreamid].fscod = hdr->sr_code;
+        info->substream[hdr->substreamid].bsid  = hdr->bitstream_id;
+        info->substream[hdr->substreamid].bsmod = hdr->bitstream_mode;
+        info->substream[hdr->substreamid].acmod = hdr->channel_mode;
+        info->substream[hdr->substreamid].lfeon = hdr->lfe_on;
+
+        /* Parse dependent substream(s), if any */
+        if (pkt->size != hdr->frame_size) {
+            int cumul_size = hdr->frame_size;
+            int parent = hdr->substreamid;
+
+            while (cumul_size != pkt->size) {
+                int i;
+                init_get_bits(&gbc, pkt->data + cumul_size, (pkt->size - cumul_size) * 8);
+                if (avpriv_ac3_parse_header2(&gbc, &hdr) < 0)
+                    return AVERROR_INVALIDDATA;
+                if (hdr->frame_type != EAC3_FRAME_TYPE_DEPENDENT)
+                    return AVERROR(EINVAL);
+                cumul_size += hdr->frame_size;
+                info->substream[parent].num_dep_sub++;
+
+                /* header is parsed up to lfeon, but custom channel map may be needed */
+                /* skip bsid */
+                skip_bits(&gbc, 5);
+                /* skip volume control params */
+                for (i = 0; i < (hdr->channel_mode ? 1 : 2); i++) {
+                    skip_bits(&gbc, 5); // skip dialog normalization
+                    if (get_bits1(&gbc)) {
+                        skip_bits(&gbc, 8); // skip compression gain word
+                    }
+                }
+                /* get the dependent stream channel map, if exists */
+                if (get_bits1(&gbc))
+                    info->substream[parent].chan_loc |= (get_bits(&gbc, 16) >> 5) & 0x1f;
+                else
+                    info->substream[parent].chan_loc |= hdr->channel_mode;
+            }
+        }
+    }
+
+/* TODO: concatenate syncframes to have 6 blocks per entry */
+concatenate:
+    if (num_blocks != 6) {
+        avpriv_request_sample(track->enc, "%d block(s) in syncframe", num_blocks);
+        return AVERROR_PATCHWELCOME;
+    }
+
+    return pkt->size;
+}
+
+static int mov_write_eac3_tag(AVIOContext *pb, MOVTrack *track)
+{
+    PutBitContext pbc;
+    uint8_t *buf;
+    struct eac3_info *info;
+    int size, i;
+
+    if (!track->eac3_priv)
+        return AVERROR(EINVAL);
+
+    info = track->eac3_priv;
+    size = 2 + 4 * (info->num_ind_sub + 1);
+    buf = av_malloc(size);
+    if (!buf) {
+        av_freep(&track->eac3_priv);
+        return AVERROR(ENOMEM);
+    }
+
+    init_put_bits(&pbc, buf, size);
+    put_bits(&pbc, 13, info->data_rate);
+    put_bits(&pbc,  3, info->num_ind_sub);
+    for (i = 0; i <= info->num_ind_sub; i++) {
+        put_bits(&pbc, 2, info->substream[i].fscod);
+        put_bits(&pbc, 5, info->substream[i].bsid);
+        put_bits(&pbc, 1, 0); /* reserved */
+        put_bits(&pbc, 1, 0); /* asvc */
+        put_bits(&pbc, 3, info->substream[i].bsmod);
+        put_bits(&pbc, 3, info->substream[i].acmod);
+        put_bits(&pbc, 1, info->substream[i].lfeon);
+        put_bits(&pbc, 5, 0); /* reserved */
+        put_bits(&pbc, 4, info->substream[i].num_dep_sub);
+        if (!info->substream[i].num_dep_sub) {
+            put_bits(&pbc, 1, 0); /* reserved */
+            size--;
+        } else {
+            put_bits(&pbc, 9, info->substream[i].chan_loc);
+        }
+    }
+    flush_put_bits(&pbc);
+
+    avio_wb32(pb, size + 8);
+    ffio_wfourcc(pb, "dec3");
+    avio_write(pb, buf, size);
+
+    av_free(buf);
+    av_freep(&track->eac3_priv);
+
+    return size;
+}
+
 /**
  * This function writes extradata "as is".
  * Extradata must be formatted like a valid atom (with size and tag).
@@ -486,6 +663,8 @@ static int mov_write_wave_tag(AVIOContext *pb, MOVTrack *track)
         mov_write_amr_tag(pb, track);
     } else if (track->enc->codec_id == AV_CODEC_ID_AC3) {
         mov_write_ac3_tag(pb, track);
+    } else if (track->enc->codec_id == AV_CODEC_ID_EAC3) {
+        mov_write_eac3_tag(pb, track);
     } else if (track->enc->codec_id == AV_CODEC_ID_ALAC ||
                track->enc->codec_id == AV_CODEC_ID_QDM2) {
         mov_write_extradata_tag(pb, track);
@@ -756,6 +935,7 @@ static int mov_write_audio_tag(AVIOContext *pb, MOVTrack *track)
     if (track->mode == MODE_MOV &&
         (track->enc->codec_id == AV_CODEC_ID_AAC           ||
          track->enc->codec_id == AV_CODEC_ID_AC3           ||
+         track->enc->codec_id == AV_CODEC_ID_EAC3          ||
          track->enc->codec_id == AV_CODEC_ID_AMR_NB        ||
          track->enc->codec_id == AV_CODEC_ID_ALAC          ||
          track->enc->codec_id == AV_CODEC_ID_ADPCM_MS      ||
@@ -770,6 +950,8 @@ static int mov_write_audio_tag(AVIOContext *pb, MOVTrack *track)
         mov_write_amr_tag(pb, track);
     else if (track->enc->codec_id == AV_CODEC_ID_AC3)
         mov_write_ac3_tag(pb, track);
+    else if (track->enc->codec_id == AV_CODEC_ID_EAC3)
+        mov_write_eac3_tag(pb, track);
     else if (track->enc->codec_id == AV_CODEC_ID_ALAC)
         mov_write_extradata_tag(pb, track);
     else if (track->enc->codec_id == AV_CODEC_ID_WMAPRO)
@@ -877,6 +1059,7 @@ static int mp4_get_codec_tag(AVFormatContext *s, MOVTrack *track)
     if      (track->enc->codec_id == AV_CODEC_ID_H264)      tag = MKTAG('a','v','c','1');
     else if (track->enc->codec_id == AV_CODEC_ID_HEVC)      tag = MKTAG('h','e','v','1');
     else if (track->enc->codec_id == AV_CODEC_ID_AC3)       tag = MKTAG('a','c','-','3');
+    else if (track->enc->codec_id == AV_CODEC_ID_EAC3)      tag = MKTAG('e','c','-','3');
     else if (track->enc->codec_id == AV_CODEC_ID_DIRAC)     tag = MKTAG('d','r','a','c');
     else if (track->enc->codec_id == AV_CODEC_ID_MOV_TEXT)  tag = MKTAG('t','x','3','g');
     else if (track->enc->codec_id == AV_CODEC_ID_VC1)       tag = MKTAG('v','c','-','1');
@@ -3600,6 +3783,11 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
         } else {
             size = ff_hevc_annexb2mp4(pb, pkt->data, pkt->size, 0, NULL);
         }
+    } else if (enc->codec_id == AV_CODEC_ID_EAC3) {
+        size = handle_eac3(pkt, trk);
+        if (size < 0)
+            return size;
+        avio_write(pb, pkt->data, size);
     } else {
         avio_write(pb, pkt->data, size);
     }
diff --git a/libavformat/movenc.h b/libavformat/movenc.h
index 9ce4a86..4e7db7a 100644
--- a/libavformat/movenc.h
+++ b/libavformat/movenc.h
@@ -142,6 +142,8 @@ typedef struct MOVTrack {
         int     packet_entry;
         int     slices;
     } vc1_info;
+
+    void       *eac3_priv;
 } MOVTrack;
 
 typedef struct MOVMuxContext {
-- 
2.1.0.127.g0c72b98

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel

Reply via email to