I will try to fix all the problems, although I'm not the original author of most of the code, I just added better fragments/segment calculation for live streams, and other small changes.
2015-04-28 15:32 GMT+02:00 Clément Bœsch <u...@pkh.me>: > 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 <develo...@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. > > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > http://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel