[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