[FFmpeg-devel] [PATCH v7] Add support for Audible AA files

Michael Niedermayer michael at niedermayer.cc
Tue Aug 11 16:29:33 CEST 2015


On Fri, Aug 07, 2015 at 02:09:34PM +0300, Vesselin Bontchev wrote:
>  doc/demuxers.texi        |    6 
>  doc/general.texi         |    2 
>  libavformat/Makefile     |    1 
>  libavformat/aadec.c      |  305 +++++++++++++++++++++++++++++++++++++++++++++++
>  libavformat/allformats.c |    1 
>  5 files changed, 315 insertions(+)
> 6706a53b7339407d11ba55499152a61c8d234c80  0001-Add-support-for-Audible-AA-files.patch
> From 0568a9385aa024ff015adab1c8f085de73edc644 Mon Sep 17 00:00:00 2001
> From: Vesselin Bontchev <vesselin.bontchev at yandex.com>
> Date: Sun, 19 Jul 2015 23:16:36 +0200
> Subject: [PATCH] Add support for Audible AA files
> 
> https://en.wikipedia.org/wiki/Audible.com#Quality
> ---
>  doc/demuxers.texi        |   6 +
>  doc/general.texi         |   2 +
>  libavformat/Makefile     |   1 +
>  libavformat/aadec.c      | 305 +++++++++++++++++++++++++++++++++++++++++++++++
>  libavformat/allformats.c |   1 +
>  5 files changed, 315 insertions(+)
>  create mode 100644 libavformat/aadec.c
> 
> diff --git a/doc/demuxers.texi b/doc/demuxers.texi
> index e45e1af..c86e8a4 100644
> --- a/doc/demuxers.texi
> +++ b/doc/demuxers.texi
> @@ -18,6 +18,12 @@ enabled demuxers.
>  
>  The description of some of the currently available demuxers follows.
>  
> + at section aa
> +
> +Audible Format 2, 3, and 4 demuxer.
> +
> +This demuxer is used to demux Audible Format 2, 3, and 4 (.aa) files.
> +
>  @section applehttp
>  
>  Apple HTTP Live Streaming demuxer.
> diff --git a/doc/general.texi b/doc/general.texi
> index a260e79..2b782e0 100644
> --- a/doc/general.texi
> +++ b/doc/general.texi
> @@ -228,6 +228,8 @@ library:
>  @item 8088flex TMV              @tab   @tab X
>  @item AAX                       @tab   @tab X
>      @tab Audible Enhanced Audio format, used in audiobooks.
> + at item AA                        @tab   @tab X
> +    @tab Audible Format 2, 3, and 4, used in audiobooks.
>  @item ACT Voice                 @tab   @tab X
>      @tab contains G.729 audio
>  @item Adobe Filmstrip           @tab X @tab X
> diff --git a/libavformat/Makefile b/libavformat/Makefile
> index cc73fd8..466da51 100644
> --- a/libavformat/Makefile
> +++ b/libavformat/Makefile
> @@ -59,6 +59,7 @@ OBJS-$(CONFIG_SHARED)                    += log2_tab.o golomb_tab.o
>  
>  # muxers/demuxers
>  OBJS-$(CONFIG_A64_MUXER)                 += a64.o rawenc.o
> +OBJS-$(CONFIG_AA_DEMUXER)                += aadec.o
>  OBJS-$(CONFIG_AAC_DEMUXER)               += aacdec.o apetag.o img2.o rawdec.o
>  OBJS-$(CONFIG_AC3_DEMUXER)               += ac3dec.o rawdec.o
>  OBJS-$(CONFIG_AC3_MUXER)                 += rawenc.o
> diff --git a/libavformat/aadec.c b/libavformat/aadec.c
> new file mode 100644
> index 0000000..e336283
> --- /dev/null
> +++ b/libavformat/aadec.c
> @@ -0,0 +1,305 @@
> +/*
> + * Audible AA demuxer
> + * Copyright (c) 2015 Vesselin Bontchev
> + *
> + * Header parsing is borrowed from https://github.com/jteeuwen/audible project.
> + * Copyright (c) 2001-2014, Jim Teeuwen
> + *
> + * Redistribution and use in source and binary forms, with or without modification,
> + * are permitted provided that the following conditions are met:
> + *
> + * 1. Redistributions of source code must retain the above copyright notice, this
> + *    list of conditions and the following disclaimer.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
> + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
> + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
> + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
> + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
> + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
> + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
> + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + */
> +
> +#include "avformat.h"
> +#include "internal.h"
> +#include "libavutil/intreadwrite.h"
> +#include "libavutil/tea.h"
> +#include "libavutil/opt.h"
> +
> +#define AA_MAGIC 1469084982 /* this identifies an audible .aa file */
> +#define MAX_CODEC_SECOND_SIZE 3982
> +#define MAX_TOC_ENTRIES 16
> +#define MAX_DICTIONARY_ENTRIES 128
> +#define TEA_BLOCK_SIZE 8
> +
> +typedef struct AADemuxContext {
> +    AVClass *class;
> +    uint8_t *aa_fixed_key;
> +    int aa_fixed_key_len;
> +    int32_t codec_second_size;
> +    struct AVTEA *tea_ctx;
> +    uint8_t file_key[16];
> +    int64_t current_chapter_size;
> +    int64_t current_codec_second_size;
> +    int chapter_idx;
> +} AADemuxContext;
> +

> +static int32_t get_second_size(char *codec_name)

why int32 and not int ?



> +{
> +    int32_t result = -1;
> +
> +    if (!strcmp(codec_name, "mp332")) {
> +        result = 3982;
> +    } else if (!strcmp(codec_name, "acelp16")) {
> +        result = 2000;
> +    } else if (!strcmp(codec_name, "acelp85")) {
> +        result = 1045;
> +    }
> +
> +    return result;
> +}
> +
> +static int aa_read_header(AVFormatContext *s)
> +{
> +    int i, j, idx, largest_idx = -1;
> +    uint32_t nkey, nval, toc_size, npairs, header_seed, start;
> +    char key[128], val[128], codec_name[64] = {0};
> +    uint8_t output[24], dst[8], src[8];
> +    int64_t largest_size = -1, current_size = -1;
> +    struct toc_entry {
> +        uint32_t offset;
> +        uint32_t size;
> +    } TOC[MAX_TOC_ENTRIES];
> +    union {
> +        uint8_t key[16];
> +        uint32_t part[4];
> +    } header_key;
> +    AADemuxContext *c = s->priv_data;
> +    AVIOContext *pb = s->pb;
> +    AVStream *st;
> +
> +    /* parse .aa header */
> +    avio_skip(pb, 4); // file size
> +    avio_skip(pb, 4); // magic string
> +    toc_size = avio_rb32(pb); // TOC size
> +    avio_skip(pb, 4); // unidentified integer
> +    if (toc_size > MAX_TOC_ENTRIES)
> +        return AVERROR_INVALIDDATA;
> +    for (i = 0; i < toc_size; i++) { // read TOC
> +        avio_skip(pb, 4); // TOC entry index
> +        TOC[i].offset = avio_rb32(pb); // block offset
> +        TOC[i].size = avio_rb32(pb); // block size
> +    }




> +    avio_skip(pb, 24); // header termination block (ignored)
> +    npairs = avio_rb32(pb); // read dictionary entries
> +    if (npairs > MAX_DICTIONARY_ENTRIES)
> +        return AVERROR_INVALIDDATA;
> +    for (i = 0; i < npairs; i++) {
> +        memset(val, 0, sizeof(val));
> +        memset(key, 0, sizeof(key));
> +        avio_skip(pb, 1); // unidentified integer
> +        nkey = avio_rb32(pb); // key string length
> +        nval = avio_rb32(pb); // value string length
> +        if (nkey > sizeof(key)) {
> +            avio_skip(pb, nkey);
> +        } else {
> +            avio_read(pb, key, nkey); // key string
> +        }
> +        if (nval > sizeof(val)) {
> +            avio_skip(pb, nval);
> +        } else {
> +            avio_read(pb, val, nval); // value string
> +        }
> +        if (!strcmp(key, "codec")) {
> +            strncpy(codec_name, val, sizeof(codec_name) - 1);
> +        }
> +        if (!strcmp(key, "HeaderSeed")) {

> +            header_seed = atoi(val);

missing error checking


> +        }
> +        if (!strcmp(key, "HeaderKey")) {

> +            sscanf(val, "%d%d%d%d", &header_key.part[0], &header_key.part[1], &header_key.part[2], &header_key.part[3]);

does "%d%d" work ? doesnt this parse the whole number as the first
argument ?



> +            for (idx = 0; idx < 4; idx++) {

> +                header_key.part[idx] = AV_RB32(&header_key.part[idx]); // convert to BE!

this is a bit messy
reading into a union int[]+byte[] array as int then doing some
bswap in the int basically and then using the bytes

why is this a union at all ?
2 seperate arrays seem cleaner or do i miss something?
and using AV_WB32() to write big endian values also seems more logic
than AV_RB32() but thats just personal taste, feel free to ignore ...

[...]

-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

When the tyrant has disposed of foreign enemies by conquest or treaty, and
there is nothing more to fear from them, then he is always stirring up
some war or other, in order that the people may require a leader. -- Plato
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 181 bytes
Desc: Digital signature
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20150811/441b6a40/attachment.sig>


More information about the ffmpeg-devel mailing list