[FFmpeg-devel] [PATCH v2] avformat/avcodec: Add DTS-UHD demuxer and parser, movenc support.

Michael Niedermayer michael at niedermayer.cc
Sun Apr 16 22:55:46 EEST 2023


Hi

On Sat, Apr 15, 2023 at 01:04:42PM -0700, Roy Funderburk wrote:
> 
> Parsing and demuxing of DTS-UHD input files per ETSI TS 102 114 is added
> as demuxer "dtsuhd".  movenc supports DTS-UHD audio track.
> 
> Signed-off-by: Roy Funderburk <Roy.Funderburk at xperi.com>
> ---
>  Changelog                  |   1 +
>  configure                  |   1 +
>  doc/general_contents.texi  |   1 +
>  libavcodec/Makefile        |   1 +
>  libavcodec/codec_desc.c    |   7 +
>  libavcodec/codec_id.h      |   1 +
>  libavcodec/dtsuhd_common.c | 991 +++++++++++++++++++++++++++++++++++++
>  libavcodec/dtsuhd_common.h |  84 ++++
>  libavcodec/dtsuhd_parser.c | 141 ++++++
>  libavcodec/parsers.c       |   1 +
>  libavformat/Makefile       |   1 +
>  libavformat/allformats.c   |   1 +
>  libavformat/dtshddec.c     |   2 +-
>  libavformat/dtsuhddec.c    | 214 ++++++++
>  libavformat/movenc.c       |  32 ++
>  libavformat/version.h      |   2 +-
>  16 files changed, 1479 insertions(+), 2 deletions(-)
>  create mode 100644 libavcodec/dtsuhd_common.c
>  create mode 100644 libavcodec/dtsuhd_common.h
>  create mode 100644 libavcodec/dtsuhd_parser.c
>  create mode 100644 libavformat/dtsuhddec.c
> 
[...]

> +/* In the specification, the pseudo code defaults the 'add' parameter to true.
> +   Table 7-30 shows passing an explicit false, most other calls do not
> +   pass the extractAndAdd parameter.
> +
> +   Function based on code in Table 5-2
> +*/
> +static int get_bits_var(GetBitContext *gb, const uint8_t table[], int add)
> +{
> +    static const int bits_used[8] = { 1, 1, 1, 1, 2, 2, 3, 3 };
> +    static const int index_table[8] = { 0, 0, 0, 0, 1, 1, 2, 3 };
> +    int code = show_bits(gb, 3); /* value range is [0, 7] */
> +    int i;
> +    int index = index_table[code];
> +    int value = 0;
> +
> +    skip_bits(gb, bits_used[code]);
> +    if (table[index] > 0) {
> +        if (add) {
> +            for (i = 0; i < index; i++)
> +                value += 1 << table[i];
> +        }
> +        value += get_bits_long(gb, table[index]);
> +    }

If the speed of this matters,
you could remove the indirection by index_table and remove teh add code, that
would add 12 entries to some of these tables

something like:

int code = show_bits(gb, 3);
skip_bits(gb, bits_used[code]);
if (table[code][0] == 0)
    return 0;
return get_bits_long(gb, table[code][0]) + table[code][1];
    
OTOH if speed doesnt matter then this can probably be left as is


[...]
> +
> +/* Table 6-9 p 38 */
> +static int check_crc(DTSUHD *h, int bit, int bytes)
> +{
> +    GetBitContext gb;
> +    int i;
> +    static const uint16_t lookup[16] = {
> +        0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
> +        0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF
> +    };
> +    uint16_t crc = 0xFFFF;
> +
> +    init_get_bits(&gb, h->data, h->data_bytes * 8);
> +    skip_bits(&gb, bit);
> +    for (i = -bytes; i < bytes; i++)
> +        crc = (crc << 4) ^ lookup[(crc >> 12) ^ get_bits(&gb, 4)];
> +
> +    return crc != 0;
> +}

likely should use libavutil/crc.h


[...]

> +/* Table 7-26 */
> +static void parse_ch_mask_params(DTSUHD *h, MD01 *md01, MDObject *object)
> +{
> +    GetBitContext *gb = &h->gb;
> +    const int ch_index = object->rep_type == REP_TYPE_BINAURAL ? 1 : get_bits(gb, 4);
> +    static const int mask_table[14] = { /* Table 7-27 */
> +        0x000001, 0x000002, 0x000006, 0x00000F, 0x00001F, 0x00084B, 0x00002F,
> +        0x00802F, 0x00486B, 0x00886B, 0x03FBFB, 0x000003, 0x000007, 0x000843,
> +    };
> +
> +    if (ch_index == 14)
> +        object->ch_activity_mask = get_bits(gb, 16);
> +    else if (ch_index == 15)

> +        object->ch_activity_mask = get_bits(gb, 32);

get_bits_long()

[...]

> +/** Allocate parsing handle.  The parsing handle should be used to parse
> +    one DTS:X Profile 2 Audio stream, then freed by calling DTSUHD_destroy().
> +    Do not use the same parsing handle to parse multiple audio streams.
> +
> +  @return Parsing handle for use with other functions, or NULL on failure.
> +*/
> +DTSUHD *dtsuhd_create(void)

stuff needs av / avpriv prefixes when shared between libraries other symbols arent
exported and will break build depending on build options

also minor libavcodec version needs to be +1 when adding av* symbols
and libavcodec and libavformat changes should be in 2 seperate patches



[...]
> +    if (fi) {
> +        fi->sync = h->is_sync_frame;
> +        fi->frame_bytes = h->frame_bytes;
> +        fi->sample_rate = h->sample_rate;
> +        fi->sample_count = (h->frame_duration * fi->sample_rate) / (h->clock_rate * fraction);


> +        fi->duration = (double)fi->sample_count / fi->sample_rate;

it feels as if double is not needed here
Either AVRational or a simple integer type int / int64_t in samples instead of seconds
seem better as it would be exact and no odd platform rounding difference
could happen


[...]
> +
> +/** Return the offset of the first UHD audio frame.
> +    When supplied a buffer containing DTSHDHDR file content, the DTSHD
> +    headers are skipped and the offset to the first byte of the STRMDATA
> +    chunk is returned, along with the size of that chunk.
> +
> +  @param[in] dataStart DTS:X Profile 2 file content to parse
> +  @param[in] dataSize Number of valid bytes in 'dataStart'
> +  @param[out] Number of leading DTS:X Profile 2 audio frames to discard,
> +              may be NULL
> +  @param[out] Size of STRMDATA payload, may be NULL
> +  @return STRMDATA payload offset or 0 if not a valid DTS:X Profile 2 file
> +*/
> +int dtsuhd_strmdata_payload(const uint8_t *data_start, int data_size, size_t *strmdata_size)
> +{
> +    const uint8_t *data = data_start;
> +    const uint8_t *data_end = data + data_size;
> +    uint64_t chunk_size = 0;
> +
> +    if (data + DTSUHD_CHUNK_HEADER >= data_end || memcmp(data, "DTSHDHDR", 8))
> +        return 0;
> +

> +    for (; data + DTSUHD_CHUNK_HEADER + 4 <= data_end; data += chunk_size + DTSUHD_CHUNK_HEADER) {
> +        chunk_size = AV_RB64(data + 8);
> +
> +        if (!memcmp(data, "STRMDATA", 8)) {
> +            if (strmdata_size)
> +                *strmdata_size = chunk_size;
> +            return (int)(data - data_start) + DTSUHD_CHUNK_HEADER;
> +        }
> +    }

this can infinite loop
undefined behavior for teh out of array pointers that can happen with the
"right" chunk_size
also data can decrease if one ignores that this is already undefined before


[...]
> +
> +    ffstream(st)->need_parsing = AVSTREAM_PARSE_FULL_RAW;
> +    st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
> +    st->codecpar->codec_id = s->iformat->raw_codec_id;
> +    st->codecpar->ch_layout.order = AV_CHANNEL_ORDER_NATIVE;
> +    st->codecpar->ch_layout.nb_channels = di.channel_count;
> +    st->codecpar->ch_layout.u.mask = di.ffmpeg_channel_mask;
> +    st->codecpar->codec_tag = AV_RL32(di.coding_name);
> +    st->codecpar->frame_size = 512 << di.frame_duration_code;
> +    st->codecpar->sample_rate = di.sample_rate;

you could align all the "=" below each other, that would make this look
more pretty

thx

[...]
-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

Complexity theory is the science of finding the exact solution to an
approximation. Benchmarking OTOH is finding an approximation of the exact
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 195 bytes
Desc: not available
URL: <https://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20230416/43fcd6d7/attachment.sig>


More information about the ffmpeg-devel mailing list