[FFmpeg-devel] [PATCH] Adobe HTTP Dynamic Streaming (HDS) demuxer improvements

Clément Bœsch u at pkh.me
Tue Apr 28 15:32:51 CEST 2015


On Tue, Apr 28, 2015 at 02:48:42PM +0200, Gorilla Maguila wrote:
[...]
> From 5bb2e85f2e7c4dfeb3569225e263ddc6a4f127cd Mon Sep 17 00:00:00 2001
> From: Developer Mobdro <developer at mobdro.com>
> Date: Tue, 28 Apr 2015 14:38:35 +0200
> Subject: [PATCH] hds demuxer
> 
> ---
>  configure                 |   8 +
>  libavformat/Makefile      |   1 +
>  libavformat/allformats.c  |   2 +-
>  libavformat/amfmetadata.c | 248 ++++++++++++++
>  libavformat/amfmetadata.h |  45 +++
>  libavformat/f4fbox.c      | 311 +++++++++++++++++
>  libavformat/f4fbox.h      | 101 ++++++
>  libavformat/f4mmanifest.c | 340 +++++++++++++++++++
>  libavformat/f4mmanifest.h |  65 ++++
>  libavformat/flvtag.c      | 385 +++++++++++++++++++++
>  libavformat/flvtag.h      |  39 +++
>  libavformat/hdsdec.c      | 826 ++++++++++++++++++++++++++++++++++++++++++++++
>  12 files changed, 2370 insertions(+), 1 deletion(-)
>  create mode 100644 libavformat/amfmetadata.c
>  create mode 100644 libavformat/amfmetadata.h
>  create mode 100644 libavformat/f4fbox.c
>  create mode 100644 libavformat/f4fbox.h
>  create mode 100644 libavformat/f4mmanifest.c
>  create mode 100644 libavformat/f4mmanifest.h
>  create mode 100644 libavformat/flvtag.c
>  create mode 100644 libavformat/flvtag.h
>  create mode 100644 libavformat/hdsdec.c
> 
> diff --git a/configure b/configure
> index 88e0d97..185f9bc 100755
> --- a/configure
> +++ b/configure
> @@ -277,6 +277,7 @@ External library support:
>    --enable-x11grab         enable X11 grabbing (legacy) [no]
>    --disable-xlib           disable xlib [autodetect]
>    --disable-zlib           disable zlib [autodetect]
> +  --disable-xml2           disable XML parsing using the C library libxml2 [autodetect]
>  

alphabetical order is welcome

>  Toolchain options:
>    --arch=ARCH              select architecture [$arch]
> @@ -1425,6 +1426,7 @@ EXTERNAL_LIBRARY_LIST="
>      x11grab
>      xlib
>      zlib
> +    xml2
>  "
>  
>  DOCUMENT_LIST="
> @@ -2482,6 +2484,7 @@ dxa_demuxer_select="riffdec"
>  eac3_demuxer_select="ac3_parser"
>  f4v_muxer_select="mov_muxer"
>  flac_demuxer_select="flac_parser"
> +hds_demuxer_select="xml2"
>  hds_muxer_select="flv_muxer"
>  hls_muxer_select="mpegts_muxer"
>  image2_alias_pix_demuxer_select="image2_demuxer"
> @@ -5014,6 +5017,11 @@ disabled  zlib || check_lib   zlib.h      zlibVersion -lz   || disable  zlib
>  disabled bzlib || check_lib2 bzlib.h BZ2_bzlibVersion -lbz2 || disable bzlib
>  disabled  lzma || check_lib2  lzma.h lzma_version_number -llzma || disable lzma
>  

> +disabled xml2 || {
> +    check_pkg_config libxml-2.0 libxml2/libxml/xmlversion.h xmlCheckVersion &&
> +    require_pkg_config libxml-2.0 libxml2/libxml/xmlversion.h xmlCheckVersion
> +} || disable xml2
> +

Please no auto-detect of external libs, and no fallback hack
(keep require_pkg_config exclusively)

>  check_lib math.h sin -lm && LIBM="-lm"
>  disabled crystalhd || check_lib libcrystalhd/libcrystalhd_if.h DtsCrystalHDVersion -lcrystalhd || disable crystalhd
>  
> diff --git a/libavformat/Makefile b/libavformat/Makefile
> index 8d9a770..d2062b7 100644
> --- a/libavformat/Makefile
> +++ b/libavformat/Makefile
> @@ -179,6 +179,7 @@ OBJS-$(CONFIG_H263_DEMUXER)              += h263dec.o rawdec.o
>  OBJS-$(CONFIG_H263_MUXER)                += rawenc.o
>  OBJS-$(CONFIG_H264_DEMUXER)              += h264dec.o rawdec.o
>  OBJS-$(CONFIG_H264_MUXER)                += rawenc.o
> +OBJS-$(CONFIG_HDS_DEMUXER)               += hdsdec.o amfmetadata.o f4mmanifest.o f4fbox.o flvtag.o
>  OBJS-$(CONFIG_HDS_MUXER)                 += hdsenc.o
>  OBJS-$(CONFIG_HEVC_DEMUXER)              += hevcdec.o rawdec.o
>  OBJS-$(CONFIG_HEVC_MUXER)                += rawenc.o
> diff --git a/libavformat/allformats.c b/libavformat/allformats.c
> index e6a9d01..d1be6d9 100644
> --- a/libavformat/allformats.c
> +++ b/libavformat/allformats.c
> @@ -141,7 +141,7 @@ void av_register_all(void)
>      REGISTER_MUXDEMUX(H261,             h261);
>      REGISTER_MUXDEMUX(H263,             h263);
>      REGISTER_MUXDEMUX(H264,             h264);
> -    REGISTER_MUXER   (HDS,              hds);
> +    REGISTER_MUXDEMUX(HDS,              hds);
>      REGISTER_MUXDEMUX(HEVC,             hevc);
>      REGISTER_MUXDEMUX(HLS,              hls);
>      REGISTER_DEMUXER (HNM,              hnm);
> diff --git a/libavformat/amfmetadata.c b/libavformat/amfmetadata.c
> new file mode 100644
> index 0000000..148f7cd
> --- /dev/null
> +++ b/libavformat/amfmetadata.c
> @@ -0,0 +1,248 @@
> +/*
> + * Adobe Action Message Format Parser
> + * Copyright (c) 2013 Cory McCarthy
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +/**
> + * @file
> + * @brief Adobe Action Message Format Parser

> + * @author Cory McCarthy

Copyright holder should be enough

> + * @see http://download.macromedia.com/f4v/video_file_format_spec_v10_1.pdf
> + * @see http://www.adobe.com/content/dam/Adobe/en/devnet/amf/pdf/amf-file-format-spec.pdf
> + */
> +
> +#include "amfmetadata.h"
> +#include "avio_internal.h"
> +#include "flv.h"
> +#include "libavutil/avstring.h"
> +#include "libavutil/intfloat.h"
> +

> +static int amf_metadata_parse_value(AVIOContext *in, AMFMetadata *metadata, const char *name);

Can't avoid this forward declaration?

> +
> +
> +static int amf_get_string(AVIOContext *ioc, char *buffer, int buffsize)
> +{
> +    int length = avio_rb16(ioc);
> +    if (length >= buffsize) {
> +        avio_skip(ioc, length);
> +        return -1;
> +    }
> +
> +    avio_read(ioc, buffer, length);
> +
> +    buffer[length] = '\0';
> +
> +    return length;
> +}
> +
> +static int amf_metadata_read_string_value(AVIOContext *in, char *str, int str_size)
> +{
> +    uint8_t type;
> +
> +    type = avio_r8(in);

> +    if(type != AMF_DATA_TYPE_STRING) {

style: here and several time later, space after if. See
http://ffmpeg.org/developer.html#toc-Coding-Rules-1

> +        av_log(NULL, AV_LOG_ERROR, "amfmetadata Expected type 2, type = %d \n", type);
> +        return -1;
> +    }
> +
> +    return amf_get_string(in, str, str_size);
> +}
> +
> +static void amf_metadata_assign_property_number(AMFMetadata *metadata,
> +    const char *name, double value)
> +{
> +    if(!av_strcasecmp("width", name)) {
> +        metadata->width = (int)value;
> +    }else if(!av_strcasecmp("height", name)) {
> +        metadata->height = (int)value;
> +    }else if(!av_strcasecmp("framerate", name)) {
> +        metadata->frame_rate = (int)value;
> +    }else if(!av_strcasecmp("videodatarate", name)) {
> +        metadata->video_data_rate = (int)value;
> +    }else if(!av_strcasecmp("audiosamplerate", name)) {
> +        metadata->audio_sample_rate = (int)value;
> +    }else if(!av_strcasecmp("audiochannels", name)) {
> +        metadata->nb_audio_channels = (int)value;
> +    }else if(!av_strcasecmp("stereo", name)) {
> +        metadata->nb_audio_channels = ((int)value) ? 2 : 1;
> +    }else if(!av_strcasecmp("audiodatarate", name)) {
> +        metadata->audio_data_rate = (int)value;
> +    }else if(!av_strcasecmp("audiocodecid", name)) {
> +        if((int)value == 10)
> +            metadata->audio_codec_id = AV_CODEC_ID_AAC;
> +    }else if(!av_strcasecmp("videocodecid", name)) {
> +        if((int)value == 7)
> +            metadata->video_codec_id = AV_CODEC_ID_H264;
> +    }
> +}
> +
> +static void amf_metadata_assign_property_string(AMFMetadata *metadata,
> +    const char *name, const char *value)
> +{
> +    if(!av_strcasecmp("audiocodecid", name)) {
> +        if(!av_strcasecmp("mp4a", value))
> +            metadata->audio_codec_id = AV_CODEC_ID_AAC;

> +	else if(!av_strcasecmp("aac", value))

Here and later: tabs are not allowed in FFmpeg, it won't be pushable.

> +            metadata->audio_codec_id = AV_CODEC_ID_AAC;
> +    }
> +    else
> +    if(!av_strcasecmp("videocodecid", name)) {
> +        if(!av_strcasecmp("avc1", value))
> +            metadata->video_codec_id = AV_CODEC_ID_H264;
> +	else if(!av_strcasecmp("h264", value))
> +	    metadata->video_codec_id = AV_CODEC_ID_H264;
> +    }
> +}
> +
> +static int amf_metadata_parse_object_property(AVIOContext *in, AMFMetadata *metadata)
> +{

> +    char name[INT16_MAX];

Here and later, this is way too large for a stack item.

> +    int ret;
> +
> +    if((ret = amf_get_string(in, name, sizeof(name))) < 0)
> +        return ret;
> +

> +    if(!strlen(name))
> +        return -1;

No need to call strlen to check only the first character.

> +
> +    return amf_metadata_parse_value(in, metadata, name);
> +}
> +
> +static int amf_metadata_parse_object(AVIOContext *in, AMFMetadata *metadata)
> +{
> +    int ret;
> +
> +    while(!avio_feof(in)) {
> +        if((ret = amf_metadata_parse_object_property(in, metadata)) < 0) {
> +            if(avio_r8(in) != AMF_END_OF_OBJECT)
> +                return ret;
> +            break;
> +        }
> +    }
> +
> +    return 0;
> +}
> +
> +static int amf_metadata_parse_strict_array(AVIOContext *in, AMFMetadata *metadata)
> +{
> +    int length;
> +    int ret;
> +
> +    length = avio_rb32(in);
> +    while(!avio_feof(in) && length > 0) {
> +        if((ret = amf_metadata_parse_value(in, metadata, NULL)) < 0)
> +            return ret;
> +        length--;
> +    }
> +
> +    return 0;
> +}
> +
> +static int amf_metadata_parse_value(AVIOContext *in, AMFMetadata *metadata, const char *name)
> +{
> +    uint8_t type;
> +    char value_str[INT16_MAX];
> +    double value_number;
> +    int ret = 0;
> +
> +    type = avio_r8(in);
> +

> +    if(type == AMF_DATA_TYPE_NUMBER) {
> +        value_number = av_int2double(avio_rb64(in));
> +        amf_metadata_assign_property_number(metadata, name, value_number);
> +    }
> +    else if(type == AMF_DATA_TYPE_BOOL) {
> +        value_number = avio_r8(in);
> +        amf_metadata_assign_property_number(metadata, name, value_number);
> +    }
> +    else if(type == AMF_DATA_TYPE_STRING) {
> +        if((ret = amf_get_string(in, value_str, sizeof(value_str))) < 0)
> +            return ret;
> +        amf_metadata_assign_property_string(metadata, name, value_str);
> +    }
> +    else if(type == AMF_DATA_TYPE_OBJECT) {
> +        ret = amf_metadata_parse_object(in, metadata);
> +    }
> +    else if(type == AMF_DATA_TYPE_MIXEDARRAY) {
> +        avio_skip(in, 4);
> +        ret = amf_metadata_parse_object(in, metadata);
> +    }
> +    else if(type == AMF_DATA_TYPE_ARRAY) {
> +        ret = amf_metadata_parse_strict_array(in, metadata);
> +    }

You can use a switch here

> +
> +    return ret;
> +}
> +
> +static int amf_metadata_parse(AVIOContext *in, AMFMetadata *metadata)
> +{
> +    char name[INT16_MAX];
> +    int ret;
> +
> +    if((ret = amf_metadata_read_string_value(in, name, sizeof(name))) < 0) {
> +        av_log(NULL, AV_LOG_ERROR, "amfmetadata Failed to read onMetadata string, ret: %d \n", ret);
> +        return ret;
> +    }
> +
> +    if(av_strcasecmp(name, "onMetaData")) {
> +        av_log(NULL, AV_LOG_ERROR, "amfmetadata Expected onMetadata, str = %s \n", name);
> +        return -1;
> +    }
> +
> +    return amf_metadata_parse_value(in, metadata, name);
> +}
> +
> +int ff_parse_amf_metadata(uint8_t *buffer, int buffer_size, AMFMetadata *metadata)
> +{
> +    AVIOContext *in;
> +    int ret;
> +
> +    if(!buffer)
> +        return 0;
> +    if(buffer_size <= 0)
> +        return 0;
> +
> +    in = avio_alloc_context(buffer, buffer_size,
> +        0, NULL, NULL, NULL, NULL);
> +    if(!in)
> +        return AVERROR(ENOMEM);
> +
> +    ret = amf_metadata_parse(in, metadata);
> +    av_freep(&in);
> +
> +    return ret;
> +}
> diff --git a/libavformat/amfmetadata.h b/libavformat/amfmetadata.h
> new file mode 100644
> index 0000000..a9ed998
> --- /dev/null
> +++ b/libavformat/amfmetadata.h
> @@ -0,0 +1,45 @@
> +/*
> + * Adobe Action Message Format Parser
> + * Copyright (c) 2013 Cory McCarthy
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +/**
> + * @file
> + * @brief Adobe Action Message Format Parser
> + * @author Cory McCarthy
> + * @see http://download.macromedia.com/f4v/video_file_format_spec_v10_1.pdf
> + * @see http://www.adobe.com/content/dam/Adobe/en/devnet/amf/pdf/amf-file-format-spec.pdf
> + */
> +
> +#include "libavcodec/avcodec.h"
> +
> +typedef struct AMFMetadata {
> +    int width;
> +    int height;
> +    int frame_rate;
> +    int audio_sample_rate;
> +    int nb_audio_channels;
> +    int audio_data_rate;
> +    int video_data_rate;
> +
> +    enum AVCodecID audio_codec_id;
> +    enum AVCodecID video_codec_id;
> +} AMFMetadata;
> +
> +int ff_parse_amf_metadata(uint8_t *buffer, int buffer_size, AMFMetadata *metadata); 
> diff --git a/libavformat/f4fbox.c b/libavformat/f4fbox.c
> new file mode 100644
> index 0000000..37f6912
> --- /dev/null
> +++ b/libavformat/f4fbox.c
> @@ -0,0 +1,311 @@
> +/*
> + * Adobe Fragmented F4V File (F4F) Parser
> + * Copyright (c) 2013 Cory McCarthy
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +/**
> + * @file
> + * @brief Adobe Fragmented F4V File (F4F) Parser for Adobe HDS
> + * @author Cory McCarthy
> + * @see http://download.macromedia.com/f4v/video_file_format_spec_v10_1.pdf
> + */
> +
> +#include "f4fbox.h"
> +#include "avformat.h"
> +

> +static int f4fbox_parse_single_box(AVIOContext *in, void *opaque);
> +

Again, isn't this avoidable?

> +static int f4fbox_parse_asrt(AVIOContext *in, int64_t data_size, void *opaque)
> +{
> +    F4FBootstrapInfoBox *parent = (F4FBootstrapInfoBox*)opaque;
> +    F4FSegmentRunTableBox *asrt;
> +    F4FSegmentRunEntry *entry;
> +    uint8_t quality_entry_count;
> +    uint32_t segment_run_entry_count;
> +    char url[1024];
> +    int i;
> +

> +    asrt = av_mallocz(sizeof(F4FSegmentRunTableBox));

asrt = av_mallocz(sizeof(*asrt));

ditto later on

> +    if(!asrt)
> +        return AVERROR(ENOMEM);
> +
> +    parent->segment_run_table_boxes[parent->nb_segment_run_table_boxes] = asrt;
> +    parent->nb_segment_run_table_boxes++;
> +
> +    asrt->version = avio_r8(in);
> +    asrt->flags = avio_rb24(in);
> +
> +    quality_entry_count = avio_r8(in);
> +    for(i = 0; i < quality_entry_count; i++) {
> +        avio_get_str(in, sizeof(url), url, sizeof(url));
> +    }
> +
> +    segment_run_entry_count = avio_rb32(in);
> +    for(i = 0; i < segment_run_entry_count; i++) {
> +        entry = av_mallocz(sizeof(F4FSegmentRunEntry));
> +        if(!entry)
> +            return AVERROR(ENOMEM);
> +
> +        asrt->segment_run_entries[asrt->nb_segment_run_entries] = entry;
> +        asrt->nb_segment_run_entries++;
> +
> +        entry->first_segment = avio_rb32(in);

> +	

trailing whitespace

> +        entry->fragments_per_segment = avio_rb32(in);
> +    }
> +
> +    return 0;
> +}
> +
> +static int f4fbox_parse_afrt(AVIOContext *in, int64_t data_size, void *opaque)
> +{
> +    F4FBootstrapInfoBox *parent = (F4FBootstrapInfoBox*)opaque;
> +    F4FFragmentRunTableBox *afrt;
> +    F4FFragmentRunEntry *entry;
> +    uint8_t quality_entry_count;
> +    uint32_t fragment_run_entry_count;
> +    char url[1024];
> +    int i;
> +
> +    afrt = av_mallocz(sizeof(F4FFragmentRunTableBox));
> +    if(!afrt)
> +        return AVERROR(ENOMEM);
> +
> +    parent->fragment_run_table_boxes[parent->nb_fragment_run_table_boxes] = afrt;
> +    parent->nb_fragment_run_table_boxes++;
> +
> +    afrt->version = avio_r8(in);
> +    afrt->flags = avio_rb24(in);
> +
> +    afrt->timescale = avio_rb32(in);
> +
> +    quality_entry_count = avio_r8(in);
> +    for(i = 0; i < quality_entry_count; i++) {
> +        avio_get_str(in, sizeof(url), url, sizeof(url));
> +    }
> +
> +    fragment_run_entry_count = avio_rb32(in);
> +    for(i = 0; i < fragment_run_entry_count; i++) {
> +        entry = av_mallocz(sizeof(F4FFragmentRunEntry));
> +        if(!entry)
> +            return AVERROR(ENOMEM);
> +
> +        afrt->fragment_run_entries[afrt->nb_fragment_run_entries] = entry;
> +        afrt->nb_fragment_run_entries++;
> +
> +        entry->first_fragment = avio_rb32(in);
> +        entry->first_fragment_time_stamp = avio_rb64(in);
> +        entry->fragment_duration = avio_rb32(in);
> +        if(entry->fragment_duration == 0) {
> +            entry->discontinuity_indicator = avio_r8(in);
> +        }
> +    }
> +
> +    return 0;
> +}
> +
> +
> +static int f4fbox_parse_abst(AVIOContext *in, int64_t data_size, void *opaque)
> +{
> +    F4FBox *parent = (F4FBox*)opaque;
> +    F4FBootstrapInfoBox *abst = &(parent->abst);
> +    uint8_t server_entry_count, quality_entry_count;
> +    uint8_t segment_run_table_count, fragment_run_table_count;
> +    uint8_t byte;
> +    char url[1024];
> +    int i, ret;
> +
> +    abst->version = avio_r8(in);
> +    abst->flags = avio_rb24(in);
> +    abst->bootstrap_info_version = avio_rb32(in);
> +
> +    byte = avio_r8(in);

> +    abst->profile = (byte >> 6) & 0x03;
> +    abst->is_live = (byte >> 5) & 0x01;
> +    abst->is_update = (byte >> 4) & 0x01;

nit: parenthesis are useless

> +
> +    abst->timescale = avio_rb32(in);
> +    abst->current_media_time = avio_rb64(in);
> +    abst->smpte_time_code_offset = avio_rb64(in);
> +
> +    avio_get_str(in, sizeof(abst->movie_id), abst->movie_id, sizeof(abst->movie_id));
> +
> +    server_entry_count = avio_r8(in);
> +    for(i = 0; i < server_entry_count; i++) {
> +        avio_get_str(in, sizeof(url), url, sizeof(url));
> +    }
> +
> +    quality_entry_count = avio_r8(in);
> +    for(i = 0; i < quality_entry_count; i++) {
> +        avio_get_str(in, sizeof(url), url, sizeof(url));
> +    }
> +
> +    avio_get_str(in, sizeof(abst->drm_data), abst->drm_data, sizeof(abst->drm_data));
> +    avio_get_str(in, sizeof(abst->metadata), abst->metadata, sizeof(abst->metadata));
> +
> +    segment_run_table_count = avio_r8(in);
> +    for(i = 0; i < segment_run_table_count; i++) {
> +        if((ret = f4fbox_parse_single_box(in, abst)) < 0) {
> +            av_log(NULL, AV_LOG_ERROR, "f4fbox Failed to parse asrt box, ret: %d \n", ret);
> +            return ret;
> +        }
> +    }
> +
> +    fragment_run_table_count = avio_r8(in);
> +    for(i = 0; i < fragment_run_table_count; i++) {
> +        if((ret = f4fbox_parse_single_box(in, abst)) < 0) {
> +            av_log(NULL, AV_LOG_ERROR, "f4fbox Failed to parse afrt box, ret: %d \n", ret);
> +            return ret;
> +        }
> +    }
> +
> +    return 0;
> +}
> +
> +static int f4fbox_parse_mdat(AVIOContext *in, int64_t data_size, void *opaque)
> +{
> +    F4FBox *parent = (F4FBox*)opaque;
> +    F4FMediaDataBox *mdat = &(parent->mdat);
> +
> +    mdat->data = av_mallocz(sizeof(uint8_t)*data_size);
> +    if(!mdat->data)
> +        return AVERROR(ENOMEM);
> +
> +    mdat->size = data_size;
> +    avio_read(in, mdat->data, mdat->size);
> +
> +    return 0;
> +}
> +
> +static int f4fbox_parse_single_box(AVIOContext *in, void *opaque)
> +{
> +    int64_t bytes_read, bytes_left, start_pos, end_pos;
> +    uint64_t size;
> +    uint32_t type;
> +    int ret = 0;
> +
> +    bytes_read = 0;
> +    start_pos = avio_tell(in);
> +
> +    size = avio_rb32(in);
> +    type = avio_rl32(in);
> +    bytes_read += 8;
> +
> +    if(size == 1) {/* 64 bit extended size */
> +        size = avio_rb64(in) - 8;
> +        bytes_read += 8;
> +    }
> +
> +    if(size == 0)
> +        return -1;
> +
> +    if(type == MKTAG('a', 'b', 's', 't')) {
> +        ret = f4fbox_parse_abst(in, size, opaque);
> +    }
> +    if(type == MKTAG('a', 's', 'r', 't')) {
> +        ret = f4fbox_parse_asrt(in, size, opaque);
> +    }
> +    if(type == MKTAG('a', 'f', 'r', 't')) {
> +        ret = f4fbox_parse_afrt(in, size, opaque);
> +    }
> +    if(type == MKTAG('m', 'd', 'a', 't')) {
> +        ret = f4fbox_parse_mdat(in, size, opaque);
> +    }
> +
> +    if(ret < 0)
> +        return ret;
> +
> +    end_pos = avio_tell(in);
> +    bytes_left = size - (end_pos - start_pos);
> +    if(bytes_left > 0)
> +        avio_skip(in, bytes_left);
> +
> +    bytes_read += size;
> +
> +    return bytes_read;
> +}
> +
> +static int f4fbox_parse(AVIOContext *in, int64_t data_size, void *opaque)
> +{
> +    int64_t bytes_read = 0;
> +    int ret;
> +
> +    while(!avio_feof(in) && bytes_read + 8 < data_size) {
> +        if((ret = f4fbox_parse_single_box(in, opaque)) < 0) {
> +            av_log(NULL, AV_LOG_ERROR, "f4fbox Failed to parse box, ret: %d \n", ret);
> +            return ret;
> +        }
> +        bytes_read += ret;
> +    }
> +
> +    return 0;
> +}
> +
> +int ff_parse_f4f_box(uint8_t *buffer, int buffer_size, F4FBox *box)
> +{
> +    AVIOContext *in;
> +    int ret;
> +
> +    in = avio_alloc_context(buffer, buffer_size, 0, NULL, NULL, NULL, NULL);
> +    if(!in)
> +        return AVERROR(ENOMEM);
> +
> +    ret = f4fbox_parse(in, buffer_size, box);
> +    av_freep(&in);
> +
> +    return ret;
> +}
> +
> +int ff_free_f4f_box(F4FBox *box)
> +{
> +    F4FBootstrapInfoBox *abst;
> +    F4FSegmentRunTableBox *asrt;
> +    F4FSegmentRunEntry *sre;
> +    F4FFragmentRunTableBox *afrt;
> +    F4FFragmentRunEntry *fre;
> +    F4FMediaDataBox *mdat;
> +    int i, j;
> +
> +    abst = &(box->abst);
> +    for(i = 0; i < abst->nb_segment_run_table_boxes; i++) {
> +        asrt = abst->segment_run_table_boxes[i];
> +        for(j = 0; j < asrt->nb_segment_run_entries; j++) {
> +            sre = asrt->segment_run_entries[j];
> +            av_freep(&sre);
> +        }
> +        av_freep(&asrt);
> +    }
> +
> +    for(i = 0; i < abst->nb_fragment_run_table_boxes; i++) {
> +        afrt = abst->fragment_run_table_boxes[i];
> +        for(j = 0; j < afrt->nb_fragment_run_entries; j++) {
> +            fre = afrt->fragment_run_entries[j];
> +            av_freep(&fre);
> +        }
> +        av_freep(&afrt);
> +    }
> +
> +    mdat = &(box->mdat);
> +    if(mdat->size > 0)
> +        av_freep(&mdat->data);
> +

> +    memset(box, 0x00, sizeof(F4FBox));
> +

sizeof(*box);

[...]
> +#include "f4mmanifest.h"
> +#include "libavutil/avstring.h"
> +#include "libavutil/base64.h"

> +#include <libxml/parser.h>
> +#include <libxml/tree.h>

system headers before local ones

> +
> +#define XML_FORMATIC_TAB 0x0a
> +#define XML_FORMATIC_LF 0x09
> +#define XML_FORMATIC_CR 0x0d
> +#define XML_FORMATIC_WHITE 0x20
> +
> +
> +static int f4m_get_xml_content_offset(xmlChar *p){
> +  
> +    int result = 0;
> +    int len = strlen(p);
> +    int i;
> +    
> +    for(i = 0; i < len; i++){
> +        if(p[i] == XML_FORMATIC_LF || p[i] == XML_FORMATIC_TAB || p[i] == XML_FORMATIC_CR || p[i] == XML_FORMATIC_WHITE)
> +            result++;
> +        else
> +	  break;
> +    }
> +    
> +    if(result > len)
> +        result = 0;
> +      
> +    return result;
> +}
> +
> +static int f4m_get_content_length(xmlChar *p){
> +  
> +    int result = 0;
> +    int len = strlen(p);
> +    int i;
> +  
> +    for(i = 0; i < len; i++){
> +        if(p[i] != XML_FORMATIC_LF && p[i] != XML_FORMATIC_TAB && p[i] != XML_FORMATIC_CR && p[i] != XML_FORMATIC_WHITE)
> +	 result++;
> +        
> +    }
> +	
> +    result++;
> +    
> +    if(result > MAX_URL_SIZE)
> +        result = MAX_URL_SIZE;
> +    
> +    return result;
> +  
> +}

Many trailing whitespaces (and tab) here. git or your configured editor should show them

[...]

> + * @note Test streams are below:
> + * @test http://multiplatform-f.akamaihd.net/z/multi/april11/hdworld/hdworld_,512x288_450_b,640x360_700_b,768x432_1000_b,1024x576_1400_m,1280x720_1900_m,1280x720_2500_m,1280x720_3500_m,.mp4.csmil/manifest.f4m?hdcore
> + * @test http://multiplatform-f.akamaihd.net/z/multi/april11/cctv/cctv_,512x288_450_b,640x360_700_b,768x432_1000_b,1024x576_1400_m,1280x720_1900_m,1280x720_2500_m,1280x720_3500_m,.mp4.csmil/manifest.f4m?hdcore
> + * @test http://multiplatform-f.akamaihd.net/z/multi/april11/sintel/sintel-hd_,512x288_450_b,640x360_700_b,768x432_1000_b,1024x576_1400_m,1280x720_1900_m,1280x720_2500_m,1280x720_3500_m,.mp4.csmil/manifest.f4m?hdcore
> + * @test http://multiplatform-f.akamaihd.net/z/multi/akamai10year/Akamai_10_Year_,200,300,600,800,1000,1500,2500,4000,k.mp4.csmil/manifest.f4m?hdcore
> + * @test http://zerihdndemo-f.akamaihd.net/z/h264/seeker/LegendofSeeker_16x9_24fps_H264_,400K,650K,1Mbps,1.4Mbps,1.8Mbps,2.5Mbps,.mp4.csmil/manifest.f4m?hdcore
> + * @test http://multiplatform-f.akamaihd.net/z/multi/will/bunny/big_buck_bunny_,640x360_400,640x360_700,640x360_1000,950x540_1500,1280x720_2000,1280x720_3000,.f4v.csmil/manifest.f4m?hdcore
> + * @test http://multiplatform-f.akamaihd.net/z/multi/companion/nba_game/nba_game.mov_,300,600,800,1000,2500,4000,9000,k.mp4.csmil/manifest.f4m?hdcore
> + * @test http://multiplatform-f.akamaihd.net/z/multi/companion/big_bang_theory/big_bang_theory.mov_,300,600,800,1000,2500,4000,9000,k.mp4.csmil/manifest.f4m?hdcore
> + * @test http://multiplatform-f.akamaihd.net/z/multi/shuttle/shuttle_,300,600,800,1000,k.mp4.csmil/manifest.f4m?hdcore
> + * @test http://multiplatform-f.akamaihd.net/z/multi/up_trailer/up_trailer_720p_,300,600,800,1000,k.mp4.csmil/manifest.f4m?hdcore
> + * @test http://multiformatlive-f.akamaihd.net/z/demostream_1@2131/manifest.f4m?hdcore
> + * @test http://zerihdndemo-f.akamaihd.net/z/h264/darkknight/darkknight.smil/manifest.f4m?hdcore
> + * @test http://zerihdndemo-f.akamaihd.net/z/h264/amours/amours.smil/manifest.f4m?hdcore
> + * @test http://zerihdndemo-f.akamaihd.net/z/h264/robinhood/robinhood.smil/manifest.f4m?hdcore
> + * @test http://zerihdndemo-f.akamaihd.net/z/h264/wallstreet/wallstreet.smil/manifest.f4m?hdcore
> + * @test http://zerihdndemo-f.akamaihd.net/z/h264/rockandroll/rockandroll.smil/manifest.f4m?hdcore
> + * @test http://184.72.239.149/vod/smil:bigbuckbunny.smil/manifest.f4m
> + * 
> + * @test http://livehds.rasset.ie/hds-live/_definst_/newsnow/newsnow_540p.f4m
> + * @test http://livehds.rasset.ie/hds-live/_definst_/rte1/rte1_288p.f4m
> + * @test http://livehds.rasset.ie/hds-live/_definst_/rte2/rte2_288p.f4m
> + * @test http://ooyalahd2-f.akamaihd.net/z/godtv02_delivery@17351/manifest.f4m?hdcore=2.10.3&g=ILYQWQWFPMLW

These will die pretty quickly. Add a FATE test instead.

[...]

-- 
Clément B.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 473 bytes
Desc: not available
URL: <https://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20150428/74716c45/attachment.asc>


More information about the ffmpeg-devel mailing list