summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-x[-rw-r--r--]libavcodec/Makefile2
-rwxr-xr-x[-rw-r--r--]libavcodec/aac_ac3_parser.c3
-rwxr-xr-x[-rw-r--r--]libavcodec/allcodecs.c2
-rwxr-xr-x[-rw-r--r--]libavcodec/avcodec.h57
-rwxr-xr-x[-rw-r--r--]libavcodec/avpacket.c6
-rwxr-xr-xlibavcodec/bluraytextsubtitle.c824
-rwxr-xr-xlibavcodec/bluraytextsubtitle.h247
-rwxr-xr-x[-rw-r--r--]libavcodec/h264.c74
-rwxr-xr-x[-rw-r--r--]libavcodec/h264.h161
-rwxr-xr-x[-rw-r--r--]libavcodec/h264_parser.c219
-rwxr-xr-x[-rw-r--r--]libavcodec/h264_ps.c546
-rwxr-xr-x[-rw-r--r--]libavcodec/h264_refs.c12
-rwxr-xr-x[-rw-r--r--]libavcodec/h264_sei.c2
-rwxr-xr-xlibavcodec/ig.c987
-rwxr-xr-xlibavcodec/ig.h191
-rwxr-xr-x[-rw-r--r--]libavcodec/mpeg12.c42
-rwxr-xr-x[-rw-r--r--]libavcodec/parser.c61
-rwxr-xr-x[-rw-r--r--]libavcodec/pgssubdec.c26
-rwxr-xr-x[-rw-r--r--]libavcodec/pthread.c2
-rwxr-xr-xlibavcodec/rkon2_mpeg2dec.cpp598
-rwxr-xr-x[-rw-r--r--]libavcodec/utils.c16
-rwxr-xr-x[-rw-r--r--]libavfilter/af_aconvert.obin17660 -> 17604 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/af_aformat.obin18732 -> 18744 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/af_amerge.obin33532 -> 33448 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/af_amix.obin30328 -> 30068 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/af_anull.obin11560 -> 11540 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/af_aresample.obin22912 -> 22636 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/af_asetnsamples.obin19928 -> 19964 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/af_ashowinfo.obin15408 -> 15108 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/af_astreamsync.obin23160 -> 22580 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/af_atempo.obin60160 -> 59312 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/af_channelmap.obin26884 -> 26924 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/af_channelsplit.obin17708 -> 17680 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/af_earwax.obin14800 -> 14752 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/af_join.obin29632 -> 29412 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/af_pan.obin29068 -> 28500 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/af_silencedetect.obin22676 -> 22288 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/af_volume.obin18292 -> 17900 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/af_volumedetect.obin17124 -> 17148 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/allfilters.obin21228 -> 21064 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/asink_anullsink.obin11472 -> 11452 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/asrc_aevalsrc.obin21152 -> 20900 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/asrc_anullsrc.obin16396 -> 16392 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/audio.obin18756 -> 18804 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/avcodec.obin61532 -> 61492 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/avf_concat.obin37732 -> 38332 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/avf_showspectrum.obin34124 -> 33856 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/avf_showwaves.obin30796 -> 30640 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/avfilter.obin41964 -> 42008 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/avfiltergraph.obin58280 -> 58128 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/bbox.obin4388 -> 4344 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/buffer.obin18288 -> 18280 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/buffersink.obin17968 -> 18004 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/buffersrc.obin76824 -> 77052 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/drawutils.obin46240 -> 46368 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/f_sendcmd.obin35156 -> 35456 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/f_setpts.obin19304 -> 18552 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/f_settb.obin18660 -> 18488 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/fifo.obin23444 -> 23400 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/formats.obin45768 -> 45340 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/graphdump.obin21788 -> 21900 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/graphparser.obin28536 -> 28436 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/lavfutils.obin66000 -> 65928 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/libavfilter.abin2728250 -> 2656244 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/libavfilter.pc10
-rwxr-xr-x[-rw-r--r--]libavfilter/sink_buffer.obin42212 -> 42176 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/split.obin17408 -> 17144 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/src_buffer.obin13996 -> 14032 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/src_movie.obin93536 -> 93048 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/transform.obin14704 -> 11848 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/vf_alphaextract.obin21880 -> 21872 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/vf_alphamerge.obin30500 -> 29944 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/vf_aspect.obin18964 -> 18960 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/vf_bbox.obin23940 -> 23832 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/vf_blackdetect.obin31724 -> 31216 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/vf_copy.obin11144 -> 11120 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/vf_crop.obin33628 -> 33328 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/vf_deshake.obin85896 -> 84104 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/vf_drawbox.obin29860 -> 29544 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/vf_edgedetect.obin32944 -> 33268 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/vf_fade.obin32272 -> 32444 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/vf_field.obin18128 -> 18092 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/vf_fieldorder.obin27644 -> 27632 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/vf_format.obin24952 -> 24880 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/vf_fps.obin26596 -> 26596 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/vf_framestep.obin15876 -> 15644 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/vf_gradfun.obin33016 -> 32812 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/vf_hflip.obin25008 -> 25000 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/vf_idet.obin32816 -> 32772 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/vf_lut.obin40428 -> 40044 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/vf_null.obin11140 -> 11116 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/vf_overlay.obin50292 -> 49828 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/vf_pad.obin43472 -> 42972 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/vf_pixdesctest.obin17336 -> 17312 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/vf_scale.obin42168 -> 41476 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/vf_select.obin81684 -> 80988 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/vf_setfield.obin13092 -> 13064 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/vf_showinfo.obin16892 -> 16688 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/vf_slicify.obin16236 -> 16204 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/vf_swapuv.obin20748 -> 20752 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/vf_thumbnail.obin28316 -> 27848 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/vf_tile.obin29072 -> 29048 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/vf_transpose.obin32384 -> 32320 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/vf_unsharp.obin33428 -> 33044 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/vf_vflip.obin14844 -> 14880 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/video.obin33280 -> 33024 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/vsink_nullsink.obin11476 -> 11448 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/vsrc_cellauto.obin35840 -> 35768 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/vsrc_life.obin39860 -> 40072 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/vsrc_mandelbrot.obin51396 -> 48732 bytes
-rwxr-xr-x[-rw-r--r--]libavfilter/vsrc_testsrc.obin55568 -> 56244 bytes
-rwxr-xr-xlibavformat/.utils.c.swpbin0 -> 28672 bytes
-rwxr-xr-x[-rw-r--r--]libavformat/Makefile2
-rwxr-xr-xlibavformat/RkPcm.c162
-rwxr-xr-xlibavformat/RkSeamless.c1423
-rwxr-xr-x[-rw-r--r--]libavformat/allformats.c6
-rwxr-xr-x[-rw-r--r--]libavformat/avformat.h29
-rwxr-xr-x[-rw-r--r--]libavformat/avio.c38
-rwxr-xr-x[-rw-r--r--]libavformat/avio.h21
-rwxr-xr-x[-rw-r--r--]libavformat/aviobuf.c56
-rwxr-xr-x[-rw-r--r--]libavformat/file.c21
-rwxr-xr-x[-rw-r--r--]libavformat/flvdec.c74
-rwxr-xr-x[-rw-r--r--]libavformat/hls.c1506
-rwxr-xr-x[-rw-r--r--]libavformat/http.c639
-rwxr-xr-x[-rw-r--r--]libavformat/id3v1.c49
-rwxr-xr-x[-rw-r--r--]libavformat/id3v2.c3
-rwxr-xr-x[-rw-r--r--]libavformat/isom.c2
-rwxr-xr-x[-rw-r--r--]libavformat/matroska.c4
-rwxr-xr-x[-rw-r--r--]libavformat/matroska.h21
-rwxr-xr-x[-rw-r--r--]libavformat/matroskadec.c22
-rwxr-xr-x[-rw-r--r--]libavformat/mmsh.c4
-rwxr-xr-x[-rw-r--r--]libavformat/mov.c57
-rwxr-xr-x[-rw-r--r--]libavformat/mpegts.c141
-rwxr-xr-x[-rw-r--r--]libavformat/mpegts.h2
-rwxr-xr-x[-rw-r--r--]libavformat/network.c167
-rwxr-xr-x[-rw-r--r--]libavformat/network.h37
-rwxr-xr-x[-rw-r--r--]libavformat/options.c1
-rwxr-xr-x[-rw-r--r--]libavformat/options_table.h4
-rwxr-xr-x[-rw-r--r--]libavformat/riff.c3
-rwxr-xr-x[-rw-r--r--]libavformat/rmdec.c7
-rwxr-xr-x[-rw-r--r--]libavformat/rtmpproto.c1
-rwxr-xr-x[-rw-r--r--]libavformat/rtsp.c113
-rwxr-xr-x[-rw-r--r--]libavformat/rtsp.h4
-rwxr-xr-x[-rw-r--r--]libavformat/tcp.c146
-rwxr-xr-x[-rw-r--r--]libavformat/udp.c2
-rwxr-xr-x[-rw-r--r--]libavformat/url.h15
-rwxr-xr-x[-rw-r--r--]libavformat/utils.c327
-rwxr-xr-x[-rw-r--r--]libavutil/avutil.h9
-rwxr-xr-x[-rw-r--r--]libavutil/common.h2
-rwxr-xr-x[-rw-r--r--]libavutil/error.h3
-rwxr-xr-x[-rw-r--r--]libavutil/mathematics.c25
-rwxr-xr-x[-rw-r--r--]libavutil/mathematics.h25
-rwxr-xr-x[-rw-r--r--]libavutil/opt.c4
-rwxr-xr-xlibcrypto.sobin0 -> 883372 bytes
-rwxr-xr-xlibssl.sobin0 -> 224844 bytes
155 files changed, 8904 insertions, 361 deletions
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 5f8776d..02e9013 100644..100755
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -326,6 +326,8 @@ OBJS-$(CONFIG_PGM_ENCODER) += pnmenc.o pnm.o
OBJS-$(CONFIG_PGMYUV_DECODER) += pnmdec.o pnm.o
OBJS-$(CONFIG_PGMYUV_ENCODER) += pnmenc.o pnm.o
OBJS-$(CONFIG_PGSSUB_DECODER) += pgssubdec.o
+OBJS-$(CONFIG_BLURAYTEXTSUB_DECODER) += bluraytextsubtitle.o
+OBJS-$(CONFIG_BLURAYIG_DECODER) += ig.o
OBJS-$(CONFIG_PICTOR_DECODER) += pictordec.o cga_data.o
OBJS-$(CONFIG_PNG_DECODER) += png.o pngdec.o pngdsp.o
OBJS-$(CONFIG_PNG_ENCODER) += png.o pngenc.o
diff --git a/libavcodec/aac_ac3_parser.c b/libavcodec/aac_ac3_parser.c
index 6f1e188..96c57f4 100644..100755
--- a/libavcodec/aac_ac3_parser.c
+++ b/libavcodec/aac_ac3_parser.c
@@ -79,7 +79,8 @@ get_next:
and total number of samples found in an AAC ADTS header are not
reliable. Bit rate is still accurate because the total frame duration in
seconds is still correct (as is the number of bits in the frame). */
- if (avctx->codec_id != AV_CODEC_ID_AAC) {
+ if (avctx->codec_id != AV_CODEC_ID_AAC)
+ {
avctx->sample_rate = s->sample_rate;
/* allow downmixing to stereo (or mono for AC-3) */
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 6bad573..7372cc9 100644..100755
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -421,6 +421,8 @@ void avcodec_register_all(void)
REGISTER_DECODER (MICRODVD, microdvd);
REGISTER_ENCDEC (MOVTEXT, movtext);
REGISTER_DECODER (PGSSUB, pgssub);
+ REGISTER_DECODER (BLURAYTEXTSUB,bluraytextsub);
+ REGISTER_DECODER (BLURAYIG,blurayig);
REGISTER_DECODER (REALTEXT, realtext);
REGISTER_DECODER (SAMI, sami);
REGISTER_ENCDEC (SRT, srt);
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index ac756a9..4c37c18 100644..100755
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -267,6 +267,8 @@ enum AVCodecID {
AV_CODEC_ID_MTS2,
AV_CODEC_ID_CLLC,
AV_CODEC_ID_MSS2,
+ AV_CODEC_ID_VP9,
+ AV_CODEC_ID_HEVC,
AV_CODEC_ID_Y41P = MKBETAG('Y','4','1','P'),
AV_CODEC_ID_ESCAPE130 = MKBETAG('E','1','3','0'),
AV_CODEC_ID_EXR = MKBETAG('0','E','X','R'),
@@ -454,6 +456,8 @@ enum AVCodecID {
AV_CODEC_ID_SUBVIEWER = MKBETAG('S','u','b','V'),
AV_CODEC_ID_SUBRIP = MKBETAG('S','R','i','p'),
AV_CODEC_ID_WEBVTT = MKBETAG('W','V','T','T'),
+ AV_CODEC_ID_BLURAY_TEXT_SUBTITLE,
+ AV_CODEC_ID_BLURAY_IG,
/* other specific kind of codecs (generally used for attachments) */
AV_CODEC_ID_FIRST_UNKNOWN = 0x18000, ///< A dummy ID pointing at the start of various fake codecs.
@@ -949,6 +953,9 @@ enum AVPacketSideDataType {
* the list, so it is required to rely on the side data size to stop.
*/
AV_PKT_DATA_STRINGS_METADATA,
+ AV_PKT_DATA_WEBVTT_IDENTIFIER,
+ AV_PKT_DATA_WEBVTT_SETTINGS,
+ AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL,
/**
* Subtitle event position
@@ -1046,6 +1053,11 @@ typedef struct AVPacket {
* subtitles are correctly displayed after seeking.
*/
int64_t convergence_duration;
+
+ /*
+ * add by hh for hls pts sync
+ */
+ int seq;
} AVPacket;
#define AV_PKT_FLAG_KEY 0x0001 ///< The packet contains a keyframe
#define AV_PKT_FLAG_CORRUPT 0x0002 ///< The packet content is corrupted
@@ -3025,8 +3037,6 @@ typedef struct AVCodecContext {
#define FF_PROFILE_H264_HIGH_444_PREDICTIVE 244
#define FF_PROFILE_H264_HIGH_444_INTRA (244|FF_PROFILE_H264_INTRA)
#define FF_PROFILE_H264_CAVLC_444 44
-#define FF_PROFILE_H264_MVC_HIGH (118)
-#define FF_PROFILE_H264_STEREO_HIGH (128)
#define FF_PROFILE_VC1_SIMPLE 0
#define FF_PROFILE_VC1_MAIN 1
@@ -3420,12 +3430,22 @@ typedef struct AVSubtitleRect {
} AVSubtitleRect;
typedef struct AVSubtitle {
- uint16_t format; /* 0 = graphics */
+ uint16_t format; /* 0 = graphics */ /* 1 = bluray Text Subtitle */ /* 2 = bluray IG */
uint32_t start_display_time; /* relative to packet pts, in ms */
uint32_t end_display_time; /* relative to packet pts, in ms */
unsigned num_rects;
AVSubtitleRect **rects;
int64_t pts; ///< Same as packet pts, in AV_TIME_BASE
+
+ /*
+ * PGS 字幕对应的高宽和宽度
+ */
+ int width;
+ int height;
+
+ // add by hh for bluray
+ void* dialogStyle; //for bluray Text Subtitle Diaglog Style
+ void* dialog; //for bluray Text Subtitle Diaglog
} AVSubtitle;
/**
@@ -4019,6 +4039,15 @@ int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub,
int *got_sub_ptr,
AVPacket *avpkt);
+typedef struct CodecCallBack
+{
+ int (*callback)(void*);
+ void (*msg_callback)(void*,int,int);
+ int (*operate_callback)(void*,int,void*,void**);
+ void *opaque;
+ void* msg_opaque;
+ void* operate_opaque;
+} CodecCallBack;
/**
* @defgroup lavc_parsing Frame parsing
* @{
@@ -4158,8 +4187,30 @@ typedef struct AVCodecParserContext {
* For all other types, this is in units of AVCodecContext.time_base.
*/
int duration;
+ // add by hh
+ CodecCallBack callback;
} AVCodecParserContext;
+
+/*
+* add by hh
+* 用于codec回调和通知消息给ffplayer
+*/
+void av_parser_init_callback(AVCodecParserContext*parse,
+ int (*callback)(void*),
+ void (*msg_callback)(void*,int,int),
+ int (*operate_callback)(void*,int,void*,void**),
+ void *opaque,
+ void* msg_opaque,
+ void* operate_opaque);
+
+void av_parse_deinit_callback(AVCodecParserContext*parse);
+int ff_codec_check_interrupt(CodecCallBack* cb);
+void ff_codec_send_message(CodecCallBack* cb,int what,int msg);
+int ff_codec_check_operate(CodecCallBack*cb,int operate,void* para1,void** para2);
+
+
+
typedef struct AVCodecParser {
int codec_ids[5]; /* several codec IDs are permitted */
int priv_data_size;
diff --git a/libavcodec/avpacket.c b/libavcodec/avpacket.c
index 516f1c9..9625e23 100644..100755
--- a/libavcodec/avpacket.c
+++ b/libavcodec/avpacket.c
@@ -38,7 +38,10 @@ void ff_packet_free_side_data(AVPacket *pkt)
void av_destruct_packet(AVPacket *pkt)
{
- av_free(pkt->data);
+ if(pkt->data != NULL)
+ {
+ av_free(pkt->data);
+ }
pkt->data = NULL;
pkt->size = 0;
@@ -57,6 +60,7 @@ void av_init_packet(AVPacket *pkt)
pkt->destruct = NULL;
pkt->side_data = NULL;
pkt->side_data_elems = 0;
+ pkt->seq = 0;
}
int av_new_packet(AVPacket *pkt, int size)
diff --git a/libavcodec/bluraytextsubtitle.c b/libavcodec/bluraytextsubtitle.c
new file mode 100755
index 0000000..a9acbbe
--- /dev/null
+++ b/libavcodec/bluraytextsubtitle.c
@@ -0,0 +1,824 @@
+/*
+ * Blu-ray Text subtitle decoder
+ * Copyright (c) 2014 Fuzhou Rockchip Electronics Co., Ltd
+ *
+ * This file is using to parse Blu-ray's Text Subtitle
+ * Author:hh@rock-chips.com
+ */
+#include "bluraytextsubtitle.h"
+#include "dsputil.h"
+#include "bytestream.h"
+#include "libavutil/colorspace.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/opt.h"
+
+#define RGBA(r,g,b,a) (((unsigned)(a) << 24) | ((r) << 16) | ((g) << 8) | (b))
+#define POSITIVE(x) ( x > 0 ? x : 0)
+
+#define YUV_TO_RGB0(y,cb,cr)\
+{\
+ r = POSITIVE(floor(1.164*y + 1.793*cr - 247.628));\
+ g = POSITIVE(floor(1.164*y -0.213*cb - 0.533*cr + 77.364));\
+ b = POSITIVE(floor(1.164*y +2.112*cb - 288.46));\
+}
+
+static void deleteTextSubtitleDialog(DialogPresentation* dialog)
+{
+ av_log(NULL, AV_LOG_ERROR,"deleteTextSubtitleDialog()");
+ if(dialog != NULL)
+ {
+ if(dialog->mPalette != NULL)
+ {
+ av_log(NULL, AV_LOG_ERROR,"av_free(&dialog->mPalette)");
+ av_freep(&dialog->mPalette);
+ }
+
+ if(dialog->mRegion != NULL)
+ {
+ av_log(NULL, AV_LOG_ERROR,"dialog->mRegion");
+ for(int i = 0; i < dialog->mRegionCount; i++)
+ {
+ for(int j = 0; j < dialog->mRegion[i].mLineCount; j++)
+ {
+ TextLineData* lineData = dialog->mRegion[i].mLineData[j];
+ if(lineData != NULL)
+ {
+ if(lineData->mText != NULL)
+ {
+ av_freep(&lineData->mText);
+ }
+
+ if(lineData->mInLineStyleValues != NULL)
+ {
+ av_freep(&lineData->mInLineStyleValues);
+ }
+
+ if(lineData->mInLineStyleType != NULL)
+ {
+ av_freep(&lineData->mInLineStyleType);
+ }
+
+ if(lineData->mInLineStylePosition != NULL)
+ {
+ av_freep(&lineData->mInLineStylePosition);
+ }
+ }
+ }
+
+ dialog->mRegion[i].mLineCount = 0;
+ }
+ dialog->mRegionCount = 0;
+ av_log(NULL, AV_LOG_ERROR,"dialog->mRegion");
+ av_freep(&dialog->mRegion);
+ }
+
+ av_freep(&dialog);
+ }
+}
+
+static void deleteDialogStyle(DialogStyle* style)
+{
+ if(style != NULL)
+ {
+ av_log(NULL, AV_LOG_ERROR,"deleteDialogStyle(),av_freep(&style->mRegionStyle)");
+ if(style->mRegionStyle != NULL)
+ {
+ av_freep(&style->mRegionStyle);
+ }
+ av_log(NULL, AV_LOG_ERROR,"deleteDialogStyle(),av_freep(&style->mUserStyle)");
+ if(style->mUserStyle != NULL)
+ {
+ av_freep(&style->mUserStyle);
+ }
+ av_log(NULL, AV_LOG_ERROR,"deleteDialogStyle(),av_freep(&style->mPalette)");
+ if(style->mPalette != NULL)
+ {
+ av_freep(&style->mPalette);
+ }
+ av_log(NULL, AV_LOG_ERROR,"deleteDialogStyle(),av_freep(&style)");
+ av_freep(&style);
+ }
+}
+
+static av_cold int init_decoder(AVCodecContext *avctx)
+{
+ avctx->pix_fmt = AV_PIX_FMT_PAL8;
+ TextSubtitle *text = avctx->priv_data;
+ if(text != NULL)
+ {
+ text->mDialog = NULL;
+ text->mDialogStyle = NULL;
+ }
+ av_log(NULL, AV_LOG_ERROR,"Bluray Text Subtitle:init_decoder()");
+ return 0;
+}
+
+static av_cold int close_decoder(AVCodecContext *avctx)
+{
+ av_log(NULL, AV_LOG_ERROR,"Bluray Text Subtitle:close_decoder()");
+ TextSubtitle *text = avctx->priv_data;
+ if(text != NULL)
+ {
+ deleteTextSubtitleDialog(text->mDialog);
+
+ deleteDialogStyle(text->mDialogStyle);
+ // av_freep(&text->mDialogStyle);
+ }
+ av_freep(&avctx->priv_data);
+ return 0;
+}
+
+static int decodeFontSytle(uint8_t** buffer,FontStyle* fontStyle)
+{
+ if(fontStyle == NULL)
+ {
+ av_log(NULL, AV_LOG_ERROR,"decodeFontSytle(), param is invalid");
+ return -1;
+ }
+
+ unsigned char font_style = bytestream_get_byte(buffer);//getByte(buffer); buffer ++;
+ fontStyle->mBold = font_style & 1;
+ fontStyle->mItalic = (font_style & 2)>>1;
+ fontStyle->mOutLineBorder = (font_style & 4)>>2;
+
+ av_log(NULL, AV_LOG_ERROR,"decodeFontSytle(),bold = %d,italic = %d,mOutLineBorder = %d",fontStyle->mBold,fontStyle->mItalic,fontStyle->mOutLineBorder);
+
+ return 0;
+}
+
+
+static int decodeRect(uint8_t** buf,TextSubtitleRect* rect)
+{
+ if((buf == NULL) || (rect == NULL))
+ {
+ av_log(NULL, AV_LOG_ERROR,"decodeRect(), param is invalid");
+ return -1;
+ }
+
+ rect->x = (int)bytestream_get_be16(&(*buf));
+ rect->y = (int)bytestream_get_be16(&(*buf));
+ rect->mWidth = (int)bytestream_get_be16(&(*buf));
+ rect->mHight = (int)bytestream_get_be16(&(*buf));
+
+ av_log(NULL, AV_LOG_ERROR,"decodeRect(), x = %d,y = %d,width = %d,height = %d",rect->x,rect->y,rect->mWidth,rect->mHight);
+
+ return 0;
+}
+
+
+static int decodeRegionInfo(uint8_t** buf,RectRegion* region)
+{
+ if((buf == NULL) || (region == NULL))
+ {
+ av_log(NULL, AV_LOG_ERROR,"decodeRegionInfo(), param is invalid");
+ return -1;
+ }
+
+ decodeRect(buf, &region->mRegion);
+ region->mBackColorPaletteRefId = bytestream_get_byte(&(*buf));
+ // (*buf)+= 1;
+
+ //skip 8bits
+ bytestream_get_byte(&(*buf));
+ // (*buf)+= 1;
+
+ return 0;
+}
+
+static int decodeRegionStyle(uint8_t** buf,RegionStyle* style)
+{
+ if((buf == NULL) ||(style == NULL))
+ {
+ av_log(NULL, AV_LOG_ERROR,"decodeRegionStyle(), param is invalid");
+ return -1;
+ }
+
+ style->mRegionStyleId = bytestream_get_byte(&(*buf));
+
+ av_log(NULL, AV_LOG_ERROR,"decodeRegionStyle(), mRegionStyleId = %d",style->mRegionStyleId);
+ // LOGD("decodeRegionStyle()******,mRegionStyleId = %d",style->mRegionStyleId);
+ decodeRegionInfo(buf, &style->mRegion);
+ decodeRect(buf, &style->mTextRect);
+
+ /* Set additional text info for the region style */
+ style->mTextFlow = bytestream_get_byte(&(*buf));
+ style->mTextHalign = bytestream_get_byte(&(*buf));
+ style->mTextValign = bytestream_get_byte(&(*buf));
+ style->mLineSpace = bytestream_get_byte(&(*buf));
+
+ /* Set font style info for the region style */
+ style->mFontIdRef = bytestream_get_byte(&(*buf));
+ decodeFontSytle(buf, &style->mFontStyle);
+
+ style->mFontSize = bytestream_get_byte(&(*buf));
+ style->mFontColor = bytestream_get_byte(&(*buf));
+ style->mOutLineColor = bytestream_get_byte(&(*buf));
+ style->mOuntLIneThickness = bytestream_get_byte(&(*buf));
+
+ av_log(NULL, AV_LOG_ERROR,"decodeRegionStyle(), font size = %d,font color = %d",style->mFontSize,style->mFontColor);
+ av_log(NULL, AV_LOG_ERROR,"decodeRegionStyle(), mOutLineColor = %d,mOuntLIneThickness = %d",style->mOutLineColor,style->mOuntLIneThickness);
+
+
+ return 0;
+}
+
+static int decodeUserStyle(uint8_t** buf,UserStyle* style)
+{
+ if((buf == NULL) || (style == NULL))
+ {
+ av_log(NULL, AV_LOG_ERROR,"decodeUserStyle(),param is invalid");
+ return -1;
+ }
+
+ #if 0
+ TextSTInfo->pDSS->region_style[i].user_control_style[j].user_style_id = TextST_SPB[ulSPBOffset];
+ ulSPBOffset++;
+
+ /* Set region info for the user control style */
+ TextSTInfo->pDSS->region_style[i].user_control_style[j].region_horizontal_position_diretion = TextST_SPB[ulSPBOffset] >> 7;
+ TextSTInfo->pDSS->region_style[i].user_control_style[j].region_horizontal_position_delta = MAKE_WORD(&TextST_SPB[ulSPBOffset]) & 0x7fff;
+ TextSTInfo->pDSS->region_style[i].user_control_style[j].region_vertical_position_direction = TextST_SPB[ulSPBOffset + 2] >> 7;
+ TextSTInfo->pDSS->region_style[i].user_control_style[j].region_vertical_position_delta = MAKE_WORD(&TextST_SPB[ulSPBOffset + 2]) & 0x7fff;
+ ulSPBOffset += 4;
+
+ /* Set font info for the user control style */
+ TextSTInfo->pDSS->region_style[i].user_control_style[j].font_size_inc_dec = TextST_SPB[ulSPBOffset] >> 7;
+ TextSTInfo->pDSS->region_style[i].user_control_style[j].font_size_delta = TextST_SPB[ulSPBOffset] & 0x7f;
+ ulSPBOffset++;
+
+ /* Set text box info for the user control style */
+ TextSTInfo->pDSS->region_style[i].user_control_style[j].text_box_horizontal_position_direction = TextST_SPB[ulSPBOffset] >> 7;
+ TextSTInfo->pDSS->region_style[i].user_control_style[j].text_box_horizontal_position_delta = MAKE_WORD(&TextST_SPB[ulSPBOffset]) & 0x7fff;
+ TextSTInfo->pDSS->region_style[i].user_control_style[j].text_box_vertical_position_direction = TextST_SPB[ulSPBOffset + 2] >> 7;
+ TextSTInfo->pDSS->region_style[i].user_control_style[j].text_box_vertical_position_delta = MAKE_WORD(&TextST_SPB[ulSPBOffset + 2]) & 0x7fff;
+ TextSTInfo->pDSS->region_style[i].user_control_style[j].text_box_width_inc_dec = TextST_SPB[ulSPBOffset + 4] >> 7;
+ TextSTInfo->pDSS->region_style[i].user_control_style[j].text_box_width_delta = MAKE_WORD(&TextST_SPB[ulSPBOffset + 4]) & 0x7fff;
+ TextSTInfo->pDSS->region_style[i].user_control_style[j].text_box_height_inc_dec = TextST_SPB[ulSPBOffset + 6] >> 7;
+ TextSTInfo->pDSS->region_style[i].user_control_style[j].text_box_height_delta = MAKE_WORD(&TextST_SPB[ulSPBOffset + 6]) & 0x7fff;
+ ulSPBOffset += 8;
+
+ /* Set line space info for the user control style */
+ TextSTInfo->pDSS->region_style[i].user_control_style[j].line_space_inc_dec = TextST_SPB[ulSPBOffset] >> 7;
+ TextSTInfo->pDSS->region_style[i].user_control_style[j].line_space_delta = TextST_SPB[ulSPBOffset] & 0x7f;
+ ulSPBOffset++;
+ #endif
+
+
+ style->mUserStyleId = bytestream_get_byte(&(*buf));
+
+ /* Set region info for the user control style */
+ unsigned short temp = (unsigned short)bytestream_get_be16(&(*buf));
+ style->mRegionHorizontalDiretion = (unsigned char)(temp >> 15);
+ style->mRegionHorizontaDelta = (short)(temp & 0x7fff);
+
+ temp = (unsigned short)bytestream_get_be16(&(*buf));
+ style->mRegionVerticalDirection = (unsigned char)(temp >> 15);
+ style->mRegionVerticalDelta = (short)(temp & 0x7fff);
+
+ /* Set font info for the user control style */
+ unsigned char Font = bytestream_get_byte(&(*buf));
+ style->mFontIncDec = Font>>7;
+ style->mFontSizeDelta = Font&0x7f;
+
+ /* Set text box info for the user control style */
+ temp = (unsigned short)bytestream_get_be16(&(*buf));
+ style->mTextBoxHorizontalDirection = (unsigned char)(temp >> 15);
+ style->mTextBoxHorizontalDelta = (short)(temp & 0x7fff);
+
+ temp = (unsigned short)bytestream_get_be16(&(*buf));
+ style->mTextBoxVerticalDirection = (unsigned char)(temp >> 15);
+ style->mTextBoxVerticalDelta = (short)(temp & 0x7fff);
+
+ temp = (unsigned short)bytestream_get_be16(&(*buf));
+ style->mTextBoxWidthIncDec = (unsigned char)(temp >> 15);
+ style->mTextBoxWidthDelta = (short)(temp & 0x7fff);
+
+ temp = (unsigned short)bytestream_get_be16(&(*buf));
+ style->mTextBoxHeightIncDec = (unsigned char)(temp >> 15);
+ style->mTextBoxHeightDelta = (short)(temp & 0x7fff);
+
+ /* Set line space info for the user control style */
+ unsigned char Line = bytestream_get_byte(&(*buf));
+ style->mLineSpaceIncDec = Line>>7;
+ style->mLineSpaceDelta = Line&0x7f;
+
+ av_log(NULL, AV_LOG_ERROR,"decodeUserStyle(),mUserStyleId = %d",style->mUserStyleId);
+ return 0;
+}
+
+static int decodePalette(uint8_t** buf,int count,PaletteEntry* palette)
+{
+ if((buf != NULL) && palette != NULL)
+ {
+ int color_id;
+ int y, cb, cr, alpha;
+ int r, g, b, r_add, g_add, b_add;
+
+ for(int i = 0; i < count; i++)
+ {
+ color_id = bytestream_get_byte(&(*buf));
+ y = bytestream_get_byte(&(*buf));
+ cr = bytestream_get_byte(&(*buf));
+ cb = bytestream_get_byte(&(*buf));
+ alpha = bytestream_get_byte(&(*buf));
+
+ YUV_TO_RGB0(y, cb, cr);
+ #if 1
+ if(r > 255) r = 255;
+ if(g > 255) g = 255;
+ if(b > 255) b = 255;
+
+ // av_log(avctx, AV_LOG_DEBUG, " Color %d := (%d,%d,%d,%d)\n", color_id, r, g, b, alpha);
+
+ double temp = ((double)alpha)/255;
+ r *= temp;
+ g *= temp;
+ b *= temp;
+ alpha *= temp;
+#endif
+ /* Store color in palette */
+ palette->color[color_id] = RGBA(r,g,b,alpha);
+// av_log(NULL, AV_LOG_ERROR, "color_id = %d,r = %d,g = %d,b = %d,alpha = %d",color_id,r,g,b,alpha);
+ }
+
+ return 0;
+ }
+
+ return -1;
+}
+
+
+static int decodeDialogStyle(uint8_t** buf,DialogStyle* style)
+{
+ if((buf == NULL) || (style == NULL))
+ {
+ av_log(NULL, AV_LOG_ERROR,"decodeDialogStyle(), param is invalid");
+ return -1;
+ }
+
+ av_log(NULL, AV_LOG_ERROR,"decodeDialogStyle()");
+ unsigned char temp = bytestream_get_byte(&(*buf));
+ style->mPlayerStyleFlag = temp>>7;
+// LOGD("decodeDialogStyle(), buffer = 0x%x",buffer);
+
+ //skip 8bits
+ bytestream_get_byte(&(*buf));
+
+ style->mRegoinStyleCount = bytestream_get_byte(&(*buf));
+ style->mUserStyleCount = bytestream_get_byte(&(*buf));
+ av_log(NULL, AV_LOG_ERROR,"mRegoinStyleCount = %d,mUserStyleCount = %d",style->mRegoinStyleCount,style->mUserStyleCount);
+ style->mRegionStyle = NULL;
+ if(style->mRegoinStyleCount > 0)
+ {
+ style->mRegionStyle = av_malloc(sizeof(RegionStyle)*style->mRegoinStyleCount);
+ if(style->mRegionStyle != NULL)
+ {
+ memset(style->mRegionStyle,0,sizeof(RegionStyle)*style->mRegoinStyleCount);
+ for(int i = 0; i < style->mRegoinStyleCount; i++)
+ {
+ decodeRegionStyle(buf,&style->mRegionStyle[i]);
+ }
+ }
+ }
+
+ style->mUserStyle = NULL;
+ if(style->mUserStyleCount > 0)
+ {
+ style->mUserStyle = av_malloc(sizeof(UserStyle)*style->mUserStyleCount);//new UserStyle[style->mUserStyleCount];
+ if(style->mUserStyle != NULL)
+ {
+ memset(style->mUserStyle,0,sizeof(UserStyle)*style->mUserStyleCount);
+ for(int i = 0; i < style->mUserStyleCount; i++)
+ {
+ decodeUserStyle(buf,&style->mUserStyle[i]);
+ }
+ }
+ }
+
+ int length = bytestream_get_be16(&(*buf));//bytestream_get_be16(buf); (*buf)+= 2;
+ int count = length/5;
+
+ style->mPalette = av_malloc(sizeof(PaletteEntry));//new PaletteEntry();
+ if(style->mPalette != NULL)
+ {
+ memset(style->mPalette,0,sizeof(PaletteEntry));
+ decodePalette(buf,count,style->mPalette);
+ }
+
+ return 0;
+}
+
+
+static int parseDialogStyle(AVCodecContext *avctx,uint8_t *data,uint8_t* buffer,int length)
+{
+ if((avctx == NULL) || (buffer == NULL) || (length <= 0) || (data == NULL))
+ {
+ av_log(NULL, AV_LOG_ERROR,"parseDialogStyle(), param is invalid");
+ return 0;
+ }
+
+ AVSubtitle *subtitle = (AVSubtitle *)data;
+ subtitle->dialogStyle = av_malloc(sizeof(DialogStyle));
+ if(subtitle->dialogStyle != NULL)
+ {
+ if(decodeDialogStyle(&buffer,subtitle->dialogStyle) != 0)
+ {
+ deleteDialogStyle(subtitle->dialogStyle);
+ av_log(NULL, AV_LOG_ERROR,"parseDialogStyle(), decodeDialogStyle fail");
+ return 0;
+ }
+ }
+
+ int totalDialog = bytestream_get_be16(&buffer);
+ av_log(NULL, AV_LOG_ERROR,"parseDialogStyle():mTotalDialog = %d",totalDialog);
+
+ if (totalDialog < 1)
+ {
+ av_log(NULL, AV_LOG_ERROR,"parseDialogStyle():no dialog segments");
+ }
+
+ return 1;
+}
+
+static void initLineData(TextLineData* line)
+{
+ if(line != NULL)
+ {
+ line->mText = av_malloc(sizeof(char)*MAX_CHARS_PER_DPS_REGION);
+ line->mInLineStyleValues = av_malloc(sizeof(char)*MAX_CHARS_PER_DPS_REGION);
+ line->mInLineStyleType = av_malloc(sizeof(char)*MAX_CHARS_PER_DPS_REGION);
+ line->mInLineStylePosition = av_malloc(sizeof(char)*MAX_CHARS_PER_DPS_REGION);
+ if(line->mText != NULL)
+ {
+ memset(line->mText, 0, MAX_CHARS_PER_DPS_REGION);
+ }
+
+ if(line->mInLineStyleValues)
+ {
+ memset(line->mInLineStyleValues, 0, MAX_CHARS_PER_DPS_REGION);
+ }
+
+ if(line->mInLineStyleType)
+ {
+ memset(line->mInLineStyleType, 0, MAX_CHARS_PER_DPS_REGION);
+ }
+
+ if(line->mInLineStylePosition != NULL)
+ {
+ memset(line->mInLineStylePosition, 0xff, MAX_CHARS_PER_DPS_REGION);
+ }
+ }
+}
+
+static int decodeDialogRegion(uint8_t** buf,DialogRegion* region)
+{
+ if(region == NULL)
+ {
+ av_log(NULL, AV_LOG_ERROR,"decodeDialogRegion(): param is invalid");
+ return -1;
+ }
+
+ unsigned char temp = bytestream_get_byte(&(*buf));
+ region->mContinousPresentFlag = temp>>7;
+ ////// maybe some problem here ////////////////
+
+
+ region->mForceOnFlag = (temp>>6)&0x01;
+ region->mRegionStyleRefId = bytestream_get_byte(&(*buf));
+
+ int length = bytestream_get_be16(&(*buf));
+ int byteRead = 0;
+
+ /* set initial counter values */
+ int textStringOffset = 0;
+ int inlineStyleOffset = 0;
+ int numberOfInlineStyles = 0;
+
+ int numberOfLine = 0;
+ region->mLineCount = 1;
+ TextLineData* lineData = av_malloc(sizeof(TextLineData));//new TextLineData();
+ if(lineData == NULL)
+ {
+ av_log(NULL, AV_LOG_ERROR,"decodeDialogRegion(): malloc lineData fail");
+ return -1;
+ }
+#if 0
+ lineData->mText = av_malloc(sizeof(char)*MAX_CHARS_PER_DPS_REGION);
+ lineData->mInLineStyleValues = av_malloc(sizeof(char)*MAX_CHARS_PER_DPS_REGION);
+ lineData->mInLineStyleType = av_malloc(sizeof(char)*MAX_CHARS_PER_DPS_REGION);
+ lineData->mInLineStylePosition = av_malloc(sizeof(char)*MAX_CHARS_PER_DPS_REGION);
+ if(lineData->mText != NULL)
+ {
+ memset(lineData->mText, 0, MAX_CHARS_PER_DPS_REGION);
+ }
+ if(lineData->mInLineStylePosition != NULL)
+ {
+ memset(lineData->mInLineStylePosition, 0xff, MAX_CHARS_PER_DPS_REGION);
+ }
+#endif
+ initLineData(lineData);
+ while (byteRead < length)
+ {
+ /* parse header */
+ unsigned char code = bytestream_get_byte(&(*buf));
+ byteRead++;
+ if (code != 0x1b) // 0x1b in ascii is ESC (escape)
+ {
+ continue;
+ }
+
+ unsigned char type = bytestream_get_byte(&(*buf));
+ unsigned char dataLength = bytestream_get_byte(&(*buf));
+ byteRead += 2 + dataLength;
+
+ switch (type)
+ {
+ case BD_TEXTST_DATA_STRING:
+ {
+ if(lineData->mText != NULL)
+ {
+ for (int j = 0; j < dataLength; j++)
+ {
+ /* Read text string */
+ lineData->mText[j+textStringOffset] = (*buf)[j];
+ }
+ }
+
+ av_log(NULL, AV_LOG_ERROR,"%s",lineData->mText);
+ /* Adjust string offset */
+ // buf += dataLength;
+ (*buf) += dataLength;
+ textStringOffset += dataLength;
+ break;
+ }
+
+ case BD_TEXTST_DATA_NEWLINE:
+ {
+ // a new line coming, reset the counter
+ textStringOffset = 0;
+ inlineStyleOffset = 0;
+ numberOfInlineStyles = 0;
+ // store the subtitle's lenght
+ // lineData->mTextLength = textStringOffset;
+ textStringOffset = 0;
+
+ // store the text subtitle
+ region->mLineData[region->mLineCount-1] = lineData;
+ region->mLineCount ++;
+ // malloc new TextLineData
+ lineData = av_malloc(sizeof(TextLineData));
+ #if 0
+ if(lineData != NULL)
+ {
+ lineData->mText = av_malloc(sizeof(char)*MAX_CHARS_PER_DPS_REGION);
+ lineData->mInLineStyleValues = av_malloc(sizeof(char)*MAX_CHARS_PER_DPS_REGION);
+ lineData->mInLineStyleType = av_malloc(sizeof(char)*MAX_CHARS_PER_DPS_REGION);
+ lineData->mInLineStylePosition = av_malloc(sizeof(char)*MAX_CHARS_PER_DPS_REGION);
+ if(lineData->mText != NULL)
+ {
+ memset(lineData->mText, 0, MAX_CHARS_PER_DPS_REGION);
+ }
+ if(lineData->mInLineStylePosition != NULL)
+ {
+ memset(lineData->mInLineStylePosition, 0xff, MAX_CHARS_PER_DPS_REGION);
+ }
+ }
+ #endif
+
+ initLineData(lineData);
+ break;
+ }
+
+ case BD_TEXTST_DATA_FONT_ID:
+ case BD_TEXTST_DATA_FONT_STYLE:
+ case BD_TEXTST_DATA_FONT_SIZE:
+ case BD_TEXTST_DATA_FONT_COLOR:
+ // case BD_TEXTST_DATA_NEWLINE:
+ case BD_TEXTST_DATA_RESET_STYLE:
+ {
+ if(lineData != NULL)
+ {
+ /* set the inline style data type */
+ if(lineData->mInLineStyleType != NULL)
+ {
+ lineData->mInLineStyleType[numberOfInlineStyles] = type;
+ }
+
+ /* set the inline style position */
+ if(lineData->mInLineStylePosition != NULL)
+ {
+ lineData->mInLineStylePosition[numberOfInlineStyles] = textStringOffset;
+ }
+
+ if(lineData->mInLineStyleValues != NULL)
+ {
+ for (int j = 0; j < dataLength; j++)
+ {
+ /* Read inline style values */
+ lineData->mInLineStyleValues[j+inlineStyleOffset] = (*buf)[j];
+ }
+ }
+ }
+
+ (*buf) += dataLength;
+
+ /* Adjust inline style offset */
+ inlineStyleOffset += dataLength;
+
+ /* increment number of inline styles */
+ numberOfInlineStyles++;
+ break;
+ }
+
+ default:
+ {
+ av_log(NULL, AV_LOG_ERROR,"decodeDialogRegion(): unknown type %d (len %d)\n", type, length);
+ (*buf) += length;
+ continue;
+ }
+ }
+ }
+
+ region->mLineData[region->mLineCount-1] = lineData;
+
+ return 0;
+}
+
+static void initDialogPresention(DialogRegion* region)
+{
+ if(region != NULL)
+ {
+ region->mContinousPresentFlag = 0;
+ region->mForceOnFlag = 0;
+ region->mRegionStyleRefId = 0;
+ region->mLineCount = 0;
+ for(int i = 0; i < MAX_TEXTSUBTITLE_LINE; i++)
+ {
+ region->mLineData[i] = NULL;
+ }
+ }
+}
+
+static int decodeDialogPresention(uint8_t** buf,DialogPresentation* dialog)
+{
+ if((buf == NULL) || (dialog == NULL))
+ {
+ av_log(NULL, AV_LOG_ERROR,"decodeDialogPresention():param is invalid");
+ return -1;
+ }
+
+ /* Set Start PTS value */
+ int64_t temp = (bytestream_get_byte(&(*buf))&0x01)<<32;
+ dialog->mStartPTS = bytestream_get_be32(&(*buf));
+ dialog->mStartPTS |= temp;
+
+ /* Set End PTS value */
+ temp = (bytestream_get_byte(&(*buf))&0x01)<<32;
+ dialog->mEndPTS = bytestream_get_be32(&(*buf));
+ dialog->mEndPTS |= temp;//(uint64)(buffer[0] & 0x01) << 32;
+
+// av_log(NULL, AV_LOG_ERROR,"decodeDialogPresention(), start PTS = %lld,sec = %d",dialog->mStartPTS,(dialog->mStartPTS/45000));
+// av_log(NULL, AV_LOG_ERROR,"decodeDialogPresention(), end PTS = %lld,sec = %d",dialog->mEndPTS,(dialog->mEndPTS/45000));
+
+ unsigned char flag = bytestream_get_byte(&(*buf));
+ dialog->mPaletteUpdataFlag = flag>>7;
+ av_log(NULL, AV_LOG_ERROR,"decodeDialogPresention(), dialog->mPaletteUpdataFlag = %d",dialog->mPaletteUpdataFlag);
+ dialog->mPalette = NULL;
+ if(dialog->mPaletteUpdataFlag)
+ {
+ int length = bytestream_get_be16(&(*buf));
+ int count = length/5;
+ dialog->mPalette = av_malloc(sizeof(PaletteEntry));
+ if(dialog->mPalette == NULL)
+ {
+ av_log(NULL, AV_LOG_ERROR,"decodeDialogPresention():malloc mPaletteUpdate fail");
+ return -1;
+ }
+
+ decodePalette(buf,count,dialog->mPalette);
+ }
+
+ dialog->mRegionCount = bytestream_get_byte(&(*buf));
+ av_log(NULL, AV_LOG_ERROR,"decodeDialogPresention(),RegionCount = %d",dialog->mRegionCount);
+ dialog->mRegion = NULL;
+ if(dialog->mRegionCount > 0)
+ {
+ dialog->mRegion = av_malloc(sizeof(DialogRegion)*dialog->mRegionCount);//new DialogRegion[dialog->mRegionCount];
+ if(dialog->mRegion != NULL)
+ {
+ av_log(NULL, AV_LOG_ERROR,"decodeDialogPresention(),dialog->mRegion = 0x%x",dialog->mRegion);
+// memset(&dialog->mRegion,0,sizeof(DialogRegion)*dialog->mRegionCount);
+ for(int i = 0; i < dialog->mRegionCount; i++)
+ {
+ initDialogPresention(&dialog->mRegion[i]);
+ decodeDialogRegion(buf,&dialog->mRegion[i]);
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+static int parseDialogPresentation(AVCodecContext *avctx,uint8_t *data,uint8_t* buffer,int length)
+{
+ if((avctx == NULL) || (buffer == NULL) || (data == NULL))
+ {
+ av_log(NULL, AV_LOG_ERROR,"parseDialogPresentation()unexpected dialog segment");
+ return 0;
+ }
+
+ AVSubtitle *subtitle = (AVSubtitle *)data;
+ subtitle->format = 1;
+ subtitle->dialog = av_malloc(sizeof(DialogPresentation));
+ if(subtitle->dialog != NULL)
+ {
+ av_log(NULL, AV_LOG_ERROR,"text->mDialog address = 0x%x",subtitle->dialog);
+ if(decodeDialogPresention(&buffer, subtitle->dialog) != 0)
+ {
+ deleteTextSubtitleDialog(subtitle->dialog);
+ return 0;
+ }
+ }
+ else
+ {
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static int decode(AVCodecContext *avctx, uint8_t *data, int *data_size,
+ AVPacket *avpkt)
+{
+ TextSubtitle *ctx = avctx->priv_data;
+ const uint8_t *buf = avpkt->data;
+ int buf_size = avpkt->size;
+ AVSubtitle *sub = data;
+
+ const uint8_t *buf_end;
+ uint8_t segment_type;
+ int segment_length;
+ int i;
+
+
+ *data_size = 0;
+
+ /* Ensure that we have received at a least a segment code and segment length */
+ if (buf_size < 3)
+ return -1;
+
+ buf_end = buf + buf_size;
+
+ /* Step through buffer to identify segments */
+ while (buf < buf_end) {
+ segment_type = bytestream_get_byte(&buf);
+ segment_length = bytestream_get_be16(&buf);
+
+ switch (segment_type) {
+ case Text_DIALOG_STYLE:
+ *data_size = parseDialogStyle(avctx,data,buf,segment_length);
+ break;
+
+ case Text_DIALOG_PRESENTATION:
+ *data_size = parseDialogPresentation(avctx,data,buf,segment_length);
+ break;
+
+ default:
+ av_log(avctx, AV_LOG_ERROR, "Unknown Text subtitle segment type 0x%x, length %d\n",
+ segment_type, segment_length);
+ break;
+ }
+
+ buf += segment_length;
+ }
+
+ return buf_size;
+}
+
+static const AVOption options[] = {
+ // {"forced_subs_only", "Only show forced subtitles", OFFSET(forced_subs_only), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, SD},
+ { NULL },
+};
+
+static const AVClass textSutbittle_class = {
+ .class_name = "PGS subtitle decoder",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+
+AVCodec ff_bluraytextsub_decoder = {
+ .name = "BlurayTextSubtitle",
+ .type = AVMEDIA_TYPE_SUBTITLE,
+ .id = AV_CODEC_ID_BLURAY_TEXT_SUBTITLE,
+ .priv_data_size = sizeof(TextSubtitle),
+ .init = init_decoder,
+ .close = close_decoder,
+ .decode = decode,
+ .long_name = NULL_IF_CONFIG_SMALL("blu-ray Text subtitles"),
+ .priv_class = &textSutbittle_class,
+};
+
diff --git a/libavcodec/bluraytextsubtitle.h b/libavcodec/bluraytextsubtitle.h
new file mode 100755
index 0000000..1da2a96
--- /dev/null
+++ b/libavcodec/bluraytextsubtitle.h
@@ -0,0 +1,247 @@
+#ifndef AVCODEC_BLURAY_TEXT_SUBTITLE_H
+#define AVCODEC_BLURAY_TEXT_SUBTITLE_H
+
+/*
+ * Blu-ray Text subtitle decoder
+ * Copyright (c) 2014 Fuzhou Rockchip Electronics Co., Ltd
+ * hh@rock-chips.com
+ */
+
+#include "avcodec.h"
+
+#define MAX_TEXTSUBTITLE_LINE 100
+#define MAX_CHARS_PER_DPS_REGION 256
+
+#define BD_TEXTST_FLOW_LEFT_RIGHT 1 /* Left-to-Right character progression, Top-to-Bottom line progression */
+#define BD_TEXTST_FLOW_RIGHT_LEFT 2 /* Right-to-Left character progression, Top-to-Bottom line progression */
+#define BD_TEXTST_FLOW_TOP_BOTTOM 3 /* Top-to-Bottom character progression, Right-to-Left line progression */
+
+#define BD_TEXTST_HALIGN_LEFT 1
+#define BD_TEXTST_HALIGN_CENTER 2
+#define BD_TEXTST_HALIGN_RIGHT 3
+
+#define BD_TEXTST_VALIGN_TOP 1
+#define BD_TEXTST_VALIGN_MIDDLE 2
+#define BD_TEXTST_VALIGN_BOTTOM 3
+
+#define BD_TEXTST_FONT_OUTLINE_THIN 1
+#define BD_TEXTST_FONT_OUTLINE_MEDIUM 2
+#define BD_TEXTST_FONT_OUTLINE_THICK 3
+
+#define BD_TEXTST_DATA_STRING 1
+#define BD_TEXTST_DATA_FONT_ID 2
+#define BD_TEXTST_DATA_FONT_STYLE 3
+#define BD_TEXTST_DATA_FONT_SIZE 4
+#define BD_TEXTST_DATA_FONT_COLOR 5
+#define BD_TEXTST_DATA_NEWLINE 0x0a
+#define BD_TEXTST_DATA_RESET_STYLE 0x0b
+
+/**
+ * TextST Constraints
+ */
+#define TEXTST_SPB_SIZE (512*1024) // Subtitle Preloading Buffer Size = 512K
+#define TEXTST_DB_SIZE (2*1024) // Dialog Buffer Size = 2K
+#define TEXTST_DCB_SIZE (32*1024) // Dialog Composition Buffer Size = 32K
+#define TEXTST_BOB_SIZE (2*1024*1024) // Bitmap Object Buffer Size = 2M
+#define TEXTST_BOB_DEPTH 10
+#define TEXTST_MAX_DSS_REGION_STYLES 60
+#define TEXTST_MAX_DSS_USER_STYLES 25
+#define TEXTST_MAX_PALETTE_ENTRIES 255
+#define TEXTST_MAX_REGIONS_PER_DPS 2
+#define TEXTST_MAX_CHARS_PER_DPS_REGION 255
+#define TEXTST_MAX_FONTS 255
+#define TEXTST_MAX_FONTSIZE 144
+#define TEXTST_MIN_FONTSIZE 8
+
+
+
+enum SegmentType {
+ /* Text subtitles */
+ Text_DIALOG_STYLE = 0x81,
+ Text_DIALOG_PRESENTATION = 0x82,
+};
+
+
+typedef struct PaletteEntry
+{
+ unsigned int color[256];
+}PaletteEntry;
+
+/*
+* A "Text box" is defined by position and size within a Text Region. Text boxes are used for the
+ placement of text for display
+*/
+typedef struct TextSubtitleRect
+{
+ int x,y;
+ int mWidth,mHight;
+}TextSubtitleRect;
+
+
+/*
+* A "Text Region" is defined by position and size within the Graphic plane. Each Text Region can
+ have a unique background color.
+*/
+typedef struct RectRegion
+{
+ TextSubtitleRect mRegion;
+ int mBackColorPaletteRefId; /* palette entry id ref */
+}RectRegion;
+
+typedef struct FontStyle
+{
+ int mBold;
+ int mItalic;
+ int mOutLineBorder;
+}FontStyle;
+
+typedef struct RegionStyle
+{
+ unsigned char mRegionStyleId;
+
+ /*
+ * mTextFlow 文字的排列方式 1(其他): 正常的排列方式 2: 文字需要反转
+ */
+ unsigned char mTextFlow; /* BD_TEXTST_FLOW_* */
+
+ /*
+ * mTextHalign 行对齐方式 1: 左对齐 3: 右对齐 其他: 居中
+ */
+ unsigned char mTextHalign; /* BD_TEXTST_HALIGN_* */ // horizontal_alignment
+
+ /*
+ * mTextValign 列对齐方式 1: 顶端对齐(Top align) 2: 居中 其他: 底端对齐(Bottom align)
+ */
+ unsigned char mTextValign; /* BD_TEXTST_VALIGN_* */ // vertical_alignment
+
+ /*
+ * 每一行之间的间距
+ */
+ unsigned char mLineSpace;
+
+ /*
+ * 字体标识
+ */
+ unsigned char mFontIdRef;
+
+ unsigned char mFontIncDec; /* 根据该标志位来判断是否可以调节字体大小是增加还是减小 */
+ unsigned char mFontSize;
+ unsigned char mFontColor; /* palette entry id ref */
+ unsigned char mOutLineColor; /* palette entry id ref */
+ unsigned char mOuntLIneThickness; /* BD_TEXTST_FONT_OUTLINE_* */
+
+ RectRegion mRegion;
+ TextSubtitleRect mTextRect; /* relative to region */
+ FontStyle mFontStyle;
+}RegionStyle;
+
+typedef struct UserStyle
+{
+ unsigned char mUserStyleId;
+
+ unsigned char mFontIncDec;
+ unsigned char mFontSizeDelta; // adjust Font size,increase/descrease this Delta
+
+ unsigned char mLineSpaceIncDec; // 0 increase 1: decrease
+ unsigned char mLineSpaceDelta;
+
+ unsigned char mRegionHorizontalDiretion;
+ unsigned char mRegionVerticalDirection;
+
+ unsigned char mTextBoxHorizontalDirection;
+ unsigned char mTextBoxVerticalDirection;
+
+ unsigned char mTextBoxWidthIncDec;
+ unsigned char mTextBoxHeightIncDec;
+
+ short mRegionHorizontaDelta;
+ short mRegionVerticalDelta;
+ short mTextBoxHorizontalDelta;
+ short mTextBoxVerticalDelta;
+ short mTextBoxWidthDelta;
+ short mTextBoxHeightDelta;
+}UserStyle;
+
+typedef struct TextSubtitleText
+{
+ unsigned char mLength;
+ unsigned char* mString;
+}TextSubtitleText;
+
+typedef struct DataStyle
+{
+ FontStyle mFontStyle;
+ unsigned char mOutLineColor;
+ unsigned char mOutLineThickness;
+}DataStyle;
+
+
+/*
+* A Line Text Subtitle 一行字幕数据
+*/
+typedef struct TextLineData
+{
+ unsigned char* mText;
+ unsigned char* mInLineStyleValues;
+ unsigned char* mInLineStyleType;
+ unsigned char* mInLineStylePosition;
+}TextLineData;
+
+
+typedef struct TextSubtitleData
+{
+ unsigned char mType;
+
+ unsigned char mFontRefId;
+ unsigned char mFontSize;
+ unsigned char mFontColor;
+
+ TextSubtitleText* mText;
+ DataStyle* mDataStyle;
+}TextSubtitleData;
+
+typedef struct DialogRegion
+{
+ /* NOTE: this flag indicates a continuous presentation between this DPS and the NEXT DPS */
+ unsigned char mContinousPresentFlag;
+
+ /*
+ * If display is off, but the forced on flag is set, then
+ * turn the display on.
+ */
+ unsigned char mForceOnFlag;
+ unsigned char mRegionStyleRefId;
+
+ // how many line in this Region
+ int mLineCount;
+ TextLineData* mLineData[MAX_TEXTSUBTITLE_LINE];
+}DialogRegion;
+
+typedef struct DialogStyle
+{
+ unsigned char mPlayerStyleFlag;
+ unsigned char mRegoinStyleCount;
+ unsigned char mUserStyleCount;
+
+ RegionStyle* mRegionStyle;
+ UserStyle* mUserStyle; // 当userStyle存在时,可以使用userStyle来调节字体,线宽等
+ PaletteEntry* mPalette;
+}DialogStyle;
+
+typedef struct DialogPresentation
+{
+ int64_t mStartPTS;
+ int64_t mEndPTS;
+
+ int mRegionCount;
+ int mPaletteUpdataFlag;
+ PaletteEntry* mPalette;
+ DialogRegion* mRegion;
+}DialogPresentation;
+
+typedef struct TextSubtitle
+{
+ DialogPresentation* mDialog;
+ DialogStyle* mDialogStyle;
+}TextSubtitle;
+#endif
diff --git a/libavcodec/h264.c b/libavcodec/h264.c
index ea5b059..184d6d1 100644..100755
--- a/libavcodec/h264.c
+++ b/libavcodec/h264.c
@@ -178,16 +178,50 @@ const uint8_t *ff_h264_decode_nal(H264Context *h, const uint8_t *src,
int *dst_length, int *consumed, int length)
{
int i, si, di;
- uint8_t *dst;
+ uint8_t *dst, svc_ext = 0;
int bufidx;
// src[0]&0x80; // forbidden bit
- h->nal_ref_idc = src[0] >> 5;
+ h->nal_ref_idc = (src[0] >> 5) & 0x03;
h->nal_unit_type = src[0] & 0x1F;
src++;
length--;
+ // SVC extension flag
+ if (h->nal_unit_type == NAL_PREFIX || h->nal_unit_type == NAL_SLICE_EXT || h->nal_unit_type == NAL_SLICE_EXTD)
+ {
+ h->svc_ext_flag = src[0] >> 7;
+ //av_log(NULL, AV_LOG_ERROR, "svc ext = %d", svc_ext);
+ if (h->svc_ext_flag)
+ {
+ av_log(NULL, AV_LOG_ERROR, "NOT handled SVC extension......");
+ uint8_t idr_flag;
+ h->idr_flag = (src[0] & 0x40) >> 6;
+ h->svc_priority_id = src[0] & 0x2F;
+ h->no_inter_layer_pred_flag = src[1] >> 7;
+ h->dependency_flag = (src[1] & 0x70) >> 4;
+ h->quality_flag = src[1] & 0x0F;
+ h->svc_temporal_id = (src[2] & 0xE0) >> 5;
+ h->use_ref_base_pic_flag = (src[2] & 0x08) >> 4;
+ h->discardable_flag = (src[2] & 0x04) >> 3;
+ h->output_flag = (src[2] & 0x02) >> 2;
+ }
+ else // handler mvc extension
+ {
+ h->non_idr_flag = (src[0] & 0x40) >> 6;
+ h->mvc_priority_id = src[0] & 0x2F;
+ h->view_id = src[1] << 2 | ((src[2] & 0xC0) >> 6);
+ h->mvc_temporal_id = (src[2] & 0x38) >> 3;
+ h->anchor_pic_flag = (src[2] & 0x04) >> 2;
+ h->inter_view_flag = (src[2] & 0x02) >> 1;
+ //av_log(NULL, AV_LOG_ERROR, "MVC EXT: non_idr=%d prio=%d view=%d temp=%d anchor=%d inter=%d",
+ // h->non_idr_flag, h->mvc_priority_id, h->view_id,
+ // h->mvc_temporal_id, h->anchor_pic_flag, h->inter_view_flag);
+ }
+ length -= 3;
+ src += 3;
+ }
#define STARTCODE_TEST \
if (i + 2 < length && src[i + 1] == 0 && src[i + 2] <= 3) { \
if (src[i + 2] != 3) { \
@@ -800,6 +834,8 @@ static void free_tables(H264Context *h, int free_rbsp)
if (i)
av_freep(&h->thread_context[i]);
}
+
+ release_subset_seq_parameter_set(h->sps.sps_ext);
}
static void init_dequant8_coeff_table(H264Context *h)
@@ -3858,6 +3894,13 @@ again:
goto end;
}
idr(h); // FIXME ensure we don't lose some frames if there is reordering
+ case NAL_SLICE_EXT:
+ case NAL_SLICE_EXTD:
+ if(hx->svc_ext_flag)
+ {
+ av_log(NULL, AV_LOG_ERROR, "Not handled SVC extension.");
+ break;
+ }
case NAL_SLICE:
init_get_bits(&hx->s.gb, ptr, bit_length);
hx->intra_gb_ptr =
@@ -3996,6 +4039,31 @@ again:
case NAL_SPS_EXT:
case NAL_AUXILIARY_SLICE:
break;
+ #if 1
+ case NAL_SUB_SPS:
+ // init_get_bits(&s->gb, ptr, bit_length);
+ // ff_h264_decode_subset_seq_parameter_set(h);
+
+ init_get_bits(&s->gb, ptr, bit_length);
+ if (ff_h264_decode_subset_seq_parameter_set(h) < 0 && (h->is_avc ? (nalsize != consumed) && nalsize : 1)) {
+ av_log(h->s.avctx, AV_LOG_DEBUG,
+ "SPS decoding failure, trying again with the complete NAL\n");
+ if (h->is_avc)
+ av_assert0(next_avc - buf_index + consumed == nalsize);
+ init_get_bits(&s->gb, &buf[buf_index + 1 - consumed],
+ 8*(next_avc - buf_index + consumed - 1));
+ ff_h264_decode_subset_seq_parameter_set(h);
+ }
+
+ if (s->flags & CODEC_FLAG_LOW_DELAY ||
+ (h->sps.bitstream_restriction_flag &&
+ !h->sps.num_reorder_frames))
+ s->low_delay = 1;
+ if (avctx->has_b_frames < 2)
+ avctx->has_b_frames = !s->low_delay;
+
+ break;
+ #endif
default:
av_log(avctx, AV_LOG_DEBUG, "Unknown NAL code: %d (%d bits)\n",
hx->nal_unit_type, bit_length);
@@ -4194,8 +4262,6 @@ static const AVProfile profiles[] = {
{ FF_PROFILE_H264_HIGH_444_PREDICTIVE, "High 4:4:4 Predictive" },
{ FF_PROFILE_H264_HIGH_444_INTRA, "High 4:4:4 Intra" },
{ FF_PROFILE_H264_CAVLC_444, "CAVLC 4:4:4" },
- { FF_PROFILE_H264_MVC_HIGH, "Multiview high" },
- { FF_PROFILE_H264_STEREO_HIGH, "Stereo high" },
{ FF_PROFILE_UNKNOWN },
};
diff --git a/libavcodec/h264.h b/libavcodec/h264.h
index 430a6f9..a1951a2 100644..100755
--- a/libavcodec/h264.h
+++ b/libavcodec/h264.h
@@ -121,8 +121,16 @@ enum {
NAL_END_STREAM,
NAL_FILLER_DATA,
NAL_SPS_EXT,
- NAL_SUBSET_SEQ_PARAM_SET = 0x0F,
- NAL_AUXILIARY_SLICE = 19
+
+ // add by hh for mvc parser
+ NAL_PREFIX = 14, // Prefix NAL unit, prefix_nal_unit_rbsp( )
+ NAL_SUB_SPS = 15, // Subset sequence parameter set, subset_seq_parameter_set_rbsp( )
+
+ NAL_AUXILIARY_SLICE = 19,
+
+ NAL_SLICE_EXT = 20, // Coded slice extension, slice_layer_extension_rbsp( )
+ NAL_SLICE_EXTD = 21, // Coded slice extension for depth view.
+ NAL_VDRD = 24, // View and Dependency Representation Delimiter NAL Unit
};
/**
@@ -151,6 +159,113 @@ typedef enum {
SEI_PIC_STRUCT_FRAME_TRIPLING = 8 ///< 8: %frame tripling
} SEI_PicStructType;
+typedef struct SPS_EXT_ANCHER
+{
+ int number_anchor_ref_l0;
+ int* anchor_refs_l0;
+
+ int number_anchor_ref_l1;
+ int* anchor_refs_l1;
+}SPS_EXT_ANCHER;
+
+typedef struct SPS_EXT_APP_OP_TARGET_VIEW
+{
+ int applicable_op_target_view_id;
+}SPS_EXT_APP_OP_TARGET_VIEW;
+
+
+typedef struct SPS_EXT_APPLICABEL_OP
+{
+ int applicable_op_temporal_id;
+ int applicable_num_target_view;
+ SPS_EXT_APP_OP_TARGET_VIEW* view;
+ int applicable_op_num_view;
+}SPS_EXT_APPLICABEL_OP;
+
+
+typedef struct SPS_EXT_APPLICABEL_OPS
+{
+ // int num_level_values_signalled;
+ int level_idc;
+ int num_applicable_ops;
+ SPS_EXT_APPLICABEL_OP* applicable_ops;
+}SPS_EXT_APPLICABEL_OPS;
+
+// add by hh for mvc parser
+typedef struct SPS_MVC_EXTESNSION
+{
+ int num_views;
+ int* view_id;
+
+ SPS_EXT_ANCHER* ancher_refs;
+ SPS_EXT_ANCHER* non_ancher_refs;
+
+ int num_level_value_signalled;
+ SPS_EXT_APPLICABEL_OPS* applicable_op;
+}SPS_MVC_EXT;
+
+
+
+typedef struct SPS_VUI_MVC_TARGET_OUTPUT_VIEW
+{
+ int vui_mvc_view_id;
+}SPS_VUI_MVC_TARGET_OUTPUT_VIEW;
+
+typedef struct HRD_PARAMETER
+{
+ int cpb_count;
+ int bit_rate_scale;
+ int cpb_size_scale;
+
+ int initial_cpb_removal_delay_length;
+ int cpb_removal_delay_length;
+ int dpb_output_delay_length;
+ int time_offset_length;
+}HRD_PARAMETER;
+
+
+
+typedef struct SPS_VUI_MVC_OPS
+{
+ int vui_mvc_temporal_id;
+
+ int vui_mvc_num_target_output_views;
+ SPS_VUI_MVC_TARGET_OUTPUT_VIEW* view;
+
+ int vui_mvc_timing_info_present_flag;
+ int vui_mvc_num_units_in_ticks;
+ int vui_mvc_time_scale;
+ int vui_mvc_fixed_frame_rate_flag;
+
+ int vui_mvc_nal_hrd_parameters_present_flag;
+ HRD_PARAMETER* nal_hrd;
+
+ int vui_mvc_vcl_hrd_parameters_present_flag;
+ HRD_PARAMETER* vcl_hrd;
+
+ int vui_mvc_low_delay_hrd_present_flag;
+ int vui_mvc_pic_struct_present_flag;
+}SPS_VUI_MVC_OPS;
+
+typedef struct SPS_VUI_PARAMETER_EXT
+{
+ int vui_mvc_num_ops;
+ SPS_VUI_MVC_OPS* vui_mvc_ops;
+}SPS_VUI_PARAMETER_EXT;
+
+
+typedef struct SPS_EXT
+{
+ SPS_MVC_EXT* sps_mvc_ext;
+
+ int mvc_vui_parameter_present_flag;
+ SPS_VUI_PARAMETER_EXT* vui_para_ext;
+
+ int additional_extension2_flag;
+
+}SPS_EXT;
+
+
/**
* Sequence parameter set
*/
@@ -208,6 +323,9 @@ typedef struct SPS {
int bit_depth_chroma; ///< bit_depth_chroma_minus8 + 8
int residual_color_transform_flag; ///< residual_colour_transform_flag
int constraint_set_flags; ///< constraint_set[0-3]_flag
+
+ // add by hh for mvc parser
+ SPS_EXT* sps_ext;
} SPS;
/**
@@ -446,6 +564,27 @@ typedef struct H264Context {
int nal_ref_idc;
int nal_unit_type;
+
+ uint8_t svc_ext_flag;
+ // SVC extension in NAL header
+ uint8_t idr_flag;
+ uint8_t svc_priority_id;
+ uint8_t no_inter_layer_pred_flag;
+ uint8_t dependency_flag;
+ uint8_t quality_flag;
+ uint8_t svc_temporal_id;
+ uint8_t use_ref_base_pic_flag;
+ uint8_t discardable_flag;
+ uint8_t output_flag;
+ // reserved 2 bits
+
+ // MVC extension in NAL header
+ uint8_t non_idr_flag;
+ uint8_t mvc_priority_id;
+ unsigned int view_id;
+ uint8_t mvc_temporal_id;
+ uint8_t anchor_pic_flag;
+ uint8_t inter_view_flag;
uint8_t *rbsp_buffer[2];
unsigned int rbsp_buffer_size[2];
@@ -603,6 +742,13 @@ typedef struct H264Context {
uint8_t parse_history[4];
int parse_history_count;
int parse_last_mb;
+
+ int last_nal_type;
+ FILE * sps_writefd;
+ int sps_writeok;
+ int force_sps;
+
+ int first;
} H264Context;
extern const uint8_t ff_h264_chroma_qp[7][QP_MAX_NUM + 1]; ///< One chroma qp table for each possible bit depth (8-14).
@@ -628,6 +774,16 @@ int ff_h264_get_profile(SPS *sps);
*/
int ff_h264_decode_picture_parameter_set(H264Context *h, int bit_length);
+
+// this function is add by hh for mvc parser
+int ff_h264_decode_subset_seq_parameter_set(H264Context *h);
+
+/*
+* release subset sps
+*/
+void release_subset_seq_parameter_set(SPS_EXT* ext);
+
+
/**
* Decode a network abstraction layer unit.
* @param consumed is the number of bytes used as input
@@ -757,6 +913,7 @@ void ff_h264_reset_sei(H264Context *h);
#define LUMA_DC_BLOCK_INDEX 48
#define CHROMA_DC_BLOCK_INDEX 49
+
// This table must be here because scan8[constant] must be known at compiletime
static const uint8_t scan8[16 * 3 + 3] = {
4 + 1 * 8, 5 + 1 * 8, 4 + 2 * 8, 5 + 2 * 8,
diff --git a/libavcodec/h264_parser.c b/libavcodec/h264_parser.c
index 743bd76..f732a28 100644..100755
--- a/libavcodec/h264_parser.c
+++ b/libavcodec/h264_parser.c
@@ -31,7 +31,7 @@
#include "h264data.h"
#include "golomb.h"
-
+#define RECORD_SPS 0
static int ff_h264_find_frame_end(H264Context *h, const uint8_t *buf, int buf_size)
{
int i, j;
@@ -62,6 +62,7 @@ static int ff_h264_find_frame_end(H264Context *h, const uint8_t *buf, int buf_si
}
if(state==7){
+ h->last_nal_type = 0;
#if HAVE_FAST_UNALIGNED
/* we check i<buf_size instead of i+3/7 because its simpler
* and there should be FF_INPUT_BUFFER_PADDING_SIZE bytes at the end
@@ -80,22 +81,57 @@ static int ff_h264_find_frame_end(H264Context *h, const uint8_t *buf, int buf_si
break;
}
}
+ /*
+ * 状态为2时,表示已经定位到NAL头中的第一个0x00。
+ * 状态为0时,表示模块第一次进行H264帧解析。之后就不会切换到该状态。
+ * 当状态小等于2时,
+ * a. 找到0x01时,下一个状态:
+ * 2->7 (0x00 0x01), 1->4 (0x00 0x00 0x01), 0->5 (0x00 0x00 0x00 0x01)
+ * b. 找到非0x01和0x00,则下一个状态为 7,即没有找到NAL头。
+ * c. 找到0x00时,下一个状态: 2->1, 1->0, 0->0
+ */
}else if(state<=2){
if(buf[i]==1) state^= 5; //2->7, 1->4, 0->5
else if(buf[i]) state = 7;
else state>>=1; //2->1, 1->0, 0->0
+ /*
+ * 实际上并不会出现值为3和4的状态,2之后就是5。表示找到NAL头了。
+ */
}else if(state<=5){
int v= buf[i] & 0x1F;
- if(v==6 || v==7 || v==8 || v==9){
+ h->last_nal_type = v;
+ /*
+ * NAL==9,间隔符,表示一个AU的间隔,通常就是指一个帧。
+ * NAL==7, 序列参数集
+ * NAL==8, 图像参数集
+ * NAL==15, 扩展序列参数集
+ * 遇到这4种NAL,且已经找到帧开始位置时,则这里找到了帧结束位置。
+ */
+ if(v==7 || v==8 || v==9 || v==15 || v==24){
if(pc->frame_start_found){
i++;
goto found;
}
- }else if(v==1 || v==2 || v==5){
+ /*
+ * NAL==5, IDR帧,肯定是一个序列的间隔。
+ * NAL==1, 非IDR帧,是I帧。
+ * NAL==2, Slice data partiton A, Slice分块的第一块。
+ * NAL==20, Slice extension
+ * 遇到如上的4种NAL时,开始查找帧开始位置。
+ */
+ }else if(v==1 || v==2 || v==5 || v==20){
state+=8;
+ if (v == 20)
+ i += 3; // ignore the NAL MVC extension
continue;
}
+ // 如果没有找到如上的NAL,则接着往下找。
state= 7;
+ /*
+ * 走到这里表示在找到NAL头后,还发现了NAL为1, 2, 5, 20类型的数据。
+ * 这几种类型都是Slice,检查Slice header.
+ * slice header的第一位就是first_mb_in_slice.
+ */
}else{
h->parse_history[h->parse_history_count++]= buf[i];
if(h->parse_history_count>3){
@@ -108,7 +144,11 @@ static int ff_h264_find_frame_end(H264Context *h, const uint8_t *buf, int buf_si
last_mb= h->parse_last_mb;
h->parse_last_mb= mb;
if(pc->frame_start_found){
- if(mb <= last_mb)
+ #if 0
+ if((mb <= last_mb) && (last_mb > 10))
+ goto found;
+ #endif
+ if((mb <= last_mb) && ((h->last_nal_type != 20) || ((h->last_nal_type == 20) && (last_mb > 0))))
goto found;
}else
pc->frame_start_found = 1;
@@ -129,6 +169,7 @@ found:
return i-(state&5) - 3*(state>7);
}
+
/**
* Parse NAL units of found picture and decode some basic information.
*
@@ -149,6 +190,13 @@ static inline int parse_nal_units(AVCodecParserContext *s,
const uint8_t *ptr;
int q264 = buf_size >=4 && !memcmp("Q264", buf, 4);
+ int i,flag = 0,end_off = 0,sps_off = 0,pps_off = 0,times = 0;
+
+ unsigned char *sps_buf;
+ unsigned char *pps_buf;
+ int sps_size;
+ int pps_size;
+
/* set some sane default values */
s->pict_type = AV_PICTURE_TYPE_I;
s->key_frame = 0;
@@ -189,6 +237,10 @@ static inline int parse_nal_units(AVCodecParserContext *s,
if (src_length > 20)
src_length = 20;
break;
+ case NAL_SLICE_EXT:
+ case NAL_SLICE_EXTD:
+ case NAL_PREFIX:
+ break;
}
ptr= ff_h264_decode_nal(h, buf, &dst_length, &consumed, src_length);
if (ptr==NULL || dst_length < 0)
@@ -196,9 +248,107 @@ static inline int parse_nal_units(AVCodecParserContext *s,
init_get_bits(&h->s.gb, ptr, 8*dst_length);
switch(h->nal_unit_type) {
+ case NAL_SUB_SPS:
+ ff_h264_decode_subset_seq_parameter_set(h);
+ break;
case NAL_SPS:
- case NAL_SUBSET_SEQ_PARAM_SET:
+
+
+#if RECORD_SPS
+ if ((h->sps_writefd != NULL) && (h->sps_writeok== 0)){
+ fwrite(buf,buf_size,1,h->sps_writefd);
+ fflush(h->sps_writefd);
+ h->sps_writeok= 0;
+ av_log(NULL,AV_LOG_ERROR,"**************write sps buf");
+ }
+#endif
ff_h264_decode_seq_parameter_set(h);
+ if(h->first == 0) {
+ for (i=0; i<buf_size; i++) {
+ if ((buf[i] == 0x00) && (buf[i+1] == 0x00)
+ && (buf[i+2] == 0x00) && (buf[i+3] == 0x01)) {
+ if (i > buf_size - 5) {
+ times = 1;
+ }
+ if (((buf[i+4] & 0x1f) == 0x07) && (flag == 0)) {
+ sps_off = i;
+ flag = 1;
+ } else if (((buf[i+4] & 0x1f) == 0x08)&&(flag == 1)) {
+ pps_off = i;
+ flag = 2;
+ } else if (flag == 2){
+ end_off = i;
+ flag = 0;
+ break;
+ }
+ }
+ }
+ flag = 0;
+ if ((pps_off == 0) && (sps_off == 0) && (times == 1)) {
+ if ((buf[0] & 0x1f) == 0x07) {
+ sps_off = 0;
+ flag = 1;
+ }
+ for (i=0; i<buf_size; i++) {
+ if (flag >= 1) {
+ if ((buf[i] == 0x00) && (buf[i+1] == 0x00)
+ && (buf[i+2] == 0x00) && (buf[i+3] == 0x01)) {
+ if (((buf[i+4] & 0x1f) == 0x08)&&(flag == 1)) {
+ pps_off = i;
+ flag = 2;
+ } else if (flag == 2){
+ end_off = i;
+ flag = 0;
+ break;
+ }
+ }
+ } else {
+ break;
+ }
+ }
+ }
+
+ sps_size = pps_off - sps_off;
+ pps_size = end_off - pps_off;
+
+ if ((sps_size == 0) || ( pps_size == 0)) {
+ break;
+ }
+ if (times == 1)
+ sps_size += 4;
+
+ sps_buf = (unsigned char *)av_malloc(sps_size);
+ pps_buf = (unsigned char *)av_malloc(pps_size);
+
+ if (!sps_buf)
+ av_log(NULL,AV_LOG_ERROR,"avmalloc sps error");
+ if (!pps_buf)
+ av_log(NULL,AV_LOG_ERROR,"avmalloc pps error");
+
+ memset(sps_buf, 0, sps_size);
+ memset(pps_buf, 0, pps_size);
+
+ if (times == 1) {
+ sps_buf[0] = 0x00;
+ sps_buf[1] = 0x00;
+ sps_buf[2] = 0x00;
+ sps_buf[3] = 0x01;
+ memcpy(sps_buf+4, buf+sps_off, sps_size);
+ } else {
+ memcpy(sps_buf, buf+sps_off, sps_size);
+ }
+ memcpy(pps_buf, buf+pps_off, pps_size);
+
+ for (i=0; i<sps_size; i++)
+ av_log(NULL, AV_LOG_DEBUG, "s->sps_buf [%d] = 0x%x", i, sps_buf[i]);
+ for (i=0; i<pps_size; i++)
+ av_log(NULL, AV_LOG_DEBUG, "s->pps_buf [%d] = 0x%x", i, pps_buf[i]);
+
+ ff_codec_check_operate(&s->callback,OPERATE_GET_SPS,sps_buf,&sps_size);
+ ff_codec_check_operate(&s->callback,OPERATE_GET_PPS,pps_buf,&pps_size);
+ h->first = 1;
+ }
+
break;
case NAL_PPS:
ff_h264_decode_picture_parameter_set(h, h->s.gb.size_in_bits);
@@ -209,6 +359,13 @@ static inline int parse_nal_units(AVCodecParserContext *s,
case NAL_IDR_SLICE:
s->key_frame = 1;
/* fall through */
+ case NAL_SLICE_EXT:
+ case NAL_SLICE_EXTD:
+ if(h->svc_ext_flag)
+ {
+ av_log(NULL, AV_LOG_ERROR, "Not handled SVC extension.");
+ break;
+ }
case NAL_SLICE:
get_ue_golomb_long(&h->s.gb); // skip first_mb_in_slice
slice_type = get_ue_golomb_31(&h->s.gb);
@@ -231,17 +388,7 @@ static inline int parse_nal_units(AVCodecParserContext *s,
av_log(h->s.avctx, AV_LOG_ERROR, "non-existing SPS referenced\n");
return -1;
}
-
- /*
- ** if current stream is mvc stream, use mvc profile_idc as
- ** sps->profile_idc, all here is for report mvc profile_idc
- ** to player for mvc disable support.
- ** @Sep 17th, 2013, by hbb.
- */
- if ((h->sps.profile_idc !=118) && (h->sps.profile_idc !=128)) {
- h->sps = *h->sps_buffers[h->pps.sps_id];
- }
-
+ h->sps = *h->sps_buffers[h->pps.sps_id];
h->frame_num = get_bits(&h->s.gb, h->sps.log2_max_frame_num);
avctx->profile = ff_h264_get_profile(&h->sps);
@@ -287,6 +434,12 @@ static inline int parse_nal_units(AVCodecParserContext *s,
}
return 0; /* no need to evaluate the rest */
+
+ case NAL_AUD: // nothing need to be done.
+ break;
+ default:
+ av_log(h->s.avctx, AV_LOG_DEBUG, "Not handled NAL=%d", h->nal_unit_type);
+ break;
}
buf += h->is_avc ? nalsize : consumed;
}
@@ -352,7 +505,7 @@ static int h264_parse(AVCodecParserContext *s,
if (s->flags & PARSER_FLAG_ONCE) {
s->flags &= PARSER_FLAG_COMPLETE_FRAMES;
}
-
+
*poutbuf = buf;
*poutbuf_size = buf_size;
return next;
@@ -364,18 +517,24 @@ static int h264_split(AVCodecContext *avctx,
int i;
uint32_t state = -1;
int has_sps= 0;
+ /*begin $ edit by hbb $ for http url hava Audio but not Video $ yuanfeng $ 2013-07-03 $ */
+ int has_pps= 0;
for(i=0; i<=buf_size; i++){
if((state&0xFFFFFF1F) == 0x107)
has_sps=1;
+ if((state&0xFFFFFF1F) == 0x108)
+ has_pps=1;
/* if((state&0xFFFFFF1F) == 0x101 || (state&0xFFFFFF1F) == 0x102 || (state&0xFFFFFF1F) == 0x105){
}*/
- if((state&0xFFFFFF00) == 0x100 && (state&0xFFFFFF1F) != 0x107 && (state&0xFFFFFF1F) != 0x108 && (state&0xFFFFFF1F) != 0x109){
- if(has_sps){
+ if((state&0xFFFFFF00) == 0x100 && (state&0xFFFFFF1F) != 0x107 &&
+ (state&0xFFFFFF1F) != 0x108 && (state&0xFFFFFF1F) != 0x109){
+ if(has_sps && has_pps){
while(i>4 && buf[i-5]==0) i--;
return i-4;
}
}
+ /*end $ edit by hbb $ for http url hava Audio but not Video $ yuanfeng $ 2013-07-03 $ */
if (i<buf_size)
state= (state<<8) | buf[i];
}
@@ -386,6 +545,14 @@ static void close(AVCodecParserContext *s)
{
H264Context *h = s->priv_data;
ParseContext *pc = &h->s.parse_context;
+#if RECORD_SPS
+ if(h->sps_writefd != NULL)
+ {
+ fclose(h->sps_writefd);
+ h->sps_writefd = NULL;
+ }
+ h->sps_writeok = 0;
+#endif
av_free(pc->buffer);
ff_h264_free_context(h);
@@ -396,6 +563,20 @@ static int init(AVCodecParserContext *s)
H264Context *h = s->priv_data;
h->thread_context[0] = h;
h->s.slice_context_count = 1;
+
+#if RECORD_SPS
+ h->sps_writefd = fopen("/data/buf.pps","w");
+
+ if(h->sps_writefd != NULL) {
+ av_log(NULL,AV_LOG_ERROR,"%s:create file success",__FUNCTION__);
+
+ } else {
+ av_log(NULL,AV_LOG_ERROR,"%s:create file failed",__FUNCTION__);
+ }
+ h->sps_writeok = 0;
+#endif
+
+ h->first = 0;
return 0;
}
diff --git a/libavcodec/h264_ps.c b/libavcodec/h264_ps.c
index 2a62ebc..19707ca 100644..100755
--- a/libavcodec/h264_ps.c
+++ b/libavcodec/h264_ps.c
@@ -37,6 +37,8 @@
//#undef NDEBUG
#include <assert.h>
+#define AV_LOG AV_LOG_DEBUG //AV_LOG_ERROR
+
static const AVRational pixel_aspect[17]={
{0, 1},
{1, 1},
@@ -333,6 +335,7 @@ int ff_h264_decode_seq_parameter_set(H264Context *h){
unsigned int sps_id;
int i;
SPS *sps;
+ SPS_EXT* sps_ext = NULL;
profile_idc= get_bits(&s->gb, 8);
constraint_set_flags |= get_bits1(&s->gb) << 0; //constraint_set0_flag
@@ -354,18 +357,7 @@ int ff_h264_decode_seq_parameter_set(H264Context *h){
return -1;
sps->time_offset_length = 24;
- /*
- ** if current stream is mvc stream, use mvc profile_idc as
- ** sps->profile_idc, all here is for report mvc profile_idc
- ** to player for mvc disable support.
- ** @Sep 17th, 2013, by hbb.
- */
- if ((h->sps.profile_idc !=118) && (h->sps.profile_idc !=128)) {
- sps->profile_idc = profile_idc;
- } else {
- sps->profile_idc = h->sps.profile_idc;
- }
-
+ sps->profile_idc= profile_idc;
sps->constraint_set_flags = constraint_set_flags;
sps->level_idc= level_idc;
sps->full_range = -1;
@@ -678,3 +670,533 @@ fail:
av_free(pps);
return -1;
}
+static void release_seq_parameter_set_mvc_extension(SPS_MVC_EXT* mvc_ext)
+{
+ int i = 0,j = 0;
+ if(mvc_ext == NULL)
+ {
+ return ;
+ }
+
+ if(mvc_ext->view_id != NULL)
+ {
+ av_free(mvc_ext->view_id);
+ }
+
+ if(mvc_ext->ancher_refs != NULL)
+ {
+ for(i = 0; i < mvc_ext->num_views-1; i++)
+ {
+ if(mvc_ext->ancher_refs[i].anchor_refs_l0 != NULL)
+ {
+ av_free(mvc_ext->ancher_refs[i].anchor_refs_l0);
+ }
+
+ if(mvc_ext->ancher_refs[i].anchor_refs_l1 != NULL)
+ {
+ av_free(mvc_ext->ancher_refs[i].anchor_refs_l0);
+ }
+ }
+
+ av_free(mvc_ext->ancher_refs);
+ }
+
+ if(mvc_ext->non_ancher_refs != NULL)
+ {
+ for(i = 0; i < mvc_ext->num_views-1; i++)
+ {
+ if(mvc_ext->non_ancher_refs[i].anchor_refs_l0 != NULL)
+ {
+ av_free(mvc_ext->non_ancher_refs[i].anchor_refs_l0);
+ }
+
+ if(mvc_ext->non_ancher_refs[i].anchor_refs_l1 != NULL)
+ {
+ av_free(mvc_ext->non_ancher_refs[i].anchor_refs_l0);
+ }
+ }
+
+ av_free(mvc_ext->non_ancher_refs);
+ }
+
+
+ if(mvc_ext->applicable_op != NULL)
+ {
+ for(i = 0; i < mvc_ext->num_level_value_signalled; i++)
+ {
+ if(mvc_ext->applicable_op[i].applicable_ops != NULL)
+ {
+ for(j = 0; j < mvc_ext->applicable_op[i].num_applicable_ops; j++)
+ {
+ if(mvc_ext->applicable_op[i].applicable_ops[j].view != NULL)
+ {
+ av_free(mvc_ext->applicable_op[i].applicable_ops[j].view);
+ }
+ }
+
+ av_free(mvc_ext->applicable_op[i].applicable_ops);
+ }
+ }
+ av_free(mvc_ext->applicable_op);
+ }
+
+ av_free(mvc_ext);
+}
+
+static inline int decode_seq_parameter_set_mvc_extension(H264Context *h,SPS_MVC_EXT **mvc_ext)
+{
+ MpegEncContext * const s = &h->s;
+ SPS *sps = &h->sps;
+ int i = 0, j = 0, k = 0;
+
+ SPS_MVC_EXT* sps_mvc_ext = av_mallocz(sizeof(SPS_MVC_EXT));
+ if(sps_mvc_ext == NULL)
+ {
+ return -1;
+ }
+
+ sps_mvc_ext->num_views = get_ue_golomb(&s->gb) + 1; // 0 to 1023
+ av_log(h->s.avctx, AV_LOG,"decode_seq_parameter_set_mvc_extension(),num_views = %d",sps_mvc_ext->num_views);
+ sps_mvc_ext->view_id = av_mallocz(sizeof(int)*sps_mvc_ext->num_views);
+ if(sps_mvc_ext->view_id != NULL)
+ {
+ for(i = 0; i < sps_mvc_ext->num_views; i++)
+ {
+ sps_mvc_ext->view_id[i] = get_ue_golomb(&s->gb) + 1; // 0 to 1023
+ av_log(h->s.avctx, AV_LOG, "decode_seq_parameter_set_mvc_extension(),view_id[%d] = %d",i,sps_mvc_ext->view_id[i]);
+ }
+ }
+ else
+ {
+ goto fail;
+ }
+
+ sps_mvc_ext->ancher_refs = av_mallocz(sizeof(SPS_EXT_ANCHER)*(sps_mvc_ext->num_views-1));
+ if(sps_mvc_ext->ancher_refs == NULL)
+ {
+ goto fail;
+ }
+
+ for(i = 0; i < sps_mvc_ext->num_views-1; i++)
+ {
+ sps_mvc_ext->ancher_refs[i].number_anchor_ref_l0 = get_ue_golomb_31(&s->gb);//get_ue_golomb(&s->gb);
+ av_log(h->s.avctx, AV_LOG, "decode_seq_parameter_set_mvc_extension(),sps_mvc_ext->ancher_refs[%d] = %d",
+ i,sps_mvc_ext->ancher_refs[i].number_anchor_ref_l0);
+ if((sps_mvc_ext->ancher_refs[i].number_anchor_ref_l0 > 0) && (sps_mvc_ext->ancher_refs[i].number_anchor_ref_l0 <= 15))
+ {
+ sps_mvc_ext->ancher_refs[i].anchor_refs_l0 = av_mallocz(sizeof(int)*sps_mvc_ext->ancher_refs[i].number_anchor_ref_l0);
+ if(sps_mvc_ext->ancher_refs[i].anchor_refs_l0 == NULL)
+ {
+ av_log(h->s.avctx, AV_LOG_ERROR, "anchor_refs[%d].anchor_refs_l0 = NULL");
+ goto fail;
+ }
+
+ for(j = 0; j< sps_mvc_ext->ancher_refs[i].number_anchor_ref_l0; j++)
+ {
+ sps_mvc_ext->ancher_refs[i].anchor_refs_l0[j] = get_ue_golomb(&s->gb);
+ av_log(h->s.avctx, AV_LOG, "decode_seq_parameter_set_mvc_extension(),sps_mvc_ext->ancher_refs[%d].anchor_refs_l0[%d] = %d",
+ i,j,sps_mvc_ext->ancher_refs[i].anchor_refs_l0[j]);
+ }
+ }
+ else if(sps_mvc_ext->ancher_refs[i].number_anchor_ref_l0 > 15)
+ {
+ av_log(h->s.avctx, AV_LOG_ERROR, "ancher_refs[%d].number_anchor_ref_l0 = %d count error",
+ i,sps_mvc_ext->ancher_refs[i].number_anchor_ref_l0);
+ goto fail;
+ }
+
+ sps_mvc_ext->ancher_refs[i].number_anchor_ref_l1 = get_ue_golomb_31(&s->gb);//get_ue_golomb(&s->gb);
+ av_log(h->s.avctx, AV_LOG, "decode_seq_parameter_set_mvc_extension(),sps_mvc_ext->number_anchor_ref_l1[%d] = %d",
+ i,sps_mvc_ext->ancher_refs[i].number_anchor_ref_l1);
+ if((sps_mvc_ext->ancher_refs[i].number_anchor_ref_l1 > 0) && (sps_mvc_ext->ancher_refs[i].number_anchor_ref_l1 <= 15))
+ {
+ sps_mvc_ext->ancher_refs[i].anchor_refs_l1 = av_mallocz(sizeof(int)*sps_mvc_ext->ancher_refs[i].number_anchor_ref_l1);
+ if(sps_mvc_ext->ancher_refs[i].anchor_refs_l1 == NULL)
+ {
+ av_log(h->s.avctx, AV_LOG_ERROR, "anchor_refs[%d].anchor_refs_l1 = NULL");
+ goto fail;
+ }
+
+ for(j = 0; j< sps_mvc_ext->ancher_refs[i].number_anchor_ref_l1; j++)
+ {
+ sps_mvc_ext->ancher_refs[i].anchor_refs_l1[j] = get_ue_golomb(&s->gb);
+ av_log(h->s.avctx, AV_LOG, "decode_seq_parameter_set_mvc_extension(),sps_mvc_ext->ancher_refs[%d].anchor_refs_l1[%d] = %d",
+ i,j,sps_mvc_ext->ancher_refs[i].anchor_refs_l1[j]);
+ }
+ }
+ else if(sps_mvc_ext->ancher_refs[i].number_anchor_ref_l1 > 15)
+ {
+ av_log(h->s.avctx, AV_LOG_ERROR, "anchor_refs[%d].number_ancher_ref = %d too larger",i,sps_mvc_ext->ancher_refs[i].number_anchor_ref_l1);
+ goto fail;
+ }
+ }
+
+ sps_mvc_ext->non_ancher_refs = av_mallocz(sizeof(SPS_EXT_ANCHER)*(sps_mvc_ext->num_views-1));
+ if(sps_mvc_ext->non_ancher_refs == NULL)
+ {
+ goto fail;
+ }
+
+ for(i = 0; i < sps_mvc_ext->num_views-1; i++)
+ {
+ sps_mvc_ext->non_ancher_refs[i].number_anchor_ref_l0 = get_ue_golomb_31(&s->gb);
+ if((sps_mvc_ext->non_ancher_refs[i].number_anchor_ref_l0 > 0) && (sps_mvc_ext->non_ancher_refs[i].number_anchor_ref_l0 <= 15))
+ {
+ sps_mvc_ext->non_ancher_refs[i].anchor_refs_l0 = av_mallocz(sizeof(int)*sps_mvc_ext->non_ancher_refs[i].number_anchor_ref_l0);
+ if(sps_mvc_ext->non_ancher_refs[i].anchor_refs_l0 == NULL)
+ {
+ av_log(h->s.avctx, AV_LOG_ERROR, "non_ancher_refs[%d].anchor_refs_l0 = NULL");
+ goto fail;
+ }
+
+ for(j = 0; j< sps_mvc_ext->non_ancher_refs[i].number_anchor_ref_l0; j++)
+ {
+ sps_mvc_ext->non_ancher_refs[i].anchor_refs_l0[j] = get_ue_golomb(&s->gb);
+ }
+ }
+ else if(sps_mvc_ext->non_ancher_refs[i].number_anchor_ref_l0 > 15)
+ {
+ av_log(h->s.avctx, AV_LOG_ERROR, "anchor_refs[%d].number_anchor_ref_l0 = %d error",i,sps_mvc_ext->non_ancher_refs[i].number_anchor_ref_l0);
+ goto fail;
+ }
+
+ sps_mvc_ext->non_ancher_refs[i].number_anchor_ref_l1 = get_ue_golomb_31(&s->gb);
+ if((sps_mvc_ext->non_ancher_refs[i].number_anchor_ref_l1 > 0) && (sps_mvc_ext->non_ancher_refs[i].number_anchor_ref_l1 <= 15))
+ {
+ sps_mvc_ext->non_ancher_refs[i].anchor_refs_l1 = av_mallocz(sizeof(int)*sps_mvc_ext->non_ancher_refs[i].number_anchor_ref_l1);
+ if(sps_mvc_ext->non_ancher_refs[i].anchor_refs_l1 == NULL)
+ {
+ av_log(h->s.avctx, AV_LOG_ERROR, "non_ancher_refs[%d].anchor_refs_l1 = NULL");
+ goto fail;
+ }
+
+ for(j = 0; j< sps_mvc_ext->non_ancher_refs[i].number_anchor_ref_l1; j++)
+ {
+ sps_mvc_ext->non_ancher_refs[i].anchor_refs_l1[j] = get_ue_golomb(&s->gb);
+ }
+ }
+ else if(sps_mvc_ext->non_ancher_refs[i].number_anchor_ref_l1 > 15)
+ {
+ av_log(h->s.avctx, AV_LOG_ERROR, "non_ancher_refs[%d].number_anchor_ref_l1 = %d error",i,sps_mvc_ext->non_ancher_refs[i].number_anchor_ref_l1);
+ goto fail;
+ }
+
+ }
+
+ sps_mvc_ext->num_level_value_signalled = get_ue_golomb(&s->gb) + 1;
+ av_log(h->s.avctx, AV_LOG, "num_level_value_signalled = %d",sps_mvc_ext->num_level_value_signalled);
+ sps_mvc_ext->applicable_op = av_mallocz(sizeof(SPS_EXT_APPLICABEL_OP)*sps_mvc_ext->num_level_value_signalled);
+ if(sps_mvc_ext->applicable_op == NULL)
+ {
+ av_log(h->s.avctx, AV_LOG_ERROR, "applicable_op = NULL");
+ goto fail;
+ }
+
+ for(i = 0; i < sps_mvc_ext->num_level_value_signalled; i++)
+ {
+ sps_mvc_ext->applicable_op[i].level_idc = get_bits(&s->gb, 8);
+ sps_mvc_ext->applicable_op[i].num_applicable_ops = get_ue_golomb(&s->gb) + 1;
+
+ av_log(h->s.avctx, AV_LOG, "level_idc[%d] = %d,num_applicable_ops[%d] = %d",//AV_LOG
+ i,sps_mvc_ext->applicable_op[i].level_idc,i,sps_mvc_ext->applicable_op[i].num_applicable_ops);
+
+ sps_mvc_ext->applicable_op[i].applicable_ops = av_mallocz(sizeof(SPS_EXT_APPLICABEL_OPS)*sps_mvc_ext->applicable_op[i].num_applicable_ops);
+ if(sps_mvc_ext->applicable_op[i].applicable_ops == NULL)
+ {
+ av_log(h->s.avctx, AV_LOG_ERROR, "applicable_op = NULL");
+ goto fail;
+ }
+
+ for(j = 0; j < sps_mvc_ext->applicable_op[i].num_applicable_ops ; j++)
+ {
+ sps_mvc_ext->applicable_op[i].applicable_ops[j].applicable_op_temporal_id = get_bits(&s->gb, 3);
+ sps_mvc_ext->applicable_op[i].applicable_ops[j].applicable_num_target_view = get_ue_golomb(&s->gb) + 1;
+
+ av_log(h->s.avctx, AV_LOG, "applicable_op_temporal_id[%d] = %d,applicable_num_target_view[%d] = %d",
+ j,sps_mvc_ext->applicable_op[i].applicable_ops[j].applicable_op_temporal_id,
+ j,sps_mvc_ext->applicable_op[i].applicable_ops[j].applicable_num_target_view);
+
+ sps_mvc_ext->applicable_op[i].applicable_ops[j].view =
+ av_mallocz(sizeof(SPS_EXT_APP_OP_TARGET_VIEW)*sps_mvc_ext->applicable_op[i].applicable_ops[j].applicable_num_target_view);
+
+ if(sps_mvc_ext->applicable_op[i].applicable_ops[j].view == NULL)
+ {
+ av_log(h->s.avctx, AV_LOG_ERROR, "applicable_op = NULL");
+ goto fail;
+ }
+
+ for(k = 0; k < sps_mvc_ext->applicable_op[i].applicable_ops[j].applicable_num_target_view; k++)
+ {
+ sps_mvc_ext->applicable_op[i].applicable_ops[j].view[k].applicable_op_target_view_id = get_ue_golomb(&s->gb);
+
+ av_log(h->s.avctx, AV_LOG, "applicable_num_target_view[%d] = %d",
+ k,sps_mvc_ext->applicable_op[i].applicable_ops[j].view[k].applicable_op_target_view_id);
+ }
+
+ sps_mvc_ext->applicable_op[i].applicable_ops[j].applicable_op_num_view = get_ue_golomb(&s->gb);
+ }
+ }
+
+ *mvc_ext = sps_mvc_ext;
+ return 0;
+
+fail:
+ release_seq_parameter_set_mvc_extension(sps_mvc_ext);
+ return -1;
+}
+
+static inline int decode_sps_ext_hrd_parameters(H264Context *h, HRD_PARAMETER *hrd)
+{
+ MpegEncContext * const s = &h->s;
+ int cpb_count, i;
+ if((hrd == NULL) || (h == NULL))
+ {
+ return -1;
+ }
+
+ cpb_count = get_ue_golomb_31(&s->gb) + 1;
+ if(cpb_count > 32U)
+ {
+ av_log(h->s.avctx, AV_LOG_ERROR, "decode_sps_ext_hrd_parameters():cpb_count %d invalid\n", cpb_count);
+ return -1;
+ }
+
+ hrd->cpb_count = cpb_count;
+ hrd->bit_rate_scale = get_bits(&s->gb, 4); /* bit_rate_scale */
+ hrd->cpb_size_scale = get_bits(&s->gb, 4); /* cpb_size_scale */
+
+ for(i=0; i<cpb_count; i++)
+ {
+ get_ue_golomb_long(&s->gb); /* bit_rate_value_minus1 */
+ get_ue_golomb_long(&s->gb); /* cpb_size_value_minus1 */
+ get_bits1(&s->gb); /* cbr_flag */
+ }
+
+ hrd->initial_cpb_removal_delay_length = get_bits(&s->gb, 5) + 1;
+ hrd->cpb_removal_delay_length = get_bits(&s->gb, 5) + 1;
+ hrd->dpb_output_delay_length = get_bits(&s->gb, 5) + 1;
+ hrd->time_offset_length = get_bits(&s->gb, 5);
+ return 0;
+}
+
+
+static void release_mvc_vui_parameter_extension(SPS_VUI_PARAMETER_EXT* vui_para_ext)
+{
+ int i = 0;
+ if(vui_para_ext != NULL)
+ {
+ for(i = 0; i < vui_para_ext->vui_mvc_num_ops; i++)
+ {
+ if(vui_para_ext->vui_mvc_ops[i].view != NULL)
+ {
+ av_free(vui_para_ext->vui_mvc_ops[i].view);
+ }
+
+ if(vui_para_ext->vui_mvc_ops[i].nal_hrd == NULL)
+ {
+ av_free(vui_para_ext->vui_mvc_ops[i].nal_hrd);
+ }
+
+ if(vui_para_ext->vui_mvc_ops[i].vcl_hrd == NULL)
+ {
+ av_free(vui_para_ext->vui_mvc_ops[i].vcl_hrd);
+ }
+ }
+
+ if(vui_para_ext->vui_mvc_ops != NULL)
+ {
+ av_free(vui_para_ext->vui_mvc_ops);
+ }
+
+ av_free(vui_para_ext);
+ }
+}
+
+
+static inline int decode_mvc_vui_parameter_extension(H264Context *h,SPS_VUI_PARAMETER_EXT** vui_para)
+{
+ MpegEncContext * const s = &h->s;
+ SPS *sps = &h->sps;
+ int i = 0, j = 0, k = 0;
+ SPS_VUI_MVC_OPS* mvc_ops = NULL;
+
+
+ SPS_VUI_PARAMETER_EXT* vui_para_ext = av_mallocz(sizeof(SPS_VUI_PARAMETER_EXT));
+ if(vui_para_ext == NULL)
+ {
+ goto fail;
+ }
+
+ vui_para_ext->vui_mvc_num_ops = get_ue_golomb(&s->gb) + 1;
+ av_log(h->s.avctx, AV_LOG, "decode_mvc_vui_parameter_extension():vui_mvc_num_ops = %d",vui_para_ext->vui_mvc_num_ops);
+
+ vui_para_ext->vui_mvc_ops = av_mallocz(sizeof(SPS_VUI_MVC_OPS)*vui_para_ext->vui_mvc_num_ops);
+ if(vui_para_ext->vui_mvc_ops == NULL)
+ {
+ av_log(h->s.avctx, AV_LOG_ERROR, "vui_para_ext->vui_mvc_ops = NULL");
+ goto fail;
+ }
+
+ for(i = 0; i < vui_para_ext->vui_mvc_num_ops; i++)
+ {
+ vui_para_ext->vui_mvc_ops[i].vui_mvc_temporal_id = get_bits(&s->gb,3);
+ vui_para_ext->vui_mvc_ops[i].vui_mvc_num_target_output_views = get_ue_golomb(&s->gb) + 1;
+
+ av_log(h->s.avctx, AV_LOG,
+ "decode_mvc_vui_parameter_extension():vui_mvc_temporal_id = %d,vui_mvc_num_target_output_views = %d",
+ vui_para_ext->vui_mvc_ops[i].vui_mvc_temporal_id,
+ vui_para_ext->vui_mvc_ops[i].vui_mvc_num_target_output_views);
+
+ vui_para_ext->vui_mvc_ops[i].view =
+ av_mallocz(sizeof(SPS_VUI_MVC_TARGET_OUTPUT_VIEW)*vui_para_ext->vui_mvc_ops[i].vui_mvc_num_target_output_views);
+ if(vui_para_ext->vui_mvc_ops[i].view == NULL)
+ {
+ av_log(h->s.avctx, AV_LOG_ERROR, "vui_para_ext->vui_mvc_ops[%d].view = NULL",i);
+ goto fail;
+ }
+
+ for(j = 0; j < vui_para_ext->vui_mvc_ops[i].vui_mvc_num_target_output_views; j++)
+ {
+ vui_para_ext->vui_mvc_ops[i].view[j].vui_mvc_view_id = get_ue_golomb(&s->gb);
+ av_log(h->s.avctx, AV_LOG,
+ "decode_mvc_vui_parameter_extension():vui_mvc_view_id[%d][%d] = %d",
+ i,j,
+ vui_para_ext->vui_mvc_ops[i].view[j].vui_mvc_view_id);
+ }
+
+ vui_para_ext->vui_mvc_ops[i].vui_mvc_timing_info_present_flag = get_bits(&s->gb,1);
+ if(vui_para_ext->vui_mvc_ops[i].vui_mvc_timing_info_present_flag)
+ {
+ vui_para_ext->vui_mvc_ops[i].vui_mvc_num_units_in_ticks = get_bits(&s->gb,32);
+ vui_para_ext->vui_mvc_ops[i].vui_mvc_time_scale = get_bits(&s->gb,32);
+ vui_para_ext->vui_mvc_ops[i].vui_mvc_fixed_frame_rate_flag = get_bits(&s->gb,1);
+ }
+
+ vui_para_ext->vui_mvc_ops[i].vui_mvc_nal_hrd_parameters_present_flag = get_bits(&s->gb,1);
+ if(vui_para_ext->vui_mvc_ops[i].vui_mvc_nal_hrd_parameters_present_flag)
+ {
+ vui_para_ext->vui_mvc_ops[i].nal_hrd = av_mallocz(sizeof(HRD_PARAMETER));
+ if(vui_para_ext->vui_mvc_ops[i].nal_hrd == NULL)
+ {
+ av_log(h->s.avctx, AV_LOG_ERROR, "vui_para_ext->vui_mvc_ops[%d].nal_hrd = NULL",i);
+ goto fail;
+ }
+ decode_sps_ext_hrd_parameters(h,vui_para_ext->vui_mvc_ops[i].nal_hrd);
+ }
+
+ vui_para_ext->vui_mvc_ops[i].vui_mvc_vcl_hrd_parameters_present_flag = get_bits(&s->gb,1);
+ if(vui_para_ext->vui_mvc_ops[i].vui_mvc_vcl_hrd_parameters_present_flag)
+ {
+ vui_para_ext->vui_mvc_ops[i].vcl_hrd = av_mallocz(sizeof(HRD_PARAMETER));
+ if(vui_para_ext->vui_mvc_ops[i].vcl_hrd == NULL)
+ {
+ av_log(h->s.avctx, AV_LOG_ERROR, "vui_para_ext->vui_mvc_ops[%d].vcl_hrd = NULL",i);
+ goto fail;
+ }
+ decode_sps_ext_hrd_parameters(h,vui_para_ext->vui_mvc_ops[i].vcl_hrd);
+ }
+
+ if(vui_para_ext->vui_mvc_ops[i].vui_mvc_nal_hrd_parameters_present_flag ||
+ vui_para_ext->vui_mvc_ops[i].vui_mvc_vcl_hrd_parameters_present_flag)
+ {
+ vui_para_ext->vui_mvc_ops[i].vui_mvc_low_delay_hrd_present_flag = get_bits(&s->gb,1);
+ }
+
+ vui_para_ext->vui_mvc_ops[i].vui_mvc_pic_struct_present_flag = get_bits(&s->gb,1);
+ }
+
+ *vui_para = vui_para_ext;
+ return 0;
+fail:
+ release_mvc_vui_parameter_extension(vui_para_ext);
+ return -1;
+}
+
+void release_subset_seq_parameter_set(SPS_EXT* ext)
+{
+ if(ext != NULL)
+ {
+ if(ext->sps_mvc_ext != NULL)
+ {
+ release_seq_parameter_set_mvc_extension(ext->sps_mvc_ext);
+ }
+
+ if(ext->vui_para_ext != NULL)
+ {
+ release_mvc_vui_parameter_extension(ext->vui_para_ext);
+ }
+
+ av_free(ext);
+ }
+}
+
+
+int ff_h264_decode_subset_seq_parameter_set(H264Context *h)
+{
+ MpegEncContext * const s = &h->s;
+ SPS *sps = &h->sps;
+ SPS_EXT* sps_ext = NULL;
+
+ // firset parse sps,if parse success, then parse sps extesntion
+ if(ff_h264_decode_seq_parameter_set(h) == 0)
+ {
+ // if(sps != NULL)
+ {
+ sps_ext = av_mallocz(sizeof(SPS_EXT));
+ if(sps_ext == NULL)
+ {
+ av_log(NULL, AV_LOG_ERROR, "ff_h264_decode_subset_seq_parameter_set():sps_ext == NULL");
+ goto fail;
+ }
+ av_log(h->s.avctx, AV_LOG, "ff_h264_decode_subset_seq_parameter_set(),sps->profile_idc = %d",sps->profile_idc);// AV_LOG
+ if((sps->profile_idc == 83) || (sps->profile_idc == 86))
+ {
+ av_log(NULL, AV_LOG_ERROR, "ff_h264_decode_subset_seq_parameter_set():profile_idc = %d not support",sps->profile_idc);
+ goto fail;
+ }
+ else if((sps->profile_idc == 118) || (sps->profile_idc == 128))
+ {
+ int bit_equal_to_one = get_bits(&s->gb, 1);
+ decode_seq_parameter_set_mvc_extension(h,&(sps_ext->sps_mvc_ext));
+
+ sps_ext->mvc_vui_parameter_present_flag = get_bits(&s->gb, 1);
+ if(sps_ext->mvc_vui_parameter_present_flag == 1)
+ {
+ decode_mvc_vui_parameter_extension(h,&(sps_ext->vui_para_ext));
+ }
+ }
+ else if(sps->profile_idc == 138)
+ {
+ av_log(NULL, AV_LOG_ERROR, "ff_h264_decode_subset_seq_parameter_set():profile_idc = %d not support",sps->profile_idc);
+ goto fail;
+ }
+
+ sps_ext->additional_extension2_flag = get_bits(&s->gb, 1);
+ if(sps_ext->additional_extension2_flag == 1)
+ {
+ // int bits_left = bit_length - get_bits_count(&s->gb);
+ // while(bit_length - get_bits_count(&s->gb))//(bits_left > 0 && more_rbsp_data_in_pps(h, pps))
+ while(get_bits_left(&s->gb))
+ {
+ int additinal_extension2_data_flag = get_bits(&s->gb, 1);
+ }
+ }
+
+ sps->sps_ext = sps_ext;
+ return 0;
+ }
+ }
+ else
+ {
+ av_log(h->s.avctx, AV_LOG_ERROR, "ff_h264_decode_subset_seq_parameter_set(): ff_h264_decode_seq_parameter_set fail");
+ }
+
+
+fail:
+ if(sps_ext != NULL)
+ {
+ release_subset_seq_parameter_set(sps_ext);
+ }
+ return -1;
+
+}
diff --git a/libavcodec/h264_refs.c b/libavcodec/h264_refs.c
index dbdd531..991e97c 100644..100755
--- a/libavcodec/h264_refs.c
+++ b/libavcodec/h264_refs.c
@@ -277,8 +277,16 @@ int ff_h264_decode_ref_pic_list_reordering(H264Context *h){
pic_as_field(&h->ref_list[list][index], pic_structure);
}
}
- }else{
- av_log(h->s.avctx, AV_LOG_ERROR, "illegal reordering_of_pic_nums_idc\n");
+ }
+ else if((reordering_of_pic_nums_idc == 4) || (reordering_of_pic_nums_idc == 5))
+ {
+ unsigned int abs_diff_view_idx = get_ue_golomb(&s->gb) + 1;
+ av_log(h->s.avctx, AV_LOG_ERROR,
+ "ff_h264_decode_ref_pic_list_reordering():reordering_of_pic_nums_idc = %d,abs_diff_view_idx = %d",reordering_of_pic_nums_idc,abs_diff_view_idx);
+ }
+ else
+ {
+ av_log(h->s.avctx, AV_LOG_ERROR, "illegal reordering_of_pic_nums_idc = %d\n",reordering_of_pic_nums_idc);
return -1;
}
}
diff --git a/libavcodec/h264_sei.c b/libavcodec/h264_sei.c
index 62320e2..7c358de 100644..100755
--- a/libavcodec/h264_sei.c
+++ b/libavcodec/h264_sei.c
@@ -177,7 +177,7 @@ static int decode_buffering_period(H264Context *h){
sps_id = get_ue_golomb_31(&s->gb);
if(sps_id > 31 || !h->sps_buffers[sps_id]) {
- av_log(h->s.avctx, AV_LOG_ERROR, "non-existing SPS %d referenced in buffering period\n", sps_id);
+// av_log(h->s.avctx, AV_LOG_ERROR, "non-existing SPS %d referenced in buffering period\n", sps_id);
return -1;
}
sps = h->sps_buffers[sps_id];
diff --git a/libavcodec/ig.c b/libavcodec/ig.c
new file mode 100755
index 0000000..98e1198
--- /dev/null
+++ b/libavcodec/ig.c
@@ -0,0 +1,987 @@
+#include "ig.h"
+
+#include "dsputil.h"
+#include "bytestream.h"
+#include "libavutil/colorspace.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/opt.h"
+
+#define RGBA(r,g,b,a) (((unsigned)(a) << 24) | ((r) << 16) | ((g) << 8) | (b))
+#define POSITIVE(x) ( x > 0 ? x : 0)
+
+#define YUV_TO_RGB0(y,cb,cr)\
+{\
+ r = POSITIVE(floor(1.164*y + 1.793*cr - 247.628));\
+ g = POSITIVE(floor(1.164*y -0.213*cb - 0.533*cr + 77.364));\
+ b = POSITIVE(floor(1.164*y +2.112*cb - 288.46));\
+}
+
+enum SegmentType {
+ PALETTE_SEGMENT = 0x14,
+ PICTURE_SEGMENT = 0x15,
+ ICS_SEGMENT = 0x18,
+ DISPLAY_SEGMENT = 0x80,
+};
+
+static void deleteIG(IG* ig)
+{
+ int i = 0;
+ int j = 0;
+ int k = 0;
+ if(ig != NULL)
+ {
+ if(ig->mPictures != NULL)
+ {
+ for (i=0;i < ig->mPicturesCount;i++)
+ {
+ if(ig->mPictures[i].rle != NULL)
+ {
+ av_freep(&ig->mPictures[i].rle);
+ }
+
+ if(ig->mPictures[i].picture != NULL)
+ {
+ av_freep(&ig->mPictures[i].picture);
+ }
+ }
+ av_freep(&ig->mPictures);
+ }
+
+ if(ig->mPalettes != NULL)
+ {
+ av_freep(&ig->mPalettes);
+ }
+
+ ig->mPicturesCount = 0;
+
+ if(ig->mICS != NULL)
+ {
+ ICS *ics = ig->mICS;
+ if(ics->mPages != NULL)
+ {
+ for (i=0;i<ics->mPages_count;i++)
+ {
+ IGSPage *page = &ics->mPages[i];
+ if(page != NULL)
+ {
+ for (j=0;j<page->bogs_count;j++)
+ {
+ IGSBOG *bog = &page->bogs[j];
+ if(bog != NULL)
+ {
+ for (k=0;k<bog->buttons_count;k++)
+ {
+ IGSButton *button = &bog->buttons[k];
+ if(button != NULL)
+ {
+ if (button->cmds != NULL)
+ {
+ av_freep(&button->cmds);
+ }
+ av_freep(&bog->buttons);
+ }
+ }
+ }
+ }
+
+ av_freep(&page->bogs);
+ }
+ EffectSequence* effect = page->mInEffectSequnce;
+ if(effect != NULL)
+ {
+ av_freep(&effect->mWindow);
+ av_freep(&effect->mEffect);
+ av_freep(&page->mInEffectSequnce);
+ }
+ effect = page->mOutEffectSequnce;
+ if(effect != NULL)
+ {
+ av_freep(&effect->mWindow);
+ av_freep(&effect->mEffect);
+ av_freep(&page->mOutEffectSequnce);
+ }
+ }
+ av_freep(&ics->mPages);
+ }
+ av_freep(&ig->mICS);
+ }
+ }
+}
+
+
+static av_cold int init_decoder(AVCodecContext *avctx)
+{
+ avctx->pix_fmt = AV_PIX_FMT_PAL8;
+ IGContext* context = (IGContext*)avctx->priv_data;
+ int i = 0;
+ if(context != NULL)
+ {
+ context->mIg = NULL;
+ context->mICSBuffer = NULL;
+ context->mICSDataSize = 0;
+ context->mICSDataTotalSize = 0;
+ }
+ av_log(NULL, AV_LOG_ERROR,"Bluray IG:init_decoder()");
+ return 0;
+}
+
+static av_cold int close_decoder(AVCodecContext *avctx)
+{
+ int i,j,k;
+ av_log(NULL, AV_LOG_ERROR,"Bluray IG:close_decoder()");
+
+ IGContext* context = (IGContext*)avctx->priv_data;
+ if(context != NULL)
+ {
+ if(context->mICSBuffer != NULL)
+ {
+ av_freep(&context->mICSBuffer);
+ }
+ context->mICSDataSize = 0;
+ context->mICSDataTotalSize = 0;
+
+ if(context->mIg != NULL)
+ {
+ av_log(NULL, AV_LOG_ERROR,"close_decoder(),free IG");
+ deleteIG(context->mIg);
+ av_freep(&context->mIg);
+ }
+
+ av_freep(&avctx->priv_data);
+ }
+
+ return 0;
+}
+
+
+static void initIG(IG* ig)
+{
+ if(ig != NULL)
+ {
+ ig->mPicturesCount = 0;
+ ig->mPalettesCount = 0;
+ ig->mICS = NULL;
+ ig->mPalettes = NULL;
+ ig->mPictures = NULL;
+ }
+}
+
+
+static void initPage(IGSPage* page)
+{
+ if(page != NULL)
+ {
+ page->def_button = -1;
+ page->sel_button = -1;
+ page->in_time = 0;
+ page->timeout = 0;
+ page->palette = 0;
+
+ page->bogs = NULL;
+ page->bogs_count = 0;
+
+ page->id = 0;
+
+ page->mInEffectSequnce = NULL;
+ page->mOutEffectSequnce = NULL;
+ }
+}
+
+static void initBog(IGSBOG* bog)
+{
+ if(bog != NULL)
+ {
+ bog->buttons = NULL;
+ bog->buttons_count = 0;
+ bog->cur_button = -1;
+ bog->def_button = -1;
+ }
+}
+
+static void initButton(IGSButton* button)
+{
+ if(button != NULL)
+ {
+ button->x = 0;
+ button->y = 0;
+ button->cmds = NULL;
+ button->cmds_count = 0;
+ button->autoAction = 0;
+ button->pRepeat[0] = 0;
+ button->pRepeat[1] = 0;
+ button->pRepeat[2] = 0;
+ button->mAnimtaionId = 0;
+ button->mSelectedSoundId = 0xff;
+ button->mActiveSoundId = 0xff;
+ }
+}
+
+static int displayWindow(AVCodecContext *avctx,char** p,EffectSequence *effectSequence)
+{
+ if(p == NULL)
+ return -1;
+
+ unsigned char windowId = bytestream_get_byte(&(*p));
+ unsigned short windowX = bytestream_get_be16(&(*p));
+ unsigned short windowY = bytestream_get_be16(&(*p));
+ unsigned short windowWidth = bytestream_get_be16(&(*p));
+ unsigned short windowHeight = bytestream_get_be16(&(*p));
+
+
+// av_log(avctx, AV_LOG_ERROR, "display_window():id:%d, x:%d, y:%d, width:%d, height:%d\n",windowId,windowX,windowY,windowWidth,windowHeight);
+#if 0
+ if(effectSequence != NULL)
+ {
+ effectSequence->mWindow
+ }
+#endif
+ return 0;
+}
+
+static int displayCompositionObject(AVCodecContext *avctx,char** p)
+{
+ if(p == NULL)
+ return -1;
+
+ unsigned short objId = bytestream_get_be16(&(*p));
+ unsigned char window = bytestream_get_byte(&(*p));
+ unsigned char force = bytestream_get_byte(&(*p));
+ unsigned char x = bytestream_get_be16(&(*p));
+ unsigned char y = bytestream_get_be16(&(*p));
+// LOGD("display_composition_object():obj_id:%d, window:%d, force:%s, pos(%d,%d)", p[0]<<8|p[1], p[2], ((p[3]&0x40)?"yes":"no"), p[4]<<8|p[5], p[6]<<8|p[7]);
+ if (force&0x80) //cropping?
+ {
+// LOGD("display_composition_object():crop{h_pos:%d,v_pos:%d,w:%d,h:%d}", p[8]<<8|p[9], p[10]<<8|p[11], p[12]<<8|p[13], p[14]<<8|p[15]);
+ unsigned short cropX = bytestream_get_be16(&(*p));
+ unsigned short cropY = bytestream_get_be16(&(*p));
+ unsigned short cropWidth = bytestream_get_be16(&(*p));
+ unsigned short cropHeight = bytestream_get_be16(&(*p));
+ }
+
+ return 0;
+}
+
+
+static int displayEffect(AVCodecContext *avctx,char** p)
+{
+ if(p == NULL)
+ return -1;
+
+ int effectDuration = bytestream_get_be24(&(*p));
+ unsigned char paletteRefId = bytestream_get_byte(&(*p));
+ int obj_num = bytestream_get_byte(&(*p));
+
+// LOGD("display_composition_object():effect_duration:%d, palette_id:%d,number_of_composition_obj:%d\n", p[0]<<16|p[1]<<8|p[2], p[3], obj_num);
+
+// av_log(avctx, AV_LOG_ERROR, "displayEffect(), obj_num = %d",obj_num);
+ if (obj_num > MAX_EFFECT_OBJECT_NUM)
+ {
+ av_log(avctx, AV_LOG_ERROR, "displayEffect(), obj_num = %d,error",obj_num);
+// return -1;
+ }
+ for (int i = 0; i < obj_num; ++i)
+ {
+ displayCompositionObject(avctx,p);
+ }
+
+ return 0;
+}
+
+
+static int displayEffectSequence(AVCodecContext *avctx,char** p,EffectSequence *effectSequence)
+{
+ if(p == NULL)
+ return -1;
+
+ if(effectSequence != NULL)
+ {
+ effectSequence->mWindow = NULL;
+ effectSequence->mEffect = NULL;
+ }
+
+ int win_num = bytestream_get_byte(&(*p));
+// av_log(avctx, AV_LOG_ERROR, "displayEffectSequence(), window Number =%d",win_num);
+ if(effectSequence != NULL)
+ {
+ effectSequence->mNumberWidow = win_num;
+ }
+
+ if(win_num > MAX_WINDOW_NUM)
+ {
+ av_log(avctx, AV_LOG_ERROR, "displayEffectSequence(), window Number =%d,error",win_num);
+// return -1;
+ }
+
+// LOGD("displayEffectSequence(), win_num = %d",win_num);
+ for (int i = 0; i < win_num; ++i)
+ {
+ if(displayWindow(avctx,p,effectSequence) != 0)
+ {
+ // return -1;
+ }
+ }
+
+ int effect_num = bytestream_get_byte(&(*p));
+// av_log(avctx, AV_LOG_ERROR, "displayEffectSequence(), effect_num =%d",effect_num);
+ if(effect_num > MAX_EFFECT_NUM)
+ {
+ av_log(avctx, AV_LOG_ERROR, "displayEffectSequence(), effect Number =%d,error",effect_num);
+// return -1;
+ }
+
+ for (int i = 0; i < effect_num; ++i)
+ {
+ displayEffect(avctx,p);
+ // if(displayEffect(p) != 0)
+ // return -1;
+ }
+
+ return 0;
+}
+
+
+
+/**
+ * Parse the picture segment packet.
+ *
+ * The picture segment contains details on the sequence id,
+ * width, height and Run Length Encoded (RLE) bitmap data.
+ *
+ * @param avctx contains the current codec context
+ * @param buf pointer to the packet to process
+ * @param buf_size size of packet to process
+ * @todo TODO: Enable support for RLE data over multiple packets
+ */
+ static int parsePictureSegment(AVCodecContext *avctx,
+ const uint8_t *buf, int buf_size)
+{
+ IGContext * ctx = avctx->priv_data;
+ if((ctx == NULL) || (ctx->mIg == NULL))
+ {
+ av_log(avctx, AV_LOG_ERROR, "parsePictureSegment(), IGContext == NULL");
+ return NULL;
+ }
+
+ IG* ig = ctx->mIg;
+ IGSPicture *pic = NULL;
+ uint16_t oid;
+ uint8_t version,sequence_desc;
+ unsigned int rle_bitmap_len, width, height;
+
+ if (buf_size <= 4)
+ return -1;
+
+ /* skip 3 unknown bytes: Object ID (2 bytes), Version Number */
+ oid = bytestream_get_be16(&buf);
+ buf_size -= 2;
+
+ //version,just skip
+ version = bytestream_get_byte(&buf);
+ buf_size -= 1;
+
+ /* Read the Sequence Description to determine if start of RLE data or appended to previous RLE */
+ sequence_desc = bytestream_get_byte(&buf);
+ buf_size -= 1;
+ uint8_t firstSequence = (sequence_desc & 0x80) >> 7;
+ uint8_t lastSequence = (sequence_desc & 0x40) >> 6;
+
+ // av_log(avctx, AV_LOG_ERROR, "parsePictureSegment(): firstSequence = %d,lastSequence = %d",firstSequence,lastSequence);
+ if(firstSequence == 1)
+ {
+ if (buf_size <= 7)
+ return -1;
+
+ /* Decode rle bitmap length, stored size includes width/height data */
+ rle_bitmap_len = bytestream_get_be24(&buf) - 2*2;
+ buf_size -= 3;
+
+ /* Get bitmap dimensions from data */
+ width = bytestream_get_be16(&buf);
+ buf_size -= 2;
+ height = bytestream_get_be16(&buf);
+ buf_size -= 2;
+
+ /* Make sure the bitmap is not too large */
+ if(width > 1920 || height > 1080)
+ {
+ av_log(avctx, AV_LOG_ERROR, "Bitmap dimensions (%dx%d) larger than video.\n", width, height);
+ return -1;
+ }
+
+ /* add this picture */
+// av_log(avctx, AV_LOG_ERROR, "parsePictureSegment() mPicturesCount = %d",ig->mPicturesCount);
+ ig->mPicturesCount++;
+ pic = av_realloc(ig->mPictures, ig->mPicturesCount * sizeof(IGSPicture));
+ if (pic == NULL) {
+ av_log(avctx, AV_LOG_ERROR, "Can't reallocate bitmaps table.\n");
+ ig->mPicturesCount--;
+ return -2;
+ }
+ ig->mPictures = pic;
+ pic = &(ig->mPictures[ig->mPicturesCount-1]);
+
+ pic->id = oid;
+ pic->w = width;
+ pic->h = height;
+ pic->picture = NULL;
+// av_log(avctx, AV_LOG_ERROR, "parsePictureSegment() id = %d,width = %d,height = %d",pic->id,width,height);
+ pic->rle = av_malloc(rle_bitmap_len);
+ if (pic->rle == NULL)
+ {
+ av_log(avctx, AV_LOG_ERROR, "Can't malloc rle space, id = %d,width = %d,height = %d",pic->id,pic->w,pic->h);
+ return -1;
+ }
+
+ memset(pic->rle,0,rle_bitmap_len);
+ pic->rle_buffer_size=rle_bitmap_len;
+
+ if (buf_size>pic->rle_buffer_size)
+ buf_size=pic->rle_buffer_size;
+
+ memcpy(pic->rle, buf, buf_size);
+ pic->rle_data_len = buf_size;
+ pic->rle_remaining_len = rle_bitmap_len - buf_size;
+ }
+ else
+ {
+ /* Additional RLE data to picture */
+ /* first find the picture accord the id */
+ for(int position = ig->mPicturesCount-1; position >= 0; position --)
+ {
+ pic = &ig->mPictures[position];
+ if((pic != NULL) && (pic->id == oid))
+ {
+ if (buf_size > pic->rle_remaining_len)
+ {
+ av_log(avctx, AV_LOG_ERROR, "parsePictureSegment(): too much data in Pictures[%d], error",position);
+ return -1;
+ }
+ if(pic->rle != NULL)
+ {
+ memcpy(pic->rle + pic->rle_data_len, buf, buf_size);
+ pic->rle_data_len += buf_size;
+ pic->rle_remaining_len -= buf_size;
+ }
+
+ return 0;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/**
+* Parse the palette segment packet.
+*
+* The palette segment contains details of the palette,
+* a maximum of 256 colors can be defined.
+*
+* @param avctx contains the current codec context
+* @param buf pointer to the packet to process
+* @param buf_size size of packet to process
+*/
+static int parsePaletteSegment(AVCodecContext *avctx,const uint8_t *buf, int buf_size)
+{
+ IGContext *ctx = avctx->priv_data;
+ if((ctx == NULL) || (ctx->mIg == NULL))
+ {
+ av_log(avctx, AV_LOG_ERROR, "parsePaletteSegment(): IGContext == NULL");
+ return -1;
+ }
+
+ IG* ig = ctx->mIg;
+
+ const uint8_t *buf_end = buf + buf_size;
+ const uint8_t *cm = ff_cropTbl + MAX_NEG_CROP;
+ int color_id;
+ int y, cb, cr, alpha;
+ int r, g, b, r_add, g_add, b_add;
+
+ /* add this picture */
+ ig->mPalettesCount++;
+ IGSPalette * pal = av_realloc(ig->mPalettes, ig->mPalettesCount * sizeof(IGSPalette));
+ if (pal == NULL) {
+ av_log(avctx, AV_LOG_ERROR, "parsePaletteSegment():Can't reallocate palettes table.\n");
+ ig->mPalettesCount--;
+ return -1;
+ }
+
+ ig->mPalettes = pal;
+ pal = &(ig->mPalettes[ig->mPalettesCount-1]);
+ memset(&pal->clut,0,sizeof(pal->clut));
+
+// av_log(avctx, AV_LOG_ERROR, "parsePaletteSegment(): mPalettesCount = %d,mPalettes = 0x%x",ig->mPalettesCount,ig->mPalettes);
+ /* Skip two null bytes */
+ pal->id = bytestream_get_byte(&buf);
+ int version = bytestream_get_byte(&buf);
+
+/* av_log(avctx, AV_LOG_ERROR, "New palette %04X @ %p: idx=%d, size=%d, %d colors.\n",
+ oid, pal, ctx->mPalettesCount-1, buf_size-2, (buf_size-2)/5);*/
+ while (buf < buf_end) {
+ color_id = bytestream_get_byte(&buf);
+ y = bytestream_get_byte(&buf);
+ cr = bytestream_get_byte(&buf);
+ cb = bytestream_get_byte(&buf);
+ alpha = bytestream_get_byte(&buf);
+
+ YUV_TO_RGB0(y, cb, cr);
+
+ if(r > 255) r = 255;
+ if(g > 255) g = 255;
+ if(b > 255) b = 255;
+
+ // av_log(avctx, AV_LOG_DEBUG, " Color %d := (%d,%d,%d,%d)\n", color_id, r, g, b, alpha);
+
+ double temp = ((double)alpha)/255;
+ r *= temp;
+ g *= temp;
+ b *= temp;
+ alpha *= temp;
+
+ /* Store color in palette */
+ pal->clut[color_id] = RGBA(r,g,b,alpha);
+ }
+ return 0;
+}
+
+static void freeBuffer(AVCodecContext *avctx)
+{
+ if(avctx != NULL)
+ {
+ IGContext* cxt = (IGContext*)avctx->priv_data;
+ if(cxt != NULL)
+ {
+ if(cxt->mICSBuffer != NULL)
+ {
+ av_log(avctx, AV_LOG_ERROR, "freeBuffer()");
+ av_freep(&cxt->mICSBuffer);
+ }
+
+ cxt->mICSDataSize = 0;
+ cxt->mICSDataTotalSize = 0;
+ }
+ }
+}
+
+/**
+ * Parse the button segment packet.
+ *
+ * The button segment contains details on the interactive graphics.
+ *
+ * @param avctx contains the current codec context
+ * @param buf pointer to the packet to process
+ * @param buf_size size of packet to process
+ * @todo TODO: Implement cropping
+ */
+static int parseICS(AVCodecContext *avctx,const uint8_t *buf, int buf_size)
+{
+ IGContext *ctx = avctx->priv_data;
+ const uint8_t *start = buf;
+ uint8_t* endBuffer = buf+buf_size;
+ int i, page_cnt;
+ uint32_t to;
+
+ if(ctx->mIg == NULL)
+ {
+ av_log(avctx, AV_LOG_ERROR, "parseICS():Can't malloc mICS \n");
+ return -1;
+ }
+
+ if(ctx->mIg->mICS == NULL)
+ {
+ ctx->mIg->mICS = av_malloc(sizeof(ICS));
+ if(ctx->mIg->mICS == NULL)
+ {
+ av_log(avctx, AV_LOG_ERROR, "parseICS():Can't malloc mICS \n");
+ return -1;
+ }
+ }
+
+ ICS* ic = ctx->mIg->mICS;
+ ic->mWidth = bytestream_get_be16(&buf);
+ ic->mHeight = bytestream_get_be16(&buf);
+
+// av_log(avctx, AV_LOG_ERROR, "Interactive Graphics dimensions %dx%d\n", ic->mWidth, ic->mHeight);
+// if (av_image_check_size(ic->mWidth, ic->mHeight, 0, avctx) >= 0)
+// avcodec_set_dimensions(avctx, ic->mWidth, ic->mHeight);
+
+ // skip framerate (0x20 => 2 => 24fps, 0x60 => 50fps)
+ ic->mFrameRate = ((bytestream_get_byte(&buf)& 0xF0) >> 4);
+ buf += 2; // composition_number (0x0000) 8.9
+ buf += 1; // composition state (0x80) 10
+// av_log(avctx, AV_LOG_ERROR, "ic->mFrameRate = %d",ic->mFrameRate);
+ unsigned char sequence = bytestream_get_byte(&buf);//sequence descriptor 11
+ unsigned char first = (sequence & 0x80)>>7; // start flag
+ unsigned char last = (sequence & 0x40)>>6; // end flag
+// av_log(avctx, AV_LOG_ERROR, "sequence = %d,first = %d,last = %d",sequence,first,last);
+ uint8_t* data = NULL;
+ // first squence
+ if(first == 1)
+ {
+ int ics_len = buf[0]<<16|buf[1]<<8|buf[2];//load the composition length 12,13,14
+ buf += 3;
+
+ // end flag
+ if(last == 1)
+ {
+ data = buf;
+ }
+ else
+ {
+ // mallo space to store this data
+ // freeBuffer(avctx);
+ if(ctx->mICSBuffer != NULL)
+ {
+ av_freep(&ctx->mICSBuffer);
+ }
+ ctx->mICSDataSize = 0;
+ ctx->mICSDataTotalSize = ics_len;
+ ctx->mICSBuffer = av_malloc(ics_len);
+ if(ctx->mICSBuffer == NULL)
+ {
+ av_log(avctx, AV_LOG_DEBUG, "parseICS(), malloc mICSTempBuffer fail");
+ return -1;
+ }
+
+ memcpy(&ctx->mICSBuffer[ctx->mICSDataSize],buf,endBuffer- buf);
+ ctx->mICSDataSize += endBuffer - buf;
+ return 0;
+ }
+ }
+ else
+ {
+ int size = endBuffer- buf;
+ if((size + ctx->mICSDataSize) <= ctx->mICSDataTotalSize)
+ {
+ if(ctx->mICSBuffer != NULL)
+ {
+ memcpy(&ctx->mICSBuffer[ctx->mICSDataSize],buf,size);
+ ctx->mICSDataSize += size;
+ }
+ else
+ {
+ av_log(avctx, AV_LOG_ERROR, "parseICS(), mICSTempBuffer = NULL");
+ return -1;
+ }
+ }
+ else
+ {
+ av_log(avctx, AV_LOG_ERROR, "parseICS(), wrong length");
+ freeBuffer(avctx);
+ return -1;
+ }
+
+ // if it's not the last package,then return ,else parse
+ if(last == 0)
+ {
+ return 0;
+ }
+
+ data = ctx->mICSBuffer;
+ }
+
+ if(data == NULL)
+ {
+ freeBuffer(avctx);
+ return -1;
+ }
+
+ // ten more byte skipped (output generated by TMpegEnc Authoring 5)
+ ic->mUiMode = bytestream_get_byte(&data);
+ if((ic->mUiMode&0x80) == 0) /* load the UI and stream model */
+ {
+ /*get the upper 32 bits of the 33 here 45khz granularity */
+ ic->compositionTimeoutPTS = (bytestream_get_byte(&data) & 0x01) << 31;
+ ic->compositionTimeoutPTS |= bytestream_get_be32(&data) >> 1;
+
+ ic->selectionTimeoutPTS = (bytestream_get_byte(&data) & 0x01) << 31;
+ ic->selectionTimeoutPTS |= bytestream_get_be32(&data) >> 1;
+
+ int time = ic->selectionTimeoutPTS/45000;
+
+ av_log(avctx, AV_LOG_ERROR,"parseICS(): selectionTimeoutPTS = %lld,time = %d",ic->selectionTimeoutPTS,time);
+ }
+
+// buf+=4; // skip IN_time (0xc0000163)
+ ic->userTimeout = bytestream_get_be24(&data);/* load user timeout duration */
+ ic->mPages_count = bytestream_get_byte(&data);
+ ic->mPages = av_malloc(ic->mPages_count*sizeof(IGSPage));
+// av_log(avctx, AV_LOG_ERROR, "parseICS(), mPages_count = %d",ic->mPages_count);
+ if(ic->mPages == NULL)
+ {
+ av_log(avctx, AV_LOG_ERROR, "parseICS(): malloc Pages fail");
+ freeBuffer(avctx);
+ return -1;
+ }
+
+ /* pages loop */
+ for (i=0;i<ic->mPages_count;i++)
+ {
+ IGSPage *page = &(ic->mPages[i]);
+ int j, bog_cnt;
+
+ initPage(page);
+ /* skip page_id */
+ page->id = bytestream_get_byte(&data);
+// av_log(avctx, AV_LOG_ERROR, "parseICS(), page->id = %d",page->id);
+ /* skip version */
+ int version = bytestream_get_byte(&data);
+
+ /* skip UO MASK Table*/
+ data += 8;
+
+ // in effect
+ page->mInEffectSequnce = av_malloc(sizeof(EffectSequence));
+ displayEffectSequence(avctx,&data,page->mInEffectSequnce);
+
+ // out effect
+ page->mOutEffectSequnce = av_malloc(sizeof(EffectSequence));
+ displayEffectSequence(avctx,&data,page->mOutEffectSequnce);
+
+/* if(displayEffectSequence(buf) != 0) // in effect
+ {
+ LOGD("parseICS():displayEffectSequence error");
+ return -1;
+ }
+ if(displayEffectSequence(buf) != 0) // out effect
+ {
+ LOGD("parseICS():displayEffectSequence error");
+ return -1;
+ }*/
+
+ page->frameRate = bytestream_get_byte(&data);/* framerate */
+ // av_log(avctx, AV_LOG_ERROR, "parseICS(),page->frameRate = %d",page->frameRate);
+ page->def_button = bytestream_get_be16(&data);// default select button
+ page->sel_button = page->def_button;
+
+ int act_btn = bytestream_get_be16(&data);/* default activated button*/
+ page->palette = bytestream_get_byte(&data); // palette id
+
+ bog_cnt = bytestream_get_byte(&data);
+
+ // av_log(avctx, AV_LOG_ERROR, "parseICS(): BOG count = %d,default selected button id = %d,default active button id = %d",bog_cnt,page->def_button, act_btn);
+
+ page->bogs = av_malloc(bog_cnt*sizeof(IGSBOG));//new IGSBOG[bog_cnt];
+ if (page->bogs != NULL)
+ {
+ page->bogs_count = bog_cnt;
+ }
+ else
+ {
+ av_log(avctx, AV_LOG_ERROR, "parseICS(): malloc bogs fail");
+ break;
+ }
+
+ /* bogs loop */
+// av_log(avctx, AV_LOG_ERROR, "parseICS(): page->bogs_count = %d",page->bogs_count);
+ for (j=0;j<page->bogs_count;j++)
+ {
+ IGSBOG *bog = &(page->bogs[j]);
+
+ int k, button_cnt;
+
+ initBog(bog);
+ bog->def_button = bytestream_get_be16(&data); //default valid button id
+ bog->cur_button = bog->def_button;
+// av_log(avctx, AV_LOG_ERROR, "parseICS():BOG id = %d",j);
+ button_cnt = bytestream_get_byte(&data); // button count
+
+// av_log(avctx, AV_LOG_ERROR, "parseICS():BOG id = %d, button_cnt = %d,bog->def_button = %d",j,button_cnt,bog->def_button);
+
+ bog->buttons = av_malloc(button_cnt*sizeof(IGSButton));//new IGSButton[button_cnt];
+ if (bog->buttons != NULL)
+ {
+ bog->buttons_count = button_cnt;
+ }
+ else
+ {
+ bog->buttons_count = 0;
+ av_log(avctx, AV_LOG_ERROR, "parseICS(): malloc IGSButton fail");
+ break;
+ }
+
+ /* buttons loop */
+ for (k=0;k<bog->buttons_count;k++)
+ {
+ IGSButton *but = &(bog->buttons[k]);
+
+ initButton(but);
+
+ but->id = bytestream_get_be16(&data);
+ but->numericValue = bytestream_get_be16(&data); //Numeric Select Value
+ but->autoAction = (bytestream_get_byte(&data) & 0x80) >> 7; //auto action flag
+ but->x = bytestream_get_be16(&data);
+ but->y = bytestream_get_be16(&data);
+ // neighbor info
+ but->n[0] = bytestream_get_be16(&data); // up button
+ but->n[1] = bytestream_get_be16(&data); // low button
+ but->n[2] = bytestream_get_be16(&data); // left button
+ but->n[3] = bytestream_get_be16(&data); // right button
+// av_log(avctx, AV_LOG_ERROR, "parseICS(): but->id = %d",but->id);
+// av_log(avctx, AV_LOG_ERROR,"parseICS(): button->id = %d : x=%d, y=%d,auto = %d", but->id, but->x, but->y,but->autoAction);
+// av_log(avctx, AV_LOG_ERROR,"up = %d low = %d, left = %d, right = %d", but->n[0], but->n[1], but->n[2], but->n[3]);
+ // normal state info (animation)
+ but->pstart[0] = bytestream_get_be16(&data); // normal start object Id
+ but->pstop[0] = bytestream_get_be16(&data); // normal stop object Id
+ but->pRepeat[0] = ((bytestream_get_byte(&data) & 0x80)>>7);// repeat flag
+
+ // select state info (animation)
+ but->mSelectedSoundId = bytestream_get_byte(&data);// selected sound id
+ but->pstart[1] = bytestream_get_be16(&data);
+ but->pstop[1] = bytestream_get_be16(&data);
+ but->pRepeat[1] = ((bytestream_get_byte(&data) & 0x80)>>7);// repeat flag
+
+ // activie
+ but->mActiveSoundId = bytestream_get_byte(&data);// sound
+ but->pstart[2] = bytestream_get_be16(&data);
+ but->pstop[2] = bytestream_get_be16(&data);
+ but->cmds_count = bytestream_get_be16(&data);
+
+// av_log(avctx, AV_LOG_ERROR,"parseICS(): id = %d,start normal = %d,select = %d,activie = %d,",but->id,but->pstart[0],but->pstart[1],but->pstart[2]);
+// av_log(avctx, AV_LOG_ERROR,"parseICS(): id = %d,stop normal = %d,select = %d,activie = %d,",but->id,but->pstop[0],but->pstop[1],but->pstop[2]);
+
+ but->cmds = NULL;
+ if (but->cmds_count)
+ {
+ but->cmds = av_malloc(but->cmds_count*sizeof(IGCommand));//new NavigationCommand[but->cmds_count];
+// av_log(avctx, AV_LOG_ERROR, "parseICS(): but->id = %d,cmds_count = %d",but->id,but->cmds_count);
+ if(but->cmds != NULL)
+ {
+ for(int cmdCount = 0; cmdCount < but->cmds_count; cmdCount++)
+ {
+ but->cmds[cmdCount].mOpCode = bytestream_get_be32(&data);
+ but->cmds[cmdCount].mDstOperand = bytestream_get_be32(&data);
+ but->cmds[cmdCount].mSrcOperand = bytestream_get_be32(&data);
+ }
+ }
+ else
+ {
+ av_log(avctx, AV_LOG_ERROR, "parseICS(): malloc but->cmds fail");
+ }
+ }
+
+ /* load extra flags */
+ but->mState = BUTTON_DISABLED;
+
+ // LOGD("pics=%04X/%04X/%04X, cmds=%d\n", but->pstart[0], but->pstart[1], but->pstart[2], but->cmds_count);
+
+ but->mAnimtaionId = but->pstart[0];
+
+ // set this button current if not already set
+ if (bog->cur_button == 0xffff) bog->cur_button = but->id;
+ }
+
+ }
+
+ // set selected button if not already set
+ if (page->sel_button == 0xffff) {
+ for (j=0;j<page->bogs_count;j++) {
+ IGSBOG *bog = &(page->bogs[j]);
+ int k;
+ for (k=0;k<bog->buttons_count;k++) {
+ IGSButton *but = &(bog->buttons[k]);
+ // search first button with nav to other button
+ if (but->n[0] != but->id ||
+ but->n[1] != but->id ||
+ but->n[2] != but->id ||
+ but->n[3] != but->id) {
+ page->sel_button = but->id;
+ break;
+ }
+ }
+ if (page->sel_button != 0xffff) break;
+ }
+ }
+ }
+
+ freeBuffer(avctx);
+ return 0;
+}
+
+
+
+static int decode(AVCodecContext *avctx, uint8_t *data, int *data_size,
+ AVPacket *avpkt)
+{
+ IG *ctx = avctx->priv_data;
+ const uint8_t *buf = avpkt->data;
+ int buf_size = avpkt->size;
+ AVSubtitle *sub = data;
+
+ const uint8_t *buf_end;
+ uint8_t segment_type;
+ int segment_length;
+ int i;
+
+ // av_log(avctx, AV_LOG_ERROR, "blu-ray decode IGS packet");
+
+ *data_size = 0;
+
+ /* Ensure that we have received at a least a segment code and segment length */
+ if (buf_size < 3)
+ return -1;
+
+ buf_end = buf + buf_size;
+
+ /* Step through buffer to identify segments */
+ while (buf < buf_end) {
+ segment_type = bytestream_get_byte(&buf);
+ segment_length = bytestream_get_be16(&buf);
+
+// av_dlog(avctx, "Segment Length %d, Segment Type %x\n", segment_length, segment_type);
+
+ switch (segment_type) {
+ case PALETTE_SEGMENT:
+ parsePaletteSegment(avctx, buf, segment_length);
+ break;
+
+ case PICTURE_SEGMENT: // Bitmap image data compressed with an RLE compression schema
+ parsePictureSegment(avctx,buf, segment_length);
+ break;
+
+ case ICS_SEGMENT:
+ parseICS(avctx,buf,segment_length);
+ break;
+
+ case DISPLAY_SEGMENT:
+ break;
+
+ default:
+ av_log(avctx, AV_LOG_ERROR, "Unknown IGS segment type 0x%x, length %d\n",
+ segment_type, segment_length);
+ break;
+ }
+
+ buf += segment_length;
+ }
+
+ return buf_size;
+}
+
+
+
+static const AVOption options[] = {
+ { NULL },
+};
+
+static const AVClass ig_class = {
+ .class_name = "IG decoder",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_blurayig_decoder = {
+ .name = "BlurayIG",
+ .type = AVMEDIA_TYPE_SUBTITLE,
+ .id = AV_CODEC_ID_BLURAY_IG,
+ .priv_data_size = sizeof(IGContext),
+ .init = init_decoder,
+ .close = close_decoder,
+ .decode = decode,
+ .long_name = NULL_IF_CONFIG_SMALL("blu-ray ig decoder"),
+ .priv_class = &ig_class,
+};
+
+
diff --git a/libavcodec/ig.h b/libavcodec/ig.h
new file mode 100755
index 0000000..16a35dc
--- /dev/null
+++ b/libavcodec/ig.h
@@ -0,0 +1,191 @@
+#ifndef AVCODEC_BLURAY_IG_H
+#define AVCODEC_BLURAY_IG_H
+
+/*
+ * Blu-ray IG decoder
+ * Copyright (c) 2014 Fuzhou Rockchip Electronics Co., Ltd
+ * hh@rock-chips.com
+ */
+
+
+#define MAX_WINDOW_NUM 2
+#define MAX_EFFECT_NUM 128
+#define MAX_EFFECT_OBJECT_NUM 2
+
+
+#define NUMBER 256
+#define PICTURENUMBER (4096)
+
+typedef struct CompositionObject
+{
+ int mObjectRefId;
+ int mWindowRefId;
+ int mForcedOnFlag;
+
+ int x;
+ int y;
+
+ int mCropFlag;
+ int mCropX;
+ int mCropY;
+ int mCropWidth;
+ int mCropHeight;
+}CompositionObject ;
+
+
+typedef struct Effect
+{
+ unsigned int mDuration; /* 90kHz ticks */
+ int mPaletteRefId;
+
+ unsigned int mNumberCompositionObj;
+ CompositionObject *mCompositionObject;
+}Effect ;
+
+
+typedef struct Window
+{
+ int mId;
+ int x;
+ int y;
+ int mWidth;
+ int mHeight;
+}Window;
+
+typedef struct EffectSequence
+{
+ int mNumberWidow;
+ int mNumberEffect;
+
+ Window *mWindow;
+ Effect *mEffect;
+}EffectSequence;
+
+/* possible states for a button */
+typedef enum tag_Button_State
+{
+ BUTTON_DISABLED,
+ BUTTON_ENABLED,
+ BUTTON_SELECTED,
+ BUTTON_ACTIVE,
+ BUTTON_MAX
+} BUTTON_STATE;
+
+typedef struct IGCommand
+{
+ unsigned int mOpCode;
+ unsigned int mDstOperand;
+ unsigned int mSrcOperand;
+}IGCommand;
+
+
+
+
+typedef struct IGSButton {
+ unsigned short id;
+ unsigned short numericValue;
+ unsigned char autoAction;
+ unsigned short x;
+ unsigned short y;
+ unsigned short n[4];//0:up,1:down,2:left,3:right
+ unsigned short pstart[3]; //0:normal,1:selected,2:activated
+ unsigned short pstop[3];
+ unsigned short pRepeat[3];
+ unsigned int mAnimtaionId; // 用于指示当前button的动画图片的id
+ unsigned short cmds_count;
+
+ unsigned char mSelectedSoundId;
+ unsigned char mActiveSoundId;
+ IGCommand *cmds;
+
+ BUTTON_STATE mState; /* current state of this button */
+} IGSButton;
+
+
+typedef struct IGSBOG {
+ unsigned short def_button;
+ unsigned short cur_button;
+ int buttons_count;
+ IGSButton *buttons;
+} IGSBOG;
+
+
+
+typedef struct IGSPage {
+ int frameRate;
+ int def_button;
+ int sel_button;
+ int in_time;
+ int timeout;
+ int palette;
+ int bogs_count;
+ int id;
+ IGSBOG *bogs;
+
+ EffectSequence* mInEffectSequnce;
+ EffectSequence* mOutEffectSequnce;
+} IGSPage;
+
+
+
+typedef struct ICS
+{
+ int mPages_count;
+
+ int mWidth;
+ int mHeight;
+ int mFrameRate;
+
+ int mUiMode; // bit7 set 1 means this is popup menu, whic is invisible default until is enable to pop up
+ unsigned long compositionTimeoutPTS;
+ unsigned long selectionTimeoutPTS; // 选中button显示的时间长度
+ unsigned long userTimeout; // 用于显示没有点击,多长时间导航隐藏
+
+ IGSPage *mPages;
+}ICS;
+
+
+typedef struct IGSPalette {
+ int id;
+ unsigned int clut[256];
+} IGSPalette;
+
+
+typedef struct IGSPicture {
+ int id;
+ int w;
+ int h;
+ unsigned int rle_buffer_size, rle_data_len;
+ unsigned int rle_remaining_len;
+ unsigned char *rle;
+ unsigned char *picture;
+} IGSPicture;
+
+
+typedef struct IG
+{
+ // 图片数量
+ int mPicturesCount;
+
+ // 调试板数量
+ int mPalettesCount;
+
+ ICS *mICS;
+ // 调试板数据
+ IGSPalette *mPalettes;
+
+ // IG导航图片数据
+ IGSPicture *mPictures;
+}IG;
+
+typedef struct IGContext
+{
+ // mICSDataSize,mICSDataTotalSize,mICSBuffer 用于缓冲ICS数据,拼凑成完整的ICS后再解析
+ int mICSDataSize;
+ int mICSDataTotalSize;
+ unsigned char* mICSBuffer;
+ IG* mIg;
+}IGContext;
+
+
+#endif
diff --git a/libavcodec/mpeg12.c b/libavcodec/mpeg12.c
index b5bf68d..dcc2a8a 100644..100755
--- a/libavcodec/mpeg12.c
+++ b/libavcodec/mpeg12.c
@@ -2185,6 +2185,40 @@ static void mpeg_decode_gop(AVCodecContext *avctx,
tcbuf, s->closed_gop, broken_link);
}
}
+static void mpeg_fetch_timestamp(AVCodecParserContext *s, int off, int remove){
+ int i;
+
+ s->dts= s->pts= AV_NOPTS_VALUE;
+ s->pos= -1;
+ s->offset= 0;
+
+ for(i = 0; i < AV_PARSER_PTS_NB; i++) {
+ if ( s->cur_offset + off >= s->cur_frame_offset[i]
+ && (s->frame_offset < s->cur_frame_offset[i] ||
+ (!s->frame_offset && !s->next_frame_offset)) // first field/frame
+ //check is disabled because mpeg-ts doesn't send complete PES packets
+ && /*s->next_frame_offset + off <*/ s->cur_frame_end[i]){
+
+ if (remove) {
+ if (s->cur_frame_dts[i] !=AV_NOPTS_VALUE)
+ s->dts= s->cur_frame_dts[i];
+
+ if (s->cur_frame_pts[i] !=AV_NOPTS_VALUE)
+ s->pts= s->cur_frame_pts[i];
+ } else {
+ s->dts= s->cur_frame_dts[i];
+ s->pts= s->cur_frame_pts[i];
+ }
+ s->pos= s->cur_frame_pos[i];
+ s->offset = s->next_frame_offset - s->cur_frame_offset[i];
+
+ if(remove)
+ s->cur_frame_offset[i]= INT64_MAX;
+ if(s->cur_offset + off < s->cur_frame_end[i])
+ break;
+ }
+ }
+}
/**
* Find the end of the current frame in the bitstream.
* @return the position of the first byte of the next frame, or -1
@@ -2241,7 +2275,13 @@ int ff_mpeg1_find_frame_end(ParseContext *pc, const uint8_t *buf, int buf_size,
}
}
if (pc->frame_start_found == 0 && s && state == PICTURE_START_CODE) {
- ff_fetch_timestamp(s, i - 3, 1);
+ /*
+ ** we have found av_read_frame sometimes get error pts, so instead
+ ** of call function: ff_fetch_timestamp(libavcodec/parser.c),
+ ** we use mpeg_fetch_timestamp here.
+ ** @Jun 9th, 2013. by hbb.
+ */
+ mpeg_fetch_timestamp(s, i - 3, 1);
}
}
}
diff --git a/libavcodec/parser.c b/libavcodec/parser.c
index cd1bcbc..f0a9f04 100644..100755
--- a/libavcodec/parser.c
+++ b/libavcodec/parser.c
@@ -201,6 +201,7 @@ int av_parser_change(AVCodecParserContext *s,
void av_parser_close(AVCodecParserContext *s)
{
if(s){
+ av_parse_deinit_callback(s);
if (s->parser->parser_close)
s->parser->parser_close(s);
av_free(s->priv_data);
@@ -296,3 +297,63 @@ int ff_mpeg4video_split(AVCodecContext *avctx,
}
return 0;
}
+
+
+void av_parser_init_callback(AVCodecParserContext*parse,
+ int (*interrupt_callback)(void*),
+ void (*msg_callback)(void*,int,int),
+ int (*operate_callback)(void*,int,void*,void**),
+ void *opaque,
+ void* msg_opaque,
+ void* operate_opaque)
+{
+ if(parse != NULL)
+ {
+ parse->callback.callback = interrupt_callback;
+ parse->callback.msg_callback = msg_callback;
+ parse->callback.operate_callback = operate_callback;
+ parse->callback.opaque = opaque;
+ parse->callback.msg_opaque = msg_opaque;
+ parse->callback.operate_opaque = operate_opaque;
+ }
+}
+
+void av_parse_deinit_callback(AVCodecParserContext*parse)
+{
+ if(parse != NULL)
+ {
+ parse->callback.callback = NULL;
+ parse->callback.msg_callback = NULL;
+ parse->callback.operate_callback = NULL;
+ parse->callback.opaque = NULL;
+ parse->callback.msg_opaque = NULL;
+ parse->callback.operate_opaque = NULL;
+ }
+}
+
+
+int ff_codec_check_interrupt(CodecCallBack* cb)
+{
+ int ret;
+ if (cb && cb->callback && cb->opaque && (ret = cb->callback(cb->opaque)))
+ return ret;
+ return 0;
+}
+
+void ff_codec_send_message(CodecCallBack* cb,int what,int msg)
+{
+ if((cb != NULL) && (cb->msg_opaque != NULL) && (cb->msg_callback != NULL))
+ {
+ cb->msg_callback(cb->msg_opaque,what,msg);
+ }
+}
+
+int ff_codec_check_operate(CodecCallBack*cb,int operate,void* para1,void** para2)
+{
+ if((cb != NULL) && (cb->operate_opaque != NULL) && (cb->operate_callback != NULL))
+ {
+ return cb->operate_callback(cb->operate_opaque,operate,para1,para2);
+ }
+
+ return 0;
+}
diff --git a/libavcodec/pgssubdec.c b/libavcodec/pgssubdec.c
index 2876c6a..e8cddd1 100644..100755
--- a/libavcodec/pgssubdec.c
+++ b/libavcodec/pgssubdec.c
@@ -33,6 +33,14 @@
#define RGBA(r,g,b,a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
+#define RGBA_A(color) ((color>>24)& 0xff)
+#define RGBA_R(color) ((color>>16)& 0xff)
+#define RGBA_G(color) ((color>>8)& 0xff)
+#define RGBA_B(color) (color& 0xff)
+
+
+
+
enum SegmentType {
PALETTE_SEGMENT = 0x14,
PICTURE_SEGMENT = 0x15,
@@ -74,14 +82,12 @@ typedef struct PGSSubContext {
static av_cold int init_decoder(AVCodecContext *avctx)
{
avctx->pix_fmt = AV_PIX_FMT_PAL8;
-
return 0;
}
static av_cold int close_decoder(AVCodecContext *avctx)
{
uint16_t picture;
-
PGSSubContext *ctx = avctx->priv_data;
av_freep(&ctx->presentation.objects);
@@ -222,6 +228,8 @@ static int parse_picture_segment(AVCodecContext *avctx,
return -1;
}
+ av_log(avctx, AV_LOG_ERROR, "parse_picture_segment: avctx->width = %d,avctx->height = %d",avctx->width,avctx->height);
+
ctx->pictures[picture_id].w = width;
ctx->pictures[picture_id].h = height;
@@ -301,9 +309,12 @@ static void parse_presentation_segment(AVCodecContext *avctx,
av_dlog(avctx, "Video Dimensions %dx%d\n",
w, h);
+
if (av_image_check_size(w, h, 0, avctx) >= 0)
avcodec_set_dimensions(avctx, w, h);
+ avctx->width = w;
+ avctx->height = h;
/* Skip 1 bytes of unknown, frame rate? */
buf++;
@@ -380,7 +391,7 @@ static int display_end_segment(AVCodecContext *avctx, void *data,
AVSubtitle *sub = data;
PGSSubContext *ctx = avctx->priv_data;
int64_t pts;
-
+
uint16_t rect;
/*
@@ -394,6 +405,9 @@ static int display_end_segment(AVCodecContext *avctx, void *data,
sub->pts = pts;
ctx->pts = AV_NOPTS_VALUE;
+ sub->width = avctx->width;
+ sub->height = avctx->height;
+
// Blank if last object_count was 0.
if (!ctx->presentation.object_count)
return 1;
@@ -404,7 +418,7 @@ static int display_end_segment(AVCodecContext *avctx, void *data,
sub->num_rects = ctx->presentation.object_count;
sub->rects = av_mallocz(sizeof(*sub->rects) * sub->num_rects);
-
+
for (rect = 0; rect < sub->num_rects; ++rect) {
uint16_t picture_id = ctx->presentation.objects[rect].picture_id;
sub->rects[rect] = av_mallocz(sizeof(*sub->rects[rect]));
@@ -432,7 +446,9 @@ static int display_end_segment(AVCodecContext *avctx, void *data,
sub->rects[rect]->flags = (ctx->presentation.objects[rect].composition & 0x40) != 0 ? AV_SUBTITLE_FLAG_FORCED : 0;
if (!ctx->forced_subs_only || ctx->presentation.objects[rect].composition & 0x40)
- memcpy(sub->rects[rect]->pict.data[1], ctx->clut, sub->rects[rect]->nb_colors * sizeof(uint32_t));
+ {
+ memcpy(sub->rects[rect]->pict.data[1], ctx->clut, sub->rects[rect]->nb_colors * sizeof(uint32_t));
+ }
}
return 1;
diff --git a/libavcodec/pthread.c b/libavcodec/pthread.c
index c0a872e..308d0c1 100644..100755
--- a/libavcodec/pthread.c
+++ b/libavcodec/pthread.c
@@ -402,7 +402,7 @@ static attribute_align_arg void *frame_worker_thread(void *arg)
p->state = STATE_INPUT_READY;
pthread_cond_broadcast(&p->progress_cond);
- pthread_cond_signal(&p->output_cond);
+ pthread_cond_broadcast(&p->output_cond);
pthread_mutex_unlock(&p->progress_mutex);
}
pthread_mutex_unlock(&p->mutex);
diff --git a/libavcodec/rkon2_mpeg2dec.cpp b/libavcodec/rkon2_mpeg2dec.cpp
new file mode 100755
index 0000000..4c270b0
--- /dev/null
+++ b/libavcodec/rkon2_mpeg2dec.cpp
@@ -0,0 +1,598 @@
+/*
+ * Interface to the Android Stagefright library for
+ * H/W accelerated H.264 decoding
+ *
+ * Copyright (C) 2011 Mohamed Naufal
+ * Copyright (C) 2011 Martin Storsj枚
+ *
+ * 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
+ */
+
+#include <binder/ProcessState.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/OMXClient.h>
+#include <media/stagefright/OMXCodec.h>
+#include <utils/List.h>
+#include <new>
+#include <map>
+
+extern "C" {
+#include "avcodec.h"
+#include "libavutil/imgutils.h"
+}
+
+#define OMX_QCOM_COLOR_FormatYVU420SemiPlanar 0x7FA30C00
+
+using namespace android;
+
+struct Frame {
+ status_t status;
+ size_t size;
+ int64_t time;
+ int key;
+ uint8_t *buffer;
+ AVFrame *vframe;
+};
+
+struct TimeStamp {
+ int64_t pts;
+ int64_t reordered_opaque;
+};
+
+class CustomSource;
+
+struct StagefrightContext {
+ AVCodecContext *avctx;
+ AVBitStreamFilterContext *bsfc;
+ uint8_t* orig_extradata;
+ int orig_extradata_size;
+ sp<MediaSource> *source;
+ List<Frame*> *in_queue, *out_queue;
+ pthread_mutex_t in_mutex, out_mutex;
+ pthread_cond_t condition;
+ pthread_t decode_thread_id;
+
+ Frame *end_frame;
+ bool source_done;
+ volatile sig_atomic_t thread_started, thread_exited, stop_decode;
+
+ AVFrame *prev_frame;
+ std::map<int64_t, TimeStamp> *ts_map;
+ int64_t frame_index;
+
+ uint8_t *dummy_buf;
+ int dummy_bufsize;
+
+ OMXClient *client;
+ sp<MediaSource> *decoder;
+ const char *decoder_component;
+};
+
+class CustomSource : public MediaSource {
+public:
+ CustomSource(AVCodecContext *avctx, sp<MetaData> meta) {
+ s = (StagefrightContext*)avctx->priv_data;
+ source_meta = meta;
+ frame_size = (avctx->width * avctx->height * 3) / 2;
+ buf_group.add_buffer(new MediaBuffer(frame_size));
+ }
+
+ virtual sp<MetaData> getFormat() {
+ return source_meta;
+ }
+
+ virtual status_t start(MetaData *params) {
+ return OK;
+ }
+
+ virtual status_t stop() {
+ return OK;
+ }
+
+ virtual status_t read(MediaBuffer **buffer,
+ const MediaSource::ReadOptions *options) {
+ Frame *frame;
+ status_t ret;
+
+ if (s->thread_exited)
+ return ERROR_END_OF_STREAM;
+ pthread_mutex_lock(&s->in_mutex);
+
+ while (s->in_queue->empty())
+ pthread_cond_wait(&s->condition, &s->in_mutex);
+
+ frame = *s->in_queue->begin();
+ ret = frame->status;
+
+ if (ret == OK) {
+ ret = buf_group.acquire_buffer(buffer);
+ if (ret == OK) {
+ memcpy((*buffer)->data(), frame->buffer, frame->size);
+ (*buffer)->set_range(0, frame->size);
+ (*buffer)->meta_data()->clear();
+ (*buffer)->meta_data()->setInt32(kKeyIsSyncFrame,frame->key);
+ (*buffer)->meta_data()->setInt64(kKeyTime, frame->time);
+ } else {
+ av_log(s->avctx, AV_LOG_ERROR, "Failed to acquire MediaBuffer\n");
+ }
+ av_freep(&frame->buffer);
+ }
+
+ s->in_queue->erase(s->in_queue->begin());
+ pthread_mutex_unlock(&s->in_mutex);
+
+ av_freep(&frame);
+ return ret;
+ }
+
+private:
+ MediaBufferGroup buf_group;
+ sp<MetaData> source_meta;
+ StagefrightContext *s;
+ int frame_size;
+};
+
+void* decode_thread(void *arg)
+{
+ AVCodecContext *avctx = (AVCodecContext*)arg;
+ StagefrightContext *s = (StagefrightContext*)avctx->priv_data;
+ const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(avctx->pix_fmt);
+ Frame* frame;
+ MediaBuffer *buffer;
+ int32_t w, h;
+ int decode_done = 0;
+ int ret;
+ int src_linesize[3];
+ const uint8_t *src_data[3];
+ int64_t out_frame_index = 0;
+
+ do {
+ buffer = NULL;
+ frame = (Frame*)av_mallocz(sizeof(Frame));
+ if (!frame) {
+ frame = s->end_frame;
+ frame->status = AVERROR(ENOMEM);
+ decode_done = 1;
+ s->end_frame = NULL;
+ goto push_frame;
+ }
+ frame->status = (*s->decoder)->read(&buffer);
+ if (frame->status == OK) {
+ sp<MetaData> outFormat = (*s->decoder)->getFormat();
+ outFormat->findInt32(kKeyWidth , &w);
+ outFormat->findInt32(kKeyHeight, &h);
+ frame->vframe = (AVFrame*)av_mallocz(sizeof(AVFrame));
+ if (!frame->vframe) {
+ frame->status = AVERROR(ENOMEM);
+ decode_done = 1;
+ buffer->release();
+ goto push_frame;
+ }
+ ret = ff_get_buffer(avctx, frame->vframe);
+ if (ret < 0) {
+ av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ frame->status = ret;
+ decode_done = 1;
+ buffer->release();
+ goto push_frame;
+ }
+
+ // The OMX.SEC decoder doesn't signal the modified width/height
+ if (s->decoder_component && !strncmp(s->decoder_component, "OMX.SEC", 7) &&
+ (w & 15 || h & 15)) {
+ if (((w + 15)&~15) * ((h + 15)&~15) * 3/2 == buffer->range_length()) {
+ w = (w + 15)&~15;
+ h = (h + 15)&~15;
+ }
+ }
+
+ if (!avctx->width || !avctx->height || avctx->width > w || avctx->height > h) {
+ avctx->width = w;
+ avctx->height = h;
+ }
+
+ src_linesize[0] = av_image_get_linesize(avctx->pix_fmt, w, 0);
+ src_linesize[1] = av_image_get_linesize(avctx->pix_fmt, w, 1);
+ src_linesize[2] = av_image_get_linesize(avctx->pix_fmt, w, 2);
+
+ src_data[0] = (uint8_t*)buffer->data();
+ src_data[1] = src_data[0] + src_linesize[0] * h;
+ src_data[2] = src_data[1] + src_linesize[1] * -(-h>>pix_desc->log2_chroma_h);
+ av_image_copy(frame->vframe->data, frame->vframe->linesize,
+ src_data, src_linesize,
+ avctx->pix_fmt, avctx->width, avctx->height);
+
+ buffer->meta_data()->findInt64(kKeyTime, &out_frame_index);
+ if (out_frame_index && s->ts_map->count(out_frame_index) > 0) {
+ frame->vframe->pts = (*s->ts_map)[out_frame_index].pts;
+ frame->vframe->reordered_opaque = (*s->ts_map)[out_frame_index].reordered_opaque;
+ s->ts_map->erase(out_frame_index);
+ }
+ buffer->release();
+ } else if (frame->status == INFO_FORMAT_CHANGED) {
+ if (buffer)
+ buffer->release();
+ av_free(frame);
+ continue;
+ } else {
+ decode_done = 1;
+ }
+push_frame:
+ while (true) {
+ pthread_mutex_lock(&s->out_mutex);
+ if (s->out_queue->size() >= 10) {
+ pthread_mutex_unlock(&s->out_mutex);
+ usleep(10000);
+ continue;
+ }
+ break;
+ }
+ s->out_queue->push_back(frame);
+ pthread_mutex_unlock(&s->out_mutex);
+ } while (!decode_done && !s->stop_decode);
+
+ s->thread_exited = true;
+
+ return 0;
+}
+
+static av_cold int Stagefright_init(AVCodecContext *avctx)
+{
+ StagefrightContext *s = (StagefrightContext*)avctx->priv_data;
+ sp<MetaData> meta, outFormat;
+ int32_t colorFormat = 0;
+ int ret;
+
+ if (!avctx->extradata || !avctx->extradata_size || avctx->extradata[0] != 1)
+ return -1;
+
+ s->avctx = avctx;
+ s->bsfc = av_bitstream_filter_init("h264_mp4toannexb");
+ if (!s->bsfc) {
+ av_log(avctx, AV_LOG_ERROR, "Cannot open the h264_mp4toannexb BSF!\n");
+ return -1;
+ }
+
+ s->orig_extradata_size = avctx->extradata_size;
+ s->orig_extradata = (uint8_t*) av_mallocz(avctx->extradata_size +
+ FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!s->orig_extradata) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ memcpy(s->orig_extradata, avctx->extradata, avctx->extradata_size);
+
+ meta = new MetaData;
+ if (meta == NULL) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
+ meta->setInt32(kKeyWidth, avctx->width);
+ meta->setInt32(kKeyHeight, avctx->height);
+ meta->setData(kKeyAVCC, kTypeAVCC, avctx->extradata, avctx->extradata_size);
+
+ android::ProcessState::self()->startThreadPool();
+
+ s->source = new sp<MediaSource>();
+ *s->source = new CustomSource(avctx, meta);
+ s->in_queue = new List<Frame*>;
+ s->out_queue = new List<Frame*>;
+ s->ts_map = new std::map<int64_t, TimeStamp>;
+ s->client = new OMXClient;
+ s->end_frame = (Frame*)av_mallocz(sizeof(Frame));
+ if (s->source == NULL || !s->in_queue || !s->out_queue || !s->client ||
+ !s->ts_map || !s->end_frame) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ if (s->client->connect() != OK) {
+ av_log(avctx, AV_LOG_ERROR, "Cannot connect OMX client\n");
+ ret = -1;
+ goto fail;
+ }
+
+ s->decoder = new sp<MediaSource>();
+ *s->decoder = OMXCodec::Create(s->client->interface(), meta,
+ false, *s->source, NULL,
+ OMXCodec::kClientNeedsFramebuffer);
+ if ((*s->decoder)->start() != OK) {
+ av_log(avctx, AV_LOG_ERROR, "Cannot start decoder\n");
+ ret = -1;
+ s->client->disconnect();
+ goto fail;
+ }
+
+ outFormat = (*s->decoder)->getFormat();
+ outFormat->findInt32(kKeyColorFormat, &colorFormat);
+ if (colorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar ||
+ colorFormat == OMX_COLOR_FormatYUV420SemiPlanar)
+ avctx->pix_fmt = AV_PIX_FMT_NV21;
+ else if (colorFormat == OMX_COLOR_FormatYCbYCr)
+ avctx->pix_fmt = AV_PIX_FMT_YUYV422;
+ else if (colorFormat == OMX_COLOR_FormatCbYCrY)
+ avctx->pix_fmt = AV_PIX_FMT_UYVY422;
+ else
+ avctx->pix_fmt = AV_PIX_FMT_YUV420P;
+
+ outFormat->findCString(kKeyDecoderComponent, &s->decoder_component);
+ if (s->decoder_component)
+ s->decoder_component = av_strdup(s->decoder_component);
+
+ pthread_mutex_init(&s->in_mutex, NULL);
+ pthread_mutex_init(&s->out_mutex, NULL);
+ pthread_cond_init(&s->condition, NULL);
+ return 0;
+
+fail:
+ av_bitstream_filter_close(s->bsfc);
+ av_freep(&s->orig_extradata);
+ av_freep(&s->end_frame);
+ delete s->in_queue;
+ delete s->out_queue;
+ delete s->ts_map;
+ delete s->client;
+ return ret;
+}
+
+static int Stagefright_decode_frame(AVCodecContext *avctx, void *data,
+ int *got_frame, AVPacket *avpkt)
+{
+ StagefrightContext *s = (StagefrightContext*)avctx->priv_data;
+ Frame *frame;
+ status_t status;
+ int orig_size = avpkt->size;
+ AVPacket pkt = *avpkt;
+ AVFrame *ret_frame;
+
+ if (!s->thread_started) {
+ pthread_create(&s->decode_thread_id, NULL, &decode_thread, avctx);
+ s->thread_started = true;
+ }
+
+ if (avpkt && avpkt->data) {
+ av_bitstream_filter_filter(s->bsfc, avctx, NULL, &pkt.data, &pkt.size,
+ avpkt->data, avpkt->size, avpkt->flags & AV_PKT_FLAG_KEY);
+ avpkt = &pkt;
+ }
+
+ if (!s->source_done) {
+ if(!s->dummy_buf) {
+ s->dummy_buf = (uint8_t*)av_malloc(avpkt->size);
+ if (!s->dummy_buf)
+ return AVERROR(ENOMEM);
+ s->dummy_bufsize = avpkt->size;
+ memcpy(s->dummy_buf, avpkt->data, avpkt->size);
+ }
+
+ frame = (Frame*)av_mallocz(sizeof(Frame));
+ if (avpkt->data) {
+ frame->status = OK;
+ frame->size = avpkt->size;
+ frame->key = avpkt->flags & AV_PKT_FLAG_KEY ? 1 : 0;
+ frame->buffer = (uint8_t*)av_malloc(avpkt->size);
+ if (!frame->buffer) {
+ av_freep(&frame);
+ return AVERROR(ENOMEM);
+ }
+ uint8_t *ptr = avpkt->data;
+ // The OMX.SEC decoder fails without this.
+ if (avpkt->size == orig_size + avctx->extradata_size) {
+ ptr += avctx->extradata_size;
+ frame->size = orig_size;
+ }
+ memcpy(frame->buffer, ptr, orig_size);
+ if (avpkt == &pkt)
+ av_free(avpkt->data);
+
+ frame->time = ++s->frame_index;
+ (*s->ts_map)[s->frame_index].pts = avpkt->pts;
+ (*s->ts_map)[s->frame_index].reordered_opaque = avctx->reordered_opaque;
+ } else {
+ frame->status = ERROR_END_OF_STREAM;
+ s->source_done = true;
+ }
+
+ while (true) {
+ if (s->thread_exited) {
+ s->source_done = true;
+ break;
+ }
+ pthread_mutex_lock(&s->in_mutex);
+ if (s->in_queue->size() >= 10) {
+ pthread_mutex_unlock(&s->in_mutex);
+ usleep(10000);
+ continue;
+ }
+ s->in_queue->push_back(frame);
+ pthread_cond_signal(&s->condition);
+ pthread_mutex_unlock(&s->in_mutex);
+ break;
+ }
+ }
+ while (true) {
+ pthread_mutex_lock(&s->out_mutex);
+ if (!s->out_queue->empty()) break;
+ pthread_mutex_unlock(&s->out_mutex);
+ if (s->source_done) {
+ usleep(10000);
+ continue;
+ } else {
+ return orig_size;
+ }
+ }
+
+ frame = *s->out_queue->begin();
+ s->out_queue->erase(s->out_queue->begin());
+ pthread_mutex_unlock(&s->out_mutex);
+
+ ret_frame = frame->vframe;
+ status = frame->status;
+ av_freep(&frame);
+
+ if (status == ERROR_END_OF_STREAM)
+ return 0;
+ if (status != OK) {
+ if (status == AVERROR(ENOMEM))
+ return status;
+ av_log(avctx, AV_LOG_ERROR, "Decode failed: %x\n", status);
+ return -1;
+ }
+
+ if (s->prev_frame) {
+ avctx->release_buffer(avctx, s->prev_frame);
+ av_freep(&s->prev_frame);
+ }
+ s->prev_frame = ret_frame;
+
+ *got_frame = 1;
+ *(AVFrame*)data = *ret_frame;
+ return orig_size;
+}
+
+static av_cold int Stagefright_close(AVCodecContext *avctx)
+{
+ StagefrightContext *s = (StagefrightContext*)avctx->priv_data;
+ Frame *frame;
+
+ if (s->thread_started) {
+ if (!s->thread_exited) {
+ s->stop_decode = 1;
+
+ // Make sure decode_thread() doesn't get stuck
+ pthread_mutex_lock(&s->out_mutex);
+ while (!s->out_queue->empty()) {
+ frame = *s->out_queue->begin();
+ s->out_queue->erase(s->out_queue->begin());
+ if (frame->vframe) {
+ avctx->release_buffer(avctx, frame->vframe);
+ av_freep(&frame->vframe);
+ }
+ av_freep(&frame);
+ }
+ pthread_mutex_unlock(&s->out_mutex);
+
+ // Feed a dummy frame prior to signalling EOF.
+ // This is required to terminate the decoder(OMX.SEC)
+ // when only one frame is read during stream info detection.
+ if (s->dummy_buf && (frame = (Frame*)av_mallocz(sizeof(Frame)))) {
+ frame->status = OK;
+ frame->size = s->dummy_bufsize;
+ frame->key = 1;
+ frame->buffer = s->dummy_buf;
+ pthread_mutex_lock(&s->in_mutex);
+ s->in_queue->push_back(frame);
+ pthread_cond_signal(&s->condition);
+ pthread_mutex_unlock(&s->in_mutex);
+ s->dummy_buf = NULL;
+ }
+
+ pthread_mutex_lock(&s->in_mutex);
+ s->end_frame->status = ERROR_END_OF_STREAM;
+ s->in_queue->push_back(s->end_frame);
+ pthread_cond_signal(&s->condition);
+ pthread_mutex_unlock(&s->in_mutex);
+ s->end_frame = NULL;
+ }
+
+ pthread_join(s->decode_thread_id, NULL);
+
+ if (s->prev_frame) {
+ avctx->release_buffer(avctx, s->prev_frame);
+ av_freep(&s->prev_frame);
+ }
+
+ s->thread_started = false;
+ }
+
+ while (!s->in_queue->empty()) {
+ frame = *s->in_queue->begin();
+ s->in_queue->erase(s->in_queue->begin());
+ if (frame->size)
+ av_freep(&frame->buffer);
+ av_freep(&frame);
+ }
+
+ while (!s->out_queue->empty()) {
+ frame = *s->out_queue->begin();
+ s->out_queue->erase(s->out_queue->begin());
+ if (frame->vframe) {
+ avctx->release_buffer(avctx, frame->vframe);
+ av_freep(&frame->vframe);
+ }
+ av_freep(&frame);
+ }
+
+ (*s->decoder)->stop();
+ s->client->disconnect();
+
+ if (s->decoder_component)
+ av_freep(&s->decoder_component);
+ av_freep(&s->dummy_buf);
+ av_freep(&s->end_frame);
+
+ // Reset the extradata back to the original mp4 format, so that
+ // the next invocation (both when decoding and when called from
+ // av_find_stream_info) get the original mp4 format extradata.
+ av_freep(&avctx->extradata);
+ avctx->extradata = s->orig_extradata;
+ avctx->extradata_size = s->orig_extradata_size;
+
+ delete s->in_queue;
+ delete s->out_queue;
+ delete s->ts_map;
+ delete s->client;
+ delete s->decoder;
+ delete s->source;
+
+ pthread_mutex_destroy(&s->in_mutex);
+ pthread_mutex_destroy(&s->out_mutex);
+ pthread_cond_destroy(&s->condition);
+ av_bitstream_filter_close(s->bsfc);
+ return 0;
+}
+
+AVCodec ff_libstagefright_h264_decoder = {
+ "libstagefright_h264",
+ NULL_IF_CONFIG_SMALL("libstagefright H.264"),
+ AVMEDIA_TYPE_VIDEO,
+ AV_CODEC_ID_H264,
+ CODEC_CAP_DELAY,
+ NULL, //supported_framerates
+ NULL, //pix_fmts
+ NULL, //supported_samplerates
+ NULL, //sample_fmts
+ NULL, //channel_layouts
+ 0, //max_lowres
+ NULL, //priv_class
+ NULL, //profiles
+ sizeof(StagefrightContext),
+ NULL, //next
+ NULL, //init_thread_copy
+ NULL, //update_thread_context
+ NULL, //defaults
+ NULL, //init_static_data
+ Stagefright_init,
+ NULL, //encode
+ NULL, //encode2
+ Stagefright_decode_frame,
+ Stagefright_close,
+};
diff --git a/libavcodec/utils.c b/libavcodec/utils.c
index 931f3fd..c5e99f6 100644..100755
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@ -47,11 +47,14 @@
#include <stdarg.h>
#include <limits.h>
#include <float.h>
+#include <pthread.h>
+
static int volatile entangled_thread_counter = 0;
static int (*ff_lockmgr_cb)(void **mutex, enum AVLockOp op);
static void *codec_mutex;
static void *avformat_mutex;
+static pthread_mutex_t avcodec_mutex =PTHREAD_RECURSIVE_MUTEX_INITIALIZER;
void *av_fast_realloc(void *ptr, unsigned int *size, size_t min_size)
{
@@ -809,6 +812,7 @@ int attribute_align_arg ff_codec_open2_recursive(AVCodecContext *avctx, const AV
if (ff_lockmgr_cb) {
(*ff_lockmgr_cb)(&codec_mutex, AV_LOCK_RELEASE);
}
+ pthread_mutex_unlock(&avcodec_mutex);
ret = avcodec_open2(avctx, codec, options);
@@ -817,6 +821,8 @@ int attribute_align_arg ff_codec_open2_recursive(AVCodecContext *avctx, const AV
if ((*ff_lockmgr_cb)(&codec_mutex, AV_LOCK_OBTAIN))
return -1;
}
+
+ pthread_mutex_lock(&avcodec_mutex);
entangled_thread_counter++;
return ret;
}
@@ -852,6 +858,7 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code
if ((ret = (*ff_lockmgr_cb)(&codec_mutex, AV_LOCK_OBTAIN)) < 0)
return ret;
}
+ pthread_mutex_lock(&avcodec_mutex);
entangled_thread_counter++;
if (entangled_thread_counter != 1) {
@@ -865,7 +872,7 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code
ret = AVERROR(ENOMEM);
goto end;
}
-
+
if (codec->priv_data_size > 0) {
if (!avctx->priv_data) {
avctx->priv_data = av_mallocz(codec->priv_data_size);
@@ -1103,6 +1110,7 @@ end:
if (ff_lockmgr_cb) {
(*ff_lockmgr_cb)(&codec_mutex, AV_LOCK_RELEASE);
}
+ pthread_mutex_unlock(&avcodec_mutex);
if (options) {
av_dict_free(options);
*options = tmp;
@@ -1766,7 +1774,6 @@ int attribute_align_arg avcodec_decode_audio4(AVCodecContext *avctx,
}
avcodec_get_frame_defaults(frame);
-
if ((avctx->codec->capabilities & CODEC_CAP_DELAY) || avpkt->size) {
uint8_t *side;
int side_size;
@@ -1920,6 +1927,7 @@ av_cold int ff_codec_close_recursive(AVCodecContext *avctx)
if (ff_lockmgr_cb) {
(*ff_lockmgr_cb)(&codec_mutex, AV_LOCK_RELEASE);
}
+ pthread_mutex_unlock(&avcodec_mutex);
ret = avcodec_close(avctx);
@@ -1928,17 +1936,20 @@ av_cold int ff_codec_close_recursive(AVCodecContext *avctx)
if ((*ff_lockmgr_cb)(&codec_mutex, AV_LOCK_OBTAIN))
return -1;
}
+ pthread_mutex_lock(&avcodec_mutex);
entangled_thread_counter++;
return ret;
}
av_cold int avcodec_close(AVCodecContext *avctx)
{
+
/* If there is a user-supplied mutex locking routine, call it. */
if (ff_lockmgr_cb) {
if ((*ff_lockmgr_cb)(&codec_mutex, AV_LOCK_OBTAIN))
return -1;
}
+ pthread_mutex_lock(&avcodec_mutex);
entangled_thread_counter++;
if (entangled_thread_counter != 1) {
@@ -1979,6 +1990,7 @@ av_cold int avcodec_close(AVCodecContext *avctx)
if (ff_lockmgr_cb) {
(*ff_lockmgr_cb)(&codec_mutex, AV_LOCK_RELEASE);
}
+ pthread_mutex_unlock(&avcodec_mutex);
return 0;
}
diff --git a/libavfilter/af_aconvert.o b/libavfilter/af_aconvert.o
index de6b2a5..612c3d9 100644..100755
--- a/libavfilter/af_aconvert.o
+++ b/libavfilter/af_aconvert.o
Binary files differ
diff --git a/libavfilter/af_aformat.o b/libavfilter/af_aformat.o
index 379261f..932b9ad 100644..100755
--- a/libavfilter/af_aformat.o
+++ b/libavfilter/af_aformat.o
Binary files differ
diff --git a/libavfilter/af_amerge.o b/libavfilter/af_amerge.o
index c85fa37..2d28167 100644..100755
--- a/libavfilter/af_amerge.o
+++ b/libavfilter/af_amerge.o
Binary files differ
diff --git a/libavfilter/af_amix.o b/libavfilter/af_amix.o
index 9831a63..fd0eaf8 100644..100755
--- a/libavfilter/af_amix.o
+++ b/libavfilter/af_amix.o
Binary files differ
diff --git a/libavfilter/af_anull.o b/libavfilter/af_anull.o
index e293ef8..f46e315 100644..100755
--- a/libavfilter/af_anull.o
+++ b/libavfilter/af_anull.o
Binary files differ
diff --git a/libavfilter/af_aresample.o b/libavfilter/af_aresample.o
index fe69707..bdf86be 100644..100755
--- a/libavfilter/af_aresample.o
+++ b/libavfilter/af_aresample.o
Binary files differ
diff --git a/libavfilter/af_asetnsamples.o b/libavfilter/af_asetnsamples.o
index 19c6a59..ee71361 100644..100755
--- a/libavfilter/af_asetnsamples.o
+++ b/libavfilter/af_asetnsamples.o
Binary files differ
diff --git a/libavfilter/af_ashowinfo.o b/libavfilter/af_ashowinfo.o
index 8a22184..42d17da 100644..100755
--- a/libavfilter/af_ashowinfo.o
+++ b/libavfilter/af_ashowinfo.o
Binary files differ
diff --git a/libavfilter/af_astreamsync.o b/libavfilter/af_astreamsync.o
index 6ab98b2..5d76cb8 100644..100755
--- a/libavfilter/af_astreamsync.o
+++ b/libavfilter/af_astreamsync.o
Binary files differ
diff --git a/libavfilter/af_atempo.o b/libavfilter/af_atempo.o
index 5c0670d..d5a0157 100644..100755
--- a/libavfilter/af_atempo.o
+++ b/libavfilter/af_atempo.o
Binary files differ
diff --git a/libavfilter/af_channelmap.o b/libavfilter/af_channelmap.o
index ea5a172..0297782 100644..100755
--- a/libavfilter/af_channelmap.o
+++ b/libavfilter/af_channelmap.o
Binary files differ
diff --git a/libavfilter/af_channelsplit.o b/libavfilter/af_channelsplit.o
index 5fbfefb..f41eb84 100644..100755
--- a/libavfilter/af_channelsplit.o
+++ b/libavfilter/af_channelsplit.o
Binary files differ
diff --git a/libavfilter/af_earwax.o b/libavfilter/af_earwax.o
index 353c903..9f26d8c 100644..100755
--- a/libavfilter/af_earwax.o
+++ b/libavfilter/af_earwax.o
Binary files differ
diff --git a/libavfilter/af_join.o b/libavfilter/af_join.o
index 561ce12..ec2f3b4 100644..100755
--- a/libavfilter/af_join.o
+++ b/libavfilter/af_join.o
Binary files differ
diff --git a/libavfilter/af_pan.o b/libavfilter/af_pan.o
index c5d79b2..d180bd6 100644..100755
--- a/libavfilter/af_pan.o
+++ b/libavfilter/af_pan.o
Binary files differ
diff --git a/libavfilter/af_silencedetect.o b/libavfilter/af_silencedetect.o
index 196558c..0864038 100644..100755
--- a/libavfilter/af_silencedetect.o
+++ b/libavfilter/af_silencedetect.o
Binary files differ
diff --git a/libavfilter/af_volume.o b/libavfilter/af_volume.o
index 9b05243..4bb8602 100644..100755
--- a/libavfilter/af_volume.o
+++ b/libavfilter/af_volume.o
Binary files differ
diff --git a/libavfilter/af_volumedetect.o b/libavfilter/af_volumedetect.o
index fa63851..1c32d2d 100644..100755
--- a/libavfilter/af_volumedetect.o
+++ b/libavfilter/af_volumedetect.o
Binary files differ
diff --git a/libavfilter/allfilters.o b/libavfilter/allfilters.o
index dad3c40..44575d3 100644..100755
--- a/libavfilter/allfilters.o
+++ b/libavfilter/allfilters.o
Binary files differ
diff --git a/libavfilter/asink_anullsink.o b/libavfilter/asink_anullsink.o
index c2954c8..4bca9c1 100644..100755
--- a/libavfilter/asink_anullsink.o
+++ b/libavfilter/asink_anullsink.o
Binary files differ
diff --git a/libavfilter/asrc_aevalsrc.o b/libavfilter/asrc_aevalsrc.o
index 94f218c..82da52e 100644..100755
--- a/libavfilter/asrc_aevalsrc.o
+++ b/libavfilter/asrc_aevalsrc.o
Binary files differ
diff --git a/libavfilter/asrc_anullsrc.o b/libavfilter/asrc_anullsrc.o
index 48bfbd9..b28fb38 100644..100755
--- a/libavfilter/asrc_anullsrc.o
+++ b/libavfilter/asrc_anullsrc.o
Binary files differ
diff --git a/libavfilter/audio.o b/libavfilter/audio.o
index 3dd46aa..be54e30 100644..100755
--- a/libavfilter/audio.o
+++ b/libavfilter/audio.o
Binary files differ
diff --git a/libavfilter/avcodec.o b/libavfilter/avcodec.o
index e8bc2f7..7f55f68 100644..100755
--- a/libavfilter/avcodec.o
+++ b/libavfilter/avcodec.o
Binary files differ
diff --git a/libavfilter/avf_concat.o b/libavfilter/avf_concat.o
index 3f7cb11..c056664 100644..100755
--- a/libavfilter/avf_concat.o
+++ b/libavfilter/avf_concat.o
Binary files differ
diff --git a/libavfilter/avf_showspectrum.o b/libavfilter/avf_showspectrum.o
index 6529f50..a31081d 100644..100755
--- a/libavfilter/avf_showspectrum.o
+++ b/libavfilter/avf_showspectrum.o
Binary files differ
diff --git a/libavfilter/avf_showwaves.o b/libavfilter/avf_showwaves.o
index 90a5f04..e04c497 100644..100755
--- a/libavfilter/avf_showwaves.o
+++ b/libavfilter/avf_showwaves.o
Binary files differ
diff --git a/libavfilter/avfilter.o b/libavfilter/avfilter.o
index 35ff958..35c1a6b 100644..100755
--- a/libavfilter/avfilter.o
+++ b/libavfilter/avfilter.o
Binary files differ
diff --git a/libavfilter/avfiltergraph.o b/libavfilter/avfiltergraph.o
index 202c41e..544434f 100644..100755
--- a/libavfilter/avfiltergraph.o
+++ b/libavfilter/avfiltergraph.o
Binary files differ
diff --git a/libavfilter/bbox.o b/libavfilter/bbox.o
index 875a00b..70d9b4c 100644..100755
--- a/libavfilter/bbox.o
+++ b/libavfilter/bbox.o
Binary files differ
diff --git a/libavfilter/buffer.o b/libavfilter/buffer.o
index 56e2fe2..3464eee 100644..100755
--- a/libavfilter/buffer.o
+++ b/libavfilter/buffer.o
Binary files differ
diff --git a/libavfilter/buffersink.o b/libavfilter/buffersink.o
index 0ac2e37..ac1bf6e 100644..100755
--- a/libavfilter/buffersink.o
+++ b/libavfilter/buffersink.o
Binary files differ
diff --git a/libavfilter/buffersrc.o b/libavfilter/buffersrc.o
index cd8fca5..f78f4f9 100644..100755
--- a/libavfilter/buffersrc.o
+++ b/libavfilter/buffersrc.o
Binary files differ
diff --git a/libavfilter/drawutils.o b/libavfilter/drawutils.o
index 000466f..c72780f 100644..100755
--- a/libavfilter/drawutils.o
+++ b/libavfilter/drawutils.o
Binary files differ
diff --git a/libavfilter/f_sendcmd.o b/libavfilter/f_sendcmd.o
index 0c96994..4f7fee5 100644..100755
--- a/libavfilter/f_sendcmd.o
+++ b/libavfilter/f_sendcmd.o
Binary files differ
diff --git a/libavfilter/f_setpts.o b/libavfilter/f_setpts.o
index 183164f..ede6c1b 100644..100755
--- a/libavfilter/f_setpts.o
+++ b/libavfilter/f_setpts.o
Binary files differ
diff --git a/libavfilter/f_settb.o b/libavfilter/f_settb.o
index 947d3c2..46e31f2 100644..100755
--- a/libavfilter/f_settb.o
+++ b/libavfilter/f_settb.o
Binary files differ
diff --git a/libavfilter/fifo.o b/libavfilter/fifo.o
index c7551c7..0fa65f5 100644..100755
--- a/libavfilter/fifo.o
+++ b/libavfilter/fifo.o
Binary files differ
diff --git a/libavfilter/formats.o b/libavfilter/formats.o
index 878c7c5..c71c2ce 100644..100755
--- a/libavfilter/formats.o
+++ b/libavfilter/formats.o
Binary files differ
diff --git a/libavfilter/graphdump.o b/libavfilter/graphdump.o
index df2b572..967632f 100644..100755
--- a/libavfilter/graphdump.o
+++ b/libavfilter/graphdump.o
Binary files differ
diff --git a/libavfilter/graphparser.o b/libavfilter/graphparser.o
index b5e96c9..07dc043 100644..100755
--- a/libavfilter/graphparser.o
+++ b/libavfilter/graphparser.o
Binary files differ
diff --git a/libavfilter/lavfutils.o b/libavfilter/lavfutils.o
index af9fc5c..bdcd48b 100644..100755
--- a/libavfilter/lavfutils.o
+++ b/libavfilter/lavfutils.o
Binary files differ
diff --git a/libavfilter/libavfilter.a b/libavfilter/libavfilter.a
index fe20772..b15cc50 100644..100755
--- a/libavfilter/libavfilter.a
+++ b/libavfilter/libavfilter.a
Binary files differ
diff --git a/libavfilter/libavfilter.pc b/libavfilter/libavfilter.pc
index 1873b23..31bac83 100644..100755
--- a/libavfilter/libavfilter.pc
+++ b/libavfilter/libavfilter.pc
@@ -1,4 +1,4 @@
-prefix=/usr/local
+prefix=./android/armv7-a
exec_prefix=${prefix}
libdir=${prefix}/lib
includedir=${prefix}/include
@@ -6,9 +6,9 @@ includedir=${prefix}/include
Name: libavfilter
Description: FFmpeg video filtering library
Version: 3.21.106
-Requires:
-Requires.private: libswresample = 0.16.100, libswscale = 2.1.102, libavformat = 54.35.100, libavcodec = 54.71.100
+Requires: libswresample = 0.16.100, libavformat = 54.35.100, libavcodec = 54.71.100
+Requires.private:
Conflicts:
-Libs: -L${libdir} -lavfilter
-Libs.private: -lm -lz -lgcc
+Libs: -L${libdir} -lavfilter -lm -lz -lgcc
+Libs.private:
Cflags: -I${includedir}
diff --git a/libavfilter/sink_buffer.o b/libavfilter/sink_buffer.o
index 9550535..4d930a6 100644..100755
--- a/libavfilter/sink_buffer.o
+++ b/libavfilter/sink_buffer.o
Binary files differ
diff --git a/libavfilter/split.o b/libavfilter/split.o
index 1bdedb5..66c6098 100644..100755
--- a/libavfilter/split.o
+++ b/libavfilter/split.o
Binary files differ
diff --git a/libavfilter/src_buffer.o b/libavfilter/src_buffer.o
index 8e98a72..d82ca3b 100644..100755
--- a/libavfilter/src_buffer.o
+++ b/libavfilter/src_buffer.o
Binary files differ
diff --git a/libavfilter/src_movie.o b/libavfilter/src_movie.o
index 1b85767..968b7ef 100644..100755
--- a/libavfilter/src_movie.o
+++ b/libavfilter/src_movie.o
Binary files differ
diff --git a/libavfilter/transform.o b/libavfilter/transform.o
index 3aa0dfc..1621519 100644..100755
--- a/libavfilter/transform.o
+++ b/libavfilter/transform.o
Binary files differ
diff --git a/libavfilter/vf_alphaextract.o b/libavfilter/vf_alphaextract.o
index 6d86355..7c2539a 100644..100755
--- a/libavfilter/vf_alphaextract.o
+++ b/libavfilter/vf_alphaextract.o
Binary files differ
diff --git a/libavfilter/vf_alphamerge.o b/libavfilter/vf_alphamerge.o
index 6101cd3..0d81bed 100644..100755
--- a/libavfilter/vf_alphamerge.o
+++ b/libavfilter/vf_alphamerge.o
Binary files differ
diff --git a/libavfilter/vf_aspect.o b/libavfilter/vf_aspect.o
index 71f3a9c..867fe2e 100644..100755
--- a/libavfilter/vf_aspect.o
+++ b/libavfilter/vf_aspect.o
Binary files differ
diff --git a/libavfilter/vf_bbox.o b/libavfilter/vf_bbox.o
index 897a158..c4a6a56 100644..100755
--- a/libavfilter/vf_bbox.o
+++ b/libavfilter/vf_bbox.o
Binary files differ
diff --git a/libavfilter/vf_blackdetect.o b/libavfilter/vf_blackdetect.o
index 5cd8465..89e8703 100644..100755
--- a/libavfilter/vf_blackdetect.o
+++ b/libavfilter/vf_blackdetect.o
Binary files differ
diff --git a/libavfilter/vf_copy.o b/libavfilter/vf_copy.o
index 9ceaf0c..9446058 100644..100755
--- a/libavfilter/vf_copy.o
+++ b/libavfilter/vf_copy.o
Binary files differ
diff --git a/libavfilter/vf_crop.o b/libavfilter/vf_crop.o
index 106f57f..c76bf83 100644..100755
--- a/libavfilter/vf_crop.o
+++ b/libavfilter/vf_crop.o
Binary files differ
diff --git a/libavfilter/vf_deshake.o b/libavfilter/vf_deshake.o
index 279ba34..a4a70d2 100644..100755
--- a/libavfilter/vf_deshake.o
+++ b/libavfilter/vf_deshake.o
Binary files differ
diff --git a/libavfilter/vf_drawbox.o b/libavfilter/vf_drawbox.o
index 715abea..d361fb8 100644..100755
--- a/libavfilter/vf_drawbox.o
+++ b/libavfilter/vf_drawbox.o
Binary files differ
diff --git a/libavfilter/vf_edgedetect.o b/libavfilter/vf_edgedetect.o
index 2658f00..b048752 100644..100755
--- a/libavfilter/vf_edgedetect.o
+++ b/libavfilter/vf_edgedetect.o
Binary files differ
diff --git a/libavfilter/vf_fade.o b/libavfilter/vf_fade.o
index 9798427..51a6ee4 100644..100755
--- a/libavfilter/vf_fade.o
+++ b/libavfilter/vf_fade.o
Binary files differ
diff --git a/libavfilter/vf_field.o b/libavfilter/vf_field.o
index 0911caa..0a40fc1 100644..100755
--- a/libavfilter/vf_field.o
+++ b/libavfilter/vf_field.o
Binary files differ
diff --git a/libavfilter/vf_fieldorder.o b/libavfilter/vf_fieldorder.o
index 68a39bf..2be63dc 100644..100755
--- a/libavfilter/vf_fieldorder.o
+++ b/libavfilter/vf_fieldorder.o
Binary files differ
diff --git a/libavfilter/vf_format.o b/libavfilter/vf_format.o
index aa0f025..733180e 100644..100755
--- a/libavfilter/vf_format.o
+++ b/libavfilter/vf_format.o
Binary files differ
diff --git a/libavfilter/vf_fps.o b/libavfilter/vf_fps.o
index 527e66b..a22f628 100644..100755
--- a/libavfilter/vf_fps.o
+++ b/libavfilter/vf_fps.o
Binary files differ
diff --git a/libavfilter/vf_framestep.o b/libavfilter/vf_framestep.o
index 1f82030..b114a2c 100644..100755
--- a/libavfilter/vf_framestep.o
+++ b/libavfilter/vf_framestep.o
Binary files differ
diff --git a/libavfilter/vf_gradfun.o b/libavfilter/vf_gradfun.o
index 39f4ede..3713196 100644..100755
--- a/libavfilter/vf_gradfun.o
+++ b/libavfilter/vf_gradfun.o
Binary files differ
diff --git a/libavfilter/vf_hflip.o b/libavfilter/vf_hflip.o
index 9e08d34..2faec47 100644..100755
--- a/libavfilter/vf_hflip.o
+++ b/libavfilter/vf_hflip.o
Binary files differ
diff --git a/libavfilter/vf_idet.o b/libavfilter/vf_idet.o
index 65ba7ba..e932edb 100644..100755
--- a/libavfilter/vf_idet.o
+++ b/libavfilter/vf_idet.o
Binary files differ
diff --git a/libavfilter/vf_lut.o b/libavfilter/vf_lut.o
index 63d7d6d..7fd39fa 100644..100755
--- a/libavfilter/vf_lut.o
+++ b/libavfilter/vf_lut.o
Binary files differ
diff --git a/libavfilter/vf_null.o b/libavfilter/vf_null.o
index c7a7ac2..33ae3f5 100644..100755
--- a/libavfilter/vf_null.o
+++ b/libavfilter/vf_null.o
Binary files differ
diff --git a/libavfilter/vf_overlay.o b/libavfilter/vf_overlay.o
index 487120a..7952434 100644..100755
--- a/libavfilter/vf_overlay.o
+++ b/libavfilter/vf_overlay.o
Binary files differ
diff --git a/libavfilter/vf_pad.o b/libavfilter/vf_pad.o
index 7e5569e..a50bfb3 100644..100755
--- a/libavfilter/vf_pad.o
+++ b/libavfilter/vf_pad.o
Binary files differ
diff --git a/libavfilter/vf_pixdesctest.o b/libavfilter/vf_pixdesctest.o
index 7575b32..771f968 100644..100755
--- a/libavfilter/vf_pixdesctest.o
+++ b/libavfilter/vf_pixdesctest.o
Binary files differ
diff --git a/libavfilter/vf_scale.o b/libavfilter/vf_scale.o
index 0152c06..5507e36 100644..100755
--- a/libavfilter/vf_scale.o
+++ b/libavfilter/vf_scale.o
Binary files differ
diff --git a/libavfilter/vf_select.o b/libavfilter/vf_select.o
index 56bb1bd..75947cb 100644..100755
--- a/libavfilter/vf_select.o
+++ b/libavfilter/vf_select.o
Binary files differ
diff --git a/libavfilter/vf_setfield.o b/libavfilter/vf_setfield.o
index 1190eef..2c23c06 100644..100755
--- a/libavfilter/vf_setfield.o
+++ b/libavfilter/vf_setfield.o
Binary files differ
diff --git a/libavfilter/vf_showinfo.o b/libavfilter/vf_showinfo.o
index eb6db6e..ab45471 100644..100755
--- a/libavfilter/vf_showinfo.o
+++ b/libavfilter/vf_showinfo.o
Binary files differ
diff --git a/libavfilter/vf_slicify.o b/libavfilter/vf_slicify.o
index 1626bb8..f13b3df 100644..100755
--- a/libavfilter/vf_slicify.o
+++ b/libavfilter/vf_slicify.o
Binary files differ
diff --git a/libavfilter/vf_swapuv.o b/libavfilter/vf_swapuv.o
index eead52e..4cb5c09 100644..100755
--- a/libavfilter/vf_swapuv.o
+++ b/libavfilter/vf_swapuv.o
Binary files differ
diff --git a/libavfilter/vf_thumbnail.o b/libavfilter/vf_thumbnail.o
index d5a3006..95e5245 100644..100755
--- a/libavfilter/vf_thumbnail.o
+++ b/libavfilter/vf_thumbnail.o
Binary files differ
diff --git a/libavfilter/vf_tile.o b/libavfilter/vf_tile.o
index e0ab6c9..8471ecd 100644..100755
--- a/libavfilter/vf_tile.o
+++ b/libavfilter/vf_tile.o
Binary files differ
diff --git a/libavfilter/vf_transpose.o b/libavfilter/vf_transpose.o
index 269fdfe..8a605f4 100644..100755
--- a/libavfilter/vf_transpose.o
+++ b/libavfilter/vf_transpose.o
Binary files differ
diff --git a/libavfilter/vf_unsharp.o b/libavfilter/vf_unsharp.o
index 4859027..0f46ad5 100644..100755
--- a/libavfilter/vf_unsharp.o
+++ b/libavfilter/vf_unsharp.o
Binary files differ
diff --git a/libavfilter/vf_vflip.o b/libavfilter/vf_vflip.o
index dbd8a8a..dc2d4f9 100644..100755
--- a/libavfilter/vf_vflip.o
+++ b/libavfilter/vf_vflip.o
Binary files differ
diff --git a/libavfilter/video.o b/libavfilter/video.o
index cb92595..f77e41c 100644..100755
--- a/libavfilter/video.o
+++ b/libavfilter/video.o
Binary files differ
diff --git a/libavfilter/vsink_nullsink.o b/libavfilter/vsink_nullsink.o
index ea27d7b..3edbef6 100644..100755
--- a/libavfilter/vsink_nullsink.o
+++ b/libavfilter/vsink_nullsink.o
Binary files differ
diff --git a/libavfilter/vsrc_cellauto.o b/libavfilter/vsrc_cellauto.o
index fafa852..ca4cb47 100644..100755
--- a/libavfilter/vsrc_cellauto.o
+++ b/libavfilter/vsrc_cellauto.o
Binary files differ
diff --git a/libavfilter/vsrc_life.o b/libavfilter/vsrc_life.o
index 0bbb508..9cb72f5 100644..100755
--- a/libavfilter/vsrc_life.o
+++ b/libavfilter/vsrc_life.o
Binary files differ
diff --git a/libavfilter/vsrc_mandelbrot.o b/libavfilter/vsrc_mandelbrot.o
index 030d7fc..ea171e7 100644..100755
--- a/libavfilter/vsrc_mandelbrot.o
+++ b/libavfilter/vsrc_mandelbrot.o
Binary files differ
diff --git a/libavfilter/vsrc_testsrc.o b/libavfilter/vsrc_testsrc.o
index 69347d4..a206112 100644..100755
--- a/libavfilter/vsrc_testsrc.o
+++ b/libavfilter/vsrc_testsrc.o
Binary files differ
diff --git a/libavformat/.utils.c.swp b/libavformat/.utils.c.swp
new file mode 100755
index 0000000..c84d0ff
--- /dev/null
+++ b/libavformat/.utils.c.swp
Binary files differ
diff --git a/libavformat/Makefile b/libavformat/Makefile
index ff16b3b..f833731 100644..100755
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -124,6 +124,8 @@ OBJS-$(CONFIG_H263_MUXER) += rawenc.o
OBJS-$(CONFIG_H264_DEMUXER) += h264dec.o rawdec.o
OBJS-$(CONFIG_H264_MUXER) += rawenc.o
OBJS-$(CONFIG_HLS_DEMUXER) += hls.o
+OBJS-$(CONFIG_SEAMLESS_DEMUXER) += RkSeamless.o
+OBJS-$(CONFIG_RKPCM_DEMUXER) += RkPcm.o
OBJS-$(CONFIG_ICO_DEMUXER) += icodec.o
OBJS-$(CONFIG_ICO_MUXER) += icoenc.o
OBJS-$(CONFIG_IDCIN_DEMUXER) += idcin.o
diff --git a/libavformat/RkPcm.c b/libavformat/RkPcm.c
new file mode 100755
index 0000000..2eb2dda
--- /dev/null
+++ b/libavformat/RkPcm.c
@@ -0,0 +1,162 @@
+/*
+ * RKPcm demuxer
+ * Copyright (c) 2003 The FFmpeg Project
+ *
+ * This demuxer will generate a 1 byte extradata for VP6F content.
+ * It is composed of:
+ * - upper 4bits: difference between encoded width and visible width
+ * - lower 4bits: difference between encoded height and visible height
+ *
+ * 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
+ */
+
+#include "libavutil/avstring.h"
+#include "libavutil/dict.h"
+#include "libavutil/opt.h"
+#include "libavutil/intfloat.h"
+#include "libavutil/mathematics.h"
+#include "libavcodec/bytestream.h"
+#include "libavcodec/mpeg4audio.h"
+#include "avformat.h"
+#include "internal.h"
+#include "avio_internal.h"
+#include "flv.h"
+
+#define RKPCM_DEBUG 0
+
+#if RKPCM_DEBUG
+#define RKPCM_LOG(...) av_log(NULL, AV_LOG_INFO, __VA_ARGS__)
+#else
+#define RKPCM_LOG(...) do { if (0) av_log(NULL, AV_LOG_INFO, __VA_ARGS__); } while (0)
+#endif
+
+#define VALIDATE_INDEX_TS_THRESH 2500
+#define FLV_TAG 0x464C5601 //.pcm
+
+typedef struct {
+ int64_t filesize;
+ int xing_toc;
+ int start_pad;
+ int end_pad;
+} RKPCMContext;
+static int rkpcm_probe(AVProbeData *p)
+{
+ const uint8_t *d;
+ d = p->buf;
+ int score = 0;
+ #if 1
+ int i;
+ for(i = 0; i < p->buf_size; i++){
+ if(d[i] != 0)
+ break;
+ }
+
+
+ if(i == p->buf_size && (i != 0)){
+ av_log(NULL, AV_LOG_ERROR,"Hery, probe p->buf_size = %d", p->buf_size);
+ score = AVPROBE_SCORE_MAX;
+ }else{
+ score = 0;
+ }
+ #endif
+ av_log(NULL, AV_LOG_ERROR,"Hery, probe size = %d", i);
+ //return score;
+ return 0;
+}
+
+static AVStream *create_stream(AVFormatContext *s, int codec_type)
+{
+ RKPCMContext *rkpcm = s->priv_data;
+ AVStream *st = avformat_new_stream(s, NULL);
+ if (!st)
+ return NULL;
+ st->codec->codec_type = codec_type;
+ st->codec->codec_id = AV_CODEC_ID_FIRST_AUDIO;
+ st->codec->channels = 2;
+ st->codec->sample_rate = 44100;
+ st->need_parsing = AVSTREAM_PARSE_FULL_RAW;
+ st->start_time = 0;
+ avpriv_set_pts_info(st, 32, 1, 1000); /* 32 bit pts in ms */
+ return st;
+}
+
+static int rkpcm_read_header(AVFormatContext *s)
+{
+ av_log(NULL, AV_LOG_ERROR, "Hery, rkpcm_read_header");
+ create_stream(s, AVMEDIA_TYPE_AUDIO);
+ s->start_time = 0;
+ return 0;
+}
+
+static int rkpcm_read_close(AVFormatContext *s)
+{
+ av_log(NULL, AV_LOG_ERROR, "Hery, rkpcm_read_close");
+ return 0;
+}
+
+static int rkpcm_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ int size = 4096;
+ int ret= av_get_packet(s->pb, pkt, size);
+ if (ret < 0){
+ av_log(NULL, AV_LOG_ERROR, "Hery, return ret = %d", ret);
+ return ret;
+ }
+ pkt->size = ret;
+ return 0;
+}
+
+static int rkpcm_read_seek(AVFormatContext *s, int stream_index,
+ int64_t ts, int flags)
+{
+ int ret ;
+ AVIOContext * pcmtest = s->pb;
+ URLContext * h = pcmtest->opaque;
+ int64_t totalsize = avio_size(s->pb);
+ int seek_time = ts / 1000;
+ int seek_pos = (seek_time * totalsize )/ 60;
+ seek_pos = (seek_pos / 4096) * 4096;
+ ret = h->prot->url_seek(h, seek_pos, SEEK_SET);
+ av_log(NULL, AV_LOG_ERROR, "Hery, rkpcm_read_seek ret = %d", ret);
+ return 0;
+}
+
+#define OFFSET(x) offsetof(RKPCMContext, x)
+#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM
+static const AVOption options[] = {
+ { NULL }
+};
+
+static const AVClass class = {
+ .class_name = "rkpcmdec",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVInputFormat ff_rkpcm_demuxer = {
+ .name = "rk, pcm",
+ .long_name = NULL_IF_CONFIG_SMALL("RKPCM (RK PCM Audio)"),
+ .priv_data_size = sizeof(RKPCMContext),
+ .read_probe = rkpcm_probe,
+ .read_header = rkpcm_read_header,
+ .read_packet = rkpcm_read_packet,
+ .read_seek = rkpcm_read_seek,
+ .read_close = rkpcm_read_close,
+ .extensions = "rkpcm",
+ .priv_class = &class,
+};
diff --git a/libavformat/RkSeamless.c b/libavformat/RkSeamless.c
new file mode 100755
index 0000000..20597e1
--- /dev/null
+++ b/libavformat/RkSeamless.c
@@ -0,0 +1,1423 @@
+/*
+ * RockChip Seemless demuxer
+ * Copyright (c) 2013 Rockchip
+ *
+ * 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
+ * RockChip Seemless demuxer
+ */
+
+#include "libavutil/avstring.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/mathematics.h"
+#include "libavutil/opt.h"
+#include "libavutil/dict.h"
+#include "libavutil/time.h"
+#include "avformat.h"
+#include "internal.h"
+#include "avio_internal.h"
+#include "url.h"
+#include <pthread.h>
+
+
+#define SEAMLESS_INITIAL_BUFFER_SIZE 32768
+#define SEAMLESS_DEBUG 0
+
+#if SEAMLESS_DEBUG
+#define SEAMLESS_LOG(...) av_log(NULL, AV_LOG_INFO, __VA_ARGS__)
+#else
+#define SEAMLESS_LOG(...) do { if (0) av_log(NULL, AV_LOG_INFO, __VA_ARGS__); } while (0)
+#endif
+
+#define RK_SEAMLESS_IDENTIFIER_TAG "#HISIPLAY"
+#define RK_SEAMLESS_START "#HISIPLAY_START_SEAMLESS"
+#define RK_SEAMLESS_STREAM "#HISIPLAY_STREAM:"
+
+#define RK_SEAM_SEG_UPDATE_THRD 5
+#define RK_SEAM_FLV_READ_FAIL_TOLERAT_THRD 5
+#define RK_SEAM_MAX_STREAMS 16
+#define RK_SEAM_DROP_PKT_CNT 8
+
+/*
+ * An apple http stream consists of a playlist with media segment files,
+ * played sequentially. There may be several playlists with the same
+ * video content, in different bandwidth variants, that are played in
+ * parallel (preferably only one bandwidth variant at a time). In this case,
+ * the user supplied the url to a main playlist that only lists the variant
+ * playlists.
+ *
+ * If the main playlist doesn't point at any variants, we still create
+ * one anonymous toplevel variant for this, to maintain the structure.
+ */
+
+enum SeamKeyType {
+ SEAM_KEY_NONE,
+ SEAM_KEY_AES_128,
+};
+
+struct SeamSegment {
+ double duration;
+ int discontinuity;
+ char url[MAX_URL_SIZE];
+ char key[MAX_URL_SIZE];
+ enum SeamKeyType key_type;
+ uint8_t iv[16];
+};
+
+struct streamTimeUpdateContext {
+ int64_t segBaseTimeStrmScale; /* with time scale of stream */
+ int64_t segThreshold; /* with time scale of stream */
+ int64_t prePktPts;
+ int64_t prePktDts;
+ int32_t haveJumpCnt;
+ int32_t forceUpdateInSeek;
+};
+
+typedef struct forceDropAudio {
+ int drop_cnt;
+}forceDropAudio;
+
+typedef enum {
+ HAVE_SEEK_FLAG = 0x01,
+ HAVE_OPEN_URL = 0x02,
+ HAVE_DONE_SUB_FORMAT_SEEK = 0x04,
+}RKSEAMLESS_SEEK_MAP;
+
+/*
+ * Each variant has its own demuxer. If it currently is active,
+ * it has an open AVIOContext too, and potentially an AVPacket
+ * containing the next packet from this stream.
+ */
+struct SeamVariant {
+ int bandwidth;
+ char url[MAX_URL_SIZE];
+ AVIOContext pb;
+ uint8_t* read_buffer;
+ URLContext *input;
+ AVFormatContext *parent;
+ int index;
+ AVFormatContext *ctx;
+ AVPacket pkt;
+ int stream_offset;
+
+ int finished;
+ int target_duration;
+ int start_seq_no;
+ int n_segments;
+ struct SeamSegment **segments;
+ int needed, cur_needed;
+ int cur_seq_no;
+ int64_t last_load_time;
+ int64_t segBaseTimeUs;
+ struct streamTimeUpdateContext upCtx[RK_SEAM_MAX_STREAMS];
+ forceDropAudio drop_audio[RK_SEAM_MAX_STREAMS];
+ char key_url[MAX_URL_SIZE];
+ uint8_t key[16];
+
+ int readPktErrCnt;
+ int newUrlAfterSeek;
+ pthread_mutex_t mutex;
+};
+
+typedef struct SeamContext {
+ int n_variants;
+ struct SeamVariant **variants;
+ int cur_seq_no;
+ int end_of_segment;
+ int first_packet;
+ int64_t first_timestamp;
+ int64_t seek_timestamp;
+ int64_t seek_origin_timestamp;
+ int seek_flags;
+ int abort;
+ AVIOInterruptCB *interrupt_callback;
+} SeamContext;
+
+static int read_chomp_line(AVIOContext *s, char *buf, int maxlen)
+{
+ int len = ff_get_line(s, buf, maxlen);
+ while (len > 0 && isspace(buf[len - 1]))
+ buf[--len] = '\0';
+ return len;
+}
+
+static void free_segment_list(struct SeamVariant *var)
+{
+ int i;
+ for (i = 0; i < var->n_segments; i++)
+ av_free(var->segments[i]);
+ av_freep(&var->segments);
+ var->n_segments = 0;
+}
+
+static void free_variant_list(SeamContext *c)
+{
+ int i;
+ for (i = 0; i < c->n_variants; i++) {
+ struct SeamVariant *var = c->variants[i];
+
+ free_segment_list(var);
+ av_free_packet(&var->pkt);
+ av_free(var->pb.buffer);
+
+ if (var->input)
+ ffurl_close(var->input);
+
+ if (var->ctx) {
+ avformat_close_input(&var->ctx);
+ }
+
+ av_free(var);
+ }
+ av_freep(&c->variants);
+ c->n_variants = 0;
+}
+
+/*
+ * Used to reset a statically allocated AVPacket to a clean slate,
+ * containing no data.
+ */
+static void reset_packet(AVPacket *pkt)
+{
+ av_init_packet(pkt);
+ pkt->data = NULL;
+}
+
+static void flush_avio_buffer(struct SeamVariant *var)
+{
+ if (var ==NULL)
+ return;
+
+ /* flush avio buffer in flv format */
+ if (!strcmp(var->ctx->iformat->name, "flv")) {
+ int len = var->ctx->pb->buf_end - var->ctx->pb->buf_ptr;
+ char buf[300] = {0};
+ int canRead = len >=300 ? 300 : len;
+ while (len) {
+ canRead = len >=300 ? 300 : len;
+ avio_read(var->ctx->pb, buf, canRead);
+ len -=canRead;
+ }
+ }
+}
+
+static void reset_demuxer_if_necessary(struct SeamVariant *var)
+{
+ int i =0;
+
+ if (var == NULL) {
+ return;
+ }
+
+ if (var->ctx && var->ctx->pb) {
+ if (var->ctx->iformat &&
+ (!strcmp(var->ctx->iformat->name, "mov,mp4,m4a,3gp,3g2,mj2") ||
+ !strcmp(var->ctx->iformat->name, "flv"))) {
+ if (var->ctx->iformat->read_close) {
+ var->ctx->iformat->read_close(var->ctx);
+ }
+
+ for(i=var->ctx->nb_streams-1; i>=0; i--) {
+ ff_free_stream(var->ctx, var->ctx->streams[i]);
+ }
+
+ var->ctx->pb->pos =0;
+ var->ctx->nb_streams = 0;
+ var->readPktErrCnt =0;
+ }
+ }
+
+ return;
+}
+
+static int flv_read_seamless_seek(AVFormatContext *s, int stream_index,
+ int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
+{
+ if (s == NULL) {
+ return -1;
+ }
+ int index = -1;
+ int64_t ret =0, seekPos = 0, curPos =0;
+ AVStream *st = NULL;
+ AVIndexEntry *ie = NULL;
+ int avioBufLen =0;
+
+ if(stream_index <0)
+ return -1;
+
+ SEAMLESS_LOG("flv_subformat_read_seek in, s: 0x%X, cur pos: %lld\n",
+ s, avio_tell(s->pb));
+
+ st = s->streams[stream_index];
+
+ SEAMLESS_LOG("stream_index: %d, st: %p, s->nb_streams: %d, st->nb_index_entries: %d\n",
+ stream_index, st, s->nb_streams, st->nb_index_entries);
+
+ if (!st || (stream_index >=s->nb_streams)) {
+ return -1;
+ }
+
+ if (st->nb_index_entries >=1) {
+ SEAMLESS_LOG("ts: %lld, idx[0]->ts: %lld, pos: %lld, idx[nb_index-1]->ts: %lld, pos: %lld\n",
+ ts, st->index_entries[0].timestamp, st->index_entries[0].pos,
+ st->index_entries[st->nb_index_entries-1].timestamp,
+ st->index_entries[st->nb_index_entries-1].pos);
+ }
+
+ if (st->index_entries) {
+ if (ts <=st->index_entries[0].timestamp) {
+ seekPos = st->index_entries[0].pos;
+ goto FLV_SEEK_SEAMLESS_OUT;
+ } else if (ts >=st->index_entries[st->nb_index_entries-1].timestamp) {
+ seekPos = st->index_entries[st->nb_index_entries-1].pos;
+ goto FLV_SEEK_SEAMLESS_OUT;
+ }
+ }
+ for (int k=0; k <st->nb_index_entries; k++) {
+ SEAMLESS_LOG("index[%d].timestamp: %lld, pos: %lld\n",
+ k, st->index_entries[k].timestamp, st->index_entries[k].pos);
+ }
+
+ index = av_index_search_timestamp(st, ts, flags);
+ SEAMLESS_LOG("after search, index: %d, nb_index_entries: %d\n",
+ index, st->nb_index_entries);
+
+ if((index < 0) || (index >=st->nb_index_entries))
+ return -1;
+
+ seekPos = st->index_entries[index].pos;
+FLV_SEEK_SEAMLESS_OUT:
+ if (seekPos >0) {
+ SEAMLESS_LOG("seek to index: %d, seekPos: %lld, seekTime: %lld\n",
+ index, seekPos, st->index_entries[index].timestamp);
+ avio_seek(s->pb, seekPos, SEEK_SET);
+ }
+
+ SEAMLESS_LOG("flv_read_seamless_seek out, cur pos: %lld, seekPos: %lld\n",
+ avio_tell(s->pb), seekPos);
+
+ return 0;
+}
+
+static struct SeamVariant *new_variant(SeamContext *c, int bandwidth,
+ const char *url, const char *base)
+{
+ struct SeamVariant *var = av_mallocz(sizeof(struct SeamVariant));
+ if (!var)
+ return NULL;
+
+ reset_packet(&var->pkt);
+ var->bandwidth = bandwidth;
+ ff_make_absolute_url(var->url, sizeof(var->url), base, url);
+ dynarray_add(&c->variants, &c->n_variants, var);
+ return var;
+}
+
+struct seam_variant_info {
+ char bandwidth[20];
+};
+
+static void handle_variant_args(struct seam_variant_info *info, const char *key,
+ int key_len, char **dest, int *dest_len)
+{
+ if (!strncmp(key, "BANDWIDTH=", key_len)) {
+ *dest = info->bandwidth;
+ *dest_len = sizeof(info->bandwidth);
+ }
+}
+
+struct seam_key_info {
+ char uri[MAX_URL_SIZE];
+ char method[10];
+ char iv[35];
+};
+
+static void handle_key_args(struct seam_key_info *info, const char *key,
+ int key_len, char **dest, int *dest_len)
+{
+ if (!strncmp(key, "METHOD=", key_len)) {
+ *dest = info->method;
+ *dest_len = sizeof(info->method);
+ } else if (!strncmp(key, "URI=", key_len)) {
+ *dest = info->uri;
+ *dest_len = sizeof(info->uri);
+ } else if (!strncmp(key, "IV=", key_len)) {
+ *dest = info->iv;
+ *dest_len = sizeof(info->iv);
+ }
+}
+
+static int parse_playlist(SeamContext *c, const char *url,
+ struct SeamVariant *var, AVIOContext *in)
+{
+ SEAMLESS_LOG("Seamless parse_playlist in\n");
+
+ int ret = 0,is_segment = 0,is_discontinuity = 0, is_variant = 0, bandwidth = 0;
+ double duration = 0;
+ enum SeamKeyType key_type = SEAM_KEY_NONE;
+ uint8_t iv[16] = "";
+ int has_iv = 0;
+ char key[MAX_URL_SIZE] = "";
+ char line[1024];
+ const char *ptr;
+ int close_in = 0;
+ if (!in) {
+ AVDictionary *opts = NULL;
+ close_in = 1;
+ /* Some Seamless servers dont like being sent the range header */
+ av_dict_set(&opts, "seekable", "0", 0);
+ av_dict_set(&opts, "user-agent","Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B334b Safari/531.21.10",0);
+ ret = avio_open2(&in, url, AVIO_FLAG_READ,
+ c->interrupt_callback, &opts);
+
+ av_dict_free(&opts);
+ if (ret < 0)
+ return ret;
+ }
+
+ read_chomp_line(in, line, sizeof(line));
+ if (strcmp(line, RK_SEAMLESS_IDENTIFIER_TAG)) {
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+
+ read_chomp_line(in, line, sizeof(line));
+ if (strcmp(line, RK_SEAMLESS_START)) {
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+
+ if (var) {
+ free_segment_list(var);
+ var->finished = 0;
+ }
+ while (!url_feof(in)) {
+ read_chomp_line(in, line, sizeof(line));
+ if (av_strstart(line, "#EXT-X-STREAM-INF:", &ptr)) {
+ struct seam_variant_info info = {{0}};
+ is_variant = 1;
+ SEAMLESS_LOG("parse_playlist, EXT-X-STREAM-INF\n");
+
+ ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_variant_args,
+ &info);
+ bandwidth = atoi(info.bandwidth);
+ } else if (av_strstart(line, "#EXT-X-KEY:", &ptr)) {
+ struct seam_key_info info = {{0}};
+ ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_key_args,
+ &info);
+ key_type = SEAM_KEY_NONE;
+ has_iv = 0;
+ if (!strcmp(info.method, "AES-128"))
+ key_type = SEAM_KEY_AES_128;
+ if (!strncmp(info.iv, "0x", 2) || !strncmp(info.iv, "0X", 2)) {
+ ff_hex_to_data(iv, info.iv + 2);
+ has_iv = 1;
+ }
+ av_strlcpy(key, info.uri, sizeof(key));
+ } else if (av_strstart(line, "#EXT-X-TARGETDURATION:", &ptr)) {
+ if (!var) {
+ var = new_variant(c, 0, in->url, NULL);
+ if (!var) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ }
+ var->target_duration = atoi(ptr);
+ } else if (av_strstart(line, "#EXT-X-MEDIA-SEQUENCE:", &ptr)) {
+ if (!var) {
+ var = new_variant(c, 0, in->url, NULL);
+ if (!var) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ }
+ var->start_seq_no = atoi(ptr);
+ } else if (av_strstart(line, "#HISIPLAY_ENDLIST", &ptr)) {
+ if (var)
+ var->finished = 1;
+ } else if (av_strstart(line, "#HISIPLAY_STREAM:", &ptr)) {
+ is_segment = 1;
+ duration = strtod(ptr,NULL);
+ }else if(av_strstart(line, "#EXT-X-DISCONTINUITY",NULL)){
+ is_discontinuity = 1;
+ } else if (av_strstart(line, "#", NULL)) {
+ continue;
+ } else if (line[0]) {
+ if (is_variant) {
+ SEAMLESS_LOG("parse_playlist, 1st url = %s\n", in->url);
+
+ if (!new_variant(c, bandwidth, line, in->url)) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ is_variant = 0;
+ bandwidth = 0;
+ }
+ if (is_segment) {
+ struct SeamSegment *seg;
+ if (!var) {
+ var = new_variant(c, 0, in->url, NULL);
+ if (!var) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ }
+
+ seg = av_malloc(sizeof(struct SeamSegment));
+ if (!seg) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ seg->duration = duration;
+ seg->key_type = key_type;
+
+ if(is_discontinuity){
+ seg->discontinuity = 1;
+ is_discontinuity = 0;
+ }else{
+ seg->discontinuity = 0;
+ }
+ if (has_iv) {
+ memcpy(seg->iv, iv, sizeof(iv));
+ } else {
+ int seq = var->start_seq_no + var->n_segments;
+ memset(seg->iv, 0, sizeof(seg->iv));
+ AV_WB32(seg->iv + 12, seq);
+ }
+
+ SEAMLESS_LOG("queue : %d segment, durMs: %f, url: %s\n",
+ var->n_segments, seg->duration, line);
+
+ ff_make_absolute_url(seg->key, sizeof(seg->key), in->url, key);
+ ff_make_absolute_url(seg->url, sizeof(seg->url), in->url, line);
+ dynarray_add(&var->segments, &var->n_segments, seg);
+ is_segment = 0;
+ }
+ }
+ }
+ if (var)
+ var->last_load_time = av_gettime();
+
+fail:
+ if (close_in)
+ avio_close(in);
+ return ret;
+}
+
+static int open_input(struct SeamVariant *var)
+{
+ AVDictionary *opts = NULL;
+ int ret, i =0;
+
+ struct SeamSegment *seg = var->segments[var->cur_seq_no - var->start_seq_no];
+ av_dict_set(&opts, "seekable", "1", 0);
+ av_dict_set(&opts, "timeout", "500000", 0);
+ av_dict_set(&opts, "user-agent","Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B334b Safari/531.21.10",0);
+
+ /* now open a new url of SeamSegment */
+ if (var->cur_seq_no >=0) {
+ SEAMLESS_LOG("open_input, cur_seq: %d, seg->key_type: %d, seg->url: %s\n",
+ var->cur_seq_no, seg->key_type, seg->url);
+ }
+
+ if (var->newUrlAfterSeek & HAVE_SEEK_FLAG) {
+ var->newUrlAfterSeek |=HAVE_OPEN_URL;
+ var->newUrlAfterSeek &=(~HAVE_SEEK_FLAG);
+ }
+
+ var->segBaseTimeUs =0;
+ if (var->cur_seq_no >var->start_seq_no) {
+ for (i =0; i <RK_SEAM_MAX_STREAMS; i++) {
+ var->drop_audio[i].drop_cnt =RK_SEAM_DROP_PKT_CNT;
+ }
+ }
+
+ /* calculate the base time of segments */
+ for (i =0; i <var->cur_seq_no; i++) {
+ if (var->segments[i]) {
+ var->segBaseTimeUs +=(var->segments[i]->duration*1000000);
+ }
+ }
+ SEAMLESS_LOG("open_input, segBaseTimeUs is: %lld\n", var->segBaseTimeUs);
+
+ if (seg->key_type == SEAM_KEY_NONE) {
+ ret = ffurl_open(&var->input, seg->url, AVIO_FLAG_READ,
+ &var->parent->interrupt_callback, &opts);
+ if (var->cur_seq_no >=0) {
+ SEAMLESS_LOG("open_input, ret: %d, s->pos: %lld\n",
+ ret, var->pb.pos);
+ if (var->ctx && var->ctx->pb) {
+ SEAMLESS_LOG("var->ctx->pb pos: %lld\n", var->ctx->pb->pos);
+ }
+ if (!ret) {
+ reset_demuxer_if_necessary(var);
+ }
+ }
+ goto cleanup;
+ } else if (seg->key_type == SEAM_KEY_AES_128) {
+ char iv[33], key[33], url[MAX_URL_SIZE];
+ if (strcmp(seg->key, var->key_url)) {
+ URLContext *uc;
+ if (ffurl_open(&uc, seg->key, AVIO_FLAG_READ,
+ &var->parent->interrupt_callback, &opts) == 0) {
+ if (ffurl_read_complete(uc, var->key, sizeof(var->key))
+ != sizeof(var->key)) {
+ av_log(NULL, AV_LOG_ERROR, "Unable to read key file %s\n",
+ seg->key);
+ }
+ ffurl_close(uc);
+ } else {
+ av_log(NULL, AV_LOG_ERROR, "Unable to open key file %s\n",
+ seg->key);
+ }
+ av_strlcpy(var->key_url, seg->key, sizeof(var->key_url));
+ }
+ ff_data_to_hex(iv, seg->iv, sizeof(seg->iv), 0);
+ ff_data_to_hex(key, var->key, sizeof(var->key), 0);
+ iv[32] = key[32] = '\0';
+ if (strstr(seg->url, "://"))
+ snprintf(url, sizeof(url), "crypto+%s", seg->url);
+ else
+ snprintf(url, sizeof(url), "crypto:%s", seg->url);
+ if ((ret = ffurl_alloc(&var->input, url, AVIO_FLAG_READ,
+ &var->parent->interrupt_callback)) < 0)
+ goto cleanup;
+ av_opt_set(var->input->priv_data, "key", key, 0);
+ av_opt_set(var->input->priv_data, "iv", iv, 0);
+ /* Need to repopulate options */
+ av_dict_free(&opts);
+ av_dict_set(&opts, "seekable", "0", 0);
+ av_dict_set(&opts, "user-agent","Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B334b Safari/531.21.10",0);
+ av_dict_set(&opts, "timeout", "500000", 0);
+ if ((ret = ffurl_connect(var->input, &opts)) < 0) {
+ ffurl_close(var->input);
+ var->input = NULL;
+ goto cleanup;
+ }
+ ret = 0;
+ }
+ else
+ ret = AVERROR(ENOSYS);
+
+cleanup:
+ av_dict_free(&opts);
+ return ret;
+}
+
+static int64_t read_seek(void *opaque, int64_t offset, int whence)
+{
+ struct SeamVariant *v = opaque;
+ if ((v == NULL) || (v->input == NULL)) {
+ SEAMLESS_LOG("read_seek error, input parameter invalid\n");
+ return -1;
+ }
+
+ int avioBufSize = v->ctx->pb->buf_end - v->ctx->pb->buf_ptr;
+ /*SEAMLESS_LOG("read_seek in, offset: %lld, avio_buf size: %d, newUrlAfterSeek: 0x%X\n",
+ offset, avioBufSize, v->newUrlAfterSeek);*/
+
+ int64_t ret = 0;
+ int seekTryCnt = 5;
+ while(seekTryCnt--) {
+ ret = ffurl_seek(v->input, offset, whence);
+ if (ret <0) {
+ av_usleep(500000);
+ SEAMLESS_LOG("read_seek, seek offset: %lld fail, try time: %d th\n",
+ offset, seekTryCnt);
+ } else {
+ break;
+ }
+ }
+ //SEAMLESS_LOG("read_seek ret: %lld\n", ret);
+ return ret;
+}
+
+static int read_data(void *opaque, uint8_t *buf, int buf_size)
+{
+ struct SeamVariant *v = opaque;
+ SeamContext *c = v->parent->priv_data;
+ int ret, i,retry = 0,parse_list_retry = 20,read_timeout_cnt = 0;
+ int64_t last_load_timeUs = av_gettime();
+ if(v->parent->exit_flag){
+ return AVERROR_EOF;
+ }
+
+ int haveOpenInput =0;
+
+restart:
+ if (!v->input) {
+ /* If this is a live stream and the reload interval has elapsed since
+ * the last playlist reload, reload the variant playlists now. */
+ int64_t reload_interval = v->n_segments > 0 ?
+ v->segments[v->n_segments - 1]->duration :
+ v->target_duration;
+ reload_interval *= 1000000;
+
+reload:
+ if (c->cur_seq_no >=1) {
+ SEAMLESS_LOG("cur_seq: %d, finished: %d\n",
+ c->cur_seq_no, v->finished);
+ }
+
+ if (!v->finished &&
+ av_gettime() - v->last_load_time >= reload_interval) {
+ if ((ret = parse_playlist(c, v->url, v, NULL)) < 0){
+ parse_list_retry--;
+ if(parse_list_retry < 0){
+ av_log(NULL, AV_LOG_ERROR,"parse_playlist return ret = %d",ret);
+ return ret;
+ }
+ av_usleep(1000*1000);
+ }
+ /* If we need to reload the playlist again below (if
+ * there's still no more segments), switch to a reload
+ * interval of half the target duration. */
+ reload_interval = v->target_duration * 500000LL;
+ }
+ if (v->cur_seq_no < v->start_seq_no) {
+ av_log(NULL, AV_LOG_WARNING,
+ "skipping %d segments ahead, expired from playlists\n",
+ v->start_seq_no - v->cur_seq_no);
+ v->cur_seq_no = v->start_seq_no;
+ }
+
+ if (c->cur_seq_no >=1) {
+ SEAMLESS_LOG("cur_seq: %d, start_seq_no: %d, n_segments: %d\n",
+ c->cur_seq_no, v->start_seq_no, v->n_segments);
+ }
+
+ if (v->cur_seq_no >= v->start_seq_no + v->n_segments) {
+ if (v->finished){
+ av_log(NULL, AV_LOG_ERROR, "finished Seamless read data AVERROR_EOF\n");
+ return AVERROR_EOF;
+ }
+ while (av_gettime() - v->last_load_time < reload_interval) {
+ if (ff_check_interrupt(c->interrupt_callback))
+ return AVERROR_EXIT;
+ av_usleep(100*1000);
+ }
+ /* Enough time has elapsed since the last reload */
+ goto reload;
+ }
+
+ if (c->cur_seq_no >=1) {
+ SEAMLESS_LOG("cur_seq: %d, call open_input\n", c->cur_seq_no);
+ }
+
+ ret = open_input(v);
+ if (ret < 0){
+ if((av_gettime() - last_load_timeUs) >= 60000000){
+ ffurl_close(v->input);
+ v->input = NULL;
+ v->cur_seq_no++;
+ av_log(NULL, AV_LOG_ERROR, "Seamless read data skip current url");
+ c->end_of_segment = 1;
+ c->cur_seq_no = v->cur_seq_no;
+ last_load_timeUs = av_gettime();
+
+ return ret;
+ }else{
+ if(c->abort || v->parent->exit_flag){
+ return AVERROR_EOF;
+ }
+ av_log(NULL, AV_LOG_ERROR,"open_input reload");
+ av_usleep(200*1000);
+ goto reload;
+ }
+ }else {
+ haveOpenInput = 1;
+ }
+ }
+ last_load_timeUs = av_gettime();
+ retry = 15;
+ int notGetDataCnt =0;
+ while(retry--){
+ ret = ffurl_read(v->input, buf, buf_size);
+ if (haveOpenInput) {
+ SEAMLESS_LOG("ffurl_read read %d bytes after open one new input, ret: %d\n",
+ buf_size, ret);
+ }
+ if (ret > 0){
+ return ret;
+ }
+ if(ret == 0){
+ notGetDataCnt++;
+ SEAMLESS_LOG("%d th not get any data from net....\n", notGetDataCnt);
+ if (notGetDataCnt >=5) {
+ break;
+ }
+ } else if (ret == AVERROR(ETIMEDOUT)) {
+ retry++;
+ SEAMLESS_LOG("ffurl_read timeout in read_data of RkSeamless\n");
+ } else {
+ SEAMLESS_LOG("ffurl_read <0 in read_data of RkSeamless, ret: %d\n", ret);
+ }
+
+ if(c->abort || v->parent->exit_flag){
+ av_log(NULL, AV_LOG_ERROR,"ffurl_read ret = %d",ret);
+ return AVERROR_EOF;
+ }
+ }
+
+ SEAMLESS_LOG("now we will open next url of the playList\n");
+ ffurl_close(v->input);
+ v->input = NULL;
+ v->cur_seq_no++;
+
+ c->end_of_segment = 1;
+ c->cur_seq_no = v->cur_seq_no;
+ read_timeout_cnt = 0;
+
+ if (v->ctx && v->ctx->nb_streams && v->parent->nb_streams >= v->stream_offset + v->ctx->nb_streams) {
+ v->needed = 0;
+ for (i = v->stream_offset; i < v->stream_offset + v->ctx->nb_streams;
+ i++) {
+ if (v->parent->streams[i]->discard < AVDISCARD_ALL)
+ v->needed = 1;
+ }
+ }
+
+ SEAMLESS_LOG("read_data, v->needed: %d, cur_seq_no: %d, start_seq_no: %d\n",
+ v->needed, c->cur_seq_no, v->start_seq_no);
+
+ if (!v->needed) {
+ av_log(v->parent, AV_LOG_ERROR, "No longer receiving variant %d\n",
+ v->index);
+ return AVERROR_EOF;
+ }
+ goto restart;
+}
+
+static int seamless_read_header(AVFormatContext *s)
+{
+ SEAMLESS_LOG("seamless_read_header in\n");
+
+ SeamContext *c = s->priv_data;
+ int ret = 0, i, j, stream_offset = 0,retry = 0;
+ c->interrupt_callback = &s->interrupt_callback;
+
+loadplaylist:
+ if ((ret = parse_playlist(c, s->filename, NULL, s->pb)) < 0){
+ if(retry > 5){
+ goto fail;
+ }else{
+ if(ret == AVERROR_EXIT || s->exit_flag){
+ ret = AVERROR_EOF;
+ goto fail;
+ }
+ retry++;
+ av_usleep(100*1000);
+ goto loadplaylist;
+ }
+ }
+
+ if (c->n_variants == 0) {
+ av_log(NULL, AV_LOG_WARNING, "Empty playlist\n");
+ ret = AVERROR_EOF;
+ goto fail;
+ }
+ /* If the playlist only contained variants, parse each individual
+ * variant playlist. */
+ retry = 0;
+loadplaylist1:
+ if (c->n_variants > 1 || c->variants[0]->n_segments == 0) {
+ // for (i = 0; i < c->n_variants; i++) {
+ struct SeamVariant *v = c->variants[0];
+ if ((ret = parse_playlist(c, v->url, v, NULL)) < 0){
+ if(retry > 5){
+ goto fail;
+ }else{
+ if(ret == AVERROR_EXIT || s->exit_flag){
+ ret = AVERROR_EOF;
+ goto fail;
+ }
+ retry++;
+ av_usleep(100*1000);
+ goto loadplaylist1;
+ }
+ }
+ }
+
+ if (c->variants[0]->n_segments == 0) {
+ av_log(NULL, AV_LOG_WARNING, "Empty playlist\n");
+ ret = AVERROR_EOF;
+ goto fail;
+ }
+
+ SEAMLESS_LOG("after parse list, live stream flag: %d\n",
+ !c->variants[0]->finished);
+
+ /* If this isn't a live stream, calculate the total duration of the
+ * stream. */
+ if (c->variants[0]->finished) {
+ double duration = 0;
+ for (i = 0; i < c->variants[0]->n_segments; i++)
+ duration += c->variants[0]->segments[i]->duration;
+ s->duration = duration * AV_TIME_BASE;
+ }
+
+ /* Open the demuxer for each variant */
+// for (i = 0; i < c->n_variants; i++) {
+ i = 0;
+ struct SeamVariant *v = c->variants[i];
+ AVInputFormat *in_fmt = NULL;
+ char bitrate_str[20];
+ // if (v->n_segments == 0)
+ // continue;
+
+ if (!(v->ctx = avformat_alloc_context())) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ v->index = i;
+ v->needed = 1;
+ v->parent = s;
+ memset(&v->upCtx, 0, sizeof(v->upCtx));
+ memset(&v->drop_audio, 0, sizeof(v->drop_audio));
+
+ pthread_mutex_init(&v->mutex, NULL);
+
+ /* If this is a live stream with more than 3 segments, start at the
+ * third last segment. */
+ v->cur_seq_no = v->start_seq_no;
+ if (!v->finished && v->n_segments > 3)
+ v->cur_seq_no = v->start_seq_no + v->n_segments - 3;
+
+ v->read_buffer = av_malloc(SEAMLESS_INITIAL_BUFFER_SIZE);
+
+ ffio_init_context(&v->pb, v->read_buffer, SEAMLESS_INITIAL_BUFFER_SIZE, 0, v,
+ read_data, NULL, read_seek);
+
+ v->pb.seekable = 0;
+ ret = av_probe_input_buffer(&v->pb, &in_fmt, v->segments[0]->url,
+ NULL, 0, 0);
+ if (ret < 0) {
+ /* Free the ctx - it isn't initialized properly at this point,
+ * so avformat_close_input shouldn't be called. If
+ * avformat_open_input fails below, it frees and zeros the
+ * context, so it doesn't need any special treatment like this. */
+ av_log(s, AV_LOG_ERROR, "Error when loading first segment '%s'\n", v->segments[0]->url);
+ avformat_free_context(v->ctx);
+ v->ctx = NULL;
+ goto fail;
+ }
+
+ if (in_fmt && in_fmt->name && !strcmp(in_fmt->name, "flv")) {
+ v->pb.seekable = 1;
+ } else {
+ v->pb.seekable = 0;
+ v->pb.seamless_mp4 = 1;
+ }
+ if (v->ctx->pb) {
+ av_free(v->ctx->pb);
+ v->ctx->pb = NULL;
+ }
+
+ if (!v->ctx->pb) {
+ v->ctx->pb = (AVIOContext*)av_malloc(sizeof(AVIOContext));
+ if (!v->ctx->pb) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ }
+ memcpy(v->ctx->pb, &v->pb, sizeof(AVIOContext));
+
+ SEAMLESS_LOG("read_header, will call avformat_open_input, v->pb: %p\n", v->ctx->pb);
+
+ ret = avformat_open_input(&v->ctx, v->segments[0]->url, in_fmt, NULL);
+
+ SEAMLESS_LOG("read_header, after do avformat_open_input, ret: %d\n", ret);
+
+ if (ret < 0)
+ goto fail;
+
+ v->stream_offset = stream_offset;
+ v->ctx->ctx_flags &= ~AVFMTCTX_NOHEADER;
+ ret = avformat_find_stream_info(v->ctx, NULL);
+ if (ret < 0) {
+ SEAMLESS_LOG("read_header, find stream info fail\n");
+ goto fail;
+ }
+
+ SEAMLESS_LOG("read_header, stream num: %d\n", v->ctx->nb_streams);
+
+ snprintf(bitrate_str, sizeof(bitrate_str), "%d", v->bandwidth);
+ /* Create new AVStreams for each stream in this variant */
+ for (j = 0; j < v->ctx->nb_streams; j++) {
+ SEAMLESS_LOG("now new stream num: %d\n", j);
+
+ AVStream *st = avformat_new_stream(s, NULL);
+ if (!st) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ st->id = i;
+ if (v->ctx && v->ctx->iformat &&
+ (!strcmp(v->ctx->iformat->name, "mov,mp4,m4a,3gp,3g2,mj2") ||
+ !strcmp(v->ctx->iformat->name, "flv"))) {
+ st->time_base.num = v->ctx->streams[j]->time_base.num;
+ st->time_base.den = v->ctx->streams[j]->time_base.den;
+ }
+
+ avcodec_copy_context(st->codec, v->ctx->streams[j]->codec);
+ if (v->bandwidth)
+ av_dict_set(&st->metadata, "variant_bitrate", bitrate_str,
+ 0);
+ }
+ stream_offset += v->ctx->nb_streams;
+ // }
+
+ c->first_packet = 1;
+ c->first_timestamp = AV_NOPTS_VALUE;
+ c->seek_timestamp = AV_NOPTS_VALUE;
+ c->seek_origin_timestamp = AV_NOPTS_VALUE;
+
+ SEAMLESS_LOG("read_header out\n");
+ return 0;
+fail:
+ free_variant_list(c);
+ return ret;
+}
+
+static int recheck_discard_flags(AVFormatContext *s, int first)
+{
+ SeamContext *c = s->priv_data;
+ int i, changed = 0;
+
+ /* Check if any new streams are needed */
+ for (i = 0; i < c->n_variants; i++)
+ c->variants[i]->cur_needed = 0;
+
+ for (i = 0; i < s->nb_streams; i++) {
+ AVStream *st = s->streams[i];
+ struct SeamVariant *var = c->variants[s->streams[i]->id];
+ if (st->discard < AVDISCARD_ALL)
+ var->cur_needed = 1;
+ }
+ for (i = 0; i < c->n_variants; i++) {
+ struct SeamVariant *v = c->variants[i];
+ if (v->cur_needed && !v->needed) {
+ v->needed = 1;
+ changed = 1;
+ v->cur_seq_no = c->cur_seq_no;
+ v->pb.eof_reached = 0;
+ av_log(s, AV_LOG_INFO, "Now receiving variant %d\n", i);
+ } else if (first && !v->cur_needed && v->needed) {
+ if (v->input)
+ ffurl_close(v->input);
+ v->input = NULL;
+ v->needed = 0;
+ changed = 1;
+ av_log(s, AV_LOG_INFO, "No longer receiving variant %d\n", i);
+ }
+ }
+ return changed;
+}
+
+static int check_update_base_time(struct SeamVariant* v, AVPacket *pkt)
+{
+ if ((v ==NULL) || (pkt == NULL)) {
+ return 0;
+ }
+
+ if (pkt->stream_index >=RK_SEAM_MAX_STREAMS) {
+ /* invalid stream index */
+ return 0;
+ }
+
+ int32_t* jumpCnt = &v->upCtx[pkt->stream_index].haveJumpCnt;
+ if ((pkt->pts == AV_NOPTS_VALUE) && (pkt->dts == AV_NOPTS_VALUE)) {
+ if (((*jumpCnt)++) >=10) {
+ *jumpCnt =0;
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+
+ int64_t deltaTime = 0;
+ int64_t* prePts = &v->upCtx[pkt->stream_index].prePktPts;
+ int64_t* preDts = &v->upCtx[pkt->stream_index].prePktDts;
+ int64_t* threshold = &v->upCtx[pkt->stream_index].segThreshold;
+
+ if (pkt->pts != AV_NOPTS_VALUE) {
+ if (*prePts ==0) {
+ *prePts = pkt->pts;
+ } else {
+ deltaTime = abs(pkt->pts - *prePts);
+ }
+ }
+ if (pkt->dts != AV_NOPTS_VALUE) {
+ if (*preDts ==0) {
+ *preDts = pkt->dts;
+ } else {
+ if (deltaTime ==0) {
+ deltaTime = abs(pkt->dts - *preDts);
+ }
+ }
+ }
+
+ /*SEAMLESS_LOG("stream: %d, deltaTime: %lld, segThreshold: %lld",
+ pkt->stream_index, deltaTime, *threshold);*/
+
+ if (deltaTime && (deltaTime >(*threshold))) {
+ SEAMLESS_LOG("segment time jump cnt: %d, delta: %lld",
+ *jumpCnt, deltaTime);
+ (*jumpCnt)++;
+ if ((*jumpCnt) >=RK_SEAM_SEG_UPDATE_THRD) {
+ *jumpCnt =0;
+ *prePts =0;
+ *preDts =0;
+ v->upCtx[pkt->stream_index].forceUpdateInSeek = 0;
+ return 1;
+ }
+ } else {
+ *jumpCnt ==0;
+ }
+
+ if (*jumpCnt ==0) {
+ if (pkt->pts != AV_NOPTS_VALUE) {
+ *prePts = pkt->pts;
+ }
+
+ if (pkt->dts != AV_NOPTS_VALUE) {
+ *preDts = pkt->dts;
+ }
+ }
+
+ return 0;
+}
+
+static int seamless_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ SeamContext *c = s->priv_data;
+ int ret, i, minvariant = -1;
+
+ if (c->first_packet) {
+ recheck_discard_flags(s, 1);
+ c->first_packet = 0;
+ }
+
+start:
+ c->end_of_segment = 0;
+ // for (i = 0; i < c->n_variants; i++) {
+ i = 0;
+ struct SeamVariant *var = c->variants[i];
+
+ /* Make sure we've got one buffered packet from each open variant
+ * stream */
+ if (var->needed && !var->pkt.data) {
+ while (1) {
+ int64_t ts_diff;
+ AVStream *st;
+ ret = av_read_frame(var->ctx, &var->pkt);
+
+ if (ret < 0) {
+ SEAMLESS_LOG("read packet, read frame fail, readPktErrCnt: %d, ret: %d\n",
+ var->readPktErrCnt, ret);
+ if (!url_feof(&var->pb) && ret != AVERROR_EOF){
+ SEAMLESS_LOG("seamless_read_packet fail, ret: %d, AVERROR(): %d, EAGAIN: %d\n",
+ ret, AVERROR(EAGAIN), EAGAIN);
+ if ((ret ==AVERROR(EAGAIN)) &&
+ (!strcmp(var->ctx->iformat->name, "flv"))) {
+ if (var->readPktErrCnt <RK_SEAM_FLV_READ_FAIL_TOLERAT_THRD) {
+ var->readPktErrCnt++;
+ reset_packet(&var->pkt);
+ SEAMLESS_LOG("continue\n");
+ continue;
+ } else {
+ SEAMLESS_LOG("read packet, readPktErrCnt beyonds threshold\n");
+ var->readPktErrCnt =0;
+ }
+ }
+
+ SEAMLESS_LOG("read packet return err: %d\n", ret);
+ return ret;
+ }
+ SEAMLESS_LOG("seamless_read_packet AVERROR_EOF ret = %d\n",ret);
+
+ reset_packet(&var->pkt);
+ break;
+ } else {
+ if (c->first_timestamp == AV_NOPTS_VALUE)
+ c->first_timestamp = var->pkt.dts;
+ }
+
+ if (c->seek_timestamp == AV_NOPTS_VALUE)
+ break;
+
+ if (var->pkt.dts == AV_NOPTS_VALUE) {
+ c->seek_timestamp = AV_NOPTS_VALUE;
+ c->seek_origin_timestamp = AV_NOPTS_VALUE;
+ break;
+ }
+
+ st = var->ctx->streams[var->pkt.stream_index];
+ ts_diff = av_rescale_rnd(var->pkt.dts, AV_TIME_BASE,
+ st->time_base.den, AV_ROUND_DOWN) -
+ c->seek_timestamp;
+
+ if ((var->newUrlAfterSeek & HAVE_OPEN_URL) &&
+ (!(var->newUrlAfterSeek & HAVE_DONE_SUB_FORMAT_SEEK))) {
+ int64_t seekTimeUs = c->seek_timestamp;
+ seekTimeUs = (seekTimeUs)/(1000000ll*av_q2d(st->time_base));
+ int64_t curPos = avio_tell(var->ctx->pb);
+ int seekRet = 0;
+ int flags =0;
+
+ SEAMLESS_LOG("call av_seek_frame for new url after seek, pkt size: %d, index: %d\n",
+ var->pkt.size, var->pkt.stream_index);
+
+ if (!strcmp(var->ctx->iformat->name, "flv")) {
+ flags |=AVSEEK_FLAG_BYTE;
+ seekRet = flv_read_seamless_seek(var->ctx,
+ var->pkt.stream_index, -1, seekTimeUs, INT64_MAX, flags);
+ } else {
+ if (var->ctx->iformat->read_seek) {
+ var->ctx->iformat->read_seek(var->ctx,
+ var->pkt.stream_index, seekTimeUs,
+ flags | AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_ANY);
+ }
+ }
+
+ var->newUrlAfterSeek |=HAVE_DONE_SUB_FORMAT_SEEK;
+
+ SEAMLESS_LOG("pb: 0x%X, new url seek to: %lld(us), %lld(StrmScale), ret: %d, curPos: %lld\n",
+ var->ctx->pb, c->seek_timestamp, seekTimeUs, seekRet, curPos);
+ continue;
+ }
+
+ SEAMLESS_LOG("ts_diff: %lld, stream_index: %d, pts: %lld, dts: %lld, "
+ "seek_timestamp: %lld, var->pkt.flags: 0x%X, base: %d/%d, curPos: %lld\n",
+ ts_diff, var->pkt.stream_index, var->pkt.pts, var->pkt.dts,
+ c->seek_timestamp, var->pkt.flags, st->time_base.num, st->time_base.den,
+ avio_tell(var->ctx->pb));
+
+ if (ts_diff >=0 && (var->newUrlAfterSeek & HAVE_OPEN_URL) &&
+ (c->seek_flags & AVSEEK_FLAG_ANY || var->pkt.flags & AV_PKT_FLAG_KEY)) {
+ c->seek_timestamp = AV_NOPTS_VALUE;
+ break;
+ }
+ }
+ }
+
+ var->newUrlAfterSeek =0;
+
+ /* Check if this stream has the packet with the lowest dts */
+ if (var->pkt.data) {
+ if(minvariant < 0) {
+ minvariant = i;
+ } else {
+ struct SeamVariant *minvar = c->variants[minvariant];
+ int64_t dts = var->pkt.dts;
+ int64_t mindts = minvar->pkt.dts;
+ AVStream *st = var->ctx->streams[ var->pkt.stream_index];
+ AVStream *minst= minvar->ctx->streams[minvar->pkt.stream_index];
+
+ if( st->start_time != AV_NOPTS_VALUE) dts -= st->start_time;
+ if(minst->start_time != AV_NOPTS_VALUE) mindts -= minst->start_time;
+
+ if (av_compare_ts(dts, st->time_base, mindts, minst->time_base) < 0)
+ minvariant = i;
+ }
+ }
+ // }
+ if (c->end_of_segment) {
+ if (recheck_discard_flags(s, 0)){
+ goto start;
+ }
+ }
+ /* If we got a packet, return it */
+ if (minvariant >= 0) {
+ AVStream *st = NULL;
+ if (var && (var->pkt.stream_index >=0) &&
+ (var->pkt.stream_index <var->ctx->nb_streams)) {
+ /* save segment base time, avoid calculating it every time */
+ if (var->pkt.stream_index <RK_SEAM_MAX_STREAMS) {
+ int64_t* segBase = &var->upCtx[var->pkt.stream_index].segBaseTimeStrmScale;
+ int64_t* segHold = &var->upCtx[var->pkt.stream_index].segThreshold;
+ st = var->ctx->streams[var->pkt.stream_index];
+
+ if (*segHold ==0) {
+ *segHold =(5000000ll)/(1000000ll*av_q2d(st->time_base)); /* 5s */
+ }
+
+ if (check_update_base_time(var, &var->pkt) ||
+ var->upCtx[var->pkt.stream_index].forceUpdateInSeek) {
+ *segBase =(var->segBaseTimeUs)/(1000000ll*av_q2d(st->time_base));
+ SEAMLESS_LOG("update segBaseTimeUs to: %lld", *segBase);
+ }
+
+ c->variants[minvariant]->pkt.pts +=(*segBase);
+ c->variants[minvariant]->pkt.dts +=(*segBase);
+ }
+ }
+
+ *pkt = c->variants[minvariant]->pkt;
+ pkt->stream_index += c->variants[minvariant]->stream_offset;
+ reset_packet(&c->variants[minvariant]->pkt);
+
+ if (pkt && (pkt->stream_index >=0) &&
+ (pkt->stream_index <RK_SEAM_MAX_STREAMS) &&
+ (var->drop_audio[var->pkt.stream_index].drop_cnt) &&
+ st && st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
+ /* drop some audio packet after open new url */
+ pkt->stream_index = -1;
+ av_free_packet(pkt);
+ var->drop_audio[var->pkt.stream_index].drop_cnt--;
+
+ SEAMLESS_LOG("drop one audio packet, left %d packet(s) to drop\n",
+ var->drop_audio[var->pkt.stream_index].drop_cnt);
+ }
+
+ return 0;
+ }
+
+ av_log(NULL, AV_LOG_ERROR, "Seamless read AVERROR_EOF\n");
+ return AVERROR_EOF;
+}
+
+static int seamless_close(AVFormatContext *s)
+{
+ SeamContext *c = s->priv_data;
+
+ free_variant_list(c);
+ return 0;
+}
+
+static int seamless_read_seek(AVFormatContext *s, int stream_index,
+ int64_t timestamp, int flags)
+{
+ SeamContext *c = s->priv_data;
+ int i, j, ret;
+ i = 0;
+ struct SeamVariant *var = c->variants[i];
+
+ SEAMLESS_LOG("seek to: %lld, flags: %d, streamIdx: %d, newUrlAfterSeek: 0x%X\n",
+ timestamp, flags, stream_index, var->newUrlAfterSeek);
+
+ if ((flags & AVSEEK_FLAG_BYTE) || !c->variants[0]->finished)
+ return AVERROR(ENOSYS);
+
+ if (var->newUrlAfterSeek) {
+ SEAMLESS_LOG("we are current in seek now, skip this seek\n");
+ return 0;
+ }
+
+ c->seek_flags = flags;
+ c->seek_timestamp = stream_index < 0 ? timestamp :
+ av_rescale_rnd(timestamp, AV_TIME_BASE,
+ s->streams[stream_index]->time_base.den,
+ flags & AVSEEK_FLAG_BACKWARD ?
+ AV_ROUND_DOWN : AV_ROUND_UP);
+ timestamp = av_rescale_rnd(timestamp, 1, stream_index >= 0 ?
+ s->streams[stream_index]->time_base.den :
+ AV_TIME_BASE, flags & AVSEEK_FLAG_BACKWARD ?
+ AV_ROUND_DOWN : AV_ROUND_UP);
+ if (s->duration < c->seek_timestamp) {
+ c->seek_timestamp = s->duration;
+ }
+
+ c->seek_origin_timestamp = c->seek_timestamp;
+
+ ret = AVERROR(EIO);
+ // for (i = 0; i < c->n_variants; i++) {
+ /* Reset reading */
+ var->newUrlAfterSeek |=HAVE_SEEK_FLAG;
+ double pos = c->first_timestamp == AV_NOPTS_VALUE ? 0 :
+ av_rescale_rnd(c->first_timestamp, 1, stream_index >= 0 ?
+ s->streams[stream_index]->time_base.den :
+ AV_TIME_BASE, flags & AVSEEK_FLAG_BACKWARD ?
+ AV_ROUND_DOWN : AV_ROUND_UP);
+
+ if (var->input) {
+ ffurl_close(var->input);
+ var->input = NULL;
+ }
+
+ av_free_packet(&var->pkt);
+ reset_packet(&var->pkt);
+ var->pb.eof_reached = 0;
+ /* Clear any buffered data */
+ var->pb.buf_end = var->pb.buf_ptr = var->pb.buffer;
+ /* Reset the pos, to let the mpegts demuxer know we've seeked. */
+ var->pb.pos = 0;
+
+ /* Locate the segment that contains the target timestamp */
+ for (j = 0; j < var->n_segments; j++) {
+ if (timestamp >= pos &&
+ timestamp < pos + var->segments[j]->duration) {
+ var->cur_seq_no = var->start_seq_no + j;
+ ret = 0;
+ break;
+ }
+ pos += var->segments[j]->duration;
+ }
+ if(j == var->n_segments){
+ var->cur_seq_no = var->start_seq_no + j;
+ ret = 0;
+ }
+ if (ret)
+ c->seek_timestamp = AV_NOPTS_VALUE;
+ //}
+ if(pos >=0){
+ c->seek_timestamp -= ((int64_t)pos)*1000000;
+ }else{
+ c->seek_timestamp = timestamp * 1000000ll;
+ }
+
+ for (i =0; i <var->ctx->nb_streams; i++) {
+ var->upCtx[i].forceUpdateInSeek = 1;
+ }
+
+ flush_avio_buffer(var);
+ reset_demuxer_if_necessary(var);
+
+ return ret;
+}
+
+static int seamless_probe(AVProbeData *p)
+{
+ SEAMLESS_LOG("seamless_probe in\n");
+
+ /* Require #ROCKCHIPPLAY at the start, and either one of the ones below
+ * somewhere for a proper match. */
+ if (strncmp(p->buf, RK_SEAMLESS_IDENTIFIER_TAG, strlen(RK_SEAMLESS_IDENTIFIER_TAG)))
+ return 0;
+ if (strstr(p->buf, RK_SEAMLESS_IDENTIFIER_TAG) ||
+ strstr(p->buf, RK_SEAMLESS_STREAM)) {
+ SEAMLESS_LOG("seamless probe pass\n");
+ return AVPROBE_SCORE_MAX;
+ }
+ return 0;
+}
+
+AVInputFormat ff_seamless_demuxer = {
+ .name = "rockchip_seamless",
+ .long_name = NULL_IF_CONFIG_SMALL("RockChip Seamless Streaming"),
+ .priv_data_size = sizeof(SeamContext),
+ .read_probe = seamless_probe,
+ .read_header = seamless_read_header,
+ .read_packet = seamless_read_packet,
+ .read_close = seamless_close,
+ .read_seek = seamless_read_seek,
+};
diff --git a/libavformat/allformats.c b/libavformat/allformats.c
index 3551394..1f0e934 100644..100755
--- a/libavformat/allformats.c
+++ b/libavformat/allformats.c
@@ -114,6 +114,8 @@ void av_register_all(void)
REGISTER_MUXDEMUX (H263, h263);
REGISTER_MUXDEMUX (H264, h264);
REGISTER_DEMUXER (HLS, hls);
+ REGISTER_DEMUXER (SEAMLESS, seamless);
+ REGISTER_DEMUXER (RKPCM, rkpcm);
REGISTER_MUXDEMUX (ICO, ico);
REGISTER_DEMUXER (IDCIN, idcin);
REGISTER_DEMUXER (IDF, idf);
@@ -275,6 +277,8 @@ void av_register_all(void)
#if FF_API_APPLEHTTP_PROTO
REGISTER_PROTOCOL (APPLEHTTP, applehttp);
#endif
+ REGISTER_PROTOCOL (HLS, hls);
+ REGISTER_PROTOCOL (HTTP, http);
REGISTER_PROTOCOL (BLURAY, bluray);
REGISTER_PROTOCOL (CACHE, cache);
REGISTER_PROTOCOL (CONCAT, concat);
@@ -283,8 +287,6 @@ void av_register_all(void)
REGISTER_PROTOCOL (FFRTMPHTTP, ffrtmphttp);
REGISTER_PROTOCOL (FILE, file);
REGISTER_PROTOCOL (GOPHER, gopher);
- REGISTER_PROTOCOL (HLS, hls);
- REGISTER_PROTOCOL (HTTP, http);
REGISTER_PROTOCOL (HTTPPROXY, httpproxy);
REGISTER_PROTOCOL (HTTPS, https);
REGISTER_PROTOCOL (MMSH, mmsh);
diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index 61bc4a6..a1afe25 100644..100755
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -290,6 +290,12 @@ struct AVFormatContext;
/* packet functions */
+#define MEDIA_INFO_DOWNLOAD_START 10086
+#define MEDIA_INFO_DOWNLOAD_END 10087
+#define MEDIA_INFO_DOWNLOAD_ERROR 10088
+#define MEDIA_INFO_DOWNLOAD_TIMEOUT 99110
+
+
/**
* Allocate and read the payload of a packet and initialize its
* fields with default values.
@@ -637,6 +643,7 @@ typedef struct AVIndexEntry {
* sizeof(AVStream) must not be used outside libav*.
*/
typedef struct AVStream {
+ int tsstreampid;
int index; /**< stream index in AVFormatContext */
/**
* Format-specific stream ID.
@@ -846,6 +853,8 @@ typedef struct AVStream {
* NOT PART OF PUBLIC API
*/
int64_t mux_ts_offset;
+ int64_t continuity_counter_totalnum;
+ int cur_continuity_counter;
} AVStream;
@@ -974,7 +983,7 @@ typedef struct AVFormatContext {
* durations and also do not set any of them. This is deduced from the
* AVStream values if not set.
*/
- int64_t duration;
+ double duration;
/**
* Decoding: total stream bitrate in bit/s, 0 if not
@@ -1092,6 +1101,8 @@ typedef struct AVFormatContext {
*/
AVIOInterruptCB interrupt_callback;
+ // char header[4096];
+ char* header;
/**
* Flags to enable debugging.
*/
@@ -1199,6 +1210,19 @@ typedef struct AVFormatContext {
*/
#define RAW_PACKET_BUFFER_SIZE 2500000
int raw_packet_buffer_remaining_size;
+ int exit_flag;
+ int mhlsdynamic;
+ int mhlsSort;
+ int mhlsHeShiJie;
+ int ts_debug_flag;
+ int mIPTVControlProbe;
+ int mTaoBaoHevc;
+ int mDiscontinuityNum;
+
+ unsigned char *sps_buf;
+ unsigned char *pps_buf;
+ int sps_size;
+ int pps_size;
} AVFormatContext;
/**
@@ -1677,6 +1701,9 @@ void av_set_pts_info(AVStream *s, int pts_wrap_bits,
#define AVSEEK_FLAG_BYTE 2 ///< seeking based on position in bytes
#define AVSEEK_FLAG_ANY 4 ///< seek to any frame, even non-keyframes
#define AVSEEK_FLAG_FRAME 8 ///< seeking based on frame number
+#define AVSEEK_FLAG_READ_NEED_OPEN_NEW_URL 16 ///< for seek optimize with hls by ht
+#define AVSEEK_FLAG_SPECIAL_URL 32 ///< for Ysten or BestTv lookback special url
+#define AVSEEK_FLAG_SEEK_USE_NEW_URL 64
/**
* @addtogroup lavf_encoding
diff --git a/libavformat/avio.c b/libavformat/avio.c
index 6d8a8bb..4d8fe44 100644..100755
--- a/libavformat/avio.c
+++ b/libavformat/avio.c
@@ -183,7 +183,15 @@ int ffurl_connect(URLContext* uc, AVDictionary **options)
uc->prot->url_open2 ? uc->prot->url_open2(uc, uc->filename, uc->flags, options) :
uc->prot->url_open(uc, uc->filename, uc->flags);
if (err)
+ {
+ av_log(NULL,AV_LOG_DEBUG,"errcode=%d",uc->errcode);
+ if(uc->errcode != 0 && uc->errcode > 0)
+ {
+ return -(uc->errcode);
+ }
+ else
return err;
+ }
uc->is_connected = 1;
//We must be careful here as ffurl_seek() could be slow, for example for http
if( (uc->flags & AVIO_FLAG_WRITE)
@@ -222,10 +230,10 @@ int ffurl_alloc(URLContext **puc, const char *filename, int flags,
*ptr = '\0';
while (up = ffurl_protocol_next(up)) {
- if (!strcmp(proto_str, up->name))
+ if (!av_strcasecmp(proto_str, up->name))
return url_alloc_for_protocol (puc, up, filename, flags, int_cb);
if (up->flags & URL_PROTOCOL_FLAG_NESTED_SCHEME &&
- !strcmp(proto_nested, up->name))
+ !av_strcasecmp(proto_nested, up->name))
return url_alloc_for_protocol (puc, up, filename, flags, int_cb);
}
*puc = NULL;
@@ -316,9 +324,14 @@ int ffurl_write(URLContext *h, const unsigned char *buf, int size)
int64_t ffurl_seek(URLContext *h, int64_t pos, int whence)
{
int64_t ret;
-
+ if(h == NULL || h->prot == NULL)
+ {
+ av_log(NULL, AV_LOG_ERROR, "ffurl_seek == NULL, return -1");
+ return -1;
+ }
if (!h->prot->url_seek)
return AVERROR(ENOSYS);
+
ret = h->prot->url_seek(h, pos, whence & ~AVSEEK_FORCE);
return ret;
}
@@ -420,3 +433,22 @@ int ff_check_interrupt(AVIOInterruptCB *cb)
return ret;
return 0;
}
+
+void ff_send_message(AVIOInterruptCB* cb,int what,int msg)
+{
+ if((cb != NULL) && (cb->msg_callback != NULL))
+ {
+ cb->msg_callback(cb->msg_opaque,what,msg);
+ }
+}
+
+int ff_check_operate(AVIOInterruptCB *cb,int operate,void* para1,void** para2)
+{
+ if((cb != NULL) && (cb->operate_callback != NULL))
+ {
+ return cb->operate_callback(cb->operate_opaque,operate,para1,para2);
+ }
+
+ return 0;
+}
+
diff --git a/libavformat/avio.h b/libavformat/avio.h
index 17b341d..fca53cb 100644..100755
--- a/libavformat/avio.h
+++ b/libavformat/avio.h
@@ -37,6 +37,16 @@
#define AVIO_SEEKABLE_NORMAL 0x0001 /**< Seeking works like for a local file */
+typedef struct AVIOParams {
+ char host[256];
+ int port;
+ int type;
+ int willclose;
+ void *hd;
+ char url[4096];
+ int redirect;
+} AVIOParams;
+
/**
* Callback for checking whether to abort blocking functions.
* AVERROR_EXIT is returned in this case by the interrupted
@@ -50,9 +60,15 @@
*/
typedef struct AVIOInterruptCB {
int (*callback)(void*);
+ void (*msg_callback)(void*,int,int);
+ int (*operate_callback)(void*,int,void*,void**);
void *opaque;
+ void* msg_opaque;
+ void* operate_opaque;
+ AVIOParams *ioparams;
} AVIOInterruptCB;
+
/**
* Bytestream IO Context.
* New fields can be added to the end with minor version bumps.
@@ -140,6 +156,11 @@ typedef struct AVIOContext {
* This field is internal to libavformat and access from outside is not allowed.
*/
int seek_count;
+
+ char url[4096];
+ int seamless_mp4;
+ int reserved[30];
+ int (*read_seqno)(void *opaque);// read hls seq no for ffplayer pts sync
} AVIOContext;
/* unbuffered I/O */
diff --git a/libavformat/aviobuf.c b/libavformat/aviobuf.c
index 906415d..2f7781a 100644..100755
--- a/libavformat/aviobuf.c
+++ b/libavformat/aviobuf.c
@@ -32,14 +32,18 @@
#include "url.h"
#include <stdarg.h>
-#define IO_BUFFER_SIZE 32768
+//#define IO_BUFFER_SIZE 2*1024*1024
+static size_t IO_BUFFER_SIZE = 32768;
+
/**
* Do seeks within this distance ahead of the current buffer by skipping
* data instead of calling the protocol seek function, for seekable
* protocols.
*/
-#define SHORT_SEEK_THRESHOLD 4096
+//#define SHORT_SEEK_THRESHOLD 4096
+static size_t SHORT_SEEK_THRESHOLD = 4096;
+
static void *ffio_url_child_next(void *obj, void *prev)
{
@@ -218,7 +222,7 @@ int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
s->buf_ptr = s->buffer + offset1;
} else if ((!s->seekable ||
offset1 <= s->buf_end + SHORT_SEEK_THRESHOLD - s->buffer) &&
- !s->write_flag && offset1 >= 0 &&
+ !s->write_flag && offset1 >= 0 && (s->seamless_mp4 ==0) &&
(!s->direct || !s->seek) &&
(whence != SEEK_END || force)) {
while(s->pos < offset && !s->eof_reached)
@@ -386,7 +390,7 @@ static void fill_buffer(AVIOContext *s)
{
uint8_t *dst= !s->max_packet_size && s->buf_end - s->buffer < s->buffer_size ? s->buf_end : s->buffer;
int len= s->buffer_size - (dst - s->buffer);
- int max_buffer_size = s->max_packet_size ? s->max_packet_size : IO_BUFFER_SIZE;
+ int max_buffer_size = s->max_packet_size ? s->max_packet_size : IO_BUFFER_SIZE;
/* can't fill the buffer without read_packet, just set EOF if appropriate */
if (!s->read_packet && s->buf_ptr >= s->buf_end)
@@ -418,7 +422,7 @@ static void fill_buffer(AVIOContext *s)
/* do not modify buffer if EOF reached so that a seek back can
be done without rereading data */
s->eof_reached = 1;
- if(len<0)
+ if(len<=0) //ht for huashu identified whether end of stream or reading TimeOut
s->error= len;
} else {
s->pos += len;
@@ -491,10 +495,23 @@ int avio_read(AVIOContext *s, unsigned char *buf, int size)
s->buf_end = s->buffer/* + len*/;
}
}else{
+ if(s->error == -110) // modified for huashu auto cancel playing when receive eagain by ht
+ {
+ // av_log(NULL,AV_LOG_ERROR,"avio_read:EAGIN");
+ s->eof_reached = 0;
+ }
fill_buffer(s);
len = s->buf_end - s->buf_ptr;
- if (len == 0)
+ if (len == 0)
+ {
+ if(s->error == -110) // modified for huashu auto cancel playing when receive eagain by ht
+ {
+// av_log(NULL,AV_LOG_ERROR,"avio_read:fill_buffer:EAGIN");
+ s->eof_reached = 0;
+ }
break;
+ }
+
}
} else {
memcpy(buf, s->buf_ptr, len);
@@ -673,7 +690,9 @@ int ffio_fdopen(AVIOContext **s, URLContext *h)
if (max_packet_size) {
buffer_size = max_packet_size; /* no need to bufferize more than one packet */
} else {
- buffer_size = IO_BUFFER_SIZE;
+
+ buffer_size = IO_BUFFER_SIZE;
+
}
buffer = av_malloc(buffer_size);
if (!buffer)
@@ -693,6 +712,9 @@ int ffio_fdopen(AVIOContext **s, URLContext *h)
(*s)->read_seek = (int64_t (*)(void *, int, int64_t, int))h->prot->url_read_seek;
}
(*s)->av_class = &ffio_url_class;
+
+ strcpy((*s)->url, h->url);
+
return 0;
}
@@ -771,23 +793,41 @@ int ffio_rewind_with_probe_data(AVIOContext *s, unsigned char **bufp, int buf_si
int avio_open(AVIOContext **s, const char *filename, int flags)
{
+
return avio_open2(s, filename, flags, NULL, NULL);
}
int avio_open2(AVIOContext **s, const char *filename, int flags,
const AVIOInterruptCB *int_cb, AVDictionary **options)
{
+ if(filename != NULL){
+ if(strstr(filename, "file/fd::") ){
+ IO_BUFFER_SIZE = 4096;
+ }
+ else if(strstr(filename,".mp4") && !strstr(filename,"mp4."))
+ {
+ av_log(NULL,AV_LOG_ERROR,"ffio_fdopen:MP4,IO_BUFFER_SIZE set 1MB");
+ IO_BUFFER_SIZE = 1*1024*1024;
+ SHORT_SEEK_THRESHOLD = 256*1024;
+ }
+ }
+
+ int static mControlSeekSize = 0;
URLContext *h;
int err;
err = ffurl_open(&h, filename, flags, int_cb, options);
+
if (err < 0)
return err;
err = ffio_fdopen(s, h);
+
+
if (err < 0) {
ffurl_close(h);
return err;
}
+
return 0;
}
@@ -804,6 +844,8 @@ int avio_close(AVIOContext *s)
if (!s->write_flag)
av_log(s, AV_LOG_DEBUG, "Statistics: %"PRId64" bytes read, %d seeks\n", s->bytes_read, s->seek_count);
av_free(s);
+ IO_BUFFER_SIZE = 32768;
+ SHORT_SEEK_THRESHOLD = 4096;
return ffurl_close(h);
}
diff --git a/libavformat/file.c b/libavformat/file.c
index 4d2f84a..c80d99e 100644..100755
--- a/libavformat/file.c
+++ b/libavformat/file.c
@@ -48,6 +48,7 @@
typedef struct FileContext {
const AVClass *class;
int fd;
+ int64_t offset;
int trunc;
} FileContext;
@@ -65,7 +66,7 @@ static const AVClass file_class = {
static int file_read(URLContext *h, unsigned char *buf, int size)
{
- FileContext *c = h->priv_data;
+ FileContext *c = h->priv_data;
int r = read(c->fd, buf, size);
return (-1 == r)?AVERROR(errno):r;
}
@@ -103,6 +104,7 @@ static int file_open(URLContext *h, const char *filename, int flags)
FileContext *c = h->priv_data;
int access;
int fd = -1;
+ int64_t pos = 0;
struct stat st;
av_strstart(filename, "file:", &filename);
@@ -126,11 +128,15 @@ static int file_open(URLContext *h, const char *filename, int flags)
}else{
char *p = strstr(filename, "fd::");
fd = dup(atoi(p + 4));
+ p = strstr(filename, "offset::");
+ if(p){
+ pos = atoi(p+8);
+ }
}
if (fd == -1)
return AVERROR(errno);
c->fd = fd;
-
+ c->offset = pos;
h->is_streamed = !fstat(fd, &st) && S_ISFIFO(st.st_mode);
return 0;
@@ -147,9 +153,14 @@ static int64_t file_seek(URLContext *h, int64_t pos, int whence)
ret = fstat(c->fd, &st);
return ret < 0 ? AVERROR(errno) : (S_ISFIFO(st.st_mode) ? 0 : st.st_size);
}
-
- ret = lseek(c->fd, pos, whence);
-
+ if(whence == 0)
+ {
+ ret = lseek64(c->fd,pos + c->offset, whence);
+ }
+ else
+ {
+ ret = lseek64(c->fd,pos, whence);
+ }
return ret < 0 ? AVERROR(errno) : ret;
}
diff --git a/libavformat/flvdec.c b/libavformat/flvdec.c
index 24302f6..548be33 100644..100755
--- a/libavformat/flvdec.c
+++ b/libavformat/flvdec.c
@@ -36,7 +36,16 @@
#include "avio_internal.h"
#include "flv.h"
+#define FLV_DEBUG 0
+
+#if FLV_DEBUG
+#define FLV_LOG(...) av_log(NULL, AV_LOG_INFO, __VA_ARGS__)
+#else
+#define FLV_LOG(...) do { if (0) av_log(NULL, AV_LOG_INFO, __VA_ARGS__); } while (0)
+#endif
+
#define VALIDATE_INDEX_TS_THRESH 2500
+#define FLV_TAG 0x464C5601 //.flv
typedef struct {
const AVClass *class; ///< Class for private options.
@@ -55,15 +64,41 @@ typedef struct {
int searched_for_end;
} FLVContext;
+static int SkipFlvFileHeader(AVFormatContext* s)
+{
+ if (s == NULL) {
+ return -1;
+ }
+
+ avio_skip(s->pb, 1);
+
+ int dataoffset = avio_rb32(s->pb);
+ if (dataoffset >= 9) {
+ if (dataoffset > 9) {
+ avio_skip(s->pb, dataoffset-9);
+ }
+ avio_skip(s->pb, 4);
+ return dataoffset;
+ } else {
+ return -1;
+ }
+
+ return 0;
+}
+
static int flv_probe(AVProbeData *p)
{
const uint8_t *d;
d = p->buf;
+
+ int score = 0;
if (d[0] == 'F' && d[1] == 'L' && d[2] == 'V' && d[3] < 5 && d[5]==0 && AV_RB32(d+5)>8) {
- return AVPROBE_SCORE_MAX;
+ score = AVPROBE_SCORE_MAX;
}
- return 0;
+
+ av_log(NULL, AV_LOG_INFO, "flv_probe get probe score: %d\n", score);
+ return score;
}
static AVStream *create_stream(AVFormatContext *s, int codec_type)
@@ -644,12 +679,41 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt)
int av_uninit(sample_rate);
AVStream *st = NULL;
+FLV_RETRY:
+
for(;;avio_skip(s->pb, 4)){ /* pkt size is repeated at end. skip it */
pos = avio_tell(s->pb);
- type = avio_r8(s->pb);
- size = avio_rb24(s->pb);
+
+ uint32_t tmpData = avio_rb32(s->pb);
+ if (tmpData == FLV_TAG)
+ {
+ /*
+ ** may be we are in Rock-chip Seamless play mode, so if last
+ ** segment has been readed, we need to skip flv header.
+ */
+ if (s->nb_streams ==0) {
+ av_log(NULL, AV_LOG_ERROR, "Hery, flvdec readpacket");
+ FLV_LOG("may be we are in Rock-chip Seamless play, try read flv header\n");
+ avio_seek(s->pb, -4, SEEK_CUR);
+ ret = flv_read_header(s);
+ if (ret) {
+ FLV_LOG("flv_read_header fail, ret: %d\n", ret);
+ goto leave;
+ }
+ goto FLV_RETRY;
+ } else {
+ SkipFlvFileHeader(s);
+ type = avio_r8(s->pb);
+ size = avio_rb24(s->pb);
+ }
+ } else {
+ type = ((tmpData >>24) & 0xFF);
+ size = (tmpData & 0xFFFFFF);
+ }
+
dts = avio_rb24(s->pb);
dts |= avio_r8(s->pb) << 24;
+
av_dlog(s, "type:%d, size:%d, dts:%"PRId64"\n", type, size, dts);
if (url_feof(s->pb))
return AVERROR_EOF;
@@ -726,6 +790,7 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt)
break;
}
}
+
if(i == s->nb_streams){
av_log(s, AV_LOG_WARNING, "Stream discovered after head already parsed\n");
st = create_stream(s,
@@ -734,6 +799,7 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt)
return AVERROR(ENOMEM);
}
+
av_dlog(s, "%d %X %d \n", stream_type, flags, st->discard);
if( (st->discard >= AVDISCARD_NONKEY && !((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY || (stream_type == FLV_STREAM_TYPE_AUDIO)))
||(st->discard >= AVDISCARD_BIDIR && ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_DISP_INTER && (stream_type == FLV_STREAM_TYPE_VIDEO)))
diff --git a/libavformat/hls.c b/libavformat/hls.c
index ef5803b..27fb6b2 100644..100755
--- a/libavformat/hls.c
+++ b/libavformat/hls.c
@@ -37,6 +37,13 @@
#include "url.h"
#define INITIAL_BUFFER_SIZE 32768
+#define HLS_DEBUG 1
+#define QVOD_NEED 0
+
+#define DOWNLOAD_M3U8_START -1
+#define DOWNLOAD_M3U8_END -1
+
+#define TIMEOUT 2000
/*
* An apple http stream consists of a playlist with media segment files,
@@ -55,13 +62,43 @@ enum KeyType {
KEY_AES_128,
};
+//add by xhr, for QVOD AV async
+typedef enum distontinutystatus {
+ Distontinuty_NONE,
+ Distontinuty_ONE,
+ Distontinuty_ALL,
+}DistontinutyStatus;
+
+
struct segment {
- int duration;
+ double duration;
+ int discontinuity;
+ int is_seek; //add by xhr, for Bluray
+ double seek_time; //add by xhr, for Bluray
+ double seek_time_end; //add by xhr, for Bluray
+ double seek_operation_time; //add by xhr, for Bluray
char url[MAX_URL_SIZE];
char key[MAX_URL_SIZE];
enum KeyType key_type;
uint8_t iv[16];
};
+struct bandwidth_info{
+ int bandwidth;
+ char url[MAX_URL_SIZE];
+};
+typedef struct bandwidthcontext{
+ int64_t mtime;
+ int32_t msize;
+ struct bandwidthcontext *next;
+}BandWidthContext;
+
+typedef struct bandWidthqueue{
+ BandWidthContext *front;
+ BandWidthContext *rear;
+ int num;
+ int64_t mTotalSize;
+ int64_t mTotalTimeUs;
+}BandWidthQueue;
/*
* Each variant has its own demuxer. If it currently is active,
@@ -87,23 +124,198 @@ struct variant {
struct segment **segments;
int needed, cur_needed;
int cur_seq_no;
+ int filesize;
+ int64_t load_time;
int64_t last_load_time;
+ int64_t ts_send_time;
+ int64_t ts_first_time;
+ int64_t ts_last_time;
+
char key_url[MAX_URL_SIZE];
uint8_t key[16];
};
typedef struct HLSContext {
int n_variants;
+ int n_bandwidth_info;
struct variant **variants;
+ struct bandwidth_info **bandwidth_info;
+ BandWidthQueue *BandWidthqueue;
+ char *cookies; //add by xhr, for set cookies
int cur_seq_no;
int end_of_segment;
int first_packet;
int64_t first_timestamp;
int64_t seek_timestamp;
int seek_flags;
+ int abort;
+ int mTaobaoHevc; //add by xhr, for QVOD AV async
+ int mdynamic;
+ int mSort; //add by ht ,1 save min bandwidth rate; 0,default save max bandwidth rate
+ int misHeShiJie;
AVIOInterruptCB *interrupt_callback;
+ char header[MAX_URL_SIZE];
+ int read_seq_no;
} HLSContext;
+BandWidthQueue* InitQueue();
+int IsEmpty(BandWidthQueue *pqueue);
+BandWidthContext* DeQueue(BandWidthQueue *pqueue);
+void EnQueue(BandWidthQueue *pqueue,int32_t size, int64_t time);
+void ClearQueue(BandWidthQueue *pqueue);
+void DestroyQueue(BandWidthQueue *pqueue);
+int GetSize(BandWidthQueue *pqueue);
+int EstimateBandwidth(HLSContext *c,int32_t *);
+int SortBandwidth(HLSContext* c);
+
+BandWidthQueue* InitQueue()
+{
+ BandWidthQueue* pqueue = (BandWidthQueue*)av_mallocz(sizeof(BandWidthQueue));
+ if(pqueue != NULL)
+ {
+ pqueue->front = NULL;
+ pqueue->rear = NULL;
+ pqueue->num = 0;
+ pqueue->mTotalSize = 0;
+ pqueue->mTotalTimeUs = 0;
+ }
+ return pqueue;
+}
+int IsEmpty(BandWidthQueue *pqueue)
+{
+ if(pqueue == NULL)
+ {
+ av_log(NULL,AV_LOG_DEBUG,"IsEmpty:something err");
+ return 1;
+ }
+ if(pqueue->front == NULL && pqueue->rear == NULL && pqueue->num == 0)
+ {
+ return 1;
+ }else{
+ return 0;
+ }
+}
+BandWidthContext * DeQueue(BandWidthQueue *pqueue)
+{
+ if(pqueue == NULL)
+ {
+ av_log(NULL,AV_LOG_DEBUG,"DeQueue:something err");
+ return NULL;
+ }
+ BandWidthContext* pnode = pqueue->front;
+ if(IsEmpty(pqueue)!=1 && pnode!=NULL)
+ {
+ pqueue->num--;
+ pqueue->front = pnode->next;
+ pqueue->mTotalSize -= pnode->msize;
+ pqueue->mTotalTimeUs -= pnode->mtime;
+ av_free(pnode);
+ if(pqueue->num==0)
+ pqueue->rear = NULL;
+ }
+ return pqueue->front;
+}
+void EnQueue(BandWidthQueue *pqueue, int32_t size, int64_t time)
+{
+ if(pqueue == NULL)
+ {
+ av_log(NULL,AV_LOG_DEBUG,"EnQueue:something err");
+ return;
+ }
+ BandWidthContext * pnode = (BandWidthContext *)av_mallocz(sizeof(BandWidthContext));
+ if(pnode != NULL)
+ {
+ pnode->msize = size;
+ pnode->mtime = time;
+ pnode->next = NULL;
+ if(IsEmpty(pqueue))
+ {
+ pqueue->front = pnode;
+ }
+ else
+ {
+ pqueue->rear->next = pnode;
+ }
+ pqueue->rear = pnode;
+ pqueue->num++;
+ pqueue->mTotalSize += pnode->msize;
+ pqueue->mTotalTimeUs += pnode->mtime;
+ }
+ if (pqueue->num > 100)
+ {
+ DeQueue(pqueue);
+ }
+}
+void ClearQueue(BandWidthQueue *pqueue)
+{
+ while(IsEmpty(pqueue) != 0){
+ DeQueue(pqueue);
+ }
+}
+void DestroyQueue(BandWidthQueue * pqueue)
+{
+ if(IsEmpty(pqueue) != 1)
+ ClearQueue(pqueue);
+ if(pqueue != NULL)
+ av_free(pqueue);
+}
+int GetSize(BandWidthQueue *pqueue)
+{
+ if(pqueue == NULL)
+ {
+ av_log(NULL,AV_LOG_DEBUG,"GetSize:something err");
+ return 0;
+ }
+ return pqueue->num;
+}
+int EstimateBandwidth(HLSContext *c,int32_t *bandwidth_bps)
+{
+ if(GetSize(c->BandWidthqueue) >= 2)
+ {
+
+ av_log(NULL, AV_LOG_DEBUG, "c->Bandwidthqueue->mTotalSize = %lld", c->BandWidthqueue->mTotalSize);
+ av_log(NULL, AV_LOG_DEBUG, "c->Bandwidthqueue->mTotalTimeUs = %lld", c->BandWidthqueue->mTotalTimeUs);
+
+ *bandwidth_bps = ((c->BandWidthqueue->mTotalSize * 8000000ll)/c->BandWidthqueue->mTotalTimeUs);
+ return 1;
+
+ }
+ return 0;
+}
+int SortBandwidth(HLSContext* c)
+{
+ int i,j,h;
+ int tmp = 0;
+ char* ptr = (char*)av_malloc(MAX_URL_SIZE+1);
+
+ for(i=0;i<c->n_bandwidth_info-1;i++)
+ {
+ for(j=0;j<c->n_bandwidth_info-1-i;j++)
+ {
+ if(c->bandwidth_info[j]->bandwidth > c->bandwidth_info[j+1]->bandwidth)
+ {
+ tmp = c->bandwidth_info[j]->bandwidth;
+ c->bandwidth_info[j]->bandwidth = c->bandwidth_info[j+1]->bandwidth;
+ c->bandwidth_info[j+1]->bandwidth = tmp;
+
+ memcpy(ptr,c->bandwidth_info[j]->url,MAX_URL_SIZE);
+ memcpy(c->bandwidth_info[j]->url,c->bandwidth_info[j+1]->url,MAX_URL_SIZE);
+ memcpy(c->bandwidth_info[j+1]->url,ptr,MAX_URL_SIZE);
+ }
+ }
+ }
+
+ for(h=0;h<c->n_bandwidth_info;h++)
+ {
+ av_log(NULL,AV_LOG_DEBUG,"h=%d",h);
+ av_log(NULL,AV_LOG_DEBUG,"***bandwidth=%d",c->bandwidth_info[h]->bandwidth);
+ av_log(NULL,AV_LOG_DEBUG,"***url=%s",c->bandwidth_info[h]->url);
+ }
+
+ av_free(ptr);
+ ptr = NULL;
+
+}
static int read_chomp_line(AVIOContext *s, char *buf, int maxlen)
{
@@ -138,8 +350,15 @@ static void free_variant_list(HLSContext *c)
}
av_free(var);
}
+ for(i=0;i<c->n_bandwidth_info;i++)
+ {
+ struct bandwidth_info * tmp = c->bandwidth_info[i];
+ av_free(tmp);
+ }
av_freep(&c->variants);
+ av_freep(&c->bandwidth_info);
c->n_variants = 0;
+ c->n_bandwidth_info = 0;
}
/*
@@ -156,12 +375,17 @@ static struct variant *new_variant(HLSContext *c, int bandwidth,
const char *url, const char *base)
{
struct variant *var = av_mallocz(sizeof(struct variant));
- if (!var)
+ struct bandwidth_info *tmp = av_mallocz(sizeof(struct bandwidth_info));
+ if (!var && !tmp)
return NULL;
reset_packet(&var->pkt);
var->bandwidth = bandwidth;
+ tmp->bandwidth = bandwidth;
ff_make_absolute_url(var->url, sizeof(var->url), base, url);
+ ff_make_absolute_url(tmp->url, sizeof(tmp->url), base, url);
+ av_log(NULL,AV_LOG_DEBUG,"new_variant:%s",var->url);
dynarray_add(&c->variants, &c->n_variants, var);
+ dynarray_add(&c->bandwidth_info,&c->n_bandwidth_info, tmp);
return var;
}
@@ -202,7 +426,22 @@ static void handle_key_args(struct key_info *info, const char *key,
static int parse_playlist(HLSContext *c, const char *url,
struct variant *var, AVIOContext *in)
{
- int ret = 0, duration = 0, is_segment = 0, is_variant = 0, bandwidth = 0;
+ //Use redirect url
+ AVIOParams *ioparams = c->interrupt_callback->ioparams;
+ if(ioparams&&ioparams->type==1&&ioparams->redirect==1&&ioparams->url[0]!='\0') {
+ url = ioparams->url;
+ }
+#if HLS_DEBUG
+ av_log(NULL, AV_LOG_DEBUG,"HLS parse_playlist in, url = %s\n", url);
+#endif
+
+ DistontinutyStatus distontinuty_status = Distontinuty_NONE; //add by xhr, for QVOD
+ c->mTaobaoHevc = 0; //add by xhr, for taobao hevc 0x6
+ int ret = 0,is_segment = 0,is_discontinuity = 0, is_variant = 0, bandwidth = 0;
+ int is_seek = 0; //add by xhr, for Bluray
+ double seek_time = 0; //add by xhr, for Bluray
+ double seek_time_end = 0; //add by xhr, for Bluray
+ double duration = 0;
enum KeyType key_type = KEY_NONE;
uint8_t iv[16] = "";
int has_iv = 0;
@@ -210,18 +449,61 @@ static int parse_playlist(HLSContext *c, const char *url,
char line[1024];
const char *ptr;
int close_in = 0;
-
if (!in) {
AVDictionary *opts = NULL;
close_in = 1;
/* Some HLS servers dont like being sent the range header */
av_dict_set(&opts, "seekable", "0", 0);
+ if(c->cookies){
+ av_dict_set(&opts, "cookies", c->cookies, 0);
+ }
+// av_dict_set(&opts, "hls", "1", 0); // ht modified for hls timeout 500ms; other is 60s
+ av_dict_set(&opts, "timeout", "5000000", 0);
+ av_dict_set(&opts, "multiple_requests", "0", 0);
+ av_dict_set(&opts, "hls_parse", "1", 0);
+ if(strlen(c->header) > 0)
+ {
+ av_dict_set(&opts, "headers", c->header, 0);
+ }
+
+ //Init http persist connection params
+ if(c->misHeShiJie==1&&!c->interrupt_callback->ioparams){
+ c->interrupt_callback->ioparams = av_malloc(sizeof(struct AVIOParams));
+ AVIOParams *params = c->interrupt_callback->ioparams;
+ if(params) {
+ params->host[0] = '\0';
+ params->port = -1;
+ params->hd = NULL;
+ params->type = 1;
+ params->willclose = 1;
+ params->url[0] = '\0';
+ params->redirect = 0;
+ }
+ }
+
+ // not set user-agent here, set user-agent in ffplayer or use default user-agent in http_connect
+ // AppleCoreMedia/1.0.0.7B367 (iPad; U; CPU OS 4_3_3 like Mac OS X)
+// av_dict_set(&opts, "user-agent","Mozilla/4.0 (compatible; MS IE 6.0; (ziva))",0);//"stagefright/1.2 (Linux;Android 4.2.2)"
ret = avio_open2(&in, url, AVIO_FLAG_READ,
c->interrupt_callback, &opts);
+ av_log(NULL,AV_LOG_ERROR,"%s:avio_open2 ",__FUNCTION__);
av_dict_free(&opts);
if (ret < 0)
+ {
+#if HLS_DEBUG
+ av_log(NULL,AV_LOG_DEBUG,"%s:avio_open failed ret=0x%x",__FUNCTION__,ret);
+#endif
+ if(ioparams&&ioparams->type==1)
+ {
+ ioparams->url[0] = '\0';
+ ioparams->redirect = 0;
+ }
return ret;
+ }
}
+#if HLS_DEBUG
+ av_log(NULL,AV_LOG_DEBUG,"%s:avio_open ok",__FUNCTION__,ret);
+#endif
read_chomp_line(in, line, sizeof(line));
if (strcmp(line, "#EXTM3U")) {
@@ -229,18 +511,52 @@ static int parse_playlist(HLSContext *c, const char *url,
goto fail;
}
+ struct variant *bkVar = NULL;
+ /* Disable merge m3u8
+ if(var&&var->finished==0&&var->n_segments>0){//Http Living Streaming
+ bkVar = var;
+ var = av_mallocz(sizeof(struct variant));//new_variant(c, 0, in->url, NULL);
+ ff_make_absolute_url(var->url, sizeof(var->url), NULL, in->url);
+ }*/
+
if (var) {
free_segment_list(var);
var->finished = 0;
}
while (!url_feof(in)) {
+ //add by xhr ,for prevent m3u8 too big lead full leap
+ if(var && var->n_segments >=4096)
+ {
+ break;
+ }
read_chomp_line(in, line, sizeof(line));
+// av_log(NULL,AV_LOG_ERROR,"%s",line);
+
+ /*
+ * 如果read_chomp_line读失败,将导致http_buf_read调用special_read
+ * 这种情况下,会重新向服务器申请m3u8表,导致一次读到多个m3u8表的情况
+ * 不同的m3u8表可能带有同一个sequence,因此可能会导致某个ts片段播放多次的情况
+ * 因此,这边需要判断是否有新的m3u8表进来,如果有的话只保存最好一个m3u8表
+ */
+ if (strstr(line, "#EXTM3U"))
+ {
+ if (var != NULL)
+ {
+ free_segment_list(var);
+ var->finished = 0;
+ }
+ }
+
if (av_strstart(line, "#EXT-X-STREAM-INF:", &ptr)) {
struct variant_info info = {{0}};
is_variant = 1;
+#if HLS_DEBUG
+ av_log(NULL, AV_LOG_DEBUG,"EXT-X-STREAM-INF\n");
+#endif
ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_variant_args,
&info);
bandwidth = atoi(info.bandwidth);
+ av_log(NULL,AV_LOG_DEBUG,"bandwidth=%d",bandwidth);
} else if (av_strstart(line, "#EXT-X-KEY:", &ptr)) {
struct key_info info = {{0}};
ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_key_args,
@@ -256,16 +572,20 @@ static int parse_playlist(HLSContext *c, const char *url,
av_strlcpy(key, info.uri, sizeof(key));
} else if (av_strstart(line, "#EXT-X-TARGETDURATION:", &ptr)) {
if (!var) {
- var = new_variant(c, 0, url, NULL);
+ var = new_variant(c, 0, in->url, NULL);
if (!var) {
ret = AVERROR(ENOMEM);
goto fail;
}
}
+ //add by xhr, for QVOD AV async
+ if(distontinuty_status == Distontinuty_NONE){
+ distontinuty_status = Distontinuty_ONE;
+ }
var->target_duration = atoi(ptr);
} else if (av_strstart(line, "#EXT-X-MEDIA-SEQUENCE:", &ptr)) {
if (!var) {
- var = new_variant(c, 0, url, NULL);
+ var = new_variant(c, 0, in->url, NULL);
if (!var) {
ret = AVERROR(ENOMEM);
goto fail;
@@ -275,24 +595,108 @@ static int parse_playlist(HLSContext *c, const char *url,
} else if (av_strstart(line, "#EXT-X-ENDLIST", &ptr)) {
if (var)
var->finished = 1;
- } else if (av_strstart(line, "#EXTINF:", &ptr)) {
+ }
+ else if(av_strstart(line, "#SLICE-CODEC:H.265", &ptr))
+ {
+ av_log(NULL, AV_LOG_ERROR, "#SLICE-CODEC:H.265");
+ c->mTaobaoHevc = 1;
+ }
+ else if (av_strstart(line, "#EXTINF", &ptr)) {
+ char *temp = NULL;
is_segment = 1;
- duration = atoi(ptr);
- } else if (av_strstart(line, "#", NULL)) {
+ temp = strstr(ptr,":");
+
+ ptr = temp+1;
+ duration = strtod(ptr,NULL);
+ }else if(av_strstart(line, "#EXT-X-DISCONTINUITY",NULL)){
+ //add by xhr, for QVOD AV async
+ if(distontinuty_status == Distontinuty_NONE){
+ distontinuty_status = Distontinuty_ALL;
+ }
+ is_discontinuity = 1;
+ av_log(NULL, AV_LOG_DEBUG,"HLS parse DISCONTINUITY\n");
+ }else if(av_strstart(line, "#EXT-X-SEEK:",&ptr)) { //add by xhr, for Bluray
+ is_seek = 1;
+ seek_time = strtod(ptr,NULL);
+ av_log(NULL, AV_LOG_DEBUG, "Hery, seek_position = %f", seek_time);
+ }else if(av_strstart(line,"#EXT-X-SEEK-END:", &ptr)){
+ seek_time_end = strtod(ptr,NULL);
+ av_log(NULL, AV_LOG_DEBUG, "Hery, seek_position_end = %f", seek_time_end);
+ } else if (av_strstart(line, "#", NULL)) {
continue;
} else if (line[0]) {
if (is_variant) {
- if (!new_variant(c, bandwidth, line, url)) {
+#if HLS_DEBUG
+ av_log(NULL, AV_LOG_DEBUG,"url = %s\n",url);
+#endif
+
+ if(0 == c->mdynamic)
+ {
+ int tempMax = 0;
+ int firstVariants = 0;
+ if(c->n_variants == 0)
+ {
+ tempMax = bandwidth;
+ firstVariants = 1;
+ }
+
+ for (int i = 0; i < c->n_variants; i++) {
+ struct variant *var = c->variants[i];
+
+ if(var != NULL)
+ {
+ if(c->mSort == 0)
+ {
+ if(bandwidth > var->bandwidth)
+ {
+ tempMax = bandwidth;
+ av_log(NULL,AV_LOG_DEBUG," change max =%d",tempMax);
+ free_variant_list(c);
+
+ }
+ }
+ else if(c->mSort == 1)
+ {
+ if(bandwidth < var->bandwidth)
+ {
+ tempMax = bandwidth;
+ av_log(NULL,AV_LOG_DEBUG," change min =%d",tempMax);
+ free_variant_list(c);
+
+ }
+
+ }
+ }
+
+ }
+
+ if(tempMax != 0 || 1 == firstVariants)
+ {
+ if (!new_variant(c, tempMax, line, in->url))
+ {
+
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ }
+ }
+ else
+ {
+
+ if (!new_variant(c, bandwidth, line, in->url)) {
+
ret = AVERROR(ENOMEM);
goto fail;
}
+ }
+
is_variant = 0;
bandwidth = 0;
}
if (is_segment) {
struct segment *seg;
if (!var) {
- var = new_variant(c, 0, url, NULL);
+ var = new_variant(c, 0, in->url, NULL);
if (!var) {
ret = AVERROR(ENOMEM);
goto fail;
@@ -305,6 +709,31 @@ static int parse_playlist(HLSContext *c, const char *url,
}
seg->duration = duration;
seg->key_type = key_type;
+ seg->seek_operation_time = 0; //add by xhr, for Bluray seek operation
+ if(is_discontinuity){
+ seg->discontinuity = 1;
+ is_discontinuity = 0;
+ }else{
+ seg->discontinuity = 0;
+ }
+ //add by xhr , for Bluray
+ if(is_seek){
+ seg->is_seek = 1;
+ seg->seek_time = seek_time;
+ seg->seek_time_end = seek_time_end;
+ //seg->real_duration = real_duration;
+ is_seek = 0;
+ seek_time = 0;
+ seek_time_end = 0;
+ //real_duration = 0;
+ duration= 0;
+ }else{
+ seg->is_seek = 0;
+ seg->seek_time = 0;
+ seg->seek_time_end = 0;
+ //seg->real_duration = 0;
+ duration = 0;
+ }
if (has_iv) {
memcpy(seg->iv, iv, sizeof(iv));
} else {
@@ -312,15 +741,100 @@ static int parse_playlist(HLSContext *c, const char *url,
memset(seg->iv, 0, sizeof(seg->iv));
AV_WB32(seg->iv + 12, seq);
}
- ff_make_absolute_url(seg->key, sizeof(seg->key), url, key);
- ff_make_absolute_url(seg->url, sizeof(seg->url), url, line);
+ ff_make_absolute_url(seg->key, sizeof(seg->key), in->url, key);
+ ff_make_absolute_url(seg->url, sizeof(seg->url), in->url, line);
dynarray_add(&var->segments, &var->n_segments, seg);
is_segment = 0;
}
}
}
- if (var)
+ if (var){
+ //Merge m3u8
+ int m3u8_handled = 0;
+ int last_bk_seq_no = bkVar?(bkVar->start_seq_no+bkVar->n_segments-1):0;
+ if(!var->finished&&bkVar&&bkVar->cur_seq_no>=bkVar->start_seq_no&&bkVar->cur_seq_no<=last_bk_seq_no){
+ av_log(NULL,AV_LOG_DEBUG, "we try to merge m3u8. ");
+ if(var->start_seq_no-bkVar->cur_seq_no>0){//May be jump
+ if(var->start_seq_no-last_bk_seq_no<=1){
+ int i=0, j=0;
+ //1.free used segments
+ av_log(NULL,AV_LOG_DEBUG,"free used segments: %d, %d - %d", bkVar->cur_seq_no, bkVar->start_seq_no, last_bk_seq_no);
+ if(bkVar->cur_seq_no>bkVar->start_seq_no){
+ for (i = 0; i < bkVar->n_segments; i++){
+ if((bkVar->start_seq_no+i) < bkVar->cur_seq_no){
+ av_free(bkVar->segments[i]);
+ }else{
+ bkVar->segments[j++] = bkVar->segments[i];
+ bkVar->segments[i] = NULL;
+ }
+ }
+ bkVar->start_seq_no = bkVar->cur_seq_no;
+ bkVar->n_segments = j;
+ }
+ //2.add new segments
+ int last_cur_seq_no = var->start_seq_no+var->n_segments-1;
+ av_log(NULL,AV_LOG_DEBUG,"add new segments: %d - %d", var->start_seq_no, last_cur_seq_no);
+ for (i = 0; i < var->n_segments; i++){
+ if((var->start_seq_no+i)<=last_bk_seq_no){
+ av_free(var->segments[i]);
+ }else if(bkVar->n_segments>50){//If we have store more then 50 segments, we need goto living
+ av_free(var->segments[i]);
+ av_log(NULL,AV_LOG_DEBUG,"we have already stored more then %d segments ", bkVar->n_segments);
+ }else{
+ dynarray_add(&bkVar->segments, &bkVar->n_segments, var->segments[i]);
+ var->segments[i] = NULL;
+ }
+ }
+ //3.set new something, then free
+ bkVar->target_duration = var->target_duration;
+ av_freep(&var->segments);
+ av_freep(&var);
+ var = bkVar;
+
+ av_log(NULL,AV_LOG_DEBUG,"now segments: %d - %d", var->start_seq_no, var->start_seq_no+var->n_segments-1);
+ //for(i=0; i<var->n_segments; i++){
+ // av_log(NULL,AV_LOG_DEBUG,"Merge m3u8: %s", var->segments[i]->url);
+ //}
+
+ m3u8_handled = 1;
+ }
+ }
+ }
+
+ if(!m3u8_handled&&!var->finished&&bkVar){
+ av_log(NULL,AV_LOG_DEBUG,"Recovery m3u8: %d - %d", var->start_seq_no, var->start_seq_no+var->n_segments-1);
+ free_segment_list(bkVar);
+ int i = 0;
+
+ for(i = 0; i < var->n_segments; i++){
+ dynarray_add(&bkVar->segments, &bkVar->n_segments, var->segments[i]);
+ var->segments[i] = NULL;
+ }
+ bkVar->finished = var->finished;
+ bkVar->start_seq_no = var->start_seq_no;
+ bkVar->target_duration = var->target_duration;
+ free_segment_list(var);
+ av_freep(&var->segments);
+ av_freep(&var);
+ var = bkVar;
+ av_log(NULL,AV_LOG_DEBUG,"Recovery m3u82: %d - %d", var->start_seq_no, var->start_seq_no+var->n_segments-1);
+ for(i=0; i<var->n_segments; i++){
+ //av_log(NULL,AV_LOG_DEBUG,"Merge m3u8: %s", var->segments[i]->url);
+ }
+ }
+
var->last_load_time = av_gettime();
+
+ }
+
+#if HLS_DEBUG
+ if(var)
+ {
+
+ av_log(NULL, AV_LOG_DEBUG,"%s::firstQ=%d,curQ=%d,LastQ=%d,var->n_segments = %d",__FUNCTION__,var->start_seq_no,var->cur_seq_no,var->start_seq_no+var->n_segments,var->n_segments);
+ }
+
+#endif
fail:
if (close_in)
@@ -328,15 +842,70 @@ fail:
return ret;
}
-static int open_input(struct variant *var)
+static int open_input(HLSContext *c, struct variant *var)
{
AVDictionary *opts = NULL;
int ret;
struct segment *seg = var->segments[var->cur_seq_no - var->start_seq_no];
av_dict_set(&opts, "seekable", "0", 0);
+ av_dict_set(&opts, "timeout", "5000000", 0);
+ av_dict_set(&opts, "hls", "1", 0); // ht modified for hls timeout 500ms; other is 60s
+ av_dict_set(&opts, "multiple_requests", "0", 0);
+ av_dict_set(&opts, "hls_parse", "0", 0);
+
+ if(strlen(c->header) > 0)
+ {
+ av_log(NULL, AV_LOG_DEBUG, "open_input(), c->header = %s",c->header);
+ av_dict_set(&opts, "headers", c->header, 0);
+ }
+ // not set user-agent here, set user-agent in ffplayer or use default user-agent in http_connect
+ // AppleCoreMedia/1.0.0.9A405 (iPad; U; CPU OS 5_0_1 like Mac OS X; zh_cn)
+// av_dict_set(&opts, "user-agent","Mozilla/4.0 (compatible; MS IE 6.0; (ziva))",0);//"stagefright/1.2 (Linux;Android 4.2.2)"
+ if(c->cookies){
+ av_dict_set(&opts, "cookies", c->cookies, 0);
+ }
+#if HLS_DEBUG
+ av_log(NULL, AV_LOG_DEBUG,"%s:url=(%s)",__FUNCTION__,seg->url);
+#endif
+
if (seg->key_type == KEY_NONE) {
ret = ffurl_open(&var->input, seg->url, AVIO_FLAG_READ,
&var->parent->interrupt_callback, &opts);
+ //add by xhr, for Bluray
+ if(seg->is_seek){
+ if(seg->seek_operation_time){
+ int64_t filesize = ffurl_size(var->input);
+
+ int64_t totolsize = seg->seek_time + ((seg->seek_time_end - seg->seek_time) / seg->duration) * seg->seek_operation_time;
+ int ret = ffurl_seek(var->input,totolsize,SEEK_SET);
+ if (ret < 0){
+ av_log(NULL, AV_LOG_DEBUG, "Hery, seek err");
+ }
+ }else{
+ int64_t filesize = ffurl_size(var->input);
+
+ int ret = ffurl_seek(var->input,seg->seek_time,SEEK_SET);
+
+ if (ret < 0){
+ av_log(NULL, AV_LOG_DEBUG, "Hery, seek err");
+ }
+ }
+
+ }else{
+ if(av_strncasecmp("http://", seg->url, 7)|| av_strncasecmp("https://", seg->url, 8)){
+ if(seg->seek_operation_time){
+ int64_t filesize = ffurl_size(var->input);
+
+ int64_t totolsize = (filesize / seg->duration) * seg->seek_operation_time;
+ int ret = ffurl_seek(var->input,totolsize,SEEK_SET);
+ if (ret < 0){
+ av_log(NULL, AV_LOG_DEBUG, "Hery, seek err");
+ }
+
+ }
+ }
+
+ }
goto cleanup;
} else if (seg->key_type == KEY_AES_128) {
char iv[33], key[33], url[MAX_URL_SIZE];
@@ -346,12 +915,12 @@ static int open_input(struct variant *var)
&var->parent->interrupt_callback, &opts) == 0) {
if (ffurl_read_complete(uc, var->key, sizeof(var->key))
!= sizeof(var->key)) {
- av_log(NULL, AV_LOG_ERROR, "Unable to read key file %s\n",
+ av_log(NULL, AV_LOG_DEBUG, "Unable to read key file %s\n",
seg->key);
}
ffurl_close(uc);
} else {
- av_log(NULL, AV_LOG_ERROR, "Unable to open key file %s\n",
+ av_log(NULL, AV_LOG_DEBUG, "Unable to open key file %s\n",
seg->key);
}
av_strlcpy(var->key_url, seg->key, sizeof(var->key_url));
@@ -371,6 +940,16 @@ static int open_input(struct variant *var)
/* Need to repopulate options */
av_dict_free(&opts);
av_dict_set(&opts, "seekable", "0", 0);
+
+ // not set user-agent here, set user-agent in ffplayer or use default user-agent in http_connect
+ //AppleCoreMedia/1.0.0.9A405 (iPad; U; CPU OS 5_0_1 like Mac OS X; zh_cn)
+ // av_dict_set(&opts, "user-agent","Mozilla/4.0 (compatible; MS IE 6.0; (ziva))",0);//"stagefright/1.2 (Linux;Android 4.2.2)"
+ av_dict_set(&opts, "timeout", "500000", 0);
+ av_dict_set(&opts, "hls", "1", 0); // ht modified for hls timeout 500ms; other is 60s
+ if(strlen(c->header) > 0)
+ {
+ av_dict_set(&opts, "headers", c->header, 0);
+ }
if ((ret = ffurl_connect(var->input, &opts)) < 0) {
ffurl_close(var->input);
var->input = NULL;
@@ -386,12 +965,23 @@ cleanup:
return ret;
}
-static int read_data(void *opaque, uint8_t *buf, int buf_size)
+static int read_seqno(void *opaque)
{
struct variant *v = opaque;
HLSContext *c = v->parent->priv_data;
- int ret, i;
+ return c->read_seq_no;
+}
+
+static int read_data(void *opaque, uint8_t *buf, int buf_size)
+{
+ struct variant *v = opaque;
+ HLSContext *c = v->parent->priv_data;
+ int ret, i,retry = 0,parse_list_retry = 200,read_timeout_cnt = 0;
+ int64_t last_load_timeUs = av_gettime();
+ if(v->parent->exit_flag){
+ return AVERROR_EOF;
+ }
restart:
if (!v->input) {
/* If this is a live stream and the reload interval has elapsed since
@@ -399,49 +989,298 @@ restart:
int64_t reload_interval = v->n_segments > 0 ?
v->segments[v->n_segments - 1]->duration :
v->target_duration;
- reload_interval *= 1000000;
+ c->seek_flags &= (~AVSEEK_FLAG_READ_NEED_OPEN_NEW_URL);
+#if HLS_DEBUG
+ av_log(NULL, AV_LOG_DEBUG,"reload_interval = %"PRId64"\n",reload_interval);
+#endif
+ reload_interval *= 1000000;
+ int expired_list = 0;
+ int sliceSmooth = 0;//Slice smooth handle by fxw
reload:
+ if(ff_check_operate(c->interrupt_callback,OPERATE_SEEK,NULL,NULL))
+ {
+ av_log(NULL,AV_LOG_ERROR,"read_data, new seek arrival,return immediately");
+ return AVERROR(EAGAIN);
+ }
+
if (!v->finished &&
av_gettime() - v->last_load_time >= reload_interval) {
- if ((ret = parse_playlist(c, v->url, v, NULL)) < 0)
+#if HLS_DEBUG
+ av_log(NULL, AV_LOG_DEBUG,"%s:parse_playlist start:%s",__FUNCTION__,v->url);
+#endif
+ int64_t startTime = av_gettime();
+ ff_send_message(c->interrupt_callback,MEDIA_INFO_DOWNLOAD_START,-1); // c->interrupt_callback
+ if ((ret = parse_playlist(c, v->url, v, NULL)) < 0){
+// parse_list_retry--;
+ if(parse_list_retry < 0){
+ av_log(NULL, AV_LOG_DEBUG,"parse_playlist return ret = %d",ret);
return ret;
+ }
+ av_log(NULL, AV_LOG_DEBUG,"read_data():parse_playlist, ret = 0x%x",ret);
+ int errorcode = TIMEOUT;
+ if(v != NULL)
+ {
+ URLContext *input = v->input;
+ if(input != NULL)
+ {
+ if(input->errcode != 0)
+ {
+ errorcode = input->errcode;
+ av_log(NULL,AV_LOG_DEBUG,"read_data():parse_playlist, errorcode = %d",errorcode);
+ }
+ }
+ }
+ ff_send_message(c->interrupt_callback,MEDIA_INFO_DOWNLOAD_ERROR,errorcode);
+ av_usleep(1000*1000);
+ if(expired_list == 1){
+ //free_segment_list(v);
+ if (ff_check_interrupt(c->interrupt_callback))
+ return AVERROR_EXIT;
+ av_log(NULL,AV_LOG_DEBUG,"open_input time out, need retry parse list");
+ goto reload;
+ }
+ }
+ else
+ {
+ //add info for AliyunOS
+ v->ts_last_time = av_gettime();
+
+ ff_send_message(c->interrupt_callback,MEDIA_INFO_DOWNLOAD_END,(av_gettime()-startTime)/1000);
+ }
/* If we need to reload the playlist again below (if
* there's still no more segments), switch to a reload
* interval of half the target duration. */
reload_interval = v->target_duration * 500000LL;
}
+ else{
+ expired_list = 0;
+ }
if (v->cur_seq_no < v->start_seq_no) {
- av_log(NULL, AV_LOG_WARNING,
+ av_log(NULL, AV_LOG_DEBUG,
"skipping %d segments ahead, expired from playlists\n",
v->start_seq_no - v->cur_seq_no);
- v->cur_seq_no = v->start_seq_no;
+ for(int i = v->cur_seq_no; i < v->start_seq_no; i++)
+ {
+ ff_send_message(c->interrupt_callback,MEDIA_INFO_DOWNLOAD_START,i);
+ ff_send_message(c->interrupt_callback,MEDIA_INFO_DOWNLOAD_ERROR,TIMEOUT);
+ }
+ if(!v->finished&&c->misHeShiJie==1&&v->n_segments>4){
+ v->cur_seq_no = v->start_seq_no + 4;//+ v->n_segments - 1; //reduce jump times
+ }else{
+ v->cur_seq_no = v->start_seq_no;
+ }
}
+ av_log(NULL,AV_LOG_DEBUG,"read_data:cur_seq_no = %d,start_seq_no = %d,n_segments = %d",v->cur_seq_no,
+ v->start_seq_no,v->n_segments);
if (v->cur_seq_no >= v->start_seq_no + v->n_segments) {
- if (v->finished)
+ if (v->finished){
+ av_log(NULL, AV_LOG_DEBUG, "finished HLS read data AVERROR_EOF\n");
return AVERROR_EOF;
+ }
while (av_gettime() - v->last_load_time < reload_interval) {
if (ff_check_interrupt(c->interrupt_callback))
return AVERROR_EXIT;
av_usleep(100*1000);
}
/* Enough time has elapsed since the last reload */
- goto reload;
+ if (ff_check_interrupt(c->interrupt_callback))
+ {
+ av_log(NULL,AV_LOG_DEBUG,"read_data:ff_check_interrupt");
+ return AVERROR_EXIT;
+ }
+#if HLS_DEBUG
+ av_log(NULL, AV_LOG_DEBUG,"%s:need reload\n",__FUNCTION__);
+#endif
+ //Slice smooth handle, EXT-X-MEDIA-SEQUENCE become too smaller than last time suddenly
+ if(v->cur_seq_no-(v->start_seq_no + v->n_segments)>v->n_segments*10){
+ sliceSmooth++;
+ av_log(NULL, AV_LOG_ERROR,"%s:slice smooth times=%d, v->cur_seq_no=%d, v->start_seq_no=%d, v->n_segments=%d\n",
+ __FUNCTION__, sliceSmooth, v->cur_seq_no, v->start_seq_no, v->n_segments);
+ }
+ if(sliceSmooth>=3){
+ v->cur_seq_no = v->start_seq_no;
+ av_log(NULL, AV_LOG_ERROR,"%s:slice smooth to seq = %d\n",__FUNCTION__, v->cur_seq_no);
+ }else{
+ goto reload;
+ }
+
}
- ret = open_input(v);
- if (ret < 0)
- return ret;
+ ff_send_message(c->interrupt_callback,MEDIA_INFO_DOWNLOAD_START,v->cur_seq_no);
+ v->load_time = av_gettime();
+ v->ts_send_time = av_gettime();
+ v->ts_first_time = 0;
+ v->ts_last_time = 0;
+ av_log(NULL, AV_LOG_DEBUG,"%s:need reload,v->cur_seq_no = %d,load_time = %lld",__FUNCTION__,v->cur_seq_no,v->load_time);
+ ret = open_input(c , v);
+ if (ret < 0){
+ av_log(NULL, AV_LOG_DEBUG, "HLS read data %d\n",ret);
+ int errorcode = TIMEOUT;
+ if(v != NULL)
+ {
+ URLContext *input = v->input;
+ if(input != NULL)
+ {
+ if(input->errcode != 0)
+ {
+ errorcode = input->errcode;
+ av_log(NULL,AV_LOG_DEBUG,"read_data():open_input fail, errorcode = %d",errorcode);
+ }
+ }
+ }
+ ff_send_message(c->interrupt_callback,MEDIA_INFO_DOWNLOAD_ERROR,errorcode);
+
+ if(c->abort || v->parent->exit_flag){
+ return AVERROR_EOF;
+ }
+ if (ff_check_interrupt(c->interrupt_callback))
+ {
+ av_log(NULL,AV_LOG_DEBUG,"read_data:ff_check_interrupt");
+ return AVERROR_EXIT;
+ }
+ av_log(NULL, AV_LOG_DEBUG,"read_data:open_input failed,reload");
+
+ int64_t expired_interval = 30;//30s
+ expired_interval = (expired_interval<v->target_duration ? v->target_duration : expired_interval)+1;
+ expired_interval *= 1000000;
+ if(!v->finished&&av_gettime() - last_load_timeUs >= expired_interval){
+ ffurl_close(v->input);
+ v->input = NULL;
+ expired_list = 1;
+ /*
+ av_log(NULL, AV_LOG_DEBUG, "HLS read data skip current seq no %d, open_interval %lld", v->cur_seq_no, open_interval);
+ v->cur_seq_no++;
+ c->end_of_segment = 1;
+ c->cur_seq_no = v->cur_seq_no;
+ last_load_timeUs = av_gettime();
+
+ ff_send_message(c->interrupt_callback,MEDIA_INFO_DOWNLOAD_START,i);
+ ff_send_message(c->interrupt_callback,MEDIA_INFO_DOWNLOAD_ERROR,TIMEOUT);*/
+ }
+ av_usleep(200*1000);
+ goto reload;
+
+ }
+ expired_list = 0;
+ c->read_seq_no = v->cur_seq_no;
}
+ last_load_timeUs = av_gettime();
+ int temp = 1 + (v->n_segments > 0 ?
+ v->segments[v->cur_seq_no- v->start_seq_no]->duration/2 :
+ v->target_duration/2);
+ retry = temp;//for huashu auto return by timeout
+#if HLS_DEBUG
+// av_log(NULL,AV_LOG_DEBUG,"RETRY = %d",retry);
+#endif
+ struct segment *seg = v->segments[v->cur_seq_no - v->start_seq_no]; //add by xhr, for Bluray
+ int64_t start_time = av_gettime();
+ while(retry--){
ret = ffurl_read(v->input, buf, buf_size);
- if (ret > 0)
- return ret;
+ if (ret > 0){
+ if(0 == v->ts_first_time){
+ v->ts_first_time = av_gettime();
+ }
+ int64_t off_time = av_gettime() - start_time;
+ int32_t size = GetSize(c->BandWidthqueue);
+ EnQueue(c->BandWidthqueue,ret, off_time);
+
+ if(seg->is_seek){
+
+ //int64_t pos = avio_tell(&v->pb);
+ //int64_t total = avio_size(&v->pb);
+ int64_t seek_position = ffurl_seek(v->input, 0, SEEK_CUR);
+ //av_log(NULL, AV_LOG_DEBUG, "Hery, seek_position = %lld", seek_position);
+ //int64_t total = ffurl_size(v->input);
+ //av_log(NULL, AV_LOG_DEBUG, "Hery, pos = %lld, total = %lld", pos, total);
+ if (seek_position >= seg->seek_time_end){
+ av_log(NULL, AV_LOG_DEBUG, "Hery, read data break = %lld", seek_position);
+ break;
+ }
+ }
+ return ret;
+ }
+ if(ret == 0 ){
+ av_log(NULL,AV_LOG_DEBUG,"read_data len is 0, cur_seq_no=%d", v->cur_seq_no);
+ break;
+ }
+ if(ret == AVERROR_EOF){
+ v->filesize = ffurl_size(v->input);
+ v->last_load_time = av_gettime();
+ av_log(NULL,AV_LOG_DEBUG, "read_data finished. ");
+ break;
+ }
+ if(c->abort || v->parent->exit_flag){
+ av_log(NULL, AV_LOG_DEBUG,"ffurl_read ret = %d",ret);
+ return AVERROR_EOF;
+ }
+
+ if(ff_check_operate(c->interrupt_callback,OPERATE_SEEK,NULL,NULL))
+ {
+ av_log(NULL,AV_LOG_ERROR,"read_data, new seek arrival,return immediately");
+ return AVERROR(EAGAIN);
+ }
+
+ av_log(NULL,AV_LOG_DEBUG,"read:retry=%d,ret=%d",retry,ret);
+ }
+#if HLS_DEBUG
+ av_log(NULL, AV_LOG_DEBUG, "read_data:parse one Segment ret = 0x%x",ret);
+#endif
ffurl_close(v->input);
v->input = NULL;
+
+ if(ret != -ETIMEDOUT)
+ {
+ //add info for AliyunOS
+ v->ts_last_time = av_gettime();
+
+ // send download end event
+ int64_t endTime = av_gettime();
+ av_log(NULL, AV_LOG_DEBUG, "read_data(), download ts file cur_seq_no = %d,time = %lld,startTime = %lld",v->cur_seq_no,endTime,v->load_time);
+ ff_send_message(c->interrupt_callback,MEDIA_INFO_DOWNLOAD_END,(endTime - v->load_time)/1000);
+ }
+ else
+ {
+ ff_send_message(c->interrupt_callback,MEDIA_INFO_DOWNLOAD_TIMEOUT, v->cur_seq_no);
+ ff_send_message(c->interrupt_callback,MEDIA_INFO_DOWNLOAD_ERROR,TIMEOUT);
+ }
v->cur_seq_no++;
c->end_of_segment = 1;
c->cur_seq_no = v->cur_seq_no;
+ read_timeout_cnt = 0;
+
+ int32_t estimatebandwidth = 0;
+ if(EstimateBandwidth(c,&estimatebandwidth) == 1)
+ {
+ int index = c->n_bandwidth_info - 1;
+#if HLS_DEBUG
+ av_log(NULL,AV_LOG_DEBUG,"bandwidth estimated at %.2f kbps", estimatebandwidth/ 1024.0f);
+#endif
+ // Consider only 80% of the available bandwidth usable.
+ while (index > 0 && c->bandwidth_info[index]->bandwidth > estimatebandwidth*8/10)
+ {
+ --index;
+ }
+#if HLS_DEBUG
+ av_log(NULL,AV_LOG_DEBUG,"bandwidth=%d,c->bandwidth=%d",v->bandwidth,c->bandwidth_info[index]->bandwidth );
+#endif
+ if(v->bandwidth != c->bandwidth_info[index]->bandwidth)
+ {
+ av_log(NULL,AV_LOG_DEBUG,"final estimateBH(%d)=%d",index,c->bandwidth_info[index]->bandwidth);
+ memcpy(v->url,c->bandwidth_info[index]->url,sizeof(v->url));
+ v->bandwidth = c->bandwidth_info[index]->bandwidth;
+ v->finished = 0;
+#if HLS_DEBUG
+ av_log(NULL,AV_LOG_DEBUG,"there is BandChanged,so recompute loadtime");
+#endif
+ v->last_load_time = 0;
+
+ }
+ }
+#if HLS_DEBUG
+ av_log(NULL, AV_LOG_DEBUG, "read_data:nextQ = %d",c->cur_seq_no);
+#endif
if (v->ctx && v->ctx->nb_streams && v->parent->nb_streams >= v->stream_offset + v->ctx->nb_streams) {
v->needed = 0;
@@ -452,7 +1291,7 @@ reload:
}
}
if (!v->needed) {
- av_log(v->parent, AV_LOG_INFO, "No longer receiving variant %d\n",
+ av_log(v->parent, AV_LOG_DEBUG, "No longer receiving variant %d\n",
v->index);
return AVERROR_EOF;
}
@@ -461,27 +1300,78 @@ reload:
static int hls_read_header(AVFormatContext *s)
{
+ URLContext *u = (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : s->pb->opaque;
HLSContext *c = s->priv_data;
- int ret = 0, i, j, stream_offset = 0;
+ int ret = 0, i, j, stream_offset = 0,retry = 0;
+ c->cookies = u->cookies;
c->interrupt_callback = &s->interrupt_callback;
+ c->mdynamic = s->mhlsdynamic;
+ c->mSort = s->mhlsSort;
+ c->misHeShiJie = s->mhlsHeShiJie;
+ av_log(NULL, AV_LOG_ERROR, "HLS header in:mdynamic=%d,sort=%d,mhlsHeShiJie=%d\n",c->mdynamic,c->mSort,c->misHeShiJie);
+
+ if((s != NULL) && (s->header != NULL))
+ {
+ memset(c->header,0,MAX_URL_SIZE);
+ int length = strlen(s->header);
+ if(length < MAX_URL_SIZE)
+ {
+ memcpy(c->header,s->header,length);
+ }
+ }
- if ((ret = parse_playlist(c, s->filename, NULL, s->pb)) < 0)
- goto fail;
-
+// ff_send_message(c->interrupt_callback,MEDIA_INFO_DOWNLOAD_START,DOWNLOAD_M3U8_START);
+// int64_t startTime = av_gettime();
+loadplaylist:
+ if ((ret = parse_playlist(c, s->filename, NULL, s->pb)) < 0){
+ if(retry > 5){
+ av_log(NULL, AV_LOG_DEBUG, "hls_read_header(), parse_playlist fail,ret = 0x%x",ret);
+
+ goto fail;
+ }else{
+ if(ret == AVERROR_EXIT || s->exit_flag){
+ ret = AVERROR_EOF;
+ goto fail;
+ }
+ retry++;
+ av_usleep(100*1000);
+ goto loadplaylist;
+ }
+ }
if (c->n_variants == 0) {
av_log(NULL, AV_LOG_WARNING, "Empty playlist\n");
ret = AVERROR_EOF;
goto fail;
}
+
+ int64_t endTime = av_gettime();
+ // av_log(NULL, AV_LOG_DEBUG, "hls_read_header(), download m3u8 time = %lld,endTime = %lld,startTime = %lld",(endTime-startTime),endTime,startTime);
+ // ff_send_message(c->interrupt_callback,MEDIA_INFO_DOWNLOAD_END,(endTime-startTime)/1000);
/* If the playlist only contained variants, parse each individual
* variant playlist. */
+ retry = 0;
+loadplaylist1:
if (c->n_variants > 1 || c->variants[0]->n_segments == 0) {
- for (i = 0; i < c->n_variants; i++) {
- struct variant *v = c->variants[i];
- if ((ret = parse_playlist(c, v->url, v, NULL)) < 0)
- goto fail;
- }
+ // for (i = 0; i < c->n_variants; i++) {
+ struct variant *v = c->variants[0];
+ if ((ret = parse_playlist(c, v->url, v, NULL)) < 0){
+ if(retry > 5){
+ goto fail;
+ }else{
+ if(ret == AVERROR_EXIT || s->exit_flag){
+ ret = AVERROR_EOF;
+ goto fail;
+ }
+ retry++;
+ av_usleep(100*1000);
+ goto loadplaylist1;
+ }
+ }
+ }
+ if(c->n_bandwidth_info> 1)
+ {
+ SortBandwidth(c);
}
if (c->variants[0]->n_segments == 0) {
@@ -492,26 +1382,53 @@ static int hls_read_header(AVFormatContext *s)
/* If this isn't a live stream, calculate the total duration of the
* stream. */
- if (c->variants[0]->finished) {
- int64_t duration = 0;
+ av_log(NULL,AV_LOG_DEBUG,"hls_read_header:list finished is %d",c->variants[0]->finished);
+ if (c->variants[0]->finished)
+ {
+ double duration = 0;
for (i = 0; i < c->variants[0]->n_segments; i++)
duration += c->variants[0]->segments[i]->duration;
s->duration = duration * AV_TIME_BASE;
}
+ else
+ {
+ if(1 == c->misHeShiJie)
+ {
+ double duration = 0;
+ for (i = 0; i < c->variants[0]->n_segments; i++)
+ duration += c->variants[0]->segments[i]->duration;
+ s->duration = duration * AV_TIME_BASE;
+ av_log(NULL,AV_LOG_DEBUG,"%s: May be He Shi Jie",__FUNCTION__);
+
+ }
+ else
+ {
+ av_log(NULL,AV_LOG_DEBUG,"%s:livemode now set duration = 20",__FUNCTION__);
+ s->duration = 20; // If living stream has no duration,set 20 to avoid random int
+
+ }
+ }
/* Open the demuxer for each variant */
- for (i = 0; i < c->n_variants; i++) {
+// for (i = 0; i < c->n_variants; i++) {
+ i = 0;
struct variant *v = c->variants[i];
AVInputFormat *in_fmt = NULL;
char bitrate_str[20];
- if (v->n_segments == 0)
- continue;
+ // if (v->n_segments == 0)
+ // continue;
if (!(v->ctx = avformat_alloc_context())) {
ret = AVERROR(ENOMEM);
goto fail;
}
-
+ v->ctx->ts_debug_flag = s->ts_debug_flag;
+ v->ctx->mTaoBaoHevc = 0;
+ if(c->mTaobaoHevc == 1)
+ {
+ v->ctx->mTaoBaoHevc = 1;
+ }
+
v->index = i;
v->needed = 1;
v->parent = s;
@@ -519,12 +1436,34 @@ static int hls_read_header(AVFormatContext *s)
/* If this is a live stream with more than 3 segments, start at the
* third last segment. */
v->cur_seq_no = v->start_seq_no;
- if (!v->finished && v->n_segments > 3)
- v->cur_seq_no = v->start_seq_no + v->n_segments - 3;
+// if (!v->finished && v->n_segments > 3)
+// v->cur_seq_no = v->start_seq_no + v->n_segments - 3;
v->read_buffer = av_malloc(INITIAL_BUFFER_SIZE);
+ if(c->BandWidthqueue == NULL)
+ {
+ c->BandWidthqueue = InitQueue();
+ av_log(NULL,AV_LOG_DEBUG,"init BandWidthqueue");
+ }
+ if (strstr(s->filename, "file/m3u8:fd")){
+ v->ctx->probesize = 50000000;
+ }
+ else
+ {
+ if(s->duration > 20) // discriminate VOD stream
+ {
+ v->ctx->probesize = 4*1024*1024;
+ v->ctx->max_analyze_duration = 10*1000*1000;
+ }
+ else //discriminate living stream
+ {
+ v->ctx->probesize = 200*1024; // prevent video information err of width or height
+ v->ctx->max_analyze_duration = 4*1000*1000;
+ }
+ }
ffio_init_context(&v->pb, v->read_buffer, INITIAL_BUFFER_SIZE, 0, v,
read_data, NULL, NULL);
+ v->pb.read_seqno = read_seqno;
v->pb.seekable = 0;
ret = av_probe_input_buffer(&v->pb, &in_fmt, v->segments[0]->url,
NULL, 0, 0);
@@ -533,13 +1472,20 @@ static int hls_read_header(AVFormatContext *s)
* so avformat_close_input shouldn't be called. If
* avformat_open_input fails below, it frees and zeros the
* context, so it doesn't need any special treatment like this. */
- av_log(s, AV_LOG_ERROR, "Error when loading first segment '%s'\n", v->segments[0]->url);
+ av_log(s, AV_LOG_DEBUG, "Error when loading first segment '%s'\n", v->segments[0]->url);
avformat_free_context(v->ctx);
v->ctx = NULL;
goto fail;
}
v->ctx->pb = &v->pb;
+
+#if HLS_DEBUG
+ av_log(NULL, AV_LOG_DEBUG, "hls:avformat_open_input in \n");
+#endif
ret = avformat_open_input(&v->ctx, v->segments[0]->url, in_fmt, NULL);
+#if HLS_DEBUG
+ av_log(NULL, AV_LOG_DEBUG, "hls:avformat_open_input out \n");
+#endif
if (ret < 0)
goto fail;
@@ -552,23 +1498,59 @@ static int hls_read_header(AVFormatContext *s)
/* Create new AVStreams for each stream in this variant */
for (j = 0; j < v->ctx->nb_streams; j++) {
AVStream *st = avformat_new_stream(s, NULL);
+ AVStream *tmp;
if (!st) {
ret = AVERROR(ENOMEM);
goto fail;
}
st->id = i;
avcodec_copy_context(st->codec, v->ctx->streams[j]->codec);
+
+ tmp = v->ctx->streams[j];
+ if(tmp != NULL)
+ {
+ av_log(NULL,AV_LOG_ERROR,"%s:source %d:timebse: den %d,num %d",__FUNCTION__,tmp->codec->codec_type,
+ tmp->time_base.den,tmp->time_base.num);
+
+ st->time_base = tmp->time_base;
+ }
+
+
+ if(v->ctx->streams[j]->start_time != AV_NOPTS_VALUE)
+ {
+ av_log(NULL,AV_LOG_ERROR, "HLS:%d: start_time: %0.3f duration: %0.3f\n", j,
+ (double) v->ctx->streams[j]->start_time / AV_TIME_BASE,
+ (double) v->ctx->streams[j]->duration / AV_TIME_BASE);
+ st->start_time = v->ctx->streams[j]->start_time;
+
+ }
if (v->bandwidth)
av_dict_set(&st->metadata, "variant_bitrate", bitrate_str,
0);
}
+
stream_offset += v->ctx->nb_streams;
- }
+ if(v->ctx->start_time != AV_NOPTS_VALUE)
+ {
+ av_log(NULL,AV_LOG_ERROR,"HLS: start_time: %0.3f duration: %0.3f bitrate=%d kb/s\n",
+ (double) v->ctx->start_time / AV_TIME_BASE,
+ (double) v->ctx->duration / AV_TIME_BASE,
+ v->ctx->bit_rate / 1000);
+ s->start_time = v->ctx->start_time;
+
+ }
+
+ if (v->ctx->bit_rate > 0 && s->bit_rate <= 0)
+ {
+ s->bit_rate = v->ctx->bit_rate;
+ }
+ // }
+
c->first_packet = 1;
c->first_timestamp = AV_NOPTS_VALUE;
c->seek_timestamp = AV_NOPTS_VALUE;
-
+ av_log(NULL,AV_LOG_DEBUG,"HLS header end");
return 0;
fail:
free_variant_list(c);
@@ -622,7 +1604,8 @@ static int hls_read_packet(AVFormatContext *s, AVPacket *pkt)
start:
c->end_of_segment = 0;
- for (i = 0; i < c->n_variants; i++) {
+ // for (i = 0; i < c->n_variants; i++) {
+ i = 0;
struct variant *var = c->variants[i];
/* Make sure we've got one buffered packet from each open variant
* stream */
@@ -631,9 +1614,23 @@ start:
int64_t ts_diff;
AVStream *st;
ret = av_read_frame(var->ctx, &var->pkt);
+ //var->pkt.seq = var->cur_seq_no;
if (ret < 0) {
- if (!url_feof(&var->pb) && ret != AVERROR_EOF)
+#if HLS_DEBUG
+ av_log(NULL, AV_LOG_DEBUG, "hls_read_packet = %d\n",ret);
+#endif
+ if(ff_check_operate(c->interrupt_callback,OPERATE_SEEK,NULL,NULL))
+ {
+ av_log(NULL,AV_LOG_ERROR,"hls_read_packet, new seek arrival,return immediately");
+ return AVERROR(EAGAIN);
+ }
+
+ if (!url_feof(&var->pb) && ret != AVERROR_EOF){
return ret;
+ }
+#if HLS_DEBUG
+ av_log(NULL, AV_LOG_DEBUG, "hls_read_packet AVERROR_EOF ret = %d\n",ret);
+#endif
reset_packet(&var->pkt);
break;
} else {
@@ -641,7 +1638,7 @@ start:
c->first_timestamp = var->pkt.dts;
}
- if (c->seek_timestamp == AV_NOPTS_VALUE)
+ if (c->seek_timestamp == AV_NOPTS_VALUE && !(c->seek_flags & AVSEEK_FLAG_READ_NEED_OPEN_NEW_URL))
break;
if (var->pkt.dts == AV_NOPTS_VALUE) {
@@ -653,7 +1650,17 @@ start:
ts_diff = av_rescale_rnd(var->pkt.dts, AV_TIME_BASE,
st->time_base.den, AV_ROUND_DOWN) -
c->seek_timestamp;
- if (ts_diff >= 0 && (c->seek_flags & AVSEEK_FLAG_ANY ||
+
+ if (st->codec && (st->codec->codec_type == AVMEDIA_TYPE_VIDEO)) {
+ if (c->seek_flags & AVSEEK_FLAG_READ_NEED_OPEN_NEW_URL) {
+ av_log(NULL, AV_LOG_DEBUG, "read packet not open url yet, drop it...\n");
+ av_free_packet(&var->pkt);
+// reset_packet(&var->pkt);
+ continue;
+ }
+ }
+
+ if ((c->seek_flags & AVSEEK_FLAG_ANY ||
var->pkt.flags & AV_PKT_FLAG_KEY)) {
c->seek_timestamp = AV_NOPTS_VALUE;
break;
@@ -678,10 +1685,11 @@ start:
minvariant = i;
}
}
- }
+ // }
if (c->end_of_segment) {
- if (recheck_discard_flags(s, 0))
+ if (recheck_discard_flags(s, 0)){
goto start;
+ }
}
/* If we got a packet, return it */
if (minvariant >= 0) {
@@ -690,27 +1698,323 @@ start:
reset_packet(&c->variants[minvariant]->pkt);
return 0;
}
+
+ av_log(NULL, AV_LOG_DEBUG, "HLS read AVERROR_EOF\n");
return AVERROR_EOF;
}
static int hls_close(AVFormatContext *s)
{
+ av_log(NULL, AV_LOG_DEBUG, "Hery, hls_close");
HLSContext *c = s->priv_data;
+ AVIOParams *params = c->interrupt_callback->ioparams;
+ if(params) params->willclose = 1;
+
free_variant_list(c);
+ av_log(NULL,AV_LOG_DEBUG,"hls_close:DestroyQueue");
+ if(c->BandWidthqueue != NULL)
+ {
+ DestroyQueue(c->BandWidthqueue);
+ c->BandWidthqueue = NULL;
+ }
+ if(params){
+ if(params->hd){
+ ffurl_closep(&params->hd);
+ }
+ av_free(params);
+ c->interrupt_callback->ioparams = NULL;
+ }
return 0;
}
+static int hls_seek_new_url(AVFormatContext *s)
+{
+ HLSContext *c = s->priv_data;
+ av_log(NULL,AV_LOG_DEBUG,"%s",__FUNCTION__);
+ int ret = 0;
+ int retry = 0;
+ int i = 0;
+ int j = 0;
+ int stream_offset = 0;
+ char* new_url = NULL;
+
+ // get the seek url
+ ff_check_operate(c->interrupt_callback,OPERATE_GET_URL,NULL,(void**)&new_url);
+ if(new_url == NULL)
+ {
+ return -1;
+ }
+
+ AVIOParams *params = c->interrupt_callback->ioparams;
+ if(params&&params->type==1&&params->redirect==1&&params->url[0]!='\0')
+ {
+ params->redirect = 0;//avoid parse_playlist use redirect url
+ }
+
+ // release all variant in HlsContext
+ if(c != NULL)
+ {
+ free_variant_list(c);
+ }
+
+ // release band queue
+ if(c->BandWidthqueue != NULL)
+ {
+ DestroyQueue(c->BandWidthqueue);
+ c->BandWidthqueue = NULL;
+ }
+
+ URLContext *u = (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : s->pb->opaque;
+ if(u != NULL)
+ {
+ c->cookies = u->cookies;
+ }
+ c->interrupt_callback = &s->interrupt_callback;
+ c->mdynamic = s->mhlsdynamic;
+ c->mSort = s->mhlsSort;
+ c->misHeShiJie = s->mhlsHeShiJie;
+
+ ret = parse_playlist(c, new_url, NULL, NULL);
+ if (c->n_variants == 0)
+ {
+ av_log(NULL, AV_LOG_ERROR, "Empty playlist\n");
+ ret = AVERROR_EOF;
+ goto fail;
+ }
+
+loadplaylist1:
+ if (c->n_variants > 1 || c->variants[0]->n_segments == 0)
+ {
+ struct variant *v = c->variants[0];
+ if ((ret = parse_playlist(c, v->url, v, NULL)) < 0)
+ {
+ if(retry > 5)
+ {
+ goto fail;
+ }
+ else
+ {
+ if(ret == AVERROR_EXIT || s->exit_flag)
+ {
+ ret = AVERROR_EOF;
+ goto fail;
+ }
+ retry++;
+ av_usleep(100*1000);
+ goto loadplaylist1;
+ }
+ }
+ }
+
+ //the next code is coying form hls_read_head
+ if(c->n_bandwidth_info> 1)
+ {
+ SortBandwidth(c);
+ }
+
+ if (c->variants[0]->n_segments == 0)
+ {
+ av_log(NULL, AV_LOG_WARNING, "Empty playlist\n");
+ ret = AVERROR_EOF;
+ goto fail;
+ }
+
+ /* If this isn't a live stream, calculate the total duration of the
+ * stream. */
+ av_log(NULL,AV_LOG_DEBUG,"hls_seek_new_url:list finished is %d",c->variants[0]->finished);
+ if (c->variants[0]->finished)
+ {
+ double duration = 0;
+ for (i = 0; i < c->variants[0]->n_segments; i++)
+ duration += c->variants[0]->segments[i]->duration;
+ s->duration = duration * AV_TIME_BASE;
+ }
+ else
+ {
+ if(1 == c->misHeShiJie)
+ {
+ double duration = 0;
+ for (i = 0; i < c->variants[0]->n_segments; i++)
+ duration += c->variants[0]->segments[i]->duration;
+ s->duration = duration * AV_TIME_BASE;
+ av_log(NULL,AV_LOG_DEBUG,"%s: May be He Shi Jie",__FUNCTION__);
+ }
+ else
+ {
+ av_log(NULL,AV_LOG_DEBUG,"%s:livemode now set duration = 20",__FUNCTION__);
+ s->duration = 20; // If living stream has no duration,set 20 to avoid random int
+
+ }
+ }
+
+ /* Open the demuxer for each variant */
+ i = 0;
+ struct variant *v = c->variants[i];
+ AVInputFormat *in_fmt = NULL;
+ char bitrate_str[20];
+
+ if (!(v->ctx = avformat_alloc_context()))
+ {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ v->ctx->ts_debug_flag = s->ts_debug_flag;
+ v->ctx->mTaoBaoHevc = 0;
+ if(c->mTaobaoHevc == 1)
+ {
+ v->ctx->mTaoBaoHevc = 1;
+ }
+
+ v->index = i;
+ v->needed = 1;
+ v->parent = s;
+
+ /* If this is a live stream with more than 3 segments, start at the
+ * third last segment. */
+ v->cur_seq_no = v->start_seq_no;
+
+ v->read_buffer = av_malloc(INITIAL_BUFFER_SIZE);
+ if(c->BandWidthqueue == NULL)
+ {
+ c->BandWidthqueue = InitQueue();
+ av_log(NULL,AV_LOG_DEBUG,"init BandWidthqueue");
+ }
+
+ if (strstr(s->filename, "file/m3u8:fd"))
+ {
+ v->ctx->probesize = 50000000;
+ }
+ else
+ {
+ if(s->duration > 20) // discriminate VOD stream
+ {
+ v->ctx->probesize = 4*1024*1024;
+ v->ctx->max_analyze_duration = 10*1000*1000;
+ }
+ else //discriminate living stream
+ {
+ v->ctx->probesize = 200*1024; // prevent video information err of width or height
+ v->ctx->max_analyze_duration = 4*1000*1000;
+ }
+ }
+ ffio_init_context(&v->pb, v->read_buffer, INITIAL_BUFFER_SIZE, 0, v,
+ read_data, NULL, NULL);
+ v->pb.read_seqno = read_seqno;
+ v->pb.seekable = 0;
+ ret = av_probe_input_buffer(&v->pb, &in_fmt, v->segments[0]->url,
+ NULL, 0, 0);
+ if (ret < 0) {
+ /* Free the ctx - it isn't initialized properly at this point,
+ * so avformat_close_input shouldn't be called. If
+ * avformat_open_input fails below, it frees and zeros the
+ * context, so it doesn't need any special treatment like this. */
+ av_log(s, AV_LOG_DEBUG, "Error when loading first segment '%s'\n", v->segments[0]->url);
+ avformat_free_context(v->ctx);
+ v->ctx = NULL;
+ goto fail;
+ }
+ v->ctx->pb = &v->pb;
+
+ ret = avformat_open_input(&v->ctx, v->segments[0]->url, in_fmt, NULL);
+
+ if (ret < 0)
+ goto fail;
+
+ v->stream_offset = stream_offset;
+ v->ctx->ctx_flags &= ~AVFMTCTX_NOHEADER;
+ ret = avformat_find_stream_info(v->ctx, NULL);
+ if (ret < 0)
+ goto fail;
+
+ snprintf(bitrate_str, sizeof(bitrate_str), "%d", v->bandwidth);
+ /* Create new AVStreams for each stream in this variant */
+ for (j = 0; j < v->ctx->nb_streams; j++)
+ {
+ AVStream *st = avformat_new_stream(s, NULL);
+ AVStream *tmp;
+ if (!st) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ st->id = i;
+ avcodec_copy_context(st->codec, v->ctx->streams[j]->codec);
+
+ tmp = v->ctx->streams[j];
+ if(tmp != NULL)
+ {
+ av_log(NULL,AV_LOG_ERROR,"%s:source %d:timebse: den %d,num %d",__FUNCTION__,tmp->codec->codec_type,
+ tmp->time_base.den,tmp->time_base.num);
+ st->time_base = tmp->time_base;
+ }
+
+
+ if(v->ctx->streams[j]->start_time != AV_NOPTS_VALUE)
+ {
+ av_log(NULL,AV_LOG_ERROR, "HLS:%d: start_time: %0.3f duration: %0.3f\n", j,
+ (double) v->ctx->streams[j]->start_time / AV_TIME_BASE,
+ (double) v->ctx->streams[j]->duration / AV_TIME_BASE);
+ st->start_time = v->ctx->streams[j]->start_time;
+ }
+ if (v->bandwidth)
+ av_dict_set(&st->metadata, "variant_bitrate", bitrate_str,0);
+ }
+
+ stream_offset += v->ctx->nb_streams;
+ if(v->ctx->start_time != AV_NOPTS_VALUE)
+ {
+ av_log(NULL,AV_LOG_ERROR,"HLS: start_time: %0.3f duration: %0.3f bitrate=%d kb/s\n",
+ (double) v->ctx->start_time / AV_TIME_BASE,
+ (double) v->ctx->duration / AV_TIME_BASE,
+ v->ctx->bit_rate / 1000);
+ s->start_time = v->ctx->start_time;
+
+ }
+
+ c->first_packet = 1;
+ c->first_timestamp = AV_NOPTS_VALUE;
+ c->seek_timestamp = AV_NOPTS_VALUE;
+ av_log(NULL,AV_LOG_DEBUG,"hls_seek_new_url ok");
+
+ return 0;
+fail:
+ free_variant_list(c);
+ return -1;
+}
static int hls_read_seek(AVFormatContext *s, int stream_index,
int64_t timestamp, int flags)
{
HLSContext *c = s->priv_data;
int i, j, ret;
+#if HLS_DEBUG
+ av_log(NULL,AV_LOG_DEBUG,"%s:start:timestamp=%lld",__FUNCTION__,timestamp);
+#endif
+
+ //add by hh for wase seek using new url
+ if(flags & AVSEEK_FLAG_SEEK_USE_NEW_URL)
+ {
+ int result = hls_seek_new_url(s);
+ if(result < 0)
+ {
+ av_log(NULL,AV_LOG_ERROR,"hls_read_seek retult = %d",result);
+ return AVERROR_SEEK_FAIL;
+ }
- if ((flags & AVSEEK_FLAG_BYTE) || !c->variants[0]->finished)
+ return 0;
+ }
+
+ /*
+ * (金亚问题)CNTV 直播流无法seek的问题,听从ht建议,增加对n_bandwidth_info的判读(直播流一般没有动态码率)
+ */
+ if ((flags & AVSEEK_FLAG_BYTE) || (!c->variants[0]->finished && c->n_bandwidth_info > 1))
+ {
+#if HLS_DEBUG
+ av_log(NULL,AV_LOG_DEBUG,"%s:ENOSYS",__FUNCTION__);
+#endif
return AVERROR(ENOSYS);
+ }
- c->seek_flags = flags;
+ c->seek_flags |= (flags | AVSEEK_FLAG_READ_NEED_OPEN_NEW_URL);
c->seek_timestamp = stream_index < 0 ? timestamp :
av_rescale_rnd(timestamp, AV_TIME_BASE,
s->streams[stream_index]->time_base.den,
@@ -721,20 +2025,21 @@ static int hls_read_seek(AVFormatContext *s, int stream_index,
AV_TIME_BASE, flags & AVSEEK_FLAG_BACKWARD ?
AV_ROUND_DOWN : AV_ROUND_UP);
if (s->duration < c->seek_timestamp) {
- c->seek_timestamp = AV_NOPTS_VALUE;
- return AVERROR(EIO);
+ c->seek_timestamp = s->duration;
}
ret = AVERROR(EIO);
- for (i = 0; i < c->n_variants; i++) {
+ // for (i = 0; i < c->n_variants; i++) {
/* Reset reading */
+ i = 0;
struct variant *var = c->variants[i];
- int64_t pos = c->first_timestamp == AV_NOPTS_VALUE ? 0 :
+ double pos = c->first_timestamp == AV_NOPTS_VALUE ? 0 :
av_rescale_rnd(c->first_timestamp, 1, stream_index >= 0 ?
s->streams[stream_index]->time_base.den :
AV_TIME_BASE, flags & AVSEEK_FLAG_BACKWARD ?
AV_ROUND_DOWN : AV_ROUND_UP);
- if (var->input) {
+ double dispos = -1;
+ if (var->input) {
ffurl_close(var->input);
var->input = NULL;
}
@@ -745,20 +2050,84 @@ static int hls_read_seek(AVFormatContext *s, int stream_index,
var->pb.buf_end = var->pb.buf_ptr = var->pb.buffer;
/* Reset the pos, to let the mpegts demuxer know we've seeked. */
var->pb.pos = 0;
-
+ av_log(NULL,AV_LOG_DEBUG,"hls_read_seek:pos%f",pos);
+
+ av_log(NULL,AV_LOG_DEBUG,"c->seek_flags = %d",c->seek_flags);
+ if(var)
+ {
+ if(c->seek_flags & AVSEEK_FLAG_SPECIAL_URL)
+ {
+ av_log(NULL,AV_LOG_DEBUG,"yst or BestTv lookback,need changed pos");
+ pos = 0;
+ c->seek_flags &= (~AVSEEK_FLAG_SPECIAL_URL);
+ }
+ }
/* Locate the segment that contains the target timestamp */
- for (j = 0; j < var->n_segments; j++) {
+ av_log(NULL,AV_LOG_DEBUG,"var->n_segments = %d,timestamp = %lld,pos = %f",var->n_segments,timestamp,pos);
+
+ //edit by xhr , Unified, timeus is equal to mSeekTimeUs,not to add s->start_time
+ //Coordination to ffmpeg hls to use
+ timestamp += pos;
+
+
+ for (j = 0; j < var->n_segments; j++) {
+ if(var->segments[j]->discontinuity){
+ dispos = pos;
+ }
+
+ /*
+ * 如果seek时间落在切片的前半段,则使用该切片
+ */
if (timestamp >= pos &&
- timestamp < pos + var->segments[j]->duration) {
+ timestamp <= pos + var->segments[j]->duration/2) {
+ var->cur_seq_no = var->start_seq_no + j;
+// var->segments[j]->seek_operation_time = timestamp - pos; //add by xhr, for Bluray seek operation
+ ret = 0;
+ break;
+ }
+
+ /*
+ * 如果seek时间落在切片的后半段,则使用该切片的下一个切片
+ */
+ if(timestamp > pos + var->segments[j]->duration/2 && timestamp < pos + var->segments[j]->duration)
+ {
+ if(j < (var->n_segments - 1))
+ {
+ j++;
+ }
var->cur_seq_no = var->start_seq_no + j;
ret = 0;
break;
}
pos += var->segments[j]->duration;
}
+ av_log(NULL,AV_LOG_DEBUG,"j1 = %d",j);
+ //如果timestamp=0,期望从头开始播放,但是小于pos,初始值,那么需要修正cur_seq_no
+ if(j == var->n_segments && timestamp== 0 && timestamp < pos)
+ {
+ j = 0;
+ var->cur_seq_no = var->start_seq_no + j;
+ }
+ if(j == var->n_segments){
+ var->cur_seq_no = var->start_seq_no + j;
+ ret = 0;
+ }
+
+ av_log(NULL,AV_LOG_DEBUG,"j = %d",j);
if (ret)
c->seek_timestamp = AV_NOPTS_VALUE;
+ if(dispos > 0){
+#if HLS_DEBUG
+ av_log(NULL, AV_LOG_DEBUG, "c->seek_timestamp= %lld,dispos = %lf\n",c->seek_timestamp,dispos*1000000);
+#endif
+ c->seek_timestamp -= ((int64_t)dispos)*1000000;
+#if HLS_DEBUG
+ av_log(NULL, AV_LOG_DEBUG, "seek_timestamp after = %lld \n",c->seek_timestamp);
+#endif
+ }else{
+ c->seek_timestamp = AV_NOPTS_VALUE;
}
+ av_log(NULL,AV_LOG_DEBUG,"hls_seek:tm=%lld,curQ=%d",timestamp,var->cur_seq_no);
return ret;
}
@@ -766,6 +2135,9 @@ static int hls_probe(AVProbeData *p)
{
/* Require #EXTM3U at the start, and either one of the ones below
* somewhere for a proper match. */
+#if HLS_DEBUG
+ av_log(NULL,AV_LOG_DEBUG,"hls_probe in\n");
+#endif
if (strncmp(p->buf, "#EXTM3U", 7))
return 0;
if (strstr(p->buf, "#EXT-X-STREAM-INF:") ||
diff --git a/libavformat/http.c b/libavformat/http.c
index 308c22d..2ac2f68 100644..100755
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -29,6 +29,10 @@
#include "url.h"
#include "libavutil/opt.h"
+#if CONFIG_ZLIB
+#include <zlib.h>
+#endif
+
/* XXX: POST protocol is not completely implemented because ffmpeg uses
only a subset of it. */
@@ -38,6 +42,9 @@
*/
#define BUFFER_SIZE MAX_URL_SIZE
#define MAX_REDIRECTS 8
+#define HTTP_DEBUG 1
+
+#define HTTP_TIMEOUT 2000
typedef struct {
const AVClass *class;
@@ -52,7 +59,9 @@ typedef struct {
char location[MAX_URL_SIZE];
HTTPAuthState auth_state;
HTTPAuthState proxy_auth_state;
+ char *cookies; /**< add by xhr, for set cookies. */
char *headers;
+ int mmsh;
int willclose; /**< Set if the server correctly handles Connection: close and will close the connection after feeding us the content. */
int seekable; /**< Control seekability, 0 = disable, 1 = enable, -1 = probe. */
int chunked_post;
@@ -62,7 +71,18 @@ typedef struct {
uint8_t *post_data;
int post_datalen;
int is_akamai;
- int rw_timeout;
+ int rw_timeout;
+ int mHlsConductor;
+ int mFlvConductor;
+ int mMovConductor;
+ char mHostname[1024];//ht for 302 http service answer a relative address .
+ int mHlsParse;
+ int mZeroRange;
+#if CONFIG_ZLIB
+ int compressed;
+ z_stream inflate_stream;
+ uint8_t *inflate_buffer;
+#endif
} HTTPContext;
#define OFFSET(x) offsetof(HTTPContext, x)
@@ -78,6 +98,12 @@ static const AVOption options[] = {
{"multiple_requests", "use persistent connections", OFFSET(multiple_requests), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, D|E },
{"post_data", "custom HTTP post data", OFFSET(post_data), AV_OPT_TYPE_BINARY, .flags = D|E },
{"timeout", "timeout of socket i/o operations", OFFSET(rw_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, D|E },
+{"hls", "hls conductor", OFFSET(mHlsConductor), AV_OPT_TYPE_INT, {.i64 = -1},-1, INT_MAX, D|E },
+{"flv", "flv conductor", OFFSET(mFlvConductor), AV_OPT_TYPE_INT, {.i64 = -1},-1, INT_MAX, D|E },
+{"mmsh", "mmsh", OFFSET(mmsh), AV_OPT_TYPE_INT, {.i64 = -1},-1, INT_MAX, D|E },
+{"mp4", "mp4 conductor", OFFSET(mMovConductor), AV_OPT_TYPE_INT, {.i64 = -1},-1, INT_MAX, D|E },
+{"hls_parse", "hls m3u8 parse", OFFSET(mHlsParse), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, D|E },
+{"cookies", "set cookies to be sent in applicable future requests, use newline delimited Set-Cookie HTTP field value syntax", OFFSET(cookies), AV_OPT_TYPE_STRING, {0}, 0, 0, D },
{NULL}
};
#define HTTP_CLASS(flavor)\
@@ -91,6 +117,75 @@ static const AVClass flavor ## _context_class = {\
HTTP_CLASS(http);
HTTP_CLASS(https);
+static int http_buf_read(URLContext *h, uint8_t *buf, int size);
+static int http_read(URLContext *h, uint8_t *buf, int size);
+
+
+static int parse_content_encoding(URLContext *h, const char *p)
+{
+ HTTPContext *s = h->priv_data;
+
+ if (!av_strncasecmp(p, "gzip", 4) ||
+ !av_strncasecmp(p, "deflate", 7)) {
+#if CONFIG_ZLIB
+ av_log(NULL,AV_LOG_ERROR,"parse_content_encoding");
+ s->compressed = 1;
+ inflateEnd(&s->inflate_stream);
+ if (inflateInit2(&s->inflate_stream, 32 + 15) != Z_OK) {
+ av_log(h, AV_LOG_ERROR, "Error during zlib initialisation: %s\n",
+ s->inflate_stream.msg);
+ return AVERROR(ENOSYS);
+ }
+ if (zlibCompileFlags() & (1 << 17)) {
+ av_log(h, AV_LOG_ERROR,
+ "Your zlib was compiled without gzip support.\n");
+ return AVERROR(ENOSYS);
+ }
+#else
+ av_log(h, AV_LOG_ERROR,
+ "Compressed (%s) content, need zlib with gzip support\n", p);
+ return AVERROR(ENOSYS);
+#endif
+ } else if (!av_strncasecmp(p, "identity", 8)) {
+ // The normal, no-encoding case (although servers shouldn't include
+ // the header at all if this is the case).
+ } else {
+ av_log(h, AV_LOG_ERROR, "Unknown content coding: %s\n", p);
+ }
+ return 0;
+}
+#if CONFIG_ZLIB
+#define DECOMPRESS_BUF_SIZE (256 * 1024)
+static int http_buf_read_compressed(URLContext *h, uint8_t *buf, int size)
+{
+ HTTPContext *s = h->priv_data;
+ int ret;
+ av_log(NULL,AV_LOG_ERROR,"http_buf_read_compressed");
+ if (!s->inflate_buffer) {
+ s->inflate_buffer = av_malloc(DECOMPRESS_BUF_SIZE);
+ if (!s->inflate_buffer)
+ return AVERROR(ENOMEM);
+ }
+
+ if (s->inflate_stream.avail_in == 0) {
+ int read = http_buf_read(h, s->inflate_buffer, DECOMPRESS_BUF_SIZE);
+ if (read <= 0)
+ return read;
+ s->inflate_stream.next_in = s->inflate_buffer;
+ s->inflate_stream.avail_in = read;
+ }
+
+ s->inflate_stream.avail_out = size;
+ s->inflate_stream.next_out = buf;
+
+ ret = inflate(&s->inflate_stream, Z_SYNC_FLUSH);
+ if (ret != Z_OK && ret != Z_STREAM_END)
+ av_log(h, AV_LOG_ERROR, "inflate return value: %d, %s\n", ret, s->inflate_stream.msg);
+ av_log(NULL,AV_LOG_ERROR,"ret=%d",size - s->inflate_stream.avail_out);
+ return size - s->inflate_stream.avail_out;
+}
+#endif
+
static int http_connect(URLContext *h, const char *path, const char *local_path,
const char *hoststr, const char *auth,
const char *proxyauth, int *new_location);
@@ -104,6 +199,87 @@ void ff_http_init_auth_state(URLContext *dest, const URLContext *src)
sizeof(HTTPAuthState));
}
+//Persist http connection begin, HLS only, need set multiple_requests 1
+#define HTTP_PERSIST_DEBUG 1
+static void http_reset_params(URLContext *h)
+{
+ AVIOParams *params = h->interrupt_callback.ioparams;
+ if(params){
+ #if HTTP_PERSIST_DEBUG
+ //av_log(NULL, AV_LOG_DEBUG, "reset http persist connection params");
+ #endif
+ params->host[0] = '\0';
+ params->port = -1;
+ params->hd = NULL;
+ params->willclose = 1;
+ }
+}
+
+static int http_keep_conn(URLContext *h, HTTPContext *s)
+{
+ AVIOParams *params = h->interrupt_callback.ioparams;
+ if(params&&params->type==1&&s->multiple_requests==1){
+ if(!params->willclose&&params->hd)
+ {
+ #if HTTP_PERSIST_DEBUG
+ av_log(NULL, AV_LOG_DEBUG, "keep persist connection, don't close it");
+ #endif
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static void http_get_persist_conn(URLContext *h, HTTPContext *s, char* hostname, int port)
+{
+ if(s->hd){
+ av_log(NULL, AV_LOG_DEBUG, "may be use last connection again");
+ return;
+ }
+ AVIOParams *params = h->interrupt_callback.ioparams;
+ if(params&&params->type==1&&s->multiple_requests==1&&params->hd)
+ {
+ if(strncmp(params->host, hostname, strlen(params->host))==0&&params->port==port){
+ #if HTTP_PERSIST_DEBUG
+ av_log(NULL, AV_LOG_DEBUG, "restore last http persist connection again");
+ #endif
+ if(s->rw_timeout == -1)
+ s->rw_timeout = 10*1000*1000;
+ s->hd = params->hd;
+ } else {
+ #if HTTP_PERSIST_DEBUG
+ av_log(NULL, AV_LOG_DEBUG, "host/port changed, need to close last connection");
+ #endif
+ ffurl_closep(&params->hd);
+ http_reset_params(h);
+ }
+ }
+}
+
+static void http_set_persist_conn(URLContext *h, HTTPContext *s, char* hostname, int port)
+{
+ AVIOParams *params = h->interrupt_callback.ioparams;
+ if(params&&params->type==1&&s->multiple_requests==1){
+ params->willclose = s->willclose;
+ if(s->willclose) return;
+
+ params->hd = s->hd;
+ params->port = port;
+ memcpy(params->host, hostname, sizeof(params->host));
+ av_log(NULL, AV_LOG_DEBUG, "save current http persist connection");
+ }
+}
+
+static void http_save_redirect_url(URLContext *h, HTTPContext *s, char* location)
+{
+ AVIOParams *params = h->interrupt_callback.ioparams;
+ if(params&&params->type==1&&s->mHlsParse==1) {
+ strcpy(params->url, location);
+ params->redirect = 1;
+ }
+}
+//Persist http connection end
+
/* return non zero if error */
static int http_open_cnx(URLContext *h)
{
@@ -116,6 +292,8 @@ static int http_open_cnx(URLContext *h)
HTTPAuthType cur_auth_type, cur_proxy_auth_type;
HTTPContext *s = h->priv_data;
+ strcpy(h->url, h->filename);
+
proxy_path = getenv("http_proxy");
use_proxy = (proxy_path != NULL) && !getenv("no_proxy") &&
av_strstart(proxy_path, "http://", NULL);
@@ -126,6 +304,14 @@ static int http_open_cnx(URLContext *h)
av_url_split(proto, sizeof(proto), auth, sizeof(auth),
hostname, sizeof(hostname), &port,
path1, sizeof(path1), s->location);
+ if(strlen(hostname) == 0)
+ {
+ if(s->mHostname[0]!='\0')
+ {
+ strcpy(hostname,s->mHostname);
+ av_log(NULL,AV_LOG_DEBUG,"get new hostnmae failed,used old one");
+ }
+ }
ff_url_join(hoststr, sizeof(hoststr), NULL, NULL, hostname, port, NULL);
if (!strcmp(proto, "https")) {
@@ -154,22 +340,51 @@ static int http_open_cnx(URLContext *h)
ff_url_join(buf, sizeof(buf), lower_proto, NULL, hostname, port, NULL);
+ //pesist connection by fxw 20141023
+ //1. Get old connection
+ int new_conn = 0;
+ http_get_persist_conn(h, s, hostname, port);
+
if (!s->hd) {
AVDictionary *opts = NULL;
char opts_format[20];
+ if(s->rw_timeout == -1)
+ s->rw_timeout = 10*1000*1000;
if (s->rw_timeout != -1) {
+#if HTTP_DEBUG
+ av_log(NULL, AV_LOG_DEBUG,"http_open_cnx:reload_interval = %d \n", s->rw_timeout);
+#endif
snprintf(opts_format, sizeof(opts_format), "%d", s->rw_timeout);
av_dict_set(&opts, "timeout", opts_format, 0);
} /* if option is not given, don't pass it and let tcp use its own default */
err = ffurl_open(&s->hd, buf, AVIO_FLAG_READ_WRITE,
&h->interrupt_callback, &opts);
av_dict_free(&opts);
- if (err < 0)
+ if (err < 0){
+#if HTTP_DEBUG
+ av_log(NULL, AV_LOG_DEBUG,"reload_interval = %d \n", s->rw_timeout);
+#endif
+ av_log(h, AV_LOG_DEBUG, "ffurl_open in err = %d",err);
+
goto fail;
+ }
+ new_conn = 1;
+
+ if((s->mHostname[0] == '\0')||(strcmp(s->mHostname,hostname)!=0))
+ {
+ strcpy(s->mHostname,hostname);
+#if HTTP_DEBUG
+ av_log(NULL,AV_LOG_DEBUG,"new mHostname=%s",s->mHostname);
+#endif
+ }
}
cur_auth_type = s->auth_state.auth_type;
cur_proxy_auth_type = s->auth_state.auth_type;
+#if HTTP_DEBUG
+ av_log(NULL,AV_LOG_DEBUG,"http_open_cnx:ffurl_open ok");
+#endif
+
if (http_connect(h, path, local_path, hoststr, auth, proxyauth, &location_changed) < 0)
goto fail;
attempts++;
@@ -177,6 +392,7 @@ static int http_open_cnx(URLContext *h)
if ((cur_auth_type == HTTP_AUTH_NONE || s->auth_state.stale) &&
s->auth_state.auth_type != HTTP_AUTH_NONE && attempts < 4) {
ffurl_closep(&s->hd);
+ http_reset_params(h);
goto redo;
} else
goto fail;
@@ -185,6 +401,7 @@ static int http_open_cnx(URLContext *h)
if ((cur_proxy_auth_type == HTTP_AUTH_NONE || s->proxy_auth_state.stale) &&
s->proxy_auth_state.auth_type != HTTP_AUTH_NONE && attempts < 4) {
ffurl_closep(&s->hd);
+ http_reset_params(h);
goto redo;
} else
goto fail;
@@ -192,7 +409,12 @@ static int http_open_cnx(URLContext *h)
if ((s->http_code == 301 || s->http_code == 302 || s->http_code == 303 || s->http_code == 307)
&& location_changed == 1) {
/* url moved, get next */
+
ffurl_closep(&s->hd);
+ http_reset_params(h);
+
+ strcpy(h->url, s->location);
+
if (redirects++ >= MAX_REDIRECTS)
return AVERROR(EIO);
/* Restart the authentication process with the new target, which
@@ -200,12 +422,42 @@ static int http_open_cnx(URLContext *h)
memset(&s->auth_state, 0, sizeof(s->auth_state));
attempts = 0;
location_changed = 0;
+ //record 30x url
+ http_save_redirect_url(h, s, s->location);
+
+#if HTTP_DEBUG
+ av_log(NULL,AV_LOG_DEBUG,"http_open_cnx:http_code=%d,redo!!",s->http_code);
+#endif
+
goto redo;
}
+#if HTTP_DEBUG
+ av_log(h, AV_LOG_DEBUG, "http_open_cnx ok");
+#endif
+
+ //2. Save new connection
+ if(new_conn)
+ http_set_persist_conn(h, s, hostname, port);
return 0;
fail:
- if (s->hd)
+
+ av_log(h, AV_LOG_DEBUG, "http_open_cnx fail:code=%d,err = %d,ETIMEDOUT = %d",s->http_code,err,ETIMEDOUT);
+ h->errcode = s->http_code;
+#if 0
+ if(h->errcode != 0 && h->errcode > 0)
+ {
+ ff_send_message(&h->interrupt_callback,MEDIA_INFO_DOWNLOAD_ERROR,h->errcode);
+ }
+ av_log(h, AV_LOG_DEBUG, "http_open_cnx :*********err = %d,ETIMEDOUT = %d",err,ETIMEDOUT);
+ if((err == -ETIMEDOUT) || (err == -101))
+ {
+ ff_send_message(&h->interrupt_callback,MEDIA_INFO_DOWNLOAD_ERROR,100000);// HTTP_TIMEOUT
+ }
+#endif
+ if (s->hd){
ffurl_closep(&s->hd);
+ http_reset_params(h);
+ }
return AVERROR(EIO);
}
@@ -229,16 +481,23 @@ static int http_open(URLContext *h, const char *uri, int flags)
h->is_streamed = 1;
s->filesize = -1;
+ s->mZeroRange = 0;
+
+#if HTTP_DEBUG
+ av_log(h, AV_LOG_DEBUG, "http_open:uri = %s\n",uri);
+#endif
av_strlcpy(s->location, uri, sizeof(s->location));
if (s->headers) {
int len = strlen(s->headers);
+
if (len < 2 || strcmp("\r\n", s->headers + len - 2))
av_log(h, AV_LOG_WARNING, "No trailing CRLF found in HTTP header.\n");
}
return http_open_cnx(h);
}
+
static int http_getc(HTTPContext *s)
{
int len;
@@ -280,12 +539,134 @@ static int http_get_line(HTTPContext *s, char *line, int line_size)
}
}
+
+
+/**
+ * Create a string containing cookie values for use as a HTTP cookie header
+ * field value for a particular path and domain from the cookie values stored in
+ * the HTTP protocol context. The cookie string is stored in *cookies.
+ *
+ * @return a negative value if an error condition occurred, 0 otherwise
+ */
+ //add by xhr
+static int get_cookies(char *s, char **cookies, const char *path,
+ const char *domain)
+{
+ // cookie strings will look like Set-Cookie header field values. Multiple
+ // Set-Cookie fields will result in multiple values delimited by a newline
+ int ret = 0;
+ char *next, *cookie, *set_cookies = av_strdup(s), *cset_cookies = set_cookies;
+
+ if (!set_cookies) return AVERROR(EINVAL);
+
+ *cookies = NULL;
+ while ((cookie = av_strtok(set_cookies, "\n", &next))) {
+ int domain_offset = 0;
+ char *param, *next_param, *cdomain = NULL, *cpath = NULL, *cvalue = NULL;
+ set_cookies = NULL;
+
+ while ((param = av_strtok(cookie, "; ", &next_param))) {
+ cookie = NULL;
+ if (!av_strncasecmp("path=", param, 5)) {
+ cpath = av_strdup(&param[5]);
+ } else if (!av_strncasecmp("domain=", param, 7)) {
+ cdomain = av_strdup(&param[7]);
+ } else if (!av_strncasecmp("secure", param, 6) ||
+ !av_strncasecmp("comment", param, 7) ||
+ !av_strncasecmp("max-age", param, 7) ||
+ !av_strncasecmp("version", param, 7)) {
+ // ignore Comment, Max-Age, Secure and Version
+ } else {
+ cvalue = av_strdup(param);
+ }
+ }
+
+ // ensure all of the necessary values are valid
+ if (!cdomain && !cpath && !cvalue) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Invalid cookie found, no value, path or domain specified\n");
+ goto done_cookie;
+ }
+
+ // check if the request path matches the cookie path
+ if (cpath && av_strncasecmp(path, cpath, strlen(cpath)))
+ {
+ goto done_cookie;
+ }
+
+ // the domain should be at least the size of our cookie domain
+ int cdomain_len;
+ if(!cdomain)
+ {
+ cdomain_len = 0;
+ }
+ else
+ {
+ cdomain_len = strlen(cdomain);
+ }
+ domain_offset = strlen(domain) - cdomain_len;
+ if (domain_offset < 0)
+ goto done_cookie;
+
+ // match the cookie domain
+ if (cdomain && av_strcasecmp(&domain[domain_offset], cdomain))
+ goto done_cookie;
+
+ // cookie parameters match, so copy the value
+ if (!*cookies) {
+ if (!(*cookies = av_strdup(cvalue))) {
+ ret = AVERROR(ENOMEM);
+ goto done_cookie;
+ }
+ } else {
+ char *tmp = *cookies;
+ size_t str_size = strlen(cvalue) + strlen(*cookies) + 3;
+ if (!(*cookies = av_malloc(str_size))) {
+ ret = AVERROR(ENOMEM);
+ goto done_cookie;
+ }
+ snprintf(*cookies, str_size, "%s; %s", tmp, cvalue);
+ av_free(tmp);
+ }
+
+ done_cookie:
+ av_free(cdomain);
+ av_free(cpath);
+ av_free(cvalue);
+ if (ret < 0) {
+ if (*cookies) av_freep(cookies);
+ av_free(cset_cookies);
+ return ret;
+ }
+ }
+
+ av_free(cset_cookies);
+
+ return 0;
+}
+
+static int parse_location(HTTPContext *s, const char *p)
+{
+ char redirected_location[MAX_URL_SIZE], *new_loc;
+ ff_make_absolute_url(redirected_location, sizeof(redirected_location),s->location, p);
+ new_loc = av_strdup(redirected_location);
+
+ if (!new_loc)
+ return AVERROR(ENOMEM);
+// av_free(s->location);
+// s->location = new_loc;
+ av_strlcpy(s->location, new_loc, sizeof(s->location));
+// av_log(NULL,AV_LOG_ERROR,"parse_location:new:%s",s->location);
+ return 0;
+}
+
+
static int process_line(URLContext *h, char *line, int line_count,
int *new_location)
{
HTTPContext *s = h->priv_data;
char *tag, *p, *end;
-
+ int ret;
/* end of header */
if (line[0] == '\0') {
s->end_header = 1;
@@ -300,7 +681,7 @@ static int process_line(URLContext *h, char *line, int line_count,
p++;
s->http_code = strtol(p, &end, 10);
- av_dlog(NULL, "http_code=%d\n", s->http_code);
+ // av_log(NULL,AV_LOG_DEBUG,"http_code=%d\n", s->http_code);
/* error codes are 4xx and 5xx, but regard 401 as a success, so we
* don't abort until all headers have been parsed. */
@@ -308,7 +689,7 @@ static int process_line(URLContext *h, char *line, int line_count,
|| s->auth_state.auth_type != HTTP_AUTH_NONE) &&
(s->http_code != 407 || s->proxy_auth_state.auth_type != HTTP_AUTH_NONE)) {
end += strspn(end, SPACE_CHARS);
- av_log(h, AV_LOG_WARNING, "HTTP error %d %s\n",
+ av_log(h, AV_LOG_ERROR, "HTTP error %d %s\n",
s->http_code, end);
return -1;
}
@@ -324,7 +705,10 @@ static int process_line(URLContext *h, char *line, int line_count,
while (isspace(*p))
p++;
if (!av_strcasecmp(tag, "Location")) {
- av_strlcpy(s->location, p, sizeof(s->location));
+// av_strlcpy(s->location, p, sizeof(s->location));
+
+ if ((ret = parse_location(s, p)) < 0)
+ return ret;
*new_location = 1;
} else if (!av_strcasecmp (tag, "Content-Length") && s->filesize == -1) {
s->filesize = strtoll(p, NULL, 10);
@@ -355,7 +739,37 @@ static int process_line(URLContext *h, char *line, int line_count,
s->willclose = 1;
} else if (!av_strcasecmp (tag, "Server") && !av_strcasecmp (p, "AkamaiGHost")) {
s->is_akamai = 1;
- }
+ }else if (!av_strcasecmp (tag, "Set-Cookie") && !s->cookies) {
+ #if HTTP_DEBUG
+ av_log(NULL, AV_LOG_DEBUG, "Hery, Set-Cookie");
+ #endif
+ if (!s->cookies) {
+ #if HTTP_DEBUG
+ av_log(NULL, AV_LOG_DEBUG, "Hery, Set-Cookie, p one= %s", p);
+ #endif
+ if (!(s->cookies = av_strdup(p)))
+ return AVERROR(ENOMEM);
+ #if HTTP_DEBUG
+ av_log(NULL, AV_LOG_DEBUG, "Hery, Set-Cookie, s->cookies= %s", s->cookies);
+ #endif
+ h->cookies = s->cookies;
+ } else {
+ /*
+ char *tmp = s->cookies;
+ size_t str_size = strlen(tmp) + strlen(p) + 2;
+ if (!(s->cookies = av_malloc(str_size))) {
+ s->cookies = tmp;
+ return AVERROR(ENOMEM);
+ }
+ snprintf(s->cookies, str_size, "%s\n%s", tmp, p);
+ av_free(tmp);
+ }
+ */
+ }
+ } else if (!av_strcasecmp(tag, "Content-Encoding")) {
+ if ((ret = parse_content_encoding(h, p)) < 0)
+ return ret;
+ }
}
return 1;
}
@@ -372,16 +786,19 @@ static int http_read_header(URLContext *h, int *new_location)
{
HTTPContext *s = h->priv_data;
char line[MAX_URL_SIZE];
- int err = 0;
+ char res_header[MAX_URL_SIZE]={0};
+ int err = 0;
s->chunksize = -1;
-
+ memset(h->mResponseHeader, 0, MAX_URL_SIZE);
for (;;) {
if ((err = http_get_line(s, line, sizeof(line))) < 0)
return err;
-
- av_dlog(NULL, "header='%s'\n", line);
-
+#if HTTP_DEBUG
+ av_log(NULL,AV_LOG_DEBUG,"header='%s'\n", line);
+#endif
+ snprintf(h->mResponseHeader+strlen(h->mResponseHeader),
+ MAX_URL_SIZE-strlen(h->mResponseHeader), "%s\r\n", line);
err = process_line(h, line, s->line_count, new_location);
if (err < 0)
return err;
@@ -405,7 +822,10 @@ static int http_connect(URLContext *h, const char *path, const char *local_path,
int len = 0;
const char *method;
-
+#if HTTP_DEBUG
+ av_log(h, AV_LOG_DEBUG, "http_connect:path = %s \n,local_path = %s \n,hoststr = %s \n,auth %s \n",path,local_path,hoststr,auth);
+#endif
+ h->endFlag = 0;
/* send http header */
post = h->flags & AVIO_FLAG_WRITE;
@@ -423,20 +843,28 @@ static int http_connect(URLContext *h, const char *path, const char *local_path,
local_path, method);
/* set default headers if needed */
- if (!has_header(s->headers, "\r\nUser-Agent: "))
+ if (!has_header(s->headers, "\r\nUser-Agent: ")){
+ //av_log(h, AV_LOG_DEBUG, "user_agent set \n");
+
+ // CMCC anhui user-agent:Ysten/1.0.0 (Linux; U; Android 4.2.2; EC6106 Build/HuaWei)
+ // o£??: Mozilla/4.0 (compatible; MS IE 6.0; (ziva))
+ // ??1?: AppleCoreMedia/1.0.0.9A405 (iPad; U; CPU OS 5_0_1 like Mac OS X; zh_cn)
len += av_strlcatf(headers + len, sizeof(headers) - len,
"User-Agent: %s\r\n",
- s->user_agent ? s->user_agent : LIBAVFORMAT_IDENT);
+ s->user_agent ? s->user_agent :"Mozilla/4.0 (compatible; MS IE 6.0; (ziva))");
+ }
+ //if some url can't open ,try to shiled this
+ #if 1
if (!has_header(s->headers, "\r\nAccept: "))
len += av_strlcpy(headers + len, "Accept: */*\r\n",
sizeof(headers) - len);
+ #endif
// Note: we send this on purpose even when s->off is 0 when we're probing,
// since it allows us to detect more reliably if a (non-conforming)
// server supports seeking by analysing the reply headers.
- if (!has_header(s->headers, "\r\nRange: ") && !post && (s->off > 0 || s->seekable == -1))
+ if (!has_header(s->headers, "\r\nRange: ") && !post && (s->off > 0 || s->seekable == -1 ||(s->off==0&&s->mZeroRange==1)))
len += av_strlcatf(headers + len, sizeof(headers) - len,
"Range: bytes=%"PRId64"-\r\n", s->off);
-
if (!has_header(s->headers, "\r\nConnection: ")) {
if (s->multiple_requests) {
len += av_strlcpy(headers + len, "Connection: keep-alive\r\n",
@@ -456,6 +884,14 @@ static int http_connect(URLContext *h, const char *path, const char *local_path,
if (!has_header(s->headers, "\r\nContent-Type: ") && s->content_type)
len += av_strlcatf(headers + len, sizeof(headers) - len,
"Content-Type: %s\r\n", s->content_type);
+ if (!has_header(s->headers, "\r\nCookie: ") && s->cookies) {
+ char *cookies = NULL;
+ if(!get_cookies(s->cookies, &cookies, path, hoststr)) {
+ len += av_strlcatf(headers + len, sizeof(headers) - len,
+ "Cookie: %s\r\n", cookies);
+ av_free(cookies);
+ }
+ }
/* now add in custom headers */
if (s->headers)
@@ -477,8 +913,20 @@ static int http_connect(URLContext *h, const char *path, const char *local_path,
av_freep(&authstr);
av_freep(&proxyauthstr);
+
+#if HTTP_DEBUG
+ av_log(h,AV_LOG_DEBUG,"s->buffer = %s",s->buffer);
+ av_log(h, AV_LOG_DEBUG, "ffurl_write in");
+#endif
if ((err = ffurl_write(s->hd, s->buffer, strlen(s->buffer))) < 0)
+ {
+ av_log(NULL,AV_LOG_DEBUG,"http_connect:ffurl_write failed");
return err;
+ }
+
+#if HTTP_DEBUG
+ av_log(h, AV_LOG_DEBUG, "ffurl_write out");
+#endif
if (s->post_data)
if ((err = ffurl_write(s->hd, s->post_data, s->post_datalen)) < 0)
@@ -502,14 +950,72 @@ static int http_connect(URLContext *h, const char *path, const char *local_path,
}
/* wait for header */
+#if HTTP_DEBUG
+ av_log(h, AV_LOG_DEBUG, "http_read_header in");
+#endif
+
err = http_read_header(h, new_location);
- if (err < 0)
- return err;
+ if (err < 0){
+#if HTTP_DEBUG
+ av_log(h, AV_LOG_DEBUG, "http_read_header err %d",err);
+#endif
+ return err;
+ }
+ if(s->off < 0)
+ s->off = 0;
+#if HTTP_DEBUG
+ av_log(NULL,AV_LOG_DEBUG,"http_connect return off=%lld,s->off=%lld",off,s->off);
+#endif
return (off == s->off) ? 0 : -1;
}
-
+static int special_read(URLContext *h, uint8_t *buf, int size)
+{
+ HTTPContext *s = h->priv_data;
+ uint8_t old_buf[BUFFER_SIZE];
+ int old_buf_size = 0;
+ int64_t old_off = 0;
+ if(s->mHlsParse!=1){
+ old_off = s->off;
+ old_buf_size = s->buf_end - s->buf_ptr;
+ memcpy(old_buf, s->buf_ptr, old_buf_size);
+ s->mZeroRange = 0;
+ }else{//hls m3u8 retry from begin(offset 0)
+ s->mZeroRange = 1;
+ }
+ while(1)
+ {
+ if (ff_check_interrupt(&h->interrupt_callback))
+ {
+ av_log(NULL,AV_LOG_DEBUG,"special_read:ff_check_interrupt");
+ return AVERROR_EXIT;
+ }
+
+ if (s->hd)
+ ffurl_closep(&s->hd);
+ http_reset_params(h);
+ s->rw_timeout = 5000*1000;
+ s->off = old_off;
+ memcpy(s->buffer, old_buf, old_buf_size);
+ s->buf_ptr = s->buffer;
+ s->buf_end = s->buffer + old_buf_size;
+ if (http_open_cnx(h) < 0)
+ {
+ av_log(NULL,AV_LOG_DEBUG,"%s:http_open_cnx fail",__FUNCTION__);
+ }
+ else
+ {
+ av_log(NULL,AV_LOG_DEBUG,"%s:http_open again",__FUNCTION__);
+ break;
+ }
+ av_usleep(1000*1000);
+
+ }
+ s->mZeroRange = 0;
+ av_log(NULL,AV_LOG_DEBUG,"%s:read again",__FUNCTION__);
+ return http_read(h,buf,size);
+}
static int http_buf_read(URLContext *h, uint8_t *buf, int size)
{
HTTPContext *s = h->priv_data;
@@ -522,8 +1028,13 @@ static int http_buf_read(URLContext *h, uint8_t *buf, int size)
memcpy(buf, s->buf_ptr, len);
s->buf_ptr += len;
} else {
- if (!s->willclose && s->filesize >= 0 && s->off >= s->filesize)
+ if (/*!s->willclose && */s->filesize >= 0 && s->off >= s->filesize)
+ {
+#if HTTP_DEBUG
+ av_log(NULL,AV_LOG_DEBUG,"http_buf_read:off=%lld,size=%lld",s->off,s->filesize);
+#endif
return AVERROR_EOF;
+ }
len = ffurl_read(s->hd, buf, size);
}
if (len > 0) {
@@ -531,6 +1042,34 @@ static int http_buf_read(URLContext *h, uint8_t *buf, int size)
if (s->chunksize > 0)
s->chunksize -= len;
}
+
+
+ if(len <0 && s->mHlsConductor <= 0)
+ {
+ av_log(NULL,AV_LOG_DEBUG,"%s:len=%d",__FUNCTION__,len);
+ len = special_read(h,buf,size);
+ }
+// av_log(NULL,AV_LOG_DEBUG,"%s:len=%d,%d",__FUNCTION__,len,s->mFlvConductor);
+ if(s->mFlvConductor > 0 || s->mmsh > 0)
+ {
+ if(len <=0)
+ av_log(NULL,AV_LOG_DEBUG,"%s:flv or mmsh:len=%d",__FUNCTION__,len);
+ if(len == -104 || len == -110 || (len == 0 && s->off < s->filesize)) //add off with filesize for judaging end of file
+ {
+ if (s->hd)
+ ffurl_closep(&s->hd);
+ http_reset_params(h);
+ // s->off = 0;
+ if (http_open_cnx(h) < 0)
+ {
+ av_log(NULL,AV_LOG_DEBUG,"%s:http_open_cnx fail",__FUNCTION__);
+ return len;
+ }
+ // s->off = tmpoff;
+ av_log(NULL,AV_LOG_DEBUG,"%s:read again",__FUNCTION__);
+ return http_buf_read(h,buf,size);
+ }
+ }
return len;
}
@@ -541,7 +1080,22 @@ static int http_read(URLContext *h, uint8_t *buf, int size)
if (!s->hd)
return AVERROR_EOF;
+ if(s->mHlsConductor > 0) // ht modified for hls timeout 500ms ; other is 60 s
+ {
+ s->hd->rw_timeout = 5000*1000;
+ }
+ else if(s->mFlvConductor > 0)
+ {
+ s->hd->rw_timeout = 60*1000*1000;
+ }
+ else
+ {
+ s->hd->rw_timeout = 5000*1000;
+ }
+ if(h->endFlag){
+ return AVERROR_EOF;
+ }
if (s->end_chunked_post && !s->end_header) {
err = http_read_header(h, &new_location);
if (err < 0)
@@ -551,7 +1105,6 @@ static int http_read(URLContext *h, uint8_t *buf, int size)
if (s->chunksize >= 0) {
if (!s->chunksize) {
char line[32];
-
for(;;) {
do {
if ((err = http_get_line(s, line, sizeof(line))) < 0)
@@ -559,16 +1112,22 @@ static int http_read(URLContext *h, uint8_t *buf, int size)
} while (!*line); /* skip CR LF from last chunk */
s->chunksize = strtoll(line, NULL, 16);
-
- av_dlog(NULL, "Chunked encoding data size: %"PRId64"'\n", s->chunksize);
-
- if (!s->chunksize)
+#if HTTP_DEBUG
+ av_log(NULL, AV_LOG_DEBUG, "Chunked encoding data size: %"PRId64"'\n", s->chunksize);
+#endif
+ if (!s->chunksize){
+ h->endFlag = 1;
return 0;
+ }
break;
}
}
size = FFMIN(size, s->chunksize);
}
+#if CONFIG_ZLIB
+ if (s->compressed)
+ return http_buf_read_compressed(h, buf, size);
+#endif
return http_buf_read(h, buf, size);
}
@@ -619,14 +1178,29 @@ static int http_close(URLContext *h)
{
int ret = 0;
HTTPContext *s = h->priv_data;
+#if CONFIG_ZLIB
+ inflateEnd(&s->inflate_stream);
+ av_freep(&s->inflate_buffer);
+#endif
if (!s->end_chunked_post) {
/* Close the write direction by sending the end of chunked encoding. */
ret = http_shutdown(h, h->flags);
}
- if (s->hd)
+ if(s->cookies != NULL){
+ av_free(s->cookies);
+ s->cookies = NULL;
+ }
+
+ if(http_keep_conn(h, s)){
+ return ret;
+ }
+
+ if (s->hd){
ffurl_closep(&s->hd);
+ http_reset_params(h);
+ }
return ret;
}
@@ -635,6 +1209,7 @@ static int64_t http_seek(URLContext *h, int64_t off, int whence)
HTTPContext *s = h->priv_data;
URLContext *old_hd = s->hd;
int64_t old_off = s->off;
+ int64_t old_filesize = s->filesize;
uint8_t old_buf[BUFFER_SIZE];
int old_buf_size;
@@ -654,12 +1229,15 @@ static int64_t http_seek(URLContext *h, int64_t off, int whence)
s->off = off;
/* if it fails, continue on old connection */
+ s->rw_timeout = 3*1000*1000;
if (http_open_cnx(h) < 0) {
+ av_log(NULL,AV_LOG_DEBUG,"http_seek:http_open_cnx failed");
memcpy(s->buffer, old_buf, old_buf_size);
s->buf_ptr = s->buffer;
s->buf_end = s->buffer + old_buf_size;
s->hd = old_hd;
s->off = old_off;
+ s->filesize = old_filesize;// for fix asf seek
return -1;
}
ffurl_close(old_hd);
@@ -708,8 +1286,10 @@ URLProtocol ff_https_protocol = {
static int http_proxy_close(URLContext *h)
{
HTTPContext *s = h->priv_data;
- if (s->hd)
+ if (s->hd){
ffurl_closep(&s->hd);
+ http_reset_params(h);
+ }
return 0;
}
@@ -791,6 +1371,7 @@ redo:
(cur_auth_type == HTTP_AUTH_NONE || s->proxy_auth_state.stale) &&
s->proxy_auth_state.auth_type != HTTP_AUTH_NONE && attempts < 2) {
ffurl_closep(&s->hd);
+ http_reset_params(h);
goto redo;
}
diff --git a/libavformat/id3v1.c b/libavformat/id3v1.c
index 2d1e806..29601ab 100644..100755
--- a/libavformat/id3v1.c
+++ b/libavformat/id3v1.c
@@ -174,11 +174,53 @@ const char * const ff_id3v1_genre_str[ID3v1_GENRE_MAX + 1] = {
[147] = "SynthPop",
};
+
+
+
+static void convertISO8859ToString8(
+ uint8_t *data, size_t size,
+ char *s) {
+
+ size_t utf8len = 0;
+ for (size_t i = 0; i < size; ++i) {
+ if (data[i] == '\0') {
+ size = i;
+ break;
+ } else if (data[i] < 0x80) {
+ ++utf8len;
+ } else {
+ utf8len += 2;
+ }
+ }
+ if (utf8len == size) {
+
+ // s->setTo((const char *)data, size);
+ return;
+ }
+ char *ptr1 = s;
+ for (size_t i = 0; i < size; ++i) {
+ if (data[i] == '\0') {
+ break;
+ } else if (data[i] < 0x80) {
+ *ptr1++ = data[i];
+ } else if (data[i] < 0xc0) {
+ *ptr1++ = 0xc2;
+ *ptr1++ = data[i];
+ } else {
+ *ptr1++ = 0xc3;
+ *ptr1++ = data[i] - 64;
+ }
+ }
+}
+
+
+
static void get_string(AVFormatContext *s, const char *key,
const uint8_t *buf, int buf_size)
{
int i, c;
char *q, str[512];
+ char str1[1024] = {0};
q = str;
for(i = 0; i < buf_size; i++) {
@@ -191,8 +233,11 @@ static void get_string(AVFormatContext *s, const char *key,
}
*q = '\0';
- if (*str)
- av_dict_set(&s->metadata, key, str, 0);
+ if (*str){
+ convertISO8859ToString8(str, strlen(str),str1);
+ //av_dict_set(&s->metadata, key, str, 0);
+ av_dict_set(&s->metadata, key, str1, 0);
+ }
}
/**
diff --git a/libavformat/id3v2.c b/libavformat/id3v2.c
index 14aa9e0..97eb96c 100644..100755
--- a/libavformat/id3v2.c
+++ b/libavformat/id3v2.c
@@ -717,7 +717,8 @@ static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t
err = uncompress(buffer, &dlen, compressed_buffer, n);
if (err != Z_OK) {
av_log(s, AV_LOG_ERROR, "Failed to uncompress tag: %d\n", err);
- goto seek;
+ //goto seek;
+ goto error;
}
}
#endif
diff --git a/libavformat/isom.c b/libavformat/isom.c
index 3271056..602fe4f 100644..100755
--- a/libavformat/isom.c
+++ b/libavformat/isom.c
@@ -166,6 +166,8 @@ const AVCodecTag ff_codec_movvideo_tags[] = {
{ AV_CODEC_ID_H264, MKTAG('a', 'i', '1', '3') }, /* AVC-Intra 100M 1080p24/30/60 */
{ AV_CODEC_ID_H264, MKTAG('a', 'i', '1', '5') }, /* AVC-Intra 100M 1080i50 */
{ AV_CODEC_ID_H264, MKTAG('a', 'i', '1', '6') }, /* AVC-Intra 100M 1080i60 */
+ { AV_CODEC_ID_HEVC, MKTAG('h', 'v', 'c', '1') }, /* hevc add by csy */
+ { AV_CODEC_ID_HEVC, MKTAG('h', 'e', 'v', '1') }, /* hevc add by csy */
{ AV_CODEC_ID_MPEG1VIDEO, MKTAG('m', '1', 'v', '1') }, /* Apple MPEG-1 Camcorder */
{ AV_CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', 'e', 'g') }, /* MPEG */
diff --git a/libavformat/matroska.c b/libavformat/matroska.c
index 64d0a45..d9ec88e 100644..100755
--- a/libavformat/matroska.c
+++ b/libavformat/matroska.c
@@ -72,6 +72,7 @@ const CodecTags ff_mkv_codec_tags[]={
{"V_MPEG4/ISO/AP" , AV_CODEC_ID_MPEG4},
{"V_MPEG4/ISO/SP" , AV_CODEC_ID_MPEG4},
{"V_MPEG4/ISO/AVC" , AV_CODEC_ID_H264},
+ {"V_MPEGH/ISO/HEVC" , AV_CODEC_ID_HEVC},
{"V_MPEG4/MS/V3" , AV_CODEC_ID_MSMPEG4V3},
{"V_PRORES" , AV_CODEC_ID_PRORES},
{"V_REAL/RV10" , AV_CODEC_ID_RV10},
@@ -82,6 +83,7 @@ const CodecTags ff_mkv_codec_tags[]={
{"V_THEORA" , AV_CODEC_ID_THEORA},
{"V_UNCOMPRESSED" , AV_CODEC_ID_RAWVIDEO},
{"V_VP8" , AV_CODEC_ID_VP8},
+ {"V_VP9" , AV_CODEC_ID_VP9},
{"" , AV_CODEC_ID_NONE}
};
@@ -111,7 +113,7 @@ const char * const ff_matroska_video_stereo_mode[MATROSKA_VIDEO_STEREO_MODE_COUN
"bottom_top",
"top_bottom",
"checkerboard_rl",
- "checkerboard_lr"
+ "checkerboard_lr",
"row_interleaved_rl",
"row_interleaved_lr",
"col_interleaved_rl",
diff --git a/libavformat/matroska.h b/libavformat/matroska.h
index 8411633..15dcfad 100644..100755
--- a/libavformat/matroska.h
+++ b/libavformat/matroska.h
@@ -91,6 +91,8 @@
#define MATROSKA_ID_CODECINFOURL 0x3B4040
#define MATROSKA_ID_CODECDOWNLOADURL 0x26B240
#define MATROSKA_ID_CODECDECODEALL 0xAA
+#define MATROSKA_ID_CODECDELAY 0x56AA
+#define MATROSKA_ID_SEEKPREROLL 0x56BB
#define MATROSKA_ID_TRACKNAME 0x536E
#define MATROSKA_ID_TRACKLANGUAGE 0x22B59C
#define MATROSKA_ID_TRACKFLAGENABLED 0xB9
@@ -118,6 +120,7 @@
#define MATROSKA_ID_VIDEODISPLAYUNIT 0x54B2
#define MATROSKA_ID_VIDEOFLAGINTERLACED 0x9A
#define MATROSKA_ID_VIDEOSTEREOMODE 0x53B8
+#define MATROSKA_ID_VIDEOALPHAMODE 0x53C0
#define MATROSKA_ID_VIDEOASPECTRATIO 0x54B3
#define MATROSKA_ID_VIDEOCOLORSPACE 0x2EB524
@@ -136,6 +139,15 @@
#define MATROSKA_ID_ENCODINGCOMPALGO 0x4254
#define MATROSKA_ID_ENCODINGCOMPSETTINGS 0x4255
+#define MATROSKA_ID_ENCODINGENCRYPTION 0x5035
+#define MATROSKA_ID_ENCODINGENCAESSETTINGS 0x47E7
+#define MATROSKA_ID_ENCODINGENCALGO 0x47E1
+#define MATROSKA_ID_ENCODINGENCKEYID 0x47E2
+#define MATROSKA_ID_ENCODINGSIGALGO 0x47E5
+#define MATROSKA_ID_ENCODINGSIGHASHALGO 0x47E6
+#define MATROSKA_ID_ENCODINGSIGKEYID 0x47E4
+#define MATROSKA_ID_ENCODINGSIGNATURE 0x47E3
+
/* ID in the cues master */
#define MATROSKA_ID_POINTENTRY 0xBB
@@ -146,6 +158,8 @@
/* IDs in the cuetrackposition master */
#define MATROSKA_ID_CUETRACK 0xF7
#define MATROSKA_ID_CUECLUSTERPOSITION 0xF1
+#define MATROSKA_ID_CUERELATIVEPOSITION 0xF0
+#define MATROSKA_ID_CUEDURATION 0xB2
#define MATROSKA_ID_CUEBLOCKNUMBER 0x5378
/* IDs in the tags master */
@@ -175,12 +189,18 @@
#define MATROSKA_ID_CLUSTERPOSITION 0xA7
#define MATROSKA_ID_CLUSTERPREVSIZE 0xAB
#define MATROSKA_ID_BLOCKGROUP 0xA0
+#define MATROSKA_ID_BLOCKADDITIONS 0x75A1
+#define MATROSKA_ID_BLOCKMORE 0xA6
+#define MATROSKA_ID_BLOCKADDID 0xEE
+#define MATROSKA_ID_BLOCKADDITIONAL 0xA5
#define MATROSKA_ID_SIMPLEBLOCK 0xA3
/* IDs in the blockgroup master */
#define MATROSKA_ID_BLOCK 0xA1
#define MATROSKA_ID_BLOCKDURATION 0x9B
#define MATROSKA_ID_BLOCKREFERENCE 0xFB
+#define MATROSKA_ID_CODECSTATE 0xA4
+#define MATROSKA_ID_DISCARDPADDING 0x75A2
/* IDs in the attachments master */
#define MATROSKA_ID_ATTACHEDFILE 0x61A7
@@ -215,6 +235,7 @@ typedef enum {
MATROSKA_TRACK_TYPE_LOGO = 0x10,
MATROSKA_TRACK_TYPE_SUBTITLE = 0x11,
MATROSKA_TRACK_TYPE_CONTROL = 0x20,
+ MATROSKA_TRACK_TYPE_METADATA = 0x21,
} MatroskaTrackType;
typedef enum {
diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c
index ba53e34..0923290 100644..100755
--- a/libavformat/matroskadec.c
+++ b/libavformat/matroskadec.c
@@ -1445,6 +1445,7 @@ static void matroska_metadata_creation_time(AVDictionary **metadata, int64_t dat
static int matroska_read_header(AVFormatContext *s)
{
+ av_log(NULL, AV_LOG_ERROR, "matroska_read_header");
MatroskaDemuxContext *matroska = s->priv_data;
EbmlList *attachements_list = &matroska->attachments;
MatroskaAttachement *attachements;
@@ -1583,6 +1584,7 @@ static int matroska_read_header(AVFormatContext *s)
}
}
+ av_log(NULL, AV_LOG_ERROR, "track->codec_id = %s",track->codec_id);
for(j=0; ff_mkv_codec_tags[j].id != AV_CODEC_ID_NONE; j++){
if(!strncmp(ff_mkv_codec_tags[j].str, track->codec_id,
strlen(ff_mkv_codec_tags[j].str))){
@@ -1756,7 +1758,9 @@ static int matroska_read_header(AVFormatContext *s)
st->codec->height * track->video.display_width,
st->codec-> width * track->video.display_height,
255);
- st->need_parsing = AVSTREAM_PARSE_HEADERS;
+ if (st->codec->codec_id != AV_CODEC_ID_HEVC)
+ st->need_parsing = AVSTREAM_PARSE_HEADERS;
+
if (track->default_duration) {
av_reduce(&st->avg_frame_rate.num, &st->avg_frame_rate.den,
1000000000, track->default_duration, 30000);
@@ -2317,7 +2321,12 @@ static int matroska_parse_cluster_incremental(MatroskaDemuxContext *matroska)
}
}
- if (res < 0) matroska->done = 1;
+ /*
+ * 码流解析出错是设置matroska->done=1会导致ffmpeg报AVERROR_EOF
+ * AVERROR_EOF会导致ffmpeg退出播放,因此暂时先屏蔽对matroska->done=1的设置,
+ * 这样会继续播放,视频解码由于错误数据可能出现花屏,但比直接退出要好
+ */
+ // if (res < 0) matroska->done = 1;
return res;
}
@@ -2356,7 +2365,7 @@ static int matroska_read_packet(AVFormatContext *s, AVPacket *pkt)
while (matroska_deliver_packet(matroska, pkt)) {
int64_t pos = avio_tell(matroska->ctx->pb);
- if (matroska->done)
+ if (matroska->done == 1) // if (matroska->done)
return AVERROR_EOF;
if (matroska_parse_cluster(matroska) < 0)
matroska_resync(matroska, pos);
@@ -2372,6 +2381,8 @@ static int matroska_read_seek(AVFormatContext *s, int stream_index,
MatroskaTrack *tracks = matroska->tracks.elem;
AVStream *st = s->streams[stream_index];
int i, index, index_sub, index_min;
+ int64_t seekUs = av_gettime();
+ int64_t seek_timeout = 5000000; //5s
/* Parse the CUES now since we need the index data to seek. */
if (matroska->cues_parsing_deferred > 0) {
@@ -2391,6 +2402,11 @@ static int matroska_read_seek(AVFormatContext *s, int stream_index,
matroska_clear_queue(matroska);
if (matroska_parse_cluster(matroska) < 0)
break;
+
+ if (abs(av_gettime() -seekUs) >seek_timeout) {
+ av_log(NULL, AV_LOG_INFO, "matroska_read_seek timeout\n");
+ break;
+ }
}
}
diff --git a/libavformat/mmsh.c b/libavformat/mmsh.c
index 86a0575..e581b93 100644..100755
--- a/libavformat/mmsh.c
+++ b/libavformat/mmsh.c
@@ -245,7 +245,7 @@ static int mmsh_open_internal(URLContext *h, const char *uri, int flags, int tim
"Connection: Close\r\n",
host, port, mmsh->request_seq++);
av_opt_set(mms->mms_hd->priv_data, "headers", headers, 0);
-
+ av_opt_set(mms->mms_hd->priv_data, "mmsh", "1", 0);
err = ffurl_connect(mms->mms_hd, NULL);
if (err) {
goto fail;
@@ -293,7 +293,7 @@ static int mmsh_open_internal(URLContext *h, const char *uri, int flags, int tim
}
av_dlog(NULL, "out_buffer is %s", headers);
av_opt_set(mms->mms_hd->priv_data, "headers", headers, 0);
-
+ av_opt_set(mms->mms_hd->priv_data, "mmsh", "1", 0);
err = ffurl_connect(mms->mms_hd, NULL);
if (err) {
goto fail;
diff --git a/libavformat/mov.c b/libavformat/mov.c
index d7d7f21..4d9e6d3 100644..100755
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -1963,7 +1963,7 @@ static void mov_build_index(MOVContext *mov, AVStream *st)
int rap_group_present = sc->rap_group_count && sc->rap_group;
int key_off = (sc->keyframe_count && sc->keyframes[0] > 0) || (sc->stps_data && sc->stps_data[0] > 0);
- current_dts -= sc->dts_shift;
+ // current_dts -= sc->dts_shift; //modify by csy
if (!sc->sample_count || st->nb_index_entries)
return;
@@ -2738,6 +2738,7 @@ static const MOVParseTableEntry mov_default_parse_table[] = {
{ MKTAG('S','M','I',' '), mov_read_svq3 },
{ MKTAG('a','l','a','c'), mov_read_alac }, /* alac specific atom */
{ MKTAG('a','v','c','C'), mov_read_glbl },
+{ MKTAG('h','v','c','C'), mov_read_glbl },
{ MKTAG('p','a','s','p'), mov_read_pasp },
{ MKTAG('s','t','b','l'), mov_read_default },
{ MKTAG('s','t','c','o'), mov_read_stco },
@@ -2824,6 +2825,9 @@ static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom)
parse = mov_read_udta_string;
if (!parse) { /* skip leaf atoms data */
+ if (pb && (avio_size(pb) <=(avio_tell(pb) + a.size))) {
+ a.size = avio_size(pb) - avio_tell(pb);
+ }
avio_skip(pb, a.size);
} else {
int64_t start_pos = avio_tell(pb);
@@ -3233,11 +3237,39 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
mov->fc = s;
retry:
sample = mov_find_next_sample(s, &st);
+
+#if CONFIG_SEAMLESS_DEMUXER
+ if ((!sample) || (!s->nb_streams)) {
+ mov->found_mdat = 0;
+ if (!mov->next_root_atom) {
+ return AVERROR_EOF;
+ }
+
+ if (!s->nb_streams) {
+ avio_seek(s->pb, 0, SEEK_SET);
+ } else {
+ if (mov->next_root_atom >=avio_size(s->pb)) {
+ mov->next_root_atom = avio_size(s->pb) - 16;
+ }
+ avio_seek(s->pb, mov->next_root_atom, SEEK_SET);
+ }
+
+ mov->next_root_atom = 0;
+ if (mov_read_default(mov, s->pb, (MOVAtom){ AV_RL32("root"), INT64_MAX }) < 0 ||
+ url_feof(s->pb))
+ return AVERROR_EOF;
+ av_dlog(s, "read fragments, offset 0x%"PRIx64"\n", avio_tell(s->pb));
+ goto retry;
+ }
+#else
if (!sample) {
mov->found_mdat = 0;
- if (!mov->next_root_atom)
+ if (!mov->next_root_atom) {
return AVERROR_EOF;
+ }
+
avio_seek(s->pb, mov->next_root_atom, SEEK_SET);
+
mov->next_root_atom = 0;
if (mov_read_default(mov, s->pb, (MOVAtom){ AV_RL32("root"), INT64_MAX }) < 0 ||
url_feof(s->pb))
@@ -3245,6 +3277,7 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
av_dlog(s, "read fragments, offset 0x%"PRIx64"\n", avio_tell(s->pb));
goto retry;
}
+#endif
sc = st->priv_data;
/* must be done just before reading, to avoid infinite loop on sample */
sc->current_sample++;
@@ -3253,7 +3286,8 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
if (avio_seek(sc->pb, sample->pos, SEEK_SET) != sample->pos) {
av_log(mov->fc, AV_LOG_ERROR, "stream %d, offset 0x%"PRIx64": partial file\n",
sc->ffindex, sample->pos);
- return AVERROR_INVALIDDATA;
+ goto retry;
+// return AVERROR_INVALIDDATA;
}
ret = av_get_packet(sc->pb, pkt, sample->size);
if (ret < 0)
@@ -3281,10 +3315,25 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
#endif
}
+#if CONFIG_SEAMLESS_DEMUXER
+ /*
+ ** may be we are in Rock-chip Seamless play mode, so if last
+ ** segment has been closed, we need to retry one more time.
+ */
+ if (s->nb_streams ==0) {
+ goto retry;
+ } else {
+ pkt->stream_index = sc->ffindex;
+ pkt->dts = sample->timestamp;
+ }
+#else
pkt->stream_index = sc->ffindex;
pkt->dts = sample->timestamp;
+#endif
+
if (sc->ctts_data && sc->ctts_index < sc->ctts_count) {
- pkt->pts = pkt->dts + sc->dts_shift + sc->ctts_data[sc->ctts_index].duration;
+// pkt->pts = pkt->dts + sc->dts_shift + sc->ctts_data[sc->ctts_index].duration;
+ pkt->pts = pkt->dts + sc->ctts_data[sc->ctts_index].duration; //modify by csy
/* update ctts context */
sc->ctts_sample++;
if (sc->ctts_index < sc->ctts_count &&
diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c
index 5b04b63..b55f889 100644..100755
--- a/libavformat/mpegts.c
+++ b/libavformat/mpegts.c
@@ -35,7 +35,7 @@
#include "seek.h"
#include "mpeg.h"
#include "isom.h"
-
+#define FILE_DEBUG
/* maximum size in which we look for synchronisation if
synchronisation is lost */
#define MAX_RESYNC_SIZE 65536
@@ -127,6 +127,8 @@ struct MpegTSContext {
/** filters for various streams specified by PMT + for the PAT and PMT */
MpegTSFilter *pids[NB_PID_MAX];
+ FILE* fd;
+
};
static const AVOption options[] = {
@@ -408,7 +410,8 @@ static int analyze(const uint8_t *buf, int size, int packet_size, int *index){
memset(stat, 0, packet_size*sizeof(int));
for(x=i=0; i<size-3; i++){
- if(buf[i] == 0x47 && !(buf[i+1] & 0x80) && buf[i+3] != 0x47){
+// if(buf[i] == 0x47 && !(buf[i+1] & 0x80) && buf[i+3] != 0x47){
+ if(buf[i] == 0x47){
stat[x]++;
if(stat[x] > best_score){
best_score= stat[x];
@@ -541,12 +544,18 @@ static const StreamType ISO_types[] = {
{ 0x02, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_MPEG2VIDEO },
{ 0x03, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_MP3 },
{ 0x04, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_MP3 },
+ // { 0x06, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_EAC3 },
{ 0x0f, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AAC },
{ 0x10, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_MPEG4 },
/* Makito encoder sets stream type 0x11 for AAC,
* so auto-detect LOAS/LATM instead of hardcoding it. */
// { 0x11, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AAC_LATM }, /* LATM syntax */
{ 0x1b, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_H264 },
+ { 0x20, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_H264},
+ { 0x24, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_HEVC },
+ { 0x27, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_HEVC },
+ //{ 0x06, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_HEVC },
+ { 0x42, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_CAVS },
{ 0xd1, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_DIRAC },
{ 0xea, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_VC1 },
{ 0 },
@@ -563,6 +572,8 @@ static const StreamType HDMV_types[] = {
{ 0xa1, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_EAC3 }, /* E-AC3 Secondary Audio */
{ 0xa2, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_DTS }, /* DTS Express Secondary Audio */
{ 0x90, AVMEDIA_TYPE_SUBTITLE, AV_CODEC_ID_HDMV_PGS_SUBTITLE },
+ { 0x91, AVMEDIA_TYPE_SUBTITLE, AV_CODEC_ID_BLURAY_IG},
+ { 0x92, AVMEDIA_TYPE_SUBTITLE, AV_CODEC_ID_BLURAY_TEXT_SUBTITLE},
{ 0 },
};
@@ -580,6 +591,7 @@ static const StreamType REGD_types[] = {
{ MKTAG('D','T','S','1'), AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_DTS },
{ MKTAG('D','T','S','2'), AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_DTS },
{ MKTAG('D','T','S','3'), AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_DTS },
+ { MKTAG('H','E','V','C'), AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_HEVC },
{ MKTAG('V','C','-','1'), AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_VC1 },
{ 0 },
};
@@ -597,6 +609,11 @@ static const StreamType DESC_types[] = {
static void mpegts_find_stream_type(AVStream *st,
uint32_t stream_type, const StreamType *types)
{
+ if (avcodec_is_open(st->codec)) {
+ av_log(NULL, AV_LOG_DEBUG, "cannot set stream info, codec is open\n");
+ return;
+ }
+
for (; types->stream_type; types++) {
if (stream_type == types->stream_type) {
st->codec->codec_type = types->codec_type;
@@ -612,6 +629,12 @@ static int mpegts_set_stream_info(AVStream *st, PESContext *pes,
{
int old_codec_type= st->codec->codec_type;
int old_codec_id = st->codec->codec_id;
+
+ if (avcodec_is_open(st->codec)) {
+ av_log(pes->stream, AV_LOG_DEBUG, "cannot set stream info, codec is open\n");
+ return 0;
+ }
+
avpriv_set_pts_info(st, 33, 1, 90000);
st->priv_data = pes;
st->codec->codec_type = AVMEDIA_TYPE_DATA;
@@ -625,8 +648,14 @@ static int mpegts_set_stream_info(AVStream *st, PESContext *pes,
st->index, pes->stream_type, pes->pid, (char*)&prog_reg_desc);
st->codec->codec_tag = pes->stream_type;
-
+ av_log(NULL,AV_LOG_ERROR,"%s:pet->stream_type=%d",__FUNCTION__,pes->stream_type);
mpegts_find_stream_type(st, pes->stream_type, ISO_types);
+ if(pes->stream->mTaoBaoHevc == 1 && pes->stream_type == 6)
+ {
+ av_log(NULL, AV_LOG_ERROR, "pes->stream_type = %d",pes->stream_type);
+ st->codec->codec_id = 171;
+ st->codec->codec_type = 0;
+ }
if ((prog_reg_desc == AV_RL32("HDMV") ||
prog_reg_desc == AV_RL32("HDPR")) &&
st->codec->codec_id == AV_CODEC_ID_NONE) {
@@ -662,7 +691,7 @@ static int mpegts_set_stream_info(AVStream *st, PESContext *pes,
st->codec->codec_id = old_codec_id;
st->codec->codec_type= old_codec_type;
}
-
+ st->tsstreampid = pes->pid;/* $ add by xhr $ 20130707 $ for notify ts stream track PID $ Bluray Program $ */
return 0;
}
@@ -909,12 +938,14 @@ static int mpegts_push_data(MpegTSFilter *filter,
pes->dts = AV_NOPTS_VALUE;
if ((flags & 0xc0) == 0x80) {
pes->dts = pes->pts = ff_parse_pes_pts(r);
+// av_log(NULL,AV_LOG_ERROR,"%s:%d:pts=%lld",__FUNCTION__,__LINE__,pes->pts);
r += 5;
} else if ((flags & 0xc0) == 0xc0) {
pes->pts = ff_parse_pes_pts(r);
r += 5;
pes->dts = ff_parse_pes_pts(r);
r += 5;
+// av_log(NULL,AV_LOG_ERROR,"%s:%d:pts=%lld",__FUNCTION__,__LINE__,pes->pts);
}
pes->extended_stream_id = -1;
if (flags & 0x01) { /* PES extension */
@@ -1713,6 +1744,26 @@ static int handle_packet(MpegTSContext *ts, const uint8_t *packet)
/* continuity check (currently not used) */
cc = (packet[3] & 0xf);
+ int mDisErr = 0;
+ for(int i = 0; i < s->nb_streams; i++)
+ {
+ if(s->streams[i]->tsstreampid == pid)
+ {
+ if(s->streams[i]->cur_continuity_counter +1 == cc
+ || s->streams[i]->cur_continuity_counter - 15 == cc )
+ {
+ s->streams[i]->cur_continuity_counter = cc;
+ }
+ else
+ {
+ s->streams[i]->cur_continuity_counter = cc;
+ s->streams[i]->continuity_counter_totalnum++;
+ }
+ }
+ mDisErr += s->streams[i]->continuity_counter_totalnum;
+ }
+ if(mDisErr != s->mDiscontinuityNum)
+ s->mDiscontinuityNum = mDisErr;
expected_cc = has_payload ? (tss->last_cc + 1) & 0x0f : tss->last_cc;
cc_ok = pid == 0x1FFF // null packet PID
|| is_discontinuity
@@ -1869,6 +1920,17 @@ static int handle_packets(MpegTSContext *ts, int nb_packets)
ret = read_packet(s, packet, ts->raw_packet_size);
if (ret != 0)
break;
+#ifdef FILE_DEBUG
+
+ if(1 == s->ts_debug_flag)
+ {
+ if(ts->fd)
+ {
+ fwrite(packet,1,188,ts->fd);
+ fflush(ts->fd);
+ }
+ }
+#endif
ret = handle_packet(ts, packet);
if (ret != 0)
break;
@@ -1946,8 +2008,8 @@ static int mpegts_read_header(AVFormatContext *s)
uint8_t buf[8*1024]={0};
int len;
int64_t pos;
-
/* read the first 8192 bytes to get packet size */
+ av_log(NULL,AV_LOG_ERROR,"mpegts_read_header:ts_debug_flag=%d",s->ts_debug_flag);
pos = avio_tell(pb);
len = avio_read(pb, buf, sizeof(buf));
ts->raw_packet_size = get_packet_size(buf, len);
@@ -2029,6 +2091,21 @@ static int mpegts_read_header(AVFormatContext *s)
}
avio_seek(pb, pos, SEEK_SET);
+#ifdef FILE_DEBUG
+ if(1 == s->ts_debug_flag)
+ {
+
+ ts->fd = fopen("/data/test.ts","wr+");
+ if(ts->fd != NULL)
+ {
+ av_log(NULL,AV_LOG_ERROR,"%s:create file success",__FUNCTION__);
+ }
+ else
+ {
+ av_log(NULL,AV_LOG_ERROR,"%s:create file failed",__FUNCTION__);
+ }
+ }
+#endif
return 0;
fail:
return -1;
@@ -2114,12 +2191,21 @@ static int mpegts_read_close(AVFormatContext *s)
{
MpegTSContext *ts = s->priv_data;
int i;
-
clear_programs(ts);
for(i=0;i<NB_PID_MAX;i++)
if (ts->pids[i]) mpegts_close_filter(ts, ts->pids[i]);
-
+#ifdef FILE_DEBUG
+ if(1 == s->ts_debug_flag)
+ {
+ if(ts->fd)
+ {
+ fclose(ts->fd);
+ ts->fd = NULL;
+ av_log(NULL,AV_LOG_ERROR,"mpegts_read_close:fd close");
+ }
+ }
+#endif
return 0;
}
@@ -2200,6 +2286,22 @@ MpegTSContext *ff_mpegts_parse_open(AVFormatContext *s)
ts->auto_guess = 1;
mpegts_open_section_filter(ts, SDT_PID, sdt_cb, ts, 1);
mpegts_open_section_filter(ts, PAT_PID, pat_cb, ts, 1);
+ av_log(NULL,AV_LOG_ERROR,"ff_mpegts_parse_open:s->ts_debug_flag=%d",s->ts_debug_flag);
+#ifdef FILE_DEBUG
+ if(1 == s->ts_debug_flag)
+ {
+
+ ts->fd = fopen("/data/test.ts","wr+");
+ if(ts->fd != NULL)
+ {
+ av_log(NULL,AV_LOG_ERROR,"%s:create file success",__FUNCTION__);
+ }
+ else
+ {
+ av_log(NULL,AV_LOG_ERROR,"%s:create file failed",__FUNCTION__);
+ }
+ }
+#endif
return ts;
}
@@ -2221,6 +2323,18 @@ int ff_mpegts_parse_packet(MpegTSContext *ts, AVPacket *pkt,
buf++;
len--;
} else {
+#ifdef FILE_DEBUG
+
+ if(1 == ts->stream->ts_debug_flag)
+ {
+ if(ts->fd)
+ {
+// av_log(NULL,AV_LOG_ERROR,"ff_mpegts_parse_packet write");
+ fwrite(buf,1,188,ts->fd);
+ fflush(ts->fd);
+ }
+ }
+#endif
handle_packet(ts, buf);
buf += TS_PACKET_SIZE;
len -= TS_PACKET_SIZE;
@@ -2237,6 +2351,19 @@ void ff_mpegts_parse_close(MpegTSContext *ts)
for(i=0;i<NB_PID_MAX;i++)
av_free(ts->pids[i]);
+#ifdef FILE_DEBUG
+ av_log(NULL,AV_LOG_ERROR,"ff_mpegts_parse_close");
+
+ if(1 == ts->stream->ts_debug_flag)
+ {
+ if(ts->fd)
+ {
+ fclose(ts->fd);
+ ts->fd = NULL;
+ av_log(NULL,AV_LOG_ERROR,"ff_mpegts_parse_close:fd close");
+ }
+ }
+#endif
av_free(ts);
}
diff --git a/libavformat/mpegts.h b/libavformat/mpegts.h
index 98c4b93..4d702a2 100644..100755
--- a/libavformat/mpegts.h
+++ b/libavformat/mpegts.h
@@ -52,6 +52,8 @@
#define STREAM_TYPE_AUDIO_AAC_LATM 0x11
#define STREAM_TYPE_VIDEO_MPEG4 0x10
#define STREAM_TYPE_VIDEO_H264 0x1b
+#define STREAM_TYPE_VIDEO_HEVC 0x24 //Definition of 0x24 HEVC video MPEG TS stream type
+#define STREAM_TYPE_VIDEO_CAVS 0x42
#define STREAM_TYPE_VIDEO_VC1 0xea
#define STREAM_TYPE_VIDEO_DIRAC 0xd1
diff --git a/libavformat/network.c b/libavformat/network.c
index 6e924be..5e10560 100644..100755
--- a/libavformat/network.c
+++ b/libavformat/network.c
@@ -20,6 +20,7 @@
#include "libavutil/avutil.h"
#include "network.h"
+#include "url.h"
#include "libavcodec/internal.h"
#include "libavutil/mem.h"
#include "url.h"
@@ -28,8 +29,10 @@
#if HAVE_THREADS
#if HAVE_PTHREADS
#include <pthread.h>
+#elif HAVE_OS2THREADS
+#include "compat/os2threads.h"
#else
-#include "libavcodec/w32pthreads.h"
+#include "compat/w32pthreads.h"
#endif
#endif
@@ -39,6 +42,7 @@ static int openssl_init;
#if HAVE_THREADS
#include <openssl/crypto.h>
#include "libavutil/avutil.h"
+
pthread_mutex_t *openssl_mutexes;
static void openssl_lock(int mode, int type, const char *file, int line)
{
@@ -60,8 +64,6 @@ static unsigned long openssl_thread_id(void)
#if HAVE_THREADS && GNUTLS_VERSION_NUMBER <= 0x020b00
#include <gcrypt.h>
#include <errno.h>
-#undef malloc
-#undef free
GCRY_THREAD_OPTION_PTHREAD_IMPL;
#endif
#endif
@@ -147,6 +149,7 @@ int ff_network_wait_fd(int fd, int write)
struct pollfd p = { .fd = fd, .events = ev, .revents = 0 };
int ret;
ret = poll(&p, 1, 100);
+
return ret < 0 ? ff_neterrno() : p.revents & (ev | POLLERR | POLLHUP) ? 0 : AVERROR(EAGAIN);
}
@@ -156,12 +159,20 @@ int ff_network_wait_fd_timeout(int fd, int write, int64_t timeout, AVIOInterrupt
int64_t wait_start = 0;
while (1) {
+ if (ff_check_interrupt(int_cb))
+ return AVERROR_EXIT;
ret = ff_network_wait_fd(fd, write);
if (ret != AVERROR(EAGAIN))
return ret;
- if (ff_check_interrupt(int_cb))
- return AVERROR_EXIT;
- if (timeout) {
+ if (timeout > 0) {
+ /*
+ * 检测是否有新的seek到来,有新的seek到来则直接返回,不需等待超时
+ */
+ if(ff_check_operate(int_cb,OPERATE_SEEK,NULL,NULL))
+ {
+ av_log(NULL,AV_LOG_ERROR,"ff_network_wait_fd_timeout: new seek arrival,return immediately");
+ return AVERROR(EAGAIN);
+ }
if (!wait_start)
wait_start = av_gettime();
else if (av_gettime() - wait_start > timeout)
@@ -212,3 +223,147 @@ int ff_is_multicast_address(struct sockaddr *addr)
return 0;
}
+static int ff_poll_interrupt(struct pollfd *p, nfds_t nfds, int timeout,
+ AVIOInterruptCB *cb)
+{
+ int runs = timeout / POLLING_TIME;
+ int ret = 0;
+
+ do {
+ if (ff_check_interrupt(cb))
+ return AVERROR_EXIT;
+ ret = poll(p, nfds, POLLING_TIME);
+ if (ret != 0)
+ break;
+ } while (timeout <= 0 || runs-- > 0);
+
+ if (!ret)
+ return AVERROR(ETIMEDOUT);
+ if (ret < 0)
+ return AVERROR(errno);
+ return ret;
+}
+
+int ff_listen_bind(int fd, const struct sockaddr *addr,
+ socklen_t addrlen, int timeout, URLContext *h)
+{
+ int ret;
+ int reuse = 1;
+ struct pollfd lp = { fd, POLLIN, 0 };
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse))) {
+ av_log(NULL, AV_LOG_WARNING, "setsockopt(SO_REUSEADDR) failed\n");
+ }
+ ret = bind(fd, addr, addrlen);
+ if (ret)
+ return ff_neterrno();
+
+ ret = listen(fd, 1);
+ if (ret)
+ return ff_neterrno();
+
+ ret = ff_poll_interrupt(&lp, 1, timeout, &h->interrupt_callback);
+ if (ret < 0)
+ return ret;
+
+ ret = accept(fd, NULL, NULL);
+ if (ret < 0)
+ return ff_neterrno();
+
+ closesocket(fd);
+
+ ff_socket_nonblock(ret, 1);
+ return ret;
+}
+
+int ff_listen_connect(int fd, const struct sockaddr *addr,
+ socklen_t addrlen, int timeout, URLContext *h)
+{
+ struct pollfd p = {fd, POLLOUT, 0};
+ int ret;
+ socklen_t optlen;
+
+ ff_socket_nonblock(fd, 1);
+
+ while ((ret = connect(fd, addr, addrlen))) {
+ ret = ff_neterrno();
+ switch (ret) {
+ case AVERROR(EINTR):
+ if (ff_check_interrupt(&h->interrupt_callback))
+ return AVERROR_EXIT;
+ continue;
+ case AVERROR(EINPROGRESS):
+ case AVERROR(EAGAIN):
+ ret = ff_poll_interrupt(&p, 1, timeout, &h->interrupt_callback);
+ if (ret < 0)
+ return ret;
+ optlen = sizeof(ret);
+ if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen))
+ ret = AVUNERROR(ff_neterrno());
+ if (ret != 0) {
+ char errbuf[100];
+ ret = AVERROR(ret);
+ av_strerror(ret, errbuf, sizeof(errbuf));
+ av_log(h, AV_LOG_ERROR,
+ "Connection to %s failed: %s\n",
+ h->filename, errbuf);
+ }
+ default:
+ return ret;
+ }
+ }
+ return ret;
+}
+
+static int match_host_pattern(const char *pattern, const char *hostname)
+{
+ int len_p, len_h;
+ if (!strcmp(pattern, "*"))
+ return 1;
+ // Skip a possible *. at the start of the pattern
+ if (pattern[0] == '*')
+ pattern++;
+ if (pattern[0] == '.')
+ pattern++;
+ len_p = strlen(pattern);
+ len_h = strlen(hostname);
+ if (len_p > len_h)
+ return 0;
+ // Simply check if the end of hostname is equal to 'pattern'
+ if (!strcmp(pattern, &hostname[len_h - len_p])) {
+ if (len_h == len_p)
+ return 1; // Exact match
+ if (hostname[len_h - len_p - 1] == '.')
+ return 1; // The matched substring is a domain and not just a substring of a domain
+ }
+ return 0;
+}
+
+int ff_http_match_no_proxy(const char *no_proxy, const char *hostname)
+{
+ char *buf, *start;
+ int ret = 0;
+ if (!no_proxy)
+ return 0;
+ if (!hostname)
+ return 0;
+ buf = av_strdup(no_proxy);
+ if (!buf)
+ return 0;
+ start = buf;
+ while (start) {
+ char *sep, *next = NULL;
+ start += strspn(start, " ,");
+ sep = start + strcspn(start, " ,");
+ if (*sep) {
+ next = sep + 1;
+ *sep = '\0';
+ }
+ if (match_host_pattern(start, hostname)) {
+ ret = 1;
+ break;
+ }
+ start = next;
+ }
+ av_free(buf);
+ return ret;
+}
diff --git a/libavformat/network.h b/libavformat/network.h
index f8b4dee..d0a1e31 100644..100755
--- a/libavformat/network.h
+++ b/libavformat/network.h
@@ -28,6 +28,7 @@
#include "libavutil/error.h"
#include "os_support.h"
#include "avio.h"
+#include "url.h"
#if HAVE_UNISTD_H
#include <unistd.h>
@@ -222,4 +223,40 @@ const char *ff_gai_strerror(int ecode);
int ff_is_multicast_address(struct sockaddr *addr);
+#define POLLING_TIME 100 /// Time in milliseconds between interrupt check
+
+/**
+ * Bind to a file descriptor and poll for a connection.
+ *
+ * @param fd First argument of bind().
+ * @param addr Second argument of bind().
+ * @param addrlen Third argument of bind().
+ * @param timeout Polling timeout in milliseconds.
+ * @param h URLContext providing interrupt check
+ * callback and logging context.
+ * @return A non-blocking file descriptor on success
+ * or an AVERROR on failure.
+ */
+int ff_listen_bind(int fd, const struct sockaddr *addr,
+ socklen_t addrlen, int timeout,
+ URLContext *h);
+
+/**
+ * Connect to a file descriptor and poll for result.
+ *
+ * @param fd First argument of connect(),
+ * will be set as non-blocking.
+ * @param addr Second argument of connect().
+ * @param addrlen Third argument of connect().
+ * @param timeout Polling timeout in milliseconds.
+ * @param h URLContext providing interrupt check
+ * callback and logging context.
+ * @return 0 on success, AVERROR on failure.
+ */
+int ff_listen_connect(int fd, const struct sockaddr *addr,
+ socklen_t addrlen, int timeout,
+ URLContext *h);
+
+int ff_http_match_no_proxy(const char *no_proxy, const char *hostname);
+
#endif /* AVFORMAT_NETWORK_H */
diff --git a/libavformat/options.c b/libavformat/options.c
index 42307d1..00957b7 100644..100755
--- a/libavformat/options.c
+++ b/libavformat/options.c
@@ -99,6 +99,7 @@ static void avformat_get_context_defaults(AVFormatContext *s)
memset(s, 0, sizeof(AVFormatContext));
s->av_class = &av_format_context_class;
+ s->interrupt_callback.ioparams = NULL;//add by fxw for http persist connection
av_opt_set_defaults(s);
}
diff --git a/libavformat/options_table.h b/libavformat/options_table.h
index 778c740..68862c7 100644..100755
--- a/libavformat/options_table.h
+++ b/libavformat/options_table.h
@@ -35,7 +35,7 @@
static const AVOption options[]={
{"avioflags", NULL, OFFSET(avio_flags), AV_OPT_TYPE_FLAGS, {.i64 = DEFAULT }, INT_MIN, INT_MAX, D|E, "avioflags"},
{"direct", "reduce buffering", 0, AV_OPT_TYPE_CONST, {.i64 = AVIO_FLAG_DIRECT }, INT_MIN, INT_MAX, D|E, "avioflags"},
-{"probesize", "set probing size", OFFSET(probesize), AV_OPT_TYPE_INT, {.i64 = 5000000 }, 32, INT_MAX, D},
+{"probesize", "set probing size", OFFSET(probesize), AV_OPT_TYPE_INT, {.i64 = 10000000 }, 32, INT_MAX, D},
{"packetsize", "set packet size", OFFSET(packet_size), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, 0, INT_MAX, E},
{"fflags", NULL, OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = DEFAULT }, INT_MIN, INT_MAX, D|E, "fflags"},
{"ignidx", "ignore index", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_IGNIDX }, INT_MIN, INT_MAX, D, "fflags"},
@@ -48,7 +48,7 @@ static const AVOption options[]={
{"keepside", "dont merge side data", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_KEEP_SIDE_DATA }, INT_MIN, INT_MAX, D, "fflags"},
{"latm", "enable RTP MP4A-LATM payload", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_MP4A_LATM }, INT_MIN, INT_MAX, E, "fflags"},
{"nobuffer", "reduce the latency introduced by optional buffering", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_NOBUFFER }, 0, INT_MAX, D, "fflags"},
-{"analyzeduration", "how many microseconds are analyzed to estimate duration", OFFSET(max_analyze_duration), AV_OPT_TYPE_INT, {.i64 = 5*AV_TIME_BASE }, 0, INT_MAX, D},
+{"analyzeduration", "how many microseconds are analyzed to estimate duration", OFFSET(max_analyze_duration), AV_OPT_TYPE_INT, {.i64 = 3*AV_TIME_BASE }, 0, INT_MAX, D},
{"cryptokey", "decryption key", OFFSET(key), AV_OPT_TYPE_BINARY, {.dbl = 0}, 0, 0, D},
{"indexmem", "max memory used for timestamp index (per stream)", OFFSET(max_index_size), AV_OPT_TYPE_INT, {.i64 = 1<<20 }, 0, INT_MAX, D},
{"rtbufsize", "max memory used for buffering real-time frames", OFFSET(max_picture_buffer), AV_OPT_TYPE_INT, {.i64 = 3041280 }, 0, INT_MAX, D}, /* defaults to 1s of 15fps 352x288 YUYV422 video */
diff --git a/libavformat/riff.c b/libavformat/riff.c
index 6ca3f2d..535dea6 100644..100755
--- a/libavformat/riff.c
+++ b/libavformat/riff.c
@@ -321,6 +321,9 @@ const AVCodecTag ff_codec_bmp_tags[] = {
{ AV_CODEC_ID_CLLC, MKTAG('C', 'L', 'L', 'C') },
{ AV_CODEC_ID_MSS2, MKTAG('M', 'S', 'S', '2') },
{ AV_CODEC_ID_SVQ3, MKTAG('S', 'V', 'Q', '3') },
+
+ { AV_CODEC_ID_HEVC, MKTAG('h', 'v', 'c', '1') },
+ { AV_CODEC_ID_HEVC, MKTAG('h', 'e', 'v', '1') },
{ AV_CODEC_ID_NONE, 0 }
};
diff --git a/libavformat/rmdec.c b/libavformat/rmdec.c
index a2c8bfb..77f10cd 100644..100755
--- a/libavformat/rmdec.c
+++ b/libavformat/rmdec.c
@@ -19,6 +19,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include "libavutil/time.h"
#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
#include "libavutil/intreadwrite.h"
@@ -575,6 +576,7 @@ static int sync(AVFormatContext *s, int64_t *timestamp, int *flags, int *stream_
AVIOContext *pb = s->pb;
AVStream *st;
uint32_t state=0xFFFFFFFF;
+ int64_t inputTimeus = av_gettime();
while(!url_feof(pb)){
int len, num, i;
@@ -609,6 +611,11 @@ static int sync(AVFormatContext *s, int64_t *timestamp, int *flags, int *stream_
"DATA tag in middle of chunk, file may be broken.\n");
}
+ if (av_gettime() - inputTimeus >5000000) {
+ s->pb->eof_reached = 1;
+ return -1;
+ }
+
if(state > (unsigned)0xFFFF || state <= 12)
continue;
len=state - 12;
diff --git a/libavformat/rtmpproto.c b/libavformat/rtmpproto.c
index 1d00cbb..df9e085 100644..100755
--- a/libavformat/rtmpproto.c
+++ b/libavformat/rtmpproto.c
@@ -2107,6 +2107,7 @@ static int rtmp_open(URLContext *s, const char *uri, int flags)
ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL);
}
+ av_dict_set(&opts, "timeout", "20000000", 0);
if ((ret = ffurl_open(&rt->stream, buf, AVIO_FLAG_READ_WRITE,
&s->interrupt_callback, &opts)) < 0) {
av_log(s , AV_LOG_ERROR, "Cannot open connection %s\n", buf);
diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c
index 201938c..88b9bbd 100644..100755
--- a/libavformat/rtsp.c
+++ b/libavformat/rtsp.c
@@ -107,6 +107,55 @@ static const AVOption rtp_options[] = {
RTSP_REORDERING_OPTS(),
{ NULL },
};
+int ff_rtsp_getnameinfo(const struct sockaddr *sa, int salen,
+ char *host, int hostlen,
+ char *serv, int servlen, int flags)
+{
+ const struct sockaddr_in *sin = (const struct sockaddr_in *)sa;
+
+ if (sa->sa_family != AF_INET)
+ {
+ return EAI_FAMILY;
+ }
+ if (!host && !serv)
+ return EAI_NONAME;
+
+ if (host && hostlen > 0) {
+ struct hostent *ent = NULL;
+ uint32_t a;
+ if (!(flags & NI_NUMERICHOST))
+ {
+ ent = gethostbyaddr((const char *)&sin->sin_addr,
+ sizeof(sin->sin_addr), AF_INET);
+ }
+
+ if (ent) {
+ snprintf(host, hostlen, "%s", ent->h_name);
+ } else if (flags & NI_NAMERQD) {
+ return EAI_NONAME;
+ } else {
+ a = ntohl(sin->sin_addr.s_addr);
+ snprintf(host, hostlen, "%d.%d.%d.%d",
+ ((a >> 24) & 0xff), ((a >> 16) & 0xff),
+ ((a >> 8) & 0xff), (a & 0xff));
+ }
+ }
+
+ if (serv && servlen > 0) {
+ struct servent *ent = NULL;
+#if HAVE_GETSERVBYPORT
+ if (!(flags & NI_NUMERICSERV))
+ ent = getservbyport(sin->sin_port, flags & NI_DGRAM ? "udp" : "tcp");
+#endif
+
+ if (ent)
+ snprintf(serv, servlen, "%s", ent->s_name);
+ else
+ snprintf(serv, servlen, "%d", ntohs(sin->sin_port));
+ }
+
+ return 0;
+}
static void get_word_until_chars(char *buf, int buf_size,
const char *sep, const char **pp)
@@ -166,9 +215,11 @@ static void rtsp_parse_range_npt(const char *p, int64_t *start, int64_t *end)
static int get_sockaddr(const char *buf, struct sockaddr_storage *sock)
{
struct addrinfo hints = { 0 }, *ai = NULL;
- hints.ai_flags = AI_NUMERICHOST;
+// hints.ai_flags = AI_NUMERICHOST;
+ hints.ai_flags = 0;
if (getaddrinfo(buf, NULL, &hints, &ai))
return -1;
+ av_log(NULL,AV_LOG_ERROR,"get_sockaddr:ip=%s",inet_ntoa(((struct sockaddr_in *)(ai->ai_addr))->sin_addr));
memcpy(sock, ai->ai_addr, FFMIN(sizeof(*sock), ai->ai_addrlen));
freeaddrinfo(ai);
return 0;
@@ -180,6 +231,7 @@ static void init_rtp_handler(RTPDynamicProtocolHandler *handler,
{
if (!handler)
return;
+ if (codec)
codec->codec_id = handler->codec_id;
rtsp_st->dynamic_handler = handler;
if (handler->alloc) {
@@ -1254,7 +1306,9 @@ int ff_rtsp_make_setup_request(AVFormatContext *s, const char *host, int port,
}
if (rtx == rt->nb_rtsp_streams)
return -1; /* no RTX found */
- rtsp_st = rt->rtsp_streams[rtx];
+ //ht for wms In WMS mode rtx can't link server,filter rtx
+// rtsp_st = rt->rtsp_streams[rtx];
+ continue;
} else
rtsp_st = rt->rtsp_streams[i > rtx ? i : i - 1];
} else
@@ -1344,7 +1398,15 @@ int ff_rtsp_make_setup_request(AVFormatContext *s, const char *host, int port,
if (reply->status_code == 461 /* Unsupported protocol */ && i == 0) {
err = 1;
goto fail;
- } else if (reply->status_code != RTSP_STATUS_OK ||
+ }
+ else if(rt->server_type == RTSP_SERVER_WMS && reply->status_code == 461)
+ {
+ //ht for wms, In wms mode, if the link fails, try to use other transport-protocol
+ //for example: RTP/AVP;RTP/AVP/TCP and so on
+ err = 1;
+ goto fail;
+
+ }else if (reply->status_code != RTSP_STATUS_OK ||
reply->nb_transports != 1) {
err = AVERROR_INVALIDDATA;
goto fail;
@@ -1420,8 +1482,10 @@ int ff_rtsp_make_setup_request(AVFormatContext *s, const char *host, int port,
}
if (ttl > 0)
snprintf(optbuf, sizeof(optbuf), "?ttl=%d", ttl);
- getnameinfo((struct sockaddr*) &addr, sizeof(addr),
+ ff_rtsp_getnameinfo((struct sockaddr*) &addr, sizeof(addr),
namebuf, sizeof(namebuf), NULL, 0, NI_NUMERICHOST);
+// getnameinfo((struct sockaddr*) &addr, sizeof(addr),
+// namebuf, sizeof(namebuf), NULL, 0, NI_NUMERICHOST);
ff_url_join(url, sizeof(url), "rtp", NULL, namebuf,
port, "%s", optbuf);
if (ffurl_open(&rtsp_st->rtp_handle, url, AVIO_FLAG_READ_WRITE,
@@ -1598,7 +1662,8 @@ redirect:
}
} else {
/* open the tcp connection */
- ff_url_join(tcpname, sizeof(tcpname), "tcp", NULL, host, port, NULL);
+ ff_url_join(tcpname, sizeof(tcpname), "tcp", NULL, host, port,
+ "?timeout=%d",20*1000*1000);
if (ffurl_open(&rt->rtsp_hd, tcpname, AVIO_FLAG_READ_WRITE,
&s->interrupt_callback, NULL) < 0) {
err = AVERROR(EIO);
@@ -1610,8 +1675,10 @@ redirect:
tcp_fd = ffurl_get_file_handle(rt->rtsp_hd);
if (!getpeername(tcp_fd, (struct sockaddr*) &peer, &peer_len)) {
- getnameinfo((struct sockaddr*) &peer, peer_len, host, sizeof(host),
+ ff_rtsp_getnameinfo((struct sockaddr*) &peer, peer_len, host, sizeof(host),
NULL, 0, NI_NUMERICHOST);
+// getnameinfo((struct sockaddr*) &peer, peer_len, host, sizeof(host),
+// NULL, 0, NI_NUMERICHOST);
}
/* request options supported by the server; this also detects server
@@ -1747,6 +1814,8 @@ static int udp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st,
if (rtsp_st->rtp_handle) {
if (p[j].revents & POLLIN || p[j+1].revents & POLLIN) {
ret = ffurl_read(rtsp_st->rtp_handle, buf, buf_size);
+ if(ret < 0)
+ av_log(NULL,AV_LOG_DEBUG,"%s:ffurl_read:ret =%d",__FUNCTION__,ret);
if (ret > 0) {
*prtsp_st = rtsp_st;
return ret;
@@ -1778,9 +1847,13 @@ static int udp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st,
}
#endif
} else if (n == 0 && ++timeout_cnt >= MAX_TIMEOUTS) {
+ av_log(NULL,AV_LOG_DEBUG,"%s:ETIMEDOUT",__FUNCTION__);
return AVERROR(ETIMEDOUT);
} else if (n < 0 && errno != EINTR)
+ {
+ av_log(NULL,AV_LOG_DEBUG,"%s:errno =0x%x",__FUNCTION__,errno);
return AVERROR(errno);
+ }
}
}
@@ -1817,7 +1890,9 @@ int ff_rtsp_fetch_packet(AVFormatContext *s, AVPacket *pkt)
rt->cur_transport_priv = NULL;
}
+redo:
if (rt->transport == RTSP_TRANSPORT_RTP) {
+
int i;
int64_t first_queue_time = 0;
for (i = 0; i < rt->nb_rtsp_streams; i++) {
@@ -1832,12 +1907,15 @@ int ff_rtsp_fetch_packet(AVFormatContext *s, AVPacket *pkt)
first_queue_st = rt->rtsp_streams[i];
}
}
- if (first_queue_time)
+ if (first_queue_time){
wait_end = first_queue_time + s->max_delay;
+ } else {
+ wait_end = 0;
+ first_queue_st = NULL;
+ }
}
/* read next RTP packet */
- redo:
if (!rt->recvbuf) {
rt->recvbuf = av_malloc(RECVBUF_SIZE);
if (!rt->recvbuf)
@@ -1854,24 +1932,33 @@ int ff_rtsp_fetch_packet(AVFormatContext *s, AVPacket *pkt)
case RTSP_LOWER_TRANSPORT_UDP:
case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
len = udp_read_packet(s, &rtsp_st, rt->recvbuf, RECVBUF_SIZE, wait_end);
+
if (len > 0 && rtsp_st->transport_priv && rt->transport == RTSP_TRANSPORT_RTP)
ff_rtp_check_and_send_back_rr(rtsp_st->transport_priv, len);
break;
}
if (len == AVERROR(EAGAIN) && first_queue_st &&
rt->transport == RTSP_TRANSPORT_RTP) {
+ av_log(NULL,AV_LOG_DEBUG,"%s: line:%d",__FUNCTION__,__LINE__);
rtsp_st = first_queue_st;
ret = ff_rtp_parse_packet(rtsp_st->transport_priv, pkt, NULL, 0);
goto end;
}
if (len < 0)
+ {
+ av_log(NULL,AV_LOG_DEBUG,"%s:udp_read_packet:len=%d",__FUNCTION__,len);
return len;
+ }
if (len == 0)
+ {
+ av_log(NULL,AV_LOG_DEBUG,"%s:len == 0, return AVERROR_EOF",__FUNCTION__);
return AVERROR_EOF;
+ }
if (rt->transport == RTSP_TRANSPORT_RDT) {
ret = ff_rdt_parse_packet(rtsp_st->transport_priv, pkt, &rt->recvbuf, len);
} else if (rt->transport == RTSP_TRANSPORT_RTP) {
ret = ff_rtp_parse_packet(rtsp_st->transport_priv, pkt, &rt->recvbuf, len);
+// av_log(NULL,AV_LOG_DEBUG,"%s:ff_rtp_parse_packet , ret=%d",__FUNCTION__,ret);
if (ret < 0) {
/* Either bad packet, or a RTCP packet. Check if the
* first_rtcp_ntp_time field was initialized. */
@@ -1906,7 +1993,10 @@ int ff_rtsp_fetch_packet(AVFormatContext *s, AVPacket *pkt)
rtsp_st->stream_index, rt->nb_byes, rt->nb_rtsp_streams);
if (rt->nb_byes == rt->nb_rtsp_streams)
+ {
+ av_log(NULL,AV_LOG_DEBUG,"%s:ret=RTCP_BYE,AVERROR_EOF",__FUNCTION__);
return AVERROR_EOF;
+ }
}
}
} else if (rt->ts && CONFIG_RTPDEC) {
@@ -1988,8 +2078,11 @@ static int sdp_read_header(AVFormatContext *s)
char namebuf[50];
rtsp_st = rt->rtsp_streams[i];
- getnameinfo((struct sockaddr*) &rtsp_st->sdp_ip, sizeof(rtsp_st->sdp_ip),
- namebuf, sizeof(namebuf), NULL, 0, NI_NUMERICHOST);
+// getnameinfo((struct sockaddr*) &rtsp_st->sdp_ip, sizeof(rtsp_st->sdp_ip),
+// namebuf, sizeof(namebuf), NULL, 0, NI_NUMERICSERV);
+ ff_rtsp_getnameinfo((struct sockaddr*) &rtsp_st->sdp_ip, sizeof(rtsp_st->sdp_ip),
+ namebuf, sizeof(namebuf), NULL, 0, NI_NUMERICHOST);
+
ff_url_join(url, sizeof(url), "rtp", NULL,
namebuf, rtsp_st->sdp_port,
"?localport=%d&ttl=%d&connect=%d", rtsp_st->sdp_port,
diff --git a/libavformat/rtsp.h b/libavformat/rtsp.h
index 3a5ad71..c70703b 100644..100755
--- a/libavformat/rtsp.h
+++ b/libavformat/rtsp.h
@@ -586,6 +586,10 @@ int ff_rtsp_make_setup_request(AVFormatContext *s, const char *host, int port,
*/
void ff_rtsp_undo_setup(AVFormatContext *s);
+int ff_rtsp_getnameinfo(const struct sockaddr *sa, int salen,
+ char *host, int hostlen,
+ char *serv, int servlen, int flags);
+
/**
* Open RTSP transport context.
*/
diff --git a/libavformat/tcp.c b/libavformat/tcp.c
index 8b35fb1..cea14f3 100644..100755
--- a/libavformat/tcp.c
+++ b/libavformat/tcp.c
@@ -21,10 +21,12 @@
#include "avformat.h"
#include "libavutil/parseutils.h"
#include "libavutil/opt.h"
+#include "libavutil/time.h"
#include "internal.h"
#include "network.h"
#include "os_support.h"
#include "url.h"
+//#include <setjmp.h> //add by xhr
#if HAVE_POLL_H
#include <poll.h>
#endif
@@ -33,6 +35,7 @@ typedef struct TCPContext {
const AVClass *class;
int fd;
int listen;
+ int open_timeout;
int rw_timeout;
int listen_timeout;
} TCPContext;
@@ -42,7 +45,7 @@ typedef struct TCPContext {
#define E AV_OPT_FLAG_ENCODING_PARAM
static const AVOption options[] = {
{"listen", "listen on port instead of connecting", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, D|E },
-{"timeout", "timeout of socket i/o operations", OFFSET(rw_timeout), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, D|E },
+{"timeout", "timeout of socket i/o operations", OFFSET(rw_timeout), AV_OPT_TYPE_INT, {.i64 = 5000000}, 0, INT_MAX, D|E },
{"listen_timeout", "connection awaiting timeout", OFFSET(listen_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, D|E },
{NULL}
};
@@ -54,6 +57,23 @@ static const AVClass tcp_context_class = {
.version = LIBAVUTIL_VERSION_INT,
};
+//add by xhr, in order for add timeout prevent block too many time
+/*
+static sigjmp_buf jmpbuf;
+static volatile sig_atomic_t canjump;
+
+static void
+sig_alrm(int signo)
+{
+ if (!canjump)
+ return;
+
+ siglongjmp(jmpbuf, 1);
+ canjump = 0;
+}
+*/
+
+
/* return non zero if error */
static int tcp_open(URLContext *h, const char *uri, int flags)
{
@@ -63,10 +83,9 @@ static int tcp_open(URLContext *h, const char *uri, int flags)
const char *p;
char buf[256];
int ret;
- socklen_t optlen;
char hostname[1024],proto[1024],path[1024];
char portstr[10];
- h->rw_timeout = 5000000;
+ s->open_timeout = 5000000;
av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname),
&port, path, sizeof(path), uri);
@@ -82,21 +101,45 @@ static int tcp_open(URLContext *h, const char *uri, int flags)
s->listen = 1;
if (av_find_info_tag(buf, sizeof(buf), "timeout", p)) {
s->rw_timeout = strtol(buf, NULL, 10);
+// av_log(NULL,AV_LOG_ERROR,"TCPopen:OPTtimeout=%lld",s->rw_timeout);
}
if (av_find_info_tag(buf, sizeof(buf), "listen_timeout", p)) {
s->listen_timeout = strtol(buf, NULL, 10);
}
}
+ if (s->rw_timeout >= 0) {
+ s->open_timeout = s->rw_timeout;
h->rw_timeout = s->rw_timeout;
+// av_log(NULL,AV_LOG_ERROR,"TCPopen:timeout=%lld",h->rw_timeout);
+ }
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
snprintf(portstr, sizeof(portstr), "%d", port);
+
+//add by xhr, in order for add timeout prevent block too many time
+/*
+ if (signal(SIGALRM, sig_alrm) == SIG_ERR)
+ av_log(NULL,AV_LOG_ERROR,"Hery, signal err");
+ canjump = 1;
+ if (sigsetjmp(jmpbuf, 1))
+ {
+ av_log(NULL,AV_LOG_ERROR,"Hery, getaddrinfo err");
+ return -1;
+ }
+ alarm(8);
+*/
+
if (s->listen)
hints.ai_flags |= AI_PASSIVE;
if (!hostname[0])
ret = getaddrinfo(NULL, portstr, &hints, &ai);
else
ret = getaddrinfo(hostname, portstr, &hints, &ai);
+
+// canjump = 0; add by xhr
+// alarm(0); add by xhr
+
+
if (ret) {
av_log(h, AV_LOG_ERROR,
"Failed to resolve hostname %s: %s\n",
@@ -107,89 +150,29 @@ static int tcp_open(URLContext *h, const char *uri, int flags)
cur_ai = ai;
restart:
- ret = AVERROR(EIO);
fd = socket(cur_ai->ai_family, cur_ai->ai_socktype, cur_ai->ai_protocol);
- if (fd < 0)
+ if (fd < 0) {
+ ret = ff_neterrno();
goto fail;
+ }
if (s->listen) {
- int fd1;
- int reuse = 1;
- struct pollfd lp = { fd, POLLIN, 0 };
- setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
- ret = bind(fd, cur_ai->ai_addr, cur_ai->ai_addrlen);
- if (ret) {
- ret = ff_neterrno();
- goto fail1;
- }
- ret = listen(fd, 1);
- if (ret) {
- ret = ff_neterrno();
- goto fail1;
- }
- ret = poll(&lp, 1, s->listen_timeout >= 0 ? s->listen_timeout : -1);
- if (ret <= 0) {
- ret = AVERROR(ETIMEDOUT);
- goto fail1;
- }
- fd1 = accept(fd, NULL, NULL);
- if (fd1 < 0) {
- ret = ff_neterrno();
+ if ((fd = ff_listen_bind(fd, cur_ai->ai_addr, cur_ai->ai_addrlen,
+ s->listen_timeout, h)) < 0) {
+ ret = fd;
goto fail1;
}
- closesocket(fd);
- fd = fd1;
- ff_socket_nonblock(fd, 1);
} else {
- redo:
- ff_socket_nonblock(fd, 1);
- ret = connect(fd, cur_ai->ai_addr, cur_ai->ai_addrlen);
- }
-
- if (ret < 0) {
- struct pollfd p = {fd, POLLOUT, 0};
- int64_t wait_started;
- ret = ff_neterrno();
- if (ret == AVERROR(EINTR)) {
- if (ff_check_interrupt(&h->interrupt_callback)) {
- ret = AVERROR_EXIT;
- goto fail1;
- }
- goto redo;
- }
- if (ret != AVERROR(EINPROGRESS) &&
- ret != AVERROR(EAGAIN))
- goto fail;
+ if ((ret = ff_listen_connect(fd, cur_ai->ai_addr, cur_ai->ai_addrlen,
+ s->open_timeout / 1000, h)) < 0) {
- /* wait until we are connected or until abort */
- wait_started = av_gettime();
- do {
- if (ff_check_interrupt(&h->interrupt_callback)) {
- ret = AVERROR_EXIT;
+ if (ret == AVERROR_EXIT)
goto fail1;
- }
- ret = poll(&p, 1, 100);
- if (ret > 0)
- break;
- } while (!h->rw_timeout || (av_gettime() - wait_started < h->rw_timeout));
- if (ret <= 0) {
- ret = AVERROR(ETIMEDOUT);
- goto fail;
- }
- /* test error */
- optlen = sizeof(ret);
- if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen))
- ret = AVUNERROR(ff_neterrno());
- if (ret != 0) {
- char errbuf[100];
- ret = AVERROR(ret);
- av_strerror(ret, errbuf, sizeof(errbuf));
- av_log(h, AV_LOG_ERROR,
- "TCP connection to %s:%d failed: %s\n",
- hostname, port, errbuf);
- goto fail;
+ else
+ goto fail;
}
}
+
h->is_streamed = 1;
s->fd = fd;
freeaddrinfo(ai);
@@ -201,6 +184,7 @@ static int tcp_open(URLContext *h, const char *uri, int flags)
cur_ai = cur_ai->ai_next;
if (fd >= 0)
closesocket(fd);
+ ret = 0;
goto restart;
}
fail1:
@@ -214,12 +198,20 @@ static int tcp_read(URLContext *h, uint8_t *buf, int size)
{
TCPContext *s = h->priv_data;
int ret;
-
+// if(h->rw_timeout != 500*1000)
+ /// av_log(NULL,AV_LOG_ERROR,"tcp_read:h->rw_timeout=%lld",h->rw_timeout);
if (!(h->flags & AVIO_FLAG_NONBLOCK)) {
- ret = ff_network_wait_fd_timeout(s->fd, 0, h->rw_timeout, &h->interrupt_callback);
+ ret = ff_network_wait_fd_timeout(s->fd, 0, h->rw_timeout, &h->interrupt_callback);
if (ret)
+ {
+ if(ret == -110)
+ av_log(NULL,AV_LOG_ERROR,"tcp:TIMEOUT:%lld",h->rw_timeout);
+
+ // ff_send_message(&h->interrupt_callback,MEDIA_INFO_DOWNLOAD_ERROR,2000);
return ret;
+ }
}
+
ret = recv(s->fd, buf, size, 0);
return ret < 0 ? ff_neterrno() : ret;
}
diff --git a/libavformat/udp.c b/libavformat/udp.c
index a88fbe4..031f20c 100644..100755
--- a/libavformat/udp.c
+++ b/libavformat/udp.c
@@ -53,7 +53,7 @@
#endif
#define UDP_TX_BUF_SIZE 32768
-#define UDP_MAX_PKT_SIZE 65536
+#define UDP_MAX_PKT_SIZE 1024*1024
typedef struct {
const AVClass *class;
diff --git a/libavformat/url.h b/libavformat/url.h
index 5f75dc9..6a784b0 100644..100755
--- a/libavformat/url.h
+++ b/libavformat/url.h
@@ -43,12 +43,17 @@ typedef struct URLContext {
struct URLProtocol *prot;
void *priv_data;
char *filename; /**< specified URL */
+ char * cookies; /**< add by xhr, for set cookies. */
int flags;
int max_packet_size; /**< if non zero, the stream is packetized with this max packet size */
int is_streamed; /**< true if streamed (no seek possible), default = false */
int is_connected;
AVIOInterruptCB interrupt_callback;
int64_t rw_timeout; /**< maximum time to wait for (network) read/write operation completion, in mcs */
+ char url[4096];
+ int endFlag;
+ int errcode;
+ char mResponseHeader[4096]; /*http response header*/
} URLContext;
typedef struct URLProtocol {
@@ -237,6 +242,16 @@ int ffurl_register_protocol(URLProtocol *protocol, int size);
*/
int ff_check_interrupt(AVIOInterruptCB *cb);
+/*add by hh@rock-chips.com
+* send msg to player
+*/
+void ff_send_message(AVIOInterruptCB* cb,int what,int msg);
+
+/*add by hh@rock-chips.com
+* check user operate
+*/
+int ff_check_operate(AVIOInterruptCB *cb,int opreate,void* para1,void** para2);
+
/**
* Iterate over all available protocols.
*
diff --git a/libavformat/utils.c b/libavformat/utils.c
index 72a3d5e..0fc6568 100644..100755
--- a/libavformat/utils.c
+++ b/libavformat/utils.c
@@ -50,6 +50,7 @@
#undef NDEBUG
#include <assert.h>
+
/**
* @file
* various utility functions for use within FFmpeg
@@ -322,6 +323,10 @@ AVInputFormat *av_probe_input_format3(AVProbeData *pd, int is_opened, int *score
if (score > score_max) {
score_max = score;
fmt = fmt1;
+ if(fmt1&&!strncmp(fmt1->name, "hls,applehttp", 6)){
+ av_log(NULL, AV_LOG_DEBUG,"av_probe_input_format3 hls,applehttp\n");
+ break;
+ }
}else if (score == score_max)
fmt = NULL;
}
@@ -440,6 +445,7 @@ int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt,
return AVERROR(ENOMEM);
}
buf=buftmp;
+ av_log(NULL,AV_LOG_ERROR,"av_probe_input_buffer:avio_read");
if ((ret = avio_read(pb, buf + buf_offset, probe_size - buf_offset)) < 0) {
/* fail if error was not end of file, otherwise, lower score */
if (ret != AVERROR_EOF) {
@@ -494,14 +500,51 @@ static int init_input(AVFormatContext *s, const char *filename, AVDictionary **o
if ( (s->iformat && s->iformat->flags & AVFMT_NOFILE) ||
(!s->iformat && (s->iformat = av_probe_input_format2(&pd, 0, &score))))
+ {
+ av_log(NULL,AV_LOG_ERROR,"find iformat");
return 0;
+ }
+ if(strstr(filename,".m3u8") || strstr(filename,".m3u")) // only for test
+ {
+ av_log(NULL,AV_LOG_ERROR,"May Be appleHTTP file type");
+ av_dict_set(options, "hls", "1", 0); // ht modified for hls timeout 500ms; other is 60s
+ }
+ else
+ av_dict_set(options, "hls", "0", 0);
+
+// if(strstr(filename,"file") && strstr(filename,"m3u8")) //add for xhr, for Bluray
+ if(strstr(filename, "file/fd::"))
+ {
+ s->probesize = 10000000;
+ }
+ if(strstr(filename,".flv") || strstr(filename,".pfv"))
+ {
+ av_log(NULL,AV_LOG_ERROR,"May Be FLV file type");
+ av_dict_set(options, "flv", "1", 0); // ht modified for hls timeout 500ms; other is 60s
+
+ }
+ else
+ av_dict_set(options, "flv", "0", 0);
+
+ if(strstr(filename,".mp4") && !strstr(filename,".mp4."))
+ {
+ av_log(NULL,AV_LOG_ERROR,"May Be MP4 file type");
+ av_dict_set(options, "mp4", "1", 0); // ht modified for hls timeout 500ms; other is 60s
+ }
+ else
+ av_dict_set(options, "mp4", "0", 0);
if ((ret = avio_open2(&s->pb, filename, AVIO_FLAG_READ | s->avio_flags,
&s->interrupt_callback, options)) < 0)
+ {
+ av_log(NULL,AV_LOG_ERROR,"init_input:avio_open2 failed");
return ret;
+ }
if (s->iformat)
return 0;
- return av_probe_input_buffer(s->pb, &s->iformat, filename, s, 0, s->probesize);
+
+ return av_probe_input_buffer(s->pb, &s->iformat, filename, s, 0, s->probesize);
+
}
static AVPacket *add_to_pktbuf(AVPacketList **packet_buffer, AVPacket *pkt,
@@ -539,7 +582,7 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputForma
int ret = 0;
AVDictionary *tmp = NULL;
ID3v2ExtraMeta *id3v2_extra_meta = NULL;
-
+ av_log(NULL,AV_LOG_ERROR,"ffmpeg version 4-7\n");
if (!s && !(s = avformat_alloc_context()))
return AVERROR(ENOMEM);
if (!s->av_class){
@@ -556,7 +599,10 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputForma
goto fail;
if ((ret = init_input(s, filename, &tmp)) < 0)
+ {
+ av_log(NULL,AV_LOG_ERROR,"init_input failed");
goto fail;
+ }
/* check filename in case an image number is expected */
if (s->iformat->flags & AVFMT_NEEDNUMBER) {
@@ -588,9 +634,12 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputForma
ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta);
if (!(s->flags&AVFMT_FLAG_PRIV_OPT) && s->iformat->read_header)
+ {
+ av_log(NULL,AV_LOG_ERROR,"%s:read_header",__FUNCTION__);
if ((ret = s->iformat->read_header(s)) < 0)
goto fail;
-
+ }
+ av_log(NULL,AV_LOG_ERROR,"%s:read_header ok",__FUNCTION__);
if (id3v2_extra_meta) {
if (!strcmp(s->iformat->name, "mp3")) {
if((ret = ff_id3v2_parse_apic(s, &id3v2_extra_meta)) < 0)
@@ -691,6 +740,13 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt)
AVStream *st;
for(;;){
+
+ if (ff_check_interrupt(&s->interrupt_callback.callback))
+ {
+ av_log(NULL,AV_LOG_ERROR,"ff_read_packet:ff_check_interrupt");
+ return AVERROR_EXIT;
+ }
+
AVPacketList *pktl = s->raw_packet_buffer;
if (pktl) {
@@ -708,6 +764,10 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt)
pkt->size = 0;
av_init_packet(pkt);
ret= s->iformat->read_packet(s, pkt);
+ if(pkt&&s->pb&&s->pb->read_seqno){
+ int seqno = s->pb->read_seqno(s->pb->opaque);
+ pkt->seq = seqno;
+ }
if (ret < 0) {
if (!pktl || ret == AVERROR(EAGAIN))
return ret;
@@ -742,10 +802,20 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt)
force_codec_ids(s, st);
+ if(s->mIPTVControlProbe == 1)
+ {
+ //av_log(NULL, AV_LOG_ERROR, "mIPTVControlProbe == 1");
+ return ;
+ }
+ else
+ {
+ //av_log(NULL, AV_LOG_ERROR, "mIPTVControlProbe == 0");
+ ;
+ }
+
/* TODO: audio: time filter; video: frame reordering (pts != dts) */
if (s->use_wallclock_as_timestamps)
pkt->dts = pkt->pts = av_rescale_q(av_gettime(), AV_TIME_BASE_Q, st->time_base);
-
if(!pktl && st->request_probe <= 0)
return ret;
@@ -948,7 +1018,7 @@ static void update_initial_durations(AVFormatContext *s, AVStream *st,
}
}
if(pktl && pktl->pkt.dts != st->first_dts) {
- av_log(s, AV_LOG_DEBUG, "first_dts %s not matching first dts %s in que\n", av_ts2str(st->first_dts), av_ts2str(pktl->pkt.dts));
+// av_log(s, AV_LOG_DEBUG, "first_dts %s not matching first dts %s in que\n", av_ts2str(st->first_dts), av_ts2str(pktl->pkt.dts));
return;
}
if(!pktl) {
@@ -983,6 +1053,7 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st,
{
int num, den, presentation_delayed, delay, i;
int64_t offset;
+ AVRational duration;
if (s->flags & AVFMT_FLAG_NOFILLIN)
return;
@@ -990,7 +1061,8 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st,
if((s->flags & AVFMT_FLAG_IGNDTS) && pkt->pts != AV_NOPTS_VALUE)
pkt->dts= AV_NOPTS_VALUE;
- if (st->codec->codec_id != AV_CODEC_ID_H264 && pc && pc->pict_type == AV_PICTURE_TYPE_B)
+ if (pc && pc->pict_type == AV_PICTURE_TYPE_B
+ && !st->codec->has_b_frames)
//FIXME Set low_delay = 0 when has_b_frames = 1
st->codec->has_b_frames = 1;
@@ -1004,7 +1076,9 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st,
pc && pc->pict_type != AV_PICTURE_TYPE_B)
presentation_delayed = 1;
- if(pkt->pts != AV_NOPTS_VALUE && pkt->dts != AV_NOPTS_VALUE && st->pts_wrap_bits<63 && pkt->dts - (1LL<<(st->pts_wrap_bits-1)) > pkt->pts){
+ if (pkt->pts != AV_NOPTS_VALUE && pkt->dts != AV_NOPTS_VALUE &&
+ st->pts_wrap_bits < 63 &&
+ pkt->dts - (1LL << (st->pts_wrap_bits - 1)) > pkt->pts) {
if(is_relative(st->cur_dts) || pkt->dts - (1LL<<(st->pts_wrap_bits-1)) > st->cur_dts) {
pkt->dts -= 1LL<<st->pts_wrap_bits;
} else
@@ -1016,13 +1090,16 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st,
// Note, if this is misbehaving for a H.264 file then possibly presentation_delayed is not set correctly.
if(delay==1 && pkt->dts == pkt->pts && pkt->dts != AV_NOPTS_VALUE && presentation_delayed){
av_log(s, AV_LOG_DEBUG, "invalid dts/pts combination %"PRIi64"\n", pkt->dts);
- if(strcmp(s->iformat->name, "mov,mp4,m4a,3gp,3g2,mj2")) // otherwise we discard correct timestamps for vc1-wmapro.ism
+ if ( strcmp(s->iformat->name, "mov,mp4,m4a,3gp,3g2,mj2")
+ && strcmp(s->iformat->name, "flv")) // otherwise we discard correct timestamps for vc1-wmapro.ism
pkt->dts= AV_NOPTS_VALUE;
}
+ duration = av_mul_q((AVRational){pkt->duration, 1}, st->time_base);
if (pkt->duration == 0) {
ff_compute_frame_duration(&num, &den, st, pc, pkt);
if (den && num) {
+ duration = (AVRational){num, den};
pkt->duration = av_rescale_rnd(1, num * (int64_t)st->time_base.den, den * (int64_t)st->time_base.num, AV_ROUND_DOWN);
}
}
@@ -1040,25 +1117,6 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st,
pkt->dts += offset;
}
- if (pc && pc->dts_sync_point >= 0) {
- // we have synchronization info from the parser
- int64_t den = st->codec->time_base.den * (int64_t) st->time_base.num;
- if (den > 0) {
- int64_t num = st->codec->time_base.num * (int64_t) st->time_base.den;
- if (pkt->dts != AV_NOPTS_VALUE) {
- // got DTS from the stream, update reference timestamp
- st->reference_dts = pkt->dts - pc->dts_ref_dts_delta * num / den;
- pkt->pts = pkt->dts + pc->pts_dts_delta * num / den;
- } else if (st->reference_dts != AV_NOPTS_VALUE) {
- // compute DTS based on reference timestamp
- pkt->dts = st->reference_dts + pc->dts_ref_dts_delta * num / den;
- pkt->pts = pkt->dts + pc->pts_dts_delta * num / den;
- }
- if (pc->dts_sync_point > 0)
- st->reference_dts = pkt->dts; // new reference
- }
- }
-
/* This may be redundant, but it should not hurt. */
if(pkt->dts != AV_NOPTS_VALUE && pkt->pts != AV_NOPTS_VALUE && pkt->pts > pkt->dts)
presentation_delayed = 1;
@@ -1090,21 +1148,6 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st,
} else if (pkt->pts != AV_NOPTS_VALUE ||
pkt->dts != AV_NOPTS_VALUE ||
pkt->duration ) {
- int duration = pkt->duration;
-
- if(st->cur_dts != AV_NOPTS_VALUE && pkt->pts != AV_NOPTS_VALUE && duration){
- int64_t old_diff= FFABS(st->cur_dts - duration - pkt->pts);
- int64_t new_diff= FFABS(st->cur_dts - pkt->pts);
- if( old_diff < new_diff && old_diff < (duration>>3)
- && st->codec->codec_type == AVMEDIA_TYPE_VIDEO
- && (!strcmp(s->iformat->name, "mpeg") ||
- !strcmp(s->iformat->name, "mpegts"))){
- pkt->pts += duration;
- av_log(s, AV_LOG_WARNING, "Adjusting PTS forward\n");
-// av_log(NULL, AV_LOG_DEBUG, "id:%d old:%"PRId64" new:%"PRId64" dur:%d cur:%s size:%d\n",
-// pkt->stream_index, old_diff, new_diff, pkt->duration, av_ts2str(st->cur_dts), pkt->size);
- }
- }
/* presentation is not delayed : PTS and DTS are the same */
if (pkt->pts == AV_NOPTS_VALUE)
@@ -1115,7 +1158,7 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st,
pkt->pts = st->cur_dts;
pkt->dts = pkt->pts;
if (pkt->pts != AV_NOPTS_VALUE)
- st->cur_dts = pkt->pts + duration;
+ st->cur_dts = av_add_stable(st->time_base, pkt->pts, duration, 1);
}
}
@@ -1215,12 +1258,13 @@ static int parse_packet(AVFormatContext *s, AVPacket *pkt, int stream_index)
out_pkt.pts = st->parser->pts;
out_pkt.dts = st->parser->dts;
out_pkt.pos = st->parser->pos;
+ out_pkt.seq = pkt->seq;
if(st->need_parsing == AVSTREAM_PARSE_FULL_RAW)
out_pkt.pos = st->parser->frame_offset;
if (st->parser->key_frame == 1 ||
- (st->parser->key_frame == -1 &&
+ (/*st->parser->key_frame == 0 &&*/
st->parser->pict_type == AV_PICTURE_TYPE_I))
out_pkt.flags |= AV_PKT_FLAG_KEY;
@@ -1282,6 +1326,7 @@ static int read_frame_internal(AVFormatContext *s, AVPacket *pkt)
/* read next packet */
ret = ff_read_packet(s, &cur_pkt);
+ pkt->seq = cur_pkt.seq;
if (ret < 0) {
if (ret == AVERROR(EAGAIN))
return ret;
@@ -1331,6 +1376,17 @@ static int read_frame_internal(AVFormatContext *s, AVPacket *pkt)
} else if(st->need_parsing == AVSTREAM_PARSE_FULL_RAW) {
st->parser->flags |= PARSER_FLAG_USE_CODEC_TS;
}
+
+ if(st->parser != NULL)
+ {
+ av_parser_init_callback(st->parser,
+ s->interrupt_callback.callback,
+ s->interrupt_callback.msg_callback,
+ s->interrupt_callback.operate_callback,
+ s->interrupt_callback.opaque,
+ s->interrupt_callback.msg_opaque,
+ s->interrupt_callback.operate_opaque);
+ }
}
if (!st->need_parsing || !st->parser) {
@@ -1866,6 +1922,8 @@ static int seek_frame_generic(AVFormatContext *s,
int64_t ret;
AVStream *st;
AVIndexEntry *ie;
+ int64_t seekUs = av_gettime();
+ int64_t seek_timeout = 5000000; //5s
st = s->streams[stream_index];
@@ -1896,6 +1954,11 @@ static int seek_frame_generic(AVFormatContext *s,
if (read_status < 0)
break;
av_free_packet(&pkt);
+ if (s->iformat && strstr(s->iformat->name, "matroska") &&
+ abs(av_gettime() -seekUs) >seek_timeout) {
+ av_log(NULL, AV_LOG_INFO, "seek_frame_generic timeout\n");
+ break;
+ }
if(stream_index == pkt.stream_index && pkt.dts > timestamp){
if(pkt.flags & AV_PKT_FLAG_KEY)
break;
@@ -1928,7 +1991,6 @@ static int seek_frame_internal(AVFormatContext *s, int stream_index,
{
int ret;
AVStream *st;
-
if (flags & AVSEEK_FLAG_BYTE) {
if (s->iformat->flags & AVFMT_NO_BYTE_SEEK)
return -1;
@@ -1956,6 +2018,10 @@ static int seek_frame_internal(AVFormatContext *s, int stream_index,
return 0;
}
+ if(ret == AVERROR_SEEK_FAIL){
+ return ret;
+ }
+
if (s->iformat->read_timestamp && !(s->iformat->flags & AVFMT_NOBINSEARCH)) {
ff_read_frame_flush(s);
return ff_seek_frame_binary(s, stream_index, timestamp, flags);
@@ -1999,8 +2065,11 @@ int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts, int
//Fallback to old API if new is not implemented but old is
//Note the old has somewhat different semantics
if (s->iformat->read_seek || 1) {
- int dir = (ts - (uint64_t)min_ts > (uint64_t)max_ts - ts ? AVSEEK_FLAG_BACKWARD : 0);
+ int dir = 0;//(ts - (uint64_t)min_ts > (uint64_t)max_ts - ts ? AVSEEK_FLAG_BACKWARD : 0); //edit by xhr
int ret = av_seek_frame(s, stream_index, ts, flags | dir);
+ if(ret == AVERROR_SEEK_FAIL) {
+ return ret;
+ }
if (ret<0 && ts != min_ts && max_ts != ts) {
ret = av_seek_frame(s, stream_index, dir ? max_ts : min_ts, flags | dir);
if (ret >= 0)
@@ -2167,6 +2236,7 @@ static void estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset)
int64_t end_time;
int64_t filesize, offset, duration;
int retry=0;
+ int64_t ret_seek = -1;
/* flush packet queue */
flush_packet_queue(ic);
@@ -2190,8 +2260,18 @@ static void estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset)
offset = filesize - (DURATION_MAX_READ_SIZE<<retry);
if (offset < 0)
offset = 0;
-
- avio_seek(ic->pb, offset, SEEK_SET);
+
+ ret_seek = avio_seek(ic->pb, offset, SEEK_SET);
+ while(ret_seek < 0)
+ {
+ if (ff_check_interrupt(&(ic->interrupt_callback)))
+ {
+ av_log(NULL,AV_LOG_DEBUG,"%s:interrupt ok",__FUNCTION__);
+ return AVERROR_EXIT;
+ }
+ ret_seek = avio_seek(ic->pb, offset, SEEK_SET);
+ }
+ av_log(NULL,AV_LOG_DEBUG,"%s::ret_seek=%lld",__FUNCTION__,ret_seek);
read_size = 0;
for(;;) {
if (read_size >= DURATION_MAX_READ_SIZE<<(FFMAX(retry-1,0)))
@@ -2209,7 +2289,12 @@ static void estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset)
st->first_dts != AV_NOPTS_VALUE)) {
duration = end_time = pkt->pts;
if (st->start_time != AV_NOPTS_VALUE)
- duration -= st->start_time;
+ {
+ if(duration > st->start_time) // ht for some pts err at end of file
+ {
+ duration -= st->start_time;
+ }
+ }
else
duration -= st->first_dts;
if (duration < 0)
@@ -2225,6 +2310,7 @@ static void estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset)
&& filesize > (DURATION_MAX_READ_SIZE<<retry)
&& ++retry <= DURATION_MAX_RETRY);
+
fill_all_stream_timings(ic);
avio_seek(ic->pb, old_offset, SEEK_SET);
@@ -2272,16 +2358,64 @@ static void estimate_timings(AVFormatContext *ic, int64_t old_offset)
AVStream av_unused *st;
for(i = 0;i < ic->nb_streams; i++) {
st = ic->streams[i];
- av_dlog(ic, "%d: start_time: %0.3f duration: %0.3f\n", i,
+ av_log(NULL,AV_LOG_ERROR, "%s:%d: start_time: %0.3f duration: %0.3f,base_time.den=%d,base_time.num=%d\n", __FUNCTION__,i,
(double) st->start_time / AV_TIME_BASE,
- (double) st->duration / AV_TIME_BASE);
+ (double) st->duration / AV_TIME_BASE,st->time_base.den,st->time_base.num);
}
- av_dlog(ic, "stream: start_time: %0.3f duration: %0.3f bitrate=%d kb/s\n",
+ av_log(NULL,AV_LOG_ERROR, "stream: start_time: %0.3f duration: %0.3f bitrate=%d kb/s\n",
(double) ic->start_time / AV_TIME_BASE,
(double) ic->duration / AV_TIME_BASE,
ic->bit_rate / 1000);
}
}
+/*add by smj 增加parameters检测回调机制(暂时只用于avformat_find_info),用于在ffplayer中判断是否进行返回或报错*/
+static int has_codec_parameters_for_avformat(AVFormatContext *s, AVStream *st, const char **errmsg_ptr)
+{
+ AVCodecContext *avctx = st->codec;
+ int ret = 0;
+ int type = 0;
+ int value = 0;
+#define FAIL(errmsg, type, value) \
+ do { \
+ if (errmsg_ptr) \
+ *errmsg_ptr = errmsg; \
+ ret = ff_check_operate (&s->interrupt_callback, OPERATE_GET_PARAMETER_FAIL_VALUE , &type, &value); \
+ return ret; \
+ } while (0)
+ type = (int) (avctx->codec_type);
+ switch (avctx->codec_type) {
+ case AVMEDIA_TYPE_AUDIO:
+ if (!avctx->frame_size && determinable_frame_size(avctx))
+ { value = 0; FAIL("unspecified frame size", type, value); }
+ if (st->info->found_decoder >= 0 && avctx->sample_fmt == AV_SAMPLE_FMT_NONE)
+ { value = 1; FAIL("unspecified sample format", type, value);}
+ if (!avctx->sample_rate)
+ { value = 2; FAIL("unspecified sample rate", type, value);}
+ if (!avctx->channels)
+ { value = 3; FAIL("unspecified number of channels", avctx->codec_type, value);}
+ if (st->info->found_decoder >= 0 && !st->nb_decoded_frames && avctx->codec_id == AV_CODEC_ID_DTS)
+ { value = 4; FAIL("no decodable DTS frames", type,value); }
+ break;
+ case AVMEDIA_TYPE_VIDEO:
+ if (!avctx->width)
+ { value = 0; FAIL("unspecified size", type, value); }
+ if (st->info->found_decoder >= 0 && avctx->pix_fmt == AV_PIX_FMT_NONE)
+ { value = 1; FAIL("unspecified pixel format", type, value);}
+ break;
+ case AVMEDIA_TYPE_SUBTITLE:
+ if (avctx->codec_id == AV_CODEC_ID_HDMV_PGS_SUBTITLE && !avctx->width)
+ { value = 0; FAIL("unspecified size", type, value); }
+ break;
+ case AVMEDIA_TYPE_DATA:
+ if(avctx->codec_id == AV_CODEC_ID_NONE) return 1;
+ }
+
+ if (avctx->codec_id == AV_CODEC_ID_NONE)
+ { value = 0; FAIL("unknown codec",avctx->codec_id, value);}
+
+ return 1;
+
+}
static int has_codec_parameters(AVStream *st, const char **errmsg_ptr)
{
@@ -2322,6 +2456,7 @@ static int has_codec_parameters(AVStream *st, const char **errmsg_ptr)
if (avctx->codec_id == AV_CODEC_ID_NONE)
FAIL("unknown codec");
+
return 1;
}
@@ -2514,9 +2649,11 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
int64_t old_offset = avio_tell(ic->pb);
int orig_nb_streams = ic->nb_streams; // new streams might appear, no options for those
int flush_codecs = ic->probesize > 0;
-
+ int trynum = 5;
if(ic->pb)
av_log(ic, AV_LOG_DEBUG, "File position before avformat_find_stream_info() is %"PRId64"\n", avio_tell(ic->pb));
+
+tryAgain:
for(i=0;i<ic->nb_streams;i++) {
const AVCodec *codec;
@@ -2539,6 +2676,18 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
} else if(st->need_parsing == AVSTREAM_PARSE_FULL_RAW) {
st->parser->flags |= PARSER_FLAG_USE_CODEC_TS;
}
+
+ if(st->parser != NULL)
+ {
+ av_log(NULL,AV_LOG_ERROR,"avformat_find_stream_info: av_parser_init_callback");
+ av_parser_init_callback(st->parser,
+ ic->interrupt_callback.callback,
+ ic->interrupt_callback.msg_callback,
+ ic->interrupt_callback.operate_callback,
+ ic->interrupt_callback.opaque,
+ ic->interrupt_callback.msg_opaque,
+ ic->interrupt_callback.operate_opaque);
+ }
} else if (st->need_parsing) {
av_log(ic, AV_LOG_VERBOSE, "parser not found for codec "
"%s, packets or times may be invalid.\n",
@@ -2559,7 +2708,7 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
: &thread_opt);
//try to just open decoders, in case this is enough to get parameters
- if (!has_codec_parameters(st, NULL) && st->request_probe <= 0) {
+ if (!has_codec_parameters_for_avformat(ic, st, NULL) && st->request_probe <= 0) {
if (codec && !st->codec->codec)
avcodec_open2(st->codec, codec, options ? &options[i]
: &thread_opt);
@@ -2585,12 +2734,39 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
break;
}
+
+ if(ic->mIPTVControlProbe == 1)
+ {
+ for(i=0;i<ic->nb_streams;i++)
+ {
+ st = ic->streams[i];
+ if(has_codec_parameters_for_avformat(ic,st, NULL))
+ {
+ av_log(NULL, AV_LOG_ERROR, "codec have find");
+ continue;
+ }
+ else
+ {
+ av_log(NULL, AV_LOG_ERROR, "codec no find");
+ break;
+ }
+ }
+
+ if(i == ic->nb_streams && i != 0)
+ {
+ av_log(ic, AV_LOG_ERROR, "all stream has parameter ************** break");
+ break ;
+ }
+ }
+
+
+
/* check if one codec still needs to be handled */
for(i=0;i<ic->nb_streams;i++) {
int fps_analyze_framecount = 20;
st = ic->streams[i];
- if (!has_codec_parameters(st, NULL))
+ if (!has_codec_parameters_for_avformat(ic, st, NULL))
break;
/* if the timebase is coarse (like the usual millisecond precision
of mkv), we need to analyze more frames to reliably arrive at
@@ -2615,7 +2791,7 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
/* NOTE: if the format has no header, then we need to read
some packets to get most of the streams, so we cannot
stop here */
- if (!(ic->ctx_flags & AVFMTCTX_NOHEADER)) {
+ if (!(ic->ctx_flags & AVFMTCTX_NOHEADER) && ic->nb_streams != 0) {
/* if we found the info for all the codecs, we can stop */
ret = count;
av_log(ic, AV_LOG_DEBUG, "All info found\n");
@@ -2626,14 +2802,29 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
/* we did not get all the codec info, but we read too much data */
if (read_size >= ic->probesize) {
ret = count;
- av_log(ic, AV_LOG_DEBUG, "Probe buffer size limit %d reached\n", ic->probesize);
+ av_log(ic, AV_LOG_ERROR, "Probe buffer size limit %d reached\n", ic->probesize);
for (i = 0; i < ic->nb_streams; i++)
if (!ic->streams[i]->r_frame_rate.num &&
ic->streams[i]->info->duration_count <= 1)
- av_log(ic, AV_LOG_WARNING,
+ av_log(ic, AV_LOG_ERROR,
"Stream #%d: not enough frames to estimate rate; "
"consider increasing probesize\n", i);
- break;
+ if(ic->mIPTVControlProbe == 0)
+ {
+ if(trynum--<0)
+ break;
+ else
+ {
+ av_log(NULL,AV_LOG_ERROR,"avformat_find_stream_info:add probesize");
+ ic->probesize += 1024*100;
+ goto tryAgain;
+ }
+ }
+ else
+ {
+ av_log(NULL,AV_LOG_ERROR,"avformat_find_stream_info:IPTV break");
+ break;
+ }
}
/* NOTE: a new stream can be added there if no header in file
@@ -2699,7 +2890,7 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
t = FFMAX(t, av_rescale_q(st->codec_info_nb_frames, av_inv_q(st->avg_frame_rate), AV_TIME_BASE_Q));
if (t >= ic->max_analyze_duration) {
- av_log(ic, AV_LOG_WARNING, "max_analyze_duration %d reached at %"PRId64"\n", ic->max_analyze_duration, t);
+ av_log(ic, AV_LOG_ERROR, "max_analyze_duration %d reached at %"PRId64"\n", ic->max_analyze_duration, t);
break;
}
if (pkt->duration) {
@@ -2780,7 +2971,7 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
err = try_decode_frame(st, &empty_pkt,
(options && i < orig_nb_streams) ?
&options[i] : NULL);
- } while (err > 0 && !has_codec_parameters(st, NULL));
+ } while (err > 0 && !has_codec_parameters_for_avformat(ic, st, NULL));
if (err < 0) {
av_log(ic, AV_LOG_INFO,
@@ -2788,10 +2979,10 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
}
}
- if (!has_codec_parameters(st, &errmsg)) {
+ if (!has_codec_parameters_for_avformat(ic, st, &errmsg)) {
char buf[256];
avcodec_string(buf, sizeof(buf), st->codec, 0);
- av_log(ic, AV_LOG_WARNING,
+ av_log(ic, AV_LOG_DEBUG,
"Could not find codec parameters for stream %d (%s): %s\n"
"Consider increasing the value for the 'analyzeduration' and 'probesize' options\n",
i, buf, errmsg);
@@ -2913,7 +3104,15 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
for (i=0; i < ic->nb_streams; i++) {
if (ic->streams[i]->codec)
ic->streams[i]->codec->thread_count = 0;
- av_freep(&ic->streams[i]->info);
+ if(ic->streams[i]->info != NULL)
+ {
+ av_freep(&ic->streams[i]->info);
+ av_log(NULL,AV_LOG_ERROR,"%s:find_stream_info_err:free info,ok",__FUNCTION__);
+ }
+ else
+ {
+ av_log(NULL,AV_LOG_ERROR,"%s:find_stream_info_err:free info is NULL,err",__FUNCTION__);
+ }
}
if(ic->pb)
av_log(ic, AV_LOG_DEBUG, "File position after avformat_find_stream_info() is %"PRId64"\n", avio_tell(ic->pb));
diff --git a/libavutil/avutil.h b/libavutil/avutil.h
index db016a5..170813b 100644..100755
--- a/libavutil/avutil.h
+++ b/libavutil/avutil.h
@@ -257,4 +257,13 @@ static inline void *av_x_if_null(const void *p, const void *x)
* @}
*/
+/* define by hh for operate_callback in AVIOInterruptCB
+* operate type
+*/
+#define OPERATE_SEEK 0
+#define OPERATE_GET_URL 1
+#define OPERATE_CHECK_USE_LOCAL_PPS_SPS 2
+#define OPERATE_GET_SPS 3
+#define OPERATE_GET_PPS 4
+#define OPERATE_GET_PARAMETER_FAIL_VALUE 5
#endif /* AVUTIL_AVUTIL_H */
diff --git a/libavutil/common.h b/libavutil/common.h
index 03a2354..662ecc6 100644..100755
--- a/libavutil/common.h
+++ b/libavutil/common.h
@@ -167,7 +167,7 @@ static av_always_inline av_const int16_t av_clip_int16_c(int a)
*/
static av_always_inline av_const int32_t av_clipl_int32_c(int64_t a)
{
- if ((a+0x80000000u) & ~UINT64_C(0xFFFFFFFF)) return (a>>63) ^ 0x7FFFFFFF;
+ if ((a+0x80000000u) & ~(0xFFFFFFFF)) return (a>>63) ^ 0x7FFFFFFF;
else return (int32_t)a;
}
diff --git a/libavutil/error.h b/libavutil/error.h
index f3fd7bb..5fd25ad 100644..100755
--- a/libavutil/error.h
+++ b/libavutil/error.h
@@ -63,6 +63,9 @@
#define AVERROR_PROTOCOL_NOT_FOUND FFERRTAG(0xF8,'P','R','O') ///< Protocol not found
#define AVERROR_STREAM_NOT_FOUND FFERRTAG(0xF8,'S','T','R') ///< Stream not found
+
+#define AVERROR_SEEK_FAIL FFERRTAG( 'S','F','A','L') // hh define for wasu special seek fail
+
/**
* This is semantically identical to AVERROR_BUG
* it has been introduced in Libav after our AVERROR_BUG and with a modified value.
diff --git a/libavutil/mathematics.c b/libavutil/mathematics.c
index 6c2f6c0..30963aa 100644..100755
--- a/libavutil/mathematics.c
+++ b/libavutil/mathematics.c
@@ -61,7 +61,16 @@ int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding rnd){
int64_t r=0;
av_assert2(c > 0);
av_assert2(b >=0);
- av_assert2((unsigned)rnd<=5 && rnd!=4);
+ av_assert2((unsigned)(rnd&~AV_ROUND_PASS_MINMAX)<=5 && (rnd&~AV_ROUND_PASS_MINMAX)!=4);
+
+ if (c <= 0 || b < 0 || !((unsigned)(rnd&~AV_ROUND_PASS_MINMAX)<=5 && (rnd&~AV_ROUND_PASS_MINMAX)!=4))
+ return INT64_MIN;
+
+ if (rnd & AV_ROUND_PASS_MINMAX) {
+ if (a == INT64_MIN || a == INT64_MAX)
+ return a;
+ rnd -= AV_ROUND_PASS_MINMAX;
+ }
if(a<0 && a != INT64_MIN) return -av_rescale_rnd(-a, b, c, rnd ^ ((rnd>>1)&1));
@@ -165,3 +174,17 @@ simple_round:
return av_rescale_q(this, fs_tb, out_tb);
}
+
+int64_t av_add_stable(AVRational ts_tb, int64_t ts, AVRational inc_tb, int64_t inc)
+{
+ AVRational step = av_mul_q(inc_tb, (AVRational) {inc, 1});
+
+ if (av_cmp_q(step, ts_tb) < 0) {
+ //increase step is too small for even 1 step to be representable
+ return ts;
+ } else {
+ int64_t old = av_rescale_q(ts, ts_tb, step);
+ int64_t old_ts = av_rescale_q(old, step, ts_tb);
+ return av_rescale_q(old + 1, step, ts_tb) + (ts - old_ts);
+ }
+}
diff --git a/libavutil/mathematics.h b/libavutil/mathematics.h
index 0021d52..a8b1d8e 100644..100755
--- a/libavutil/mathematics.h
+++ b/libavutil/mathematics.h
@@ -70,6 +70,7 @@ enum AVRounding {
AV_ROUND_DOWN = 2, ///< Round toward -infinity.
AV_ROUND_UP = 3, ///< Round toward +infinity.
AV_ROUND_NEAR_INF = 5, ///< Round to nearest and halfway cases away from zero.
+ AV_ROUND_PASS_MINMAX = 8192, ///< Flag to pass INT64_MIN/MAX through instead of rescaling, this avoids special cases for AV_NOPTS_VALUE
};
/**
@@ -88,6 +89,9 @@ int64_t av_rescale(int64_t a, int64_t b, int64_t c) av_const;
/**
* Rescale a 64-bit integer with specified rounding.
* A simple a*b/c isn't possible as it can overflow.
+ *
+ * @return rescaled value a, or if AV_ROUND_PASS_MINMAX is set and a is
+ * INT64_MIN or INT64_MAX then a is passed through unchanged.
*/
int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding) av_const;
@@ -98,6 +102,9 @@ int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq) av_const;
/**
* Rescale a 64-bit integer by 2 rational numbers with specified rounding.
+ *
+ * @return rescaled value a, or if AV_ROUND_PASS_MINMAX is set and a is
+ * INT64_MIN or INT64_MAX then a is passed through unchanged.
*/
int64_t av_rescale_q_rnd(int64_t a, AVRational bq, AVRational cq,
enum AVRounding) av_const;
@@ -126,14 +133,28 @@ int64_t av_compare_mod(uint64_t a, uint64_t b, uint64_t mod);
* Rescale a timestamp while preserving known durations.
*
* @param in_ts Input timestamp
- * @param in_tb Input timesbase
+ * @param in_tb Input timebase
* @param fs_tb Duration and *last timebase
* @param duration duration till the next call
- * @param out_tb Output timesbase
+ * @param out_tb Output timebase
*/
int64_t av_rescale_delta(AVRational in_tb, int64_t in_ts, AVRational fs_tb, int duration, int64_t *last, AVRational out_tb);
/**
+ * Add a value to a timestamp.
+ *
+ * This function gurantees that when the same value is repeatly added that
+ * no accumulation of rounding errors occurs.
+ *
+ * @param ts Input timestamp
+ * @param ts_tb Input timestamp timebase
+ * @param inc value to add to ts
+ * @param inc_tb inc timebase
+ */
+int64_t av_add_stable(AVRational ts_tb, int64_t ts, AVRational inc_tb, int64_t inc);
+
+
+ /**
* @}
*/
diff --git a/libavutil/opt.c b/libavutil/opt.c
index 11e757e..700c91f 100644..100755
--- a/libavutil/opt.c
+++ b/libavutil/opt.c
@@ -723,18 +723,21 @@ void av_opt_set_defaults2(void *s, int mask, int flags)
case AV_OPT_TYPE_INT:
case AV_OPT_TYPE_INT64:
av_opt_set_int(s, opt->name, opt->default_val.i64, 0);
+ //av_log(s, AV_LOG_ERROR, "44opt->name '%s'\n", opt->name);
break;
case AV_OPT_TYPE_DOUBLE:
case AV_OPT_TYPE_FLOAT: {
double val;
val = opt->default_val.dbl;
av_opt_set_double(s, opt->name, val, 0);
+ //av_log(s, AV_LOG_ERROR, "33opt->name '%s'\n", opt->name);
}
break;
case AV_OPT_TYPE_RATIONAL: {
AVRational val;
val = av_d2q(opt->default_val.dbl, INT_MAX);
av_opt_set_q(s, opt->name, val, 0);
+ //av_log(s, AV_LOG_ERROR, "22opt->name '%s'\n", opt->name);
}
break;
case AV_OPT_TYPE_STRING:
@@ -742,6 +745,7 @@ void av_opt_set_defaults2(void *s, int mask, int flags)
case AV_OPT_TYPE_PIXEL_FMT:
case AV_OPT_TYPE_SAMPLE_FMT:
av_opt_set(s, opt->name, opt->default_val.str, 0);
+ //av_log(s, AV_LOG_ERROR, "11opt->name '%s'\n", opt->name);
break;
case AV_OPT_TYPE_BINARY:
/* Cannot set default for binary */
diff --git a/libcrypto.so b/libcrypto.so
new file mode 100755
index 0000000..d1bbf64
--- /dev/null
+++ b/libcrypto.so
Binary files differ
diff --git a/libssl.so b/libssl.so
new file mode 100755
index 0000000..1bab85f
--- /dev/null
+++ b/libssl.so
Binary files differ