]> git.webhop.me Git - bs-cst-neutrino-hd.git/commitdiff
Lets use FFMPEG Git (> 3.3)
authorMarkham <markham001@gmx.de>
Wed, 3 May 2017 18:27:02 +0000 (20:27 +0200)
committerMarkham <markham001@gmx.de>
Wed, 3 May 2017 18:27:02 +0000 (20:27 +0200)
archive-patches/ffmpeg/0001-ffmpeg-hds-libroxml-3.x.patch [new file with mode: 0644]
archive-patches/ffmpeg/0002-ffmpeg-aac-3.x.patch [new file with mode: 0644]
archive-patches/ffmpeg/0003-ffmpeg-Revert-lavc-Switch-bitrate-to-64bit.patch [new file with mode: 0644]
make/archives.mk
make/libraries.mk
make/versions.mk

diff --git a/archive-patches/ffmpeg/0001-ffmpeg-hds-libroxml-3.x.patch b/archive-patches/ffmpeg/0001-ffmpeg-hds-libroxml-3.x.patch
new file mode 100644 (file)
index 0000000..40ea9b6
--- /dev/null
@@ -0,0 +1,2774 @@
+From a6ceed822b71d46c30b0f70270b59b7afb0e5137 Mon Sep 17 00:00:00 2001
+From: Markham <markham001@gmx.de>
+Date: Wed, 3 May 2017 17:51:31 +0200
+Subject: [PATCH] ffmpeg-hds-libroxml-3.x
+
+---
+ configure                 |    5 +
+ libavformat/Makefile      |    1 +
+ libavformat/allformats.c  |    2 +-
+ libavformat/amfmetadata.c |  290 +++++++++++++
+ libavformat/amfmetadata.h |   47 ++
+ libavformat/f4fbox.c      |  345 +++++++++++++++
+ libavformat/f4fbox.h      |  110 +++++
+ libavformat/f4mmanifest.c |  256 +++++++++++
+ libavformat/f4mmanifest.h |   65 +++
+ libavformat/flv.h         |    2 +
+ libavformat/flvdec.c      |    5 +
+ libavformat/flvtag.c      |  408 ++++++++++++++++++
+ libavformat/flvtag.h      |   40 ++
+ libavformat/hdsdec.c      | 1036 +++++++++++++++++++++++++++++++++++++++++++++
+ 14 files changed, 2611 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 c3fa9d8..1934364 100755
+--- a/configure
++++ b/configure
+@@ -293,6 +293,7 @@ External library support:
+                            on OSX if openssl and gnutls are not used [autodetect]
+   --disable-xlib           disable xlib [autodetect]
+   --disable-zlib           disable zlib [autodetect]
++  --disable-libroxml       disable XML parsing using the C library libroxml [autodetect]
+   The following libraries provide various hardware acceleration features:
+   --disable-audiotoolbox   disable Apple AudioToolbox code [autodetect]
+@@ -1555,6 +1556,7 @@ EXTERNAL_LIBRARY_LIST="
+     libopenmpt
+     libopus
+     libpulse
++    libroxml
+     librtmp
+     libschroedinger
+     libshine
+@@ -2921,6 +2923,7 @@ eac3_demuxer_select="ac3_parser"
+ f4v_muxer_select="mov_muxer"
+ fifo_muxer_deps="threads"
+ flac_demuxer_select="flac_parser"
++hds_demuxer_select="libroxml"
+ hds_muxer_select="flv_muxer"
+ hls_muxer_select="mpegts_muxer"
+ image2_alias_pix_demuxer_select="image2_demuxer"
+@@ -5728,6 +5731,8 @@ disabled  zlib || check_lib zlib   zlib.h      zlibVersion    -lz
+ disabled bzlib || check_lib bzlib bzlib.h BZ2_bzlibVersion    -lbz2
+ disabled  lzma || check_lib lzma   lzma.h lzma_version_number -llzma
++disabled libroxml || check_lib roxml roxml.h roxml_load_buf -lroxml || disable libroxml
++
+ check_lib libm math.h sin -lm && LIBM="-lm"
+ disabled crystalhd || check_lib crystalhd "stdint.h libcrystalhd/libcrystalhd_if.h" DtsCrystalHDVersion -lcrystalhd
+diff --git a/libavformat/Makefile b/libavformat/Makefile
+index d82639d..baf027e 100644
+--- a/libavformat/Makefile
++++ b/libavformat/Makefile
+@@ -200,6 +200,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_HASH_MUXER)                += hashenc.o
+ OBJS-$(CONFIG_HDS_MUXER)                 += hdsenc.o
+ OBJS-$(CONFIG_HEVC_DEMUXER)              += hevcdec.o rawdec.o
+diff --git a/libavformat/allformats.c b/libavformat/allformats.c
+index 09e62c3..8e99a3b 100644
+--- a/libavformat/allformats.c
++++ b/libavformat/allformats.c
+@@ -142,7 +142,7 @@ static void register_all(void)
+     REGISTER_MUXDEMUX(H263,             h263);
+     REGISTER_MUXDEMUX(H264,             h264);
+     REGISTER_MUXER   (HASH,             hash);
+-    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..5bad763
+--- /dev/null
++++ b/libavformat/amfmetadata.c
+@@ -0,0 +1,290 @@
++/*
++ * 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 "amfmetadata.h"
++#include "avio_internal.h"
++#include "flv.h"
++#include "libavutil/avstring.h"
++#include "libavutil/intfloat.h"
++#include "libavformat/avformat.h"
++
++static int amf_metadata_parse_value(AVIOContext *in, AMFMetadata *metadata, const char *name);
++
++static int amf_metadata_read_string_value(AVIOContext *in, char *str, int str_size)
++{
++    uint8_t type;
++
++    type = avio_r8(in);
++    if(type != 0x02) {
++      av_log(NULL, AV_LOG_ERROR, "amfmetadata Expected type 2, type = %d \n", type);
++      return -1;
++    }
++
++    return flv_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("audiosamplesize", name)) {
++      metadata->audio_sample_size = (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)) {
++      switch(FLV_AUDIO_CODECID_MASK & ((int)value << FLV_AUDIO_CODECID_OFFSET)) {
++      case FLV_CODECID_PCM:
++          metadata->audio_codec_id = metadata->audio_sample_size == 8
++                                     ? AV_CODEC_ID_PCM_U8
++#if HAVE_BIGENDIAN
++                                     : AV_CODEC_ID_PCM_S16BE;
++#else
++                                     : AV_CODEC_ID_PCM_S16LE;
++#endif
++          break;
++      case FLV_CODECID_ADPCM:
++          metadata->audio_codec_id = AV_CODEC_ID_ADPCM_SWF;
++          break;
++      case FLV_CODECID_MP3:
++          metadata->audio_stream_need_parsing = AVSTREAM_PARSE_FULL;
++          metadata->audio_codec_id = AV_CODEC_ID_MP3;
++          break;
++      case FLV_CODECID_PCM_LE:
++          metadata->audio_codec_id = metadata->audio_sample_size == 8
++                                     ? AV_CODEC_ID_PCM_U8
++                                     : AV_CODEC_ID_PCM_S16LE;
++          break;
++      case FLV_CODECID_NELLYMOSER_16KHZ_MONO:
++          if (!metadata->audio_sample_rate)
++              metadata->audio_sample_rate = 16000;
++          metadata->nb_audio_channels = 1;
++          metadata->audio_codec_id = AV_CODEC_ID_NELLYMOSER;
++          break;
++      case FLV_CODECID_NELLYMOSER_8KHZ_MONO:
++          if (!metadata->audio_sample_rate)
++              metadata->audio_sample_rate = 8000;
++          metadata->nb_audio_channels = 1;
++          metadata->audio_codec_id = AV_CODEC_ID_NELLYMOSER;
++          break;
++      case FLV_CODECID_NELLYMOSER:
++          metadata->audio_codec_id = AV_CODEC_ID_NELLYMOSER;
++          break;
++      case FLV_CODECID_PCM_ALAW:
++          metadata->audio_sample_rate = 8000;
++          metadata->audio_codec_id = AV_CODEC_ID_PCM_ALAW;
++          break;
++      case FLV_CODECID_PCM_MULAW:
++          metadata->audio_sample_rate = 8000;
++          metadata->audio_codec_id = AV_CODEC_ID_PCM_MULAW;
++          break;
++      case FLV_CODECID_AAC:
++          metadata->audio_codec_id = AV_CODEC_ID_AAC;
++          break;
++      case FLV_CODECID_SPEEX:
++          metadata->audio_sample_rate = 16000;
++          metadata->audio_codec_id = AV_CODEC_ID_SPEEX;
++          break;
++      default:
++          break;
++      }
++    }
++    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(".mp3", value)) {
++          metadata->audio_stream_need_parsing = AVSTREAM_PARSE_FULL;
++          metadata->audio_codec_id = AV_CODEC_ID_MP3;
++      }
++      else
++          av_log(NULL, AV_LOG_ERROR, "amfmetadata audiocodecid=%s unhandled\n", value);
++    }
++    else
++    if(!av_strcasecmp("videocodecid", name)) {
++      if(!av_strcasecmp("avc1", value))
++          metadata->video_codec_id = AV_CODEC_ID_H264;
++      else
++          av_log(NULL, AV_LOG_ERROR, "amfmetadata videocodecid=%s unhandled\n", value);
++    }
++}
++
++static int amf_metadata_parse_object_property(AVIOContext *in, AMFMetadata *metadata)
++{
++    char name[INT16_MAX];
++    int ret;
++
++    if((ret = flv_amf_get_string(in, name, sizeof(name))) < 0)
++      return ret;
++
++    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)
++          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 = flv_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);
++    }
++    else if(type == AMF_END_OF_OBJECT) {
++        ret = -1; // EOF
++    }
++
++    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_free(in);
++
++    return ret;
++}
+diff --git a/libavformat/amfmetadata.h b/libavformat/amfmetadata.h
+new file mode 100644
+index 0000000..c47cd6e
+--- /dev/null
++++ b/libavformat/amfmetadata.h
+@@ -0,0 +1,47 @@
++/*
++ * 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 audio_sample_size;
++    int nb_audio_channels;
++    int audio_data_rate;
++    int video_data_rate;
++    int audio_stream_need_parsing;
++
++    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..4c05cd0
+--- /dev/null
++++ b/libavformat/f4fbox.c
+@@ -0,0 +1,345 @@
++/*
++ * 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 *opague);
++
++static int f4fbox_parse_asrt(AVIOContext *in, int64_t data_size, void *opague)
++{
++    F4FBootstrapInfoBox *parent = (F4FBootstrapInfoBox*)opague;
++    F4FSegmentRunTableBox *asrt;
++    F4FSegmentRunEntry *entry;
++    uint32_t segment_run_entry_count;
++    char url[1024];
++    int i;
++
++    asrt = av_mallocz(sizeof(F4FSegmentRunTableBox));
++    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);
++
++    asrt->nb_quality_entries = avio_r8(in);
++    if (asrt->nb_quality_entries)
++        asrt->quality_entries = (char **) av_malloc(asrt->nb_quality_entries * sizeof(char *));
++    for(i = 0; i < asrt->nb_quality_entries; i++) {
++        avio_get_str(in, sizeof(url), url, sizeof(url));
++        av_log(NULL, AV_LOG_DEBUG, "f4fbox asrt quality[%d]=%s\n", i, url);
++        asrt->quality_entries[i] = av_strdup(url);
++    }
++
++    segment_run_entry_count = avio_rb32(in);
++    if(segment_run_entry_count > MAX_NB_SEGMENT_RUN_ENTRIES) {
++        av_log(NULL, AV_LOG_ERROR, "f4fbox segment run entry count exceeds maximum, %d > %d \n",
++            segment_run_entry_count, MAX_NB_SEGMENT_RUN_ENTRIES);
++        segment_run_entry_count = MAX_NB_SEGMENT_RUN_ENTRIES;
++    }
++
++    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);
++        entry->fragments_per_segment = avio_rb32(in);
++    }
++
++    return 0;
++}
++
++static int f4fbox_parse_afrt(AVIOContext *in, int64_t data_size, void *opague)
++{
++    F4FBootstrapInfoBox *parent = (F4FBootstrapInfoBox*)opague;
++    F4FFragmentRunTableBox *afrt;
++    F4FFragmentRunEntry *entry;
++    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);
++
++    afrt->nb_quality_entries = avio_r8(in);
++    if (afrt->nb_quality_entries)
++        afrt->quality_entries = (char **) av_malloc(afrt->nb_quality_entries * sizeof(char *));
++    for(i = 0; i < afrt->nb_quality_entries; i++) {
++        avio_get_str(in, sizeof(url), url, sizeof(url));
++        av_log(NULL, AV_LOG_DEBUG, "f4fbox afrt quality[%d]=%s\n", i, url);
++        afrt->quality_entries[i] = av_strdup(url);
++    }
++
++    fragment_run_entry_count = avio_rb32(in);
++    if(fragment_run_entry_count > MAX_NB_FRAGMENT_RUN_ENTRIES) {
++        av_log(NULL, AV_LOG_ERROR, "f4fbox fragment run entry count exceeds maximum, %d > %d \n",
++            fragment_run_entry_count, MAX_NB_FRAGMENT_RUN_ENTRIES);
++        fragment_run_entry_count = MAX_NB_FRAGMENT_RUN_ENTRIES;
++    }
++
++    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 *opague)
++{
++    F4FBox *parent = (F4FBox*)opague;
++    F4FBootstrapInfoBox *abst = &(parent->abst);
++    uint8_t server_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;
++
++    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));
++    }
++
++    abst->nb_quality_entries = avio_r8(in);
++    if (abst->nb_quality_entries)
++        abst->quality_entries = (char **) av_malloc(abst->nb_quality_entries * sizeof(char *));
++    for(i = 0; i < abst->nb_quality_entries; i++) {
++        avio_get_str(in, sizeof(url), url, sizeof(url));
++        av_log(NULL, AV_LOG_DEBUG, "f4fbox abst quality[%d]=%s\n", i, url);
++        abst->quality_entries[i] = av_strdup(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 *opague)
++{
++    F4FBox *parent = (F4FBox*)opague;
++    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 *opague)
++{
++    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, opague);
++    }
++    if(type == MKTAG('a', 's', 'r', 't')) {
++        ret = f4fbox_parse_asrt(in, size, opague);
++    }
++    if(type == MKTAG('a', 'f', 'r', 't')) {
++        ret = f4fbox_parse_afrt(in, size, opague);
++    }
++    if(type == MKTAG('m', 'd', 'a', 't')) {
++        ret = f4fbox_parse_mdat(in, size, opague);
++    }
++
++    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 *opague)
++{
++    int64_t bytes_read = 0;
++    int ret;
++
++    while(!avio_feof(in) && bytes_read + 8 < data_size) {
++        if((ret = f4fbox_parse_single_box(in, opague)) < 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_free(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(j = 0; j < abst->nb_quality_entries; j++)
++        av_freep(&abst->quality_entries[j]);
++    if (abst->quality_entries)
++        av_freep(&abst->quality_entries);
++
++    for(i = 0; i < abst->nb_segment_run_table_boxes; i++) {
++        asrt = abst->segment_run_table_boxes[i];
++        for(j = 0; j < asrt->nb_quality_entries; j++)
++            av_freep(&asrt->quality_entries[j]);
++        if (asrt->quality_entries)
++            av_freep(&asrt->quality_entries);
++        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_quality_entries; j++)
++            av_freep(&afrt->quality_entries[j]);
++        if (afrt->quality_entries)
++            av_freep(&afrt->quality_entries);
++        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));
++
++    return 0;
++}
+diff --git a/libavformat/f4fbox.h b/libavformat/f4fbox.h
+new file mode 100644
+index 0000000..da3ac24
+--- /dev/null
++++ b/libavformat/f4fbox.h
+@@ -0,0 +1,110 @@
++/*
++ * 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 "avio_internal.h"
++
++#define MAX_NB_SEGMENT_RUN_TABLE_BOXES 256
++#define MAX_NB_FRAGMENT_RUN_TABLE_BOXES 256
++
++#define MAX_NB_SEGMENT_RUN_ENTRIES 1024
++#define MAX_NB_FRAGMENT_RUN_ENTRIES 1024
++
++typedef struct F4FFragmentRunEntry {
++    uint32_t first_fragment;
++    uint64_t first_fragment_time_stamp;
++    uint32_t fragment_duration;
++    uint8_t discontinuity_indicator;
++} F4FFragmentRunEntry;
++
++typedef struct F4FFragmentRunTableBox {
++    uint8_t version;
++    uint32_t flags;
++    uint32_t timescale;
++
++    uint8_t nb_quality_entries;
++    char **quality_entries;
++
++    uint32_t nb_fragment_run_entries;
++    F4FFragmentRunEntry *fragment_run_entries[MAX_NB_FRAGMENT_RUN_ENTRIES];
++} F4FFragmentRunTableBox;
++
++typedef struct F4FSegmentRunEntry {
++    uint32_t first_segment;
++    uint32_t fragments_per_segment;
++} F4FSegmentRunEntry;
++
++typedef struct F4FSegmentRunTableBox {
++    uint8_t version;
++    uint32_t flags;
++
++    uint8_t nb_quality_entries;
++    char **quality_entries;
++
++    uint32_t nb_segment_run_entries;
++    F4FSegmentRunEntry *segment_run_entries[MAX_NB_SEGMENT_RUN_ENTRIES];
++} F4FSegmentRunTableBox;
++
++typedef struct F4FBootstrapInfoBox {
++    uint8_t version;
++    uint32_t flags;
++    uint32_t bootstrap_info_version;
++
++    uint8_t profile;
++    uint8_t is_live;
++    uint8_t is_update;
++
++    uint32_t timescale;
++    uint64_t current_media_time;
++    uint64_t smpte_time_code_offset;
++
++    char movie_id[1024];
++    char drm_data[1024];
++    char metadata[1024];
++
++    uint8_t nb_quality_entries;
++    char **quality_entries;
++
++    uint8_t nb_segment_run_table_boxes;
++    F4FSegmentRunTableBox *segment_run_table_boxes[MAX_NB_SEGMENT_RUN_TABLE_BOXES];
++
++    uint8_t nb_fragment_run_table_boxes;
++    F4FFragmentRunTableBox *fragment_run_table_boxes[MAX_NB_FRAGMENT_RUN_TABLE_BOXES];
++} F4FBootstrapInfoBox;
++
++typedef struct F4FMediaDataBox {
++    uint32_t size;
++    uint8_t *data;
++} F4FMediaDataBox;
++
++typedef struct F4FBox {
++    F4FBootstrapInfoBox abst;
++    F4FMediaDataBox mdat;
++} F4FBox;
++
++int ff_parse_f4f_box(uint8_t *buffer, int buffer_size, F4FBox *box);
++int ff_free_f4f_box(F4FBox *box);
+diff --git a/libavformat/f4mmanifest.c b/libavformat/f4mmanifest.c
+new file mode 100644
+index 0000000..2f3ea7f
+--- /dev/null
++++ b/libavformat/f4mmanifest.c
+@@ -0,0 +1,256 @@
++/*
++ * Adobe Media Manifest (F4M) File 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 Media Manifest (F4M) File Parser
++ * @author Cory McCarthy
++ * @see http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/devnet/hds/pdfs/adobe-media-manifest-specification.pdf
++ */
++
++#include "f4mmanifest.h"
++#include "libavutil/avstring.h"
++#include "libavutil/base64.h"
++#include <roxml.h>
++
++static int f4m_parse_bootstrap_info_node(node_t * node, F4MBootstrapInfo *bootstrap_info)
++{
++    const char *p;
++    uint8_t *dst;
++    int ret;
++    node_t *attr;
++
++    attr = roxml_get_attr(node, "id", 0);
++    p =roxml_get_content(attr,NULL,0,NULL);
++    if(p) {
++        av_strlcpy(bootstrap_info->id, p, sizeof(bootstrap_info->id));
++    }
++
++    attr = roxml_get_attr(node, "url", 0);
++    p =roxml_get_content(attr,NULL,0,NULL);
++    if(p) {
++        av_strlcpy(bootstrap_info->url, p, sizeof(bootstrap_info->url));
++    }
++
++    attr = roxml_get_attr(node, "profile", 0);
++    p =roxml_get_content(attr,NULL,0,NULL);
++    if(p) {
++        av_strlcpy(bootstrap_info->profile, p, sizeof(bootstrap_info->profile));
++    }
++
++    p = roxml_get_content(node, NULL, 0, NULL);
++    if(p) {
++        dst = av_mallocz(sizeof(uint8_t)*strlen(p));
++        if(!dst)
++            return AVERROR(ENOMEM);
++
++        if((ret = av_base64_decode(dst, p, strlen(p))) < 0) {
++            av_log(NULL, AV_LOG_ERROR, "f4mmanifest Failed to decode bootstrap node base64 metadata, ret: %d \n", ret);
++            av_free(dst);
++            return ret;
++        }
++
++        bootstrap_info->metadata = av_mallocz(sizeof(uint8_t)*ret);
++        if(!bootstrap_info->metadata)
++            return AVERROR(ENOMEM);
++
++        bootstrap_info->metadata_size = ret;
++        memcpy(bootstrap_info->metadata, dst, ret);
++
++        av_free(dst);
++    }
++
++    return 0;
++}
++
++static int f4m_parse_metadata_node(node_t * node, F4MMedia *media)
++{
++    const char  *p = NULL;
++    uint8_t *dst;
++    int ret;
++
++    node_t * metadata_node = roxml_get_chld(node, NULL, 0);
++    while(metadata_node) {
++        if(!strcmp(roxml_get_name(metadata_node, NULL, 0), "metadata")) {
++            p = roxml_get_content(metadata_node, NULL, 0, NULL);
++            break;
++        }
++        metadata_node = roxml_get_next_sibling(metadata_node);
++    }
++
++    if(!p)
++        return 0;
++
++    dst = av_mallocz(sizeof(uint8_t)*strlen(p));
++    if(!dst)
++        return AVERROR(ENOMEM);
++
++    if((ret = av_base64_decode(dst, p, strlen(p))) < 0) {
++        av_log(NULL, AV_LOG_ERROR, "f4mmanifest Failed to decode base64 metadata, ret: %d \n", ret);
++        av_free(dst);
++        return ret;
++    }
++
++    media->metadata = av_mallocz(sizeof(uint8_t)*ret);
++    if(!media->metadata)
++        return AVERROR(ENOMEM);
++
++    media->metadata_size = ret;
++    memcpy(media->metadata, dst, ret);
++
++    av_free(dst);
++
++    return 0;
++}
++
++static int f4m_parse_media_node(node_t * node, F4MMedia *media)
++{
++    const char  *p;
++    int ret;
++    node_t * attr;
++
++    attr = roxml_get_attr(node, "bitrate", 0);
++    p =roxml_get_content(attr,NULL,0,NULL);
++    if(p) {
++        media->bitrate = strtoul(p, NULL, 10);
++    }
++
++    attr = roxml_get_attr(node, "url", 0);
++    p =roxml_get_content(attr,NULL,0,NULL);
++    if(p) {
++        av_strlcpy(media->url, p, sizeof(media->url));
++    }
++
++    attr = roxml_get_attr(node, "bootstrapInfoId", 0);
++    p =roxml_get_content(attr,NULL,0,NULL);
++    if(p) {
++        av_strlcpy(media->bootstrap_info_id, p, sizeof(media->bootstrap_info_id));
++    }
++
++    if((ret = f4m_parse_metadata_node(node, media)) < 0) {
++        return ret;
++    }
++
++    return 0;
++}
++
++static int f4m_parse_manifest_node(node_t * root_node, F4MManifest *manifest)
++{
++    F4MBootstrapInfo *bootstrap_info;
++    F4MMedia *media;
++    node_t * node;
++    const char  *node_content;
++    int ret = 0,chld_idx=0;
++
++    for (chld_idx=0; chld_idx<roxml_get_chld_nb(root_node); chld_idx++){
++      node = roxml_get_chld(root_node, NULL, chld_idx);
++      const char * node_name = roxml_get_name(node, NULL, 0);
++        if(!strcmp(node_name, "text"))
++            continue;
++
++      node_content = roxml_get_content(node, NULL, 0, NULL);
++
++        if(!strcmp(node_name, "id") && node_content) {
++            av_strlcpy(manifest->id, node_content, sizeof(manifest->id));
++        } else if(!strcmp(node_name, "streamType") && node_content) {
++            av_strlcpy(manifest->stream_type, node_content, sizeof(manifest->stream_type));
++        } else if(!strcmp(node_name, "bootstrapInfo")) {
++            bootstrap_info = av_mallocz(sizeof(F4MBootstrapInfo));
++            if(!bootstrap_info)
++                return AVERROR(ENOMEM);
++            manifest->bootstraps[manifest->nb_bootstraps++] = bootstrap_info;
++            ret = f4m_parse_bootstrap_info_node(node, bootstrap_info);
++        } else if(!strcmp(node_name, "media")) {
++            media = av_mallocz(sizeof(F4MMedia));
++            if(!media)
++                return AVERROR(ENOMEM);
++            manifest->media[manifest->nb_media++] = media;
++            ret = f4m_parse_media_node(node, media);
++        } else if (!strcmp(node_name, "duration")) {
++          double duration = strtod(node_content, NULL);
++          manifest->duration = duration * AV_TIME_BASE;
++      }
++
++        if(ret < 0)
++            return ret;
++    }
++
++    return 0;
++}
++
++static int f4m_parse_xml_file(uint8_t *buffer, int size, F4MManifest *manifest)
++{
++    node_t * doc;
++    node_t * root_node;
++    int ret;
++
++    doc = roxml_load_buf(buffer);
++    if(!doc) {
++        return -1;
++    }
++
++    doc = roxml_get_root(doc);
++    root_node = roxml_get_chld(doc, NULL, 0);
++    if(!root_node) {
++        av_log(NULL, AV_LOG_ERROR, "f4mmanifest Root element not found \n");
++        roxml_close(doc);
++        return -1;
++    }
++    const char * root_node_name = roxml_get_name(root_node, NULL, 0);
++    if(strcmp(root_node_name, "manifest")) {
++        av_log(NULL, AV_LOG_ERROR, "f4mmanifest Root element is not named manifest, name = %s \n", root_node_name);
++        roxml_close(doc);
++        return -1;
++    }
++
++    ret = f4m_parse_manifest_node(root_node, manifest);
++    roxml_close(doc);
++
++    return ret;
++}
++
++int ff_parse_f4m_manifest(uint8_t *buffer, int size, F4MManifest *manifest)
++{
++    return f4m_parse_xml_file(buffer, size, manifest);
++}
++
++int ff_free_manifest(F4MManifest *manifest)
++{
++    F4MBootstrapInfo *bootstrap_info;
++    F4MMedia *media;
++    int i;
++
++    for(i = 0; i < manifest->nb_bootstraps; i++) {
++        bootstrap_info = manifest->bootstraps[i];
++        av_freep(&bootstrap_info->metadata);
++        av_freep(&bootstrap_info);
++    }
++
++    for(i = 0; i < manifest->nb_media; i++) {
++        media = manifest->media[i];
++        av_freep(&media->metadata);
++        av_freep(&media);
++    }
++
++    memset(manifest, 0x00, sizeof(F4MManifest));
++
++    return 0;
++}
+diff --git a/libavformat/f4mmanifest.h b/libavformat/f4mmanifest.h
+new file mode 100644
+index 0000000..97a5885
+--- /dev/null
++++ b/libavformat/f4mmanifest.h
+@@ -0,0 +1,65 @@
++/*
++ * Adobe Media Manifest (F4M) File 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 Media Manifest (F4M) File Parser
++ * @author Cory McCarthy
++ * @see http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/devnet/hds/pdfs/adobe-media-manifest-specification.pdf
++ */
++
++#include "internal.h"
++
++#define MAX_NB_BOOTSTRAPS 32
++#define MAX_NB_MEDIA 32
++
++typedef struct F4MBootstrapInfo {
++    char id[MAX_URL_SIZE];
++    char url[MAX_URL_SIZE];
++    char profile[MAX_URL_SIZE];
++
++    int metadata_size;
++    uint8_t *metadata;
++} F4MBootstrapInfo;
++
++typedef struct F4MMedia {
++    int bitrate;
++    char url[MAX_URL_SIZE];
++    char bootstrap_info_id[MAX_URL_SIZE];
++
++    int metadata_size;
++    uint8_t *metadata;
++} F4MMedia;
++
++typedef struct F4MManifest {
++    char id[MAX_URL_SIZE];
++    char stream_type[MAX_URL_SIZE];
++    int64_t duration;
++
++    int nb_bootstraps;
++    F4MBootstrapInfo *bootstraps[MAX_NB_BOOTSTRAPS];
++
++    int nb_media;
++    F4MMedia *media[MAX_NB_MEDIA];
++} F4MManifest;
++
++int ff_parse_f4m_manifest(uint8_t *buffer, int size, F4MManifest *manifest);
++int ff_free_manifest(F4MManifest *manifest);
+diff --git a/libavformat/flv.h b/libavformat/flv.h
+index df5ce3d..b204817 100644
+--- a/libavformat/flv.h
++++ b/libavformat/flv.h
+@@ -135,4 +135,6 @@ typedef enum {
+     AMF_DATA_TYPE_UNSUPPORTED = 0x0d,
+ } AMFDataType;
++int flv_amf_get_string(AVIOContext *ioc, char *buffer, int buffsize);
++
+ #endif /* AVFORMAT_FLV_H */
+diff --git a/libavformat/flvdec.c b/libavformat/flvdec.c
+index 94c9e28..84d081a 100644
+--- a/libavformat/flvdec.c
++++ b/libavformat/flvdec.c
+@@ -368,6 +368,11 @@ static int amf_get_string(AVIOContext *ioc, char *buffer, int buffsize)
+     return length;
+ }
++int flv_amf_get_string(AVIOContext *ioc, char *buffer, int buffsize)
++{
++    return amf_get_string(ioc, buffer, buffsize);
++}
++
+ static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc, int64_t max_pos)
+ {
+     FLVContext *flv       = s->priv_data;
+diff --git a/libavformat/flvtag.c b/libavformat/flvtag.c
+new file mode 100644
+index 0000000..5087fdb
+--- /dev/null
++++ b/libavformat/flvtag.c
+@@ -0,0 +1,408 @@
++/*
++ * Adobe FLV Tag Parser
++ * Copyright (c) 2013 Cory McCarthy
++ * Copyright (c) 2014 martii
++ *
++ * 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 FLV Tag Parser for Adobe HDS F4F Files
++ * @author Cory McCarthy
++ * @see http://download.macromedia.com/f4v/video_file_format_spec_v10_1.pdf
++ */
++
++#include "flvtag.h"
++#include "libavformat/avio.h"
++#include "libavcodec/get_bits.h"
++#include "libavutil/channel_layout.h"
++#include "flv.h"
++
++typedef struct FLVTagAudioHeader {
++    uint8_t sound_format;
++    uint8_t sound_rate;
++    uint8_t sound_size;
++    uint8_t sound_type;
++
++    uint8_t aac_packet_type;
++} FLVTagAudioHeader;
++
++typedef struct FLVTagAudioBody {
++    uint8_t sound_format;
++    uint8_t sound_rate;
++    uint8_t sound_size;
++    uint8_t sound_type;
++
++    uint8_t aac_packet_type;
++} FLVTagAudioBody;
++
++typedef struct FLVTagVideoHeader {
++    uint8_t frame_type;
++    uint8_t codec_id;
++
++    uint8_t avc_packet_type;
++    int32_t cts;
++} FLVTagVideoHeader;
++
++typedef struct FLVTagVideoBody {
++    //AVCDecoderConfigurationRecord
++    uint8_t configuration_version;
++    uint8_t avc_profile_indication;
++    uint8_t profile_compatibility;
++    uint8_t avc_level_indication;
++
++    uint8_t length_size_minus_one;
++
++    uint8_t *sps_data;
++    int sps_data_size;
++
++    uint8_t *pps_data;
++    int pps_data_size;
++} FLVTagVideoBody;
++
++static int flv_tag_parse_audio_header(AVIOContext *in,
++    FLVTagAudioHeader *header)
++{
++    int ret = 0;
++    uint8_t byte;
++
++    byte = avio_r8(in);
++    ret++;
++
++    header->sound_format = byte & FLV_AUDIO_CODECID_MASK;
++    header->sound_rate   = (byte >> FLV_AUDIO_SAMPLERATE_OFFSET) & 0x03;
++    header->sound_size   = (byte >> FLV_AUDIO_SAMPLESSIZE_OFFSET) & 0x01;
++    header->sound_type   = byte & 0x01;
++
++    if(header->sound_format == FLV_CODECID_AAC) {
++      header->aac_packet_type = avio_r8(in);
++      ret++;
++    }
++
++    return ret;
++}
++
++static int flv_tag_parse_audio_body(AVIOContext *in, uint32_t data_size,
++    FLVTagAudioHeader *header, FLVTagAudioBody *body, FLVMediaSample **sample_out)
++{
++    FLVMediaSample *sample;
++
++    if(header->sound_format != FLV_CODECID_AAC) {
++      av_log(NULL, AV_LOG_ERROR, "flvtag Unhandled sound format %d\n", header->sound_format >> FLV_AUDIO_CODECID_OFFSET);
++      return 0;
++    }
++
++    if(header->aac_packet_type == 0) {
++      av_log(NULL, AV_LOG_DEBUG, "flvtag skipped aac_packet_type %d\n", header->aac_packet_type);
++      return 0;
++    }
++
++    if(header->aac_packet_type != 1) {
++      av_log(NULL, AV_LOG_ERROR, "flvtag Unhandled aac_packet_type %d\n", header->aac_packet_type);
++      return 0;
++    }
++
++    sample = av_mallocz(sizeof(FLVMediaSample));
++    if(!sample)
++      return AVERROR(ENOMEM);
++
++    sample->type = AVMEDIA_TYPE_AUDIO;
++
++    sample->data = av_mallocz(sizeof(uint8_t) * data_size);
++    if(!sample->data) {
++      av_free(sample);
++      return AVERROR(ENOMEM);
++    }
++
++    sample->data_size = data_size;
++    avio_read(in, sample->data, sample->data_size);
++
++    if(sample_out)
++      *sample_out = sample;
++
++    return data_size;
++}
++
++static int flv_tag_parse_video_header(AVIOContext *in,
++    FLVTagVideoHeader *header)
++{
++    int ret = 0;
++    uint8_t byte;
++
++    byte = avio_r8(in);
++    ret++;
++
++    header->frame_type = byte >> 4;
++    header->codec_id = byte & 0x0F;
++
++    if(header->codec_id == 0x07) {
++      header->avc_packet_type = avio_r8(in);
++      header->cts = (avio_rb24(in) + 0xff800000) ^ 0xff800000;
++      ret += 4;
++    }
++
++    return ret;
++}
++
++static int flv_tag_parse_video_body(AVIOContext *in, uint32_t data_size,
++    FLVTagVideoHeader *header, FLVTagVideoBody *body, FLVMediaSample **sample_out)
++{
++    FLVMediaSample *sample = NULL;
++    uint8_t *p;
++    uint8_t nb_sps, nb_pps;
++    uint16_t sps_length, pps_length;
++    int i, ret = 0;
++
++    if(header->frame_type == 0x05) {
++      avio_r8(in);
++      return 1;
++    }
++
++    if(header->codec_id != FLV_CODECID_H264) {
++      av_log(NULL, AV_LOG_ERROR, "flvtag Unhandled video codec id, id: %d \n", header->codec_id);
++      return 0;
++    }
++
++    if(header->avc_packet_type == 0x00) {
++      body->configuration_version = avio_r8(in);
++      body->avc_profile_indication = avio_r8(in);
++      body->profile_compatibility = avio_r8(in);
++      body->avc_level_indication = avio_r8(in);
++      ret += 4;
++
++      body->length_size_minus_one = avio_r8(in) & 0x03;
++      ret++;
++
++      if(body->sps_data_size > 0)
++          av_freep(&body->sps_data);
++      if(body->pps_data_size > 0)
++          av_freep(&body->pps_data);
++
++      nb_sps = avio_r8(in) & 0x1F;
++      ret++;
++
++      for(i = 0; i < nb_sps; i++) {
++          sps_length = avio_rb16(in);
++          ret += 2;
++
++          body->sps_data = av_realloc(body->sps_data,
++              body->sps_data_size + sps_length + 4);
++          if(!body->sps_data)
++              return AVERROR(ENOMEM);
++
++          p = body->sps_data + body->sps_data_size;
++
++          *p++ = 0x00;
++          *p++ = 0x00;
++          *p++ = 0x00;
++          *p++ = 0x01;
++          body->sps_data_size += 4;
++
++          avio_read(in, p, sps_length);
++          body->sps_data_size += sps_length;
++
++          ret += sps_length;
++      }
++
++      nb_pps = avio_r8(in);
++      ret++;
++
++      for(i = 0; i < nb_pps; i++) {
++          pps_length = avio_rb16(in);
++          ret += 2;
++
++          body->pps_data = av_realloc(body->pps_data,
++              body->pps_data_size + pps_length + 4);
++          if(!body->pps_data)
++              return AVERROR(ENOMEM);
++
++          p = body->pps_data + body->pps_data_size;
++
++          *p++ = 0x00;
++          *p++ = 0x00;
++          *p++ = 0x00;
++          *p++ = 0x01;
++          body->pps_data_size += 4;
++
++          avio_read(in, p, pps_length);
++          body->pps_data_size += pps_length;
++
++          ret += pps_length;
++      }
++    }
++    else if(header->avc_packet_type == 0x01) { // AVC NALU
++      sample = av_mallocz(sizeof(FLVMediaSample));
++      if(!sample)
++          return AVERROR(ENOMEM);
++
++      sample->type = AVMEDIA_TYPE_VIDEO;
++
++      sample->data_size = body->sps_data_size + body->pps_data_size;
++      sample->data_size += 4 + data_size;
++
++      sample->data = av_mallocz(sizeof(uint8_t) * sample->data_size);
++      if(!sample->data) {
++          av_free(sample);
++          return AVERROR(ENOMEM);
++      }
++
++      p = sample->data;
++
++      memcpy(p, body->sps_data, body->sps_data_size);
++      p += body->sps_data_size;
++
++      memcpy(p, body->pps_data, body->pps_data_size);
++      p += body->pps_data_size;
++
++      while(ret < data_size) {
++          int length_size = body->length_size_minus_one + 1;
++          uint32_t nal_size = 0;
++          *p++ = 0x00;
++          *p++ = 0x00;
++          *p++ = 0x00;
++          *p++ = 0x01;
++
++          while (length_size) {
++              nal_size <<= 8;
++              nal_size |= avio_r8(in);
++              length_size--;
++              ret++;
++          }
++
++          avio_read(in, p, nal_size);
++          p += nal_size;
++          ret += nal_size;
++      }
++    }
++
++    if(sample_out)
++      *sample_out = sample;
++
++    return ret;
++}
++
++static int flv_tag_decode_body(uint8_t *buffer, int buffer_size,
++    FLVMediaSample **samples, int *nb_samples_out)
++{
++    FLVMediaSample *sample;
++    AVIOContext *in;
++    FLVTagAudioHeader audio_header;
++    FLVTagAudioBody audio_body;
++    FLVTagVideoHeader video_header;
++    FLVTagVideoBody video_body;
++    uint8_t byte, filter, tag_type;
++    uint32_t data_size, dts, stream_id;
++    int nb_samples = 0;
++    int ret;
++
++    memset(&audio_header, 0x00, sizeof(FLVTagAudioHeader));
++    memset(&audio_body, 0x00, sizeof(FLVTagAudioBody));
++    memset(&video_header, 0x00, sizeof(FLVTagVideoHeader));
++    memset(&video_body, 0x00, sizeof(FLVTagVideoBody));
++
++    in = avio_alloc_context(buffer, buffer_size, 0, NULL, NULL, NULL, NULL);
++    if(!in)
++      return AVERROR(ENOMEM);
++
++    while(!avio_feof(in)) {
++      byte = avio_r8(in);
++      filter = byte & 0x20;
++      tag_type = (byte & 0x01F);
++
++      data_size = avio_rb24(in);
++
++      dts = avio_rb24(in);
++      dts |= avio_r8(in) << 24;
++
++      stream_id = avio_rb24(in);
++      if(stream_id != 0) {
++          av_log(NULL, AV_LOG_ERROR, "flvtag Invalid stream_id %d \n", stream_id);
++          return -1;
++      }
++
++      if(tag_type == FLV_TAG_TYPE_AUDIO) {
++          data_size -= flv_tag_parse_audio_header(in, &audio_header);
++      } else if(tag_type == FLV_TAG_TYPE_VIDEO) {
++          data_size -= flv_tag_parse_video_header(in, &video_header);
++      }
++
++#if 0
++      if(filter) {
++          //EncryptionTagHeader
++          //FilterParams
++      }
++#endif
++
++      sample = NULL;
++
++      if(tag_type == FLV_TAG_TYPE_AUDIO) {
++          if((ret = flv_tag_parse_audio_body(in, data_size,
++                  &audio_header, &audio_body, &sample)) < 0) {
++
++              av_free(in);
++              return ret;
++          }
++          data_size -= ret;
++      } else if(tag_type == FLV_TAG_TYPE_VIDEO) {
++          if((ret = flv_tag_parse_video_body(in, data_size,
++                  &video_header, &video_body, &sample)) < 0) {
++
++              av_free(in);
++              return ret;
++          }
++          data_size -= ret;
++      }
++#if 0
++      else if(tag_type == 18) {
++          //ScriptData
++      }
++#endif
++
++      if(sample) {
++          sample->dts = dts;
++          if (tag_type == FLV_TAG_TYPE_VIDEO)
++                  sample->pts = dts + video_header.cts;
++          else
++                  sample->pts = AV_NOPTS_VALUE;
++          samples[nb_samples++] = sample;
++      }
++
++      if(data_size) {
++          avio_skip(in, data_size);
++      }
++      avio_rb32(in);
++    }
++
++    av_free(in);
++
++    if(video_body.sps_data_size > 0)
++      av_free(video_body.sps_data);
++    if(video_body.pps_data_size > 0)
++      av_free(video_body.pps_data);
++
++    if(nb_samples_out)
++      *nb_samples_out = nb_samples;
++
++    return 0;
++}
++
++int ff_decode_flv_body(uint8_t *buffer, int buffer_size,
++    FLVMediaSample **samples, int *nb_samples_out)
++{
++    return flv_tag_decode_body(buffer, buffer_size, samples, nb_samples_out);
++}
+diff --git a/libavformat/flvtag.h b/libavformat/flvtag.h
+new file mode 100644
+index 0000000..51b94b4
+--- /dev/null
++++ b/libavformat/flvtag.h
+@@ -0,0 +1,40 @@
++/*
++ * Adobe FLV Tag 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 FLV Tag Parser for Adobe HDS F4F Files
++ * @author Cory McCarthy
++ * @see http://download.macromedia.com/f4v/video_file_format_spec_v10_1.pdf
++ */
++
++#include "libavutil/avutil.h"
++
++typedef struct FLVMediaSample {
++    enum AVMediaType type;
++    uint64_t dts;
++    uint64_t pts;
++    int data_size;
++    uint8_t *data;
++} FLVMediaSample;
++
++int ff_decode_flv_body(uint8_t *buffer, int buffer_size,
++    FLVMediaSample **samples, int *nb_samples_out);
+diff --git a/libavformat/hdsdec.c b/libavformat/hdsdec.c
+new file mode 100644
+index 0000000..1fadfc8
+--- /dev/null
++++ b/libavformat/hdsdec.c
+@@ -0,0 +1,1036 @@
++/*
++ * Adobe HTTP Dynamic Streaming (HDS) demuxer
++ * Copyright (c) 2013 Cory McCarthy
++ * Copyright (c) 2014 martii
++ *
++ * 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 HTTP Dynamic Streaming (HDS) demuxer
++ * @author Cory McCarthy
++ * @see http://www.adobe.com/devnet/hds.html
++ * @see http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/devnet/hds/pdfs/adobe-hds-specification.pdf
++ * @see http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/devnet/hds/pdfs/adobe-media-manifest-specification.pdf
++ * @see http://download.macromedia.com/f4v/video_file_format_spec_v10_1.pdf
++ *
++ * @note Link for a HDS test player below:
++ * @see http://mediapm.edgesuite.net/edgeflash/public/zeri/debug/Main.html
++ *
++ * @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
++ */
++
++#include "avformat.h"
++#include "internal.h"
++#include "url.h"
++#include "avio_internal.h"
++#include "libavutil/avstring.h"
++#include "libavutil/parseutils.h"
++#include "libavutil/opt.h"
++#include "libavutil/dict.h"
++#include "libavutil/time.h"
++
++#include "amfmetadata.h"
++#include "f4mmanifest.h"
++#include "f4fbox.h"
++#include "flvtag.h"
++
++#include <unistd.h>
++#include <pthread.h>
++#include <semaphore.h>
++#include <alloca.h>
++
++#define MAX_NB_SAMPLES 1024
++
++struct HDSDownloadThreadData
++{
++    pthread_mutex_t mutex;                    // protects access to this struct
++    pthread_t thread;                         // download thread id
++    sem_t *to_thread;                         // send signal to thread
++    sem_t *to_caller;                         // send signal to caller
++    sem_t _to_thread;                         // send signal to thread
++    sem_t _to_caller;                         // send signal to caller
++    char *cookies;                            // cookies, if any
++    char *url;                                        // current url
++    int run;                                  // thread will run until == 0
++    int abort;                                        // setting this to !=0 aborts download
++    uint8_t *buffer;                          // set by thread, unset by thread or caller
++    uint32_t buflen;                          // set by thread, unset by thread or caller
++    AVIOInterruptCB *interrupt_callback;
++    AVIOInterruptCB *abort_callback;
++    AVIOInterruptCB download_abort_callback;
++};
++
++typedef struct HDSBootstrapInfo {
++    char id[MAX_URL_SIZE];
++    char url[MAX_URL_SIZE];
++    char profile[MAX_URL_SIZE];
++    char *quality;
++
++    F4FBox box;
++} HDSBootstrapInfo;
++
++typedef struct HDSMedia {
++    int media_index;
++    int bitrate;
++    char url[MAX_URL_SIZE];
++    HDSBootstrapInfo *bootstrap_info;
++
++    AVStream *audio_stream;
++    AVStream *video_stream;
++
++    int nb_samples;
++    FLVMediaSample *samples[MAX_NB_SAMPLES];
++    int sample_index;
++
++    unsigned int nb_fragments_read;
++
++    struct HDSDownloadThreadData download_data;
++} HDSMedia;
++
++typedef struct HDSContext {
++    char id[MAX_URL_SIZE];
++    char base_url[MAX_URL_SIZE];
++    int is_live;
++    int last_media_index;
++
++    int nb_bootstraps;
++    HDSBootstrapInfo *bootstrap_info[MAX_NB_BOOTSTRAPS];
++
++    int nb_media;
++    HDSMedia *media[MAX_NB_MEDIA];
++
++    int64_t seek_timestamp;
++    char *cookies;
++} HDSContext;
++
++static void construct_bootstrap_url(const char *base_url, const char *bootstrap_url,
++    const char *suffix, char *url_out, size_t url_size)
++{
++    char *p;
++
++    p = url_out;
++    p += av_strlcat(p, base_url, url_size);
++    p += av_strlcat(p, bootstrap_url, url_size);
++    p += av_strlcat(p, suffix, url_size);
++}
++
++static int download_bootstrap(AVFormatContext *s, HDSBootstrapInfo *bootstrap,
++    uint8_t **buffer_out, int *buffer_size_out)
++{
++    HDSContext *c = s->priv_data;
++    URLContext *puc = NULL;
++    AVDictionary *opts = NULL;
++    char url[MAX_URL_SIZE];
++    uint8_t *buffer;
++    int buffer_size;
++    int ret;
++
++    memset(url, 0x00, sizeof(url));
++
++    if(!av_stristr(bootstrap->url, "?") && av_stristr(s->filename, "?")) {
++      construct_bootstrap_url(c->base_url, bootstrap->url, av_stristr(s->filename, "?"), url, MAX_URL_SIZE);
++    } else {
++      construct_bootstrap_url(c->base_url, bootstrap->url, "", url, MAX_URL_SIZE);
++    }
++
++    av_dict_set(&opts, "cookies", c->cookies, 0);
++    ret = ffurl_open(&puc, url, AVIO_FLAG_READ, &s->interrupt_callback, &opts);
++    av_dict_free(&opts);
++
++    if(ret < 0) {
++      av_log(NULL, AV_LOG_ERROR, "hds Failed to start downloading bootstrap, ret: %d\n", ret);
++      return ret;
++    }
++
++    buffer_size = ffurl_size(puc);
++    buffer = av_mallocz(buffer_size+FF_INPUT_BUFFER_PADDING_SIZE);
++    if(!buffer)
++      return AVERROR(ENOMEM);
++
++    if((ret = ffurl_read_complete(puc, buffer, buffer_size)) < 0) {
++      av_log(NULL, AV_LOG_ERROR, "hds Failed to download bootstrap, ret: %d\n", ret);
++      av_free(buffer);
++      return ret;
++    }
++
++    if (c->cookies)
++      av_freep(&c->cookies);
++    av_opt_get(puc->priv_data, "cookies", 0, (uint8_t **) &c->cookies);
++    if (c->cookies && !strlen(c->cookies))
++      av_freep(&c->cookies);
++
++    if((ret = ffurl_close(puc)) < 0) {
++      av_log(NULL, AV_LOG_ERROR, "hds Failed to finish downloading bootstrap, ret: %d\n", ret);
++      av_free(buffer);
++      return ret;
++    }
++
++    if(buffer_out)
++      *buffer_out = buffer;
++    else
++      av_free(buffer);
++
++    if(buffer_size_out)
++      *buffer_size_out = buffer_size;
++
++    return 0;
++}
++
++static int create_bootstrap_info(AVFormatContext *s, F4MBootstrapInfo *f4m_bootstrap_info)
++{
++    HDSContext *c = s->priv_data;
++    HDSBootstrapInfo *bootstrap_info;
++    uint8_t *buffer;
++    int buffer_size, ret;
++
++    bootstrap_info = av_mallocz(sizeof(HDSBootstrapInfo));
++    if(!bootstrap_info)
++      return AVERROR(ENOMEM);
++
++    c->bootstrap_info[c->nb_bootstraps++] = bootstrap_info;
++
++    memcpy(bootstrap_info->id, f4m_bootstrap_info->id, sizeof(bootstrap_info->id));
++    memcpy(bootstrap_info->url, f4m_bootstrap_info->url, sizeof(bootstrap_info->url));
++    memcpy(bootstrap_info->profile, f4m_bootstrap_info->profile, sizeof(bootstrap_info->profile));
++
++    buffer = f4m_bootstrap_info->metadata;
++    buffer_size = f4m_bootstrap_info->metadata_size;
++
++    if(buffer_size > 0) {
++      if((ret = ff_parse_f4f_box(buffer, buffer_size, &(bootstrap_info->box))) < 0) {
++          av_log(NULL, AV_LOG_ERROR, "hds Failed to parse metadata bootstrap box, ret: %d\n", ret);
++          return ret;
++      }
++    } else {
++      if((ret = download_bootstrap(s, bootstrap_info, &buffer, &buffer_size)) < 0) {
++          av_log(NULL, AV_LOG_ERROR, "hds Failed to download bootstrap, ret: %d\n", ret);
++          return ret;
++      }
++
++      if((ret = ff_parse_f4f_box(buffer, buffer_size, &(bootstrap_info->box))) < 0) {
++          av_log(NULL, AV_LOG_ERROR, "hds Failed to parse downloaded bootstrap box, ret: %d\n", ret);
++          return ret;
++      }
++    }
++
++    return 0;
++}
++
++static int create_streams(AVFormatContext *s, HDSMedia *media, AMFMetadata *metadata, int i)
++{
++    if (metadata->video_codec_id) {
++      AVStream *st = avformat_new_stream(s, NULL);
++      if(!st)
++          return AVERROR(ENOMEM);
++
++      media->video_stream = st;
++      avpriv_set_pts_info(st, 32, 1, 1000);
++      st->discard = AVDISCARD_ALL;
++      st->id = 0 + 2 * i;
++      st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
++      st->codec->codec_id = metadata->video_codec_id;
++      st->codec->width = metadata->width;
++      st->codec->height = metadata->height;
++      st->codec->bit_rate = metadata->video_data_rate * 1000;
++    }
++
++    if (metadata->audio_codec_id) {
++      AVStream *st = avformat_new_stream(s, NULL);
++      if(!st)
++          return AVERROR(ENOMEM);
++
++      media->audio_stream = st;
++      avpriv_set_pts_info(st, 32, 1, 1000);
++      st->discard = AVDISCARD_ALL;
++      st->id = 1 + 2 * i;
++      st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
++      st->codec->codec_id = metadata->audio_codec_id;
++      st->codec->channels = metadata->nb_audio_channels;
++      st->codec->channel_layout = (st->codec->channels == 2) ?  AV_CH_LAYOUT_STEREO : AV_CH_LAYOUT_MONO;
++      st->codec->sample_rate = metadata->audio_sample_rate;
++      st->codec->sample_fmt = AV_SAMPLE_FMT_S16;
++      st->codec->bit_rate = metadata->audio_data_rate * 1000;
++      st->need_parsing = metadata->audio_stream_need_parsing;
++    }
++
++    return 0;
++}
++
++static int create_media(AVFormatContext *s, F4MMedia *f4m_media, int i)
++{
++    HDSContext *c = s->priv_data;
++    HDSMedia *media;
++    AMFMetadata metadata;
++    int ret, j;
++
++    media = av_mallocz(sizeof(HDSMedia));
++    if(!media)
++      return AVERROR(ENOMEM);
++
++    c->media[c->nb_media++] = media;
++
++    media->media_index = i;
++    media->bitrate = f4m_media->bitrate;
++    memcpy(media->url, f4m_media->url, sizeof(media->url));
++
++    for(j = 0; j < c->nb_bootstraps; j++) {
++      if(!av_strcasecmp(f4m_media->bootstrap_info_id, c->bootstrap_info[j]->id))
++          continue;
++      media->bootstrap_info = c->bootstrap_info[j];
++      break;
++    }
++
++    memset(&metadata, 0x00, sizeof(AMFMetadata));
++    metadata.nb_audio_channels = 1;
++    if((ret = ff_parse_amf_metadata(f4m_media->metadata, f4m_media->metadata_size, &metadata)) < 0) {
++      av_log(NULL, AV_LOG_ERROR, "hds Failed to parse metadata, ret: %d\n", ret);
++      return ret;
++    }
++
++    return create_streams(s, media, &metadata, i);
++}
++
++static int create_pmt(AVFormatContext *s)
++{
++    HDSContext *c = s->priv_data;
++    HDSMedia *media;
++    AVProgram *p;
++    int i, j;
++
++    j = 0;
++    for(i = 0; i < c->nb_media; i++) {
++      media = c->media[i];
++
++      p = av_new_program(s, j++);
++      if(!p)
++          return AVERROR(ENOMEM);
++
++      av_dict_set(&p->metadata,"name",
++          av_asprintf("%d kbit/s", media->bitrate), 0);
++
++      if (media->video_stream)
++          av_program_add_stream_index(s, p->id, media->video_stream->index);
++      if (media->audio_stream)
++          av_program_add_stream_index(s, p->id, media->audio_stream->index);
++    }
++
++    return 0;
++}
++
++static void download_thread_start(AVFormatContext *s, HDSMedia *media);
++
++static int initialize_context(AVFormatContext *s, F4MManifest *manifest)
++{
++    HDSContext *c = s->priv_data;
++    F4MBootstrapInfo *f4m_bootstrap_info;
++    F4MMedia *f4m_media;
++    int i, ret;
++
++    for(i = 0; i < manifest->nb_bootstraps; i++) {
++      f4m_bootstrap_info = manifest->bootstraps[i];
++      if((ret = create_bootstrap_info(s, f4m_bootstrap_info)) < 0) {
++          av_log(NULL, AV_LOG_ERROR, "hds Failed to create bootstrap_info, ret: %d\n", ret);
++          return ret;
++      }
++    }
++
++    for(i = 0; i < manifest->nb_media; i++) {
++      f4m_media = manifest->media[i];
++      if((ret = create_media(s, f4m_media, i)) < 0) {
++          av_log(NULL, AV_LOG_ERROR, "hds Failed to create media, ret: %d\n", ret);
++          return ret;
++      }
++    }
++
++    if((ret = create_pmt(s)) < 0) {
++      av_log(NULL, AV_LOG_ERROR, "hds Failed to create PMT, ret: %d\n", ret);
++      return ret;
++    }
++
++    if(!av_strcasecmp(manifest->stream_type, "live"))
++      c->is_live = 1;
++
++    s->duration = manifest->duration;
++    c->seek_timestamp = AV_NOPTS_VALUE;
++
++    for(i = 0; i < c->nb_media; i++)
++      download_thread_start(s, c->media[i]);
++
++    return 0;
++}
++
++//#define HDS_ENABLE_LOG_CALLBACK
++#ifdef HDS_ENABLE_LOG_CALLBACK
++static void log_callback(void *ptr __attribute__ ((unused)), int lvl __attribute__ ((unused)), const char *format, va_list ap)
++{
++    vfprintf(stderr, format, ap);
++}
++#endif
++
++static int hds_read_header(AVFormatContext *s)
++{
++    HDSContext *c = s->priv_data;
++    AVIOContext *in = s->pb;
++    F4MManifest manifest;
++    int64_t filesize;
++    uint8_t *buf;
++    char *p;
++    int ret;
++#ifdef HDS_ENABLE_LOG_CALLBACK
++    av_log_set_callback(log_callback);
++#endif
++
++    p = av_stristr(s->filename, "manifest.f4m");
++    if(!p) {
++      av_log(NULL, AV_LOG_ERROR, "hds \"manifest.f4m\" is not a substring of \"%s\"\n", s->filename);
++      return -1;
++    }
++    av_strlcpy(c->base_url, s->filename, p - s->filename + 1);
++
++    filesize = avio_size(in);
++    if(filesize <= 0)
++      return -1;
++
++    buf = av_mallocz(filesize*sizeof(uint8_t));
++    if(!buf)
++      return AVERROR(ENOMEM);
++
++    avio_read(in, buf, filesize);
++
++    memset(&manifest, 0x00, sizeof(F4MManifest));
++    ret = ff_parse_f4m_manifest(buf, filesize, &manifest);
++
++    av_free(buf);
++
++    if (ret > -1)
++      ret = initialize_context(s, &manifest);
++
++    ff_free_manifest(&manifest);
++
++    return ret;
++}
++
++static void construct_fragment_url(const char *base_url, const char *media_url,
++    unsigned int segment, unsigned int fragment, const char *suffix, char *url_out, size_t url_size)
++{
++    char *p;
++    char *fragment_str;
++
++    p = url_out;
++    p += av_strlcat(p, base_url, url_size);
++    p += av_strlcat(p, media_url, url_size);
++
++    fragment_str = av_asprintf("Seg%u-Frag%u", segment, fragment);
++    p += av_strlcat(p, fragment_str, url_size);
++    av_free(fragment_str);
++
++    p += av_strlcat(p, suffix, url_size);
++}
++
++static int get_fragment_offset(HDSMedia *media, int64_t timestamp)
++{
++    F4FBootstrapInfoBox *abst = &(media->bootstrap_info->box.abst);
++    int fragments_max = 0;
++    int i, j;
++
++    for(i = 0; i < abst->nb_segment_run_table_boxes; i++) {
++      F4FSegmentRunTableBox *asrt = abst->segment_run_table_boxes[i];
++      int found = 0;
++      if (asrt->nb_quality_entries && media->bootstrap_info->quality)
++          for(j = 0; !found && j < asrt->nb_quality_entries; j++)
++              found = !strcmp(asrt->quality_entries[j], media->bootstrap_info->quality);
++      else
++          found = 1;
++
++      if (found) {
++          F4FSegmentRunEntry *segment_entry = asrt->segment_run_entries[asrt->nb_segment_run_entries - 1];
++          fragments_max = segment_entry->fragments_per_segment;
++          break;
++      }
++    }
++
++    for(i = 0; i < abst->nb_fragment_run_table_boxes; i++) {
++      int found = 0;
++      F4FFragmentRunTableBox *afrt = abst->fragment_run_table_boxes[i];
++      if (afrt->nb_quality_entries && media->bootstrap_info->quality)
++          for(j = 0; !found && j < afrt->nb_quality_entries; j++)
++              found = !strcmp(afrt->quality_entries[j], media->bootstrap_info->quality);
++      else
++          found = 1;
++
++      if (found) {
++          for(j = 0; j < afrt->nb_fragment_run_entries; j++) {
++              F4FFragmentRunEntry *fre = afrt->fragment_run_entries[j];
++              int fragcount;
++              if (j + 1 < afrt->nb_fragment_run_entries) {
++                  fragcount = afrt->fragment_run_entries[j + 1]->first_fragment - fre->first_fragment;
++                  fragments_max -= fragcount;
++              } else
++                  fragcount = fragments_max;
++
++              if (timestamp >= fre->first_fragment_time_stamp && timestamp <= fre->first_fragment_time_stamp + fragcount * fre->fragment_duration)
++                  return fre->first_fragment + (timestamp - fre->first_fragment_time_stamp)/fre->fragment_duration;
++          }
++          break;
++      }
++    }
++    return 0;
++}
++
++static int get_segment_fragment(int is_live, HDSMedia *media, unsigned int *segment_out, unsigned int *fragment_out)
++{
++    F4FBootstrapInfoBox *abst = &(media->bootstrap_info->box.abst);
++    unsigned int segment = ~0, fragment = ~0, fragments_max = 0;
++    int i, j, skip;
++
++    if (is_live) {
++      // FIXME. This is a crude hack.
++      *segment_out = 1;
++      *fragment_out = media->nb_fragments_read;
++      return 0;
++    }
++
++    skip = media->nb_fragments_read;
++    for(i = 0; segment == ~0 && i < abst->nb_segment_run_table_boxes; i++) {
++      F4FSegmentRunTableBox *asrt = abst->segment_run_table_boxes[i];
++      int found = 0;
++      if (asrt->nb_quality_entries && media->bootstrap_info->quality)
++          for(j = 0; !found && j < asrt->nb_quality_entries; j++)
++              found = !strcmp(asrt->quality_entries[j], media->bootstrap_info->quality);
++      else
++          found = 1;
++
++      if (found) {
++          for (j = 0; segment == ~0 && j < asrt->nb_segment_run_entries; j++) {
++              F4FSegmentRunEntry *segment_entry = asrt->segment_run_entries[j];
++
++              if (segment_entry->fragments_per_segment < skip) {
++                  skip -= segment_entry->fragments_per_segment;
++                  fragments_max = segment_entry->fragments_per_segment;
++              } else
++                  segment = segment_entry->first_segment;
++          }
++          break;
++      }
++    }
++
++    if(segment == ~0) {
++      av_log(NULL, AV_LOG_ERROR, "hds segment entry for next fragment (%u) not found, skip: %d\n", media->nb_fragments_read, skip);
++      return 0;
++    }
++
++    skip = media->nb_fragments_read;
++    for(i = 0; fragment == ~0 && i < abst->nb_fragment_run_table_boxes; i++) {
++      int found = 0;
++      F4FFragmentRunTableBox *afrt = abst->fragment_run_table_boxes[i];
++      if (afrt->nb_quality_entries && media->bootstrap_info->quality)
++          for(j = 0; !found && j < afrt->nb_quality_entries; j++)
++              found = !strcmp(afrt->quality_entries[j], media->bootstrap_info->quality);
++      else
++          found = 1;
++
++      if (found) {
++          for(j = 0; fragment == ~0 && j < afrt->nb_fragment_run_entries; j++) {
++              int fragcount;
++              F4FFragmentRunEntry *fre = afrt->fragment_run_entries[j];
++              if (j + 1 < afrt->nb_fragment_run_entries) {
++                  fragcount = afrt->fragment_run_entries[j + 1]->first_fragment - fre->first_fragment;
++                  fragments_max -= fragcount;
++              } else
++                  fragcount = fragments_max;
++
++              if (fragcount < skip)
++                  fragcount -= skip;
++              else {
++                  fragment = fre->first_fragment + skip;
++                  skip = 0;
++              }
++          }
++          break;
++      }
++    }
++
++    if (!is_live && skip > 0) {
++      av_log(NULL, AV_LOG_ERROR, "hds fragment %d fragments beyond EOF\n", skip);
++      return AVERROR_EOF;
++    }
++
++    if(fragment == ~0) {
++      av_log(NULL, AV_LOG_ERROR, "hds fragment entry not found\n");
++      return -1;
++    }
++
++    if(segment_out)
++      *segment_out = segment;
++    if(fragment_out)
++      *fragment_out = fragment;
++
++    return 0;
++}
++
++static int download_abort_callback_function(void *opaque)
++{
++    HDSMedia *media = (HDSMedia *) opaque;
++    return media->download_data.abort || ff_check_interrupt(media->download_data.interrupt_callback);
++}
++
++static void *download_thread(void *opaque)
++{
++    HDSMedia *media = (HDSMedia *) opaque;
++
++    while (media->download_data.run && !download_abort_callback_function(media)) {
++      AVDictionary *opts = NULL;
++      URLContext *puc = NULL;
++      uint8_t *buffer = NULL;
++      int buffer_size = 0, ret;
++      char *url = NULL;
++      int url_len;
++      int tries_left = 15;
++
++      if (sem_wait(media->download_data.to_thread))
++          break;
++      if (!media->download_data.run)
++          continue;
++
++      pthread_mutex_lock(&media->download_data.mutex);
++      media->download_data.abort = 0;
++      if (media->download_data.buffer)
++          av_freep(&media->download_data.buffer);
++      media->download_data.buflen = 0;
++      // generate local copies from HDSDownloadThreadData
++      if (media->download_data.cookies)
++          av_dict_set(&opts, "cookies", media->download_data.cookies, 0);
++      url_len = strlen(media->download_data.url) + 1;
++      url = alloca(url_len);
++      strncpy(url, media->download_data.url, url_len);
++      pthread_mutex_unlock(&media->download_data.mutex);
++      //av_log(NULL, AV_LOG_DEBUG, "%s %d: downloading %s\n", __FILE__,__LINE__, url);
++
++      // initiate download
++      do {
++          ret = ffurl_open(&puc, url, AVIO_FLAG_READ, &media->download_data.download_abort_callback, &opts);
++          if (ret < 0) {
++              sleep(1);
++              if (download_abort_callback_function(media))
++                  break;
++              sleep(1);
++              tries_left--;
++          }
++      } while (ret < 0 && media->download_data.run && !download_abort_callback_function(media) && tries_left > 0);
++
++      if (opts)
++          av_dict_free(&opts);
++
++      if(ret < 0) {
++          av_log(NULL, AV_LOG_ERROR, "hds Failed to start downloading url:%s, ret:%d\n", url, ret);
++      } else {
++          buffer_size = ffurl_size(puc);
++          if (buffer_size > -1)
++              buffer = av_mallocz(buffer_size+FF_INPUT_BUFFER_PADDING_SIZE);
++          if(!buffer)
++              av_log(NULL, AV_LOG_DEBUG, "hds Failed to allocate %d bytes buffer\n", buffer_size);
++      }
++
++      if(buffer && (ret = ffurl_read_complete(puc, buffer, buffer_size)) < 0) {
++          av_log(NULL, AV_LOG_ERROR, "hds Failed to download fragment, ret: %d\n", ret);
++          av_freep(&buffer);
++      }
++
++      pthread_mutex_lock(&media->download_data.mutex);
++      if (media->download_data.abort || !buffer) {
++          media->download_data.abort = 0;
++      } else {
++          //av_log(NULL, AV_LOG_DEBUG, "%s %d: downloaded  %s\n", __FILE__,__LINE__, media->download_data.url);
++          if (media->download_data.cookies)
++              av_freep(&media->download_data.cookies);
++          av_opt_get(puc->priv_data, "cookies", 0, (uint8_t **) &media->download_data.cookies);
++          if (media->download_data.cookies && !strlen(media->download_data.cookies))
++              av_freep(&media->download_data.cookies);
++          media->download_data.buffer = buffer;
++          media->download_data.buflen = buffer_size;
++      }
++      sem_post(media->download_data.to_caller);       // confirm download
++      pthread_mutex_unlock(&media->download_data.mutex);
++      if (puc)
++          ffurl_close(puc);
++    }
++    pthread_exit(NULL);
++}
++
++static void download_thread_start(AVFormatContext *s, HDSMedia *media)
++{
++#if defined(__APPLE__)
++    char buf[40];
++#endif
++    pthread_mutex_init(&media->download_data.mutex, NULL);
++#if defined(__APPLE__) // no unnamed semaphores on darwin
++    snprintf(buf, sizeof(buf), "sem_to_thread%d", media->media_index);
++    media->download_data.to_thread = sem_open(buf, O_CREAT, 0644, 0);
++    snprintf(buf, sizeof(buf), "sem_to_caller%d", media->media_index);
++    media->download_data.to_caller = sem_open(buf, O_CREAT, 0644, 0);
++#else
++    sem_init(&media->download_data._to_thread, 0, 0);
++    sem_init(&media->download_data._to_caller, 0, 0);
++    media->download_data.to_thread = &media->download_data._to_thread;
++    media->download_data.to_caller = &media->download_data._to_caller;
++#endif
++    media->download_data.thread = 0;
++    media->download_data.run = 1;
++    media->download_data.abort = 0;
++    media->download_data.url = NULL;
++    media->download_data.buffer = NULL;
++    media->download_data.buflen = 0;
++    media->download_data.cookies = NULL;
++    media->download_data.interrupt_callback = &s->interrupt_callback;
++    media->download_data.download_abort_callback.callback = download_abort_callback_function;
++    media->download_data.download_abort_callback.opaque = media;
++    media->download_data.abort_callback = &media->download_data.download_abort_callback;
++    if (pthread_create(&media->download_data.thread, NULL, download_thread, media))
++      av_log(NULL, AV_LOG_ERROR, "hds: creating download thread failed\n");
++}
++
++static void download_thread_stop(HDSMedia *media)
++{
++    if (media->download_data.thread) {
++#if defined(__APPLE__)
++      char buf[40];
++#endif
++      media->download_data.run = 0;
++      media->download_data.abort = 1;
++      sem_post(media->download_data.to_thread);
++      pthread_join(media->download_data.thread, NULL);
++      media->download_data.thread = 0;
++      if (media->download_data.url)
++              av_freep(&media->download_data.url);
++      if (media->download_data.cookies)
++              av_freep(&media->download_data.cookies);
++      if (media->download_data.buffer)
++              av_freep(&media->download_data.buffer);
++      media->download_data.buflen = 0;
++#if defined(__APPLE__)
++      sem_close(media->download_data.to_thread);
++      sem_close(media->download_data.to_caller);
++      snprintf(buf, sizeof(buf), "sem_to_thread%d", media->media_index);
++      sem_unlink(buf);
++      snprintf(buf, sizeof(buf), "sem_to_caller%d", media->media_index);
++      sem_unlink(buf);
++#else
++      sem_destroy(&media->download_data._to_thread);
++      sem_destroy(&media->download_data._to_caller);
++#endif
++      pthread_mutex_destroy(&media->download_data.mutex);
++    }
++}
++
++static int download_fragment(AVFormatContext *s, HDSMedia *media, uint8_t **buffer_out, int *buffer_size_out)
++{
++    HDSContext *c = s->priv_data;
++    char url[MAX_URL_SIZE];
++    unsigned int segment, fragment;
++    int ret;
++
++    if((ret = get_segment_fragment(c->is_live, media, &segment, &fragment)) < 0)
++      return ret;
++    memset(url, 0x00, sizeof(url));
++    if(!av_stristr(media->url, "?") && av_stristr(s->filename, "?"))
++      construct_fragment_url(c->base_url, media->url, segment, fragment, av_stristr(s->filename, "?"), url, MAX_URL_SIZE);
++    else
++      construct_fragment_url(c->base_url, media->url, segment, fragment, "", url, MAX_URL_SIZE);
++
++    pthread_mutex_lock(&media->download_data.mutex);
++
++    if (!media->download_data.cookies)
++      media->download_data.cookies = av_strdup(c->cookies);
++    if (media->download_data.url && strcmp(media->download_data.url, url)) {
++      // download in progress or finished, but not the wanted one. abort it.
++      media->download_data.abort = 1; // initiate abort
++      pthread_mutex_unlock(&media->download_data.mutex);
++      sem_wait(media->download_data.to_caller); // wait until current transfer has finished
++      pthread_mutex_lock(&media->download_data.mutex);
++      av_freep(&media->download_data.url);
++    }
++    if (!media->download_data.url) {
++      // queue retrieval of wanted url
++      media->download_data.url = av_strdup(url);
++      sem_post(media->download_data.to_thread);       // initiate download
++    }
++    if (media->download_data.url && !strcmp(media->download_data.url, url)) {
++      // download matches what we want
++      pthread_mutex_unlock(&media->download_data.mutex);
++      sem_wait(media->download_data.to_caller); // wait until finished
++      pthread_mutex_lock(&media->download_data.mutex);
++      av_freep(&media->download_data.url);
++      if (media->download_data.buffer) {
++          *buffer_out = media->download_data.buffer;
++          *buffer_size_out = media->download_data.buflen;
++          media->download_data.buffer = NULL;
++          media->download_data.buflen = 0;
++          ret = 0;
++          media->nb_fragments_read++;
++          //initiate retrieval of next url
++          if(!get_segment_fragment(c->is_live, media, &segment, &fragment))
++              memset(url, 0x00, sizeof(url));
++              if(!av_stristr(media->url, "?") && av_stristr(s->filename, "?"))
++                  construct_fragment_url(c->base_url, media->url, segment, fragment, av_stristr(s->filename, "?"), url, MAX_URL_SIZE);
++              else
++                  construct_fragment_url(c->base_url, media->url, segment, fragment, "", url, MAX_URL_SIZE);
++              media->download_data.url = av_strdup(url);
++              sem_post(media->download_data.to_thread);       // initiate download
++      } else {
++          // finished but failed
++          ret = AVERROR(EIO);
++      }
++    }
++    pthread_mutex_unlock(&media->download_data.mutex);
++    return ret;
++}
++
++static int get_next_fragment(AVFormatContext *s, HDSMedia *media)
++{
++    F4FBox box;
++    uint8_t *buffer = NULL;
++    int buffer_size = 0, ret;
++
++    if (ff_check_interrupt(media->download_data.interrupt_callback))
++      return AVERROR(EIO);
++
++    if((ret = download_fragment(s, media, &buffer, &buffer_size)) < 0)
++      return ret;
++
++    memset(&box, 0x00, sizeof(F4FBox));
++    if((ret = ff_parse_f4f_box(buffer, buffer_size, &box)) < 0) {
++      av_log(NULL, AV_LOG_ERROR, "hds Failed to parse bootstrap box, ret: %d\n", ret);
++      av_free(buffer);
++      ff_free_f4f_box(&box);
++      return ret;
++    }
++    av_free(buffer);
++
++    if((ret = ff_decode_flv_body(box.mdat.data, box.mdat.size, media->samples, &media->nb_samples)) < 0) {
++      av_log(NULL, AV_LOG_ERROR, "hds Failed to decode FLV body, ret: %d\n", ret);
++      ff_free_f4f_box(&box);
++      return ret;
++    }
++
++    ff_free_f4f_box(&box);
++
++    return 0;
++}
++
++static void read_next_sample(HDSMedia *media, AVPacket *pkt)
++{
++    FLVMediaSample *sample;
++
++    sample = media->samples[media->sample_index];
++    media->sample_index++;
++
++    av_new_packet(pkt, sample->data_size);
++    memcpy(pkt->data, sample->data, sample->data_size);
++
++    pkt->dts = sample->dts;
++    pkt->pts = sample->pts;
++
++    if(sample->type == AVMEDIA_TYPE_VIDEO && media->video_stream)
++      pkt->stream_index = media->video_stream->index;
++    else if(sample->type == AVMEDIA_TYPE_AUDIO && media->audio_stream)
++      pkt->stream_index = media->audio_stream->index;
++}
++
++static void clear_samples(HDSMedia *media)
++{
++    FLVMediaSample *sample;
++    int i;
++
++    for(i = 0; i < media->nb_samples; i++) {
++      sample = media->samples[i];
++      av_freep(&sample->data);
++      av_freep(&sample);
++      media->samples[i] = NULL;
++    }
++
++    media->nb_samples = 0;
++    media->sample_index = 0;
++}
++
++static int get_next_packet(AVFormatContext *s, HDSMedia *media, AVPacket *pkt)
++{
++    HDSContext *c = s->priv_data;
++    int ret;
++
++    if (c->is_live && !media->nb_fragments_read) {
++      int64_t ts = media->bootstrap_info->box.abst.current_media_time;
++      media->nb_fragments_read = get_fragment_offset(media, ts);
++      if (media->nb_fragments_read > 1)
++              media->nb_fragments_read--;
++    }
++
++    if (c->seek_timestamp != AV_NOPTS_VALUE) {
++      int64_t ts = c->seek_timestamp;
++      c->seek_timestamp = AV_NOPTS_VALUE;
++      media->nb_fragments_read = get_fragment_offset(media, ts);
++      clear_samples(media);
++    }
++
++    if(media->nb_samples == 0) {
++      if((ret = get_next_fragment(s, media)) < 0) {
++          return ret;
++      }
++    }
++
++    if(media->nb_samples > 0) {
++      read_next_sample(media, pkt);
++    }
++
++    if(media->sample_index >= media->nb_samples) {
++      clear_samples(media);
++    }
++
++    return 0;
++}
++
++static int hds_read_packet(AVFormatContext *s, AVPacket *pkt)
++{
++    HDSContext *c = s->priv_data;
++    HDSMedia *media = NULL;
++    int i, ret;
++
++    for (i = c->last_media_index + 1; !media && i < c->nb_media; i++) {
++      media = c->media[i];
++      if ((!media->video_stream || (media->video_stream->discard == AVDISCARD_ALL))
++       && (!media->audio_stream || (media->audio_stream->discard == AVDISCARD_ALL)))
++          media = NULL;
++    }
++    for (i = 0; !media && i < c->nb_media; i++) {
++      media = c->media[i];
++      if ((!media->video_stream || (media->video_stream->discard == AVDISCARD_ALL))
++       && (!media->audio_stream || (media->audio_stream->discard == AVDISCARD_ALL)))
++          media = NULL;
++    }
++    c->last_media_index = i;
++
++    if (media && !media->bootstrap_info && c->nb_bootstraps)
++        media->bootstrap_info = c->bootstrap_info[0];
++
++    if (!media || !media->bootstrap_info) {
++      av_log(NULL, AV_LOG_ERROR, "hds Failed to find valid stream\n");
++      return AVERROR(EIO);
++    }
++
++    if((ret = get_next_packet(s, media, pkt)) < 0) {
++      if(ret != AVERROR_EOF)
++          av_log(NULL, AV_LOG_ERROR, "hds Failed to get next packet, ret: %d\n", ret);
++      return ret;
++    }
++
++    return 0;
++}
++
++static int hds_close(AVFormatContext *s)
++{
++    HDSContext *c = s->priv_data;
++    HDSBootstrapInfo *bootstrap_info;
++    HDSMedia *media;
++    int i;
++
++    for(i = 0; i < c->nb_media; i++)
++      download_thread_stop(c->media[i]);
++
++    for(i = 0; i < c->nb_bootstraps; i++) {
++      bootstrap_info = c->bootstrap_info[i];
++
++      ff_free_f4f_box(&bootstrap_info->box);
++      av_freep(&bootstrap_info);
++    }
++
++    for(i = 0; i < c->nb_media; i++) {
++      media = c->media[i];
++
++      if (media->download_data.buffer)
++          av_freep(&media->download_data.buffer);
++
++      clear_samples(media);
++      av_freep(&media);
++    }
++
++    if(c->cookies)
++      av_freep(&c->cookies);
++
++    memset(c, 0x00, sizeof(HDSContext));
++
++    return 0;
++}
++
++static int hds_probe(AVProbeData *p)
++{
++    if(p->filename && av_stristr(p->filename, ".f4m"))
++      return AVPROBE_SCORE_MAX;
++    return 0;
++}
++
++static int hds_read_seek(AVFormatContext *s, int stream_index,
++                             int64_t timestamp, int flags)
++{
++    HDSContext *c = s->priv_data;
++
++    if (flags & AVSEEK_FLAG_BYTE)
++      return AVERROR(ENOSYS);
++    if (s->duration < c->seek_timestamp) {
++      c->seek_timestamp = AV_NOPTS_VALUE;
++      return AVERROR(EIO);
++    }
++    c->seek_timestamp = timestamp;
++
++    if (c->is_live) {
++      int i;
++      for(i = 0; i < c->nb_media; i++)
++          c->media[i]->nb_fragments_read = 0;
++      c->seek_timestamp = AV_NOPTS_VALUE;
++      return 0;
++    }
++
++    return 0;
++}
++
++AVInputFormat ff_hds_demuxer = {
++    .name        = "hds",
++    .long_name      = NULL_IF_CONFIG_SMALL("Adobe HTTP Dynamic Streaming Demuxer"),
++    .priv_data_size = sizeof(HDSContext),
++    .read_probe     = hds_probe,
++    .read_header    = hds_read_header,
++    .read_packet    = hds_read_packet,
++    .read_close     = hds_close,
++    .read_seek      = hds_read_seek,
++};
+-- 
+1.9.1
+
diff --git a/archive-patches/ffmpeg/0002-ffmpeg-aac-3.x.patch b/archive-patches/ffmpeg/0002-ffmpeg-aac-3.x.patch
new file mode 100644 (file)
index 0000000..e6ae1b2
--- /dev/null
@@ -0,0 +1,53 @@
+--- a/libavcodec/aacdec_template.c
++++ b/libavcodec/aacdec_template.c
+@@ -2359,7 +2359,7 @@
+  * @param   decode  1 if tool is used normally, 0 if tool is used in LTP.
+  * @param   coef    spectral coefficients
+  */
+-static void apply_tns(INTFLOAT coef[1024], TemporalNoiseShaping *tns,
++static __attribute__((optimize(0))) void apply_tns(INTFLOAT coef[1024], TemporalNoiseShaping *tns,
+                       IndividualChannelStream *ics, int decode)
+ {
+     const int mmm = FFMIN(ics->tns_max_bands, ics->max_sfb);
+--- a/libavcodec/mdct_template.c
++++ b/libavcodec/mdct_template.c
+@@ -102,7 +102,7 @@ av_cold int ff_mdct_init(FFTContext *s, int nbits, int inverse, double scale)
+  * @param output N/2 samples
+  * @param input N/2 samples
+  */
+-void ff_imdct_half_c(FFTContext *s, FFTSample *output, const FFTSample *input)
++void __attribute__((optimize(0))) ff_imdct_half_c(FFTContext *s, FFTSample *output, const FFTSample *input)
+ {
+     int k, n8, n4, n2, n, j;
+     const uint16_t *revtab = s->revtab;
+--- a/libavcodec/aacps.c
++++ b/libavcodec/aacps.c
+@@ -654,7 +654,7 @@
+     par[ 1] = AAC_HALF_SUM(par[ 0], par[ 1]);
+ }
+-static void decorrelation(PSContext *ps, INTFLOAT (*out)[32][2], const INTFLOAT (*s)[32][2], int is34)
++static void __attribute__((optimize(0))) decorrelation(PSContext *ps, INTFLOAT (*out)[32][2], const INTFLOAT (*s)[32][2], int is34)
+ {
+     LOCAL_ALIGNED_16(INTFLOAT, power, [34], [PS_QMF_TIME_SLOTS]);
+     LOCAL_ALIGNED_16(INTFLOAT, transient_gain, [34], [PS_QMF_TIME_SLOTS]);
+--- a/libavcodec/fft_template.c
++++ b/libavcodec/fft_template.c
+@@ -475,7 +475,7 @@
+     pass(z,FFT_NAME(ff_cos_##n),n4/2);\
+ }
+-static void fft4(FFTComplex *z)
++static void __attribute__((optimize(0))) fft4(FFTComplex *z)
+ {
+     FFTDouble t1, t2, t3, t4, t5, t6, t7, t8;
+@@ -489,7 +489,7 @@
+     BF(z[2].im, z[0].im, t2, t5);
+ }
+-static void fft8(FFTComplex *z)
++static void __attribute__((optimize(0))) fft8(FFTComplex *z)
+ {
+     FFTDouble t1, t2, t3, t4, t5, t6;
+
diff --git a/archive-patches/ffmpeg/0003-ffmpeg-Revert-lavc-Switch-bitrate-to-64bit.patch b/archive-patches/ffmpeg/0003-ffmpeg-Revert-lavc-Switch-bitrate-to-64bit.patch
new file mode 100644 (file)
index 0000000..f6d6b7e
--- /dev/null
@@ -0,0 +1,381 @@
+diff --git a/ffserver.c b/ffserver.c
+index 8b819b6..2732d7f 100644
+--- a/ffserver.c
++++ b/ffserver.c
+@@ -1914,9 +1914,9 @@ static inline void print_stream_params(AVIOContext *pb, FFServerStream *stream)
+             abort();
+         }
+-        avio_printf(pb, "<tr><td>%d<td>%s<td>%"PRId64
++        avio_printf(pb, "<tr><td>%d<td>%s<td>%d"
+                         "<td>%s<td>%s\n",
+-                    i, type, (int64_t)st->codecpar->bit_rate/1000,
++                    i, type, st->codecpar->bit_rate/1000,
+                     codec ? codec->name : "", parameters);
+      }
+diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
+index 35df4f6..34363a7 100644
+--- a/libavcodec/avcodec.h
++++ b/libavcodec/avcodec.h
+@@ -1794,7 +1794,7 @@ typedef struct AVCodecContext {
+      * - decoding: Set by user, may be overwritten by libavcodec
+      *             if this info is available in the stream
+      */
+-    int64_t bit_rate;
++    int bit_rate;
+     /**
+      * number of bits the bitstream is allowed to diverge from the reference.
+@@ -2729,14 +2729,14 @@ typedef struct AVCodecContext {
+      * - encoding: Set by user.
+      * - decoding: Set by user, may be overwritten by libavcodec.
+      */
+-    int64_t rc_max_rate;
++    int rc_max_rate;
+     /**
+      * minimum bitrate
+      * - encoding: Set by user.
+      * - decoding: unused
+      */
+-    int64_t rc_min_rate;
++    int rc_min_rate;
+ #if FF_API_MPV_OPT
+     /**
+diff --git a/libavcodec/cook.c b/libavcodec/cook.c
+index 53cb8385..2cd96cf 100644
+--- a/libavcodec/cook.c
++++ b/libavcodec/cook.c
+@@ -1035,7 +1035,7 @@ static void dump_cook_context(COOKContext *q)
+     }
+     ff_dlog(q->avctx, "COOKContext\n");
+     PRINT("nb_channels", q->avctx->channels);
+-    PRINT("bit_rate", (int)q->avctx->bit_rate);
++    PRINT("bit_rate", q->avctx->bit_rate);
+     PRINT("sample_rate", q->avctx->sample_rate);
+     PRINT("samples_per_channel", q->subpacket[0].samples_per_channel);
+     PRINT("subbands", q->subpacket[0].subbands);
+diff --git a/libavcodec/dcaenc.c b/libavcodec/dcaenc.c
+index 3c5c33c..28ab9b2 100644
+--- a/libavcodec/dcaenc.c
++++ b/libavcodec/dcaenc.c
+@@ -161,7 +161,7 @@ static int encode_init(AVCodecContext *avctx)
+     c->samplerate_index = i;
+     if (avctx->bit_rate < 32000 || avctx->bit_rate > 3840000) {
+-        av_log(avctx, AV_LOG_ERROR, "Bit rate %"PRId64" not supported.", (int64_t)avctx->bit_rate);
++        av_log(avctx, AV_LOG_ERROR, "Bit rate %i not supported.", avctx->bit_rate);
+         return AVERROR(EINVAL);
+     }
+     for (i = 0; ff_dca_bit_rates[i] < avctx->bit_rate; i++)
+diff --git a/libavcodec/libfdk-aacenc.c b/libavcodec/libfdk-aacenc.c
+index 98a817b..5df0c90 100644
+--- a/libavcodec/libfdk-aacenc.c
++++ b/libavcodec/libfdk-aacenc.c
+@@ -215,8 +215,8 @@ static av_cold int aac_encode_init(AVCodecContext *avctx)
+         }
+         if ((err = aacEncoder_SetParam(s->handle, AACENC_BITRATE,
+                                        avctx->bit_rate)) != AACENC_OK) {
+-            av_log(avctx, AV_LOG_ERROR, "Unable to set the bitrate %"PRId64": %s\n",
+-                   (int64_t)avctx->bit_rate, aac_get_error(err));
++            av_log(avctx, AV_LOG_ERROR, "Unable to set the bitrate %d: %s\n",
++                   avctx->bit_rate, aac_get_error(err));
+             goto error;
+         }
+     }
+diff --git a/libavcodec/libgsmenc.c b/libavcodec/libgsmenc.c
+index 69ce439..45fdb8e 100644
+--- a/libavcodec/libgsmenc.c
++++ b/libavcodec/libgsmenc.c
+@@ -62,8 +62,8 @@ static av_cold int libgsm_encode_init(AVCodecContext *avctx) {
+     if (avctx->bit_rate != 13000 /* Official */ &&
+         avctx->bit_rate != 13200 /* Very common */ &&
+         avctx->bit_rate != 0 /* Unknown; a.o. mov does not set bitrate when decoding */ ) {
+-        av_log(avctx, AV_LOG_ERROR, "Bitrate 13000bps required for GSM, got %"PRId64"bps\n",
+-               (int64_t)avctx->bit_rate);
++        av_log(avctx, AV_LOG_ERROR, "Bitrate 13000bps required for GSM, got %dbps\n",
++               avctx->bit_rate);
+         if (avctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL)
+             return -1;
+     }
+diff --git a/libavcodec/libopusenc.c b/libavcodec/libopusenc.c
+index c40fcde..cab7e3a 100644
+--- a/libavcodec/libopusenc.c
++++ b/libavcodec/libopusenc.c
+@@ -351,12 +351,12 @@ static av_cold int libopus_encode_init(AVCodecContext *avctx)
+         avctx->bit_rate = 64000 * opus->stream_count +
+                           32000 * coupled_stream_count;
+         av_log(avctx, AV_LOG_WARNING,
+-               "No bit rate set. Defaulting to %"PRId64" bps.\n", (int64_t)avctx->bit_rate);
++               "No bit rate set. Defaulting to %d bps.\n", avctx->bit_rate);
+     }
+     if (avctx->bit_rate < 500 || avctx->bit_rate > 256000 * avctx->channels) {
+-        av_log(avctx, AV_LOG_ERROR, "The bit rate %"PRId64" bps is unsupported. "
+-               "Please choose a value between 500 and %d.\n", (int64_t)avctx->bit_rate,
++        av_log(avctx, AV_LOG_ERROR, "The bit rate %d bps is unsupported. "
++               "Please choose a value between 500 and %d.\n", avctx->bit_rate,
+                256000 * avctx->channels);
+         ret = AVERROR(EINVAL);
+         goto fail;
+diff --git a/libavcodec/libspeexenc.c b/libavcodec/libspeexenc.c
+index 4bdb961..b96b217 100644
+--- a/libavcodec/libspeexenc.c
++++ b/libavcodec/libspeexenc.c
+@@ -125,10 +125,10 @@ static av_cold void print_enc_params(AVCodecContext *avctx,
+         av_log(avctx, AV_LOG_DEBUG, "  quality: %f\n", s->vbr_quality);
+     } else if (s->abr) {
+         av_log(avctx, AV_LOG_DEBUG, "rate control: ABR\n");
+-        av_log(avctx, AV_LOG_DEBUG, "  bitrate: %"PRId64" bps\n", (int64_t)avctx->bit_rate);
++        av_log(avctx, AV_LOG_DEBUG, "  bitrate: %d bps\n", avctx->bit_rate);
+     } else {
+         av_log(avctx, AV_LOG_DEBUG, "rate control: CBR\n");
+-        av_log(avctx, AV_LOG_DEBUG, "  bitrate: %"PRId64" bps\n", (int64_t)avctx->bit_rate);
++        av_log(avctx, AV_LOG_DEBUG, "  bitrate: %d bps\n", avctx->bit_rate);
+     }
+     av_log(avctx, AV_LOG_DEBUG, "complexity: %d\n",
+            avctx->compression_level);
+diff --git a/libavcodec/mpegvideo_enc.c b/libavcodec/mpegvideo_enc.c
+index db241c8..46ee6a4 100644
+--- a/libavcodec/mpegvideo_enc.c
++++ b/libavcodec/mpegvideo_enc.c
+@@ -506,7 +506,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
+         avctx->bit_rate * av_q2d(avctx->time_base) >
+             avctx->bit_rate_tolerance) {
+         av_log(avctx, AV_LOG_WARNING,
+-               "bitrate tolerance %d too small for bitrate %"PRId64", overriding\n", avctx->bit_rate_tolerance, (int64_t)avctx->bit_rate);
++               "bitrate tolerance %d too small for bitrate %d, overriding\n", avctx->bit_rate_tolerance, avctx->bit_rate);
+         avctx->bit_rate_tolerance = 5 * avctx->bit_rate * av_q2d(avctx->time_base);
+     }
+diff --git a/libavcodec/options_table.h b/libavcodec/options_table.h
+index 022cb1d..14dc914 100644
+--- a/libavcodec/options_table.h
++++ b/libavcodec/options_table.h
+@@ -42,8 +42,8 @@
+ #define AV_CODEC_DEFAULT_BITRATE 200*1000
+ static const AVOption avcodec_options[] = {
+-{"b", "set bitrate (in bits/s)", OFFSET(bit_rate), AV_OPT_TYPE_INT64, {.i64 = AV_CODEC_DEFAULT_BITRATE }, 0, INT64_MAX, A|V|E},
+-{"ab", "set bitrate (in bits/s)", OFFSET(bit_rate), AV_OPT_TYPE_INT64, {.i64 = 128*1000 }, 0, INT_MAX, A|E},
++{"b", "set bitrate (in bits/s)", OFFSET(bit_rate), AV_OPT_TYPE_INT, {.i64 = AV_CODEC_DEFAULT_BITRATE }, 0, INT64_MAX, A|V|E},
++{"ab", "set bitrate (in bits/s)", OFFSET(bit_rate), AV_OPT_TYPE_INT, {.i64 = 128*1000 }, 0, INT_MAX, A|E},
+ {"bt", "Set video bitrate tolerance (in bits/s). In 1-pass mode, bitrate tolerance specifies how far "
+        "ratecontrol is willing to deviate from the target average bitrate value. This is not related "
+        "to minimum/maximum bitrate. Lowering tolerance too much has an adverse effect on quality.",
+@@ -194,9 +194,9 @@ static const AVOption avcodec_options[] = {
+ #if FF_API_MPV_OPT
+ {"rc_eq", "deprecated, use encoder private options instead", OFFSET(rc_eq), AV_OPT_TYPE_STRING, {.str = NULL}, CHAR_MIN, CHAR_MAX, V|E},
+ #endif
+-{"maxrate", "maximum bitrate (in bits/s). Used for VBV together with bufsize.", OFFSET(rc_max_rate), AV_OPT_TYPE_INT64, {.i64 = DEFAULT }, 0, INT_MAX, V|A|E},
++{"maxrate", "maximum bitrate (in bits/s). Used for VBV together with bufsize.", OFFSET(rc_max_rate), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, 0, INT_MAX, V|A|E},
+ {"minrate", "minimum bitrate (in bits/s). Most useful in setting up a CBR encode. It is of little use otherwise.",
+-            OFFSET(rc_min_rate), AV_OPT_TYPE_INT64, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|A|E},
++            OFFSET(rc_min_rate), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|A|E},
+ {"bufsize", "set ratecontrol buffer size (in bits)", OFFSET(rc_buffer_size), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, A|V|E},
+ #if FF_API_MPV_OPT
+ {"rc_buf_aggressivity", "deprecated, use encoder private options instead", OFFSET(rc_buffer_aggressivity), AV_OPT_TYPE_FLOAT, {.dbl = 1.0 }, -FLT_MAX, FLT_MAX, V|E},
+diff --git a/libavcodec/pcm-bluray.c b/libavcodec/pcm-bluray.c
+index 22c1c08..e7f9ee4 100644
+--- a/libavcodec/pcm-bluray.c
++++ b/libavcodec/pcm-bluray.c
+@@ -117,9 +117,9 @@ static int pcm_bluray_parse_header(AVCodecContext *avctx,
+     if (avctx->debug & FF_DEBUG_PICT_INFO)
+         ff_dlog(avctx,
+-                "pcm_bluray_parse_header: %d channels, %d bits per sample, %d Hz, %"PRId64" bit/s\n",
++                "pcm_bluray_parse_header: %d channels, %d bits per sample, %d Hz, %d bit/s\n",
+                 avctx->channels, avctx->bits_per_coded_sample,
+-                avctx->sample_rate, (int64_t)avctx->bit_rate);
++                avctx->sample_rate, avctx->bit_rate);
+     return 0;
+ }
+diff --git a/libavcodec/pcm-dvd.c b/libavcodec/pcm-dvd.c
+index 04c321e..46f730d 100644
+--- a/libavcodec/pcm-dvd.c
++++ b/libavcodec/pcm-dvd.c
+@@ -140,9 +140,9 @@ static int pcm_dvd_parse_header(AVCodecContext *avctx, const uint8_t *header)
+     if (avctx->debug & FF_DEBUG_PICT_INFO)
+         ff_dlog(avctx,
+-                "pcm_dvd_parse_header: %d channels, %d bits per sample, %d Hz, %"PRId64" bit/s\n",
++                "pcm_dvd_parse_header: %d channels, %d bits per sample, %d Hz, %d bit/s\n",
+                 avctx->channels, avctx->bits_per_coded_sample,
+-                avctx->sample_rate, (int64_t)avctx->bit_rate);
++                avctx->sample_rate, avctx->bit_rate);
+     s->last_header = header_int;
+diff --git a/libavcodec/sipr.c b/libavcodec/sipr.c
+index 70d460a..5e428ef 100644
+--- a/libavcodec/sipr.c
++++ b/libavcodec/sipr.c
+@@ -493,8 +493,8 @@ static av_cold int sipr_decoder_init(AVCodecContext * avctx)
+         else if (avctx->bit_rate > 5750 ) ctx->mode = MODE_6k5;
+         else                              ctx->mode = MODE_5k0;
+         av_log(avctx, AV_LOG_WARNING,
+-               "Invalid block_align: %d. Mode %s guessed based on bitrate: %"PRId64"\n",
+-               avctx->block_align, modes[ctx->mode].mode_name, (int64_t)avctx->bit_rate);
++               "Invalid block_align: %d. Mode %s guessed based on bitrate: %d\n",
++               avctx->block_align, modes[ctx->mode].mode_name, avctx->bit_rate);
+     }
+     av_log(avctx, AV_LOG_DEBUG, "Mode: %s\n", modes[ctx->mode].mode_name);
+diff --git a/libavcodec/utils.c b/libavcodec/utils.c
+index 1336e92..7877488 100644
+--- a/libavcodec/utils.c
++++ b/libavcodec/utils.c
+@@ -967,7 +967,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
+         }
+         if (   (avctx->codec_type == AVMEDIA_TYPE_VIDEO || avctx->codec_type == AVMEDIA_TYPE_AUDIO)
+             && avctx->bit_rate>0 && avctx->bit_rate<1000) {
+-            av_log(avctx, AV_LOG_WARNING, "Bitrate %"PRId64" is extremely low, maybe you mean %"PRId64"k\n", (int64_t)avctx->bit_rate, (int64_t)avctx->bit_rate);
++            av_log(avctx, AV_LOG_WARNING, "Bitrate %d is extremely low, maybe you mean %dk\n", avctx->bit_rate, avctx->bit_rate);
+         }
+         if (!avctx->rc_initial_buffer_occupancy)
+@@ -1522,7 +1522,7 @@ void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode)
+                  ", %"PRId64" kb/s", bitrate / 1000);
+     } else if (enc->rc_max_rate > 0) {
+         snprintf(buf + strlen(buf), buf_size - strlen(buf),
+-                 ", max. %"PRId64" kb/s", (int64_t)enc->rc_max_rate / 1000);
++                 ", max. %d kb/s", enc->rc_max_rate / 1000);
+     }
+ }
+diff --git a/libavcodec/wma.c b/libavcodec/wma.c
+index f70937f..717f950 100644
+--- a/libavcodec/wma.c
++++ b/libavcodec/wma.c
+@@ -185,8 +185,8 @@ av_cold int ff_wma_init(AVCodecContext *avctx, int flags2)
+             high_freq = high_freq * 0.5;
+     }
+     ff_dlog(s->avctx, "flags2=0x%x\n", flags2);
+-    ff_dlog(s->avctx, "version=%d channels=%d sample_rate=%d bitrate=%"PRId64" block_align=%d\n",
+-            s->version, avctx->channels, avctx->sample_rate, (int64_t)avctx->bit_rate,
++    ff_dlog(s->avctx, "version=%d channels=%d sample_rate=%d bitrate=%d block_align=%d\n",
++            s->version, avctx->channels, avctx->sample_rate, avctx->bit_rate,
+             avctx->block_align);
+     ff_dlog(s->avctx, "bps=%f bps1=%f high_freq=%f bitoffset=%d\n",
+             bps, bps1, high_freq, s->byte_offset_bits);
+diff --git a/libavcodec/wmaenc.c b/libavcodec/wmaenc.c
+index c68babd..765f570 100644
+--- a/libavcodec/wmaenc.c
++++ b/libavcodec/wmaenc.c
+@@ -52,8 +52,8 @@ static av_cold int encode_init(AVCodecContext *avctx)
+     if (avctx->bit_rate < 24 * 1000) {
+         av_log(avctx, AV_LOG_ERROR,
+-               "bitrate too low: got %"PRId64", need 24000 or higher\n",
+-               (int64_t)avctx->bit_rate);
++               "bitrate too low: got %i, need 24000 or higher\n",
++               avctx->bit_rate);
+         return AVERROR(EINVAL);
+     }
+diff --git a/libavdevice/fbdev_dec.c b/libavdevice/fbdev_dec.c
+index 3b31373..33a2054 100644
+--- a/libavdevice/fbdev_dec.c
++++ b/libavdevice/fbdev_dec.c
+@@ -136,11 +136,11 @@ static av_cold int fbdev_read_header(AVFormatContext *avctx)
+         fbdev->width * fbdev->height * fbdev->bytes_per_pixel * av_q2d(fbdev->framerate_q) * 8;
+     av_log(avctx, AV_LOG_INFO,
+-           "w:%d h:%d bpp:%d pixfmt:%s fps:%d/%d bit_rate:%"PRId64"\n",
++           "w:%d h:%d bpp:%d pixfmt:%s fps:%d/%d bit_rate:%d\n",
+            fbdev->width, fbdev->height, fbdev->varinfo.bits_per_pixel,
+            av_get_pix_fmt_name(pix_fmt),
+            fbdev->framerate_q.num, fbdev->framerate_q.den,
+-           (int64_t)st->codecpar->bit_rate);
++           st->codecpar->bit_rate);
+     return 0;
+ fail:
+diff --git a/libavformat/movenc.c b/libavformat/movenc.c
+index d20d272..9adf08f 100644
+--- a/libavformat/movenc.c
++++ b/libavformat/movenc.c
+@@ -3897,7 +3897,7 @@ static int mov_write_isml_manifest(AVIOContext *pb, MOVMuxContext *mov, AVFormat
+             manifest_bit_rate = props->max_bitrate;
+         }
+-        avio_printf(pb, "<%s systemBitrate=\"%"PRId64"\">\n", type,
++        avio_printf(pb, "<%s systemBitrate=\"%d\">\n", type,
+                     manifest_bit_rate);
+         param_write_int(pb, "systemBitrate", manifest_bit_rate);
+         param_write_int(pb, "trackID", track_id);
+diff --git a/libavformat/rdt.c b/libavformat/rdt.c
+index 8670ead..57ee07e 100644
+--- a/libavformat/rdt.c
++++ b/libavformat/rdt.c
+@@ -448,7 +448,7 @@ real_parse_asm_rule(AVStream *st, const char *p, const char *end)
+ {
+     do {
+         /* can be either averagebandwidth= or AverageBandwidth= */
+-        if (sscanf(p, " %*1[Aa]verage%*1[Bb]andwidth=%"SCNd64, &st->codecpar->bit_rate) == 1)
++        if (sscanf(p, " %*1[Aa]verage%*1[Bb]andwidth=%d", &st->codecpar->bit_rate) == 1)
+             break;
+         if (!(p = strchr(p, ',')) || p > end)
+             p = end;
+diff --git a/libavformat/sdp.c b/libavformat/sdp.c
+index 4e37f65..df2cb43 100644
+--- a/libavformat/sdp.c
++++ b/libavformat/sdp.c
+@@ -748,7 +748,7 @@ void ff_sdp_write_media(char *buff, int size, AVStream *st, int idx,
+     av_strlcatf(buff, size, "m=%s %d RTP/AVP %d\r\n", type, port, payload_type);
+     sdp_write_address(buff, size, dest_addr, dest_type, ttl);
+     if (p->bit_rate) {
+-        av_strlcatf(buff, size, "b=AS:%"PRId64"\r\n", (int64_t)p->bit_rate / 1000);
++        av_strlcatf(buff, size, "b=AS:%d\r\n", p->bit_rate / 1000);
+     }
+     sdp_write_media_attributes(buff, size, st, payload_type, fmt);
+diff --git a/libavformat/smoothstreamingenc.c b/libavformat/smoothstreamingenc.c
+index dabd1ea..6d126e9 100644
+--- a/libavformat/smoothstreamingenc.c
++++ b/libavformat/smoothstreamingenc.c
+@@ -263,7 +263,7 @@ static int write_manifest(AVFormatContext *s, int final)
+             if (s->streams[i]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO)
+                 continue;
+             last = i;
+-            avio_printf(out, "<QualityLevel Index=\"%d\" Bitrate=\"%"PRId64"\" FourCC=\"%s\" MaxWidth=\"%d\" MaxHeight=\"%d\" CodecPrivateData=\"%s\" />\n", index, (int64_t)s->streams[i]->codecpar->bit_rate, os->fourcc, s->streams[i]->codecpar->width, s->streams[i]->codecpar->height, os->private_str);
++            avio_printf(out, "<QualityLevel Index=\"%d\" Bitrate=\"%d\" FourCC=\"%s\" MaxWidth=\"%d\" MaxHeight=\"%d\" CodecPrivateData=\"%s\" />\n", index, s->streams[i]->codecpar->bit_rate, os->fourcc, s->streams[i]->codecpar->width, s->streams[i]->codecpar->height, os->private_str);
+             index++;
+         }
+         output_chunk_list(&c->streams[last], out, final, c->lookahead_count, c->window_size);
+@@ -277,7 +277,7 @@ static int write_manifest(AVFormatContext *s, int final)
+             if (s->streams[i]->codecpar->codec_type != AVMEDIA_TYPE_AUDIO)
+                 continue;
+             last = i;
+-            avio_printf(out, "<QualityLevel Index=\"%d\" Bitrate=\"%"PRId64"\" FourCC=\"%s\" SamplingRate=\"%d\" Channels=\"%d\" BitsPerSample=\"16\" PacketSize=\"%d\" AudioTag=\"%d\" CodecPrivateData=\"%s\" />\n", index, (int64_t)s->streams[i]->codecpar->bit_rate, os->fourcc, s->streams[i]->codecpar->sample_rate, s->streams[i]->codecpar->channels, os->packet_size, os->audio_tag, os->private_str);
++            avio_printf(out, "<QualityLevel Index=\"%d\" Bitrate=\"%d\" FourCC=\"%s\" SamplingRate=\"%d\" Channels=\"%d\" BitsPerSample=\"16\" PacketSize=\"%d\" AudioTag=\"%d\" CodecPrivateData=\"%s\" />\n", index, s->streams[i]->codecpar->bit_rate, os->fourcc, s->streams[i]->codecpar->sample_rate, s->streams[i]->codecpar->channels, os->packet_size, os->audio_tag, os->private_str);
+             index++;
+         }
+         output_chunk_list(&c->streams[last], out, final, c->lookahead_count, c->window_size);
+@@ -324,7 +324,7 @@ static int ism_write_header(AVFormatContext *s)
+             ret = AVERROR(EINVAL);
+             goto fail;
+         }
+-        snprintf(os->dirname, sizeof(os->dirname), "%s/QualityLevels(%"PRId64")", s->filename, (int64_t)s->streams[i]->codecpar->bit_rate);
++        snprintf(os->dirname, sizeof(os->dirname), "%s/QualityLevels(%d)", s->filename, s->streams[i]->codecpar->bit_rate);
+         if (mkdir(os->dirname, 0777) == -1 && errno != EEXIST) {
+             ret = AVERROR(errno);
+             av_log(s, AV_LOG_ERROR, "mkdir failed\n");
+diff --git a/libavformat/vqf.c b/libavformat/vqf.c
+index 841840e..b5cdb78 100644
+--- a/libavformat/vqf.c
++++ b/libavformat/vqf.c
+@@ -211,8 +211,8 @@ static int vqf_read_header(AVFormatContext *s)
+         size = 2048;
+         break;
+     default:
+-        av_log(s, AV_LOG_ERROR, "Mode not supported: %d Hz, %"PRId64" kb/s.\n",
+-               st->codecpar->sample_rate, (int64_t)st->codecpar->bit_rate);
++        av_log(s, AV_LOG_ERROR, "Mode not supported: %d Hz, %d kb/s.\n",
++               st->codecpar->sample_rate, st->codecpar->bit_rate);
+         return -1;
+     }
+     c->frame_bit_len = st->codecpar->bit_rate*size/st->codecpar->sample_rate;
index ad77871249f1457c0f48af293fa39e7d0e32929c..b161f0d2130329fd1a90da68944d9210d964da17 100755 (executable)
@@ -33,8 +33,15 @@ $(ARCHIVE)/hotplug.tar.gz:
 $(ARCHIVE)/fbshot-0.3.tar.gz:
        $(WGET) http://www.fhloston-paradise.de/fbshot-0.3.tar.gz
 
-$(ARCHIVE)/ffmpeg-$(FFMPEG_VER).tar.xz:
-       $(WGET) http://www.ffmpeg.org/releases/ffmpeg-$(FFMPEG_VER).tar.xz
+$(ARCHIVE)/ffmpeg-git-$(FFMPEG_GIT).tar.gz:
+       set -e; cd $(BUILD_TMP); \
+               rm -rf ffmpeg-git-$(FFMPEG_GIT); \
+               git clone https://git.ffmpeg.org/ffmpeg.git ffmpeg-git-$(FFMPEG_GIT)
+       set -e; cd $(BUILD_TMP)/ffmpeg-git-$(FFMPEG_GIT); \
+               git reset --hard $(FFMPEG_GIT)
+       set -e; cd $(BUILD_TMP); \
+               tar cvpzf $@ ffmpeg-git-$(FFMPEG_GIT)
+       $(REMOVE)/ffmpeg-git-$(FFMPEG_GIT)
 
 $(ARCHIVE)/freetype-$(FREETYPE_VER).tar.bz2:
        $(WGET) http://downloads.sourceforge.net/project/freetype/freetype2/$(FREETYPE_VER)/freetype-$(FREETYPE_VER).tar.bz2
index e9d0607b8554ac36f0efe7e04932f261626d670a..6ac4f99d2009f8f6c86c3a387647f974d5809215 100755 (executable)
@@ -511,7 +511,7 @@ FFMPEG_CONFIGURE = \
                --enable-cross-compile \
                --enable-shared \
                --enable-small \
-               --enable-bzlib \
+               --disable-bzlib \
                --enable-zlib \
                --disable-debug \
                --enable-stripping \
@@ -519,27 +519,28 @@ FFMPEG_CONFIGURE = \
                --enable-decoder=vc1 \
                --target-os=linux \
                --disable-neon \
+               --disable-runtime-cpudetect \
                --arch=arm
 endif # ifeq ($(BOXARCH), arm)
 
 ifeq ($(PLATFORM), $(filter $(PLATFORM), apollo kronos))
-FFMPEG_CONFIGURE += --cpu=cortex-a9 --extra-cflags="-mfpu=vfpv3-d16 -mfloat-abi=hard -I$(TARGETPREFIX)/include"
+FFMPEG_CONFIGURE += --cpu=cortex-a9 --enable-vfp --extra-cflags="-mfpu=vfpv3-d16 -mfloat-abi=hard -I$(TARGETPREFIX)/include"
 else
 FFMPEG_CONFIGURE += --disable-iconv
-FFMPEG_CONFIGURE += --cpu=armv6 --extra-cflags="-I$(TARGETPREFIX)/include"
+FFMPEG_CONFIGURE += --cpu=armv6 --disable-vfp --extra-cflags="-I$(TARGETPREFIX)/include"
 endif
-$(D)/ffmpeg: $(D)/librtmp $(D)/libroxml $(ARCHIVE)/ffmpeg-$(FFMPEG_VER).tar.xz | $(TARGETPREFIX)
-       $(REMOVE)/ffmpeg-$(FFMPEG_VER)
-       $(UNTAR)/ffmpeg-$(FFMPEG_VER).tar.xz
-       set -e; pushd $(BUILD_TMP)/ffmpeg-$(FFMPEG_VER) && \
-               $(PATCH)/ffmpeg-hds-libroxml-2.8.x.patch; \
-               $(PATCH)/ffmpeg-aac-2.8.x.patch; \
-               $(PATCH)/ffmpeg-fixed-memleak-in-mpegts-demuxer-on-some-malformed-mpegts-files.patch; \
+$(D)/ffmpeg: $(D)/librtmp $(D)/libroxml $(ARCHIVE)/ffmpeg-git-$(FFMPEG_GIT).tar.gz | $(TARGETPREFIX)
+       $(REMOVE)/ffmpeg-git-$(FFMPEG_GIT)
+       $(UNTAR)/ffmpeg-git-$(FFMPEG_GIT).tar.gz
+       set -e; pushd $(BUILD_TMP)/ffmpeg-git-$(FFMPEG_GIT) && \
+               $(PATCH)/ffmpeg/0001-ffmpeg-hds-libroxml-3.x.patch; \
+               $(PATCH)/ffmpeg/0002-ffmpeg-aac-3.x.patch; \
+               $(PATCH)/ffmpeg/0003-ffmpeg-Revert-lavc-Switch-bitrate-to-64bit.patch; \
                $(BUILDENV) \
                ./configure \
                        $(FFMPEG_CONFIGURE) \
                        --extra-ldflags="-L$(TARGETPREFIX)/lib -lz" \
-                       --logfile=$(BUILD_TMP)/Config-$(FFMPEG_VER).log \
+                       --logfile=$(BUILD_TMP)/Config-$(FFMPEG_GIT).log \
                        --cross-prefix=$(TARGET)- \
                        --prefix=$(TARGETPREFIX) \
                        --mandir=/.remove; \
@@ -551,7 +552,7 @@ $(D)/ffmpeg: $(D)/librtmp $(D)/libroxml $(ARCHIVE)/ffmpeg-$(FFMPEG_VER).tar.xz |
        $(REWRITE_PKGCONF) $(PKG_CONFIG_PATH)/libavcodec.pc
        $(REWRITE_PKGCONF) $(PKG_CONFIG_PATH)/libavutil.pc
        $(REWRITE_PKGCONF) $(PKG_CONFIG_PATH)/libswresample.pc
-       $(REMOVE)/ffmpeg $(TARGETPREFIX)/.remove
+       $(REMOVE)/ffmpeg-git-$(FFMPEG_GIT) $(TARGETPREFIX)/.remove
        touch $@
 
 $(D)/libroxml: $(ARCHIVE)/libroxml-$(LIBROXML_VER).tar.gz | $(TARGETPREFIX)
index d4623769b3b8318f770739af5caa0dec93d6827b..50f227b101aae784b9276a22b6c8edd16f1f2f90 100644 (file)
@@ -42,7 +42,7 @@ E2FSPROGS_VER=1.42.13
 EXPAT_VER = 2.1.0
 
 # A complete, cross-platform solution to record, convert and stream audio and video
-FFMPEG_VER=2.8.11
+FFMPEG_GIT = dec2fa8
 
 # FLEX (the fast lexical analyser)
 FLEX_VER=2.5.35