From deebad87809d50e73e442f95695723ea5972b297 Mon Sep 17 00:00:00 2001 From: Markham Date: Wed, 3 May 2017 20:33:57 +0200 Subject: [PATCH] cleanup ffmpeg patches --- archive-patches/ffmpeg-0.8.6-dvbsubs.diff | 136 - archive-patches/ffmpeg-aac-2.8.x.patch | 52 - archive-patches/ffmpeg-dvbsubs.diff | 154 - .../ffmpeg-export-missing-symbol.diff | 41 - ...muxer-on-some-malformed-mpegts-files.patch | 44 - .../ffmpeg-hds-libroxml-2.8.x.patch | 2775 ----------------- 6 files changed, 3202 deletions(-) delete mode 100644 archive-patches/ffmpeg-0.8.6-dvbsubs.diff delete mode 100644 archive-patches/ffmpeg-aac-2.8.x.patch delete mode 100644 archive-patches/ffmpeg-dvbsubs.diff delete mode 100644 archive-patches/ffmpeg-export-missing-symbol.diff delete mode 100644 archive-patches/ffmpeg-fixed-memleak-in-mpegts-demuxer-on-some-malformed-mpegts-files.patch delete mode 100644 archive-patches/ffmpeg-hds-libroxml-2.8.x.patch diff --git a/archive-patches/ffmpeg-0.8.6-dvbsubs.diff b/archive-patches/ffmpeg-0.8.6-dvbsubs.diff deleted file mode 100644 index 4e88e75..0000000 --- a/archive-patches/ffmpeg-0.8.6-dvbsubs.diff +++ /dev/null @@ -1,136 +0,0 @@ ---- ffmpeg-0.8.6/libavcodec/dvbsubdec.c 2011-09-22 02:39:22.000000000 +0200 -+++ ffmpeg-0.8.6/libavcodec/dvbsubdec.c 2011-11-13 13:16:29.000000000 +0100 -@@ -23,7 +23,9 @@ - #include "get_bits.h" - #include "bytestream.h" - #include "libavutil/colorspace.h" -+#include - -+#define DEBUG - #define DVBSUB_PAGE_SEGMENT 0x10 - #define DVBSUB_REGION_SEGMENT 0x11 - #define DVBSUB_CLUT_SEGMENT 0x12 -@@ -101,6 +103,10 @@ - char fname[40], fname2[40]; - char command[1024]; - -+#ifdef DEBUG -+ av_log(0, AV_LOG_INFO, "SAVE FILE: %s\n", filename); -+#endif -+ - snprintf(fname, sizeof(fname), "%s.ppm", filename); - - f = fopen(fname, "w"); -@@ -142,11 +148,13 @@ - } - fclose(f); - -+#if 0 - snprintf(command, sizeof(command), "pnmtopng -alpha %s %s > %s.png 2> /dev/null", fname2, fname, filename); - system(command); - - snprintf(command, sizeof(command), "rm %s %s", fname, fname2); - system(command); -+#endif - } - #endif - -@@ -789,8 +797,8 @@ - y_pos++; - - while (buf < buf_end) { -- if (x_pos > region->width || y_pos > region->height) { -- av_log(avctx, AV_LOG_ERROR, "Invalid object location!\n"); -+ if (x_pos > region->width || y_pos >= region->height) { -+ av_log(avctx, AV_LOG_ERROR, "Invalid object location: x %d y %d, region %dx%d\n", x_pos, y_pos, region->width, region->height); - return; - } - -@@ -989,7 +997,9 @@ - YUV_TO_RGB1_CCIR(cb, cr); - YUV_TO_RGB2_CCIR(r, g, b, y); - -+#ifdef DEBUG_CLUT - av_dlog(avctx, "clut %d := (%d,%d,%d,%d)\n", entry_id, r, g, b, alpha); -+#endif - - if (depth & 0x80) - clut->clut4[entry_id] = RGBA(r,g,b,255 - alpha); -@@ -1332,6 +1342,10 @@ - int i; - int offset_x=0, offset_y=0; - -+#ifdef DEBUG -+ av_log(avctx, AV_LOG_INFO, "************** dvbsub_display_end_segment ******************\n"); -+#endif -+ - sub->end_display_time = ctx->time_out * 1000; - - if (display_def) { -@@ -1412,6 +1426,11 @@ - int segment_type; - int page_id; - int segment_length; -+ -+#ifdef DEBUG -+ av_log(avctx, AV_LOG_INFO, "dvbsub_decode: ctx %x data %x data_size %x (%d) avpkt %x len %d\n", avctx, data, data_size, *data_size, avpkt, buf_size); -+#endif -+ - int i; - - av_dlog(avctx, "DVB sub packet:\n"); -@@ -1442,28 +1461,50 @@ - p += 2; - - if (p_end - p < segment_length) { -- av_dlog(avctx, "incomplete or broken packet"); -- return -1; -+ //av_dlog(avctx, "incomplete or broken packet"); -+ av_log(avctx, AV_LOG_INFO, "incomplete or broken packet, size %d, processed %d\n", p_end-p, p_end-buf); -+ //return -1; - } - -- if (page_id == ctx->composition_id || page_id == ctx->ancillary_id || -- ctx->composition_id == -1 || ctx->ancillary_id == -1) { -+ //if (page_id == ctx->composition_id || page_id == ctx->ancillary_id || -+ //ctx->composition_id == -1 || ctx->ancillary_id == -1) { -+ { - switch (segment_type) { - case DVBSUB_PAGE_SEGMENT: -+#ifdef DEBUG -+ av_log(avctx, AV_LOG_INFO, "DVBSUB_PAGE_SEGMENT: page id %d, length %d (composition_id %d ancillary_id %d)\n", -+ page_id, segment_length, ctx->composition_id, ctx->ancillary_id); -+#endif - dvbsub_parse_page_segment(avctx, p, segment_length); - break; - case DVBSUB_REGION_SEGMENT: -+#ifdef DEBUG -+ av_log(avctx, AV_LOG_INFO, "DVBSUB_REGION_SEGMENT: page id %d, length %d (composition_id %d ancillary_id %d)\n", -+ page_id, segment_length, ctx->composition_id, ctx->ancillary_id); -+#endif - dvbsub_parse_region_segment(avctx, p, segment_length); - break; - case DVBSUB_CLUT_SEGMENT: -+#ifdef DEBUG -+ av_log(avctx, AV_LOG_INFO, "DVBSUB_CLUT_SEGMENT: page id %d, length %d (composition_id %d ancillary_id %d)\n", -+ page_id, segment_length, ctx->composition_id, ctx->ancillary_id); -+#endif - dvbsub_parse_clut_segment(avctx, p, segment_length); - break; - case DVBSUB_OBJECT_SEGMENT: -+#ifdef DEBUG -+ av_log(avctx, AV_LOG_INFO, "DVBSUB_OBJECT_SEGMENT: page id %d, length %d (composition_id %d ancillary_id %d)\n", -+ page_id, segment_length, ctx->composition_id, ctx->ancillary_id); -+#endif - dvbsub_parse_object_segment(avctx, p, segment_length); - break; - case DVBSUB_DISPLAYDEFINITION_SEGMENT: - dvbsub_parse_display_definition_segment(avctx, p, segment_length); - case DVBSUB_DISPLAY_SEGMENT: -+#ifdef DEBUG -+ av_log(avctx, AV_LOG_INFO, "DVBSUB_DISPLAY_SEGMENT: page id %d, length %d (composition_id %d ancillary_id %d)\n", -+ page_id, segment_length, ctx->composition_id, ctx->ancillary_id); -+#endif - *data_size = dvbsub_display_end_segment(avctx, p, segment_length, sub); - break; - default: diff --git a/archive-patches/ffmpeg-aac-2.8.x.patch b/archive-patches/ffmpeg-aac-2.8.x.patch deleted file mode 100644 index 9ce3595..0000000 --- a/archive-patches/ffmpeg-aac-2.8.x.patch +++ /dev/null @@ -1,52 +0,0 @@ ---- a/libavcodec/aacdec_template.c -+++ b/libavcodec/aacdec_template.c -@@ -2347,7 +2347,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 -@@ -101,7 +101,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 -@@ -452,7 +452,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; - -@@ -466,7 +466,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-dvbsubs.diff b/archive-patches/ffmpeg-dvbsubs.diff deleted file mode 100644 index 5a8057e..0000000 --- a/archive-patches/ffmpeg-dvbsubs.diff +++ /dev/null @@ -1,154 +0,0 @@ ---- ffmpeg-0.7-rc1/libavcodec/dvbsubdec.c 2011-04-27 00:58:23.000000000 +0200 -+++ ffmpeg-0.7-rc1/libavcodec/dvbsubdec.c 2011-05-28 18:38:29.000000000 +0200 -@@ -23,8 +23,10 @@ - #include "get_bits.h" - #include "bytestream.h" - #include "libavutil/colorspace.h" -+#include - --//#define DEBUG -+#define DEBUG -+//#define DEBUG_CLUT - //#define DEBUG_PACKET_CONTENTS - //#define DEBUG_SAVE_IMAGES - -@@ -104,12 +106,16 @@ - char fname[40], fname2[40]; - char command[1024]; - -+#ifdef DEBUG -+ av_log(0, AV_LOG_INFO, "SAVE FILE: %s\n", filename); -+#endif - snprintf(fname, sizeof(fname), "%s.ppm", filename); - - f = fopen(fname, "w"); - if (!f) { - perror(fname); -- exit(1); -+ //exit(1); -+ return; - } - fprintf(f, "P6\n" - "%d %d\n" -@@ -131,7 +137,8 @@ - f = fopen(fname2, "w"); - if (!f) { - perror(fname2); -- exit(1); -+ //exit(1); -+ return; - } - fprintf(f, "P5\n" - "%d %d\n" -@@ -145,11 +152,13 @@ - } - fclose(f); - -+#if 0 - snprintf(command, sizeof(command), "pnmtopng -alpha %s %s > %s.png 2> /dev/null", fname2, fname, filename); - system(command); - - snprintf(command, sizeof(command), "rm %s %s", fname, fname2); - system(command); -+#endif - } - #endif - -@@ -777,8 +786,8 @@ - y_pos++; - - while (buf < buf_end) { -- if (x_pos > region->width || y_pos > region->height) { -- av_log(avctx, AV_LOG_ERROR, "Invalid object location!\n"); -+ if (x_pos > region->width || y_pos >= region->height) { -+ av_log(avctx, AV_LOG_ERROR, "Invalid object location: x %d y %d, region %dx%d\n", x_pos, y_pos, region->width, region->height); - return; - } - -@@ -982,7 +991,9 @@ - YUV_TO_RGB1_CCIR(cb, cr); - YUV_TO_RGB2_CCIR(r, g, b, y); - -+#ifdef DEBUG_CLUT - av_dlog(avctx, "clut %d := (%d,%d,%d,%d)\n", entry_id, r, g, b, alpha); -+#endif - - if (depth & 0x80) - clut->clut4[entry_id] = RGBA(r,g,b,255 - alpha); -@@ -1323,6 +1334,10 @@ - int i; - int offset_x=0, offset_y=0; - -+#ifdef DEBUG -+ av_log(avctx, AV_LOG_INFO, "************** dvbsub_display_end_segment ******************\n"); -+#endif -+ - sub->end_display_time = ctx->time_out * 1000; - - if (display_def) { -@@ -1404,6 +1419,10 @@ - int page_id; - int segment_length; - -+#ifdef DEBUG -+ av_log(avctx, AV_LOG_INFO, "dvbsub_decode: ctx %x data %x data_size %x (%d) avpkt %x len %d\n", avctx, data, data_size, *data_size, avpkt, buf_size); -+#endif -+ - #ifdef DEBUG_PACKET_CONTENTS - int i; - -@@ -1437,28 +1456,50 @@ - p += 2; - - if (p_end - p < segment_length) { -- av_dlog(avctx, "incomplete or broken packet"); -- return -1; -+ //av_dlog(avctx, "incomplete or broken packet"); -+ av_log(avctx, AV_LOG_INFO, "incomplete or broken packet, size %d, processed %d\n", p_end-p, p_end-buf); -+ //return -1; - } - -- if (page_id == ctx->composition_id || page_id == ctx->ancillary_id || -- ctx->composition_id == -1 || ctx->ancillary_id == -1) { -+ //if (page_id == ctx->composition_id || page_id == ctx->ancillary_id || -+ //ctx->composition_id == -1 || ctx->ancillary_id == -1) { -+ { - switch (segment_type) { - case DVBSUB_PAGE_SEGMENT: -+#ifdef DEBUG -+ av_log(avctx, AV_LOG_INFO, "DVBSUB_PAGE_SEGMENT: page id %d, length %d (composition_id %d ancillary_id %d)\n", -+ page_id, segment_length, ctx->composition_id, ctx->ancillary_id); -+#endif - dvbsub_parse_page_segment(avctx, p, segment_length); - break; - case DVBSUB_REGION_SEGMENT: -+#ifdef DEBUG -+ av_log(avctx, AV_LOG_INFO, "DVBSUB_REGION_SEGMENT: page id %d, length %d (composition_id %d ancillary_id %d)\n", -+ page_id, segment_length, ctx->composition_id, ctx->ancillary_id); -+#endif - dvbsub_parse_region_segment(avctx, p, segment_length); - break; - case DVBSUB_CLUT_SEGMENT: -+#ifdef DEBUG -+ av_log(avctx, AV_LOG_INFO, "DVBSUB_CLUT_SEGMENT: page id %d, length %d (composition_id %d ancillary_id %d)\n", -+ page_id, segment_length, ctx->composition_id, ctx->ancillary_id); -+#endif - dvbsub_parse_clut_segment(avctx, p, segment_length); - break; - case DVBSUB_OBJECT_SEGMENT: -+#ifdef DEBUG -+ av_log(avctx, AV_LOG_INFO, "DVBSUB_OBJECT_SEGMENT: page id %d, length %d (composition_id %d ancillary_id %d)\n", -+ page_id, segment_length, ctx->composition_id, ctx->ancillary_id); -+#endif - dvbsub_parse_object_segment(avctx, p, segment_length); - break; - case DVBSUB_DISPLAYDEFINITION_SEGMENT: - dvbsub_parse_display_definition_segment(avctx, p, segment_length); - case DVBSUB_DISPLAY_SEGMENT: -+#ifdef DEBUG -+ av_log(avctx, AV_LOG_INFO, "DVBSUB_DISPLAY_SEGMENT: page id %d, length %d (composition_id %d ancillary_id %d)\n", -+ page_id, segment_length, ctx->composition_id, ctx->ancillary_id); -+#endif - *data_size = dvbsub_display_end_segment(avctx, p, segment_length, sub); - break; - default: diff --git a/archive-patches/ffmpeg-export-missing-symbol.diff b/archive-patches/ffmpeg-export-missing-symbol.diff deleted file mode 100644 index 1b9e364..0000000 --- a/archive-patches/ffmpeg-export-missing-symbol.diff +++ /dev/null @@ -1,41 +0,0 @@ -Index: b/libavformat/avformat.h -=================================================================== ---- a/libavformat/avformat.h -+++ b/libavformat/avformat.h -@@ -206,16 +206,19 @@ int av_dup_packet(AVPacket *pkt); - /** - * Free a packet. - * - * @param pkt packet to free - */ -+void av_free_packet(AVPacket *pkt); -+#if 0 - static inline void av_free_packet(AVPacket *pkt) - { - if (pkt && pkt->destruct) { - pkt->destruct(pkt); - } - } -+#endif - - /*************************************************/ - /* fractional numbers for exact pts handling */ - - /** -Index: b/libavformat/mmf.c -=================================================================== ---- a/libavformat/mmf.c -+++ b/libavformat/mmf.c -@@ -314,5 +314,12 @@ AVOutputFormat mmf_muxer = { - mmf_write_header, - mmf_write_packet, - mmf_write_trailer, - }; - #endif -+ -+void av_free_packet(AVPacket *pkt) -+{ -+ if (pkt && pkt->destruct) { -+ pkt->destruct(pkt); -+ } -+} diff --git a/archive-patches/ffmpeg-fixed-memleak-in-mpegts-demuxer-on-some-malformed-mpegts-files.patch b/archive-patches/ffmpeg-fixed-memleak-in-mpegts-demuxer-on-some-malformed-mpegts-files.patch deleted file mode 100644 index d280124..0000000 --- a/archive-patches/ffmpeg-fixed-memleak-in-mpegts-demuxer-on-some-malformed-mpegts-files.patch +++ /dev/null @@ -1,44 +0,0 @@ -From cb7c19124165508ae5f38a385a14f9c13b096a27 Mon Sep 17 00:00:00 2001 -From: Joakim Plate -Date: Fri, 26 Nov 2010 20:56:48 +0000 -Subject: [PATCH 10/13] fixed: memleak in mpegts demuxer on some malformed (??) - mpegts files with too large pes packets - -at-visions sample file brokenStream.mpg - -Patch part of the XBMC patch set for ffmpeg, downloaded from -https://github.com/xbmc/FFmpeg/. - -Signed-off-by: Bernd Kuhls -Signed-off-by: Thomas Petazzoni ---- - libavformat/mpegts.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c -index d5a8a45..e070f1f 100644 ---- a/libavformat/mpegts.c -+++ b/libavformat/mpegts.c -@@ -850,6 +850,10 @@ static void reset_pes_packet_state(PESContext *pes) - - static void new_pes_packet(PESContext *pes, AVPacket *pkt) - { -+ if(pkt->data) { -+ av_log(pes->stream, AV_LOG_ERROR, "ignoring previously allocated packet on stream %d\n", pkt->stream_index); -+ av_free_packet(pkt); -+ } - av_init_packet(pkt); - - pkt->buf = pes->buffer; -@@ -2644,6 +2649,8 @@ static int mpegts_read_packet(AVFormatContext *s, AVPacket *pkt) - - pkt->size = -1; - ts->pkt = pkt; -+ ts->pkt->data = NULL; -+ - ret = handle_packets(ts, 0); - if (ret < 0) { - av_free_packet(ts->pkt); --- -2.1.0 - diff --git a/archive-patches/ffmpeg-hds-libroxml-2.8.x.patch b/archive-patches/ffmpeg-hds-libroxml-2.8.x.patch deleted file mode 100644 index 807e1df..0000000 --- a/archive-patches/ffmpeg-hds-libroxml-2.8.x.patch +++ /dev/null @@ -1,2775 +0,0 @@ -From a311102d78840d25474d0158db478862bef5ae59 Mon Sep 17 00:00:00 2001 -From: Jacek Jendrzej -Date: Thu, 23 Apr 2015 19:57:16 +0200 -Subject: [PATCH 1/4] add HDS ro - -Signed-off-by: Jacek Jendrzej ---- - 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 2eada0e..30f75e0 100755 ---- a/configure -+++ b/configure -@@ -284,6 +284,7 @@ - --enable-x11grab enable X11 grabbing (legacy) [no] - --disable-xlib disable xlib [autodetect] - --disable-zlib disable zlib [autodetect] -+ --disable-libroxml disable XML parsing using the C library libroxml [autodetect] - - Toolchain options: - --arch=ARCH select architecture [$arch] -@@ -1395,6 +1396,7 @@ - libopus - libpulse - libquvi -+ libroxml - librtmp - libschroedinger - libshine -@@ -2580,6 +2582,7 @@ - eac3_demuxer_select="ac3_parser" - f4v_muxer_select="mov_muxer" - 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" -@@ -5193,6 +5196,8 @@ - disabled bzlib || check_lib2 bzlib.h BZ2_bzlibVersion -lbz2 || disable bzlib - disabled lzma || check_lib2 lzma.h lzma_version_number -llzma || disable lzma - -+disabled libroxml || check_lib roxml.h roxml_load_buf -lroxml || disable libroxml -+ - check_lib math.h sin -lm && LIBM="-lm" - disabled crystalhd || check_lib libcrystalhd/libcrystalhd_if.h DtsCrystalHDVersion -lcrystalhd || disable crystalhd - -diff --git a/libavformat/Makefile b/libavformat/Makefile -index bca9d5b..e8334c0 100644 ---- a/libavformat/Makefile -+++ b/libavformat/Makefile -@@ -183,6 +183,7 @@ OBJS-$(CONFIG_H263_DEMUXER) += h263dec.o rawdec.o - OBJS-$(CONFIG_H263_MUXER) += rawenc.o - OBJS-$(CONFIG_H264_DEMUXER) += h264dec.o rawdec.o - OBJS-$(CONFIG_H264_MUXER) += rawenc.o -+OBJS-$(CONFIG_HDS_DEMUXER) += hdsdec.o amfmetadata.o f4mmanifest.o f4fbox.o flvtag.o - OBJS-$(CONFIG_HDS_MUXER) += hdsenc.o - OBJS-$(CONFIG_HEVC_DEMUXER) += hevcdec.o rawdec.o - OBJS-$(CONFIG_HEVC_MUXER) += rawenc.o -diff --git a/libavformat/allformats.c b/libavformat/allformats.c -index 0f53d4c..06652e5 100644 ---- a/libavformat/allformats.c -+++ b/libavformat/allformats.c -@@ -143,7 +143,7 @@ void av_register_all(void) - REGISTER_MUXDEMUX(H261, h261); - REGISTER_MUXDEMUX(H263, h263); - REGISTER_MUXDEMUX(H264, h264); -- REGISTER_MUXER (HDS, hds); -+ REGISTER_MUXDEMUX(HDS, hds); - REGISTER_MUXDEMUX(HEVC, hevc); - REGISTER_MUXDEMUX(HLS, hls); - REGISTER_DEMUXER (HNM, hnm); -diff --git a/libavformat/amfmetadata.c b/libavformat/amfmetadata.c -new file mode 100644 -index 0000000..f2fe7ca ---- /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(!url_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(!url_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..393fbee ---- /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(!url_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..b33247b ---- /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 -+ -+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_idxid, 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 db9468f..8d97e06 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 07f7b68..afe7e51 100644 ---- a/libavformat/flvdec.c -+++ b/libavformat/flvdec.c -@@ -298,6 +298,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, - AVStream *vstream, int64_t max_pos) - { -diff --git a/libavformat/flvtag.c b/libavformat/flvtag.c -new file mode 100644 -index 0000000..a611ea0 ---- /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(!url_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 -+#include -+#include -+#include -+ -+#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) -+ ff_program_add_stream_index(s, p->id, media->video_stream->index); -+ if (media->audio_stream) -+ ff_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, -+}; --- -2.4.0 - -- 2.39.5